changeset 24302:b3d7bad26e40

[illumos-gate merge] commit c85f09cc92abd00c84e58ec9f0f5d942906cb713 11972 resync smatch commit 3128654191cf8267843c8a40c4e0f3ac65f599f1 11973 tem: we only can translate colors 0-7 commit 62ce8e2e52946c2ebc855b02452650365c19eafc 12003 libefi: add efi_reserved_sectors() commit 78d83021c1426eb570f801cac4175645da13efe4 11986 libproc: cast between incompatible function types commit 5928363ef66d875d343b47ca57f45a68d08a056a 12008 libc symbol test timeout should be bumped
author Jerry Jelinek <jerry.jelinek@joyent.com>
date Thu, 21 Nov 2019 12:33:13 +0000
parents 1401bc8d2554 (current diff) 79022555a4a9 (diff)
children 7614c37fde4b
files manifest usr/src/lib/libefi/common/rdwr_efi.c usr/src/lib/libproc/common/Psymtab.c usr/src/test/libc-tests/runfiles/default.run usr/src/tools/smatch/Makefile usr/src/tools/smatch/src/Documentation/project-ideas.md usr/src/tools/smatch/src/Documentation/sparse.txt usr/src/tools/smatch/src/Documentation/test-suite usr/src/tools/smatch/src/check_memory.c usr/src/tools/smatch/src/smatch_auto_copy.c usr/src/tools/smatch/src/smatch_local_values.c usr/src/tools/smatch/src/sparse.pc.in usr/src/tools/smatch/src/validation/alias-distinct.c usr/src/tools/smatch/src/validation/alias-mixed.c usr/src/tools/smatch/src/validation/alias-same.c usr/src/tools/smatch/src/validation/asm-toplevel.c usr/src/tools/smatch/src/validation/bitfield-size.c usr/src/tools/smatch/src/validation/bool-cast-explicit.c usr/src/tools/smatch/src/validation/bool-cast-implicit.c usr/src/tools/smatch/src/validation/cast-constant-to-float.c usr/src/tools/smatch/src/validation/cast-constants.c usr/src/tools/smatch/src/validation/cast-kinds.c usr/src/tools/smatch/src/validation/cond-address-array.c usr/src/tools/smatch/src/validation/cond-address-function.c usr/src/tools/smatch/src/validation/external-function-has-definition.c usr/src/tools/smatch/src/validation/fp-vs-ptrcast.c usr/src/tools/smatch/src/validation/kill-casts.c usr/src/tools/smatch/src/validation/linear/asm-toplevel.c usr/src/tools/smatch/src/validation/linear/bitfield-init-zero.c usr/src/tools/smatch/src/validation/linear/cast-constant-to-float.c usr/src/tools/smatch/src/validation/linear/cast-constants.c usr/src/tools/smatch/src/validation/linear/fp-vs-ptrcast.c usr/src/tools/smatch/src/validation/loop-linearization.c usr/src/tools/smatch/src/validation/mem2reg/alias-distinct.c usr/src/tools/smatch/src/validation/mem2reg/alias-mixed.c usr/src/tools/smatch/src/validation/mem2reg/alias-same.c usr/src/tools/smatch/src/validation/optim/bitfield-size.c usr/src/tools/smatch/src/validation/phase2/backslash usr/src/tools/smatch/src/validation/phase3/comments usr/src/tools/smatch/src/validation/preprocessor/predef-char-bit.c usr/src/tools/smatch/src/validation/preprocessor/predef-max.c usr/src/tools/smatch/src/validation/preprocessor/predef-sizeof.c usr/src/tools/smatch/src/validation/test-be.c usr/src/tools/smatch/src/validation/testsuite-selfcheck1.c usr/src/tools/smatch/src/validation/testsuite-selfcheck2.c usr/src/tools/smatch/src/validation/testsuite-selfcheck3.c usr/src/uts/common/io/mac/mac.c usr/src/uts/intel/mac/Makefile usr/src/uts/intel/zfs/Makefile
diffstat 669 files changed, 24097 insertions(+), 7299 deletions(-) [+]
line wrap: on
line diff
--- a/manifest	Wed Nov 20 15:03:31 2019 +0000
+++ b/manifest	Thu Nov 21 12:33:13 2019 +0000
@@ -15601,6 +15601,7 @@
 f usr/share/man/man3ext/efi_alloc_and_init.3ext 0444 root bin
 s usr/share/man/man3ext/efi_alloc_and_read.3ext=efi_alloc_and_init.3ext
 s usr/share/man/man3ext/efi_free.3ext=efi_alloc_and_init.3ext
+s usr/share/man/man3ext/efi_reserved_sectors.3ext=efi_alloc_and_init.3ext
 s usr/share/man/man3ext/efi_use_whole_disk.3ext=efi_alloc_and_init.3ext
 s usr/share/man/man3ext/efi_write.3ext=efi_alloc_and_init.3ext
 s usr/share/man/man3ext/encrypt.3ext=crypt.3ext
--- a/usr/src/boot/Makefile.version	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/boot/Makefile.version	Thu Nov 21 12:33:13 2019 +0000
@@ -33,4 +33,4 @@
 # Use date like formatting here, YYYY.MM.DD.XX, without leading zeroes.
 # The version is processed from left to right, the version number can only
 # be increased.
-BOOT_VERSION = $(LOADER_VERSION)-2019.11.06.1
+BOOT_VERSION = $(LOADER_VERSION)-2019.11.15.1
--- a/usr/src/boot/sys/boot/common/tem.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/boot/sys/boot/common/tem.c	Thu Nov 21 12:33:13 2019 +0000
@@ -2815,23 +2815,22 @@
 static void
 tem_get_color(text_color_t *fg, text_color_t *bg, term_char_t c)
 {
-	if (c.tc_fg_color < 16) {
+	*fg = c.tc_fg_color;
+	*bg = c.tc_bg_color;
+
+	if (c.tc_fg_color < XLATE_NCOLORS) {
 		if (TEM_CHAR_ATTR(c.tc_char) &
 		    (TEM_ATTR_BRIGHT_FG | TEM_ATTR_BOLD))
 			*fg = brt_xlate[c.tc_fg_color];
 		else
 			*fg = dim_xlate[c.tc_fg_color];
-	} else {
-		*fg = c.tc_fg_color;
 	}
 
-	if (c.tc_bg_color < 16) {
+	if (c.tc_bg_color < XLATE_NCOLORS) {
 		if (TEM_CHAR_ATTR(c.tc_char) & TEM_ATTR_BRIGHT_BG)
 			*bg = brt_xlate[c.tc_bg_color];
 		else
 			*bg = dim_xlate[c.tc_bg_color];
-	} else {
-		*bg = c.tc_bg_color;
 	}
 }
 
--- a/usr/src/cmd/auditreduce/Makefile	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/cmd/auditreduce/Makefile	Thu Nov 21 12:33:13 2019 +0000
@@ -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:
 
--- a/usr/src/cmd/auditreduce/main.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/cmd/auditreduce/main.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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"));
+		}
 	}
 }
 
--- a/usr/src/common/font/font.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/common/font/font.c	Thu Nov 21 12:33:13 2019 +0000
@@ -48,9 +48,9 @@
 
 /* ANSI color to sun color translation. */
 /* BEGIN CSTYLED */
-/*                            Bk  Rd  Gr  Br  Bl  Mg  Cy  Wh */
-const uint8_t dim_xlate[] = {  1,  5,  3,  7,  2,  6,  4,  8 };
-const uint8_t brt_xlate[] = {  9, 13, 11, 15, 10, 14, 12,  0 };
+/*                                         Bk  Rd  Gr  Br  Bl  Mg  Cy  Wh */
+const uint8_t dim_xlate[XLATE_NCOLORS] = {  1,  5,  3,  7,  2,  6,  4,  8 };
+const uint8_t brt_xlate[XLATE_NCOLORS] = {  9, 13, 11, 15, 10, 14, 12,  0 };
 
 const uint8_t solaris_color_to_pc_color[16] = {
 	pc_brt_white,		/*  0 - brt_white	*/
--- a/usr/src/lib/libefi/common/mapfile-vers	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/lib/libefi/common/mapfile-vers	Thu Nov 21 12:33:13 2019 +0000
@@ -38,6 +38,11 @@
 
 $mapfile_version 2
 
+SYMBOL_VERSION ILLUMOS_0.1 {
+    global:
+	efi_reserved_sectors;
+} SUNW_1.2;
+
 SYMBOL_VERSION SUNW_1.2 {
     global:
 	efi_use_whole_disk;
--- a/usr/src/lib/libefi/common/rdwr_efi.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/lib/libefi/common/rdwr_efi.c	Thu Nov 21 12:33:13 2019 +0000
@@ -240,6 +240,19 @@
 #define	MAX_PARTS	((4294967295UL - sizeof (struct dk_gpt)) / \
 			    sizeof (struct dk_part))
 
+/*
+ * The EFI reserved partition size is 8 MiB. This calculates the number of
+ * sectors required to store 8 MiB, taking into account the device's sector
+ * size.
+ */
+uint_t
+efi_reserved_sectors(dk_gpt_t *efi)
+{
+	/* roundup to sector size */
+	return ((EFI_MIN_RESV_SIZE * DEV_BSIZE + efi->efi_lbasize - 1) /
+	    efi->efi_lbasize);
+}
+
 int
 efi_alloc_and_init(int fd, uint32_t nparts, struct dk_gpt **vtoc)
 {
@@ -1013,7 +1026,7 @@
 	 * physically non-zero partition.
 	 */
 	if (pl_start + pl_size - 1 == efi_label->efi_last_u_lba -
-	    EFI_MIN_RESV_SIZE) {
+	    efi_reserved_sectors(efi_label)) {
 		efi_label->efi_parts[phy_last_slice].p_size +=
 		    efi_label->efi_last_lba - efi_label->efi_altern_lba;
 	}
@@ -1270,10 +1283,12 @@
 	int			i, j;
 	diskaddr_t		istart, jstart, isize, jsize, endsect;
 	int			overlap = 0;
+	uint_t			reserved;
 
 	/*
 	 * make sure no partitions overlap
 	 */
+	reserved = efi_reserved_sectors(vtoc);
 	for (i = 0; i < vtoc->efi_nparts; i++) {
 		/* It can't be unassigned and have an actual size */
 		if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) &&
@@ -1292,10 +1307,10 @@
 				    "%d\n", i);
 			}
 			resv_part = i;
-			if (vtoc->efi_parts[i].p_size != EFI_MIN_RESV_SIZE)
+			if (vtoc->efi_parts[i].p_size != reserved)
 				(void) fprintf(stderr,
 				    "Warning: reserved partition size must "
-				    "be %d sectors\n", EFI_MIN_RESV_SIZE);
+				    "be %u sectors\n", reserved);
 		}
 		if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) ||
 		    (vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) {
--- a/usr/src/lib/libproc/common/Psymtab.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/lib/libproc/common/Psymtab.c	Thu Nov 21 12:33:13 2019 +0000
@@ -3355,7 +3355,7 @@
     const char *object_name, int which, int mask, proc_sym_f *func, void *cd)
 {
 	return (Psymbol_iter_com(P, lmid, object_name, which, mask,
-	    PRO_NATURAL, (proc_xsym_f *)func, cd));
+	    PRO_NATURAL, (proc_xsym_f *)(uintptr_t)func, cd));
 }
 
 int
@@ -3363,7 +3363,7 @@
     const char *object_name, int which, int mask, proc_sym_f *func, void *cd)
 {
 	return (Psymbol_iter_com(P, PR_LMID_EVERY, object_name, which, mask,
-	    PRO_NATURAL, (proc_xsym_f *)func, cd));
+	    PRO_NATURAL, (proc_xsym_f *)(uintptr_t)func, cd));
 }
 
 int
@@ -3371,7 +3371,7 @@
     const char *object_name, int which, int mask, proc_sym_f *func, void *cd)
 {
 	return (Psymbol_iter_com(P, PR_LMID_EVERY, object_name, which, mask,
-	    PRO_BYADDR, (proc_xsym_f *)func, cd));
+	    PRO_BYADDR, (proc_xsym_f *)(uintptr_t)func, cd));
 }
 
 int
@@ -3379,7 +3379,7 @@
     const char *object_name, int which, int mask, proc_sym_f *func, void *cd)
 {
 	return (Psymbol_iter_com(P, PR_LMID_EVERY, object_name, which, mask,
-	    PRO_BYNAME, (proc_xsym_f *)func, cd));
+	    PRO_BYNAME, (proc_xsym_f *)(uintptr_t)func, cd));
 }
 
 /*
--- a/usr/src/lib/udapl/libdat/Makefile.com	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/lib/udapl/libdat/Makefile.com	Thu Nov 21 12:33:13 2019 +0000
@@ -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,19 +42,19 @@
 
 include ../../../Makefile.lib
 
-LIBS =	$(DYNLIB) $(LINTLIB)
+LIBS =	$(DYNLIB)
 LDLIBS += -lc
 
 SRCDIR =	../common
 
 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
--- a/usr/src/man/man3ext/Makefile	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/man/man3ext/Makefile	Thu Nov 21 12:33:13 2019 +0000
@@ -16,28 +16,28 @@
 
 include		$(SRC)/Makefile.master
 
-MANSECT= 	3ext
+MANSECT=	3ext
 
-MANFILES= 	NOTE.3ext			\
-	 	SUNW_C_GetMechSession.3ext	\
-	 	auto_ef.3ext			\
-	 	crypt.3ext			\
-	 	demangle.3ext			\
-	 	ecb_crypt.3ext			\
-	 	efi_alloc_and_init.3ext		\
-	 	ld_support.3ext			\
-	 	md4.3ext			\
-	 	md5.3ext			\
-	 	read_vtoc.3ext			\
-	 	rtld_audit.3ext			\
-	 	rtld_db.3ext			\
-	 	sendfile.3ext			\
-	 	sendfilev.3ext			\
-	 	sha1.3ext			\
-	 	sha2.3ext			\
-	 	stdarg.3ext			\
-	 	tsalarm_get.3ext		\
-	 	varargs.3ext
+MANFILES=	NOTE.3ext			\
+		SUNW_C_GetMechSession.3ext	\
+		auto_ef.3ext			\
+		crypt.3ext			\
+		demangle.3ext			\
+		ecb_crypt.3ext			\
+		efi_alloc_and_init.3ext		\
+		ld_support.3ext			\
+		md4.3ext			\
+		md5.3ext			\
+		read_vtoc.3ext			\
+		rtld_audit.3ext			\
+		rtld_db.3ext			\
+		sendfile.3ext			\
+		sendfilev.3ext			\
+		sha1.3ext			\
+		sha2.3ext			\
+		stdarg.3ext			\
+		tsalarm_get.3ext		\
+		varargs.3ext
 
 MANLINKS=	DES_FAILED.3ext			\
 		MD4Final.3ext			\
@@ -77,6 +77,7 @@
 		des_setparity.3ext		\
 		efi_alloc_and_read.3ext		\
 		efi_free.3ext			\
+		efi_reserved_sectors.3ext	\
 		efi_use_whole_disk.3ext		\
 		efi_write.3ext			\
 		encrypt.3ext			\
@@ -154,6 +155,7 @@
 
 efi_alloc_and_read.3ext		:= LINKSRC = efi_alloc_and_init.3ext
 efi_free.3ext			:= LINKSRC = efi_alloc_and_init.3ext
+efi_reserved_sectors.3ext	:= LINKSRC = efi_alloc_and_init.3ext
 efi_use_whole_disk.3ext		:= LINKSRC = efi_alloc_and_init.3ext
 efi_write.3ext			:= LINKSRC = efi_alloc_and_init.3ext
 
--- a/usr/src/man/man3ext/efi_alloc_and_init.3ext	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/man/man3ext/efi_alloc_and_init.3ext	Thu Nov 21 12:33:13 2019 +0000
@@ -4,12 +4,11 @@
 .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License").  You may not use this file except in compliance with the License.
 .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.  See the License for the specific language governing permissions and limitations under the License.
 .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE.  If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH EFI_ALLOC_AND_INIT 3EXT "February 6, 2018"
+.TH EFI_ALLOC_AND_INIT 3EXT "November 20, 2019"
 .SH NAME
-efi_alloc_and_init, efi_alloc_and_read, efi_free, efi_write, efi_use_whole_disk
-\- manipulate a disk's EFI Partition Table
+efi_alloc_and_init, efi_alloc_and_read, efi_free, efi_write, efi_use_whole_disk,
+efi_reserved_sectors \- manipulate a disk's EFI Partition Table
 .SH SYNOPSIS
-.LP
 .nf
 cc [ \fIflag \&.\|.\|.\fR ] \fIfile\fR\&.\|.\|. \fB-lefi\fR [ \fIlibrary \&.\|.\|.\fR ]
 #include <sys/vtoc.h>
@@ -38,8 +37,12 @@
 \fBint\fR \fBefi_use_whole_disk\fR(\fBint\fR \fIfd\fR);
 .fi
 
+.LP
+.nf
+\fBuint_t\fR \fBefi_reserved_sectors\fR(\fBdk_gpt_t *\fR\fIvtoc\fR);
+.fi
+
 .SH DESCRIPTION
-.LP
 The \fBefi_alloc_and_init()\fR function initializes the \fBdk_gpt_t\fR
 structure specified by \fIvtoc\fR in preparation for a call to
 \fBefi_write()\fR. It calculates and initializes the \fBefi_version\fR,
@@ -65,6 +68,14 @@
 reserved slice (from slice 0 to slice 6 or unallocated space).
 .sp
 .LP
+The \fBefi_reserved_sectors()\fR function calculates number of sectors
+needed to create the reserved partition. The reserved partition is used
+by the operating system for internal purposes. The sector size used is
+based on the device and is recorded in the \fBefi_lbasize\fR member of
+the \fBdkgpt_t\fR structure indicated by the \fIvtoc\fR argument.
+A full description of the \fBdk_gpt_t\fR structure appears later in the manual.
+.sp
+.LP
 The \fIfd\fR argument refers to any slice on a raw disk, opened with
 \fBO_NDELAY\fR. See \fBopen\fR(2).
 .sp
@@ -88,7 +99,6 @@
 .in -2
 
 .SS "Protective Master Boot Record"
-.LP
 When a disk receives an EFI label, a protective MBR (\fBPMBR\fR) is also
 written containing a single partiton of type \fBEEh\fR and spanning the
 entire disk (up to the limit of what can be represented in an MBR). By
@@ -100,7 +110,6 @@
 information.
 
 .SH RETURN VALUES
-.LP
 Upon successful completion, \fBefi_alloc_and_init()\fR returns 0. Otherwise it
 returns \fBVT_EIO\fR if an I/O operation to the disk fails.
 .sp
@@ -137,6 +146,11 @@
 
 .sp
 .LP
+The \fBefi_reserved_sectors()\fR function always returns the number of
+reserved sectors required. It will always succeed.
+
+.sp
+.LP
 Upon successful completion, \fBefi_write()\fR returns 0. Otherwise, it returns
 a negative integer to indicate one of the following:
 .sp
@@ -207,14 +221,12 @@
 .RE
 
 .SH USAGE
-.LP
 The EFI label is used on disks with more than 1^32-1 blocks. For compatibility
 reasons, the \fBread_vtoc\fR(3EXT) and \fBwrite_vtoc()\fR functions should be
 used on smaller disks. The application should attempt the \fBread_vtoc()\fR or
 \fBwrite_vtoc()\fR call, check for an error of \fBVT_ENOTSUP\fR, then call the
 analogous EFI function.
 .SH ATTRIBUTES
-.LP
 See \fBattributes\fR(5) for descriptions of the following attributes:
 .sp
 
@@ -231,7 +243,6 @@
 .TE
 
 .SH SEE ALSO
-.LP
 \fBfmthard\fR(1M), \fBformat\fR(1M), \fBprtvtoc\fR(1M), \fBioctl\fR(2),
 \fBopen\fR(2), \fBlibefi\fR(3LIB), \fBread_vtoc\fR(3EXT), \fBattributes\fR(5),
 \fBdkio\fR(7I)
--- a/usr/src/man/man3lib/libefi.3lib	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/man/man3lib/libefi.3lib	Thu Nov 21 12:33:13 2019 +0000
@@ -3,22 +3,17 @@
 .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License").  You may not use this file except in compliance with the License.
 .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.  See the License for the specific language governing permissions and limitations under the License.
 .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE.  If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH LIBEFI 3LIB "May 8, 2008"
+.TH LIBEFI 3LIB "November 20, 2019"
 .SH NAME
 libefi \- EFI partition table library
 .SH SYNOPSIS
-.LP
 .nf
 cc [ \fIflag\fR... ] \fIfile\fR... \fB-lefi\fR [ \fIlibrary\fR... ]
 .fi
 
 .SH DESCRIPTION
-.sp
-.LP
 The functions in this library manipulate a disk's EFI partition table.
 .SH INTERFACES
-.sp
-.LP
 The shared object \fBlibefi.so.1\fR provides the public interfaces defined
 below. See \fBIntro\fR(3) for additional information on shared object
 interfaces.
@@ -29,12 +24,11 @@
 l l
 l l .
 \fBefi_alloc_and_init\fR	\fBefi_alloc_and_read\fR
-\fBefi_free\fR	\fBefi_use_whole_disk\fR
-\fBefi_write\fR	
+\fBefi_free\fR	\fBefi_reserved_sectors\fR
+\fBefi_use_whole_disk\fR	\fBefi_write\fR
 .TE
 
 .SH FILES
-.sp
 .ne 2
 .na
 \fB\fB/lib/libefi.so.1\fR\fR
@@ -53,8 +47,6 @@
 .RE
 
 .SH ATTRIBUTES
-.sp
-.LP
 See \fBattributes\fR(5) for descriptions of the following attributes:
 .sp
 
@@ -71,6 +63,4 @@
 .TE
 
 .SH SEE ALSO
-.sp
-.LP
 \fBIntro\fR(3), \fBefi_alloc_and_init\fR(3EXT), \fBattributes\fR(5)
--- a/usr/src/pkg/manifests/system-library.man3ext.inc	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/pkg/manifests/system-library.man3ext.inc	Thu Nov 21 12:33:13 2019 +0000
@@ -74,6 +74,8 @@
 link path=usr/share/man/man3ext/efi_alloc_and_read.3ext \
     target=efi_alloc_and_init.3ext
 link path=usr/share/man/man3ext/efi_free.3ext target=efi_alloc_and_init.3ext
+link path=usr/share/man/man3ext/efi_reserved_sectors.3ext \
+    target=efi_alloc_and_init.3ext
 link path=usr/share/man/man3ext/efi_use_whole_disk.3ext \
     target=efi_alloc_and_init.3ext
 link path=usr/share/man/man3ext/efi_write.3ext target=efi_alloc_and_init.3ext
--- a/usr/src/test/libc-tests/runfiles/default.run	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/test/libc-tests/runfiles/default.run	Thu Nov 21 12:33:13 2019 +0000
@@ -12,14 +12,14 @@
 #
 # Copyright (c) 2012 by Delphix. All rights reserved.
 # Copyright 2014 Garrett D'Amore <garrett@damore.org>
-# Copyright 2018 Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
 #
 
 [DEFAULT]
 pre =
 verbose = False
 quiet = False
-timeout = 60
+timeout = 120
 post =
 outputdir = /var/tmp/test_results
 
--- a/usr/src/tools/smatch/Makefile	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/Makefile	Thu Nov 21 12:33:13 2019 +0000
@@ -13,14 +13,14 @@
 
 #
 # 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.
 #
 
 PROG = smatch
-SPARSE_VERSION = 0.5.1-il-6
+SPARSE_VERSION = 0.6.1-rc1-il-1
 
 include ../Makefile.tools
 
@@ -60,78 +60,168 @@
 INS.file = $(RM) $@; $(CP) $< $(@D); $(CHMOD) $(FILEMODE) $@
 INS.dir = mkdir -p $@; $(CHMOD) $(DIRMODE) $@
 
+# fine for us
+OS=linux
+
+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
+
+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
+
 SMATCH_CHECK_OBJS:sh=ls src/check_*.c | sed -e 's+\.c+.o+;s+src/++;'
 
-OBJS = smatch.o $(SMATCH_CHECK_OBJS)
-
-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
-
-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
+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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/Documentation/.gitignore	Thu Nov 21 12:33:13 2019 +0000
@@ -0,0 +1,2 @@
+build
+dev-options.1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/Documentation/IR.rst	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/Documentation/Makefile	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/Documentation/TODO.md	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/Documentation/api.rst	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/Documentation/arm64-detecting-tagged-addresses.txt	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/Documentation/conf.py	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/Documentation/dev-options.rst	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/Documentation/doc-guide.rst	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/Documentation/index.rst	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/Documentation/logo.svg	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/Documentation/nocast-vs-bitwise.md	Thu Nov 21 12:33:13 2019 +0000
@@ -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>
--- a/usr/src/tools/smatch/src/Documentation/project-ideas.md	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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
-
--- a/usr/src/tools/smatch/src/Documentation/smatch.txt	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/Documentation/smatch.txt	Thu Nov 21 12:33:13 2019 +0000
@@ -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:
 
--- a/usr/src/tools/smatch/src/Documentation/sparse.txt	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/Documentation/sphinx/cdoc.py	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/Documentation/sphinx/ir.py	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/Documentation/test-suite	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/Documentation/test-suite.rst	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+	 */
--- a/usr/src/tools/smatch/src/Makefile	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/Makefile	Thu Nov 21 12:33:13 2019 +0000
@@ -1,96 +1,284 @@
-VERSION=0.5.1-il-6
+VERSION=0.6.1-rc1-il-1
 
-# 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
+
+CC ?= gcc
+LD = $(CC)
+AR = ar
+
+CFLAGS ?= -O2 -g
 
-CFLAGS += -O2 -finline-functions -fno-strict-aliasing -g
-CFLAGS += -Wall -Wwrite-strings -Wno-switch
-LDFLAGS += -g -lm -lsqlite3 -lssl -lcrypto
-LD = gcc
-AR = ar
-PKG_CONFIG = pkg-config
-COMMON_CFLAGS = -O2 -finline-functions -fno-strict-aliasing -g
-COMMON_CFLAGS += -Wall -Wwrite-strings
+DESTDIR ?=
+PREFIX ?= $(HOME)
+BINDIR ?= $(PREFIX)/bin
+MANDIR ?= $(PREFIX)/share/man
 
-ALL_CFLAGS = $(COMMON_CFLAGS) $(PKG_CFLAGS) $(CFLAGS)
-#
+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')
+
+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
+
+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
+
+INST_PROGRAMS=smatch sparse cgcc
+INST_MAN1=sparse.1 cgcc.1
+
+
+all:
+
+########################################################################
+# common flags/options/...
+
+cflags = -fno-strict-aliasing
+cflags += -Wall -Wwrite-strings -Wno-switch
+
+GCC_BASE := $(shell $(CC) --print-file-name=)
+cflags += -DGCC_BASE=\"$(GCC_BASE)\"
+
+MULTIARCH_TRIPLET := $(shell $(CC) -print-multiarch 2>/dev/null)
+cflags += -DMULTIARCH_TRIPLET=\"$(MULTIARCH_TRIPLET)\"
+
+
+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,-MD,.gcc-test.d .gcc-test.c 2>/dev/null && \
+		$(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-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')
+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))
+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
+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')
-
-GCC_BASE := $(shell $(CC) --print-file-name=)
-COMMON_CFLAGS += -DGCC_BASE=\"$(GCC_BASE)\"
-
-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
+ifeq ($(HAVE_LLVM),yes)
+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 := -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-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 ${arch})
+endif
+else
+$(warning Your system does not have llvm, disabling sparse-llvm)
 endif
 
-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
+########################################################################
+LIBS := libsparse.a
+OBJS := $(LIB_OBJS) $(EXTRA_OBJS) $(PROGRAMS:%=%.o)
+
+# Pretty print
+V := @
+Q := $(V:1=)
+
+########################################################################
+
 SMATCHDATADIR=$(INSTALL_PREFIX)/share/smatch
 
-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
+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
 
 SMATCH_CHECKS=$(shell ls check_*.c | sed -e 's/\.c/.o/')
 SMATCH_DATA=smatch_data/kernel.allocation_funcs \
@@ -118,201 +306,85 @@
 	smatch_scripts/trace_params.pl smatch_scripts/unlocked_paths.pl \
 	smatch_scripts/whitespace_only.sh smatch_scripts/wine_checker.sh \
 
-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
-
-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)
-else
-$(warning Your system does not have libxml, disabling c2xml)
-endif
-
-ifeq ($(HAVE_GTK),yes)
-GTK_CFLAGS := $(shell $(PKG_CONFIG) --cflags gtk+-$(GTK_VERSION))
-GTK_LIBS := $(shell $(PKG_CONFIG) --libs gtk+-$(GTK_VERSION))
-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
-
-ifeq ($(HAVE_LLVM),yes)
-ifeq ($(shell uname -m | grep -q '\(i386\|x86\)' && echo ok),ok)
-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_LIBS := $(shell $(LLVM_CONFIG) --libs)
-LLVM_LIBS += $(shell $(LLVM_CONFIG) --system-libs 2>/dev/null)
-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)
-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))
-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
-
-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
+SMATCH_LDFLAGS := -lsqlite3  -lssl -lcrypto -lm
 
-# 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  ';)
-
-define INSTALL_EXEC
-	$(QUIET_INST)install -v $1 $(DESTDIR)$2/$1 || exit 1;
-
-endef
-
-define INSTALL_FILE
-	$(QUIET_INST)install -v -m 644 $1 $(DESTDIR)$2/$1 || exit 1;
-
-endef
-
-SED_PC_CMD = 's|@version@|$(VERSION)|g;		\
-	      s|@prefix@|$(INSTALL_PREFIX)|g;		\
-	      s|@libdir@|$(LIBDIR)|g;		\
-	      s|@includedir@|$(INCLUDEDIR)|g'
-
-
-
-# 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)
+smatch: smatch.o $(SMATCH_OBJS) $(SMATCH_CHECKS) $(LIBS)
+	$(Q)$(LD) -o $@ $< $(SMATCH_OBJS) $(SMATCH_CHECKS) $(LIBS) $(SMATCH_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)
+
+$(SMATCH_OBJS) $(SMATCH_CHECKS): smatch.h smatch_slist.h smatch_extra.h avl.h
 
-ifneq ($(DEP_FILES),)
-include $(DEP_FILES)
-endif
+########################################################################
+all: $(PROGRAMS) smatch
 
-c2xml.o c2xml.sc: PKG_CFLAGS += $(LIBXML_CFLAGS)
+ldflags += $($(@)-ldflags) $(LDFLAGS)
+ldlibs  += $($(@)-ldlibs)  $(LDLIBS) -lm
+$(PROGRAMS): % : %.o $(LIBS)
+	@echo "  LD      $@"
+	$(Q)$(LD) $(ldflags) $^ $(ldlibs) -o $@
 
-pre-process.sc: CHECKER_FLAGS += -Wno-vla
+libsparse.a: $(LIB_OBJS)
+	@echo "  AR      $@"
+	$(Q)$(AR) rcs $@ $^
+
 
-%.o: %.c $(LIB_H)
-	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
+cflags   += $($(*)-cflags) $(CPPFLAGS) $(CFLAGS)
+%.o: %.c
+	@echo "  CC      $@"
+	$(Q)$(CC) $(cflags) -c -o $@ $<
 
 %.sc: %.c sparse
-	$(QUIET_CHECK) $(CHECKER) $(CHECKER_FLAGS) -c $(ALL_CFLAGS) $<
+	@echo "  CHECK   $<"
+	$(Q)CHECK=./sparse ./cgcc -no-compile $(CHECKER_FLAGS) $(cflags) -c $<
+
+selfcheck: $(OBJS:.o=.sc)
+
 
-ALL_OBJS :=  $(LIB_OBJS) $(foreach p,$(PROGRAMS),$(p).o $($(p)_EXTRA_DEPS))
-selfcheck: $(ALL_OBJS:.o=.sc)
+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
+
+
+check: all
+	$(Q)cd validation && ./test-suite
+validation/%.t: $(PROGRAMS)
+	@validation/test-suite single $*.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
+	@rm -f *.[oa] .*.d $(PROGRAMS) version.h smatch
+clean-check:
+	@echo "  CLEAN"
+	@find validation/ \( -name "*.c.output.*" \
+			  -o -name "*.c.error.*" \
+			  -o -name "*.o" \
+	                  \) -exec rm {} \;
 
-dist:
-	@if test "$(SPARSE_VERSION)" != "v$(VERSION)" ; then \
-		echo 'Update VERSION in the Makefile before running "make dist".' ; \
-		exit 1 ; \
-	fi
-	git archive --format=tar --prefix=sparse-$(VERSION)/ HEAD^{tree} | gzip -9 > sparse-$(VERSION).tar.gz
 
-check: all
-	$(Q)cd validation && ./test-suite
+install: install-bin install-man
+install-bin: $(INST_PROGRAMS:%=$(bindir)/%)
+install-man: $(INST_MAN1:%=$(man1dir)/%)
 
-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 {} \;
+$(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)
--- a/usr/src/tools/smatch/src/README	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/README	Thu Nov 21 12:33:13 2019 +0000
@@ -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:
 
-For parsing implicit dependencies, see smatch_scripts/implicit_dependencies.
+ - 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.
--- a/usr/src/tools/smatch/src/allocate.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/allocate.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
--- a/usr/src/tools/smatch/src/allocate.h	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/allocate.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/bits.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/builtin.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/builtin.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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,35 +52,39 @@
 	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;
+	struct expression *arg;
+	struct symbol *sym;
+	const char *msg;
+	int rc = 1;
+
+	FOR_EACH_PTR(expr->args, arg) {
+		if (n-- == 0) {
+			msg = "too many arguments";
+			goto error;
+		}
+		if (!evaluate_expression(arg))
+			rc = 0;
+	} END_FOR_EACH_PTR(arg);
+	if (n > 0) {
+		msg = "not enough arguments";
+		goto error;
+	}
+	return rc;
+
+error:
+	sym = expr->fn->ctype;
+	expression_error(expr, "%s for %s", msg, show_ident(sym->ident));
+	return 0;
 }
 
-static int arguments_choose(struct expression *expr)
+static int args_triadic(struct expression *expr)
 {
-	struct expression_list *arglist = expr->args;
-	struct expression *arg;
-	int i = 0;
-
-	FOR_EACH_PTR (arglist, arg) {
-		if (!evaluate_expression(arg))
-			return 0;
-		i++;
-	} 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;
-	}
-	return 1;
+	return eval_args(expr, 3);
 }
 
 static int evaluate_choose(struct expression *expr)
@@ -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);
+}
--- a/usr/src/tools/smatch/src/c2xml.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/c2xml.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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);
--- a/usr/src/tools/smatch/src/cgcc	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/cgcc	Thu Nov 21 12:33:13 2019 +0000
@@ -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,69 +292,88 @@
 	    " -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`;
 	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) {
--- a/usr/src/tools/smatch/src/char.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/char.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
--- a/usr/src/tools/smatch/src/check_access_ok_math.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/check_access_ok_math.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/check_arm64_tagged.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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);
+}
--- a/usr/src/tools/smatch/src/check_check_deref.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/check_check_deref.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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))
--- a/usr/src/tools/smatch/src/check_continue_vs_break.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/check_continue_vs_break.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
 }
--- a/usr/src/tools/smatch/src/check_debug.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/check_debug.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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,13 +205,16 @@
 {
 	struct expression *arg;
 	struct range_list *rl = NULL;
+	bool capped = false;
 	char *name;
 
 	arg = get_argument_from_call_expr(expr->args, 0);
 	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);
--- a/usr/src/tools/smatch/src/check_deref.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/check_deref.c	Thu Nov 21 12:33:13 2019 +0000
@@ -186,7 +186,7 @@
 {
 	struct statement *stmt;
 
-	if (!is_zero(expr->right))
+	if (!expr_is_zero(expr->right))
 		return;
 
 	if (__in_fake_assign)
--- a/usr/src/tools/smatch/src/check_deref_check.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/check_deref_check.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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))
--- a/usr/src/tools/smatch/src/check_dereferences_param.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/check_dereferences_param.c	Thu Nov 21 12:33:13 2019 +0000
@@ -78,8 +78,6 @@
 {
 	if (expr->type != EXPR_PREOP)
 		return;
-	if (getting_address())
-		return;
 	check_deref(expr->unop);
 }
 
--- a/usr/src/tools/smatch/src/check_double_checking.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/check_double_checking.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
--- a/usr/src/tools/smatch/src/check_free.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/check_free.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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)
--- a/usr/src/tools/smatch/src/check_free_strict.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/check_free_strict.c	Thu Nov 21 12:33:13 2019 +0000
@@ -36,10 +36,27 @@
 		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)
@@ -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);
--- a/usr/src/tools/smatch/src/check_get_user_overflow.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/check_get_user_overflow.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
 	}
 
--- a/usr/src/tools/smatch/src/check_kernel.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/check_kernel.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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);
--- a/usr/src/tools/smatch/src/check_list.h	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/check_list.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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)
--- a/usr/src/tools/smatch/src/check_locking.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/check_locking.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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)
--- a/usr/src/tools/smatch/src/check_memory.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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);
-	}
-}
--- a/usr/src/tools/smatch/src/check_memset.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/check_memset.c	Thu Nov 21 12:33:13 2019 +0000
@@ -19,22 +19,39 @@
 
 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;
 	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;
--- a/usr/src/tools/smatch/src/check_nospec.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/check_nospec.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
--- a/usr/src/tools/smatch/src/check_readl_infinite_loops.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/check_readl_infinite_loops.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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);
--- a/usr/src/tools/smatch/src/check_rosenberg.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/check_rosenberg.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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,14 +292,49 @@
 	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)
@@ -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);
+}
+
--- a/usr/src/tools/smatch/src/check_testing_index_after_use.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/check_testing_index_after_use.c	Thu Nov 21 12:33:13 2019 +0000
@@ -58,7 +58,7 @@
 	if (buf_comparison_index_ok(expr))
 		return;
 
-	if (getting_address())
+	if (getting_address(expr))
 		return;
 	if (is_capped(offset))
 		return;
--- a/usr/src/tools/smatch/src/check_uninitialized.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/check_uninitialized.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
--- a/usr/src/tools/smatch/src/check_unwind.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/check_unwind.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
--- a/usr/src/tools/smatch/src/compat.h	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/compat.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/compile-i386.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/compile-i386.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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);
--- a/usr/src/tools/smatch/src/compile.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/compile.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/cse.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/cse.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/cse.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/ctags.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/ctags.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/dominate.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/dominate.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/evaluate.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/evaluate.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
-
-	mod = 0; as = 0;
+	unsigned long mod = 0;
+	struct ident *as = NULL;
+
 	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);
-
 	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;
-
-	if (!target)
+	struct symbol *ttype, *stype;
+	int tclass, sclass;
+	struct ident *tas = NULL, *sas = NULL;
+
+	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,84 +2964,84 @@
 	expr->ctype = ctype;
 	expr->cast_type = ctype;
 
-	evaluate_expression(target);
-	degenerate(target);
-
-	class1 = classify_type(ctype, &t1);
-
-	expr->flags = cast_flags(expr, target);
+	evaluate_expression(source);
+	degenerate(source);
+
+	tclass = classify_type(ctype, &ttype);
+
+	expr->flags = cast_flags(expr, source);
 
 	/*
 	 * You can always throw a value away by casting to
 	 * "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);
-
-	if (class2 & TYPE_COMPOUND)
-		warning(expr->pos, "cast from non-scalar");
+	sclass = classify_type(stype, &stype);
 
 	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 (t1 != t2) {
-		if ((class1 & TYPE_RESTRICT) && restricted_value(target, t1))
+	if (sclass & TYPE_FOULED)
+		stype = unfoul(stype);
+
+	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);
-
-	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)) {
+			"cast adds address space '%s' to expression", show_as(tas));
+
+	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,9 +3276,9 @@
 	case EXPR_SYMBOL:
 		return evaluate_symbol_expression(expr);
 	case EXPR_BINOP:
-		if (!evaluate_expression(expr->left))
-			return NULL;
-		if (!evaluate_expression(expr->right))
+		evaluate_expression(expr->left);
+		evaluate_expression(expr->right);
+		if (!valid_subexpr_type(expr))
 			return NULL;
 		return evaluate_binop(expr);
 	case EXPR_LOGICAL:
@@ -3196,15 +3289,15 @@
 			return NULL;
 		return evaluate_comma(expr);
 	case EXPR_COMPARE:
-		if (!evaluate_expression(expr->left))
-			return NULL;
-		if (!evaluate_expression(expr->right))
+		evaluate_expression(expr->left);
+		evaluate_expression(expr->right);
+		if (!valid_subexpr_type(expr))
 			return NULL;
 		return evaluate_compare(expr);
 	case EXPR_ASSIGNMENT:
-		if (!evaluate_expression(expr->left))
-			return NULL;
-		if (!evaluate_expression(expr->right))
+		evaluate_expression(expr->left);
+		evaluate_expression(expr->right);
+		if (!valid_subexpr_type(expr))
 			return NULL;
 		return evaluate_assignment(expr);
 	case EXPR_PREOP:
@@ -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;
-
-		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;
-			}
+	FOR_EACH_PTR(stmt->asm_outputs, op) {
+		/* Identifier */
+
+		/* 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);
-
-	state = 0;
-	FOR_EACH_PTR(stmt->asm_inputs, expr) {
-		switch (state) {
-		case 0: /* Identifier */
-			state = 1;
-			continue;
-
-		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;
-			}
+
+		/* 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);
+
+	FOR_EACH_PTR(stmt->asm_inputs, op) {
+		/* Identifier */
+
+		/* 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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/evaluate.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/example.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/example.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
 }
 
--- a/usr/src/tools/smatch/src/expand.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/expand.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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,11 +163,33 @@
 	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;
 }
 
 /*
@@ -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,27 +553,27 @@
 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);
 	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;
 		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);
--- a/usr/src/tools/smatch/src/expression.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/expression.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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);
 }
 
--- a/usr/src/tools/smatch/src/expression.h	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/expression.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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);
--- a/usr/src/tools/smatch/src/flow.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/flow.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
-}
-
-static void kill_store(struct instruction *insn)
-{
-	if (insn) {
-		insn->bb = NULL;
-		insn->opcode = OP_SNOP;
-		kill_use(&insn->target);
-	}
+end:
+	repeat_phase |= REPEAT_SYMBOL_CLEANUP;
 }
 
 /* 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);
-
-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);
-
-	/* If we converted all the loads, remove the stores. They are dead */
-	if (all && !mod) {
-		FOR_EACH_PTR(pseudo->users, pu) {
-			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);
-		}
-	}
-			
-	return;
+	return NULL;
 }
 
-void simplify_symbol_usage(struct entrypoint *ep)
+void kill_dead_stores(struct entrypoint *ep, pseudo_t addr, int local)
 {
-	pseudo_t pseudo;
+	unsigned long generation;
+	struct basic_block *bb;
 
-	FOR_EACH_PTR(ep->accesses, pseudo) {
-		simplify_one_symbol(ep, pseudo->sym);
-	} END_FOR_EACH_PTR(pseudo);
+	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_instruction_force(insn);
+				return;
+			}
+		}
+	default:
+		break;
+	}
+
+	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;
--- a/usr/src/tools/smatch/src/flow.h	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/flow.h	Thu Nov 21 12:33:13 2019 +0000
@@ -5,35 +5,37 @@
 
 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;
 
 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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/flowgraph.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/flowgraph.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/gcc-attr-list.h	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/gcc-attr-list.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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,20 +130,17 @@
 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)
 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)
--- a/usr/src/tools/smatch/src/gdbhelpers	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/gdbhelpers	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/graph.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/graph.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
--- a/usr/src/tools/smatch/src/ident-list.h	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/ident-list.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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__);
--- a/usr/src/tools/smatch/src/inline.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/inline.c	Thu Nov 21 12:33:13 2019 +0000
@@ -32,6 +32,9 @@
 #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)
 {
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/ir.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/ir.h	Thu Nov 21 12:33:13 2019 +0000
@@ -0,0 +1,8 @@
+#ifndef	_IR_H
+#define	_IR_H
+
+#include "linearize.h"
+
+int ir_validate(struct entrypoint *ep);
+
+#endif
--- a/usr/src/tools/smatch/src/lib.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/lib.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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"
-
-static const char *progname;
+#include "bits.h"
 
-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 dbg_entry = 0;
-int dbg_dead = 0;
+int dump_macros_only = 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,33 +568,79 @@
 		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
 	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"
 
 	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[] = {
+static struct flag debugs[] = {
+	{ "compound", &dbg_compound},
+	{ "dead", &dbg_dead},
+	{ "domtree", &dbg_domtree},
 	{ "entry", &dbg_entry},
-	{ "dead", &dbg_dead},
+	{ "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 (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=\"");
+	if (*opt == '\0')
+		die("error: missing argument to \"%s\"", arg);
 
 	/* 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 int handle_fdiagnostic_prefix(const char *arg, const char *opt, const struct flag *flag, int options)
+{
+	switch (*opt) {
+	case '\0':
+		diag_prefix = "sparse";
+		return 1;
+	case '=':
+		diag_prefix = xasprintf("%s", opt+1);
+		return 1;
+	default:
+		return 0;
 	}
 }
 
-	static char **handle_switch_fdump(char *arg, char **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 },
+		{ },
+	};
+
+	return handle_suboption_mask(arg, opt, dump_ir_options, &fdump_ir);
+}
+
+static int handle_fmemcpy_max_count(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;
-	}
+	opt_ullong(arg, opt, &fmemcpy_max_count, OPTNUM_ZERO_IS_INF|OPTNUM_UNLIMITED);
+	return 1;
+}
+
+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;
+}
 
-	/* ignore others flags */
-	return next;
-
-err:
-	die("error: unknown flag \"-fdump-%s\"", arg);
-}
+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, },
+	{ },
+};
 
 static char **handle_switch_f(char *arg, char **next)
 {
-	arg++;
-
-	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);
-
-	if (!strcmp(arg, "unsigned-char")) {
-		funsigned_char = 1;
-		return next;
-	}
-
-	/* handle switches w/ arguments above, boolean and only boolean below */
-	if (handle_simple_switch(arg, "mem-report", &fmem_report))
+	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_width(const char *name, unsigned bits)
+{
+	char buf[32];
+
+	snprintf(buf, sizeof(buf), "__%s_WIDTH__", name);
+	predefine(buf, 1, "%d", bits);
+}
+
+static void predefined_max(const char *name, struct symbol *type)
+{
+	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_max(const char *name, const char *suffix, unsigned bits)
+static void predefined_min(const char *name, struct symbol *type)
 {
-	unsigned long long max = (1ULL << (bits - 1 )) - 1;
+	const char *suffix = builtin_type_suffix(type);
+	char buf[32];
+
+	snprintf(buf, sizeof(buf), "__%s_MIN__", name);
 
-	add_pre_buffer("#weak_define __%s_MAX__ %#llx%s\n", name, max, suffix);
+	if (is_signed_type(type))
+		predefine(buf, 1, "(-__%s_MAX__ - 1)", name);
+	else
+		predefine(buf, 1, "0%s", suffix);
 }
 
-static void predefined_type_size(const char *name, const char *suffix, unsigned bits)
+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);
+}
+
+static void predefined_ctype(const char *name, struct symbol *type, int flags)
 {
-	predefined_max(name, suffix, bits);
-	predefined_sizeof(name, bits);
+	unsigned bits = type->bit_size;
+
+	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);
 }
 
 static void predefined_macros(void)
 {
-	add_pre_buffer("#define __CHECKER__ 1\n");
+	predefine("__CHECKER__", 0, "1");
+	predefine("__GNUC__", 1, "%d", gcc_major);
+	predefine("__GNUC_MINOR__", 1, "%d", gcc_minor);
+	predefine("__GNUC_PATCHLEVEL__", 1, "%d", gcc_patchlevel);
+
+	predefine("__STDC__", 1, "1");
+	switch (standard) {
+	case STANDARD_C89:
+		predefine("__STRICT_ANSI__", 1, "1");
+		break;
+
+	case STANDARD_C94:
+		predefine("__STDC_VERSION__", 1, "199409L");
+		predefine("__STRICT_ANSI__", 1, "1");
+		break;
+
+	case STANDARD_C99:
+		predefine("__STDC_VERSION__", 1, "199901L");
+		predefine("__STRICT_ANSI__", 1, "1");
+		break;
 
-	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);
+	case STANDARD_GNU89:
+	default:
+		break;
+
+	case STANDARD_GNU99:
+		predefine("__STDC_VERSION__", 1, "199901L");
+		break;
+
+	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;
+	}
+
+	predefine("__CHAR_BIT__", 1, "%d", bits_in_char);
+	if (funsigned_char)
+		predefine("__CHAR_UNSIGNED__", 1, "1");
 
-	predefined_type_size("INT", "", bits_in_int);
-	predefined_type_size("LONG", "L", bits_in_long);
-	predefined_type_size("LONG_LONG", "LL", bits_in_longlong);
+	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);
 
-	predefined_sizeof("INT128", 128);
+	predefined_ctype("INT",         &int_ctype, PTYPE_ALL);
+	predefined_ctype("LONG",       &long_ctype, PTYPE_ALL);
+	predefined_ctype("LONG_LONG", &llong_ctype, PTYPE_ALL);
+
+	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);
+
+	predefined_sizeof("INT128", "", 128);
 
-	predefined_sizeof("SIZE_T", bits_in_pointer);
-	predefined_sizeof("PTRDIFF_T", bits_in_pointer);
-	predefined_sizeof("POINTER", bits_in_pointer);
+	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);
+
+	predefined_sizeof("FLOAT", "", bits_in_float);
+	predefined_sizeof("DOUBLE", "", bits_in_double);
+	predefined_sizeof("LONG_DOUBLE", "", bits_in_longdouble);
 
-	predefined_sizeof("FLOAT", bits_in_float);
-	predefined_sizeof("DOUBLE", bits_in_double);
-	predefined_sizeof("LONG_DOUBLE", bits_in_longdouble);
+	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__");
+	}
+
+	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);
 
-	add_pre_buffer("#weak_define __%s_ENDIAN__ 1\n",
-		arch_big_endian ? "BIG" : "LITTLE");
-
-	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");
-
-	add_pre_buffer("#weak_define __PRAGMA_REDEFINE_EXTNAME 1\n");
+	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;
+	}
 
-	/*
-	 * This is far from perfect...
-	 */
+	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
-	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");
+	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 declare_builtin_functions(void)
+static void create_builtin_stream(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");
-
-	/* 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");
-
-	/* 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");
-
-	/* 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");
-
-	/* 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");
-
-	/* 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");
-
-	/* 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"
-	);
-
-	/* 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");
-
-	/* 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");
-
-	/* 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");
-
-	/* 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");
-
-	/* 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");
-}
-
-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();
 
+		predefined_macros();
 		create_builtin_stream();
-		predefined_macros();
-		if (!preprocess_only)
-			declare_builtin_functions();
+		declare_builtins();
 
 		list = sparse_initial();
 
--- a/usr/src/tools/smatch/src/lib.h	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/lib.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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,13 +116,32 @@
 #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;
 
 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 dbg_entry;
-extern int dbg_dead;
+extern int dump_macros_only;
 
+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);
--- a/usr/src/tools/smatch/src/linearize.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/linearize.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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,14 +72,13 @@
 {
 	static int nr;
 	struct basic_block *bb = __alloc_basic_block(0);
-	bb->context = -1;
 	bb->pos = pos;
 	bb->ep = ep;
 	bb->nr = nr++;
 	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,33 +366,36 @@
 			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);
 		}
 		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,35 +793,39 @@
 		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);
 
 	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 */
 	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,26 +840,68 @@
 	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->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;
-	insn->target = phi;
 	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;
 }
 
 /*
@@ -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,40 +988,75 @@
 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,
 		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,29 +1078,53 @@
 	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);
 	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_bitfield_extract(struct entrypoint *ep,
+		pseudo_t val, struct symbol *ctype, struct symbol *btype)
+{
+	unsigned int off = ctype->bit_offset;
+
+	if (off) {
+		pseudo_t shift = value_pseudo(off);
+		val = add_binary_op(ep, btype, OP_LSR, val, shift);
+	}
+	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->result_type;
-	pseudo_t new = add_load(ep, ad);
+	struct symbol *ctype = ad->type;
+	struct symbol *btype;
+	pseudo_t new;
 
-	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 (ctype->bit_size != type_size(ad->source_type))
-		new = cast_pseudo(ep, new, ad->source_type, ad->result_type);
+	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,31 +1136,36 @@
 	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))
 		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;
+
+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);
 
-	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);
+	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->ctype)
-		ctype = &fn->ctype->ctype;
+	if (fn->type == EXPR_PREOP && fn->op == '*' && is_func_type(fn->ctype))
+		fn = fn->unop;
 
-	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;
+
+	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);
 
-	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);
+	// 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,28 +1976,49 @@
 {
 	pseudo_t pseudo;
 	struct statement *s;
-	struct symbol *ret = stmt->ret;
 
 	pseudo = VOID;
 	FOR_EACH_PTR(stmt->stmts, s) {
 		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);
-
+	if (!expr || !expr->ctype)
+		return VOID;
+	pseudo = linearize_expression(ep, expr);
 	active = ep->active;
-	if (!bb_reachable(active))
-		return VOID;
+	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);
-
-		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);
+	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);
 
-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;
 }
 
--- a/usr/src/tools/smatch/src/linearize.h	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/linearize.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
-	union {
-		pseudo_t target;
-		pseudo_t cond;		/* for branch and switch */
-	};
+	pseudo_t target;
 	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,7 +113,11 @@
 		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,109 +149,24 @@
 	};
 };
 
-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;
 
 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,7 +241,32 @@
 
 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)
@@ -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 */
 
--- a/usr/src/tools/smatch/src/liveness.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/liveness.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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,31 +130,12 @@
 		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;
 	}
 }
 
-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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/liveness.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/machine.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/macro_table.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/macro_table.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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);
 }
--- a/usr/src/tools/smatch/src/memops.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/memops.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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);
 }
--- a/usr/src/tools/smatch/src/obfuscate.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/obfuscate.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/opcode.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/opcode.def	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/opcode.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/optimize.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/optimize.h	Thu Nov 21 12:33:13 2019 +0000
@@ -0,0 +1,9 @@
+#ifndef OPTIMIZE_H
+#define OPTIMIZE_H
+
+struct entrypoint;
+
+/* optimize.c */
+void optimize(struct entrypoint *ep);
+
+#endif
--- a/usr/src/tools/smatch/src/parse.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/parse.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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,10 +192,17 @@
 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 = {
@@ -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,13 +482,17 @@
 	{ "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 },
 	{ "__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,76 +808,108 @@
 	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 >= (sizeof(val) * 8))
+		return 0;
+	return val >> n;
+}
+
+struct range {
+	long long		neg;
+	unsigned long long	pos;
+};
+
+static void update_range(struct range *range, unsigned long long uval, struct symbol *vtype)
+{
+	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 void lower_boundary(Num *n, Num *v)
-{
-	if (n->x < v->x)
-		return;
-	if (n->x > v->x) {
-		*n = *v;
-		return;
-	}
-	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;
 
 	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,31 +1007,31 @@
 		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))
+	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 if (type_is_ok(&ullong_ctype, &upper, &lower))
-		base_type = &ullong_ctype;
 	else
 		base_type = &bad_ctype;
 	parent->ctype.base_type = base_type;
 	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;
+		token = conditional_expression(token, &args[2]);
+		token = expect(token, ')', "after context 3rd argument");
+		context->context = args[0];
+		idx++;
+	} else {
+		token = expect(token, ')', "after context 2nd argument");
 	}
-
-	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:
-		context->context = args[0];
-		context->in = get_expression_value(args[1]);
-		context->out = get_expression_value(args[2]);
-		break;
-	}
-
-	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,15 +2128,16 @@
 
 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)) {
-		token = token->next;
-	}
-	if (token_type(token) == TOKEN_IDENT && token->ident == &goto_ident) {
-		is_goto = 1;
+	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;
 	}
 	token = expect(token, '(', "after asm");
@@ -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,26 +2484,33 @@
 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");
 }
 
 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, ','))
--- a/usr/src/tools/smatch/src/parse.h	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/parse.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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);
--- a/usr/src/tools/smatch/src/pre-process.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/pre-process.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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,13 +960,14 @@
 		return NULL;
 
 	if (!getcwd(cwd, sizeof(cwd)))
-		return NULL;
+		goto close;
 
 	while ((entry = readdir(dp))) {
 		lstat(entry->d_name, &statbuf);
 
 		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,13 +1477,102 @@
 	return NULL;
 }
 
+static int do_define(struct position pos, struct token *token, struct ident *name,
+		     struct token *arglist, struct token *expansion, int attr)
+{
+	struct symbol *sym;
+	int ret = 1;
+
+	expansion = parse_expansion(expansion, arglist, name);
+	if (!expansion)
+		return 1;
+
+	sym = lookup_symbol(name, NS_MACRO | NS_UNDEF);
+	if (sym) {
+		int clean;
+
+		if (attr < sym->attr)
+			goto out;
+
+		clean = (attr == sym->attr && sym->namespace == NS_MACRO);
+
+		if (token_list_different(sym->expansion, expansion) ||
+		    token_list_different(sym->arglist, arglist)) {
+			ret = 0;
+			if ((clean && attr == SYM_ATTR_NORMAL)
+					|| sym->used_in == file_scope) {
+				warning(pos, "preprocessor token %.*s redefined",
+						name->len, name->name);
+				info(sym->pos, "this was the original definition");
+			}
+		} else if (clean)
+			goto out;
+	}
+
+	if (!sym || sym->scope != file_scope) {
+		sym = alloc_symbol(pos, SYM_NODE);
+		bind_symbol(sym, name, NS_MACRO);
+		add_ident(&macros, name);
+		ret = 0;
+	}
+
+	if (!ret) {
+		sym->expansion = expansion;
+		sym->arglist = arglist;
+		if (token) /* Free the "define" token, but not the rest of the line */
+			__free_token(token);
+	}
+
+	sym->namespace = NS_MACRO;
+	sym->used_in = NULL;
+	sym->attr = attr;
+out:
+	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 symbol *sym;
 	struct ident *name;
-	int ret;
 
 	if (token_type(left) != TOKEN_IDENT) {
 		sparse_error(token->pos, "expected identifier to 'define'");
@@ -1449,51 +1595,7 @@
 		}
 	}
 
-	expansion = parse_expansion(expansion, arglist, name);
-	if (!expansion)
-		return 1;
-
-	ret = 1;
-	sym = lookup_symbol(name, NS_MACRO | NS_UNDEF);
-	if (sym) {
-		int clean;
-
-		if (attr < sym->attr)
-			goto out;
-
-		clean = (attr == sym->attr && sym->namespace == NS_MACRO);
-
-		if (token_list_different(sym->expansion, expansion) ||
-		    token_list_different(sym->arglist, arglist)) {
-			ret = 0;
-			if ((clean && attr == SYM_ATTR_NORMAL)
-					|| sym->used_in == file_scope) {
-				warning(left->pos, "preprocessor token %.*s redefined",
-						name->len, name->name);
-				info(sym->pos, "this was the original definition");
-			}
-		} else if (clean)
-			goto out;
-	}
-
-	if (!sym || sym->scope != file_scope) {
-		sym = alloc_symbol(left->pos, SYM_NODE);
-		bind_symbol(sym, name, NS_MACRO);
-		add_ident(&macros, name);
-		ret = 0;
-	}
-
-	if (!ret) {
-		sym->expansion = expansion;
-		sym->arglist = arglist;
-		__free_token(token);	/* Free the "define" token, but not the rest of the line */
-	}
-
-	sym->namespace = NS_MACRO;
-	sym->used_in = NULL;
-	sym->attr = attr;
-out:
-	return ret;
+	return do_define(left->pos, token, name, arglist, expansion, attr);
 }
 
 static int handle_define(struct stream *stream, struct token **line, struct token *token)
@@ -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;
 	}
--- a/usr/src/tools/smatch/src/ptrlist.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/ptrlist.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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,18 +239,21 @@
 }
 
 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 */
 	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;
--- a/usr/src/tools/smatch/src/ptrlist.h	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/ptrlist.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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 (29)
+#define LIST_NODE_NR (13)
 
-struct ptr_list {
-	int nr:8;
-	int rm:8;
-	struct ptr_list *prev;
-	struct ptr_list *next;
-	void *list[LIST_NODE_NR];
-};
+#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];	\
+	}
 
-#define ptr_list_empty(x) ((x) == NULL)
+DECLARE_PTR_LIST(ptr_list, void);
+
 
 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,256 +53,230 @@
  * 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)
-
-#define PTR_ENTRY_NOTAG(h,i)	((h)->list[i])
-#define PTR_ENTRY(h,i)	(void *)(~3UL & (unsigned long)PTR_ENTRY_NOTAG(h,i))
-
-static inline void *first_ptr_list(struct ptr_list *list)
-{
-	struct ptr_list *head = list;
-
-	if (!list)
-		return NULL;
-
-	while (list->nr == 0) {
-		list = list->next;
-		if (list == head)
-			return NULL;
-	}
-	return PTR_ENTRY(list, 0);
-}
-
-static inline void *last_ptr_list(struct ptr_list *list)
-{
-	struct ptr_list *head = list;
+extern void **__add_ptr_list(struct ptr_list **, void *);
+extern void **__add_ptr_list_tag(struct ptr_list **, void *, unsigned long);
 
-	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 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 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);\
+	})
 
-#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 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);			\
+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)
 
-#define DO_FINISH(ptr, __head, __list, __nr)						\
-		(void)(__nr); /* Sanity-check nesting */				\
-	} while (0)
 
+////////////////////////////////////////////////////////////////////////
+// API
 #define PREPARE_PTR_LIST(head, ptr) \
-	DO_PREPARE(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY)
+	DO_PREPARE(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY_UNTAG)
 
 #define NEXT_PTR_LIST(ptr) \
-	DO_NEXT(ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY)
+	DO_NEXT(ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY_UNTAG)
 
 #define RESET_PTR_LIST(ptr) \
-	DO_RESET(ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY)
+	DO_RESET(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 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 DO_END_FOR_EACH(ptr, __head, __list, __nr)					\
-					} while (0);					\
-				} while (0);						\
-			}								\
-		} while ((__list = __list->next) != __head);				\
-	}										\
-} while (0)
-
-#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 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_END_FOR_EACH_REVERSE(ptr, __head, __list, __nr)				\
-					} while (0);					\
-				} while (0);						\
-			}								\
-		} while (__list != __head);						\
-	}										\
-} while (0)
+#define FOR_EACH_PTR(head, ptr) \
+	DO_FOR_EACH(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY_NOTAG)
 
-#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 RECURSE_PTR_REVERSE(ptr, new)							\
-	DO_REVERSE(ptr, __head##ptr, __list##ptr, __nr##ptr,				\
-		   new, __head##new, __list##new, __nr##new, PTR_ENTRY)
-
-#define DO_THIS_ADDRESS(ptr, __head, __list, __nr)					\
-	((__typeof__(&(ptr))) (__list->list + __nr))
-
-#define FOR_EACH_PTR(head, ptr) \
-	DO_FOR_EACH(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY)
+#define FOR_EACH_PTR_TAG(head, ptr) \
+	DO_FOR_EACH(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY_UNTAG)
 
 #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 FOR_EACH_PTR_REVERSE(head, ptr) \
+	DO_FOR_EACH_REVERSE(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY_NOTAG)
 
-#define END_FOR_EACH_PTR_NOTAG(ptr) END_FOR_EACH_PTR(ptr)
-
-#define FOR_EACH_PTR_REVERSE(head, ptr) \
-	DO_FOR_EACH_REVERSE(head, 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 END_FOR_EACH_PTR_REVERSE(ptr) \
 	DO_END_FOR_EACH_REVERSE(ptr, __head##ptr, __list##ptr, __nr##ptr)
 
-#define FOR_EACH_PTR_REVERSE_NOTAG(head, ptr) \
-	DO_FOR_EACH_REVERSE(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY_NOTAG)
-
-#define END_FOR_EACH_PTR_REVERSE_NOTAG(ptr) END_FOR_EACH_PTR_REVERSE(ptr)
-
 #define THIS_ADDRESS(ptr) \
 	DO_THIS_ADDRESS(ptr, __head##ptr, __list##ptr, __nr##ptr)
 
-extern void split_ptr_list_head(struct ptr_list *);
-
-#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++;									\
-} while (0)
-
 #define INSERT_CURRENT(new, ptr) \
-	DO_INSERT_CURRENT(new, ptr, __head##ptr, __list##ptr, __nr##ptr)
-
-#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)
+	DO_INSERT_CURRENT(new, __head##ptr, __list##ptr, __nr##ptr)
 
 #define DELETE_CURRENT_PTR(ptr) \
-	DO_DELETE_CURRENT(ptr, __head##ptr, __list##ptr, __nr##ptr)
+	DO_DELETE_CURRENT(__head##ptr, __list##ptr, __nr##ptr)
 
-#define REPLACE_CURRENT_PTR(ptr, new_ptr)						\
+#define REPLACE_CURRENT_PTR(ptr, new_ptr)				\
 	do { *THIS_ADDRESS(ptr) = (new_ptr); } while (0)
 
-#define DO_MARK_CURRENT_DELETED(ptr, __list) do {	\
-		REPLACE_CURRENT_PTR(ptr, NULL);		\
-		__list->rm++;				\
-	} 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)
 
-extern void pack_ptr_list(struct ptr_list **);
+#define PACK_PTR_LIST(x) \
+	pack_ptr_list((struct ptr_list **)(x))
+
+#define CURRENT_TAG(ptr)	(3 & (unsigned long)*THIS_ADDRESS(ptr))
+#define TAG_CURRENT(ptr,val)	update_tag(THIS_ADDRESS(ptr),val)
+
+// 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)
+
+////////////////////////////////////////////////////////////////////////
+// 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 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 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 DO_NEXT(ptr, __head, __list, __nr, PTR_ENTRY)			\
+		if (ptr) {						\
+			PTR_NEXT(ptr, __head, __list, __nr, PTR_ENTRY);	\
+		}
+
+#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 DO_FINISH(ptr, __head, __list, __nr)				\
+		VRFY_PTR_LIST(__head); /* Sanity-check nesting */	\
+	} while (0)
+
+#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 DO_END_FOR_EACH(ptr, __head, __list, __nr)			\
+		}							\
+	} while ((__list = __list->next) != __head);			\
+} while (0)
 
-#define PACK_PTR_LIST(x) pack_ptr_list((struct ptr_list **)(x))
+#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_END_FOR_EACH_REVERSE(ptr, __head, __list, __nr)		\
+		}							\
+	} while (__list != __head);					\
+} while (0)
+
+#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_THIS_ADDRESS(ptr, __head, __list, __nr)			\
+	(&__list->list[__nr])
+
+
+extern void split_ptr_list_head(struct ptr_list *);
+
+#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 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)
+
+
+#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)
 {
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/ptrmap.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/ptrmap.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/scope.h	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/scope.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
 };
--- a/usr/src/tools/smatch/src/show-parse.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/show-parse.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
 }
--- a/usr/src/tools/smatch/src/simplify.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/simplify.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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,42 +362,38 @@
 		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;
 
 	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,7 +465,14 @@
 	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)
@@ -366,19 +486,18 @@
 	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;
 
 	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,192 +511,16 @@
 	return size;
 }
 
-static int simplify_asr(struct instruction *insn, pseudo_t pseudo, long long value)
-{
-	unsigned int size = operand_size(insn, pseudo);
-
-	if (value >= size) {
-		warning(insn->pos, "right shift by bigger than source value");
-		return replace_with_pseudo(insn, value_pseudo(insn->type, 0));
-	}
-	if (!value)
-		return replace_with_pseudo(insn, pseudo);
-	return 0;
-}
-
-static int simplify_mul_div(struct instruction *insn, long long value)
-{
-	unsigned long long sbit = 1ULL << (insn->size - 1);
-	unsigned long long bits = sbit | (sbit - 1);
-
-	if (value == 1)
-		return replace_with_pseudo(insn, insn->src1);
-
-	switch (insn->opcode) {
-	case OP_MULS:
-	case OP_MULU:
-		if (value == 0)
-			return replace_with_pseudo(insn, insn->src2);
-	/* Fall through */
-	case OP_DIVS:
-		if (!(value & sbit))	// positive
-			break;
-
-		value |= ~bits;
-		if (value == -1) {
-			insn->opcode = OP_NEG;
-			return REPEAT_CSE;
-		}
-	}
-
-	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;
-	int inverse;
-	int opcode;
-
-	if (value != 0 && value != 1)
-		return 0;
-
-	if (!def)
-		return 0;
-
-	inverse = (insn->opcode == OP_SET_NE) == value;
-	opcode = def->opcode;
-	switch (opcode) {
-	case OP_BINCMP ... OP_BINCMP_END:
-		// Convert:
-		//	setcc.n	%t <- %a, %b
-		//	setne.m %r <- %t, $0
-		// into:
-		//	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);
-		remove_usage(old, &insn->src1);
-		return REPEAT_CSE;
-
-	default:
-		return 0;
-	}
-}
-
-static int simplify_constant_rightside(struct instruction *insn)
-{
-	long long value = insn->src2->value;
-
-	switch (insn->opcode) {
-	case OP_OR_BOOL:
-		if (value == 1)
-			return replace_with_pseudo(insn, insn->src2);
-		goto case_neutral_zero;
-
-	case OP_SUB:
-		if (value) {
-			insn->opcode = OP_ADD;
-			insn->src2 = value_pseudo(insn->type, -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_MODU: case OP_MODS:
-		if (value == 1)
-			return replace_with_pseudo(insn, value_pseudo(insn->type, 0));
-		return 0;
-
-	case OP_DIVU: case OP_DIVS:
-	case OP_MULU: case OP_MULS:
-		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;
-
-	case OP_SET_NE:
-	case OP_SET_EQ:
-		return simplify_seteq_setne(insn, value);
-	}
-	return 0;
-}
-
-static int simplify_constant_leftside(struct instruction *insn)
-{
-	long long value = insn->src1->value;
-
-	switch (insn->opcode) {
-	case OP_ADD: case OP_OR: case OP_XOR:
-		if (!value)
-			return replace_with_pseudo(insn, insn->src2);
-		return 0;
-
-	case OP_SHL:
-	case OP_LSR: case OP_ASR:
-	case OP_AND:
-	case OP_MULU: case OP_MULS:
-		if (!value)
-			return replace_with_pseudo(insn, insn->src1);
-		return 0;
-	}
-	return 0;
-}
-
-static int simplify_constant_binop(struct instruction *insn)
+static pseudo_t eval_insn(struct instruction *insn)
 {
 	/* 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;
 
-	mask = 1ULL << (insn->size-1);
+	mask = 1ULL << (size-1);
 	bits = mask | (mask-1);
 
 	if (left & mask)
@@ -594,43 +537,46 @@
 	case OP_SUB:
 		res = left - right;
 		break;
-	case OP_MULU:
+	case OP_MUL:
 		res = ul * ur;
 		break;
-	case OP_MULS:
-		res = left * right;
-		break;
 	case OP_DIVU:
 		if (!ur)
-			return 0;
+			goto undef;
 		res = ul / ur;
 		break;
 	case OP_DIVS:
 		if (!right)
-			return 0;
+			goto undef;
 		if (left == mask && right == -1)
-			return 0;
+			goto undef;
 		res = left / right;
 		break;
 	case OP_MODU:
 		if (!ur)
-			return 0;
+			goto undef;
 		res = ul % ur;
 		break;
 	case OP_MODS:
 		if (!right)
-			return 0;
+			goto undef;
 		if (left == mask && right == -1)
-			return 0;
+			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 */
@@ -643,13 +589,7 @@
 	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;
@@ -682,11 +622,543 @@
 		res = ul >= ur;
 		break;
 	default:
-		return 0;
+		return NULL;
 	}
 	res &= bits;
 
-	replace_with_pseudo(insn, value_pseudo(insn->type, res));
+	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)
+{
+	unsigned long long sbit = 1ULL << (insn->size - 1);
+	unsigned long long bits = sbit | (sbit - 1);
+
+	if (value == 1)
+		return replace_with_pseudo(insn, insn->src1);
+
+	switch (insn->opcode) {
+	case OP_MUL:
+		if (value == 0)
+			return replace_with_pseudo(insn, insn->src2);
+	/* Fall through */
+	case OP_DIVS:
+		if (!(value & sbit))	// positive
+			break;
+
+		value |= ~bits;
+		if (value == -1) {
+			insn->opcode = OP_NEG;
+			return REPEAT_CSE;
+		}
+	}
+
+	return 0;
+}
+
+static int simplify_seteq_setne(struct instruction *insn, long long value)
+{
+	pseudo_t old = insn->src1;
+	struct instruction *def;
+	unsigned osize;
+	int inverse;
+	int opcode;
+
+	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_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
+		// into:
+		//	setcc.n	%t <- %a, %b
+		//	setcc.m %r <- %a, $b
+		// and similar for setne/eq ... 0/1
+		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;
+
+	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:
+		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(-value);
+			return REPEAT_CSE;
+		}
+	/* Fall through */
+	case OP_ADD:
+	case_neutral_zero:
+		if (!value)
+			return replace_with_pseudo(insn, insn->src1);
+		return 0;
+	case OP_ASR:
+	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(0));
+		return 0;
+
+	case OP_DIVU: case OP_DIVS:
+	case OP_MUL:
+		return simplify_mul_div(insn, value);
+
+	case OP_AND:
+		if (!value)
+			return replace_with_pseudo(insn, insn->src2);
+		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:
+		return simplify_seteq_setne(insn, value);
+	}
+	return 0;
+}
+
+static int simplify_constant_leftside(struct instruction *insn)
+{
+	long long value = insn->src1->value;
+
+	switch (insn->opcode) {
+	case OP_ADD: case OP_OR: case OP_XOR:
+		if (!value)
+			return replace_with_pseudo(insn, insn->src2);
+		return 0;
+
+	case OP_SHL:
+	case OP_LSR: case OP_ASR:
+	case OP_AND:
+	case OP_MUL:
+		if (!value)
+			return replace_with_pseudo(insn, insn->src1);
+		return 0;
+	}
+	return 0;
+}
+
+static int simplify_constant_binop(struct instruction *insn)
+{
+	pseudo_t res = eval_insn(insn);
+
+	if (!res)
+		return 0;
+
+	replace_with_pseudo(insn, res);
 	return REPEAT_CSE;
 }
 
@@ -700,26 +1172,19 @@
 			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:
 	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,13 +1230,23 @@
 	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)
@@ -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,13 +1288,22 @@
 	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;
 	}
 	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;
-
-	/* 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;
-
-	orig_size = orig_type->bit_size;
-	size = insn->size;
 	src = insn->src;
 
 	/* 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;
-	}
+	if (constant(src))
+		return simplify_constant_unop(insn);
+
+	// can merge with the previous instruction?
+	size = insn->size;
+	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;
+
+			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);
 		}
-	}
-
-	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;
+		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;
 	}
 
 	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:
+		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:
-		return simplify_cast(insn);
+		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;
 }
--- a/usr/src/tools/smatch/src/smatch.h	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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,15 +404,18 @@
 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);
 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,13 +1239,14 @@
 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 */
 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);
--- a/usr/src/tools/smatch/src/smatch_array_values.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_array_values.c	Thu Nov 21 12:33:13 2019 +0000
@@ -188,10 +188,37 @@
 	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;
 
 	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));
 }
--- a/usr/src/tools/smatch/src/smatch_assigned_expr.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_assigned_expr.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
--- a/usr/src/tools/smatch/src/smatch_auto_copy.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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);
-}
--- a/usr/src/tools/smatch/src/smatch_bits.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_bits.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
--- a/usr/src/tools/smatch/src/smatch_buf_size.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_buf_size.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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);
--- a/usr/src/tools/smatch/src/smatch_common_functions.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_common_functions.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
 }
--- a/usr/src/tools/smatch/src/smatch_comparison.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_comparison.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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,8 +287,13 @@
 {
 	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;
-
-	orig = remove_unsigned_from_comparison(orig);
-	op = remove_unsigned_from_comparison(op);
-
-	switch (orig) {
-	case 0:
-		return op;
+	int LT, GT, EQ, NE, total;
+
+	if (left_compare == IMPOSSIBLE_COMPARISON ||
+	    right_compare == IMPOSSIBLE_COMPARISON)
+		return IMPOSSIBLE_COMPARISON;
+
+	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 '>':
+		GT++;
+		total += 1;
+		break;
+	default:
+		return UNKNOWN_COMPARISON;
+	}
+
+	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 '>':
-		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;
+	}
+
+	if (LT == 2) {
+		if (EQ == 2)
+			return SPECIAL_LTE;
+		return '<';
+	}
+
+	if (GT == 2) {
+		if (EQ == 2)
+			return SPECIAL_GTE;
+		return '>';
 	}
-	return 0;
+	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;
-
-	set_state(compare_id, sm->name, NULL,
+	new = comparison_intersection(extra, data->comparison);
+	if (new == data->comparison)
+		return;
+
+	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,7 +730,14 @@
 	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:
@@ -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;
-
-	if (!a || !b)
-		return 0;
+	int ret = UNKNOWN_COMPARISON;
+	int extra = UNKNOWN_COMPARISON;
+
+	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;
+
+	/*
+	 * 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 (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 (data->comparison &&
-	    data->comparison == filter_comparison(data->comparison, op))
-		istrue = 1;
-
-	if (data->comparison &&
-	    data->comparison == filter_comparison(data->comparison, negate_comparison(op)))
-		isfalse = 1;
-
-	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;
--- a/usr/src/tools/smatch/src/smatch_conditions.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_conditions.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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);
--- a/usr/src/tools/smatch/src/smatch_data/db/clear_user_data.sh	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_data/db/clear_user_data.sh	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/smatch_data/db/copy_function_pointers.pl	Thu Nov 21 12:33:13 2019 +0000
@@ -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();
--- a/usr/src/tools/smatch/src/smatch_data/db/create_db.sh	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_data/db/create_db.sh	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/smatch_data/db/fill_db_sql.pl	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_data/db/fill_db_sql.pl	Thu Nov 21 12:33:13 2019 +0000
@@ -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);
 }
--- a/usr/src/tools/smatch/src/smatch_data/db/fixup_kernel.sh	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_data/db/fixup_kernel.sh	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/smatch_data/db/kernel.return_fixes	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_data/db/kernel.return_fixes	Thu Nov 21 12:33:13 2019 +0000
@@ -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]
--- a/usr/src/tools/smatch/src/smatch_data/db/smdb.py	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_data/db/smdb.py	Thu Nov 21 12:33:13 2019 +0000
@@ -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()
--- a/usr/src/tools/smatch/src/smatch_data/db/vim_smdb	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_data/db/vim_smdb	Thu Nov 21 12:33:13 2019 +0000
@@ -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
 
--- a/usr/src/tools/smatch/src/smatch_data/kernel.bit_shifters.remove	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_data/kernel.bit_shifters.remove	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/smatch_data/kernel.check_string_condition.ignore	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_data/kernel.check_string_condition.ignore	Thu Nov 21 12:33:13 2019 +0000
@@ -1,1 +1,2 @@
 TRACE_EVENT
+WARN_ON_ONCE
--- a/usr/src/tools/smatch/src/smatch_data/kernel.ignore_casted_params	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_data/kernel.ignore_casted_params	Thu Nov 21 12:33:13 2019 +0000
@@ -2,6 +2,7 @@
 clear_bit
 __clear_bit
 __set_bit
+test_bit
 test_and_set_bit
 find_last_bit
 change_bit
--- a/usr/src/tools/smatch/src/smatch_data/kernel.ignore_side_effects	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_data/kernel.ignore_side_effects	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/smatch_data/kernel.ignore_uninitialized_param	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_data/kernel.ignore_uninitialized_param	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/smatch_data/kernel.unreachable.ignore	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_data/kernel.unreachable.ignore	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/smatch_db.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_db.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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,25 +2338,38 @@
 	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;
 	}
 	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,14 +2563,14 @@
 
 	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 "->" */
 	    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;
 }
--- a/usr/src/tools/smatch/src/smatch_estate.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_estate.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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)
--- a/usr/src/tools/smatch/src/smatch_expressions.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_expressions.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
--- a/usr/src/tools/smatch/src/smatch_extra.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_extra.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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++;
-			continue;
-		case 2: /* expression */
-			state = 0;
-			type = get_type(strip_expr(expr));
-			set_extra_expr_mod(expr, alloc_estate_whole(type));
+		if (expr->type != EXPR_ASM_OPERAND) {
+			sm_perror("unexpected asm param type %d", expr->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);
--- a/usr/src/tools/smatch/src/smatch_extra.h	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_extra.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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);
--- a/usr/src/tools/smatch/src/smatch_flow.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_flow.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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(expr->fn);
 		split_expr_list(expr->args, expr);
-		__split_expr(expr->fn);
 		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)
--- a/usr/src/tools/smatch/src/smatch_function_hooks.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_function_hooks.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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);
 }
--- a/usr/src/tools/smatch/src/smatch_function_ptrs.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_function_ptrs.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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) ||
--- a/usr/src/tools/smatch/src/smatch_helper.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_helper.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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)
--- a/usr/src/tools/smatch/src/smatch_hooks.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_hooks.c	Thu Nov 21 12:33:13 2019 +0000
@@ -18,6 +18,7 @@
 #include "smatch.h"
 
 enum data_type {
+	NO_DATA,
 	EXPR_PTR,
 	STMT_PTR,
 	SYMBOL_PTR,
@@ -26,15 +27,61 @@
 
 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;
@@ -51,123 +98,14 @@
 
 	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);
 }
 
 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,53 +113,42 @@
 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)
 {
 	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);
 }
--- a/usr/src/tools/smatch/src/smatch_implied.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_implied.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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,14 +456,15 @@
 	struct sm_state *left;
 	struct sm_state *right;
 	int removed = 0;
-	struct timeval now;
+	struct timeval now, diff;
 
 	if (!sm)
 		return NULL;
 	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);
--- a/usr/src/tools/smatch/src/smatch_integer_overflow.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_integer_overflow.c	Thu Nov 21 12:33:13 2019 +0000
@@ -184,7 +184,7 @@
 	struct smatch_state *state;
 	char *name;
 	struct symbol *sym;
-	int ret;
+	int ret = 1;
 
 	type = get_type(expr);
 	if (!type)
--- a/usr/src/tools/smatch/src/smatch_kernel_user_data.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_kernel_user_data.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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);
 }
+
--- a/usr/src/tools/smatch/src/smatch_local_values.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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;");
-}
--- a/usr/src/tools/smatch/src/smatch_math.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_math.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
--- a/usr/src/tools/smatch/src/smatch_mem_tracker.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_mem_tracker.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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,6 +47,24 @@
 
 	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)
 {
--- a/usr/src/tools/smatch/src/smatch_modification_hooks.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_modification_hooks.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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);
--- a/usr/src/tools/smatch/src/smatch_mtag.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_mtag.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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 == '*') {
--- a/usr/src/tools/smatch/src/smatch_mtag_data.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_mtag_data.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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,13 +260,15 @@
 	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)
 		return 0;
 
 	type = get_type(expr);
-	if (!type)
+	if (invalid_type(type))
 		return 0;
 
 	return get_rl_from_mtag_offset(tag, offset, type, rl);
--- a/usr/src/tools/smatch/src/smatch_nul_terminator.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_nul_terminator.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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)
--- a/usr/src/tools/smatch/src/smatch_param_filter.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_param_filter.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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)
--- a/usr/src/tools/smatch/src/smatch_param_limit.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_param_limit.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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,14 +116,13 @@
 	 * 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);
--- a/usr/src/tools/smatch/src/smatch_param_set.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_param_set.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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,6 +216,18 @@
 			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) {
@@ -215,27 +247,65 @@
 		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);
 
 	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;
+
+	if (!name)
+		return 0;
 
-	FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
-		if (sm->sym != sym)
+	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;
 }
--- a/usr/src/tools/smatch/src/smatch_param_to_mtag_data.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_param_to_mtag_data.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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)
--- a/usr/src/tools/smatch/src/smatch_param_used.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_param_used.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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);
 }
--- a/usr/src/tools/smatch/src/smatch_parse_call_math.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_parse_call_math.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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)
-{
-	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)
+const char *get_allocation_math(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);
 }
 
--- a/usr/src/tools/smatch/src/smatch_ranges.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_ranges.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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) {
--- a/usr/src/tools/smatch/src/smatch_real_absolute.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_real_absolute.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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);
 }
--- a/usr/src/tools/smatch/src/smatch_returns.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_returns.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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)
--- a/usr/src/tools/smatch/src/smatch_scripts/build_generic_data.sh	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_scripts/build_generic_data.sh	Thu Nov 21 12:33:13 2019 +0000
@@ -52,7 +52,14 @@
     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
 
--- a/usr/src/tools/smatch/src/smatch_scripts/gen_dma_funcs.sh	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_scripts/gen_dma_funcs.sh	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/smatch_scripts/gen_rosenberg_funcs.sh	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_scripts/gen_rosenberg_funcs.sh	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/smatch_scripts/kchecker	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_scripts/kchecker	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/smatch_scripts/summarize_errs.sh	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_scripts/summarize_errs.sh	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/smatch_scripts/test_generic.sh	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_scripts/test_generic.sh	Thu Nov 21 12:33:13 2019 +0000
@@ -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
 
--- a/usr/src/tools/smatch/src/smatch_scripts/test_kernel.sh	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_scripts/test_kernel.sh	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/smatch_slist.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_slist.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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)
--- a/usr/src/tools/smatch/src/smatch_states.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_states.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
 }
 
--- a/usr/src/tools/smatch/src/smatch_struct_assignment.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_struct_assignment.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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);
--- a/usr/src/tools/smatch/src/smatch_type.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_type.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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)
--- a/usr/src/tools/smatch/src/smatch_type_val.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_type_val.c	Thu Nov 21 12:33:13 2019 +0000
@@ -227,13 +227,46 @@
 	return 1;
 }
 
+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)
+	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);
--- a/usr/src/tools/smatch/src/smatch_untracked_param.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/smatch_untracked_param.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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)
--- a/usr/src/tools/smatch/src/sort.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/sort.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/sparse-llvm-dis	Thu Nov 21 12:33:13 2019 +0000
@@ -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 '
--- a/usr/src/tools/smatch/src/sparse-llvm.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/sparse-llvm.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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,39 +172,42 @@
 	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;
 
 	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,30 +218,25 @@
 	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();
 		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,31 +255,118 @@
 
 #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_PHI:
+		snprintf(buf, MAX_PSEUDO_NAME, "PHI%d.", pseudo->nr);
 		break;
 	case PSEUDO_SYM:
-		assert(0);
-		break;
 	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;
+
+	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;
+
+			data = LLVMAddGlobal(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;
+		}
+	}
+
+	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);
+	}
+
+	return result;
+}
+
+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;
 
@@ -316,56 +374,11 @@
 	case PSEUDO_REG:
 		result = pseudo->priv;
 		break;
-	case PSEUDO_SYM: {
-		struct symbol *sym = pseudo->sym;
-		struct expression *expr;
-
-		assert(sym->bb_target == NULL);
-
-		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(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));
-				break;
-			}
-			case EXPR_SYMBOL: {
-				struct symbol *sym = expr->symbol;
-
-				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);
-
-			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);
-			}
-		}
+	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,36 +400,114 @@
 	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);
 	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;
 }
 
 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);
-
-	rhs = pseudo_to_value(fn, insn, insn->src2);
+	lhs = get_ioperand(fn, insn->type, insn->src1);
+	rhs = get_ioperand(fn, insn->type, 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,25 +621,47 @@
 	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,33 +705,33 @@
 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;
 }
 
 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,39 +862,124 @@
 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;
 }
 
 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);
+	}
+
+	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));
 
-	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);
+	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;
 }
 
@@ -822,7 +999,10 @@
 		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);
@@ -839,37 +1019,42 @@
 	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;
 	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;
-
-	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);
+	int i;
 
-	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;
 
+		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) {
-		if (bb->generation == generation)
-			continue;
-
+		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,7 +1206,10 @@
 	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,15 +1226,20 @@
 			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);
 
@@ -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);
 
--- a/usr/src/tools/smatch/src/sparse.1	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/sparse.1	Thu Nov 21 12:33:13 2019 +0000
@@ -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,12 +37,20 @@
 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.
--- a/usr/src/tools/smatch/src/sparse.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/sparse.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
--- a/usr/src/tools/smatch/src/sparse.pc.in	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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}
--- a/usr/src/tools/smatch/src/sparsec	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/sparsec	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/sparsei	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/sparsei	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/ssa.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/ssa.h	Thu Nov 21 12:33:13 2019 +0000
@@ -0,0 +1,8 @@
+#ifndef SSA_H
+#define SSA_H
+
+struct entrypoint;
+
+void ssa_convert(struct entrypoint *ep);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/sset.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/sset.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/symbol.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/symbol.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
+	}
 }
--- a/usr/src/tools/smatch/src/symbol.h	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/symbol.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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,55 +203,56 @@
 };
 
 /* 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_TLS		0x20000
-#define MOD_INLINE	0x40000
-#define MOD_ADDRESSABLE	0x80000
+#define MOD_SIGNED		0x00002000
+#define MOD_UNSIGNED		0x00004000
+#define MOD_EXPLICITLY_SIGNED	0x00008000
 
-#define MOD_NOCAST	0x100000
-#define MOD_NODEREF	0x200000
-#define MOD_ACCESSED	0x400000
-#define MOD_TOPLEVEL	0x800000	// scoping..
+#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_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_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_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)
 #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,6 +274,17 @@
 			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,21 +320,33 @@
 
 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);
 
 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 */
--- a/usr/src/tools/smatch/src/target.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/target.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+}
--- a/usr/src/tools/smatch/src/target.h	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/target.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
 
 /*
--- a/usr/src/tools/smatch/src/test-dissect.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/test-dissect.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
 }
--- a/usr/src/tools/smatch/src/test-inspect.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/test-inspect.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
 }
--- a/usr/src/tools/smatch/src/test-lexing.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/test-lexing.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
 }
--- a/usr/src/tools/smatch/src/test-linearize.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/test-linearize.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
--- a/usr/src/tools/smatch/src/test-parsing.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/test-parsing.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/test-unssa.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/test-unssa.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
--- a/usr/src/tools/smatch/src/token.h	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/token.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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)
 {
--- a/usr/src/tools/smatch/src/tokenize.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/tokenize.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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,32 +493,20 @@
 	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,
 	['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),
--- a/usr/src/tools/smatch/src/unssa.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/unssa.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/utils.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/utils.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/Waddress-array.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/Waddress-function.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/Waddress-space-all-attr.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/Waddress-space-from.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/Waddress-space-strict.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/Waddress-weak.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/Waddress.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/Wcast-to-as.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/Wexternal-function-has-definition.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/Wunknown-attribute-def.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/Wunknown-attribute-def.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
  */
--- a/usr/src/tools/smatch/src/validation/Wunknown-attribute-yes.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/Wunknown-attribute-yes.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/abi-integer.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/address_space.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/address_space.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
  */
--- a/usr/src/tools/smatch/src/validation/alias-distinct.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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
- */
--- a/usr/src/tools/smatch/src/validation/alias-mixed.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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
- */
--- a/usr/src/tools/smatch/src/validation/alias-same.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/array-implicit-size.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/as-name.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/asm-inline.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/asm-toplevel.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/attr-context.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/backend/arithmetic-ops.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/arithmetic-ops.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/call-variadic.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/backend/cast.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/cast.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/compare-with-null.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/constant-pointer.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/degenerate-ptr.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/fn-ref.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/function-ptr-xtype.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/backend/function-ptr.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/function-ptr.c	Thu Nov 21 12:33:13 2019 +0000
@@ -1,8 +1,150 @@
-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);
+
+// 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)))
+{
+	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);
 
-static int run(fn_t fn, int x, int y)
+	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)
 {
-	return fn(x, y);
+	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);
 }
 
 /*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/label-as-value.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/load-global.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/pointer-add.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/pointer-cmp.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/pointer-param.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/pointer-sub.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/setval.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/shift-special.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/store-x2.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/string-value.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/backend/sum.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/sum.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/switch.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/symaddr.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/backend/type-constant.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/bad-return-type.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/bad-type-twice0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/bad-type-twice1.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/bad-type-twice2.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/bitfield-bool-layout.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/bitfield-kr.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/bitfield-size.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/bitwise-cast-ptr.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/bitwise-cast.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/bitwise-cast.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/validation/bool-cast-explicit.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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\\.
- */
--- a/usr/src/tools/smatch/src/validation/bool-cast-implicit.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/bool-float.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/bug-bad-type.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/bug-crash16.c	Thu Nov 21 12:33:13 2019 +0000
@@ -0,0 +1,11 @@
+static void foo(void)
+{
+	int b[] = { 8 };
+	int c;
+	for (;;)
+		b[c] = b[0];
+}
+
+/*
+ * check-name: bug-crash16
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/bug-expand-union0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/bug-expand-union1.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/bug-rshift-ub.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/builtin-arith.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/builtin-bswap-variable.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/builtin-bswap-variable.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/builtin-fp-unop.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/builtin-overflow.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/builtin-prototype.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/c11-alignas.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/c11-alignas.c	Thu Nov 21 12:33:13 2019 +0000
@@ -36,5 +36,5 @@
  * check-error-end
  *
  * check-output-ignore
- * check-output-contains: ret\\.32 *\$0
+ * check-output-contains: ret\\.32 *\\$0
  */
--- a/usr/src/tools/smatch/src/validation/c11-alignof.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/c11-alignof.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/c11-atomic.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/c11-noreturn.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/c11-noreturn.c	Thu Nov 21 12:33:13 2019 +0000
@@ -5,5 +5,5 @@
  * check-command: test-parsing -std=c11 $file
  *
  * check-output-ignore
- * check-output-contains: \[noreturn\]
+ * check-output-contains: \\[noreturn\\]
  */
--- a/usr/src/tools/smatch/src/validation/c11-thread-local.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/c11-thread-local.c	Thu Nov 21 12:33:13 2019 +0000
@@ -5,5 +5,5 @@
  * check-command: test-parsing -std=c11 $file
  *
  * check-output-ignore
- * check-output-contains: \[tls\]
+ * check-output-contains: \\[tls\\]
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/call-inlined.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/call-variadic.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/cast-bad-00.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/cast-bad-01.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/cast-constant-to-float.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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
- */
--- a/usr/src/tools/smatch/src/validation/cast-constants.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/cast-kinds-check.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/cast-kinds.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,387 +0,0 @@
-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; }
-
-/*
- * check-name: cast-kinds
- * check-command: test-linearize -m64 $file
- *
- * check-output-start
-uint_2_int:
-.L0:
-	<entry-point>
-	ret.32      %arg1
-
-
-long_2_int:
-.L2:
-	<entry-point>
-	scast.32    %r5 <- (64) %arg1
-	ret.32      %r5
-
-
-ulong_2_int:
-.L4:
-	<entry-point>
-	cast.32     %r8 <- (64) %arg1
-	ret.32      %r8
-
-
-vptr_2_int:
-.L6:
-	<entry-point>
-	cast.32     %r11 <- (64) %arg1
-	ret.32      %r11
-
-
-iptr_2_int:
-.L8:
-	<entry-point>
-	cast.32     %r14 <- (64) %arg1
-	ret.32      %r14
-
-
-float_2_int:
-.L10:
-	<entry-point>
-	ret.32      %arg1
-
-
-double_2_int:
-.L12:
-	<entry-point>
-	cast.32     %r20 <- (64) %arg1
-	ret.32      %r20
-
-
-int_2_uint:
-.L14:
-	<entry-point>
-	ret.32      %arg1
-
-
-long_2_uint:
-.L16:
-	<entry-point>
-	scast.32    %r26 <- (64) %arg1
-	ret.32      %r26
-
-
-ulong_2_uint:
-.L18:
-	<entry-point>
-	cast.32     %r29 <- (64) %arg1
-	ret.32      %r29
-
-
-vptr_2_uint:
-.L20:
-	<entry-point>
-	cast.32     %r32 <- (64) %arg1
-	ret.32      %r32
-
-
-iptr_2_uint:
-.L22:
-	<entry-point>
-	cast.32     %r35 <- (64) %arg1
-	ret.32      %r35
-
-
-float_2_uint:
-.L24:
-	<entry-point>
-	ret.32      %arg1
-
-
-double_2_uint:
-.L26:
-	<entry-point>
-	cast.32     %r41 <- (64) %arg1
-	ret.32      %r41
-
-
-int_2_long:
-.L28:
-	<entry-point>
-	scast.64    %r44 <- (32) %arg1
-	ret.64      %r44
-
-
-uint_2_long:
-.L30:
-	<entry-point>
-	cast.64     %r47 <- (32) %arg1
-	ret.64      %r47
-
-
-ulong_2_long:
-.L32:
-	<entry-point>
-	ret.64      %arg1
-
-
-vptr_2_long:
-.L34:
-	<entry-point>
-	cast.64     %r53 <- (64) %arg1
-	ret.64      %r53
-
-
-iptr_2_long:
-.L36:
-	<entry-point>
-	cast.64     %r56 <- (64) %arg1
-	ret.64      %r56
-
-
-float_2_long:
-.L38:
-	<entry-point>
-	cast.64     %r59 <- (32) %arg1
-	ret.64      %r59
-
-
-double_2_long:
-.L40:
-	<entry-point>
-	ret.64      %arg1
-
-
-int_2_ulong:
-.L42:
-	<entry-point>
-	scast.64    %r65 <- (32) %arg1
-	ret.64      %r65
-
-
-uint_2_ulong:
-.L44:
-	<entry-point>
-	cast.64     %r68 <- (32) %arg1
-	ret.64      %r68
-
-
-long_2_ulong:
-.L46:
-	<entry-point>
-	ret.64      %arg1
-
-
-vptr_2_ulong:
-.L48:
-	<entry-point>
-	cast.64     %r74 <- (64) %arg1
-	ret.64      %r74
-
-
-iptr_2_ulong:
-.L50:
-	<entry-point>
-	cast.64     %r77 <- (64) %arg1
-	ret.64      %r77
-
-
-float_2_ulong:
-.L52:
-	<entry-point>
-	cast.64     %r80 <- (32) %arg1
-	ret.64      %r80
-
-
-double_2_ulong:
-.L54:
-	<entry-point>
-	ret.64      %arg1
-
-
-int_2_vptr:
-.L56:
-	<entry-point>
-	scast.64    %r86 <- (32) %arg1
-	ret.64      %r86
-
-
-uint_2_vptr:
-.L58:
-	<entry-point>
-	cast.64     %r89 <- (32) %arg1
-	ret.64      %r89
-
-
-long_2_vptr:
-.L60:
-	<entry-point>
-	scast.64    %r92 <- (64) %arg1
-	ret.64      %r92
-
-
-ulong_2_vptr:
-.L62:
-	<entry-point>
-	cast.64     %r95 <- (64) %arg1
-	ret.64      %r95
-
-
-iptr_2_vptr:
-.L64:
-	<entry-point>
-	cast.64     %r98 <- (64) %arg1
-	ret.64      %r98
-
-
-int_2_iptr:
-.L66:
-	<entry-point>
-	ptrcast.64  %r101 <- (32) %arg1
-	ret.64      %r101
-
-
-uint_2_iptr:
-.L68:
-	<entry-point>
-	ptrcast.64  %r104 <- (32) %arg1
-	ret.64      %r104
-
-
-long_2_iptr:
-.L70:
-	<entry-point>
-	ptrcast.64  %r107 <- (64) %arg1
-	ret.64      %r107
-
-
-ulong_2_iptr:
-.L72:
-	<entry-point>
-	ptrcast.64  %r110 <- (64) %arg1
-	ret.64      %r110
-
-
-vptr_2_iptr:
-.L74:
-	<entry-point>
-	ptrcast.64  %r113 <- (64) %arg1
-	ret.64      %r113
-
-
-int_2_float:
-.L76:
-	<entry-point>
-	fpcast.32   %r116 <- (32) %arg1
-	ret.32      %r116
-
-
-uint_2_float:
-.L78:
-	<entry-point>
-	fpcast.32   %r119 <- (32) %arg1
-	ret.32      %r119
-
-
-long_2_float:
-.L80:
-	<entry-point>
-	fpcast.32   %r122 <- (64) %arg1
-	ret.32      %r122
-
-
-ulong_2_float:
-.L82:
-	<entry-point>
-	fpcast.32   %r125 <- (64) %arg1
-	ret.32      %r125
-
-
-double_2_float:
-.L84:
-	<entry-point>
-	fpcast.32   %r128 <- (64) %arg1
-	ret.32      %r128
-
-
-int_2_double:
-.L86:
-	<entry-point>
-	fpcast.64   %r131 <- (32) %arg1
-	ret.64      %r131
-
-
-uint_2_double:
-.L88:
-	<entry-point>
-	fpcast.64   %r134 <- (32) %arg1
-	ret.64      %r134
-
-
-long_2_double:
-.L90:
-	<entry-point>
-	fpcast.64   %r137 <- (64) %arg1
-	ret.64      %r137
-
-
-ulong_2_double:
-.L92:
-	<entry-point>
-	fpcast.64   %r140 <- (64) %arg1
-	ret.64      %r140
-
-
-float_2_double:
-.L94:
-	<entry-point>
-	fpcast.64   %r143 <- (32) %arg1
-	ret.64      %r143
-
-
- * check-output-end
- */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/cast-weirds.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/char-signed.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/char-unsigned.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/check_access-multi.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/check_access-store.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/check_byte_count-ice.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/check_byte_count-ice.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
  */
--- a/usr/src/tools/smatch/src/validation/choose_expr.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/choose_expr.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
  */
--- a/usr/src/tools/smatch/src/validation/compound-assign-type.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/compound-assign-type.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/compound-sizes.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/cond-address-array.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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
- */
--- a/usr/src/tools/smatch/src/validation/cond-address-function.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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
- */
--- a/usr/src/tools/smatch/src/validation/cond-address.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/cond-address.c	Thu Nov 21 12:33:13 2019 +0000
@@ -10,5 +10,5 @@
  * check-command: test-linearize -Wno-decl $file
  * check-output-ignore
  *
- * check-excludes: VOID
+ * check-output-excludes: VOID
  */
--- a/usr/src/tools/smatch/src/validation/cond-err-expand.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/cond-err-expand.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
  */
--- a/usr/src/tools/smatch/src/validation/conditional-type.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/conditional-type.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
  */
--- a/usr/src/tools/smatch/src/validation/constant-suffix-64.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/constant-suffix-64.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/validation/constexpr-addr-of-static-member.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/constexpr-addr-of-static-member.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/validation/constexpr-addr-of-static.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/constexpr-addr-of-static.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/validation/constexpr-binop.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/constexpr-binop.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/validation/constexpr-cast.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/constexpr-cast.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/validation/constexpr-compound-literal.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/constexpr-compound-literal.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/validation/constexpr-conditional.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/constexpr-conditional.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/validation/constexpr-init.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/constexpr-init.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/validation/constexpr-labelref.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/constexpr-labelref.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/validation/constexpr-offsetof.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/constexpr-offsetof.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/validation/constexpr-pointer-arith.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/constexpr-pointer-arith.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/validation/constexpr-pointer-cast.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/constexpr-pointer-cast.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/validation/constexpr-preop.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/constexpr-preop.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/constexpr-shift.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/constexpr-string.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/constexpr-string.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/validation/constexpr-types-compatible-p.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/constexpr-types-compatible-p.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/context-stmt.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/crash-select.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/doc/cdoc.cdoc	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/empty-expr.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/enum+mode.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/enum-base-type.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/enum-bitwise-bad.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/enum-bitwise-mixed.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/enum-bitwise.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/enum-bounds.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/enum-init-constness.c	Thu Nov 21 12:33:13 2019 +0000
@@ -0,0 +1,9 @@
+extern int invalid;
+
+enum e {
+	E = 1 ? 1 : invalid
+};
+
+/*
+ * check-name: enum-init-constness
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/enum-invalid.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/enum-min-size.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/enum-mismatch.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/enum-mismatch.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/enum-same-type.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/enum-sign-gcc.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/enum-typecheck.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/error-at-eof.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/eval-typeof-vla.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/expand/bad-shift.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/expand/builtin-expect.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/expand/builtin_fpclassify.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/expand/builtin_huge_val.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/expand/builtin_isinf.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/expand/builtin_isnan.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/expand/builtin_isnormal.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/expand/builtin_nan.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/expand/function-pointer.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/external-function-has-definition.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/fdiag-prefix.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/fp-ops.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/fp-vs-ptrcast.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/function-pointer-type.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/function-redecl2.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/goto-reserved.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/implicit-KR-arg-type1.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/inc-dec-float.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/incomplete-struct.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/infinite-loop01.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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:
+ */
--- a/usr/src/tools/smatch/src/validation/infinite-loop02.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/infinite-loop02.c	Thu Nov 21 12:33:13 2019 +0000
@@ -8,4 +8,5 @@
 /*
  * check-name: infinite loop 02
  * check-command: sparse -Wno-decl $file
+ * check-timeout:
  */
--- a/usr/src/tools/smatch/src/validation/infinite-loop03.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/infinite-loop03.c	Thu Nov 21 12:33:13 2019 +0000
@@ -13,4 +13,5 @@
 /*
  * check-name: infinite loop 03
  * check-command: sparse -Wno-decl $file
+ * check-timeout:
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/infinite-loop04.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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:
+ */
--- a/usr/src/tools/smatch/src/validation/int128.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/int128.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/integer-const-expr.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/kill-casts.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-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\\.
- */
--- a/usr/src/tools/smatch/src/validation/kill-load.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/kill-load.c	Thu Nov 21 12:33:13 2019 +0000
@@ -13,5 +13,5 @@
  *	- bb unreachable.
  *
  * check-output-ignore
- * check-output-pattern-1-times: load\\.
+ * check-output-pattern(1): load\\.
  */
--- a/usr/src/tools/smatch/src/validation/kill-phi-ttsbb.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/kill-phi-ttsbb.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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;
 
--- a/usr/src/tools/smatch/src/validation/kill-store.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/kill-store.c	Thu Nov 21 12:33:13 2019 +0000
@@ -12,5 +12,5 @@
  *	- bb unreachable.
  *
  * check-output-ignore
- * check-output-pattern-1-times: store\\.
+ * check-output-pattern(1): store\\.
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/kill-switch.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/label-redefined.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/asm-toplevel.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/bitfield-expand-deref.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/bitfield-inc.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/linear/bitfield-init-mask.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/bitfield-init-mask.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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\$
--- a/usr/src/tools/smatch/src/validation/linear/bitfield-init-zero.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/bitfield-preinc.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/bitfield-size.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/bitfield-store.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/bool-cast-lp32.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/bool-cast-lp64.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/bool-cast.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/builtin_unreachable.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/call-basic.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/call-builtin.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/call-casted-pointer.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/call-complex-pointer.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/call-direct.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/call-indirect.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/call-inline.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/cast-constant-to-float.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/cast-constants.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/cast-volatile.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/compound-literal00.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/compound-literal01.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/compound-literal02.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/degen-array.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/degen-function.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/degen-log-not.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/deref-ptr-ptr.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/fp-vs-ptrcast.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/fp2i-cast.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/logical-phi0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/logical.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/missing-return0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/missing-return1.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/missing-return2.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/missing-return3.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/missing-return4.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/missing-return5.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/non-const-case.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/phi-order01.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/phi-order02.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/phi-order03.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/phi-order04.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/range-op.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/unexamined-base-type.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/linear/unreachable-label0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/loop-linearization.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/address-used00.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/alias-distinct.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/alias-mixed.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/alias-same.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/broken-phi02.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/broken-phi03.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/cond-expr.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/cond-expr5.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/dead-phisrc.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/global-direct-undef.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/global-direct.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/global-loop.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/global-noalias.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/global-pointer.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/if-direct.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/if-pointer.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/init-global-array.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/init-local-array.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/init-local-union0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/init-local-union1.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/init-local32.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/init-local64.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/load-dead.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/load-deadborn.c	Thu Nov 21 12:33:13 2019 +0000
@@ -0,0 +1,9 @@
+static void foo(int a)
+{
+	return;
+	a;
+}
+
+/*
+ * check-name: load-deadborn
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/loop00.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/loop01-global.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/loop02-array.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/loop02-global.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/loop02-local.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/loop02-pointer.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/missing-return.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/quadra00.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/quadra01.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/quadra02.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/reload-aliasing.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/short-load.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/store-deadborn.c	Thu Nov 21 12:33:13 2019 +0000
@@ -0,0 +1,9 @@
+static void foo(int a)
+{
+	return;
+	a = 0;
+}
+
+/*
+ * check-name: store-deadborn
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/stray-phisrc.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/struct.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/undef00.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/undef01.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/unused-var.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/mem2reg/volatile-store00.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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\\.
+ */
--- a/usr/src/tools/smatch/src/validation/memops-volatile.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/memops-volatile.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/missing-return.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/multi-input.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/nested-declarator.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/nested-declarator.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
  */
--- a/usr/src/tools/smatch/src/validation/nested-declarator2.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/nested-declarator2.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
  */
--- a/usr/src/tools/smatch/src/validation/nocast.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/nocast.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
--- a/usr/src/tools/smatch/src/validation/noderef.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/noderef.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/address-used01.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-extend.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-extendx.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-lsr.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-bf0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-bf1.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-bf2.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-bfs.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-bfu.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-bfx.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-constant0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-constant1.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-constant2.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-crash.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-lsr0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-lsr1.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-lsr2.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-lsrx.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-mask.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-mask0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-mask1.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-mask2.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-mask3s.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-mask3u.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-mask4.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-maskx.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-shl0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-shl1.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-shl2.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-shlx.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-trunc0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-trunc1.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-trunc2.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-or-truncx.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/and-trunc.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/bitfield-init-zero.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/bitfield-size.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/bitfield-store-load0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/bitfield-store-loads.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/bitfield-store-loadu.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/bits-not-zero.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/bool-context-fp.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/optim/bool-context.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/bool-context.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/bool-eq0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/bool-int-bool.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/bool-ne0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/bool-neq0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/bool-sext-test.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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\\.
+ */
--- a/usr/src/tools/smatch/src/validation/optim/bool-simplify.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/bool-simplify.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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:
@@ -51,5 +60,18 @@
 	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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/bool-simplify2.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/bool-zext-test.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/call-complex-pointer.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/call-inlined.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/canonical-add.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/canonical-cmp.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/canonical-fcmp.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/canonical-mul.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/cast-kinds.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/cast-nop.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/cse-cmp-next.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/cse-fcmp.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/cse-setfval.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/cse-size.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/dup-cond0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/ext-trunc-greater.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/ext-trunc-same.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/ext-trunc-smaller.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/fpcast-constant.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/inline-return.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/kill-casts.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/kill-stores0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/kill-stores1.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/kill-stores2.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/killed-insn.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/live-stores0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/load-converted.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/load-dead.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/load-semi-volatile.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/lsr-and0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/lsr-and1.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/lsr-asr.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/lsr-shl0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/mask-lsr.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/mask-out.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/mask1-setne0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/missing-select.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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\\.
+ */
--- a/usr/src/tools/smatch/src/validation/optim/muldiv-minus-one.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/muldiv-minus-one.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/null-phi.c	Thu Nov 21 12:33:13 2019 +0000
@@ -0,0 +1,9 @@
+static int foo(void)
+{
+	if (0)
+		return 0;
+}
+
+/*
+ * check-name: null-phi
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/or-and-constant1.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/phi-ret.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/restrict.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/select-zero.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/setcc-mask.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/setne0-sext.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/setne0-trunc.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/setne0-zext.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/sext-sext.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/sext.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/sh-or-and0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/sh-or-and1.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/sh-or-and2.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/shift-big.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/shift-shift.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/shift-zext.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/shl-and0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/shl-and1.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/shl-lsr0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/store-dominated.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/trivial-phis.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/trunc-mask-zext.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/trunc-or-shl.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/trunc-seteq0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/trunc-setne0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/trunc-trunc.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/volatile-bitfield.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/volatile-side-effect.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/volatile-store00.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/zext-and.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/zext-and1.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/zext-asr.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/zext-sext.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/optim/zext-zext.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/option-parsing-00.c	Thu Nov 21 12:33:13 2019 +0000
@@ -0,0 +1,5 @@
+
+/*
+ * check-name: option parsing 00
+ * check-command: sparse -foptimize-xyz $file
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/option-parsing-01.c	Thu Nov 21 12:33:13 2019 +0000
@@ -0,0 +1,5 @@
+
+/*
+ * check-name: option parsing 01
+ * check-command: sparse -fno-optimize-xyz $file
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/overflow.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/phase2/backslash	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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 */
-\
--- a/usr/src/tools/smatch/src/validation/phase3/comments	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-/*
- *  Each comment should be treated as if it had been a single space.
- */
-
-/* This should give nothing */
-/* XXX: currently sparse produces Y */
-/* Fixed */
-#define X /*
- */ Y
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/base-file.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/base-file.h	Thu Nov 21 12:33:13 2019 +0000
@@ -0,0 +1,2 @@
+__FILE__
+__BASE_FILE__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/builtin.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/cli-D-arg.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/cli-D-space.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/preprocessor/dump-macros-empty.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/dump-macros-empty.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
  */
--- a/usr/src/tools/smatch/src/validation/preprocessor/dump-macros-multi.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/dump-macros-multi.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/dump-macros-only.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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: ^\\[^#]
+ */
--- a/usr/src/tools/smatch/src/validation/preprocessor/dump-macros.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/dump-macros.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/dynamic.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/extra-token.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/has-attribute.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/has-builtin.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/ident-pragma.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/ident.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/include-level.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/include-level.h	Thu Nov 21 12:33:13 2019 +0000
@@ -0,0 +1,1 @@
+__FILE__: __INCLUDE_LEVEL__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/missing-delim.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/phase2-backslash.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/phase3-comments.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/preprocessor/predef-char-bit.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/predef-llp64.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/predef-lp32.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/predef-lp64.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/preprocessor/predef-max.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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
- */
--- a/usr/src/tools/smatch/src/validation/preprocessor/predef-sizeof.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/predef-unsigned.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/preprocessor/predef.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/ptr-inherit.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/ptr-inherit.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/ptr-sub-blows.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/range-syntax.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/repeat.h	Thu Nov 21 12:33:13 2019 +0000
@@ -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)
--- a/usr/src/tools/smatch/src/validation/reserved.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/reserved.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/restrict.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/self-quote-args.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/shift-negative.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/shift-undef-long.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/shift-undef.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/sizeof-bool.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/sizeof-bool.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/sizeof-builtin.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/sizeof-function.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/sizeof-incomplete-type.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/sm_compare18.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/storage-struct-member.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/struct-as.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/struct-as.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/switch-long.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/test-be.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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
- */
--- a/usr/src/tools/smatch/src/validation/test-suite	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/test-suite	Thu Nov 21 12:33:13 2019 +0000
@@ -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,7 +32,36 @@
 
 # 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
@@ -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,24 +163,41 @@
 # 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
 
@@ -134,33 +205,48 @@
 }
 
 ##
-# 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
 }
 
 ##
@@ -177,13 +263,14 @@
 {
 	test_failed=0
 	file="$1"
+	quiet=0
 
 	get_tag_value $file
 
 	# 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
-
-	cmd=`eval echo $default_path/$check_command`
+	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
 
-	echo "     TEST    $test_name ($file)"
+	if [ -z "$vquiet" ]; then
+		echo "  TEST    $test_name ($file)"
+	fi
 
-	verbose "Using command       : $cmd"
+	verbose "Using command       : $(echo "$@")"
 
 	# 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: XPASS: test '$file' is known to fail but succeed!"
+		fi
+	else
+		if [ "$test_failed" -eq "1" ]; then
+			echo "error: FAIL: test '$file' failed"
 		else
-			echo "error: test '$file' is known to fail but succeed!"
-			test_failed=1
+			[ "$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
 
--- a/usr/src/tools/smatch/src/validation/testsuite-selfcheck1.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-good
-
-/*
- * check-name: selfcheck1
- * check-command: sparse -E $file
- * check-output-ignore
- *
- * check-output-contains: good
- * check-output-excludes: evil
- */
--- a/usr/src/tools/smatch/src/validation/testsuite-selfcheck2.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-evil
-
-/*
- * check-name: selfcheck2
- * check-command: sparse -E $file
- * check-output-ignore
- * check-known-to-fail
- *
- * check-output-contains: good
- */
--- a/usr/src/tools/smatch/src/validation/testsuite-selfcheck3.c	Wed Nov 20 15:03:31 2019 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/type-compare.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/typedef-redef-c89.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/typedef-redef.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/typedef_shadow.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/typedef_shadow.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/typediff-arraysize.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/typediff-enum.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/typeof-bad.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/tools/smatch/src/validation/typeof-mods.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/tools/smatch/src/validation/typeof-mods.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/var-undef-partial.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/vla-sizeof-ice.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/vla-sizeof.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/vla-sizeof0.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/vla-sizeof1.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/vla-sizeof2.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/vla-sizeof3.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/tools/smatch/src/validation/vla-sizeof4.c	Thu Nov 21 12:33:13 2019 +0000
@@ -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
+ */
--- a/usr/src/uts/common/io/mac/mac.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/uts/common/io/mac/mac.c	Thu Nov 21 12:33:13 2019 +0000
@@ -5234,7 +5234,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);
--- a/usr/src/uts/common/io/tem_safe.c	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/uts/common/io/tem_safe.c	Thu Nov 21 12:33:13 2019 +0000
@@ -2375,7 +2375,7 @@
 	*fg = c.tc_fg_color;
 	*bg = c.tc_bg_color;
 
-	if (c.tc_fg_color < 16) {
+	if (c.tc_fg_color < XLATE_NCOLORS) {
 		if (TEM_ATTR_ISSET(c.tc_char,
 		    TEM_ATTR_BRIGHT_FG | TEM_ATTR_BOLD))
 			*fg = brt_xlate[c.tc_fg_color];
@@ -2383,7 +2383,7 @@
 			*fg = dim_xlate[c.tc_fg_color];
 	}
 
-	if (c.tc_bg_color < 16) {
+	if (c.tc_bg_color < XLATE_NCOLORS) {
 		if (TEM_ATTR_ISSET(c.tc_char, TEM_ATTR_BRIGHT_BG))
 			*bg = brt_xlate[c.tc_bg_color];
 		else
--- a/usr/src/uts/common/sys/efi_partition.h	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/uts/common/sys/efi_partition.h	Thu Nov 21 12:33:13 2019 +0000
@@ -255,6 +255,7 @@
 #define	EFI_NUMPAR	9
 
 #ifndef _KERNEL
+extern	uint_t	efi_reserved_sectors(struct dk_gpt *);
 extern	int	efi_alloc_and_init(int, uint32_t, struct dk_gpt **);
 extern	int	efi_alloc_and_read(int, struct dk_gpt **);
 extern	int	efi_write(int, struct dk_gpt *);
--- a/usr/src/uts/common/sys/rgb.h	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/uts/common/sys/rgb.h	Thu Nov 21 12:33:13 2019 +0000
@@ -67,8 +67,9 @@
 	pc_brt_white	= 15
 } pc_colors_t;
 
-extern const uint8_t dim_xlate[];
-extern const uint8_t brt_xlate[];
+#define	XLATE_NCOLORS	8
+extern const uint8_t dim_xlate[XLATE_NCOLORS];
+extern const uint8_t brt_xlate[XLATE_NCOLORS];
 extern const uint8_t solaris_color_to_pc_color[16];
 
 extern uint32_t rgb_color_map(const rgb_t *, uint8_t);
--- a/usr/src/uts/intel/mac/Makefile	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/uts/intel/mac/Makefile	Thu Nov 21 12:33:13 2019 +0000
@@ -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).
@@ -66,11 +66,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.
 #
--- a/usr/src/uts/intel/procfs/Makefile	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/uts/intel/procfs/Makefile	Thu Nov 21 12:33:13 2019 +0000
@@ -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.
 #
--- a/usr/src/uts/intel/sol_ofs/Makefile	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/uts/intel/sol_ofs/Makefile	Thu Nov 21 12:33:13 2019 +0000
@@ -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.
 #
--- a/usr/src/uts/intel/sol_uverbs/Makefile	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/uts/intel/sol_uverbs/Makefile	Thu Nov 21 12:33:13 2019 +0000
@@ -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.
 #
--- a/usr/src/uts/intel/zfs/Makefile	Wed Nov 20 15:03:31 2019 +0000
+++ b/usr/src/uts/intel/zfs/Makefile	Thu Nov 21 12:33:13 2019 +0000
@@ -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.