This is a patch against the official GCC 6.3.0.  You can find GCC 6.3.0 via
https://gcc.gnu.org/mirrors.html, http://ftpmirror.gnu.org, and elsewhere.
The SHA-512 checksum for gcc-6.3.0.tar.bz2 is
  234dd9b1 bdc9a9c6 e352216a 7ef4ccad c6c07f15 6006a597 59c5e0e6 a69f0abc
  dc14630e ff11e382 6dd6ba59 33a8faa4 3043f3d1 d62df6bd 5ab1e828 62f9bf78.
===========================================================================
diff --git a/ChangeLog.ia16 b/ChangeLog.ia16
new file mode 100644
index 0000000..2d83590
--- /dev/null
+++ b/ChangeLog.ia16
@@ -0,0 +1,56 @@
+2007-07-30  Rask Ingemann Lambertsen  <rask@sygehus.dk>
+
+	libgcc/
+	* config.host: Add support for ia16.
+	* ia16/t-ia16: New.
+
+	gcc/
+	* config.gcc: Add support for ia16.
+	* doc/invoke.texi: Update for new ia16 back end.
+	* doc/contrib.texi: Likewise.
+	* doc/install.texi: Likewise.	
+	* doc/md.texi: Likewise.
+	* config/ia16/ia16.md: New.
+	* config/ia16/ia16-peepholes.md: New.
+	* config/ia16/ia16.opt: New.
+	* config/ia16/ia16.c: New.
+	* config/ia16/t-ia16: New.
+	* config/ia16/ia16-modes.def: New.
+	* config/ia16/predicates.md: New.
+	* config/ia16/constraints.md: New.
+	* config/ia16/ia16.h: New.
+	* config/ia16/ia16-protos.h: New.
+	* config/ia16/elf.h: New.
+	* config/ia16/elks.h: New.
+
+2007-07-30  Rask Ingemann Lambertsen  <rask@sygehus.dk>
+
+	* gcc.dg/20020312-2.c: Skip test of unsupported feature on ia16.
+	* gcc.c-torture/compile/20010327-1.c: Likewise.
+	* gcc.c-torture/compile/20020604-1.c: Likewise.
+	* gcc.dg/pr27639.c: Likewise.
+	* gcc.dg/pr19340.c: Likewise.
+	* gcc.dg/cpp/_Pragma6.c: Likewise.
+	* gcc.dg/20040813-1.c: Likewise.
+	* gcc.dg/sibcall-3.c: Xfail on ia16 until sibling calls work.
+	* gcc.dg/sibcall-4.c: Likewise.
+
+2007-07-30  Rask Ingemann Lambertsen  <rask@sygehus.dk>
+
+	* reload.c (reload_inner_reg_of_subreg): No special handling is
+	  needed if a subreg consists of more hard regs than words.
+	  (push_reload): Likewise.
+
+2007-07-30  Rask Ingemann Lambertsen  <rask@sygehus.dk>
+
+	* reload1.c (reload_reg_free_p): A register isn't free to use in
+	  RELOAD_FOR_OPADDR_ADDR when already inherited for use in
+	  RELOAD_FOR_OPERAND_ADDRESS.
+
+2007-07-30  Rask Ingemann Lambertsen  <rask@sygehus.dk>
+
+	* reload1.c (reloads_unique_chain_p): Check both reloads.
+
+2007-07-30  Rask Ingemann Lambertsen  <rask@sygehus.dk>
+
+	* config.sub: Add support for 16-bit Intel x86.
diff --git a/config-ml.in b/config-ml.in
index 5e51994..1fc0eaf 100644
--- a/config-ml.in
+++ b/config-ml.in
@@ -2,7 +2,7 @@
 # wanting multilib support.
 #
 # Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-# 2005, 2006, 2007, 2008, 2010, 2011, 2014 Free Software Foundation, Inc.
+# 2005, 2006, 2007, 2008, 2010, 2011, 2014, 2019 Free Software Foundation, Inc.
 #
 # This file is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -301,6 +301,34 @@ arm-*-*)
 	  done
 	fi
 	;;
+ia16-*)
+	if [ x"$enable_elks_libc" = xno \
+	     -o \( x"$PACKAGE" = xlibstdc++ \
+		   -a x"$enable_elks_libc" != xyes \) ]
+	then
+	  old_multidirs=${multidirs}
+	  multidirs=""
+	  for x in ${old_multidirs}; do
+	    case "${x}" in
+	      *elks-libc* | *elkslibc*) : ;;
+	      *) multidirs="${multidirs} ${x}" ;;
+	    esac
+	  done
+	fi
+	if [ x"$enable_cmodel_medium" = xno \
+	     -o \( x"$PACKAGE" = xlibstdc++ \
+		   -a x"$enable_cmodel_medium" != xyes \) ]
+	then
+	  old_multidirs=${multidirs}
+	  multidirs=""
+	  for x in ${old_multidirs}; do
+	    case "${x}" in
+	      *medium*) : ;;
+	      *) multidirs="${multidirs} ${x}" ;;
+	    esac
+	  done
+	fi
+	;;
 m68*-*-*)
 	if [ x$enable_softfloat = xno ]
 	then
diff --git a/config.sub b/config.sub
index 41146e1..ca9a709 100755
--- a/config.sub
+++ b/config.sub
@@ -2,7 +2,7 @@
 # Configuration validation subroutine script.
 #   Copyright 1992-2016 Free Software Foundation, Inc.
 
-timestamp='2016-01-01'
+timestamp='2016-12-15'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -263,7 +263,7 @@ case $basic_machine in
 	| fido | fr30 | frv | ft32 \
 	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
 	| hexagon \
-	| i370 | i860 | i960 | ia64 \
+	| i370 | i860 | i960 | ia64 | ia16 \
 	| ip2k | iq2000 \
 	| k1om \
 	| le32 | le64 \
@@ -387,7 +387,7 @@ case $basic_machine in
 	| h8300-* | h8500-* \
 	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
 	| hexagon-* \
-	| i*86-* | i860-* | i960-* | ia64-* \
+	| i*86-* | i860-* | i960-* | ia64-* | ia16-* \
 	| ip2k-* | iq2000-* \
 	| k1om-* \
 	| le32-* | le64-* \
diff --git a/config/acx.m4 b/config/acx.m4
index 9ff31eb..30de5c6 100644
--- a/config/acx.m4
+++ b/config/acx.m4
@@ -235,8 +235,28 @@ fi
 ])
 
 
+dnl ####
+dnl # GCC_BASE_VER
+dnl # Determine GCC version number to use in compiler directories.
+
+AC_DEFUN([GCC_BASE_VER],
+[
+  get_gcc_base_ver="cat"
+  AC_ARG_WITH(gcc-major-version-only,
+  [AS_HELP_STRING([--with-gcc-major-version-only], [use only GCC major number in filesystem paths])],
+  [if test x$with_gcc_major_version_only = xyes ; then
+    changequote(,)dnl
+    get_gcc_base_ver="sed -e 's/^\([0-9]*\).*\$\$/\1/'"
+    changequote([,])dnl
+  fi
+  ])
+  AC_SUBST(get_gcc_base_ver)
+])
+
+
 AC_DEFUN([ACX_TOOL_DIRS], [
 AC_REQUIRE([ACX_PATH_SEP])
+AC_REQUIRE([GCC_BASE_VER])
 if test "x$exec_prefix" = xNONE; then
         if test "x$prefix" = xNONE; then
                 gcc_cv_tool_prefix=$ac_default_prefix
@@ -251,7 +271,13 @@ fi
 # case, if there is no compiler in the tree nobody should use
 # AS_FOR_TARGET and LD_FOR_TARGET.
 if test x$host = x$build && test -f $srcdir/gcc/BASE-VER; then
-    gcc_version=`cat $srcdir/gcc/BASE-VER`
+    if test x$with_gcc_major_version_only = xyes ; then
+        changequote(,)dnl
+        gcc_version=`sed -e 's/^\([0-9]*\).*$/\1/' $srcdir/gcc/BASE-VER`
+        changequote([,])dnl
+    else
+        gcc_version=`cat $srcdir/gcc/BASE-VER`
+    fi
     gcc_cv_tool_dirs="$gcc_cv_tool_prefix/libexec/gcc/$target_noncanonical/$gcc_version$PATH_SEPARATOR"
     gcc_cv_tool_dirs="$gcc_cv_tool_dirs$gcc_cv_tool_prefix/libexec/gcc/$target_noncanonical$PATH_SEPARATOR"
     gcc_cv_tool_dirs="$gcc_cv_tool_dirs/usr/lib/gcc/$target_noncanonical/$gcc_version$PATH_SEPARATOR"
diff --git a/configure b/configure
index 35f231e..f4781c3 100755
--- a/configure
+++ b/configure
@@ -643,6 +643,7 @@ CXXFLAGS_FOR_TARGET
 CFLAGS_FOR_TARGET
 DEBUG_PREFIX_CFLAGS_FOR_TARGET
 SYSROOT_CFLAGS_FOR_TARGET
+get_gcc_base_ver
 extra_host_zlib_configure_flags
 extra_host_libiberty_configure_flags
 stage1_languages
@@ -787,6 +788,7 @@ enable_linker_plugin_configure_flags
 enable_linker_plugin_flags
 enable_stage1_languages
 enable_objc_gc
+with_gcc_major_version_only
 with_build_sysroot
 with_debug_prefix_map
 with_build_config
@@ -1556,6 +1558,8 @@ Optional Packages:
                           --with-isl-lib=PATH/lib
   --with-isl-include=PATH Specify directory for installed isl include files
   --with-isl-lib=PATH     Specify the directory for the installed isl library
+  --with-gcc-major-version-only
+                          use only GCC major number in filesystem paths
   --with-build-sysroot=SYSROOT
                           use sysroot as the system root during the build
   --with-debug-prefix-map='A=B C=D ...'
@@ -6716,6 +6720,20 @@ if test "${PATH_SEPARATOR+set}" != set; then
 fi
 
 
+  get_gcc_base_ver="cat"
+
+# Check whether --with-gcc-major-version-only was given.
+if test "${with_gcc_major_version_only+set}" = set; then :
+  withval=$with_gcc_major_version_only; if test x$with_gcc_major_version_only = xyes ; then
+        get_gcc_base_ver="sed -e 's/^\([0-9]*\).*\$\$/\1/'"
+      fi
+
+fi
+
+
+
+
+
 
 if test "x$exec_prefix" = xNONE; then
         if test "x$prefix" = xNONE; then
@@ -6731,7 +6749,11 @@ fi
 # case, if there is no compiler in the tree nobody should use
 # AS_FOR_TARGET and LD_FOR_TARGET.
 if test x$host = x$build && test -f $srcdir/gcc/BASE-VER; then
-    gcc_version=`cat $srcdir/gcc/BASE-VER`
+    if test x$with_gcc_major_version_only = xyes ; then
+                gcc_version=`sed -e 's/^\([0-9]*\).*$/\1/' $srcdir/gcc/BASE-VER`
+            else
+        gcc_version=`cat $srcdir/gcc/BASE-VER`
+    fi
     gcc_cv_tool_dirs="$gcc_cv_tool_prefix/libexec/gcc/$target_noncanonical/$gcc_version$PATH_SEPARATOR"
     gcc_cv_tool_dirs="$gcc_cv_tool_dirs$gcc_cv_tool_prefix/libexec/gcc/$target_noncanonical$PATH_SEPARATOR"
     gcc_cv_tool_dirs="$gcc_cv_tool_dirs/usr/lib/gcc/$target_noncanonical/$gcc_version$PATH_SEPARATOR"
diff --git a/fixincludes/Makefile.in b/fixincludes/Makefile.in
index 5dc1b23..1937dca 100644
--- a/fixincludes/Makefile.in
+++ b/fixincludes/Makefile.in
@@ -49,7 +49,7 @@ target = @target@
 target_noncanonical:=@target_noncanonical@
 
 # The version of GCC in this tree
-gcc_version := $(shell cat $(srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(srcdir)/../gcc/BASE-VER)
 
 # Directory in which the compiler finds libraries etc.
 libsubdir = $(libdir)/gcc/$(target_noncanonical)/$(gcc_version)
diff --git a/fixincludes/configure b/fixincludes/configure
index 4836cd8..ab97983 100755
--- a/fixincludes/configure
+++ b/fixincludes/configure
@@ -590,6 +590,7 @@ ac_includes_default="\
 
 ac_subst_vars='LTLIBOBJS
 LIBOBJS
+get_gcc_base_ver
 MAINT
 TARGET
 target_noncanonical
@@ -664,6 +665,7 @@ enable_werror_always
 with_local_prefix
 enable_twoprocess
 enable_maintainer_mode
+with_gcc_major_version_only
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1298,6 +1300,8 @@ Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
   --with-local-prefix=DIR specifies directory to put local include
+  --with-gcc-major-version-only
+                          use only GCC major number in filesystem paths
 
 Some influential environment variables:
   CC          C compiler command
@@ -4561,6 +4565,12 @@ $as_echo "$ac_cv_path_SED" >&6; }
 # Figure out what compiler warnings we can enable.
 # See config/warnings.m4 for details.
 
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
 WARN_CFLAGS=
 save_CFLAGS="$CFLAGS"
 for real_option in -W -Wall -Wwrite-strings -Wstrict-prototypes \
@@ -4607,6 +4617,18 @@ $as_echo "$ac_res" >&6; }
 fi
   done
 CFLAGS="$save_CFLAGS"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 WARN_PEDANTIC=
 # Do the check with the no- prefix removed from the warning options
@@ -4645,10 +4667,22 @@ if test $acx_cv_prog_cc_pedantic__Wlong_long = yes; then :
 fi
 
 fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
 
 
 # Only enable with --enable-werror-always until existing warnings are
 # corrected.
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
 WERROR=
 # Check whether --enable-werror-always was given.
 if test "${enable_werror_always+set}" = set; then :
@@ -4661,6 +4695,12 @@ if test $enable_werror_always = yes; then :
   WERROR="$WERROR${WERROR:+ }-Werror"
 fi
 
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
 
 
 # Determine the noncanonical target name, for directory use.
@@ -5354,6 +5394,21 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
+# Determine what GCC version number to use in filesystem paths.
+
+  get_gcc_base_ver="cat"
+
+# Check whether --with-gcc-major-version-only was given.
+if test "${with_gcc_major_version_only+set}" = set; then :
+  withval=$with_gcc_major_version_only; if test x$with_gcc_major_version_only = xyes ; then
+        get_gcc_base_ver="sed -e 's/^\([0-9]*\).*\$\$/\1/'"
+      fi
+
+fi
+
+
+
+
 ac_config_headers="$ac_config_headers config.h"
 
 ac_config_files="$ac_config_files Makefile mkheaders.almost:mkheaders.in"
diff --git a/fixincludes/configure.ac b/fixincludes/configure.ac
index f8f352f..190f538 100644
--- a/fixincludes/configure.ac
+++ b/fixincludes/configure.ac
@@ -114,6 +114,9 @@ AC_SUBST(MAINT)
 AC_DEFINE_UNQUOTED([SED_PROGRAM], "${SED}",
    [Defined to the best working sed program on the host system])
 
+# Determine what GCC version number to use in filesystem paths.
+GCC_BASE_VER
+
 AC_CONFIG_HEADERS(config.h, [echo timestamp > stamp-h])
 AC_CONFIG_FILES(Makefile mkheaders.almost:mkheaders.in)
 AC_OUTPUT
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 13d0d1b..fa894f4 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -844,7 +844,7 @@ else
 REVISION_c  := $(shell cat $(REVISION))
 endif
 
-version     := $(BASEVER_c)
+version     := $(shell @get_gcc_base_ver@ $(BASEVER))
 
 PATCHLEVEL_c := \
   $(shell echo $(BASEVER_c) | sed -e 's/^[0-9]*\.[0-9]*\.\([0-9]*\)$$/\1/')
@@ -2035,7 +2035,8 @@ DRIVER_DEFINES = \
   $(if $(SHLIB),$(if $(filter yes,@enable_shared@),-DENABLE_SHARED_LIBGCC)) \
   -DCONFIGURE_SPECS="\"@CONFIGURE_SPECS@\""
 
-CFLAGS-gcc.o += $(DRIVER_DEFINES)
+CFLAGS-gcc.o += $(DRIVER_DEFINES) -DBASEVER=$(BASEVER_s)
+gcc.o: $(BASEVER)
 
 specs.h : s-specs ; @true
 s-specs : Makefile
diff --git a/gcc/builtins.c b/gcc/builtins.c
index bb9ee35..f87397b 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -1310,12 +1310,14 @@ apply_args_size (void)
 	  {
 	    mode = targetm.calls.get_raw_arg_mode (regno);
 
-	    gcc_assert (mode != VOIDmode);
+	    if (mode != VOIDmode)
+	      {
+		align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
+		if (size % align != 0)
+		  size = CEIL (size, align) * align;
+		size += GET_MODE_SIZE (mode);
+	      }
 
-	    align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
-	    if (size % align != 0)
-	      size = CEIL (size, align) * align;
-	    size += GET_MODE_SIZE (mode);
 	    apply_args_mode[regno] = mode;
 	  }
 	else
@@ -1346,12 +1348,14 @@ apply_result_size (void)
 	  {
 	    mode = targetm.calls.get_raw_result_mode (regno);
 
-	    gcc_assert (mode != VOIDmode);
+	    if (mode != VOIDmode)
+	      {
+		align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
+		if (size % align != 0)
+		  size = CEIL (size, align) * align;
+		size += GET_MODE_SIZE (mode);
+	      }
 
-	    align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
-	    if (size % align != 0)
-	      size = CEIL (size, align) * align;
-	    size += GET_MODE_SIZE (mode);
 	    apply_result_mode[regno] = mode;
 	  }
 	else
diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c
index 3d4587e..815b84d 100644
--- a/gcc/c-family/c-cppbuiltin.c
+++ b/gcc/c-family/c-cppbuiltin.c
@@ -1119,10 +1119,12 @@ c_cpp_builtins (cpp_reader *pfile)
       builtin_define_with_value ("__LIBGCC_EH_FRAME_SECTION_NAME__",
 				 EH_FRAME_SECTION_NAME, 1);
 #endif
+#if TARGET_USE_JCR_SECTION
 #ifdef JCR_SECTION_NAME
       builtin_define_with_value ("__LIBGCC_JCR_SECTION_NAME__",
 				 JCR_SECTION_NAME, 1);
 #endif
+#endif
 #ifdef CTORS_SECTION_ASM_OP
       builtin_define_with_value ("__LIBGCC_CTORS_SECTION_ASM_OP__",
 				 CTORS_SECTION_ASM_OP, 1);
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index b237e93..2b06cac 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -4601,7 +4601,7 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
 	ce = declarator->declarator;
       if (ce->kind == cdk_function)
 	{
-	  tree args = ce->u.arg_info->parms;
+	  tree args = ce->u.function.arg_info->parms;
 	  for (; args; args = DECL_CHAIN (args))
 	    {
 	      tree type = TREE_TYPE (args);
@@ -6123,13 +6123,24 @@ grokdeclarator (const struct c_declarator *declarator,
 
 	    /* Construct the function type and go to the next
 	       inner layer of declarator.  */
-	    arg_info = declarator->u.arg_info;
+	    arg_info = declarator->u.function.arg_info;
 	    arg_types = grokparms (arg_info, really_funcdef);
 
 	    /* Type qualifiers before the return type of the function
 	       qualify the return type, not the function type.  */
 	    if (type_quals)
 	      {
+#ifdef TARGET_ADDR_SPACE_MAY_HAVE_FUNCTIONS_P
+# ifdef TARGET_FUNCTION_ADDR_SPACE_FROM_RETURN_TYPE_P
+		if (CLEAR_QUAL_ADDR_SPACE (type_quals) == 0
+		    && TARGET_ADDR_SPACE_MAY_HAVE_FUNCTIONS_P
+			(DECODE_QUAL_ADDR_SPACE (type_quals))
+		    && TARGET_FUNCTION_ADDR_SPACE_FROM_RETURN_TYPE_P
+			(DECODE_QUAL_ADDR_SPACE (type_quals)))
+		  ;
+		else
+# endif
+#endif
 		/* Type qualifiers on a function return type are
 		   normally permitted by the standard but have no
 		   effect, so give a warning at -Wreturn-type.
@@ -6148,6 +6159,42 @@ grokdeclarator (const struct c_declarator *declarator,
 	    type_quals = TYPE_UNQUALIFIED;
 
 	    type = build_function_type (type, arg_types);
+#ifdef TARGET_ADDR_SPACE_MAY_HAVE_FUNCTIONS_P
+	    if (! ADDR_SPACE_GENERIC_P (declarator->u.function.as))
+	      {
+		type_quals
+		  = ENCODE_QUAL_ADDR_SPACE (declarator->u.function.as);
+		type = c_build_qualified_type (type, type_quals);
+	      }
+# ifdef TARGET_FUNCTION_ADDR_SPACE_FROM_RETURN_TYPE_P
+	    else
+	      {
+		addr_space_t rv_as = TYPE_ADDR_SPACE (TREE_TYPE (type));
+		if (! ADDR_SPACE_GENERIC_P (rv_as)
+		    && TARGET_ADDR_SPACE_MAY_HAVE_FUNCTIONS_P (rv_as)
+		    && TARGET_FUNCTION_ADDR_SPACE_FROM_RETURN_TYPE_P (rv_as))
+		  {
+		    /* Remove the address space qualifier from the return
+		       type, and construct the function type again.
+
+		       Removing the return type's address space is not
+		       really needed for the compiled output to be correct. 
+		       However, doing so does ward off some spurious
+		       "function with qualified void return type called"
+		       warning messages.
+
+		       See https://github.com/tkchia/gcc-ia16/issues/25 .
+			 -- tkchia */
+		    tree rtype = TREE_TYPE (type);
+		    rtype = c_build_qualified_type
+			      (rtype, TYPE_QUALS_NO_ADDR_SPACE (rtype));
+		    type = build_function_type (rtype, arg_types);
+		    type_quals = ENCODE_QUAL_ADDR_SPACE (rv_as);
+		    type = c_build_qualified_type (type, type_quals);
+		  }
+	      }
+# endif
+#endif
 	    declarator = declarator->declarator;
 
 	    /* Set the TYPE_CONTEXTs for each tagged type which is local to
@@ -9437,12 +9484,18 @@ build_attrs_declarator (tree attrs, struct c_declarator *target)
 
 struct c_declarator *
 build_function_declarator (struct c_arg_info *args,
+			   addr_space_t as,
 			   struct c_declarator *target)
 {
   struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator);
   ret->kind = cdk_function;
   ret->declarator = target;
-  ret->u.arg_info = args;
+  ret->u.function.arg_info = args;
+#ifdef TARGET_ADDR_SPACE_MAY_HAVE_FUNCTIONS_P
+  ret->u.function.as = as;
+#else
+  gcc_assert (as == ADDR_SPACE_GENERIC);
+#endif
   return ret;
 }
 
@@ -9524,6 +9577,9 @@ declspecs_add_addrspace (source_location location,
       specs->address_space = as;
       specs->locations[cdw_address_space] = location;
     }
+#ifdef TARGET_WARN_ADDR_SPACE_SYNTAX_P
+  specs->address_space_is_last_p = true;
+#endif
   return specs;
 }
 
@@ -9540,6 +9596,9 @@ declspecs_add_qual (source_location loc,
   specs->declspecs_seen_p = true;
   gcc_assert (TREE_CODE (qual) == IDENTIFIER_NODE
 	      && C_IS_RESERVED_WORD (qual));
+#ifdef TARGET_WARN_ADDR_SPACE_SYNTAX_P
+  specs->address_space_is_last_p = false;
+#endif
   i = C_RID_CODE (qual);
   switch (i)
     {
@@ -9583,6 +9642,9 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
   specs->typespec_kind = spec.kind;
   if (TREE_DEPRECATED (type))
     specs->deprecated_p = true;
+#ifdef TARGET_WARN_ADDR_SPACE_SYNTAX_P
+  specs->address_space_is_last_p = false;
+#endif
 
   /* Handle type specifier keywords.  */
   if (TREE_CODE (type) == IDENTIFIER_NODE
@@ -10332,6 +10394,9 @@ declspecs_add_scspec (source_location loc,
   specs->declspecs_seen_p = true;
   gcc_assert (TREE_CODE (scspec) == IDENTIFIER_NODE
 	      && C_IS_RESERVED_WORD (scspec));
+#ifdef TARGET_WARN_ADDR_SPACE_SYNTAX_P
+  specs->address_space_is_last_p = false;
+#endif
   i = C_RID_CODE (scspec);
   if (specs->non_sc_seen_p)
     warning (OPT_Wold_style_declaration,
@@ -10443,6 +10508,9 @@ declspecs_add_scspec (source_location loc,
 struct c_declspecs *
 declspecs_add_attrs (source_location loc, struct c_declspecs *specs, tree attrs)
 {
+#ifdef TARGET_WARN_ADDR_SPACE_SYNTAX_P
+  specs->address_space_is_last_p = false;
+#endif
   specs->attrs = chainon (attrs, specs->attrs);
   specs->locations[cdw_attributes] = loc;
   specs->declspecs_seen_p = true;
@@ -10457,6 +10525,9 @@ declspecs_add_alignas (source_location loc,
 		       struct c_declspecs *specs, tree align)
 {
   int align_log;
+#ifdef TARGET_WARN_ADDR_SPACE_SYNTAX_P
+  specs->address_space_is_last_p = false;
+#endif
   specs->alignas_p = true;
   specs->locations[cdw_alignas] = loc;
   if (align == error_mark_node)
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index c9eb8dd..08c7e01 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1637,6 +1637,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
   tree prefix_attrs;
   tree all_prefix_attrs;
   bool diagnosed_no_specs = false;
+#ifdef TARGET_WARN_ADDR_SPACE_SYNTAX_P
+  bool diagnosed_addr_space_syntax = false;
+#endif
   location_t here = c_parser_peek_token (parser)->location;
 
   if (static_assert_ok
@@ -1807,6 +1810,28 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
       bool dummy = false;
       timevar_id_t tv;
       tree fnbody;
+#ifdef TARGET_WARN_ADDR_SPACE_SYNTAX_P
+      if (!diagnosed_addr_space_syntax && !first)
+	{
+	  addr_space_t as = specs->address_space;
+	  location_t there = c_parser_peek_token (parser)->location;
+	  diagnosed_addr_space_syntax = true;
+	  if (!ADDR_SPACE_GENERIC_P (as)
+	      && TARGET_WARN_ADDR_SPACE_SYNTAX_P (specs->address_space)
+	      && specs->address_space_is_last_p)
+	    {
+	      const char *as_name = c_addr_space_name (as);
+	      if (warning_at (there, OPT_Waddress,
+			      "following declarators will also go in "
+			      "%qs space", as_name))
+		{
+		  inform (there, "suggest to either split declaration,");
+		  inform (there, "or place %qs before %qT", as_name,
+			  specs->type);
+		}
+	    }
+	}
+#endif
       /* Declaring either one or more declarators (in which case we
 	 should diagnose if there were no declaration specifiers) or a
 	 function definition (in which case the diagnostic for
@@ -1971,7 +1996,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 		      while (ce != NULL)
 			if (ce->kind == cdk_function)
 			  {
-			    parms = ce->u.arg_info->parms;
+			    parms = ce->u.function.arg_info->parms;
 			    break;
 			  }
 			else
@@ -3370,6 +3395,38 @@ c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
   return c_parser_direct_declarator (parser, type_seen_p, kind, seen_id);
 }
 
+#ifdef TARGET_ADDR_SPACE_MAY_HAVE_FUNCTIONS_P
+
+/* Special case for ia16-elf.  Parse an optional address space qualifier
+   after a function's parameter type list.  (To avoid ambiguities, an
+   address space qualifier (e.g. __far) after a K&R-style identifier-list
+   is treated as part of the following declaration-list.)
+
+   direct-declarator:
+     direct-declarator ( parameter-type-list ) address-space-qualifier[opt]
+     direct-declarator ( ) address-space-qualifier[opt]
+ */
+static addr_space_t
+c_parser_optional_address_space_qualifier (c_parser *parser)
+{
+  c_token *token = c_parser_peek_token (parser);
+  addr_space_t as;
+
+  if (token->type != CPP_NAME
+      || token->id_kind != C_ID_ADDRSPACE)
+    return ADDR_SPACE_GENERIC;
+
+  as = token->keyword - RID_FIRST_ADDR_SPACE;
+
+  if (! ADDR_SPACE_GENERIC_P (as)
+      && ! TARGET_ADDR_SPACE_MAY_HAVE_FUNCTIONS_P (as))
+    return ADDR_SPACE_GENERIC;
+
+  c_parser_consume_token (parser);
+  return as;
+}
+#endif
+
 /* Parse a direct declarator or direct abstract declarator; arguments
    as c_parser_declarator.  */
 
@@ -3453,8 +3510,16 @@ c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
 	    return NULL;
 	  else
 	    {
+	      addr_space_t as = ADDR_SPACE_GENERIC;
+#ifdef TARGET_ADDR_SPACE_MAY_HAVE_FUNCTIONS_P
+	      /* Only accept an address space qualifier here if this is not
+		 a K&R-style identifier list.  */
+	      if (! args->types
+		  || TREE_CODE (TREE_VALUE (args->types)) != IDENTIFIER_NODE)
+		as = c_parser_optional_address_space_qualifier (parser);
+#endif
 	      inner
-		= build_function_declarator (args,
+		= build_function_declarator (args, as,
 					     build_id_declarator (NULL_TREE));
 	      return c_parser_direct_declarator_inner (parser, *seen_id,
 						       inner);
@@ -3603,7 +3668,13 @@ c_parser_direct_declarator_inner (c_parser *parser, bool id_present,
 	return NULL;
       else
 	{
-	  inner = build_function_declarator (args, inner);
+	  addr_space_t as = ADDR_SPACE_GENERIC;
+#ifdef TARGET_ADDR_SPACE_MAY_HAVE_FUNCTIONS_P
+	  if (! args->types
+	      || TREE_CODE (TREE_VALUE (args->types)) != IDENTIFIER_NODE)
+	    as = c_parser_optional_address_space_qualifier (parser);
+#endif
+	  inner = build_function_declarator (args, as, inner);
 	  return c_parser_direct_declarator_inner (parser, id_present, inner);
 	}
     }
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index bb12a20..f99829d 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -357,6 +357,11 @@ struct c_declspecs {
   /* Whether any alignment specifier (even with zero alignment) was
      specified.  */
   BOOL_BITFIELD alignas_p : 1;
+#ifdef TARGET_WARN_ADDR_SPACE_SYNTAX_P
+  /* Whether the address space specifier (below) comes last in the
+     declaration specifiers.  */
+  BOOL_BITFIELD address_space_is_last_p : 1;
+#endif
   /* The address space that the declaration belongs to.  */
   addr_space_t address_space;
 };
@@ -416,7 +421,12 @@ struct c_declarator {
        declarator.  */
     tree id;
     /* For functions.  */
-    struct c_arg_info *arg_info;
+    struct {
+      struct c_arg_info *arg_info;
+#ifdef TARGET_ADDR_SPACE_MAY_HAVE_FUNCTIONS_P
+      addr_space_t as;
+#endif
+    } function;
     /* For arrays.  */
     struct {
       /* The array dimension, or NULL for [] and [*].  */
@@ -559,6 +569,7 @@ extern struct c_parm *build_c_parm (struct c_declspecs *, tree,
 extern struct c_declarator *build_attrs_declarator (tree,
 						    struct c_declarator *);
 extern struct c_declarator *build_function_declarator (struct c_arg_info *,
+						       addr_space_t,
 						       struct c_declarator *);
 extern struct c_declarator *build_id_declarator (tree);
 extern struct c_declarator *make_pointer_declarator (struct c_declspecs *,
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 2bea816..8f72f65 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -13508,6 +13508,14 @@ c_build_qualified_type (tree type, int type_quals, tree orig_qual_type,
 
 	  t = build_variant_type_copy (type);
 	  TREE_TYPE (t) = element_type;
+	  /* Fix https://github.com/tkchia/gcc-ia16/issues/3 .  An array
+	     type was not marked as having the same address space as its
+	     element type.  This led to a compiler crash when trying to cast
+	     a far array to a far pointer.  -- tkchia  */
+	  TYPE_ADDR_SPACE (t) = TYPE_ADDR_SPACE (element_type);
+	  /* composite_type () does not allow any other qualifiers on array
+	     types, so do _not_ copy TYPE_READONLY (.), TYPE_VOLATILE (.),
+	     etc., over to the new type.  -- tkchia  */
 
           if (TYPE_STRUCTURAL_EQUALITY_P (element_type)
               || (domain && TYPE_STRUCTURAL_EQUALITY_P (domain)))
diff --git a/gcc/calls.c b/gcc/calls.c
index 6cc1fc7..20245da 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -185,19 +185,38 @@ rtx
 prepare_call_address (tree fndecl_or_type, rtx funexp, rtx static_chain_value,
 		      rtx *call_fusage, int reg_parm_seen, int sibcallp)
 {
+  /* Incorporate address space information from the function type, in order
+     to support far functions on ia16-elf.  -- tkchia */
+  addr_space_t as = ADDR_SPACE_GENERIC;
+
+  if (fndecl_or_type)
+    {
+      if (TREE_CODE (fndecl_or_type) != FUNCTION_DECL)
+	as = TYPE_ADDR_SPACE (fndecl_or_type);
+      else
+	as = TYPE_ADDR_SPACE (TREE_TYPE (fndecl_or_type));
+    }
+
   /* Make a valid memory address and copy constants through pseudo-regs,
      but not for a constant address if -fno-function-cse.  */
   if (GET_CODE (funexp) != SYMBOL_REF)
     /* If we are using registers for parameters, force the
        function address into a register now.  */
-    funexp = ((reg_parm_seen
-	       && targetm.small_register_classes_for_mode_p (FUNCTION_MODE))
-	      ? force_not_mem (memory_address (FUNCTION_MODE, funexp))
-	      : memory_address (FUNCTION_MODE, funexp));
+    {
+#ifdef TARGET_ADDR_SPACE_WEIRD_P
+      if (! TARGET_ADDR_SPACE_WEIRD_P (as))
+#endif
+	{
+	  funexp = memory_address_addr_space (FUNCTION_MODE, funexp, as);
+	  if (reg_parm_seen
+	      && targetm.small_register_classes_for_mode_p (FUNCTION_MODE))
+	    funexp = force_not_mem (funexp);
+	}
+    }
   else if (! sibcallp)
     {
       if (!NO_FUNCTION_CSE && optimize && ! flag_no_function_cse)
-	funexp = force_reg (Pmode, funexp);
+	funexp = force_reg (targetm.addr_space.address_mode (as), funexp);
     }
 
   if (static_chain_value != 0
@@ -290,7 +309,13 @@ emit_call_1 (rtx funexp, tree fntree ATTRIBUTE_UNUSED, tree fndecl ATTRIBUTE_UNU
      and we don't want to load it into a register as an optimization,
      because prepare_call_address already did it if it should be done.  */
   if (GET_CODE (funexp) != SYMBOL_REF)
-    funexp = memory_address (FUNCTION_MODE, funexp);
+    {
+      addr_space_t as = TYPE_ADDR_SPACE (funtype);
+#ifdef TARGET_ADDR_SPACE_WEIRD_P
+      if (! TARGET_ADDR_SPACE_WEIRD_P (as))
+#endif
+	funexp = memory_address_addr_space (FUNCTION_MODE, funexp, as);
+    }
 
   funmem = gen_rtx_MEM (FUNCTION_MODE, funexp);
   if (fndecl && TREE_CODE (fndecl) == FUNCTION_DECL)
diff --git a/gcc/common.opt b/gcc/common.opt
index 67048db..f81660a 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -823,6 +823,9 @@ Driver
 dumpversion
 Driver
 
+dumpfullversion
+Driver
+
 e
 Driver Joined Separate
 
diff --git a/gcc/config.gcc b/gcc/config.gcc
index 1d5b23f..204f2a7 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -403,6 +403,13 @@ x86_64-*-*)
 		       avx512vbmivlintrin.h clwbintrin.h mwaitxintrin.h
 		       clzerointrin.h pkuintrin.h"
 	;;
+ia16-*-*)
+	cpu_type=ia16
+	c_target_objs="ia16-c.o"
+	cxx_target_objs="ia16-c.o"
+	extra_objs="ia16-builtins.o ia16-reorg.o ia16-no-ss-data.o"
+	target_has_targetm_common=no
+	;;
 ia64-*-*)
 	extra_headers=ia64intrin.h
 	extra_options="${extra_options} g.opt fused-madd.opt"
@@ -1802,6 +1809,14 @@ i[34567]86-*-interix[3-9]*)
 		tm_file="${tm_file} dbxcoff.h"
 	fi
 	;;
+ia16-*-elf)
+	tm_file="elfos.h ${tm_file} ia16/elf.h newlib-stdint.h"
+	tmake_file="ia16/t-ia16"
+	;;
+ia16-*-elks)
+	tm_file="elfos.h ${tm_file} ia16/elks.h"
+	tmake_file="ia16/t-ia16"
+	;;
 ia64*-*-elf*)
 	tm_file="${tm_file} dbxelf.h elfos.h newlib-stdint.h ia64/sysv4.h ia64/elf.h"
 	tmake_file="ia64/t-ia64"
diff --git a/gcc/config/ia16/constraints.md b/gcc/config/ia16/constraints.md
new file mode 100644
index 0000000..467b873
--- /dev/null
+++ b/gcc/config/ia16/constraints.md
@@ -0,0 +1,168 @@
+;  Constraint definitions for Intel 16-bit x86.
+;  Copyright (C) 2006-2017 Free Software Foundation, Inc.
+;  Contributed by Rask Ingemann Lambertsen <rask@sygehus.dk>
+;  Changes by Andrew Jenner <andrew@codesourcery.com>
+;
+;  This file is part of GCC.
+;
+;  GCC 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 3 of the License, or (at your option) any
+;  later version.
+;
+;  GCC 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/licenses/>.
+
+
+; Predefined constraints:
+;          E Fg  i       m n o p   r s      V   X    <>0123456789
+
+; Machine specific integer constant constraints:
+; Available:
+;                   J K       O
+
+; Machine specific floating point constant constraints:
+; Available:
+;             G H
+
+; Machine specific constraints:
+; Used register constraints:
+; aAbBc dDe    h   j k l         qQ R S Tu   w x
+; Used constant constraints (IJKLMNOP integers only):
+;                 I     L MN    P         U         Z
+; Available:
+;      C    f                          t   v  W  yYz
+
+; Individual 16-bit registers.
+(define_register_constraint "a"	  "AX_REGS"	"The @code{ax} register.")
+(define_register_constraint "b"	  "BX_REGS"	"The @code{bx} register.")
+(define_register_constraint "c"	  "CX_REGS"	"The @code{cx} register.")
+(define_register_constraint "d"   "DX_REGS"	"The @code{dx} register.")
+(define_register_constraint "S"	  "SI_REGS"	"The @code{si} register.")
+(define_register_constraint "D"	  "DI_REGS"	"The @code{di} register.")
+(define_register_constraint "Rbp" "BP_REGS"	"The @code{bp} register.")
+(define_register_constraint "e"   "ES_REGS"	"The @code{es} register.")
+(define_register_constraint "Rds" "DS_REGS"	"The @code{ds} register.")
+
+; Individual 8-bit registers.
+(define_register_constraint "Ral" "AL_REGS"	"The @code{al} register.")
+(define_register_constraint "Rah" "AH_REGS"	"The @code{ah} register.")
+(define_register_constraint "Rcl" "CL_REGS"	"The @code{cl} register.")
+(define_register_constraint "Rdl" "DL_REGS"	"The @code{dl} register.")
+(define_register_constraint "Rdh" "DH_REGS"	"The @code{dh} register.")
+
+; General purpose register classes.
+(define_register_constraint "T"	"SEG_GENERAL_REGS"
+	"All general and segment registers.")
+(define_register_constraint "q" "QI_REGS"
+	"The 8-bit registers.")
+(define_register_constraint "l"	"LO_QI_REGS"
+	"The lower half of pairs of 8-bit registers.")
+(define_register_constraint "u"	"UP_QI_REGS"
+	"The upper half of pairs of 8-bit registers.")
+(define_register_constraint "B"	"BASE_REGS"
+	"The @code{bx}, @code{si}, @code{di} and @code{bp} registers.")
+(define_register_constraint "w"	"BASE_W_INDEX_REGS"
+	"The @code{bx} and @code{bp} registers.")
+(define_register_constraint "x"	"INDEX_REGS"
+	"The @code{si} and @code{di} registers.")
+
+; Special groups of registers.
+(define_register_constraint "A"	"DXAX_REGS"  "The @code{dx:ax} register pair.")
+(define_register_constraint "j"	"BXDX_REGS"  "The @code{bx:dx} register pair.")
+(define_register_constraint "Q" "SEGMENT_REGS"	"A segment register.")
+(define_register_constraint "k"	"QISI_REGS"
+	"SImode registers with two 8-bit low parts.")
+
+; Constraints for integer constants.
+(define_constraint	"Z"	"The constant 0."
+   (and (match_code "const_int,const_vector")
+	(match_test "op == CONST0_RTX (mode)")))
+
+(define_constraint	"P1"	"The constant 1."
+   (and (match_code "const_int")
+	(match_test "ival == 1")))
+
+(define_constraint	"M1"	"The constant @minus{}1."
+   (and (match_code "const_int")
+	(match_test "ival == -1")))
+
+; An upper byte mask constant.
+(define_constraint	"Um"	"The constant @minus{}256."
+   (and (match_code "const_int")
+	(match_test "ival == -256")))
+
+; A lower byte mask constant.
+(define_constraint	"Lbm"	"The constant 255."
+   (and (match_code "const_int")
+	(match_test "ival == 255")))
+
+; Low part constants for IOR and XOR with a register operand.
+; 0x0080 (128) to 0x00FE (254).
+(define_constraint	"Lor"	"Constants 128 @dots{} 254."
+   (and (match_code "const_int")
+	(match_test "ival >= 128 && ival <= 254")))
+
+; Low part constants for IOR and XOR with a memory operand.
+; 0x0001 (1) to 0x00FE (254).
+(define_constraint	"Lom"	"Constants 1 @dots{} 254."
+   (and (match_code "const_int")
+	(match_test "ival >= 1 && ival <= 254")))
+
+; Low part constants for AND with a register operand.
+; 0xFF01 (-255) to 0xFF7F (-129).
+(define_constraint	"Lar"	"Constants @minus{}255 @dots{} @minus{}129."
+   (and (match_code "const_int")
+	(match_test "ival >= -255 && ival <= -129")))
+
+; Low part constants for AND with a memory operand.
+; 0xFF01 (-255) to 0xFFFE (-2).
+(define_constraint	"Lam"	"Constants @minus{}255 @dots{} @minus{}2."
+   (and (match_code "const_int")
+	(match_test "ival >= -255 && ival <= -2")))
+
+; High part constants for IOR, XOR, PLUS and MINUS.
+(define_constraint	"Uo"	"Constants 0xXX00 except @minus{}256."
+   (and (match_code "const_int")
+	(match_test "ival != -256 && (ival & 0xFF) == 0")))
+
+; High part constants for AND.
+; Note that this matches -1 too, but is hopefully optimized away.
+(define_constraint	"Ua"	"Constants 0xXXFF."
+   (and (match_code "const_int")
+	(match_test "(ival & 0xFF) == 0xFF")))
+
+; Supported immediate shift counts.
+(define_constraint	"Ish"	"A constant usable as a shift count."
+   (and (match_code "const_int")
+	(match_test "TARGET_SHIFT_IMM ? true : ival == 1")))
+
+; Supported immediate multipliers for "aad".
+(define_constraint	"Iaa"	"A constant multiplier for the @code{aad} instruction."
+   (and (match_code "const_int")
+	(match_test "TARGET_AAD_IMM ? true : ival == 10")))
+
+; Supported immediate operands for "push".
+(define_constraint	"Ipu"	"A constant usable with the @code{push} instruction."
+   (and (match_code "const_int")
+	(match_test "TARGET_PUSH_IMM ? true : false")))
+
+; Supported immediate operands for "imul" except 257.
+(define_constraint	"Imu"	"A constant usable with the @code{imul} instruction except 257."
+   (and (match_code "const_int")
+	(match_test "TARGET_IMUL_IMM ? ival != 257 : false")))
+
+; Multiplying by 257 is cheap. High and low byte are both 1.
+(define_constraint	"I11"	"The constant 257."
+   (and (match_code "const_int")
+	(match_test "ival == 257")))
+
+; Supported immediate operands for "in" and "out".
+(define_constraint	"N"	"Unsigned 8-bit integer constant (for @code{in} and @code{out} instructions."
+   (and (match_code "const_int")
+	(match_test "ival >= 0 && ival <= 255")))
diff --git a/gcc/config/ia16/elf.h b/gcc/config/ia16/elf.h
new file mode 100644
index 0000000..b2238f0
--- /dev/null
+++ b/gcc/config/ia16/elf.h
@@ -0,0 +1,128 @@
+/* GNU Compiler Collection target macros for ia16-*-elf targets.
+   Copyright (C) 2007-2017 Free Software Foundation, Inc.
+   Contributed by Rask Ingemann Lambertsen <rask@sygehus.dk>
+   Changes by Andrew Jenner <andrew@codesourcery.com>
+   Very preliminary small code model support by TK Chia
+
+   This file is part of GCC.
+
+   GCC 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 3 of the License, or (at your option) any
+   later version.
+
+   GCC 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/licenses/>.
+*/
+
+/* Controlling the Compilation Driver, gcc.  */
+
+#define DRIVER_SELF_SPECS \
+  "%{melks-libc:-nostdinc}", \
+  "%{melks-libc|mdpmiable:%{!mno-protected-mode:-mprotected-mode}}", \
+  "%{melks-libc|mseparate-code-segment:%{mcmodel=*:;:-mcmodel=small}}", \
+  "%{mcmodel=small|mcmodel=medium:" \
+    "%{!mno-segment-relocation-stuff:-msegment-relocation-stuff}}", \
+  "%{mcmodel=medium:"	\
+    "%{melks-libc:%emedium model not supported for ELKS}}", \
+  "%{maout-total=*:"	\
+    "%{maout-chmem=*:%emay not use both -maout-total= and -maout-chmem=}}"
+
+/* This is a hack.  When -melks-libc is specified, then, combined with the
+   -nostdinc above, this hack will (try to) make GCC use the include files
+   under the -melks-libc multilib directory, rather than the Newlib include
+   files in the usual locations.
+
+   We also need to extend the hack to
+     * rope in the libgcc include directories --- via `include-fixed' ---
+       since elks-libc's headers use libgcc's.
+     * fall back on the include directories for the default calling
+       convention (.../ia16-elf/lib/elkslibc/include/), in case the user
+       says e.g. `-melks-libc -mregparmcall' and no include files are
+       installed specifically for this calling convention.
+
+   Again, this is a hack.  -- tkchia  */
+#define CPP_SPEC	\
+  "%{melks-libc:-isystem include-fixed/../include%s " \
+	       "-isystem include-fixed%s " \
+	       "-isystem include%s " \
+	       "-isystem elkslibc/include%s}" \
+  "%{mcmodel=medium:%{,c++|,c++-header:%emedium model not supported for C++}}"
+
+#define ASM_SPEC	\
+  "%{msegelf:--32-segelf}"
+
+/* For -nostdlib, -nodefaultlibs, and -nostartfiles:  arrange for the linker
+   script specification (%T...) to appear in LIB_SPEC if we are linking in
+   default libraries, but in LINK_SPEC if we are not (i.e. -nostdlib or
+   -nodefaultlibs).
+
+   If default libraries are used, then we want them to appear at the end of
+   the ld command line, so LIB_SPEC is the right place to use.
+
+   If default libraries are not used, then GCC will not use LIB_SPEC at all,
+   so we need to rely on LINK_SPEC to pass the linker script to ld.
+
+   As for the (undocumented) -r option:  I currently just arrange not to
+   pass any linker script at all if -r appears.  (FIXME: This only really
+   works if something like -nostdlib is also specified.  One is out of luck
+   if they would also like to link in startup files or default libraries
+   during -r.)  -- tkchia  */
+#define LINK_SPEC	\
+  "%{!T*:"		\
+    "%{mmsdos-handle-v1:-ldosv1} " \
+    "%{!r:"		\
+      "%{melks-libc:"	\
+	  "%Telks-%(cmodel_long_ld);" \
+	"nostdlib|nodefaultlibs:" \
+	"%{mdpmiable:"	\
+	    "%{nostdlib|nostartfiles:%Tdpm-m%(cmodel_ld);" \
+	      ":%Tdpm-m%(cmodel_s_ld)};" \
+	  "nostdlib|nostartfiles:" \
+	    "%Tdos-m%(cmodel_ld);" \
+	  ":%Tdos-m%(cmodel_s_ld)" \
+	"}"		\
+      "} "		\
+      "%{melks-libc:"	\
+	"%{maout-total=*:--defsym=_total=%*} " \
+	"%{maout-chmem=*:--defsym=_chmem=%*}}" \
+    "}"			\
+  "}"
+
+#define STARTFILE_SPEC	\
+  "%{melks-libc:-l:crt0.o}"
+
+#define ENDFILE_SPEC	\
+  ""
+
+#define LIB_SPEC	\
+  "%{melks-libc:-lc -lgcc;" \
+    "!T*:"		\
+    "%{!r:"		\
+      "%{!nostdlib:"	\
+	"%{!nodefaultlibs:" \
+	  "%{mnewlib-nano-stdio:" \
+	    "%{mnewlib-autofloat-stdio:-lanstdio} -lnstdio;" \
+	    "mnewlib-autofloat-stdio:-lastdio} " \
+	  "%{mdpmiable:" \
+	      "%{nostartfiles:%Tdpm-m%(cmodel_l_ld);:%Tdpm-m%(cmodel_sl_ld)};"\
+	    "nostartfiles:" \
+	      "%Tdos-m%(cmodel_l_ld);" \
+	    ":%Tdos-m%(cmodel_sl_ld)" \
+	  "}"		\
+	"}"		\
+      "}"		\
+    "}"			\
+  "}"
+
+#define EXTRA_SPECS	\
+  { "cmodel_ld", "%{mcmodel=medium:m.ld;mcmodel=small:s.ld;:t.ld}" }, \
+  { "cmodel_s_ld", "%{mcmodel=medium:ms.ld;mcmodel=small:ss.ld;:ts.ld}" }, \
+  { "cmodel_l_ld", "%{mcmodel=medium:ml.ld;mcmodel=small:sl.ld;:tl.ld}" }, \
+  { "cmodel_sl_ld", "%{mcmodel=medium:msl.ld;mcmodel=small:ssl.ld;:tsl.ld}" },\
+  { "cmodel_long_ld", "%{mcmodel=*:%*.ld;:tiny.ld}" }
diff --git a/gcc/config/ia16/elks.h b/gcc/config/ia16/elks.h
new file mode 100644
index 0000000..3db1072
--- /dev/null
+++ b/gcc/config/ia16/elks.h
@@ -0,0 +1,52 @@
+/* GNU Compiler Collection target macros for ia16-*-elks targets.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   Contributed by Rask Ingemann Lambertsen <rask@sygehus.dk>
+   Changes by Andrew Jenner <andrew@codesourcery.com>
+
+   This file is part of GCC.
+
+   GCC 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 3 of the License, or (at your option) any
+   later version.
+
+   GCC 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/licenses/>.
+*/
+
+/* This file is no longer used now.  The ELKS specs are now in elf.h.
+	-- tkchia 20190413  */
+
+/* Controlling the Compilation Driver, gcc.  */
+
+#define LINK_SPEC	\
+  ""
+
+#define LIB_SPEC        \
+  "-lc -lelks -lnosys "	\
+  "%{mseparate-code-segment:%Telks-separate.ld;:%Telks-combined.ld}"
+
+#define STARTFILE_SPEC  \
+  "crt0%O%s"
+
+#define ENDFILE_SPEC    \
+  ""
+
+/* Run-time Target Specification */
+#define TARGET_OS_CPP_BUILTINS()	\
+	do { builtin_define_std ("ELKS"); } while (0)
+
+#undef TARGET_OBJFMT_CPP_BUILTINS
+
+/* Macros Controlling Initialization Routines */
+/* We don't have .init/.fini support (yet).  */
+#undef  INIT_SECTION_ASM_OP
+
+/* Output of Assembler Instructions */
+#undef  USER_LABEL_PREFIX
+#define USER_LABEL_PREFIX "_"
diff --git a/gcc/config/ia16/ia16-builtins.c b/gcc/config/ia16/ia16-builtins.c
new file mode 100755
index 0000000..3f2a268
--- /dev/null
+++ b/gcc/config/ia16/ia16-builtins.c
@@ -0,0 +1,258 @@
+/* Machine-specific built-in functions for Intel 16-bit x86 target.
+   Copyright (C) 2018-2020 Free Software Foundation, Inc.
+   Contributed by TK Chia <https://github.com/tkchia/>
+
+   This file is part of GCC.
+
+   GCC 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 3 of the License, or (at your option) any
+   later version.
+
+   GCC 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/licenses/>.
+*/
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "rtl.h"
+#include "tree.h"
+#include "gimple.h"
+#include "cfgloop.h"
+#include "df.h"
+#include "tm_p.h"
+#include "expmed.h"
+#include "optabs.h"
+#include "regs.h"
+#include "emit-rtl.h"
+#include "diagnostic.h"
+#include "fold-const.h"
+#include "calls.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "output.h"
+#include "explow.h"
+#include "expr.h"
+#include "gimple-iterator.h"
+#include "tree-vectorizer.h"
+#include "builtins.h"
+#include "cfgrtl.h"
+#include "libiberty.h"
+#include "hashtab.h"
+#include "print-tree.h"
+#include "langhooks.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "varasm.h"
+#include "recog.h"
+
+tree ia16_builtin_decls[IA16_BUILTIN_MAX];
+
+void
+ia16_init_builtins (void)
+{
+  tree intSEG_type_node = unsigned_intHI_type_node, const_void_far_type_node,
+       const_void_far_ptr_type_node,
+       intSEG_ftype_intHI, unsigned_intHI_ftype_const_void_far_ptr,
+       intSEG_ftype_void, func;
+
+  /* With -mprotected-mode, we need a type node for PHImode for use with
+     __builtin_ia16_selector (), but there is no such existing node.  So
+     fashion one.  */
+  if (TARGET_PROTECTED_MODE)
+    {
+      intSEG_type_node = build_distinct_type_copy (unsigned_intHI_type_node);
+      SET_TYPE_MODE (intSEG_type_node, PHImode);
+    }
+  (*lang_hooks.types.register_builtin_type) (intSEG_type_node,
+					     "__builtin_ia16_segment_t");
+  const_void_far_type_node
+    = build_qualified_type (void_type_node,
+			    TYPE_QUAL_CONST
+			    | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_FAR));
+  const_void_far_ptr_type_node = build_pointer_type (const_void_far_type_node);
+
+  intSEG_ftype_intHI = build_function_type_list (intSEG_type_node,
+						 unsigned_intHI_type_node,
+						 NULL_TREE);
+  unsigned_intHI_ftype_const_void_far_ptr
+    = build_function_type_list (unsigned_intHI_type_node,
+				const_void_far_ptr_type_node, NULL_TREE);
+  intSEG_ftype_void = build_function_type (intSEG_type_node, void_list_node);
+
+  func = add_builtin_function ("__builtin_ia16_selector", intSEG_ftype_intHI,
+			       IA16_BUILTIN_SELECTOR, BUILT_IN_MD, NULL,
+			       NULL_TREE);
+  TREE_READONLY (func) = 1;
+  ia16_builtin_decls[IA16_BUILTIN_SELECTOR] = func;
+
+  func = add_builtin_function ("__builtin_ia16_FP_OFF",
+			       unsigned_intHI_ftype_const_void_far_ptr,
+			       IA16_BUILTIN_FP_OFF, BUILT_IN_MD, NULL,
+			       NULL_TREE);
+  TREE_READONLY (func) = 1;
+  ia16_builtin_decls[IA16_BUILTIN_FP_OFF] = func;
+
+  func = add_builtin_function ("__builtin_ia16_near_data_segment",
+			       intSEG_ftype_void,
+			       IA16_BUILTIN_NEAR_DATA_SEGMENT, BUILT_IN_MD,
+			       NULL, NULL_TREE);
+  TREE_READONLY (func) = 1;
+  ia16_builtin_decls[IA16_BUILTIN_NEAR_DATA_SEGMENT] = func;
+
+  func = add_builtin_function ("__builtin_ia16_ss",
+			       intSEG_ftype_void, IA16_BUILTIN_SS,
+			       BUILT_IN_MD, NULL, NULL_TREE);
+  TREE_READONLY (func) = 1;
+  ia16_builtin_decls[IA16_BUILTIN_SS] = func;
+}
+
+tree
+ia16_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
+{
+  if (code < IA16_BUILTIN_MAX)
+    return ia16_builtin_decls[code];
+  else
+    return error_mark_node;
+}
+
+rtx
+ia16_expand_builtin (tree expr, rtx target ATTRIBUTE_UNUSED,
+		     rtx subtarget ATTRIBUTE_UNUSED,
+		     machine_mode mode ATTRIBUTE_UNUSED,
+		     int ignore ATTRIBUTE_UNUSED)
+{
+  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (expr), 0), arg0;
+  rtx op0, res;
+  unsigned fcode = DECL_FUNCTION_CODE (fndecl);
+
+  switch (fcode)
+    {
+    case IA16_BUILTIN_SELECTOR:
+      arg0 = CALL_EXPR_ARG (expr, 0);
+      op0 = expand_normal (arg0);
+      return ia16_bless_selector (op0);
+
+    case IA16_BUILTIN_FP_OFF:
+      arg0 = CALL_EXPR_ARG (expr, 0);
+      op0 = expand_normal (arg0);
+      return ia16_far_pointer_offset (op0);
+
+    case IA16_BUILTIN_NEAR_DATA_SEGMENT:
+      res = ia16_data_seg_rtx ();
+      if (res)
+	return res;
+      /* fall through */
+
+    case IA16_BUILTIN_SS:
+      return gen_rtx_REG (SEGmode, SS_REG);
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
+static bool
+ia16_fp_off_foldable_for_as (addr_space_t as)
+{
+  return as == ADDR_SPACE_FAR || as == ADDR_SPACE_GENERIC;
+}
+
+tree
+ia16_fold_builtin (tree fndecl, int n_args, tree *args,
+		   bool ignore ATTRIBUTE_UNUSED)
+{
+  unsigned fcode = DECL_FUNCTION_CODE (fndecl);
+  tree op, name, fake, faketype, ptrtype;
+
+  switch (fcode)
+    {
+    case IA16_BUILTIN_SELECTOR:
+      gcc_assert (n_args == 1);
+      /* If -mprotected-mode is off, `__builtin_ia16_selector (seg)' is the
+	 same as `seg', so we can fold the call right here.  If not, pass
+	 the buck to ia16_expand_builtin (...) above.  */
+      if (TARGET_PROTECTED_MODE)
+	return NULL_TREE;
+      return args[0];
+
+    case IA16_BUILTIN_FP_OFF:
+      gcc_assert (n_args == 1);
+      /* Do a hack to handle the special case of using a far pointer's
+	 offset in a static initializer, like so:
+		void foo (void) __far;
+		static unsigned bar = __builtin_ia16_FP_OFF (foo);
+	 The FreeDOS kernel code does something like the above when installing
+	 its interrupt handlers.  */
+      op = args[0];
+
+      if (! TREE_CONSTANT (op))
+	return NULL_TREE;
+
+      /* Check if we are taking the address of a public, external, or static
+	 near/far function or near/far variable; if not, again hand over to
+	 ia16_expand_builtin (...).  First strip away layers of NOP_EXPR.
+
+	 TODO: generalize this to handle other types of far addresses.  */
+      while (TREE_CODE (op) == NOP_EXPR
+	     && POINTER_TYPE_P (TREE_TYPE (op))
+	     && ia16_fp_off_foldable_for_as (TYPE_ADDR_SPACE
+					     (TREE_TYPE (TREE_TYPE (op)))))
+	op = TREE_OPERAND (op, 0);
+
+      if (TREE_CODE (op) != ADDR_EXPR
+	  || ! POINTER_TYPE_P (TREE_TYPE (op))
+	  || ! ia16_fp_off_foldable_for_as (TYPE_ADDR_SPACE
+					    (TREE_TYPE (TREE_TYPE (op)))))
+	return NULL_TREE;
+
+      op = TREE_OPERAND (op, 0);
+      if (! VAR_OR_FUNCTION_DECL_P (op))
+	return NULL_TREE;
+      if (! DECL_EXTERNAL (op) && ! TREE_PUBLIC (op) && ! TREE_STATIC (op))
+	return NULL_TREE;
+      if (DECL_EXTERNAL (op) && flag_lto)
+	return NULL_TREE;
+
+      /* Mark the original declaration as addressable.  */
+      mark_addressable (op);
+
+      /* Create a fake "declaration" which aliases to the same assembler
+	 name, but which is placed in the generic address space.  Then take
+	 the address of that.  */
+      name = DECL_ASSEMBLER_NAME (op);
+      faketype = build_qualified_type (TREE_TYPE (op), TYPE_UNQUALIFIED);
+      fake = build_decl (UNKNOWN_LOCATION,
+			 VAR_P (op) ? VAR_DECL : FUNCTION_DECL,
+			 create_tmp_var_name ("__ia16_alias"), faketype);
+      DECL_ATTRIBUTES (fake) = tree_cons (get_identifier ("weakref"), NULL,
+					  DECL_ATTRIBUTES (fake));
+      DECL_ATTRIBUTES (fake)
+	= tree_cons (get_identifier ("alias"), tree_cons (NULL, name, NULL),
+		     DECL_ATTRIBUTES (fake));
+      TREE_STATIC (fake) = 1;
+      DECL_ARTIFICIAL (fake) = 1;
+      TREE_USED (fake) = 1;
+      assemble_alias (fake, name);
+
+      ptrtype = build_pointer_type_for_mode (faketype, HImode, true);
+      op = build_fold_addr_expr_with_type_loc (UNKNOWN_LOCATION, fake,
+					       ptrtype);
+      op = fold_build1 (NOP_EXPR, unsigned_intHI_type_node, op);
+      return op;
+
+    case IA16_BUILTIN_NEAR_DATA_SEGMENT:
+    case IA16_BUILTIN_SS:
+      return NULL_TREE;
+
+    default:
+      gcc_unreachable ();
+    }
+}
diff --git a/gcc/config/ia16/ia16-c.c b/gcc/config/ia16/ia16-c.c
new file mode 100644
index 0000000..59003d5
--- /dev/null
+++ b/gcc/config/ia16/ia16-c.c
@@ -0,0 +1,259 @@
+/* Subroutines used for macro/preprocessor support for Intel 16-bit x86.
+   Copyright (C) 2011-2016 Free Software Foundation, Inc.
+   Very preliminary IA-16 far pointer support and __IA16_* macros by TK Chia
+
+   This file is part of GCC.
+
+   GCC 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 3, or (at your option)
+   any later version.
+
+   GCC 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 GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "c-family/c-common.h"
+#include "c-family/c-pragma.h"
+#include "hard-reg-set.h"
+#include "output.h"
+
+static void
+def_macro (const char *name)
+{
+  cpp_define (parse_in, name);
+}
+
+static void
+def_or_undef_macro (const char *name, bool def_p)
+{
+  if (def_p)
+    def_macro (name);
+  else
+    cpp_undef (parse_in, name);
+}
+
+static void
+assert_or_unassert (const char *predicate, bool assert_p)
+{
+  if (assert_p)
+    cpp_assert (parse_in, predicate);
+  else
+    cpp_unassert (parse_in, predicate);
+}
+
+/* Implements TARGET_CPU_CPP_BUILTINS.  */
+void
+ia16_cpu_cpp_builtins (void)
+{
+  bool def_p;
+  char *defn;
+  int rv;
+
+  def_macro ("__ia16__=20200307L");
+  def_macro ("__FAR");
+  def_macro ("__SEG_SS");
+
+  /* Define macros corresponding to features supported in the chosen -march=
+     architecture.  Here I follow the ARM convention of defining macros with
+     names __*_FEATURE_*, since it seems clearer than the i386 convention of
+     using just the feature names.
+
+     I omit TARGET_TUNE_8BIT --- it does not denote a CPU capability, and
+     should probably be handled another way.  -- tkchia  */
+  def_or_undef_macro ("__IA16_FEATURE_SHIFT_IMM", TARGET_SHIFT_IMM);
+  def_or_undef_macro ("__IA16_FEATURE_PUSH_IMM", TARGET_PUSH_IMM);
+  def_or_undef_macro ("__IA16_FEATURE_IMUL_IMM", TARGET_IMUL_IMM);
+  def_or_undef_macro ("__IA16_FEATURE_PUSHA", TARGET_PUSHA);
+  def_or_undef_macro ("__IA16_FEATURE_ENTER_LEAVE", TARGET_ENTER_LEAVE);
+  def_or_undef_macro ("__IA16_FEATURE_SHIFT_MASKED", TARGET_SHIFT_MASKED);
+  def_or_undef_macro ("__IA16_FEATURE_AAD_IMM", TARGET_AAD_IMM);
+  def_or_undef_macro ("__IA16_FEATURE_FSTSW_AX", TARGET_FSTSW_AX);
+
+  /* If %ds is an allocatable register, define a macro to advertise this.  */
+  def_or_undef_macro ("__IA16_FEATURE_ALLOCABLE_DS_REG",
+		      TARGET_ALLOCABLE_DS_REG);
+
+  /* Define macros saying whether we are generating code for protected mode
+     operation, and for DPMI-able operation.  */
+  def_or_undef_macro ("__IA16_FEATURE_PROTECTED_MODE", TARGET_PROTECTED_MODE);
+  def_or_undef_macro ("__IA16_FEATURE_DPMIABLE", TARGET_DPMIABLE);
+
+  /* Define macros for various compiler features:
+       * far static variables
+       * far functions of the form `int foo (void) __far;'
+       * function calling conventions available through __attribute__ ((.))
+       * calling near functions from __attribute__ ((far_section)) functions
+       * __builtin_ia16_... (.) functions
+       * etc.  */
+  def_or_undef_macro ("__IA16_FEATURE_FAR_STATIC_STORAGE",
+		      ! TARGET_CMODEL_IS_TINY);
+  def_macro ("__IA16_FEATURE_FAR_FUNCTION_SYNTAX");
+  def_macro ("__IA16_FEATURE_ATTRIBUTE_CDECL");
+  def_macro ("__IA16_FEATURE_ATTRIBUTE_STDCALL");
+  def_macro ("__IA16_FEATURE_ATTRIBUTE_REGPARMCALL");
+  def_macro ("__IA16_FEATURE_ATTRIBUTE_ASSUME_DS_DATA");
+  def_macro ("__IA16_FEATURE_ATTRIBUTE_NO_ASSUME_DS_DATA");
+  def_macro ("__IA16_FEATURE_ATTRIBUTE_RESTORE_DS");
+  def_macro ("__IA16_FEATURE_ATTRIBUTE_ASSUME_SS_DATA");
+  def_macro ("__IA16_FEATURE_ATTRIBUTE_NO_ASSUME_SS_DATA");
+  def_macro ("__IA16_FEATURE_ATTRIBUTE_NEAR_SECTION");
+  def_macro ("__IA16_FEATURE_ATTRIBUTE_FAR_SECTION");
+  def_macro ("__IA16_FEATURE_FAR_SECTION_TO_NEAR_CALLS");
+  def_or_undef_macro ("__IA16_FEATURE_SEGMENT_RELOCATION_STUFF",
+		      TARGET_SEG_RELOC_STUFF);
+  def_or_undef_macro ("__IA16_FEATURE_NEWLIB_AUTOFLOAT_STDIO",
+		      TARGET_NEWLIB_AUTOFLOAT_STDIO);
+  def_macro ("__BUILTIN_IA16_SELECTOR");
+  def_macro ("__BUILTIN_IA16_FP_OFF");
+  def_macro ("__BUILTIN_IA16_NEAR_DATA_SEGMENT");
+  def_macro ("__BUILTIN_IA16_SS");
+
+  /* Also define macros to give the function calling convention settings
+     and/or the object file ABI variant in use (segelf vs. non-segelf),
+     as specified on the command line.  */
+  def_or_undef_macro ("__IA16_CALLCVT_CDECL",
+		      target_call_parm_cvt == CALL_PARM_CVT_CDECL);
+  def_or_undef_macro ("__IA16_CALLCVT_STDCALL",
+		      target_call_parm_cvt == CALL_PARM_CVT_STDCALL);
+  def_or_undef_macro ("__IA16_CALLCVT_REGPARMCALL",
+		      target_call_parm_cvt == CALL_PARM_CVT_REGPARMCALL);
+  def_or_undef_macro ("__IA16_CALLCVT_FAR_FUNCTION_IF_FAR_RETURN_TYPE",
+		      TARGET_FAR_FUNCTION_IF_FAR_RETURN_TYPE);
+  def_or_undef_macro ("__IA16_CALLCVT_ASSUME_DS_DATA", TARGET_ASSUME_DS_DATA);
+  def_or_undef_macro ("__IA16_CALLCVT_NO_ASSUME_DS_DATA",
+		      ! TARGET_ASSUME_DS_DATA);
+  def_or_undef_macro ("__IA16_CALLCVT_ASSUME_SS_DATA", TARGET_ASSUME_SS_DATA);
+  def_or_undef_macro ("__IA16_CALLCVT_NO_ASSUME_SS_DATA",
+		      ! TARGET_ASSUME_SS_DATA);
+  def_or_undef_macro ("__IA16_ABI_SEGELF", TARGET_ABI_SEGELF);
+
+  /* Since the `regparmcall' convention is still in a state of flux, I am
+     adding a crude versioning mechanism so that users can ask the compiler
+     which convention it is actually implementing...  */
+  def_macro ("__IA16_REGPARMCALL_ABI=20180814L");
+
+  /* Define macros corresponding to the chosen memory model.  I define both
+     an AArch64-style macro __IA16_CMODEL_{TINY | SMALL | ...}__, and a
+     simple __{TINY | SMALL | ...}__ macro as used in the classical Borland
+     C and Open Watcom compilers (and others).  -- tkchia */
+  def_p = (target_cmodel == CMODEL_TINY);
+  def_or_undef_macro ("__IA16_CMODEL_TINY__", def_p);
+  def_or_undef_macro ("__TINY__", def_p);
+  def_p = (target_cmodel == CMODEL_SMALL);
+  def_or_undef_macro ("__IA16_CMODEL_SMALL__", def_p);
+  def_or_undef_macro ("__SMALL__", def_p);
+  def_p = (target_cmodel == CMODEL_MEDIUM);
+  def_or_undef_macro ("__IA16_CMODEL_MEDIUM__", def_p);
+  def_or_undef_macro ("__MEDIUM__", def_p);
+  def_p = (target_cmodel == CMODEL_COMPACT);
+  def_or_undef_macro ("__IA16_CMODEL_COMPACT__", def_p);
+  def_or_undef_macro ("__COMPACT__", def_p);
+  def_p = (target_cmodel == CMODEL_LARGE);
+  def_or_undef_macro ("__IA16_CMODEL_LARGE__", def_p);
+  def_or_undef_macro ("__LARGE__", def_p);
+  def_p = (target_cmodel == CMODEL_HUGE);
+  def_or_undef_macro ("__IA16_CMODEL_HUGE__", def_p);
+  def_or_undef_macro ("__HUGE__", def_p);
+
+  /* Convenience macro.  */
+  def_or_undef_macro ("__IA16_CMODEL_IS_FAR_TEXT", TARGET_CMODEL_IS_FAR_TEXT);
+
+  /* Define a macro for the chosen -march=.  A source file can use this to
+     decide whether to employ a capability not covered by the
+     __IA16_FEATURE_* macros, e.g. the `arpl' or the `bound' instruction.
+
+     Following the practice for both the ARM and i386 ports, only one macro
+     is defined.  This means that for some features, a user may need to test
+     for several macros --- e.g. `bound' is supported if the compiler defines
+     either __IA16_ARCH_ANY_186, __IA16_ARCH_80186, __IA16_ARCH_NEC_V20,
+     __IA16_ARCH_NEC_V30, or __IA16_ARCH_I80286.
+
+     This is obviously clunky from the user's viewpoint, but I am not sure
+     what a _really_ good alternative might be.  -- tkchia  */
+  def_or_undef_macro ("__IA16_ARCH_ANY", target_arch == PROCESSOR_ANY);
+  def_or_undef_macro ("__IA16_ARCH_ANY_186", target_arch == PROCESSOR_ANY_186);
+  def_or_undef_macro ("__IA16_ARCH_I8086", target_arch == PROCESSOR_I8086);
+  def_or_undef_macro ("__IA16_ARCH_I8088", target_arch == PROCESSOR_I8088);
+  def_or_undef_macro ("__IA16_ARCH_NEC_V30", target_arch == PROCESSOR_NEC_V30);
+  def_or_undef_macro ("__IA16_ARCH_NEC_V20", target_arch == PROCESSOR_NEC_V20);
+  def_or_undef_macro ("__IA16_ARCH_I80186", target_arch == PROCESSOR_I80186);
+  def_or_undef_macro ("__IA16_ARCH_I80188", target_arch == PROCESSOR_I80188);
+  def_or_undef_macro ("__IA16_ARCH_I80286", target_arch == PROCESSOR_I80286);
+
+  /* Define a macro for the chosen -mtune=, for good measure.  */
+  def_or_undef_macro ("__IA16_TUNE_I8086", target_tune == PROCESSOR_I8086);
+  def_or_undef_macro ("__IA16_TUNE_I8088", target_tune == PROCESSOR_I8088);
+  def_or_undef_macro ("__IA16_TUNE_NEC_V30", target_tune == PROCESSOR_NEC_V30);
+  def_or_undef_macro ("__IA16_TUNE_NEC_V20", target_tune == PROCESSOR_NEC_V20);
+  def_or_undef_macro ("__IA16_TUNE_I80186", target_tune == PROCESSOR_I80186);
+  def_or_undef_macro ("__IA16_TUNE_I80188", target_tune == PROCESSOR_I80188);
+  def_or_undef_macro ("__IA16_TUNE_I80286", target_tune == PROCESSOR_I80286);
+
+  /* Define macros corresponding to the chosen target operating system.
+     Borland C apparently defines __MSDOS__, and Bruce's C compiler defines
+     either __MSDOS__ or __ELKS__.  */
+  def_or_undef_macro ("__ELKS__", TARGET_SYS_ELKS);
+  def_or_undef_macro ("__IA16_SYS_ELKS", TARGET_SYS_ELKS);
+  assert_or_unassert ("system=elks", TARGET_SYS_ELKS);
+  def_or_undef_macro ("__MSDOS__", TARGET_SYS_MSDOS);
+  def_or_undef_macro ("__IA16_SYS_MSDOS", TARGET_SYS_MSDOS);
+  assert_or_unassert ("system=msdos", TARGET_SYS_MSDOS);
+
+  /* If the user says -mnewlib-nano-stdio, try to pretend that <newlib.h>
+     defines _NANO_FORMATTED_IO (actually this just defines the macro whether
+     or not <newlib.h> is used).
+
+     Do not undefine _NANO_FORMATTED_IO if it is explicitly defined.  */
+  if (TARGET_NEWLIB_NANO_STDIO)
+    def_macro ("_NANO_FORMATTED_IO");
+
+  /* This is used by the ia16.h portion of the machine description to
+     implement CRT_CALL_STATIC_FUNCTION (, ).  */
+  if (! TARGET_CMODEL_IS_FAR_TEXT)
+    rv = asprintf (&defn, "__IA16___CRT_CALL_STATIC_FUNCTION(o,f)"
+			  "=__asm(o \"; call %s\" #f \"; .text\");",
+		   user_label_prefix);
+  else if (! TARGET_ABI_SEGELF)
+    rv = asprintf (&defn, "__IA16___CRT_CALL_STATIC_FUNCTION(o,f)"
+			  "=__asm(\".pushsection .text; "
+				   "\" o \"; "
+				   ".reloc .+3, R_386_OZSEG16, %s\" #f \"; "
+				   "lcall $0, $%s\" #f \"; "
+				   ".text; "
+				   ".popsection\");",
+		   user_label_prefix, user_label_prefix);
+  else
+    rv = asprintf (&defn, "__IA16___CRT_CALL_STATIC_FUNCTION(o,f)"
+			  "=__asm(\".pushsection .text; "
+				   "\" o \"; "
+				   ".reloc .+3, R_386_SEG16, "
+					  "\\\"%s\" #f \"!\\\"; "
+				   "lcall $0, $%s\" #f \"; "
+				   ".text; "
+				   ".popsection\");",
+		   user_label_prefix, user_label_prefix);
+
+  if (rv > 0)
+    {
+      def_macro (defn);
+      free (defn);
+    }
+}
+
+/* Implements REGISTER_TARGET_PRAGMAS.  */
+void
+ia16_register_pragmas (void)
+{
+  c_register_addr_space ("__far", ADDR_SPACE_FAR);
+  c_register_addr_space ("__seg_ss", ADDR_SPACE_SEG_SS);
+}
diff --git a/gcc/config/ia16/ia16-modes.def b/gcc/config/ia16/ia16-modes.def
new file mode 100644
index 0000000..3d4861e
--- /dev/null
+++ b/gcc/config/ia16/ia16-modes.def
@@ -0,0 +1,88 @@
+/* GNU Compiler Collection machine modes for target machine Intel 16-bit x86.
+   Copyright (C) 2005-2017 Free Software Foundation, Inc.
+   Contributed by Rask Ingemann Lambertsen <rask@sygehus.dk>
+   Changes by Andrew Jenner <andrew@codesourcery.com>
+   Changes by TK Chia
+
+   This file is part of GCC.
+
+   GCC 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 3 of the License, or (at your option) any
+   later version.
+
+   GCC 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/licenses/>.
+*/
+/* Please keep these definition in sync with ia16_hard_regno_nregs[][].  */
+
+VECTOR_MODE (INT, QI, 2);
+
+/* PHImode has the same range as HImode, but under -mprotected-mode it is
+   used to "mark" RTXs which can be loaded into segment registers.  */
+PARTIAL_INT_MODE (HI, 16, PHI);
+
+/* Comparison modes.  The basic CCmode contains all of the Sign,
+   Carry, Overflow and Zero flags.  The rest of the modes only contain
+   the flags implied by the mode name letters after the initial CC.  */
+
+/* EQ and NE need this mode.  */
+CC_MODE (CCZ);
+
+/* This mode is used when making an equality comparison using the carry flag
+   instead of the zero flag.  */
+CC_MODE (CCZ_C);
+
+/* This mode is used when making an equality comparison using the carry flag
+   instead of the zero flag and the carry flag is inverted.  */
+CC_MODE (CCZ_NC);
+
+/* LTU and GEU need this mode.  */
+CC_MODE (CCC);
+
+/* LEU and GTU need this mode.  */
+CC_MODE (CCCZ);
+
+/* This mode is for LEU and GTU when checking for overflow of subtraction.
+   Only the carry flag is set and it is negated.  */
+CC_MODE (CCCZ_NC);
+
+/* This mode is used when making an unsigned comparison against an immediate
+   and the result would normally require both carry and zero flags (LEU and
+   GTU). This mode may be used with the cmp instruction.  */
+CC_MODE (CCCZ_C);
+
+/* GE and LT need this mode.  */
+CC_MODE (CCSO);
+
+/* GT and LE need this mode.  */
+CC_MODE (CCSOZ);
+
+/* The following modes don't set the overflow flag.  Signed comparisons (LT, LE,
+   GT and GE) in these modes are only valid against zero.  They are therefore
+   incompatible with the ones which set both the sign and overflow flags.  */
+
+/* GE and LT can use this mode when comparing against zero.  */
+CC_MODE (CCS);
+
+/* As above, but instead of setting the sign flag, it sets the carry flag. The
+   sense of the carry flag is inverted.  */
+CC_MODE (CCS_NC);
+
+/* This mode is used when the zero and overflow flags aren't set correctly.
+   For example by SImode/DImode/TImode plus/minus patterns.  */
+CC_MODE (CCSC);
+
+/* GT and LE can use this mode when comparing against zero, but we seem to
+   have no jump instruction (in hardware) for it.
+   This mode is used by the inc/dec instructions.  */
+CC_MODE (CCSZ);
+
+/* This mode is used when the overflow flag isn't set correctly.
+   For example by the add/sub/neg instructions.  */
+CC_MODE (CCSCZ);
diff --git a/gcc/config/ia16/ia16-no-ss-data.c b/gcc/config/ia16/ia16-no-ss-data.c
new file mode 100755
index 0000000..edd4478
--- /dev/null
+++ b/gcc/config/ia16/ia16-no-ss-data.c
@@ -0,0 +1,379 @@
+/* Hacks for %ss != .data calling conventions for Intel 16-bit x86 target.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   Contributed by TK Chia <https://github.com/tkchia/>
+
+   This file is part of GCC.
+
+   GCC 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 3 of the License, or (at your option) any
+   later version.
+
+   GCC 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/licenses/>.
+*/
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "rtl.h"
+#include "tree.h"
+#include "df.h"
+#include "tm_p.h"
+#include "expmed.h"
+#include "optabs.h"
+#include "regs.h"
+#include "emit-rtl.h"
+#include "diagnostic.h"
+#include "fold-const.h"
+#include "calls.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "output.h"
+#include "explow.h"
+#include "expr.h"
+#include "builtins.h"
+#include "cfgrtl.h"
+#include "libiberty.h"
+#include "hashtab.h"
+#include "print-tree.h"
+#include "langhooks.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "varasm.h"
+#include "recog.h"
+
+/* XXX: deep black magic ahead.  */
+
+/* These pointers may be NULL-ified by the GCC garbage collector.  */
+struct target_rtl *ia16_ss_data_target_rtl = NULL,
+		  *ia16_no_ss_data_target_rtl = NULL;
+
+/* GCC invokes TARGET_LRA_P () some time after producing RTL, and just
+   before doing register allocation.
+
+   1) For %ss != .data, this is a good time to tag segment override terms ---
+      of the form `(unspec:HI [<data-seg-rtx>] UNSPEC_SEG_OVERRIDE)' ---
+      onto `(mem ...)' addresses that go to the generic address space.
+
+      (Exceptions are `(call (mem ...) ...)`, where the `(mem ...)' refer to
+      text segment addresses.)
+
+      To make sure that the <data-seg-rtx> is not eliminated or moved around
+      too much early on during RTL optimization (!), _and_ ensure that %ds
+      is properly restored on function exit:
+
+      a) I add a special-case hack to the "mov<mode>" insn pattern in ia16.md
+	 to `(use)' the <data-seg-rtx> whenever it is `(set)' (near the
+	 function entry); and
+
+      b) I add insns
+		(set (reg:SEG DS_REG) <data-seg-rtx>)
+		(use (reg:SEG DS_REG))
+	 at every place where the function may exit.
+
+   2) Also take this chance to look for any `(mem/u ...)' RTXs --- which
+      should refer to static constant memory --- that erroneously point into
+      the __seg_ss address space, and correct them to point into the generic
+      address space.
+
+      (FIXME: this latter correction should probably be done at an earlier
+      stage.  At least, it should happen before any RTL-level
+      optimizations.)  */
+static rtx
+ia16_rectify_mems (rtx x, enum rtx_code outer_code)
+{
+  const char *fmt;
+  int fmt_len, i;
+  enum rtx_code code;
+  bool copied = false;
+  rtx subx, new_subx;
+
+  if (! x)
+    return x;
+
+  code = GET_CODE (x);
+
+  if (code == MEM)
+    {
+      if (MEM_ADDR_SPACE (x) == ADDR_SPACE_SEG_SS && MEM_READONLY_P (x))
+	{
+	  x = shallow_copy_rtx (x);
+	  set_mem_addr_space (x, ADDR_SPACE_GENERIC);
+	  copied = true;
+	}
+
+      if (ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (x)) && outer_code != CALL)
+	{
+	  rtx addr = XEXP (x, 0);
+	  if (! ia16_have_seg_override_p (addr))
+	    {
+	      rtx data_seg = ia16_data_seg_rtx (), ovr;
+	      gcc_assert (data_seg);
+	      ovr = ia16_seg_override_term (data_seg);
+	      addr = gen_rtx_PLUS (HImode, addr, ovr);
+	      if (! copied)
+		{
+		  x = shallow_copy_rtx (x);
+		  copied = true;
+		}
+		XEXP (x, 0) = addr;
+	    }
+	}
+    }
+
+  fmt = GET_RTX_FORMAT (code);
+  fmt_len = GET_RTX_LENGTH (code);
+
+  for (i = 0; i < fmt_len; ++i)
+    {
+      switch (fmt[i])
+	{
+	case 'e':
+	  subx = XEXP (x, i);
+	  new_subx = ia16_rectify_mems (subx, code);
+	  if (new_subx != subx)
+	    {
+	      if (! copied)
+		{
+		  x = shallow_copy_rtx (x);
+		  copied = true;
+		}
+	      XEXP (x, i) = new_subx;
+	    }
+	  break;
+
+	case 'E':
+	  if (XVEC (x, i))
+	    {
+	      bool vec_copied = false;
+	      int vec_len = XVECLEN (x, i);
+	      int j;
+
+	      for (j = 0; j < vec_len; ++j)
+		{
+		  subx = XVECEXP (x, i, j);
+		  new_subx = ia16_rectify_mems (subx, code);
+		  if (new_subx != subx)
+		    {
+		      if (! copied)
+			{
+			  x = shallow_copy_rtx (x);
+			  copied = true;
+			}
+		      if (! vec_copied)
+			{
+			  XVEC (x, i) = shallow_copy_rtvec (XVEC (x, i));
+			  vec_copied = true;
+			}
+		      XVECEXP (x, i, j) = new_subx;
+		    }
+		}
+	    }
+	  break;
+
+	default:
+	  break;
+	}
+    }
+
+  return x;
+}
+
+static void
+add_ds_resets (void)
+{
+  rtx data_seg = ia16_data_seg_rtx ();
+  rtx ds_reg = gen_rtx_REG (SEGmode, DS_REG);
+  edge e;
+  edge_iterator ei;
+
+  FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
+    {
+      basic_block bb = e->src;
+      rtx_insn *insn = BB_END (bb),
+	       *set_insn = make_insn_raw (gen_rtx_SET (ds_reg, data_seg)),
+	       *use_insn = make_insn_raw (gen_rtx_USE (SEGmode, ds_reg));
+
+      while (insn != BB_HEAD (bb) && ! INSN_P (insn))
+	insn = PREV_INSN (insn);
+
+      if (INSN_P (insn)
+	  && (JUMP_P (insn)
+	      || (CALL_P (insn) && SIBLING_CALL_P (insn))))
+	{
+	  add_insn_before (set_insn, insn, bb);
+	  add_insn_before (use_insn, insn, bb);
+	}
+      else
+	{
+	  add_insn_after (set_insn, insn, bb);
+	  add_insn_after (use_insn, set_insn, bb);
+	}
+
+      df_insn_rescan (set_insn);
+      df_insn_rescan (use_insn);
+    }
+}
+
+bool
+ia16_lra_p (void)
+{
+  rtx_insn *insn;
+
+  if (! ia16_in_ss_data_function_p ())
+    {
+      for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+	{
+	  if (INSN_P (insn))
+	    {
+	      rtx pat = PATTERN (insn);
+	      rtx new_pat = ia16_rectify_mems (pat, GET_CODE (insn));
+	      if (new_pat != pat)
+		{
+		  PATTERN (insn) = new_pat;
+		  ia16_recog (insn);
+		  df_insn_rescan (insn);
+		}
+	    }
+	}
+
+      add_ds_resets ();
+    }
+
+  return true;
+}
+
+/* Given a type TYPE, return a version of the type which is in the __seg_ss
+   address space (unless TYPE is already in a non-generic address space, or
+   is void).  */
+static tree
+ia16_stackify_type (tree type)
+{
+  int quals;
+
+  if (! ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (type))
+      || VOID_TYPE_P (type))
+    return type;
+
+  quals = TYPE_QUALS_NO_ADDR_SPACE (type)
+	  | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_SEG_SS);
+
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      tree new_elem_type = ia16_stackify_type (TREE_TYPE (type));
+      type = build_array_type (new_elem_type, TYPE_DOMAIN (type));
+    }
+
+  return build_qualified_type (type, quals);
+}
+
+void
+ia16_override_abi_format (tree fndecl)
+{
+  tree parm;
+
+  if (! fndecl)
+    {
+#if 0
+      /* This often results in spurious warnings in cases where no actual
+	 function calls appear.  So just do nothing here, and rely on the
+	 other checking mechanisms in the back-end.  */
+      if (! TARGET_ASSUME_SS_DATA)
+	warning (OPT_Wmaybe_uninitialized, "unsupported: calling "
+		 "compiler support functions with %%ss != .data");
+#endif
+      return;
+    }
+
+  if (ia16_ss_data_function_type_p (TREE_TYPE (fndecl)))
+    return;
+
+  /* Make stack parameter declarations refer to the __seg_ss address space. */
+  for (parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm))
+    {
+      TREE_TYPE (parm) = ia16_stackify_type (TREE_TYPE (parm));
+      DECL_ARG_TYPE (parm) = ia16_stackify_type (DECL_ARG_TYPE (parm));
+    }
+}
+
+void
+ia16_insert_attributes (tree node, tree *attr_ptr ATTRIBUTE_UNUSED)
+{
+  /* For every non-static variable declaration in an __attribute__
+     ((no_assume_ss_data)) function, make it refer to the __seg_ss address
+     space rather than the generic space.
+
+     Stack spill slots etc. are handled by TARGET_SET_CURRENT_FUNCTION.  */
+  switch (TREE_CODE (node))
+    {
+    case PARM_DECL:
+    case VAR_DECL:
+      if (! ia16_in_ss_data_function_p ()
+	  && ! TREE_STATIC (node) && ! TREE_PUBLIC (node)
+	  && ! DECL_EXTERNAL (node))
+	TREE_TYPE (node) = ia16_stackify_type (TREE_TYPE (node));
+      break;
+
+    default:
+      break;
+    }
+}
+
+/* Return a pointer to a `struct target_rtl' with its mode_mem_attrs[]
+   structures specifying the address space AS.
+
+   For __attribute__ ((no_assume_ss_data)) functions, this fashions and uses
+   mode_mem_attrs[] structures which specify __seg_ss.  This causes
+   gen_rtx_MEM (, ) to return (mem ...) RTXs that refer to the __seg_ss
+   space on default.
+
+   Yep, this works, except when it does not.  */
+static struct target_rtl *
+ia16_target_rtl_as (addr_space_t as)
+{
+  int i;
+  struct target_rtl *r;
+
+  if (this_target_rtl->x_mode_mem_attrs[(int) VOIDmode]->addrspace == as)
+    return this_target_rtl;
+
+  r = ggc_alloc <target_rtl> ();
+  *r = *this_target_rtl;
+
+  for (i = 0; i < (int) MAX_MACHINE_MODE; ++i)
+    {
+      mem_attrs *as_attrs = ggc_alloc <mem_attrs> ();
+      *as_attrs = *this_target_rtl->x_mode_mem_attrs[i];
+      as_attrs->addrspace = as;
+      r->x_mode_mem_attrs[i] = as_attrs;
+    }
+
+  return r;
+}
+
+void
+ia16_set_current_function (tree decl)
+{
+  tree type = decl ? TREE_TYPE (decl) : NULL_TREE;
+  bool need_no_ss_data = ! ia16_ss_data_function_type_p (type);
+
+  if (! need_no_ss_data)
+    {
+      if (! ia16_ss_data_target_rtl)
+	ia16_ss_data_target_rtl = ia16_target_rtl_as (ADDR_SPACE_GENERIC);
+      this_target_rtl = ia16_ss_data_target_rtl;
+    }
+  else
+    {
+      if (! ia16_no_ss_data_target_rtl)
+	ia16_no_ss_data_target_rtl = ia16_target_rtl_as (ADDR_SPACE_SEG_SS);
+      this_target_rtl = ia16_no_ss_data_target_rtl;
+    }
+}
diff --git a/gcc/config/ia16/ia16-peepholes.md b/gcc/config/ia16/ia16-peepholes.md
new file mode 100644
index 0000000..7551ce8
--- /dev/null
+++ b/gcc/config/ia16/ia16-peepholes.md
@@ -0,0 +1,813 @@
+;  Peephole optimizations for Intel 16-bit x86.
+;  Copyright (C) 2005-2017 Free Software Foundation, Inc.
+;  Contributed by Rask Ingemann Lambertsen <rask@sygehus.dk>
+;  Changes by Andrew Jenner <andrew@codesourcery.com>
+;  Changes by TK Chia
+;
+;  This file is part of GCC.
+;
+;  GCC 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 3 of the License, or (at your option) any
+;  later version.
+;
+;  GCC 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/licenses/>.
+
+
+; Avoid changing the mode or register number of operands because this
+; prevents e.g. the rnreg pass from optimizing the code. Likewise,
+; avoid adding output operands.
+
+; TODO list
+; (This one might happen automatically when inc/dec CC is fixed.)
+; cmp $-1/$1, scratch_reg; je/jne -> inc/dec scratch_reg; je/jne
+
+; cmp $80/$8000, QI/HIdest; jb/ja -> (cmp $0, dest;) jns/js
+
+; From unwinde-dw2-fde.o (search_object):
+;     c78:       8b 76 ce                mov    -50(%bp),%si
+;     c7b:       2b 76 d4                sub    -44(%bp),%si
+;     c7e:       d1 fe                   sar    %si
+;     c80:       d1 e6                   shl    %si
+;     c82:       83 c6 04                add    $0x4,%si
+
+; Contents:
+; Move multiple peepholes.
+; Misc peepholes.
+; And with constants.
+; Far pointers, far addresses, and general 32-bit weirdness.
+; Handling the %ds ?= %ss problem.
+
+;; Move multiple peepholes.
+
+; Optimize "movb $12, mem; movb $34, mem+1" into "movw $3412, mem".
+; Optimize "movb $12, %cl; movb $34, %ch" into "movw $3412, %cx".
+; TODO: We want "xorw %dx" from "movb $0, %dl; movb $0, %dh".
+(define_peephole2
+  [(set (match_operand:QI 0 "nonimmediate_operand")
+	(match_operand:QI 2 "const_int_operand"))
+   (set (match_operand:QI 1 "nonimmediate_operand")
+	(match_operand:QI 3 "const_int_operand"))]
+  "(MEM_P (operands[0])
+      && MEM_P (operands[1])
+      && ia16_move_multiple_mem_p (QImode, operands[0], operands[1]))
+    || (REG_P (operands[0])
+      && REG_P (operands[1])
+      && ia16_move_multiple_reg_p (QImode, operands[0], operands[1]))"
+  [(parallel
+  [(set (match_dup 0) (match_dup 2))
+   (set (match_dup 1) (match_dup 3))]
+  )]
+)
+
+; Optimize "movb $12, mem+1; movb $34, mem" into "movw $1234, mem".
+; Optimize "movb $12, %ch; movb $34, %cl" into "movw $1234, %cx".
+; TODO: We want "xorw %dx" from "movb $0, %dh; movb $0, %dl".
+(define_peephole2
+  [(set (match_operand:QI 0 "nonimmediate_operand")
+	(match_operand:QI 2 "const_int_operand"))
+   (set (match_operand:QI 1 "nonimmediate_operand")
+	(match_operand:QI 3 "const_int_operand"))]
+  "(MEM_P (operands[0])
+      && MEM_P (operands[1])
+      && ia16_move_multiple_mem_p (QImode, operands[1], operands[0]))
+    || (REG_P (operands[0])
+      && REG_P (operands[1])
+      && ia16_move_multiple_reg_p (QImode, operands[1], operands[0]))"
+  [(parallel
+  [(set (match_dup 1) (match_dup 3))
+   (set (match_dup 0) (match_dup 2))]
+  )]
+)
+
+; Optimize "movb %al, mem; movb %ah, mem+1" into "movw %ax, mem".
+(define_peephole2
+  [(set (match_operand:QI 0 "memory_operand")
+	(match_operand:QI 2 "register_operand"))
+   (set (match_operand:QI 1 "memory_operand")
+	(match_operand:QI 3 "register_operand"))]
+  "ia16_move_multiple_mem_p (QImode, operands[0], operands[1])
+   && ia16_move_multiple_reg_p (QImode, operands[2], operands[3])"
+  [(parallel
+  [(set (match_dup 0) (match_dup 2))
+   (set (match_dup 1) (match_dup 3))]
+  )]
+)
+
+; Optimize "movb %ah, mem+1; movb %al, mem" into "movw %ax, mem".
+; For example foo() in testsuite/gcc.c-torture/execute/va-arg-22.c.
+(define_peephole2
+  [(set (match_operand:QI 0 "memory_operand")
+	(match_operand:QI 2 "register_operand"))
+   (set (match_operand:QI 1 "memory_operand")
+	(match_operand:QI 3 "register_operand"))]
+  "ia16_move_multiple_mem_p (QImode, operands[1], operands[0])
+   && ia16_move_multiple_reg_p (QImode, operands[3], operands[2])"
+  [(parallel
+  [(set (match_dup 1) (match_dup 3))
+   (set (match_dup 0) (match_dup 2))]
+  )]
+)
+
+; Optimize "movb %ah, mem; movb %al, mem+1" into "xchgb %al, %ah; movw %ax, mem"
+; if %al and %ah die here.
+(define_peephole2
+  [(set (match_operand:QI 0 "memory_operand")
+	(match_operand:QI 2 "register_operand"))
+   (set (match_operand:QI 1 "memory_operand")
+	(match_operand:QI 3 "register_operand"))]
+  "ia16_move_multiple_mem_p (QImode, operands[0], operands[1])
+   && ia16_move_multiple_reg_p (QImode, operands[3], operands[2])
+   && peep2_reg_dead_p (1, operands[2])
+   && peep2_reg_dead_p (2, operands[3])"
+  [(parallel
+  [(set (match_dup 2) (match_dup 3))
+   (set (match_dup 3) (match_dup 2))
+  ])
+   (parallel
+  [(set (match_dup 0) (match_dup 3))
+   (set (match_dup 1) (match_dup 2))]
+  )]
+)
+
+; Optimize "movb mem, %cl; movb mem+1, %ch" into "movw mem, %cx".
+(define_peephole2
+  [(set (match_operand:QI 0 "register_operand")
+	(match_operand:QI 2 "memory_operand"))
+   (set (match_operand:QI 1 "register_operand")
+	(match_operand:QI 3 "memory_operand"))]
+  "ia16_move_multiple_mem_p (QImode, operands[2], operands[3])
+   && ia16_move_multiple_reg_p (QImode, operands[0], operands[1])"
+  [(parallel
+  [(set (match_dup 0) (match_dup 2))
+   (set (match_dup 1) (match_dup 3))]
+  )]
+)
+
+; Optimize "movb mem+1, %ch; movb mem, %cl" into "movw mem, %cx".
+(define_peephole2
+  [(set (match_operand:QI 0 "register_operand")
+	(match_operand:QI 2 "memory_operand"))
+   (set (match_operand:QI 1 "register_operand")
+	(match_operand:QI 3 "memory_operand"))]
+  "ia16_move_multiple_mem_p (QImode, operands[3], operands[2])
+   && ia16_move_multiple_reg_p (QImode, operands[1], operands[0])"
+  [(parallel
+  [(set (match_dup 1) (match_dup 3))
+   (set (match_dup 0) (match_dup 2))]
+  )]
+)
+
+(define_insn "*load_multipleqi"
+  [(set (match_operand:QI 0 "register_operand" "=l")
+	(match_operand:QI 1 "nonregister_operand" "mn"))
+   (set (match_operand:QI 2 "register_operand" "=u")
+	(match_operand:QI 3 "nonregister_operand" "mn"))]
+  "reload_completed
+   && ((CONST_INT_P (operands[1]) && CONST_INT_P (operands[3]))
+      || (MEM_P (operands[1]) && MEM_P (operands[3])
+	 && ia16_move_multiple_mem_p (QImode, operands[1], operands[3])))
+   && ia16_move_multiple_reg_p (QImode, operands[0], operands[2])"
+{
+  operands[4] = simplify_gen_subreg (HImode, operands[0], QImode, 0);
+  if (CONST_INT_P (operands[1]) && CONST_INT_P (operands[3]))
+    operands[5] = gen_rtx_CONST_INT (HImode, (UINTVAL (operands[1]) & 0xff)
+				     + INTVAL (operands[3]) * 256);
+  else
+    operands[5] = widen_memory_access (operands[1], HImode, 0);
+  return "movw\t%5,\t%4";
+})
+
+(define_insn "*store_multipleqi"
+  [(set (match_operand:QI 0 "memory_operand" "=m")
+	(match_operand:QI 1 "nonmemory_operand" "ln"))
+   (set (match_operand:QI 2 "memory_operand" "=m")
+	(match_operand:QI 3 "nonmemory_operand" "un"))]
+  "reload_completed
+   && ((CONST_INT_P (operands[1]) && CONST_INT_P (operands[3]))
+      || (REG_P (operands[1]) && REG_P (operands[3])
+	 && ia16_move_multiple_reg_p (QImode, operands[1], operands[3])))
+   && ia16_move_multiple_mem_p (QImode, operands[0], operands[2])"
+{
+  if (CONST_INT_P (operands[1]) && CONST_INT_P (operands[3]))
+    operands[4] = gen_rtx_CONST_INT (HImode, (UINTVAL (operands[1]) & 0xff)
+				     + INTVAL (operands[3]) * 256);
+  else
+    operands[4] = simplify_gen_subreg (HImode, operands[1], QImode, 0);
+  operands[5] = widen_memory_access (operands[0], HImode, 0);
+  return "movw\t%4,\t%5";
+})
+
+; Optimize "movw mem, reg16; movw mem+2, %es" into "lesw mem, reg16".
+(define_peephole2
+  [(set (match_operand:HI 0 "nonsegment_register_operand")
+	(match_operand:HI 1 "memory_operand"))
+   (set (match_operand:SEG 2 "segment_register_operand")
+	(match_operand:SEG 3 "memory_operand"))]
+  "TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], REGNO (operands[0]))
+   && ia16_move_multiple_mem_p (HImode, operands[1], operands[3])"
+  [(parallel
+  [(set (match_dup 0) (match_dup 1))
+   (set (match_dup 2) (match_dup 3))]
+  )]
+)
+
+; Optimize "movw mem+2, %es; movw mem, reg16" into "lesw mem, reg16".
+(define_peephole2
+  [(set (match_operand:SEG 2 "segment_register_operand")
+	(match_operand:SEG 3 "memory_operand"))
+   (set (match_operand:HI 0 "nonsegment_register_operand")
+	(match_operand:HI 1 "memory_operand"))]
+  "TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], REGNO (operands[0]))
+   && ia16_move_multiple_mem_p (HImode, operands[1], operands[3])"
+  [(parallel
+  [(set (match_dup 0) (match_dup 1))
+   (set (match_dup 2) (match_dup 3))]
+  )]
+)
+
+; Try this optimization (from libgcc/udivmodsi4.o):
+;	movw	42(%bp),%ax	   lesw	42(%bp),%ax
+;	movw	%ax,	12(%bp)	-> movw	%ax,	12(%bp)
+;	movw	44(%bp),%es
+(define_peephole2
+  [(set (match_operand:HI 0 "nonsegment_register_operand")
+	(match_operand:HI 1 "memory_operand"))
+   (set (match_operand:MO 2 "memory_operand")
+	(match_operand:MO 3 "nonmemory_operand"))
+   (set (match_operand:SEG 4 "segment_register_operand")
+	(match_operand:SEG 5 "memory_operand"))]
+  "TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], REGNO (operands[0]))
+   && ia16_move_multiple_mem_p (HImode, operands[1], operands[5])
+   && !reg_overlap_mentioned_p (operands[4], operands[3])
+   && ia16_non_overlapping_mem_p (operands[2], operands[5])"
+  [(parallel
+  [(set (match_dup 0) (match_dup 1))
+   (set (match_dup 4) (match_dup 5))
+  ])
+   (set (match_dup 2) (match_dup 3))]
+)
+
+; Seen in many places (e.g. _udivdi3.o).
+; movw	mem1,	%tmp1		lesw	mem1,	%tmp1
+; movw	%tmp1,	mem2	->	movw	%tmp1,	mem2
+; movw	mem1+2,	%tmp2
+; movw	%tmp2,	mem3		movw	%es,	mem3
+(define_peephole2
+  [(match_scratch:HI 6 "e,!Rds")
+   (set (match_operand:HI 0 "nonsegment_register_operand")
+	(match_operand:HI 1 "memory_operand"))
+   (set (match_operand:HI 2 "memory_operand")
+	(match_dup 0))
+   (set (match_operand:HI 3 "register_operand")
+	(match_operand:HI 4 "memory_operand"))
+   (match_dup 6)
+   (set (match_operand:HI 5 "memory_operand")
+	(match_dup 3))]
+  "peep2_reg_dead_p (4, operands[3])
+   && ia16_move_multiple_mem_p (HImode, operands[1], operands[4])"
+  [(parallel
+  [(set (match_dup 0) (match_dup 1))
+   (set (match_dup 6) (match_dup 4))
+  ])
+   (set (match_dup 2) (match_dup 0))
+   (set (match_dup 5) (match_dup 6))]
+)
+
+; TODO: (libm _kernel_standard)
+; movw	mem1,	%es		lesw	mem1,	%tmp
+; movw	%es,	mem2	->	movw	%tmp,	mem2
+; movw	mem1+2,	%es
+; movw	%es,	mem3		movw	%es,	mem3
+
+(define_insn "*load_multiplehi"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+	(match_operand:HI 1 "memory_operand" "m"))
+   (set (match_operand:SEG 2 "segment_register_operand" "=Q")
+	(match_operand:SEG 3 "memory_operand" "m"))]
+  "reload_completed
+   && ia16_move_multiple_mem_p (HImode, operands[1], operands[3])"
+  "l%R2w\t%1,\t%0"
+)
+
+;; Misc peepholes.
+; Optimize "mov $0,reg" into "xor reg,reg" if we can clobber CC_REG.
+(define_peephole2
+  [(set (match_operand:MO 0 "register_operand" "")
+	(const_int 0))]
+  "TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], REGNO (operands[0]))
+   && peep2_regno_dead_p (1, CC_REG)"
+  [(parallel
+  [(set (match_dup 0) (const_int 0))
+   (clobber (reg:CC CC_REG))]
+   )]
+  ""
+)
+
+; Optimize EQ/NE comparison of a register against zero followed by a branch
+; from CCZ_Cmode to CCZ_mode, saving one byte.
+(define_peephole2
+  [(set (reg:CCZ_C CC_REG)
+	(compare:CCZ_C (match_operand:MO 0 "register_operand") (const_int 0)))
+   (set (pc) (if_then_else (any_cond_z (reg:CCZ_C CC_REG) (const_int 0))
+			   (label_ref (match_operand 1))
+			   (pc)))]
+  "peep2_regno_dead_p (2, CC_REG)"
+  [(set (reg:CCZ CC_REG) (compare:CCZ (match_dup 0) (const_int 0)))
+   (set (pc) (if_then_else (any_cond_z (reg:CCZ CC_REG) (const_int 0))
+			   (label_ref (match_dup 1))
+			   (pc)))]
+)
+
+; Similarly for LT/GE: Change CCS_NCmode into CCSmode.
+(define_peephole2
+  [(set (reg:CCS_NC CC_REG)
+	(compare:CCS_NC (match_operand:MO 0 "register_operand") (const_int 0)))
+   (set (pc) (if_then_else (any_cond_so (reg:CCS_NC CC_REG) (const_int 0))
+			   (label_ref (match_operand 1))
+			   (pc)))]
+  "peep2_regno_dead_p (2, CC_REG)"
+  [(set (reg:CCS CC_REG) (compare:CCS (match_dup 0) (const_int 0)))
+   (set (pc) (if_then_else (any_cond_so (reg:CCS CC_REG) (const_int 0))
+			   (label_ref (match_dup 1))
+			   (pc)))]
+)
+
+; Convert "add $-2, %sp" into "push %ds" and "add $-4, %sp" into
+; "push %ds; push %ds" when size matters.  Use pusha on i80186+.
+(define_insn "*subhi3_sp_const2_4_16_18_32"
+  [(set (reg:HI SP_REG)
+	(minus:HI (reg:HI SP_REG)
+		  (match_operand:HI 0 "const_int_operand" "n")))
+   (clobber (reg:CC CC_REG))]
+  "optimize_size && ((INTVAL (operands[0]) == 2 || INTVAL (operands[0]) == 4)
+   || (TARGET_PUSHA && (INTVAL (operands[0]) == 16 || INTVAL (operands[0]) == 18
+       || INTVAL (operands[0]) == 32)))"
+{
+  switch (INTVAL (operands[0]))
+    {
+      case 32:
+	return ("pusha\;pusha");
+      case 18:
+	return ("pushw\t%%ds\;pusha");
+      case 16:
+	return ("pusha");
+      case  4:
+	return ("pushw\t%%ds\;pushw\t%%ds");
+      case  2:
+	return ("pushw\t%%ds");
+      default:
+	gcc_unreachable ();
+    }
+})
+
+; Convert "add $2, %sp" into "pop %scratch" when optimizing for size.
+; Convert "add $4, %sp" into "pop %scratch; pop %scratch" when optimizing
+; for size.
+(define_peephole2
+  [(match_scratch:HI 1 "R")
+   (parallel [
+   (set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG)
+				 (match_operand:HI 0 "const_int_operand")))
+   (clobber (reg:CC CC_REG))]
+   )]
+   "optimize_size && ((INTVAL (operands[0]) == 2 || INTVAL (operands[0]) == 4))"
+  [(parallel
+  [(set (reg:HI SP_REG)	(plus:HI (reg:HI SP_REG) (match_dup 0)))
+   (clobber (match_dup 1))]
+   )]
+   ""
+)
+
+(define_insn "*addhi3_sp_const2_4"
+  [(set (reg:HI SP_REG)
+	(plus:HI (reg:HI SP_REG)
+		  (match_operand:HI 0 "const_int_operand" "n")))
+   (clobber (match_scratch:HI 1 "=T"))]
+  "optimize_size && reload_completed
+   && (INTVAL (operands[0]) == 2 || INTVAL (operands[0]) == 4)"
+{
+  switch (INTVAL (operands[0]))
+    {
+      case  4:
+	return ("popw\t%1\;popw\t%1");
+      case  2:
+	return ("popw\t%1");
+      default:
+	gcc_unreachable ();
+    }
+})
+
+
+; 'sub $-128, dest' is one byte shorter than 'add $128, dest'.
+; TODO Non-clobber versions.
+(define_peephole2
+	[(parallel
+	[(set (match_operand:MO 0 "nonimmediate_operand")
+	      (plus:MO (match_dup 0) (const_int 128)))
+	 (clobber (reg:CC CC_REG))]
+	)]
+	""
+	[(parallel
+	[(set (match_dup 0) (minus:MO (match_dup 0) (const_int -128)))
+	 (clobber (reg:CC CC_REG))]
+	)]
+	""
+)
+
+; 'add $-128, dest' is one byte shorter than 'sub $128, dest'.
+; TODO Non-clobber versions.
+(define_peephole2
+	[(parallel
+	[(set (match_operand:MO 0 "nonimmediate_operand")
+	      (minus:MO (match_dup 0) (const_int 128)))
+	 (clobber (reg:CC CC_REG))]
+	)]
+	""
+	[(parallel
+	[(set (match_dup 0) (plus:MO (match_dup 0) (const_int -128)))
+	 (clobber (reg:CC CC_REG))]
+	)]
+	""
+)
+
+; "and" can sign-extend an 8-bit immediate. "test" can't. Optimize
+; 0:	f7 c3 55 00	test	$0x55,%bx
+; 4:	89 c3		mov	%ax,%bx
+; 6:	75 xx		jne	xx <fubar>
+; into
+; 0:	83 e3 55	and	$0x55,%bx
+; 3:	89 c3		mov	%ax,%bx
+; 5:	75 xx		jne	xx <fubar>
+; when bx is a scratch register.
+; FIXME Documentation doesn't say you can't use constraints except in
+; match_scratch.
+;(define_peephole2
+;  [(set (reg:SET_CC CC_REG)
+;	(compare:SET_CC (and:MO (match_operand:MO 0 "register_operand")
+;				(match_operand:MO 1 "general_operand"))
+;			(const_int 0)))]
+;  "peep2_reg_dead_p (1, operands[0])"
+;  [(parallel
+;  [(set (reg:SET_CC CC_REG)
+;	(compare:SET_CC (and:MO (match_dup 0) (match_dup 1))
+;			(const_int 0)))
+;   (clobber (match_dup 0))]
+;  )]
+;  ""
+;)
+
+; Try to rewrite
+;	movw	$648,	%bp
+;	addw	%sp,	%bp
+;	movw	%sp,	%si
+;	movw	126(%si), %si
+;	leaw	-320(%bp,%si), %di
+; into
+;	movw	%sp,	%si
+;	movw	126(%si), %bp
+;	leaw	328(%bp,%si),%di
+; if %bp and %si die here. Reload generates this sequence.
+(define_peephole2
+  [(set (match_operand:HI 0 "register_operand")
+	(match_operand:HI 1 "const_int_operand"))
+   (parallel [
+   (set (match_dup 0) (plus:HI  (match_dup 0)
+				(match_operand:HI 2 "register_operand")))
+   (clobber (reg CC_REG))
+   ])
+   (set (match_operand:HI 5 "register_operand")	(match_dup 2))
+   (set (match_dup 5) (match_operand:HI 6 "general_operand"))
+   (set (match_operand:HI 3 "register_operand")
+	(plus:HI (plus:HI (match_dup 0) (match_dup 5))
+		 (match_operand:HI 4 "immediate_operand")))]
+  "!reg_mentioned_p (operands[0], operands[6])
+   && (rtx_equal_p (operands[0], operands[3])
+       || peep2_reg_dead_p (5, operands[0]))
+   && (rtx_equal_p (operands[5], operands[3])
+       || peep2_reg_dead_p (5, operands[5]))"
+  [(set (match_dup 5) (match_dup 2))
+   (set (match_dup 0) (match_dup 6))
+   (set (match_dup 3) (plus:HI  (plus:HI (match_dup 0) (match_dup 5))
+				(match_dup 7)))]
+{
+  operands[7] = plus_constant (HImode, operands[4], INTVAL (operands[1]));
+})
+
+; Try to rewrite
+;	movw	$1100,	%bp
+;	addw	%sp,	%bp
+;	movw	%cx,	%di	; optional
+;	leaw	-400(%bp,%di), %cx
+; into
+;	movw	%sp,	%bp
+;	movw 	%cx,	%di	; optional
+;	leaw	700(%bp,%di), %cx
+; if %bp dies here. This sequence is generated during reload.
+; TODO: Try to change "const_int_operand" into "immediate_operand".
+(define_peephole2
+  [(set (match_operand:HI 0 "register_operand")
+	(match_operand:HI 1 "const_int_operand"))
+   (parallel [
+   (set (match_dup 0) (plus:HI  (match_dup 0)
+				(match_operand:HI 2 "register_operand")))
+   (clobber (reg CC_REG))
+   ])
+   (set (match_operand:HI 5 "register_operand")
+	(match_operand:HI 6 "general_operand"))
+   (set (match_operand:HI 3 "register_operand")
+	(plus:HI (plus:HI (match_dup 0) (match_dup 5))
+		 (match_operand:HI 4 "immediate_operand")))]
+  "peep2_reg_dead_p (4, operands[0])"
+  [(set (match_dup 0) (match_dup 2))
+   (set (match_dup 5) (match_dup 6))
+   (set (match_dup 3)
+	(plus:HI (plus:HI (match_dup 0) (match_dup 5))
+		 (match_dup 7)))]
+{
+  operands[7] = plus_constant (HImode, operands[4], INTVAL (operands[1]));
+})
+
+(define_peephole2
+  [(set (match_operand:HI 0 "register_operand")
+	(match_operand:HI 1 "const_int_operand"))
+   (parallel [
+   (set (match_dup 0) (plus:HI  (match_dup 0)
+				(match_operand:HI 2 "register_operand")))
+   (clobber (reg CC_REG))
+   ])
+   (set (match_operand:HI 3 "register_operand")
+	(plus:HI (plus:HI (match_dup 0)
+			  (match_operand:HI 5 "register_operand"))
+		 (match_operand:HI 4 "immediate_operand")))]
+  "peep2_reg_dead_p (3, operands[0])"
+  [(set (match_dup 0) (match_dup 2))
+   (set (match_dup 3)
+	(plus:HI (plus:HI (match_dup 0) (match_dup 5))
+		 (match_dup 6)))]
+{
+  operands[6] = plus_constant (HImode, operands[4], INTVAL (operands[1]));
+})
+
+; For some oddball reason GCC sometimes outputs something like
+;	movw	$-28,	%dx
+;	addw	%bp,	%dx
+; when a
+;	leaw	-28(%bp), %dx
+; will do just fine.
+;
+; I am not sure what causes this, but it seems to tend to happen when the
+; user code needs to pass a parameter in a register (-mregparmcall).
+;
+; Anyway, rewrite such things here.
+(define_peephole2
+  [(set (match_operand:HI 0 "register_operand")
+	(match_operand:HI 1 "const_int_operand"))
+   (parallel [(set (match_dup 0) (plus:HI (match_dup 0) (reg:HI BP_REG)))
+	      (clobber (reg CC_REG))])]
+  "REGNO (operands[0]) != BP_REG"
+  [(set (match_dup 0) (plus:HI (reg:HI BP_REG) (match_dup 1)))]
+)
+
+; Try to rewrite
+;	movw	mem,	%ax
+;	addw	$2,	%ax
+;	movw	%ax,	mem
+; into
+;	addw	$2,	mem
+; if %ax dies here.
+;
+; Make sure that the intermediate register (%ax) cannot overlap with any
+; registers used in the mem --- namely, that it is also dead before the
+; `movw mem, ...'.
+(define_peephole2
+  [(set (match_operand:MO 0 "register_operand")
+	(match_operand:MO 1 "nonimmediate_nonsegment_operand"))
+   (parallel
+     [(set (match_dup 0)
+	   (any_arith3:MO (match_dup 0)
+			  (match_operand:MO 2 "const_int_operand")))
+      (clobber (reg:CC CC_REG))])
+   (set (match_dup 1) (match_dup 0))]
+  "peep2_reg_dead_p (0, operands[0])
+   && peep2_reg_dead_p (3, operands[0])"
+  [(parallel
+    [(set (match_dup 1)
+	  (any_arith3:MO (match_dup 1) (match_dup 2)))
+     (clobber (reg:CC CC_REG))])]
+  ""
+)
+
+; As above, but rather than (clobber ...) CC_REG, we (set ...) it for its ZF.
+(define_peephole2
+  [(set (match_operand:MO 0 "register_operand")
+	(match_operand:MO 1 "nonimmediate_nonsegment_operand"))
+   (parallel
+     [(set (reg:CCZ CC_REG)
+	   (compare:CCZ
+	     (any_arith3:MO (match_dup 0)
+			    (match_operand:MO 2 "const_int_operand"))
+	     (const_int 0)))
+      (set (match_dup 0)
+	   (any_arith3:MO (match_dup 0) (match_dup 2)))])
+   (set (match_dup 1) (match_dup 0))]
+  "peep2_reg_dead_p (0, operands[0])
+   && peep2_reg_dead_p (3, operands[0])"
+  [(parallel
+    [(set (reg:CCZ CC_REG)
+	  (compare:CCZ (any_arith3:MO (match_dup 1) (match_dup 2))
+		       (const_int 0)))
+     (set (match_dup 1)
+	  (any_arith3:MO (match_dup 1) (match_dup 2)))])]
+  ""
+)
+
+; Try to rewrite
+;	movw	%es,	%bx
+;	movw	%bx,	%es
+; into
+;	movw	%es,	%bx
+; This sequence is generated during reload, when far pointers are used in a
+; loop; this might be due to address -> pointer and pointer -> address
+; conversions.
+(define_peephole2
+  [(set (match_operand:MO 0 "nonsegment_register_operand")
+	(match_operand:MO 1 "register_operand"))
+   (set (match_dup 1) (match_dup 0))]
+  ""
+  [(set (match_dup 0) (match_dup 1))]
+  ""
+)
+
+; Try to rewrite
+;	movw	$128,	%ax
+;	movw	%ax,	%di
+; into
+;	movw	$128,	%di
+; if %ax dies here.
+(define_peephole2
+  [(set (match_operand:MO 0 "register_operand")
+	(match_operand:MO 1 "nonmemory_operand"))
+   (set (match_operand:MO 2 "nonsegment_register_operand") (match_dup 0))]
+  "peep2_reg_dead_p (2, operands[0])"
+  [(set (match_dup 2) (match_dup 1))]
+  ""
+)
+
+;; And with constants.
+
+; Recursive peepholes would help - xor reg,reg vs. mov $0,mem.
+
+; TODO: In unwind-dw2-fde.o (__register_frame_info_table_bases), we get:
+;      f7:       c7 47 08 00 00          movw   $0x0,8(%bx)
+;      fc:       80 4f 08 02             orb    $0x2,8(%bx)
+;     100:       81 4f 08 f8 07          orw    $0x7f8,8(%bx)
+; This should be just "movw $0x7fa, 8(%bx)".
+
+; TODO: Despite the pattern below, I still see sequences like this in
+; unwinde-dw2-fde.o (search_object):
+;    1145:       80 67 09 07             andb   $0x7,9(%bx)
+;    1149:       81 67 0a 00 f8          andw   $0xf800,10(%bx)
+;    114e:       80 67 0b 07             andb   $0x7,11(%bx)
+
+; Optimize "and $-x, dest; and $x-1, dest" into "mov $0, dest".
+; TODO: This should be machine independent.
+(define_peephole2
+  [(parallel
+  [(set (match_operand:MO 0 "nonimmediate_operand")
+	(and:MO (match_dup 0)
+		(match_operand:MO 1 "immediate_operand")))
+   (clobber (reg:CC CC_REG))
+   ])
+   (parallel [
+   (set (match_dup 0) (and:MO (match_dup 0)
+			      (match_operand:MO 2 "immediate_operand")))
+   (clobber (reg:CC CC_REG))]
+   )]
+   "INTVAL (operands[1]) + INTVAL (operands[2]) == -1"
+   [(set (match_dup 0) (const_int 0))]
+   ""
+)
+
+(define_insn "*andhi3_const255_noclobber"
+	[(set (match_operand:HI 0 "nonimmediate_operand" "=qm")
+	      (and:HI (match_operand:HI 1 "nonimmediate_operand" "0")
+	              (const_int 255)))]
+	""
+{
+	return "movb\t$0,\t%H0";
+})
+
+; Optimize "movw mem, reg; andw $x, reg" into "movb mem, reg; andw $x, reg"
+; for x & 0xff00 == 0 to speed up execution on 8-bit CPUs.
+; This can't really be done before reload because pseudos may turn out to be
+; memory and thus miss this optimization.
+(define_peephole2
+  [(set (match_operand:HI 0 "register_operand")
+  	(match_operand:HI 1 "memory_operand"))
+   (parallel [
+   (set (match_dup 0) (and:HI (match_dup 0)
+  			      (match_operand:HI 2 "const_int_operand")))
+   (clobber (reg:CC CC_REG))]
+   )]
+  "(INTVAL (operands[2]) & 0xff00) == 0
+   && TEST_HARD_REG_BIT (reg_class_contents[LO_QI_REGS], REGNO (operands[0]))"
+  [(clobber (match_dup 3))
+   (set (match_dup 4)
+  	(match_dup 5))
+   (parallel [
+   (set (match_dup 0) (and:HI (match_dup 0)
+  			      (match_operand:HI 2 "const_int_operand")))
+   (clobber (reg:CC CC_REG))]
+   )]
+{
+  operands[3] = simplify_gen_subreg (QImode, operands[0], HImode, 1);
+  operands[4] = simplify_gen_subreg (QImode, operands[0], HImode, 0);
+  operands[5] = simplify_gen_subreg (QImode, operands[1], HImode, 0);
+})
+
+;; Far pointers, far addresses, and general 32-bit weirdness.
+
+; Try to rewrite
+;	movw	%es,	%bx
+;   [	movw	%bx,	%es	]
+;	movw	mem,	%bx
+; into
+;	movw	mem,	%bx
+; This happens during reload, when far pointers are used in a loop.  Make
+; sure that %bx does not overlap with any registers used in mem.
+(define_peephole2
+  [(set (match_operand:SEG 0 "register_operand")
+	(match_operand:SEG 1 "segment_register_operand"))
+   (set (match_dup 0) (match_operand:SEG 2 "memory_operand"))]
+  "peep2_reg_dead_p (1, operands[0])"
+  [(set (match_dup 0) (match_dup 2))]
+  ""
+)
+
+;	movw	6(%bp),	%bx
+;	movw	8(%bp),	%ax	->	lesw	6(%bp), %bx
+;	movw	%ax,	%es
+; if %ax and %bx are already dead, and %ax dies again.
+(define_peephole2
+  [(set (match_operand:HI 0 "nonsegment_register_operand")
+	(match_operand:HI 1 "memory_operand"))
+   (set (match_operand:SEG 2 "nonsegment_register_operand")
+	(match_operand:SEG 3 "memory_operand"))
+   (set (match_operand:SEG 4 "segment_register_operand") (match_dup 2))]
+  "reload_completed
+   && peep2_reg_dead_p (0, operands[0])
+   && peep2_reg_dead_p (0, operands[2])
+   && peep2_reg_dead_p (3, operands[2])
+   && ia16_move_multiple_mem_p (HImode, operands[1], operands[3])"
+  [(parallel
+    [(set (match_dup 0) (match_dup 1))
+     (set (match_dup 4) (match_dup 3))]
+  )]
+  ""
+)
+
+;	movw	6(%bp),	%bx
+;	movw	8(%bp),	%si	->	lesw	6(%bp), %bx
+;	movw	%si,	%es		movw	%es,	%si
+; if %bx and %si are already dead, but %si goes live again later.
+(define_peephole2
+  [(set (match_operand:HI 0 "nonsegment_register_operand")
+	(match_operand:HI 1 "memory_operand"))
+   (set (match_operand:SEG 2 "nonsegment_register_operand")
+	(match_operand:SEG 3 "memory_operand"))
+   (set (match_operand:SEG 4 "segment_register_operand") (match_dup 2))]
+  "reload_completed
+   && peep2_reg_dead_p (0, operands[0])
+   && peep2_reg_dead_p (0, operands[2])
+   && ! peep2_reg_dead_p (3, operands[2])
+   && ia16_move_multiple_mem_p (HImode, operands[1], operands[3])"
+  [(parallel
+    [(set (match_dup 0) (match_dup 1))
+     (set (match_dup 4) (match_dup 3))])
+   (set (match_dup 2) (match_dup 4))]
+  ""
+)
+
+;; Handling the %ds ?= .data problem.
+
+; Insn to reset %ds = .data, via %ss, before a function call or just before
+; a function return, when (the default) -mcallee-assume-ds-data and
+; -mcallee-assume-ss-data are in effect.
+;
+; Instead of writing out the unwieldy `pushw %ss' and `popw %ds' RTXs, I
+; define a new insn which does the same thing at the x86 code level, but has
+; a simpler RTL representation.
+;
+; TODO: allow rewriting this insn as `movw %ss, %tmp; movw %tmp, %ds'.
+(define_insn "_mov<mode>_ds_ss_slow"
+  [(set (reg:SEG DS_REG) (reg:SEG SS_REG))]
+  ""
+  "pushw\t%%ss\;popw\t%%ds"
+)
diff --git a/gcc/config/ia16/ia16-protos.h b/gcc/config/ia16/ia16-protos.h
new file mode 100644
index 0000000..c4058ed
--- /dev/null
+++ b/gcc/config/ia16/ia16-protos.h
@@ -0,0 +1,107 @@
+/* GNU Compiler Collection prototypes for target machine Intel 16-bit x86.
+   Copyright (C) 2005-2020 Free Software Foundation, Inc.
+   Contributed by Rask Ingemann Lambertsen <rask@sygehus.dk>
+   Changes by Andrew Jenner <andrew@codesourcery.com>
+   Very preliminary IA-16 far pointer support and other changes by TK Chia
+
+   This file is part of GCC.
+
+   GCC 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 3 of the License, or (at your option) any
+   later version.
+
+   GCC 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/licenses/>.
+*/
+
+extern struct gcc_target targetm;
+extern unsigned char	ia16_hard_regno_nregs[17][FIRST_PSEUDO_REGISTER];
+extern enum reg_class const ia16_regno_class[FIRST_PSEUDO_REGISTER];
+extern int		ia16_regno_in_class_p (unsigned, unsigned);
+extern int		ia16_save_reg_p (unsigned);
+extern tree		ia16_get_function_type_for_addr (rtx);
+extern rtx		ia16_data_seg_rtx (void);
+extern int		ia16_in_far_function_p (void);
+extern int		ia16_ds_data_function_type_p (const_tree funtype);
+extern int		ia16_restore_ds_function_type_p (const_tree funtype);
+extern int		ia16_ss_data_function_type_p (const_tree funtype);
+extern int		ia16_ds_data_function_rtx_p (rtx);
+extern int		ia16_restore_ds_function_rtx_p (rtx);
+extern int		ia16_in_ds_data_function_p (void);
+extern int		ia16_in_restore_ds_function_p (void);
+extern int		ia16_in_ss_data_function_p (void);
+extern void		ia16_recog (rtx_insn *insn);
+extern bool		ia16_have_seg_override_p (rtx x);
+extern rtx		ia16_bless_selector (rtx seg);
+extern rtx		ia16_seg_override_term (rtx seg);
+extern void		ia16_override_abi_format (tree fndecl);
+extern HOST_WIDE_INT	ia16_first_parm_offset (tree fundecl);
+extern HOST_WIDE_INT	ia16_initial_frame_pointer_offset (void);
+extern HOST_WIDE_INT
+		ia16_initial_elimination_offset (unsigned int from,
+						 unsigned int to);
+extern void	ia16_init_cumulative_args (CUMULATIVE_ARGS *, const_tree, rtx,
+					   const_tree tree, int);
+extern enum machine_mode
+		ia16_cc_modes_compatible (enum machine_mode mode1,
+					  enum machine_mode mode2);
+
+extern rtx	ia16_expand_weird_pointer_plus_expr (rtx op0, rtx op1,
+						     rtx target,
+						     machine_mode mode);
+extern rtx	ia16_as_convert_weird_memory_address (machine_mode to_mode,
+						      rtx x, addr_space_t as,
+						      bool in_const,
+						      bool no_emit);
+extern void	ia16_split_seg_override_and_offset (rtx x, rtx *ovr, rtx *off);
+
+#ifdef RTX_CODE
+extern void	ia16_initialize_trampoline (rtx addr, rtx fnaddr,
+					    rtx static_chain);
+extern bool	ia16_parse_address (rtx e, rtx *p_r1, rtx *p_r2, rtx *p_c,
+				    rtx *p_r9, addr_space_t as);
+extern bool	ia16_parse_address_strict (rtx x, rtx *p_rb, rtx *p_ri,
+					   rtx *p_c, rtx *p_rs,
+					   addr_space_t as);
+#endif
+extern rtx	ia16_push_reg (unsigned int regno);
+extern rtx	ia16_pop_reg (unsigned int regno);
+#ifdef RTX_CODE
+extern rtx	ia16_far_pointer_offset (rtx op);
+extern enum machine_mode
+		ia16_select_cc_mode (enum rtx_code op, rtx x, rtx y,
+				     bool branch);
+extern int	ia16_branch_cost (bool speed_p, bool predictable_p);
+extern rtx	ia16_gen_compare_reg (enum rtx_code op, rtx x, rtx y,
+				      bool branch);
+extern bool	ia16_arith_operands_p (enum rtx_code code, rtx *operands);
+extern rtx	ia16_prepare_operands (enum rtx_code, rtx *operands);
+extern bool	ia16_move_multiple_mem_p (enum machine_mode mode, rtx m1,
+					  rtx m2);
+extern bool	ia16_move_multiple_reg_p (enum machine_mode mode, rtx r1,
+					  rtx r2);
+extern bool	ia16_non_overlapping_mem_p (rtx m1, rtx m2);
+#endif
+
+extern void	ia16_expand_prologue (void);
+extern void	ia16_expand_reset_ds_for_call (rtx addr);
+extern void	ia16_expand_reset_ds_for_return (void);
+extern void	ia16_expand_epilogue (bool sibcall);
+extern const char *
+		ia16_get_call_expansion (rtx, machine_mode, unsigned);
+extern bool	ia16_use_far_thunked_call_p (rtx, machine_mode);
+extern const char *
+		ia16_get_far_thunked_call_expansion (unsigned, bool);
+extern const char *
+		ia16_get_sibcall_expansion (rtx, machine_mode, unsigned);
+extern void	ia16_asm_output_addr_diff_elt (FILE *, rtx, int, int);
+extern void	ia16_asm_output_addr_vec_elt (FILE *, int);
+
+extern void	ia16_cpu_cpp_builtins (void);
+extern void	ia16_register_pragmas (void);
diff --git a/gcc/config/ia16/ia16-reorg.c b/gcc/config/ia16/ia16-reorg.c
new file mode 100755
index 0000000..bd7646e
--- /dev/null
+++ b/gcc/config/ia16/ia16-reorg.c
@@ -0,0 +1,1323 @@
+/* Machine-dependent reorganization pass for Intel 16-bit x86 target.
+   Copyright (C) 2018-2020 Free Software Foundation, Inc.
+   Contributed by TK Chia <https://github.com/tkchia/>
+
+   This file is part of GCC.
+
+   GCC 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 3 of the License, or (at your option) any
+   later version.
+
+   GCC 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/licenses/>.
+*/
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "rtl.h"
+#include "tree.h"
+#include "df.h"
+#include "tm_p.h"
+#include "expmed.h"
+#include "optabs.h"
+#include "regs.h"
+#include "emit-rtl.h"
+#include "diagnostic.h"
+#include "fold-const.h"
+#include "calls.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "output.h"
+#include "explow.h"
+#include "expr.h"
+#include "builtins.h"
+#include "cfgrtl.h"
+#include "libiberty.h"
+#include "hashtab.h"
+#include "print-tree.h"
+#include "langhooks.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "varasm.h"
+#include "recog.h"
+
+static int
+ia16_ss_data_function_rtx_p (rtx addr)
+{
+  tree type = ia16_get_function_type_for_addr (addr);
+  return ia16_ss_data_function_type_p (type);
+}
+
+/* If we are in an __attribute__ ((no_assume_ds_data)) function, and %ds is
+   fixed, check whether it calls any __attribute__ ((assume_ds_data))
+   functions.  Flag warnings if it does.  */
+static void
+ia16_verify_calls_from_no_assume_ds (void)
+{
+  rtx_insn *insn;
+
+  if (TARGET_ALLOCABLE_DS_REG
+      || ia16_in_ds_data_function_p ())
+    return;
+
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    {
+      if (CALL_P (insn))
+	{
+	  rtx call = get_call_rtx_from (insn);
+	  rtx callee = XEXP (XEXP (call, 0), 0);
+	  if (ia16_ds_data_function_rtx_p (callee))
+	      warning_at (LOCATION_LOCUS (INSN_LOCATION (insn)),
+			  OPT_Wmaybe_uninitialized,
+			  "%%ds is fixed, not resetting %%ds for call to "
+			  "assume_ds_data function");
+	}
+    }
+}
+
+/* If we are in an __attribute__ ((no_assume_ss_data)) function,
+   check whether it calls any __attribute__ ((assume_ss_data)) functions. 
+   Flag warnings if it does.  */
+static void
+ia16_verify_calls_from_no_assume_ss (void)
+{
+  rtx_insn *insn;
+
+  if (ia16_in_ss_data_function_p ())
+    return;
+
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    {
+      if (CALL_P (insn))
+	{
+	  rtx call = get_call_rtx_from (insn);
+	  rtx callee = XEXP (XEXP (call, 0), 0);
+	  if (ia16_ss_data_function_rtx_p (callee))
+	      warning_at (LOCATION_LOCUS (INSN_LOCATION (insn)),
+			  OPT_Wmaybe_uninitialized,
+			  "calling assume_ss_data function when "
+			  "%%ss may not point to data segment");
+	}
+    }
+}
+
+/* Say whether an RTX operand is the %bp register.  */
+static bool
+ia16_operand_is_bp_reg_p (rtx op)
+{
+  return REG_P (op) && REGNO (op) == BP_REG && GET_MODE (op) == HImode;
+}
+
+/* Say whether an RTX operand is the %sp register.  */
+static bool
+ia16_operand_is_sp_reg_p (rtx op)
+{
+  return REG_P (op) && REGNO (op) == SP_REG && GET_MODE (op) == HImode;
+}
+
+/* Say whether an RTX insn pattern is a (clobber (reg CC_REG)).  */
+static bool
+ia16_pattern_is_clobber_cc_reg_p (rtx pat)
+{
+  rtx op;
+  if (GET_CODE (pat) != CLOBBER)
+    return false;
+  op = SET_DEST (pat);
+  return REG_P (op) && REGNO (op) == CC_REG;
+}
+
+/* Say whether an insn is a `pushw %bp' in a prologue.  */
+static bool
+ia16_insn_is_prologue_pushw_bp_p (rtx_insn *insn)
+{
+  rtx pat, pat0;
+
+  if (! INSN_P (insn)
+      || ! RTX_FRAME_RELATED_P (insn)
+      || INSN_CODE (insn) != CODE_FOR__pushhi1_nonimm)
+    return false;
+
+  pat = PATTERN (insn);
+  gcc_assert (GET_CODE (pat) == PARALLEL);
+
+  pat0 = XVECEXP (pat, 0, 0);
+  gcc_assert (GET_CODE (pat0) == SET);
+
+  return ia16_operand_is_bp_reg_p (SET_SRC (pat0));
+}
+
+/* Say whether an insn is a `movw %sp, %bp' in a prologue.  */
+static bool
+ia16_insn_is_prologue_movw_sp_bp_p (rtx_insn *insn)
+{
+  rtx pat = PATTERN (insn);
+
+  return INSN_P (insn)
+	 && RTX_FRAME_RELATED_P (insn)
+	 && GET_CODE (pat) == SET
+	 && ia16_operand_is_bp_reg_p (SET_DEST (pat))
+	 && ia16_operand_is_sp_reg_p (SET_SRC (pat));
+}
+
+/* Say whether an insn is a `subw $CONST_INT, %sp' in a prologue.  If so,
+   also say what the CONST_INT is.  */
+static bool
+ia16_insn_is_prologue_subw_const_sp_p (rtx_insn *insn, HOST_WIDE_INT *p_value)
+{
+  rtx pat, pat0, pat0_src, pat1;
+
+  if (! INSN_P (insn) || ! RTX_FRAME_RELATED_P (insn))
+    return false;
+
+  pat = PATTERN (insn);
+  if (GET_CODE (pat) != PARALLEL || XVECLEN (pat, 0) != 2)
+    return false;
+
+  pat0 = XVECEXP (pat, 0, 0);
+  pat1 = XVECEXP (pat, 0, 1);
+
+  if (GET_CODE (pat0) != SET
+      || ! ia16_operand_is_sp_reg_p (SET_DEST (pat0))
+      || ! ia16_pattern_is_clobber_cc_reg_p (pat1))
+    return false;
+
+  pat0_src = SET_SRC (pat0);
+  if (GET_CODE (pat0_src) != MINUS
+      || ! ia16_operand_is_sp_reg_p (XEXP (pat0_src, 0))
+      || ! CONST_INT_P (XEXP (pat0_src, 1)))
+    return false;
+
+  *p_value = INTVAL (XEXP (pat0_src, 1));
+  return true;
+}
+
+/* Say whether an insn is a `popw %bp'.  */
+static bool
+ia16_insn_is_popw_bp_p (rtx_insn *insn)
+{
+  rtx pat;
+
+  if (! INSN_P (insn) || INSN_CODE (insn) != CODE_FOR__pophi1)
+    return false;
+  pat = PATTERN (insn);
+  gcc_assert (GET_CODE (pat) == SET);
+  return ia16_operand_is_bp_reg_p (SET_DEST (pat));
+}
+
+/* Say whether an RTX corresponds to an expression which performs arithmetic
+   on registers without altering them.  */
+static bool
+ia16_rtx_is_pure_reg_arith_p (rtx x)
+{
+  switch (GET_RTX_CLASS (GET_CODE (x)))
+    {
+    case RTX_OBJ:
+      return REG_P (x);
+
+    case RTX_CONST_OBJ:
+      return true;
+
+    case RTX_UNARY:
+      return ia16_rtx_is_pure_reg_arith_p (XEXP (x, 0));
+
+    case RTX_COMPARE:
+    case RTX_COMM_COMPARE:
+    case RTX_COMM_ARITH:
+    case RTX_BIN_ARITH:
+      return ia16_rtx_is_pure_reg_arith_p (XEXP (x, 0))
+	     && ia16_rtx_is_pure_reg_arith_p (XEXP (x, 1));
+
+    case RTX_BITFIELD_OPS:
+    case RTX_TERNARY:
+      return ia16_rtx_is_pure_reg_arith_p (XEXP (x, 0))
+	     && ia16_rtx_is_pure_reg_arith_p (XEXP (x, 1))
+	     && ia16_rtx_is_pure_reg_arith_p (XEXP (x, 2));
+
+    default:
+      return false;
+    }
+}
+
+/* Say whether an RTX (in the currently compiled function) is for a memory
+   operand in the program's default data segment.  */
+static bool
+ia16_data_seg_mem_p (rtx x)
+{
+  return MEM_P (x) && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (x));
+}
+
+/* Say whether an RTX (in the currently compiled function) is for a memory
+   operand in the same IA-16 segment as the stack.  */
+static bool
+ia16_stack_seg_mem_p (rtx x)
+{
+  if (! MEM_P (x))
+    return false;
+
+  switch (MEM_ADDR_SPACE (x))
+    {
+    case ADDR_SPACE_GENERIC:
+      return ia16_in_ss_data_function_p () ? true : false;
+
+    case ADDR_SPACE_SEG_SS:
+      return true;
+
+    default:
+      return false;
+    }
+}
+
+/* In our reorganization subpasses, we sometimes need to look for pairs of
+   adjacent instructions --- within the same basic block, and possibly only
+   separated by NOTE's.  Define a macro FOR_EACH_IA16_INSN_PAIR to help in
+   this.
+
+   When using this macro, the basic block information for each of the insns
+   should be set correctly.  */
+static void
+insn_pair_iterator_next (rtx_insn **p_insn1, rtx_insn **p_insn2)
+{
+  rtx_insn *insn1, *insn2 = *p_insn2;
+
+  gcc_assert (insn2);
+
+  do
+    {
+      insn1 = insn2;
+      insn2 = NEXT_INSN (insn1);
+
+      if (insn1 && BLOCK_FOR_INSN (insn1)
+	  && insn1 == BB_END (BLOCK_FOR_INSN (insn1)))
+	insn1 = NULL;
+
+      while (insn2 && ! INSN_P (insn2))
+	{
+	  if (! NOTE_P (insn2))  /* probably a BARRIER or CODE_LABEL */
+	    insn1 = NULL;
+	  else if (BLOCK_FOR_INSN (insn2)
+		   && insn2 == BB_END (BLOCK_FOR_INSN (insn2)))
+	    insn1 = NULL;
+	  insn2 = NEXT_INSN (insn2);
+	}
+    }
+  while (! insn1 && insn2);
+
+  *p_insn1 = insn1;
+  *p_insn2 = insn2;
+}
+
+static void
+insn_pair_iterator_init (rtx_insn **p_insn1, rtx_insn **p_insn2)
+{
+  rtx_insn *insn2 = get_insns ();
+
+  while (insn2 && ! INSN_P (insn2))
+    insn2 = NEXT_INSN (insn2);
+
+  *p_insn1 = NULL;
+  *p_insn2 = insn2;
+  if (insn2)
+    insn_pair_iterator_next (p_insn1, p_insn2);
+}
+
+#define FOR_EACH_IA16_INSN_PAIR(insn1, insn2) \
+	for (insn_pair_iterator_init (&(insn1), &(insn2)); \
+	     (insn2); \
+	     insn_pair_iterator_next (&(insn1), &(insn2)))
+
+/* Try to rewrite something like
+		movw	%sp,	%bp
+		subw	$6,	%sp
+		...				// %sp and %bp unchanged
+		movw	%cx,	-6(%bp)		// %cx unchanged
+		...
+		movw	%dx,	-4(%bp)		// %dx unchanged
+   into something like
+		movw	%sp,	%bp
+		subw	$2,	%sp		// or `pushw %ds'
+		pushw	%dx
+		pushw	%cx
+		...
+ */
+static void
+ia16_rewrite_reg_parm_save_as_push (void)
+{
+  basic_block bb;
+  rtx_insn *insn1, *insn2, *insn;
+
+  FOR_EACH_IA16_INSN_PAIR (insn1, insn2)
+    {
+      enum
+	{
+	  /* The maximum offset from %sp for which we want to track the
+	     stack slot contents.  */
+	  MAX_TRACK_SP_OFF = 2 * LAST_ALLOCABLE_REG,
+	  /* Bogus register number meaning "this stack slot is not filled
+	     yet".  */
+	  UNFILLED = FIRST_PSEUDO_REGISTER,
+	  /* Bogus register number meaning "this stack slot is filled with
+	     something, but we are not sure what".  */
+	  UNKNOWN = FIRST_PSEUDO_REGISTER + 1
+	};
+      rtx pat, dest, dest_addr, src, sp_reg;
+      HOST_WIDE_INT bp_sp_off = 0, new_bp_sp_off;
+      unsigned sp_off_contents[MAX_TRACK_SP_OFF / 2 + 1];
+      rtx_insn *sp_off_insn[MAX_TRACK_SP_OFF / 2 + 1];
+      bool pristine[LAST_ALLOCABLE_REG + 1];
+      unsigned regno, index;
+      machine_mode mode;
+
+      /* Look for the sequence `movw %sp, %bp; subw $CONST_INT, %sp' in a
+	 prologue.  Bail out if this sequence is missing, if the CONST_INT
+	 is not sane, or if we encounter an instruction which might throw
+	 exceptions.  */
+      if (insn_could_throw_p (insn2)
+	  || ! ia16_insn_is_prologue_movw_sp_bp_p (insn1)
+	  || ! ia16_insn_is_prologue_subw_const_sp_p (insn2, &bp_sp_off))
+	continue;
+
+      if (bp_sp_off < 2)
+	continue;
+
+      /* We found the sequence.  Scan through any simple register assignments
+	 and/or simple arithmetic operations immediately following the `subw
+	 $..., %sp'.
+
+	 Record the places where the original values of registers are stored
+	 in the stack slots we are tracking.
+
+	 TODO: handle more instruction types.  */
+      for (regno = 0; regno <= LAST_ALLOCABLE_REG; ++regno)
+        pristine[regno] = true;
+
+      /* (INDEX is really an offset from %sp, divided by 2...)  */
+      for (index = 0; index <= MAX_TRACK_SP_OFF / 2; ++index)
+	{
+	  sp_off_contents[index] = UNFILLED;
+	  sp_off_insn[index] = NULL;
+	}
+
+      insn = insn2;
+      bb = BLOCK_FOR_INSN (insn);
+      while (insn != BB_END (bb))
+	{
+	  insn = NEXT_INSN (insn);
+	  if (! INSN_P (insn))
+	    continue;
+
+	  if (insn_could_throw_p (insn))
+	    break;
+
+	  pat = PATTERN (insn);
+	  if (GET_CODE (pat) == PARALLEL)
+	    {
+	      if (XVECLEN (pat, 0) != 2
+		  || ! ia16_pattern_is_clobber_cc_reg_p (XVECEXP (pat, 0, 1)))
+		break;
+	      pat = XVECEXP (pat, 0, 0);
+	    }
+
+	  /* We may have (use (reg:SEG DS_REG)) here if %ss != .data .  */
+	  if (GET_CODE (pat) == USE && REG_P (XEXP (pat, 0)))
+	    continue;
+
+	  if (GET_CODE (pat) != SET)
+	    break;
+
+	  dest = SET_DEST (pat);
+	  src = SET_SRC (pat);
+	  mode = GET_MODE (dest);
+
+	  if (mode != HImode && mode != QImode
+	      && mode != PHImode && mode != V2QImode)
+	    break;
+
+	  if (! ia16_rtx_is_pure_reg_arith_p (src))
+	    break;
+
+	  if (REG_P (dest))
+	    {
+	      regno = REGNO (dest);
+	      if (regno > LAST_ALLOCABLE_REG || regno == BP_REG)
+		break;
+
+	      pristine[regno] = false;
+	      if (regno < FIRST_NOQI_REG && mode != QImode)
+		pristine[regno + 1] = false;
+	    }
+	  else if (ia16_stack_seg_mem_p (dest))
+	    {
+	      dest_addr = XEXP (dest, 0);
+	      if (GET_CODE (dest_addr) == PLUS
+		  && CONST_INT_P (XEXP (dest_addr, 1))
+		  && ia16_operand_is_bp_reg_p (XEXP (dest_addr, 0)))
+		{
+		  /* We found a
+			movw	%reg,	CONST_INT(%bp)
+		     or
+			movb	%reg,	CONST_INT(%bp)
+		     insn.  Convert the offset from %bp into an offset from
+		     the top of the stack.  And, if %reg still has its
+		     initial value at this point, note down that the stack
+		     slot contains this value.  */
+		  HOST_WIDE_INT sp_operand_off
+				  = bp_sp_off + INTVAL (XEXP (dest_addr, 1));
+
+		  if (sp_operand_off % 2 != 0)
+		    break;
+
+		  if (sp_operand_off < 0  /* ??? */
+		      || sp_operand_off > MAX_TRACK_SP_OFF
+		      || sp_operand_off > bp_sp_off - 2)
+		    continue;
+
+		  if (sp_off_contents[sp_operand_off / 2] != UNFILLED)
+		    break;
+
+		  if (REG_P (src)
+		      && REGNO (src) <= LAST_ALLOCABLE_REG
+		      && pristine[REGNO (src)]
+		      && ! ia16_regno_in_class_p (REGNO (src), UP_QI_REGS)
+		      && (mode == QImode || REGNO (src) >= FIRST_NOQI_REG
+			  || pristine[REGNO (src) + 1]))
+		    {
+		      sp_off_contents[sp_operand_off / 2] = REGNO (src);
+		      sp_off_insn[sp_operand_off / 2] = insn;
+		    }
+		  else
+		    sp_off_contents[sp_operand_off / 2] = UNKNOWN;
+		}
+	      else
+		break;
+	    }
+	  else
+	    break;
+	}
+
+      /* We can now try to replace the insns.  */
+      index = 0;
+      while (index <= MAX_TRACK_SP_OFF / 2
+	     && sp_off_contents[index] != UNFILLED
+	     && sp_off_contents[index] != UNKNOWN)
+	++index;
+
+      if (! index)
+	continue;
+
+      insn = insn2;
+      new_bp_sp_off = bp_sp_off - 2 * index;
+      sp_reg = SET_DEST (XVECEXP (PATTERN (insn), 0, 0));
+
+      if (new_bp_sp_off)
+	{
+	  rtx pat0, pat1;
+	  pat0 = gen_rtx_SET (sp_reg,
+			      gen_rtx_MINUS (HImode, sp_reg,
+					    GEN_INT (new_bp_sp_off)));
+	  pat1 = gen_hard_reg_clobber (CCmode, CC_REG);
+	  PATTERN (insn) = gen_rtx_PARALLEL (VOIDmode,
+					     gen_rtvec (2, pat0, pat1));
+	  ia16_recog (insn);
+	}
+      else
+	{
+	  /* We can completely elide the %sp adjustment.  Instead of emitting
+	     a `subw $0, %sp' insn, replace it with a dummy (use ...).  */
+	  PATTERN (insn) = gen_rtx_USE (HImode, sp_reg);
+	  INSN_CODE (insn) = -1;
+	  RTX_FRAME_RELATED_P (insn) = 0;
+	}
+
+      while (index != 0)
+	{
+	  rtx reg;
+	  rtx_insn *push_reg_insn, *mov_reg_insn;
+
+	  --index;
+
+	  /* Build and insert the new `pushw' insn.  */
+	  reg = gen_rtx_REG (HImode, sp_off_contents[index]);
+	  push_reg_insn = make_insn_raw (gen__pushhi1_nonimm (reg));
+	  RTX_FRAME_RELATED_P (push_reg_insn) = 1;
+	  ia16_recog (push_reg_insn);
+	  add_insn_after (push_reg_insn, insn, bb);
+
+	  /* Blank out the original `mov{w|b} %reg, ...(%bp)' insn.  */
+	  mov_reg_insn = sp_off_insn[index];
+	  PATTERN (mov_reg_insn) = gen_rtx_USE (HImode, reg);
+	  INSN_CODE (mov_reg_insn) = -1;
+	  RTX_FRAME_RELATED_P (mov_reg_insn) = 0;
+
+	  insn = push_reg_insn;
+	}
+
+      /* The basic block information should still be correct, so we can
+	 simply continue iterating over the insn chain.  */
+    }
+}
+
+/* Try to rewrite the current function so that instead of using the frame
+   pointer register, %bp, it uses %bx.  This can potentially allow the
+   function to preserve one less register --- unlike %bp, %bx is call-used.
+ */
+static void
+ia16_rewrite_bp_as_bx (void)
+{
+  edge e;
+  edge_iterator ei;
+  rtx_insn *insn, *pushw_bp_insn = NULL, *movw_sp_bp_insn = NULL, **stack;
+  rtx sp_reg, bx_reg, use_sp, movw_sp_bx, *rewrite_insn_pat;
+  int max_insn_uid, uid, sp = 0;
+  bool bp_used = false;
+  typedef enum
+    {
+      RBPS_UNKNOWN,
+      RBPS_BP_GOOD,
+      RBPS_BX_CLOBBERED,
+      RBPS_BP_POPPED
+    } rewrite_bp_state_t;
+  rewrite_bp_state_t *insn_state, state;
+  basic_block bb;
+
+  /* Bail out early if we are not supposed to eliminate the frame pointer,
+     or if the function does not use %bp anyway, or in the unlikely future
+     case that we actually pass function arguments via %bx.  */
+  if (! global_options.x_flag_omit_frame_pointer
+      || ! ia16_save_reg_p (BP_REG)
+      || FUNCTION_ARG_REGNO_P (B_REG)
+      || FUNCTION_ARG_REGNO_P (BH_REG))
+    return;
+
+  /* For now, do not try to rewrite functions which may throw exceptions ---
+     until we can figure out how to do the rewriting correctly.
+
+     TODO: allow rewriting functions marked __attribute__ ((nothrow)) etc.  */
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    if (INSN_P (insn) && insn_could_throw_p (insn))
+      return;
+
+  /* Look for the `pushw %bp; movw %sp, %bp' stack frame setup sequence in
+     the very first basic block.
+
+     Bail out if this sequence is missing, or if the function frobs %bp or %bx
+     in a different way.
+
+     Also, to simplify the logic here, and save some time --- at the expense
+     of missing some optimization opportunities --- do not try to look for
+     this insn beyond the first basic block.  */
+  if (EDGE_COUNT (ENTRY_BLOCK_PTR_FOR_FN (cfun)->succs) != 1)
+    return;
+
+  FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR_FOR_FN (cfun)->succs)
+    {
+      bb = e->dest;
+
+      for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = NEXT_INSN (insn))
+	{
+	  if (! INSN_P (insn))
+	    continue;
+
+	  if (dead_or_set_regno_p (insn, B_REG)
+	      || dead_or_set_regno_p (insn, BH_REG)
+	      || dead_or_set_regno_p (insn, BP_REG))
+	    return;
+
+	  if (ia16_insn_is_prologue_pushw_bp_p (insn)
+	      && ia16_insn_is_prologue_movw_sp_bp_p (NEXT_INSN (insn)))
+	    {
+	      pushw_bp_insn = insn;
+	      movw_sp_bp_insn = NEXT_INSN (insn);
+	      break;
+	    }
+	}
+    }
+
+  if (! pushw_bp_insn)
+    return;
+
+  /* Do a depth-first search to decide if we want to rewrite this function's
+     insns, and how.  */
+  max_insn_uid = get_max_uid ();
+  insn_state = XCNEWVEC (rewrite_bp_state_t, max_insn_uid);
+  stack = XCNEWVEC (rtx_insn *, max_insn_uid);
+  rewrite_insn_pat = XCNEWVEC (rtx, max_insn_uid);
+
+  sp_reg = gen_rtx_REG (HImode, SP_REG);
+  bx_reg = gen_rtx_REG (HImode, B_REG);
+  use_sp = gen_rtx_USE (HImode, sp_reg);
+
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    {
+      uid = INSN_UID (insn);
+      insn_state[uid] = RBPS_UNKNOWN;
+      rewrite_insn_pat[uid] = NULL_RTX;
+    }
+
+  uid = INSN_UID (pushw_bp_insn);
+  rewrite_insn_pat[uid] = use_sp;
+
+  stack[sp++] = movw_sp_bp_insn;
+  uid = INSN_UID (movw_sp_bp_insn);
+  insn_state[uid] = RBPS_BP_GOOD;
+  movw_sp_bx = gen_rtx_SET (bx_reg, sp_reg);
+  RTX_FRAME_RELATED_P (movw_sp_bx) = 1;
+  rewrite_insn_pat[uid] = movw_sp_bx;
+
+  while (sp != 0)
+    {
+      rtx pat;
+
+      insn = stack[--sp];
+      pat = PATTERN (insn);
+      uid = INSN_UID (insn);
+      state = insn_state[uid];
+
+      switch (state)
+	{
+	case RBPS_BP_GOOD:
+	  if (insn == movw_sp_bp_insn || ! INSN_P (insn))
+	    break;
+
+	  if (RTX_FRAME_RELATED_P (insn))
+	    goto bail;
+
+	  if (refers_to_regno_p (BP_REG, BP_REG + 1, pat, NULL))
+	    {
+	      rtx dest, src, addr;
+
+	      bp_used = true;
+	      if (GET_CODE (pat) == SET)
+		{
+		  /* Deal with the common case of a (set ...) insn involving
+		     stack arguments or stack local variables.  */
+		  dest = SET_DEST (pat);
+		  src = SET_SRC (pat);
+
+		  if (REG_P (dest) && REGNO (dest) != BP_REG
+		      && ia16_stack_seg_mem_p (src))
+		    {
+		      addr = XEXP (src, 0);
+		      if (GET_CODE (addr) == PLUS
+			  && ia16_operand_is_bp_reg_p (XEXP (addr, 0))
+			  && CONST_INT_P (XEXP (addr, 1)))
+			{
+			  HOST_WIDE_INT off = INTVAL (XEXP (addr, 1));
+			  if (off >= 2)
+			    off -= 2;
+			  else if (off >= 0)
+			    goto bail;
+
+			  addr = gen_rtx_PLUS (GET_MODE (addr), bx_reg,
+					       GEN_INT (off));
+			  src = gen_rtx_MEM (GET_MODE (src), addr);
+			  rewrite_insn_pat[uid] = gen_rtx_SET (dest, src);
+			}
+		      else
+			goto bail;
+
+		      if (REGNO (dest) == B_REG || REGNO (dest) == BH_REG)
+			state = RBPS_BX_CLOBBERED;
+		    }
+		  else if (ia16_stack_seg_mem_p (dest)
+			   && REG_P (src) && REGNO (src) != BP_REG
+			   && REGNO (src) != B_REG && REGNO (src) != BH_REG)
+		    {
+		      addr = XEXP (dest, 0);
+		      if (GET_CODE (addr) == PLUS
+			  && ia16_operand_is_bp_reg_p (XEXP (addr, 0))
+			  && CONST_INT_P (XEXP (addr, 1)))
+			{
+			  HOST_WIDE_INT off = INTVAL (XEXP (addr, 1));
+			  if (off >= 2)
+			    off -= 2;
+			  else if (off >= 0)
+			    goto bail;
+
+			  addr = gen_rtx_PLUS (GET_MODE (addr), bx_reg,
+					       GEN_INT (off));
+			  dest = gen_rtx_MEM (GET_MODE (dest), addr);
+			  rewrite_insn_pat[uid] = gen_rtx_SET (dest, src);
+			}
+		      else
+			goto bail;
+		    }
+		  else
+		    goto bail;
+		}
+	      else
+		goto bail;
+	    }
+	  else if (dead_or_set_regno_p (insn, BP_REG))
+	    {
+	      if (ia16_insn_is_popw_bp_p (insn))
+		{
+		  /* `popw %bp'.  */
+		  rewrite_insn_pat[uid] = use_sp;
+		  state = RBPS_BP_POPPED;
+		}
+	      else if (INSN_CODE (insn) == CODE_FOR__leave)
+		{
+		  /* `leave'.  */
+		  rewrite_insn_pat[uid] = gen_rtx_SET (sp_reg, bx_reg);
+		  state = RBPS_BP_POPPED;
+		}
+	      else
+		goto bail;
+	    }
+	  else if (refers_to_regno_p (B_REG, BH_REG + 1, pat, NULL))
+	    goto bail;
+	  else if (dead_or_set_regno_p (insn, B_REG)
+		   || dead_or_set_regno_p (insn, BH_REG))
+	    state = RBPS_BX_CLOBBERED;
+
+	  break;
+
+	case RBPS_BX_CLOBBERED:
+	  if (ia16_insn_is_popw_bp_p (insn))
+	    {
+	      state = RBPS_BP_POPPED;
+	      rewrite_insn_pat[uid] = use_sp;
+	      break;
+	    }
+
+	  /* fall through */
+	case RBPS_BP_POPPED:
+	  if (INSN_P (insn)
+	      && (refers_to_regno_p (BP_REG, BP_REG + 1, pat, NULL)
+		  || dead_or_set_regno_p (insn, BP_REG)))
+	    goto bail;
+
+	  break;
+
+	default:
+	  gcc_unreachable ();
+	}
+
+      bb = BLOCK_FOR_INSN (insn);
+      if (insn != BB_END (bb))
+	{
+	  insn = NEXT_INSN (insn);
+	  uid = INSN_UID (insn);
+
+	  if (insn_state[uid] == RBPS_UNKNOWN)
+	    {
+	      insn_state[uid] = state;
+	      stack[sp++] = insn;
+	    }
+	  else if (insn_state[uid] != state)
+	    goto bail;
+	}
+      else
+	{
+	  FOR_EACH_EDGE (e, ei, bb->succs)
+	    {
+	      if (e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
+		{
+		  if (state != RBPS_BP_POPPED)
+		    goto bail;
+		  continue;
+		}
+
+	      insn = BB_HEAD (e->dest);
+	      uid = INSN_UID (insn);
+
+	      if (insn_state[uid] == RBPS_UNKNOWN)
+		{
+		  insn_state[uid] = state;
+		  stack[sp++] = insn;
+		}
+	      else if (insn_state[uid] != state)
+		goto bail;
+	    }
+	}
+    }
+
+  /* It looks like we can rewrite this function, so do it.  */
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    {
+      rtx pat;
+      uid = INSN_UID (insn);
+      pat = rewrite_insn_pat[uid];
+      if (pat)
+	{
+	  PATTERN (insn) = pat;
+	  ia16_recog (insn);
+	  RTX_FRAME_RELATED_P (insn) = RTX_FRAME_RELATED_P (pat);
+	}
+    }
+
+  /* If %bp is never used, we can also eliminate the `movw %sp, %bx'...  */
+  if (! bp_used)
+    {
+      PATTERN (movw_sp_bp_insn) = use_sp;
+      INSN_CODE (movw_sp_bp_insn) = -1;
+      RTX_FRAME_RELATED_P (movw_sp_bp_insn) = 0;
+    }
+
+bail:
+  free (insn_state);
+  free (stack);
+  free (rewrite_insn_pat);
+}
+
+/* Return true iff INSN is a (set (reg:SEG SOME_REG) (reg:SEG SS_REG)) where
+   SOME_REG is a general register.  */
+static bool
+ia16_insn_is_copy_ss_p (rtx_insn *insn)
+{
+  rtx pat, op;
+
+  if (! NONJUMP_INSN_P (insn))
+    return false;
+
+  pat = PATTERN (insn);
+  if (GET_CODE (pat) != SET)
+    return false;
+
+  op = SET_SRC (pat);
+  if (! REG_P (op) || REGNO (op) != SS_REG || GET_MODE (op) != SEGmode)
+    return false;
+
+  op = SET_DEST (pat);
+  if (! REG_P (op) || ! ia16_regno_in_class_p (REGNO (op), GENERAL_REGS)
+      || GET_MODE (op) != SEGmode)
+    return false;
+
+  return true;
+}
+
+/* Return true iff INSN is a (set (reg:SEG DS_REG) (reg:SEG SS_REG)).  */
+static bool
+ia16_insn_is_reset_ds_p (rtx_insn *insn)
+{
+  rtx pat, op;
+
+  if (! NONJUMP_INSN_P (insn))
+    return false;
+
+  pat = PATTERN (insn);
+  if (GET_CODE (pat) != SET)
+    return false;
+
+  op = SET_DEST (pat);
+  if (! REG_P (op) || REGNO (op) != DS_REG || GET_MODE (op) != SEGmode)
+    return false;
+
+  op = SET_SRC (pat);
+  if (! REG_P (op) || REGNO (op) != SS_REG || GET_MODE (op) != SEGmode)
+    return false;
+
+  return true;
+}
+
+/* Return true iff INSN is a (use (reg:SEG DS_REG)).  */
+static bool
+ia16_insn_is_use_ds_p (rtx_insn *insn)
+{
+  rtx pat, op;
+
+  if (! NONJUMP_INSN_P (insn))
+    return false;
+
+  pat = PATTERN (insn);
+  if (GET_CODE (pat) != USE)
+    return false;
+
+  op = XEXP (pat, 0);
+  if (! REG_P (op) || REGNO (op) != DS_REG || GET_MODE (op) != SEGmode)
+    return false;
+
+  return true;
+}
+
+/* Elide unneeded instances of (set (reg:SEG DS_REG) (reg:SEG SS_REG)) in
+   the current function.  Also elide any unneeded `%ss:' segment overrides
+   from simple moves to/from memory (`ldsw', `cmpw', etc. are not yet
+   handled).
+
+   This routine should only be called on functions which assume %ss == .data .
+ */
+static void
+ia16_elide_unneeded_ss_stuff (void)
+{
+  int max_insn_uid = get_max_uid ();
+  bool *insn_pushed_p = XCNEWVEC (bool, max_insn_uid);
+  bool *keep_insn_p = XCNEWVEC (bool, max_insn_uid);
+  rtx_insn *insn, **stack = XCNEWVEC (rtx_insn *, max_insn_uid);
+  int sp = 0;
+  rtx ds = gen_rtx_REG (SEGmode, DS_REG),
+      override = ia16_seg_override_term (ds);
+  bool default_ds_abi_p = ia16_in_ds_data_function_p ();
+  bool keep_any_resets_p = false;
+  edge e;
+  edge_iterator ei;
+
+  /* Starting from insns which set (or clobber) %ds to not-.data, "flood"
+     insns along the control flow until we hit
+	(set (reg:SEG DS_REG) (reg:SEG SS_REG)).
+     Assume %ss == .data always.
+
+     If the current function does not assume %ds == .data on entry, also
+     flood from the function entry point.
+
+     Mark all the insns along each path --- excluding the first set to
+     non-.data, but including the final %ds <- .data --- as insns we want to
+     "keep" as is.  */
+  if (! default_ds_abi_p)
+    {
+      FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR_FOR_FN (cfun)->succs)
+	{
+	  insn = BB_HEAD (e->dest);
+	  if (! insn_pushed_p[INSN_UID (insn)])
+	    {
+	      stack[sp++] = insn;
+	      insn_pushed_p[INSN_UID (insn)] = true;
+	    }
+	}
+    }
+
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    {
+      /* GCC's machine-independent code thinks function calls always clobber
+	 %ds, but we know that this is not really true.  */
+      if (CALL_P (insn))
+	{
+	  rtx call = get_call_rtx_from (insn);
+	  rtx callee = XEXP (XEXP (call, 0), 0);
+	  if (ia16_restore_ds_function_rtx_p (callee))
+	    continue;
+	}
+
+      if (NOTE_P (insn)
+	  || ! reg_set_p (ds, insn)
+	  || ia16_insn_is_reset_ds_p (insn))
+	continue;
+
+      if (! insn_pushed_p[INSN_UID (insn)])
+	{
+	  stack[sp++] = insn;
+	  insn_pushed_p[INSN_UID (insn)] = true;
+	}
+    }
+
+  while (sp != 0)
+    {
+      rtx_insn *insn;
+      basic_block bb;
+
+      gcc_assert (sp > 0 && sp <= max_insn_uid);
+      insn = stack[--sp];
+
+      if (ia16_insn_is_reset_ds_p (insn))
+	{
+	  keep_any_resets_p = true;
+	  continue;
+	}
+
+      bb = BLOCK_FOR_INSN (insn);
+      if (insn != BB_END (bb))
+	{
+	  insn = NEXT_INSN (insn);
+	  keep_insn_p[INSN_UID (insn)] = true;
+	  if (! insn_pushed_p[INSN_UID (insn)])
+	    {
+	      stack[sp++] = insn;
+	      insn_pushed_p[INSN_UID (insn)] = true;
+	    }
+	}
+      else
+	{
+	  FOR_EACH_EDGE (e, ei, bb->succs)
+	    {
+	      if (e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
+		continue;
+
+	      insn = BB_HEAD (e->dest);
+	      keep_insn_p[INSN_UID (insn)] = true;
+	      if (! insn_pushed_p[INSN_UID (insn)])
+		{
+		  stack[sp++] = insn;
+		  insn_pushed_p[INSN_UID (insn)] = true;
+		}
+	    }
+	}
+    }
+
+  /* Rescan the whole insn list for
+	(set (reg:SEG DS_REG) (reg:SEG SS_REG))
+     and simple moves to/from the generic address space, and rewrite those
+     which we have not marked as "keep".  */
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    {
+      rtx pat, dest, src;
+
+      if (keep_insn_p[INSN_UID (insn)])
+	continue;
+
+      if (ia16_insn_is_reset_ds_p (insn))
+	{
+	  /* Rewrite
+		(set (reg:SEG DS_REG) (reg:SEG SS_REG))
+	     as
+		(use (reg:SEG SS_REG)).
+
+	     If this insn is followed by
+		(use (reg:SEG DS_REG))
+	     then rewrite that too.  */
+	  rtx ss = XEXP (PATTERN (insn), 1);
+	  PATTERN (insn) = gen_rtx_USE (VOIDmode, ss);
+	  INSN_CODE (insn) = -1;
+
+	  if (insn != BB_END (BLOCK_FOR_INSN (insn)))
+	    {
+	      rtx_insn *next_insn = NEXT_INSN (insn);
+	      if (ia16_insn_is_use_ds_p (next_insn))
+		XEXP (PATTERN (next_insn), 0) = ss;
+	    }
+
+	  continue;
+	}
+
+      if (! NONJUMP_INSN_P (insn) || GET_CODE (PATTERN (insn)) != SET)
+	continue;
+
+      pat = PATTERN (insn);
+      dest = SET_DEST (pat);
+      src = SET_SRC (pat);
+
+      if (ia16_data_seg_mem_p (dest) && (REG_P (src) || CONSTANT_P (src)))
+	{
+	  /* If the insn is a simple move to generic memory, and the address
+	     does not involve %bp, then _add_ a `%ds:' segment override to
+	     the destination address term.
+
+	     (These added overrides are not counted towards determining
+	      whether %ds is ever live (below).  As Obi-Wan never said:
+	      "These are not the %ds references you are looking for.")  */
+	  rtx addr = XEXP (dest, 0), rb, rs;
+
+	  if (ia16_parse_address_strict (addr, &rb, NULL, NULL, &rs,
+					 ADDR_SPACE_GENERIC)
+	      && ! rs && (! rb || REGNO (rb) != BP_REG))
+	    {
+	      rtx new_dest = shallow_copy_rtx (dest);
+	      XEXP (new_dest, 0) = gen_rtx_PLUS (HImode, override, addr);
+	      PATTERN (insn) = gen_rtx_SET (new_dest, src);
+	      ia16_recog (insn);
+	    }
+	}
+      else if (ia16_data_seg_mem_p (src) && REG_P (dest))
+	{
+	  /* Ditto if the insn is a simple move from generic memory.  */
+	  rtx addr = XEXP (src, 0), rb, rs;
+
+	  if (ia16_parse_address_strict (addr, &rb, NULL, NULL, &rs,
+					 ADDR_SPACE_GENERIC)
+	      && ! rs && (! rb || REGNO (rb) != BP_REG))
+	    {
+	      rtx new_src = shallow_copy_rtx (src);
+	      XEXP (new_src, 0) = gen_rtx_PLUS (HImode, override, addr);
+	      PATTERN (insn) = gen_rtx_SET (dest, new_src);
+	      ia16_recog (insn);
+	    }
+	}
+    }
+
+  /* If at no point in the function do we need to reset %ds to .data, then
+     deduce that %ds is no longer live within the function.  */
+  if (default_ds_abi_p && ! keep_any_resets_p)
+    df_set_regs_ever_live (DS_REG, false);
+
+  free (insn_pushed_p);
+  free (keep_insn_p);
+  free (stack);
+}
+
+/* Try to rewrite
+		movw	%ss,	%reg
+		pushw	%ss
+		popw	%ds
+   as
+		movw	%ss,	%reg
+		movw	%reg,	%ds
+
+   We cannot do this as a peephole rule, since we want to do it _after_ the
+   above subpass to eliminate any (set (reg:SEG DS_REG) (reg:SEG SS_REG))
+   patterns which are totally redundant in the first place.
+
+   This routine should only be called on functions which assume %ss == .data .
+ */
+static void
+ia16_tweak_reset_ds (void)
+{
+  rtx_insn *insn1, *insn2;
+
+  FOR_EACH_IA16_INSN_PAIR (insn1, insn2)
+    {
+      rtx dest, new_src;
+
+      if (! ia16_insn_is_copy_ss_p (insn1)
+	  || ! ia16_insn_is_reset_ds_p (insn2))
+	continue;
+
+      new_src = SET_DEST (PATTERN (insn1));
+      dest = SET_DEST (PATTERN (insn2));
+      PATTERN (insn2) = gen_rtx_SET (dest, new_src);
+      ia16_recog (insn2);
+    }
+}
+
+/* If optimizing for size, try to rewrite each 2-byte `movw %reg, %ax' or
+   `movw %ax, %reg' into a 1-byte `xchgw %ax, %reg', wherever possible.
+
+   This optimization needs to be done as late as possible --- if it is in,
+   say, the peephole2 pass, the resulting insn patterns for `xchgw' may
+   interfere with subsequent passes.  */
+static void
+ia16_rewrite_movw_as_xchgw (void)
+{
+  bool reg_now_clobbered_p[LAST_ALLOCABLE_REG + 1];
+  rtx_insn *insn;
+  rtx pat, dest, src;
+  unsigned rd, rs;
+
+  for (rs = 0; rs <= LAST_ALLOCABLE_REG; ++rs)
+    reg_now_clobbered_p[rs] = false;
+
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    {
+      if (! INSN_P (insn))
+	continue;
+
+      pat = PATTERN (insn);
+      if (GET_CODE (pat) != SET)
+	continue;
+
+      dest = SET_DEST (pat);
+      src = SET_SRC (pat);
+      if ((! REG_P (dest) && ! SUBREG_P (dest))
+	  || (! REG_P (src) && ! SUBREG_P (src))
+	  || GET_MODE_SIZE (GET_MODE (dest)) != 2
+	  || GET_MODE_SIZE (GET_MODE (src)) != 2)
+	continue;
+
+      while (SUBREG_P (dest))
+	dest = SUBREG_REG (dest);
+      while (SUBREG_P (src))
+	src = SUBREG_REG (src);
+
+      if (! REG_P (dest)
+	  || ! REG_P (src)
+	  || GET_MODE_SIZE (GET_MODE (dest)) != 2
+	  || GET_MODE_SIZE (GET_MODE (src)) != 2)
+	continue;
+
+      rd = REGNO (dest);
+      rs = REGNO (src);
+
+      if (rd == A_REG)
+	{
+	  if (! ia16_regno_in_class_p (rs, GENERAL_REGS)
+	      || ! find_regno_note (insn, REG_DEAD, rs)
+	      || (rs < FIRST_NOQI_REG - 1
+		  && ! find_regno_note (insn, REG_DEAD, rs + 1)))
+	    continue;
+	  PATTERN (insn) = gen__xchghi2 (gen_rtx_REG (HImode, rs),
+					 gen_rtx_REG (HImode, A_REG));
+	  ia16_recog (insn);
+	  reg_now_clobbered_p[rs] = true;
+	}
+      else if (rs == A_REG)
+	{
+	  if (! ia16_regno_in_class_p (rd, GENERAL_REGS)
+	      || ! find_regno_note (insn, REG_DEAD, A_REG)
+	      || ! find_regno_note (insn, REG_DEAD, AH_REG))
+	    continue;
+	  PATTERN (insn) = gen__xchghi2 (gen_rtx_REG (HImode, rd),
+					 gen_rtx_REG (HImode, A_REG));
+	  ia16_recog (insn);
+	  reg_now_clobbered_p[A_REG] = true;
+	}
+    }
+
+  /* If e.g. `movw %bx, %ax' was rewritten into `xchgw %bx, %ax', then any
+     REG_EQUAL or REG_EQUIV notes involving %bx may no longer be correct.
+     Remove such notes.  */
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    {
+      if (! INSN_P (insn))
+	continue;
+
+      pat = single_set (insn);
+      if (! pat)
+	continue;
+
+      dest = SET_DEST (pat);
+      while (SUBREG_P (dest))
+	dest = SUBREG_REG (dest);
+
+      if (! REG_P (dest))
+	continue;
+
+      rd = REGNO (dest);
+      if (rd <= LAST_ALLOCABLE_REG
+	  && (reg_now_clobbered_p[rd]
+	      || (rd < FIRST_NOQI_REG && reg_now_clobbered_p[rd / 2 * 2])))
+	remove_note (insn, find_reg_equal_equiv_note (insn));
+    }
+}
+
+void
+ia16_machine_dependent_reorg (void)
+{
+  /* Do correctness checks.  */
+  ia16_verify_calls_from_no_assume_ds ();
+  ia16_verify_calls_from_no_assume_ss ();
+
+  /* Do optimizations.  */
+  if (optimize)
+    {
+      compute_bb_for_insn ();
+      ia16_rewrite_reg_parm_save_as_push ();
+
+      if (TARGET_ALLOCABLE_DS_REG && call_used_regs[DS_REG])
+	ia16_rewrite_bp_as_bx ();
+
+      /* The insn notes are only needed by the `movw' -> `xchgw' rewriting
+	 subpass (ia16_rewrite_movw_as_xchg ()), but I put the df_analyze ()
+	 before the %ss elimination subpass (ia16_elide_unneeded_ss_stuff
+	 ()).
+
+	 This is because df_analyze () might overwrite the %ss subpass's
+	 judgement on whether %ds is live.  (This caused a minor regression
+	 in gcc.target/ia16/torture/optimize/opt-1.c, as an extraneous %ss
+	 was sticking out.)  -- tkchia  */
+      if (optimize_size)
+	{
+	  df_note_add_problem ();
+	  df_analyze ();
+	}
+
+      if (TARGET_ALLOCABLE_DS_REG && call_used_regs[DS_REG])
+	{
+	  if (ia16_in_ss_data_function_p ())
+	    {
+	      ia16_elide_unneeded_ss_stuff ();
+	      ia16_tweak_reset_ds ();
+	    }
+	}
+
+      free_bb_for_insn ();
+
+      if (optimize_size)
+	ia16_rewrite_movw_as_xchgw ();
+    }
+}
diff --git a/gcc/config/ia16/ia16.c b/gcc/config/ia16/ia16.c
new file mode 100755
index 0000000..e181903
--- /dev/null
+++ b/gcc/config/ia16/ia16.c
@@ -0,0 +1,4915 @@
+/* Subroutines used during code generation for Intel 16-bit x86.
+   Copyright (C) 2005-2020 Free Software Foundation, Inc.
+   Contributed by Rask Ingemann Lambertsen <rask@sygehus.dk>
+   Changes by Andrew Jenner <andrew@codesourcery.com>
+   Very preliminary IA-16 far pointer support and other changes by TK Chia
+
+   This file is part of GCC.
+
+   GCC 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 3 of the License, or (at your option) any
+   later version.
+
+   GCC 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/licenses/>.
+*/
+
+/* I have no or little idea how many and which of these headers files I need
+ * to include.  So don't look here if you don't have a clue either.
+ *
+ * FIXME: Docs say config.h includes tm.h, but it doesn't.
+ */
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "rtl.h"
+#include "tree.h"
+#include "gimple.h"
+#include "cfgloop.h"
+#include "df.h"
+#include "tm_p.h"
+#include "expmed.h"
+#include "optabs.h"
+#include "regs.h"
+#include "emit-rtl.h"
+#include "diagnostic.h"
+#include "fold-const.h"
+#include "calls.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "output.h"
+#include "explow.h"
+#include "expr.h"
+#include "gimple-iterator.h"
+#include "tree-vectorizer.h"
+#include "builtins.h"
+#include "cfgrtl.h"
+#include "libiberty.h"
+#include "hashtab.h"
+#include "print-tree.h"
+#include "langhooks.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "varasm.h"
+#include "recog.h"
+
+/* This file should be included last.  */
+#include "target-def.h"
+
+/* The Global targetm Variable.  */
+/* Part 1.  Part 2 is at the end of this file.  */
+
+/* Storage Layout.  */
+
+/* Cached information for each compiled function */
+struct GTY (()) machine_function
+{
+  unsigned callcvt_cached_p : 1,
+	   data_seg_rtx_cached_p : 1;
+  unsigned cached_callcvt;
+  rtx data_seg_rtx;
+};
+
+#undef	TARGET_EXPAND_TO_RTL_HOOK
+#define	TARGET_EXPAND_TO_RTL_HOOK	ia16_expand_to_rtl_hook
+
+static void ia16_cache_function_info (bool);
+
+void ia16_expand_to_rtl_hook (void)
+{
+  /* Get cfun->machine->data_seg_rtx as early as possible!  */
+  ia16_cache_function_info (true);
+}
+
+/* Type Layout.  */
+
+/* Layout of Source Language Data Types */
+#undef  TARGET_DEFAULT_SHORT_ENUMS
+#define TARGET_DEFAULT_SHORT_ENUMS	hook_bool_void_true
+
+/* How Values Fit in Registers */
+/* This is complex enough to warrant a table.
+ * Only 8-bit registers can hold QImode values. TODO: Lift this restriction.
+ * Multibyte values are forced to start in even registers because the hw
+ * makes this much easier and faster and some insn patterns may rely on it.
+ * Don't put 8-byte values in bx because it would take all BASE_REGS.
+ * Don't put 8-byte values in bx or dx because subreg_get_info can't handle it.
+ * find_valid_class() fails if we don't take the ending register into account.
+ * subreg_get_info() dies on libssp/gets-chk.c if !H_R_M_O (SP_REG, HImode).
+ * Disallow register size changes unless HARD_REGNO_NREGS_HAS_PADDING.
+ * CCmode is 4 bytes.
+ */
+unsigned char ia16_hard_regno_nregs[17][FIRST_PSEUDO_REGISTER] =
+{
+/* size     cl  ch  al  ah  dl  dh  bl  bh  si  di  bp  es  ds  sp  cc  ss  cs  ap */
+/*  0 */  {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
+/*  1 */  {  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
+/*  2 */  {  2,  0,  2,  0,  2,  0,  2,  0,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1 },
+/*  3 */  {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
+/*  4 */  {  4,  0,  4,  0,  4,  0,  3,  0,  2,  2,  2,  2,  0,  0,  1,  0,  0,  0 },
+/*  5 */  {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
+/*  6 */  {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
+/*  7 */  {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
+/*  8 */  {  8,  0,  7,  0,  0,  0,  0,  0,  4,  4,  0,  0,  0,  0,  0,  0,  0,  0 },
+/*  9 */  {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
+/* 10 */  {  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
+/* 11 */  {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
+/* 12 */  {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
+/* 13 */  {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
+/* 14 */  {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
+/* 15 */  {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
+/* 16 */  {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
+};
+
+/* Register Classes.  */
+enum reg_class const ia16_regno_class[FIRST_PSEUDO_REGISTER] = {
+	/*  0 cl */ CL_REGS,
+	/*  1 ch */ CX_REGS,
+	/*  2 al */ AL_REGS,
+	/*  3 ah */ AH_REGS,
+	/*  4 dl */ DL_REGS,
+	/*  5 dh */ DH_REGS,
+	/*  6 bl */ BX_REGS,
+	/*  7 bh */ BX_REGS,
+	/*  8 si */ SI_REGS,
+	/*  9 di */ DI_REGS,
+	/* 10 bp */ BP_REGS,
+	/* 11 es */ ES_REGS,
+	/* 12 ds */ DS_REGS,
+	/* 13 sp */ HI_REGS,
+	/* 14 cc */ ALL_REGS,
+	/* 15 ss */ SEGMENT_REGS,
+	/* 16 cs */ SEGMENT_REGS,
+	/* 17 ap */ ALL_REGS,
+};
+
+/* Processor target table, indexed by processor number */
+struct ptt
+{
+  const struct processor_costs *cost;           /* Processor costs */
+  int features;
+};
+
+#undef	TARGET_PREFERRED_RELOAD_CLASS
+#define	TARGET_PREFERRED_RELOAD_CLASS ia16_preferred_reload_class
+
+static reg_class_t
+ia16_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, reg_class_t rclass)
+{
+  /* Try to avoid roping in %ds.  */
+  switch (rclass)
+    {
+    case SEGMENT_REGS:
+      return ES_REGS;
+
+    case SEG_GENERAL_REGS:
+      return TARGET_PROTECTED_MODE ? GENERAL_REGS : ES_GENERAL_REGS;
+
+    default:
+      return rclass;
+    }
+}
+
+#undef  TARGET_SECONDARY_RELOAD
+#define TARGET_SECONDARY_RELOAD ia16_secondary_reload
+
+/* Handle loading a constant into a segment register.  Handle loading a frame
+ * pointer offset into a segment register.  This is also where copies between
+ * segment registers should be handled, if needed.  All of this needs an
+ * intermediate register of class GENERAL_REGS.  */
+static reg_class_t
+ia16_secondary_reload (bool in_p, rtx x, reg_class_t reload_class,
+		       enum machine_mode reload_mode ATTRIBUTE_UNUSED,
+		       secondary_reload_info *sri ATTRIBUTE_UNUSED)
+{
+  if (in_p
+      && (reload_class == SEG_GENERAL_REGS
+	  || reload_class == SEGMENT_REGS
+	  || reload_class == ES_REGS
+	  || reload_class == DS_REGS)
+      && (CONSTANT_P (x) || PLUS == GET_CODE (x)))
+    {
+      return (GENERAL_REGS);
+    }
+  return (NO_REGS);
+}
+
+#undef TARGET_LRA_P
+#define TARGET_LRA_P	ia16_lra_p
+
+/* In ia16-no-ss-data.c .  */
+extern bool ia16_lra_p (void);
+
+#undef TARGET_CANNOT_SUBSTITUTE_MEM_EQUIV_P
+#define TARGET_CANNOT_SUBSTITUTE_MEM_EQUIV_P ia16_cannot_substitute_mem_equiv_p
+
+/* Return true if SUBST can't safely replace its equivalent during RA.  */
+static bool
+ia16_cannot_substitute_mem_equiv_p (rtx subst)
+{
+  if (!MEM_P  (subst))
+    return false;
+  rtx e = XEXP (subst, 0);
+  if (GET_CODE (e) != PLUS)
+    return false;
+  rtx x = XEXP (e, 0);
+  if (GET_CODE (x) == PLUS)
+    return true;
+  rtx y = XEXP (e, 1);
+  return GET_CODE (x) == REG && GET_CODE (y) == REG;
+}
+
+/* Convenience function --- say whether register r belongs to class c.  */
+int
+ia16_regno_in_class_p (unsigned r, unsigned c)
+{
+  return r < FIRST_PSEUDO_REGISTER
+	 && TEST_HARD_REG_BIT (reg_class_contents[c], r);
+}
+
+/* Returns non-zero if register r must be saved by a function, zero if not.  */
+/* Always returns zero for upper halves of 16-bit registers
+ * (i.e. ah, dh, bh or ch).  */
+int
+ia16_save_reg_p (unsigned int r)
+{
+  if (r == BP_REG)
+    {
+      if (! frame_pointer_needed && get_frame_size () != 0)  /* FIXME */
+	frame_pointer_needed = 1;
+
+      return frame_pointer_needed;
+    }
+  /* Note: assume_ds_data functions will also correctly restore %ds on
+     return, but they are handled separately (e.g. we might be able to
+     restore %ds from %ss).  */
+  if (r == DS_REG)
+    return (df_regs_ever_live_p (r) && ! ia16_in_ds_data_function_p ()
+				    && ia16_in_restore_ds_function_p ());
+  if (! ia16_regno_in_class_p (r, QI_REGS))
+    return (df_regs_ever_live_p (r) && !call_used_regs[r]);
+  if (ia16_regno_in_class_p (r, UP_QI_REGS))
+    return (0);
+  return ((df_regs_ever_live_p (r + 0) && !call_used_regs[r + 0]) ||
+	  (df_regs_ever_live_p (r + 1) && !call_used_regs[r + 1]));
+}
+
+static enum call_parm_cvt_type
+ia16_get_call_parm_cvt (const_tree type)
+{
+  if (type)
+    {
+      tree attrs = TYPE_ATTRIBUTES (type);
+
+      if (attrs != NULL_TREE)
+	{
+	  if (lookup_attribute ("cdecl", attrs))
+	    return CALL_PARM_CVT_CDECL;
+	  else if (lookup_attribute ("stdcall", attrs))
+	    return CALL_PARM_CVT_STDCALL;
+	  else if (lookup_attribute ("regparmcall", attrs))
+	    return CALL_PARM_CVT_REGPARMCALL;
+	}
+    }
+
+  return (enum call_parm_cvt_type) target_call_parm_cvt;
+}
+
+/* Calling convention flags as returned by ia16_get_callcvt (.).
+
+   These should only cover specifiers, qualifiers, and attributes that
+   affect what happens when one function tries to call another function. 
+   Attributes which only affect how code behaves _within_ a function should
+   not be included.  */
+#define IA16_CALLCVT_CDECL		0x0001
+#define IA16_CALLCVT_STDCALL		0x0002
+#define IA16_CALLCVT_REGPARMCALL	0x0004
+#define IA16_CALLCVT_FAR		0x0008
+#define IA16_CALLCVT_DS_DATA		0x0010
+#define IA16_CALLCVT_SS_DATA		0x0020
+#define IA16_CALLCVT_RESTORE_DS		0x0040
+#define IA16_CALLCVT_NEAR_SECTION	0x0080
+#define IA16_CALLCVT_FAR_SECTION	0x0100
+
+static bool ia16_far_function_type_p (const_tree funtype);
+
+static unsigned
+ia16_get_callcvt (const_tree type)
+{
+  tree attrs;
+  unsigned callcvt;
+
+  switch (ia16_get_call_parm_cvt (type))
+    {
+    case CALL_PARM_CVT_CDECL:
+      callcvt = IA16_CALLCVT_CDECL;
+      break;
+    case CALL_PARM_CVT_STDCALL:
+      callcvt = IA16_CALLCVT_STDCALL;
+      break;
+    case CALL_PARM_CVT_REGPARMCALL:
+      callcvt = IA16_CALLCVT_REGPARMCALL;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  if (ia16_far_function_type_p (type))
+    callcvt |= IA16_CALLCVT_FAR;
+
+  if (! type)
+    return callcvt;
+
+  attrs = TYPE_ATTRIBUTES (type);
+
+  if (attrs != NULL_TREE)
+    {
+      if (lookup_attribute ("near_section", attrs))
+	callcvt |= IA16_CALLCVT_NEAR_SECTION;
+      else if (lookup_attribute ("far_section", attrs))
+	callcvt |= IA16_CALLCVT_FAR_SECTION;
+    }
+
+  if (ia16_ds_data_function_type_p (type))
+    callcvt |= IA16_CALLCVT_DS_DATA;
+
+  if (ia16_restore_ds_function_type_p (type))
+    callcvt |= IA16_CALLCVT_RESTORE_DS;
+
+  if (ia16_ss_data_function_type_p (type))
+    callcvt |= IA16_CALLCVT_SS_DATA;
+
+  if ((callcvt & (IA16_CALLCVT_DS_DATA | IA16_CALLCVT_SS_DATA)) == 0)
+    error_at (type && TYPE_NAME (type)
+		? DECL_SOURCE_LOCATION (TYPE_NAME (type)) : UNKNOWN_LOCATION,
+	      "unsupported: function with both %%ds and %%ss != .data");
+
+  return callcvt;
+}
+
+/* Given the address ADDR of a function or variable, return its declaration
+   node, or NULL_TREE if none can be found.
+   FIXME: this may not be 100% reliable...  */
+static tree
+ia16_get_decl_for_addr (rtx addr)
+{
+  switch (GET_CODE (addr))
+    {
+    case MEM:
+      return MEM_EXPR (addr);
+      break;
+
+    case REG:
+      return REG_EXPR (addr);
+      break;
+
+    case SYMBOL_REF:
+      return SYMBOL_REF_DECL (addr);
+      break;
+
+    default:
+      return NULL_TREE;
+    }
+}
+
+/* Given the declaration node DECL of a function --- or NULL_TREE --- return
+   its type node, or NULL_TREE if no type node can be found.  */
+static tree
+ia16_get_function_type_for_decl (tree decl)
+{
+  tree type;
+
+  if (! decl)
+    return NULL_TREE;
+
+  type = TREE_TYPE (decl);
+  while (POINTER_TYPE_P (type))
+    type = TREE_TYPE (type);
+
+  return type;
+}
+
+/* Given the address ADDR of a function, return its type node, or NULL_TREE
+   if no type node can be found.  */
+tree
+ia16_get_function_type_for_addr (rtx addr)
+{
+  tree decl = ia16_get_decl_for_addr (addr);
+  return ia16_get_function_type_for_decl (decl);
+}
+
+/* Return true iff TYPE is a type for a far function (which returns with
+   `lret').  TYPE may be NULL, which indicates a compiler support routine.
+
+   Currently a function is considered to be "far" if the function type
+   itself is in __far space.  Unless the user specifies `-mno-far-
+   function-if-far-return-type', a __far on the return type will also
+   magically become a __far on the function itself.  */
+static bool
+ia16_far_function_type_p (const_tree funtype)
+{
+  if (! funtype)
+    return TARGET_CMODEL_IS_FAR_TEXT;
+  else
+    return TYPE_ADDR_SPACE (funtype) == ADDR_SPACE_FAR;
+}
+
+/* Determine the current function's calling convention.  Also obtain an RTX
+   for the initial %ds value, if necessary --- this is used if the current
+   function has %ss != .data.
+
+   Cache these pieces of information under cfun->machine.  */
+static void
+ia16_cache_function_info (bool need_data_seg_rtx_p)
+{
+  struct machine_function *machine = cfun->machine;
+
+  if (! machine->callcvt_cached_p)
+    {
+      tree type = cfun->decl ? TREE_TYPE (cfun->decl) : NULL_TREE;
+      machine->cached_callcvt = ia16_get_callcvt (type);
+      machine->callcvt_cached_p = true;
+    }
+
+  if (need_data_seg_rtx_p && ! machine->data_seg_rtx_cached_p)
+    {
+      if ((machine->cached_callcvt & IA16_CALLCVT_SS_DATA) != 0)
+	machine->data_seg_rtx = NULL_RTX;
+      else
+	machine->data_seg_rtx = get_hard_reg_initial_val (SEGmode, DS_REG);
+      machine->data_seg_rtx_cached_p = true;
+    }
+}
+
+/* Return an RTX for the program's data segment value (.data), or NULL_RTX
+   if none should be needed (%ss == .data).  */
+rtx
+ia16_data_seg_rtx (void)
+{
+  ia16_cache_function_info (true);
+  return cfun->machine->data_seg_rtx;
+}
+
+/* Return true iff we are currently compiling a far function.  */
+int
+ia16_in_far_function_p (void)
+{
+  if (! cfun)
+    return TARGET_CMODEL_IS_FAR_TEXT;
+  ia16_cache_function_info (false);
+  return (cfun->machine->cached_callcvt & IA16_CALLCVT_FAR) != 0;
+}
+
+/* Return true iff TYPE is a type for a function which assumes that %ds
+   points to the program's data segment on function entry.
+
+   If %ds is a call-saved register (-fcall-saved-ds), this is always false.  */
+int
+ia16_ds_data_function_type_p (const_tree funtype)
+{
+  tree attrs;
+
+  if (! call_used_regs[DS_REG])
+    return 0;
+
+  attrs = funtype ? TYPE_ATTRIBUTES (funtype) : NULL_TREE;
+
+  if (TARGET_ASSUME_DS_DATA)
+    return ! attrs || ! lookup_attribute ("no_assume_ds_data", attrs);
+  else
+    return attrs && lookup_attribute ("assume_ds_data", attrs);
+}
+
+int
+ia16_ds_data_function_rtx_p (rtx addr)
+{
+  tree type = ia16_get_function_type_for_addr (addr);
+  return ia16_ds_data_function_type_p (type);
+}
+
+int
+ia16_in_ds_data_function_p (void)
+{
+  if (! cfun)
+    return TARGET_ASSUME_DS_DATA && call_used_regs[DS_REG];
+  ia16_cache_function_info (false);
+  return (cfun->machine->cached_callcvt & IA16_CALLCVT_DS_DATA) != 0;
+}
+
+/* Return true iff TYPE is a type for a function which correctly restores the
+   value of %ds on function exit.
+
+   If the function assume %ds == .data on entry, this is always true.
+
+   If %ds is a call-saved register (-fcall-saved-ds), this is always false.  */
+int
+ia16_restore_ds_function_type_p (const_tree funtype)
+{
+  tree attrs;
+
+  if (! call_used_regs[DS_REG])
+    return 0;
+
+  attrs = funtype ? TYPE_ATTRIBUTES (funtype) : NULL_TREE;
+
+  if (TARGET_ASSUME_DS_DATA)
+    return ! attrs || ! lookup_attribute ("no_assume_ds_data", attrs)
+		   || lookup_attribute ("restore_ds", attrs);
+  else
+    return attrs && (lookup_attribute ("assume_ds_data", attrs)
+		     || lookup_attribute ("restore_ds", attrs));
+}
+
+int
+ia16_restore_ds_function_rtx_p (rtx addr)
+{
+  tree type = ia16_get_function_type_for_addr (addr);
+  return ia16_restore_ds_function_type_p (type);
+}
+
+int
+ia16_in_restore_ds_function_p (void)
+{
+  if (! cfun)
+    return TARGET_ASSUME_DS_DATA && call_used_regs[DS_REG];
+  ia16_cache_function_info (false);
+  return (cfun->machine->cached_callcvt & IA16_CALLCVT_RESTORE_DS) != 0;
+}
+
+/* Return true iff TYPE is a type for a function which assumes that %ss
+   points to the program's data segment on function entry.  */
+int
+ia16_ss_data_function_type_p (const_tree funtype)
+{
+  tree attrs = funtype ? TYPE_ATTRIBUTES (funtype) : NULL_TREE;
+
+  if (TARGET_ASSUME_SS_DATA)
+    return ! attrs || ! lookup_attribute ("no_assume_ss_data", attrs);
+  else
+    return attrs && lookup_attribute ("assume_ss_data", attrs);
+}
+
+int
+ia16_in_ss_data_function_p (void)
+{
+  if (! cfun)
+    return TARGET_ASSUME_SS_DATA;
+  ia16_cache_function_info (false);
+  return (cfun->machine->cached_callcvt & IA16_CALLCVT_SS_DATA) != 0;
+}
+
+/* Re-recognize INSN: match PATTERN (INSN), which has likely just been
+   modified, to the corresponding instruction pattern in the machine
+   description, and update INSN_CODE (INSN).  */
+void
+ia16_recog (rtx_insn *insn)
+{
+  INSN_CODE (insn) = recog (PATTERN (insn), insn, NULL);
+}
+
+static int
+ia16_near_section_function_type_p (const_tree funtype)
+{
+  tree attrs = TYPE_ATTRIBUTES (funtype);
+  return attrs && lookup_attribute ("near_section", attrs);
+}
+
+static int
+ia16_far_section_function_type_p (const_tree funtype)
+{
+  tree attrs = TYPE_ATTRIBUTES (funtype);
+  return attrs && lookup_attribute ("far_section", attrs);
+}
+
+static int
+ia16_in_far_section_function_p (void)
+{
+  if (! cfun)
+    return 0;
+  ia16_cache_function_info (false);
+  return (cfun->machine->cached_callcvt & IA16_CALLCVT_FAR_SECTION) != 0;
+}
+
+/* Basic Stack Layout */
+/* Right after the function prologue, before elimination, we have:
+   argument N
+   argument N - 1
+   ...
+   argument 1
+   return address		<-- argument pointer
+   saved reg 1
+   saved reg 2
+   ...
+   saved reg N
+   saved reg bp?		<-- frame pointer
+   local variables start
+   local variables end		<-- stack pointer
+   function outgoing arguments
+*/
+
+/* Calculates the offset from the argument pointer to the first argument.
+ * When a frame pointer is needed and bp must be saved, it is saved before the
+ * frame is created.  This increases the offset to the parameters by 2 bytes.
+ * A __far call would add another 2 bytes.
+ * FIXME: Docs: This is called before register allocation.
+ */
+HOST_WIDE_INT
+ia16_first_parm_offset (tree fundecl)
+{
+  /* Start off with 2 bytes to skip over the saved pc register.  */
+  HOST_WIDE_INT offset = GET_MODE_SIZE (Pmode);
+
+  /* Add 2 bytes if this is a far function.  */
+  if (ia16_far_function_type_p (TREE_TYPE (fundecl)))
+    offset += GET_MODE_SIZE (Pmode);
+
+  return (offset);
+}
+
+/* Eliminating Frame Pointer and Arg Pointer */
+
+#undef	TARGET_FRAME_POINTER_REQUIRED
+#define TARGET_FRAME_POINTER_REQUIRED	ia16_frame_pointer_required
+
+static bool
+ia16_frame_pointer_required (void)
+{
+  /* We absolutely need a frame pointer to refer to arguments passed on the
+     stack and local variables placed on the stack frame.  The GCC
+     middle-end does not know about this IA-16 peculiarity, so we need to
+     inform it.
+
+     TODO: This still forces a frame pointer as long as the function _has_
+     stack arguments, even if it does not actually read them.  We should fix
+     this, as an optimization.  The fix may involve scanning the insn stream.
+	-- tkchia  */
+  return crtl->args.info >= 4 || cfun->stdarg || get_frame_size () != 0;
+}
+
+#undef	TARGET_CAN_ELIMINATE
+#define	TARGET_CAN_ELIMINATE	ia16_can_eliminate
+
+static bool
+ia16_can_eliminate (const int from, const int to)
+{
+  if (ARG_POINTER_REGNUM == from && FRAME_POINTER_REGNUM == to)
+    return true;
+
+  /* There seems to be some wackiness in GCC's register elimination logic.
+
+     So yes, for some reason I need to specify a %sp -> %bp elimination in
+     ELIMINABLE_REGS, and do something for INITIAL_ELIMINATION_OFFSET
+     (STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM, ) --- and then say here
+     that GCC should not actually perform the elimination anyway.
+
+     If I omit the %sp -> %bp elimination, GCC will hang while compiling
+     libgcc.  If I specify a %bp -> %sp elimination instead, GCC will crash.
+     And actually _enabling_ a %sp -> %bp elimination results in incorrect
+     code.  Argh.  -- tkchia  */
+  if (STACK_POINTER_REGNUM == from)
+    return false;
+
+  gcc_unreachable ();
+}
+
+/* Calculates the difference between the argument pointer and the frame
+ * pointer immediately after the function prologue.  This should be kept int
+ * sync with the prologue pattern.
+ */
+static HOST_WIDE_INT
+ia16_initial_arg_pointer_offset (void)
+{
+  HOST_WIDE_INT offset = 0;
+  unsigned int i;
+
+  /* Add two bytes for each register saved.  */
+  for (i = 0; i <= LAST_ALLOCABLE_REG; i ++)
+    {
+      if (ia16_save_reg_p (i))
+	offset += GET_MODE_SIZE (HImode);
+    }
+  return offset;
+}
+
+/* Calculates the difference between the frame pointer and the stack pointer
+ * values immediately after the function prologue.  This should be kept in sync
+ * with the prologue pattern.
+ */
+HOST_WIDE_INT
+ia16_initial_frame_pointer_offset (void)
+{
+  HOST_WIDE_INT offset;
+
+  offset = get_frame_size ();
+
+  return offset;
+}
+
+HOST_WIDE_INT
+ia16_initial_elimination_offset (unsigned int from, unsigned int to)
+{
+  if (ARG_POINTER_REGNUM == from && FRAME_POINTER_REGNUM == to)
+    return (ia16_initial_arg_pointer_offset ());
+
+  if (STACK_POINTER_REGNUM == from && FRAME_POINTER_REGNUM == to)
+    return (-ia16_initial_frame_pointer_offset ());
+
+  gcc_unreachable ();
+}
+
+/* Passing Arguments in Registers */
+
+static bool may_need_printf_nofloat = false, may_need_printf_float = false,
+	    may_need_scanf_nofloat = false, may_need_scanf_float = false;
+
+static void
+ia16_handle_unnamed_function_arg (const_tree type)
+{
+  /* If the user's code passes a floating-point operand as a variadic
+     argument, assume that it might need the floating-point version of the
+     ...printf (...) functions.  Similarly, if there is a variadic argument
+     which is a pointer to a non-const floating-point operand, assume a need
+     for floating-point ...scanf (...).
+
+     FIXME: this does not detect the case of code doing something like scanf
+     ("%*f...", ...), where the program needs floating-point support but there
+     is no pointer argument.  -- tkchia 20190331  */
+  if (TARGET_NEWLIB_AUTOFLOAT_STDIO)
+    {
+      if (type)
+	{
+	  if (SCALAR_FLOAT_TYPE_P (type))
+	    may_need_printf_float = true;
+	  else if (POINTER_TYPE_P (type)
+		   && ! TYPE_READONLY (TREE_TYPE (type))
+		   && SCALAR_FLOAT_TYPE_P (TREE_TYPE (type)))
+	    may_need_scanf_float = true;
+	}
+    }
+}
+
+#undef  TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG ia16_function_arg
+
+static rtx
+ia16_function_arg (cumulative_args_t cum_v, machine_mode mode,
+		   const_tree type, bool named)
+{
+  CUMULATIVE_ARGS *cum;
+
+  if (! named)
+    {
+      ia16_handle_unnamed_function_arg (type);
+      return NULL;
+    }
+
+  cum = get_cumulative_args (cum_v);
+
+  switch (mode)
+    {
+    case QImode:
+    case HImode:
+    case PHImode:
+    case V2QImode:
+      switch (*cum)
+	{
+	case 0:
+	  return gen_rtx_REG (mode, A_REG);
+	case 1:
+	  return gen_rtx_REG (mode, D_REG);
+	case 2:
+	  return gen_rtx_REG (mode, C_REG);
+	default:
+	  return NULL;
+	}
+
+    case SImode:
+    case SFmode:
+      switch (*cum)
+      {
+      case 0:				/* %dx:%ax */
+	return gen_rtx_REG (mode, A_REG);
+      case 1:				/* %cx:%dx */
+	{
+	  rtx dx = gen_rtx_REG (HImode, D_REG);
+	  rtx list0 = gen_rtx_EXPR_LIST (VOIDmode, dx, const0_rtx);
+	  rtx cx = gen_rtx_REG (HImode, C_REG);
+	  rtx list1 = gen_rtx_EXPR_LIST (VOIDmode, cx, const2_rtx);
+	  return gen_rtx_PARALLEL (mode, gen_rtvec (2, list0, list1));
+	}
+      default:
+	return NULL;
+      }
+
+    default:
+      return NULL;
+    }
+}
+
+static bool
+ia16_regparmcall_function_type_p (const_tree fntype)
+{
+  return ia16_get_call_parm_cvt (fntype) == CALL_PARM_CVT_REGPARMCALL;
+}
+
+void
+ia16_init_cumulative_args (CUMULATIVE_ARGS *cum, const_tree fntype,
+			   rtx libname ATTRIBUTE_UNUSED,
+			   const_tree fndecl ATTRIBUTE_UNUSED,
+			   int n_named_args ATTRIBUTE_UNUSED)
+{
+  if (TARGET_NEWLIB_AUTOFLOAT_STDIO && fntype != NULL_TREE)
+    {
+      tree attrs = TYPE_ATTRIBUTES (fntype);
+      if (attrs != NULL_TREE)
+	{
+	  tree attr = lookup_attribute ("format", attrs);
+	  if (attr)
+	    {
+	      tree args = TREE_VALUE (attr);
+	      tree format_type_id = TREE_VALUE (args);
+	      if (TREE_CODE (format_type_id) == IDENTIFIER_NODE)
+		{
+		  const char *format_type_str
+		    = IDENTIFIER_POINTER (format_type_id);
+		  if (strstr ("printf", format_type_str))
+		    may_need_printf_nofloat = true;
+		  else if (strstr ("scanf", format_type_str))
+		    may_need_scanf_nofloat = true;
+		}
+	    }
+	}
+    }
+
+  if (! ia16_regparmcall_function_type_p (fntype))
+    *cum = 3;
+  else
+    *cum = 0;
+}
+
+#undef  TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE ia16_function_arg_advance
+
+static void
+ia16_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
+                           const_tree type ATTRIBUTE_UNUSED,
+			   bool named ATTRIBUTE_UNUSED)
+{
+  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
+
+  if (*cum >= 3 || ! named)
+    {
+      *cum = 4;
+      return;
+    }
+
+  switch (mode)
+    {
+    case QImode:
+    case HImode:
+    case PHImode:
+    case V2QImode:
+      ++*cum;
+      return;
+
+    case SImode:
+    case SFmode:
+      switch (*cum)
+	{
+	case 0:
+	  *cum = 2;
+	  return;
+	case 1:
+	  *cum = 3;
+	  return;
+	default:
+	  *cum = 4;
+	  return;
+	}
+
+    default:
+      *cum = 4;
+      return;
+    }
+}
+
+#undef  TARGET_VECTOR_MODE_SUPPORTED_P
+#define TARGET_VECTOR_MODE_SUPPORTED_P ia16_vector_mode_supported_p
+static bool
+ia16_vector_mode_supported_p (enum machine_mode mode)
+{
+  return (mode == V2QImode);
+}
+
+/* How Scalar Function Values Are Returned */
+#undef  TARGET_FUNCTION_VALUE
+#define TARGET_FUNCTION_VALUE ia16_function_value
+
+static rtx
+ia16_function_value (const_tree ret_type,
+		     const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
+		     bool outgoing ATTRIBUTE_UNUSED)
+{
+  return gen_rtx_REG (TYPE_MODE (ret_type), A_REG);
+}
+
+#undef	TARGET_LIBCALL_VALUE
+#define	TARGET_LIBCALL_VALUE	ia16_libcall_value
+
+static rtx
+ia16_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
+{
+  if (! HARD_REGNO_MODE_OK (A_REG, mode))
+    return NULL;
+
+  return gen_rtx_REG (mode, A_REG);
+}
+
+#undef	TARGET_FUNCTION_VALUE_REGNO_P
+#define	TARGET_FUNCTION_VALUE_REGNO_P ia16_function_value_regno_p
+
+static bool
+ia16_function_value_regno_p (unsigned regno)
+{
+  return regno == A_REG;
+}
+
+/* How Large Values Are Returned */
+/* FIXME Documentation: This is for scalar values as well.  */
+#undef  TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY ia16_return_in_memory
+
+static bool
+ia16_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
+{
+  /* Return in memory if it's larger than 4 bytes or BLKmode.
+   * TODO: Increase this to 8 bytes or so.  Doing so requires more call
+   * used registers or requires the prologue and epilogue patterns to not
+   * touch the return value registers.  */
+   return (TYPE_MODE (type) == BLKmode || int_size_in_bytes (type) > 4);
+}
+
+#undef	TARGET_GET_RAW_RESULT_MODE
+#define	TARGET_GET_RAW_RESULT_MODE ia16_get_raw_result_mode
+
+static machine_mode
+ia16_get_raw_result_mode (int regno)
+{
+  switch (regno)
+    {
+    case A_REG:
+      return SImode;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+#undef	TARGET_GET_RAW_ARG_MODE
+#define	TARGET_GET_RAW_ARG_MODE ia16_get_raw_arg_mode
+
+static machine_mode
+ia16_get_raw_arg_mode (int regno)
+{
+  switch (regno)
+    {
+    case A_REG:
+    case D_REG:
+    case C_REG:
+      return HImode;
+    case AH_REG:
+    case DH_REG:
+    case CH_REG:
+    case DS_REG:
+      return VOIDmode;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Permitting tail calls */
+#undef  TARGET_FUNCTION_OK_FOR_SIBCALL
+#define TARGET_FUNCTION_OK_FOR_SIBCALL ia16_function_ok_for_sibcall
+static bool
+ia16_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
+{
+  /* For now, only allow sibcalling known functions.
+     TODO: Try relaxing this.  */
+  if (! decl)
+    return false;
+
+  /* If the current function is a far function, but the callee is not a far
+     function, then do not allow a sibcall.  */
+  if (ia16_in_far_function_p ()
+      && ! ia16_far_function_type_p (TREE_TYPE (decl)))
+    return false;
+
+  /* Ditto if the current function is a near function but not the callee.  */
+  if (! ia16_in_far_function_p ()
+      && ia16_far_function_type_p (TREE_TYPE (decl)))
+    return false;
+
+  return true;
+}
+
+/* Passing Function Arguments on the Stack */
+#undef	TARGET_RETURN_POPS_ARGS
+#define	TARGET_RETURN_POPS_ARGS ia16_return_pops_args
+
+static int
+ia16_return_pops_args (tree fundecl ATTRIBUTE_UNUSED, tree funtype, int size)
+{
+  /* Note that the `-mrtd' or `-mregparmcall' calling convention will also be
+     applied to libgcc library functions (e.g. __udivdi3).  This usually
+     means that, if we compile code using `-mrtd'/`-mregparmcall', we will
+     need a libgcc multilib compiled with the same option to link against our
+     code.  */
+  if (stdarg_p (funtype))
+    return 0;
+
+  switch (ia16_get_callcvt (funtype)
+	  & (IA16_CALLCVT_STDCALL | IA16_CALLCVT_CDECL
+	     | IA16_CALLCVT_REGPARMCALL))
+    {
+    case IA16_CALLCVT_STDCALL:
+    case IA16_CALLCVT_REGPARMCALL:
+      return size;
+    case IA16_CALLCVT_CDECL:
+      return 0;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Implementing the Varargs Macros */
+#undef	TARGET_STRICT_ARGUMENT_NAMING
+#define TARGET_STRICT_ARGUMENT_NAMING ia16_strict_argument_naming
+
+static bool
+ia16_strict_argument_naming (cumulative_args_t cum_v ATTRIBUTE_UNUSED)
+{
+  return true;
+}
+
+/* Defining target-specific uses of __attribute__ */
+#undef	TARGET_ATTRIBUTE_TABLE
+#define	TARGET_ATTRIBUTE_TABLE ia16_attribute_table
+
+static tree
+ia16_handle_cconv_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
+			     int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+{
+  switch (TREE_CODE (*node))
+    {
+    case FUNCTION_TYPE:
+    case METHOD_TYPE:
+      break;
+
+    default:
+      warning (OPT_Wattributes, "%qE attribute only applies to functions",
+				name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  if (is_attribute_p ("stdcall", name))
+    {
+      tree attrs = TYPE_ATTRIBUTES (*node);
+      if (attrs && (lookup_attribute ("cdecl", attrs)
+		    || lookup_attribute ("regparmcall", attrs)))
+	{
+	  error ("stdcall, cdecl, and regparmcall attributes are "
+		 "not compatible");
+	  *no_add_attrs = true;
+	}
+      return NULL_TREE;
+    }
+  else if (is_attribute_p ("cdecl", name))
+    {
+      tree attrs = TYPE_ATTRIBUTES (*node);
+      if (attrs && (lookup_attribute ("stdcall", attrs)
+		    || lookup_attribute ("regparmcall", attrs)))
+	{
+	  error ("stdcall, cdecl, and regparmcall attributes are "
+		 "not compatible");
+	  *no_add_attrs = true;
+	}
+      return NULL_TREE;
+    }
+  else if (is_attribute_p ("regparmcall", name))
+    {
+      tree attrs = TYPE_ATTRIBUTES (*node);
+      if (attrs && (lookup_attribute ("cdecl", attrs)
+		    || lookup_attribute ("stdcall", attrs)))
+	{
+	  error ("stdcall, cdecl, and regparmcall attributes are "
+		 "not compatible");
+	  *no_add_attrs = true;
+	}
+      return NULL_TREE;
+    }
+
+  if (! ia16_far_function_type_p (*node)
+      && (is_attribute_p ("near_section", name)
+	  || is_attribute_p ("far_section", name)))
+    {
+      warning (OPT_Wattributes, "%qE attribute directive ignored for "
+				"non-far function", name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  /* The following attributes are ignored for non-far functions.  */
+  else if (is_attribute_p ("near_section", name))
+    {
+      tree attrs = TYPE_ATTRIBUTES (*node);
+      if (attrs && lookup_attribute ("far_section", attrs))
+	{
+	  error ("near_section and far_section attributes are not compatible");
+	  *no_add_attrs = true;
+	}
+      return NULL_TREE;
+    }
+  else if (is_attribute_p ("far_section", name))
+    {
+      tree attrs = TYPE_ATTRIBUTES (*node);
+      if (attrs && lookup_attribute ("near_section", attrs))
+	{
+	  error ("near_section and far_section attributes are not compatible");
+	  *no_add_attrs = true;
+	}
+      return NULL_TREE;
+    }
+
+  if (is_attribute_p ("assume_ss_data", name))
+    {
+      tree attrs = TYPE_ATTRIBUTES (*node);
+      if (attrs && lookup_attribute ("no_assume_ss_data", attrs))
+	{
+	  error ("assume_ss_data and no_assume_ss_data attributes are not "
+		 "compatible");
+	  *no_add_attrs = true;
+	}
+      return NULL_TREE;
+    }
+  else if (is_attribute_p ("no_assume_ss_data", name))
+    {
+      tree attrs = TYPE_ATTRIBUTES (*node);
+      if (lookup_attribute ("assume_ss_data", attrs))
+	{
+	  error ("assume_ss_data and no_assume_ss_data attributes are not "
+		 "compatible");
+	  *no_add_attrs = true;
+	}
+      return NULL_TREE;
+    }
+
+  if (! call_used_regs[DS_REG]
+      && (is_attribute_p ("assume_ds_data", name)
+	  || is_attribute_p ("no_assume_ds_data", name)))
+    {
+      warning (OPT_Wattributes, "%qE attribute directive ignored as %%ds is "
+				"a call-saved register", name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  /* The following attributes are ignored if %ds is a call-saved register.  */
+  else if (is_attribute_p ("assume_ds_data", name))
+    {
+      tree attrs = TYPE_ATTRIBUTES (*node);
+      if (attrs && lookup_attribute ("no_assume_ds_data", attrs))
+	{
+	  error ("assume_ds_data and no_assume_ds_data attributes are not "
+		 "compatible");
+	  *no_add_attrs = true;
+	}
+      return NULL_TREE;
+    }
+  else if (is_attribute_p ("no_assume_ds_data", name))
+    {
+      tree attrs = TYPE_ATTRIBUTES (*node);
+      if (lookup_attribute ("assume_ds_data", attrs))
+	{
+	  error ("assume_ds_data and no_assume_ds_data attributes are not "
+		 "compatible");
+	  *no_add_attrs = true;
+	}
+      return NULL_TREE;
+    }
+
+  if (is_attribute_p ("restore_ds", name))
+    {
+      if (fixed_regs[DS_REG])
+	{
+	  warning (OPT_Wattributes, "%qE attribute directive ignored as "
+				    "%%ds is a fixed register", name);
+	  *no_add_attrs = true;
+	  return NULL_TREE;
+	}
+    }
+
+  return NULL_TREE;
+}
+
+static const struct attribute_spec ia16_attribute_table[] =
+{
+  { "stdcall", 0, 0, false, true, true, ia16_handle_cconv_attribute, true },
+  { "cdecl",   0, 0, false, true, true, ia16_handle_cconv_attribute, true },
+  { "regparmcall",
+	       0, 0, false, true, true, ia16_handle_cconv_attribute, true },
+  { "assume_ds_data",
+	       0, 0, false, true, true, ia16_handle_cconv_attribute, true },
+  { "no_assume_ds_data",
+	       0, 0, false, true, true, ia16_handle_cconv_attribute, true },
+  { "assume_ss_data",
+	       0, 0, false, true, true, ia16_handle_cconv_attribute, true },
+  { "no_assume_ss_data",
+	       0, 0, false, true, true, ia16_handle_cconv_attribute, true },
+  { "restore_ds",
+	       0, 0, false, true, true, ia16_handle_cconv_attribute, true },
+  { "near_section",
+	       0, 0, false, true, true, ia16_handle_cconv_attribute, true },
+  { "far_section",
+	       0, 0, false, true, true, ia16_handle_cconv_attribute, true },
+  { NULL,      0, 0, false, false, false, NULL,			     false }
+};
+
+#undef	TARGET_COMP_TYPE_ATTRIBUTES
+#define TARGET_COMP_TYPE_ATTRIBUTES ia16_comp_type_attributes
+
+static int
+ia16_comp_type_attributes (const_tree type1, const_tree type2)
+{
+  if (TREE_CODE (type1) != FUNCTION_TYPE
+      && TREE_CODE (type1) != METHOD_TYPE)
+    return 1;
+
+  return (ia16_get_callcvt (type1) & ~IA16_CALLCVT_FAR_SECTION)
+	 == (ia16_get_callcvt (type2) & ~IA16_CALLCVT_FAR_SECTION);
+}
+
+#undef	TARGET_SET_DEFAULT_TYPE_ATTRIBUTES
+#define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES ia16_set_default_type_attributes
+
+static void
+ia16_set_default_type_attributes (tree type)
+{
+  if (TARGET_CMODEL_IS_FAR_TEXT)
+    {
+      /* Messy hack to make all functions far, when compiling code for a
+	 far-text memory model.  Here the "unqualified" version of a function
+	 type is actually implicitly qualified with a __far.  */
+      switch (TREE_CODE (type))
+	{
+	case FUNCTION_TYPE:
+	case METHOD_TYPE:
+	  if (ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (type)))
+	    TYPE_ADDR_SPACE (type) = ADDR_SPACE_FAR;
+	  break;
+	default:
+	  break;
+	}
+    }
+}
+
+#undef	TARGET_INSERT_ATTRIBUTES
+#define	TARGET_INSERT_ATTRIBUTES ia16_insert_attributes
+
+/* In ia16-no-ss-data.c .  */
+extern GTY ((deletable)) struct target_rtl *ia16_ss_data_target_rtl;
+extern GTY ((deletable)) struct target_rtl *ia16_no_ss_data_target_rtl;
+extern void ia16_insert_attributes (tree, tree *);
+
+#undef	TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P
+#define	TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P \
+	ia16_function_attribute_inlinable_p
+
+static bool
+ia16_function_attribute_inlinable_p (const_tree fndecl)
+{
+  /* Allow FNDECL to be inlined into the current function if the two
+     functions' calling conventions are "close enough".
+
+     Do not inline FNDECL if its caling convention makes more assumptions on
+     function entry than CFUN.
+
+     And, do not inline __attribute__ ((far_section)) functions.  There will
+     probably be special reasons why these functions are marked as such.  */
+  unsigned their_cvt = ia16_get_callcvt (TREE_TYPE (fndecl));
+  unsigned our_cvt;
+
+  if ((their_cvt & IA16_CALLCVT_FAR_SECTION) != 0)
+    return false;
+
+  ia16_cache_function_info (false);
+  our_cvt = cfun->machine->cached_callcvt;
+
+  /* Whether the caller and/or callee is/are near_section is not very
+     important...  */
+  our_cvt &= ~IA16_CALLCVT_NEAR_SECTION;
+  their_cvt &= ~IA16_CALLCVT_NEAR_SECTION;
+
+  if (their_cvt == our_cvt
+      || their_cvt == (our_cvt & ~IA16_CALLCVT_SS_DATA))
+    return true;
+
+  return false;
+}
+
+/* Addressing Modes */
+
+#undef  TARGET_ADDR_SPACE_ADDRESS_MODE
+#define TARGET_ADDR_SPACE_ADDRESS_MODE ia16_as_address_mode
+
+static enum machine_mode
+ia16_as_address_mode (addr_space_t addrspace)
+{
+  switch (addrspace)
+    {
+    case ADDR_SPACE_GENERIC:
+    case ADDR_SPACE_SEG_SS:
+      return HImode;
+    /* A far address is actually a HImode value which is "coloured" with a
+       segment term -- (plus:HI ...  (unspec:HI ...  UNSPEC_SEG_OVERRIDE)).
+       See ia16_as_convert_weird_memory_address (...) below.  */
+    case ADDR_SPACE_FAR:
+      return HImode;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+#undef  TARGET_ADDR_SPACE_POINTER_MODE
+#define TARGET_ADDR_SPACE_POINTER_MODE ia16_as_pointer_mode
+
+static machine_mode
+ia16_as_pointer_mode (addr_space_t addrspace)
+{
+  switch (addrspace)
+    {
+    case ADDR_SPACE_GENERIC:
+    case ADDR_SPACE_SEG_SS:
+      return HImode;
+    case ADDR_SPACE_FAR:
+      return SImode;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+#undef  TARGET_ADDR_SPACE_VALID_POINTER_MODE
+#define TARGET_ADDR_SPACE_VALID_POINTER_MODE ia16_as_valid_pointer_mode
+
+static bool
+ia16_as_valid_pointer_mode (machine_mode m, addr_space_t addrspace)
+{
+  switch (addrspace)
+    {
+    case ADDR_SPACE_GENERIC:
+    case ADDR_SPACE_SEG_SS:
+      return m == HImode;
+    case ADDR_SPACE_FAR:
+      return m == SImode;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+bool
+ia16_have_seg_override_p (rtx x)
+{
+  switch (GET_CODE (x))
+    {
+    case UNSPEC:
+      /* Basis case.  */
+      return (XINT (x, 1) == UNSPEC_SEG_OVERRIDE);
+    case PLUS:
+      return ia16_have_seg_override_p (XEXP (x, 0)) ||
+	     ia16_have_seg_override_p (XEXP (x, 1));
+    case MINUS:
+      return ia16_have_seg_override_p (XEXP (x, 0));
+    default:
+      return false;
+    }
+}
+
+#define REGNO_OK_FOR_SEGMENT_P(num) \
+	ia16_regno_in_class_p ((num), SEGMENT_REGS)
+
+#undef  TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P
+#define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P ia16_as_legitimate_address_p
+
+static bool
+ia16_as_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x,
+			      bool strict, addr_space_t as)
+{
+  rtx r1, r2, r9;
+  if (as == ADDR_SPACE_FAR && !ia16_have_seg_override_p (x))
+    return false;
+  if (CONSTANT_P (x))
+    return true;
+  if (!ia16_parse_address (x, &r1, &r2, NULL, &r9, as))
+    return false;
+  if (r9 != NULL_RTX && strict)
+    {
+      int r9no = REGNO (r9);
+      if (r9no > LAST_HARD_REG && reg_renumber != 0)
+	{
+	  r9no = reg_renumber[r9no];
+	  if (r9no < 0 || r9no > LAST_HARD_REG)
+	    return false;
+	}
+      if (!REGNO_OK_FOR_SEGMENT_P (r9no))
+        return false;
+    }
+
+  if (r1 == NULL_RTX)
+    return true;
+  int r1no = REGNO (r1);
+  bool r1ok = (r1no > LAST_HARD_REG);
+  if (strict)
+    {
+      r1ok = false;
+      if (r1no > LAST_HARD_REG && reg_renumber != 0)
+        {
+          r1no = reg_renumber[r1no];
+          if (r1no < 0 || r1no > LAST_HARD_REG)
+            return false;
+        }
+    }
+  if (r2 == NULL_RTX)
+    return REGNO_MODE_OK_FOR_BASE_P (r1no, mode) || r1ok;
+  int r2no = REGNO (r2);
+  bool r2ok = (r2no > LAST_HARD_REG);
+  if (strict)
+    {
+      r2ok = false;
+      if (r2no > LAST_HARD_REG && reg_renumber != 0)
+        {
+          r2no = reg_renumber[r2no];
+          if (r2no < 0 || r2no > LAST_HARD_REG)
+            return false;
+        }
+    }
+  if ((REGNO_OK_FOR_INDEX_P (r1no) || r1ok)
+      && (REGNO_MODE_OK_FOR_REG_BASE_P (r2no, mode) || r2ok))
+    return true;
+  return (REGNO_OK_FOR_INDEX_P (r2no) || r2ok)
+    && (REGNO_MODE_OK_FOR_REG_BASE_P (r1no, mode) || r1ok);
+}
+
+#undef  TARGET_ADDR_SPACE_ZERO_ADDRESS_VALID
+#define TARGET_ADDR_SPACE_ZERO_ADDRESS_VALID ia16_as_zero_address_valid
+
+static bool
+ia16_as_zero_address_valid (addr_space_t addrspace)
+{
+  switch (addrspace)
+    {
+    case ADDR_SPACE_GENERIC:
+      return false;
+    case ADDR_SPACE_SEG_SS:
+    case ADDR_SPACE_FAR:
+      return true;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+rtx
+ia16_bless_selector (rtx seg)
+{
+  if (TARGET_PROTECTED_MODE && GET_MODE (seg) != PHImode)
+    seg = force_reg (PHImode, gen_rtx_TRUNCATE (PHImode, seg));
+  return seg;
+}
+
+rtx
+ia16_seg_override_term (rtx seg)
+{
+  if (TARGET_PROTECTED_MODE)
+    return gen_seg_override_prot_mode (ia16_bless_selector (seg));
+  else
+    return gen_seg_override (seg);
+}
+
+static rtx
+ia16_seg16_reloc (rtx thang)
+{
+  if (TARGET_PROTECTED_MODE)
+    return gen_seg16_reloc_prot_mode (thang);
+  else
+    return gen_seg16_reloc (thang);
+}
+
+static void
+ia16_error_seg_reloc (location_t loc, const char *msg)
+{
+  if (msg)
+    error_at (loc, "%s", msg);
+  inform (loc, "use %<-m%s%> to allow this",
+	  TARGET_CMODEL_IS_TINY ? "cmodel=small" : "segment-relocation-stuff");
+}
+
+rtx
+ia16_as_convert_weird_memory_address (machine_mode to_mode, rtx x,
+				      addr_space_t as,
+				      bool in_const ATTRIBUTE_UNUSED,
+				      bool no_emit)
+{
+  rtx r1, r2, c, off, r9;
+
+  gcc_assert (as == ADDR_SPACE_FAR);
+
+  switch (to_mode)
+  {
+  case HImode:
+    /* We want a far address, while x is possibly a far pointer.
+
+       A far _pointer_ will likely appear in the form
+
+	(... (reg/f:SI <i>) ...)
+
+       i.e. an expression involving a register _pair_.  To form a far
+       _address_, split this up into its segment and offset components, and
+       pretend that the result is actually just a HImode operand, like so:
+
+	(set (reg:HI <o>) (subreg:HI (reg/f:SI <i>) 0))
+	(set (reg:HI <s>) (subreg:HI (reg/f:SI <i>) 2))
+	(... (plus:HI (unspec:HI [(reg:SEG <s>)] UNSPEC_SEG_OVERRIDE)
+		      (reg:HI <o>)) ...)
+
+       This is (partially) in accord with gcc/rtl.h (see a comment at struct
+       address_info), which says that `(unspec ...)' is typically used to
+       represent segments.  */
+
+    if (ia16_have_seg_override_p (x))
+      return x;
+
+    if (no_emit)
+      return NULL_RTX;
+
+    gcc_assert (GET_MODE (x) == SImode || GET_MODE (x) == VOIDmode);
+
+    x = force_reg (SImode, x);
+    r1 = force_reg (HImode, gen_rtx_SUBREG (HImode, x, 0));
+    r9 = force_reg (SEGmode, gen_rtx_SUBREG (SEGmode, x, 2));
+
+    x = gen_rtx_PLUS (HImode, r1, ia16_seg_override_term (r9));
+    return x;
+
+  case SImode:
+    /* We want a far pointer, while x is possibly a far address.  */
+    if (! ia16_parse_address (x, &r1, &r2, &c, &r9, as))
+      return x;
+
+    if (no_emit)
+      return NULL_RTX;
+
+    if (! r9)
+      {
+	switch (GET_CODE (x))
+	  {
+	  case CONST_INT:
+	    /* Absolute far address --- nothing to do.  */
+	    return x;
+
+	  case SYMBOL_REF:
+	    /* Address of a far static variable.  */
+	    if (! TARGET_SEG_RELOC_STUFF)
+	      {
+		ia16_error_seg_reloc (input_location,
+				      "cannot take address of far static "
+				      "variable");
+		/* continue after that... */
+	      }
+
+	    /* If CFUN is NULL, we are building a static initializer
+	       containing the address of a far static variable.  */
+	    if (! cfun)
+	      return gen_static_far_ptr (x);
+
+	    /* Otherwise, create a pseudo-register the normal way for the
+	       segment term.  */
+	    r9 = ia16_seg16_reloc (x);
+	    break;
+
+	  default:
+	    fprintf (stderr, "No idea how to convert this far address/pointer "
+			     "to an SImode:\n");
+	    debug_rtx (x);
+	    gcc_unreachable ();
+	  }
+      }
+
+    off = NULL_RTX;
+    if (r1)
+      off = r2 ? gen_rtx_PLUS (HImode, r1, r2) : r1;
+    if (c)
+      off = off ? gen_rtx_PLUS (HImode, x, c) : c;
+
+    if (!off)
+      off = const0_rtx;
+
+    x = gen_reg_rtx (SImode);
+    emit_move_insn (gen_rtx_SUBREG (HImode, x, 0), off);
+    emit_move_insn (gen_rtx_SUBREG (GET_MODE (r9), x, 2), r9);
+    return x;
+
+  default:
+    fprintf (stderr, "Trying to convert this far address/pointer to an "
+		     "unexpected mode %u:\n", (unsigned) to_mode);
+    debug_rtx (x);
+    gcc_unreachable ();
+  }
+}
+
+rtx
+ia16_expand_weird_pointer_plus_expr (rtx op0, rtx op1, rtx target,
+				     machine_mode mode)
+{
+  rtx seg, op0_off, off, sum;
+
+  if (mode != SImode && mode != VOIDmode)
+    {
+      fprintf (stderr, "Trying to do far pointer addition with unexpected "
+		       "target mode %u:\n", (unsigned) mode);
+      debug_rtx (op0);
+      debug_rtx (op1);
+      gcc_unreachable ();
+    }
+
+  gcc_assert (GET_MODE (op0) == SImode || GET_MODE (op0) == VOIDmode);
+  gcc_assert (GET_MODE (op1) == HImode || GET_MODE (op1) == VOIDmode);
+
+  if (GET_CODE (op0) == CONST
+      && GET_CODE (XEXP (op0, 0)) == UNSPEC
+      && XINT (XEXP (op0, 0), 1) == UNSPEC_STATIC_FAR_PTR)
+    {
+      /* This pointer arithmetic operation occurs within a static
+	 initializer.  */
+      op0 = XVECEXP (XEXP (op0, 0), 0, 0);
+      return gen_static_far_ptr (gen_rtx_PLUS (GET_MODE (op0), op0, op1));
+    }
+
+  op0 = force_reg (SImode, op0);
+
+  seg = gen_rtx_SUBREG (SEGmode, op0, 2);
+  op0_off = gen_rtx_SUBREG (HImode, op0, 0);
+
+  off = force_reg (HImode, gen_rtx_PLUS (HImode, op0_off, op1));
+
+  if (target && REG_P (target) && GET_MODE (target) == SImode)
+    sum = target;
+  else
+    sum = gen_reg_rtx (SImode);
+
+  emit_move_insn (gen_rtx_SUBREG (HImode, sum, 0), off);
+  emit_move_insn (gen_rtx_SUBREG (SEGmode, sum, 2), seg);
+  return sum;
+}
+
+/* Used by ia16_as_legitimize_address, and by ia16.md.  */
+void
+ia16_split_seg_override_and_offset (rtx x, rtx *ovr, rtx *off)
+{
+  machine_mode m = GET_MODE (x);
+  rtx op0, op1;
+  rtx op0_ovr, op0_off, op1_ovr, op1_off;
+
+  switch (GET_CODE (x))
+    {
+    case UNSPEC:
+      if (XINT (x, 1) == UNSPEC_SEG_OVERRIDE)
+	{
+	  *ovr = x;
+	  *off = NULL_RTX;
+	  break;
+	}
+      /* fall through */
+    default:
+      *ovr = NULL_RTX;
+      *off = x;
+      break;
+
+    case PLUS:
+      op0 = XEXP (x, 0);
+      op1 = XEXP (x, 1);
+
+      ia16_split_seg_override_and_offset (op0, &op0_ovr, &op0_off);
+      ia16_split_seg_override_and_offset (op1, &op1_ovr, &op1_off);
+
+      gcc_assert (! op0_ovr || ! op1_ovr);
+      *ovr = op0_ovr ? op0_ovr : op1_ovr;
+
+      if (! op0_off)
+	*off = op1_off;
+      else if (! op1_off)
+	*off = op0_off;
+      else if (op0 == op0_off && op1 == op1_off)
+	*off = x;
+      else
+	*off = gen_rtx_PLUS (m, op0_off, op1_off);
+      break;
+
+    case MINUS:
+      op0 = XEXP (x, 0);
+      op1 = XEXP (x, 1);
+
+      ia16_split_seg_override_and_offset (op0, &op0_ovr, &op0_off);
+      *ovr = op0_ovr;
+      if (! op0_off)
+	*off = gen_rtx_NEG (m, op1);
+      else
+	*off = gen_rtx_MINUS (m, op0_off, op1);
+    }
+}
+
+#undef	TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS
+#define	TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS ia16_as_legitimize_address
+
+static rtx
+ia16_as_legitimize_address (rtx x, rtx oldx,
+			    machine_mode mode ATTRIBUTE_UNUSED,
+			    addr_space_t as ATTRIBUTE_UNUSED)
+{
+  rtx ovr, off, newx;
+
+  if (as == ADDR_SPACE_GENERIC
+      || as == ADDR_SPACE_SEG_SS
+      || ia16_as_legitimate_address_p (mode, x, false, as))
+    return x;
+
+  /* We must be able to transform an expression like
+   *
+   *	                       (plus:HI)
+   *	                      /         \
+   *	              (plus:HI)         (mem:HI)
+   *	                /  \               |
+   *	(unspec:HI [.] 1)  (reg:HI 25)  (plus:HI)
+   *	            |                     /  \
+   *	      (reg:HI 26)       (reg:HI 15)  (const_int 4)
+   *
+   * (q.v. https://github.com/tkchia/gcc-ia16/issues/6) into something
+   * resembling an IA-16 addressing mode.
+   *
+   * Because of the segment override term (unspec:HI [.] 1), we cannot
+   * simply force-fit the whole thing into a (reg:HI) with force_reg (...)
+   * and call it a day.
+   *
+   * What we can do is to split the expression into its segment override and
+   * offset components.  Then we _can_ try to force the offset component
+   * into a single (reg:HI), if needed.
+   */
+  gcc_assert (GET_MODE (x) == HImode);
+
+  ia16_split_seg_override_and_offset (x, &ovr, &off);
+
+  if (! off)
+    off = const0_rtx;
+
+  /* This lack of a segment override may mean one of two things.
+
+     One possibility is that we want to take the address of a far static
+     variable.
+
+     Alternatively, it may be due to GCC's internal probing ---
+     specifically, tree-ssa-loop-ivopts.c creates nonsense addresses in
+     order to gauge the costs of using different addressing modes.
+
+     This code needs to work in both cases.  */
+  if (! ovr)
+    ovr = ia16_seg_override_term (force_reg (SEGmode,
+					     ia16_seg16_reloc (oldx)));
+
+  newx = gen_rtx_PLUS (HImode, off, ovr);
+  if (ia16_as_legitimate_address_p (mode, newx, false, as))
+    return newx;
+
+  return gen_rtx_PLUS (HImode, force_reg (HImode, off), ovr);
+}
+
+#undef	TARGET_ADDR_SPACE_SUBSET_P
+#define	TARGET_ADDR_SPACE_SUBSET_P ia16_as_subset_p
+
+static bool
+ia16_as_subset_p (addr_space_t subset, addr_space_t superset)
+{
+  return superset == ADDR_SPACE_FAR
+	 && (subset == ADDR_SPACE_GENERIC || subset == ADDR_SPACE_SEG_SS);
+}
+
+rtx
+ia16_far_pointer_offset (rtx op)
+{
+  /* Use (subreg ...) if we can.  Otherwise use (truncate ...).  */
+  if (REG_P (op))
+    return gen_rtx_SUBREG (HImode, op, 0);
+  else
+    return gen_rtx_TRUNCATE (HImode, op);
+}
+
+#undef	TARGET_ADDR_SPACE_CONVERT
+#define	TARGET_ADDR_SPACE_CONVERT ia16_as_convert
+
+static rtx
+ia16_as_convert (rtx op, tree from_type, tree to_type)
+{
+  addr_space_t from_as, to_as;
+
+  gcc_assert (POINTER_TYPE_P (from_type));
+  gcc_assert (POINTER_TYPE_P (to_type));
+
+  from_type = TREE_TYPE (from_type);
+  to_type = TREE_TYPE (to_type);
+
+  from_as = TYPE_ADDR_SPACE (from_type);
+  to_as = TYPE_ADDR_SPACE (to_type);
+
+  if (from_as == ADDR_SPACE_FAR
+      && (to_as == ADDR_SPACE_GENERIC || to_as == ADDR_SPACE_SEG_SS))
+    {
+      /* We only handle pointers for now --- not addresses.  */
+      gcc_assert (GET_MODE (op) == SImode || GET_MODE (op) == VOIDmode);
+
+      return ia16_far_pointer_offset (op);
+    }
+  else if (to_as == ADDR_SPACE_FAR
+	   && (from_as == ADDR_SPACE_GENERIC || from_as == ADDR_SPACE_SEG_SS))
+    {
+      unsigned seg_reg_no = SS_REG;
+
+      rtx op2 = gen_reg_rtx (SImode);
+      gcc_assert (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode);
+
+      if (from_as == ADDR_SPACE_GENERIC)
+	{
+	  if (FUNC_OR_METHOD_TYPE_P (from_type))
+	    seg_reg_no = CS_REG;
+	  else if (! ia16_in_ss_data_function_p ())
+	    seg_reg_no = DS_REG;
+	}
+
+      emit_move_insn (gen_rtx_SUBREG (HImode, op2, 0), op);
+      emit_move_insn (gen_rtx_SUBREG (SEGmode, op2, 2),
+		      gen_rtx_REG (SEGmode, seg_reg_no));
+
+      return op2;
+    }
+  else
+    {
+      fprintf (stderr, "Trying to convert address-space-%d pointer to "
+		       "address-space-%d:\n", (int) from_as, (int) to_as);
+      debug_rtx (op);
+      gcc_unreachable ();
+    }
+}
+
+/* Condition Code Status */
+/* Return the "smallest" usable comparison mode for the given comparison
+ * operator OP and operands X and Y.  BRANCH is true if we are optimizing for
+ * a branch instruction.  */
+enum machine_mode
+ia16_select_cc_mode (enum rtx_code op, rtx x, rtx y,
+		     bool branch ATTRIBUTE_UNUSED)
+{
+  switch (op)
+    {
+    case EQ:
+    case NE:
+      /* TODO: Explain why we check nonimmediate_operand(x) here.  */
+      if ((y == const0_rtx || y == constm1_rtx)
+	   && nonimmediate_operand (x, GET_MODE (x)))
+	return y == const0_rtx ? CCZ_Cmode : CCZ_NCmode;
+      else
+	return CCZmode;
+
+    case LT:
+    case GE:
+      /* We don't need to set the overflow flag when comparing against zero.
+	 The add/sub instructions don't set the overflow flag usefully.  */
+      if (y == const0_rtx)
+	return CCSmode;
+      else
+	return CCSOmode;
+
+    case LE:
+    case GT:
+      /* We have no jump instructions for CCSZmode, so always use CCSOZmode.  */
+      return CCSOZmode;
+
+    case LTU:
+    case GEU:
+      return CCCmode;
+
+    case LEU:
+    case GTU:
+      /* Detect overflow checks.  */
+      if (GET_CODE (x) == MINUS
+	  && rtx_equal_p (XEXP (x, 0), y))
+	return CCCZ_NCmode;
+      /* Comparison against immediates don't need to set the zero flag.  */
+      return immediate_operand (y, GET_MODE (y)) ? CCCZ_Cmode : CCCZmode;
+
+    default:
+    return CCmode;
+    }
+}
+
+/* Emit a comparison instruction for the comparison operator OP and the two
+ * operands X and Y. If BRANCH is true, optimize for a branch instruction.
+ * Return the register which holds the comparison result.  */
+rtx
+ia16_gen_compare_reg (enum rtx_code op, rtx x, rtx y, bool branch)
+{
+  enum machine_mode mode = ia16_select_cc_mode (op, x, y, branch);
+  rtx cc_reg = gen_rtx_REG (mode, CC_REG);
+
+  emit_insn (gen_rtx_SET (cc_reg, gen_rtx_COMPARE (mode, x, y)));
+  return cc_reg;
+}
+
+#undef  TARGET_CANONICALIZE_COMPARISON
+#define TARGET_CANONICALIZE_COMPARISON ia16_canonicalize_comparison
+
+static void
+ia16_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
+			      bool op0_preserve_value ATTRIBUTE_UNUSED)
+{
+  if ((*code == EQ || *code == NE) && GET_CODE (*op1) == NEG)
+    {
+      *op0 = gen_rtx_PLUS (GET_MODE (*op0), *op0, XEXP (*op1, 0));
+      *op1 = const0_rtx;
+    }
+}
+
+#undef  TARGET_FIXED_CONDITION_CODE_REGS
+#define TARGET_FIXED_CONDITION_CODE_REGS ia16_fixed_condition_code_regs
+
+/* CC_REG is a fixed condition code register.  */
+static bool
+ia16_fixed_condition_code_regs (unsigned int *reg1, unsigned int *reg2)
+{
+	*reg1 = CC_REG;
+	*reg2 = INVALID_REGNUM;
+	return (true);
+}
+
+#undef  TARGET_CC_MODES_COMPATIBLE
+#define TARGET_CC_MODES_COMPATIBLE ia16_cc_modes_compatible
+
+/* TODO: Convert this into a table.  */
+enum machine_mode
+ia16_cc_modes_compatible (enum machine_mode mode1, enum machine_mode mode2)
+{
+  switch (mode1)
+    {
+
+      case CCSCmode:
+	switch (mode2)
+	  {
+	    case CCSCZmode:
+	      return (CCSCZmode);
+	    case CCSCmode:
+	    case CCCmode:
+	      return (CCSCmode);
+	    case CCZ_Cmode:
+	    case CCZ_NCmode:
+	    case CCCZ_Cmode:
+	    case CCCZ_NCmode:
+	      return (VOIDmode);
+	    default:
+	      return (CCmode);
+	  }
+
+      case CCSOZmode:
+	switch (mode2)
+	  {
+	    case CCSOZmode:
+	    case CCSOmode:
+	    case CCSZmode:
+	    case CCZmode:
+	      return (CCSOZmode);
+	    case CCZ_Cmode:
+	    case CCZ_NCmode:
+	    case CCCZ_Cmode:
+	    case CCCZ_NCmode:
+	      return (VOIDmode);
+	    default:
+	      return (CCmode);
+	  }
+
+      case CCSOmode:
+	switch (mode2)
+	  {
+	    case CCSOZmode:
+	    case CCSOmode:
+	      return (mode2);
+	    case CCSmode:
+	      return (CCSOmode);
+	    case CCZ_Cmode:
+	    case CCZ_NCmode:
+	    case CCCZ_Cmode:
+	    case CCCZ_NCmode:
+	      return (VOIDmode);
+	    default:
+	      return (CCmode);
+	  }
+
+      case CCSmode:
+	switch (mode2)
+	  {
+	    case CCSZmode:
+	    case CCSOmode:
+	    case CCSOZmode:
+	      return (mode2);
+	    case CCZ_Cmode:
+	    case CCZ_NCmode:
+	    case CCCZ_Cmode:
+	    case CCCZ_NCmode:
+	      return (VOIDmode);
+	    default:
+	      return (CCmode);
+	  }
+
+      case CCCZmode:
+	switch (mode2)
+	  {
+	    case CCSCZmode:
+	      return (CCSCZmode);
+	    case CCCZmode:
+	    case CCZmode:
+	    case CCCmode:
+	      return (CCCZmode);
+	    case CCZ_Cmode:
+	    case CCZ_NCmode:
+	    case CCCZ_Cmode:
+	    case CCCZ_NCmode:
+	      return (VOIDmode);
+	    default:
+	      return (CCmode);
+	  }
+
+      case CCZmode:
+	switch (mode2)
+	  {
+	    case CCSCZmode:
+	    case CCSOZmode:
+	    case CCSZmode:
+	    case CCCZmode:
+	    case CCZmode:
+	      return (mode2);
+	    case CCSOmode:
+	      return (CCSOZmode);
+	    case CCCmode:
+	      return (CCCZmode);
+	    case CCZ_Cmode:
+	    case CCZ_NCmode:
+	    case CCCZ_Cmode:
+	    case CCCZ_NCmode:
+	      return (VOIDmode);
+	    default:
+	      return (CCmode);
+	  }
+
+      case CCCmode:
+	switch (mode2)
+	  {
+	    case CCSCZmode:
+	    case CCSCmode:
+	    case CCCZmode:
+	    case CCCmode:
+	      return (mode2);
+	    case CCZmode:
+	      return (CCCZmode);
+	    case CCZ_Cmode:
+	    case CCZ_NCmode:
+	    case CCCZ_Cmode:
+	    case CCCZ_NCmode:
+	      return (VOIDmode);
+	    default:
+	      return (CCmode);
+	  }
+
+      case CCZ_Cmode:
+	switch (mode2)
+	  {
+	    case CCZ_Cmode:
+	    case CCCZ_Cmode:
+	      return (mode2);
+	    default:
+	      return (VOIDmode);
+	  }
+
+      case CCZ_NCmode:
+	switch (mode2)
+	  {
+	    case CCZ_NCmode:
+	    case CCCZ_NCmode:
+	      return (mode2);
+	    default:
+	      return (VOIDmode);
+	  }
+
+      case CCCZ_Cmode:
+	switch (mode2)
+	  {
+	    case CCZ_Cmode:
+	    case CCCZ_Cmode:
+	      return (mode1);
+	    default:
+	      return (VOIDmode);
+	  }
+
+      case CCCZ_NCmode:
+	switch (mode2)
+	  {
+	    case CCZ_NCmode:
+	    case CCCZ_NCmode:
+	      return (mode1);
+	    default:
+	      return (VOIDmode);
+	  }
+
+      case CCmode:
+	switch (mode2)
+	  {
+	    case CCZ_Cmode:
+	    case CCZ_NCmode:
+	    case CCCZ_Cmode:
+	    case CCCZ_NCmode:
+	      return (VOIDmode);
+	    default:
+	      return (CCmode);
+	  }
+
+      default:
+	return (VOIDmode);
+    }
+    gcc_unreachable ();
+}
+
+/* Describing Relative Costs of Operations */
+
+/* This is modelled after the i386 port.
+   Often, there are different costs reg,reg->reg, mem,reg->reg
+   and reg,mem->mem.  The cost of memory address calculation, calculated using
+   ea_calc (also for lea), will be added except for xlat.
+*/
+struct processor_costs {
+  const int byte_fetch;		/* cost of fetching an instruction byte.  */
+  int (*const ea_calc)(rtx r1, rtx r2, rtx c, rtx r9);
+				/* cost of calculating an address.  */
+  const int move;		/* cost of reg-reg mov instruction.  */
+  const int imm_load[2];	/* cost of loading imm (QI, HI) to register.  */
+  const int imm_store[2];	/* cost of storing imm (QI, HI) to memory.  */
+  const int int_load[2];	/* cost of loading integer register
+				   from memory in QImode and HImode.  */
+  const int int_store[2];	/* cost of storing integer register
+				   to memory in QImode and HImode */
+  const int move_ratio;		/* The threshold of number of scalar
+				   memory-to-memory move insns.  */
+  const int add[3];		/* cost of an add instruction */
+  const int add_imm[2];		/* cost of an add imm (reg, mem) instruction */
+  const int inc_dec[2];
+  const int lea;		/* cost of a lea instruction */
+  const int cmp[3];		/* cost of a cmp instruction */
+  const int cmp_imm[2];		/* cost of a cmp imm (reg, mem) instruction */
+  const int shift_1bit[2];	/* single bit shift/rotate cost */
+  const int shift_start[2];	/* cost of starting shift/rotate (reg, mem) */
+  const int shift_bit;		/* cost of shift/rotate per bit */
+  const int s_mult_init[2][2];	/* cost of starting a signed multiply in
+				   { QI { r, m }, HI { r, m } } */
+  const int u_mult_init[2][2];	/* cost of starting an unsigned multiply in
+				   { QI { r, m }, HI { r, m } } */
+  const int mult_imm_init[2];	/* cost of starting imul reg/mem.  */
+  const int mult_bit;		/* cost of multiply per each bit set */
+  const int s_divide[2][2];	/* cost of a signed divide/mod
+				   in QImode, HImode */
+  const int u_divide[2][2];	/* cost of an unsigned divide.  */
+  const int sign_extend[2];	/* The cost of sign extension (QI, HI).  */
+  const int xlat;		/* cost of an xlat instruction.  */
+  const int call[3];		/* cost of call {imm, reg, mem}.  */
+  const int fp_move;		/* cost of reg,reg fld/fst */
+  const int fp_load[3];		/* cost of loading FP register
+				   in SFmode, DFmode and XFmode */
+  const int fp_store[3];	/* cost of storing FP register
+				   in SFmode, DFmode and XFmode */
+  const int branch_cost;	/* Default value for BRANCH_COST.  */
+  const int fadd;		/* cost of FADD and FSUB instructions.  */
+  const int fmul;		/* cost of FMUL instruction.  */
+  const int fdiv;		/* cost of FDIV instruction.  */
+  const int fabs;		/* cost of FABS instruction.  */
+  const int fchs;		/* cost of FCHS instruction.  */
+  const int fsqrt;		/* cost of FSQRT instruction.  */
+};
+
+extern const  struct processor_costs *ia16_costs;
+extern struct processor_costs ia16_size_costs;
+
+#define IA16_COST(F)	\
+	(MAX (ia16_costs->F, ia16_costs->byte_fetch * ia16_size_costs.F))
+
+#define C(x)	COSTS_N_INSNS(x)
+
+/* Return the cost of a constant X in mode MODE in an OUTER_CODE rtx.  */
+/* TODO: Accurate costs of vector constants.  */
+static int
+ia16_constant_cost (rtx x, enum machine_mode mode, int outer_code)
+{
+  HOST_WIDE_INT n;
+
+  if (!CONST_INT_P (x))
+    return (C (ia16_costs->byte_fetch * GET_MODE_SIZE (Pmode)));
+
+  n = INTVAL (x);
+  if (mode == VOIDmode)
+    mode = Pmode;
+
+  /* Some instructions have implicit constants.  */
+  if (n == 1)
+    switch (outer_code)
+      {
+	case PLUS:
+	case MINUS:
+	case ASHIFT:
+	case ASHIFTRT:
+	case LSHIFTRT:
+	case ROTATE:
+	case ROTATERT:
+	case EQ:
+	case NE:
+	case LTU:
+	case GEU:
+	case LEU:
+	case GTU:
+	case GT:
+	case LT:
+	case LE:
+	case GE:
+	  return (C (0));
+
+	default:
+	  break;
+      }
+  if (n == 0)
+    switch (outer_code)
+      {
+	case MINUS:
+	case EQ:
+	case NE:
+	case LTU:
+	case GEU:
+	case LEU:
+	case GTU:
+	case GT:
+	case LT:
+	case LE:
+	case GE:
+	  return (C (0));
+
+	default:
+	  break;
+      }
+  if ((outer_code == PLUS && n == -1)
+      || ((outer_code == AND || outer_code == XOR)
+	 && (n == 255 || n == -256)))
+    return (C (0));
+
+  /* Most instructions can sign extend 8-bit constants.  Exceptions:
+   * "movw $imm, reg", "testw $imm, dest" and "enterw $imm, $level".
+   * We catch the "movw" case here.  We try to peephole "testw" away.
+   * Some insn alternatives for "add", "andw", "orw" and "xorw" hack
+   * zero extension of 8-bit constants.
+   */
+  if ((outer_code != SET && n >= -128 && n <= 127)
+      || (outer_code == AND
+	 && ((n & 0xff00) == 0xff00 || (n & 0x00ff) == 0x00ff))
+      || ((outer_code == IOR || outer_code == XOR)
+	 && ((n & 0xff00) == 0x0000 || (n & 0xff00) == 0x0000))
+      || (outer_code == PLUS && (n & 0x00ff) == 0x0000))
+    return (C (ia16_costs->byte_fetch));
+  else
+    return (C (ia16_costs->byte_fetch * GET_MODE_SIZE (mode)));
+}
+
+/* Return the cost of an address when not optimizing for an Intel i808x.
+ */
+static int
+ia16_default_address_cost (rtx r1, rtx r2, rtx c, rtx r9 ATTRIBUTE_UNUSED)
+{
+  int total = 0;
+
+  if (c)
+    total = ia16_constant_cost (c, Pmode, MEM);
+
+  /* If r1 == r2, a "movw" instruction is needed.  */
+  if (rtx_equal_p (r1, r2))
+     total += IA16_COST (move);
+
+  return (total);
+}
+
+static bool
+ia16_seg_override_cost_likely_p (rtx r9, rtx r1, rtx r2)
+{
+  /* Map our RTL semantics to the x86 instruction set's segment override
+     weirdness.
+
+     On the RTL side:
+       * A null segment override (R9) means we are accessing an operand in
+	 the generic address space.  If we can assume that %ss points to
+	 this space (the default), then %ds _might_ point to this space ---
+	 if the function assumes that %ds == .data on startup, and if the
+	 function we are compiling does not use %ds for anything.  If we
+	 cannot assume that %ss == .data, then we must have %ds == .data
+	 (for now).
+       * If R9 is not null, then we are accessing an operand at an offset
+	 from the specified segment.
+
+     On the machine code side, no segment override is needed if
+       * our operand is an offset from %ss, and the offset involves the
+	 register %bp (or the virtual "register" %argp); or
+       * our operand is an offset from %ds, and %bp is not involved.  */
+  unsigned seg_reg_no = ia16_in_ss_data_function_p () ? SS_REG : DS_REG;
+
+  if (r9 && REG_P (r9))
+    seg_reg_no = REGNO (r9);
+
+  if (r1 && REG_P (r1)
+      && (REGNO (r1) == BP_REG || REGNO (r1) == ARGP_REG))
+    {
+      if (seg_reg_no == SS_REG)
+	return false;
+    }
+  else if (r2 && REG_P (r2)
+      && (REGNO (r2) == BP_REG || REGNO (r2) == ARGP_REG))
+    {
+      if (seg_reg_no == SS_REG)
+	return false;
+    }
+  else
+    {
+      if (seg_reg_no == DS_REG)
+	return false;
+    }
+  return true;
+}
+
+/* Calculate address cost for Intel i8086/i8088.  Note that %bp + %si or
+ * %bx + %di costs one more cycle than %bp + %di or %bx + %si.
+ * The %bp addressing mode is really 0 + %bp but we ignore that.
+ */
+static int
+ia16_i808x_address_cost (rtx r1, rtx r2, rtx c, rtx r9)
+{
+  int cost = 0;
+
+  if (r1)
+    {
+      if (r2)
+        {
+          cost = (C (7) + C (8)) / 2;
+
+          /* If r1 == r2, a "movw" instruction is needed.  */
+          if (rtx_equal_p (r1, r2))
+            cost += IA16_COST (move);
+        }
+      else
+        cost = C (5);
+
+      if (c)
+        cost += C (4) + ia16_constant_cost (c, Pmode, MEM);
+    }
+  else
+    {
+      if (c)
+	cost = C (6) + ia16_constant_cost (c, Pmode, MEM);
+    }
+
+  if (ia16_seg_override_cost_likely_p (r9, r1, r2))
+    cost += C (2);
+
+  return (cost);
+}
+
+/* Return the cost of an address when optimizing for size rather than speed. */
+static int
+ia16_size_address_cost (rtx r1, rtx r2, rtx c, rtx r9)
+{
+  /* Treat the r/m portion of a mod-r/m encoding as taking up half a byte.  */
+  int cost = C (1) / 2;
+
+  if (r1)
+    {
+      if (r2)
+        {
+          /* If r1 == r2, a "movw" instruction is needed.  */
+          if (rtx_equal_p (r1, r2))
+            cost += IA16_COST (move);
+        }
+    }
+
+  if (c)
+    cost += ia16_constant_cost (c, Pmode, MEM);
+
+  if (ia16_seg_override_cost_likely_p (r9, r1, r2))
+    cost += C (1);
+
+  return (cost);
+}
+
+/* Size costs for IA-16 instructions.  Used when optimizing for size.
+ * EA sizes are not included except for xlat.
+ */
+ struct processor_costs ia16_size_costs = {
+  /* byte_fetch */	1,
+  /* ea_calc */		ia16_size_address_cost,
+  /* move */		C (2),
+  /* imm_load */	{ C (1), C (1) },
+  /* imm_store */	{ C (2), C (2) },
+  /* int_load */	{ C (2), C (2) },
+  /* int_store */	{ C (2), C (2) },
+  /* move_ratio */	C (4),
+  /* add */		{ C (2), C (2), C (2) },
+  /* add_imm */		{ C (2), C (2) },
+  /* inc_dec */		{ C (1), C (2) },
+  /* lea */		C (2),
+  /* cmp */		{ C (2), C (2), C (2) },
+  /* cmp_imm */		{ C (2), C (2) },
+  /* shift_1bit	*/	{ C (2), C (2) },
+  /* shift_start */	{ C (2), C (2) },
+  /* shift_bit */	C (0),
+  /* s_mult_init */	{ { C (2), C (2) }, { C (2), C (2) } },
+  /* u_mult_init */	{ { C (2), C (2) }, { C (2), C (2) } },
+  /* mult_imm_init */	{ C (2), C (2) },
+  /* mult_bit */	C (0),
+  /* s_divide */	{ { C (2), C (2) }, { C (2), C (2) } },
+  /* u_divide */	{ { C (2), C (2) }, { C (2), C (2) } },
+  /* sign_extend */	{ C (1), C (1) },
+  /* xlat */		C (1),
+  /* call */		{ C (1), C (1), C (1) },
+  0, { 0, 0, 0 }, { 0, 0, 0 },
+  /* branch_cost */	3,
+  0, 0, 0, 0, 0, 0,
+};
+
+/* Costs for Intel i8086 CPUs.  EA calculation time is not included.
+ * Timings have been derived from the Intel i8088 timings.
+ * TODO: .mult_bit is closer to 2 for signed multiplies.
+ */
+static struct processor_costs ia16_i8086_costs = {
+  /* byte_fetch	*/	2,
+  /* ea_calc */		ia16_i808x_address_cost,
+  /* move */		C (2),
+  /* imm_load */	{ C (4), C (4) },
+  /* imm_store */	{ C (10), C (10) },
+  /* int_load */	{ C (8), C (8) },
+  /* int_store */	{ C (9), C (9) },
+  /* move_ratio */	C (4),
+  /* add */		{ C (3), C (9), C (16) },
+  /* add_imm */		{ C (4), C (17) },
+  /* inc_dec */		{ C (3), C (16) },
+  /* lea */		C (2),
+  /* cmp */		{ C (3), C (9), C (9) },
+  /* cmp_imm */		{ C (4), C (10) },
+  /* shift_1bit */	{ C (2), C (15) },
+  /* shift_start */	{ C (8), C (20) },
+  /* shift_bit */	C (4),
+  /* s_mult_init */	{ { C (80), C (86) }, { C (128), C (134) } },
+  /* u_mult_init */	{ { C (70), C (76) }, { C (118), C (124) } },
+  /* mult_imm_init */	{ C (132), C (138) },
+  /* mult_bit */	C (1),
+  /* s_divide */	{ { C (106), C (112) }, { C (174), C (180) } },
+  /* u_divide */	{ { C (85), C (91) }, { C (153), C (159) } },
+  /* sign_extend */	{ C (2), C (5) },
+  /* xlat */		C (11),
+  /* call */		{ C (19), C (16), C (21) },
+  0, { 0, 0, 0 }, { 0, 0, 0 },
+  /* branch_cost */	16,
+  0, 0, 0, 0, 0, 0,
+};
+
+/* Costs for Intel 8088 CPUs.  EA calculation time is not included.  */
+/* TODO: .mult_bit is closer to 2 for signed multiplies.  */
+static struct processor_costs ia16_i8088_costs = {
+  /* byte_fetch */	4,
+  /* ea_calc */		ia16_i808x_address_cost,
+  /* move */		C (2),
+  /* imm_load */	{ C (4), C (4) },
+  /* imm_store */	{ C (10), C (14) },
+  /* int_load */	{ C (8), C (12) },
+  /* int_store */	{ C (9), C (13) },
+  /* move_ratio */	C (4),
+  /* add */		{ C (3), C (13), C (24) },
+  /* add_imm */		{ C (4), C (25) },
+  /* inc_dec */		{ C (3), C (24) },
+  /* lea */		C (2),
+  /* cmp */		{ C (3), C (13), C (13) },
+  /* cmp_imm */		{ C (4), C (14) },
+  /* shift_1bit */	{ C (2), C (23) },
+  /* shift_start */	{ C (8), C (28) },
+  /* shift_bit */	C (4),
+  /* s_mult_init */	{ { C (80), C (86) }, { C (128), C (138) } },
+  /* u_mult_init */	{ { C (70), C (76) }, { C (118), C (128) } },
+  /* mult_imm_init */	{ C (132), C (142) },
+  /* mult_bit */	C (1),
+  /* s_divide */	{ { C (106), C (112) }, { C (174), C (184) } },
+  /* u_divide */	{ { C (85), C (91) }, { C (153), C (163) } },
+  /* sign_extend */	{ C (2), C (5) },
+  /* xlat */		C (11),
+  /* call */		{ C (23), C (20), C (29) },
+  0, { 0, 0, 0 }, { 0, 0, 0 },
+  /* branch_cost */	16,
+  0, 0, 0, 0, 0, 0,
+};
+
+/* Costs for Intel 80186 CPUs.  EA calculation time (4 cycles for all modes)
+ * is included wherever appropriate.  */
+/* TODO: Intel 80188 timings.  */
+static struct processor_costs ia16_i80186_costs = {
+  /* byte_fetch	*/	2,
+  /* ea_calc */		ia16_default_address_cost,
+  /* move */		C (2),
+  /* imm_load */	{ C (3), C (4) },
+  /* imm_store */	{ C (12), C (13) },
+  /* int_load */	{ C (9), C (9) },
+  /* int_store */	{ C (12), C (12) },
+  /* move_ratio */	C (4),
+  /* add */		{ C (3), C (10), C (15) },
+  /* add_imm */		{ C (4), C (16) },
+  /* inc_dec */		{ C (3), C (15) },
+  /* lea */		C (6),
+  /* cmp */		{ C (3), C (10), C (10) },
+  /* cmp_imm */		{ C (3), C (10) },
+  /* shift_1bit */	{ C (2), C (15) },
+  /* shift_start */	{ C (5), C (17) },
+  /* shift_bit */	C (1),
+  /* s_mult_init */	{ { C (26), C (32) }, { C (35), C (41) } },
+  /* u_mult_init */	{ { C (27), C (33) }, { C (36), C (42) } },
+  /* mult_imm_init */	{ C (23), C (30) },
+  /* mult_bit */	C (0),
+  /* s_divide */	{ { C (48), C (54) }, { C (57), C (63) } },
+  /* u_divide */	{ { C (29), C (35) }, { C (38), C (44) } },
+  /* sign_extend */	{ C (2), C (4) },
+  /* xlat */		C (11),
+  /* call */		{ C (15), C (13), C (19) },
+  0, { 0, 0, 0 }, { 0, 0, 0 },
+  /* branch_cost */	13,
+  0, 0, 0, 0, 0, 0,
+};
+
+/* Costs for Intel 80286 CPUs.  EA calculation time (? cycles for all modes)
+ * is included wherever appropriate.  */
+/* TODO: Check timings for signed vs. unsigned multiply.  */
+static struct processor_costs ia16_i80286_costs = {
+  /* byte_fetch */	1, /* guess */
+  /* ea_calc */		ia16_default_address_cost,
+  /* move */		C (2),
+  /* imm_load */	{ C (2), C (2) },
+  /* imm_store */	{ C (3), C (3) },
+  /* int_load */	{ C (5), C (5) },
+  /* int_store */	{ C (3), C (3) },
+  /* move_ratio */	C (4),
+  /* add */		{ C (2), C (7), C (7) },
+  /* add_imm */		{ C (3), C (7) },
+  /* inc_dec */		{ C (2), C (7) },
+  /* lea */		C (3),
+  /* cmp */		{ C (3), C (6), C (7) },
+  /* cmp_imm */		{ C (3), C (6) },
+  /* shift_1bit */	{ C (2), C (7) },
+  /* shift_start */	{ C (5), C (8) },
+  /* shift_bit */	C (1),
+  /* s_mult_init */	{ { C (13), C (16) }, { C (21), C (24) } },
+  /* u_mult_init */	{ { C (13), C (16) }, { C (21), C (24) } },
+  /* mult_imm_init */	{ C (21), C (24) },
+  /* mult_bit */	C (0),
+  /* s_divide */	{ { C (17), C (20) }, { C (25), C (28) } },
+  /* u_divide */	{ { C (14), C (17) }, { C (22), C (25) } },
+  /* sign_extend */	{ C (2), C (2) },
+  /* xlat */		C (5),
+  /* call */		{ C (7), C (7), C (11) },
+  0, { 0, 0, 0 }, { 0, 0, 0 },
+  /* branch_cost */	7, /* FIXME: should really be 7 + m */
+  0, 0, 0, 0, 0, 0,
+};
+
+/* Costs for NEC V30 CPUs.  EA calculation time (2 cycles for all modes)
+ * is included wherever appropriate.  Timings are derived from the V20 ones.
+ */
+static struct processor_costs ia16_nec_v30_costs = {
+  /* byte_fetch */	2,
+  /* ea_calc */		ia16_default_address_cost,
+  /* move */		C (2),
+  /* imm_load */	{ C (4), C (4) },
+  /* imm_store */	{ C (11), C (11) },
+  /* int_load */	{ C (11), C (11) },
+  /* int_store */	{ C (9), C (9) },
+  /* move_ratio */	C (4),
+  /* add */		{ C (2), C (11), C (16) },
+  /* add_imm */		{ C (4), C (18) },
+  /* inc_dec */		{ C (2), C (16) },
+  /* lea */		C (4),
+  /* cmp */		{ C (2), C (11), C (11) },
+  /* cmp_imm */		{ C (4), C (13) },
+  /* shift_1bit */	{ C (2), C (16) },
+  /* shift_start */	{ C (7), C (19) },
+  /* shift_bit */	C (1),
+  /* s_mult_init */	{ { C (33), C (39) }, { C (47), C (53) } },
+  /* u_mult_init */	{ { C (21), C (30) }, { C (27), C (32) } },
+  /* mult_imm_init */	{ C (31), C (34) },
+  /* mult_bit */	C (0),
+  /* s_divide */	{ { C (29), C (35) }, { C (43), C (49) } },
+  /* u_divide */	{ { C (19), C (25) }, { C (25), C (31) } },
+  /* sign_extend */	{ C (2), C (4) },
+  /* xlat */		C (9),
+  /* call */		{ C (16), C (14), C (23) },
+  0, { 0, 0, 0 }, { 0, 0, 0 },
+  /* branch_cost */	14,
+  0, 0, 0, 0, 0, 0,
+};
+
+/* Costs for NEC V20 CPUs.  EA calculation time (2 cycles for all modes)
+ * is included wherever appropriate.  */
+static struct processor_costs ia16_nec_v20_costs = {
+  /* byte_fetch */	4,
+  /* ea_calc */		ia16_default_address_cost,
+  /* move */		C (2),
+  /* imm_load */	{ C (4), C (4) },
+  /* imm_store */	{ C (11), C (15) },
+  /* int_load */	{ C (11), C (15) },
+  /* int_store */	{ C (9), C (13) },
+  /* move_ratio */	C (4),
+  /* add */		{ C (2), C (15), C (24) },
+  /* add_imm */		{ C (4), C (26) },
+  /* inc_dec */		{ C (2), C (24) },
+  /* lea */		C (4),
+  /* cmp */		{ C (2), C (15), C (15) },
+  /* cmp_imm */		{ C (4), C (17) },
+  /* shift_1bit */	{ C (2), C (24) },
+  /* shift_start */	{ C (7), C (27) },
+  /* shift_bit */	C (1),
+  /* s_mult_init */	{ { C (33), C (39) }, { C (47), C (57) } },
+  /* u_mult_init */	{ { C (21), C (30) }, { C (27), C (36) } },
+  /* mult_imm_init */	{ C (31), C (38) },
+  /* mult_bit */	C (0),
+  /* s_divide */	{ { C (29), C (35) }, { C (43), C (53) } },
+  /* u_divide */	{ { C (19), C (25) }, { C (25), C (35) } },
+  /* sign_extend */	{ C (2), C (4) },
+  /* xlat */		C (9),
+  /* call */		{ C (20), C (18), C (31) },
+  0, { 0, 0, 0 }, { 0, 0, 0 },
+  /* branch_cost */	14,
+  0, 0, 0, 0, 0, 0,
+};
+
+#undef C
+
+/* This table must be in sync with enum processor_type in ia16.h.  */
+static const struct ptt processor_target_table[PROCESSOR_max] =
+{
+  {&ia16_i8086_costs,    0},
+  {&ia16_i8086_costs,    1},
+  {&ia16_i8086_costs,    4},
+  {&ia16_i8088_costs,   20},
+  {&ia16_nec_v30_costs,  1},
+  {&ia16_nec_v20_costs, 17},
+  {&ia16_i80186_costs,   7},
+  {&ia16_i80186_costs,  23},
+  {&ia16_i80286_costs,  15}
+};
+
+const struct processor_costs *ia16_costs = &ia16_i8086_costs;
+int ia16_features = 0;
+
+#define I_REG	0
+#define I_MEM	1
+#define O_REGREG 0
+#define O_MEMREG 1
+#define O_REGMEM 2
+#define M_QI	0
+#define M_HI	1
+
+#define I_RTX(x)	(MEM_P (x) ? I_MEM : I_REG)
+#define M_MOD(x)	(QImode == (x) ? M_QI : M_HI)
+#define M_RTX(x)	(QImode == GET_MODE (x) ? M_QI : M_HI)
+#define H_MOD(x)	ia16_mode_hwords (x)
+#define H_RTX(x)	ia16_mode_hwords (GET_MODE (x))
+
+static unsigned
+ia16_mode_hwords (machine_mode mode)
+{
+  return (GET_MODE_SIZE (mode) + 1) / 2;
+}
+
+/* Estimate the cost of a branch instruction.  */
+int
+ia16_branch_cost (bool speed_p, bool predictable_p ATTRIBUTE_UNUSED)
+{
+  if (speed_p)
+    return IA16_COST (branch_cost);
+  else
+    return ia16_size_costs.branch_cost;
+}
+
+#undef	TARGET_REGISTER_MOVE_COST
+#define	TARGET_REGISTER_MOVE_COST ia16_register_move_cost
+
+static int
+ia16_register_move_cost (machine_mode mode, reg_class_t from ATTRIBUTE_UNUSED,
+			 reg_class_t to ATTRIBUTE_UNUSED)
+{
+  return IA16_COST (move) * ia16_mode_hwords (mode);
+}
+
+#undef	TARGET_MEMORY_MOVE_COST
+#define	TARGET_MEMORY_MOVE_COST ia16_memory_move_cost
+
+/* It is, on average, slightly cheaper to copy to/from memory with al/ax
+ * than with other registers, because a faster, immediate address
+ * instruction exists.  Segments registers, if supported, would also be
+ * cheaper to copy to/from memory.
+ */
+static int
+ia16_memory_move_cost (machine_mode mode, reg_class_t rclass ATTRIBUTE_UNUSED,
+		       bool in)
+{
+  int cost;
+
+  if (in)
+    {
+      if (GET_MODE_SIZE (mode) == 1)
+	cost = IA16_COST (int_load[M_QI]);
+      else
+	cost = IA16_COST (int_load[M_HI]) * ia16_mode_hwords (mode);
+    }
+  else
+    {
+      if (GET_MODE_SIZE (mode) == 1)
+	cost = IA16_COST (int_store[M_QI]);
+      else
+	cost = IA16_COST (int_store[M_HI]) * ia16_mode_hwords (mode);
+    }
+
+  if (rclass == AX_REGS
+      || rclass == SEGMENT_REGS
+      || rclass == ES_REGS
+      || rclass == DS_REGS)
+    {
+      if (cost > COSTS_N_INSNS (1))
+	cost -= COSTS_N_INSNS (1);
+      else
+	cost = 1;
+    }
+
+  return cost;
+}
+
+#undef  TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST ia16_address_cost
+
+static int
+ia16_address_cost_internal (rtx address, addr_space_t as)
+{
+  rtx r1, r2, c, r9;
+
+  /* Addresses in stack pushes/pops are cheap.  */
+  if (PRE_MODIFY == GET_CODE (address)
+      || POST_MODIFY == GET_CODE (address)
+      || PRE_DEC == GET_CODE (address)
+      || POST_INC == GET_CODE (address))
+    return (0);
+
+  /* Check for a (call ...) address.  This is a hack, but without knowing
+   * the mode, this is the best we can do.  At least it won't crash.  */
+  if (MEM_P (address))
+    {
+      as = MEM_ADDR_SPACE (address);
+      address = XEXP (address, 0);
+    }
+
+  /* Parse the address.  */
+  ia16_parse_address (address, &r1, &r2, &c, &r9, as);
+
+  return IA16_COST (ea_calc (r1, r2, c, r9));
+}
+
+static int
+ia16_address_cost (rtx address, machine_mode, addr_space_t as, bool)
+{
+  return ia16_address_cost_internal(address, as);
+}
+
+/* Return true if X is a valid memory operand for xlat and return the cost
+ * in TOTAL.  Don't touch TOTAL otherwise.
+ * This is complicated because combine uses many different ways of expressing
+ * xlat.  We support:
+ * (mem:QI (plus:HI (zero_extend:HI (mem_subreg_reg:QI op1)) (base:HI))
+ * (mem:QI (plus:HI (zero_extract:HI (mem_subreg_reg:HI op1) (8) (8)) (base:HI))
+ * (mem:QI (plus:HI (and:HI (stuff:HI op1) (255)) (base:HI))
+ * (mem:QI (plus:HI (lshiftrt:HI (stuff) (const_int fubar)) (base:HI)))
+ * and strip subregs as necessary.
+ */
+static bool
+ia16_xlat_cost (rtx x, int *total)
+{
+      if (GET_MODE (x) != QImode)
+        return (false);
+      if (GET_CODE (XEXP (x, 0)) == PLUS)
+	{
+	  rtx plus, zext, op1, base;
+
+	  plus = XEXP (x, 0);
+	  zext = XEXP (plus, 0);
+	  base = XEXP (plus, 1);
+	  if (GET_CODE (zext) == SUBREG)
+	    zext = SUBREG_REG (zext);
+	  if (((GET_CODE (zext) != ZERO_EXTEND && GET_CODE (zext) != ZERO_EXTRACT
+	        && (GET_CODE (zext) != AND || !CONST_INT_P (XEXP (zext, 1))
+	            || INTVAL (XEXP (zext, 1)) != 255))
+	        && (GET_CODE (zext) != LSHIFTRT || !CONST_INT_P (XEXP (zext, 1))))
+	      || (!general_operand (base, Pmode)))
+	    return (false);
+	
+	  op1 = XEXP (zext, 0);
+/*	  op2 = XEXP (zext, 1); */
+	  if (GET_CODE (op1) == SUBREG)
+	    op1 = SUBREG_REG (op1);
+	  if (!REG_P (op1) && !MEM_P (op1)
+	      && (GET_CODE (op1) != LSHIFTRT /*|| !CONST_INT_P (op2)*/))
+	    return (false);
+	  *total = IA16_COST (xlat);
+
+	  /* We may need to load the extendee into a register.  */
+	  if (!REG_P (op1))
+	    *total += IA16_COST (int_load[M_QI]);
+
+	  /* We may need to load the base into a register.  */
+	  if (CONSTANT_P (base))
+	    *total += IA16_COST (imm_load[M_HI]);
+	  else if (MEM_P (base))
+	    *total += IA16_COST (int_load[M_HI])
+		      + ia16_address_cost_internal (XEXP (base, 0),
+						    MEM_ADDR_SPACE (base));
+	  return (true);	
+	}
+      return (false);
+}
+
+#undef  TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS	ia16_rtx_costs
+
+/* Compute a (partial) cost for rtx X.  Return true if the complete
+   cost has been computed, and false if subexpressions should be
+   scanned.  In either case, *TOTAL contains the cost result.
+   FIXME: When called from combine, we only ever see the source of SET
+   expressions. We don't want to return a higher cost for
+	(set (mem) (and (mem) (reg1))
+   than we do for
+	(set (reg2) (mem))
+	(set (reg2) (and (reg2) (reg1))
+	(set (mem) (reg2))
+   so don't count the MEM twice if we get only the source expression.
+*/
+
+static bool
+ia16_rtx_costs (rtx x, machine_mode mode, int outer_code_i,
+		int opno ATTRIBUTE_UNUSED, int *total, bool speed)
+{
+  enum rtx_code code = GET_CODE (x);
+  enum rtx_code outer_code = (enum rtx_code) outer_code_i;
+
+  switch (code)
+    {
+    case SET:
+      {
+	rtx op0 = XEXP (x, 0);
+	rtx op1 = XEXP (x, 1);
+
+	if (memory_operand (op0, GET_MODE (op0)))
+	  {
+	    if (register_operand (op1, GET_MODE (op1)))
+	      *total = IA16_COST (int_store[M_RTX (op0)]) * H_RTX (op0);
+	    else if (immediate_operand (op1, GET_MODE (op1)))
+	      *total = IA16_COST (imm_store[M_RTX (op0)]) * H_RTX (op0);
+	    else
+	      {
+#if 0
+		/* Arithmetic or logic instruction which writes to memory.
+		 * Subtract the mem,reg->reg cost which will incorrectly be
+		 * added in the MEM case below.  */
+		*total = IA16_COST (add[O_REGMEM]) - IA16_COST (add[O_MEMREG]);
+#else
+		do {} while (0);
+#endif
+	      }
+	  }
+	else
+	  {
+	    if (register_operand (op0, GET_MODE (op1)))
+	      {
+		if (register_operand (op1, GET_MODE (op1)))
+		  *total = IA16_COST (move);
+		else if (memory_operand (op1, GET_MODE (op1)))
+		  *total = IA16_COST (int_load[M_RTX (op1)]);
+		else if (immediate_operand (op1, GET_MODE (op1)))
+		  *total = IA16_COST (imm_load[M_RTX (op0)]);
+		*total *= H_RTX (op0);
+	      }
+	    /* Try to get constructs involving "xlat" right.  */
+	    else
+	      {
+		if (MEM_P (op1) && ia16_xlat_cost (op1, total))
+		  return (true);
+	      }
+	  }
+	return (false);
+      }
+
+    /* It is not easy to give an accurate cost of a memory access.  "movw" is
+     * handled above.  Return a reasonable estimate for arithmetic or logic
+     * instructions.  */
+    case MEM:
+      if ((outer_code == ZERO_EXTEND || outer_code == SET)
+	&& ia16_xlat_cost (x, total))
+	return (true);
+      *total = ia16_address_cost_internal (XEXP (x, 0), MEM_ADDR_SPACE (x));
+      /* This is never called recursively from the SET case.  */
+      if (outer_code == SET)
+	*total += IA16_COST (int_load[M_MOD (mode)]);
+#if 0 /* This is handled individually for each code.  */
+      else
+	*total += IA16_COST (add[O_MEMREG]) - IA16_COST (add[O_REGREG]);
+#endif
+      *total *= H_MOD (mode);
+      return (true);
+
+    case CONST:
+    case LABEL_REF:
+    case SYMBOL_REF:
+    case CONST_INT:
+    case CONST_VECTOR:
+      *total = ia16_constant_cost (x, mode, outer_code);
+      /* Take counter measures against prepare_cmp_insn().  */
+      if (outer_code == COMPARE && *total > COSTS_N_INSNS (1))
+	*total = COSTS_N_INSNS (1);
+      /* This is never called recursively from the SET case.  */
+      if (outer_code == SET)
+	*total += IA16_COST (imm_load[M_HI]);
+      return true;
+
+    case CONST_DOUBLE:
+      *total = ia16_costs->byte_fetch * COSTS_N_INSNS (4);
+      return true;
+
+    /* This is usually "xor reg,reg" or "mov $0, dest".  */
+    case ZERO_EXTEND:
+      if (outer_code == IOR || outer_code == XOR)
+	*total = 0;
+      else
+	*total = IA16_COST (add[I_RTX (XEXP (x, 0))]);
+
+      /* Avoid the extra high cost of a subreg.  */
+      if (GET_CODE (XEXP (x, 0)) == SUBREG)
+	{
+	  *total += rtx_cost (SUBREG_REG (XEXP (x, 0)), mode, code, 0, speed);
+	  return true;
+	}
+      return false;
+
+    case SIGN_EXTEND:
+      *total = IA16_COST (sign_extend[M_MOD (GET_MODE (XEXP (x, 0)))]);
+      return false;
+
+    /* TODO: Constant shift/rotate when !TARGET_SHIFT_IMM.  */
+    case ASHIFTRT:
+      if (outer_code != COMPARE && CONST_INT_P (XEXP (x, 1)))
+	{
+	  /* This is implemented using sign extension.  */
+	  if (mode == QImode && INTVAL (XEXP (x, 1)) >= 7)
+	    if (outer_code == SIGN_EXTEND)
+	      *total = 0;
+	    else
+	      *total = IA16_COST (sign_extend[M_QI]);
+	  else if (mode == HImode && INTVAL (XEXP (x, 1)) >= 15)
+	    *total = IA16_COST (sign_extend[M_HI]);
+          *total += rtx_cost (XEXP (x, 0), mode, code, 0, speed);
+          return true;
+	}
+      /* fall through */
+    case ASHIFT:
+      /* Sometimes we get the ASHIFT and the constant for free.  */
+      if (code == ASHIFT && mode == HImode
+	  && (outer_code == PLUS || outer_code == MINUS
+	     || outer_code == IOR || outer_code == XOR)
+          && CONST_INT_P (XEXP (x, 1))
+          && INTVAL (XEXP (x, 1)) == 8)
+	{
+	  *total = rtx_cost (XEXP (x, 0), mode, code, 0, speed);
+	  return true;
+	}
+    case LSHIFTRT:
+      /* Similiarly with LSHIFTRT.  */
+      if (code == LSHIFTRT && mode == HImode
+	  && (outer_code == IOR || outer_code == XOR)
+	  && CONST_INT_P (XEXP (x, 1))
+	  && INTVAL (XEXP (x, 1)) == 8)
+	{
+	  *total = rtx_cost (XEXP (x, 0), mode, code, 0, speed);
+	  return true;
+        }
+    case ROTATE:
+    case ROTATERT:
+      if (CONST_INT_P (XEXP (x, 1)))
+	if (mode == HImode && outer_code != COMPARE
+	 && INTVAL (XEXP (x, 1)) == 8)
+	  {
+	    /* This is implemented using movb or xchgb.  */
+	    *total = IA16_COST (add[O_REGREG])
+	      + rtx_cost (XEXP (x, 0), mode, code, 0, speed);
+	    return true;
+	  }
+	else if (INTVAL (XEXP (x, 1)) == 1)
+	  {
+	    *total = IA16_COST (shift_1bit[I_REG])
+	      + rtx_cost (XEXP (x, 0), mode, code, 0, speed);
+	  }
+	else
+	  *total = MAX (ia16_costs->shift_start[I_REG]
+		        + ia16_costs->shift_bit * INTVAL (XEXP (x, 1)),
+			ia16_size_costs.shift_start[I_REG]
+			* ia16_costs->byte_fetch);
+      else
+	*total = MAX (ia16_costs->shift_start[I_REG]
+		      + ia16_costs->shift_bit
+			* GET_MODE_BITSIZE (GET_MODE (XEXP (x, 1))) / 2,
+		      ia16_size_costs.shift_start[I_REG]
+			* ia16_costs->byte_fetch);
+
+      /* (subreg:QI (ashift:HI (zero_extend:HI (mem:QI ...))) 0) */
+      if (outer_code == SUBREG
+	  && (ZERO_EXTEND == GET_CODE (XEXP (x, 0))
+	      || SIGN_EXTEND == GET_CODE (XEXP (x,0))))
+	{
+	  *total += rtx_cost (XEXP (XEXP (x, 0), 0), mode, code, 0, speed);
+	  return true;
+	}
+      else
+	return false;
+
+    case MULT:
+      if (FLOAT_MODE_P (mode))
+	{
+	  *total = IA16_COST (fmul);
+	  return false;
+	}
+      else
+	{
+	  rtx op0 = XEXP (x, 0);
+	  rtx op1 = XEXP (x, 1);
+	  int nbits;
+
+	  /* (mult:HI (...) (const_int 257) is cheap.  */
+	  if (CONST_INT_P (op1) && INTVAL (op1) == 257 && mode == HImode)
+	    {
+	      *total = IA16_COST (add[O_REGREG])
+		+ rtx_cost (op0, mode, code, 0, speed);
+	      return true;
+            }
+	  if (CONST_INT_P (op1) && ia16_costs->mult_bit != 0)
+	    {
+	      unsigned HOST_WIDE_INT value = INTVAL (XEXP (x, 1));
+	      for (nbits = 0; value != 0; value &= value - 1)
+	        nbits++;
+	    }
+	  else
+	    /* This is arbitrary.  */
+	    nbits = 7 * H_MOD (mode);
+
+	  /* Compute costs correctly for widening multiplication.  */
+	  if ((GET_CODE (op0) == SIGN_EXTEND || GET_CODE (op1) == ZERO_EXTEND)
+	      && GET_MODE_SIZE (GET_MODE (XEXP (op0, 0))) * 2
+	         == GET_MODE_SIZE (mode))
+	    {
+	      int is_mulwiden = 0;
+	      enum machine_mode inner_mode = GET_MODE (op0);
+
+	      if (GET_CODE (op0) == GET_CODE (op1))
+		is_mulwiden = 1, op1 = XEXP (op1, 0);
+	      else if (CONST_INT_P (op1))
+		{
+		  if (GET_CODE (op0) == SIGN_EXTEND)
+		    is_mulwiden = trunc_int_for_mode (INTVAL (op1), inner_mode)
+			          == INTVAL (op1);
+		  else
+		    is_mulwiden = !(INTVAL (op1) & ~GET_MODE_MASK (inner_mode));
+	        }
+
+	      if (is_mulwiden)
+	        op0 = XEXP (op0, 0), mode = GET_MODE (op0);
+	    }
+
+	  /* FIXME: Check for signed vs. unsigned.  */
+  	  *total = MAX (ia16_costs->s_mult_init[M_MOD (mode)][I_RTX (op1)]
+			+ nbits * ia16_costs->mult_bit,
+			ia16_size_costs.s_mult_init[M_MOD (mode)][I_RTX (op1)]
+			* ia16_costs->byte_fetch * H_RTX (op1))
+	    + rtx_cost (op0, mode, outer_code, 0, speed)
+	    + rtx_cost (op1, mode, outer_code, 1, speed);
+
+          return true;
+	}
+
+    /* FIXME: Docs are unclear about UDIV/UMOD on floating point modes.  */
+    case UDIV:
+    case UMOD:
+      if (FLOAT_MODE_P (mode))
+	*total = IA16_COST (fdiv);
+      else
+	*total = IA16_COST (u_divide[M_MOD (mode)][I_RTX (XEXP (x, 0))])
+		 * H_RTX (XEXP (x, 0));
+      return false;
+
+    case DIV:
+    case MOD:
+      if (FLOAT_MODE_P (mode))
+	*total = IA16_COST (fdiv);
+      else
+	*total = IA16_COST (s_divide[M_MOD (mode)][I_RTX (XEXP (x, 0))])
+		 * H_RTX (XEXP (x, 0));
+      return false;
+
+    /* FIXME: This might be too pessimistic when rtx_equal_p (op0, op1).  */
+    case PLUS:
+      if (FLOAT_MODE_P (mode))
+	{
+	  *total = IA16_COST (fadd);
+	  return false;
+	}
+      /* PLUS with -1 or 1 is cheaper.  */
+      if (XEXP (x, 1) == const1_rtx || XEXP (x, 1) == constm1_rtx)
+	{
+	  *total = IA16_COST (inc_dec[I_RTX (x)]);
+	  return (false);
+	}
+      /* "shl $1, dest" is preferred over "add dest, dest".  */
+      if (GET_MODE_SIZE (mode) <= 2
+	  && rtx_equal_p (XEXP (x, 0), XEXP (x, 1)))
+	{
+	  *total = 1 + IA16_COST (add[I_RTX (x)])
+		   * (mode == QImode ? 1 : GET_MODE_SIZE (mode) / UNITS_PER_WORD);
+	  return (false);
+	}
+      /* Compute cost of "leaw" instruction.  */
+      if (mode == HImode)
+	{
+	  if (GET_CODE (XEXP (x, 0)) == PLUS
+	    && CONSTANT_P (XEXP (x,1)))
+	    {
+	      rtx op0 = XEXP (XEXP (x, 0), 0);
+	      rtx op1 = XEXP (XEXP (x, 0), 1);
+	      rtx cst = XEXP (x, 1);
+
+	      *total = IA16_COST (lea)
+		+ IA16_COST (ea_calc (op0, op1, cst, NULL_RTX))
+		+ rtx_cost (op0, mode, outer_code, 0, speed)
+	        + rtx_cost (op1, mode, outer_code, 1, speed);
+	      return true;
+	    }
+	}
+      /* Detect *subm3_carru.  */
+      if (outer_code == MINUS
+	  && carry_flag_operator (XEXP (x, 0), mode))
+	{
+	  *total = rtx_cost (XEXP (x, 1), mode, outer_code, 1, speed);
+	  return false;
+	}
+      /* FALLTHRU */
+
+    case MINUS:
+      if (FLOAT_MODE_P (mode))
+	{
+	  *total = IA16_COST (fadd);
+	  return false;
+	}
+      /* Detect *addm3_carry.  */
+      if (outer_code == PLUS
+	  && carry_flag_operator (XEXP (x, 1), mode))
+	{
+	  *total = rtx_cost (XEXP (x, 0), mode, outer_code, 0, speed);
+	  return false;
+	}
+      /* FALLTHRU */
+
+    case AND:
+      /* Sometimes we get both the AND and the constant for free.  */
+      if (code == AND && mode == HImode
+	  && (outer_code == PLUS || outer_code == MINUS
+	     || outer_code == IOR || outer_code == XOR)
+          && CONST_INT_P (XEXP (x, 1))
+          && INTVAL (XEXP (x, 1)) == -256)
+	{
+	  *total = rtx_cost (XEXP (x, 0), mode, code, 0, speed);
+	  return true;
+        }
+    case IOR:
+    case XOR:
+      if (CONSTANT_P (XEXP (x, 1)))
+	*total = IA16_COST (add_imm[I_RTX (XEXP (x, 0))])
+	       * (mode == QImode ? 1 : GET_MODE_SIZE (mode) / UNITS_PER_WORD);
+      else
+	*total = IA16_COST (add[I_RTX (XEXP (x, 0))])
+	       * (mode == QImode ? 1 : GET_MODE_SIZE (mode) / UNITS_PER_WORD);
+      return false;
+
+    case NEG:
+      if (FLOAT_MODE_P (mode))
+	{
+	  *total = IA16_COST (fchs);
+	  return false;
+	}
+      if (carry_not_flag_operator (XEXP (x, 0), mode))
+	{
+	  *total = 0;
+	  return false;
+        }
+      /* FALLTHRU */
+
+    case NOT:
+      *total = IA16_COST (add[I_RTX (XEXP (x, 0))])
+	     * (mode == QImode ? 1 : GET_MODE_SIZE (mode) / UNITS_PER_WORD);
+      return false;
+
+    case COMPARE:
+      if (GET_CODE (XEXP (x, 0)) == ZERO_EXTRACT
+	  && XEXP (XEXP (x, 0), 1) == const1_rtx
+	  && CONST_INT_P (XEXP (XEXP (x, 0), 2))
+	  && XEXP (x, 1) == const0_rtx)
+	{
+	  /* This kind of construct is implemented using test[bw].
+	     Treat it as if we had an AND.  */
+	  *total = (IA16_COST (add_imm[I_RTX (x)])
+		    + rtx_cost (XEXP (XEXP (x, 0), 0), mode, outer_code, 0,
+				speed)
+		    + rtx_cost (const1_rtx, mode, outer_code, 1, speed));
+	  return true;
+	}
+      /* COMPARE is free in e.g. (compare (plus ...) (const_int 0)).  */
+      if ((GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == RTX_COMM_ARITH
+	   || GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == RTX_BIN_ARITH)
+	  && XEXP (x, 1) == const0_rtx)
+	{
+	  *total = rtx_cost (XEXP (x, 0), mode, outer_code, 0, speed);
+	  return true;
+	}
+      /* COMPARE is free in overflow checks.  */
+      if (GET_CODE (XEXP (x, 0)) == MINUS
+	  && rtx_equal_p (XEXP (x, 1), XEXP (XEXP (x, 0), 0)))
+	{
+	  *total = rtx_cost (XEXP (x, 0), mode, outer_code, 0, speed);
+	  return true;
+	}
+      if (CONSTANT_P (XEXP (x, 1)))
+	{
+	  *total = IA16_COST (cmp_imm[I_RTX (XEXP (x, 0))]);
+	  if (XEXP (x, 1) == const0_rtx
+	      && (REG_P (XEXP (x, 0)) || GET_CODE (XEXP (x, 0)) == SUBREG))
+	    return true;
+	}
+      else
+	*total = IA16_COST (cmp[I_RTX (XEXP (x, 0))]);
+      return false;
+
+    case ZERO_EXTRACT:
+      if (outer_code == COMPARE)
+	{
+	  /* See above under COMPARE.  */
+	  *total = (IA16_COST (add[I_RTX (x)])
+		    + rtx_cost (XEXP (x, 0), mode, outer_code, 0, speed)
+		    + rtx_cost (const1_rtx, mode, outer_code, 0, speed));
+	  return true;
+	}
+      if (REG_P (x))
+	*total = IA16_COST (move);
+      else
+	*total = IA16_COST (int_load[M_QI]);
+      return false;
+
+    case FLOAT_EXTEND:
+	*total = 0;
+      return false;
+
+    case ABS:
+      if (FLOAT_MODE_P (mode))
+	*total = IA16_COST (fabs);
+      else
+	/* This is expanded to cwtd, xorw and subw.  */
+	*total = IA16_COST (sign_extend[M_MOD (mode)])
+	       + IA16_COST (add[I_REG]) * 2;
+	*total *= H_MOD (mode);
+      return false;
+
+    case SQRT:
+      if (FLOAT_MODE_P (mode))
+	*total = IA16_COST (fsqrt);
+      return false;
+
+    case TRUNCATE:
+      *total = 0;
+      return true;
+
+    case CALL:
+      if (CONSTANT_P (XEXP (x, 0)))
+	*total = IA16_COST (call[0]);
+      else if (REG_P (XEXP (x, 0)))
+	*total = IA16_COST (call[1]);
+      else
+	*total = IA16_COST (call[2]);
+      return false;
+
+    case LTU:
+    case GEU:
+    case LEU:
+    case GTU:
+    case GT:
+    case LT:
+    case LE:
+    case GE:
+    case NE:
+    case EQ:
+      if (outer_code != SET && outer_code != NEG)
+	*total = 0;
+      else if (carry_not_flag_operator (x, mode))
+	*total = IA16_COST (add[O_REGREG])
+	       + outer_code == SET ? COSTS_N_INSNS (ia16_costs->byte_fetch) : 0
+	       + outer_code == NEG ? IA16_COST (add[I_REG]) : 0;
+      else if (outer_code != SET)
+	*total = 0;
+      else if (carry_flag_operator (x, mode))
+	*total = IA16_COST (add[O_REGREG]);
+      else if (code == LT)
+	*total = COSTS_N_INSNS (ia16_costs->byte_fetch)
+	       + IA16_COST (sign_extend[M_MOD (HImode)]);
+      else if (code == EQ)
+	*total = COSTS_N_INSNS (ia16_costs->byte_fetch)
+	       + IA16_COST (shift_1bit[I_REG])
+	       + IA16_COST (sign_extend[M_MOD (HImode)]);
+      return true;
+
+    case UNSPEC:
+      /* Instructions like cmc and lahf.  Assume they are cheap.  */
+      *total = COSTS_N_INSNS (ia16_costs->byte_fetch);
+      return false;
+
+    /* cse_insn() likes to compute costs of EXPR_LIST rtxes.  */
+    case EXPR_LIST:
+
+    /* TODO */
+    /* Check outer_code here (e.g. SET, MINUS).  */
+    case IF_THEN_ELSE:
+    case PC:
+    case CLZ:
+    case CTZ:
+    case FFS:
+    case PARITY:
+    case POPCOUNT:
+    case ASM_INPUT:
+    case ASM_OPERANDS:
+    case CONCAT:
+    case STRICT_LOW_PART:
+      return false;
+
+    /* See comment above get_last_value (const_rtx) in combine.c.  */
+    case CLOBBER:
+      return false;
+
+    default:
+      fprintf (stderr, "Unknown cost for rtx with code %s and "
+               "outer code %s:\n", GET_RTX_NAME (code),
+	       GET_RTX_NAME (outer_code));
+      debug_rtx (x);
+      return false;
+    }
+}
+
+/* Dividing the Output into Sections */
+#undef	TARGET_ASM_SELECT_SECTION
+#define	TARGET_ASM_SELECT_SECTION ia16_asm_select_section
+
+/* Convenience function --- fabricate a section name for a given __far
+   variable or function declaration, or return NULL if something is wrong or
+   if the function already has an explicit section name.
+
+   The caller should free the section name's memory with free (.) once it is
+   done with it.
+
+   To fabricate the section name, I first decide the prefix for the section
+   type, then add the (sanitized) name of the main source file or the
+   declaration; and finally I compute a hash value of everything and append
+   the hash.
+
+   (Note: apparently CFUN tends to be NULL at this point, even if the variable
+   is defined inside a function.)  */
+static char *
+ia16_fabricate_section_name_for_decl (tree decl, int reloc, bool unique)
+{
+  const char *prefix;
+  char *name1, *name2, *p, c;
+  size_t prefix_len;
+  unsigned short hash;
+  bool one_only, use_gnu_linkonce;
+
+  if (! DECL_P (decl)
+      || lookup_attribute ("section", DECL_ATTRIBUTES (decl)))
+    return NULL;
+
+  if (! TARGET_SEG_RELOC_STUFF)
+    {
+      location_t loc = DECL_SOURCE_LOCATION (decl);
+      error_at (loc,
+		"cannot create %<__far%> function or static storage variable");
+      ia16_error_seg_reloc (loc, NULL);
+      return NULL;
+    }
+
+  one_only = DECL_COMDAT_GROUP (decl) != NULL_TREE;
+  unique |= one_only;
+  use_gnu_linkonce = one_only && ! HAVE_COMDAT_GROUP;
+
+#define PL(str)		(prefix = (str), \
+			 prefix_len = strlen (prefix))
+
+  switch (categorize_decl_for_section (decl, reloc))
+    {
+    case SECCAT_TEXT:
+      PL (use_gnu_linkonce ? ".gnu.linkonce.ft." : ".fartext.");
+      break;
+
+    case SECCAT_DATA:
+    case SECCAT_DATA_REL:
+    case SECCAT_DATA_REL_LOCAL:
+    case SECCAT_BSS:
+      PL (use_gnu_linkonce ? ".gnu.linkonce.fd." : ".fardata.");
+      break;
+
+    case SECCAT_DATA_REL_RO:
+    case SECCAT_DATA_REL_RO_LOCAL:
+    case SECCAT_RODATA:
+    case SECCAT_RODATA_MERGE_STR:
+    case SECCAT_RODATA_MERGE_STR_INIT:
+    case SECCAT_RODATA_MERGE_CONST:
+      PL (use_gnu_linkonce ? ".gnu.linkonce.fr." : ".farrodata.");
+      break;
+
+    default:
+      return NULL;
+    }
+
+#undef PL
+
+  /* Extract and copy the base name of the main input file, or the name of
+     the declared variable or function, and convert non-symbol characters to
+     `_'.  Also add the prefix.  */
+  if (! unique)
+    name1 = ACONCAT ((prefix, "f.", lbasename (main_input_filename), NULL));
+  else
+    name1 = ACONCAT ((prefix, "s.",
+		      IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), NULL));
+  p = name1 + prefix_len;
+  while ((c = *p) != 0)
+    {
+      switch (c)
+	{
+	case '0': case '1': case '2': case '3': case '4': case '5': case '6':
+	case '7': case '8': case '9':
+	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
+	case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
+	case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
+	case 'v': case 'w': case 'x': case 'y': case 'z':
+	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
+	case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
+	case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
+	case 'V': case 'W': case 'X': case 'Y': case 'Z':
+	case '_': case '.': case '$':
+	  break;
+	default:
+	  *p = '_';
+	}
+      ++p;
+    }
+
+  /* Add a hash.  */
+  hash = (unsigned short) htab_hash_string (name1);
+  hash *=  036627u;
+  hash &= 0177777u;
+  hash = hash << 4 | hash >> 12;
+  hash &=  077777u;
+
+  if (asprintf (&name2, "%s.%05ho$", name1, hash) <= 0)
+    {
+      error ("not enough memory for %<__far%> function or variable "
+	     "section name");
+      return NULL;
+    }
+
+  return name2;
+}
+
+static section *
+ia16_asm_select_section (tree expr, int reloc, unsigned HOST_WIDE_INT align)
+{
+  tree type = TREE_TYPE (expr);
+  char *sname;
+
+  switch (TYPE_ADDR_SPACE (type))
+    {
+    default:
+      gcc_unreachable ();
+
+    case ADDR_SPACE_FAR:
+      sname = ia16_fabricate_section_name_for_decl (expr, reloc,
+						    flag_data_sections);
+      if (sname)
+	{
+	  section *sect = get_named_section (expr, sname, reloc);
+	  free (sname);
+	  return sect;
+	}
+
+      /* fall through */
+    case ADDR_SPACE_GENERIC:
+      return default_elf_select_section (expr, reloc, align);
+
+    case ADDR_SPACE_SEG_SS:
+      /* Do not allow explicit declarations of variables etc. in __seg_ss
+	 space.
+
+	 However, allow initializer expressions, jump tables, etc., and put
+	 them in the default data segment.  The MACHINE_DEPENDENT_REORG pass
+	 should correct any (mem/u ...) references to these things, so that
+	 they refer to %ds and not %ss.  */
+      if ((! CONSTANT_CLASS_P (expr) && ! EXPR_P (expr))
+	  || ! TREE_READONLY (expr))
+	error_at (DECL_P (expr) ? DECL_SOURCE_LOCATION (expr)
+				: UNKNOWN_LOCATION, "cannot allocate "
+		  "static storage object in %<__seg_ss%> address space");
+      return default_elf_select_section (expr, reloc, align);
+    }
+}
+
+#undef	TARGET_ASM_UNIQUE_SECTION
+#define	TARGET_ASM_UNIQUE_SECTION ia16_asm_unique_section
+
+static void
+ia16_asm_unique_section (tree decl, int reloc)
+{
+  char *sname;
+  tree type = TREE_TYPE (decl);
+
+  switch (TYPE_ADDR_SPACE (type))
+    {
+    default:
+      gcc_unreachable ();
+
+    case ADDR_SPACE_FAR:
+      sname = ia16_fabricate_section_name_for_decl (decl, reloc, true);
+      if (sname)
+	{
+	  set_decl_section_name (decl, sname);
+	  free (sname);
+	  return;
+	}
+
+      /* fall through */
+    case ADDR_SPACE_GENERIC:
+      default_unique_section (decl, reloc);
+      break;
+
+    case ADDR_SPACE_SEG_SS:
+      error_at (DECL_SOURCE_LOCATION (decl), "cannot allocate static storage "
+		"object in %<__seg_ss%> address space");
+      default_unique_section (decl, reloc);
+    }
+}
+
+/* Continued: Run-time Target Specification */
+#undef  TARGET_OPTION_OVERRIDE
+#define TARGET_OPTION_OVERRIDE	ia16_option_override
+
+static struct machine_function *
+ia16_init_machine_status (void)
+{
+  return ggc_cleared_alloc <machine_function> ();
+}
+
+static void
+ia16_option_override (void)
+{
+  ia16_costs = processor_target_table[target_arch].cost;
+  ia16_features = processor_target_table[target_arch].features;
+  if (target_tune != PROCESSOR_ANY)
+    {
+      ia16_costs = processor_target_table[target_tune].cost;
+      ia16_features = (ia16_features & 15)
+	| (processor_target_table[target_tune].features & 16);
+    }
+  if (optimize_size)
+    ia16_costs = &ia16_size_costs;
+
+  /* If -f(no-)omit-frame-pointer is not specified, try to omit the frame
+     pointer if optimization is on (even when optimizing for size).  This is
+     similar to the override in gcc/config/i386/i386.c .  -- tkchia */
+  if (optimize && ! global_options_set.x_flag_omit_frame_pointer)
+    global_options.x_flag_omit_frame_pointer = 1;
+
+  init_machine_status = ia16_init_machine_status;
+}
+
+/* The Overall Framework of an Assembler File */
+#undef  TARGET_ASM_FILE_START
+#undef  TARGET_ASM_FILE_START_APP_OFF
+#define TARGET_ASM_FILE_START			ia16_asm_file_start
+#define TARGET_ASM_FILE_START_APP_OFF		1
+
+/* GAS doesn't support .file.  */
+#undef  TARGET_ASM_FILE_START_FILE_DIRECTIVE
+#define TARGET_ASM_FILE_START_FILE_DIRECTIVE	false
+
+/* Output assembler directives to set up the GNU assembler for the CPU type,
+ * code model and assembler syntax that we use.  */
+static void
+ia16_asm_file_start (void)
+{
+	const char *arch, *code;
+
+	if (TARGET_FSTSW_AX)
+		arch = "i286";
+	else if (TARGET_PUSH_IMM)
+		arch = "i186";
+	else
+		arch = "i8086";
+	code = "16";
+
+	fprintf (asm_out_file,	"\t.arch %s,jumps\n"
+				"\t.code%s\n"
+				"\t.att_syntax prefix\n", arch, code);
+	default_file_start ();
+}
+
+#undef	TARGET_ASM_FILE_END
+#define	TARGET_ASM_FILE_END		ia16_asm_file_end
+
+static void
+ia16_asm_file_end (void)
+{
+  if (TARGET_NEWLIB_AUTOFLOAT_STDIO)
+    {
+      if (may_need_printf_nofloat)
+	fputs (	"\t.weak\t__ia16_use_printf_nofloat.v1\n"
+		"\t.set\t__ia16_use_printf_nofloat.v1,1\n", asm_out_file);
+      if (may_need_printf_float)
+	fputs (	"\t.weak\t__ia16_use_printf_float.v1\n"
+		"\t.set\t__ia16_use_printf_float.v1,1\n", asm_out_file);
+      if (may_need_scanf_nofloat)
+	fputs (	"\t.weak\t__ia16_use_scanf_nofloat.v1\n"
+		"\t.set\t__ia16_use_scanf_nofloat.v1,1\n", asm_out_file);
+      if (may_need_scanf_float)
+	fputs (	"\t.weak\t__ia16_use_scanf_float.v1\n"
+		"\t.set\t__ia16_use_scanf_float.v1,1\n", asm_out_file);
+    }
+}
+
+#undef	TARGET_ASM_FUNCTION_SECTION
+#define	TARGET_ASM_FUNCTION_SECTION	ia16_asm_function_section
+
+static section *
+ia16_asm_function_section (tree decl, enum node_frequency freq, bool startup,
+			   bool stop)
+{
+  char *sname;
+  const int reloc = 0;
+
+  if (! TARGET_CMODEL_IS_FAR_TEXT
+      && (! decl
+	  || ! ia16_far_function_type_p (TREE_TYPE (decl))
+	  || ! ia16_far_section_function_type_p (TREE_TYPE (decl))))
+    return default_function_section (decl, freq, startup, stop);
+
+  sname = ia16_fabricate_section_name_for_decl (decl, reloc,
+						flag_function_sections);
+  if (sname)
+    {
+      section *sect = get_named_section (decl, sname, reloc);
+      free (sname);
+      return sect;
+    }
+  return NULL;
+}
+
+/* Output of Data */
+#undef  TARGET_ASM_BYTE_OP
+#undef  TARGET_ASM_ALIGNED_HI_OP
+#undef  TARGET_ASM_ALIGNED_SI_OP
+#undef  TARGET_ASM_ALIGNED_DI_OP
+#undef  TARGET_ASM_ALIGNED_TI_OP
+#undef  TARGET_ASM_UNALIGNED_HI_OP
+#undef  TARGET_ASM_UNALIGNED_SI_OP
+#undef  TARGET_ASM_UNALIGNED_DI_OP
+#undef  TARGET_ASM_UNALIGNED_TI_OP
+#define TARGET_ASM_BYTE_OP		"\t.byte\t"
+#define TARGET_ASM_ALIGNED_HI_OP	"\t.hword\t"
+#define TARGET_ASM_ALIGNED_SI_OP	"\t.long\t"
+#define TARGET_ASM_ALIGNED_DI_OP	"\t.quad\t"
+#define TARGET_ASM_ALIGNED_TI_OP	"\t.octa\t"
+#define TARGET_ASM_UNALIGNED_HI_OP	"\t.hword\t"
+#define TARGET_ASM_UNALIGNED_SI_OP	"\t.long\t"
+#define TARGET_ASM_UNALIGNED_DI_OP	"\t.quad\t"
+#define TARGET_ASM_UNALIGNED_TI_OP	"\t.octa\t"
+
+#undef	TARGET_ASM_INTEGER
+#define	TARGET_ASM_INTEGER	ia16_asm_integer
+
+static rtx
+ia16_find_base_symbol_ref (rtx x)
+{
+  rtx b0;
+
+  switch (GET_CODE (x))
+    {
+    case SYMBOL_REF:
+      return x;
+
+    case PLUS:
+      b0 = ia16_find_base_symbol_ref (XEXP (x, 0));
+      if (b0)
+	return b0;
+      return ia16_find_base_symbol_ref (XEXP (x, 1));
+
+    case MINUS:
+      return ia16_find_base_symbol_ref (XEXP (x, 0));
+
+    default:
+      return NULL_RTX;
+    }
+}
+
+static bool
+ia16_assemble_far_pointer (rtx x)
+{
+  rtx base = ia16_find_base_symbol_ref (x);
+
+  if (! base)
+    return false;
+
+  fputs (TARGET_ASM_ALIGNED_HI_OP, asm_out_file);
+  output_addr_const (asm_out_file, x);
+
+  /* GNU as does not yet accept the syntax
+	.hword	foo@OZSEG16
+     so we have to say
+	.reloc	., R_386_OZSEG16, foo
+	.hword	0
+     instead.  Ditto for the SEG16 case.  */
+  if (! TARGET_ABI_SEGELF)
+    {
+      fputs ("\n"
+	     "\t.reloc\t., R_386_OZSEG16, ", asm_out_file);
+      output_addr_const (asm_out_file, base);
+      fputs ("\n" TARGET_ASM_ALIGNED_HI_OP "0\n", asm_out_file);
+    }
+  else
+    {
+      fputs ("\n"
+	     "\t.reloc\t., R_386_SEG16, \"", asm_out_file);
+      output_addr_const (asm_out_file, base);
+      fputs ("!\"\n" TARGET_ASM_ALIGNED_HI_OP "0\n", asm_out_file);
+    }
+
+  return true;
+}
+
+static bool
+ia16_asm_integer (rtx x, unsigned size, int aligned_p)
+{
+  rtx orig_x;
+
+  orig_x = x;
+  while (GET_CODE (x) == CONST)
+    x = XEXP (x, 0);
+
+  if (GET_CODE (x) != UNSPEC
+      || XINT (x, 1) != UNSPEC_STATIC_FAR_PTR
+      || GET_MODE (x) != SImode)
+    return default_assemble_integer (orig_x, size, aligned_p);
+
+  x = XVECEXP (x, 0, 0);
+  return ia16_assemble_far_pointer (x);
+}
+
+/* Macros Controlling Initialization Routines */
+#undef	TARGET_ASM_CONSTRUCTOR
+#define	TARGET_ASM_CONSTRUCTOR	ia16_asm_constructor
+
+static void
+ia16_assemble_far_pointer_to_section (rtx x, section *sec)
+{
+  switch_to_section (sec);
+  assemble_align (POINTER_SIZE);
+  if (! ia16_assemble_far_pointer (x))
+    gcc_unreachable ();
+}
+
+static void
+ia16_asm_constructor (rtx symbol, int priority)
+{
+  section *sec;
+
+  if (! TARGET_CMODEL_IS_FAR_TEXT)
+    default_named_section_asm_out_constructor (symbol, priority);
+  else
+    {
+      if (priority != DEFAULT_INIT_PRIORITY)
+	sec = get_cdtor_priority_section (priority, true);
+      else
+	sec = get_section (".ctors", SECTION_WRITE, NULL);
+      ia16_assemble_far_pointer_to_section (symbol, sec);
+    }
+}
+
+#undef	TARGET_ASM_DESTRUCTOR
+#define	TARGET_ASM_DESTRUCTOR	ia16_asm_destructor
+
+static void
+ia16_asm_destructor (rtx symbol, int priority)
+{
+  section *sec;
+
+  if (! TARGET_CMODEL_IS_FAR_TEXT)
+    default_named_section_asm_out_destructor (symbol, priority);
+  else
+    {
+      if (priority != DEFAULT_INIT_PRIORITY)
+	sec = get_cdtor_priority_section (priority, false);
+      else
+	sec = get_section (".dtors", SECTION_WRITE, NULL);
+      ia16_assemble_far_pointer_to_section (symbol, sec);
+    }
+}
+
+/* Output of Assembler Instructions */
+static const char *reg_QInames[FIRST_NOQI_REG] = {
+	"cl", "ch", "al", "ah", "dl", "dh", "bl", "bh"
+};
+
+static const char *reg_HInames[LAST_HARD_REG + 1] = {
+	"cx", 0, "ax", 0, "dx", 0, "bx", 0, "si", "di", "bp", "es", "ds", "sp",
+	0, "ss", "cs"
+};
+
+/* E is known not to be null when this is called.  These non-standard codes are
+   supported:
+   'L': Print the name of the lower 8-bits of E.
+   'H': Print the name of the upper 8-bits of E.
+   'X': Print the name of E as a 16-bit operand.
+   'W': Print the value of the constant E unsigned-divided by 2 (for loading
+	%cx before a `rep; movsw').
+   'R': Don't print any register prefix before E.
+   'O': Print the low 16 bits of the 32-bit constant E (for immediate
+	`lcall' and `ljmp').
+   'S': Print the high 16 bits of the 32-bit constant E.
+   'Z': Print the symbol name for the segelf base, sans preceding $.
+*/
+#undef	TARGET_PRINT_OPERAND
+#define	TARGET_PRINT_OPERAND	ia16_print_operand
+
+static void ia16_print_operand_address_internal (FILE *, rtx, addr_space_t);
+
+static void
+ia16_print_operand (FILE *file, rtx e, int code)
+{
+  enum machine_mode mode;
+  unsigned int regno;
+  rtx x;
+
+  /* simplify_gen_subreg() is used to allow the 'X', 'H', 'L', and 'W' output
+   * modifiers to be used for REG, MEM and constant expressions.  The cases
+   * which simplify_subreg() refuses to handle are handled by alter_subreg().
+   */
+  if (code == 'X')
+    x = simplify_gen_subreg (HImode, e, QImode, 0);
+  else if (code == 'L')
+    if (GET_MODE (e) == VOIDmode)
+      x = simplify_gen_subreg (QImode, e, HImode, 0);
+    else
+      x = simplify_gen_subreg (QImode, e, GET_MODE (e), 0);
+  else if (code == 'H')
+    x = simplify_gen_subreg (QImode, e, HImode, 1);
+  else if (code == 'W')
+    {
+      gcc_assert (CONST_INT_P (e));
+      x = GEN_INT ((INTVAL (e) / 2) & 0x7fff);
+    }
+  else if (code == 'O')
+    {
+      gcc_assert (CONST_INT_P (e));
+      x = GEN_INT (INTVAL (e) & 0xffff);
+    }
+  else if (code == 'S')
+    {
+      gcc_assert (CONST_INT_P (e));
+      x = GEN_INT ((INTVAL (e) >> 16) & 0xffff);
+    }
+  else if (code == 'Z')
+    {
+      x = ia16_find_base_symbol_ref (e);
+      if (! x)
+	x = const0_rtx;
+    }
+  else
+    x = e;
+  if (GET_CODE (x) == SUBREG)
+    x = alter_subreg (&x, true);
+  mode = GET_MODE (x);
+
+  switch (GET_CODE (x))
+    {
+      case REG:
+      regno = REGNO (x);
+      if (code != 'R')
+	fputs (REGISTER_PREFIX, file);
+      if (GET_MODE_SIZE (mode) >= 2
+       && (regno >= SI_REG || (regno & 1) == 0))
+	fputs (reg_HInames[regno], file);
+      else if (GET_MODE_SIZE (mode) == 1 && regno < SI_REG)
+	fputs (reg_QInames[regno], file);
+      else
+	output_operand_lossage ("Invalid register %s (nr. %u) in %smode.",
+	                        reg_names [REGNO (x)], REGNO (x),
+	                        GET_MODE_NAME (GET_MODE (x)));
+      break;
+
+      case CONST_VECTOR:
+      fprintf (file, "%s" HOST_WIDE_INT_PRINT_DEC, IMMEDIATE_PREFIX,
+	       (UINTVAL (XVECEXP (x, 0, 0)) & 0xff)
+	       + 256 * INTVAL (XVECEXP (x, 0, 1)));
+      break;
+
+      /* TODO: handle floating point constants here.  */
+
+      case CONST_INT:
+      case CONST:
+      case SYMBOL_REF:
+      case LABEL_REF:
+      if (code != 'Z')
+	fputs (IMMEDIATE_PREFIX, file);
+      /* fall through */
+
+      case CODE_LABEL:
+      if (code != 'Z')
+	output_addr_const (file, x);
+      else
+	{
+	  putc ('"', file);
+	  output_addr_const (file, x);
+	  fputs ("!\"", file);
+	}
+      break;
+
+      case MEM:
+      ia16_print_operand_address_internal (file, XEXP (x, 0),
+					   MEM_ADDR_SPACE (x));
+      break;
+
+      default:
+      debug_rtx (e);
+      output_operand_lossage ("Invalid or unsupported operand %s (code"
+			      " %c).", rtx_name [GET_CODE (e)], code);
+	break;
+  }
+}
+
+#define INDEX_REG_P(x) \
+	ia16_regno_in_class_p (REGNO (x), INDEX_REGS)
+#define BASE_REG_REG_P(x) \
+	ia16_regno_in_class_p (REGNO (x), BASE_W_INDEX_REGS)
+
+/* Strictly check an address X in address space AS and optionally split into
+ * its components.
+ * If there is only one register, it will be the base register.
+ * This is a helper function for ia16_print_operand_address ().
+ */
+bool
+ia16_parse_address_strict (rtx x, rtx *p_rb, rtx *p_ri, rtx *p_c, rtx *p_rs,
+			   addr_space_t as)
+{
+	rtx tmp;
+	rtx rb, ri, c, rs;
+	enum machine_mode mode ATTRIBUTE_UNUSED;
+
+	if (!ia16_parse_address (x, &rb, &ri, &c, &rs, as))
+		return (0 == 1);
+	mode = GET_MODE (x);
+
+	/* Swap the registers if necessary.  */
+	if (rb && ri && INDEX_REG_P (rb) && BASE_REG_REG_P (ri))
+	  {
+		tmp = rb; rb = ri; ri = tmp;
+	  }
+	/* Check register classes for base + index.  */
+	if (rb && ri
+	    && (!INDEX_REG_P (ri)
+		|| !BASE_REG_REG_P (rb)))
+		return (0 == 1);
+
+	/* Check register class for base.  */
+	if (rb && !ri && !REGNO_MODE_OK_FOR_BASE_P (REGNO (rb), mode))
+		return (0 == 1);
+
+	/* Check register class for segment. */
+	if (rs && !REGNO_OK_FOR_SEGMENT_P (REGNO (rs)))
+		return (0 == 1);
+
+	if (p_rb)
+		*p_rb = rb;
+	if (p_ri)
+		*p_ri = ri;
+	if (p_c)
+		*p_c = c;
+	if (p_rs)
+		*p_rs = rs;
+
+	return (0 == 0);
+}
+
+/* Say whether a segment override term for SEG_REGNO should be printed in the
+   assembly output, given that the base register term is RB.  */
+static bool
+ia16_to_print_seg_override_p (unsigned seg_reg_no, rtx rb)
+{
+  if (rb && REG_P (rb) && REGNO (rb) == BP_REG)
+    {
+      if (seg_reg_no == SS_REG)
+	return false;
+    }
+  else
+    {
+      if (seg_reg_no == DS_REG)
+	return false;
+    }
+  return true;
+}
+
+/* Possible asm operands and their address expressions:
+ * c:		(const_int c)
+ * (rb):	(reg rb)
+ * c(rb):	(plus (reg rb) (const_int c))
+ * (rb, ri):	(plus (reg rb) (reg ri))
+ * c(rb, ri):	(plus (plus (reg rb) (reg ri)) (const_int c))
+ * rs:0:	(unspec rs ...)
+ * rs:(rb)	(plus (unspec rs ...) (reg rb))
+ *		etc.
+ */
+static void
+ia16_print_operand_address_internal (FILE *file, rtx e, addr_space_t as)
+{
+  rtx rb, ri, c, rs;
+
+  if (!ia16_parse_address_strict (e, &rb, &ri, &c, &rs, as))
+    {
+      debug_rtx (e);
+      output_operand_lossage ("Invalid IA16 address expression.");
+      return;
+    }
+
+  /* See ia16_seg_override_cost_likely_p (...) above.  */
+  if (rs)
+    {
+      if (ia16_to_print_seg_override_p (REGNO (rs), rb))
+	fprintf (file, "%s%s:", REGISTER_PREFIX, reg_HInames[REGNO (rs)]);
+    }
+  else if (! ia16_in_ss_data_function_p ())
+    {
+      if (ia16_to_print_seg_override_p (DS_REG, rb))
+	fprintf (file, "%s%s:", REGISTER_PREFIX, reg_HInames[DS_REG]);
+    }
+  else if (TARGET_ALLOCABLE_DS_REG ? df_regs_ever_live_p (DS_REG)
+				   : ! ia16_in_ds_data_function_p ())
+    {
+      if (ia16_to_print_seg_override_p (SS_REG, rb))
+	fprintf (file, "%s%s:", REGISTER_PREFIX, reg_HInames[SS_REG]);
+    }
+
+  if (c)
+    output_addr_const (file, c);
+  if (rb)
+    fprintf (file, "(%s%s", REGISTER_PREFIX, reg_HInames[REGNO (rb)]);
+  if (ri)
+    fprintf (file, ",%s%s", REGISTER_PREFIX, reg_HInames[REGNO (ri)]);
+  if (rb)
+    putc (')', file);
+}
+
+#undef	TARGET_PRINT_OPERAND_ADDRESS
+#define	TARGET_PRINT_OPERAND_ADDRESS ia16_print_operand_address
+/* GCC uses this hook to write out "%aDIGIT" (e.g. "%a0") operands in
+   assembly output templates.
+
+   Alas GCC does not exactly tell us which address space the address
+   expression E is relative to.  This is problematic if there is no segment
+   override term in E, and we want to tell between ADDR_SPACE_GENERIC and
+   ADDR_SPACE_SEG_SS.
+
+   Try to fish out the underlying high-level declaration corresponding to E,
+   and use the address space information from there.  */
+static void
+ia16_print_operand_address (FILE *file, machine_mode mode ATTRIBUTE_UNUSED,
+			    rtx e)
+{
+  addr_space_t as = ADDR_SPACE_GENERIC;
+
+  if (ia16_have_seg_override_p (e))
+    as = ADDR_SPACE_FAR;
+  else
+    {
+      tree decl = ia16_get_decl_for_addr (e);
+      if (decl)
+	{
+	  tree type = TREE_TYPE (decl);
+	  if (type && POINTER_TYPE_P (type))
+	    as = TYPE_ADDR_SPACE (TREE_TYPE (type));
+	}
+    }
+
+  ia16_print_operand_address_internal (file, e, as);
+}
+
+/* Helper function for gen_prologue().  Generates RTL to push REGNO, which
+ * must be a 16-bit register, onto the stack.  */
+rtx
+ia16_push_reg (unsigned int regno)
+{
+  if (TARGET_PROTECTED_MODE && REGNO_OK_FOR_SEGMENT_P (regno))
+    return gen__pushphi1_prologue (gen_rtx_REG (PHImode, regno));
+
+  return gen__pushhi1_prologue (gen_rtx_REG (HImode, regno));
+}
+
+/* Helper function for gen_epilogue().  Generates RTL to pop REGNO, which
+ * must be a 16-bit register, off the stack.  */
+rtx
+ia16_pop_reg (unsigned int regno)
+{
+  if (TARGET_PROTECTED_MODE && REGNO_OK_FOR_SEGMENT_P (regno))
+    return gen__popphi1 (gen_rtx_REG (PHImode, regno));
+  else
+    return gen__pophi1 (gen_rtx_REG (HImode, regno));
+}
+
+/* Trampolines for Nested Functions */
+
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT ia16_trampoline_init
+
+/* tr = trampoline addr, fn = function addr, sc = static chain */
+/* FIXME: TARGET_CODE32 is not supported - add data16 and addr16 prefixes.  */
+void
+ia16_trampoline_init (rtx tr, tree fn, rtx sc)
+{
+  rtx fn_disp;
+  rtx mem;
+
+  /* Opcode register encoding   sBDSbdac for sp bp di si bx dx ax cx */
+  unsigned long int regtable = 045763201;
+
+  /* Base opcode for movw $imm16, reg16.  */
+  unsigned char mov_opcode = 0xb8;
+  unsigned char regno = STATIC_CHAIN_REGNUM;
+
+  if (! TARGET_CMODEL_IS_TINY)
+    {
+      sorry ("Trampolines are disabled under non-tiny memory models.");
+      abort ();
+    }
+
+  if (ia16_regno_in_class_p (regno, QI_REGS))
+    regno /= 2;
+  else
+    regno -= 4;
+  mov_opcode |= (regtable >> (regno * 3)) & 7;
+
+  /* Write the movw opcode.  */
+  mem = adjust_address (tr, QImode, 0);
+  emit_move_insn (mem, gen_int_mode (mov_opcode, QImode));
+
+  /* Write the static chain value.  */
+  mem = adjust_address (tr, HImode, 1);
+  emit_move_insn (mem, sc);
+
+  /* Write the absolute jmp opcode.  */
+  mem = adjust_address (tr, QImode, 3);
+  emit_move_insn (mem, gen_int_mode (0xe9, QImode));
+
+  /* Calculate the difference between the function address and %pc, which
+     points to (tr+4)+2 when the jmp instruction executes.  */
+  mem = adjust_address (tr, Pmode, 4 + 2);
+  fn_disp = expand_binop (Pmode, sub_optab, XEXP (DECL_RTL (fn), 0),
+			  plus_constant (Pmode, XEXP (tr, 0), 4 + 2), NULL_RTX,
+			  1, OPTAB_DIRECT);
+
+  /* Write the jmp offset.  */
+  mem = adjust_address (tr, HImode, 4);
+  emit_move_insn (mem, fn_disp);
+
+  /* Done.  That wasn't a lot of fun.  */
+}
+
+/* Subroutine of ia16_parse_address.  */
+bool
+ia16_parse_address_internal (rtx e, rtx *p_r1, rtx *p_r2, rtx *p_c, rtx *p_r9)
+{
+  rtx r1 = NULL, r2 = NULL, c = NULL, r9 = NULL;
+
+  if (REG_P (e))
+    r1 = e;
+  else if (GET_CODE (e) == UNSPEC && XINT (e, 1) == UNSPEC_SEG_OVERRIDE)
+    r9 = XVECEXP (e, 0, 0);
+  else if (GET_CODE (e) == PLUS)
+    {
+      rtx x, y, x_r1, x_r2, x_c, x_r9, y_r1, y_r2, y_c, y_r9;
+
+      x = XEXP (e, 0);
+      y = XEXP (e, 1);
+
+      if (!ia16_parse_address_internal (x, &x_r1, &x_r2, &x_c, &x_r9) ||
+	  !ia16_parse_address_internal (y, &y_r1, &y_r2, &y_c, &y_r9))
+	return false;
+
+      if ((x_c && y_c) || (x_r9 && y_r9))
+	return false;
+
+      if (x_r1 && y_r1)
+	{
+	  if (x_r2 || y_r2)
+	    return false;
+
+	  /* replace_oldest_value_addr(...) in gcc/regcprop.c may get
+	   * confused if an address expression contains both index and base
+	   * registers, and the registers do not come immediately under the
+	   * same (plus ...), e.g.
+	   *
+	   *	                (plus:HI)
+	   *	                  /  \
+	   *	          (plus:HI)  (reg:HI 10 bp)
+	   *	            /  \
+	   *	(reg:HI 9 di)  (const_int -1)
+	   *
+	   * In such a case, gcc/regcprop.c may decide to replace %di with
+	   * %bx (say), while not replacing %bp, leading to a bogus address
+	   * `-1(%bx,%bp)'.
+	   *
+	   * One way to work around this is to flag address like the above as
+	   * being invalid.
+	   */
+	  if (x_r1 != x || y_r1 != y)
+	    return false;
+	}
+
+      if (x_r1)
+	{
+	  r1 = x_r1;
+	  r2 = x_r2 ? x_r2 : y_r1;
+	}
+      else
+	{
+	  r1 = y_r1;
+	  r2 = y_r2;
+	}
+
+      c = x_c ? x_c : y_c;
+      r9 = x_r9 ? x_r9 : y_r9;
+    }
+  else
+    c = e;
+
+  /* Deal with the most obvious brokenness.  */
+  if ((r1 && !REG_P (r1)) || (r2 && !REG_P (r2)) || (r9 && !REG_P (r9)) ||
+      (c && !CONSTANT_P (c)))
+    return false;
+
+  if (p_r1)
+    *p_r1 = r1;
+  if (p_r2)
+    *p_r2 = r2;
+  if (p_c)
+    *p_c = c;
+  if (p_r9)
+    *p_r9 = r9;
+
+  return true;
+}
+
+/* Addressing Modes.  */
+/* Check an address E and optionally split it into its components.
+*/
+bool
+ia16_parse_address (rtx e, rtx *p_r1, rtx *p_r2, rtx *p_c, rtx *p_r9,
+		    addr_space_t as)
+{
+  rtx r1, c, r9;
+  if (ia16_parse_address_internal (e, &r1, p_r2, &c, &r9))
+    {
+      if (p_r1)
+	*p_r1 = r1;
+      if (p_c)
+	{
+	  if (c || r1)
+	    *p_c = c;
+	  else
+	    *p_c = const0_rtx;
+	}
+      if (p_r9)
+	{
+	  /* Remember to insert a %ss: override for a __seg_ss address.  */
+	  if (as == ADDR_SPACE_SEG_SS && ! r9)
+	    *p_r9 = gen_rtx_REG (SEGmode, SS_REG);
+	  else
+	    *p_r9 = r9;
+	}
+      return true;
+    }
+  if (p_r1)
+    *p_r1 = NULL;
+  if (p_r2)
+    *p_r2 = NULL;
+  if (p_c)
+    *p_c = NULL;
+  if (p_r9)
+    *p_r9 = NULL;
+  return false;
+}
+
+/* Miscellaneous Parameters */
+
+/* Only Intel i80186 and i80286 mask the shift/rotate counts.  */
+/* FIXME Documentation bug: unsigned HOST_WIDE_INT instead of int.  */
+#undef  TARGET_SHIFT_TRUNCATION_MASK
+#define TARGET_SHIFT_TRUNCATION_MASK	ia16_shift_truncation_mask
+
+static unsigned HOST_WIDE_INT
+ia16_shift_truncation_mask (enum machine_mode mode)
+{
+  return (TARGET_SHIFT_MASKED && (mode == HImode || mode == QImode) ? 31 : 0);
+}
+
+#undef	TARGET_MACHINE_DEPENDENT_REORG
+#define	TARGET_MACHINE_DEPENDENT_REORG	ia16_machine_dependent_reorg
+
+/* In ia16-reorg.c .  */
+extern void ia16_machine_dependent_reorg (void);
+
+#undef	TARGET_INIT_BUILTINS
+#define	TARGET_INIT_BUILTINS	ia16_init_builtins
+
+/* In ia16-builtins.c .  */
+extern GTY (()) tree ia16_builtin_decls[IA16_BUILTIN_MAX];
+extern void ia16_init_builtins (void);
+
+#undef	TARGET_BUILTIN_DECL
+#define	TARGET_BUILTIN_DECL	ia16_builtin_decl
+
+/* In ia16-builtins.c .  */
+extern tree ia16_builtin_decl (unsigned code, bool initialize_p);
+
+#undef	TARGET_EXPAND_BUILTIN
+#define	TARGET_EXPAND_BUILTIN	ia16_expand_builtin
+
+/* In ia16-builtins.c .  */
+extern rtx ia16_expand_builtin (tree expr, rtx target, rtx subtarget,
+				machine_mode mode, int ignore);
+
+#undef	TARGET_FOLD_BUILTIN
+#define	TARGET_FOLD_BUILTIN	ia16_fold_builtin
+
+/* In ia16-builtins.c .  */
+extern tree ia16_fold_builtin (tree fndecl, int n_args, tree *args,
+			       bool ignore);
+
+#undef	TARGET_SET_CURRENT_FUNCTION
+#define	TARGET_SET_CURRENT_FUNCTION ia16_set_current_function
+
+/* In ia16-no-ss-data.c .  */
+extern void ia16_set_current_function (tree);
+
+/* The Global targetm Variable */
+
+/* #include "target.h" */
+/* #include "target-def.h" */
+
+/* Initialize the GCC target structure.  */
+struct gcc_target targetm = TARGET_INITIALIZER;
+
+/* Support functions not documented in the GCC internals manual.  */
+
+/* Return true if the operands are suitable for an insn of code CODE.
+ * Return false otherwise.  Note that we don't bother checking combinations
+ * of register and immediate operands since the operand predicates should be
+ * enough.  SCRATCH expressions are also accepted for operand 0.
+ * The insn is assumed to have exactly three operands.
+ */
+bool ia16_arith_operands_p (enum rtx_code code, rtx *operands)
+{
+  if (MEM_P (operands[1]) && MEM_P (operands[2]))
+    return (false);
+
+  if (MEM_P (operands[0]))
+    {
+      /* OK if op0 and op1 is the same MEM.  */
+      if (rtx_equal_p (operands[0], operands[1]))
+	return (true);
+
+      /* OK if op0 and op2 is the same MEM if
+	 1) CODE is commutative, or
+	 2) CODE is MINUS and op1 is zero.  */
+      if ((RTX_COMM_ARITH == GET_RTX_CLASS (code)
+	   || (MINUS == code
+	      && operands[1] == CONST0_RTX (GET_MODE (operands[1]))))
+	  && rtx_equal_p (operands[0], operands[2]))
+	return (true);
+    }
+  else if ((RTX_COMM_ARITH == GET_RTX_CLASS (code)
+	    && !CONSTANT_P (operands[2]))
+	   || !MEM_P (operands[1]))
+    return (true);
+  return (false);
+}
+
+/* Mung OPERANDS enough to be accepted by ia16_arith_operands_p (CODE,
+   OPERANDS).  If operands[0] needs to be munged, return a new pseudo register
+   operand to use as a temporary.  Otherwise, return NULL.
+   This function may create new pseudo registers.
+   TODO: Three different memory operands are all forced to registers.  Ideally,
+   only operands[0] and operands[1] should be forced to registers.
+ */
+rtx ia16_prepare_operands (enum rtx_code code, rtx *operands)
+{
+  rtx tmp = NULL;
+
+  /* If op1 is MEM, op0 must be the same mem.  If they are the same mem, then
+     op2 must not also be a mem.  */
+  if (MEM_P (operands[1]))
+    {
+      if (!rtx_equal_p (operands[0], operands[1]))
+	operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
+      else if (MEM_P (operands[2]))
+	operands[2] = force_reg (GET_MODE (operands[2]), operands[2]);
+    }
+
+  /* If op2 is MEM, op0 must be the same mem and CODE != MINUS.  */
+  if (MEM_P (operands[2])
+      && (RTX_BIN_ARITH == GET_RTX_CLASS (code)
+	  || !rtx_equal_p (operands[0], operands[2])))
+    operands[2] = force_reg (GET_MODE (operands[2]), operands[2]);
+
+  /* If op0 is MEM different from op1 and op2, use a scratch register.  */
+  if (MEM_P (operands[0])
+      && (!MEM_P (operands[1]) || !MEM_P (operands[2])))
+    tmp = gen_reg_rtx (GET_MODE (operands[0]));
+  return (tmp);
+}
+
+/* Split a memory address displacement X into a symbolic part SYMVAL and an
+ * integer part INTVAL.  X may be NULL.
+ */
+static void
+ia16_parse_constant (rtx x, rtx *symval, rtx *intval)
+{
+  if (x == NULL)
+    {
+      *symval = NULL;
+      *intval = const0_rtx;
+    }
+  else if (CONST_INT_P (x))
+    {
+      *symval = NULL;
+      *intval = x;
+    }
+  /* Try to handle (const (plus (...) (const_int c))).  */
+  else if (CONST == GET_CODE (x) && PLUS == GET_CODE (XEXP (x, 0)))
+    {
+      if (CONST_INT_P (XEXP (XEXP (x, 0), 1)))
+	{
+	  *symval = XEXP (XEXP (x, 0), 0);
+	  *intval = XEXP (XEXP (x, 0), 1);
+	}
+      else
+	{
+	  *symval = XEXP (x, 0);
+	  *intval = const0_rtx;
+	}
+    }
+  else
+    {
+      *symval = x;
+      *intval = const0_rtx;
+    }
+}
+
+/* Return true if the addresses of memory operands M1 and M2 differ only by
+ * a fixed, numeric value, and store the number of units of M1 - M2 in OFFSET.
+ * Return false otherwise.  */
+static bool
+ia16_memory_offset_known (rtx m1, rtx m2, int *offset)
+{
+  rtx m1base, m1index, m1disp, m1seg, m1sym, m1int;
+  rtx m2base, m2index, m2disp, m2seg, m2sym, m2int;
+
+  ia16_parse_address_strict (XEXP (m1, 0), &m1base, &m1index, &m1disp, &m1seg,
+			     MEM_ADDR_SPACE (m1));
+  ia16_parse_address_strict (XEXP (m2, 0), &m2base, &m2index, &m2disp, &m2seg,
+			     MEM_ADDR_SPACE (m2));
+
+  if (!rtx_equal_p (m1base, m2base) || !rtx_equal_p (m1index, m2index) ||
+      !rtx_equal_p (m1seg, m2seg))
+    return (false);
+
+  ia16_parse_constant (m1disp, &m1sym, &m1int);
+  ia16_parse_constant (m2disp, &m2sym, &m2int);
+
+  if (!rtx_equal_p (m1sym, m2sym))
+    return (false);
+
+  *offset = INTVAL (m1int) - INTVAL (m2int);
+  return (true);
+}
+
+/* Return true if memory operands M1 and M2 are suitable for a move
+ * multiple instruction in mode MODE.  Return false otherwise.  */
+bool
+ia16_move_multiple_mem_p (enum machine_mode mode, rtx m1, rtx m2)
+{
+  int offset;
+
+  if (ia16_memory_offset_known (m2, m1, &offset))
+    return (GET_MODE_SIZE (mode) == offset);
+  else
+    return (false);
+}
+
+/* Return true if register operands R1 and R2 are suitable for a move
+ * multiple instruction in mode MODE.  Return false otherwise.  */
+bool
+ia16_move_multiple_reg_p (enum machine_mode mode, rtx r1, rtx r2)
+{
+  enum machine_mode mode2x = GET_MODE_2XWIDER_MODE (mode);
+  unsigned int reg1no = REGNO (r1);
+
+  if (!HARD_REGNO_MODE_OK (reg1no, mode2x))
+    return (false);
+  return (REGNO (r2) - reg1no
+	  == subreg_regno_offset (reg1no, mode2x, GET_MODE_SIZE (mode), mode));
+}
+
+/* Return true if we can prove that memory operands M1 and M2 don't overlap.
+ * Return false otherwise.  */
+bool
+ia16_non_overlapping_mem_p (rtx m1, rtx m2)
+{
+  int offset;
+
+  if (!ia16_memory_offset_known (m1, m2, &offset))
+    return (false);
+
+  if (offset < 0)
+    return (GET_MODE_SIZE (GET_MODE (m1)) <= -offset);
+  else if (offset > 0)
+    return (GET_MODE_SIZE (GET_MODE (m2)) <=  offset);
+  else
+    return (false);
+}
+
+/* Emit instructions to reset %ds to .data.  */
+static void
+ia16_expand_reset_ds_internal (void)
+{
+  rtx ds = gen_rtx_REG (SEGmode, DS_REG);
+  if (! ia16_in_ss_data_function_p ())
+    emit_move_insn (ds, ia16_data_seg_rtx ());
+  else if (TARGET_PROTECTED_MODE)
+    emit_insn (gen__movphi_ds_ss_slow ());
+  else
+    emit_insn (gen__movhi_ds_ss_slow ());
+  emit_use (ds);
+}
+
+void
+ia16_expand_reset_ds_for_call (rtx addr)
+{
+  if (ia16_ds_data_function_rtx_p (addr))
+    ia16_expand_reset_ds_internal ();
+}
+
+void
+ia16_expand_reset_ds_for_return (void)
+{
+  if (ia16_in_ds_data_function_p () && ia16_in_ss_data_function_p ())
+    ia16_expand_reset_ds_internal ();
+}
+
+void
+ia16_expand_prologue (void)
+{
+  rtx insn;
+  unsigned int i;
+  HOST_WIDE_INT size = get_frame_size ();
+
+  /* Save used registers which are not call clobbered. */
+  for (i = 0; i <= LAST_ALLOCABLE_REG; ++i)
+    {
+      if (i != BP_REG && ia16_save_reg_p (i))
+	{
+	  insn = emit_insn (ia16_push_reg (i));
+	  RTX_FRAME_RELATED_P (insn) = 1;
+	}
+    }
+  if (ia16_save_reg_p (BP_REG))
+    {
+      if (HAVE__enter && size != 0)
+	{
+	  insn = gen__enter (gen_rtx_CONST_INT (HImode, size + 2));
+	  insn = emit_insn (insn);
+	  RTX_FRAME_RELATED_P (insn) = 1;
+	}
+      else
+	{
+	  insn = emit_insn (ia16_push_reg (BP_REG));
+	  RTX_FRAME_RELATED_P (insn) = 1;
+	  insn = emit_move_insn (gen_rtx_REG (Pmode, BP_REG),
+				 gen_rtx_REG (Pmode, SP_REG));
+	  RTX_FRAME_RELATED_P (insn) = 1;
+	  if (size != 0)
+	    {
+	      insn = emit_insn (gen_subhi3 (gen_rtx_REG (Pmode, SP_REG),
+					    gen_rtx_REG (Pmode, SP_REG),
+					    gen_rtx_CONST_INT (HImode, size)));
+	      RTX_FRAME_RELATED_P (insn) = 1;
+	    }
+	}
+    }
+  if (flag_stack_usage_info)
+    {
+      current_function_static_stack_size = size +
+	ia16_initial_arg_pointer_offset () + UNITS_PER_WORD;
+    }
+}
+
+void
+ia16_expand_epilogue (bool sibcall)
+{
+  unsigned int i;
+  HOST_WIDE_INT size = get_frame_size ();
+
+  if (ia16_save_reg_p (BP_REG))
+    {
+      /* We need to restore the stack pointer. We have two options:
+       * 1) Add the frame size to sp.
+       * 2) Use the saved sp value in bp.
+       * The second option makes it possible to use the leave instruction and
+       * is shorter in any case, but ties up a register. So only refer to bp
+       * if it wasn't used during the function.
+       */
+      if (HAVE__leave)
+	{
+	  /* If sp wasn't modified, "popw %bp" is faster than "leavew". */
+	  if (size == 0 && crtl->sp_is_unchanging)
+	    emit_insn (ia16_pop_reg (BP_REG));
+	  else
+	    emit_insn (gen__leave ());
+	}
+      else
+	{
+	  if (EXIT_IGNORE_STACK)
+	    {
+	      emit_move_insn (gen_rtx_REG (Pmode, SP_REG),
+			      gen_rtx_REG (Pmode, BP_REG));
+	    }
+	  emit_insn (ia16_pop_reg (BP_REG));
+	}
+    }
+  /* Restore used registers. */
+  for (i = LAST_ALLOCABLE_REG; i < FIRST_PSEUDO_REGISTER; --i)
+    {
+      if (i != BP_REG && ia16_save_reg_p (i))
+	emit_insn (ia16_pop_reg (i));
+    }
+  if (!sibcall)
+    emit_jump_insn (gen_simple_return ());
+}
+
+/* GNU as does not like
+	lcall	$foo@OZSEG16,	$foo
+   and says "Error: can't handle non absolute segment in `lcall'".  */
+#define LCALL_TEMPLATE(dest) \
+			(TARGET_ABI_SEGELF \
+			   ?    ".reloc\t.+3, R_386_SEG16, \"" dest "!\"\n" \
+			     "\tlcall\t$0,\t$" dest \
+			   :    ".reloc\t.+3, R_386_OZSEG16, " dest "\n" \
+			     "\tlcall\t$0,\t$" dest)
+#define LJMP_TEMPLATE(dest) \
+			(TARGET_ABI_SEGELF \
+			   ?    ".reloc\t.+3, R_386_SEG16, \"" dest "!\"\n" \
+			     "\tljmp\t$0,\t$" dest \
+			   :    ".reloc\t.+3, R_386_OZSEG16, " dest "\n" \
+			     "\tljmp\t$0,\t$" dest)
+
+#define P(part)	(which_is_addr == 0 ? part "0" : part "1")
+#define P2(part_a, part_b) \
+			(which_is_addr == 0 ? part_a "0" part_b "0" : \
+					      part_a "1" part_b "1")
+/* MACRO is either LCALL_TEMPLATE or LJMP_TEMPLATE.  */
+#define PM(macro)	(which_is_addr == 0 ? macro ("%c0") : macro ("%c1"))
+
+/* Return the insn template for a normal call to a subroutine at address
+   ADDR and with machine mode MODE.  ADDR should correspond to "%0" or "%1"
+   in the (define_insn ...), depending on whether WHICH_IS_ADDR is 0 or 1.
+
+   There are 4 cases we need to handle:
+
+     * We are calling a near function (with a 16-bit address), and the current
+       function is not marked __attribute__ ((far_section)).
+
+     * We are calling a far function through a 32-bit pointer.
+
+     * We are calling a far function --- which returns with `lret' --- but
+       the function is defined in the current module, and neither caller nor
+       callee is marked __attribute__ ((far_section)), so we can probably
+       get away with a `pushw %cs' plus a near call.
+
+       There are two exceptions to this, where the caller or callee is likely
+       to get its own function-specific section, even without far_section:
+	- if the caller or callee is to go in a link-once (COMDAT) section;
+	- if -ffunction-sections is in effect.
+
+     * None of the above --- use `lcall' and do not assume that the function
+       resides in the default text section.
+
+   The case where a far_section function tries to call a near function is
+   handled by ia16_get_far_thunked_call_expansion (...) below.  */
+const char *
+ia16_get_call_expansion (rtx addr, machine_mode mode, unsigned which_is_addr)
+{
+  tree fndecl, fntype;
+
+  if (mode == SImode)
+    {
+      if (CONST_INT_P (addr))
+	return P2 ("lcall\t%S", ",\t%O");
+      else
+	return P ("lcall\t*%");
+    }
+
+  fndecl = ia16_get_decl_for_addr (addr);
+  fntype = ia16_get_function_type_for_decl (fndecl);
+
+  if (! ia16_far_function_type_p (fntype))
+    {
+      gcc_assert (! ia16_in_far_section_function_p ());
+
+      if (MEM_P (addr) || ! CONSTANT_P (addr))
+	return P ("call\t*%");
+      else
+	return P ("call\t%c");
+    }
+  else if (fntype
+	   && ! ia16_in_far_section_function_p ()
+	   && ((DECL_INITIAL (fndecl)
+		&& ! flag_function_sections
+		&& ! ia16_far_section_function_type_p (fntype)
+		&& ! DECL_COMDAT_GROUP (fndecl)
+		&& ! DECL_COMDAT_GROUP (cfun->decl))
+	       || ia16_near_section_function_type_p (fntype)))
+    {
+      if (MEM_P (addr) || ! CONSTANT_P (addr))
+	return P ("pushw\t%%cs\n\tcall\t*%");
+      else
+	return P ("pushw\t%%cs\n\tcall\t%c");
+    }
+  else
+    {
+      if (! TARGET_SEG_RELOC_STUFF)
+	ia16_error_seg_reloc (input_location, "cannot create relocatable call "
+					      "to far function");
+      return PM (LCALL_TEMPLATE);
+    }
+}
+
+/* Say whether we need to use a far thunk to call a function from the current
+   function, i.e. the current function is __attribute__ ((far_section)) and
+   trying to call a near function.  */
+bool
+ia16_use_far_thunked_call_p (rtx addr, machine_mode mode)
+{
+  tree fntype;
+
+  if (mode != HImode || ! ia16_in_far_section_function_p ())
+    return false;
+
+  fntype = ia16_get_function_type_for_addr (addr);
+  return ! ia16_far_function_type_p (fntype);
+}
+
+/* Return the insn template for a call from a far_section function to a near
+   subroutine at the address given by the operand "%0" or "%1" --- depending on
+   whether WHICH_IS_ADDR is 0 or 1 --- with "%1" or "%2" bytes of stack
+   arguments.  The caller should pop the stack arguments if POP_P is true.  */
+const char *
+ia16_get_far_thunked_call_expansion (unsigned which_is_addr, bool pop_p)
+{
+  if (! TARGET_SEG_RELOC_STUFF)
+    ia16_error_seg_reloc (input_location, "cannot create relocatable call "
+					  "to far -> near thunk");
+
+  if (! pop_p)
+    {
+      if (which_is_addr == 0)
+	return LCALL_TEMPLATE ("__ia16_far_call_thunk.%R0.%R1");
+      else
+	return LCALL_TEMPLATE ("__ia16_far_call_thunk.%R1.%R2");
+    }
+  else
+    {
+      if (which_is_addr == 0)
+	return LCALL_TEMPLATE ("__ia16_far_call_pop_thunk.%R0.%R1.%R2");
+      else
+	return LCALL_TEMPLATE ("__ia16_far_call_pop_thunk.%R1.%R2.%R3");
+    }
+}
+
+/* Return the insn template for a sibling call to a subroutine at address
+   ADDR and with machine mode MODE.  ADDR should correspond to "%0" or "%1"
+   in the (define_insn ...), depending on whether WHICH_IS_ADDR is 0 or 1.  */
+const char *
+ia16_get_sibcall_expansion (rtx addr, machine_mode mode,
+			    unsigned which_is_addr)
+{
+  tree fndecl, fntype = NULL_TREE;
+
+  if (mode == SImode)
+    {
+      if (CONST_INT_P (addr))
+	return P2 ("ljmp\t%S", ",\t%O");
+      else
+	return P ("ljmp\t*%");
+    }
+
+  fndecl = ia16_get_decl_for_addr (addr);
+  fntype = ia16_get_function_type_for_decl (fndecl);
+
+  if (! ia16_far_function_type_p (fntype))
+    {
+      if (MEM_P (addr) || ! CONSTANT_P (addr))
+	return P ("jmp\t*%");
+      else
+	return P ("jmp\t%c");
+    }
+  else if (! ia16_in_far_section_function_p ()
+	   && ((DECL_INITIAL (fndecl)
+		&& ! ia16_far_section_function_type_p (fntype))
+	       || ia16_near_section_function_type_p (fntype)))
+    {
+      if (MEM_P (addr) || ! CONSTANT_P (addr))
+	return P ("jmp\t*%");
+      else
+	return P ("jmp\t%c");
+    }
+  else
+    {
+      if (! TARGET_SEG_RELOC_STUFF)
+	ia16_error_seg_reloc (input_location, "cannot create relocatable "
+					      "sibcall to far function");
+      return PM (LJMP_TEMPLATE);
+    }
+}
+
+#undef P
+#undef P2
+#undef PM
+
+void
+ia16_asm_output_addr_diff_elt (FILE *stream, rtx body ATTRIBUTE_UNUSED,
+			   int value, int rel)
+{
+  asm_fprintf (stream, "\t.hword\t%U%LL%d-%U%LL%d\n", value, rel);
+}
+
+void
+ia16_asm_output_addr_vec_elt (FILE *stream, int value)
+{
+  asm_fprintf (stream, "\t.hword\t%U%LL%d\n", value);
+}
+
+#include "gt-ia16.h"
diff --git a/gcc/config/ia16/ia16.h b/gcc/config/ia16/ia16.h
new file mode 100644
index 0000000..9601b24
--- /dev/null
+++ b/gcc/config/ia16/ia16.h
@@ -0,0 +1,706 @@
+/* GNU Compiler Collection definitions of target machine Intel 16-bit x86.
+   Copyright (C) 2005-2020 Free Software Foundation, Inc.
+   Contributed by Rask Ingemann Lambertsen <rask@sygehus.dk>
+   Changes by Andrew Jenner <andrew@codesourcery.com>
+   Very preliminary IA-16 far pointer support and other changes by TK Chia
+
+   This file is part of GCC.
+
+   GCC 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 3 of the License, or (at your option) any
+   later version.
+
+   GCC 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/licenses/>.
+*/
+
+/* Keep this in sync with processor_target_table in ia16.c.  */
+#define TARGET_SHIFT_IMM	(ia16_features & 1)
+#define TARGET_PUSH_IMM		(ia16_features & 1)
+#define TARGET_IMUL_IMM		(ia16_features & 1)
+#define TARGET_PUSHA		(ia16_features & 1)
+#define TARGET_ENTER_LEAVE	(ia16_features & 1)
+#define TARGET_SHIFT_MASKED	(ia16_features & 2)
+#define TARGET_AAD_IMM		(ia16_features & 4)
+#define TARGET_FSTSW_AX		(ia16_features & 8)
+#define TARGET_TUNE_8BIT	(ia16_features & 16)
+
+#define TARGET_ALLOCABLE_DS_REG	(! fixed_regs[DS_REG])
+#define TARGET_CMODEL_IS_TINY	(target_cmodel == CMODEL_TINY)
+#define TARGET_CMODEL_IS_FAR_TEXT (target_cmodel == CMODEL_MEDIUM || \
+				   target_cmodel == CMODEL_LARGE || \
+				   target_cmodel == CMODEL_HUGE)
+#define SEGmode			(TARGET_PROTECTED_MODE ? PHImode : HImode)
+
+/* Run-time Target Specification */
+#define TARGET_CPU_CPP_BUILTINS() ia16_cpu_cpp_builtins ()
+/* Using SWITCHABLE_TARGET makes it a bit easier for us to mess with
+   this_target_rtl to implement %ss != .data caling conventions.  See
+   ia16-no-ss-data.c .  */
+#define SWITCHABLE_TARGET	1
+
+/* Storage Layout
+ *
+ * A unit is 8 bits, a machine word is 16 bits (two units), all little endian.
+ */
+
+#define BITS_BIG_ENDIAN 0
+#define BYTES_BIG_ENDIAN 0
+#define WORDS_BIG_ENDIAN 0
+#define UNITS_PER_WORD 2
+
+#define PARM_BOUNDARY		BITS_PER_WORD
+#define STACK_BOUNDARY		BITS_PER_WORD
+#define FUNCTION_BOUNDARY	BITS_PER_UNIT
+#define BIGGEST_ALIGNMENT	BITS_PER_WORD
+#define STRUCTURE_SIZE_BOUNDARY	BITS_PER_UNIT
+#define STRICT_ALIGNMENT	0
+#define PCC_BITFIELD_TYPE_MATTERS 1
+
+/* Layout of Source Language Data Types.  */
+#define         INT_TYPE_SIZE 16
+#define       SHORT_TYPE_SIZE 16
+#define        LONG_TYPE_SIZE 32
+#define   LONG_LONG_TYPE_SIZE 64
+#define       FLOAT_TYPE_SIZE 32
+#define      DOUBLE_TYPE_SIZE 64
+#define LONG_DOUBLE_TYPE_SIZE 64
+
+#define DEFAULT_SIGNED_CHAR		1
+#define SIZE_TYPE			"unsigned int"
+#define PTRDIFF_TYPE			"int"
+#define WCHAR_TYPE_SIZE			16
+
+#define TARGET_VTABLE_USES_DESCRIPTORS 0
+
+/* Register Usage
+ *
+ * These are the registers of the 8086 family.
+ * The argument pointer register (ap/argp) is a fixed, virtual hard register.
+ *
+ * The order matters.  dh:dl:ah:al should be consequtive because some
+ * instructions treat them as a 32-bit register.  Cl should be at one of the
+ * ends or it will be impossible to fit both a shift count and a 64-bit
+ * value at the same time.  Life is a lot easier if xl:xh pairs are kept
+ * together.  We don't want to tie up both index (si and di) or both base w/
+ * index (bx and bp) registers with a value spanning multiple hard
+ * registers.
+ *
+ * (I include SS_REG and CS_REG in the register file to make it easier to
+ * express %ds <- %ss assignments and near -> far pointer casts.  They play
+ * no part in register allocation.  -- tkchia)
+ *
+ * TODO: For optimization purposes, we'd want a 64-bit value to be held in
+ * registers such that the upper and lower bytes are in an 8-bit register.
+ *
+ * Name:  cl ch al ah dl dh bl bh si di bp es ds sp cc ss cs ap
+ * Size:   8  8  8  8  8  8  8  8 16 16 16 16 16 16 cc 16 16 16
+ * Index:  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17
+ *
+ * Basic Characteristics of Registers
+ */
+#define FIXED_REGISTERS \
+         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 }
+#define CALL_USED_REGISTERS \
+         { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 }
+
+/* Order of Allocation of Registers.  */
+/* The goal is to create opportunities for using load/store multiple
+ * instructions as well as good register allocation in general.  */
+#define REG_ALLOC_ORDER \
+	{ 2, 3, 4, 5, 0, 1,  6, 7, 10,  9, 8, 11, 12, 13, 14, 15, 16, 17 }
+/*	 al ah dl dh cl ch  bl bh  bp  di si  es  ds  sp  cc  ss  cs  ap */
+
+/* How Values Fit in Registers.  */
+/* FIXME: Not documented: CCmode is 32 bits.  */
+/* Must not return 0 or subreg_get_info() may divide by zero.  */
+/* FIXME: Handling of XFmode needs to use GET_MODE_PRECISION(). */
+#define HARD_REGNO_NREGS(REGNO, MODE) \
+  (MAX (ia16_hard_regno_nregs[GET_MODE_SIZE(MODE)][REGNO], 1))
+
+/* There are more cases than those caught here, but HARD_REGNO_MODE_OK()
+   forbids them. Catch multireg values that straddle the boundary between
+   8-bit and 16-bit registers. */
+#define HARD_REGNO_NREGS_HAS_PADDING(REGNO, MODE) \
+	((REGNO) < FIRST_NOQI_REG && \
+	 (REGNO) + GET_MODE_SIZE(MODE) > FIRST_NOQI_REG)
+
+#define HARD_REGNO_NREGS_WITH_PADDING(REGNO, MODE) \
+	(GET_MODE_SIZE(MODE))
+
+#define REGMODE_NATURAL_SIZE(MODE)	\
+	(GET_MODE_SIZE(MODE) == 1 || GET_MODE_CLASS(MODE) == MODE_CC ? \
+	 1 : UNITS_PER_WORD)
+
+/* Complex modes must not cross the boundary between 8-bit and 16-bit
+   registers because subreg_get_info() will fail in that case.  */
+#define HARD_REGNO_MODE_OK(REGNO, MODE) \
+  (GET_MODE_CLASS(MODE) == MODE_CC ? (REGNO) == CC_REG :		\
+   (REGNO) == CC_REG ? GET_MODE_CLASS(MODE) == MODE_CC :		\
+   GET_MODE_SIZE(MODE) > 16 ? 0 :					\
+   COMPLEX_MODE_P(MODE) &&						\
+     HARD_REGNO_NREGS_HAS_PADDING((REGNO), (MODE)) ? 0 :		\
+   ia16_hard_regno_nregs[GET_MODE_SIZE(MODE)][REGNO] &&			\
+     (! TARGET_PROTECTED_MODE || (MODE) == PHImode			\
+      || ((REGNO) != DS_REG && (REGNO) != ES_REG)))
+
+/* For some reason, allowing registers other than %ds to be renamed to %ds
+   during the rnreg pass (with e.g. -funroll-loops) leads to incorrect code
+   around %ds <- %ss operations, so disable that.
+
+   And, rnreg has this weird idea to rename the segment register in a
+   segment override to a non-segment register (argh!).  Disable that too.  */
+#define HARD_REGNO_RENAME_OK(FROM, TO) \
+	(((FROM) != DS_REG && (FROM) != ES_REG && (TO) != DS_REG) \
+	 || ((FROM) == DS_REG && (TO) == ES_REG))
+
+/* When this returns 0, rtx_cost() in rtlanal.c will pessimize the RTX cost
+ * estimate, and this particular case cannot be overridden by
+ * ia16_rtx_costs().  And if you get it wrong, the register allocator will
+ * be stupid about libgcc2.c's _popcountsi2().  The cases we have to reject
+ * here are:
+ * 1) Access of a 16-bit value in MODE1 as an 8-bit value MODE2.
+ *    This will fail for registers in class HI_REGS.
+ * 2) Access of an 8-bit value in MODE1 as an 16-bit value in MODE2.
+ *    This will fail for registers in class UP_QI_REGS.
+ * Used in: rtlanal.c, combine.c, regclass.c and local-alloc.c.
+ */
+#define MODES_TIEABLE_P(MODE1, MODE2)	\
+	(GET_MODE_SIZE(MODE2) > 1 && GET_MODE_SIZE(MODE1) > 1)
+
+/* Handling Leaf Functions
+ *
+ * Registers That Form a Stack
+ * (Hardware floating point is not yet supported.)
+ */
+/* Register Classes
+ *
+ * The register classes, along with contraint letter and bit mask.
+ * Keep this in sync with REG*_OK_FOR*_P() below.
+ * Keep this in sync with ia16_regno_class[] in ia16.c.
+ */
+enum reg_class {	/*	 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0 */
+  NO_REGS,	     /*   000000  4  2  1  4  2  1  4  2  1  4  2  1  4  2  1  4  2  1 */
+  AL_REGS,	   /* Ral 000004  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . al  .  . */
+  AH_REGS,	   /* Rah 000010  .  .  .  .  .  .  .  .  .  .  .  .  .  . ah  .  .  . */
+  AX_REGS,	     /* a 000014  .  .  .  .  .  .  .  .  .  .  .  .  .  . -- ax  .  . */
+  DL_REGS,	   /* Rdl 000020  .  .  .  .  .  .  .  .  .  .  .  .  . dl  .  .  .  . */ 
+  DH_REGS,	   /* Rdh 000040  .  .  .  .  .  .  .  .  .  .  .  . dh  .  .  .  .  . */
+  DX_REGS,	     /* d 000060  .  .  .  .  .  .  .  .  .  .  .  . -- dx  .  .  .  . */
+  DXAX_REGS,	     /* A 000074  .  .  .  .  .  .  .  .  .  .  .  . -- dx -- ax  .  . */
+  BX_REGS,	     /* b 000300  .  .  .  .  .  .  .  .  .  . -- bx  .  .  .  .  .  . */
+  BXDX_REGS,	     /* j 000360  .  .  .  .  .  .  .  .  .  . -- bx -- dx  .  .  .  . */
+  CL_REGS,	   /* Rcl 000001  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . cl */
+  CX_REGS,	     /* c 000003  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . -- cx */
+  LO_QI_REGS,	     /* l 000125  .  .  .  .  .  .  .  .  .  .  . bl  . dl  . al  . cl */
+  UP_QI_REGS,	     /* u 000252  .  .  .  .  .  .  .  .  .  . bh  . dh  . ah  . ch  . */
+  QI_REGS,	     /* q 000377  .  .  .  .  .  .  .  .  .  . bh bl dh dl ah al ch cl */
+  SI_REGS,	     /* S 000400  .  .  .  .  .  .  .  .  . si  .  .  .  .  .  .  .  . */
+  QISI_REGS,	     /* k 000777  .  .  .  .  .  .  .  .  . si -- bx -- dx -- ax -- cx */
+  DI_REGS,	     /* D 001000  .  .  .  .  .  .  .  . di  .  .  .  .  .  .  .  .  . */
+  INDEX_REGS,	     /* x 001400  .  .  .  .  .  .  .  . di si  .  .  .  .  .  .  .  . */
+  BP_REGS,	   /* Rbp 002000  .  .  .  .  .  .  . bp  .  .  .  .  .  .  .  .  .  . */
+  BASE_W_INDEX_REGS, /* w 002300  .  .  .  .  .  .  . bp  .  . -- bx  .  .  .  .  .  . */
+  BASE_REGS,	     /* B 003700  .  .  .  .  .  .  . bp di si -- bx  .  .  .  .  .  . */
+  ES_REGS,	     /* e 004000  .  .  .  .  .  . es  .  .  .  .  .  .  .  .  .  .  . */
+  DS_REGS,	   /* Rds 010000  .  .  .  .  . ds  .  .  .  .  .  .  .  .  .  .  .  . */
+  SEGMENT_REGS,	     /* Q 314000  . cs ss  .  . ds es  .  .  .  .  .  .  .  .  .  .  . */
+  HI_REGS,	     /*   337400  . cs ss  . sp ds es bp di si  .  .  .  .  .  .  .  . */
+  GENERAL_REGS,	     /* r 023777  .  .  .  . sp  .  . bp di si bh bl dh dl ah al ch cl */
+  ES_GENERAL_REGS,   /*   027777  .  .  .  . sp  . es bp di si bh bl dh dl ah al ch cl */
+  SEG_GENERAL_REGS,  /* T 337777  . cs ss  . sp ds es bp di si bh bl dh dl ah al ch cl */
+  ALL_REGS,	     /*   777777 ap cs ss cc sp ds es bp di si bh bl dh dl ah al ch cl */
+  LIM_REG_CLASSES
+};
+#define N_REG_CLASSES ((int) LIM_REG_CLASSES)
+
+#define REG_CLASS_NAMES \
+{ "NO_REGS", "AL_REGS", "AH_REGS", "AX_REGS", "DL_REGS", "DH_REGS", \
+  "DX_REGS", "DXAX_REGS", "BX_REGS", "BXDX_REGS", "CL_REGS", \
+  "CX_REGS", "LO_QI_REGS", "UP_QI_REGS", "QI_REGS", \
+  "SI_REGS", "QISI_REGS", "DI_REGS", "INDEX_REGS", \
+  "BP_REGS", "BASE_W_INDEX_REGS", "BASE_REGS", "ES_REGS", "DS_REGS", \
+  "SEGMENT_REGS", "HI_REGS", "GENERAL_REGS", "ES_GENERAL_REGS", \
+  "SEG_GENERAL_REGS", "ALL_REGS" }
+
+#define REG_CLASS_CONTENTS {	  /* 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0 */ \
+  { 0000000 }, /* NO_REGS,	      4  2  1  4  2  1  4  2  1  4  2  1  4  2  1  4  2  1 */ \
+  { 0000004 }, /* AL_REGS,	  Ral .  .  .  .  .  .  .  .  .  .  .  .  .  .  . al  .  . */ \
+  { 0000010 }, /* AH_REGS,	  Rah .  .  .  .  .  .  .  .  .  .  .  .  .  . ah  .  .  . */ \
+  { 0000014 }, /* AX_REGS,	    a .  .  .  .  .  .  .  .  .  .  .  .  .  . -- ax  .  . */ \
+  { 0000020 }, /* DL_REGS,	  Rdl .  .  .  .  .  .  .  .  .  .  .  .  . dl  .  .  .  . */ \
+  { 0000040 }, /* DH_REGS,	  Rdh .  .  .  .  .  .  .  .  .  .  .  . dh  .  .  .  .  . */ \
+  { 0000060 }, /* DX_REGS,	    d .  .  .  .  .  .  .  .  .  .  .  . -- dx  .  .  .  . */ \
+  { 0000074 }, /* DXAX_REGS,	    A .  .  .  .  .  .  .  .  .  .  .  . -- dx -- ax  .  . */ \
+  { 0000300 }, /* BX_REGS,	    b .  .  .  .  .  .  .  .  .  . -- bx  .  .  .  .  .  . */ \
+  { 0000360 }, /* BXDX_REGS,	    j .  .  .  .  .  .  .  .  .  . -- bx -- dx  .  .  .  . */ \
+  { 0000001 }, /* CL_REGS,	  Rcl .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . cl */ \
+  { 0000003 }, /* CX_REGS,	    c .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . -- cx */ \
+  { 0000125 }, /* LO_QI_REGS,	    l .  .  .  .  .  .  .  .  .  .  . bl  . dl  . al  . cl */ \
+  { 0000252 }, /* UP_QI_REGS,	    u .  .  .  .  .  .  .  .  .  . bh  . dh  . ah  . ch  . */ \
+  { 0000377 }, /* QI_REGS,	    q .  .  .  .  .  .  .  .  .  . bh bl dh dl ah al ch cl */ \
+  { 0000400 }, /* SI_REGS,	    S .  .  .  .  .  .  .  .  . si  .  .  .  .  .  .  .  . */ \
+  { 0000777 }, /* QISI_REGS,	    k .  .  .  .  .  .  .  .  . si -- bx -- dx -- ax -- cx */ \
+  { 0001000 }, /* DI_REGS,	    D .  .  .  .  .  .  .  . di  .  .  .  .  .  .  .  .  . */ \
+  { 0001400 }, /* INDEX_REGS,	    x .  .  .  .  .  .  .  . di si  .  .  .  .  .  .  .  . */ \
+  { 0002000 }, /* BP_REGS,	  Rbp .  .  .  .  .  .  . bp  .  .  .  .  .  .  .  .  .  . */ \
+  { 0002300 }, /* BASE_W_INDEX_REGS w .  .  .  .  .  .  . bp  .  . -- bx  .  .  .  .  .  . */ \
+  { 0003700 }, /* BASE_REGS,	    B .  .  .  .  .  .  . bp di si -- bx  .  .  .  .  .  . */ \
+  { 0004000 }, /* ES_REGS,	    e .  .  .  .  .  . es  .  .  .  .  .  .  .  .  .  .  . */ \
+  { 0010000 }, /* DS_REGS,	  Rds .  .  .  .  . ds  .  .  .  .  .  .  .  .  .  .  .  . */ \
+  { 0314000 }, /* SEGMENT_REGS,	    Q . cs ss  .  . ds es  .  .  .  .  .  .  .  .  .  .  . */ \
+  { 0337400 }, /* HI_REGS,	      . cs ss  . sp ds es bp di si  .  .  .  .  .  .  .  . */ \
+  { 0023777 }, /* GENERAL_REGS,	    r .  .  .  . sp  .  . bp di si bh bl dh dl ah al ch cl */ \
+  { 0027777 }, /* ES_GENERAL_REGS,    .  .  .  . sp  . es bp di si bh bl dh dl ah al ch cl */ \
+  { 0337777 }, /* SEG_GENERAL_REGS, T . cs ss  . sp ds es bp di si bh bl dh dl ah al ch cl */ \
+  { 0777777 }, /* ALL_REGS,	     ap cs ss cc sp ds es bp di si bh bl dh dl ah al ch cl */ \
+}
+
+#define REGNO_REG_CLASS(regno) ia16_regno_class[regno]
+
+/* We use INDEX_REGS for BASE_REG_REGS and BASE_W_INDEX_REGS for INDEX_REGS
+ * because this enables GCC to have use two base registers for base+index
+ * addressing when not eliminating the frame pointer.  This improves i80286
+ * __gcc_bcmp() a lot (or it used to).
+ */
+#define MODE_BASE_REG_CLASS(mode)	BASE_REGS
+#define MODE_BASE_REG_REG_CLASS(mode)	INDEX_REGS
+#define INDEX_REG_CLASS			BASE_W_INDEX_REGS
+
+/* We hack gcc/lra-constraints.c to recognize and use a new macro
+ * MODE_SEGMENT_REG_CLASS (outer_mode, inner_mode, unspec_op), which should
+ * be a set of registers to use for an RTL expression <expr> occurring in a
+ * SEGMENT term,
+ *	(unspec:<mode> [<expr> ...] <unspec_op>)
+ * if this SEGMENT term is part of an address.  For IA-16, the form is
+ *	(unspec:SEG [<expr>] UNSPEC_SEG_OVERRIDE)
+ * and we want to get <expr> loaded into a segment register (%ds or %es).
+ */
+#define MODE_SEGMENT_REG_CLASS(outer_mode, inner_mode, unspec_op) \
+	((unspec_op) == UNSPEC_SEG_OVERRIDE ? SEGMENT_REGS : NO_REGS)
+
+/* FIXME: Documentation:
+ * It is unclear if these definitions should be guarded by REG_OK_STRICT or not.  */
+#define REGNO_MODE_OK_FOR_BASE_P(num, mode) \
+	ia16_regno_in_class_p ((num), MODE_BASE_REG_CLASS (mode))
+#define REGNO_MODE_OK_FOR_REG_BASE_P(num, mode)	\
+	ia16_regno_in_class_p ((num), MODE_BASE_REG_REG_CLASS (mode))
+#define REGNO_OK_FOR_INDEX_P(num) \
+	ia16_regno_in_class_p ((num), INDEX_REG_CLASS)
+
+/* The value returned by CLASS_MAX_NREGS() ends up being used by reload1.c
+ * as one of the things considered when sorting reloads.  Reload is very
+ * sensitive to this on an arch like IA16.  Reloads potentially requiring
+ * many registers are handled first.  So for mixed 8-bit and 16-bit classes,
+ * pretend 8-bit registers.  The address register classes should always be
+ * considered as requiring four hard regs, although they may in fact require
+ * only one, to be sure that they are handled before SImode GENERAL_REGS.
+ * DImode GENERAL_REGS is dealt with by HARD_REGNO_MODE_OK().  However, if the
+ * class has fewer than four hard regs, regclass.c will decide that the
+ * register class is unavailable, in turn ruining local-alloc.c.  So limit this
+ * hack to the duration of the reload pass (reload_in_progress).
+ * What do you mean "jumping through hoops"?  :-(
+ * 
+ * Please see reload1.c/reload_reg_class_lower() before changing this.
+ * Also see regclass.c/init_reg_sets_1().  This is tricky.
+ * Also see regclass.c/record_reg_classes().  This is tricky.
+ * Also see reload.c/combine_reloads().  Not so tricky.
+ * TODO: A target hook for reload_reg_class_lower().
+ * FIXME: CLASS_MAX_NREGS (GENERAL_REGS, XFmode) returns 12.  10 is correct.
+ */
+#define CLASS_MAX_NREGS(class, mode) \
+	((class) == BASE_W_INDEX_REGS && reload_in_progress ? 4 :	\
+	 (class) == INDEX_REGS && reload_in_progress ? 4 :		\
+	 (class) == BASE_REGS && reload_in_progress ? 4 :		\
+	 (class) == BX_REGS && reload_in_progress ? 4 :			\
+	 (class) == CX_REGS && reload_in_progress ? 4 :			\
+	 (reg_classes_intersect_p (QI_REGS, (class)) ?			\
+ 	 GET_MODE_SIZE (mode) :						\
+	 (GET_MODE_SIZE (mode) + 1U) / 2U) + 0U)
+
+/* HI_REGS cannot change mode to QImode.  We cannot change mode to a
+ * larger mode without increasing the number of hard regs used.
+ * TODO: This will change when x87 FPUs are supported.  */
+#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS)	\
+	(GET_MODE_SIZE(TO) > GET_MODE_SIZE(FROM)	\
+	 || ((TO) == QImode && reg_classes_intersect_p (HI_REGS, (CLASS))))
+
+/* Stack Layout and Calling Conventions
+ * Basic Stack Layout
+ */
+
+#define STACK_GROWS_DOWNWARD 1
+#define FRAME_GROWS_DOWNWARD 1
+#undef  ARGS_GROW_DOWNWARD
+#define STARTING_FRAME_OFFSET 0
+#define FIRST_PARM_OFFSET(fundecl) ia16_first_parm_offset (fundecl)
+
+/* Because we have no way of knowing how many registers are saved between the
+   return address and the frame pointer, we can't find the return address for
+   count > 0.
+   TODO: Make this work by pushing the frame pointer before the saved regs
+   when not using ENTER.
+
+   For count == 0, set a flag so that ia16_save_reg_p (.) will ultimately
+   arrange to allocate a frame pointer, even if the function does not
+   otherwise need one.  */
+#define RETURN_ADDR_RTX(COUNT, FRAME)				       	      \
+	((COUNT) == 0							      \
+	 ? crtl->accesses_prior_frames = true,				      \
+	   gen_rtx_MEM (Pmode, arg_pointer_rtx)				      \
+	 : NULL_RTX)
+
+/* Exception Handling Support */
+/* XXX needs work.  */
+
+/* Specifying How Stack Checking is Done */
+/* XXX needs work.  */
+
+/* Registers That Address the Stack Frame */
+#define STACK_POINTER_REGNUM SP_REG
+#define FRAME_POINTER_REGNUM BP_REG
+#define   ARG_POINTER_REGNUM ARGP_REG
+/* XXX The rest needs work.  */
+
+/* We pick dx to choose the least likely used register.  This needs to be a
+   call-used register, because the trampoline will clobber it.  */
+#define  STATIC_CHAIN_REGNUM D_REG
+
+/* Eliminating Frame Pointer and Arg Pointer */
+
+/* INITIAL_FRAME_POINTER_OFFSET(depth_var) */
+/* FIXME Documentation bug: depth-var is invalid as a macro parameter.  */
+/* FIXME Documentation: The offset is in units and is positive if
+   STACK_GROWS_UPWARD.  */
+
+#define ELIMINABLE_REGS \
+	{ { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM }, \
+	  { STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM } }
+#define INITIAL_ELIMINATION_OFFSET(from_reg, to_reg, offset_var) \
+	offset_var = ia16_initial_elimination_offset (from_reg, to_reg)
+
+/* Passing Function Arguments on the Stack */
+#define PUSH_ARGS		1
+#define PUSH_ARGS_REVERSED	1
+#define PUSH_ROUNDING(BYTES)	(((BYTES) + 1) & ~1)
+
+/* Passing Arguments in Registers */
+#define CUMULATIVE_ARGS		int
+#define OVERRIDE_ABI_FORMAT(fndecl) ia16_override_abi_format (fndecl)
+#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \
+	ia16_init_cumulative_args (&(CUM), (FNTYPE), (LIBNAME), (FNDECL), \
+				   (N_NAMED_ARGS))
+/* If %ds is an allocatable register, pretend that it "might" be used to
+   pass arguments to functions, so that when GCC sees a %ds <- %ss just
+   before a subroutine call, it does not try to separate the two.
+   FIXME: must %ah, %dh, and %ch be listed here?  -- tkchia 20200109  */
+#define FUNCTION_ARG_REGNO_P(regno) \
+	((regno) == A_REG \
+	 || (regno) == AH_REG \
+	 || (regno) == D_REG \
+	 || (regno) == DH_REG \
+	 || (regno) == C_REG \
+	 || (regno) == CH_REG \
+	 || (TARGET_ALLOCABLE_DS_REG && (regno) == DS_REG))
+
+/* How Large Values Are Returned */
+#define DEFAULT_PCC_STRUCT_RETURN 0
+
+/* Caller-Saves Register Allocation */
+/* defaults.  */
+
+/* Function Entry and Exit */
+/* Thunks support is missing.  */
+/* Stack adjustment at function exit isn't needed if we need to tear down the
+   stack frame with `leave' or `movw %bp, %sp'.  */
+#define EXIT_IGNORE_STACK	(HAVE__leave \
+				 || get_frame_size () > 0 \
+				 || cfun->calls_alloca \
+				 || crtl->outgoing_args_size > 0)
+
+/* Generating Code for Profiling */
+/* It isn't there yet.  */
+#define FUNCTION_PROFILER(file, labelno) do {} while (0)
+
+/* Permitting tail calls */
+/* skipped for now.  */
+
+/* Stack smashing protection */
+/* skipped for now.  */
+
+/* Implementing the Varargs Macros */
+/* defaults.  */
+
+/* Trampolines for Nested Functions */
+#define TRAMPOLINE_SIZE 6
+
+/* Implicit Calls to Library Routines */
+/* defaults.  */
+
+/* Addressing Modes */
+#define CONSTANT_ADDRESS_P(x)	CONSTANT_P (x)
+#define MAX_REGS_PER_ADDRESS	3
+
+/* Condition Code Status */
+
+/* Representation of condition codes using registers */
+
+#define SELECT_CC_MODE(op, x, y)        ia16_select_cc_mode (op, x, y, false)
+#define REVERSIBLE_CC_MODE(mode)	1
+
+#define BRANCH_COST(speed_p, predictable_p) \
+	ia16_branch_cost (!! (speed_p), !! (predictable_p))
+#define SLOW_BYTE_ACCESS	(TARGET_TUNE_8BIT ? 0 : 1)
+
+/* These probably need some tweaking.  Leave the defaults for now.
+#define MOVE_RATIO
+#define CLEAR_RATIO
+*/
+
+/* Loading a function address into a register takes 3 bytes and 4 cycles
+ * (i80186) and saves at most 1 byte and 2 cycles (i80186) per call.  So don't
+ * waste a precious register on this. TODO: Why does this have no effect?
+ */
+#define NO_FUNCTION_CSE 1
+
+/* Adjusting the Instruction Scheduler.
+   #define TARGET_SCHED_ISSUE_RATE() MAX_DFA_ISSUE_RATE
+*/
+/* Dividing the Output into Sections (Texts, Data, ...).  */
+#define TEXT_SECTION_ASM_OP	"\t.text"
+#define DATA_SECTION_ASM_OP	"\t.data"
+#define BSS_SECTION_ASM_OP	"\t.bss"
+#define CRT_CALL_STATIC_FUNCTION(section_op, function) \
+	__IA16___CRT_CALL_STATIC_FUNCTION (section_op, function) /* ia16-c.c */
+#define JUMP_TABLES_IN_TEXT_SECTION 0
+
+/* Position Independent Code.  */
+/* skipped.  */
+
+/* The Overall Framework of an Assembler File */
+#define ASM_APP_ON				"#APP\n"
+#define ASM_APP_OFF				"#NO_APP\n"
+
+/* Output of Data.  */
+
+/* Output of Uninitialized Variables.  */
+
+#define ASM_OUTPUT_ALIGNED_BSS(stream, decl, name, size, alignment) \
+	asm_output_aligned_bss(stream, decl, name, size, alignment)
+
+/* Output and Generation of Labels.  */
+
+/* Used by target hook TARGET_ASM_GLOBALIZE_LABEL. */
+#define GLOBAL_ASM_OP   "\t.global\t"
+
+#undef ASM_GENERATE_INTERNAL_LABEL
+#define ASM_GENERATE_INTERNAL_LABEL(BUF,PREFIX,NUMBER)  \
+  sprintf ((BUF), LOCAL_LABEL_PREFIX "%s%ld", (PREFIX), (long)(NUMBER))
+
+/* Used by target hook TARGET_ASM_GLOBALIZE_LABEL. */
+#define GLOBAL_ASM_OP   "\t.global\t"
+
+/* This is obsoleted by TARGET_ASM_EXTERNAL_LIBCALL and wrong in elfos.h.  */
+#undef ASM_OUTPUT_EXTERNAL_LIBCALL
+
+/* How Initialization Functions Are Handled.  */
+/* skipped for now.*/
+
+/* Output of Assembler Instructions.  */
+
+#define REGISTER_NAMES { "c", "ch", "a", "ah", "d", "dh", "b", "bh", \
+                         "si", "di", "bp", "es", "ds", "sp", "cc", \
+                         "ss", "cs", "argp" }
+#define ADDITIONAL_REGISTER_NAMES \
+	{ { "cl", 0 }, {"al", 2 }, { "dl", 4 }, { "bl", 6 } }
+#define OVERLAPPING_REGISTER_NAMES \
+	{ { "cx", 0, 2 }, {"ax", 2, 2 }, { "dx", 4, 2 }, { "bx", 6, 2 } }
+#define REGISTER_PREFIX "%"
+#define LOCAL_LABEL_PREFIX "."
+#define IMMEDIATE_PREFIX "$"
+
+/* This is complicated slightly because there is no 8-bit push/pop.  */
+#define ASM_OUTPUT_REG_PUSH(stream, regno) \
+  do { \
+    fputs ("\tpush\t" REGISTER_PREFIX, stream); \
+    if (regno < SI_REG) \
+      {  \
+	putc (reg_names[(regno) & 6][0], stream); \
+	putc ('x', stream); \
+      } \
+    else \
+      fputs (reg_names[regno], stream); \
+    putc ('\n', stream); \
+  } while (0);
+
+#define ASM_OUTPUT_REG_POP(stream, regno) \
+  do { \
+    fputs ("\tpop\t" REGISTER_PREFIX, stream); \
+    if (regno < SI_REG) \
+      { \
+	putc (reg_names[(regno) & 6][0], stream); \
+	putc ('x', stream); \
+      } \
+    else \
+      fputs (reg_names[regno], stream); \
+    putc ('\n', stream); \
+  } while (0);
+
+/* Output of Dispatch Tables.  */
+#define ASM_OUTPUT_ADDR_DIFF_ELT(stream, body, value, rel) \
+	ia16_asm_output_addr_diff_elt ((stream), (body), (value), (rel))
+#define ASM_OUTPUT_ADDR_VEC_ELT(stream, value) \
+	ia16_asm_output_addr_vec_elt ((stream), (value))
+
+/* Assembler Commands for Alignment.  */
+#undef ASM_OUTPUT_SKIP
+#define ASM_OUTPUT_SKIP(stream, nbytes) asm_fprintf (stream, "\t.skip\t%wu,0\n", nbytes)
+#define ASM_OUTPUT_ALIGN(stream, power) fprintf (stream, "\t.p2align\t%u\n", power)
+#define ASM_OUTPUT_ALIGN_WITH_NOP(stream, power) \
+	fprintf (stream, "\t.p2align\t%u\n", power)
+#define ASM_OUTPUT_MAX_SKIP_ALIGN(stream, power, max_skip) \
+	fprintf (stream, "\t.p2align\t%u,,%u\n", power, max_skip)
+
+/* Controlling Debugging Information Format  */
+/* Macros Affecting All Debugging Formats  */
+#undef PREFERRED_DEBUGGING_TYPE
+/* Macros for SDB and DWARF Output  */
+#undef DWARF2_DEBUGGING_INFO
+
+#define REGISTER_TARGET_PRAGMAS() ia16_register_pragmas ()
+
+/* Cross Compilation and Floating Point
+ * Skipped for now.
+
+ * Mode Switching Instructions
+
+ * Defining target-specific uses of __attribute__
+ * This is done in ia16.c .
+
+ * Defining coprocessor specifics for MIPS targets.
+
+ * Parameters for Precompiled Header Validity Checking
+
+ * C++ ABI parameters
+ *
+ * Miscellaneous Parameters
+ *
+ * GAS provides the necessary workarounds for long conditional jumps to work.
+ */
+#define HAS_LONG_COND_BRANCH		true
+#define HAS_LONG_UNCOND_BRANCH		true
+#define CASE_VECTOR_MODE		Pmode
+#define CASE_VECTOR_PC_RELATIVE		0
+/* FIXME Not documented: caller-save.c fails if MOVE_MAX < UNITS_PER_WORD.  */
+/* #define MOVE_MAX 		(UNITS_PER_WORD / (TARGET_TUNE_8BIT ? 2 : 1)) */
+#define	MOVE_MAX			UNITS_PER_WORD
+#define MAX_MOVE_MAX			UNITS_PER_WORD
+#define TRULY_NOOP_TRUNCATION(outprec, inprec) 1
+#define STORE_FLAG_VALUE		(-1)
+#define Pmode				HImode
+#define FUNCTION_MODE			QImode
+
+/* Index codes for machine-specific built-in functions.  */
+enum ia16_builtin
+{
+  IA16_BUILTIN_SELECTOR,
+  IA16_BUILTIN_FP_OFF,
+  IA16_BUILTIN_NEAR_DATA_SEGMENT,
+  IA16_BUILTIN_SS,
+  IA16_BUILTIN_MAX
+};
+
+#define ADDR_SPACE_FAR			1
+#define ADDR_SPACE_SEG_SS		2
+/* We hack gcc/tree-ssa-loop-ivopts.c and gcc/calls.c to recognize a new
+   macro TARGET_ADDR_SPACE_WEIRD_P (as), which should return true if the
+   given address space breaks certain assumptions made by compiler passes.  */
+#define TARGET_ADDR_SPACE_WEIRD_P(as)	((as) == ADDR_SPACE_FAR)
+/* We hack gcc/c/c-parser.c to recognize TARGET_WARN_ADDR_SPACE_SYNTAX_P
+   (as), which should return true if an address space name is traditionally
+   considered as part of a `declarator' rather than `declaration-specifiers'
+   grammar-wise.  */
+#define TARGET_WARN_ADDR_SPACE_SYNTAX_P(as) ((as) == ADDR_SPACE_FAR)
+/* We also hack gcc/expr.c to recognize TARGET_ADDR_SPACE_WEIRD_P (as) ---
+   as well as another macro TARGET_EXPAND_WEIRD_POINTER_PLUS_EXPR (treeop0,
+   treeop1, target, mode, modifier).  The latter macro should say how to
+   convert a POINTER_PLUS_EXPR node into RTL, when the pointer operand
+   (treeop0) belongs to a "weird" address space.  */
+#define TARGET_EXPAND_WEIRD_POINTER_PLUS_EXPR \
+	ia16_expand_weird_pointer_plus_expr
+/* And, we hack gcc/explow.c to recognize a new macro to actually do address
+   RTX -> pointer RTX and pointer RTX -> address RTX conversions for operands
+   pointing into "weird" address spaces.  */
+#define TARGET_ADDR_SPACE_CONVERT_WEIRD_MEMORY_ADDRESS \
+	ia16_as_convert_weird_memory_address
+/* To support far functions and far function pointers, we hack the C parser
+   in gcc/c/c-parser.c to recognize a new macro which says we allow having
+   functions in a given non-default address space.  gcc/c/c-decl.c and
+   gcc/c/c-tree.h are also updated to account for the changes in the C
+   parser's internal structures.  */
+#define TARGET_ADDR_SPACE_MAY_HAVE_FUNCTIONS_P(as) ((as) == ADDR_SPACE_FAR)
+/* Also, gcc/c/c-decl.c is updated to recognize a new macro which says
+   whether a function may get its address space from its return type.  */
+#define TARGET_FUNCTION_ADDR_SPACE_FROM_RETURN_TYPE_P(as) \
+	TARGET_FAR_FUNCTION_IF_FAR_RETURN_TYPE
+
+/* Which processor to tune code generation for.  These must be in sync
+   with processor_target_table in ia16.c.  */
+
+enum processor_type
+{
+  PROCESSOR_ANY,
+  PROCESSOR_ANY_186,
+  PROCESSOR_I8086,
+  PROCESSOR_I8088,
+  PROCESSOR_NEC_V30,
+  PROCESSOR_NEC_V20,
+  PROCESSOR_I80186,
+  PROCESSOR_I80188,
+  PROCESSOR_I80286,
+  PROCESSOR_max
+};
+
+extern int ia16_features;
+
+/* Which memory model to use.  Some memory models may not actually be
+   implemented and available through the front-end.  */
+
+enum cmodel_type
+{
+  CMODEL_TINY,
+  CMODEL_SMALL,
+  CMODEL_MEDIUM,
+  CMODEL_COMPACT,
+  CMODEL_LARGE,
+  CMODEL_HUGE,
+  CMODEL_max
+};
+
+/* General calling convention for this compilation unit --- specifically, how
+   function parameters are passed and cleaned up, and how values are
+   returned, for functions which do not have attributes.  Some of these may
+   not actually be implemented and available through the front-end.  */
+
+enum call_parm_cvt_type
+{
+  CALL_PARM_CVT_CDECL,
+  CALL_PARM_CVT_STDCALL,
+  CALL_PARM_CVT_REGPARMCALL,
+  CALL_PARM_CVT_max
+};
+
+/* The linker will take care of this.  */
+#define CTOR_LISTS_DEFINED_EXTERNALLY 1
+
+/* No need to support Java.  */
+#define TARGET_USE_JCR_SECTION 0
+
+/* Avoid having register_tm_clones and unregister_tm_clones in crtstuff.  */
+#define USE_TM_CLONE_REGISTRY 0
diff --git a/gcc/config/ia16/ia16.md b/gcc/config/ia16/ia16.md
new file mode 100644
index 0000000..cef580f
--- /dev/null
+++ b/gcc/config/ia16/ia16.md
@@ -0,0 +1,3418 @@
+;  GNU Compiler Collection machine description for Intel 16-bit x86.
+;  Copyright (C) 2005-2017 Free Software Foundation, Inc.
+;  Contributed by Rask Ingemann Lambertsen <rask@sygehus.dk>
+;  Changes by Andrew Jenner <andrew@codesourcery.com>
+;  Very preliminary IA-16 far pointer support by TK Chia
+;
+;  This file is part of GCC.
+;
+;  GCC 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 3 of the License, or (at your option) any
+;  later version.
+;
+;  GCC 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/licenses/>.
+
+; A few special hard registers. Keep this list in sync with ia16.h.
+(define_constants
+	[(C_REG		 0)
+	 (CH_REG	 1)
+	 (A_REG		 2)
+	 (AH_REG	 3)
+	 (D_REG		 4)
+	 (DH_REG	 5)
+	 (B_REG		 6)
+	 (BH_REG	 7)
+	 (SI_REG	 8)
+	 (FIRST_NOQI_REG 8)
+	 (DI_REG	 9)
+	 (BP_REG	10)
+	 (ES_REG	11)
+	 (DS_REG	12)
+	 (LAST_ALLOCABLE_REG 12)
+	 (SP_REG	13)
+	 (CC_REG	14)
+	 (SS_REG	15)
+	 (CS_REG	16)
+	 (LAST_HARD_REG 16)
+	 (ARGP_REG	17)
+	 (FIRST_PSEUDO_REGISTER 18)
+
+	 (UNSPEC_NOT_CARRY	0)
+	 (UNSPEC_SEG_OVERRIDE	1)
+	 (UNSPEC_OZSEG16	2)
+	 (UNSPEC_STATIC_FAR_PTR	3)
+	])
+
+; Mode Iterators
+; The modes directly supported on ia16 for most instructions.
+(define_mode_iterator MO [HI QI])
+; All modes which are no more than 16 bits wide.
+(define_mode_iterator LE16 [PHI HI QI V2QI])
+; Modes which are exactly 16 bits wide.
+(define_mode_iterator EQ16 [PHI HI V2QI])
+; Modes which are at least 16 bits wide. Also complex ones.
+(define_mode_iterator GE16 [HI SI DI TI SF DF SD DD TD V2QI
+			    SC DC CHI CSI CDI CTI])
+; Modes which are more that 16 bits wide.
+(define_mode_iterator GT16 [SI DI TI SF DF SD DD TD SC DC CHI CSI CDI CTI])
+; Integer modes which are more that 16 bits wide.
+(define_mode_iterator GT16I [SI DI TI])
+; Possible function pointer sizes.
+(define_mode_iterator FNP [HI SI])
+
+; Complex modes excpet CQI, which needs special treatment.
+(define_mode_iterator COMPLEX [SC DC CHI CSI CDI CTI])
+; Inner mode of a complex value (concat ...).
+(define_mode_attr INNER [(SC "SF") (DC "DF")
+	(CQI "QI") (CHI "HI") (CSI "SI") (CDI "DI") (CTI "TI")])
+(define_mode_attr inner [(SC "sf") (DC "df")
+	(CQI "qi") (CHI "hi") (CSI "si") (CDI "di") (CTI "ti")
+	(V2QI "v2qi") (HI "hi") (SI "si") (DI "di") (TI "ti")
+	(SF "sf") (DF "df") (SD "sd") (DD "dd") (TD "td")])
+
+; Instruction suffix.
+(define_mode_attr s [(V2QI "w") (HI "w") (PHI "w") (QI "b")])
+; Instruction suffix for next longer mode (for cbtw/cwtd).
+(define_mode_attr S [(HI "d") (PHI "d") (QI "w")])
+; Constraint for "general_operand".
+(define_mode_attr g [(HI "g") (PHI "g") (QI "qmi") (V2QI "g")])
+; Constraint for "register_operand".
+(define_mode_attr r [(HI "r") (PHI "r") (QI "q") (V2QI "r")])
+; Constraint for function pointers.
+(define_mode_attr p [(HI "g") (SI "im")])
+; The next longer mode.
+(define_mode_attr LONG [(HI "SI") (QI "HI")])
+(define_mode_attr long [(HI "si") (QI "hi")])
+; The input/output registers of idiv/div instructions.
+(define_mode_attr div_in  [(HI "A") (QI "a")])
+(define_mode_attr div_out [(HI "a") (QI "Ral")])
+(define_mode_attr mod_out [(HI "d") (QI "Rah")])
+
+; All CCmodes which have at least the zero (Z) flag, carry (C) flag,
+; and so on for the other flags and combinations thereof. The SET_*
+; iterators are for instructions setting the flags, the USE_* iterators are
+; for instructions using the flags.
+; Notes: Modes with S but not O are not a subset of those with SO.
+(define_mode_iterator USE_Z	[CCZ CCCZ CCSZ CCSOZ CC])
+(define_mode_iterator USE_C	[CCC CCCZ CCSC CC])
+(define_mode_iterator USE_CZ	[CCCZ CCSCZ CC])
+(define_mode_iterator USE_S	[CCS CCSC CCSZ CCSCZ])
+(define_mode_iterator USE_SO	[CCSO CCSOZ CC])
+(define_mode_iterator USE_SOZ	[CCSOZ CC])
+
+(define_mode_iterator SET_CZ	[CCC CCZ CCCZ])
+(define_mode_iterator SET_SOZ	[CCZ CCSO CCSOZ])
+(define_mode_iterator SET_SOCZ	[CCC CCZ CCCZ CCSO CCSOZ CC])
+; These are only permitted for comparisons against zero.
+(define_mode_iterator SET_SC	[CCC CCS CCSC])
+(define_mode_iterator SET_SZ	[CCZ CCS CCSZ])
+(define_mode_iterator SET_SCZ	[CCC CCZ CCS CCCZ CCSC CCSZ CCSCZ])
+(define_mode_iterator SET_CC	[CCC CCZ CCS CCSO CCCZ CCSC CCSZ CCSOZ CCSCZ CC])
+
+; Code Iterators
+; Allow the same template to generate patterns for signed and unsigned mul/div.
+; Idea from mips/mips.md.
+(define_code_iterator any_extend [sign_extend zero_extend])
+; Pattern name prefix.
+(define_code_attr np [(sign_extend "")  (zero_extend "u")])
+; Instruction mnemonic prefix.
+(define_code_attr mp [(sign_extend "i") (zero_extend "")])
+
+; Collapse all of add/sub/and/ior/xor into one pattern.
+(define_code_iterator any_arith3 [plus minus and ior xor])
+(define_code_attr  optab_arith3 [(plus "add") (minus "sub")
+				 (and "and") (ior "ior") (xor "xor")])
+(define_code_attr  constr1_arith3 [(plus "%") (minus "")
+				   (and "%") (ior "%") (xor "%")])
+
+; PLUS and MINUS have special patterns.
+(define_code_iterator any_logic3 [and ior xor])
+(define_code_attr  optab_logic3 [(and "and") (ior "ior") (xor "xor")])
+(define_code_attr  constr1_logic3 [(and "%") (ior "%") (xor "%")])
+(define_code_iterator any_nosub3 [plus and ior xor])
+
+; Collapse add/sub with carry.
+(define_code_iterator any_addsub [plus minus])
+(define_code_attr  optab_addsub [(plus "add") (minus "sub")])
+(define_code_attr  const_addsub [(plus "_const") (minus "")])
+
+; Collapse all of ashl/ashr/lshr/rotl/rotr into one pattern.
+(define_code_iterator any_shift [ashift ashiftrt lshiftrt rotate rotatert])
+(define_code_iterator any_shiftcc [ashift ashiftrt lshiftrt])
+(define_code_iterator any_lshift [ashift lshiftrt])
+(define_code_attr  optab_shift
+	 [(ashift "ashl") (ashiftrt "_ashr") (lshiftrt "lshr")
+	  (rotate "rotl") (rotatert "rotr")])
+(define_code_attr  cond_shift
+	[(ashift "1") (lshiftrt "1") (rotate "1") (rotatert "1")
+	 (ashiftrt "!CONST_INT_P (operands[2]) || INTVAL (operands[2]) < GET_MODE_BITSIZE (GET_MODE (operands[0])) - 1")])
+
+; Collapse the multiword right shift instructions into one pattern.
+(define_code_iterator any_shiftrt_mw [ashiftrt lshiftrt])
+(define_code_attr optab_shiftrt_mw [(ashiftrt "ashr") (lshiftrt "lshr")])
+
+; Collapse the shift by 8 instructions into one pattern.
+(define_code_iterator any_shift8 [ashift lshiftrt])
+(define_code_attr  optab_shift8 [(ashift "ashl") (lshiftrt "lshr")])
+
+; Collapse the whole vector shifts into one pattern.
+(define_code_iterator any_vecshift3 [ashift lshiftrt])
+(define_code_attr  optab_vecshift3 [(ashift "shl") (lshiftrt "shr")])
+
+; Collapse all the b<cond> patterns into one. Likewise for *b<cond>_rev.
+(define_code_iterator any_cond [eq ne gt gtu lt ltu ge geu le leu])
+(define_code_iterator any_cond_z   [eq ne])
+(define_code_iterator any_cond_c   [geu ltu])
+(define_code_iterator any_cond_cz  [gtu leu])
+(define_code_iterator any_cond_so  [ge lt])
+(define_code_iterator any_cond_soz [gt le])
+
+; These are the s<cond> patterns available so far. Must not include lt if
+; operand 0 has HImode because of a bug in expr.c/convert_move().
+(define_code_iterator scc_cond [eq ne gtu ltu geu leu le])
+
+; Collapse patterns with ior and xor into one.
+(define_code_iterator any_or [ior xor])
+
+; Collapse patterns with plus, minus, ior and xor into one. We can get a left
+; shift by 8 or an and with 0xff00 for free with these.
+(define_code_iterator any_cheaphi [plus minus ior xor])
+
+; Define the instruction mnemonics for the instruction codes.
+(define_code_attr  mnemonic
+  [(plus "add") (minus "sub") (and "and") (ior "or") (xor "xor") (ashift "shl")
+   (ashiftrt "sar") (lshiftrt "shr") (rotate "rol") (rotatert "ror")
+   (eq "je")   (ne "jne") (gt "jg")  (gtu "ja")  (lt "jl")
+   (ltu "jb")  (ge "jge") (geu "jae") (le "jle") (leu "jbe")])
+
+; Reversed branch mnemonics.
+(define_code_attr  mnemonic_rev
+  [(eq "jne")  (ne "je")  (gt "jle") (gtu "jbe") (lt "jge")
+   (ltu "jae") (ge "jl")  (geu "jb")  (le "jg")  (leu "ja")])
+
+; Protected mode support (experimental).
+(define_mode_iterator SEG [PHI HI])
+(define_mode_attr pmrm [(PHI "_prot_mode") (HI "")])
+
+(include "predicates.md")
+(include "constraints.md")
+
+; Peepholes and associated instructions.
+(include "ia16-peepholes.md")
+
+; Patterns for instructions which set the condition codes to something
+; useful exist in three versions:
+; 1) name: Describes the instruction, except that it clobbers the CC reg.
+; 2) name_cc: Describes the instruction, including the effect on the CC reg.
+; 3) name_cconly: Describes the effect on the CC reg, clobbers the result.
+; See <URL:http://gcc.gnu.org/ml/gcc/2004-02/msg00903.html> for the reason.
+
+; See "13.9 Standard Pattern Names For Generation"
+
+;; Copying values.
+; Try to avoid mem->mem copies. This may avoid reload problems.
+(define_expand "mov<mode>"
+  [(set (match_operand:LE16 0 "nonimmediate_operand")
+        (match_operand:LE16 1 "general_operand"))]
+  ""
+{
+  gcc_assert (!push_operand (operands[0], <MODE>mode));
+  if (MEM_P (operands[0]) && MEM_P (operands[1]))
+    operands[1] = force_reg (<MODE>mode, operands[1]);
+  if (! ia16_in_ss_data_function_p ())
+    {
+      /* XXX messy hack.  See ia16-no-ss-data.c .  We need a better way.  */
+      rtx src = operands[1];
+      while (SUBREG_P (src)
+	     && (GET_MODE (src) == HImode || GET_MODE (src) == PHImode))
+	src = SUBREG_REG (src);
+      if (REG_P (src) && REGNO (src) == DS_REG && GET_MODE (src) == SEGmode)
+	{
+	  rtx dest = operands[0];
+	  while (SUBREG_P (dest)
+		 && (GET_MODE (dest) == HImode || GET_MODE (dest) == PHImode))
+	    dest = SUBREG_REG (dest);
+	  if (REG_P (dest) && GET_MODE (dest) == SEGmode
+	      && rtx_equal_p (dest, ia16_data_seg_rtx ()))
+	    {
+	      emit_insn (gen_rtx_SET (operands[0], operands[1]));
+	      emit_use (dest);
+	      DONE;
+	    }
+	}
+    }
+})
+
+; This template is used by -mprotected-mode.  It must come before the
+; "*movhi" template so that it has a chance of getting matched.  -- tkchia
+(define_insn "*trunchiphi2_via_paradoxical"
+  [(set (subreg:HI (match_operand:PHI 0 "nonimmediate_operand" "=T,rm,Q,!Q") 0)
+	(match_operand:HI 1 "nonimmediate_operand" "rm,Ti,0,Q"))]
+  ""
+  "@
+   movw\t%1,\t%0
+   movw\t%1,\t%0
+   #
+   pushw\t%1\;popw\t%0")
+
+(define_insn "*mov<mode>"
+  [(set (match_operand:EQ16 0 "nonimmediate_operand" "=T,rm,Q,!Q")
+	(match_operand:EQ16 1 "general_operand" "rm,Ti,0,Q"))]
+  "!MEM_P (operands[0]) || !MEM_P (operands[1])"
+  "@
+   movw\t%1,\t%0
+   movw\t%1,\t%0
+   #
+   pushw\t%1\;popw\t%0")
+
+(define_insn "*movqi"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=q,m")
+	(match_operand:QI 1 "general_operand" "qmi,qi"))]
+  "!MEM_P (operands[0]) || !MEM_P (operands[1])"
+  "movb\t%1,\t%0"
+)
+
+(define_expand "movstrictqi"
+  [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand"))
+	(match_operand:QI 1 "general_operand"))]
+  ""
+  ""
+)
+
+;    "	In file included from vshuf-v8qi.c:23:0:
+;	vshuf-main.inc: In function ‘main’:
+;	vshuf-main.inc:26:1: error: unable to find a register to spill
+;	 }
+;	 ^
+;	vshuf-main.inc:26:1: error: this is the insn:
+;	(insn 49 743 749 3 (set
+;		(strict_low_part (subreg:QI (reg:DI 449 [134]) 0))
+;		(mem/j:QI (plus:HI (plus:HI (reg/f:HI 125)
+;			    (reg:HI 320 [137]))
+;			(const_int 16 [0x10])) [0 vectmp.41 S1 A8]))
+;	vshuf-main.inc:12 11 {movstrictqi}
+;	     (expr_list:REG_DEAD (reg:HI 320 [137])
+;		(nil)))
+;	vshuf-main.inc:26: confused by earlier errors, bailing out  "
+(define_int_iterator DIOFF [0 2 4 6])
+(define_int_attr dioff [(0 "0") (2 "2") (4 "4") (6 "6")])
+(define_split
+  [(set (strict_low_part (subreg:QI (match_operand:DI 0
+				     "nonimmediate_operand") DIOFF))
+	(match_operand:QI 1 "memory_operand"))]
+  "optimize_size && ! reload_completed"
+  [(set (match_dup 2) (match_dup 4))
+   (set (match_dup 3) (match_dup 1))
+   (set (match_dup 4) (match_dup 2))]
+{
+  operands[2] = gen_reg_rtx (HImode);
+  operands[3] = simplify_gen_subreg (QImode, operands[2], HImode, 0);
+  operands[4] = simplify_gen_subreg (HImode, operands[0], DImode, <dioff>);
+})
+
+(define_insn_and_split "*movstrictqi"
+  [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+q,m"))
+	(match_operand:QI 1 "general_operand" "qmi,qi"))]
+  ""
+  "movb\t%1,\t%0"
+  "reload_completed && !register_operand (operands[0], QImode)"
+  [(set (match_dup 0) (match_dup 1))]
+)
+
+; The regular xor pattern has inputs and therefore causes
+; REG_DEAD notes to be removed if used as output pattern of a peephole2
+; definition.  It may also result in weird looking (but correct) instructions
+; such as "xorw %sp, %di" after the rnreg pass.  This happens following a
+; previous "movw %sp, %di" instruction.  Use this insn instead.
+(define_insn "*mov<mode>_const0"
+	[(set (match_operand:MO 0 "register_operand" "=<r>")
+	      (const_int 0))
+	 (clobber (reg:CC CC_REG))]
+	""
+	"xor<s>\t%0,\t%0"
+)
+
+; We cannot use pre_dec:HI here because then note_stores() doesn't see that the
+; stack pointer changes, which in turn breaks reload inheritance correctness.
+(define_expand "push<mode>1"
+  [(parallel
+  [(set (match_dup 1) (match_operand:EQ16 0 "general_operand"))
+   (set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG) (const_int -2)))]
+  )]
+  ""
+{
+  /* We may be passed a constant complex value.  */
+  if (!TARGET_PUSH_IMM
+      && (CONSTANT_P (operands[0])
+	  || (GET_CODE (operands[0]) == CONCAT
+	      && (CONSTANT_P (XEXP (operands[0], 0))
+		  || CONSTANT_P (XEXP (operands[0], 1))))))
+    operands[0] = force_reg (<MODE>mode, operands[0]);
+  operands[1] = gen_tmp_stack_mem (<MODE>mode,
+				   plus_constant (Pmode, stack_pointer_rtx,
+				   		  -2));
+})
+
+; This is for the prologue only.
+(define_expand "_pushhi1_prologue"
+  [(parallel
+  [(set (match_dup 1) (match_operand:HI 0 "general_operand"))
+   (set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG) (const_int -2)))]
+  )]
+  ""
+{
+  operands[1] = gen_frame_mem (HImode,
+			       plus_constant (Pmode, stack_pointer_rtx, -2));
+})
+
+; The template is a dummy.
+(define_expand "push<mode>1"
+  [(set (mem:GT16 (pre_dec:HI (reg:HI SP_REG)))
+	(match_operand:GT16 0 "general_or_concat_operand" ""))]
+  ""
+{
+  unsigned int i = GET_MODE_SIZE (<MODE>mode);
+  rtx tmp;
+  do {
+    i -= 2;
+    tmp = simplify_gen_subreg (HImode, operands[0], <MODE>mode, i);
+    emit_insn (gen_pushhi1 (tmp));
+  } while (i > 0);
+  DONE;
+})
+
+(define_insn "_push<mode>1_nonimm"
+  [(set (mem:EQ16 (plus:HI (reg:HI SP_REG) (const_int -2)))
+	(match_operand:EQ16 0 "nonimmediate_operand" "Tm"))
+   (set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG) (const_int -2)))]
+  "!TARGET_PUSH_IMM"
+  "pushw\t%0"
+)
+
+(define_insn "*push<mode>1"
+  [(set (mem:EQ16 (plus:HI (reg:HI SP_REG) (const_int -2)))
+	(match_operand:EQ16 0 "general_operand" "Tmi"))
+   (set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG) (const_int -2)))]
+  "TARGET_PUSH_IMM"
+  "pushw\t%0"
+)
+
+; We can only push the lower QImode registers or memory, and they won't
+; be sign extended in doing so. This is unlike constants with *pushihi1.
+(define_expand "pushqi1"
+  [(parallel
+  [(set (match_dup 1) (match_operand:QI 0 "general_operand"))
+   (set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG) (const_int -2)))]
+  )]
+  ""
+{
+  if (!TARGET_PUSH_IMM && CONSTANT_P (operands[0]))
+    operands[0] = force_reg (QImode, operands[0]);
+  operands[1] = gen_tmp_stack_mem (QImode,
+				   plus_constant (Pmode, stack_pointer_rtx,
+				   		  -2));
+})
+
+(define_insn "*pushqi1_subreg"
+  [(set (mem:QI (plus:HI (reg:HI SP_REG) (const_int -2)))
+	(subreg:QI (match_operand 0 "general_operand" "TmIpu") 0))
+
+   (set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG) (const_int -2)))]
+  "TARGET_PUSH_IMM || !CONSTANT_P (operands[0])"
+  "pushw\t%0"
+)
+
+(define_insn "*pushqi1"
+  [(set (mem:QI (plus:HI (reg:HI SP_REG) (const_int -2)))
+   (match_operand:QI 0 "general_operand" "lmIpu"))
+   (set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG) (const_int -2)))]
+  "TARGET_PUSH_IMM || !CONSTANT_P (operands[0])"
+  "pushw\t%X0"
+)
+
+(define_insn "_pop<mode>1"
+  [(set (match_operand:SEG 0 "nonimmediate_operand" "=Tm")
+	(mem:SEG (post_inc:HI (reg:HI SP_REG))))]
+  ""
+  "popw\t%0"
+)
+
+; This is a hack to tell the register allocator to use AX_REGS instead of
+; AL_REGS when operand 0 is a subreg of a HImode register rather than a
+; register of QImode.
+(define_insn "*xlatqi2_subreg"
+  [(set (subreg:QI (match_operand:HI 0 "register_operand" "=a") 0)
+	(mem:QI (plus:HI (zero_extend:HI
+			   (match_operand:QI 1 "single_register_operand" "0"))
+			 (match_operand:HI 2 "single_nonmemory_operand" "b"))))]
+  ""
+  "xlat\t%a2"
+)
+
+(define_insn "*xlatqi2_strict_low_part"
+  [(set (strict_low_part
+	  (subreg:QI (match_operand:HI 0 "register_operand" "+a") 0))
+	(mem:QI (plus:HI (zero_extend:HI (subreg:QI (match_dup 0) 0))
+			 (match_operand:HI 1 "single_nonmemory_operand" "b"))))]
+  ""
+  "xlat\t%a1"
+)
+
+(define_insn "*xlatqi2"
+  [(set (match_operand:QI 0 "single_register_operand" "=Ral")
+	(mem:QI (plus:HI (zero_extend:HI
+			   (match_operand:QI 1 "single_register_operand" "0"))
+			 (match_operand:HI 2 "single_nonmemory_operand" "b"))))]
+  ""
+  "xlat\t%a2"
+)
+
+(define_insn_and_split "*xlatqi2_non_strict"
+  [(set (match_operand:QI 0 "register_operand" "=Ral")
+	(match_operand:QI 1 "xlat_memory_operand" "X"))]
+  "!reload_completed"
+  "#"
+  "!reload_completed"
+  [(set (match_dup 0) (match_dup 2))
+   (set (match_dup 0) (match_dup 3))]
+{
+  rtx zext = XEXP (XEXP (operands[1], 0), 0);
+  rtx zext_op, bit_offset, new_addr;
+
+  if (GET_CODE (zext) == SUBREG)
+    zext = SUBREG_REG (zext);
+
+  switch (GET_CODE (zext))
+    {
+      case ZERO_EXTEND:
+      zext_op = XEXP (zext, 0);
+      bit_offset = const0_rtx;
+      break;
+
+      case ZERO_EXTRACT:
+      zext_op = XEXP (zext, 0);
+      bit_offset = XEXP (zext, 2);
+      break;
+
+      case AND:
+      if (GET_CODE (XEXP (zext, 0)) == SUBREG)
+	{
+	  zext_op = XEXP (XEXP (XEXP (zext, 0), 0), 0);
+	  bit_offset = XEXP (XEXP (XEXP (zext, 0), 0), 1);
+	}
+      else
+	{
+	  zext_op = XEXP (XEXP (zext, 0), 0);
+	  bit_offset = XEXP (XEXP (zext, 0), 1);
+	}
+      break;
+
+      default:
+      gcc_unreachable ();
+    }
+  /* For the benefit of the lower-subreg pass, create a HImode subreg if the
+   * zero_extract operand is larger than HImode.  */
+  if (GET_MODE_SIZE (GET_MODE (zext_op)) > UNITS_PER_WORD)
+    {
+      unsigned int unit_offset;
+
+      unit_offset = (INTVAL (bit_offset) / BITS_PER_WORD) * UNITS_PER_WORD;
+      zext_op = simplify_gen_subreg (HImode, zext_op, GET_MODE (zext_op),
+				     unit_offset);
+      bit_offset = GEN_INT (INTVAL (bit_offset) - unit_offset * BITS_PER_UNIT);
+    }
+
+  /* Use a SUBREG instead of a ZERO_EXTRACT with offset 0.  */
+  if (INTVAL (bit_offset) == 0)
+    operands[2] = simplify_gen_subreg (QImode, zext_op, GET_MODE (zext_op), 0);
+  else
+    operands[2] = gen_rtx_ZERO_EXTRACT (QImode, zext_op, GEN_INT (8), bit_offset);
+
+  /* Create the xlat memory operand.  */
+  new_addr = gen_rtx_PLUS (Pmode, gen_rtx_ZERO_EXTEND (Pmode, operands[0]),
+			   XEXP (XEXP (operands[1], 0), 1));
+  operands[3] = replace_equiv_address_nv (operands[1], new_addr);
+})
+
+; Combine sometimes doesn't try to split off an outer ZERO_EXTEND, perhaps
+; because the combined insn was made up of only two insns.  IMHO, this sucks.
+(define_insn_and_split "*xlatqi2_non_strict_zero_extendqihi"
+  [(set (match_operand:HI 0 "register_operand" "=Ral")
+	(zero_extend:HI (match_operand:QI 1 "xlat_memory_operand" "X")))
+   (clobber (reg:CC CC_REG))]
+  "!reload_completed"
+  "#"
+  "!reload_completed"
+  [(set (match_dup 3) (match_dup 2))
+   (set (match_dup 3) (match_dup 4))
+  (parallel
+  [(set (match_dup 0) (and:HI (match_dup 0) (const_int 255)))
+   (clobber (reg:CC CC_REG))])]
+{
+  rtx zext = XEXP (XEXP (operands[1], 0), 0);
+  rtx zext_op, bit_offset, new_addr, scratch;
+
+  if (GET_CODE (zext) == SUBREG)
+    zext = SUBREG_REG (zext);
+
+  switch (GET_CODE (zext))
+    {
+      case ZERO_EXTEND:
+      zext_op = XEXP (zext, 0);
+      bit_offset = const0_rtx;
+      break;
+
+      case ZERO_EXTRACT:
+      zext_op = XEXP (zext, 0);
+      bit_offset = XEXP (zext, 2);
+      break;
+
+      case AND:
+      if (GET_CODE (XEXP (zext, 0)) == SUBREG)
+	{
+	  zext_op = XEXP (XEXP (XEXP (zext, 0), 0), 0);
+	  bit_offset = XEXP (XEXP (XEXP (zext, 0), 0), 1);
+	}
+      else
+	{
+	  zext_op = XEXP (XEXP (zext, 0), 0);
+	  bit_offset = XEXP (XEXP (zext, 0), 1);
+	}
+      break;
+
+      default:
+      gcc_unreachable ();
+    }
+  /* For the benefit of the lower-subreg pass, create a HImode subreg if the
+   * zero_extract operand is larger than HImode.  */
+  if (GET_MODE_SIZE (GET_MODE (zext_op)) > UNITS_PER_WORD)
+    {
+      unsigned int unit_offset;
+
+      unit_offset = (INTVAL (bit_offset) / BITS_PER_WORD) * UNITS_PER_WORD;
+      zext_op = simplify_gen_subreg (HImode, zext_op, GET_MODE (zext_op),
+				     unit_offset);
+      bit_offset = GEN_INT (INTVAL (bit_offset) - unit_offset * BITS_PER_UNIT);
+    }
+
+  /* Use a SUBREG instead of a ZERO_EXTRACT with offset 0.  */
+  if (INTVAL (bit_offset) == 0)
+    operands[2] = simplify_gen_subreg (QImode, zext_op, GET_MODE (zext_op), 0);
+  else
+    operands[2] = gen_rtx_ZERO_EXTRACT (QImode, zext_op, GEN_INT (8), bit_offset);
+
+  /* Create the xlat memory operand.  */
+  scratch = simplify_gen_subreg (QImode, operands[0], HImode, 0);
+  new_addr = gen_rtx_PLUS (Pmode, gen_rtx_ZERO_EXTEND (Pmode, scratch),
+			   XEXP (XEXP (operands[1], 0), 1));
+  operands[4] = replace_equiv_address_nv (operands[1], new_addr);
+
+  /* Create the destination, which must be a QImode SUBREG.  */
+  if (true || GET_CODE (scratch) == SUBREG)
+    operands[3] = scratch;
+  else
+    operands[3] = gen_rtx_SUBREG (QImode, scratch, 0);
+})
+
+(define_insn_and_split "*extzv_byte"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=q,m")
+	(zero_extract:QI (match_operand 1 "nonimmediate_operand" "qm,q")
+			 (const_int 8)
+			 (match_operand 2 "const_int_operand" "n,n")))]
+  "INTVAL (operands[2]) % BITS_PER_UNIT == 0
+   && (!MEM_P (operands[0]) || !MEM_P (operands[1]))"
+  "#"
+  "reload_completed"
+  [(set (match_dup 0) (match_dup 3))]
+{
+  operands[3] = simplify_gen_subreg (QImode, operands[1],
+				     GET_MODE (operands[1]),
+				     INTVAL (operands[2]) / BITS_PER_UNIT);
+})
+
+(define_insn_and_split "*extzv_byte_strict_low_part"
+  [(set (strict_low_part (match_operand:QI 0 "register_operand" "+q"))
+	(zero_extract:QI (match_operand 1 "nonimmediate_operand" "qm")
+			 (const_int 8)
+			 (match_operand 2 "const_int_operand" "n")))]
+  "INTVAL (operands[2]) % BITS_PER_UNIT == 0
+   && (!MEM_P (operands[0]) || !MEM_P (operands[1]))"
+  "#"
+  "reload_completed"
+  [(set (match_dup 3) (match_dup 4))]
+{
+  operands[3] = simplify_gen_subreg (QImode, operands[0], QImode, 0);
+  operands[4] = simplify_gen_subreg (QImode, operands[1],
+				     GET_MODE (operands[1]),
+				     INTVAL (operands[2]) / BITS_PER_UNIT);
+})
+
+(define_insn "_xchg<mode>2"
+  [(set (match_operand:LE16 0 "register_operand" "+<r>")
+	(match_operand:LE16 1 "nonimmediate_operand" "+<r>m"))
+   (set (match_dup 1) (match_dup 0))]
+  "!MEM_P (operands[0]) || !MEM_P (operands[1])"
+  "xchg<s>\t%1,\t%0"
+)
+
+;; Arithmetic and logic operations
+; Two operand QI/HImode add/sub/and/ior/xor.
+; Don't generate mem<-mem,mem or mem<-reg,reg insns.
+(define_expand "<optab_arith3><mode>3"
+  [(parallel
+  [(set (match_operand:MO 0 "nonimmediate_operand")
+	(any_arith3:MO (match_operand:MO 1 "nonimmediate_operand")
+		       (match_operand:MO 2 "general_operand")))
+   (clobber (reg:CC CC_REG))])]
+  ""
+{
+  rtx tmp;
+
+  if ((tmp = ia16_prepare_operands (<CODE>, operands)))
+    {
+      emit_insn (gen_<optab_arith3><mode>3 (tmp,
+					    operands[1], operands[2]));
+      emit_move_insn (operands[0], tmp);
+      DONE;
+    }
+})
+
+; Two operand V2QImode and/ior/xor.
+(define_expand "<optab_logic3>v2qi3"
+  [(parallel
+  [(set (match_operand:V2QI 0 "nonimmediate_operand")
+	(any_logic3:V2QI (match_operand:V2QI 1 "nonimmediate_operand")
+			 (match_operand:V2QI 2 "general_operand")))
+   (clobber (reg:CC CC_REG))])]
+  ""
+{
+  rtx tmp;
+
+  if ((tmp = ia16_prepare_operands (<CODE>, operands)))
+    {
+      emit_insn (gen_<optab_logic3>v2qi3 (tmp,
+					  operands[1], operands[2]));
+      emit_move_insn (operands[0], tmp);
+      DONE;
+    }
+})
+
+; Four operand Himode addition using lea, not clobbering/setting CC_REG.
+(define_insn "*addhi4"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+	(plus:HI (plus:HI (match_operand:HI 1 "single_register_operand" "%w")
+			  (match_operand:HI 2 "single_register_operand" "x"))
+		 (match_operand:HI 3 "immediate_operand" "i")))]
+  ""
+  "leaw\t%c3(%1,%2),\t%0"
+)
+
+; TODO: movw    %sp,    %bp
+;       lea     66(%bp),%cx
+; TODO: lea     4(%si), %si
+; TODO:
+;  64:   89 f5     mov    %si,%bp
+;  66:   8d 72 04  lea    4(%bp,%si),%si
+
+; inc/dec reg/mem is often a little shorter and faster than add $1, reg/mem.
+; Note that inc and dec don't set the carry flag.
+(define_insn "*inc_dec<MO:mode>2_cc_<SET_SZ:mode>"
+  [(set (reg:SET_SZ CC_REG)
+	(compare:SET_SZ
+	  (plus:MO (match_operand:MO 1 "nonimmediate_operand" "0,0,0,0")
+	           (match_operand:MO 2 "const_int_operand" "M1,P1,M1,P1"))
+	  (const_int 0)))
+   (set (match_operand:MO 0 "nonimmediate_operand" "=#*Ral,#*Ral,<r>m,<r>m")
+	(plus:MO (match_dup 1) (match_dup 2)))]
+  "(INTVAL (operands[2]) == 1 || INTVAL (operands[2]) == -1)
+   && ((!MEM_P (operands[0]) && !MEM_P (operands[1]))
+       || rtx_equal_p (operands[0], operands[1]))"
+  "@
+  subb\t$1,\t%0
+  addb\t$1,\t%0
+  dec<s>\t%0
+  inc<s>\t%0"
+)
+
+(define_insn "*inc_dec<MO:mode>2_cconly_<SET_SZ:mode>"
+  [(set (reg:SET_SZ CC_REG)
+	(compare:SET_SZ
+	  (plus:MO (match_operand:MO 1 "nonimmediate_operand" "0,0,0,0")
+	           (match_operand:MO 2 "const_int_operand" "M1,P1,M1,P1"))
+	  (const_int 0)))
+   (clobber (match_scratch:MO 0 "=#*Ral,#*Ral,<r>,<r>"))]
+  "(INTVAL (operands[2]) == 1 || INTVAL (operands[2]) == -1)
+   && ((!MEM_P (operands[0]) && !MEM_P (operands[1]))
+       || rtx_equal_p (operands[0], operands[1]))"
+  "@
+  subb\t$1,\t%0
+  addb\t$1,\t%0
+  dec<s>\t%0
+  inc<s>\t%0"
+)
+
+; This works for loops like "for (i = n; i >= 0; i --)".
+(define_insn "*cmp<mode>2_const0_dec<mode>2_ccz_c"
+  [(set (reg:CCZ_C CC_REG)
+	(compare:CCZ_C (match_operand:MO 1 "nonimmediate_operand" "0")
+		       (const_int 0)))
+   (set (match_operand:MO 0 "nonimmediate_operand" "=<r>m")
+	(plus:MO (match_dup 1) (const_int -1)))]
+  "(!MEM_P (operands[0]) && !MEM_P (operands[1]))
+   || rtx_equal_p (operands[0], operands[1])"
+  "sub<s>\t$1,\t%0"
+)
+
+; Any insn which implements HImode PLUS and may clobber CC_REG.
+; w = %bx/%bp, x = %si/%di, B = %bx/%si/%di/%bp, P1 = 1, M1 = -1.
+; TODO: 2*inc/dec reg16 is shorter than add/sub $2, reg16.
+; There is no point in using "lea" if reloading is needed, thus "!".
+(define_insn "*addhi3"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm,qm,qm,r,m,!r,!r")
+     (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,0,0,0,0,*w,*B")
+	      (match_operand:HI 2 "general_operand" "P1,M1,Um,Uo,g,ri,*x,i")))
+   (clobber (reg:CC CC_REG))]
+  "ia16_arith_operands_p (PLUS, operands)"
+  "@
+   incw\t%0
+   decw\t%0
+   decb\t%H0
+   addb\t%H2,\t%H0
+   addw\t%2,\t%0
+   addw\t%2,\t%0
+   leaw\t(%1,%2),\t%0
+   leaw\t%c2(%1),\t%0"
+)
+
+; Three operand HImode addition using lea, not clobbering/setting CC_REG.
+; This is for use by reload when computing stack slot addresses.
+; TODO: There should be an alternative for %sp+const or reload will use an
+; insn sequence which clobbers CC_REG, which could be a problem in rare cases.
+(define_insn "*addhi3_lea"
+  [(set (match_operand:HI 0 "register_operand" "=r,r,r")
+	(plus:HI (match_operand:HI 1 "single_register_operand" "w,x,B")
+		 (match_operand:HI 2 "single_nonmemory_operand" "x,w,i")))]
+  "reload_in_progress || reload_completed"
+  "@
+   leaw\t(%1,%2),\t%0
+   leaw\t(%2,%1),\t%0
+   leaw\t%c2(%1),\t%0"
+)
+
+; Any insn which implements QImode PLUS and may clobber CC_REG.
+; P1 = 1, M1 = -1, A = %al.
+(define_insn "*addqi3"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=#*Ral,#*Ral,qm,qm,q,m")
+     (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0,0,0,0")
+	      (match_operand:QI 2 "general_operand" "P1,M1,P1,M1,qmi,qi")))
+   (clobber (reg:CC CC_REG))]
+  "ia16_arith_operands_p (PLUS, operands)"
+  "@
+   addb\t%2,\t%0
+   addb\t%2,\t%0
+   incb\t%0
+   decb\t%0
+   addb\t%2,\t%0
+   addb\t%2,\t%0"
+)
+
+; TODO: Split this.
+(define_insn "*subqi3_zero_extendqihi"
+	[(set (match_operand:HI 0 "nonimmediate_operand" "=q,m")
+	      (minus:HI (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,0"))
+	                (zero_extend:HI (match_operand:QI 2 "general_operand" "qmi,qi"))))
+	 (clobber (reg:CC CC_REG))]
+	"ia16_arith_operands_p (MINUS, operands)"
+	"@
+	 subb\t%2,\t%L0\;sbbb\t%H0,\t%H0
+	 movb\t$0,\t%H0\;subb\t%2,\t%L0\;sbbb\t$0,\t%H0"
+)
+
+; This defines MINUS for QImode and HImode.
+(define_insn "*sub<mode>3"
+  [(set (match_operand:MO 0 "nonimmediate_operand" "=<r>m,<r>,m")
+	(minus:MO (match_operand:MO 1 "nonimmediate_or_0_operand" "Z,0,0")
+		  (match_operand:MO 2 "general_operand" "0,<g>,<r>i")))
+   (clobber (reg:CC CC_REG))]
+  "ia16_arith_operands_p (MINUS, operands)"
+  "@
+   neg<s>\t%0
+   sub<s>\t%2,\t%0
+   sub<s>\t%2,\t%0"
+)
+
+(define_insn "*sub<MO:mode>3_cc_<SET_SCZ:mode>"
+  [(set (reg:SET_SCZ CC_REG)
+        (compare:SET_SCZ
+	  (minus:MO (match_operand:MO 1 "nonimmediate_or_0_operand" "Z,0,0")
+		    (match_operand:MO 2 "general_operand" "0,<g>,<r>i"))
+	  (const_int 0)))
+   (set (match_operand:MO 0 "nonimmediate_operand" "=<r>m,<r>,m")
+	(minus:MO (match_dup 1) (match_dup 2)))]
+  "ia16_arith_operands_p (MINUS, operands)"
+  "@
+   neg<s>\t%0
+   sub<s>\t%2,\t%0
+   sub<s>\t%2,\t%0"
+)
+
+; FIXME: Should we have this at all? It should be expressed as comparison
+; of the two operands directly.
+(define_insn "*sub<MO:mode>3_cconly_<SET_SCZ:mode>"
+  [(set (reg:SET_SCZ CC_REG)
+	(compare:SET_SCZ
+	  (minus:MO (match_operand:MO 1 "nonimmediate_or_0_operand" "Z,0,0")
+		    (match_operand:MO 2 "nonimmediate_operand" "0,<g>,<r>i"))
+	  (const_int 0)))
+   (clobber (match_scratch:MO 0 "=<r>,<r>,<r>"))]
+  "ia16_arith_operands_p (MINUS, operands)"
+  "@
+   neg<s>\t%0
+   sub<s>\t%2,\t%0
+   sub<s>\t%2,\t%0"
+)
+
+; This defines insns for the AND code, modes HI and V2QI.
+; andw $0xff7f, reg/mem	is bad, 16-bit constant (can't sign extend).
+; andb   $0x7f, reg/mem is good, 8-bit constant.
+; andb   $0x80, reg is bad, needs QI_REGS register.
+; andw $0xff80, reg is good, accepts GENERAL_REGS register.
+; andw $0xff80, mem is bad, 16-bit memory access to modify lower 8 bits.
+; andb   $0x80, mem is good, only 8-bit memory access.
+(define_insn "*and<mode>3"
+  [(set
+     (match_operand:EQ16 0 "nonimmediate_operand" "=q,m,q,m,r,m,qm,r,m")
+     (and:EQ16
+	(match_operand:EQ16 1 "nonimmediate_operand" "%0,0,0,0,0,0,0,0,0")
+	(match_operand:EQ16 2 "general_operand" "Um,Um,Lbm,Lbm,Lar,Lam,Ua,g,ri")))
+   (clobber (reg:CC CC_REG))]
+  "ia16_arith_operands_p (AND, operands)"
+  "@
+   xorb\t%L0,\t%L0
+   movb\t$0,\t%L0
+   xorb\t%H0,\t%H0
+   movb\t$0,\t%H0
+   andw\t%2,\t%0
+   andb\t%L2,\t%L0
+   andb\t%H2,\t%H0
+   andw\t%2,\t%0
+   andw\t%2,\t%0"
+)
+
+; This defines insns for the IOR code, modes HI and V2QI.
+(define_insn "*ior<mode>3"
+  [(set (match_operand:EQ16 0 "nonimmediate_operand" "=qm,qm,q,m,qm,r,m")
+	(ior:EQ16
+	  (match_operand:EQ16 1 "nonimmediate_operand" "%0,0,0,0,0,0,0")
+	  (match_operand:EQ16 2 "general_operand" "Lbm,Um,Lor,Lom,Uo,g,ri")))
+   (clobber (reg:CC CC_REG))]
+  "ia16_arith_operands_p (IOR, operands)"
+  "@
+   movb\t$255,\t%L0
+   movb\t$255,\t%H0
+   orb\t%L2,\t%L0
+   orb\t%L2,\t%L0
+   orb\t%H2,\t%H0
+   orw\t%2,\t%0
+   orw\t%2,\t%0"
+)
+
+; This defines insns for the XOR code, modes HI and V2QI.
+(define_insn "*xor<mode>3"
+  [(set (match_operand:EQ16 0 "nonimmediate_operand" "=qm,qm,q,m,qm,r,m")
+	(xor:EQ16
+	  (match_operand:EQ16 1 "nonimmediate_operand" "%0,0,0,0,0,0,0")
+	  (match_operand:EQ16 2 "general_operand" "Lbm,Um,Lor,Lom,Uo,g,ri")))
+   (clobber (reg:CC CC_REG))]
+  "ia16_arith_operands_p (XOR, operands)"
+  "@
+   notb\t%L0
+   notb\t%H0
+   xorb\t%L2,\t%L0
+   xorb\t%L2,\t%L0
+   xorb\t%H2,\t%H0
+   xorw\t%2,\t%0
+   xorw\t%2,\t%0"
+)
+
+; This defines insns for the AND, IOR and XOR codes, mode QI.
+; This used to have % for operand 1 but reload died compiling something.
+(define_insn "*<optab_arith3>qi3"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=q,m,q,m")
+	(any_logic3:QI
+	  (match_operand:QI 1 "nonimmediate_operand" "0,0,qmi,qi")
+	  (match_operand:QI 2 "general_operand" "qmi,qi,0,0")))
+   (clobber (reg:CC CC_REG))]
+  "ia16_arith_operands_p (<CODE>, operands)"
+  "@
+   <mnemonic>b\t%2,\t%0
+   <mnemonic>b\t%2,\t%0
+   <mnemonic>b\t%1,\t%0
+   <mnemonic>b\t%1,\t%0"
+)
+
+; Define insns for PLUS, AND, IOR and XOR codes combined with a comparison
+; for HImode and QImode.
+(define_insn "*<optab_arith3><MO:mode>3_cc_<SET_SCZ:mode>"
+  [(set (reg:SET_SCZ CC_REG)
+	(compare:SET_SCZ
+	  (any_nosub3:MO (match_operand:MO 1 "nonimmediate_operand" "%0,0")
+			 (match_operand:MO 2 "general_operand" "<g>,<r>i"))
+	  (const_int 0)))
+   (set (match_operand:MO 0 "nonimmediate_operand" "=<r>,m")
+	(any_nosub3:MO (match_dup 1) (match_dup 2)))]
+  "ia16_arith_operands_p (<CODE>, operands)"
+  "<mnemonic><s>\t%2,\t%0"
+)
+
+; A special case of AND + COMPARE which doesn't need a scratch register.
+(define_insn "*and<MO:mode>3_cconly_<SET_CC:mode>_noclobber"
+  [(set (reg:SET_CC CC_REG)
+	(compare:SET_CC
+	  (and:MO (match_operand:MO 0 "nonimmediate_operand" "%qm,qm,<r>,m")
+		  (match_operand:MO 1 "general_operand" "UmUo,LbmLom,<g>,<r>i"))
+	  (const_int 0)))]
+  "!MEM_P (operands[0]) || !MEM_P (operands[1])"
+  "@
+   testb\t%H1,\t%H0
+   testb\t%L1,\t%L0
+   test<s>\t%1,\t%0
+   test<s>\t%1,\t%0"
+)
+
+(define_insn "*<optab_arith3><MO:mode>3_cconly_<SET_SCZ:mode>"
+  [(set (reg:SET_SCZ CC_REG)
+	(compare:SET_SCZ
+	  (any_nosub3:MO (match_operand:MO 1 "nonimmediate_operand" "%0")
+	                 (match_operand:MO 2 "general_operand" "<g>"))
+	  (const_int 0)))
+   (clobber (match_scratch:MO 0 "=<r>"))]
+  "ia16_arith_operands_p (<CODE>, operands)"
+  "<mnemonic><s>\t%2,\t%0"
+)
+
+; Combine creates such insns. Get rid of the clobber and the scratch register.
+(define_split
+  [(set (reg:SET_SCZ CC_REG)
+	(compare:SET_SCZ (plus:MO (match_operand:MO 0 "nonimmediate_operand")
+				  (match_operand:MO 1 "const_int_operand"))
+			(const_int 0)))
+   (clobber (scratch:MO))]
+  "INTVAL (operands[1]) != -32768"
+  [(set (reg:CC CC_REG)	(compare:CC (match_dup 0) (match_dup 2)))]
+{
+  operands[2] = GEN_INT (-INTVAL (operands[1]));
+})
+
+; Shifts and zero extends combined with bitwise logic or arithmetic.
+; Mostly from newlib/libc/stdlib/ldtoa.c.
+(define_insn "*lshrhi_const8_<code>hi3"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=q,qm")
+	(any_or:HI
+	    (lshiftrt:HI (match_operand:HI 2 "nonimmediate_operand" "qm,q")
+			 (const_int 8))
+	    (match_operand:HI 1 "nonimmediate_operand" "0,0")))
+   (clobber (reg:CC CC_REG))]
+  "ia16_arith_operands_p (<CODE>, operands)"
+  "<mnemonic>b\t%H2,\t%L0"
+)
+
+(define_insn "*zero_extendqihi_<code>hi3"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=q,qm")
+	(any_or:HI
+	    (zero_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm,q"))
+	    (match_operand:HI 1 "nonimmediate_operand" "0,0")))
+   (clobber (reg:CC CC_REG))]
+  "ia16_arith_operands_p (<CODE>, operands)"
+  "<mnemonic>b\t%2,\t%L0"
+)
+
+; TODO: These two set all flags except Z correctly.
+(define_insn "*ashlhi_const8_<code>hi3"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=q,qm")
+	(any_cheaphi:HI
+	     (match_operand:HI 1 "nonimmediate_operand" "0,0")
+	     (ashift:HI (match_operand:HI 2 "nonimmediate_operand" "qm,q")
+			(const_int 8))))
+   (clobber (reg:CC CC_REG))]
+  "ia16_arith_operands_p (<CODE>, operands)"
+  "<mnemonic>b\t%L2,\t%H0"
+)
+
+; From testsuite/gcc.dg/tree-ssa/gen-vect-25.c
+;(define_insn "*vector_mergehi3"
+;  [(set (match_operand:HI 0 "nonimmediate_operand" "=q,qm")
+;	(ior:HI (ashift:HI (match_operand:HI 2 "general_operand" "qm,q")
+;			   (const_int 8))
+;		(zero_extend:HI (match_operand:QI 1 "general_operand" "0,0"))))
+;   (clobber (reg:CC CC_REG))]
+;  "ia16_arith_operands_p (IOR, operands)"
+;  "movb\t%L2,\t%H0"
+;)
+
+(define_insn "*andhi_constm256_<code>hi3"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=q,qm")
+	(any_cheaphi:HI
+	     (match_operand:HI 1 "nonimmediate_operand" "0,0")
+	     (and:HI (match_operand:HI 2 "nonimmediate_operand" "qm,q")
+		     (const_int -256))))
+   (clobber (reg:CC CC_REG))]
+  "ia16_arith_operands_p (<CODE>, operands)"
+  "<mnemonic>b\t%H2, %H0"
+)
+
+; TODO: This is from umoddi3, try to figure out what is missing for combine.
+;     a99:       03 86 7a ff             add    -134(%bp),%ax
+;     a9d:       13 96 7c ff             adc    -132(%bp),%dx
+;     aa1:       39 96 7c ff             cmp    %dx,-132(%bp)
+
+; Insn patterns used in multiword addition.
+(define_insn "_add<mode>3_cc_for_carry"
+  [(set (reg:CCC CC_REG)
+	(compare:CCC
+		(plus:MO (match_operand:MO 1 "nonimmediate_operand" "%0,0,0")
+			 (match_operand:MO 2 "general_operand" "Z,<g>,<r>i"))
+		(match_dup 1)))
+   (set (match_operand:MO 0 "nonimmediate_operand" "=<r>m,<r>,m")
+	(plus:MO (match_dup 1) (match_dup 2)))]
+  "ia16_arith_operands_p (PLUS, operands)"
+  "@
+   clc
+   add<s>\t%2,\t%0
+   add<s>\t%2,\t%0"
+)
+
+(define_insn "*add<mode>3_cconly_for_carry"
+  [(set (reg:CCC CC_REG)
+	(compare:CCC
+		(plus:MO (match_operand:MO 1 "nonimmediate_operand" "%0,0")
+			 (match_operand:MO 2 "general_operand" "Z,<g>"))
+		(match_dup 1)))
+   (clobber (match_scratch:MO 0 "=X,<r>"))]
+  "ia16_arith_operands_p (PLUS, operands)"
+  "@
+   clc
+   add<s>\t%2,\t%0"
+)
+
+(define_insn "_add<mode>3_carry"
+  [(set (match_operand:MO 0 "nonimmediate_operand" "=<r>,m")
+	(plus:MO (minus:MO (match_operand:MO 1 "nonimmediate_operand" "%0,0")
+			   (match_operand:MO 3 "carry_flag_operator"))
+		 (match_operand:MO 2 "general_operand" "<g>,<r>i")))
+   (clobber (reg:CC CC_REG))]
+  "ia16_arith_operands_p (PLUS, operands)"
+  "adc<s>\t%2,\t%0"
+)
+
+; This helps combine create more complex patterns.
+(define_insn_and_split "*inccc<mode>3_carry"
+  [(set (match_operand:MO 0 "nonimmediate_operand" "=<r>,m")
+	(minus:MO (match_operand:MO 1 "nonimmediate_operand" "%0,0")
+		  (match_operand:MO 2 "carry_flag_operator")))
+   (clobber (reg:CC CC_REG))]
+  "!MEM_P (operands[0]) || !MEM_P (operands[1])
+   || can_create_pseudo_p ()
+   || rtx_equal_p (operands[0], operands[1])"
+  "#"
+  "&& 1"
+  [(parallel
+  [(set (match_dup 0) (plus:MO (minus:MO (match_dup 1) (match_dup 2))
+				(const_int 0)))
+   (clobber (reg:CC CC_REG))]
+  )]
+{
+  if (memory_operand (operands[1], <MODE>mode)
+      && !rtx_equal_p (operands[0], operands[1]))
+    operands[1] = force_reg (<MODE>mode, operands[1]);
+})
+
+(define_insn "_add<mode>3_carry_cc_for_carry"
+  [(set (reg:CCC CC_REG)
+     (compare:CCC
+	(plus:MO (minus:MO (match_operand:MO 1 "nonimmediate_operand" "%0,0")
+			   (match_operand:MO 3 "carry_flag_operator"))
+		 (match_operand:MO 2 "general_operand" "<g>,<r>i"))
+	(match_dup 2)))
+   (set (match_operand:MO 0 "nonimmediate_operand" "=<r>,m")
+	(plus:MO (minus:MO (match_dup 1) (match_dup 3))
+		 (match_dup 2)))]
+  "ia16_arith_operands_p (PLUS, operands)"
+  "adc<s>\t%2,\t%0"
+)
+
+; Insn patterns used in multiword subtraction.
+(define_insn "_sub<mode>3_cc_for_carry"
+  [(set (reg:CCCZ_NC CC_REG)
+	(compare:CCCZ_NC
+	    (minus:MO (match_operand:MO 1 "nonimmediate_or_0_operand" "0,Z,0,0")
+		      (match_operand:MO 2 "general_operand" "Z,0,<g>,<r>i"))
+	    (match_dup 1)))
+   (set (match_operand:MO 0 "nonimmediate_operand" "=<r>m,<r>m,<r>,m")
+	(minus:MO (match_dup 1) (match_dup 2)))]
+  "ia16_arith_operands_p (MINUS, operands)"
+  "@
+   clc
+   neg<s>\t%0
+   sub<s>\t%2,\t%0
+   sub<s>\t%2,\t%0"
+)
+
+(define_insn "*sub<mode>3_cconly_for_carry"
+  [(set (reg:CCCZ_NC CC_REG)
+	(compare:CCCZ_NC
+	    (minus:MO (match_operand:MO 1 "nonimmediate_or_0_operand" "0,Z,0")
+		      (match_operand:MO 2 "general_operand" "Z,0,<g>"))
+	    (match_dup 1)))
+   (clobber (match_scratch:MO 0 "=X,<r>,<r>"))]
+  "ia16_arith_operands_p (MINUS, operands)"
+  "@
+   clc
+   neg<s>\t%0
+   sub<s>\t%2,\t%0"
+)
+
+(define_insn "_sub<mode>3_carry"
+  [(set (match_operand:MO 0 "nonimmediate_operand" "=<r>,m")
+	(minus:MO (plus:MO (match_operand:MO 3 "carry_flag_operator")
+			   (match_operand:MO 1 "nonimmediate_operand" "0,0"))
+		  (match_operand:MO 2 "general_operand" "<g>,<r>i")))
+   (clobber (reg:CC CC_REG))]
+  "ia16_arith_operands_p (MINUS, operands)"
+  "sbb<s>\t%2,\t%0"
+)
+
+; Splitter to help combine create more complex patterns.
+;(define_insn_and_split "*deccc<mode>_carry"
+;  [(set (match_operand:MO 0 "nonimmediate_operand" "=<r>m")
+;	(plus:MO (match_operand:MO 2 "carry_flag_operator")
+;	         (match_operand:MO 1 "nonimmediate_operand" "0")))
+;   (clobber (reg:CC CC_REG))]
+;  "!MEM_P (operands[0]) || !MEM_P (operands[1])"
+;  "#"
+;  ""
+;  [(parallel
+;  [(set (match_dup 0)
+;	(minus:MO (plus:MO (match_dup 2) (match_dup 1)) (const_int 0)))
+;   (clobber (reg:CC CC_REG))]
+;  )]
+;)
+
+(define_insn "_sub<mode>3_carry_cc_for_carry"
+  [(set (reg:CCCZ_NC CC_REG)
+	(compare:CCCZ_NC
+	    (minus:MO (plus:MO (match_operand:MO 3 "carry_flag_operator")
+			       (match_operand:MO 1 "nonimmediate_operand" "0,0"))
+		      (match_operand:MO 2 "general_operand" "<g>,<r>i"))
+	    (plus:MO (match_dup 3) (match_dup 1))))
+   (set (match_operand:MO 0 "nonimmediate_operand" "=<r>,m")
+	(minus:MO (plus:MO (match_dup 3) (match_dup 1))
+		  (match_dup 2)))]
+  "ia16_arith_operands_p (MINUS, operands)"
+  "sbb<s>\t%2,\t%0"
+)
+
+; Insn patterns used in multiword left shift by 1.
+(define_insn "_ashl<mode>_const1_cc_for_carry"
+  [(set (reg:CCC CC_REG)
+	(compare:CCC
+		(ashift:MO (match_operand:MO 1 "nonimmediate_operand" "0")
+			   (const_int 1))
+		(match_dup 1)))
+   (set (match_operand:MO 0 "nonimmediate_operand" "=<r>m")
+	(ashift:MO (match_dup 1) (const_int 1)))]
+  ""
+  "shl<s>\t%0"
+)
+
+(define_insn "*ashl<mode>_const1_cconly_for_carry"
+  [(set (reg:CCC CC_REG)
+	(compare:CCC
+		(ashift:MO (match_operand:MO 1 "nonimmediate_operand" "0")
+			   (const_int 1))
+		(match_dup 1)))
+   (clobber (match_scratch:MO 0 "=<r>m"))]
+  ""
+  "shl<s>\t%0"
+)
+
+(define_insn "_ashl<mode>_const1_carry"
+  [(set (match_operand:MO 0 "nonimmediate_operand" "=<r>m")
+	(minus:MO (ashift:MO (match_operand:MO 1 "nonimmediate_operand" "0")
+			     (const_int 1))
+		  (match_operand:MO 2 "carry_flag_operator")))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "rcl<s>\t%0"
+)
+
+(define_insn "_ashl<mode>_const1_carry_cc_for_carry"
+  [(set (reg:CCC CC_REG)
+     (compare:CCC
+	(minus:MO (ashift:MO (match_operand:MO 1 "nonimmediate_operand" "0")
+			     (const_int 1))
+		  (match_operand:MO 2 "carry_flag_operator"))
+	(match_dup 1)))
+   (set (match_operand:MO 0 "nonimmediate_operand" "=<r>m")
+	(minus:MO (ashift:MO (match_dup 1) (const_int 1))
+		  (match_dup 2)))]
+  ""
+  "rcl<s>\t%0"
+)
+
+; Insn patterns used in multiword right shift by 1.  TODO: simplify and
+; generalize the RTL.
+(define_insn "_<optab_shiftrt_mw><mode>_const1_cc_for_carry"
+  [(set (reg:CCC CC_REG)
+	(compare:CCC
+		(and:MO (match_operand:MO 1 "nonimmediate_operand" "0")
+			(const_int -2))
+		(match_dup 1)))
+   (set (match_operand:MO 0 "nonimmediate_operand" "=<r>m")
+	(any_shiftrt_mw:MO (match_dup 1) (const_int 1)))]
+  ""
+  "<mnemonic><s>\t%0"
+)
+
+(define_insn "*ashr<mode>_const1_cconly_for_carry"
+  [(set (reg:CCC CC_REG)
+	(compare:CCC
+		(and:MO (match_operand:MO 1 "nonimmediate_operand" "0")
+			(const_int -2))
+		(match_dup 1)))
+   (clobber (match_scratch:MO 0 "=<r>m"))]
+  ""
+  "shr<s>\t%0"
+)
+
+(define_insn "_lshr<mode>_const1_carry"
+  [(set (match_operand:MO 0 "nonimmediate_operand" "=<r>m")
+	(minus:MO (lshiftrt:MO (match_operand:MO 1 "nonimmediate_operand" "0")
+			       (const_int 1))
+		  (rotatert:MO
+		    (and:MO (match_operand:MO 2 "carry_flag_operator")
+			    (const_int 1))
+		    (const_int 1))))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "rcr<s>\t%0"
+)
+
+(define_insn "_lshr<mode>_const1_carry_cc_for_carry"
+  [(set (reg:CCC CC_REG)
+	(compare:CCC
+		(and:MO (match_operand:MO 1 "nonimmediate_operand" "0")
+			(const_int -2))
+		(match_dup 1)))
+   (set (match_operand:MO 0 "nonimmediate_operand" "=<r>m")
+	(minus:MO (lshiftrt:MO (match_dup 1) (const_int 1))
+		  (rotatert:MO
+		    (and:MO (match_operand:MO 2 "carry_flag_operator")
+			    (const_int 1))
+		    (const_int 1))))]
+  ""
+  "rcr<s>\t%0"
+)
+
+; Multiword addition and subtraction.
+; This is not optimum for some constants (e.g. 0x80000000), but still
+; lots better than GCC's generic attempt to synthesize addsi3.
+(define_expand "<optab_addsub><mode>3"
+  [(parallel
+  [(set (match_operand:GT16I 0 "nonimmediate_operand")
+	(any_addsub:GT16I (match_operand:GT16I 1 "general_operand")
+			  (match_operand:GT16I 2 "general_operand")))
+   (clobber (reg:CC CC_REG))]
+  )]
+  ""
+{
+  rtx tmp;
+
+  if (CONSTANT_P (operands[1]) && CONSTANT_P (operands[2]))
+    FAIL;
+
+  if (<CODE> == MINUS && CONSTANT_P (operands[1]))
+    operands[1] = force_reg (<MODE>mode, operands[1]);
+  if ((tmp = ia16_prepare_operands (<CODE>, operands)))
+    {
+      emit_insn (gen_<optab_addsub><mode>3 (tmp, operands[1], operands[2]));
+      emit_move_insn (operands[0], tmp);
+      DONE;
+    }
+})
+
+(define_insn_and_split "*<optab_addsub><mode>3"
+  [(set (match_operand:GT16I 0 "nonimmediate_operand" "=r,m")
+	(any_addsub:GT16I (match_operand:GT16I 1 "nonimmediate_operand" "<constr1_arith3>0,0")
+			  (match_operand:GT16I 2 "general_operand" "g,ri")))
+   (clobber (reg:CC CC_REG))]
+  "ia16_arith_operands_p (<CODE>, operands)"
+  "#"
+  ""
+  [(const_int 0)]
+{
+  /* Avoid a warning: GET_MODE_SIZE(mode) is signed. */
+  signed int i;
+  rtx op0, op1, op2;
+  enum machine_mode cc_mode = (<CODE> == PLUS) ? CCCmode : CCCZ_NCmode;
+  enum rtx_code overflow_code = (<CODE> == PLUS) ? LTU : GTU;
+  rtx cc_reg = gen_rtx_REG (cc_mode, CC_REG);
+  rtx cc_op = gen_rtx_fmt_ee (overflow_code, HImode, cc_reg, const0_rtx);
+
+  /* The least significant word (LSW). */
+  op0 = simplify_gen_subreg (HImode, operands[0], <MODE>mode, 0);
+  op1 = simplify_gen_subreg (HImode, operands[1], <MODE>mode, 0);
+  op2 = simplify_gen_subreg (HImode, operands[2], <MODE>mode, 0);
+  emit_insn (gen__<optab_addsub>hi3_cc_for_carry (op0, op1, op2));
+
+  /* The words between the LSW and MSW. */
+  for (i = UNITS_PER_WORD;
+       i < GET_MODE_SIZE (<MODE>mode) - UNITS_PER_WORD;
+       i += UNITS_PER_WORD)
+    {
+      op0 = simplify_gen_subreg (HImode, operands[0], <MODE>mode, i);
+      op1 = simplify_gen_subreg (HImode, operands[1], <MODE>mode, i);
+      op2 = simplify_gen_subreg (HImode, operands[2], <MODE>mode, i);
+      emit_insn (gen__<optab_addsub>hi3_carry_cc_for_carry (op0, op1, op2,
+							    cc_op));
+    }
+
+  /* The most significant word (MSW). */
+  op0 = simplify_gen_subreg (HImode, operands[0], <MODE>mode, i);
+  op1 = simplify_gen_subreg (HImode, operands[1], <MODE>mode, i);
+  op2 = simplify_gen_subreg (HImode, operands[2], <MODE>mode, i);
+  emit_insn (gen__<optab_addsub>hi3_carry (op0, op1, op2, cc_op));
+  DONE;
+})
+
+; Multiword left shift.
+(define_expand "ashl<mode>3"
+  [(parallel
+  [(set (match_operand:GT16I 0 "nonimmediate_operand")
+	(ashift:GT16I (match_operand:GT16I 1 "general_operand")
+		      (match_operand:GT16I 2 "general_operand")))
+   (clobber (reg:CC CC_REG))]
+  )]
+  ""
+{
+  HOST_WIDE_INT shift;
+  rtx tmp0, tmp1;
+
+  /* If the shift count is a small constant, break it down into several
+     shifts by 1, so that we can get something like
+	  c0:	d1 e0			shl    %ax
+	  c2:	d1 d2			rcl    %dx
+	  c4:	d1 e0			shl    %ax
+	  c6:	d1 d2			rcl    %dx
+	  c8:	d1 e0			shl    %ax
+	  ca:	d1 d2			rcl    %dx
+     If the shift count is not constant or is too large, fall back to
+     letting GCC synthesize the operation, e.g.
+	  cf:	89 c3			mov    %ax,%bx
+	  d1:	b1 0c			mov    $0xc,%cl
+	  d3:	d3 eb			shr    %cl,%bx
+	  d5:	b1 04			mov    $0x4,%cl
+	  d7:	d3 e2			shl    %cl,%dx
+	  d9:	09 da			or     %bx,%dx
+	  db:	d3 e0			shl    %cl,%ax
+   */
+  if (! CONST_INT_P (operands[2]))
+    FAIL;
+
+  shift = INTVAL (operands[2]);
+  if (shift != 1)
+    {
+      if (shift < 0 || shift > 3)
+	FAIL;
+      if (optimize_size && <MODE>mode != SImode)
+	FAIL;
+    }
+
+  if (CONSTANT_P (operands[1]))
+    operands[1] = force_reg (<MODE>mode, operands[1]);
+
+  tmp1 = operands[1];
+
+  if ((MEM_P (operands[0]) && ! MEM_P (operands[1]))
+      || shift != 1)
+    {
+      while (shift-- != 0)
+	{
+	  tmp0 = gen_reg_rtx (<MODE>mode);
+	  emit_insn (gen_ashl<mode>3 (tmp0, tmp1, const1_rtx));
+	  tmp1 = tmp0;
+	}
+      emit_move_insn (operands[0], tmp1);
+      DONE;
+    }
+})
+
+(define_insn_and_split "*ashl<mode>_const1"
+  [(set (match_operand:GT16I 0 "nonimmediate_operand" "=r,m")
+	(ashift:GT16I (match_operand:GT16I 1 "nonimmediate_operand" "0,0")
+		      (const_int 1)))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  ""
+  [(const_int 0)]
+{
+  /* Avoid a warning: GET_MODE_SIZE(mode) is signed. */
+  signed int i;
+  rtx op0, op1;
+  enum machine_mode cc_mode = CCCmode;
+  enum rtx_code overflow_code = LTU;
+  rtx cc_reg = gen_rtx_REG (cc_mode, CC_REG);
+  rtx cc_op = gen_rtx_fmt_ee (overflow_code, HImode, cc_reg, const0_rtx);
+
+  /* The least significant word (LSW). */
+  op0 = simplify_gen_subreg (HImode, operands[0], <MODE>mode, 0);
+  op1 = simplify_gen_subreg (HImode, operands[1], <MODE>mode, 0);
+  emit_insn (gen__ashlhi_const1_cc_for_carry (op0, op1));
+
+  /* The words between the LSW and MSW. */
+  for (i = UNITS_PER_WORD;
+       i < GET_MODE_SIZE (<MODE>mode) - UNITS_PER_WORD;
+       i += UNITS_PER_WORD)
+    {
+      op0 = simplify_gen_subreg (HImode, operands[0], <MODE>mode, i);
+      op1 = simplify_gen_subreg (HImode, operands[1], <MODE>mode, i);
+      emit_insn (gen__ashlhi_const1_carry_cc_for_carry (op0, op1, cc_op));
+    }
+
+  /* The most significant word (MSW). */
+  op0 = simplify_gen_subreg (HImode, operands[0], <MODE>mode, i);
+  op1 = simplify_gen_subreg (HImode, operands[1], <MODE>mode, i);
+  emit_insn (gen__ashlhi_const1_carry (op0, op1, cc_op));
+  DONE;
+})
+
+; Multiword right shift.
+(define_expand "<optab_shiftrt_mw><mode>3"
+  [(parallel
+  [(set (match_operand:GT16I 0 "nonimmediate_operand")
+	(any_shiftrt_mw:GT16I (match_operand:GT16I 1 "general_operand")
+			      (match_operand:GT16I 2 "general_operand")))
+   (clobber (reg:CC CC_REG))]
+  )]
+  ""
+{
+  HOST_WIDE_INT shift;
+  rtx tmp0, tmp1;
+
+  if (! CONST_INT_P (operands[2]))
+    FAIL;
+
+  shift = INTVAL (operands[2]);
+  if (shift != 1)
+    {
+      if (CODE_FOR_<optab_shiftrt_mw><mode>3 == CODE_FOR_ashr<mode>3
+	  && shift == GET_MODE_BITSIZE (<MODE>mode) - 1)
+	{
+	  /* Here we _must_ tell GCC how to extract operands[1]'s sign bit
+	     and spread it around operands[0], or else GCC will go into
+	     infinite recursion and crash...  */
+	  signed int i = GET_MODE_SIZE (<MODE>mode) - UNITS_PER_WORD;
+	  rtx w3 = simplify_gen_subreg (HImode, operands[1], <MODE>mode, i);
+	  rtx w2 = gen_reg_rtx (HImode);
+	  rtx w1 = gen_reg_rtx (HImode);
+	  rtx w0;
+	  emit_move_insn (w2, w3);
+	  w2 = gen_rtx_ASHIFTRT (HImode, w2,
+				 gen_rtx_CONST_INT (VOIDmode,
+						    (HOST_WIDE_INT) 15));
+	  emit_move_insn (w1, w2);
+	  while (i >= 0)
+	    {
+	      w0 = simplify_gen_subreg (HImode, operands[0], <MODE>mode, i);
+	      emit_move_insn (w0, w1);
+	      i -= UNITS_PER_WORD;
+	    }
+	  DONE;
+	}
+
+      if (shift < 0 || shift > 3)
+	FAIL;
+      if (optimize_size && <MODE>mode != SImode)
+	FAIL;
+    }
+
+  if (CONSTANT_P (operands[1]))
+    operands[1] = force_reg (<MODE>mode, operands[1]);
+
+  tmp1 = operands[1];
+
+  if ((MEM_P (operands[0]) && ! MEM_P (operands[1]))
+      || shift != 1)
+    {
+      while (shift-- != 0)
+	{
+	  tmp0 = gen_reg_rtx (<MODE>mode);
+	  emit_insn (gen_<optab_shiftrt_mw><mode>3 (tmp0, tmp1, const1_rtx));
+	  tmp1 = tmp0;
+	}
+      emit_move_insn (operands[0], tmp1);
+      DONE;
+    }
+})
+
+(define_insn_and_split "*<optab_shiftrt_mw><mode>_const1"
+  [(set (match_operand:GT16I 0 "nonimmediate_operand" "=r,m")
+	(any_shiftrt_mw:GT16I (match_operand:GT16I 1 "nonimmediate_operand"
+						     "0,0")
+			      (const_int 1)))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  ""
+  [(const_int 0)]
+{
+  /* Avoid a warning: GET_MODE_SIZE(mode) is signed. */
+  signed int i;
+  rtx op0, op1;
+  enum machine_mode cc_mode = CCCmode;
+  enum rtx_code overflow_code = LTU;
+  rtx cc_reg = gen_rtx_REG (cc_mode, CC_REG);
+  rtx cc_op = gen_rtx_fmt_ee (overflow_code, HImode, cc_reg, const0_rtx);
+
+  /* The most significant word (MSW). */
+  i = GET_MODE_SIZE (<MODE>mode) - UNITS_PER_WORD;
+  op0 = simplify_gen_subreg (HImode, operands[0], <MODE>mode, i);
+  op1 = simplify_gen_subreg (HImode, operands[1], <MODE>mode, i);
+  emit_insn (gen__<optab_shiftrt_mw>hi_const1_cc_for_carry (op0, op1));
+
+  /* The words between the LSW and MSW. */
+  i -= UNITS_PER_WORD;
+  while (i > 0)
+    {
+      op0 = simplify_gen_subreg (HImode, operands[0], <MODE>mode, i);
+      op1 = simplify_gen_subreg (HImode, operands[1], <MODE>mode, i);
+      emit_insn (gen__lshrhi_const1_carry_cc_for_carry (op0, op1, cc_op));
+      i -= UNITS_PER_WORD;
+    }
+  gcc_assert (i == 0);
+
+  /* The least significant word (LSW). */
+  op0 = simplify_gen_subreg (HImode, operands[0], <MODE>mode, 0);
+  op1 = simplify_gen_subreg (HImode, operands[1], <MODE>mode, 0);
+  emit_insn (gen__lshrhi_const1_carry (op0, op1, cc_op));
+  DONE;
+})
+
+; Vector addition and subtraction.
+(define_insn_and_split "*addv2qi3"
+	[(set (match_operand:V2QI 0 "nonimmediate_operand" "=qm")
+	      (plus:V2QI (match_operand:V2QI 1 "nonimmediate_operand" "%0")
+	                 (match_operand:V2QI 2 "general_operand" "qmi")))
+	 (clobber (reg:CC CC_REG))]
+	"ia16_arith_operands_p (PLUS, operands)"
+	"#"
+	"reload_completed"
+	[(parallel [
+	 (set (match_dup 3) (plus:QI (match_dup 3) (match_dup 4)))
+	 (clobber (reg:CC CC_REG))
+	 ])
+	 (parallel [
+	 (set (match_dup 5) (plus:QI (match_dup 5) (match_dup 6)))
+	 (clobber (reg:CC CC_REG))
+	 ])]
+{
+	operands[3] = simplify_gen_subreg (QImode, operands[0], V2QImode, 0);
+	operands[4] = simplify_gen_subreg (QImode, operands[2], V2QImode, 0);
+	operands[5] = simplify_gen_subreg (QImode, operands[0], V2QImode, 1);
+	operands[6] = simplify_gen_subreg (QImode, operands[2], V2QImode, 1);
+})
+
+(define_insn_and_split "*subv2qi3"
+  [(set (match_operand:V2QI 0 "nonimmediate_operand" "=qm,qm")
+	(minus:V2QI (match_operand:V2QI 1 "nonimmediate_or_0_operand" "Z,0")
+	            (match_operand:V2QI 2 "general_operand" "0,qmi")))
+   (clobber (reg:CC CC_REG))]
+  "ia16_arith_operands_p (MINUS, operands)"
+  "#"
+  "reload_completed"
+  [(parallel [
+   (set (match_dup 3) (minus:QI (match_dup 4) (match_dup 5)))
+   (clobber (reg:CC CC_REG))
+   ])
+   (parallel [
+   (set (match_dup 6) (minus:QI (match_dup 7) (match_dup 8)))
+   (clobber (reg:CC CC_REG))
+   ])]
+{
+  operands[3] = simplify_gen_subreg (QImode, operands[0], V2QImode, 0);
+  operands[6] = simplify_gen_subreg (QImode, operands[0], V2QImode, 1);
+
+  /* We have to check which operands are matched and which ones are not.  */
+  if (operands[1] == CONST0_RTX (V2QImode))
+    {
+      operands[4] = simplify_gen_subreg (QImode, operands[1], V2QImode, 0);
+      operands[5] = operands[3];
+      operands[7] = simplify_gen_subreg (QImode, operands[1], V2QImode, 1);
+      operands[8] = operands[6];
+    }
+  else
+    {
+      operands[4] = operands[3];
+      operands[5] = simplify_gen_subreg (QImode, operands[2], V2QImode, 0);
+      operands[7] = operands[6];
+      operands[8] = simplify_gen_subreg (QImode, operands[2], V2QImode, 1);
+    }
+})
+
+; The template is a dummy.
+;(define_expand "negv2qi2"
+;  [(set (match_operand:V2QI 0 "nonimmediate_operand")
+;	(minus:V2QI (const_vector:V2QI [(const_int 0) (const_int 0)])
+;		    (match_operand:V2QI 1 "general_operand")))]
+;  ""
+;{
+;  emit_insn (gen_subv2qi3 (operands[0], CONST0_RTX (V2QImode), operands[1]));
+;  DONE;
+;})
+
+; Whole vector shifts.
+(define_expand "vec_<optab_vecshift3>_v2qi"
+  [(set (match_operand:V2QI 0 "nonimmediate_operand")
+	(any_vecshift3:V2QI (match_operand:V2QI 1 "general_operand")
+			    (match_operand:QI 2 "nonmemory_operand")))]
+  ""
+{
+  emit_insn (gen_<optab_shift>hi3 (simplify_gen_subreg (HImode, operands[0],
+  	    			  		        V2QImode, 0),
+				   simplify_gen_subreg (HImode, operands[1],
+				   		        V2QImode, 0),
+				   operands[2]));
+  DONE;
+})
+
+; aad imm:  al = imm * ah + al, ah = 0
+; For the NEC V20/V30, imm is fixed at 10, thus "Iaa" instead of "i".
+; CC isn't really clobbered. It is set according to the result in al.
+(define_insn "*muladdqi4"
+	[(set (match_operand:QI 0 "register_operand" "=Ral")
+	      (plus:QI (mult:QI (match_operand:QI 1 "register_operand" "+Rah")
+	                        (match_operand:QI 2 "immediate_operand" "Iaa"))
+	               (match_operand:QI 3 "register_operand" "0")))
+	 (set (match_dup 1) (const_int 0))
+	 (clobber (reg:CC CC_REG))]
+	"TARGET_AAD_IMM || INTVAL (operands[2]) == 10"
+	"aad\t%2"
+)
+
+(define_insn "*muladdqi4_clobber"
+	[(set (match_operand:QI 0 "register_operand" "=Ral")
+	      (plus:QI (mult:QI (match_operand:QI 1 "register_operand" "%Rah")
+	                        (match_operand:QI 2 "immediate_operand" "Iaa"))
+	               (match_operand:QI 3 "register_operand" "0")))
+	 (clobber (match_scratch:QI 4 "=1"))
+	 (clobber (reg:CC CC_REG))]
+	"TARGET_AAD_IMM || INTVAL (operands[2]) == 10"
+	"aad\t%2"
+)
+
+(define_insn "*muladdqi4_zero_extendqihi"
+  [(set (match_operand:HI 0 "register_operand" "=a")
+	(zero_extend:HI
+		(plus:QI (mult:QI (match_operand:QI 1 "register_operand" "%Rah")
+				  (match_operand:QI 2 "immediate_operand" "Iaa"))
+			 (match_operand:QI 3 "register_operand" "Ral"))))
+   (clobber (match_scratch:QI 4 "=1"))
+   (clobber (match_scratch:QI 5 "=3"))
+   (clobber (reg:CC CC_REG))]
+  "TARGET_AAD_IMM || INTVAL (operands[2]) == 10"
+  "aad\t%2"
+)
+
+; Two or three operand QImode multiplication.
+; TODO: Use whatever is cheapest of imulb or mulb for the chosen cpu.
+(define_insn "mulqi3"
+	[(set (match_operand:QI 0 "register_operand" "=Ral,Ral")
+	      (mult:QI (match_operand:QI 1 "register_operand" "%Rah,0")
+	               (match_operand:QI 2 "general_operand" "Iaa,qm")))
+	 (clobber (match_scratch:QI 3 "=1,Rah"))
+	 (clobber (reg:CC CC_REG))]
+	""
+	"@
+	 xorb\t%0,\t%0\;aad\t%2
+	 mulb\t%2"
+)
+
+; Two or three operand HImode multiplication. Use temporary pseudos to
+; work around the tight constraints of *mulhi3.
+(define_expand "mulhi3"
+	[(set (match_dup 5) (match_operand:HI 1 "nonimmediate_operand"))
+	 (parallel [
+	 (set (match_dup 4)
+	      (mult:HI (match_dup 5)
+	               (match_operand:HI 2 "general_operand")))
+	 (clobber (match_dup 3))
+	 (clobber (reg:CC CC_REG))
+	 ])
+	 (set (match_operand:HI 0 "register_operand") (match_dup 4))]
+	""
+{
+	if (TARGET_IMUL_IMM && CONSTANT_P (operands[2]))
+	  operands[3] = gen_rtx_SCRATCH (HImode);
+	else
+	  operands[3] = gen_rtx_REG (HImode, D_REG);
+	operands[4] = gen_reg_rtx (HImode);
+	operands[5] = gen_reg_rtx (HImode);
+})
+
+(define_insn "*mulhi3_const"
+	[(set (match_operand:HI 0 "register_operand" "=q,r")
+	      (mult:HI (match_operand:HI 1 "nonimmediate_operand" "%0,rm")
+	               (match_operand:HI 2 "immediate_operand" "I11,sImu")))
+	 (clobber (match_scratch:HI 3 "=X,X"))
+	 (clobber (reg:CC CC_REG))]
+	"TARGET_IMUL_IMM"
+	"@
+	 addb\t%L0,\t%H0
+	 imulw\t%2,\t%1,\t%0"
+)
+
+; We use general_operand rather than nonimmediate_operand even without
+; TARGET_IMUL_IMM because reload can load the constant into a register,
+; which the constraints accept.
+; TODO: Use whatever is cheapest of imulw or mulw for the chosen cpu.
+(define_insn "*mulhi3"
+  [(set (match_operand:HI 0 "single_register_operand" "=q,r,a")
+	(mult:HI (match_operand:HI 1 "single_register_operand" "%0,r,0")
+		 (match_operand:HI 2 "general_operand" "I11,Imu,rm")))
+   (clobber (match_scratch:HI 3 "=X,X,d"))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "@
+   addb\t%L0,\t%H0
+   imulw\t%2,\t%1,\t%0
+   mulw\t%2"
+)
+
+; The middle end can synthesize mulsi3 from mulhi3 and (u)mulhisi3.
+
+; One operand expanding HImode signed/unsigned multiplication.
+(define_expand "<np>mulhisi3"
+	[(set (match_dup 3) (match_operand:HI 1 "register_operand"))
+	 (parallel [
+	 (set (match_operand:SI 0 "register_operand")
+	      (mult:SI (any_extend:SI (match_dup 3))
+	               (any_extend:SI (match_operand:HI 2 "nonimmediate_operand"))))
+	 (clobber (reg:CC CC_REG))]
+	)]
+	""
+{
+	operands[3] = gen_reg_rtx (HImode);
+})
+
+(define_insn "*<np>mulhisi3"
+	[(set (match_operand:SI 0 "register_operand" "=A")
+	      (mult:SI (any_extend:SI (match_operand:HI 1 "single_register_operand" "%0"))
+	               (any_extend:SI (match_operand:HI 2 "nonimmediate_operand" "rm"))))
+	 (clobber (reg:CC CC_REG))]
+	""
+	"<mp>mulw\t%2"
+)
+
+; One operand expanding QImode signed/unsigned multiplication.
+(define_insn "<np>mulqihi3"
+	[(set (match_operand:HI 0 "register_operand" "=a")
+	      (mult:HI (any_extend:HI (match_operand:QI 1 "register_operand" "%0"))
+	               (any_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm"))))
+	 (clobber (reg:CC CC_REG))]
+	""
+	"<mp>mulb\t%2"
+)
+
+; One operand QImode division by a constant.
+; aam imm:  ah = al / imm, al = al % imm.
+; This should work on the NEC V20/V30, unlike aad.
+; TODO: SF, ZF and PF are set according to the remainder in %al of the division.
+(define_insn "*divmodqi4_const"
+	[(set (match_operand:QI 0 "register_operand" "=Rah")
+	      (udiv:QI (match_operand:QI 1 "register_operand" "Ral")
+		       (match_operand:QI 2 "immediate_operand" "i")))
+	 (set (match_operand:QI 3 "register_operand" "=1")
+	      (umod:QI (match_dup 1) (match_dup 2)))
+	 (clobber (reg:CC CC_REG))]
+	""
+	"aam\t%2"
+)
+
+; One operand QI/HImode signed division.
+(define_insn "divmod<mode>4"
+	[(set (match_operand:MO 0 "register_operand" "=<div_out>")
+	      (div:MO (match_operand:MO 1 "register_operand" "0")
+	              (match_operand:MO 2 "nonimmediate_operand" "<r>m")))
+	 (set (match_operand:MO 3 "register_operand" "=&<mod_out>")
+	      (mod:MO (match_dup 1) (match_dup 2)))
+	 (clobber (reg:CC CC_REG))]
+	""
+	"c<s>t<S>\;idiv<s>\t%2"
+)
+
+; One operand QI/HImode unsigned division.
+(define_insn "udivmod<mode>4"
+	[(set (match_operand:MO 0 "register_operand" "=<div_out>")
+	      (udiv:MO (match_operand:MO 1 "register_operand" "0")
+	               (match_operand:MO 2 "nonimmediate_operand" "<r>m")))
+	 (set (match_operand:MO 3 "register_operand" "=&<mod_out>")
+	      (umod:MO (match_dup 1) (match_dup 2)))
+	 (clobber (reg:CC CC_REG))]
+	""
+	"xor<s>\t%3,\t%3\;div<s>\t%2"
+)
+
+;; Shifts and rotates.
+
+; Two operand QI/HImode arithmetic/logic shifts and rotates.
+; Two constant arithmetic right shifts need special magic to work around
+; reload problems with multiword registers and tight constraints.
+(define_expand "ashrhi3"
+	[(set (match_dup 4) (match_operand:HI 1 "nonimmediate_operand"))
+	 (set (match_dup 3)
+	      (ashiftrt:HI (match_dup 4)
+	                   (match_operand:QI 2 "nonmemory_operand")))
+	 (set (match_operand:HI 0 "nonimmediate_operand") (match_dup 3))]
+	""
+{
+	if (CONST_INT_P (operands[2])
+	    && (INTVAL (operands[2]) >= 15 || INTVAL (operands[2]) == 8))
+	  {
+	    operands[3] = gen_reg_rtx (HImode);
+	    operands[4] = gen_reg_rtx (HImode);
+	    if (INTVAL (operands[2]) > 15)
+	      operands[2] = GEN_INT (15);
+	  }
+	else
+	  {
+	    emit_insn (gen__ashrhi3 (operands[0], operands[1], operands[2]));
+	    DONE;
+	  }
+})
+
+(define_expand "ashrqi3"
+	[(set (match_dup 4) (match_operand:QI 1 "nonimmediate_operand"))
+	 (set (match_dup 3)
+	      (ashiftrt:QI (match_dup 4)
+	                   (match_operand:QI 2 "nonmemory_operand")))
+	 (set (match_operand:QI 0 "nonimmediate_operand") (match_dup 3))]
+	""
+{
+	if (! CONST_INT_P (operands[2]) || INTVAL (operands[2]) < 7)
+	  {
+	    emit_insn (gen__ashrqi3 (operands[0], operands[1], operands[2]));
+	    DONE;
+	  }
+
+	operands[3] = gen_reg_rtx (QImode);
+	operands[4] = gen_reg_rtx (QImode);
+	if (INTVAL (operands[2]) > 7)
+	  operands[2] = GEN_INT (7);
+})
+
+; See "*extendhisi2" below.
+(define_insn "*ashrhi3_const15"
+	[(set (match_operand:HI 0 "register_operand" "=d")
+	      (ashiftrt:HI (match_operand:HI 1 "register_operand" "a")
+	                   (const_int 15)))]
+	""
+	"cwtd"
+)
+
+(define_insn_and_split "*ashrhi3_const8"
+  [(set (match_operand:HI 0 "single_register_operand" "=a")
+	(ashiftrt:HI (match_operand:HI 1 "general_operand" "qmi")
+		     (const_int 8)))]
+  ""
+  "#"
+  "reload_completed"
+  [(set (match_dup 2) (match_dup 3))
+   (set (match_dup 0) (sign_extend:HI (match_dup 2)))]
+{
+  operands[2] = simplify_gen_subreg (QImode, operands[0], HImode, 0);
+  operands[3] = simplify_gen_subreg (QImode, operands[1], HImode, 1);
+})
+
+(define_insn "*lshrhi3_const8_mulhi3_const257"
+  [(set (match_operand:HI 0 "register_operand" "=q")
+	(mult:HI (lshiftrt:HI (match_operand:HI 1 "register_operand" "0")
+			      (const_int 8))
+		 (const_int 257)))]
+  ""
+  "movb\t%H0,\t%L0"
+)
+
+; TODO: This should be a splitter.
+(define_insn "*lshrhi_const8_andhi_const255"
+  [(set (match_operand:HI 0 "register_operand" "=q")
+	(and:HI (lshiftrt:HI (match_operand:HI 1 "general_operand" "qmi")
+			     (const_int 8))
+		(const_int 255)))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "movb\t%H1,\t%L0\;xorb\t%H0,\t%H0"
+)
+
+(define_insn "*ashrqi3_const7"
+	[(set (match_operand:QI 0 "single_register_operand" "=Rah")
+	      (ashiftrt:QI (match_operand:QI 1 "single_register_operand" "Ral")
+	                   (const_int 7)))]
+	""
+	"cbtw"
+)
+
+(define_insn "*ashrqi3_const7_extendqihi"
+  [(set (match_operand:HI 0 "single_register_operand" "=d")
+	(sign_extend:HI
+		(ashiftrt:QI (match_operand:QI 1 "single_register_operand" "Rah")
+			     (const_int 7))))]
+  ""
+  "cwtd"
+)
+
+(define_insn "*cmphi2_const0_ccs_nc"
+  [(set (reg:CCS_NC CC_REG)
+	(compare:CCS_NC (match_operand:HI 0 "nonimmediate_operand" "qm,r")
+			(const_int 0)))]
+  ""
+  "@
+   cmpb\t$0x80,\t%H0
+   cmpw\t$0x8000,\t%0"
+)
+
+(define_insn_and_split "*lshrhi3_const15"
+  [(set (match_operand:HI 0 "register_operand" "=d,r,r,r")
+	(lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "a,0,qm,r")
+		     (const_int 15)))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "@
+   cwtd\;negw\t%0
+   shlw\t%0\;sbbw\t%0,\t%0\;negw\t%0
+   #
+   #"
+  "reload_completed
+   && (REGNO (operands[0]) != D_REG
+       || !REG_P (operands[1]) || REGNO (operands[1]) != A_REG)
+   && !rtx_equal_p (operands[0], operands[1])"
+  [(set (reg:CCS_NC CC_REG) (compare:CCS_NC (match_dup 1) (const_int 0)))
+   (parallel [
+   (set (match_dup 0) (ge:HI (reg:CCS_NC CC_REG) (const_int 0)))
+   (clobber (reg:CC CC_REG))
+   ])
+   (parallel [
+   (set (match_dup 0) (plus:HI (match_dup 0) (const_int 1)))
+   (clobber (reg:CC CC_REG))]
+   )]
+)
+
+; For newlib/libc/stdlib/ldtoa.c.
+(define_insn "*lshrhi_const15_addhi3"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=r,rm,rm")
+	(plus:HI
+	   (lshiftrt:HI (match_operand:HI 2 "nonimmediate_operand" "0,qm,r")
+			(const_int 15))
+	   (match_operand:HI 1 "nonimmediate_operand" "0,0,0")))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "@
+   sarw\t%0\;rclw\t%0\;adcw\t$0,\t%0
+   cmpb\t$0x80,\t%H2\;cmc\;adcw\t$0,\t%0
+   cmpw\t$0x8000,\t%2\;cmc\;adcw\t$0,\t%0"
+)
+
+; (define_split_and_insn ...) anyone?
+(define_split
+  [(set (match_operand:HI 0 "register_operand")
+	(rotate:HI (match_operand:HI 1 "register_operand") (const_int 8)))
+   (clobber (reg:CC CC_REG))]
+  "!reload_completed"
+  [(set (match_dup 0) (rotate:HI (match_dup 1) (const_int 8)))]
+  ""
+)
+
+(define_insn "*rotlhi3_const8"
+  [(set (match_operand:HI 0 "register_operand" "=q")
+	(rotate:HI (match_operand:HI 1 "register_operand" "0") (const_int 8)))]
+  ""
+  "xchgb\t%L0,\t%H0"
+)
+
+; The other shifts may need to use the %cl register. Use the single_register
+; trick here too. Note: <optab_shift> expands into _ashr instead of ashr.
+(define_expand "<optab_shift><mode>3"
+  [(parallel [
+   (set (match_operand:MO 0 "nonimmediate_operand")
+	(any_shift:MO (match_operand:MO 1 "nonimmediate_operand")
+		      (match_operand:QI 2 "nonmemory_operand")))
+   (clobber (reg:CC CC_REG))]
+   )]
+  ""
+{
+  rtx tmp;
+  if ((tmp = ia16_prepare_operands (<CODE>, operands)))
+    {
+      emit_insn (gen_<optab_shift><mode>3 (tmp, operands[1], operands[2]));
+      emit_move_insn (operands[0], tmp);
+      DONE;
+    }
+  if (operands[2] != const1_rtx && !TARGET_SHIFT_IMM && !REG_P (operands[2]))
+    operands[2] = force_reg (QImode, operands[2]);
+})
+
+; Note: <optab_shift> expands into _ashr instead of ashr.
+; C is %cl and Ish is any imm if i80186+, else 1.
+(define_insn "*<optab_shift><mode>3_subreg"
+  [(set (match_operand:MO 0 "nonimmediate_operand" "=<r>m")
+	(any_shift:MO (match_operand:MO 1 "nonimmediate_operand" "0")
+		      (subreg:QI
+			(match_operand:MO 2 "single_register_operand" "c")
+			0)))
+   (clobber (reg:CC CC_REG))]
+  "(<cond_shift>) && ia16_arith_operands_p (<CODE>, operands)"
+  "<mnemonic><s>\t%%cl,\t%0"
+)
+
+(define_insn "*<optab_shift><mode>3"
+  [(set (match_operand:MO 0 "nonimmediate_operand" "=<r>m")
+	(any_shift:MO (match_operand:MO 1 "nonimmediate_operand" "0")
+		      (match_operand:QI 2 "single_nonmemory_operand" "RclIsh")))
+   (clobber (reg:CC CC_REG))]
+  "(<cond_shift>) && ia16_arith_operands_p (<CODE>, operands)"
+  "<mnemonic><s>\t%2,\t%0"
+)
+
+; FIXME: Don't we want <cond_shift> here and below also?
+; Shifts by 0 don't set flags. So variable shifts need some kind of support
+; for getting the information from the VRP pass.
+; Only shifts of one bit set the overflow flag.
+; TODO: We likely want a _subreg version for operand2 (see e.g. pushqi1_subreg).
+(define_insn "*<optab_shift><MO:mode>3_cc_<SET_SCZ:mode>"
+  [(set (reg:SET_SCZ CC_REG)
+	(compare:SET_SCZ
+	     (any_shiftcc:MO (match_operand:MO 1 "nonimmediate_operand" "0")
+			     (match_operand:QI 2 "const_int_operand" "RclIsh"))
+	     (const_int 0)))
+   (set (match_operand:MO 0 "nonimmediate_operand" "=<r>m")
+	(any_shiftcc:MO (match_dup 1) (match_dup 2)))]
+  "INTVAL (operands[2]) != 0 && ia16_arith_operands_p (<CODE>, operands)"
+  "<mnemonic><s>\t%2,\t%0"
+)
+
+(define_insn "*<optab_shift><MO:mode>3_cconly_<SET_SCZ:mode>"
+  [(set (reg:SET_SCZ CC_REG)
+	(compare:SET_SCZ
+	     (any_shiftcc:MO (match_operand:MO 1 "nonimmediate_operand" "0")
+			     (match_operand:QI 2 "const_int_operand" "RclIsh"))
+	     (const_int 0)))
+   (clobber (match_scratch:MO 0 "=<r>m"))]
+  "INTVAL (operands[2]) != 0 && ia16_arith_operands_p (<CODE>, operands)"
+  "<mnemonic><s>\t%2,\t%0"
+)
+
+; Shift operands are promoted to "unsigned int" in C.
+; TODO: An insn for ashiftrt.
+(define_insn "*<optab_shift>qi_promoted"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
+	(subreg:QI
+	    (any_lshift:HI
+		(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0"))
+		(match_operand:QI 2 "single_nonmemory_operand" "RclIsh"))
+	    0))
+   (clobber (reg:CC CC_REG))]
+  "(<cond_shift>) && ia16_arith_operands_p (<CODE>, operands)"
+  "<mnemonic>b\t%2,\t%0"
+)
+
+; This is for combine, to split off the outer zero_extend.
+; TODO: Mem:QI -> mem:HI would be rejected by ia16_arith_operands_p().
+(define_split
+  [(set (match_operand:HI 0 "register_operand")
+	(zero_extend:HI
+	  (subreg:QI
+	    (any_lshift:HI
+		(zero_extend:HI (match_operand:QI 1 "register_operand"))
+		(match_operand:QI 2 "single_nonmemory_operand"))
+	    0)))
+   (clobber (reg:CC CC_REG))]
+  "(<cond_shift>) && ia16_arith_operands_p (<CODE>, operands)"
+  [(parallel
+  [(set (match_dup 3)
+	(subreg:QI (any_lshift:HI (zero_extend:HI (match_dup 1))
+				  (match_dup 2))
+		   0))
+   (clobber (reg:CC CC_REG))
+   ])
+   (parallel
+  [(set (match_dup 0) (and:HI (match_dup 0) (const_int 255)))
+   (clobber (reg:CC CC_REG))
+   ])]
+{
+   operands[3] = simplify_gen_subreg (QImode, operands[0], HImode, 0);
+})
+
+; Seen in a disassembly of regexp.o. Let combine fix it.
+;  mov    -396(%bp),%ax
+;  mov    $0xf,%cl
+;  shr    %cl,%ax
+;  mov    -396(%bp),%cx
+;  shl    %cx
+(define_insn "*lshlsi_const1_twoparts"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+	(ashift:HI (match_operand:HI 1 "register_operand" "0")
+		   (const_int 15)))
+   (set (match_operand:HI 2 "register_operand" "=&r")
+	(lshiftrt:HI (match_dup 1) (const_int 1)))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "xorw\t%2,%2\;shlw\t%0\;rclw\t%2"
+)
+
+; One operand V2QI/QI/HImode not.
+(define_expand "one_cmpl<mode>2"
+  [(set (match_operand:LE16 0 "nonimmediate_operand")
+	(not:LE16 (match_operand:LE16 1 "nonimmediate_operand")))]
+  ""
+{
+  rtx tmp;
+  if (MEM_P (operands[1])
+      && !rtx_equal_p (operands[0], operands[1]))
+    operands[1] = force_reg (<MODE>mode, operands[1]);
+  if (MEM_P (operands[0]) && !MEM_P (operands[1]))
+    {
+      tmp = gen_reg_rtx (<MODE>mode);
+      emit_insn (gen_one_cmpl<mode>2 (tmp, operands[1]));
+      emit_move_insn (operands[0], tmp);
+      DONE;
+    }
+})
+
+(define_insn "*one_cmpl<mode>2"
+  [(set (match_operand:LE16 0 "nonimmediate_operand" "=<r>m")
+	(not:LE16 (match_operand:LE16 1 "nonimmediate_operand" "0")))]
+  "(!MEM_P (operands[0]) && !MEM_P (operands[1]))
+   || rtx_equal_p (operands[0], operands[1])"
+  "not<s>\t%0"
+)
+
+; This is very similiar to what the middle end will generate, but for some
+; reason the register allocator likes this better when the expression was
+; (neg (abs (...)) before expand and combine swaps the operands of MINUS.
+;(define_expand "abs<mode>2"
+;  [(set (match_dup 3) (match_operand:MO 1 "general_operand"))
+;   (set (match_dup 2) (ashiftrt:MO (match_dup 3) (match_dup 4)))
+;   (parallel [
+;   (set (match_dup 3)
+;	(xor:MO (match_dup 3) (match_dup 2)))
+;   (clobber (reg:CC CC_REG))
+;   ])
+;   (set (match_operand:MO 0) (match_dup 3))
+;   (parallel [
+;   (set (match_dup 0) (minus:MO (match_dup 0) (match_dup 2)))
+;   (clobber (reg:CC CC_REG))]
+;   )]
+;  ""
+;{
+;  operands[2] = gen_reg_rtx (<MODE>mode);
+;  operands[3] = gen_reg_rtx (<MODE>mode);
+;  operands[4] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode) - 1);
+;})
+
+; EQ/NE comparisons are usually best done in CCZ_C or CCZ_NC mode.
+(define_insn "*cmp<MO:mode>_const0_ccz_c"
+  [(set (reg:CCZ_C CC_REG)
+	(compare:CCZ_C (match_operand:MO 0 "nonimmediate_operand" "<r>m")
+		       (const_int 0)))]
+  ""
+  "cmp<s>\t$1,\t%0"
+)
+
+(define_insn "*cmp<MO:mode>_constm1_ccz_nc"
+  [(set (reg:CCZ_NC CC_REG)
+	(compare:CCZ_NC (match_operand:MO 0 "nonimmediate_operand" "<r>m")
+			(const_int -1)))]
+  ""
+  "cmp<s>\t$-1,\t%0"
+)
+
+; LEU and GTU comparisons against constants can use the more favorable
+; CCCZ_Cmode instead of CCCZmode. We really use "a < c+1" instead of "a <= c"
+; and "a >= c+1" instead of "a > c". It is ok for c+1 to overflow.
+(define_insn "*cmp<mode>_cccz_c"
+  [(set (reg:CCCZ_C CC_REG)
+	(compare:CCCZ_C (match_operand:MO 0 "nonimmediate_operand" "<r>,m,<r>m")
+			(match_operand:MO 1 "immediate_operand" "M1,M1,i")))]
+  ""
+  "@
+   and<s>\t%0,\t%0
+   cmp<s>\t$0,\t%0
+   cmp<s>\t%1+1,\t%0"
+)
+
+; Comparisons against zero. They don't need to set the overflow flag.
+(define_insn "*cmp<MO:mode>_const0_<SET_SCZ:mode>"
+  [(set (reg:SET_SCZ CC_REG)
+	(compare:SET_SCZ (match_operand:MO 0 "nonimmediate_operand" "<r>,m")
+			 (const_int 0)))]
+  ""
+  "@
+   and<s>\t%0,\t%0
+   cmp<s>\t$0,\t%0"
+)
+
+; The standard comparison insn, setting all flags.
+(define_insn "*cmp<MO:mode>_<SET_SOCZ:mode>"
+  [(set (reg:SET_SOCZ CC_REG)
+	(compare:SET_SOCZ (match_operand:MO 0 "nonimmediate_operand" "<r>,<r>,m")
+			  (match_operand:MO 1 "general_operand" "Z,<g>,<r>i")))]
+  "!MEM_P (operands[0]) || !MEM_P (operands[1])"
+  "@
+   and<s>\t%0,\t%0
+   cmp<s>\t%1,\t%0
+   cmp<s>\t%1,\t%0"
+)
+
+; Combine seems to be unable to get this right expressed with AND.
+(define_insn_and_split "*extzv<mode>_cconly_ccz"
+  [(set (reg:CCZ CC_REG)
+  	(compare:CCZ
+		(zero_extract (match_operand:MO 0 "nonimmediate_operand" "<r>m")
+			      (match_operand:QI 1 "const_int_operand" "n")
+			      (match_operand:QI 2 "const_int_operand" "n"))
+		(const_int 0)))]
+  ""
+  "#"
+  ""
+  [(set (reg:CCZ CC_REG)
+  	(compare:CCZ (and:MO (match_dup 0) (match_dup 3))
+  		     (const_int 0)))]
+{
+  operands[3] =
+    gen_int_mode (((1 << INTVAL (operands[1])) - 1) << INTVAL (operands[2]),
+		  <MODE>mode);
+})
+
+; The sign extension patterns have expanders which make HI/QImode pseudos to
+; work around register allocation problems.
+; TODO Why are extendhisi2 and extendqihi2 so different?
+(define_expand "extendhisi2"
+	[(set (match_dup 2) (match_operand:HI 1 "register_operand"))
+	 (set (match_operand:SI 0 "register_operand")
+	      (sign_extend:SI (match_dup 2)))]
+	""
+{
+	operands[2] = gen_reg_rtx (HImode);
+})
+
+; The splitting pattern is to stop GCC from crashing when building Newlib
+; with -mregparmcall:
+;
+;    "	.../stdlib/dtoa.c: In function ‘_dtoa_r’:
+;	.../stdlib/dtoa.c:872:1: error: unable to find a register to spill
+;	 }
+;	 ^
+;	.../stdlib/dtoa.c:872:1: error: this is the insn:
+;	(insn 7514 7607 7610 31 (set (reg:SI 3423 [orig:460 i ] [460])
+;		(sign_extend:SI (subreg/j:HI (reg:SI 3423 [orig:460 i ] [460])
+;	 0))) .../stdlib/dtoa.c:360 434 {*extendhisi2}
+;	     (nil))  "
+;
+; (Apparently GCC had some sort of problem unifying the views of %dx:%ax as
+; separate HImode registers with the view of %dx:%ax as a single SImode
+; thing, when trying to pass the sign-extended result to a subroutine...)
+;	-- tkchia
+(define_insn_and_split "*extendhisi2"
+	[(set (match_operand:SI 0 "register_operand" "=A")
+	      (sign_extend:SI (match_operand:HI 1 "register_operand" "0")))]
+	""
+	"cwtd"
+	""
+	[(set (subreg:HI (match_dup 0) 0) (match_dup 1))
+	 (set (subreg:HI (match_dup 0) 2)
+			 (ashiftrt:HI (match_dup 1) (const_int 15)))]
+
+)
+
+(define_expand "extendqihi2"
+	[(set (match_dup 2) (match_operand:QI 1 "register_operand"))
+	 (set (match_operand:HI 0 "register_operand")
+	      (sign_extend:HI (match_dup 2)))]
+	""
+{
+	operands[2] = gen_reg_rtx (QImode);
+})
+
+(define_insn "*extendqihi2"
+	[(set (match_operand:HI 0 "register_operand" "=a")
+	      (sign_extend:HI (match_operand:QI 1 "register_operand" "Ral")))]
+	""
+	"cbtw"
+)
+
+; GCC convert_move() handles zero extension to modes larger than a word just
+; fine.  For smaller modes, however, it defaults to a pair of unsigned shifts.
+; We want to use an AND instruction instead.
+(define_expand "zero_extendqihi2"
+  [(set (match_dup 2) (match_operand:QI 1 "general_operand"))
+   (parallel [
+   (set (match_dup 3) (and:HI (match_dup 3) (const_int 255)))
+   (clobber (reg:CC CC_REG))
+   ])
+   (set (match_operand:HI 0 "nonimmediate_operand") (match_dup 3))]
+  ""
+{
+  operands[3] = gen_reg_rtx (HImode);
+  operands[2] = simplify_gen_subreg (QImode, operands[3], HImode, 0);
+})
+
+; Combine prefers ZERO_EXTEND over AND.  Undo this transformation.
+(define_insn_and_split "*zero_extendqihi2"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=r")
+	(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0")))
+   (clobber (reg:CC CC_REG))]
+  "(!MEM_P (operands[0]) && !MEM_P (operands[1]))
+   || (MEM_P (operands[0])
+       && MEM_P (operands[1])
+       && rtx_equal_p (XEXP (operands[0], 0), XEXP (operands[1], 0)))"
+  "#"
+  ""
+  [(parallel
+  [(set (match_dup 0) (and:HI (match_dup 2) (const_int 255)))
+   (clobber (reg:CC CC_REG))]
+  )]
+{
+  /* We may be zero extending directly in memory and must not generate
+     (set (mem:HI x) (and:HI (subreg:HI (mem:QI x) 0))).  */
+  if (MEM_P (operands[0])
+      && MEM_P (operands[1])
+      && rtx_equal_p (XEXP (operands[0], 0), XEXP (operands[1], 0)))
+    operands[2] = widen_memory_access (operands[1], HImode, 0);
+  else
+    operands[2] = simplify_gen_subreg (HImode, operands[1], QImode, 0);
+})
+
+;; The scond patterns. IA-16 only has limited capabilities.
+; The following assumes STORE_FLAG_VALUE == -1.
+; We expand using QImode instead of HImode because
+; 1) QImode is requested for things like (a == 2 | b).
+; 2) Combine can optimize scondqi + sign extension into scondhi if needed
+; but not optimize away a truncation.
+; The template is a dummy.
+(define_expand "cstore<mode>4"
+  [(set (reg:CC CC_REG)
+	(compare:CC (match_operand:MO 2 "nonimmediate_operand")
+		    (match_operand:MO 3 "general_operand")))
+   (set (match_operand:QI 0 "register_operand")
+	(match_operator 1 "ordered_comparison_operator"
+	  [(reg:CC CC_REG) (const_int 0)]))]
+  "flag_if_conversion"
+{
+  rtx cc_reg, op1;
+  enum machine_mode cc_mode;
+
+  if (MEM_P (operands[2]) && MEM_P (operands[3]))
+    operands[2] = force_reg (<MODE>mode, operands[2]);
+  cc_reg = ia16_gen_compare_reg (GET_CODE (operands[1]), operands[2],
+  	   			 operands[3], false);
+  cc_mode = GET_MODE (cc_reg);
+  op1 = gen_rtx_fmt_ee (GET_CODE (operands[1]), QImode, cc_reg, const0_rtx);
+
+  /* We can do anything which tests only the carry flag.  */
+  if (carry_flag_operator (op1, QImode)
+      || carry_not_flag_operator (op1, QImode))
+    emit_insn (gen__scond (operands[0], op1));
+
+  /* We can do slt as long as we don't need the overflow flag.  */
+  else if ((GET_CODE (operands[1]) == LT
+	    && ia16_cc_modes_compatible (CCSCZmode, cc_mode) == CCSCZmode)
+
+  /* We can do seq as long as the zero flag is set.  */
+	   || (GET_CODE (operands[1]) == EQ
+	       && ia16_cc_modes_compatible (CCZmode, cc_mode) == cc_mode))
+    emit_insn (gen__scond_scratch (operands[0], op1));
+  else
+    FAIL;
+  DONE;
+})
+
+; Expand scond operations which don't need a scratch register.
+(define_expand "_scond"
+  [(parallel
+  [(set (match_operand:QI 0 "register_operand")
+	(match_operand:QI 1))
+   (clobber (reg:CC CC_REG))]
+  )]
+)
+
+; Expand scond operations needing scratch registers:
+; seq from zero flag and slt from sign flag.
+; TODO: Expand this sequence properly.
+(define_expand "_scond_scratch"
+  [(parallel [
+   (set (match_dup 4) (match_operand:QI 1))
+   (clobber (match_scratch:QI 2))
+   (clobber (match_scratch:QI 3))
+   (clobber (reg:CC CC_REG))
+   ])
+   (set (match_operand:QI 0 "register_operand") (match_dup 4))]
+  ""
+{
+  operands[4] = gen_reg_rtx (QImode);
+})
+
+; GAS does not know about salc (opcode 0xd6), also known as setalc or setcal. :-(
+(define_insn "*scond<mode>_carry"
+  [(set (match_operand:MO 0 "register_operand" "=<r>")
+	(match_operand:MO 1 "carry_flag_operator"))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "sbb<s>\t%0,\t%0"
+)
+
+; This is only to help combine build up complex instructions.
+(define_insn_and_split "*scond<mode>_carry_neg"
+  [(set (match_operand:MO 0 "register_operand" "=<r>")
+	(neg:MO (match_operand:MO 1 "carry_flag_operator")))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  ""
+  [(parallel
+  [(set (match_dup 0) (match_dup 1))
+   (clobber (reg:CC CC_REG))
+  ])
+  (parallel [
+   (set (match_dup 0) (minus:MO (const_int 0) (match_dup 0)))
+   (clobber (reg:CC CC_REG))]
+  )]
+)
+
+(define_insn_and_split "*scond<mode>_carry_not"
+  [(set (match_operand:MO 0 "register_operand" "=<r>")
+	(match_operand:MO 1 "carry_not_flag_operator"))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  ""
+  [(set (reg:CCC CC_REG)
+	(unspec:CCC [(match_dup 2)] UNSPEC_NOT_CARRY))
+   (parallel
+  [(set (match_dup 0)
+	(ltu:MO (reg:CCC CC_REG) (const_int 0)))
+   (clobber (reg:CC CC_REG))]
+  )]
+{
+  operands[2] = XEXP (operands[1], 0);
+})
+
+; Split "cmc; sbb reg,reg; neg reg" into "sbb reg,reg; inc reg".
+(define_insn_and_split "*scc<mode>_carry_not_neg"
+  [(set (match_operand:MO 0 "register_operand" "=<r>")
+	(neg:MO (match_operand:MO 1 "carry_not_flag_operator")))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  ""
+  [(parallel
+  [(set (match_dup 0) (match_dup 2))
+   (clobber (reg:CC CC_REG))
+  ])
+   (parallel [
+   (set (match_dup 0) (plus:MO (match_dup 0) (const_int 1)))
+   (clobber (reg:CC CC_REG))]
+  )]
+{
+  operands[2] = gen_rtx_fmt_ee (reverse_condition (GET_CODE (operands[1])),
+				<MODE>mode, XEXP (operands[1], 0),
+				XEXP (operands[1], 1));
+})
+
+(define_insn "*one_cmplccc2"
+  [(set (reg:CCC CC_REG)
+	(unspec:CCC [(reg CC_REG)] UNSPEC_NOT_CARRY))]
+  ""
+  "cmc"
+)
+
+; TODO: *sltsi
+(define_insn "*sltqi_<USE_S:mode>"
+	[(set (match_operand:QI 0 "register_operand" "=Rdl,?Rah")
+	      (lt:QI (reg:USE_S CC_REG) (const_int 0)))
+	 (clobber (match_scratch:QI 1 "=Rah,Ral"))
+	 (clobber (match_scratch:QI 2 "=Rdh,X"))
+	 (clobber (reg:CC CC_REG))]
+	""
+	"@
+	lahf\;cwtd
+	lahf\;movb\t%0,\t%1\;cbtw"
+)
+
+(define_insn "*slthi_<USE_S:mode>"
+	[(set (match_operand:HI 0 "single_register_operand" "=d")
+	      (lt:HI (reg:USE_S CC_REG) (const_int 0)))
+	 (clobber (match_scratch:QI 1 "=Rah"))
+	 (clobber (reg:CC CC_REG))]
+	""
+	"lahf\;cwtd"
+)
+
+(define_insn "*seqqi_<USE_Z:mode>"
+	[(set (match_operand:QI 0 "register_operand" "=Rdl,?Rah")
+	      (eq:QI (reg:USE_Z CC_REG) (const_int 0)))
+	 (clobber (match_scratch:QI 1 "=Rah,Ral"))
+	 (clobber (match_scratch:QI 2 "=Rdh,X"))
+	 (clobber (reg:CC CC_REG))]
+	""
+	"@
+	lahf\;shlb\t%1\;cwtd
+	lahf\;shlb\t%0\;movb\t%0,\t%1\;cbtw"
+)
+
+(define_insn "*seqhi_<USE_Z:mode>"
+	[(set (match_operand:HI 0 "single_register_operand" "=d")
+	      (eq:HI (reg:USE_Z CC_REG) (const_int 0)))
+	 (clobber (match_scratch:QI 1 "=Rah"))
+	 (clobber (reg:CC CC_REG))]
+	""
+	"lahf\;shlb\t%1\;cwtd"
+)
+
+; "A" means dx:ax, "j" means bx:dx.
+(define_insn_and_split "*seqsi_<USE_Z:mode>"
+	[(set (match_operand:SI 0 "register_operand" "=A,j")
+	      (eq:SI (reg:USE_Z CC_REG) (const_int 0)))
+	 (clobber (match_scratch:QI 1 "=X,Rah"))
+	 (clobber (reg:CC CC_REG))]
+	""
+	"#"
+	"reload_completed"
+	[(parallel
+	[(set (reg:HI D_REG) (eq:HI (reg:USE_Z CC_REG) (const_int 0)))
+	 (clobber (reg:QI AH_REG))
+	 (clobber (reg:CC CC_REG))
+	])
+	 (set (match_dup 2) (reg:HI D_REG))]
+{
+	if (REGNO (operands[0]) == A_REG)
+		operands[2] = gen_rtx_REG (HImode, A_REG);
+	else if (REGNO (operands[0]) == D_REG)
+		operands[2] = gen_rtx_REG (HImode, B_REG);
+	else
+		gcc_unreachable ();
+})
+
+(define_expand "parityhi2"
+  [(set (match_dup 2) (match_operand:HI 1 "general_operand"))
+   (parallel [
+   (set (reg:CC CC_REG)
+	(compare:CC
+		(xor:HI (and:HI (match_dup 2) (const_int -256))
+			(ashift:HI (match_dup 2) (const_int 8)))
+		(const_int 0)))
+   (clobber (match_dup 2))
+   ])
+   (parallel [
+   (set (match_operand:HI 0 "register_operand")
+	(parity:HI (reg:CC CC_REG)))
+   (clobber (match_scratch:QI 2))
+   (clobber (reg:CC CC_REG))]
+  )]
+  ""
+{
+  operands[2] = gen_reg_rtx (HImode);
+})
+
+(define_expand "parityqi2"
+  [(set (reg:CC CC_REG)
+	(compare:CC (match_operand:QI 1 "general_operand")
+		    (const_int 0)))
+   (parallel [
+   (set (match_operand:QI 0 "register_operand")
+	(parity:QI (reg:CC CC_REG)))
+   (clobber (match_scratch:QI 2))
+   (clobber (reg:CC CC_REG))]
+  )]
+)
+
+(define_insn "*cmphi_const0_cconly_for_parity"
+  [(set (reg:CC CC_REG)
+	(compare:CC
+		(xor:HI (and:HI (match_operand:HI 0 "register_operand" "+q")
+				(const_int -256))
+			(ashift:HI (match_dup 0) (const_int 8)))
+	    (const_int 0)))
+   (clobber (match_dup 0))]
+  ""
+  "xorb\t%L0,\t%H0"
+)
+
+; The parity flag is set for even parity, i.e. when we want to return 0.
+(define_insn "*parityhi2"
+  [(set (match_operand:HI 0 "register_operand" "=a,r")
+	(parity:HI (reg:CC CC_REG)))
+   (clobber (match_scratch:QI 1 "=X,Rah"))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "@
+  lahf\;andb\t$0x4,\t%H0\;addb\t$0xfc,\t%H0\;sbbw\t%0,\t%0\;incw\t%0
+  lahf\;andb\t$0x4,\t%1\;addb\t$0xfc,\t%1\;sbbw\t%0,\t%0\;incw\t%0"
+)
+
+(define_insn "*parityqi2"
+  [(set (match_operand:QI 0 "register_operand" "=Rah,q")
+	(parity:QI (reg:CC CC_REG)))
+   (clobber (match_scratch:QI 1 "=X,Rah"))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "@
+  lahf\;andb\t$0x4,\t%0\;addb\t$0xfc,\t%0\;sbbb\t%0,\t%0\;incb\t%0
+  lahf\;andb\t$0x4,\t%1\;addb\t$0xfc,\t%1\;sbbb\t%0,\t%0\;incb\t%0"
+)
+
+; Activate this template only if %ds is available for allocation.  If %ds is
+; configured to be a fixed-purpose register (`-ffixed-ds'), fall back on
+; GCC's default treatment of memory copyings, whatever that may be.
+;
+; Also fall back on the default (i.e. memcpy (...)) if this is a move
+; between two addresses in generic (near) space.
+(define_expand "movmemhi"
+  [(parallel
+    [(set (match_operand:BLK 0 "general_operand")
+	  (match_operand:BLK 1 "general_operand"))
+     (use (match_operand:HI 2 "nonmemory_operand"))
+     (use (match_operand:HI 3 "const_int_operand"))
+     (set (match_dup 6) (plus:HI (match_dup 9) (match_dup 2)))
+     (set (match_dup 7) (plus:HI (match_dup 10) (match_dup 2)))
+     (set (match_dup 8) (const_int 0))
+     (clobber (reg:CC CC_REG))]
+  )]
+  "! fixed_regs[DS_REG]"
+{
+  rtx ovr0, off0, ovr1, off1;
+
+  ia16_split_seg_override_and_offset (XEXP (operands[0], 0), &ovr0, &off0);
+  ia16_split_seg_override_and_offset (XEXP (operands[1], 0), &ovr1, &off1);
+
+  if (! ovr0 && ! ovr1
+      && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (operands[0]))
+      && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (operands[1])))
+    FAIL;
+
+  operands[6] = gen_reg_rtx (HImode);
+  operands[7] = gen_reg_rtx (HImode);
+  operands[8] = gen_reg_rtx (HImode);
+
+  if (! off0)
+    off0 = const0_rtx;
+  /* We need to at least massage the offset portions of operands[0] and
+     operands[1] into expressions that satisfy "general_operand", or else
+     GCC will have a hard time matching the insns below later on.  */
+  off0 = copy_addr_to_reg (off0);
+  if (! ovr0)
+    {
+      rtx seg;
+      if ((ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (operands[0]))
+	   || MEM_READONLY_P (operands[0]))  /* FIXME: see ia16-no-ss-data.c */
+	  && ! ia16_in_ss_data_function_p ())
+	seg = ia16_data_seg_rtx ();
+      else
+	seg = gen_rtx_REG (SEGmode, SS_REG);
+      ovr0 = ia16_seg_override_term (copy_to_reg (seg));
+    }
+  operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_PLUS (HImode, off0, ovr0));
+  set_mem_addr_space (operands[0], ADDR_SPACE_FAR);
+  operands[9] = off0;
+
+  if (! off1)
+    off1 = const0_rtx;
+  off1 = copy_addr_to_reg (off1);
+  if (! ovr1)
+    {
+      rtx seg;
+      if ((ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (operands[1]))
+	   || MEM_READONLY_P (operands[1]))  /* FIXME: see ia16-no-ss-data.c */
+	  && ! ia16_in_ss_data_function_p ())
+	seg = ia16_data_seg_rtx ();
+      else
+	seg = gen_rtx_REG (SEGmode, SS_REG);
+      ovr1 = ia16_seg_override_term (copy_to_reg (seg));
+    }
+  operands[1] = gen_rtx_MEM (BLKmode, gen_rtx_PLUS (HImode, off1, ovr1));
+  set_mem_addr_space (operands[1], ADDR_SPACE_FAR);
+  operands[10] = off1;
+})
+
+(define_insn "*movmemhi_far_from_far_const_count<pmrm>"
+  [(parallel
+    [(set (mem:BLK (plus:HI (match_operand:HI 0 "register_operand" "D")
+			    (unspec:HI [(match_operand:SEG 1 "register_operand"
+					 "e")] UNSPEC_SEG_OVERRIDE)))
+	  (mem:BLK (plus:HI (match_operand:HI 2 "register_operand" "S")
+			    (unspec:HI [(match_operand:SEG 3 "register_operand"
+					 "Rds")] UNSPEC_SEG_OVERRIDE))))
+     (use (match_operand:HI 4 "const_int_operand" "n"))
+     (use (match_operand:HI 5 "const_int_operand" "n"))
+     (set (match_operand:HI 6 "register_operand" "=&0")
+	  (match_operand:HI 9 ""))
+     (set (match_operand:HI 7 "register_operand" "=&2")
+	  (match_operand:HI 10 ""))
+     (set (match_operand:HI 8 "register_operand" "=&c")
+	  (match_operand:HI 11 ""))
+     (clobber (reg:CC CC_REG))]
+  )]
+  "optimize > 0"
+{
+  if (INTVAL (operands[4]) % 2 == 0)
+    return "movw\t%W4,\t%8\;cld\;rep; movsw";
+  else
+    return "movw\t%W4,\t%8\;cld\;rep; movsw\;movsb";
+})
+
+(define_insn "*movmemhi_far_from_far_nonconst_count<pmrm>"
+  [(parallel
+    [(set (mem:BLK (plus:HI (match_operand:HI 0 "register_operand" "D")
+			    (unspec:HI [(match_operand:SEG 1 "register_operand"
+					 "e")] UNSPEC_SEG_OVERRIDE)))
+	  (mem:BLK (plus:HI (match_operand:HI 2 "register_operand" "S")
+			    (unspec:HI [(match_operand:SEG 3 "register_operand"
+					 "Rds")] UNSPEC_SEG_OVERRIDE))))
+     (use (match_operand:HI 4 "general_operand" "c"))
+     (use (match_operand:HI 5 "const_int_operand" "n"))
+     (set (match_operand:HI 6 "register_operand" "=&0")
+	  (match_operand:HI 9 ""))
+     (set (match_operand:HI 7 "register_operand" "=&2")
+	  (match_operand:HI 10 ""))
+     (set (match_operand:HI 8 "register_operand" "=&4")
+	  (match_operand:HI 11 ""))
+     (clobber (reg:CC CC_REG))]
+  )]
+  ""
+{
+  if (optimize == 0 || optimize_size)
+    return "cld\;rep; movsb";
+  else
+    return "cld\;shrw\t$1,\t%4\;rep; movsw\;rclw\t$1,\t%4\;rep; movsb";
+})
+
+; Various conditional branches.
+(define_expand "cbranch<mode>4"
+  [(set (reg:CC CC_REG)
+	(compare:CC (match_operand:MO 1 "nonimmediate_operand")
+		    (match_operand:MO 2 "general_operand")))
+   (set (pc) (if_then_else
+	       (match_operator 0 "ordered_comparison_operator"
+		[(reg:CC CC_REG) (const_int 0)])
+	       (label_ref (match_operand 3))
+	       (pc)))]
+  ""
+{
+  if (MEM_P (operands[1]) && MEM_P (operands[2]))
+    operands[1] = force_reg (<MODE>mode, operands[1]);
+  ia16_gen_compare_reg (GET_CODE (operands[0]), operands[1], operands[2],
+  		        true);
+})
+
+; Branches using only the carry flag.
+(define_insn "*bcond_carry"
+  [(set (pc)
+	(if_then_else (match_operand 1 "carry_flag_operator")
+		      (label_ref (match_operand 0))
+		      (pc)))]
+  ""
+  "jc\t%l0"
+)
+
+(define_insn "*bcond_carry_not"
+  [(set (pc)
+	(if_then_else (match_operand 1 "carry_not_flag_operator")
+		      (label_ref (match_operand 0))
+		      (pc)))]
+  ""
+  "jnc\t%l0"
+)
+
+; Branches using the zero flag.
+(define_insn "*b<code>_<mode>"
+	[(set (pc)
+	      (if_then_else (any_cond_z (reg:USE_Z CC_REG)
+	                                (const_int 0))
+	                    (label_ref (match_operand 0))
+	                    (pc)))]
+	""
+	"<mnemonic>\t%l0"
+)
+
+; Branches using the carry and zero flags.
+(define_insn "*b<code>_<mode>"
+	[(set (pc)
+	      (if_then_else (any_cond_cz (reg:USE_CZ CC_REG)
+	                                 (const_int 0))
+	                    (label_ref (match_operand 0))
+	                    (pc)))]
+	""
+	"<mnemonic>\t%l0"
+)
+
+; Branches using the sign and overflow flags.
+(define_insn "*b<code>_<mode>"
+	[(set (pc)
+	      (if_then_else (any_cond_so (reg:USE_SO CC_REG)
+	                                 (const_int 0))
+	                    (label_ref (match_operand 0))
+	                    (pc)))]
+	""
+	"<mnemonic>\t%l0"
+)
+
+; Branches using the sign, overflow and zero flags.
+(define_insn "*b<code>_<mode>"
+	[(set (pc)
+	      (if_then_else (any_cond_soz (reg:USE_SOZ CC_REG)
+	                                  (const_int 0))
+	                    (label_ref (match_operand 0))
+	                    (pc)))]
+	""
+	"<mnemonic>\t%l0"
+)
+
+; Branches using only the sign flag.
+(define_insn "*blt_<mode>"
+  [(set (pc)
+	(if_then_else (lt (reg:USE_S CC_REG) (const_int 0))
+		      (label_ref (match_operand 0))
+		      (pc)))]
+  ""
+  "js\t%l0"
+)
+
+(define_insn "*bge_<mode>"
+  [(set (pc)
+	(if_then_else (ge (reg:USE_S CC_REG) (const_int 0))
+		      (label_ref (match_operand 0))
+		      (pc)))]
+  ""
+  "jns\t%l0"
+)
+
+; Docs ("13.11 Interdependence of Patterns") say we should have a reverse-
+; conditional branch for each conditional branch.
+; Branches using only the carry flag.
+(define_insn "*bcond_carry_rev"
+  [(set (pc)
+	(if_then_else (match_operand 1 "carry_flag_operator")
+		      (pc)
+		      (label_ref (match_operand 0))))]
+  ""
+  "jnc\t%l0"
+)
+
+(define_insn "*bcond_carry_not_rev"
+  [(set (pc)
+	(if_then_else (match_operand 1 "carry_not_flag_operator")
+		      (pc)
+		      (label_ref (match_operand 0))))]
+  ""
+  "jc\t%l0"
+)
+
+(define_insn "*b<code>_<mode>_rev"
+	[(set (pc)
+	      (if_then_else (any_cond_z (reg:USE_Z CC_REG)
+	                                (const_int 0))
+	                    (pc)
+	                    (label_ref (match_operand 0))))]
+	""
+	"<mnemonic_rev>\t%l0"
+)
+
+(define_insn "*b<code>_<mode>_rev"
+	[(set (pc)
+	      (if_then_else (any_cond_cz (reg:USE_CZ CC_REG)
+	                                 (const_int 0))
+	                    (pc)
+	                    (label_ref (match_operand 0))))]
+	""
+	"<mnemonic_rev>\t%l0"
+)
+
+(define_insn "*b<code>_<mode>_rev"
+	[(set (pc)
+	      (if_then_else (any_cond_so (reg:USE_SO CC_REG)
+	                                 (const_int 0))
+	                    (pc)
+	                    (label_ref (match_operand 0))))]
+	""
+	"<mnemonic_rev>\t%l0"
+)
+
+(define_insn "*b<code>_<mode>_rev"
+	[(set (pc)
+	      (if_then_else (any_cond_soz (reg:USE_SOZ CC_REG)
+	                                  (const_int 0))
+	                    (pc)
+	                    (label_ref (match_operand 0))))]
+	""
+	"<mnemonic_rev>\t%l0"
+)
+
+; Branches using only the sign flag.
+(define_insn "*blt_<mode>_rev"
+  [(set (pc)
+	(if_then_else (lt (reg:USE_S CC_REG) (const_int 0))
+		      (pc)
+		      (label_ref (match_operand 0))))]
+  ""
+  "jns\t%l0"
+)
+
+(define_insn "*bge_<mode>_rev"
+  [(set (pc)
+	(if_then_else (ge (reg:USE_S CC_REG) (const_int 0))
+		      (pc)
+		      (label_ref (match_operand 0))))]
+  ""
+  "js\t%l0"
+)
+
+; FIXME This instruction can only jump [-128;127] bytes. GAS doesn't work
+; around it.
+(define_insn "*jump_if_cx_zero"
+  [(set (pc)
+	(if_then_else (eq (match_operand:HI 0 "single_register_operand" "c")
+			  (const_int 0))
+		      (label_ref (match_operand 1))
+		      (pc)))]
+  "TARGET_SHORT_JUMPS"
+  "jcxz\t%l1"
+)
+
+(define_insn_and_split "*load_cx_jump_if_zero"
+  [(set (pc)
+	(if_then_else (eq (match_operand:HI 2 "general_operand" "g")
+			  (const_int 0))
+		      (label_ref (match_operand 1))
+		      (pc)))
+   (set (match_operand:HI 0 "single_register_operand" "=c") (match_dup 2))]
+  "TARGET_SHORT_JUMPS"
+  "#"
+  "reload_completed"
+  [(set (match_dup 0) (match_dup 2))
+   (set (pc)
+	(if_then_else (eq (match_dup 0) (const_int 0))
+		      (label_ref (match_dup 1))
+		      (pc)))]
+)
+
+(define_insn "jump"
+	[(set (pc) (label_ref (match_operand 0 "")))]
+	""
+	"jmp\t%l0"
+)
+
+; This is made needlessly complicated by a combination of inconsistent use of
+; (mem x) expressions and an inconsistent assembler syntax. Basicly, there is
+; an extra (mem x) around the function address.
+(define_expand "call"
+  [(call (match_operand:QI 0 "")
+	 (match_operand:HI  1 "general_operand"))]
+  ""
+{
+  ia16_expand_reset_ds_for_call (XEXP (operands[0], 0));
+})
+
+(define_expand "call_pop"
+  [(parallel
+    [(call (match_operand:QI 0 "")
+	   (match_operand:HI 1 "general_operand"))
+     (set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG) (match_operand:HI 3)))]
+  )]
+  ""
+{
+  ia16_expand_reset_ds_for_call (XEXP (operands[0], 0));
+})
+
+(define_expand "sibcall"
+  [(call (match_operand:QI 0 "")
+  	 (match_operand:HI 1 "general_operand"))]
+  ""
+{
+  ia16_expand_reset_ds_for_call (XEXP (operands[0], 0));
+})
+
+(define_insn "*call"
+	[(call (mem:QI (match_operand:FNP 0 "general_operand" "<p>"))
+	       (match_operand:HI  1 "general_operand" "g"))]
+	"!SIBLING_CALL_P (insn)
+	 && ! ia16_use_far_thunked_call_p (operands[0], <MODE>mode)"
+{
+  return ia16_get_call_expansion (operands[0], <MODE>mode, 0);
+})
+
+(define_insn "*call_far_thunked"
+	[(call (mem:QI (match_operand:HI 0 "general_operand" "b"))
+	       (match_operand:HI 1 "general_operand" "x"))]
+	"!SIBLING_CALL_P (insn)
+	 && ia16_use_far_thunked_call_p (operands[0], HImode)"
+{
+  return ia16_get_far_thunked_call_expansion (0, false);
+})
+
+(define_insn "*call_pop"
+	[(parallel
+	  [(call (mem:QI (match_operand:FNP 0 "general_operand" "<p>"))
+	         (match_operand:HI 1 "general_operand" "g"))
+	   (set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG)
+					 (match_operand:HI 2)))]
+	)]
+	"!SIBLING_CALL_P (insn)
+	 && ! ia16_use_far_thunked_call_p (operands[0], <MODE>mode)"
+{
+  return ia16_get_call_expansion (operands[0], <MODE>mode, 0);
+})
+
+(define_insn "*call_pop_far_thunked"
+	[(parallel
+	  [(call (mem:QI (match_operand:HI 0 "general_operand" "b,b"))
+	         (match_operand:HI 1 "general_operand" "x,x"))
+	   (set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG)
+					 (match_operand:HI 2 "general_operand"
+							     "0,x")))]
+	)]
+	"!SIBLING_CALL_P (insn)
+	 && ia16_use_far_thunked_call_p (operands[0], HImode)"
+{
+  return ia16_get_far_thunked_call_expansion (0, true);
+})
+
+(define_insn "*sibcall"
+        [(call (mem:QI (match_operand:FNP 0 "general_operand" "<p>"))
+               (match_operand:HI  1 "general_operand" "g"))]
+        "SIBLING_CALL_P (insn)"
+{
+  return ia16_get_sibcall_expansion (operands[0], <MODE>mode, 0);
+})
+
+(define_insn "*sibcall_pop"
+	[(parallel
+	  [(call (mem:QI (match_operand:FNP 0 "general_operand" "<p>"))
+	         (match_operand:HI  1 "general_operand" "g"))
+	   (set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG)
+					 (match_operand:HI 2)))]
+	)]
+	"SIBLING_CALL_P (insn)"
+{
+  return ia16_get_sibcall_expansion (operands[0], <MODE>mode, 0);
+})
+
+(define_expand "call_value"
+  [(set (match_operand 0 "")
+	(call (match_operand:QI 1 "")
+	      (match_operand:HI 2 "general_operand")))]
+  ""
+{
+  ia16_expand_reset_ds_for_call (XEXP (operands[1], 0));
+})
+
+(define_expand "call_value_pop"
+  [(parallel
+    [(set (match_operand 0 "")
+	  (call (match_operand:QI 1 "")
+		(match_operand:HI 2 "general_operand")))
+	  (set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG)
+					(match_operand:HI 4)))]
+  )]
+  ""
+{
+  ia16_expand_reset_ds_for_call (XEXP (operands[1], 0));
+})
+
+(define_expand "sibcall_value"
+  [(set (match_operand 0 "")
+        (call (match_operand:QI 1 "")
+              (match_operand:HI  2 "general_operand")))]
+  ""
+{
+  ia16_expand_reset_ds_for_call (XEXP (operands[1], 0));
+})
+
+(define_insn "*call_value"
+	[(set (match_operand 0 "register_operand" "=r")
+	      (call (mem:QI (match_operand:FNP 1 "general_operand" "<p>"))
+	            (match_operand:HI  2 "general_operand" "g")))]
+	"!SIBLING_CALL_P (insn)
+	 && ! ia16_use_far_thunked_call_p (operands[1], <MODE>mode)"
+{
+  return ia16_get_call_expansion (operands[1], <MODE>mode, 1);
+})
+
+(define_insn "*call_value_far_thunked"
+	[(set (match_operand 0 "register_operand" "=r")
+	      (call (mem:QI (match_operand:HI 1 "general_operand" "b"))
+	            (match_operand:HI  2 "general_operand" "x")))]
+	"!SIBLING_CALL_P (insn)
+	 && ia16_use_far_thunked_call_p (operands[1], HImode)"
+{
+  return ia16_get_far_thunked_call_expansion (1, false);
+})
+
+(define_insn "*call_value_pop"
+	[(parallel
+	  [(set (match_operand 0 "register_operand" "=r")
+		(call (mem:QI (match_operand:FNP 1 "general_operand" "<p>"))
+		      (match_operand:HI  2 "general_operand" "g")))
+	   (set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG)
+					 (match_operand:HI 3)))]
+	)]
+	"!SIBLING_CALL_P (insn)
+	 && ! ia16_use_far_thunked_call_p (operands[1], <MODE>mode)"
+{
+  return ia16_get_call_expansion (operands[1], <MODE>mode, 1);
+})
+
+(define_insn "*call_value_pop_far_thunked"
+	[(parallel
+	  [(set (match_operand 0 "register_operand" "=r,r")
+		(call (mem:QI (match_operand:HI 1 "general_operand" "b,b"))
+		      (match_operand:HI  2 "general_operand" "x,x")))
+	   (set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG)
+					 (match_operand:HI 3 "general_operand"
+							     "0,x")))]
+	)]
+	"!SIBLING_CALL_P (insn)
+	 && ia16_use_far_thunked_call_p (operands[1], HImode)"
+{
+  return ia16_get_far_thunked_call_expansion (1, true);
+})
+
+(define_insn "*sibcall_value"
+        [(set (match_operand 0 "register_operand" "=r")
+              (call (mem:QI (match_operand:FNP 1 "general_operand" "<p>"))
+                    (match_operand:HI  2 "general_operand" "g")))]
+        "SIBLING_CALL_P (insn)"
+{
+  return ia16_get_sibcall_expansion (operands[1], <MODE>mode, 1);
+})
+
+(define_insn "*sibcall_value_pop"
+	[(parallel
+	  [(set (match_operand 0 "register_operand" "=r")
+		(call (mem:QI (match_operand:FNP 1 "general_operand" "<p>"))
+		      (match_operand:HI  2 "general_operand" "g")))
+	   (set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG)
+					 (match_operand:HI 3)))]
+	)]
+	"SIBLING_CALL_P (insn)"
+{
+  return ia16_get_sibcall_expansion (operands[1], <MODE>mode, 1);
+})
+
+(define_insn "nop"
+	[(const_int 0)]
+	""
+	"nop"
+)
+
+(define_insn "indirect_jump"
+	[(set (pc) (match_operand:HI 0 "nonimmediate_operand" "rm"))]
+	""
+	"jmp\t*%0"
+)
+
+(define_insn "tablejump"
+  [(set (pc) (match_operand:HI 0 "nonimmediate_operand" "rm"))
+   (use (label_ref (match_operand 1)))]
+  ""
+  "jmp\t*%0"
+)
+
+; Taken almost verbatim from the GCC Internals manual.
+; FIXME Manual says "general_operand" which is invalid.
+; FIXME This instruction can only jump [-128;127] bytes. GAS doesn't work around it.
+(define_insn "decrement_and_branch_until_zero"
+	[(set (pc)
+	 (if_then_else
+	   (ge (plus:HI (match_operand:HI 0 "nonimmediate_operand" "+c*rm")
+	                (const_int -1))
+	       (const_int 0))
+	   (label_ref (match_operand 1 ""))
+	   (pc)))
+	 (set (match_dup 0)
+	      (plus:HI (match_dup 0)
+	               (const_int -1)))]
+	"TARGET_SHORT_JUMPS"
+	"loop\t%c1"
+)
+
+; Keep ia16_initial_frame_pointer_offset() in sync whith this pattern.
+; Keep ia16_first_parm_offset() in sync with this pattern.
+(define_expand "prologue"
+  [(const_int 1)]
+  ""
+  "ia16_expand_prologue (); DONE;")
+
+(define_insn "_enter"
+	[(set (mem:HI (plus:HI (reg:HI SP_REG) (const_int -2)))
+	      (reg:HI BP_REG))
+	 (set (reg:HI BP_REG) (reg:HI SP_REG))
+	 (set (reg:HI SP_REG)
+	      (minus:HI (reg:HI SP_REG)
+	                (match_operand:HI 0 "immediate_operand" "i")))]
+	"TARGET_ENTER_LEAVE"
+	"enterw\t%0-2,\t$0"
+)
+
+(define_expand "epilogue"
+  [(const_int 0)]
+  ""
+  "ia16_expand_epilogue (false); DONE;")
+
+(define_expand "sibcall_epilogue"
+  [(const_int 0)]
+  ""
+  "ia16_expand_epilogue (true); DONE;")
+
+(define_insn "_leave"
+	[(set (reg:HI SP_REG) (plus:HI (reg:HI BP_REG) (const_int 2)))
+	 (set (reg:HI BP_REG) (mem:HI (reg:HI BP_REG)))]
+	"TARGET_ENTER_LEAVE"
+	"leavew"
+)
+
+(define_expand "simple_return"
+  [(return)]
+  "reload_completed"
+{
+  int pops = crtl->args.pops_args;
+  ia16_expand_reset_ds_for_return ();
+  if (pops)
+    {
+      emit_jump_insn (gen__simple_return_with_pops (GEN_INT (pops)));
+      DONE;
+    }
+})
+
+(define_insn "*simple_return"
+  [(return)]
+  "reload_completed"
+{
+  if (ia16_in_far_function_p ())
+    return "lret";
+  else
+    return "ret";
+})
+
+(define_insn "_simple_return_with_pops"
+  [(return)
+   (use (match_operand:HI 0 "const_int_operand"))]
+  "reload_completed"
+{
+  if (ia16_in_far_function_p ())
+    return "lret\t%0";
+  else
+    return "ret\t%0";
+})
+
+(define_insn "sync_lock_test_and_set<mode>"
+	[(set (match_operand:MO 0 "register_operand" "=<r>")
+	      (match_operand:MO 1 "memory_operand" "+m"))
+	 (set (match_dup 1) (match_operand:MO 2 "nonmemory_operand" "0"))]
+	""
+	"lock\;xchg<s>\t%0,\t%1"
+)
+
+;; Far addressing support.
+(define_expand "seg_override<pmrm>"
+  [(unspec:HI [(match_operand:SEG 0 "" "")] UNSPEC_SEG_OVERRIDE)]
+  ""
+  ""
+)
+
+(define_expand "seg16_reloc<pmrm>"
+  [(unspec:SEG [(match_operand:HI 0 "" "")] UNSPEC_OZSEG16)]
+  ""
+  ""
+)
+
+(define_insn "*mov<mode>_seg16<pmrm>"
+  [(set (match_operand:SEG 0 "register_operand" "=r")
+	(unspec:SEG [(match_operand:HI 1 "" "")] UNSPEC_OZSEG16))]
+  ""
+{
+  if (TARGET_ABI_SEGELF)
+    return "movw\t$%Z1@SEG,\t%0";
+  else
+    return "movw\t%1@OZSEG16,\t%0";
+})
+
+(define_insn "*movhi_seg16_via_paradoxical"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+	(subreg:HI (unspec:PHI [(match_operand:HI 1 "" "")] UNSPEC_OZSEG16)
+		   0))]
+  ""
+{
+  if (TARGET_ABI_SEGELF)
+    return "movw\t$%Z1@SEG,\t%0";
+  else
+    return "movw\t%1@OZSEG16,\t%0";
+})
+
+(define_expand "static_far_ptr"
+  [(const:SI (unspec:SI [(match_operand:HI 0 "" "")] UNSPEC_STATIC_FAR_PTR))]
+  ""
+  ""
+)
+
+;; Protected mode support (experimental, continued).
+(define_insn "trunchiphi2"
+  [(set (match_operand:PHI 0 "nonimmediate_operand" "=T,rm,Q,!Q")
+	(truncate:PHI (match_operand:HI 1 "nonimmediate_operand"
+					  "rm,Ti,0,Q")))]
+  ""
+  "@
+   movw\t%1,\t%0
+   movw\t%1,\t%0
+   #
+   pushw\t%1\;popw\t%0")
+
+(define_insn "extendphihi2"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=r,rm")
+	(sign_extend:HI (match_operand:PHI 1 "general_operand" "rm,Ti")))]
+  ""
+{
+  if (REG_P (operands[0]) && REG_P (operands[1])
+      && REGNO(operands[0]) == REGNO (operands[1]))
+    return "";
+  else
+    return "movw\t%1,\t%0";
+})
+
+(define_insn "zero_extendphihi2"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=r,rm")
+	(zero_extend:HI (match_operand:PHI 1 "general_operand" "rm,Ti")))]
+  ""
+{
+  if (REG_P (operands[0]) && REG_P (operands[1])
+      && REGNO(operands[0]) == REGNO (operands[1]))
+    return "";
+  else
+    return "movw\t%1,\t%0";
+})
+
+(define_expand "_pushphi1_prologue"
+  [(parallel
+  [(set (match_dup 1) (match_operand:PHI 0 "general_operand"))
+   (set (reg:HI SP_REG) (plus:HI (reg:HI SP_REG) (const_int -2)))]
+  )]
+  ""
+{
+  operands[1] = gen_frame_mem (PHImode,
+			       plus_constant (Pmode, stack_pointer_rtx, -2));
+})
diff --git a/gcc/config/ia16/ia16.opt b/gcc/config/ia16/ia16.opt
new file mode 100644
index 0000000..eab8e4e
--- /dev/null
+++ b/gcc/config/ia16/ia16.opt
@@ -0,0 +1,214 @@
+march=any
+Target RejectNegative Var(target_arch,PROCESSOR_ANY) Init(PROCESSOR_ANY)
+Produce code that works on any CPU, with generic tuning options (default).
+
+march=any_186
+Target RejectNegative Var(target_arch,PROCESSOR_ANY_186)
+Use features available on both Intel 80186 and NEC V20 or better.
+
+march=i8086
+Target RejectNegative Var(target_arch,PROCESSOR_I8086)
+Use features of and optimize code for the Intel 8086.
+
+march=i8088
+Target RejectNegative Var(target_arch,PROCESSOR_I8088)
+Use features of and optimize code for the Intel 8088.
+
+march=v30
+Target RejectNegative Var(target_arch,PROCESSOR_NEC_V30)
+Use features of and optimize code for the NEC V30.
+
+march=v20
+Target RejectNegative Var(target_arch,PROCESSOR_NEC_V20)
+Use features of and optimize code for the NEC V20.
+
+march=i80186
+Target RejectNegative Var(target_arch,PROCESSOR_I80186)
+Use features of and optimize code for the Intel 80186.
+
+march=i186
+Target RejectNegative Alias(march=i80186)
+Use features of and optimize code for the Intel 80186.
+
+march=i80188
+Target RejectNegative Var(target_arch,PROCESSOR_I80188)
+Use features of and optimize code for the Intel 80188.
+
+march=i188
+Target RejectNegative Alias(march=i80188)
+Use features of and optimize code for the Intel 80188.
+
+march=i80286
+Target RejectNegative Var(target_arch,PROCESSOR_I80286)
+Use features of and optimize code for the Intel 80286.
+
+march=i286
+Target RejectNegative Alias(march=i80286)
+Use features of and optimize code for the Intel 80286.
+
+mtune=i8086
+Target RejectNegative Var(target_tune,PROCESSOR_I8086) Init(PROCESSOR_ANY)
+Optimize code for the Intel 8086.
+
+mtune=i8088
+Target RejectNegative Var(target_tune,PROCESSOR_I8088)
+Optimize code for the Intel 8088.
+
+mtune=v30
+Target RejectNegative Var(target_tune,PROCESSOR_NEC_V30)
+Optimize code for the NEC V30.
+
+mtune=v20
+Target RejectNegative Var(target_tune,PROCESSOR_NEC_V20)
+Optimize code for the NEC V20.
+
+mtune=i80186
+Target RejectNegative Var(target_tune,PROCESSOR_I80186)
+Optimize code for the Intel 80186.
+
+mtune=i186
+Target RejectNegative Alias(mtune=i80186)
+Optimize code for the Intel 80186.
+
+mtune=i80188
+Target RejectNegative Var(target_tune,PROCESSOR_I80188)
+Optimize code for the Intel 80188.
+
+mtune=i188
+Target RejectNegative Alias(mtune=i80188)
+Optimize code for the Intel 80188.
+
+mtune=i80286
+Target RejectNegative Var(target_tune,PROCESSOR_I80286)
+Optimize code for the Intel 80286.
+
+mtune=i286
+Target RejectNegative Alias(mtune=i80286)
+Optimize code for the Intel 80286.
+
+mshort-jumps
+Target Mask(SHORT_JUMPS)
+Do (not - this is the default) use jump instructions which can only jump -128/+127 bytes.
+
+; This is now equivalent to -mcmodel=small (below) unless a memory model is
+; explicitly specified.
+mseparate-code-segment
+Target RejectNegative Undocumented
+
+mcmodel=tiny
+Target RejectNegative Var(target_cmodel,CMODEL_TINY) Init(CMODEL_TINY)
+Generate code for the tiny code model (default), with one combined data and text segment.
+
+; For the compiler back-end, -mcmodel=small in contrast to -mcmodel=tiny is
+; mainly just about having separate code and data address spaces.  Most of
+; the work for implementing the small model happens at the linking stage.
+;
+; With the help of elf.h, this option also enables -msegment-relocation-stuff.
+mcmodel=small
+Target RejectNegative Var(target_cmodel,CMODEL_SMALL)
+Generate code for the small code model, with one data and one text segment.
+
+; With the help of elf.h, this option also enables -msegment-relocation-stuff.
+mcmodel=medium
+Target RejectNegative Var(target_cmodel,CMODEL_MEDIUM)
+Generate code for the medium code model, with one data segment and multiple text segments.
+
+msegment-relocation-stuff
+Target RejectNegative Mask(SEG_RELOC_STUFF) Undocumented
+
+mno-segment-relocation-stuff
+Target RejectNegative InverseMask(SEG_RELOC_STUFF)
+Disable language features which use segment relocations.
+
+mcdecl
+Target RejectNegative Report Var(target_call_parm_cvt,CALL_PARM_CVT_CDECL) Init(CALL_PARM_CVT_CDECL) Undocumented
+
+mrtd
+Target RejectNegative Report Var(target_call_parm_cvt,CALL_PARM_CVT_STDCALL)
+Alternate calling convention (callee pops arguments).
+
+mstdcall
+Target RejectNegative Alias(mrtd) Undocumented
+
+mregparmcall
+Target RejectNegative Report Var(target_call_parm_cvt,CALL_PARM_CVT_REGPARMCALL)
+Alternate calling convention (some arguments in registers; callee pops rest).
+
+mno-callee-assume-ds-data-segment
+Target RejectNegative Report Mask(NO_ASSUME_DS_DATA)
+Alternate calling convention (callee cannot assume %ds points to program's data segment on entry).
+
+mcallee-assume-ds-data-segment
+Target RejectNegative InverseMask(NO_ASSUME_DS_DATA, ASSUME_DS_DATA) Undocumented
+
+; Older name.
+mcallee-assume-ds-ss
+Target Alias(mcallee-assume-ds-data-segment) Undocumented
+
+; Older name.
+mcallee-assume-ds-data-space
+Target Alias(mcallee-assume-ds-data-segment) Undocumented
+
+mno-callee-assume-ss-data-segment
+Target RejectNegative Report Mask(NO_ASSUME_SS_DATA)
+Alternate (experimental) calling convention (callee cannot assume %ss points to program's data segment on entry).
+
+mcallee-assume-ss-data-segment
+Target RejectNegative InverseMask(NO_ASSUME_SS_DATA, ASSUME_SS_DATA) Undocumented
+
+mno-far-function-if-far-return-type
+Target RejectNegative Report Mask(NO_FAR_FUNCTION_IF_FAR_RETURN_TYPE)
+Do not treat a function as __far even if it has a __far return type.
+
+mfar-function-if-far-return-type
+Target RejectNegative InverseMask(NO_FAR_FUNCTION_IF_FAR_RETURN_TYPE, FAR_FUNCTION_IF_FAR_RETURN_TYPE) Undocumented
+
+mprotected-mode
+Target Report Mask(PROTECTED_MODE)
+Try to produce code suitable for running in protected mode.
+
+; With the help of elf.h, this also enables -mprotected-mode.
+melks-libc
+Target Report RejectNegative Mask(SYS_ELKS)
+Generate executables for ELKS OS, and link with elks-libc.
+
+melks
+Target Alias(melks-libc) Undocumented
+
+mmsdos
+Target Report RejectNegative InverseMask(SYS_ELKS, SYS_MSDOS)
+Generate executables for MS-DOS (default).
+
+mmsdos-handle-v1
+Target Report RejectNegative InverseMask(SYS_ELKS, SYS_MSDOS)
+Generate MS-DOS executables which fail gracefully on DOS v1.x.
+
+; With the help of elf.h, this also enables -mprotected-mode.
+mdpmiable
+Target Report Mask(DPMIABLE)
+Generate MS-DOS executables which use DPMI if present (experimental).
+
+msegelf
+Target Report Mask(ABI_SEGELF)
+Use H. Peter Anvin's proposed 16-bit segmented code ABI (experimental).
+
+mnewlib-nano-stdio
+Target Mask(NEWLIB_NANO_STDIO)
+Link with Newlib's limited formatted I/O routines (experimental).
+
+mnewlib-autofloat-stdio
+Target Mask(NEWLIB_AUTOFLOAT_STDIO)
+Automatically decide between floating-point and non-fp formatted I/O routines (experimental).
+
+; This is currently a no-op option.  It may come in useful if and when ELKS
+; supports more than one executable format.
+maout
+Target RejectNegative Undocumented
+
+maout-total=
+Target RejectNegative Joined UInteger
+Set the top of the data segment for ELKS OS executables.
+
+maout-chmem=
+Target RejectNegative Joined UInteger
+Set the size of non-static data for ELKS OS executables.
diff --git a/gcc/config/ia16/predicates.md b/gcc/config/ia16/predicates.md
new file mode 100644
index 0000000..5e397f4
--- /dev/null
+++ b/gcc/config/ia16/predicates.md
@@ -0,0 +1,192 @@
+;  Predicate definitions for Intel 16-bit x86.
+;  Copyright (C) 2006-2017 Free Software Foundation, Inc.
+;  Contributed by Rask Ingemann Lambertsen <rask@sygehus.dk>
+;  Changes by Andrew Jenner <andrew@codesourcery.com>
+;
+;  This file is part of GCC.
+;
+;  GCC 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 3 of the License, or (at your option) any
+;  later version.
+;
+;  GCC 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/licenses/>.
+
+; Allow anything else than a register_operand.
+(define_predicate "nonregister_operand"
+   (ior (match_operand 0 "immediate_operand")
+	(match_operand 0 "memory_operand"))
+)
+
+(define_predicate "general_or_concat_operand"
+   (ior (match_operand 0 "general_operand")
+	(match_code "concat"))
+)
+
+; This is like "register_operand", but subregs of multiword registers are not
+; allowed. This is to prevent the combiner from re-inserting such subregs
+; into the insn.
+(define_predicate "single_register_operand"
+   (and (match_operand 0 "register_operand")
+	(ior (not (match_code "subreg"))
+	     (match_test "GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))) <= UNITS_PER_WORD")))
+)
+
+; This is like "nonmemory_operand", but subregs of multiword registers are
+; not allowed. This is to prevent the combiner from re-inserting such subregs
+; into the insn.
+(define_predicate "single_nonmemory_operand"
+   (and (match_operand 0 "nonmemory_operand")
+	(ior (not (match_code "subreg"))
+	     (match_test "GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))) <= UNITS_PER_WORD")))
+)
+
+; Like "nonimmediate_operand" except that 0 is allowed.
+; This needs to be a special predicate to match const0_rtx.
+(define_special_predicate "nonimmediate_or_0_operand"
+   (ior (match_operand 0 "nonimmediate_operand")
+	(and (match_code "const_int,const_vector")
+	     (match_test "op == CONST0_RTX (mode)")))
+)
+
+(define_predicate "segment_register_operand"
+   (and (match_code "reg")
+	(match_test "ia16_regno_in_class_p (REGNO (op), SEGMENT_REGS)"))
+)
+
+(define_predicate "nonsegment_register_operand"
+   (and (match_code "reg")
+	(match_test "! ia16_regno_in_class_p (REGNO (op), SEGMENT_REGS)"))
+)
+
+(define_predicate "accumulator_register_operand"
+   (and (match_code "reg")
+	(match_test "REGNO (op) == A_REG"))
+)
+
+; Register usable in a 1-byte `xchgw (reg), %ax' instruction.
+;(define_predicate "xchgw_ax_register_operand"
+;   (and (match_operand 0 "nonsegment_register_operand")
+;	(match_test "REGNO (op) != A_REG"))
+;)
+
+; For rewriting `incb %al' as `incw %ax', etc.
+;(define_predicate "lo_qi_register_operand"
+;   (and (match_code "reg")
+;	(match_test "ia16_regno_in_class_p (REGNO (op), LO_QI_REGS)"))
+;)
+
+(define_predicate "nonimmediate_nonsegment_operand"
+    (and (match_operand 0 "nonimmediate_operand")
+	 (ior (match_operand 0 "nonregister_operand")
+	      (match_operand 0 "nonsegment_register_operand")))
+)
+
+; Match the memory operand of an xlat instruction (to be split before reload).
+; Combine creates this in a number of ways.
+; TODO: Make ia16_xlat_cost() use this predicate to reduce code duplication.
+(define_predicate "xlat_memory_operand"
+; They all have the form (mem:QI (plus:HI (...) (reg/const:HI))).
+  (and
+    (match_code "mem")
+    (match_code "plus" "0")
+    (match_code "reg,const_int,symbol_ref,label_ref" "01")
+    (ior
+; Match (zero_extend:HI (reg/mem/const:QI)).
+      (and
+	(match_code "zero_extend" "00")
+	(match_code "reg,subreg,mem,const_int,symbol_ref,label_ref" "000")
+	(match_test "GET_MODE (XEXP (XEXP (XEXP (op, 0), 0), 0)) == QImode")
+      )
+; Match (zero_extract:HI (reg/mem/const) (const_int 8) (const_int n*8))
+; This needs a patch to simplify_rtx().
+      (and
+	(match_code "zero_extract" "00")
+	(match_code "reg,subreg,mem,const_int,symbol_ref,label_ref" "000")
+	(match_code "const_int" "001")
+	(match_code "const_int" "002")
+	(match_test "INTVAL (XEXP (XEXP (XEXP (op, 0), 0), 1)) == 8")
+	(match_test "INTVAL (XEXP (XEXP (XEXP (op, 0), 0), 2)) % 8 == 0")
+      )
+; Match (subreg:HI (zero_extract (reg/mem/const) (const_int 8) (const_int n*8))
+;	 0)
+      (and
+	(match_code "subreg" "00")
+	(match_code "zero_extract" "000")
+	(match_code "reg,subreg,mem,const_int,symbol_ref,label_ref" "0000")
+	(match_code "const_int" "0001")
+	(match_code "const_int" "0002")
+	(match_test "INTVAL (XEXP (XEXP (XEXP (XEXP (op, 0), 0), 0), 1)) == 8")
+	(match_test "INTVAL (XEXP (XEXP (XEXP (XEXP (op, 0), 0), 0), 2)) % 8 == 0")
+	(match_test "GET_MODE (XEXP (XEXP (XEXP (op, 0), 0), 0)) != QImode")
+      )
+; Match (and:HI (subreg (lshiftrt (reg/mem/const) (const_int n*8)) 0)
+;		(const_int 255))
+      (and
+	(match_code "and" "00")
+	(match_code "subreg" "000")
+	(match_code "const_int" "001")
+	(match_code "lshiftrt" "0000")
+	(match_code "reg,subreg,mem,const_int,symbol_ref,label_ref" "00000")
+	(match_code "const_int" "00001")
+	(match_test "INTVAL (XEXP (XEXP (XEXP (op, 0), 0), 1)) == 255")
+	(match_test "INTVAL (XEXP (XEXP (XEXP (XEXP (XEXP (op, 0), 0), 0), 0), 1)) % 8 == 0")
+      )
+    )
+    (match_test "GET_MODE (XEXP (op, 0)) == HImode")
+    (match_test "GET_MODE (XEXP (XEXP (op, 0), 0)) == HImode")
+    (match_test "GET_MODE (XEXP (XEXP (op, 0), 1)) == HImode")
+  )
+)
+
+; Match an operator which is true if the carry flag is set.
+(define_predicate "carry_flag_operator"
+   (and (ior
+	   (and (match_code "ltu")
+		(match_test "ia16_cc_modes_compatible (CCCmode, GET_MODE (XEXP (op, 0))) == GET_MODE (XEXP (op, 0))"))
+	   (and (match_code "leu")
+		(match_test "GET_MODE (XEXP (op, 0)) == CCCZ_Cmode"))
+	   (and (match_code "gtu")
+		(match_test "GET_MODE (XEXP (op, 0)) == CCCZ_NCmode"))
+	   (and (match_code "eq")
+		(match_test "GET_MODE (XEXP (op, 0)) == CCZ_Cmode"))
+	   (and (match_code "ne")
+		(match_test "GET_MODE (XEXP (op, 0)) == CCZ_NCmode"))
+	   (and (match_code "ge")
+		(match_test "GET_MODE (XEXP (op, 0)) == CCS_NCmode"))
+	)
+	(match_code "reg" "0")
+	(match_code "const_int" "1")
+	(match_test "REGNO (XEXP (op, 0)) == CC_REG")
+	(match_test "XEXP (op, 1) == const0_rtx")
+   )
+)
+
+; Match an operator which is true if the carry flag is not set.
+(define_predicate "carry_not_flag_operator"
+   (and (ior
+	   (and (match_code "geu")
+		(match_test "ia16_cc_modes_compatible (CCCmode, GET_MODE (XEXP (op, 0))) == GET_MODE (XEXP (op, 0))"))
+	   (and (match_code "gtu")
+		(match_test "GET_MODE (XEXP (op, 0)) == CCCZ_Cmode"))
+	   (and (match_code "leu")
+		(match_test "GET_MODE (XEXP (op, 0)) == CCCZ_NCmode"))
+	   (and (match_code "ne")
+		(match_test "GET_MODE (XEXP (op, 0)) == CCZ_Cmode"))
+	   (and (match_code "eq")
+		(match_test "GET_MODE (XEXP (op, 0)) == CCZ_NCmode"))
+	   (and (match_code "lt")
+		(match_test "GET_MODE (XEXP (op, 0)) == CCS_NCmode"))
+	)
+	(match_code "reg" "0")
+	(match_code "const_int" "1")
+	(match_test "REGNO (XEXP (op, 0)) == CC_REG")
+	(match_test "XEXP (op, 1) == const0_rtx")
+   )
+)
diff --git a/gcc/config/ia16/t-ia16 b/gcc/config/ia16/t-ia16
new file mode 100644
index 0000000..900ac9c
--- /dev/null
+++ b/gcc/config/ia16/t-ia16
@@ -0,0 +1,122 @@
+# 16.1 Target Makefile Fragments
+
+# Build ia16-c.o.  Also take the opportunity to check for any previously
+# installed obsolete multilibs, which should really be cleaned away.
+#	-- tkchia
+#
+ia16-c.o: $(srcdir)/config/ia16/ia16-c.c $(RTL_H) $(TREE_H) $(CONFIG_H) \
+  $(TM_H) $(GTFILES_H)
+	@if test \
+	     -e "$(prefix)"/ia16-elf/lib/i80286 \
+	  -o -e "$(prefix)"/lib/gcc/ia16-elf/$(BASEVER_c)/i80286 \
+	  -o -e "$(prefix)"/ia16-elf/include/c++/$(BASEVER_c)/ia16-elf/i80286 \
+	  -o -e "$(prefix)"/ia16-elf/lib/any_186 \
+	  -o -e "$(prefix)"/lib/gcc/ia16-elf/$(BASEVER_c)/any_186 \
+	  -o -e "$(prefix)"/ia16-elf/include/c++/$(BASEVER_c)/ia16-elf/any_186\
+	  -o -e "$(prefix)"/ia16-elf/lib/wide-types \
+	  -o -e "$(prefix)"/lib/gcc/ia16-elf/$(BASEVER_c)/wide-types \
+	  -o -e \
+	     "$(prefix)"/ia16-elf/include/c++/$(BASEVER_c)/ia16-elf/wide-types\
+	  -o -e "$(prefix)"/ia16-elf/lib/frame-pointer \
+	  -o -e "$(prefix)"/lib/gcc/ia16-elf/$(BASEVER_c)/frame-pointer \
+	  -o -e \
+	  "$(prefix)"/ia16-elf/include/c++/$(BASEVER_c)/ia16-elf/frame-pointer\
+	  -o -e "$(prefix)"/ia16-elf/lib/rtd/elkslibc \
+	  -o -e "$(prefix)"/ia16-elf/lib/regparmcall/elkslibc; \
+	then \
+	  exec >&2 2>/dev/null; \
+	  echo; \
+	  echo '*** multilib settings have changed, please rebuild! ***'; \
+	  echo 'Please clean up the installation directory, and rebuild'; \
+	  echo 'gcc-ia16 (and libstdc++, and newlib) from start.'; \
+	  echo 'To do this using build-ia16:'; \
+	  echo '  $$ cd ....../build-ia16'; \
+	  echo '  $$ git pull'; \
+	  echo '  $$ ./build.sh gcc1 newlib gcc2'; \
+	  echo 'Alternatively, manually remove the following directories:'; \
+	  find "$(prefix)"/ia16-elf/lib -name i80286 -ls; \
+	  find "$(prefix)"/lib/gcc/ia16-elf -name i80286 -ls; \
+	  find "$(prefix)"/ia16-elf/include -name i80286 -ls; \
+	  find "$(prefix)"/ia16-elf/lib -name any_186 -ls; \
+	  find "$(prefix)"/lib/gcc/ia16-elf -name any_186 -ls; \
+	  find "$(prefix)"/ia16-elf/include -name any_186 -ls; \
+	  find "$(prefix)"/ia16-elf/lib -name wide-types -ls; \
+	  find "$(prefix)"/lib/gcc/ia16-elf -name wide-types -ls; \
+	  find "$(prefix)"/ia16-elf/include -name wide-types -ls; \
+	  find "$(prefix)"/ia16-elf/lib -name frame-pointer -ls; \
+	  find "$(prefix)"/lib/gcc/ia16-elf -name frame-pointer -ls; \
+	  find "$(prefix)"/ia16-elf/include -name frame-pointer -ls; \
+	  find "$(prefix)"/ia16-elf/lib -name elkslibc -ls; \
+	  echo 'and arrange to rebuild GCC.'; \
+	  echo; \
+	  exit 1; \
+	fi
+	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<
+
+ia16-builtins.o: $(srcdir)/config/ia16/ia16-builtins.c \
+  $(RTL_H) $(TREE_H) $(CONFIG_H) $(TM_H) $(GTFILES_H)
+	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<
+
+ia16-reorg.o: $(srcdir)/config/ia16/ia16-reorg.c \
+  $(RTL_H) $(TREE_H) $(CONFIG_H) $(TM_H) $(GTFILES_H)
+	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<
+
+ia16-no-ss-data.o: $(srcdir)/config/ia16/ia16-no-ss-data.c \
+  $(RTL_H) $(TREE_H) $(CONFIG_H) $(TM_H) $(GTFILES_H)
+	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<
+
+MULTILIB_OPTIONS=mprotected-mode melks-libc \
+	mcmodel=medium mrtd/mregparmcall march=any_186 Os
+MULTILIB_DIRNAMES=pmode elkslibc medium rtd regparmcall any_186 size
+MULTILIB_MATCHES=mprotected-mode=melks \
+	march?any_186=march?i80186 march?any_186=march?i80188 \
+	march?any_186=march?v20 march?any_186=march?v30 \
+	march?any_186=march?i80286
+ia16_all_multilibs=$(strip \
+  $(filter-out -, \
+    $(subst -/,,\
+      $(subst /-,,\
+	$(foreach pm,- mprotected-mode,\
+	  $(foreach el,- melks-libc,\
+	    $(foreach mm,- mcmodel=medium,\
+	      $(foreach cc,- mrtd mregparmcall,\
+		$(foreach ar,- march=any_186, \
+		  $(foreach op,- Os, \
+		    $(pm)/$(el)/$(mm)/$(cc)/$(ar)/$(op)))))))))))
+#
+# (1) `-mprotected-mode -melks-libc' is the same as just `-melks-libc'.
+# (2) Build 80186+ multilibs only for the `regparmcall' convention.
+# (3) For now, do not build 186+-specific multilibs at all for -melks-libc,
+#     -mprotected-mode, or -mcmodel=medium.
+# (4) Assume that -melks-libc and -mprotected-mode multilibs are always size-
+#     -optimized.  Do not build size-optimized multilibs for the medium model.
+# (5) elks-libc does not support the medium memory model yet.
+#	-- tkchia
+#
+ia16_multilib_map=$(strip \
+  $(filter-out march=any_186,\
+    $(patsubst march=any_186/%,%,\
+      $(subst mrtd/march=any_186,mrtd,\
+	$(subst mprotected-mode/march=any_186,mprotected-mode,\
+	  $(subst melks-libc/march=any_186,melks-libc,\
+	    $(subst mcmodel=medium/march=any_186,mcmodel=medium,\
+	      $(subst /mregparmcall/march=any_186,/mregparmcall,\
+		$(patsubst mprotected-mode%/Os,mprotected-mode%,\
+		  $(patsubst melks-libc%/Os,melks-libc%,\
+		    $(patsubst mcmodel=medium%/Os,mcmodel=medium%,\
+		      $(patsubst mprotected-mode/mcmodel=medium%/Os,\
+				 mprotected-mode/mcmodel=medium%,\
+			$(subst melks-libc/mcmodel=medium,melks-libc,\
+			  $(subst mprotected-mode/melks-libc,melks-libc,\
+			    $1))))))))))))))
+MULTILIB_REQUIRED=$(strip \
+	$(foreach ml,$(ia16_all_multilibs),\
+	  $(filter $(call ia16_multilib_map,$(ml)),$(ml))))
+#
+# Some multilibs variants simply map to the default multilib, hence the $(if).
+#
+MULTILIB_REUSE=$(strip \
+  $(foreach ml,\
+    $(filter-out $(MULTILIB_REQUIRED),$(ia16_all_multilibs)),\
+      $(if $(call ia16_multilib_map,$(ml)),\
+	$(subst =,.,$(call ia16_multilib_map,$(ml)))=$(subst =,.,$(ml)))))
diff --git a/gcc/configure b/gcc/configure
index 954673c..fdf3e0c 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -733,6 +733,7 @@ INCINTL
 LIBINTL_DEP
 LIBINTL
 USE_NLS
+get_gcc_base_ver
 extra_opt_files
 extra_modes_file
 NATIVE_SYSTEM_HEADER_DIR
@@ -915,6 +916,7 @@ with_multilib_list
 enable_rpath
 with_libiconv_prefix
 enable_sjlj_exceptions
+with_gcc_major_version_only
 enable_secureplt
 enable_leading_mingw64_underscores
 enable_cld
@@ -1717,6 +1719,8 @@ Optional Packages:
   --with-gnu-ld           assume the C compiler uses GNU ld default=no
   --with-libiconv-prefix[=DIR]  search for libiconv in DIR/include and DIR/lib
   --without-libiconv-prefix     don't search for libiconv in includedir and libdir
+  --with-gcc-major-version-only
+                          use only GCC major number in filesystem paths
   --with-pic              try to use only PIC/non-PIC objects [default=use
                           both]
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
@@ -11885,6 +11889,21 @@ static struct plugin_gcc_version gcc_version = {basever, datestamp,
 						configuration_arguments};
 EOF
 
+# Determine what GCC version number to use in filesystem paths.
+
+  get_gcc_base_ver="cat"
+
+# Check whether --with-gcc-major-version-only was given.
+if test "${with_gcc_major_version_only+set}" = set; then :
+  withval=$with_gcc_major_version_only; if test x$with_gcc_major_version_only = xyes ; then
+        get_gcc_base_ver="sed -e 's/^\([0-9]*\).*\$\$/\1/'"
+      fi
+
+fi
+
+
+
+
 # Internationalization
 # If we haven't got the data from the intl directory,
 # assume NLS is disabled.
@@ -18460,7 +18479,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 18463 "configure"
+#line 18482 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -18566,7 +18585,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 18569 "configure"
+#line 18588 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 4c65d44..8c9cde5 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -1775,6 +1775,9 @@ static struct plugin_gcc_version gcc_version = {basever, datestamp,
 EOF
 changequote([,])dnl
 
+# Determine what GCC version number to use in filesystem paths.
+GCC_BASE_VER
+
 # Internationalization
 ZW_GNU_GETTEXT_SISTER_DIR
 
diff --git a/gcc/doc/contrib.texi b/gcc/doc/contrib.texi
index 6d9ca58..121731c 100644
--- a/gcc/doc/contrib.texi
+++ b/gcc/doc/contrib.texi
@@ -524,6 +524,9 @@ Charles LaBrec contributed the support for the Integrated Solutions
 68020 system.
 
 @item
+Rask Ingemann Lambertsen contributed the 16-bit Intel x86 back end.
+
+@item
 Asher Langton and Mike Kumbera for contributing Cray pointer support
 to GNU Fortran, and for other GNU Fortran improvements.
 
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index ee2715d..fbefb74 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -1268,7 +1268,7 @@ As an extension, GNU C supports named address spaces as
 defined in the N1275 draft of ISO/IEC DTR 18037.  Support for named
 address spaces in GCC will evolve as the draft technical report
 changes.  Calling conventions for any target might also change.  At
-present, only the AVR, SPU, M32C, RL78, and x86 targets support
+present, only the AVR, SPU, M32C, RL78, IA-16, and x86 targets support
 address spaces other than the generic address space.
 
 Address space identifiers may be used exactly like any other C type
@@ -1424,6 +1424,240 @@ Such code requires at least binutils 2.23, see
 
 @end itemize
 
+@anchor{IA-16 Named Address Spaces}
+@subsection IA-16 Named Address Spaces
+@cindex @code{__far} IA-16 Named Address Spaces
+
+@subsubsection @code{__far}
+
+On the IA-16 target, a pointer qualified with the word @code{__far} is a
+32-bit ``far pointer'' which can be used to access memory outside of the
+64@tie{}KiB generic address space.
+
+One way to create a far pointer value is to cast a 32-bit integer value to a
+far pointer type.  The value's upper 16 bits will be the segment, and the
+lower 16 bits the offset.
+
+@smallexample
+unsigned long irq0_clock_ticks (void)
+@{
+    /* Read the 32-bit BIOS variable at segment:offset ==
+       0x0040:0x006C.  */
+    volatile unsigned long __far *p =
+        (volatile unsigned long __far *) 0x0040006C;
+    return *p;
+@}
+@end smallexample
+
+Another way is to cast a generic data pointer, @code{__seg_ss} data pointer
+(see below), or function pointer, to a far pointer type.  For a data
+pointer, the resulting pointer will have the data segment value---taken from
+the @code{ds} or @code{ss} register---as its segment component; for a
+function pointer, this will be from @code{cs}.
+
+@smallexample
+void set_diskette_params (const unsigned char params[])
+@{
+    /* Set the BIOS diskette parameters (int $0x1e vector).  */
+    * (const unsigned char __far * volatile __far *)
+        (4 * 0x1e) =
+            (const unsigned char __far *) params;
+@}
+@end smallexample
+
+@subsubheading Far Static Storage Variables
+
+Under the small memory model (@option{-mcmodel=small})---and unless you
+specify @option{-mno-segment-relocation-stuff}---you can also define far
+variables with static storage duration, and take their addresses, like so:
+
+@smallexample
+int __far x;
+int __far *f (int b)
+@{
+    static int __far y = 1;
+    return b ? &x : &y;
+@}
+@end smallexample
+
+@subsubheading Far Functions
+
+There is some preliminary support for defining and invoking far functions,
+as well as defining far function pointers.  To mark a function as far, one
+way is to write the word @code{__far} immediately after its parameter list.
+For example:
+
+@smallexample
+int (*foo) (long) __far;
+int bar (void) __far
+@{
+    return foo (3L) + 1;
+@}
+@end smallexample
+
+You can also declare or define a far function using a syntax more compatible
+with that of classical IA-16 compilers (unless you specify
+@option{-mno-far-function-if-far-return-type}):
+
+@smallexample
+int __far baz (void)
+@{
+    return 2;
+@}
+@end smallexample
+@c
+@c 1) The unwieldy
+@c	typedef void func_t (void);
+@c	typedef func_t __far far_func_t;
+@c    syntax for defining a far function pointer type can also be used, for
+@c    use with somewhat older (25--28 Feb 2018) versions of ia16-elf-gcc. 
+@c    This syntax is still supported on later versions. :-)
+@c
+@c 2) The N1275 draft does not actually support the notion of functions in
+@c    separate address spaces: (5.1.2) "Note that, since a function is not an
+@c    object, address-space type qualifiers cannot be used with functions."
+@c
+@c    But GCC supports the above unwieldy syntax (even if accidentally), so I
+@c    build on it.
+
+By default, GCC treats far functions similarly to the Open Watcom C/C++
+compiler:
+
+@itemize
+
+@item
+When a module defines a far function, GCC places it in the program's text
+segment.
+
+@item
+If a module calls a far function which is defined in the same module, GCC
+can tell that the caller and callee reside in the same IA-16 segment.  GCC
+will output a @samp{pushw %cs; call} or @samp{jmp} instruction sequence to
+realize the call.
+
+@item
+However, if a module calls a far function which is defined elsewhere---or if
+the call is done through a pointer---GCC assumes nothing about where the
+function is.  GCC will use a far @code{lcall} or @code{ljmp}, possibly with
+a segment relocation, to realize the call.
+
+@end itemize
+
+If you know that an externally defined far function is guaranteed to be in
+the program's text segment, you can get GCC to use @code{call} or @code{jmp}
+for this function, with an attribute:
+
+@smallexample
+int baz (long) __far __attribute__ ((__near_section__));
+@end smallexample
+
+Conversely, if you would like to place a locally defined far function
+@emph{outside} the normal text segment, you can use a different attribute:
+
+@smallexample
+__attribute__ ((__far_section__))
+__far int qux (long x)
+@{ ... @}
+@end smallexample
+
+It is now (April 2019) possible for @code{far_section} functions to call
+non-far functions in the normal text segment---including standard C library
+functions and compiler support routines.  However, the internal
+implementation for such calls is still rather inefficient.
+
+@subsubheading Limitations and Caveats
+
+@itemize
+
+@item
+If a pointer arithmetic operation causes the pointer's offset portion to
+wrap around---from @code{0xFFFF} to @code{0x0000}, or vice versa---the
+resulting pointer is undefined.  This may change in the future.
+@c
+@c (Nov 2017) I have modified gcc-ia16 so that it does far pointer
+@c arithmetic in the same fashion as in classical DOS compilers, i.e. only
+@c the low 16-bit offset is frobbed.  However, it probably needs to be more
+@c rigorously tested.
+@c
+@c Before the hack, gcc-ia16 treated far pointers as plain old 32-bit
+@c integers, so that 0x1234:0xFFFF wrapped around to 0x1235:0x0000, which
+@c made no sense.  -- tkchia
+
+@item
+To avoid ambiguity in parsing, the postfix @code{__far} notation above for
+declaring far functions is not allowed with K&R-style function definitions.
+
+@item
+Starting from August 2019, a declaration like
+
+@smallexample
+static int __far x, y, z;
+@end smallexample
+
+guarantees that the variables @code{x}, @code{y}, and @code{z} will be
+placed in the same far segment---@emph{though not necessarily in that order}. 
+(To lay out a set of far variables in a fixed order, you can consider
+wrapping them in a struct.)
+
+GCC also guarantees, given an appropriate linker script at link time, that
+@code{x}, @code{y}, and @code{z} will be placed outside the generic (near)
+data address space.
+
+@item
+When using the (default) tiny memory model, or if
+@option{-mno-segment-relocation-stuff} is in effect, operations which
+require the output code to contain segment relocations are not allowed.
+
+In particular, you cannot place a static storage variable in the
+@code{__far} space, or invoke an externally defined far function by name
+(unless it is marked @code{near_section}).
+
+@item
+For far pointer declarations, the GCC named address space syntax---which
+follows N1275---differs somewhat from the syntax used in classical DOS
+compilers such as Open Watcom C/C++ and Borland's Turbo C.  The code
+
+@smallexample
+char __far *p, *q;
+@end smallexample
+
+declares @code{p} and @code{q} as far pointers under GCC, but under Open
+Watcom it declares only @code{p} as a far pointer, and @code{q} as a generic
+pointer.
+
+@opindex Waddress
+@opindex Wall
+If @option{-Waddress} (or @option{-Wall}) is enabled, GCC will warn about
+cases like the above, where a declaration can be interpreted differently
+under GCC's grammar and Watcom-style grammar.
+
+Also note that, unlike Open Watcom, GCC does not support the
+
+@smallexample
+int (__far *foo) (long);
+@end smallexample
+
+syntax for declaring far function pointers.
+
+@item
+@opindex ffixed
+The option @option{-ffixed-ds} does not currently interact well with some
+far address operations---such as copying a struct between two far addresses. 
+This, too, may change in the future.
+
+@end itemize
+
+@subsubsection @code{__seg_ss}
+
+Within a function marked @code{__attribute__ ((__no_assume_ss_data__))}
+(@pxref{IA-16 Function Attributes}), a pointer qualified with
+@code{__seg_ss} can be used to refer to memory in the caller's stack, rather
+than the program's data segment.
+
+@subsubsection Preprocessor symbols
+
+@xref{IA-16 Built-in Macros}.
+
 @subsection M32C Named Address Spaces
 @cindex @code{__far} M32C Named Address Spaces
 
@@ -2251,6 +2485,7 @@ GCC plugins may provide their own attributes.
 * CR16 Function Attributes::
 * Epiphany Function Attributes::
 * H8/300 Function Attributes::
+* IA-16 Function Attributes::
 * IA-64 Function Attributes::
 * M32C Function Attributes::
 * M32R/D Function Attributes::
@@ -3975,6 +4210,100 @@ all registers except the stack pointer should be saved in the prologue
 regardless of whether they are used or not.
 @end table
 
+@node IA-16 Function Attributes
+@subsection IA-16 Function Attributes
+
+These function attributes are supported by the IA-16 back end:
+
+@table @code
+@item cdecl
+@cindex @code{cdecl} function attribute, IA-16
+@cindex functions that pop the argument stack on IA-16
+@opindex mrtd
+@opindex mregparmcall
+On the IA-16 target, the @code{cdecl} attribute causes the compiler to
+assume that the calling function pops off the stack space used to
+pass arguments.  This is useful to override the effects of a @option{-mrtd}
+or @option{-mregparmcall} switch.
+
+@item stdcall
+@cindex @code{stdcall} function attribute, IA-16
+@cindex functions that pop the argument stack on IA-16
+On the IA-16 target, the @code{stdcall} attribute causes the compiler to
+assume that the called function pops off the stack space used to
+pass arguments, unless it takes a variable number of arguments.
+
+@item regparmcall
+@cindex @code{regparmcall} function attribute, IA-16
+@cindex functions that pop the argument stack on IA-16
+@cindex functions that are passed arguments in registers on IA-16
+On the IA-16 target, the @code{regparmcall} attribute causes the compiler to
+pass its first few arguments to the function in the registers @code{ax},
+@code{dx}, and @code{cx}, instead of on the stack.  The called function pops
+the arguments off the stack.
+
+An exception is that, if the number of arguments is variable, the @code{...}
+variable arguments will always go on the stack, and the calling function
+pops all pushed arguments.
+
+@item assume_ds_data
+@cindex @code{assume_ds_data} function attribute, IA-16
+This attribute, attached to a function, causes the compiler to assume that
+the @code{ds} register points to the program's data segment on function
+entry.  The function will also arrange to restore @code{ds} to the same data
+segment on function exit.
+
+Use this attribute to override the
+@option{-mno-callee-assume-ds-data-segment} switch for a function.
+
+This attribute has no effect if @code{ds} is a call-saved register
+(@option{-fcall-saved-ds}).
+
+@item no_assume_ds_data
+@cindex @code{no_assume_ds_data} function attribute, IA-16
+This attribute, attached to a function, causes the compiler @emph{not} to
+assume that @code{ds} points to the program's data segment on function
+entry.  It has no effect if @code{ds} is a call-saved register.
+
+Note that, if @code{ds} is a call-used register (the default), this also
+means that the function may clobber @code{ds}---and callers cannot assume
+that the function will preserve it---unless you also specify the
+@code{restore_ds} attribute.
+
+@item restore_ds
+@cindex @code{restore_ds} function attribute, IA-16
+This attribute, attached to a function, means that the function should
+preserve the @code{ds} register value and restore it on function return.
+This is mostly useful in conjunction with the @code{no_assume_ds_data}
+attribute.
+
+This attribute has no effect if @code{ds} is a fixed or call-saved register
+(@option{-ffixed-ds} or @option{-fcall-saved-ds}).
+
+@item no_assume_ss_data
+@cindex @code{no_assume_ss_data} function attribute, IA-16
+This attribute, attached to a function, causes the compiler @emph{not} to
+assume that @code{ss} points to the program's data segment on function
+entry.  The function's stack parameters and variables are considered to be
+in a separate @code{__seg_ss} address space.  @xref{IA-16 Named Address
+Spaces}.
+
+@strong{Warning:} This feature is experimental, and may produce broken code.
+Use with caution.
+
+@item near_section
+@cindex @code{near_section} function attribute, IA-16
+This attribute, attached to a far function declaration, tells GCC that
+the function is known to reside in the program's text segment.  @xref{IA-16
+Named Address Spaces}.
+
+@item far_section
+@cindex @code{far_section} function attribute, IA-16
+This attribute, attached to a far function definition, tells GCC to place
+the function outside the normal text segment.  @xref{IA-16 Named Address
+Spaces}.
+@end table
+
 @node IA-64 Function Attributes
 @subsection IA-64 Function Attributes
 
@@ -11419,6 +11748,7 @@ instructions, but allow the compiler to schedule those calls.
 * AVR Built-in Functions::
 * Blackfin Built-in Functions::
 * FR-V Built-in Functions::
+* IA-16 Built-in Functions::
 * MIPS DSP Built-in Functions::
 * MIPS Paired-Single Support::
 * MIPS Loongson Built-in Functions::
@@ -12799,6 +13129,41 @@ Use the @code{nldub} instruction to load the contents of address @var{x}
 into the data cache.  The instruction is issued in slot I1@.
 @end table
 
+@node IA-16 Built-in Functions
+@subsection IA-16 Built-in Functions
+
+For each built-in function for IA-16, there is an equally named, uppercase
+built-in macro defined---for example, @code{__BUILTIN_IA16_FP_OFF}.  That
+way users can easily query if or if not a specific built-in is implemented
+or not.
+
+@table @code
+
+@item __builtin_ia16_segment_t __builtin_ia16_selector (unsigned @var{sel})
+With @option{-mprotected-mode} (@xref{IA-16 Options}), internally flag
+@var{sel} as a segment selector value which can be loaded into a segment
+register, and return the flagged value.  Without @option{-mprotected-mode},
+simply return @var{sel}.
+
+@item unsigned __builtin_ia16_FP_OFF (const void __far *@var{fp})
+Extract the offset portion of the far pointer @var{fp}.  This function can
+be used within a static initializer, under certain
+conditions@footnote{Currently, this is allowed if @var{fp} is a pointer to
+a locally defined variable or function, or if @var{fp} points to an external
+variable or function and LTO is not in effect.}.
+
+@item __builtin_ia16_segment_t __builtin_ia16_near_data_segment (void)
+Return the segment value for the generic (near) data address space.
+
+@item __builtin_ia16_segment_t __builtin_ia16_ss (void)
+Return the value of the stack segment register @code{ss}.
+
+This should return the same value as @code{__builtin_ia16_near_data_segment
+()}, unless the calling function is marked @code{__attribute__
+((__no_assume_ss_data__))} (@pxref{IA-16 Function Attributes}).
+
+@end table
+
 @node MIPS DSP Built-in Functions
 @subsection MIPS DSP Built-in Functions
 
diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi
index b60b53a..9888503 100644
--- a/gcc/doc/install.texi
+++ b/gcc/doc/install.texi
@@ -914,6 +914,10 @@ ideas of what it is for.  People use it as if it specified where to
 install part of GCC@.  Perhaps they make this assumption because
 installing GCC creates the directory.
 
+@item --with-gcc-major-version-only
+Specifies that GCC should use only the major number rather than
+@var{major}.@var{minor}.@var{patchlevel} in filesystem paths.
+
 @item --with-native-system-header-dir=@var{dirname}
 Specifies that @var{dirname} is the directory that contains native system
 header files, rather than @file{/usr/include}.  This option is most useful
@@ -3310,6 +3314,12 @@ information have to.
 @item
 @uref{#ix86-x-solaris210,,i?86-*-solaris2.10}
 @item
+@uref{#ix86-x-udk,,i?86-*-udk}
+@item
+@uref{#ia16-x-elf,,ia16-*-elf}
+@item
+@uref{#ia16-x-elks,,ia16-*-elks}
+@item
 @uref{#ia64-x-linux,,ia64-*-linux}
 @item
 @uref{#ia64-x-hpux,,ia64-*-hpux*}
@@ -3953,6 +3963,29 @@ guarantee use of Sun @command{ld}.
 @html
 <hr />
 @end html
+@heading @anchor{ia16-x-elf}ia16-*-elf
+Intel 16-bit x86 processor configuration for embedded systems.
+
+There is no binutils configuration for this target, but binutils
+configurations for @samp{i?86} ELF systems can be used.  Binutils
+releases from around 2001 or later can be used.
+
+
+@html
+<hr />
+@end html
+@heading @anchor{ia16-x-elks}ia16-*-elks
+Intel 16-bit x86 processor configuration for the Embeddable Linux Kernel Subset
+system.
+
+There is no binutils configuration for this target, but binutils
+configurations for @samp{i?86} ELF systems can be used.  Binutils
+releases from around 2001 or later can be used.
+
+
+@html
+<hr />
+@end html
 @anchor{ia64-x-linux}
 @heading ia64-*-linux
 IA-64 processor (also known as IPF, or Itanium Processor Family)
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 2ed9285..2fb824d 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -501,7 +501,8 @@ Objective-C and Objective-C++ Dialects}.
 @item Developer Options
 @xref{Developer Options,,GCC Developer Options}.
 @gccoptlist{-d@var{letters}  -dumpspecs  -dumpmachine  -dumpversion @gol
--fchecking -fdbg-cnt-list -fdbg-cnt=@var{counter-value-list} @gol
+-dumpfullversion  -fchecking  -fdbg-cnt-list @gol
+-fdbg-cnt=@var{counter-value-list} @gol
 -fdisable-ipa-@var{pass_name} @gol
 -fdisable-rtl-@var{pass_name} @gol
 -fdisable-rtl-@var{pass-name}=@var{range-list} @gol
@@ -754,6 +755,16 @@ Objective-C and Objective-C++ Dialects}.
 -mschedule=@var{cpu-type}  -mspace-regs  -msio  -mwsio @gol
 -munix=@var{unix-std}  -nolibdld  -static  -threads}
 
+@emph{IA-16 Options}
+@gccoptlist{-mtune=@var{cpu-type}  -march=@var{cpu-type} -mshort-jumps @gol
+-mmsdos -mmsdos-handle-v1 -mdpmiable -melks -melks-libc @gol
+-maout-total=@var{total} -maout-chmem=@var{chmem} -mcmodel=tiny @gol
+-mcmodel=small @gol
+-mseparate-code-segment -mno-segment-relocation-stuff -mrtd -mstdcall @gol
+-mregparmcall -mno-callee-assume-ds-data-segment @gol
+-mno-callee-assume-ss-data-segment -mno-far-function-if-far-return-type @gol
+-mprotected-mode -mnewlib-nano-stdio -mnewlib-autofloat-stdio}
+
 @emph{IA-64 Options}
 @gccoptlist{-mbig-endian  -mlittle-endian  -mgnu-as  -mgnu-ld  -mno-pic @gol
 -mvolatile-asm-stop  -mregister-names  -msdata -mno-sdata @gol
@@ -12725,8 +12736,17 @@ Print the compiler's target machine (for example,
 
 @item -dumpversion
 @opindex dumpversion
-Print the compiler version (for example, @code{3.0})---and don't do
-anything else.
+Print the compiler version (for example, @code{3.0}, @code{6.3.0} or @code{7})---and don't do
+anything else.  This is the compiler version used in filesystem paths,
+specs, can be depending on how the compiler has been configured just
+a single number (major version), two numbers separated by dot (major and
+minor version) or three numbers separated by dots (major, minor and patchlevel
+version).
+
+@item -dumpfullversion
+@opindex dumpfullversion
+Print the full compiler version, always 3 numbers separated by dots,
+major, minor and patchlevel version.
 
 @item -dumpspecs
 @opindex dumpspecs
@@ -12774,6 +12794,7 @@ platform.
 * GNU/Linux Options::
 * H8/300 Options::
 * HPPA Options::
+* IA-16 Options::
 * IA-64 Options::
 * LM32 Options::
 * M32C Options::
@@ -16480,6 +16501,416 @@ under HP-UX@.  This option sets flags for both the preprocessor and
 linker.
 @end table
 
+@node IA-16 Options
+@subsection IA-16 Options
+@cindex IA-16 Options
+
+These are the @samp{-m} options defined for the Intel IA-16 architecture.
+
+@table @gcctabopt
+@item -mtune=@var{cpu-type}
+@opindex mtune
+Tune to @var{cpu-type} everything applicable about the generated code, except
+for the ABI and the set of available instructions.  The choices for
+@var{cpu-type} are:
+@table @emph
+@item i8086
+The Intel 8086.
+
+@item i8088
+The Intel 8088.
+
+@item i80186
+@itemx i186
+The Intel 80186.
+
+@item i80286
+@itemx i286
+The Intel 80286.
+
+@item v20
+The NEC V20.
+
+@item v30
+The NEC V30.
+
+@item any
+Any CPU listed above.  The aim is to generate code which runs reasonably
+well on any CPU listed above.
+
+@item any_186
+As with @option{-mtune=any}, but assume a CPU which supports immediate
+operands for push, imul and shift/rotate instructions.
+@end table
+
+@item -march=@var{cpu-type}
+@opindex march
+Generate instructions for the machine type @var{cpu-type}.  The choices
+for @var{cpu-type} are the same as for @option{-mtune}.  Moreover,
+specifying @option{-march=@var{cpu-type}} implies
+@option{-mtune=@var{cpu-type}}.
+
+@c The standard GCC way of supporting multiple target OSes is to have a whole
+@c separate toolchain for each such OS --- and indeed I see that Lambertsen
+@c and Jenner had included code for an ia16-*-elks toolchain which targets
+@c the ELKS OS rather than MS-DOS.
+@c
+@c However, MFLD felt this approach to be rather wasteful (https://github.com/
+@c tkchia/gcc-ia16/issues/23#issuecomment-395982101), and so did I.  -- tkchia
+@c
+@item -mmsdos
+@opindex mmsdos
+Produce executables for MS-DOS.  This is the default.
+
+@item -mmsdos-handle-v1
+@opindex mmsdos-handle-v1
+Produce executables for MS-DOS, in such a way that the executables will fail
+gracefully under MS-DOS version 1.x, rather than crash the system.  This
+option implies @option{-mmsdos}.
+
+@item -melks
+@opindex melks
+@item -melks-libc
+@opindex melks-libc
+Produce executables for the Embeddable Linux Kernel Subset (ELKS) operating
+system.  In addition, link against ELKS's own C runtime library---which must
+be built with GCC, and installed---instead of the Newlib C library.
+
+This option also turns on @option{-mprotected-mode} and
+@option{-mcmodel=small}.
+@c
+@c Before December 2019, -melks used to link ELKS programs with an
+@c ELKS-ified Newlib, while -melks-libc would link with elks-libc.  Since,
+@c to my knowledge, nobody has been actually using Newlib to build ELKS
+@c programs, I have decided to unify the two options.  -- tkchia
+
+@item -maout-total=@var{total}
+@opindex maout-total
+When building an ELKS program (@option{-melks}), set it to request the
+operating system to set the top of the data segment---including static
+storage, heap, and stack---to at least @var{total}.  This requires support
+from the linker script which comes with the C library.
+
+@item -maout-chmem=@var{chmem}
+@opindex maout-chmem
+When building an ELKS program (@option{-melks}), set it to request the
+operating system to reserve at least @var{chmem} bytes in the data segment
+for non-static storage (such as heap and stack).  This requires support
+from the linker script which comes with the C library.
+
+@item -mcmodel=tiny
+@opindex mcmodel=tiny
+Generate code for the tiny code model, with a single combined data and text
+segment in a @w{64 KiB} address space.  This is the default for MS-DOS.
+
+@item -mcmodel=small
+@itemx -mseparate-code-segment
+@opindex mcmodel=small
+@opindex mseparate-code-segment
+Generate code for the small code model, with one data segment and one text
+segment, in separate @w{64 KiB} spaces.  This is now (February 2020) the
+default for ELKS (@option{-melks}).
+@c
+@c Recent versions of ELKS (e.g. 0.3.0) will only run a.out programs marked
+@c "separate I/D", and will no longer run tiny model a.out programs.  Hence
+@c this change.
+
+At the compile stage, @option{-mcmodel=small} currently disables trampolines
+for nested functions.
+
+At the linking stage---unless @option{-T} is used---this option also causes
+GCC to switch to a different output format to better support separate
+segments.  In particular, if targeting MS-DOS, GCC will produce an @code{MZ}
+executable.  (This requires support from the linker script which comes with
+the C library.)
+@c
+@c -mseparate-code-segment used to be a separate option which merely
+@c disabled trampolines.  Since this is not very useful in itself, I have
+@c now unified it with -mcmodel=small.  -- tkchia
+
+@item -msegment-relocation-stuff
+@itemx -mno-segment-relocation-stuff
+@opindex msegment-relocation-stuff
+@opindex mno-segment-relocation-stuff
+Enable (or disable) language features, such as static pointers to far
+variables, that rely on segment relocations to work.  If the small code
+model is used, the default is to allow such language features.
+
+@item -mshort-jumps
+@itemx -mno-short-jumps
+@opindex mshort-jumps
+@opindex mno-short-jumps
+Allow (or disallow) the use of jump instructions which can only jump
+@minus{}128/+127 bytes.  The default is not to use them.  This option only
+affects instructions for which the assembler doesn't provide a work-around
+and the compiler doesn't know the jump displacement.
+
+@item -mrtd
+@itemx -mstdcall
+@opindex mrtd
+@opindex mstdcall
+Use a different function-calling convention, in which functions that
+take a fixed number of arguments return with the @code{ret @var{num}}
+instruction, which pops their arguments while returning.  This saves one
+instruction in the caller since there is no need to pop the arguments
+there.
+
+At the linking stage, this option will also make GCC link your code against
+the appropriate @option{-mrtd} multilib.
+
+You can specify that an individual function is called with this calling
+sequence with the function attribute @code{stdcall}.  You can also
+override the @option{-mrtd} option by using the function attribute
+@code{cdecl} or @code{regparmcall}.  @xref{IA-16 Function Attributes}.
+
+@strong{Warning:} you must provide function prototypes for all functions that
+take variable numbers of arguments (including @code{printf});
+otherwise incorrect code is generated for calls to those
+functions.
+
+In addition, seriously incorrect code results if you call a
+function with too many arguments.  (Normally, extra arguments are
+harmlessly ignored.)
+
+@item -mregparmcall
+@opindex mregparmcall
+Use a different function-calling convention, in which functions receive
+their first few arguments in the registers @code{ax}, @code{dx}, and
+@code{cx}, and pop their remaining arguments off the stack.  An exception is
+that, if the number of arguments to a function is variable, the @code{...}
+variable arguments will always go on the stack, and the calling function
+pops all pushed arguments.
+
+At the linking stage, @option{-mregparmcall} will also make GCC link your
+code against the appropriate @option{-mregparmcall} multilib.
+
+You can specify that an individual function is called with this calling
+sequence with the function attribute @code{regparmcall}.  You can also
+override the @option{-mregparmcall} option by using the function attribute
+@code{cdecl} or @code{stdcall}.  @xref{IA-16 Function Attributes}.
+
+@strong{Warning:} you must provide function prototypes for all functions that
+take variable numbers of arguments (including @code{printf});
+otherwise incorrect code is generated for calls to those
+functions.
+
+In addition, seriously incorrect code results if you call a
+function with too many arguments.  (Normally, extra arguments are
+harmlessly ignored.)
+
+@item -mno-callee-assume-ds-data-segment
+@itemx -mcallee-assume-ds-data-segment
+@opindex mno-callee-assume-ds-data-segment
+@opindex mcallee-assume-ds-data-segment
+Use (or do not use) a different function-calling convention, in which the
+@code{ds} register is not assumed to point to the program's data segment
+(the generic address space) at function entry, and is treated as just an
+ordinary call-used register (with @option{-fcall-used-ds}) or fixed
+register (@option{-ffixed-ds}) with no special meaning.
+
+The @code{ss} register is still assumed to point to the data segment---data
+items in the generic address space will be accessed via @code{ss}.
+
+This option is ignored if @code{ds} is set to be a call-saved register
+(@option{-fcall-saved-ds}).
+
+In the default configuration (@option{-mcallee-assume-ds-data-segment
+-mcallee-assume-ss-data-segment -fcall-used-ds}), functions can assume that
+@code{ds} points to the program's data segment at function entry, and will
+arrange to reset @code{ds} to @code{ss}---if needed---just before returning.
+
+You can override this option for individual functions, by using the
+@code{assume_ds_data} and @code{no_assume_ds_data} function attributes.
+@xref{IA-16 Function Attributes}.
+
+@item -mno-far-function-if-far-return-type
+@opindex mno-far-function-if-far-return-type
+Do not treat a function with a @code{__far} return type as a far function.
+@xref{IA-16 Named Address Spaces}.
+
+@item -mprotected-mode
+@opindex mprotected-mode
+Enable partial support for generating code to run in
+Intel 80286 protected mode.
+
+With this option, the output code will avoid using segment registers
+(@code{ds}, @code{es}) to hold arbitrary 16-bit values---in protected mode,
+doing so may make the CPU crash the program.  Instead, the output code will
+only load segment registers when dereferencing near or far pointers.
+
+Currently, @option{-mprotected-mode} also causes GCC to avoid placing
+@code{asm} operands in segment registers.  You can tell GCC to let an
+operand go into a segment register, by passing the operand through a
+built-in function @samp{__builtin_ia16_selector}:
+@smallexample
+void foo (unsigned selector)
+@{
+  __asm volatile ("nop"
+                  : : "e" (__builtin_ia16_selector (selector)));
+@}
+@end smallexample
+
+At the linking stage, @option{-mprotected-mode} will also make GCC link your
+code against library routines that are built to work with protected mode.
+@end table
+
+@subsubsection Experimental IA-16 Options
+
+@table @gcctabopt
+@item -mcmodel=medium
+@opindex mcmodel=medium
+Generate code for the medium code model, with one data segment and multiple
+text segments, each in a separate @w{64 KiB} space.
+
+At the linking stage---unless @option{-T} is used---this option will also
+make GCC link your code against the appropriate medium model multilib, and
+switch to the appropriate output program format.
+
+This option is currently not supported for C++ or for the ELKS target.
+
+@item -mnewlib-nano-stdio
+@opindex mnewlib-nano-stdio
+If using the Newlib C library, link against a limited version of the
+formatted I/O routines (@code{stdio}) which supports only C89 functionality
+and by default excludes floating-point support.
+
+@item -mnewlib-autofloat-stdio
+@opindex mnewlib-autofloat-stdio
+If using the Newlib C library, try to detect whether the program needs
+floating-point support in the formatted I/O routines (@code{stdio}), and
+link against the appropriate version of the @code{stdio} code.
+
+If you use this option, specify it at compile time and during the final link.
+
+@item -mdpmiable
+@opindex mdpmiable
+Produce MS-DOS executables which try to use the DOS Protected Mode Interface
+(DPMI) to switch to and run in protected mode when they detect a DPMI host. 
+
+This option implies @option{-mmsdos} and @option{-mprotected-mode}, and
+requires support from the linker script which comes with the C library.
+
+@item -msegelf
+@opindex msegelf
+Generate object files which follow H.@: Peter Anvin's proposed 16-bit
+segmented code ABI,
+@url{https://git.zytor.com/users/hpa/segelf/abi.git/plain/segelf.txt}.
+
+@strong{Warning:} The @option{-msegelf} switch causes GCC
+to generate code that is not binary compatible with code generated
+without that switch.  Using this switch may require recompiling all
+other modules in a program, including system libraries.
+
+@item -mno-callee-assume-ss-data-segment
+@opindex mno-callee-assume-ss-data-segment
+Use a different function-calling convention, in which the @code{ss} register
+is not assumed to point to the program's data segment at function entry. 
+This option exists only for testing.
+@end table
+
+@anchor{IA-16 Built-in Macros}
+@subsubsection IA-16 Built-in Macros
+
+@table @code
+@item __FAR
+@itemx __SEG_SS
+Each of these macros is defined only if the compiler supports the named
+address space specifier (@pxref{IA-16 Named Address Spaces}).
+
+@item __IA16_CMODEL_TINY__
+@itemx __TINY__
+@itemx __IA16_CMODEL_SMALL__
+@itemx __SMALL__
+@itemx __IA16_CMODEL_MEDIUM__
+@itemx __MEDIUM__
+Each of these macros is defined only if the named code model (tiny, small,
+or medium) is selected.
+
+@item __IA16_ARCH_ANY
+@itemx __IA16_ARCH_ANY_186
+@itemx __IA16_ARCH_I8086
+@itemx __IA16_ARCH_I8088
+@itemx __IA16_ARCH_NEC_V30
+@itemx __IA16_ARCH_NEC_V20
+@itemx __IA16_ARCH_I80186
+@itemx __IA16_ARCH_I80188
+@itemx __IA16_ARCH_I80286
+These macros are defined according to the @option{-march=@var{cpu-type}}
+option settings.
+
+@item __IA16_TUNE_I8086
+@itemx __IA16_TUNE_I8088
+@itemx __IA16_TUNE_NEC_V30
+@itemx __IA16_TUNE_NEC_V20
+@itemx __IA16_TUNE_I80186
+@itemx __IA16_TUNE_I80188
+@itemx __IA16_TUNE_I80286
+These macros are defined according to the @option{-mtune=@var{cpu-type}} and
+option settings.
+
+@item __IA16_FEATURE_SHIFT_IMM
+@itemx __IA16_FEATURE_PUSH_IMM
+@itemx __IA16_FEATURE_IMUL_IMM
+@itemx __IA16_FEATURE_PUSHA
+@itemx __IA16_FEATURE_ENTER_LEAVE
+@itemx __IA16_FEATURE_AAD_IMM
+@itemx __IA16_FEATURE_FSTSW_AX
+Each of these macros is defined only if the CPU selected by
+@option{-march=@var{cpu-type}} supports the named type of IA-16 instruction.
+
+@item __IA16_FEATURE_SHIFT_MASKED
+This macro is defined only if the selected CPU's bitwise shift and rotation
+instructions---@code{rcl}, @code{shr}, and so on---implicitly mask each
+shift count to their lower 5 bits.
+
+@item __IA16_FEATURE_PROTECTED_MODE
+This macro is defined only if @option{-mprotected-mode} is in effect.
+
+@item __IA16_FEATURE_DPMIABLE
+This macro is defined only if @option{-mdpmiable} is in effect.
+
+@item __IA16_FEATURE_ALLOCABLE_DS_REG
+This macro is defined only if the @code{ds} register is configured to be
+available for register allocation---that is, it is either call-used or
+call-saved, not fixed.
+
+@item __IA16_FEATURE_FAR_FUNCTION_SYNTAX
+This macro is defined only if the postfix @code{__far} syntax for declaring
+far functions is supported (@pxref{IA-16 Named Address Spaces}).
+
+@item __IA16_CALLCVT_FAR_FUNCTION_IF_FAR_RETURN_TYPE
+This macro is defined only if the classical syntax for declaring far
+functions is supported (@pxref{IA-16 Named Address Spaces}).
+
+@item __IA16_FEATURE_FAR_STATIC_STORAGE
+This macro is defined only if static storage variables can be placed in
+@code{__far} space (@pxref{IA-16 Named Address Spaces}).
+
+@item __IA16_FEATURE_ATTRIBUTE_CDECL
+@itemx __IA16_FEATURE_ATTRIBUTE_STDCALL
+@itemx __IA16_FEATURE_ATTRIBUTE_REGPARMCALL
+@itemx __IA16_FEATURE_ATTRIBUTE_ASSUME_DS_DATA
+@itemx __IA16_FEATURE_ATTRIBUTE_NO_ASSUME_DS_DATA
+@itemx __IA16_FEATURE_ATTRIBUTE_RESTORE_DS
+@itemx __IA16_FEATURE_ATTRIBUTE_NO_ASSUME_SS_DATA
+@itemx __IA16_FEATURE_ATTRIBUTE_NEAR_SECTION
+@itemx __IA16_FEATURE_ATTRIBUTE_FAR_SECTION
+Each of these macros is defined only if the corresponding function attribute
+is supported (@pxref{IA-16 Function Attributes}).
+
+@item __BUILTIN_IA16_SELECTOR
+@itemx __BUILTIN_IA16_FP_OFF
+@itemx __BUILTIN_IA16_NEAR_DATA_SEGMENT
+@itemx __BUILTIN_IA16_SS
+Each of these macros is defined only if the corresponding
+@code{__builtin_ia16_}@dots{} macro is defined (@pxref{IA-16 Built-in
+Functions}).
+
+@c I am not sure yet if I should document and codify the remaining macros,
+@c viz. __IA16_CALLCVT_{CDECL, STDCALL}, etc.  -- tkchia
+@c
+@end table
+
 @node IA-64 Options
 @subsection IA-64 Options
 @cindex IA-64 Options
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 1418248..34f1c7d 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -2376,6 +2376,132 @@ A memory operand for floating-point loads and stores
 A register indirect memory operand
 @end table
 
+@item Intel IA-16---@file{config/ia16/constraints.md}
+@table @code
+@item a
+The @code{ax} register.  Note that for a byte operand, this constraint means
+that the operand can go into either @code{al} or @code{ah}.
+
+@item b
+The @code{bx} register.
+
+@item c
+The @code{cx} register.
+
+@item d
+The @code{dx} register.
+
+@item S
+The @code{si} register.
+
+@item D
+The @code{di} register.
+
+@item Ral
+The @code{al} register.
+
+@item Rah
+The @code{ah} register.
+
+@item Rcl
+The @code{cl} register.
+
+@item Rbp
+The @code{bp} register.
+
+@item Rds
+The @code{ds} register.
+
+@item q
+Any 8-bit register.
+
+@item T
+Any general or segment register.
+
+@item A
+The @code{dx:ax} register pair.
+
+@item j
+The @code{bx:dx} register pair.
+
+@item l
+The lower half of pairs of 8-bit registers.
+
+@item u
+The upper half of pairs of 8-bit registers.
+
+@item k
+Any 32-bit register group with access to the two lower bytes.
+
+@item x
+The @code{si} and @code{di} registers.
+
+@item w
+The @code{bx} and @code{bp} registers.
+
+@item B
+The @code{bx}, @code{si}, @code{di} and @code{bp} registers.
+
+@item e
+The @code{es} register.
+
+@item Q
+Any available segment register---either @code{ds} or
+@code{es} (unless one or both have been fixed).
+
+@item Z
+The constant 0.
+
+@item P1
+The constant 1.
+
+@item M1
+The constant @minus{}1.
+
+@item Um
+The constant @minus{}256.
+
+@item Lbm
+The constant 255.
+
+@item Lor
+Constants 128 @dots{} 254.
+
+@item Lom
+Constants 1 @dots{} 254.
+
+@item Lar
+Constants @minus{}255 @dots{} @minus{}129.
+
+@item Lam
+Constants @minus{}255 @dots{} @minus{}2.
+
+@item Uo
+Constants 0xXX00 except @minus{}256.
+
+@item Ua
+Constants 0xXXFF.
+
+@item Ish
+A constant usable as a shift count.
+
+@item Iaa
+A constant multiplier for the @code{aad} instruction.
+
+@item Ipu
+A constant usable with the @code{push} instruction.
+
+@item Imu
+A constant usable with the @code{imul} instruction except 257.
+
+@item I11
+The constant 257.
+
+@item N
+Unsigned 8-bit integer constant (for @code{in} and @code{out}
+instructions).
+@end table
+
 @item Intel IA-64---@file{config/ia64/ia64.h}
 @table @code
 @item a
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 745910f..251720d 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -2426,6 +2426,25 @@ address where its value is either multiplied by a scale factor or
 added to another register (as well as added to a displacement).
 @end defmac
 
+@defmac MODE_SEGMENT_REG_CLASS (@var{outer_mode}, @var{inner_mode}, @var{index})
+A macro which, if defined, should return a register class to control the
+loading of addresses' ``segment'' components into registers.
+
+This macro is not needed for targets with only flat address spaces---that is
+to say, most targets.  It is used in the IA-16 backend to implement
+@code{__far} pointers.
+
+With this macro, if a memory address contains a segment component in the
+form of an RTL expression
+@smallexample
+(unspec:@var{outer_mode} [@var{expr} @dots{}] @var{index})
+@end smallexample
+then GCC will consult this macro to decide which register class to load the
+inner expression @var{expr} into.  @var{inner_mode} is the mode of this
+inner expression, while @var{outer_mode} and @var{index} are the mode and
+the operation code for the @samp{(unspec @dots{})} as a whole.
+@end defmac
+
 @defmac REGNO_OK_FOR_BASE_P (@var{num})
 A C expression which is nonzero if register number @var{num} is
 suitable for use as a base register in operand addresses.
@@ -10398,6 +10417,95 @@ Define this to define how the address space is encoded in dwarf.
 The result is the value to be used with @code{DW_AT_address_class}.
 @end deftypefn
 
+@defmac TARGET_ADDR_SPACE_WEIRD_P (@var{as})
+This macro is not needed for most targets.  If defined, it should return
+true if pointers and addresses in the address space @var{as} may break
+certain assumptions.  In particular, it should return true if
+
+@enumerate
+@item
+pointer or address arithmetic does not work in the same way as integer
+arithmetic of the same modes, or if
+
+@item
+the difference between two pointers or addresses might not fit into a
+@code{sizetype}, or if
+
+@item
+function pointers pointing into @var{as}, when invoked, should not be
+converted into addresses.
+
+@end enumerate
+
+This macro is defined in the IA-16 backend to suppress certain optimizations
+and processing steps involving @code{__far} pointers.
+@end defmac
+
+@defmac TARGET_WARN_ADDR_SPACE_SYNTAX_P (@var{as})
+This macro is not needed for most targets.  For the IA-16 target, it is used
+to issue a warning for declarations such as
+
+@smallexample
+char __far *p, *q;
+@end smallexample
+
+which might be parsed differently under GCC (@code{*q} is in @code{__far}
+space) and under older IA-16 compilers (@code{*q} is in generic space).  If
+defined, the macro should return true if such a warning might apply to
+declarations involving address space @var{as}.
+@end defmac
+
+@defmac TARGET_EXPAND_WEIRD_POINTER_PLUS_EXPR (@var{op0}, @var{op1}, @var{target}, @var{mode})
+This macro is not needed for most targets.  If defined, it says how to do
+pointer arithmetic over ``weird'' address spaces.
+
+More precisely, GCC invokes this macro on the processed operands of a
+@code{POINTER_PLUS_EXPR} tree, if the pointer/reference operand points into
+an address space for which @code{TARGET_ADDR_SPACE_WEIRD_P} is true.
+
+@var{op0} will be an RTX expanded from the first operand in the
+@code{POINTER_PLUS_EXPR} expression (i.e., the pointer/reference), and
+@var{op1} an RTX for the second operand (i.e., the unsigned displacement).
+The arguments @var{target} and @var{mode} have the same meanings as in
+@samp{expand_expr ()} and @samp{expand_expr_real ()}.
+
+This macro is defined in the IA-16 backend to implement @code{__far} pointer
+arithmetic in a proper way.
+@end defmac
+
+@defmac TARGET_ADDR_SPACE_CONVERT_WEIRD_MEMORY_ADDRESS (@var{to_mode}, @var{x}, @var{as}, @var{in_const}, @var{no_emit})
+This macro is not needed for most targets.  If defined, @emph{and} if
+@code{POINTERS_EXTEND_UNSIGNED} is undefined, this macro says how to convert
+from addresses to pointers, or from pointers to addresses, for ``weird''
+address spaces.  The arguments have the same meanings as in
+@samp{convert_memory_address_addr_space_1 ()}.
+
+This macro is defined in the IA-16 backend to implement conversions between
+@code{__far} pointers and @code{__far} addresses.
+@end defmac
+
+@defmac TARGET_ADDR_SPACE_MAY_HAVE_FUNCTIONS_P (@var{as})
+This macro is not needed for most targets.  If defined, this macro should
+return true if the backend supports having functions inside the non-generic
+address space @var{as}.  (@emph{Note:} This is an extension @emph{on top of}
+the N1275 proposal, which simply forbids functions in alternate address
+spaces.)
+
+This macro is defined in the IA-16 backend to implement @code{__far}
+functions and pointers to such functions.
+@end defmac
+
+@defmac TARGET_FUNCTION_ADDR_SPACE_FROM_RETURN_TYPE_P (@var{as})
+This macro is not needed for most targets.  If defined---and if
+@code{TARGET_ADDR_SPACE_MAY_HAVE_FUNCTIONS_P} is defined---this macro should
+return true, if GCC should treat a function as belonging to the address
+space @var{as}, whenever the function's return type is marked as belonging
+to @var{as} (and the function itself has no address space qualifier).
+
+This macro is defined in the IA-16 backend to implement the option
+@option{-mno-far-function-if-far-return-type}.
+@end defmac
+
 @node Misc
 @section Miscellaneous Parameters
 @cindex parameters, miscellaneous
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index f31c763..ceb77a4 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2220,6 +2220,25 @@ address where its value is either multiplied by a scale factor or
 added to another register (as well as added to a displacement).
 @end defmac
 
+@defmac MODE_SEGMENT_REG_CLASS (@var{outer_mode}, @var{inner_mode}, @var{index})
+A macro which, if defined, should return a register class to control the
+loading of addresses' ``segment'' components into registers.
+
+This macro is not needed for targets with only flat address spaces---that is
+to say, most targets.  It is used in the IA-16 backend to implement
+@code{__far} pointers.
+
+With this macro, if a memory address contains a segment component in the
+form of an RTL expression
+@smallexample
+(unspec:@var{outer_mode} [@var{expr} @dots{}] @var{index})
+@end smallexample
+then GCC will consult this macro to decide which register class to load the
+inner expression @var{expr} into.  @var{inner_mode} is the mode of this
+inner expression, while @var{outer_mode} and @var{index} are the mode and
+the operation code for the @samp{(unspec @dots{})} as a whole.
+@end defmac
+
 @defmac REGNO_OK_FOR_BASE_P (@var{num})
 A C expression which is nonzero if register number @var{num} is
 suitable for use as a base register in operand addresses.
@@ -7466,6 +7485,95 @@ c_register_addr_space ("__ea", ADDR_SPACE_EA);
 
 @hook TARGET_ADDR_SPACE_DEBUG
 
+@defmac TARGET_ADDR_SPACE_WEIRD_P (@var{as})
+This macro is not needed for most targets.  If defined, it should return
+true if pointers and addresses in the address space @var{as} may break
+certain assumptions.  In particular, it should return true if
+
+@enumerate
+@item
+pointer or address arithmetic does not work in the same way as integer
+arithmetic of the same modes, or if
+
+@item
+the difference between two pointers or addresses might not fit into a
+@code{sizetype}, or if
+
+@item
+function pointers pointing into @var{as}, when invoked, should not be
+converted into addresses.
+
+@end enumerate
+
+This macro is defined in the IA-16 backend to suppress certain optimizations
+and processing steps involving @code{__far} pointers.
+@end defmac
+
+@defmac TARGET_WARN_ADDR_SPACE_SYNTAX_P (@var{as})
+This macro is not needed for most targets.  For the IA-16 target, it is used
+to issue a warning for declarations such as
+
+@smallexample
+char __far *p, *q;
+@end smallexample
+
+which might be parsed differently under GCC (@code{*q} is in @code{__far}
+space) and under older IA-16 compilers (@code{*q} is in generic space).  If
+defined, the macro should return true if such a warning might apply to
+declarations involving address space @var{as}.
+@end defmac
+
+@defmac TARGET_EXPAND_WEIRD_POINTER_PLUS_EXPR (@var{op0}, @var{op1}, @var{target}, @var{mode})
+This macro is not needed for most targets.  If defined, it says how to do
+pointer arithmetic over ``weird'' address spaces.
+
+More precisely, GCC invokes this macro on the processed operands of a
+@code{POINTER_PLUS_EXPR} tree, if the pointer/reference operand points into
+an address space for which @code{TARGET_ADDR_SPACE_WEIRD_P} is true.
+
+@var{op0} will be an RTX expanded from the first operand in the
+@code{POINTER_PLUS_EXPR} expression (i.e., the pointer/reference), and
+@var{op1} an RTX for the second operand (i.e., the unsigned displacement).
+The arguments @var{target} and @var{mode} have the same meanings as in
+@samp{expand_expr ()} and @samp{expand_expr_real ()}.
+
+This macro is defined in the IA-16 backend to implement @code{__far} pointer
+arithmetic in a proper way.
+@end defmac
+
+@defmac TARGET_ADDR_SPACE_CONVERT_WEIRD_MEMORY_ADDRESS (@var{to_mode}, @var{x}, @var{as}, @var{in_const}, @var{no_emit})
+This macro is not needed for most targets.  If defined, @emph{and} if
+@code{POINTERS_EXTEND_UNSIGNED} is undefined, this macro says how to convert
+from addresses to pointers, or from pointers to addresses, for ``weird''
+address spaces.  The arguments have the same meanings as in
+@samp{convert_memory_address_addr_space_1 ()}.
+
+This macro is defined in the IA-16 backend to implement conversions between
+@code{__far} pointers and @code{__far} addresses.
+@end defmac
+
+@defmac TARGET_ADDR_SPACE_MAY_HAVE_FUNCTIONS_P (@var{as})
+This macro is not needed for most targets.  If defined, this macro should
+return true if the backend supports having functions inside the non-generic
+address space @var{as}.  (@emph{Note:} This is an extension @emph{on top of}
+the N1275 proposal, which simply forbids functions in alternate address
+spaces.)
+
+This macro is defined in the IA-16 backend to implement @code{__far}
+functions and pointers to such functions.
+@end defmac
+
+@defmac TARGET_FUNCTION_ADDR_SPACE_FROM_RETURN_TYPE_P (@var{as})
+This macro is not needed for most targets.  If defined---and if
+@code{TARGET_ADDR_SPACE_MAY_HAVE_FUNCTIONS_P} is defined---this macro should
+return true, if GCC should treat a function as belonging to the address
+space @var{as}, whenever the function's return type is marked as belonging
+to @var{as} (and the function itself has no address space qualifier).
+
+This macro is defined in the IA-16 backend to implement the option
+@option{-mno-far-function-if-far-return-type}.
+@end defmac
+
 @node Misc
 @section Miscellaneous Parameters
 @cindex parameters, miscellaneous
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index 0fcd9d9..20ad0d5 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -2536,7 +2536,7 @@ set_mem_attrs_for_spill (rtx mem)
   attrs = *get_mem_attrs (mem);
   attrs.expr = get_spill_slot_decl (true);
   attrs.alias = MEM_ALIAS_SET (DECL_RTL (attrs.expr));
-  attrs.addrspace = ADDR_SPACE_GENERIC;
+  attrs.addrspace = MEM_ADDR_SPACE (DECL_RTL (attrs.expr));
 
   /* We expect the incoming memory to be of the form:
 	(mem:MODE (plus (reg sfp) (const_int offset)))
diff --git a/gcc/explow.c b/gcc/explow.c
index c59d001..68fe51d 100644
--- a/gcc/explow.c
+++ b/gcc/explow.c
@@ -186,6 +186,25 @@ plus_constant (machine_mode mode, rtx x, HOST_WIDE_INT c,
     return x;
 }
 
+/* Like plus_constant, but X is assumed to be a pointer somewhere into an
+   address space AS, and AS may be "weird" (TARGET_ADDR_SPACE_WEIRD_P).  */
+
+rtx
+pointer_plus_constant (machine_mode mode, rtx x, HOST_WIDE_INT c,
+		       addr_space_t as, bool inplace)
+{
+#ifdef TARGET_ADDR_SPACE_WEIRD_P
+# ifdef TARGET_EXPAND_WEIRD_POINTER_PLUS_EXPR
+  machine_mode size_mode = TYPE_MODE (sizetype);
+  if (TARGET_ADDR_SPACE_WEIRD_P (as))
+    return TARGET_EXPAND_WEIRD_POINTER_PLUS_EXPR (x,
+						  gen_int_mode (c, size_mode),
+						  NULL_RTX, mode);
+# endif
+#endif
+  return plus_constant (mode, x, c, inplace);
+}
+
 /* If X is a sum, return a new sum like X but lacking any constant terms.
    Add all the removed constant terms into *CONSTPTR.
    X itself is not altered.  The result != X if and only if
@@ -277,7 +296,24 @@ convert_memory_address_addr_space_1 (machine_mode to_mode ATTRIBUTE_UNUSED,
 				     bool no_emit ATTRIBUTE_UNUSED)
 {
 #ifndef POINTERS_EXTEND_UNSIGNED
-  gcc_assert (GET_MODE (x) == to_mode || GET_MODE (x) == VOIDmode);
+# ifdef TARGET_ADDR_SPACE_WEIRD_P
+#  ifdef TARGET_ADDR_SPACE_CONVERT_WEIRD_MEMORY_ADDRESS
+  /* Special case for ia16-elf pointer -> address and address -> pointer
+     conversions.  Is there a better way?  */
+  if (GET_MODE (x) != to_mode && TARGET_ADDR_SPACE_WEIRD_P (as))
+    x = TARGET_ADDR_SPACE_CONVERT_WEIRD_MEMORY_ADDRESS (to_mode, x, as,
+							in_const, no_emit);
+#  endif
+# endif
+
+  if (! x || (GET_MODE (x) != to_mode && GET_MODE (x) != VOIDmode))
+    {
+      fprintf (stderr,
+	       "trying to convert pointer or address in address space %d\n"
+	       "with unexpected mode:\n", (int) as);
+      debug_rtx (x);
+      gcc_unreachable ();
+    }
   return x;
 #else /* defined(POINTERS_EXTEND_UNSIGNED) */
   machine_mode pointer_mode, address_mode, from_mode;
@@ -396,7 +432,11 @@ memory_address_addr_space (machine_mode mode, rtx x, addr_space_t as)
 
   /* By passing constant addresses through registers
      we get a chance to cse them.  */
-  if (! cse_not_expected && CONSTANT_P (x) && CONSTANT_ADDRESS_P (x))
+  if (! cse_not_expected && CONSTANT_P (x) && CONSTANT_ADDRESS_P (x)
+#ifdef TARGET_ADDR_SPACE_WEIRD_P
+      && ! TARGET_ADDR_SPACE_WEIRD_P (as)
+#endif
+      )
     x = force_reg (address_mode, x);
 
   /* We get better cse by rejecting indirect addressing at this stage.
diff --git a/gcc/expr.c b/gcc/expr.c
index 6a6a7d6..e081b1d 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -7759,7 +7759,8 @@ expand_expr_addr_expr_1 (tree exp, rtx target, machine_mode tmode,
       gcc_assert ((bitpos % BITS_PER_UNIT) == 0);
 
       result = convert_memory_address_addr_space (tmode, result, as);
-      result = plus_constant (tmode, result, bitpos / BITS_PER_UNIT);
+      result = pointer_plus_constant (tmode, result, bitpos / BITS_PER_UNIT,
+				      as);
       if (modifier < EXPAND_SUM)
 	result = force_operand (result, target);
     }
@@ -8274,6 +8275,20 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
       }
 
     case POINTER_PLUS_EXPR:
+#ifdef TARGET_ADDR_SPACE_WEIRD_P
+# ifdef TARGET_EXPAND_WEIRD_POINTER_PLUS_EXPR
+      /* Special case for ia16-elf.  */
+      if (TARGET_ADDR_SPACE_WEIRD_P (TYPE_ADDR_SPACE
+	  (TREE_TYPE (TREE_TYPE (treeop0)))))
+	{
+	  rtx op0 = NULL_RTX, op1 = NULL_RTX;
+
+	  expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1, modifier);
+	  return TARGET_EXPAND_WEIRD_POINTER_PLUS_EXPR (op0, op1, target,
+							tmode);
+	}
+# endif
+#endif
       /* Even though the sizetype mode and the pointer's mode can be different
          expand is able to handle this correctly and get the correct result out
          of the PLUS_EXPR code.  */
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 0f042b0..c78f81e 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -3735,6 +3735,10 @@ driver_handle_option (struct gcc_options *opts,
       printf ("%s\n", spec_machine);
       exit (0);
 
+    case OPT_dumpfullversion:
+      printf ("%s\n", BASEVER);
+      exit (0);
+
     case OPT__version:
       print_version = 1;
 
diff --git a/gcc/ira-color.c b/gcc/ira-color.c
index 8433479..985b019 100644
--- a/gcc/ira-color.c
+++ b/gcc/ira-color.c
@@ -178,6 +178,7 @@ static bitmap consideration_allocno_bitmap;
 
 /* All allocnos sorted according their priorities.  */
 static ira_allocno_t *sorted_allocnos;
+static int n_sorted_allocnos;
 
 /* Vec representing the stack of allocnos used during coloring.  */
 static vec<ira_allocno_t> allocno_stack_vec;
@@ -2937,6 +2938,17 @@ improve_allocation (void)
 		/* No intersection.  */
 		continue;
 	      ALLOCNO_HARD_REGNO (conflict_a) = -1;
+	      if (n == n_sorted_allocnos)
+		{
+		  ira_allocno_t *sorted_allocnos_expanded
+		    = (ira_allocno_t *) ira_allocate (sizeof (ira_allocno_t)
+						      * n_sorted_allocnos * 2);
+		  memcpy (sorted_allocnos_expanded, sorted_allocnos,
+			  sizeof (ira_allocno_t) * n_sorted_allocnos);
+		  ira_free (sorted_allocnos);
+		  sorted_allocnos = sorted_allocnos_expanded;
+		  n_sorted_allocnos *= 2;
+		}
 	      sorted_allocnos[n++] = conflict_a;
 	      if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL)
 		fprintf (ira_dump_file, "Spilling a%dr%d for a%dr%d\n",
@@ -4740,6 +4752,7 @@ ira_initiate_assign (void)
   sorted_allocnos
     = (ira_allocno_t *) ira_allocate (sizeof (ira_allocno_t)
 				      * ira_allocnos_num);
+  n_sorted_allocnos = ira_allocnos_num;
   consideration_allocno_bitmap = ira_allocate_bitmap ();
   initiate_cost_update ();
   allocno_priorities = (int *) ira_allocate (sizeof (int) * ira_allocnos_num);
@@ -4797,6 +4810,7 @@ fast_allocation (void)
 
   sorted_allocnos = (ira_allocno_t *) ira_allocate (sizeof (ira_allocno_t)
 						    * ira_allocnos_num);
+  n_sorted_allocnos = ira_allocnos_num;
   num = 0;
   FOR_EACH_ALLOCNO (a, ai)
     sorted_allocnos[num++] = a;
diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c
index f96fd45..866992e 100644
--- a/gcc/lra-constraints.c
+++ b/gcc/lra-constraints.c
@@ -351,6 +351,10 @@ namespace {
 
   private:
     struct address_info *m_ad;
+#ifdef MODE_SEGMENT_REG_CLASS
+    rtx *m_segment_loc;
+    rtx m_segment_reg;
+#endif
     rtx *m_base_loc;
     rtx m_base_reg;
     rtx *m_index_loc;
@@ -358,13 +362,42 @@ namespace {
   };
 }
 
+#ifdef MODE_SEGMENT_REG_CLASS
+static rtx *
+segment_subterm (rtx *segment_term)
+{
+  rtx e;
+  if (! segment_term)
+    return NULL;
+  e = *segment_term;
+  gcc_assert (GET_CODE (e) == UNSPEC);
+  if (XVECLEN (e, 0) < 1)
+    return NULL;
+  if (MODE_SEGMENT_REG_CLASS (GET_MODE (e), GET_MODE (XVECEXP (e, 0, 0)),
+			      XINT (e, 1)) == NO_REGS)
+    return NULL;
+  return &XVECEXP (e, 0, 0);
+}
+#endif
+
 address_eliminator::address_eliminator (struct address_info *ad)
   : m_ad (ad),
+#ifdef MODE_SEGMENT_REG_CLASS
+    m_segment_loc (strip_subreg (segment_subterm (ad->segment_term))),
+    m_segment_reg (NULL_RTX),
+#endif
     m_base_loc (strip_subreg (ad->base_term)),
     m_base_reg (NULL_RTX),
     m_index_loc (strip_subreg (ad->index_term)),
     m_index_reg (NULL_RTX)
 {
+#ifdef MODE_SEGMENT_REG_CLASS
+  if (m_segment_loc != NULL)
+    {
+      m_segment_reg = *m_segment_loc;
+      lra_eliminate_reg_if_possible (m_segment_loc);
+    }
+#endif
   if (m_base_loc != NULL)
     {
       m_base_reg = *m_base_loc;
@@ -381,6 +414,10 @@ address_eliminator::address_eliminator (struct address_info *ad)
 
 address_eliminator::~address_eliminator ()
 {
+#ifdef MODE_SEGMENT_REG_CLASS
+  if (m_segment_loc && *m_segment_loc != m_segment_reg)
+    *m_segment_loc = m_segment_reg;
+#endif
   if (m_base_loc && *m_base_loc != m_base_reg)
     {
       *m_base_loc = m_base_reg;
@@ -1661,6 +1698,10 @@ uses_hard_regs_p (rtx x, HARD_REG_SET set)
       struct address_info ad;
 
       decompose_mem_address (&ad, x);
+#ifdef MODE_SEGMENT_REG_CLASS
+      if (ad.segment_term != NULL && uses_hard_regs_p (*ad.segment_term, set))
+	return true;
+#endif
       if (ad.base_term != NULL && uses_hard_regs_p (*ad.base_term, set))
 	return true;
       if (ad.index_term != NULL && uses_hard_regs_p (*ad.index_term, set))
@@ -2957,6 +2998,8 @@ process_address_1 (int nop, bool check_only_p,
     decompose_mem_address (&ad, SUBREG_REG (op));
   else
     return false;
+
+
   /* If INDEX_REG_CLASS is assigned to base_term already and isn't to
      index_term, swap them so to avoid assigning INDEX_REG_CLASS to both
      when INDEX_REG_CLASS is a single register class.  */
@@ -2973,6 +3016,23 @@ process_address_1 (int nop, bool check_only_p,
     }
   if (! check_only_p)
     change_p = equiv_address_substitution (&ad);
+#ifdef MODE_SEGMENT_REG_CLASS
+  if (ad.segment_term != NULL)
+    {
+      rtx *term = ad.segment_term;
+      rtx *subterm = segment_subterm (term);
+      if (subterm)
+	{
+	  enum reg_class cl = MODE_SEGMENT_REG_CLASS (GET_MODE (*term),
+				GET_MODE (*subterm), XINT (*term, 1));
+	  if (cl != NO_REGS)
+	    {
+	      if (process_addr_reg (subterm, check_only_p, before, NULL, cl))
+		change_p = true;
+	    }
+	}
+    }
+#endif
   if (ad.base_term != NULL
       && (process_addr_reg
 	  (ad.base_term, check_only_p, before,
diff --git a/gcc/regcprop.c b/gcc/regcprop.c
index 933cc8a..a25ea49 100644
--- a/gcc/regcprop.c
+++ b/gcc/regcprop.c
@@ -631,6 +631,16 @@ replace_oldest_value_addr (rtx *loc, enum reg_class cl,
     case REG:
       return replace_oldest_value_reg (loc, cl, insn, vd);
 
+#ifdef MODE_SEGMENT_REG_CLASS
+    case UNSPEC:
+      if (XVECLEN (x, 0) < 1)
+	break;
+      if (MODE_SEGMENT_REG_CLASS (GET_MODE (x), GET_MODE (XVECEXP (x, 0, 0)),
+				  XINT (x, 1)) != NO_REGS)
+	return false;
+      break;
+#endif
+
     default:
       break;
     }
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 24496f4..4e7aee3 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -2026,7 +2026,9 @@ struct address_info {
        This value is entirely target-specific and is only called a "segment"
        because that's its most typical use.  It contains exactly one UNSPEC,
        pointed to by SEGMENT_TERM.  The contents of *SEGMENT do not need
-       reloading.
+       reloading (unless the back-end machine description defines the macro
+       MODE_SEGMENT_REG_CLASS (outer_mode, inner_mode, unspec_op), which will
+       control the reloading).
 
      - *BASE is a variable expression representing a base address.
        It contains exactly one REG, SUBREG or MEM, pointed to by BASE_TERM.
@@ -2656,6 +2658,8 @@ get_full_set_src_cost (rtx x, machine_mode mode, struct full_rtx_costs *c)
 /* In explow.c */
 extern HOST_WIDE_INT trunc_int_for_mode	(HOST_WIDE_INT, machine_mode);
 extern rtx plus_constant (machine_mode, rtx, HOST_WIDE_INT, bool = false);
+extern rtx pointer_plus_constant (machine_mode, rtx, HOST_WIDE_INT,
+				  addr_space_t, bool = false);
 
 /* In rtl.c */
 extern rtx rtx_alloc_stat (RTX_CODE MEM_STAT_DECL);
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index 876b90f..4508f41 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -3736,7 +3736,7 @@ subreg_get_info (unsigned int xregno, machine_mode xmode,
       rknown = true;
     }
   info->offset = (y_offset / (mode_multiple / nregs_multiple)) * nregs_ymode;
-  info->nregs = nregs_ymode;
+  info->nregs = hard_regno_nregs[xregno + info->offset][ymode];
 }
 
 /* This function returns the regno offset of a subreg expression.
diff --git a/gcc/testsuite/c-c++-common/Wduplicated-cond-1.c b/gcc/testsuite/c-c++-common/Wduplicated-cond-1.c
index 4763a84..c840655 100644
--- a/gcc/testsuite/c-c++-common/Wduplicated-cond-1.c
+++ b/gcc/testsuite/c-c++-common/Wduplicated-cond-1.c
@@ -1,7 +1,9 @@
 /* PR c/64249 */
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-Wduplicated-cond" } */
 
+#include <stdint.h>
+
 #ifndef __cplusplus
 # define bool _Bool
 # define true 1
@@ -179,7 +181,7 @@ fn9 (int i, int j, int k)
     return 0;
 }
 
-int
+int_least32_t
 fn10 (void)
 {
   if (foo ())
diff --git a/gcc/testsuite/c-c++-common/Wduplicated-cond-3.c b/gcc/testsuite/c-c++-common/Wduplicated-cond-3.c
index e3b5ac0..938dce6 100644
--- a/gcc/testsuite/c-c++-common/Wduplicated-cond-3.c
+++ b/gcc/testsuite/c-c++-common/Wduplicated-cond-3.c
@@ -1,7 +1,9 @@
 /* PR c/64249 */
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-Wall -Wno-duplicated-cond" } */
 
+#include <stdint.h>
+
 #ifndef __cplusplus
 # define bool _Bool
 # define true 1
@@ -183,7 +185,7 @@ fn9 (int i, int j, int k)
     return 0;
 }
 
-int
+int_least32_t
 fn10 (void)
 {
   if (foo ())
diff --git a/gcc/testsuite/c-c++-common/Wlogical-op-1.c b/gcc/testsuite/c-c++-common/Wlogical-op-1.c
index 33d4f38..2b9bea7 100644
--- a/gcc/testsuite/c-c++-common/Wlogical-op-1.c
+++ b/gcc/testsuite/c-c++-common/Wlogical-op-1.c
@@ -48,7 +48,9 @@ andfn (int a, int b)
 
   if (a > 0 && a > 1) {}
   if (a > -2 && a > 1) {}
+#if !defined(__SIZEOF_INT__) || !defined(__SIZEOF_SHORT__) || __SIZEOF_INT__ != __SIZEOF_SHORT__
   if (a && (short) a) {}
+#endif
   if ((char) a && a) {}
   if (++a && a) {}
   if (++a && ++a) {}
@@ -96,7 +98,9 @@ orfn (int a, int b)
 
   if (a > 0 || a > 1) {}
   if (a > -2 || a > 1) {}
+#if !defined(__SIZEOF_INT__) || !defined(__SIZEOF_SHORT__) || __SIZEOF_INT__ != __SIZEOF_SHORT__
   if (a || (short) a) {}
+#endif
   if ((char) a || a) {}
   if (++a || a) {}
   if (++a || ++a) {}
diff --git a/gcc/testsuite/c-c++-common/builtin-shuffle-1.c b/gcc/testsuite/c-c++-common/builtin-shuffle-1.c
index 30fd690..174a2e8 100644
--- a/gcc/testsuite/c-c++-common/builtin-shuffle-1.c
+++ b/gcc/testsuite/c-c++-common/builtin-shuffle-1.c
@@ -1,7 +1,7 @@
 /* PR c++/78089 */
 /* { dg-do run } */
 
-typedef int V __attribute__((vector_size (16)));
+typedef int V __attribute__((vector_size (4*sizeof (int))));
 V a, b, c;
 
 int
diff --git a/gcc/testsuite/c-c++-common/cpp/pr63831-1.c b/gcc/testsuite/c-c++-common/cpp/pr63831-1.c
index c9e7756..c899ead 100644
--- a/gcc/testsuite/c-c++-common/cpp/pr63831-1.c
+++ b/gcc/testsuite/c-c++-common/cpp/pr63831-1.c
@@ -1,5 +1,7 @@
 /* PR preprocessor/63831 */
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
+
+#include <stdint.h>
 
 #ifdef __has_attribute
 typedef char T1[__has_attribute (__noreturn__) == 200809 ? 1 : -1];
@@ -61,4 +63,4 @@ T18 t18;
 T19 t19;
 T20 t20;
 #endif
-int t21 = __has_attribute (noreturn) + __has_cpp_attribute (__malloc__);
+int_least32_t t21 = __has_attribute (noreturn) + __has_cpp_attribute (__malloc__);
diff --git a/gcc/testsuite/c-c++-common/cpp/pr63831-2.c b/gcc/testsuite/c-c++-common/cpp/pr63831-2.c
index 2479ce8..31a1940 100644
--- a/gcc/testsuite/c-c++-common/cpp/pr63831-2.c
+++ b/gcc/testsuite/c-c++-common/cpp/pr63831-2.c
@@ -1,5 +1,5 @@
 /* PR preprocessor/63831 */
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-save-temps" } */
 
 #include "pr63831-1.c"
diff --git a/gcc/testsuite/c-c++-common/pr41779.c b/gcc/testsuite/c-c++-common/pr41779.c
index 25b0b68..9a09e0c 100644
--- a/gcc/testsuite/c-c++-common/pr41779.c
+++ b/gcc/testsuite/c-c++-common/pr41779.c
@@ -1,10 +1,12 @@
 /* PR41779: Wconversion cannot see through real*integer promotions. */
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-skip-if "doubles are floats" { "avr-*-*" } { "*" } { "" } } */
 /* { dg-options "-std=c99 -Wconversion" { target c } } */
 /* { dg-options "-Wconversion" { target c++ } } */
 /* { dg-require-effective-target large_double } */
 
+#include <stdint.h>
+
 float f1(float x, unsigned short y)
 {
   return x * y;
@@ -25,7 +27,7 @@ float f4(float x, unsigned char y)
   return x * y;
 }
 
-float f5(float x, int y)
+float f5(float x, int_least32_t y)
 {
   return x * y; /* { dg-warning "conversion" } */
 }
@@ -50,7 +52,7 @@ double c4(float x, unsigned char y, int z)
   return z ? x + x : y;
 }
 
-double c5(float x, int y, int z)
+double c5(float x, int_least32_t y, int z)
 {
   return z ? x + x : y; /* { dg-warning "conversion" } */
 }
diff --git a/gcc/testsuite/c-c++-common/pr57793.c b/gcc/testsuite/c-c++-common/pr57793.c
index f271952..94fdf11 100644
--- a/gcc/testsuite/c-c++-common/pr57793.c
+++ b/gcc/testsuite/c-c++-common/pr57793.c
@@ -3,8 +3,8 @@
 struct A { unsigned a : 1; unsigned b : 1; };
 struct B     /* { dg-error "type .B. is too large" "" { target { c++ && ilp32 } } } */
 {
-  unsigned char c[0x40000000]; /* { dg-error "size of array .c. is too large" "" { target { ! int32plus } } } */
-  unsigned char d[0x40000ff0];/* { dg-error "size of array .d. is too large" "" { target { ! int32plus } } } */
+  unsigned char c[0x40000000L]; /* { dg-error "size of array .c. is too large" "" { target { ! int32plus } } } */
+  unsigned char d[0x40000ff0L];/* { dg-error "size of array .d. is too large" "" { target { ! int32plus } } } */
   struct A e;
 }; /* { dg-error "type .struct B. is too large" "" { target { c && ilp32 } } } */
 
diff --git a/gcc/testsuite/c-c++-common/pr60226.c b/gcc/testsuite/c-c++-common/pr60226.c
index 6a686d7..6e0f791 100644
--- a/gcc/testsuite/c-c++-common/pr60226.c
+++ b/gcc/testsuite/c-c++-common/pr60226.c
@@ -2,13 +2,24 @@
 /* { dg-do compile } */
 /* { dg-options "-Wno-c++-compat" { target c } } */
 
-typedef int __attribute__ ((aligned (1 << 28))) int28;
+#ifdef __ia16__
+#define SHIFTA 12
+#else
+#define SHIFTA 28
+#define SHIFTB 29
+#endif
+
+typedef int __attribute__ ((aligned (1 << SHIFTA))) int28;
 int28 foo[4] = {}; /* { dg-error "alignment of array elements is greater than element size" } */
-typedef int __attribute__ ((aligned (1 << 29))) int29; /* { dg-error "requested alignment is too large|maximum object file alignment" } */
+#ifndef __ia16__
+typedef int __attribute__ ((aligned (1 << SHIFTB))) int29; /* { dg-error "requested alignment is too large|maximum object file alignment" "" { target { ! ia16-*-* } } } */
+#endif
 
 void
 f (void)
 {
-  struct { __attribute__((aligned (1 << 28))) double a; } x1;
-  struct { __attribute__((aligned (1 << 29))) double a; } x2; /* { dg-error "requested alignment is too large" } */
+  struct { __attribute__((aligned (1 << SHIFTA))) double a; } x1;
+#ifndef __ia16__
+  struct { __attribute__((aligned (1 << SHIFTB))) double a; } x2; /* { dg-error "requested alignment is too large" "" { target { ! ia16-*-* } } } */
+#endif
 }
diff --git a/gcc/testsuite/c-c++-common/pr68657-1.c b/gcc/testsuite/c-c++-common/pr68657-1.c
index 3db6f49..17c13fc 100644
--- a/gcc/testsuite/c-c++-common/pr68657-1.c
+++ b/gcc/testsuite/c-c++-common/pr68657-1.c
@@ -1,5 +1,5 @@
 /* PR c/68657 */
-/* { dg-options "-Werror=sign-conversion -Werror=float-conversion -Werror=frame-larger-than=65536" } */
+/* { dg-options "-Werror=sign-conversion -Werror=float-conversion -Werror=frame-larger-than=8192" } */
 
 void
 f1 (void)
@@ -19,8 +19,8 @@ int f3 (char *);
 int
 f4 (void)
 {
-  char buf[131072];
+  char buf[16384];
   return f3 (buf);
-}		/* { dg-error "the frame size of 1\[0-9]* bytes is larger than 65536 bytes" } */
+}		/* { dg-error "the frame size of 1\[0-9]* bytes is larger than" } */
 
 /* { dg-prune-output "treated as errors" } */
diff --git a/gcc/testsuite/c-c++-common/pr68657-2.c b/gcc/testsuite/c-c++-common/pr68657-2.c
index 9eb68ce..032ddf4 100644
--- a/gcc/testsuite/c-c++-common/pr68657-2.c
+++ b/gcc/testsuite/c-c++-common/pr68657-2.c
@@ -1,8 +1,8 @@
 /* PR c/68657 */
 /* { dg-do compile } */
-/* { dg-options "-Werror=larger-than=65536" } */
+/* { dg-options "-Werror=larger-than=8192" } */
 
-int a[131072];	/* { dg-error "size of 'a' is \[1-9]\[0-9]* bytes" } */
+int a[16384/sizeof (int)];	/* { dg-error "size of 'a' is \[1-9]\[0-9]* bytes" } */
 int b[1024];	/* { dg-bogus "size of 'b' is \[1-9]\[0-9]* bytes" } */
 
 /* { dg-prune-output "treated as errors" } */
diff --git a/gcc/testsuite/c-c++-common/pr68657-3.c b/gcc/testsuite/c-c++-common/pr68657-3.c
index 84622fc..bf33a0c 100644
--- a/gcc/testsuite/c-c++-common/pr68657-3.c
+++ b/gcc/testsuite/c-c++-common/pr68657-3.c
@@ -1,13 +1,13 @@
 /* PR c/68657 */
 /* { dg-do compile } */
 
-#pragma GCC diagnostic error "-Wlarger-than=65536"
-int a[131072];	/* { dg-error "size of 'a' is \[1-9]\[0-9]* bytes" } */
+#pragma GCC diagnostic error "-Wlarger-than=8192"
+int a[16384/sizeof (int)];	/* { dg-error "size of 'a' is \[1-9]\[0-9]* bytes" } */
 int b[1024];	/* { dg-bogus "size of 'b' is \[1-9]\[0-9]* bytes" } */
-#pragma GCC diagnostic ignored "-Wlarger-than=65536"
-int c[131072];	/* { dg-bogus "size of 'c' is \[1-9]\[0-9]* bytes" } */
+#pragma GCC diagnostic ignored "-Wlarger-than=8192"
+int c[16384/sizeof (int)];	/* { dg-bogus "size of 'c' is \[1-9]\[0-9]* bytes" } */
 int d[1024];	/* { dg-bogus "size of 'd' is \[1-9]\[0-9]* bytes" } */
-#pragma GCC diagnostic warning "-Wlarger-than=65536"
-int e[131072];	/* { dg-warning "size of 'e' is \[1-9]\[0-9]* bytes" } */
+#pragma GCC diagnostic warning "-Wlarger-than=8192"
+int e[16384/sizeof (int)];	/* { dg-warning "size of 'e' is \[1-9]\[0-9]* bytes" } */
 int f[1024];	/* { dg-bogus "size of 'f' is \[1-9]\[0-9]* bytes" } */
 /* { dg-prune-output "treated as errors" } */
diff --git a/gcc/testsuite/c-c++-common/pr68833-1.c b/gcc/testsuite/c-c++-common/pr68833-1.c
index e0601b3..d15ae10 100644
--- a/gcc/testsuite/c-c++-common/pr68833-1.c
+++ b/gcc/testsuite/c-c++-common/pr68833-1.c
@@ -1,8 +1,8 @@
 /* PR c/68833 */
 /* { dg-do compile } */
-/* { dg-options "-Werror=larger-than-65536 -Werror=format -Werror=missing-noreturn" } */
+/* { dg-options "-Werror=larger-than-8192 -Werror=format -Werror=missing-noreturn" } */
 
-int a[131072];	/* { dg-error "size of 'a' is \[1-9]\[0-9]* bytes" } */
+int a[16384/sizeof (int)];	/* { dg-error "size of 'a' is \[1-9]\[0-9]* bytes" } */
 int b[1024];	/* { dg-bogus "size of 'b' is \[1-9]\[0-9]* bytes" } */
 
 void
diff --git a/gcc/testsuite/c-c++-common/rotate-1a.c b/gcc/testsuite/c-c++-common/rotate-1a.c
index 07f65e5..e4695f7 100644
--- a/gcc/testsuite/c-c++-common/rotate-1a.c
+++ b/gcc/testsuite/c-c++-common/rotate-1a.c
@@ -1,6 +1,8 @@
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
 /* { dg-options "-O2 -Wno-overflow" } */
 
+#include <stdint.h>
+
 extern
 #ifdef __cplusplus
 "C"
@@ -13,7 +15,7 @@ void abort (void);
 
 #include ROTATE_N
 
-unsigned int expected[] = {
+uint_least32_t expected[] = {
 0x91a2b3c0, 0x91a2b3c0, 0x2468acf0, 0x91a2b3c, 0xb3c2, 0xb3c2, 0xc3, 0xc3,
 0x91a2b3c0, 0x91a2b3c0, 0x2468acf0, 0x91a2b3c, 0xb3c2, 0xb3c2, 0xc3, 0xc3,
 0x91a2b3c0, 0x91a2b3c0, 0x2468acf0, 0x91a2b3c, 0xb3c2, 0xb3c2, 0xc3, 0xc3,
@@ -42,7 +44,7 @@ main ()
   return 0;
 #else
 #undef F
-#define F(n) if ((unsigned int) f##n (0x12345678U, 3) != expected[n - 1]) abort ();
+#define F(n) if ((uint_least32_t) f##n (0x12345678U, 3) != expected[n - 1]) abort ();
   ALL
   return 0;
 #endif
diff --git a/gcc/testsuite/c-c++-common/rotate-2a.c b/gcc/testsuite/c-c++-common/rotate-2a.c
index d709c0d..28890bc 100644
--- a/gcc/testsuite/c-c++-common/rotate-2a.c
+++ b/gcc/testsuite/c-c++-common/rotate-2a.c
@@ -1,4 +1,4 @@
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
 /* { dg-options "-O2 -Wno-overflow" } */
 
 #define ROTATE_N "rotate-2.c"
diff --git a/gcc/testsuite/c-c++-common/rotate-3a.c b/gcc/testsuite/c-c++-common/rotate-3a.c
index 450fc22..3cdfd19 100644
--- a/gcc/testsuite/c-c++-common/rotate-3a.c
+++ b/gcc/testsuite/c-c++-common/rotate-3a.c
@@ -1,4 +1,4 @@
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
 /* { dg-options "-O2 -Wno-overflow" } */
 
 #define ROTATE_N "rotate-4.c"
diff --git a/gcc/testsuite/c-c++-common/rotate-4a.c b/gcc/testsuite/c-c++-common/rotate-4a.c
index 450fc22..3cdfd19 100644
--- a/gcc/testsuite/c-c++-common/rotate-4a.c
+++ b/gcc/testsuite/c-c++-common/rotate-4a.c
@@ -1,4 +1,4 @@
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
 /* { dg-options "-O2 -Wno-overflow" } */
 
 #define ROTATE_N "rotate-4.c"
diff --git a/gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-14.c b/gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-14.c
index 6f03cf7..faa8b23 100644
--- a/gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-14.c
+++ b/gcc/testsuite/c-c++-common/torture/builtin-arith-overflow-14.c
@@ -1,6 +1,7 @@
 /* Test __builtin_{add,sub,mul}_overflow.  */
 /* { dg-do run } */
 /* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
+/* { dg-skip-if "Does not fit in 64kB" { "ia16-*-*" } }  */
 
 #include "builtin-arith-overflow-12.h"
 
diff --git a/gcc/testsuite/c-c++-common/torture/complex-sign-mul.c b/gcc/testsuite/c-c++-common/torture/complex-sign-mul.c
index a3274d2..2e300b5 100644
--- a/gcc/testsuite/c-c++-common/torture/complex-sign-mul.c
+++ b/gcc/testsuite/c-c++-common/torture/complex-sign-mul.c
@@ -2,6 +2,7 @@
    multiplication.  */
 /* { dg-do run } */
 /* { dg-options "-std=gnu99" { target c } } */
+/* { dg-additional-options "-mcmodel=small" { target ia16-*-* } } */
 
 #include "complex-sign.h"
 
diff --git a/gcc/testsuite/c-c++-common/torture/vector-compare-1.c b/gcc/testsuite/c-c++-common/torture/vector-compare-1.c
index 4cdfcf7..8823d9a 100644
--- a/gcc/testsuite/c-c++-common/torture/vector-compare-1.c
+++ b/gcc/testsuite/c-c++-common/torture/vector-compare-1.c
@@ -1,4 +1,5 @@
 /* { dg-do run } */
+/* { dg-additional-options "-mcmodel=small" { target ia16-*-* } } */
 #define vector(elcount, type)  \
 __attribute__((vector_size((elcount)*sizeof(type)))) type
 
diff --git a/gcc/testsuite/g++.dg/Wno-frame-address.C b/gcc/testsuite/g++.dg/Wno-frame-address.C
index a2df034..df13148 100644
--- a/gcc/testsuite/g++.dg/Wno-frame-address.C
+++ b/gcc/testsuite/g++.dg/Wno-frame-address.C
@@ -1,5 +1,5 @@
 // { dg-do compile }
-// { dg-skip-if "Cannot access arbitrary stack frames." { arm*-*-* hppa*-*-* ia64-*-* } }
+// { dg-skip-if "Cannot access arbitrary stack frames." { arm*-*-* hppa*-*-* ia64-*-* ia16-*-* } }
 // { dg-options "-Werror" }
 // { dg-additional-options "-mbackchain" { target s390*-*-* } }
 
diff --git a/gcc/testsuite/g++.dg/abi/scoped1.C b/gcc/testsuite/g++.dg/abi/scoped1.C
index 7589ed4..b16035d 100644
--- a/gcc/testsuite/g++.dg/abi/scoped1.C
+++ b/gcc/testsuite/g++.dg/abi/scoped1.C
@@ -1,4 +1,4 @@
-// { dg-do run { target c++11 } }
+// { dg-do run { target { c++11 && int32plus } } }
 // { dg-options "-fabi-version=0 -Wabi=2" }
 
 enum class A: short { a1, a2, a3 };
diff --git a/gcc/testsuite/g++.dg/conversion/simd3.C b/gcc/testsuite/g++.dg/conversion/simd3.C
index 8d96264..611ca2b 100644
--- a/gcc/testsuite/g++.dg/conversion/simd3.C
+++ b/gcc/testsuite/g++.dg/conversion/simd3.C
@@ -1,15 +1,17 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 
-typedef int myint;
+#include <stdint.h>
+
+typedef int32_t myint;
 
 float __attribute__((vector_size(16))) b;
-int __attribute__((vector_size(16))) d;
+int32_t __attribute__((vector_size(16))) d;
 myint __attribute__((vector_size(16))) d2;
-unsigned int __attribute__((vector_size(16))) e;
+uint32_t __attribute__((vector_size(16))) e;
 
 void foo()
 {
 	b + d; /* { dg-error "invalid operands to binary" } */
-	d += e; /* { dg-message "use -flax-vector-conversions to permit conversions between vectors with differing element types or numbers of subparts.*cannot convert '__vector.4. unsigned int' to '__vector.4. int' in assignment" } */
+	d += e; /* { dg-message "use -flax-vector-conversions to permit conversions between vectors with differing element types or numbers of subparts.*cannot convert '__vector.4. \(long \)\?unsigned int' to '__vector.4. \(long \)\?int' in assignment" } */
 	d2 += d;
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-52892-1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-52892-1.C
index 91e1ea7..6615b83 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-52892-1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-52892-1.C
@@ -1,7 +1,7 @@
 // PR c++/52892
 // { dg-do compile { target c++11 } }
 
-constexpr __SIZE_TYPE__ fibonacci(__SIZE_TYPE__ val) {
+constexpr __UINT_LEAST32_TYPE__ fibonacci(__UINT_LEAST32_TYPE__ val) {
   return (val <= 2) ? 1 : fibonacci(val - 1) + fibonacci(val - 2);
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-70001-1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-70001-1.C
index e68ff0e..d7f050a 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-70001-1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-70001-1.C
@@ -1,5 +1,6 @@
 // PR c++/70001
 // { dg-do compile { target c++11 } }
+// { dg-skip-if "Does not fit in 64kB" { "ia16-*-*" } }
 
 struct B
 {
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-70001-3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-70001-3.C
index 99d4c38..1ce54b0 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-70001-3.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-70001-3.C
@@ -1,5 +1,6 @@
 // PR c++/70001
 // { dg-do compile { target c++11 } }
+// { dg-skip-if "Does not fit in 64kB" { "ia16-*-*" } }
 
 #include <array>
 #include <complex>
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-70001-4.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-70001-4.C
index c1ab176..284ebbc 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-70001-4.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-70001-4.C
@@ -1,5 +1,6 @@
 // PR c++/70001
 // { dg-do compile { target c++11 } }
+// { dg-skip-if "Does not fit in 64kB" { "ia16-*-*" } }
 
 struct B
 {
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-bitfield3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-bitfield3.C
index c393db4..5a8d64a 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-bitfield3.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-bitfield3.C
@@ -1,16 +1,18 @@
 // PR c++/49136
 // { dg-do compile { target c++11 } }
 
+#include <stdint.h>
+
 struct S
 {
-  unsigned : 1; unsigned s : 27; unsigned : 4;
-  constexpr S (unsigned int x) : s(x) {}
+  uint_least32_t : 1; uint_least32_t s : 27; uint_least32_t : 4;
+  constexpr S (uint_least32_t x) : s(x) {}
 };
 
 template <typename S>
 struct T
 {
-  unsigned int t;
+  uint_least32_t t;
   constexpr T (S s) : t(s.s != 7 ? 0 : s.s) {}
   constexpr T (S s, S s2) : t(s.s != s2.s ? 0 : s.s) {}
 };
@@ -22,8 +24,8 @@ static_assert (t2.t == 7, "Error");
 
 struct U
 {
-  int a : 1; int s : 1;
-  constexpr U (int x, int y) : a (x), s (y) {}
+  int_least32_t a : 1; int_least32_t s : 1;
+  constexpr U (int_least32_t x, int_least32_t y) : a (x), s (y) {}
 };
 
 constexpr U u (0, -1), u2 (-1, -1);
diff --git a/gcc/testsuite/g++.dg/cpp0x/enum13.C b/gcc/testsuite/g++.dg/cpp0x/enum13.C
index 8335fad..d9a783f 100644
--- a/gcc/testsuite/g++.dg/cpp0x/enum13.C
+++ b/gcc/testsuite/g++.dg/cpp0x/enum13.C
@@ -1,5 +1,5 @@
 // PR c++/48780
-// { dg-do compile { target c++11 } }
+// { dg-do compile { target { c++11 && int32plus } } }
 // { dg-options "-fabi-version=5 -Wabi" }
 
 typedef __builtin_va_list __gnuc_va_list;
diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-52.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-52.C
index 0f87fd4..0c16563 100644
--- a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-52.C
+++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-52.C
@@ -1,7 +1,11 @@
 // { dg-do compile { target c++11 } }
 
-struct A {int i;}  a [[gnu::aligned(16)]];
-struct B {int i;} __attribute__((aligned(16))) b;
+#include <stdint.h>
+
+struct I {int_least32_t i;} __attribute__((aligned(4)));
+
+struct A {I i;}  a [[gnu::aligned(16)]];
+struct B {I i;} __attribute__((aligned(16))) b;
 
 int
 main ()
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist5.C b/gcc/testsuite/g++.dg/cpp0x/initlist5.C
index 5f253ca..bd3da44 100644
--- a/gcc/testsuite/g++.dg/cpp0x/initlist5.C
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist5.C
@@ -1,6 +1,7 @@
 // Test for narrowing diagnostics
 // { dg-do compile { target c++11 } }
 
+#include <stdint.h>
 #include <initializer_list>
 
 struct A { int i; int j; };
@@ -32,4 +33,4 @@ char c = char{ u };		// { dg-error "narrowing" }
 
 // PR c++/50011
 short unsigned su;
-int i { su };
+int_least32_t i { su };
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist7.C b/gcc/testsuite/g++.dg/cpp0x/initlist7.C
index 7dbbf2d..277bf89 100644
--- a/gcc/testsuite/g++.dg/cpp0x/initlist7.C
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist7.C
@@ -1,9 +1,11 @@
 // PR c++/37932
 // { dg-do compile { target c++11 } }
 
+#include <stdint.h>
+
 typedef enum { AA=1, BB=2 } my_enum;
 
-typedef struct { my_enum a:4 ; unsigned b:28; } stru;
+typedef struct { my_enum a:4 ; uint_least32_t b:28; } stru;
 
 void foo (char c, my_enum x, int i)
 {
diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr04.C b/gcc/testsuite/g++.dg/cpp0x/nullptr04.C
index 372ac51..7910dbf 100644
--- a/gcc/testsuite/g++.dg/cpp0x/nullptr04.C
+++ b/gcc/testsuite/g++.dg/cpp0x/nullptr04.C
@@ -5,12 +5,12 @@
 __extension__ typedef __INTPTR_TYPE__ intptr_t;
 
 const int n4 = static_cast<const int>(nullptr); // { dg-error "invalid static_cast " }
-const short int n5 = reinterpret_cast<short int>(nullptr); // { dg-error "loses precision" }
+const short int n5 = reinterpret_cast<short int>(nullptr); // { dg-error "loses precision" "" { target { ! ia16-*-* } } }
 const intptr_t n6 = reinterpret_cast<intptr_t>(nullptr);
 const intptr_t n7 = (intptr_t)nullptr;
 
 decltype(nullptr) mynull = 0;
 const int n8 = static_cast<const int>(mynull); // { dg-error "invalid static_cast " }
-const short int n9 = reinterpret_cast<short int>(mynull); // { dg-error "loses precision" }
+const short int n9 = reinterpret_cast<short int>(mynull); // { dg-error "loses precision" "" { target { ! ia16-*-* } } }
 const intptr_t n10 = reinterpret_cast<intptr_t>(mynull);
 const intptr_t n11 = (intptr_t)mynull;
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-value1.C b/gcc/testsuite/g++.dg/cpp0x/variadic-value1.C
index 179919a..3c2a4d3 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic-value1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-value1.C
@@ -1,18 +1,20 @@
 // PR c++/52796
 // { dg-do run { target c++11 } }
 
+#include <stdint.h>
+
 inline void *operator new(__SIZE_TYPE__ s, void *p) { return p; }
 
 struct A
 {
-  int i;
+  int_least32_t i;
   template<class... Ts>
   A(Ts&&... ts): i(ts...) { }
 };
 
 static union {
   unsigned char c[sizeof(A)];
-  int i;
+  int_least32_t i;
 };
 
 int main()
diff --git a/gcc/testsuite/g++.dg/cpp1y/digit-sep-neg.C b/gcc/testsuite/g++.dg/cpp1y/digit-sep-neg.C
index 833fab7..2410267 100644
--- a/gcc/testsuite/g++.dg/cpp1y/digit-sep-neg.C
+++ b/gcc/testsuite/g++.dg/cpp1y/digit-sep-neg.C
@@ -1,9 +1,11 @@
 // { dg-do compile { target c++14 } }
 
+#include <stdint.h>
+
 int
 main()
 {
-  int i = 0;
+  int_least32_t i = 0;
   i = 1048''576; // { dg-error "adjacent digit separators" }
   i = 0X'100000; // { dg-error "digit separator after base indicator" }
   i = 0x'100000; // { dg-error "digit separator after base indicator" }
@@ -25,6 +27,6 @@ main()
   float f = 1.602'176'565e-19'F; // { dg-error "digit separator outside digit sequence" }
 }
 
-// { dg-error "exponent has no digits" "exponent has no digits" { target *-*-* } 21 }
-// { dg-error "expected ';' before" "expected ';' before" { target *-*-* } 14 }
-// { dg-error "expected ';' before" "expected ';' before" { target *-*-* } 25 }
+// { dg-error "exponent has no digits" "exponent has no digits" { target *-*-* } 23 }
+// { dg-error "expected ';' before" "expected ';' before" { target *-*-* } 16 }
+// { dg-error "expected ';' before" "expected ';' before" { target *-*-* } 27 }
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr57644.C b/gcc/testsuite/g++.dg/cpp1y/pr57644.C
index ec595a2..aabe5c9 100644
--- a/gcc/testsuite/g++.dg/cpp1y/pr57644.C
+++ b/gcc/testsuite/g++.dg/cpp1y/pr57644.C
@@ -1,8 +1,10 @@
 // { dg-do compile { target c++14 } }
 
+#include <stdint.h>
+
 struct Foo
 {
-  unsigned i: 32;
+  uint_least32_t i: 32;
 };
 
 int
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ4.C b/gcc/testsuite/g++.dg/cpp1y/var-templ4.C
index 3cd84a8..718aef5 100644
--- a/gcc/testsuite/g++.dg/cpp1y/var-templ4.C
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ4.C
@@ -1,10 +1,12 @@
 // { dg-do compile { target c++14 } }
 
+#include <stdint.h>
+
 template<typename T>
-  constexpr int var = sizeof (T);
+  constexpr int_least32_t var = sizeof (T);
 
 template<>
-  constexpr int var<int> = 100000;
+  constexpr int_least32_t var<int> = 100000;
 
 int main ()
 {
diff --git a/gcc/testsuite/g++.dg/cpp1z/utf8-neg.C b/gcc/testsuite/g++.dg/cpp1z/utf8-neg.C
index 339f0e3..6cf71d2 100644
--- a/gcc/testsuite/g++.dg/cpp1z/utf8-neg.C
+++ b/gcc/testsuite/g++.dg/cpp1z/utf8-neg.C
@@ -4,4 +4,6 @@
 const static char c0 = u8'';		// { dg-error "empty character" }
 const static char c1 = u8'ab';  	// { dg-warning "multi-character character constant" }
 const static char c2 = u8'\u0124';	// { dg-warning "multi-character character constant" }
-const static char c3 = u8'\U00064321';  // { dg-warning "multi-character character constant" }
+#ifndef __ia16__
+const static char c3 = u8'\U00064321';  // { dg-warning "multi-character character constant" "" { target { ! ia16-*-* } } }
+#endif
diff --git a/gcc/testsuite/g++.dg/delayedfold/fwrapv1.C b/gcc/testsuite/g++.dg/delayedfold/fwrapv1.C
index 412535c..a45173b 100644
--- a/gcc/testsuite/g++.dg/delayedfold/fwrapv1.C
+++ b/gcc/testsuite/g++.dg/delayedfold/fwrapv1.C
@@ -1,6 +1,12 @@
 // PR c++/69631
 // { dg-options -fwrapv }
 
+#if __SIZEOF_INT__ == 2
+#define N 32767L
+#else
+#define N 32767
+#endif
+
 struct C {
-  static const unsigned short max = static_cast<unsigned short>((32767 * 2 + 1));
+  static const unsigned short max = static_cast<unsigned short>((N * 2 + 1));
 };
diff --git a/gcc/testsuite/g++.dg/eh/spbp.C b/gcc/testsuite/g++.dg/eh/spbp.C
index 181e65d..184a65a 100644
--- a/gcc/testsuite/g++.dg/eh/spbp.C
+++ b/gcc/testsuite/g++.dg/eh/spbp.C
@@ -1,6 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-gdwarf-2" } */
-/* { dg-skip-if "No Dwarf" { { *-*-aix* hppa*-*-hpux* } && { ! hppa*64*-*-* } } { "*" } { "" } } */
+/* { dg-skip-if "No Dwarf" { { *-*-aix* hppa*-*-hpux* ia16-*-* } && { ! hppa*64*-*-* } } { "*" } { "" } } */
 
 /* This was a bug on x86-darwin, where the register numbering for SP
    and BP was swapped (it's easy to do because on that port it's
diff --git a/gcc/testsuite/g++.dg/expr/bitfield9.C b/gcc/testsuite/g++.dg/expr/bitfield9.C
index 177f65b..64eabc4 100644
--- a/gcc/testsuite/g++.dg/expr/bitfield9.C
+++ b/gcc/testsuite/g++.dg/expr/bitfield9.C
@@ -1,14 +1,16 @@
 // PR c++/32346
-// { dg-do run }
+// { dg-do run { target { stdint_types } } }
 // { dg-options "-Wno-overflow" }
 
+#include <stdint.h>
+
 extern "C" void abort();
 
 struct S {
   long long i : 32;
 };
 
-void f(int i, int j) {
+void f(int_least32_t i, int j) {
   if (i != 0xabcdef01)
     abort();
   if (j != 0)
diff --git a/gcc/testsuite/g++.dg/ext/attribute-test-1.C b/gcc/testsuite/g++.dg/ext/attribute-test-1.C
index 93e08d7..4183d9a 100644
--- a/gcc/testsuite/g++.dg/ext/attribute-test-1.C
+++ b/gcc/testsuite/g++.dg/ext/attribute-test-1.C
@@ -1,25 +1,27 @@
-// { dg-do run }
+// { dg-do run { target { stdint_types } } }
 // { dg-options "" }
 // PR c++/13989
 
+#include <stdint.h>
+
 extern "C" void abort();
 
 #define vector __attribute__((vector_size(16)))
 
 struct Constants {
-   inline vector unsigned int deadbeef(void) const {
-       return (vector unsigned int){0xdeadbeef, 0xabababab, 0x55555555, 0x12345678};
+   inline vector uint32_t deadbeef(void) const {
+       return (vector uint32_t){0xdeadbeef, 0xabababab, 0x55555555, 0x12345678};
    };
 };
 
-inline vector unsigned int const_deadbeef(Constants &C)
+inline vector uint32_t const_deadbeef(Constants &C)
 {
   return C.deadbeef();
 }
 
 union u {
-              unsigned int f[4];
-              vector unsigned int v;
+              uint32_t f[4];
+              vector uint32_t v;
 } data;
 
 int main()
diff --git a/gcc/testsuite/g++.dg/ext/bitfield1.C b/gcc/testsuite/g++.dg/ext/bitfield1.C
index 25c90df..035329f 100644
--- a/gcc/testsuite/g++.dg/ext/bitfield1.C
+++ b/gcc/testsuite/g++.dg/ext/bitfield1.C
@@ -1,10 +1,12 @@
 // PR c++/30328
-// { dg-do link }
+// { dg-do link { target { stdint_types } } }
 // { dg-options "" }
 
+#include <stdint.h>
+
 struct S
 {
-  signed int a:17;
+  int_least32_t a:17;
 } x;
 
 typedef typeof (x.a) foo;
@@ -15,7 +17,7 @@ T* inc(T* p) { return p+1; }
 int main ()
 {
   foo x[2] = { 1,2 };
-  int y[2] = { 1,2 };
+  int_least32_t y[2] = { 1,2 };
   *inc(x);
   *inc(y);
   return 0;
diff --git a/gcc/testsuite/g++.dg/ext/flexary13.C b/gcc/testsuite/g++.dg/ext/flexary13.C
index 462ed65..b054c5d 100644
--- a/gcc/testsuite/g++.dg/ext/flexary13.C
+++ b/gcc/testsuite/g++.dg/ext/flexary13.C
@@ -1,16 +1,18 @@
-// { dg-do compile }
+// { dg-do compile { target { stdint_types } } }
 // { dg-options -Wno-pedantic }
 
+#include <stdint.h>
+
 #define STR(s) #s
 #define ASSERT(exp) \
   ((exp) ? (void)0 : (void)(__builtin_printf ("%s:%i: assertion %s failed\n", \
                      __FILE__, __LINE__, STR(exp)), \
                       __builtin_abort ()))
 
-struct Ax { int n, a[]; };
-struct AAx { int i; Ax ax; };
+struct Ax { int_least32_t n, a[]; };
+struct AAx { int_least32_t i; Ax ax; };
 
-int i = 12345678;
+int_least32_t i = 12345678;
 
 int main ()
 {
@@ -44,7 +46,7 @@ int main ()
     ASSERT (s.n == 456 && s.a [0] == i);
   }
   {
-    int j = i + 1, k = j + 1;
+    int_least32_t j = i + 1, k = j + 1;
     Ax s =
       { 3, { i, j, k } }; // dg-warning "initialization of a flexible array member" }
     ASSERT (s.n == 3 && s.a [0] == i && s.a [1] == j && s.a [2] == k);
diff --git a/gcc/testsuite/g++.dg/ext/utf-cvt.C b/gcc/testsuite/g++.dg/ext/utf-cvt.C
index 366c3d4..d402dba 100644
--- a/gcc/testsuite/g++.dg/ext/utf-cvt.C
+++ b/gcc/testsuite/g++.dg/ext/utf-cvt.C
@@ -3,15 +3,19 @@
 /* { dg-do compile { target c++11 } } */
 /* { dg-options "-Wall -Wconversion -Wsign-conversion -Wsign-promo" } */
 
+#ifndef __INT_LEAST32_TYPE__
+#define __INT_LEAST32_TYPE__ int
+#endif
+
 extern void f_c (char);
 extern void fsc (signed char);
 extern void fuc (unsigned char);
 extern void f_s (short);
 extern void fss (signed short);
 extern void fus (unsigned short);
-extern void f_i (int);
-extern void fsi (signed int);
-extern void fui (unsigned int);
+extern void f_i (__INT_LEAST32_TYPE__);
+extern void fsi (signed __INT_LEAST32_TYPE__);
+extern void fui (unsigned __INT_LEAST32_TYPE__);
 extern void f_l (long);
 extern void fsl (signed long);
 extern void ful (unsigned long);
@@ -46,8 +50,8 @@ void m(char16_t c0, char32_t c1)
     f_i (c1);	/* { dg-warning "change the sign" } */
     fsi (c1);	/* { dg-warning "change the sign" } */
     fui (c1);
-    f_l (c1);	/* { dg-warning "change the sign" "" { target { llp64 || ilp32 } } } */
-    fsl (c1);	/* { dg-warning "change the sign" "" { target { llp64 || ilp32 } } } */
+    f_l (c1);	/* { dg-warning "change the sign" "" { target { llp64 || { ilp32 || ia16-*-* } } } } */
+    fsl (c1);	/* { dg-warning "change the sign" "" { target { llp64 || { ilp32 || ia16-*-* } } } } */
     ful (c1);
     f_ll (c1);
     fsll (c1);
diff --git a/gcc/testsuite/g++.dg/ext/vector28.C b/gcc/testsuite/g++.dg/ext/vector28.C
index ea48c96..aeb9d78 100644
--- a/gcc/testsuite/g++.dg/ext/vector28.C
+++ b/gcc/testsuite/g++.dg/ext/vector28.C
@@ -1,6 +1,8 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 
-typedef int veci __attribute__ ((vector_size (4 * sizeof (int))));
+#include <stdint.h>
+
+typedef int32_t veci __attribute__ ((vector_size (4 * sizeof (int32_t))));
 typedef float vecf __attribute__ ((vector_size (4 * sizeof (float))));
 
 void f (veci *a, vecf *b, int c)
diff --git a/gcc/testsuite/g++.dg/ext/vla15.C b/gcc/testsuite/g++.dg/ext/vla15.C
index feeb49f..bccc2c0 100644
--- a/gcc/testsuite/g++.dg/ext/vla15.C
+++ b/gcc/testsuite/g++.dg/ext/vla15.C
@@ -1,13 +1,15 @@
 // PR c++/44613
-// { dg-do run }
+// { dg-do run { target { stdint_types } } }
 // { dg-options "" }
 
+#include <stdint.h>
+
 void *volatile p;
 
 int
 main (void)
 {
-  int n = 0;
+  int_least32_t n = 0;
  lab:;
   int x[n % 1000 + 1];
   x[0] = 1;
diff --git a/gcc/testsuite/g++.dg/init/array11.C b/gcc/testsuite/g++.dg/init/array11.C
index e52effe..f4ca0cc 100644
--- a/gcc/testsuite/g++.dg/init/array11.C
+++ b/gcc/testsuite/g++.dg/init/array11.C
@@ -9,7 +9,11 @@
 
 int x;
 
+#if __SIZEOF_SIZE_T__ == 2
+typedef __UINT_LEAST32_TYPE__ size_t;
+#else
 typedef __SIZE_TYPE__ size_t;
+#endif
 
 struct gdt
 {
@@ -21,7 +25,7 @@ struct gdt gdt_table[2]=
 {
     {
 		0,
-		( (((size_t)(&x))<<(24))&(-1<<(8)) ),
+		( (((size_t)(__SIZE_TYPE__)(&x))<<(24))&(-1<<(8)) ),
     },
 };
 }
diff --git a/gcc/testsuite/g++.dg/init/array15.C b/gcc/testsuite/g++.dg/init/array15.C
index 17160d0..c9302e4 100644
--- a/gcc/testsuite/g++.dg/init/array15.C
+++ b/gcc/testsuite/g++.dg/init/array15.C
@@ -1,4 +1,5 @@
 // { dg-do run }
+// { dg-skip-if "Does not fit in 64kB" { "ia16-*-*" } }
 
 // Copyright (C) 2004 Free Software Foundation, Inc.
 // Contributed by Nathan Sidwell 8 Dec 2004 <nathan@codesourcery.com>
diff --git a/gcc/testsuite/g++.dg/init/array16.C b/gcc/testsuite/g++.dg/init/array16.C
index 188d1a8..37d02b7 100644
--- a/gcc/testsuite/g++.dg/init/array16.C
+++ b/gcc/testsuite/g++.dg/init/array16.C
@@ -1,6 +1,6 @@
 // Causes timeout for the MMIX simulator on a 3GHz P4 and we can't
 // have "compile" for some targets and "run" for others.
-// { dg-do run { target { ! mmix-*-* } } }
+// { dg-do run { target { ! "mmix-*-* ia16-*-*" } } }
 // { dg-options "-mstructure-size-boundary=8" { target arm*-*-* } }
 
 // Copyright (C) 2004 Free Software Foundation, Inc.
diff --git a/gcc/testsuite/g++.dg/init/array4.C b/gcc/testsuite/g++.dg/init/array4.C
index 67519bf..85d7052 100644
--- a/gcc/testsuite/g++.dg/init/array4.C
+++ b/gcc/testsuite/g++.dg/init/array4.C
@@ -10,7 +10,11 @@
 class Array
 {
 public:
+#ifdef __ia16__
+   std::string m_array[5][10][15];
+#else
    std::string m_array[10][20][30];
+#endif
 };
 
 Array func()
diff --git a/gcc/testsuite/g++.dg/init/const7.C b/gcc/testsuite/g++.dg/init/const7.C
index e1f31bc..11ebafe 100644
--- a/gcc/testsuite/g++.dg/init/const7.C
+++ b/gcc/testsuite/g++.dg/init/const7.C
@@ -3,7 +3,7 @@
 
 struct s { int x, y; };
 short offsets[1] = {
-  ((char*) &(((struct s*)16)->y) - (char *)16), // { dg-message "narrowing" "" { target c++11 } }
+  ((char*) &(((struct s*)16)->y) - (char *)16), // { dg-message "narrowing" "" { target { c++11 && int32plus } } }
 };
 
 // This ensures that we get a dump whether or not the bug is present.
diff --git a/gcc/testsuite/g++.dg/init/new44.C b/gcc/testsuite/g++.dg/init/new44.C
index ab6e348..900bb51 100644
--- a/gcc/testsuite/g++.dg/init/new44.C
+++ b/gcc/testsuite/g++.dg/init/new44.C
@@ -1,4 +1,5 @@
 // { dg-do compile }
+// { dg-options "-Wno-overflow" }
 
 // Test for PR c++/67927 - array new expression with excessive number
 // of elements not diagnosed.
@@ -24,6 +25,7 @@
 
 // For convenience.
 #define MAX __SIZE_MAX__
+#define MAX2 (__SIZE_MAX__/2 - (__SIZEOF_SIZE_T__ - 1))
 
 typedef __typeof__ (sizeof 0) size_t;
 
@@ -40,23 +42,11 @@ test_one_dim_char_array ()
     p = new char [MAX - 1];             // { dg-error "size of array" }
     p = new char [MAX - 2];             // { dg-error "size of array" }
     p = new char [MAX - 99];            // { dg-error "size of array" }
-    p = new char [MAX / 2];             // { dg-error "size of array" }
-    p = new char [MAX / 2 - 1];         // { dg-error "size of array" }
-    p = new char [MAX / 2 - 2];         // { dg-error "size of array" }
-
-    // Avoid testing the expressions below since whether or not they
-    // are accepted depends on the precision of size_t (which also
-    // determines the size of the cookie).
-    // p = new char [MAX / 2 - 3];
-    // p = new char [MAX / 2 - 4];
-    // p = new char [MAX / 2 - 5];
-    // p = new char [MAX / 2 - 6];
-
-    // The following expressions are accepted on ILP32 as well LP64
-    // (they will be diagnosed on LP128 if there ever is such a data
-    // model).
-    p = new char [MAX / 2 - 7];         // okay
-    p = new char [MAX / 2 - 8];         // okay
+    p = new char [MAX2 + 3];            // { dg-error "size of array" }
+    p = new char [MAX2 + 2];            // { dg-error "size of array" }
+    p = new char [MAX2 + 1];            // { dg-error "size of array" }
+    p = new char [MAX2];                // okay
+    p = new char [MAX2 - 1];            // okay
 }
 
 static void __attribute__ ((used))
@@ -75,12 +65,8 @@ test_one_dim_short_array ()
     p = new short [MAX / 2 - 6];        // { dg-error "size of array" }
     p = new short [MAX / 2 - 7];        // { dg-error "size of array" }
     p = new short [MAX / 2 - 8];        // { dg-error "size of array" }
-    p = new short [MAX / 4];            // { dg-error "size of array" }
-
-    // Avoid exercising data model-dependent expressions.
-    // p = new short [MAX / 4 - 1];
-
-    p = new short [MAX / 4 - 4];        // okay
+    p = new short [MAX2 / 2 + 1];       // { dg-error "size of array" }
+    p = new short [MAX2 / 2];           // okay
 }
 
 // Exercise new expression with two-dimensional arrays or char.
@@ -91,18 +77,11 @@ test_two_dim_char_array ()
     p = new char [1][MAX - 1];          // { dg-error "size of unnamed array" }
     p = new char [1][MAX - 2];          // { dg-error "size of unnamed array" }
     p = new char [1][MAX - 99];         // { dg-error "size of unnamed array" }
-    p = new char [1][MAX / 2];          // { dg-error "size of array" }
-    p = new char [1][MAX / 2 - 1];      // { dg-error "size of array" }
-    p = new char [1][MAX / 2 - 2];      // { dg-error "size of array" }
-
-    // Avoid exercising data model-dependent expressions.
-    // p = new char [1][MAX / 2 - 3];
-    // p = new char [1][MAX / 2 - 4];
-    // p = new char [1][MAX / 2 - 5];
-    // p = new char [1][MAX / 2 - 6];
-
-    p = new char [1][MAX / 2 - 7];      // okay
-    p = new char [1][MAX / 2 - 8];      // okay
+    p = new char [1][MAX2 + 3];         // { dg-error "size of \(unnamed \)\?array" }
+    p = new char [1][MAX2 + 2];         // { dg-error "size of \(unnamed \)\?array" }
+    p = new char [1][MAX2 + 1];         // { dg-error "size of array" }
+    p = new char [1][MAX2];             // okay
+    p = new char [1][MAX2 - 1];         // okay
 
     p = new char [2][MAX];              // { dg-error "size of unnamed array" }
     p = new char [2][MAX - 1];          // { dg-error "size of unnamed array" }
@@ -123,18 +102,11 @@ test_two_dim_char_array ()
     p = new char [MAX][MAX / 2 - 8];    // { dg-error "size of array" }
     p = new char [MAX][2];              // { dg-error "size of array" }
     p = new char [MAX][1];              // { dg-error "size of array" }
-    p = new char [MAX / 2][1];          // { dg-error "size of array" }
-    p = new char [MAX / 2 - 1][1];      // { dg-error "size of array" }
-    p = new char [MAX / 2 - 2][1];      // { dg-error "size of array" }
-
-    // Avoid exercising data model-dependent expressions.
-    // p = new char [MAX / 2 - 3][1];
-    // p = new char [MAX / 2 - 4][1];
-    // p = new char [MAX / 2 - 5][1];
-    // p = new char [MAX / 2 - 6][1];
-
-    p = new char [MAX / 2 - 7][1];      // okay
-    p = new char [MAX / 2 - 8][1];      // okay
+    p = new char [MAX2 + 3][1];         // { dg-error "size of array" }
+    p = new char [MAX2 + 2][1];         // { dg-error "size of array" }
+    p = new char [MAX2 + 1][1];         // { dg-error "size of array" }
+    p = new char [MAX2][1];             // okay
+    p = new char [MAX2 - 1][1];         // okay
 }
 
 
@@ -146,18 +118,11 @@ test_three_dim_char_array ()
     p = new char [1][1][MAX - 1];       // { dg-error "size of unnamed array" }
     p = new char [1][1][MAX - 2];       // { dg-error "size of unnamed array" }
     p = new char [1][1][MAX - 99];      // { dg-error "size of unnamed array" }
-    p = new char [1][1][MAX / 2];       // { dg-error "size of array" }
-    p = new char [1][1][MAX / 2 - 1];   // { dg-error "size of array" }
-    p = new char [1][1][MAX / 2 - 2];   // { dg-error "size of array" }
-
-    // Avoid exercising data model-dependent expressions.
-    // p = new char [1][1][MAX / 2 - 3];
-    // p = new char [1][1][MAX / 2 - 4];
-    // p = new char [1][1][MAX / 2 - 5];
-    // p = new char [1][1][MAX / 2 - 6];
-
-    p = new char [1][1][MAX / 2 - 7];   // okay
-    p = new char [1][1][MAX / 2 - 8];   // okay
+    p = new char [1][1][MAX2 + 3];      // { dg-error "size of \(unnamed \)\?array" }
+    p = new char [1][1][MAX2 + 2];      // { dg-error "size of \(unnamed \)\?array" }
+    p = new char [1][1][MAX2 + 1];      // { dg-error "size of array" }
+    p = new char [1][1][MAX2];          // okay
+    p = new char [1][1][MAX2 - 1];      // okay
 
     p = new char [1][2][MAX];           // { dg-error "size of unnamed array" }
     p = new char [1][2][MAX - 1];       // { dg-error "size of unnamed array" }
@@ -172,14 +137,9 @@ test_three_dim_char_array ()
     p = new char [1][2][MAX / 2 - 6];   // { dg-error "size of unnamed array" }
     p = new char [1][2][MAX / 2 - 7];   // { dg-error "size of unnamed array" }
     p = new char [1][2][MAX / 2 - 8];   // { dg-error "size of unnamed array" }
-    p = new char [1][2][MAX / 4];       // { dg-error "size of array" }
-
-    // Avoid exercising data model-dependent expressions.
-    // p = new char [1][2][MAX / 4 - 1];
-    // p = new char [1][2][MAX / 4 - 2];
-
-    p = new char [1][2][MAX / 4 - 3];   // okay
-    p = new char [1][2][MAX / 4 - 4];   // okay
+    p = new char [1][2][MAX2 / 2 + 1];  // { dg-error "size of \(unnamed \)\?array" }
+    p = new char [1][2][MAX2 / 2];      // okay
+    p = new char [1][2][MAX2 / 2 - 1];  // okay
 
     p = new char [2][1][MAX];           // { dg-error "size of unnamed array" }
     p = new char [2][1][MAX - 1];       // { dg-error "size of unnamed array" }
@@ -194,14 +154,9 @@ test_three_dim_char_array ()
     p = new char [2][1][MAX / 2 - 6];   // { dg-error "size of array" }
     p = new char [2][1][MAX / 2 - 7];   // { dg-error "size of array" }
     p = new char [2][1][MAX / 2 - 8];   // { dg-error "size of array" }
-    p = new char [2][1][MAX / 4];       // { dg-error "size of array" }
-
-    // Avoid exercising data model-dependent expressions.
-    // p = new char [2][1][MAX / 4 - 1];
-    // p = new char [2][1][MAX / 4 - 2];
-
-    p = new char [2][1][MAX / 4 - 3];   // okay
-    p = new char [2][1][MAX / 4 - 4];   // okay
+    p = new char [2][1][MAX2 / 2 + 1];  // { dg-error "size of array" }
+    p = new char [2][1][MAX2 / 2];      // okay
+    p = new char [2][1][MAX2 / 2 - 1];  // okay
 
     p = new char [2][2][MAX];           // { dg-error "size of unnamed array" }
     p = new char [2][2][MAX - 1];       // { dg-error "size of unnamed array" }
@@ -289,8 +244,12 @@ test_N_dim_char_array ()
 {
 #if __SIZEOF_SIZE_T__ == 8
     enum { N = 256 };
-#else
+#elif __SIZEOF_SIZE_T__ == 4
     enum { N = 16 };
+#elif __SIZEOF_SIZE_T__ == 2
+    enum { N = 4 };
+#else
+    #error Adjust the testcase to handle this size_t
 #endif
 
     p = new char        [N][N][N][N][N][N][N];
@@ -319,23 +278,11 @@ test_one_dim_byte_array (void *p)
     p = new (p) B [MAX - 1];            // { dg-error "size of array" }
     p = new (p) B [MAX - 2];            // { dg-error "size of array" }
     p = new (p) B [MAX - 99];           // { dg-error "size of array" }
-    p = new (p) B [MAX / 2];            // { dg-error "size of array" }
-    p = new (p) B [MAX / 2 - 1];        // { dg-error "size of array" }
-    p = new (p) B [MAX / 2 - 2];        // { dg-error "size of array" }
-
-    // Avoid testing the expressions below since whether or not they
-    // are accepted depends on the precision of size_t (which determines
-    // the size of the cookie).
-    // p = new (p) B [MAX / 2 - 3];
-    // p = new (p) B [MAX / 2 - 4];
-    // p = new (p) B [MAX / 2 - 5];
-    // p = new (p) B [MAX / 2 - 6];
-
-    // The following expressions are accepted on ILP32 as well LP64
-    // (they will be diagnosed on LP128 if there ever is such a data
-    // model).
-    p = new (p) B [MAX / 2 - 7];         // okay
-    p = new (p) B [MAX / 2 - 8];         // okay
+    p = new (p) B [MAX2 + 3];           // { dg-error "size of array" }
+    p = new (p) B [MAX2 + 2];           // { dg-error "size of array" }
+    p = new (p) B [MAX2 + 1];           // { dg-error "size of array" }
+    p = new (p) B [MAX2];               // okay
+    p = new (p) B [MAX2 - 1];           // okay
 }
 
 // Exercise placement new expression with two-dimensional arrays.
@@ -346,18 +293,11 @@ test_placement_two_dim_byte_struct_array (void *p)
     p = new (p) B [1][MAX - 1];         // { dg-error "size of unnamed array" }
     p = new (p) B [1][MAX - 2];         // { dg-error "size of unnamed array" }
     p = new (p) B [1][MAX - 99];        // { dg-error "size of unnamed array" }
-    p = new (p) B [1][MAX / 2];         // { dg-error "size of array" }
-    p = new (p) B [1][MAX / 2 - 1];     // { dg-error "size of array" }
-    p = new (p) B [1][MAX / 2 - 2];     // { dg-error "size of array" }
-
-    // Avoid exercising data model-dependent expressions.
-    // p = new (p) B [1][MAX / 2 - 3];
-    // p = new (p) B [1][MAX / 2 - 4];
-    // p = new (p) B [1][MAX / 2 - 5];
-    // p = new (p) B [1][MAX / 2 - 6];
-
-    p = new (p) B [1][MAX / 2 - 7];      // okay
-    p = new (p) B [1][MAX / 2 - 8];      // okay
+    p = new (p) B [1][MAX2 + 3];        // { dg-error "size of \(unnamed \)\?array" }
+    p = new (p) B [1][MAX2 + 2];        // { dg-error "size of \(unnamed \)\?array" }
+    p = new (p) B [1][MAX2 + 1];        // { dg-error "size of array" }
+    p = new (p) B [1][MAX2];            // okay
+    p = new (p) B [1][MAX2 - 1];        // okay
 
     p = new (p) B [2][MAX];             // { dg-error "size of unnamed array" }
     p = new (p) B [2][MAX - 1];         // { dg-error "size of unnamed array" }
@@ -378,18 +318,11 @@ test_placement_two_dim_byte_struct_array (void *p)
     p = new (p) B [MAX][MAX / 2 - 8];   // { dg-error "size of array" }
     p = new (p) B [MAX][2];             // { dg-error "size of array" }
     p = new (p) B [MAX][1];             // { dg-error "size of array" }
-    p = new (p) B [MAX / 2][1];         // { dg-error "size of array" }
-    p = new (p) B [MAX / 2 - 1][1];     // { dg-error "size of array" }
-    p = new (p) B [MAX / 2 - 2][1];     // { dg-error "size of array" }
-
-    // Avoid exercising data model-dependent expressions.
-    // p = new (p) B [MAX / 2 - 3][1];
-    // p = new (p) B [MAX / 2 - 4][1];
-    // p = new (p) B [MAX / 2 - 5][1];
-    // p = new (p) B [MAX / 2 - 6][1];
-
-    p = new (p) B [MAX / 2 - 7][1];      // okay
-    p = new (p) B [MAX / 2 - 8][1];      // okay
+    p = new (p) B [MAX2 + 3][1];        // { dg-error "size of array" }
+    p = new (p) B [MAX2 + 2][1];        // { dg-error "size of array" }
+    p = new (p) B [MAX2 + 1][1];        // { dg-error "size of array" }
+    p = new (p) B [MAX2][1];            // okay
+    p = new (p) B [MAX2 - 1][1];        // okay
 }
 
 
@@ -401,18 +334,11 @@ test_placement_three_dim_byte_struct_array (void *p)
     p = new (p) B [1][1][MAX - 1];      // { dg-error "size of unnamed array" }
     p = new (p) B [1][1][MAX - 2];      // { dg-error "size of unnamed array" }
     p = new (p) B [1][1][MAX - 99];     // { dg-error "size of unnamed array" }
-    p = new (p) B [1][1][MAX / 2];      // { dg-error "size of array" }
-    p = new (p) B [1][1][MAX / 2 - 1];  // { dg-error "size of array" }
-    p = new (p) B [1][1][MAX / 2 - 2];  // { dg-error "size of array" }
-
-    // Avoid exercising data model-dependent expressions.
-    // p = new (p) B [1][1][MAX / 2 - 3];
-    // p = new (p) B [1][1][MAX / 2 - 4];
-    // p = new (p) B [1][1][MAX / 2 - 5];
-    // p = new (p) B [1][1][MAX / 2 - 6];
-
-    p = new (p) B [1][1][MAX / 2 - 7];   // okay
-    p = new (p) B [1][1][MAX / 2 - 8];   // okay
+    p = new (p) B [1][1][MAX2 + 3];     // { dg-error "size of \(unnamed \)\?array" }
+    p = new (p) B [1][1][MAX2 + 2];     // { dg-error "size of \(unnamed \)\?array" }
+    p = new (p) B [1][1][MAX2 + 1];     // { dg-error "size of array" }
+    p = new (p) B [1][1][MAX2];         // okay
+    p = new (p) B [1][1][MAX2 - 1]  ;   // okay
 
     p = new (p) B [1][2][MAX];          // { dg-error "size of unnamed array" }
     p = new (p) B [1][2][MAX - 1];      // { dg-error "size of unnamed array" }
@@ -427,14 +353,9 @@ test_placement_three_dim_byte_struct_array (void *p)
     p = new (p) B [1][2][MAX / 2 - 6];  // { dg-error "size of unnamed array" }
     p = new (p) B [1][2][MAX / 2 - 7];  // { dg-error "size of unnamed array" }
     p = new (p) B [1][2][MAX / 2 - 8];  // { dg-error "size of unnamed array" }
-    p = new (p) B [1][2][MAX / 4];      // { dg-error "size of array" }
-
-    // Avoid exercising data model-dependent expressions.
-    // p = new (p) B [1][2][MAX / 4 - 1];
-    // p = new (p) B [1][2][MAX / 4 - 2];
-
-    p = new (p) B [1][2][MAX / 4 - 3];   // okay
-    p = new (p) B [1][2][MAX / 4 - 4];   // okay
+    p = new (p) B [1][2][MAX2 / 2 + 1]; // { dg-error "size of \(unnamed \)\?array" }
+    p = new (p) B [1][2][MAX2 / 2];     // okay
+    p = new (p) B [1][2][MAX2 / 2 - 1]; // okay
 
     p = new (p) B [2][1][MAX];          // { dg-error "size of unnamed array" }
     p = new (p) B [2][1][MAX - 1];      // { dg-error "size of unnamed array" }
@@ -449,14 +370,9 @@ test_placement_three_dim_byte_struct_array (void *p)
     p = new (p) B [2][1][MAX / 2 - 6];  // { dg-error "size of array" }
     p = new (p) B [2][1][MAX / 2 - 7];  // { dg-error "size of array" }
     p = new (p) B [2][1][MAX / 2 - 8];  // { dg-error "size of array" }
-    p = new (p) B [2][1][MAX / 4];      // { dg-error "size of array" }
-
-    // Avoid exercising data model-dependent expressions.
-    // p = new (p) B [2][1][MAX / 4 - 1];
-    // p = new (p) B [2][1][MAX / 4 - 2];
-
-    p = new (p) B [2][1][MAX / 4 - 3];   // okay
-    p = new (p) B [2][1][MAX / 4 - 4];   // okay
+    p = new (p) B [2][1][MAX2 / 2 + 1]; // { dg-error "size of array" }
+    p = new (p) B [2][1][MAX2 / 2];     // okay
+    p = new (p) B [2][1][MAX2 / 2 - 1]; // okay
 
     p = new (p) B [2][2][MAX];          // { dg-error "size of unnamed array" }
     p = new (p) B [2][2][MAX - 1];      // { dg-error "size of unnamed array" }
diff --git a/gcc/testsuite/g++.dg/init/value9.C b/gcc/testsuite/g++.dg/init/value9.C
index 4899bd8..55da5d9 100644
--- a/gcc/testsuite/g++.dg/init/value9.C
+++ b/gcc/testsuite/g++.dg/init/value9.C
@@ -1,5 +1,7 @@
 // PR c++/50793
-// { dg-do run }
+// { dg-do run { target { stdint_types } } }
+
+#include <stdint.h>
 
 struct NonTrivial
 {
@@ -9,16 +11,16 @@ struct NonTrivial
 struct S
 {
   NonTrivial nt;
-  int i;
+  int_least32_t i;
 };
 
-int f(S s)
+int_least32_t f(S s)
 {
   s.i = 0xdeadbeef;
   return s.i;
 }
 
-int g(S s = S())
+int_least32_t g(S s = S())
 {
   return s.i;
 }
diff --git a/gcc/testsuite/g++.dg/lto/20080908-1_0.C b/gcc/testsuite/g++.dg/lto/20080908-1_0.C
index 8b761c0..efa9b14 100644
--- a/gcc/testsuite/g++.dg/lto/20080908-1_0.C
+++ b/gcc/testsuite/g++.dg/lto/20080908-1_0.C
@@ -1,16 +1,19 @@
 /* { dg-lto-do run }  */
+/* { dg-require-effective-target stdint_types } */
 extern "C" { extern void *memcpy (void *, const void *, unsigned); }
 
-inline int
+#include <stdint.h>
+
+inline int_least32_t
 bci (const float &source)
 {
- int dest;
+ int_least32_t dest;
  memcpy (&dest, &source, sizeof (dest));
  return dest;
 }
 
 inline float
-bcf (const int &source)
+bcf (const int_least32_t &source)
 {
  float dest;
  memcpy (&dest, &source, sizeof (dest));
@@ -20,9 +23,9 @@ bcf (const int &source)
 float
 Foo ()
 {
- const int foo = bci (0.0f);
- int bar = foo;
- const int baz = foo & 1;
+ const int_least32_t foo = bci (0.0f);
+ int_least32_t bar = foo;
+ const int_least32_t baz = foo & 1;
  if (!baz && (foo & 2))
    bar = 0;
  return bcf (bar);
diff --git a/gcc/testsuite/g++.dg/lto/20090112_0.C b/gcc/testsuite/g++.dg/lto/20090112_0.C
index b9dc24b..ae085e0 100644
--- a/gcc/testsuite/g++.dg/lto/20090112_0.C
+++ b/gcc/testsuite/g++.dg/lto/20090112_0.C
@@ -1,5 +1,9 @@
 // { dg-lto-do run }
-const char *func(int val) {
+// { dg-require-effective-target stdint_types }
+
+#include <stdint.h>
+
+const char *func(int_least32_t val) {
  switch (val) {
    case 2147483647: return "foo";
    default: return "";
diff --git a/gcc/testsuite/g++.dg/lto/pr45679-1_0.C b/gcc/testsuite/g++.dg/lto/pr45679-1_0.C
index 349f5c2..d1cb8c8 100644
--- a/gcc/testsuite/g++.dg/lto/pr45679-1_0.C
+++ b/gcc/testsuite/g++.dg/lto/pr45679-1_0.C
@@ -1,6 +1,7 @@
 // { dg-lto-do link }
 // { dg-lto-options {{-O3 -Wno-multichar}} } 
 // { dg-extra-ld-options "-flto -flto-partition=1to1 -r -nostdlib" }
+// { dg-require-effective-target int32plus }
 
      extern "C" {
    typedef struct __locale_struct {
diff --git a/gcc/testsuite/g++.dg/lto/pr45679-2_0.C b/gcc/testsuite/g++.dg/lto/pr45679-2_0.C
index 5497419..4498abf 100644
--- a/gcc/testsuite/g++.dg/lto/pr45679-2_0.C
+++ b/gcc/testsuite/g++.dg/lto/pr45679-2_0.C
@@ -1,6 +1,8 @@
 // { dg-lto-do link }
 // { dg-lto-options {{-O3 -Wno-multichar}} } 
 // { dg-extra-ld-options "-flto -flto-partition=1to1 -r -nostdlib" }
+// { dg-require-effective-target int32plus }
+
     extern "C" {
   typedef struct {
     union   {
diff --git a/gcc/testsuite/g++.dg/lto/pr65475c_0.C b/gcc/testsuite/g++.dg/lto/pr65475c_0.C
index 8e1d8bc..19ced40 100644
--- a/gcc/testsuite/g++.dg/lto/pr65475c_0.C
+++ b/gcc/testsuite/g++.dg/lto/pr65475c_0.C
@@ -1,6 +1,8 @@
 /* { dg-lto-do link } */
 /* { dg-lto-options "-O2  -w" } */
 /* { dg-extra-ld-options { -O2 -Wno-odr -r -nostdlib } } */
+/* { dg-require-effective-target int32plus } */
+
 namespace std
 {
 template < class > struct char_traits;
diff --git a/gcc/testsuite/g++.dg/lto/pr69589_0.C b/gcc/testsuite/g++.dg/lto/pr69589_0.C
index bbdcb73..95e07b0 100644
--- a/gcc/testsuite/g++.dg/lto/pr69589_0.C
+++ b/gcc/testsuite/g++.dg/lto/pr69589_0.C
@@ -1,6 +1,7 @@
 // { dg-lto-do link }
 // { dg-lto-options "-O2 -rdynamic" } 
 // { dg-extra-ld-options "-r -nostdlib" }
+// { dg-skip-if "-rdynamic not supported" { "ia16-*-*" } }
 #pragma GCC visibility push(hidden)
 struct A { int &operator[] (long); };
 template <typename> struct B;
diff --git a/gcc/testsuite/g++.dg/opt/pr55717.C b/gcc/testsuite/g++.dg/opt/pr55717.C
index 7b3af58..170d4b0 100644
--- a/gcc/testsuite/g++.dg/opt/pr55717.C
+++ b/gcc/testsuite/g++.dg/opt/pr55717.C
@@ -1,7 +1,9 @@
 // PR debug/55717
-// { dg-do compile }
+// { dg-do compile { target { stdint_types } } }
 // { dg-options "-O -g" }
 
+#include <stdint.h>
+
 struct DebugOnly {};
 template <class T>
 struct StripConst { typedef T result; };
@@ -90,10 +92,10 @@ bool IsScriptMarked (JSScript **);
 struct AllocationSiteKey
 {
   JSScript *script;
-  unsigned offset : 24;
-  int kind;
+  uint_least32_t offset : 24;
+  int_least32_t kind;
   typedef AllocationSiteKey Lookup;
-  static unsigned hash (AllocationSiteKey key) { return (long (key.script->code + key.offset)) ^ key.kind; }
+  static uint_least32_t hash (AllocationSiteKey key) { return (long (key.script->code + key.offset)) ^ key.kind; }
 };
 void
 TypeCompartment::sweep (FreeOp *)
diff --git a/gcc/testsuite/g++.dg/opt/pr60597.C b/gcc/testsuite/g++.dg/opt/pr60597.C
index c61f767..11cf593 100644
--- a/gcc/testsuite/g++.dg/opt/pr60597.C
+++ b/gcc/testsuite/g++.dg/opt/pr60597.C
@@ -1,45 +1,47 @@
 // PR middle-end/60597
-// { dg-do compile }
+// { dg-do compile { target { stdint_types } } }
 // { dg-options "-O2 -g" }
 
+#include <stdint.h>
+
 struct A
 {
-  int foo () const;
-  int bar () const;
-  int a;
+  int_least32_t foo () const;
+  int_least32_t bar () const;
+  int_least32_t a;
 };
 
 struct B
 {
-  int foo ();
-  int bar ();
+  int_least32_t foo ();
+  int_least32_t bar ();
 };
 
-int *c, d;
+int_least32_t *c, d;
 
-int
+int_least32_t
 A::foo () const
 {
-  int b = a >> 16;
+  int_least32_t b = a >> 16;
   return b;
 }
 
-int
+int_least32_t
 A::bar () const
 {
-  int b = a;
+  int_least32_t b = a;
   return b;
 }
 
 void
-baz (A &x, B h, int i, int j)
+baz (A &x, B h, int_least32_t i, int_least32_t j)
 {
   for (; i < h.bar (); ++i)
     for (; h.foo (); ++j)
       {
-	int g = x.foo ();
-	int f = x.bar ();
-	int e = c[0] & 1;
+	int_least32_t g = x.foo ();
+	int_least32_t f = x.bar ();
+	int_least32_t e = c[0] & 1;
 	d = (e << 1) | (g << 16) | (f & 1);
 	c[j] = 0;
       }
diff --git a/gcc/testsuite/g++.dg/opt/reload3.C b/gcc/testsuite/g++.dg/opt/reload3.C
index 12f3e66..70010f5 100644
--- a/gcc/testsuite/g++.dg/opt/reload3.C
+++ b/gcc/testsuite/g++.dg/opt/reload3.C
@@ -1,32 +1,33 @@
 // PR target/38287
-// { dg-do run }
+// { dg-do run { target { stdint_types } } }
 // { dg-options "-O2 -mcpu=v8 -fPIC" { target { { sparc*-*-* } && { ilp32 && fpic } } } }
 
 #include <cstdlib>
+#include <stdint.h>
 
 class QTime
 {
 public:
-    explicit QTime(int ms = 0) : ds(ms) {}
+    explicit QTime(int_least32_t ms = 0) : ds(ms) {}
     static QTime currentTime() { return QTime(); }
-    QTime addMSecs(int ms) const;
-    int msecs() const { return ds; }
+    QTime addMSecs(int_least32_t ms) const;
+    int_least32_t msecs() const { return ds; }
 private:
-    unsigned ds;
+    uint_least32_t ds;
 };
 
-static const unsigned MSECS_PER_DAY = 86400000;
+static const uint_least32_t MSECS_PER_DAY = 86400000;
 
-QTime QTime::addMSecs(int ms) const
+QTime QTime::addMSecs(int_least32_t ms) const
 {
     QTime t;
     if ( ms < 0 ) {
         // % not well-defined for -ve, but / is.
-        int negdays = (MSECS_PER_DAY-ms) / MSECS_PER_DAY;
-        t.ds = ((int)ds + ms + negdays*MSECS_PER_DAY)
+        int_least32_t negdays = (MSECS_PER_DAY-ms) / MSECS_PER_DAY;
+        t.ds = ((int_least32_t)ds + ms + negdays*MSECS_PER_DAY)
                 % MSECS_PER_DAY;
     } else {
-        t.ds = ((int)ds + ms) % MSECS_PER_DAY;
+        t.ds = ((int_least32_t)ds + ms) % MSECS_PER_DAY;
     }
     return t;
 }
diff --git a/gcc/testsuite/g++.dg/opt/temp2.C b/gcc/testsuite/g++.dg/opt/temp2.C
index 35520a2..f80b7a0 100644
--- a/gcc/testsuite/g++.dg/opt/temp2.C
+++ b/gcc/testsuite/g++.dg/opt/temp2.C
@@ -8,6 +8,14 @@
 
 int i;
 
+#ifdef __ia16__
+#define BUFFER_SIZE 4112
+#define HEAP_SIZE 5000
+#else
+#define BUFFER_SIZE 41112
+#define HEAP_SIZE 50000
+#endif
+
 extern "C"
 void *memcpy (void *dest, const void *src, __SIZE_TYPE__ n)
 {
@@ -20,7 +28,7 @@ void *memcpy (void *dest, const void *src, __SIZE_TYPE__ n)
 }
 
 struct foo {
-  unsigned char buffer[41112];
+  unsigned char buffer[BUFFER_SIZE];
   foo() ;
   bool check () const;
 };
@@ -42,7 +50,7 @@ void *operator new (__SIZE_TYPE__ size, void *p)
   return p;
 }
 
-char heap[50000];
+char heap[HEAP_SIZE];
 
 int main ()
 {
diff --git a/gcc/testsuite/g++.dg/opt/thunk1.C b/gcc/testsuite/g++.dg/opt/thunk1.C
index 566c0f2..5da582f 100644
--- a/gcc/testsuite/g++.dg/opt/thunk1.C
+++ b/gcc/testsuite/g++.dg/opt/thunk1.C
@@ -7,7 +7,11 @@ extern "C" void abort ();
 struct A
 {
   virtual void foo() = 0;
+#ifdef __ia16__
+  char large[3*1024];
+#else
   char large[33*1024];
+#endif
 };
 
 struct B
diff --git a/gcc/testsuite/g++.dg/other/anon5.C b/gcc/testsuite/g++.dg/other/anon5.C
index 2a6f57f..815a08f 100644
--- a/gcc/testsuite/g++.dg/other/anon5.C
+++ b/gcc/testsuite/g++.dg/other/anon5.C
@@ -1,5 +1,5 @@
 // PR c++/34094
-// { dg-do link { target { ! { *-*-darwin* *-*-hpux* *-*-solaris2.* } } } }
+// { dg-do link { target { ! { *-*-darwin* *-*-hpux* *-*-solaris2.* ia16-*-* } } } }
 // { dg-options "-gdwarf-2" }
 // Ignore additional message on powerpc-ibm-aix
 // { dg-prune-output "obtain more information" } */
diff --git a/gcc/testsuite/g++.dg/other/error23.C b/gcc/testsuite/g++.dg/other/error23.C
index c60603e..c2cd15e 100644
--- a/gcc/testsuite/g++.dg/other/error23.C
+++ b/gcc/testsuite/g++.dg/other/error23.C
@@ -1,5 +1,7 @@
 // PR c++/34918
-// { dg-do compile }
+// { dg-do compile { target { stdint_types } } }
 
-int v __attribute ((vector_size (8)));
-bool b = !(v - v);	// { dg-error "not convert .__vector.2. int. to .bool. in initialization" }
+#include <stdint.h>
+
+int32_t v __attribute ((vector_size (8)));
+bool b = !(v - v);	// { dg-error "not convert .__vector.2. \(long \)\?int. to .bool. in initialization" }
diff --git a/gcc/testsuite/g++.dg/other/pr31078.C b/gcc/testsuite/g++.dg/other/pr31078.C
index 7f61071..92a5a4a 100644
--- a/gcc/testsuite/g++.dg/other/pr31078.C
+++ b/gcc/testsuite/g++.dg/other/pr31078.C
@@ -1,4 +1,8 @@
+#ifdef __UINT_LEAST32_TYPE__
+typedef __UINT_LEAST32_TYPE__ SLONG;
+#else
 typedef int SLONG;
+#endif
 typedef char SCHAR;
 typedef short SSHORT;
 typedef char TEXT;
diff --git a/gcc/testsuite/g++.dg/other/unused1.C b/gcc/testsuite/g++.dg/other/unused1.C
index b28d698..78a138b 100644
--- a/gcc/testsuite/g++.dg/other/unused1.C
+++ b/gcc/testsuite/g++.dg/other/unused1.C
@@ -1,6 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-g" } */
-/* { dg-skip-if "" { { hppa*-*-hpux* *-*-solaris2.[56]* powerpc-ibm-aix* } && { ! hppa*64*-*-* } } { "*" } { "" } } */
+/* { dg-skip-if "" { { hppa*-*-hpux* *-*-solaris2.[56]* powerpc-ibm-aix* ia16-*-* } && { ! hppa*64*-*-* } } { "*" } { "" } } */
 
 /* Make sure we didn't eliminate casted types because we thought they were
    unused.  */
diff --git a/gcc/testsuite/g++.dg/parse/defarg5.C b/gcc/testsuite/g++.dg/parse/defarg5.C
index 01a67ed..b880cee 100644
--- a/gcc/testsuite/g++.dg/parse/defarg5.C
+++ b/gcc/testsuite/g++.dg/parse/defarg5.C
@@ -1,4 +1,4 @@
-// { dg-do compile }
+// { dg-do compile { target { stdint_types } } }
 
 // Copyright (C) 2003 Free Software Foundation, Inc.
 // Contributed by Nathan Sidwell 5 Sep 2003 <nathan@codesourcery.com>
@@ -6,10 +6,12 @@
 
 // PR c++/12167 - infinite recursion
 
+#include <stdint.h>
+
 class A {   
-  void report(int d
+  void report(int_least32_t d
 	      // the default arg is what NAN etc can expand to, but
 	      // with the floatiness removed.
-	      = (__extension__ ((union { unsigned l; int d; })
+	      = (__extension__ ((union { uint_least32_t l; int_least32_t d; })
 				{ l: 0x7fc00000U }).d));
 };
diff --git a/gcc/testsuite/g++.dg/parse/parens3.C b/gcc/testsuite/g++.dg/parse/parens3.C
index 6004475..07d95f7 100644
--- a/gcc/testsuite/g++.dg/parse/parens3.C
+++ b/gcc/testsuite/g++.dg/parse/parens3.C
@@ -5,7 +5,7 @@ struct s {
   int i;
 };
 
-#ifdef __hppa__ 
+#if defined (__hppa__) || defined (__ia16__)
 /* Register %r1 can't be fixed when generating PIC code.  */
 register struct s *reg __asm__( "4" );
 #else
diff --git a/gcc/testsuite/g++.dg/pr48484.C b/gcc/testsuite/g++.dg/pr48484.C
index 1380c45..e5983d5 100644
--- a/gcc/testsuite/g++.dg/pr48484.C
+++ b/gcc/testsuite/g++.dg/pr48484.C
@@ -1,10 +1,12 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-O -finline-functions -finline-small-functions -Wuninitialized" }  */
 /* { dg-add-options bind_pic_locally } */
 
+#include <stdint.h>
+
 struct SQObjectPtr
 {
-  int _type;
+  int_least32_t _type;
   SQObjectPtr operator = (long);
 };
 struct SQObjectPtrVec
diff --git a/gcc/testsuite/g++.dg/pr66655.C b/gcc/testsuite/g++.dg/pr66655.C
index 218a2c6..0009d15 100644
--- a/gcc/testsuite/g++.dg/pr66655.C
+++ b/gcc/testsuite/g++.dg/pr66655.C
@@ -1,4 +1,4 @@
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
 /* { dg-additional-sources "pr66655_1.cc" } */
 
 #include "pr66655.h"
@@ -7,13 +7,13 @@ extern "C" void abort (void);
 
 #define COOKIE 0xabcd0123
 
-int
+int_least32_t
 g (void)
 {
   return COOKIE;
 }
 
-extern int f (void);
+extern int_least32_t f (void);
 
 int
 main (void)
diff --git a/gcc/testsuite/g++.dg/pr66655.h b/gcc/testsuite/g++.dg/pr66655.h
index ff638f4..12aa27b 100644
--- a/gcc/testsuite/g++.dg/pr66655.h
+++ b/gcc/testsuite/g++.dg/pr66655.h
@@ -1,5 +1,7 @@
+#include <stdint.h>
+
 struct S
 {
-  static int i;
-  static void set (int ii) { i = -ii; }
+  static int_least32_t i;
+  static void set (int_least32_t ii) { i = -ii; }
 };
diff --git a/gcc/testsuite/g++.dg/pr66655_1.cc b/gcc/testsuite/g++.dg/pr66655_1.cc
index d42344c..c9b5fb2 100644
--- a/gcc/testsuite/g++.dg/pr66655_1.cc
+++ b/gcc/testsuite/g++.dg/pr66655_1.cc
@@ -1,13 +1,13 @@
 #include "pr66655.h"
 
-extern int g (void);
+extern int_least32_t g (void);
 
-int S::i;
+int_least32_t S::i;
 
-int
+int_least32_t
 f (void)
 {
-  int ret = g ();
+  int_least32_t ret = g ();
 
   S::set (ret);
   return ret;
diff --git a/gcc/testsuite/g++.dg/pr67351.C b/gcc/testsuite/g++.dg/pr67351.C
index f5bdda6..ed92464 100644
--- a/gcc/testsuite/g++.dg/pr67351.C
+++ b/gcc/testsuite/g++.dg/pr67351.C
@@ -1,9 +1,11 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-O2 -fdump-tree-optimized" } */
 
+#include <stdint.h>
+
 typedef unsigned char uchar;
 typedef unsigned short ushort;
-typedef unsigned int uint;
+typedef uint_least32_t uint;
 typedef unsigned long long uint64;
 
 class MyRgba
diff --git a/gcc/testsuite/g++.dg/template/friend18.C b/gcc/testsuite/g++.dg/template/friend18.C
index 712d488..2811875 100644
--- a/gcc/testsuite/g++.dg/template/friend18.C
+++ b/gcc/testsuite/g++.dg/template/friend18.C
@@ -1,13 +1,15 @@
-// { dg-do run }
+// { dg-do run { target { stdint_types } } }
 
 // Copyright (C) 2003 Free Software Foundation, Inc.
 // Contributed by Nathan Sidwell 26 Mar 2003 <nathan@codesourcery.com>
 
 // PR 10158. implicit inline template friends ICE'd
 
-template <int N> struct X
+#include <stdint.h>
+
+template <int_least32_t N> struct X
 {
-  template <int M> friend int foo(X const &, X<M> const&)
+  template <int_least32_t M> friend int_least32_t foo(X const &, X<M> const&)
   {
     return N * 10000 + M;
   }
diff --git a/gcc/testsuite/g++.dg/template/pr68978.C b/gcc/testsuite/g++.dg/template/pr68978.C
index 1904532..0e9364b 100644
--- a/gcc/testsuite/g++.dg/template/pr68978.C
+++ b/gcc/testsuite/g++.dg/template/pr68978.C
@@ -1,39 +1,45 @@
 // PR c++/68978
 
-int i = 0, c = 0, radix = 10, max = 0x7fffffff;
+#ifdef __INT_LEAST32_TYPE__
+#define INT_LEAST32_T __INT_LEAST32_TYPE__
+#else
+#define INT_LEAST32_T int
+#endif
 
-template <typename T> int toi_1() {
+INT_LEAST32_T i = 0, c = 0, radix = 10, max = 0x7fffffff;
+
+template <typename T> INT_LEAST32_T toi_1() {
   if (max < ((i *= radix) += c))
     return 0;
   return i;
 }
 
-template <typename T> int toi_2() {
+template <typename T> INT_LEAST32_T toi_2() {
   if (max < ((i = radix) = c))
     return 0;
   return i;
 }
 
-template <typename T> int toi_3() {
+template <typename T> INT_LEAST32_T toi_3() {
   if (max < ((i = radix) += c))
     return 0;
   return i;
 }
 
-template <typename T> int toi_4() {
+template <typename T> INT_LEAST32_T toi_4() {
   if (max < ((i += radix) = c))
     return 0;
   return i;
 }
 
-template <typename T> int toi_5() {
+template <typename T> INT_LEAST32_T toi_5() {
   if (max < (((i = radix) += (c += 5)) *= 30))
     return 0;
   return i;
 }
 
-int x = toi_1<int> ();
-int y = toi_2<int> ();
-int z = toi_3<int> ();
-int w = toi_4<int> ();
-int r = toi_5<int> ();
+INT_LEAST32_T x = toi_1<INT_LEAST32_T> ();
+INT_LEAST32_T y = toi_2<INT_LEAST32_T> ();
+INT_LEAST32_T z = toi_3<INT_LEAST32_T> ();
+INT_LEAST32_T w = toi_4<INT_LEAST32_T> ();
+INT_LEAST32_T r = toi_5<INT_LEAST32_T> ();
diff --git a/gcc/testsuite/g++.dg/torture/pr33887-1.C b/gcc/testsuite/g++.dg/torture/pr33887-1.C
index 2f17d95..7348b5b 100644
--- a/gcc/testsuite/g++.dg/torture/pr33887-1.C
+++ b/gcc/testsuite/g++.dg/torture/pr33887-1.C
@@ -1,7 +1,9 @@
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
+
+#include <stdint.h>
 
 extern "C" void abort (void);
-struct S { unsigned int i : 24; } x;
+struct S { uint_least32_t i : 24; } x;
 void __attribute__((noinline)) test1()
 {
   if (--x.i != 0x00ffffff)
diff --git a/gcc/testsuite/g++.dg/torture/pr33887-2.C b/gcc/testsuite/g++.dg/torture/pr33887-2.C
index f64cfad..0c78800 100644
--- a/gcc/testsuite/g++.dg/torture/pr33887-2.C
+++ b/gcc/testsuite/g++.dg/torture/pr33887-2.C
@@ -1,17 +1,19 @@
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
+
+#include <stdint.h>
 
 extern "C" void abort() __attribute__ ((noreturn));
 
 struct s
 {
   unsigned long long f1 : 40;
-  unsigned int f2 : 24;
+  uint_least32_t f2 : 24;
 } sv;
 
 int main()
 {
-  int f2;
-  sv.f2 = (1 << 24) - 1;
+  int_least32_t f2;
+  sv.f2 = ((uint_least32_t)1 << 24) - 1;
   __asm__ volatile ("" : : : "memory");
   ++sv.f2;
   f2 = sv.f2;
diff --git a/gcc/testsuite/g++.dg/torture/pr33887-3.C b/gcc/testsuite/g++.dg/torture/pr33887-3.C
index b4b883f..65e15db 100644
--- a/gcc/testsuite/g++.dg/torture/pr33887-3.C
+++ b/gcc/testsuite/g++.dg/torture/pr33887-3.C
@@ -1,18 +1,20 @@
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
+
+#include <stdint.h>
 
 extern "C" void abort (void);
 
 struct s
 {
   unsigned long long f1 : 40;
-  unsigned int f2 : 24;
+  uint_least32_t f2 : 24;
 };
 
 s sv;
 
-void __attribute__((noinline)) foo(unsigned int i)
+void __attribute__((noinline)) foo(uint_least32_t i)
 {
-  unsigned int tmp;
+  uint_least32_t tmp;
   sv.f2 = i;
   tmp = sv.f2;
   if (tmp != 0)
diff --git a/gcc/testsuite/g++.dg/torture/pr34235.C b/gcc/testsuite/g++.dg/torture/pr34235.C
index 5f05841..46bf578 100644
--- a/gcc/testsuite/g++.dg/torture/pr34235.C
+++ b/gcc/testsuite/g++.dg/torture/pr34235.C
@@ -1,10 +1,12 @@
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
+
+#include <stdint.h>
 
 extern "C" void abort (void);
 int main()
 {
         short x = -1;
-        unsigned int c = ((unsigned int)x) >> 1;
+        uint_least32_t c = ((uint_least32_t)x) >> 1;
         if (c != 0x7fffffff)
           abort();
         return 0;
diff --git a/gcc/testsuite/g++.dg/torture/pr34641.C b/gcc/testsuite/g++.dg/torture/pr34641.C
index 0cf5077..a3d93dd 100644
--- a/gcc/testsuite/g++.dg/torture/pr34641.C
+++ b/gcc/testsuite/g++.dg/torture/pr34641.C
@@ -1,8 +1,9 @@
-// { dg-do compile }
+// { dg-do compile { target { stdint_types } } }
 // { dg-require-effective-target fpic }
 // { dg-require-visibility "" }
 // { dg-options "-fPIC" }
 
+#include <stdint.h>
 
 typedef __SIZE_TYPE__ size_t;
 extern "C" void *
@@ -40,8 +41,6 @@ template < typename _Tp > inline const _Tp &
 max (const _Tp & __a, const _Tp & __b)
 {
 }
-typedef unsigned short int uint16_t;
-typedef unsigned long int uintptr_t;
 typedef uint16_t UChar;
 namespace std __attribute__ ((__visibility__ ("default")))
 {
@@ -155,7 +154,7 @@ public:
 UChar *
 plainTextToMallocAllocatedBuffer (const Range * r, unsigned &bufferLength)
 {
-  static const unsigned cMaxSegmentSize = 1 << 16;
+  static const uint_least32_t cMaxSegmentSize = (uint_least32_t)1 << 16;
   typedef pair < UChar *, unsigned >TextSegment;
   Vector < TextSegment > *textSegments = 0;
   Vector < UChar > textBuffer;
diff --git a/gcc/testsuite/g++.dg/torture/pr37146-1.C b/gcc/testsuite/g++.dg/torture/pr37146-1.C
index ea65226..60fea74 100644
--- a/gcc/testsuite/g++.dg/torture/pr37146-1.C
+++ b/gcc/testsuite/g++.dg/torture/pr37146-1.C
@@ -1,9 +1,11 @@
 // PR c++/37146
-// { dg-do run }
+// { dg-do run { target { stdint_types } } }
+
+#include <stdint.h>
 
 extern "C" void abort ();
-int a, b;
-struct A { int i:8; int j:8; int k:16; int l:32; } c;
+int_least32_t a, b;
+struct A { int_least32_t i:8; int_least32_t j:8; int_least32_t k:16; int_least32_t l:32; } c;
 
 void
 f1 (int x, int y)
diff --git a/gcc/testsuite/g++.dg/torture/pr37146-2.C b/gcc/testsuite/g++.dg/torture/pr37146-2.C
index 2a54176..66e6744 100644
--- a/gcc/testsuite/g++.dg/torture/pr37146-2.C
+++ b/gcc/testsuite/g++.dg/torture/pr37146-2.C
@@ -1,9 +1,11 @@
 // PR c++/37146
-// { dg-do run }
+// { dg-do run { target { stdint_types } } }
+
+#include <stdint.h>
 
 extern "C" void abort ();
 int a, b;
-struct A { int i:8; int j:8; int k:16; int l:32; } c;
+struct A { int i:8; int j:8; int_least32_t k:16; int_least32_t l:32; } c;
 
 int
 f1 (int x)
diff --git a/gcc/testsuite/g++.dg/torture/pr38565.C b/gcc/testsuite/g++.dg/torture/pr38565.C
index 7216b1c..5a35bfb 100644
--- a/gcc/testsuite/g++.dg/torture/pr38565.C
+++ b/gcc/testsuite/g++.dg/torture/pr38565.C
@@ -1,12 +1,15 @@
-// { dg-do compile }
+// { dg-do compile { target { stdint_types } } }
 // Ignore warning on some powerpc-linux configurations.
 // { dg-prune-output "non-standard ABI extension" }
 // { dg-prune-output "changes the ABI" }
+
+#include <stdint.h>
+
 #define vector __attribute__((vector_size(16) ))
-vector unsigned int f(int a)
+vector uint32_t f(int a)
 {
-  vector unsigned int mask = a ? (vector unsigned int){ 0x80000000, 0x80000000,
-0x80000000, 0x80000000 } : (vector unsigned int){0};
+  vector uint32_t mask = a ? (vector uint32_t){ 0x80000000, 0x80000000,
+0x80000000, 0x80000000 } : (vector uint32_t){0};
   return mask;
 }
 
diff --git a/gcc/testsuite/g++.dg/torture/pr58369.C b/gcc/testsuite/g++.dg/torture/pr58369.C
index 9284e2c..d821c2b 100644
--- a/gcc/testsuite/g++.dg/torture/pr58369.C
+++ b/gcc/testsuite/g++.dg/torture/pr58369.C
@@ -1,13 +1,15 @@
-// { dg-do compile }
+// { dg-do compile { target { stdint_types } } }
 // Reduced from boost-1.54
 
+#include <stdint.h>
+
 int pow(int, int);
 int sqrt(int);
 
 class PolicyA { };
 
 template <class>
-int max_value() { return 0x7fffffff; }
+int_least32_t max_value() { return 0x7fffffff; }
 
 template <class>
 int min_value() { return 1; }
diff --git a/gcc/testsuite/g++.dg/torture/pr67581.C b/gcc/testsuite/g++.dg/torture/pr67581.C
index 8089c1f..8733e1d 100644
--- a/gcc/testsuite/g++.dg/torture/pr67581.C
+++ b/gcc/testsuite/g++.dg/torture/pr67581.C
@@ -1,6 +1,9 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
+
+#include <stdint.h>
+
 union U 
 {
-  int x; 
+  int32_t x; 
   float y;
 } __attribute__ ((__transparent_union__));
diff --git a/gcc/testsuite/g++.dg/torture/pr68064.C b/gcc/testsuite/g++.dg/torture/pr68064.C
index 59b6897..8f18b84 100644
--- a/gcc/testsuite/g++.dg/torture/pr68064.C
+++ b/gcc/testsuite/g++.dg/torture/pr68064.C
@@ -1,4 +1,4 @@
-// { dg-do compile }
+// { dg-do compile { target int32plus } }
 
 template <class Config> class A {
 public:
diff --git a/gcc/testsuite/g++.dg/tree-ssa/ivopts-3.C b/gcc/testsuite/g++.dg/tree-ssa/ivopts-3.C
index 6194e9d..70983ee 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/ivopts-3.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/ivopts-3.C
@@ -41,7 +41,11 @@ public:
 
 
 int main ( int , char** ) {
+#ifdef __ia16__
+    int w = ( 1 << 3 )+1;
+#else
     int w = ( 1 << 7 )+1;
+#endif
     int wsqr = w*w;
     int wcub = w*w*w;
 
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr19807.C b/gcc/testsuite/g++.dg/tree-ssa/pr19807.C
index cbe06b4..c166c7f 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/pr19807.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr19807.C
@@ -1,8 +1,10 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-O -fdump-tree-optimized" } */
 
-int a[4];
-int *x, *y, *z;
+#include <stdint.h>
+
+int32_t a[4];
+int32_t *x, *y, *z;
 
 void foo(void)
 {
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr27291.C b/gcc/testsuite/g++.dg/tree-ssa/pr27291.C
index b8b5e13..fefb2c4 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/pr27291.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr27291.C
@@ -1,6 +1,8 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-O2" } */
 
+#include <stdint.h>
+
 namespace std
 {
   template < class _T1, class _T2 > struct pair
@@ -29,7 +31,6 @@ namespace std
     static const bool is_integer = true;
   };
 };
-typedef unsigned int uint32_t;
 namespace std
 {
   template < typename _Alloc > class allocator;
@@ -69,8 +70,8 @@ namespace boost
     {
     };
   }
-  template <> class integer_traits < int >:public std::numeric_limits < int >,
-    public detail::integer_traits_base < int, (-2147483647 - 1), 2147483647 >
+  template <> class integer_traits < int32_t >:public std::numeric_limits < int32_t >,
+    public detail::integer_traits_base < int32_t, (-2147483647 - 1), 2147483647 >
   {
   };
   namespace random
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr49516.C b/gcc/testsuite/g++.dg/tree-ssa/pr49516.C
index 2c6fd04..ec621f9 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/pr49516.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr49516.C
@@ -1,12 +1,14 @@
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
 /* { dg-options "-O2" } */
 
+#include <stdint.h>
+
 extern "C" void abort (void);
 
-typedef int int32;
-typedef unsigned int uint32;
-typedef unsigned long long uint64;
-typedef short int16;
+typedef int32_t int32;
+typedef uint32_t uint32;
+typedef uint64_t uint64;
+typedef int16_t int16;
 
 class Tp {
  public:
@@ -21,7 +23,7 @@ class Tp {
   inline static bool IsValidSegment(const int segment);
   static const int kSegmentBits = 28;
   static const int kTypeBits = 4;
-  static const int kMaxSegment = (1 << kSegmentBits) - 1;
+  static const int_least32_t kMaxSegment = ((int_least32_t)1 << kSegmentBits) - 1;
 
   union {
 
diff --git a/gcc/testsuite/g++.dg/warn/Wconversion-integer.C b/gcc/testsuite/g++.dg/warn/Wconversion-integer.C
index 42d9cb0..9c39c54 100644
--- a/gcc/testsuite/g++.dg/warn/Wconversion-integer.C
+++ b/gcc/testsuite/g++.dg/warn/Wconversion-integer.C
@@ -1,20 +1,21 @@
 /* Test for diagnostics for implicit conversions between integer types
    C++ equivalent of gcc/testsuite/gcc.dg/Wconversion-integer.c  */
 
-// { dg-do compile } 
+// { dg-do compile { target { stdint_types } } } 
 // { dg-options "-fsigned-char -Wconversion" } 
 
+#include <stdint.h>
 #include <limits.h>
 
 void fsc (signed char sc);
 void fuc (unsigned char uc);
-unsigned fui (unsigned int  ui);
-void fsi (signed int ui);
+unsigned fui (uint_least32_t ui);
+void fsi (int_least32_t ui);
 
 void h (int x)
 {
-  unsigned int ui = 3;
-  int   si = 3;
+  uint_least32_t ui = 3;
+  int_least32_t   si = 3;
   unsigned char uc = 3;
   signed char   sc = 3;
 
diff --git a/gcc/testsuite/g++.dg/warn/Wplacement-new-size.C b/gcc/testsuite/g++.dg/warn/Wplacement-new-size.C
index c0d753f..31a0b6b 100644
--- a/gcc/testsuite/g++.dg/warn/Wplacement-new-size.C
+++ b/gcc/testsuite/g++.dg/warn/Wplacement-new-size.C
@@ -1,6 +1,8 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-Wplacement-new -fpermissive" } */
 
+#include <stdint.h>
+
 typedef __typeof__ (sizeof 0) size_t;
 
 void* operator new (size_t, void *p) { return p; }
@@ -167,83 +169,83 @@ void test (void *p, int n)
     new (ac8) char [2][2][2];
     new (ac8) char [2][2][3];           // { dg-warning "placement" }
 
-    new (&c) int;                       // { dg-warning "placement" }
+    new (&c) int32_t;                   // { dg-warning "placement" }
 
-    new (&ac1) int;                     // { dg-warning "placement" }
-    new (&ac2) int;                     // { dg-warning "placement" }
-    new (&ac3) int;                     // { dg-warning "placement" }
-    new (&ac4) int;
+    new (&ac1) int32_t;                 // { dg-warning "placement" }
+    new (&ac2) int32_t;                 // { dg-warning "placement" }
+    new (&ac3) int32_t;                 // { dg-warning "placement" }
+    new (&ac4) int32_t;
 
     // Constructing at an address of an array element.
-    new (&ac1 [0]) int;                 // { dg-warning "placement" }
-    new (&ac2 [0]) int;                 // { dg-warning "placement" }
-    new (&ac3 [0]) int;                 // { dg-warning "placement" }
-    new (&ac4 [0]) int;
+    new (&ac1 [0]) int32_t;             // { dg-warning "placement" }
+    new (&ac2 [0]) int32_t;             // { dg-warning "placement" }
+    new (&ac3 [0]) int32_t;             // { dg-warning "placement" }
+    new (&ac4 [0]) int32_t;
 
     // ...plus or minus a constant offset.
-    new (&ac1 [0] + 0) int;             // { dg-warning "placement" }
-    new (&ac2 [0] + 0) int;             // { dg-warning "placement" }
-    new (&ac3 [0] + 0) int;             // { dg-warning "placement" }
-    new (&ac4 [0] + 0) int;
-    new (&ac4 [1] + 0) int;             // { dg-warning "placement" }
-    new (&ac4 [1] - 1) int;
-    new (&ac4 [2] - 1) int;             // { dg-warning "placement" }
-    new (&ac4 [2] - 2) int;
-    new (&ac4 [3] - 1) int;             // { dg-warning "placement" }
-    new (&ac4 [3] - 2) int;             // { dg-warning "placement" }
-    new (&ac4 [3] - 3) int;
-    new (&ac4 [4] - 1) int;             // { dg-warning "placement" }
-    new (&ac4 [4] - 2) int;             // { dg-warning "placement" }
-    new (&ac4 [4] - 3) int;             // { dg-warning "placement" }
-    new (&ac4 [4] - 4) int;
-
-    new (&ac1 [0] + 1) int;             // { dg-warning "placement" }
-    new (&ac2 [0] + 1) int;             // { dg-warning "placement" }
-    new (&ac3 [0] + 1) int;             // { dg-warning "placement" }
-    new (&ac4 [0] + 1) int;             // { dg-warning "placement" }
-
-    new (&ac3 [0] + n) int;             // { dg-warning "placement" }
-    new (&ac4 [0] + n) int;             // no warning (n could be zero)
-    new (&ac4 [1] + n) int;             // no warning (n could be negative)
-    new (&ac4 [2] + n) int;             // ditto
-    new (&ac4 [3] + n) int;             // ditto
-    new (&ac4 [4] + n) int;             // ditto
-    new (&ac4 [4] - n) int;             // (or positive)
-
-    new (&c + 0) int;                   // { dg-warning "placement" }
-    new (&c + 1) int;                   // { dg-warning "placement" }
+    new (&ac1 [0] + 0) int32_t;         // { dg-warning "placement" }
+    new (&ac2 [0] + 0) int32_t;         // { dg-warning "placement" }
+    new (&ac3 [0] + 0) int32_t;         // { dg-warning "placement" }
+    new (&ac4 [0] + 0) int32_t;
+    new (&ac4 [1] + 0) int32_t;         // { dg-warning "placement" }
+    new (&ac4 [1] - 1) int32_t;
+    new (&ac4 [2] - 1) int32_t;         // { dg-warning "placement" }
+    new (&ac4 [2] - 2) int32_t;
+    new (&ac4 [3] - 1) int32_t;         // { dg-warning "placement" }
+    new (&ac4 [3] - 2) int32_t;         // { dg-warning "placement" }
+    new (&ac4 [3] - 3) int32_t;
+    new (&ac4 [4] - 1) int32_t;         // { dg-warning "placement" }
+    new (&ac4 [4] - 2) int32_t;         // { dg-warning "placement" }
+    new (&ac4 [4] - 3) int32_t;         // { dg-warning "placement" }
+    new (&ac4 [4] - 4) int32_t;
+
+    new (&ac1 [0] + 1) int32_t;         // { dg-warning "placement" }
+    new (&ac2 [0] + 1) int32_t;         // { dg-warning "placement" }
+    new (&ac3 [0] + 1) int32_t;         // { dg-warning "placement" }
+    new (&ac4 [0] + 1) int32_t;         // { dg-warning "placement" }
+
+    new (&ac3 [0] + n) int32_t;         // { dg-warning "placement" }
+    new (&ac4 [0] + n) int32_t;         // no warning (n could be zero)
+    new (&ac4 [1] + n) int32_t;         // no warning (n could be negative)
+    new (&ac4 [2] + n) int32_t;         // ditto
+    new (&ac4 [3] + n) int32_t;         // ditto
+    new (&ac4 [4] + n) int32_t;         // ditto
+    new (&ac4 [4] - n) int32_t;         // (or positive)
+
+    new (&c + 0) int32_t;               // { dg-warning "placement" }
+    new (&c + 1) int32_t;               // { dg-warning "placement" }
 
     // Constructing at an offset into the address of an array.
-    new (&ac1 + 0) int;                 // { dg-warning "placement" }
-    new (&ac1 + 1) int;                 // { dg-warning "placement" }
-    new (&ac1 + n) int;                 // { dg-warning "placement" }
-    new (&ac2 + 0) int;                 // { dg-warning "placement" }
-    new (&ac2 + 1) int;                 // { dg-warning "placement" }
-    new (&ac2 + n) int;                 // { dg-warning "placement" }
-    new (&ac3 + 0) int;                 // { dg-warning "placement" }
-    new (&ac3 + 1) int;                 // { dg-warning "placement" }
+    new (&ac1 + 0) int32_t;             // { dg-warning "placement" }
+    new (&ac1 + 1) int32_t;             // { dg-warning "placement" }
+    new (&ac1 + n) int32_t;             // { dg-warning "placement" }
+    new (&ac2 + 0) int32_t;             // { dg-warning "placement" }
+    new (&ac2 + 1) int32_t;             // { dg-warning "placement" }
+    new (&ac2 + n) int32_t;             // { dg-warning "placement" }
+    new (&ac3 + 0) int32_t;             // { dg-warning "placement" }
+    new (&ac3 + 1) int32_t;             // { dg-warning "placement" }
 
     // Even though n below is uknown an array of 3 bytes isn't large
     // enugh for an int.
-    new (&ac3 + n) int;                 // { dg-warning "placement" }
+    new (&ac3 + n) int32_t;             // { dg-warning "placement" }
 
-    new (&ac4 + 0) int;
-    new (&ac4 + 1) int;                 // { dg-warning "placement" }
-    new (&ac4 + n) int;                 // no warning (n could be zero)
+    new (&ac4 + 0) int32_t;
+    new (&ac4 + 1) int32_t;             // { dg-warning "placement" }
+    new (&ac4 + n) int32_t;             // no warning (n could be zero)
 
     // Constructing in an array object.
-    new (ac1) int;                      // { dg-warning "placement" }
-    new (ac2) int;                      // { dg-warning "placement" }
-    new (ac3) int;                      // { dg-warning "placement" }
-    new (ac4) int;
-    new (ac5) int;
-    new (ac5 + 0) int;
-    new (ac5 + 1) int;
-    new (ac5 + n) int;                  // no warning (n could be zero)
-    new (ac5 + 2) int;                  // { dg-warning "placement" }
-    new (ac5 + 3) int;                  // { dg-warning "placement" }
-    new (ac5 + 4) int;                  // { dg-warning "placement" }
-    new (ac5 + 5) int;                  // { dg-warning "placement" }
+    new (ac1) int32_t;                  // { dg-warning "placement" }
+    new (ac2) int32_t;                  // { dg-warning "placement" }
+    new (ac3) int32_t;                  // { dg-warning "placement" }
+    new (ac4) int32_t;
+    new (ac5) int32_t;
+    new (ac5 + 0) int32_t;
+    new (ac5 + 1) int32_t;
+    new (ac5 + n) int32_t;              // no warning (n could be zero)
+    new (ac5 + 2) int32_t;              // { dg-warning "placement" }
+    new (ac5 + 3) int32_t;              // { dg-warning "placement" }
+    new (ac5 + 4) int32_t;              // { dg-warning "placement" }
+    new (ac5 + 5) int32_t;              // { dg-warning "placement" }
 
     new (ac1_1) char;
     new (ac1_1) char[1];
@@ -278,65 +280,65 @@ void test (void *p, int n)
     new (ac2_2) char[4][2];             // { dg-warning "placement" }
     new (ac2_2) char[5];                // { dg-warning "placement" }
 
-    new (&s) int;                       // { dg-warning "placement" }
-    new (&as1) int;                     // { dg-warning "placement" }
-    new (&as2) int;
+    new (&s) int32_t;                   // { dg-warning "placement" }
+    new (&as1) int32_t;                 // { dg-warning "placement" }
+    new (&as2) int32_t;
 
-    new (as1) int;                      // { dg-warning "placement" }
-    new (as2) int;
+    new (as1) int32_t;                  // { dg-warning "placement" }
+    new (as2) int32_t;
 
-    new (&sc.c) int;                    // { dg-warning "placement" }
-    new (&sac1.ac) int;                 // { dg-warning "placement" }
-    new (&sac2.ac) int;                 // { dg-warning "placement" }
-    new (&sac3.ac) int;                 // { dg-warning "placement" }
-    new (&sac4.ac) int;
+    new (&sc.c) int32_t;                // { dg-warning "placement" }
+    new (&sac1.ac) int32_t;             // { dg-warning "placement" }
+    new (&sac2.ac) int32_t;             // { dg-warning "placement" }
+    new (&sac3.ac) int32_t;             // { dg-warning "placement" }
+    new (&sac4.ac) int32_t;
 
     new (sc.pc) char;
-    new (sc.pc) int;
-    new (sc.pc) int[1024];
-    new (sc.pc + 0) int;
-    new (sc.pc + 0) int[2048];
-    new (sc.pv) int;
+    new (sc.pc) int32_t;
+    new (sc.pc) int32_t[1024];
+    new (sc.pc + 0) int32_t;
+    new (sc.pc + 0) int32_t[2048];
+    new (sc.pv) int32_t;
     new (sc.pv) char[1024];
 
-    new (sac1.ac) int;                  // { dg-warning "placement" }
-    new (sac2.ac) int;                  // { dg-warning "placement" }
-    new (sac3.ac) int;                  // { dg-warning "placement" }
-    new (sac4.ac) int;
+    new (sac1.ac) int32_t;              // { dg-warning "placement" }
+    new (sac2.ac) int32_t;              // { dg-warning "placement" }
+    new (sac3.ac) int32_t;              // { dg-warning "placement" }
+    new (sac4.ac) int32_t;
 
     new (&ssc.sc) SSC;                  // { dg-warning "placement" }
-    new (&ssac1.sac) int;               // { dg-warning "placement" }
-    new (&ssac2.sac) int;               // { dg-warning "placement" }
-    new (&ssac3.sac) int;               // { dg-warning "placement" }
-    new (&ssac4.sac) int;
+    new (&ssac1.sac) int32_t;           // { dg-warning "placement" }
+    new (&ssac2.sac) int32_t;           // { dg-warning "placement" }
+    new (&ssac3.sac) int32_t;           // { dg-warning "placement" }
+    new (&ssac4.sac) int32_t;
 
     new (&sssac4_2) char[sizeof sssac4_2];
     new (&sssac4_2) char[sizeof sssac4_2 + 1];   // { dg-warning "placement" }
 
     // taking the address of a temporary is allowed with -fpermissive
-    new (&fsc ().c) int;                // { dg-warning "address|placement" }
-    new (&fasc1 ().ac) int;             // { dg-warning "address|placement" }
-    new (&fasc2 ().ac) int;             // { dg-warning "address|placement" }
-    new (&fasc3 ().ac) int;             // { dg-warning "address|placement" }
-    new (&fasc4 ().ac) int;             // { dg-warning "address|placement" }
-
-    new (&uac1) int;                    // { dg-warning "placement" }
-    new (&uac2) int;                    // { dg-warning "placement" }
-    new (&uac3) int;                    // { dg-warning "placement" }
-    new (&uac4) int;
-    new (&uac4 + 1) int;                // { dg-warning "placement" }
-
-    new (&uac1.c) int;                  // { dg-warning "placement" }
-    new (&uac2.c) int;                  // { dg-warning "placement" }
-    new (&uac3.c) int;                  // { dg-warning "placement" }
+    new (&fsc ().c) int32_t;            // { dg-warning "address|placement" }
+    new (&fasc1 ().ac) int32_t;         // { dg-warning "address|placement" }
+    new (&fasc2 ().ac) int32_t;         // { dg-warning "address|placement" }
+    new (&fasc3 ().ac) int32_t;         // { dg-warning "address|placement" }
+    new (&fasc4 ().ac) int32_t;         // { dg-warning "address|placement" }
+
+    new (&uac1) int32_t;                // { dg-warning "placement" }
+    new (&uac2) int32_t;                // { dg-warning "placement" }
+    new (&uac3) int32_t;                // { dg-warning "placement" }
+    new (&uac4) int32_t;
+    new (&uac4 + 1) int32_t;            // { dg-warning "placement" }
+
+    new (&uac1.c) int32_t;              // { dg-warning "placement" }
+    new (&uac2.c) int32_t;              // { dg-warning "placement" }
+    new (&uac3.c) int32_t;              // { dg-warning "placement" }
 
     // Diagnose the following even though the size of uac4.c could be
     // expected to extend to the end of the union (as it is by Built-in
     // Object Size and so isn't diagnosed in calls to functions like
     // memset(&uac4.c, 0, sizeof(int)) when _FORTIFY_SOURCE is non-zero.  */
-    new (&uac4.c) int;                  // { dg-warning "placement" }
+    new (&uac4.c) int32_t;              // { dg-warning "placement" }
 
-    new (&uac4.c + 1) int;              // { dg-warning "placement" }
+    new (&uac4.c + 1) int32_t;          // { dg-warning "placement" }
 }
 
 
diff --git a/gcc/testsuite/g++.dg/warn/Wstrict-aliasing-5.C b/gcc/testsuite/g++.dg/warn/Wstrict-aliasing-5.C
index a049251..3910ba6 100644
--- a/gcc/testsuite/g++.dg/warn/Wstrict-aliasing-5.C
+++ b/gcc/testsuite/g++.dg/warn/Wstrict-aliasing-5.C
@@ -1,9 +1,11 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-Wstrict-aliasing=2 -O2" } */
 
+#include <stdint.h>
+
 float foo ()
 {
-  unsigned int MASK = 0x80000000;
+  uint32_t MASK = 0x80000000;
   return (float &) MASK; /* { dg-warning "strict-aliasing" } */
 }
 
diff --git a/gcc/testsuite/g++.dg/warn/Wstrict-aliasing-bogus-signed-unsigned.C b/gcc/testsuite/g++.dg/warn/Wstrict-aliasing-bogus-signed-unsigned.C
index 5e71ebf..a6e366b 100644
--- a/gcc/testsuite/g++.dg/warn/Wstrict-aliasing-bogus-signed-unsigned.C
+++ b/gcc/testsuite/g++.dg/warn/Wstrict-aliasing-bogus-signed-unsigned.C
@@ -1,10 +1,11 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-O2 -Wstrict-aliasing -fstrict-aliasing" } */
 
+#include <stdint.h>
 
-int foo () {
-  int i;
-  unsigned int* pu = reinterpret_cast<unsigned int*> (&i);  /* { dg-bogus "signed vs. unsigned" } */
+int32_t foo () {
+  int32_t i;
+  uint32_t* pu = reinterpret_cast<uint32_t*> (&i);  /* { dg-bogus "signed vs. unsigned" } */
   *pu = 1000000;
   return i;
 }
diff --git a/gcc/testsuite/g++.dg/warn/Wtype-limits-Wextra.C b/gcc/testsuite/g++.dg/warn/Wtype-limits-Wextra.C
index f840f30..e19136e 100644
--- a/gcc/testsuite/g++.dg/warn/Wtype-limits-Wextra.C
+++ b/gcc/testsuite/g++.dg/warn/Wtype-limits-Wextra.C
@@ -20,13 +20,15 @@ void a (unsigned char x)
 
 }
 
+#ifndef __ia16__
 void b (unsigned short x)
 {
-  if (x < 0)  return;/* { dg-warning "comparison is always false due to limited range of data type" } */
-  if (x >= 0) return;/* { dg-warning "comparison is always true due to limited range of data type" } */
-  if (0 > x)  return;/* { dg-warning "comparison is always false due to limited range of data type" } */
-  if (0 <= x) return;/* { dg-warning "comparison is always true due to limited range of data type" } */
+  if (x < 0)  return;/* { dg-warning "comparison is always false due to limited range of data type" "" { target { ! ia16-*-* } } } */
+  if (x >= 0) return;/* { dg-warning "comparison is always true due to limited range of data type" "" { target { ! ia16-*-* } } } */
+  if (0 > x)  return;/* { dg-warning "comparison is always false due to limited range of data type" "" { target { ! ia16-*-* } } } */
+  if (0 <= x) return;/* { dg-warning "comparison is always true due to limited range of data type" "" { target { ! ia16-*-* } } } */
 }
+#endif
 
 void c (unsigned int x)
 {
@@ -58,7 +60,7 @@ void e (unsigned long long x)
 
 int test (int x) 
 {
-  if ((long long)x <= 0x123456789ABCLL) /* { dg-bogus "comparison is always true due to limited range of data type" "" { xfail *-*-* } 61 } */
+  if ((long long)x <= 0x123456789ABCLL) /* { dg-bogus "comparison is always true due to limited range of data type" "" { xfail *-*-* } 63 } */
     return 1;
   else 
     return 0;
diff --git a/gcc/testsuite/g++.dg/warn/Wtype-limits.C b/gcc/testsuite/g++.dg/warn/Wtype-limits.C
index a352e7b..ff8d522 100644
--- a/gcc/testsuite/g++.dg/warn/Wtype-limits.C
+++ b/gcc/testsuite/g++.dg/warn/Wtype-limits.C
@@ -20,13 +20,15 @@ void a (unsigned char x)
 
 }
 
+#ifndef __ia16__
 void b (unsigned short x)
 {
-  if (x < 0)  return;/* { dg-warning "comparison is always false due to limited range of data type" } */
-  if (x >= 0) return;/* { dg-warning "comparison is always true due to limited range of data type" } */
-  if (0 > x)  return;/* { dg-warning "comparison is always false due to limited range of data type" } */
-  if (0 <= x) return;/* { dg-warning "comparison is always true due to limited range of data type" } */
+  if (x < 0)  return;/* { dg-warning "comparison is always false due to limited range of data type" "" { target { ! ia16-*-* } } } */
+  if (x >= 0) return;/* { dg-warning "comparison is always true due to limited range of data type" "" { target { ! ia16-*-* } } } */
+  if (0 > x)  return;/* { dg-warning "comparison is always false due to limited range of data type" "" { target { ! ia16-*-* } } } */
+  if (0 <= x) return;/* { dg-warning "comparison is always true due to limited range of data type" "" { target { ! ia16-*-* } } } */
 }
+#endif
 
 void c (unsigned int x)
 {
@@ -58,7 +60,7 @@ void e (unsigned long long x)
 
 int test (int x) 
 {
-  if ((long long)x <= 0x123456789ABCLL) /* { dg-bogus "comparison is always true due to limited range of data type" "" { xfail *-*-* } 61 } */
+  if ((long long)x <= 0x123456789ABCLL) /* { dg-bogus "comparison is always true due to limited range of data type" "" { xfail *-*-* } 63 } */
     return 1;
   else 
     return 0;
diff --git a/gcc/testsuite/g++.old-deja/g++.abi/ptrmem.C b/gcc/testsuite/g++.old-deja/g++.abi/ptrmem.C
index 3417358..36d88fd 100644
--- a/gcc/testsuite/g++.old-deja/g++.abi/ptrmem.C
+++ b/gcc/testsuite/g++.old-deja/g++.abi/ptrmem.C
@@ -7,7 +7,7 @@
    function.  However, some platforms use all bits to encode a
    function pointer.  Such platforms use the lowest bit of the delta,
    that is shifted left by one bit.  */
-#if defined __MN10300__ || defined __SH5__ || defined __arm__ || defined __thumb__ || defined __mips__ || defined __aarch64__
+#if defined __MN10300__ || defined __SH5__ || defined __arm__ || defined __thumb__ || defined __mips__ || defined __aarch64__ || defined __ia16__
 #define ADJUST_PTRFN(func, virt) ((void (*)())(func))
 #define ADJUST_DELTA(delta, virt) (((delta) << 1) + !!(virt))
 #else
diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/enum11.C b/gcc/testsuite/g++.old-deja/g++.brendan/enum11.C
index fda718b4..874d0c6 100644
--- a/gcc/testsuite/g++.old-deja/g++.brendan/enum11.C
+++ b/gcc/testsuite/g++.old-deja/g++.brendan/enum11.C
@@ -1,4 +1,4 @@
-// { dg-do assemble  }
+// { dg-do assemble { target int32plus } }
 // GROUPS passed enums
 class X
 {
diff --git a/gcc/testsuite/g++.old-deja/g++.bugs/900227_01.C b/gcc/testsuite/g++.old-deja/g++.bugs/900227_01.C
index b441eff..ed596a9 100644
--- a/gcc/testsuite/g++.old-deja/g++.bugs/900227_01.C
+++ b/gcc/testsuite/g++.old-deja/g++.bugs/900227_01.C
@@ -33,7 +33,7 @@
 
 int main ();
 
-short s = (short) &main;	// { dg-error "loses precision" "lose" { xfail h8*-*-* xstormy16-*-* } }
+short s = (short) &main;	// { dg-error "loses precision" "lose" { xfail h8*-*-* xstormy16-*-* ia16-*-* } }
 char c = (char) &main;		// { dg-error "loses precision" "lose" }
 
 int main () { return 0; }
diff --git a/gcc/testsuite/g++.old-deja/g++.jason/thunk3.C b/gcc/testsuite/g++.old-deja/g++.jason/thunk3.C
index 7e0b93a..07a2400 100644
--- a/gcc/testsuite/g++.old-deja/g++.jason/thunk3.C
+++ b/gcc/testsuite/g++.old-deja/g++.jason/thunk3.C
@@ -1,5 +1,5 @@
 // { dg-do run }
-// { dg-skip-if "fails with generic thunk support" { rs6000-*-* powerpc-*-eabi v850-*-* sh-*-* sh64-*-* h8*-*-* xtensa*-*-* m32r*-*-* lm32-*-* nios2-*-* } { "*" } { "" } }
+// { dg-skip-if "fails with generic thunk support" { rs6000-*-* powerpc-*-eabi v850-*-* sh-*-* sh64-*-* h8*-*-* xtensa*-*-* m32r*-*-* lm32-*-* nios2-*-* ia16-*-* } { "*" } { "" } }
 // Test that variadic function calls using thunks work right.
 // Note that this will break on any target that uses the generic thunk
 //  support, because it doesn't support variadic functions.
diff --git a/gcc/testsuite/g++.old-deja/g++.mike/ns15.C b/gcc/testsuite/g++.old-deja/g++.mike/ns15.C
index 4e767b8..f6a4a3b 100644
--- a/gcc/testsuite/g++.old-deja/g++.mike/ns15.C
+++ b/gcc/testsuite/g++.old-deja/g++.mike/ns15.C
@@ -4,7 +4,11 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#ifdef __ia16__
+#define MAX 16
+#else
 #define MAX 256
+#endif
 #define MAXSTATE 1000000
 
 struct R {
diff --git a/gcc/testsuite/g++.old-deja/g++.other/exprstmt1.C b/gcc/testsuite/g++.old-deja/g++.other/exprstmt1.C
index abe0729..a2e44b3 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/exprstmt1.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/exprstmt1.C
@@ -1,25 +1,27 @@
-// { dg-do run  }
+// { dg-do run { target { stdint_types } } }
 // { dg-options "-O" }
 // { dg-error "limited range of data type" "16-bit target" { target xstormy16-*-* } 0 }
 // { dg-error "shift count >=" "16-bit target" { target xstormy16-*-* } 0 }
 
+#include <stdint.h>
+
 int main()
 {
-  unsigned int x = 1381237248;
+  uint32_t x = 1381237248;
 
   if (sizeof (x) != 4)
     return 0;
 
   x =
     ({
-      unsigned int y = x;
+      uint32_t y = x;
       ({
-        unsigned int z = y;
-        (unsigned int)
-          ((((unsigned int)z & (unsigned int)0x000000ffUL) << 24)
-           | (((unsigned int)z & (unsigned int)0x0000ff00UL) << 8)
-           | (((unsigned int)z & (unsigned int)0x00ff0000UL) >> 8)
-           | (((unsigned int)z & (unsigned int)0xff000000UL) >> 24));
+        uint32_t z = y;
+        (uint32_t)
+          ((((uint32_t)z & (uint32_t)0x000000ffUL) << 24)
+           | (((uint32_t)z & (uint32_t)0x0000ff00UL) << 8)
+           | (((uint32_t)z & (uint32_t)0x00ff0000UL) >> 8)
+           | (((uint32_t)z & (uint32_t)0xff000000UL) >> 24));
        });
      });
   return x != 152658;
diff --git a/gcc/testsuite/g++.old-deja/g++.other/inline12.C b/gcc/testsuite/g++.old-deja/g++.other/inline12.C
index c91845c..5df62a3 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/inline12.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/inline12.C
@@ -1,10 +1,12 @@
-// { dg-do assemble  }
+// { dg-do assemble { target { stdint_types } } }
 // { dg-options "-O2 -g" }
 // (Should preferrably cycle through options.)
 // Origin: Hans-Peter Nilsson <hp@axis.com>
 // See <URL:http://gcc.gnu.org/ml/gcc-patches/2000-06/msg00310.html>
 
-typedef unsigned int    udword;
+#include <stdint.h>
+
+typedef uint32_t    udword;
 extern "C" {
 void __assert (const char *, int, const char *);
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.other/new6.C b/gcc/testsuite/g++.old-deja/g++.other/new6.C
index 7013337..e37c4cc 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/new6.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/new6.C
@@ -1,12 +1,13 @@
-// { dg-do run  }
+// { dg-do run { target { stdint_types } } }
 // Test that we properly default-initialize the new int when () is given.
 
+#include <stdint.h>
 #include <new>
 using namespace std;
 extern "C" void *malloc (size_t);
 
 int special;
-int space = 0xdeadbeef;
+int_least32_t space = 0xdeadbeef;
 
 void *operator new (size_t size)
 #if __cplusplus <= 199711L
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash16.C b/gcc/testsuite/g++.old-deja/g++.pt/crash16.C
index aa25c22..fbaeb91 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/crash16.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/crash16.C
@@ -2,6 +2,12 @@
 // { dg-xfail-if "" { xstormy16-*-* } { "*" } { "" } }
 // { dg-options "" }
 
+#ifdef __ia16__
+#define MAX 16
+#else
+#define MAX 256
+#endif
+
 extern "C" void qsort(void *base, __SIZE_TYPE__ nmemb, __SIZE_TYPE__ size,
               int (*compar)(const void *, const void *));
 
@@ -25,6 +31,6 @@ namespace CXX {
 using namespace CXX;
 
 void sort_machine() {
-  struct R d[256][256];
-  qsort<R,256> (d, cmp_d);
+  struct R d[MAX][MAX];
+  qsort<R,MAX> (d, cmp_d);
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.robertl/eb76.C b/gcc/testsuite/g++.old-deja/g++.robertl/eb76.C
index 3125dc1..b2a4bd2 100644
--- a/gcc/testsuite/g++.old-deja/g++.robertl/eb76.C
+++ b/gcc/testsuite/g++.old-deja/g++.robertl/eb76.C
@@ -1,4 +1,4 @@
-// { dg-do assemble  }
+// { dg-do assemble { target int32plus } }
 // { dg-options "-fno-short-enums" }
 // the template operator!= interferes.  It should be in a namespace.
 
diff --git a/gcc/testsuite/g++.old-deja/g++.warn/flow1.C b/gcc/testsuite/g++.old-deja/g++.warn/flow1.C
index 61f6a55..e652842 100644
--- a/gcc/testsuite/g++.old-deja/g++.warn/flow1.C
+++ b/gcc/testsuite/g++.old-deja/g++.warn/flow1.C
@@ -1,12 +1,14 @@
-// { dg-do assemble  }
+// { dg-do assemble { target { stdint_types } } }
 // { dg-options "-Wreturn-type" }
 // Test that we don't get a warning about flowing off the end.
 
+#include <stdint.h>
+
 struct A {
   ~A ();
 };
 
-int f()
+int_least32_t f()
 {
   A a1[2];
   A a2[2];
diff --git a/gcc/testsuite/gcc.c-torture/compile/20000804-1.c b/gcc/testsuite/gcc.c-torture/compile/20000804-1.c
index 38e42be..1e7cff1 100644
--- a/gcc/testsuite/gcc.c-torture/compile/20000804-1.c
+++ b/gcc/testsuite/gcc.c-torture/compile/20000804-1.c
@@ -2,7 +2,7 @@
    statement to force a 'long long' (64-bits) to go in a register.  */
 /* { dg-do assemble } */
 /* { dg-skip-if "" { { i?86-*-* x86_64-*-* } && { ia32 && { ! nonpic } } } { "*" } { "" } } */
-/* { dg-skip-if "No 64-bit registers" { m32c-*-* } { "*" } { "" } } */
+/* { dg-skip-if "No 64-bit registers" { m32c-*-* ia16-*-* } { "*" } { "" } } */
 /* { dg-skip-if "Not enough 64-bit registers" { pdp11-*-* } { "-O0" } { "" } } */
 /* { dg-xfail-if "" { h8300-*-* } { "*" } { "" } } */
 
diff --git a/gcc/testsuite/gcc.c-torture/compile/20151204.c b/gcc/testsuite/gcc.c-torture/compile/20151204.c
index e07e13d..58daae0 100644
--- a/gcc/testsuite/gcc.c-torture/compile/20151204.c
+++ b/gcc/testsuite/gcc.c-torture/compile/20151204.c
@@ -2,6 +2,12 @@
 
 typedef __SIZE_TYPE__ size_t;
 
+#ifdef __ia16__
+#define BUFFER_LENGTH 3275
+#else
+#define BUFFER_LENGTH 32753
+#endif
+
 int strcmp (const char*, const char*);
 void *memchr (const void *, int, size_t);
 char* strncpy (char *, const char *, size_t);
@@ -9,8 +15,8 @@ char* strncpy (char *, const char *, size_t);
 int
 main (int argc, char** argv)
 {
-  char target[32753] = "A";
-  char buffer[32753];
+  char target[BUFFER_LENGTH] = "A";
+  char buffer[BUFFER_LENGTH];
   char *x;
   x = buffer;
 
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr35318.c b/gcc/testsuite/gcc.c-torture/compile/pr35318.c
index 6837d2d..52b4946 100644
--- a/gcc/testsuite/gcc.c-torture/compile/pr35318.c
+++ b/gcc/testsuite/gcc.c-torture/compile/pr35318.c
@@ -1,4 +1,4 @@
-/* { dg-skip-if "" { pdp11-*-* } { "*" } { "" } } */
+/* { dg-skip-if "" { pdp11-*-* ia16-*-* } { "*" } { "" } } */
 /* PR target/35318 */
 
 void
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr37669.c b/gcc/testsuite/gcc.c-torture/compile/pr37669.c
index c78243b..1e33cc7 100644
--- a/gcc/testsuite/gcc.c-torture/compile/pr37669.c
+++ b/gcc/testsuite/gcc.c-torture/compile/pr37669.c
@@ -1,5 +1,8 @@
 /* This testcase used to fail because a miscompiled execute_fold_all_builtins. */
 /* { dg-options "-fgnu89-inline" } */
+/* { dg-require-effective-target stdint_types } */
+
+#include <stdint.h>
 
 typedef __SIZE_TYPE__ size_t;
 extern __inline __attribute__ ((__always_inline__)) int __attribute__
@@ -8,7 +11,7 @@ extern __inline __attribute__ ((__always_inline__)) int __attribute__
   return __builtin___snprintf_chk (__s, __n, 2 - 1,       
 __builtin_object_size (__s, 2 > 1), __fmt, __builtin_va_arg_pack ());
 }
-int n1, n2, n3, n4, f5, f6;
+int_least32_t n1, n2, n3, n4, f5, f6;
 char * BackgroundGetUniqueString(void)
 {
   char s[256];
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr69102.c b/gcc/testsuite/gcc.c-torture/compile/pr69102.c
index b1328ca..1f0cdc6 100644
--- a/gcc/testsuite/gcc.c-torture/compile/pr69102.c
+++ b/gcc/testsuite/gcc.c-torture/compile/pr69102.c
@@ -1,4 +1,5 @@
 /* { dg-options "-Og -fPIC -fschedule-insns2 -fselective-scheduling2 -fno-tree-fre --param=max-sched-extend-regions-iters=10" } */
+/* { dg-require-effective-target scheduling } */
 void bar (unsigned int);
 
 void
diff --git a/gcc/testsuite/gcc.c-torture/execute/20101011-1.c b/gcc/testsuite/gcc.c-torture/execute/20101011-1.c
index 744763f..6382f50 100644
--- a/gcc/testsuite/gcc.c-torture/execute/20101011-1.c
+++ b/gcc/testsuite/gcc.c-torture/execute/20101011-1.c
@@ -89,6 +89,9 @@ __aeabi_idiv0 (int return_value)
 #elif defined (__nvptx__)
 /* There isn't even a signal function.  */
 # define DO_TEST 0
+#elif defined (__ia16__)
+/* We need to hook a hardware interrupt and implement it in the simulator.  */
+# define DO_TEST 0
 #else
 # define DO_TEST 1
 #endif
diff --git a/gcc/testsuite/gcc.c-torture/execute/bitfld-6.c b/gcc/testsuite/gcc.c-torture/execute/bitfld-6.c
index 50927dc..f81ad4f 100644
--- a/gcc/testsuite/gcc.c-torture/execute/bitfld-6.c
+++ b/gcc/testsuite/gcc.c-torture/execute/bitfld-6.c
@@ -1,7 +1,11 @@
+/* { dg-require-effective-target stdint_types } */
+
+#include <stdint.h>
+
 union U
 {
-  const int a;
-  unsigned b : 20;
+  const int_least32_t a;
+  uint_least32_t b : 20;
 };
 
 static union U u = { 0x12345678 };
diff --git a/gcc/testsuite/gcc.c-torture/execute/bitfld-7.c b/gcc/testsuite/gcc.c-torture/execute/bitfld-7.c
index e9a61df..2cc0133 100644
--- a/gcc/testsuite/gcc.c-torture/execute/bitfld-7.c
+++ b/gcc/testsuite/gcc.c-torture/execute/bitfld-7.c
@@ -1,7 +1,11 @@
+/* { dg-require-effective-target stdint_types } */
+
+#include <stdint.h>
+
 union U
 {
-  const int a;
-  unsigned b : 24;
+  const int_least32_t a;
+  uint_least32_t b : 24;
 };
 
 static union U u = { 0x12345678 };
diff --git a/gcc/testsuite/gcc.c-torture/execute/bswap-2.c b/gcc/testsuite/gcc.c-torture/execute/bswap-2.c
index 88132fe..a936f06 100644
--- a/gcc/testsuite/gcc.c-torture/execute/bswap-2.c
+++ b/gcc/testsuite/gcc.c-torture/execute/bswap-2.c
@@ -1,7 +1,7 @@
 #ifdef __UINT32_TYPE__
 typedef __UINT32_TYPE__ uint32_t;
 #else
-typedef __UINT32_TYPE__ unsigned;
+typedef unsigned uint32_t;
 #endif
 
 struct bitfield {
@@ -29,15 +29,15 @@ union bf_or_uint32 {
 __attribute__ ((noinline, noclone)) uint32_t
 partial_read_le32 (union bf_or_uint32 in)
 {
-  return in.bfval.f0 | (in.bfval.f1 << 8)
-	 | (in.bfval.f2 << 16) | (in.bfval.f3 << 24);
+  return in.bfval.f0 | ((uint32_t)in.bfval.f1 << 8)
+    | ((uint32_t)in.bfval.f2 << 16) | ((uint32_t)in.bfval.f3 << 24);
 }
 
 __attribute__ ((noinline, noclone)) uint32_t
 partial_read_be32 (union bf_or_uint32 in)
 {
-  return in.bfval.f3 | (in.bfval.f2 << 8)
-	 | (in.bfval.f1 << 16) | (in.bfval.f0 << 24);
+  return in.bfval.f3 | ((uint32_t)in.bfval.f2 << 8)
+    | ((uint32_t)in.bfval.f1 << 16) | ((uint32_t)in.bfval.f0 << 24);
 }
 
 __attribute__ ((noinline, noclone)) uint32_t
@@ -50,7 +50,7 @@ fake_read_le32 (char *x, char *y)
   *y = 1;
   c2 = x[2];
   c3 = x[3];
-  return c0 | c1 << 8 | c2 << 16 | c3 << 24;
+  return c0 | (uint32_t)c1 << 8 | (uint32_t)c2 << 16 | (uint32_t)c3 << 24;
 }
 
 __attribute__ ((noinline, noclone)) uint32_t
@@ -63,7 +63,7 @@ fake_read_be32 (char *x, char *y)
   *y = 1;
   c2 = x[2];
   c3 = x[3];
-  return c3 | c2 << 8 | c1 << 16 | c0 << 24;
+  return c3 | (uint32_t)c2 << 8 | (uint32_t)c1 << 16 | (uint32_t)c0 << 24;
 }
 
 __attribute__ ((noinline, noclone)) uint32_t
@@ -76,7 +76,7 @@ incorrect_read_le32 (char *x, char *y)
   c2 = x[2];
   c3 = x[3];
   *y = 1;
-  return c0 | c1 << 8 | c2 << 16 | c3 << 24;
+  return c0 | (uint32_t)c1 << 8 | (uint32_t)c2 << 16 | (uint32_t)c3 << 24;
 }
 
 __attribute__ ((noinline, noclone)) uint32_t
@@ -89,7 +89,7 @@ incorrect_read_be32 (char *x, char *y)
   c2 = x[2];
   c3 = x[3];
   *y = 1;
-  return c3 | c2 << 8 | c1 << 16 | c0 << 24;
+  return c3 | (uint32_t)c2 << 8 | (uint32_t)c1 << 16 | (uint32_t)c0 << 24;
 }
 
 int
diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/builtins.exp b/gcc/testsuite/gcc.c-torture/execute/builtins/builtins.exp
index a959b4a..42a6eac 100644
--- a/gcc/testsuite/gcc.c-torture/execute/builtins/builtins.exp
+++ b/gcc/testsuite/gcc.c-torture/execute/builtins/builtins.exp
@@ -47,6 +47,9 @@ if { [istarget *-*-eabi*]
      || [istarget *-*-rtems*] } {
    lappend additional_flags "-Wl,--allow-multiple-definition"
 }
+if [istarget "ia16-*-elf"] {
+   lappend additional_flags "-mcmodel=small"
+}
 
 foreach src [lsort [find $srcdir/$subdir *.c]] {
     if {![string match *-lib.c $src] && [runtest_file_p $runtests $src]} {
diff --git a/gcc/testsuite/gcc.c-torture/execute/divmod-1.c b/gcc/testsuite/gcc.c-torture/execute/divmod-1.c
index 2bcd109..83fba00 100644
--- a/gcc/testsuite/gcc.c-torture/execute/divmod-1.c
+++ b/gcc/testsuite/gcc.c-torture/execute/divmod-1.c
@@ -54,20 +54,22 @@ main ()
 {
   if (div1 (-(1 << 7)) != 1 << 7)
     abort ();
-  if (div2 (-(1 << 15)) != 1 << 15)
-    abort ();
   if (div3 (-(1 << 7), -1) != 1 << 7)
     abort ();
-  if (div4 (-(1 << 15), -1) != 1 << 15)
-    abort ();
   if (mod1 (-(1 << 7)) != 0)
     abort ();
-  if (mod2 (-(1 << 15)) != 0)
-    abort ();
   if (mod3 (-(1 << 7), -1) != 0)
     abort ();
+#if __SIZEOF_SHORT__ < __SIZEOF_INT__
+  if (div2 (-(1 << 15)) != 1 << 15)
+    abort ();
+  if (div4 (-(1 << 15), -1) != 1 << 15)
+    abort ();
+  if (mod2 (-(1 << 15)) != 0)
+    abort ();
   if (mod4 (-(1 << 15), -1) != 0)
     abort ();
+#endif
   if (mod5 (0x50000000, 2) != 0)
     abort ();
   if (mod6 (0x50000000, 2) != 0)
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr38151.c b/gcc/testsuite/gcc.c-torture/execute/pr38151.c
index 5ee058d..957f6ca 100644
--- a/gcc/testsuite/gcc.c-torture/execute/pr38151.c
+++ b/gcc/testsuite/gcc.c-torture/execute/pr38151.c
@@ -1,10 +1,11 @@
 /* { dg-options "-Wno-psabi" } */
+
 void abort (void);
 
 struct S2848
 {
-  unsigned int a;
-  _Complex int b;
+  __UINT_LEAST32_TYPE__ a;
+  _Complex __INT_LEAST32_TYPE__ b;
   struct
   {
   } __attribute__ ((aligned)) c;
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr47237.c b/gcc/testsuite/gcc.c-torture/execute/pr47237.c
index 0802531..12c7b57 100644
--- a/gcc/testsuite/gcc.c-torture/execute/pr47237.c
+++ b/gcc/testsuite/gcc.c-torture/execute/pr47237.c
@@ -2,6 +2,12 @@
 /* { dg-require-effective-target untyped_assembly } */
 #define INTEGER_ARG  5
 
+#ifdef __ia16__
+#define ARGS_SIZE 2
+#else
+#define ARGS_SIZE 16
+#endif
+
 extern void abort(void);
 
 static void foo(int arg)
@@ -13,7 +19,7 @@ static void foo(int arg)
 static void bar(int arg)
 {
   foo(arg);
-  __builtin_apply(foo, __builtin_apply_args(), 16);
+  __builtin_apply(foo, __builtin_apply_args(), ARGS_SIZE);
 }
 
 int main(void)
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr52286.c b/gcc/testsuite/gcc.c-torture/execute/pr52286.c
index bb56295..4fd5d6a 100644
--- a/gcc/testsuite/gcc.c-torture/execute/pr52286.c
+++ b/gcc/testsuite/gcc.c-torture/execute/pr52286.c
@@ -11,7 +11,7 @@ main ()
   b = (~a | 1) & -2038094497;
 #else
   long a, b;
-  asm ("" : "=r" (a) : "0" (0));
+  asm ("" : "=r" (a) : "0" (0L));
   b = (~a | 1) & -2038094497L;
 #endif
   if (b >= 0)
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr53645.c b/gcc/testsuite/gcc.c-torture/execute/pr53645.c
index d86a895..0329cb7 100644
--- a/gcc/testsuite/gcc.c-torture/execute/pr53645.c
+++ b/gcc/testsuite/gcc.c-torture/execute/pr53645.c
@@ -1,8 +1,11 @@
 /* PR tree-optimization/53645 */
 /* { dg-options "-std=gnu89" } */
+/* { dg-require-effective-target stdint_types } */
 
-typedef unsigned int UV __attribute__((vector_size (16)));
-typedef int SV __attribute__((vector_size (16)));
+#include <stdint.h>
+
+typedef uint32_t UV __attribute__((vector_size (16)));
+typedef int32_t SV __attribute__((vector_size (16)));
 extern void abort (void);
 
 #define TEST(a, b, c, d) \
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr66556.c b/gcc/testsuite/gcc.c-torture/execute/pr66556.c
index f7acf1c..f8a3d56 100644
--- a/gcc/testsuite/gcc.c-torture/execute/pr66556.c
+++ b/gcc/testsuite/gcc.c-torture/execute/pr66556.c
@@ -1,9 +1,11 @@
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
+
+#include <stdint.h>
 
 extern void abort (void);
 
 struct {
-  unsigned f2;
+  uint32_t f2;
   unsigned f3 : 15;
   unsigned f5 : 3;
   short f6;
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr67781.c b/gcc/testsuite/gcc.c-torture/execute/pr67781.c
index bf50aa2..4e32988 100644
--- a/gcc/testsuite/gcc.c-torture/execute/pr67781.c
+++ b/gcc/testsuite/gcc.c-torture/execute/pr67781.c
@@ -10,13 +10,19 @@ typedef __UINT8_TYPE__ uint8_t;
 typedef unsigned char uint8_t;
 #endif
 
+#ifdef __INT32_TYPE__
+typedef __INT32_TYPE__ int32_t;
+#else
+typedef int int32_t;
+#endif
+
 struct
 {
   uint32_t a;
   uint8_t b;
 } s = { 0x123456, 0x78 };
 
-int pr67781()
+int32_t pr67781()
 {
   uint32_t c = (s.a << 8) | s.b;
   return c;
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr68648.c b/gcc/testsuite/gcc.c-torture/execute/pr68648.c
index fc66806..c6cafc4 100644
--- a/gcc/testsuite/gcc.c-torture/execute/pr68648.c
+++ b/gcc/testsuite/gcc.c-torture/execute/pr68648.c
@@ -1,13 +1,17 @@
+/* { dg-require-effective-target stdint_types } */
+
+#include <stdint.h>
+
 int __attribute__ ((noinline))
 foo (void)
 {
   return 123;
 }
 
-int __attribute__ ((noinline))
+int_least32_t __attribute__ ((noinline))
 bar (void)
 {
-  int c = 1;
+  int_least32_t c = 1;
   c |= 4294967295 ^ (foo () | 4073709551608);
   return c;
 }
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr70602.c b/gcc/testsuite/gcc.c-torture/execute/pr70602.c
index c6628b0..873d301 100644
--- a/gcc/testsuite/gcc.c-torture/execute/pr70602.c
+++ b/gcc/testsuite/gcc.c-torture/execute/pr70602.c
@@ -1,12 +1,15 @@
 /* PR tree-optimization/70602 */
+/* { dg-require-effective-target stdint_types } */
+
+#include <stdint.h>
 
 struct __attribute__((packed)) S
 {
-  int s : 1;
-  int t : 20;
+  int_least32_t s : 1;
+  int_least32_t t : 20;
 };
 
-int a, b, c;
+int_least32_t a, b, c;
 
 int
 main ()
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr71083.c b/gcc/testsuite/gcc.c-torture/execute/pr71083.c
index 0574434..f7c9b95 100644
--- a/gcc/testsuite/gcc.c-torture/execute/pr71083.c
+++ b/gcc/testsuite/gcc.c-torture/execute/pr71083.c
@@ -1,5 +1,9 @@
+/* { dg-require-effective-target stdint_types } */
+
+#include <stdint.h>
+
 struct lock_chain {
-  unsigned int irq_context: 2,
+  uint_least32_t irq_context: 2,
     depth: 6,
     base: 24;
 };
diff --git a/gcc/testsuite/gcc.dg/20020312-2.c b/gcc/testsuite/gcc.dg/20020312-2.c
index 5fce50d..868d2fb 100644
--- a/gcc/testsuite/gcc.dg/20020312-2.c
+++ b/gcc/testsuite/gcc.dg/20020312-2.c
@@ -109,6 +109,8 @@ extern void abort (void);
 /* No pic register.  */
 #elif defined (__nvptx__)
 /* No pic register.  */
+#elif defined(__ia16__)
+/* No pic register.  */
 #else
 # error "Modify the test for your target."
 #endif
diff --git a/gcc/testsuite/gcc.dg/20060410.c b/gcc/testsuite/gcc.dg/20060410.c
index 88253bb..1cd67a6 100644
--- a/gcc/testsuite/gcc.dg/20060410.c
+++ b/gcc/testsuite/gcc.dg/20060410.c
@@ -1,5 +1,6 @@
 /* { dg-do compile } */
 /* { dg-options "-g" } */
+/* { dg-skip-if "No debug information" { ia16-*-* } { "*" } { "" } } */
 
 /* Make sure we didn't eliminate foo because we thought it was unused.  */
 
diff --git a/gcc/testsuite/gcc.dg/20100906-1.c b/gcc/testsuite/gcc.dg/20100906-1.c
index 042ba99..08d1590 100644
--- a/gcc/testsuite/gcc.dg/20100906-1.c
+++ b/gcc/testsuite/gcc.dg/20100906-1.c
@@ -12,7 +12,13 @@ enum rtx_code {
 void abort (void);
 
 struct rtx_def {
-  __extension__ enum rtx_code code:16;
+  __extension__ enum rtx_code code:
+#if __SIZEOF_INT__ == 2
+  8
+#else
+  16
+#endif
+;
 };
 typedef struct rtx_def *rtx;
 
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-11.c b/gcc/testsuite/gcc.dg/Warray-bounds-11.c
index 92e92c0..7220353 100644
--- a/gcc/testsuite/gcc.dg/Warray-bounds-11.c
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-11.c
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-O3 -Warray-bounds=2" } */
 
-extern void* malloc(unsigned long x);
+extern void* malloc(__SIZE_TYPE__ x);
 
 int e[3];
 
diff --git a/gcc/testsuite/gcc.dg/Wno-frame-address.c b/gcc/testsuite/gcc.dg/Wno-frame-address.c
index de5a8b8..82a420f 100644
--- a/gcc/testsuite/gcc.dg/Wno-frame-address.c
+++ b/gcc/testsuite/gcc.dg/Wno-frame-address.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-skip-if "Cannot access arbitrary stack frames" { arm*-*-* hppa*-*-* ia64-*-* visium-*-* } } */
+/* { dg-skip-if "Cannot access arbitrary stack frames" { arm*-*-* hppa*-*-* ia64-*-* visium-*-* ia16-*-* } } */
 /* { dg-options "-Werror" } */
 /* { dg-additional-options "-mbackchain" { target { s390*-*-* } } } */
 
diff --git a/gcc/testsuite/gcc.dg/asr_div1.c b/gcc/testsuite/gcc.dg/asr_div1.c
index 11b5246..0d1a6b2 100644
--- a/gcc/testsuite/gcc.dg/asr_div1.c
+++ b/gcc/testsuite/gcc.dg/asr_div1.c
@@ -1,19 +1,21 @@
 /* Test division by const int generates only one shift.  */
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
 /* { dg-options "-O2 -fdump-rtl-combine-all" } */
 
+#include <stdint.h>
+
 extern void abort (void);
 
 #define NOINLINE __attribute__((noinline))
 
-static NOINLINE int
-f1 (int n)
+static NOINLINE int_least32_t
+f1 (int_least32_t n)
 {
   return n / 33;
 }
 
-static NOINLINE int
-f2 (int n)
+static NOINLINE int_least32_t
+f2 (int_least32_t n)
 {
   return n / 77;
 }
@@ -21,9 +23,9 @@ f2 (int n)
 int
 main ()
 {
-  int a = 0xaaaaaaaa;
-  int b = 0x55555555;
-  int c;
+  int_least32_t a = 0xaaaaaaaa;
+  int_least32_t b = 0x55555555;
+  int_least32_t c;
   c = f1 (a);
   if (c != 0xfd6a052c)
     abort ();
diff --git a/gcc/testsuite/gcc.dg/builtin-apply2.c b/gcc/testsuite/gcc.dg/builtin-apply2.c
index b6cbe39..7535159 100644
--- a/gcc/testsuite/gcc.dg/builtin-apply2.c
+++ b/gcc/testsuite/gcc.dg/builtin-apply2.c
@@ -10,10 +10,12 @@
    with pre-pushed arguments (e.g. SPARC).  */
 
 
-
 #define INTEGER_ARG  5
 
-#if defined(__ARM_PCS) || defined(__epiphany__)
+#if defined(__ia16__)
+/* All args on stack but pointers and ints are 2 bytes each.  */
+#define STACK_ARGUMENTS_SIZE 28
+#elif defined(__ARM_PCS) || defined(__epiphany__)
 /* For Base AAPCS, NAME is passed in r0.  D is passed in r2 and r3.
    E, F and G are passed on stack.  So the size of the stack argument
    data is 20.  */
diff --git a/gcc/testsuite/gcc.dg/builtin-apply3.c b/gcc/testsuite/gcc.dg/builtin-apply3.c
index 37c5209..4b8c492 100644
--- a/gcc/testsuite/gcc.dg/builtin-apply3.c
+++ b/gcc/testsuite/gcc.dg/builtin-apply3.c
@@ -10,6 +10,12 @@
 
 #define INTEGER_ARG  5
 
+#ifdef __ia16__
+#define ARGS_SIZE 2
+#else
+#define ARGS_SIZE 16
+#endif
+
 extern void abort(void);
 
 void foo(int arg)
@@ -21,7 +27,7 @@ void foo(int arg)
 void bar(int arg)
 {
   foo(arg);
-  __builtin_apply(foo, __builtin_apply_args(), 16);
+  __builtin_apply(foo, __builtin_apply_args(), ARGS_SIZE);
 }
 
 int main(void)
diff --git a/gcc/testsuite/gcc.dg/compat/struct-by-value-5b_main.c b/gcc/testsuite/gcc.dg/compat/struct-by-value-5b_main.c
index dcb5f27..74754c0 100644
--- a/gcc/testsuite/gcc.dg/compat/struct-by-value-5b_main.c
+++ b/gcc/testsuite/gcc.dg/compat/struct-by-value-5b_main.c
@@ -1,3 +1,5 @@
+/* { dg-skip-if "Program too big" { "ia16-*-*" } { "*" } { "" } } */
+
 /* Test structures passed by value, including to a function with a
    variable-length argument lists.  All struct members are float
    scalars.  */
diff --git a/gcc/testsuite/gcc.dg/cpp/_Pragma6.c b/gcc/testsuite/gcc.dg/cpp/_Pragma6.c
index 7f3f776..be60b11 100644
--- a/gcc/testsuite/gcc.dg/cpp/_Pragma6.c
+++ b/gcc/testsuite/gcc.dg/cpp/_Pragma6.c
@@ -1,7 +1,7 @@
 /* PR c/27747 */
 /* This is supposed to succeed only if
    the target doesn't define HANDLE_PRAGMA_PACK_WITH_EXPANSION.  */
-/* { dg-do compile { target { ! { *-*-solaris2* } } } } */
+/* { dg-do compile { target { ! { *-*-solaris2* ia16-*-* } } } } */
 
 #define push bar
 #define foo _Pragma ("pack(push)")
diff --git a/gcc/testsuite/gcc.dg/enum-mode-1.c b/gcc/testsuite/gcc.dg/enum-mode-1.c
index a701123..5e588e0 100644
--- a/gcc/testsuite/gcc.dg/enum-mode-1.c
+++ b/gcc/testsuite/gcc.dg/enum-mode-1.c
@@ -1,4 +1,5 @@
 /* { dg-do compile } */
+/* { dg-options "-Wno-pedantic" } */
 
 enum e1 { A = 256 } __attribute__((__mode__(__byte__))); /* { dg-error "specified mode too small for enumeral values" } */
 enum e2 { B = 256 } __attribute__((__packed__, __mode__(__byte__))); /* { dg-error "specified mode too small for enumeral values" } */
@@ -6,5 +7,5 @@ enum e2 { B = 256 } __attribute__((__packed__, __mode__(__byte__))); /* { dg-err
 enum e3 { C = __INT_MAX__ } __attribute__((__mode__(__QI__))); /* { dg-error "specified mode too small for enumeral values" } */
 enum e4 { D = __INT_MAX__ } __attribute__((__packed__, __mode__(__QI__))); /* { dg-error "specified mode too small for enumeral values" } */
 
-enum e5 { E = __INT_MAX__ } __attribute__((__mode__(__HI__))); /* { dg-error "specified mode too small for enumeral values" } */
-enum e6 { F = __INT_MAX__ } __attribute__((__packed__, __mode__(__HI__))); /* { dg-error "specified mode too small for enumeral values" } */
+enum e5 { E = __INT_LEAST32_MAX__ } __attribute__((__mode__(__HI__))); /* { dg-error "specified mode too small for enumeral values" } */
+enum e6 { F = __INT_LEAST32_MAX__ } __attribute__((__packed__, __mode__(__HI__))); /* { dg-error "specified mode too small for enumeral values" } */
diff --git a/gcc/testsuite/gcc.dg/graphite/isl-ast-op-select.c b/gcc/testsuite/gcc.dg/graphite/isl-ast-op-select.c
index 688176e..c6d76cc 100644
--- a/gcc/testsuite/gcc.dg/graphite/isl-ast-op-select.c
+++ b/gcc/testsuite/gcc.dg/graphite/isl-ast-op-select.c
@@ -1,6 +1,12 @@
 /* { dg-options "-O2 -floop-nest-optimize" } */
 
-static void kernel_gemm(int ni, int nj, int nk, double alpha, double beta, double C[1024][1024], double A[1024][1024], double B[1024][1024])
+#if defined(STACK_SIZE)
+#define SIZE 32
+#else
+#define SIZE 1024
+#endif
+
+static void kernel_gemm(int ni, int nj, int nk, double alpha, double beta, double C[SIZE][SIZE], double A[SIZE][SIZE], double B[SIZE][SIZE])
 {
  int i, j, k;
  for (i = 0; i < ni; i++)
@@ -15,15 +21,15 @@ static void kernel_gemm(int ni, int nj, int nk, double alpha, double beta, doubl
 void *polybench_alloc_data (int, int);
 
 int main(int argc, char** argv) {
-  int ni = 1024;
-  int nj = 1024;
-  int nk = 1024;
+  int ni = SIZE;
+  int nj = SIZE;
+  int nk = SIZE;
   double alpha;
   double beta;
-  double (*C)[1024][1024];
-  C = (double(*)[1024][1024])polybench_alloc_data ((1024) * (1024), sizeof(double));
-  double (*A)[1024][1024];
-  A = (double(*)[1024][1024])polybench_alloc_data ((1024) * (1024), sizeof(double));
-  double (*B)[1024][1024];
+  double (*C)[SIZE][SIZE];
+  C = (double(*)[SIZE][SIZE])polybench_alloc_data ((SIZE) * (SIZE), sizeof(double));
+  double (*A)[SIZE][SIZE];
+  A = (double(*)[SIZE][SIZE])polybench_alloc_data ((SIZE) * (SIZE), sizeof(double));
+  double (*B)[SIZE][SIZE];
   kernel_gemm (ni, nj, nk, alpha, beta, *C, *A, *B);
 }
diff --git a/gcc/testsuite/gcc.dg/graphite/pr42205-1.c b/gcc/testsuite/gcc.dg/graphite/pr42205-1.c
index 413b9f7..b8abce0 100644
--- a/gcc/testsuite/gcc.dg/graphite/pr42205-1.c
+++ b/gcc/testsuite/gcc.dg/graphite/pr42205-1.c
@@ -1,6 +1,9 @@
 /* { dg-options "-O1 -ffast-math -floop-interchange" } */
+/* { dg-require-effective-target stdint_types } */
 
-int adler32(int adler, char *buf, int n)
+#include <stdint.h>
+
+int_least32_t adler32(int adler, char *buf, int n)
 {
   int sum = 0;
   do {
@@ -13,5 +16,5 @@ int adler32(int adler, char *buf, int n)
      adler += buf[3];
      sum += adler;
   } while (--n);
-  return adler | (sum << 16);
+  return adler | ((int_least32_t)sum << 16);
 }
diff --git a/gcc/testsuite/gcc.dg/graphite/pr42221.c b/gcc/testsuite/gcc.dg/graphite/pr42221.c
index da8daa1..33075d1 100644
--- a/gcc/testsuite/gcc.dg/graphite/pr42221.c
+++ b/gcc/testsuite/gcc.dg/graphite/pr42221.c
@@ -1,24 +1,27 @@
 /* { dg-options "-Os -fgraphite-identity" } */
+/* { dg-require-effective-target stdint_types } */
 
-static void b2w(unsigned int *out, const unsigned char *in, unsigned int len)
+#include <stdint.h>
+
+static void b2w(uint_least32_t *out, const unsigned char *in, unsigned int len)
 {
   const unsigned char *bpend = in + len;
   for (; in != bpend; in += 4, ++out)
   {
-    *out = (unsigned int) (in[0] ) |
-          (unsigned int) (in[3] << 24);
+    *out = (uint_least32_t) (in[0] ) |
+      (uint_least32_t) ((int_least32_t)in[3] << 24);
   }
 }
-static void md4step(unsigned int state[4], const unsigned char *data)
+static void md4step(uint_least32_t state[4], const unsigned char *data)
 {
-  unsigned int A, X[16];
+  uint_least32_t A, X[16];
   b2w(X, data, 64);
   state[0] += A;
 }
 void md4sum(void)
 {
   unsigned char final[128];
-  unsigned int state[4];
+  uint_least32_t state[4];
   md4step(state, final);
   md4step(state, final + 64);
 }
diff --git a/gcc/testsuite/gcc.dg/graphite/pr46185.c b/gcc/testsuite/gcc.dg/graphite/pr46185.c
index 36d46a4..aae9e40 100644
--- a/gcc/testsuite/gcc.dg/graphite/pr46185.c
+++ b/gcc/testsuite/gcc.dg/graphite/pr46185.c
@@ -6,7 +6,13 @@
 #include <stdio.h>
 #endif
 
-double u[1782225];
+#ifdef __ia16__
+#define SIZE 50
+#else
+#define SIZE 1335
+#endif
+
+double u[SIZE*SIZE];
 
 static int __attribute__((noinline))
 foo (int N, int *res)
@@ -15,12 +21,12 @@ foo (int N, int *res)
   double sum = 0;
   for (i = 0; i < N; i++)
     for (j = 0; j < N; j++)
-      sum = sum + u[i + 1335 * j];
+      sum = sum + u[i + SIZE * j];
 
   for (i = 0; i < N; i++)
-    u[1336 * i] *= 2;
+    u[(SIZE + 1) * i] *= 2;
 
-  *res = sum + N + u[1336 * 2] + u[1336];
+  *res = sum + N + u[(SIZE + 1) * 2] + u[SIZE + 1];
 }
 
 extern void abort ();
@@ -30,16 +36,16 @@ main (void)
 {
   int i, j, res;
 
-  for (i = 0; i < 1782225; i++)
+  for (i = 0; i < SIZE*SIZE; i++)
     u[i] = 2;
 
-  foo (1335, &res);
+  foo (SIZE, &res);
 
 #if DEBUG
   fprintf (stderr, "res = %d \n", res);
 #endif
 
-  if (res != 3565793)
+  if (res != 2*SIZE*SIZE + SIZE + 4 + 4)
     abort ();
 
   return 0;
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-0.c b/gcc/testsuite/gcc.dg/graphite/scop-0.c
index abeabce..55e4357 100644
--- a/gcc/testsuite/gcc.dg/graphite/scop-0.c
+++ b/gcc/testsuite/gcc.dg/graphite/scop-0.c
@@ -1,16 +1,24 @@
 int foo (void);
 void bar (void);
 
+#if defined (STACK_SIZE) && STACK_SIZE <= 50000
+#define LARGE 100
+#define SMALL 50
+#else
+#define LARGE 200
+#define SMALL 100
+#endif
+
 int toto()
 {
   /* Scop 1. */
   int i, j, k;
-  int a[201][100];
-  int b[100];
+  int a[LARGE + 1][SMALL];
+  int b[SMALL];
   int N = foo ();
 
-  for (i = 0; i < N+ 100; i++)
-    for (j = 0; j < 200; j++)
+  for (i = 0; i < N+ SMALL; i++)
+    for (j = 0; j < LARGE; j++)
       a[j][i] = a[j+1][10] + 2;
 
   return a[3][5] + b[1];
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-22.c b/gcc/testsuite/gcc.dg/graphite/scop-22.c
index 6ff5ccd..0986ca5 100644
--- a/gcc/testsuite/gcc.dg/graphite/scop-22.c
+++ b/gcc/testsuite/gcc.dg/graphite/scop-22.c
@@ -1,4 +1,8 @@
+#ifdef __ia16__
+double u[1782];
+#else
 double u[1782225];
+#endif
 
 void foo(int N, int *res)
 {
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-3.c b/gcc/testsuite/gcc.dg/graphite/scop-3.c
index 96e6639..7413b4e 100644
--- a/gcc/testsuite/gcc.dg/graphite/scop-3.c
+++ b/gcc/testsuite/gcc.dg/graphite/scop-3.c
@@ -1,23 +1,38 @@
+#if defined (STACK_SIZE) && STACK_SIZE <= 50000
+#define LARGE 100
+#define SMALL 50
+#define SMALL8 40
+#define SMALL6 30
+#define SMALL4 20
+#else
+#define LARGE 200
+#define SMALL 100
+#define SMALL8 80
+#define SMALL6 60
+#define SMALL4 40
+#endif
+
+
 int toto()
 {
   int i, j, k;
-  int a[100][200];
-  int b[100];
+  int a[SMALL][LARGE];
+  int b[SMALL];
 
-  for (i = 1; i < 100; i++)
+  for (i = 1; i < SMALL; i++)
     {
-      for (j = 1; j < 80; j++)
+      for (j = 1; j < SMALL8; j++)
 	a[j][i] = a[j+1][2*i-1*j] + 12;
 
       b[i] = b[i-1] + 10;
 
-      for (j = 1; j < 60; j++)
+      for (j = 1; j < SMALL6; j++)
 	a[j][i] = a[j+1][i-1] + 8;
 
       if (i == 23)
 	b[i] = a[i-1][i] + 6;
 
-      for (j = 1; j < 40; j++)
+      for (j = 1; j < SMALL4; j++)
 	a[j][i] = a[j+1][i-1] + 4;
     }
 
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-dsyr2k.c b/gcc/testsuite/gcc.dg/graphite/scop-dsyr2k.c
index d09c130..f86e0d4 100644
--- a/gcc/testsuite/gcc.dg/graphite/scop-dsyr2k.c
+++ b/gcc/testsuite/gcc.dg/graphite/scop-dsyr2k.c
@@ -1,4 +1,8 @@
+#ifdef __ia16__
+#define NMAX 30
+#else
 #define NMAX 3000
+#endif
 
 static double a[NMAX][NMAX], b[NMAX][NMAX], c[NMAX][NMAX];
 
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-dsyrk.c b/gcc/testsuite/gcc.dg/graphite/scop-dsyrk.c
index 2f8919d..7f0f934 100644
--- a/gcc/testsuite/gcc.dg/graphite/scop-dsyrk.c
+++ b/gcc/testsuite/gcc.dg/graphite/scop-dsyrk.c
@@ -1,4 +1,8 @@
+#ifdef __ia16__
+#define NMAX 30
+#else
 #define NMAX 3000
+#endif
 #define MEASURE_TIME 1
 
 static double a[NMAX][NMAX], c[NMAX][NMAX];
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-mvt.c b/gcc/testsuite/gcc.dg/graphite/scop-mvt.c
index 442a3a0..edf8687 100644
--- a/gcc/testsuite/gcc.dg/graphite/scop-mvt.c
+++ b/gcc/testsuite/gcc.dg/graphite/scop-mvt.c
@@ -1,4 +1,8 @@
+#ifdef __ia16__
+#define NMAX 20
+#else
 #define NMAX 2000
+#endif
 
 static double x1[NMAX], x2[NMAX], a[NMAX][NMAX], y_1[NMAX], y_2[NMAX];
 
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-sor.c b/gcc/testsuite/gcc.dg/graphite/scop-sor.c
index ad5278a..06e4a13 100644
--- a/gcc/testsuite/gcc.dg/graphite/scop-sor.c
+++ b/gcc/testsuite/gcc.dg/graphite/scop-sor.c
@@ -1,4 +1,8 @@
+#ifdef __ia16__
+#define SIZE 50
+#else
 #define SIZE 10000
+#endif
 
 static double P[SIZE][SIZE];
 
diff --git a/gcc/testsuite/gcc.dg/ifcvt-4.c b/gcc/testsuite/gcc.dg/ifcvt-4.c
index 319b583..2c7ba85 100644
--- a/gcc/testsuite/gcc.dg/ifcvt-4.c
+++ b/gcc/testsuite/gcc.dg/ifcvt-4.c
@@ -1,6 +1,6 @@
 /* { dg-options "-fdump-rtl-ce1 -O2 --param max-rtl-if-conversion-insns=3" } */
 /* { dg-additional-options "-misel" { target { powerpc*-*-* } } } */
-/* { dg-skip-if "Multiple set if-conversion not guaranteed on all subtargets" { "arm*-*-* hppa*64*-*-* visium-*-*" } }  */
+/* { dg-skip-if "Multiple set if-conversion not guaranteed on all subtargets" { "arm*-*-* hppa*64*-*-* visium-*-* ia16-*-*" } }  */
 
 typedef int word __attribute__((mode(word)));
 
diff --git a/gcc/testsuite/gcc.dg/init-excess-2.c b/gcc/testsuite/gcc.dg/init-excess-2.c
index 1bf0a96..88be1ba 100644
--- a/gcc/testsuite/gcc.dg/init-excess-2.c
+++ b/gcc/testsuite/gcc.dg/init-excess-2.c
@@ -3,7 +3,9 @@
    c/71115 - Missing warning: excess elements in struct initializer.  */
 /* { dg-do compile } */
 /* { dg-options "" } */
+/* { dg-require-effective-target stdint_types } */
 
+#include <stdint.h>
 #include <stddef.h>
 
 int* a[1] = {
@@ -36,7 +38,7 @@ union U {
   NULL              /* { dg-warning "excess elements|near init" } */
 };
 
-int __attribute__ ((vector_size (16))) ivec = {
+int32_t __attribute__ ((vector_size (16))) ivec = {
   0, 0, 0, 0,
   NULL              /* { dg-warning "excess elements|near init" } */
 };
diff --git a/gcc/testsuite/gcc.dg/ipa/pr63551.c b/gcc/testsuite/gcc.dg/ipa/pr63551.c
index 48b020a..9c5c217 100644
--- a/gcc/testsuite/gcc.dg/ipa/pr63551.c
+++ b/gcc/testsuite/gcc.dg/ipa/pr63551.c
@@ -21,7 +21,13 @@ void
 fn2 ()
 {
   d = 0;
-  union U b = { 4294967286U };
+  union U b = {
+#if __SIZEOF_INT__ == __SIZEOF_SHORT__
+    65526U
+#else
+    4294967286U
+#endif
+  };
   fn1 (b);
 }
 
diff --git a/gcc/testsuite/gcc.dg/ipa/pr63595.c b/gcc/testsuite/gcc.dg/ipa/pr63595.c
index d656de5..ee0899a 100644
--- a/gcc/testsuite/gcc.dg/ipa/pr63595.c
+++ b/gcc/testsuite/gcc.dg/ipa/pr63595.c
@@ -1,6 +1,7 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-O2 -fdump-ipa-icf-details"  } */
 
+#include <stdint.h>
 typedef int size_t;
 
 typedef struct TypHeader {
@@ -29,11 +30,11 @@ TypHandle FunOnRight (TypHandle hdCall)
 
     if ( ((hdCall)->size) != 3*((size_t)sizeof(TypHandle)) )
         return Error("",0L,0L);
-    hdPnt = ((long)(((TypHandle*)((hdCall)->ptr))[1])&1 ? (((TypHandle*)((hdCall)->ptr))[1]) : (* EvTab[(((long)(((TypHandle*)((hdCall)->ptr))[1]) & 1) ? 1 : ((((TypHandle*)((hdCall)->ptr))[1])->type))])((((TypHandle*)((hdCall)->ptr))[1])));
-    hdElm = ((long)(((TypHandle*)((hdCall)->ptr))[2])&1 ? (((TypHandle*)((hdCall)->ptr))[2]) : (* EvTab[(((long)(((TypHandle*)((hdCall)->ptr))[2]) & 1) ? 1 : ((((TypHandle*)((hdCall)->ptr))[2])->type))])((((TypHandle*)((hdCall)->ptr))[2])));
+    hdPnt = ((intptr_t)(((TypHandle*)((hdCall)->ptr))[1])&1 ? (((TypHandle*)((hdCall)->ptr))[1]) : (* EvTab[(((intptr_t)(((TypHandle*)((hdCall)->ptr))[1]) & 1) ? 1 : ((((TypHandle*)((hdCall)->ptr))[1])->type))])((((TypHandle*)((hdCall)->ptr))[1])));
+    hdElm = ((intptr_t)(((TypHandle*)((hdCall)->ptr))[2])&1 ? (((TypHandle*)((hdCall)->ptr))[2]) : (* EvTab[(((intptr_t)(((TypHandle*)((hdCall)->ptr))[2]) & 1) ? 1 : ((((TypHandle*)((hdCall)->ptr))[2])->type))])((((TypHandle*)((hdCall)->ptr))[2])));
 
 
-    hdRes = ((*TabProd[(((long)(hdPnt) & 1) ? 1 : ((hdPnt)->type))][(((long)(hdElm) & 1) ? 1 : ((hdElm)->type))])((hdPnt),(hdElm)));
+    hdRes = ((*TabProd[(((intptr_t)(hdPnt) & 1) ? 1 : ((hdPnt)->type))][(((intptr_t)(hdElm) & 1) ? 1 : ((hdElm)->type))])((hdPnt),(hdElm)));
     return hdRes;
 }
 
@@ -47,11 +48,11 @@ TypHandle FunOnLeft (TypHandle hdCall)
 
     if ( ((hdCall)->size) != 3*((size_t)sizeof(TypHandle)) )
         return Error("",0L,0L);
-    hdPnt = ((long)(((TypHandle*)((hdCall)->ptr))[1])&1 ? (((TypHandle*)((hdCall)->ptr))[1]) : (* EvTab[(((long)(((TypHandle*)((hdCall)->ptr))[1]) & 1) ? 1 : ((((TypHandle*)((hdCall)->ptr))[1])->type))])((((TypHandle*)((hdCall)->ptr))[1])));
-    hdElm = ((long)(((TypHandle*)((hdCall)->ptr))[2])&1 ? (((TypHandle*)((hdCall)->ptr))[2]) : (* EvTab[(((long)(((TypHandle*)((hdCall)->ptr))[2]) & 1) ? 1 : ((((TypHandle*)((hdCall)->ptr))[2])->type))])((((TypHandle*)((hdCall)->ptr))[2])));
+    hdPnt = ((intptr_t)(((TypHandle*)((hdCall)->ptr))[1])&1 ? (((TypHandle*)((hdCall)->ptr))[1]) : (* EvTab[(((intptr_t)(((TypHandle*)((hdCall)->ptr))[1]) & 1) ? 1 : ((((TypHandle*)((hdCall)->ptr))[1])->type))])((((TypHandle*)((hdCall)->ptr))[1])));
+    hdElm = ((intptr_t)(((TypHandle*)((hdCall)->ptr))[2])&1 ? (((TypHandle*)((hdCall)->ptr))[2]) : (* EvTab[(((intptr_t)(((TypHandle*)((hdCall)->ptr))[2]) & 1) ? 1 : ((((TypHandle*)((hdCall)->ptr))[2])->type))])((((TypHandle*)((hdCall)->ptr))[2])));
 
 
-    hdRes = ((*TabProd[(((long)(hdElm) & 1) ? 1 : ((hdElm)->type))][(((long)(hdPnt) & 1) ? 1 : ((hdPnt)->type))])((hdElm),(hdPnt)));
+    hdRes = ((*TabProd[(((intptr_t)(hdElm) & 1) ? 1 : ((hdElm)->type))][(((intptr_t)(hdPnt) & 1) ? 1 : ((hdPnt)->type))])((hdElm),(hdPnt)));
     return hdRes;
 }
 
diff --git a/gcc/testsuite/gcc.dg/ipa/pr64041.c b/gcc/testsuite/gcc.dg/ipa/pr64041.c
index 4877b4b..55b8fdf 100644
--- a/gcc/testsuite/gcc.dg/ipa/pr64041.c
+++ b/gcc/testsuite/gcc.dg/ipa/pr64041.c
@@ -1,14 +1,16 @@
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
 /* { dg-options "-O2" } */
 
+#include <stdint.h>
+
 int printf (const char *, ...);
 
 int a, b = 1, d;
 
 union U1
 {
-  unsigned int f0;
-  int f1;
+  uint_least32_t f0;
+  int_least32_t f1;
 };
 
 union U2
diff --git a/gcc/testsuite/gcc.dg/ipa/propalign-1.c b/gcc/testsuite/gcc.dg/ipa/propalign-1.c
index fe12682..778bbd2 100644
--- a/gcc/testsuite/gcc.dg/ipa/propalign-1.c
+++ b/gcc/testsuite/gcc.dg/ipa/propalign-1.c
@@ -12,7 +12,7 @@ foo (void *p)
 {
   uintptr_t a = (uintptr_t) p;
 
-  if (a % 4)
+  if (a % __BIGGEST_ALIGNMENT__)
     return fail_the_test (p);
   else
     return pass_the_test (p);
diff --git a/gcc/testsuite/gcc.dg/ipa/propalign-2.c b/gcc/testsuite/gcc.dg/ipa/propalign-2.c
index ee2c71d..ac0f4d8 100644
--- a/gcc/testsuite/gcc.dg/ipa/propalign-2.c
+++ b/gcc/testsuite/gcc.dg/ipa/propalign-2.c
@@ -24,7 +24,11 @@ foo (void *p)
 {
   uintptr_t a = (uintptr_t) p;
 
+#if __SIZEOF_POINTER__ == 2
+  if (a % 2)
+#else
   if (a % 4)
+#endif
     return fail_the_test (p);
   else
     return pass_the_test (p);
diff --git a/gcc/testsuite/gcc.dg/ipa/propalign-4.c b/gcc/testsuite/gcc.dg/ipa/propalign-4.c
index 4b2b597..8041b42 100644
--- a/gcc/testsuite/gcc.dg/ipa/propalign-4.c
+++ b/gcc/testsuite/gcc.dg/ipa/propalign-4.c
@@ -1,5 +1,8 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-O2 -fdump-ipa-cp"  } */
+
+#include <stdint.h>
+
 int n;
 
 static void
@@ -9,7 +12,7 @@ test(void *a)
   __builtin_memset (a,0,n);
 }
 
-static __attribute__ ((aligned(16))) int aa[10];
+static __attribute__ ((aligned(16))) int_least32_t aa[10];
 
 int
 main()
diff --git a/gcc/testsuite/gcc.dg/lto/20091013-1_1.c b/gcc/testsuite/gcc.dg/lto/20091013-1_1.c
index b75d095..c87d0f3 100644
--- a/gcc/testsuite/gcc.dg/lto/20091013-1_1.c
+++ b/gcc/testsuite/gcc.dg/lto/20091013-1_1.c
@@ -1,4 +1,7 @@
 /* { dg-xfail-if "cast to pointer of different size" { "avr-*-*" x86_64-*-mingw* } { "*" } { "" } } */
+
+#include <stdint.h>
+
 typedef struct HDC__ { int unused; } *HDC;
 typedef struct HFONT__ { int unused; } *HFONT;
 
@@ -75,7 +78,7 @@ static void update_font_code_page( DC *dc )
     if (dc->gdiFont)
         charset = WineEngGetTextCharsetInfo( dc->gdiFont, ((void *)0), 0 );
 
-    if (TranslateCharsetInfo( ((void *)(unsigned long)((unsigned long)charset)), &csi, 1) )
+    if (TranslateCharsetInfo( ((void *)(uintptr_t)((uintptr_t)charset)), &csi, 1) )
         dc->font_code_page = csi.ciACP;
     else {
         switch(charset) {
diff --git a/gcc/testsuite/gcc.dg/lto/20091013-1_2.c b/gcc/testsuite/gcc.dg/lto/20091013-1_2.c
index c856041..4fcdf9d 100644
--- a/gcc/testsuite/gcc.dg/lto/20091013-1_2.c
+++ b/gcc/testsuite/gcc.dg/lto/20091013-1_2.c
@@ -1,4 +1,7 @@
 /* { dg-xfail-if "cast to pointer of different size" { "avr-*-*" x86_64-*-mingw* } { "*" } { "" } } */
+
+#include <stdint.h>
+
 typedef struct HDC__ { int unused; } *HDC;
 typedef struct HFONT__ { int unused; } *HFONT;
 
@@ -14,7 +17,7 @@ typedef struct tagLOGFONTW
 typedef struct tagGdiFont GdiFont;
 typedef struct tagDC DC;
 
-extern unsigned int WineEngGetFontData(GdiFont*, unsigned int, unsigned int, void*, unsigned int);
+extern unsigned int WineEngGetFontData(GdiFont*, uint32_t, unsigned int, void*, unsigned int);
 
 struct list
 {
@@ -122,11 +125,11 @@ static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pma
 
 
     for ((font_elem_ptr) = (&gdi_font_list)->next; (font_elem_ptr) != (&gdi_font_list); (font_elem_ptr) = (font_elem_ptr)->next) {
-        ret = ((struct tagGdiFont *)((char *)(font_elem_ptr) - (unsigned long)(&((struct tagGdiFont *)0)->entry)));
+        ret = ((struct tagGdiFont *)((char *)(font_elem_ptr) - (uintptr_t)(&((struct tagGdiFont *)0)->entry)));
         if(!fontcmp(ret, &fd)) {
             if(!can_use_bitmap && !( ret->ft_face->face_flags & ( 1L << 0 ) )) continue;
             for ((hfontlist_elem_ptr) = (&ret->hfontlist)->next; (hfontlist_elem_ptr) != (&ret->hfontlist); (hfontlist_elem_ptr) = (hfontlist_elem_ptr)->next) {
-                hflist = ((struct tagHFONTLIST *)((char *)(hfontlist_elem_ptr) - (unsigned long)(&((struct tagHFONTLIST *)0)->entry)));
+                hflist = ((struct tagHFONTLIST *)((char *)(hfontlist_elem_ptr) - (uintptr_t)(&((struct tagHFONTLIST *)0)->entry)));
                 if(hflist->hfont == hfont)
                     return ret;
             }
@@ -137,7 +140,7 @@ static GdiFont *find_in_cache(HFONT hfont, const LOGFONTW *plf, const FMAT2 *pma
     }
 
     while(font_elem_ptr) {
-        ret = ((struct tagGdiFont *)((char *)(font_elem_ptr) - (unsigned long)(&((struct tagGdiFont *)0)->entry)));
+        ret = ((struct tagGdiFont *)((char *)(font_elem_ptr) - (uintptr_t)(&((struct tagGdiFont *)0)->entry)));
         if(!fontcmp(ret, &fd)) {
             if(!can_use_bitmap && !( ret->ft_face->face_flags & ( 1L << 0 ) )) continue;
             hflist = HeapAlloc(0, 0, sizeof(*hflist));
@@ -194,7 +197,7 @@ static int get_glyph_index_linked(GdiFont *font, unsigned int c, GdiFont **linke
     unsigned int g;
     CHILD_FONT *child_font;
 
-    for ((child_font) = ((CHILD_FONT *)((char *)((&font->child_fonts)->next) - (unsigned long)(&((CHILD_FONT *)0)->entry))); &(child_font)->entry != (&font->child_fonts); (child_font) = ((CHILD_FONT *)((char *)((child_font)->entry.next) - (unsigned long)(&((CHILD_FONT *)0)->entry))))
+    for ((child_font) = ((CHILD_FONT *)((char *)((&font->child_fonts)->next) - (uintptr_t)(&((CHILD_FONT *)0)->entry))); &(child_font)->entry != (&font->child_fonts); (child_font) = ((CHILD_FONT *)((char *)((child_font)->entry.next) - (uintptr_t)(&((CHILD_FONT *)0)->entry))))
     {
         if(!load_child_font(font, child_font))
             continue;
@@ -211,7 +214,7 @@ static int get_glyph_index_linked(GdiFont *font, unsigned int c, GdiFont **linke
 
 void load_sfnt_table ();
 
-unsigned int WineEngGetFontData(GdiFont *font, unsigned int table, unsigned int offset, void* buf,
+unsigned int WineEngGetFontData(GdiFont *font, uint32_t table, unsigned int offset, void* buf,
     unsigned int cbData)
 {
     unsigned long len;
diff --git a/gcc/testsuite/gcc.dg/lto/pr54709_0.c b/gcc/testsuite/gcc.dg/lto/pr54709_0.c
index f3db5dc..ac7f8cf 100644
--- a/gcc/testsuite/gcc.dg/lto/pr54709_0.c
+++ b/gcc/testsuite/gcc.dg/lto/pr54709_0.c
@@ -3,6 +3,7 @@
 /* { dg-require-effective-target fpic } */
 /* { dg-extra-ld-options { -shared } } */
 /* { dg-lto-options { { -fPIC -fvisibility=hidden -flto } } } */
+/* { dg-skip-if "-shared not supported" { "ia16-*-*" } }  */
 
 void foo (void *p, void *q, unsigned s)
 {
diff --git a/gcc/testsuite/gcc.dg/lto/pr60449_0.c b/gcc/testsuite/gcc.dg/lto/pr60449_0.c
index a430830..66547ad 100644
--- a/gcc/testsuite/gcc.dg/lto/pr60449_0.c
+++ b/gcc/testsuite/gcc.dg/lto/pr60449_0.c
@@ -17,14 +17,14 @@ struct timezone
   };
 typedef struct timezone *__restrict __timezone_ptr_t;
 
-extern int gettimeofday (struct timeval *__restrict __tv, __timezone_ptr_t __tz);
+extern int gettimeofday1 (struct timeval *__restrict __tv, __timezone_ptr_t __tz);
 
 int bar (void)
 {
   struct timeval tv;
   struct timezone tz;
 
-  gettimeofday (&tv, &tz);
+  gettimeofday1 (&tv, &tz);
   printf ("This is from bar %i\n", tz.tz_dsttime);
   return 5;
 }
diff --git a/gcc/testsuite/gcc.dg/lto/pr60449_1.c b/gcc/testsuite/gcc.dg/lto/pr60449_1.c
index ddc2529..3f35dcb 100644
--- a/gcc/testsuite/gcc.dg/lto/pr60449_1.c
+++ b/gcc/testsuite/gcc.dg/lto/pr60449_1.c
@@ -12,7 +12,7 @@ struct timezone
     int tz_dsttime;
   };
 typedef struct timezone *__restrict __timezone_ptr_t;
-extern int gettimeofday (struct timeval *__restrict __tv,
+extern int gettimeofday1 (struct timeval *__restrict __tv,
     __timezone_ptr_t __tz) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1)));
 
 typedef long int __jmp_buf[8];
@@ -63,7 +63,7 @@ int main (void)
 
   if (!get_input ())
     {
-      gettimeofday (&tv, &tz);
+      gettimeofday1 (&tv, &tz);
       z = 0;
       printf ("This is from main %i\n", tz.tz_dsttime);
     }
diff --git a/gcc/testsuite/gcc.dg/lto/pr60449_2.c b/gcc/testsuite/gcc.dg/lto/pr60449_2.c
new file mode 100644
index 0000000..fe5a426
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/pr60449_2.c
@@ -0,0 +1,18 @@
+typedef long int __time_t;
+typedef long int __suseconds_t;
+struct timeval
+  {
+    __time_t tv_sec;
+    __suseconds_t tv_usec;
+  };
+struct timezone
+  {
+    int tz_minuteswest;
+    int tz_dsttime;
+  };
+typedef struct timezone *__restrict __timezone_ptr_t;
+int gettimeofday1 (struct timeval *__restrict __tv,
+		   __timezone_ptr_t __tz)
+{
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/lto/pr61526_0.c b/gcc/testsuite/gcc.dg/lto/pr61526_0.c
index 8a631f0..a1e3a1b 100644
--- a/gcc/testsuite/gcc.dg/lto/pr61526_0.c
+++ b/gcc/testsuite/gcc.dg/lto/pr61526_0.c
@@ -2,6 +2,7 @@
 /* { dg-lto-do link } */
 /* { dg-lto-options { { -fPIC -flto -flto-partition=1to1 } } } */
 /* { dg-extra-ld-options { -shared } } */
+/* { dg-skip-if "-shared not supported" { "ia16-*-*" } }  */
 
 static void *master;
 void *foo () { return master; }
diff --git a/gcc/testsuite/gcc.dg/lto/pr64415_0.c b/gcc/testsuite/gcc.dg/lto/pr64415_0.c
index 4faab2b..a1898a4 100644
--- a/gcc/testsuite/gcc.dg/lto/pr64415_0.c
+++ b/gcc/testsuite/gcc.dg/lto/pr64415_0.c
@@ -3,6 +3,7 @@
 /* { dg-lto-options { { -O -flto -fpic } } } */
 /* { dg-extra-ld-options { -shared } } */
 /* { dg-extra-ld-options "-Wl,-undefined,dynamic_lookup" { target *-*-darwin* } } */
+/* { dg-skip-if "-shared not supported" { "ia16-*-*" } }  */
 
 extern void bar(char *, int);
 
diff --git a/gcc/testsuite/gcc.dg/pch/valid-1.c b/gcc/testsuite/gcc.dg/pch/valid-1.c
index d445c47..2e5e695 100644
--- a/gcc/testsuite/gcc.dg/pch/valid-1.c
+++ b/gcc/testsuite/gcc.dg/pch/valid-1.c
@@ -1,5 +1,6 @@
 /* { dg-require-effective-target pch_supported_debug } */
 /* { dg-options "-I. -Winvalid-pch -g" } */
+/* { dg-skip-if "No debug information" { ia16-*-* } { "*" } { "" } } */
 
 #include "valid-1.h"/* { dg-warning "created with -gnone, but used with -g" } */
 /* { dg-error "No such file" "no such file" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/gcc.dg/pr35258.c b/gcc/testsuite/gcc.dg/pr35258.c
index d1c45a7..e1cb051 100644
--- a/gcc/testsuite/gcc.dg/pr35258.c
+++ b/gcc/testsuite/gcc.dg/pr35258.c
@@ -10,7 +10,11 @@ char str[9] = "1234";
 void
 bar (void)
 {
+#if __SIZEOF_INT__ >= 4
   unsigned int temp;
+#else
+  unsigned long temp;
+#endif
   char *p = &str[2];
 
   memcpy (&temp, &str[1], 4);
diff --git a/gcc/testsuite/gcc.dg/pr55940.c b/gcc/testsuite/gcc.dg/pr55940.c
index d046d0b..1648fac 100644
--- a/gcc/testsuite/gcc.dg/pr55940.c
+++ b/gcc/testsuite/gcc.dg/pr55940.c
@@ -12,11 +12,17 @@ bar (struct S *x, unsigned long y)
   return x->s + y;
 }
 
+#ifdef __ia16__
+#define STACK_OFFSET 0x2U
+#else
+#define STACK_OFFSET 0x1000U
+#endif
+
 __attribute__ ((noinline, noclone)) unsigned long long
 foo (struct S *x, unsigned long y)
 {
   unsigned long a;
-  if (__builtin_expect (((__UINTPTR_TYPE__) (x) + 0x1000U < 0x2000U), 0))
+  if (__builtin_expect (((__UINTPTR_TYPE__) (x) + STACK_OFFSET < 0x2000U), 0))
     return ~0ULL;
   if (__builtin_expect (x->s <= 0 || x->s > 9, 0))
     return ~0ULL;
diff --git a/gcc/testsuite/gcc.dg/pr56094.c b/gcc/testsuite/gcc.dg/pr56094.c
index 364e368..005203d 100644
--- a/gcc/testsuite/gcc.dg/pr56094.c
+++ b/gcc/testsuite/gcc.dg/pr56094.c
@@ -2,6 +2,12 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -g -fdump-tree-optimized-lineno" } */
 
+#ifdef __ia16__
+#define QI_CONSTRAINT "qmi"
+#else
+#define QI_CONSTRAINT "g"
+#endif
+
 _Bool cond;
 
 int
@@ -19,8 +25,9 @@ fn1 (unsigned char arg0, unsigned char arg1, unsigned char arg2,
      unsigned char arg3, unsigned char arg4, unsigned char arg5,
      unsigned short arg6)
 {
-  asm volatile ("" :: "g" ((unsigned long long) arg0), "g" (arg1),
-		      "g" (arg2), "g" (arg3), "g" (arg4), "g" (arg5),
+  asm volatile ("" :: "g" ((unsigned long long) arg0), QI_CONSTRAINT (arg1),
+		      QI_CONSTRAINT (arg2), QI_CONSTRAINT (arg3),
+		      QI_CONSTRAINT (arg4), QI_CONSTRAINT (arg5),
 		      "g" (arg6));
   if (cond)
     {
@@ -39,8 +46,8 @@ static __inline__ __attribute__ ((always_inline)) void
 fn5 (unsigned int arg0, unsigned char arg1, unsigned int arg2,
      unsigned char arg3)
 {
-  asm volatile ("" :: "g" (arg0), "g" (arg1),
-		      "g" ((unsigned long long) arg2), "g" (arg3));
+  asm volatile ("" :: "g" (arg0), QI_CONSTRAINT (arg1),
+		      "g" ((unsigned long long) arg2), QI_CONSTRAINT (arg3));
 }
 
 static __inline__ __attribute__ ((always_inline)) void
diff --git a/gcc/testsuite/gcc.dg/pr59471.c b/gcc/testsuite/gcc.dg/pr59471.c
index 7f2a787..eacb528 100644
--- a/gcc/testsuite/gcc.dg/pr59471.c
+++ b/gcc/testsuite/gcc.dg/pr59471.c
@@ -1,4 +1,7 @@
 /* { dg-do compile } */
+/* { dg-require-effective-target stdint_types } */
+
+#include <stdint.h>
 
 typedef unsigned char uint8x4_t
 __attribute__ ((__vector_size__ (4)));
@@ -6,7 +9,7 @@ __attribute__ ((__vector_size__ (4)));
 typedef unsigned short uint16x8_t
 __attribute__ ((__vector_size__ (16)));
 
-typedef unsigned int uint32x4_t
+typedef uint32_t uint32x4_t
 __attribute__ ((__vector_size__ (16)));
 
 void
diff --git a/gcc/testsuite/gcc.dg/pr59605-2.c b/gcc/testsuite/gcc.dg/pr59605-2.c
index 6d6ff23..dc0bba28 100644
--- a/gcc/testsuite/gcc.dg/pr59605-2.c
+++ b/gcc/testsuite/gcc.dg/pr59605-2.c
@@ -1,6 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-O2" } */
-/* { dg-additional-options "-DMAX_COPY=1025" { target { { simulator } || { nvptx-*-* } } } } */
+/* { dg-additional-options "-DMAX_COPY=1025" { target { { simulator } || { nvptx-*-* ia16-*-* } } } } */
 /* { dg-additional-options "-minline-stringops-dynamically" { target { i?86-*-* x86_64-*-* } } } */
 
 #include "pr59605.c"
diff --git a/gcc/testsuite/gcc.dg/pr59963-2.c b/gcc/testsuite/gcc.dg/pr59963-2.c
index ea05946..2a19998 100644
--- a/gcc/testsuite/gcc.dg/pr59963-2.c
+++ b/gcc/testsuite/gcc.dg/pr59963-2.c
@@ -1,12 +1,14 @@
 /* PR c/59963 */
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-Woverflow -Wconversion" } */
 
+#include <stdint.h>
+
 extern void bar (unsigned char);
 extern void bar8 (unsigned char, unsigned char, unsigned char, unsigned char,
 		  unsigned char, unsigned char, unsigned char, unsigned char);
 extern void bazu (unsigned int, ...);
-extern void bazi (char, int);
+extern void bazi (char, int32_t);
 extern int f (short a, short b);
 
 int
diff --git a/gcc/testsuite/gcc.dg/pr60114.c b/gcc/testsuite/gcc.dg/pr60114.c
index c656a95..762e8cd 100644
--- a/gcc/testsuite/gcc.dg/pr60114.c
+++ b/gcc/testsuite/gcc.dg/pr60114.c
@@ -1,20 +1,22 @@
 /* PR c/60114 */
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-Wconversion" } */
 
-struct S { int n, u[2]; };
+#include <stdint.h>
+
+struct S { int32_t n, u[2]; };
 const signed char z[] = {
   [0] = 0x100, /* { dg-warning "9:overflow in implicit constant conversion" } */
   [2] = 0x101, /* { dg-warning "9:overflow in implicit constant conversion" } */
 };
-int A[] = {
+int32_t A[] = {
             0, 0x80000000, /* { dg-warning "16:conversion of unsigned constant value to negative integer" } */
             0xA, 0x80000000, /* { dg-warning "18:conversion of unsigned constant value to negative integer" } */
             0xA, 0xA, 0x80000000 /* { dg-warning "23:conversion of unsigned constant value to negative integer" } */
           };
-int *p = (int []) { 0x80000000 }; /* { dg-warning "21:conversion of unsigned constant value to negative integer" } */
-union { int k; } u = { .k = 0x80000000 }; /* { dg-warning "29:conversion of unsigned constant value to negative integer" } */
-typedef int H[];
+int32_t *p = (int32_t []) { 0x80000000 }; /* { dg-warning "29:conversion of unsigned constant value to negative integer" } */
+union { int32_t k; } u = { .k = 0x80000000 }; /* { dg-warning "33:conversion of unsigned constant value to negative integer" } */
+typedef int32_t H[];
 void
 foo (void)
 {
diff --git a/gcc/testsuite/gcc.dg/pr62090-2.c b/gcc/testsuite/gcc.dg/pr62090-2.c
index 5bddc53..a589a46 100644
--- a/gcc/testsuite/gcc.dg/pr62090-2.c
+++ b/gcc/testsuite/gcc.dg/pr62090-2.c
@@ -1,7 +1,11 @@
 /* { dg-do compile } */
 /* { dg-options "-O2" } */
 
+#ifdef __SIZE_TYPE__
+typedef __SIZE_TYPE__ size_t;
+#else
 typedef long unsigned int size_t;
+#endif
 extern __inline __attribute__ ((__always_inline__))
 __attribute__ ((__gnu_inline__)) int
 snprintf (char *__restrict __s, size_t __n, const char *__restrict __fmt, ...)
diff --git a/gcc/testsuite/gcc.dg/pr63914.c b/gcc/testsuite/gcc.dg/pr63914.c
index 8bf18b3..5d595f0 100644
--- a/gcc/testsuite/gcc.dg/pr63914.c
+++ b/gcc/testsuite/gcc.dg/pr63914.c
@@ -11,7 +11,7 @@ struct dt_interpolation c;
 __m128
 fn1 (float p1)
 {
-  return (__attribute__ ((__vector_size__ (4 * sizeof 0))) float){ p1 };
+  return (__attribute__ ((__vector_size__ (16))) float){ p1 };
 }
 __m128
 fn2 (float p1)
diff --git a/gcc/testsuite/gcc.dg/pr64252.c b/gcc/testsuite/gcc.dg/pr64252.c
index 71f9c78..6811624 100644
--- a/gcc/testsuite/gcc.dg/pr64252.c
+++ b/gcc/testsuite/gcc.dg/pr64252.c
@@ -2,7 +2,7 @@
 /* { dg-do run } */
 /* { dg-options "-O2" } */
 
-typedef unsigned int V __attribute__((vector_size (32)));
+typedef unsigned int V __attribute__((vector_size (8*sizeof (int))));
 
 __attribute__((noinline, noclone)) void
 foo (V *a, V *b, V *c, V *d, V *e)
diff --git a/gcc/testsuite/gcc.dg/pr64277.c b/gcc/testsuite/gcc.dg/pr64277.c
index 62f6f1c..44ebdd1 100644
--- a/gcc/testsuite/gcc.dg/pr64277.c
+++ b/gcc/testsuite/gcc.dg/pr64277.c
@@ -3,18 +3,21 @@
 /* { dg-options "-O3 -Wall -Werror -fdump-tree-cunroll-details" } */
 /* { dg-final { scan-tree-dump "loop with 5 iterations completely unrolled" "cunroll" } } */
 /* { dg-final { scan-tree-dump "loop with 6 iterations completely unrolled" "cunroll" } } */
+/* { dg-require-effective-target stdint_types } */
+
+#include <stdint.h>
 
 int f1[10];
 void test1 (short a[], short m, unsigned short l)
 {
-  int i = l;
+  int32_t i = l;
   for (i = i + 5; i < m; i++)
     f1[i] = a[i]++;
 }
 
 void test2 (short a[], short m, short l)
 {
-  int i;
+  int32_t i;
   if (m > 5)
     m = 5;
   for (i = m; i > l; i--)
diff --git a/gcc/testsuite/gcc.dg/pr64536.c b/gcc/testsuite/gcc.dg/pr64536.c
index 9a79829..351febd 100644
--- a/gcc/testsuite/gcc.dg/pr64536.c
+++ b/gcc/testsuite/gcc.dg/pr64536.c
@@ -1,11 +1,13 @@
 /* PR rtl-optimization/64536 */
-/* { dg-do link } */
+/* { dg-do link { target { stdint_types } } } */
 /* { dg-options "-O2" } */
 /* { dg-additional-options "-fPIC" { target fpic } } */
 
-struct S { long q; } *h;
-long a, b, g, j, k, *c, *d, *e, *f, *i;
-long *baz (void)
+#include <stdint.h>
+
+struct S { intptr_t q; } *h;
+intptr_t a, b, g, j, k, *c, *d, *e, *f, *i;
+intptr_t *baz (void)
 {
   asm volatile ("" : : : "memory");
   return e;
@@ -39,8 +41,8 @@ bar (int x)
 	      h->q = *f;
 	    }
 	  else
-	    i = (long *) (h->q = *f);
-	  *c++ = (long) f;
+	    i = (intptr_t *) (h->q = *f);
+	  *c++ = (intptr_t) f;
 	  e += 6;
 	}
       else
@@ -53,8 +55,8 @@ bar (int x)
 	      h->q = *f;
 	    }
 	  else
-	    i = (long *) (h->q = *f);
-	  *c++ = (long) f;
+	    i = (intptr_t *) (h->q = *f);
+	  *c++ = (intptr_t) f;
 	  e += 6;
 	}
     }
diff --git a/gcc/testsuite/gcc.dg/pr65658.c b/gcc/testsuite/gcc.dg/pr65658.c
index cce0f2a..3249b67 100644
--- a/gcc/testsuite/gcc.dg/pr65658.c
+++ b/gcc/testsuite/gcc.dg/pr65658.c
@@ -1,6 +1,8 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-Wuninitialized -O2 -Wno-implicit" } */
 
+#include <stdint.h>
+
 extern int optind;
 struct undefinfo
 {
@@ -15,7 +17,7 @@ struct undeffoo
 };
 struct problem
 {
-  unsigned long l1;
+  uintptr_t l1;
   unsigned long l2;
   unsigned long l3;
   unsigned long l4;
@@ -59,7 +61,7 @@ fn6 (struct undefinfo *uip, struct problem *problem)
   unsigned long amt;
   if (external_function3 (((void *) 0), ((void *) 0), &amt, 0, 0))
     return 1;
-  problem->l1 = (unsigned long) undefvp1;
+  problem->l1 = (uintptr_t) undefvp1;
   problem->l4 = uip->l1;
   problem->l3 = uip->l2;
   return 0;
diff --git a/gcc/testsuite/gcc.dg/pr66299-1.c b/gcc/testsuite/gcc.dg/pr66299-1.c
index e75146b..cd58ac9 100644
--- a/gcc/testsuite/gcc.dg/pr66299-1.c
+++ b/gcc/testsuite/gcc.dg/pr66299-1.c
@@ -1,7 +1,9 @@
 /* PR tree-optimization/66299 */
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
 /* { dg-options "-fdump-tree-original" } */
 
+#include <stdint.h>
+
 void
 test1 (int x)
 {
@@ -71,11 +73,11 @@ test4 (unsigned int x)
 }
 
 void
-test5 (int x)
+test5 (int_least32_t x)
 {
-  if ((0 << x) == 1
-      || (0 << x) != 0
-      || (0x8001U << x) != 0x20000U)
+  if (((int_least32_t)0 << x) == 1
+      || ((int_least32_t)0 << x) != 0
+      || ((int_least32_t)0x8001U << x) != 0x20000U)
     __builtin_abort ();
 }
 
diff --git a/gcc/testsuite/gcc.dg/pr66299-2.c b/gcc/testsuite/gcc.dg/pr66299-2.c
index 45e9218..ea6c281 100644
--- a/gcc/testsuite/gcc.dg/pr66299-2.c
+++ b/gcc/testsuite/gcc.dg/pr66299-2.c
@@ -1,9 +1,11 @@
 /* PR tree-optimization/66299 */
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
 /* { dg-options "-fdump-tree-optimized -O" } */
 
+#include <stdint.h>
+
 void
-test1 (int x, unsigned u)
+test1 (int_least32_t x, unsigned u)
 {
   if ((1U << x) != 64
       || (2 << x) != u
diff --git a/gcc/testsuite/gcc.dg/pr67271.c b/gcc/testsuite/gcc.dg/pr67271.c
index b6988a3..9acf5d8 100644
--- a/gcc/testsuite/gcc.dg/pr67271.c
+++ b/gcc/testsuite/gcc.dg/pr67271.c
@@ -1,12 +1,14 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-O" } */
 
+#include <stdint.h>
+
 extern long int labs (long int j);
 int
 main ()
 {
   long *a = (long *)"empty";
-  int i = 1441516387;
+  int_least32_t i = 1441516387;
   a[i] = labs (a[i]);
   return 0;
 }
diff --git a/gcc/testsuite/gcc.dg/pr68112.c b/gcc/testsuite/gcc.dg/pr68112.c
index 0a45b03..7161d56 100644
--- a/gcc/testsuite/gcc.dg/pr68112.c
+++ b/gcc/testsuite/gcc.dg/pr68112.c
@@ -1,11 +1,13 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-O2 -Waggressive-loop-optimizations" } */
 
-int *a;
+#include <stdint.h>
+
+int_least32_t *a;
 
 void
 foo ()
 {
-  for (int i = 0; i < 65536; i++)
+  for (int_least32_t i = 0; i < 65536; i++)
     *a = i << 24;
 }
diff --git a/gcc/testsuite/gcc.dg/pr69071.c b/gcc/testsuite/gcc.dg/pr69071.c
index 1a17a94..50f92dc 100644
--- a/gcc/testsuite/gcc.dg/pr69071.c
+++ b/gcc/testsuite/gcc.dg/pr69071.c
@@ -2,12 +2,20 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -g" } */
 
+#if defined(STACK_SIZE) && (STACK_SIZE < 65536)
+# define BYTEMEM_SIZE 10000
+#endif
+
+#ifndef BYTEMEM_SIZE
+# define BYTEMEM_SIZE 65400
+#endif
+
 void *bar (void *);
 
 void
 foo (int c)
 {
-  unsigned char bf[65400];
+  unsigned char bf[BYTEMEM_SIZE];
   unsigned char *p2 = bar (bf);
   unsigned char *p3 = bar (bf);
   for (; *p2; p2++, c++)
diff --git a/gcc/testsuite/gcc.dg/pr69634.c b/gcc/testsuite/gcc.dg/pr69634.c
index 59e3739..e4032b6 100644
--- a/gcc/testsuite/gcc.dg/pr69634.c
+++ b/gcc/testsuite/gcc.dg/pr69634.c
@@ -1,6 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fno-dce -fschedule-insns -fno-tree-vrp -fcompare-debug" } */
 /* { dg-additional-options "-Wno-psabi -mno-sse" { target i?86-*-* x86_64-*-* } } */
+/* { dg-require-effective-target scheduling } */
 
 typedef unsigned short u16;
 typedef short v16u16 __attribute__ ((vector_size (16)));
diff --git a/gcc/testsuite/gcc.dg/pr69973.c b/gcc/testsuite/gcc.dg/pr69973.c
index 648bc56..d108b50 100644
--- a/gcc/testsuite/gcc.dg/pr69973.c
+++ b/gcc/testsuite/gcc.dg/pr69973.c
@@ -1,2 +1,9 @@
 /* { dg-do compile } */
-typedef int v4si __attribute__ ((vector_size (1 << 29)));
+
+#ifdef __ia16__
+#define SHIFT 13
+#else
+#define SHIFT 29
+#endif
+
+typedef int v4si __attribute__ ((vector_size (1 << SHIFT)));
diff --git a/gcc/testsuite/gcc.dg/sso-6.c b/gcc/testsuite/gcc.dg/sso-6.c
index 48759b4..b911083 100644
--- a/gcc/testsuite/gcc.dg/sso-6.c
+++ b/gcc/testsuite/gcc.dg/sso-6.c
@@ -1,6 +1,8 @@
 /* Test support of scalar_storage_order pragma */
 
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
+
+#include <stdint.h>
 
 #pragma scalar_storage_order /* { dg-warning "missing .big-endian.little-endian.default." } */
 
@@ -8,31 +10,31 @@
 
 struct S1
 {
-  int i;
+  int32_t i;
 };
 
 struct __attribute__((scalar_storage_order("little-endian"))) S2
 {
-  int i;
+  int32_t i;
 };
 
 #pragma scalar_storage_order little-endian
 
 struct S3
 {
-  int i;
+  int32_t i;
 };
 
 struct __attribute__((scalar_storage_order("big-endian"))) S4
 {
-  int i;
+  int32_t i;
 };
 
 #pragma scalar_storage_order default
 
 struct S5
 {
-  int i;
+  int32_t i;
 };
 
 #pragma scalar_storage_order other /* { dg-warning "expected .big-endian.little-endian.default." } */
diff --git a/gcc/testsuite/gcc.dg/sso-7.c b/gcc/testsuite/gcc.dg/sso-7.c
index b4d9d65..44f0b9d 100644
--- a/gcc/testsuite/gcc.dg/sso-7.c
+++ b/gcc/testsuite/gcc.dg/sso-7.c
@@ -1,25 +1,27 @@
 /* Test support of scalar_storage_order pragma */
 
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
 /* { dg-options "-fsso-struct=big-endian" } */
 
+#include <stdint.h>
+
 struct S1
 {
-  int i;
+  int32_t i;
 };
 
 #pragma scalar_storage_order little-endian
 
 struct S2
 {
-  int i;
+  int32_t i;
 };
 
 #pragma scalar_storage_order default
 
 struct S3
 {
-  int i;
+  int32_t i;
 };
 
 struct S1 my_s1 = { 0x12345678 };
diff --git a/gcc/testsuite/gcc.dg/sso-8.c b/gcc/testsuite/gcc.dg/sso-8.c
index 1938835..3ed4a75 100644
--- a/gcc/testsuite/gcc.dg/sso-8.c
+++ b/gcc/testsuite/gcc.dg/sso-8.c
@@ -1,25 +1,27 @@
 /* Test support of scalar_storage_order pragma */
 
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
 /* { dg-options "-fsso-struct=little-endian" } */
 
+#include <stdint.h>
+
 struct S1
 {
-  int i;
+  int32_t i;
 };
 
 #pragma scalar_storage_order big-endian
 
 struct S2
 {
-  int i;
+  int32_t i;
 };
 
 #pragma scalar_storage_order default
 
 struct S3
 {
-  int i;
+  int32_t i;
 };
 
 struct S1 my_s1 = { 0x12345678 };
diff --git a/gcc/testsuite/gcc.dg/sso/sso.exp b/gcc/testsuite/gcc.dg/sso/sso.exp
index 87dd494..0e0fe87 100644
--- a/gcc/testsuite/gcc.dg/sso/sso.exp
+++ b/gcc/testsuite/gcc.dg/sso/sso.exp
@@ -33,6 +33,8 @@ set SSO_TORTURE_OPTIONS [list \
 set-torture-options $SSO_TORTURE_OPTIONS
 
 if { ![check_effective_target_int32] } {
+    dg-finish
+    torture-finish
     return
 }
 
diff --git a/gcc/testsuite/gcc.dg/stack-usage-1.c b/gcc/testsuite/gcc.dg/stack-usage-1.c
index 7864c6a..f5f398a 100644
--- a/gcc/testsuite/gcc.dg/stack-usage-1.c
+++ b/gcc/testsuite/gcc.dg/stack-usage-1.c
@@ -91,6 +91,8 @@
 #define SIZE 252
 #elif defined (__M32R__)
 #define SIZE 252
+#elif defined (__ia16__)
+#define SIZE 252
 #else
 #  define SIZE 256
 #endif
diff --git a/gcc/testsuite/gcc.dg/torture/fp-int-convert-double.c b/gcc/testsuite/gcc.dg/torture/fp-int-convert-double.c
index 39ec3cd..306c0e2 100644
--- a/gcc/testsuite/gcc.dg/torture/fp-int-convert-double.c
+++ b/gcc/testsuite/gcc.dg/torture/fp-int-convert-double.c
@@ -2,6 +2,7 @@
 /* Origin: Joseph Myers <joseph@codesourcery.com> */
 /* { dg-do run } */
 /* { dg-options "" } */
+/* { dg-options "-mcmodel=small" { target ia16-*-* } } */
 
 #include <float.h>
 #include "fp-int-convert.h"
diff --git a/gcc/testsuite/gcc.dg/torture/fp-int-convert-long-double.c b/gcc/testsuite/gcc.dg/torture/fp-int-convert-long-double.c
index bb189a3..b9f2f5b 100644
--- a/gcc/testsuite/gcc.dg/torture/fp-int-convert-long-double.c
+++ b/gcc/testsuite/gcc.dg/torture/fp-int-convert-long-double.c
@@ -2,6 +2,7 @@
 /* Origin: Joseph Myers <joseph@codesourcery.com> */
 /* { dg-do run } */
 /* { dg-options "" } */
+/* { dg-options "-mcmodel=small" { target ia16-*-* } } */
 
 #include <float.h>
 #include "fp-int-convert.h"
diff --git a/gcc/testsuite/gcc.dg/torture/pr68067-1.c b/gcc/testsuite/gcc.dg/torture/pr68067-1.c
index a7b6aa0..79daf64 100644
--- a/gcc/testsuite/gcc.dg/torture/pr68067-1.c
+++ b/gcc/testsuite/gcc.dg/torture/pr68067-1.c
@@ -1,11 +1,13 @@
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
+
+#include <stdint.h>
 
 int main()
 {
-  int a = -1;
-  static int b = -2147483647 - 1;
-  static int c = 0;
-  int t = a - (b - c);
+  int32_t a = -1;
+  static int32_t b = -2147483647 - 1;
+  static int32_t c = 0;
+  int32_t t = a - (b - c);
   if (t != 2147483647)
     __builtin_abort();
   return 0;
diff --git a/gcc/testsuite/gcc.dg/torture/pr68067-2.c b/gcc/testsuite/gcc.dg/torture/pr68067-2.c
index 38a459b..15bba4e 100644
--- a/gcc/testsuite/gcc.dg/torture/pr68067-2.c
+++ b/gcc/testsuite/gcc.dg/torture/pr68067-2.c
@@ -1,11 +1,13 @@
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
+
+#include <stdint.h>
 
 int main()
 {
-  int a = -1;
-  static int b = -2147483647 - 1;
-  static int c = 0;
-  int t = a - (b + c*-2);
+  int32_t a = -1;
+  static int32_t b = -2147483647 - 1;
+  static int32_t c = 0;
+  int32_t t = a - (b + c*-2);
   if (t != 2147483647)
     __builtin_abort();
   return 0;
diff --git a/gcc/testsuite/gcc.dg/torture/pr69352.c b/gcc/testsuite/gcc.dg/torture/pr69352.c
index ad718b9..72d35b6 100644
--- a/gcc/testsuite/gcc.dg/torture/pr69352.c
+++ b/gcc/testsuite/gcc.dg/torture/pr69352.c
@@ -1,19 +1,23 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 
-int a[10][14], b, c, d, e, f, g, h, i;
+#include <stdint.h>
+
+intptr_t a[10][14];
+int b, c, d, e, f, g, h, i;
 void bar (void);
 int
 foo (int x)
 {
   unsigned j;
-  int k = 0, l;
+  int k = 0;
+  intptr_t l;
   int m;
   if (h)
     m = 12;
   else
     m = 13;
   if (a[x][m])
-    l = (long) foo;
+    l = (intptr_t) foo;
   a[x][i] = l;
   while (c)
     {
diff --git a/gcc/testsuite/gcc.dg/torture/pr69714.c b/gcc/testsuite/gcc.dg/torture/pr69714.c
index 229b7ad..8fa97a6 100644
--- a/gcc/testsuite/gcc.dg/torture/pr69714.c
+++ b/gcc/testsuite/gcc.dg/torture/pr69714.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fno-strict-aliasing" } */
+/* { dg-skip-if "Does not fit in 64kB" { "ia16-*-*" } } */
 
 #include <stdint.h>
 #include <stdio.h>
diff --git a/gcc/testsuite/gcc.dg/torture/pr69771.c b/gcc/testsuite/gcc.dg/torture/pr69771.c
index 8314c82..979418a 100644
--- a/gcc/testsuite/gcc.dg/torture/pr69771.c
+++ b/gcc/testsuite/gcc.dg/torture/pr69771.c
@@ -1,12 +1,14 @@
 /* PR rtl-optimization/69771 */
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
+
+#include <stdint.h>
 
 unsigned char a = 5, c;
 unsigned short b = 0;
-unsigned d = 0x76543210;
+uint32_t d = 0x76543210;
 
 void
 foo (void)
 {
-  c = d >> ~(a || ~b);	/* { dg-warning "shift count is negative" } */
+  c = d >> ~(a || ~b);	/* { dg-warning "shift count is negative" "" { target { ! ia16-*-* } } } */
 }
diff --git a/gcc/testsuite/gcc.dg/torture/pr69941.c b/gcc/testsuite/gcc.dg/torture/pr69941.c
index f15d41a..ccaa5d1 100644
--- a/gcc/testsuite/gcc.dg/torture/pr69941.c
+++ b/gcc/testsuite/gcc.dg/torture/pr69941.c
@@ -1,11 +1,13 @@
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
+
+#include <stdint.h>
  
 int a = 0;
 int b = 0;
 int c = 0;
-int e = 0;
+int32_t e = 0;
 int f = 0;
-int *g = &e;
+int32_t *g = &e;
  
 int fn1() { return b ? a : b; }
  
diff --git a/gcc/testsuite/gcc.dg/torture/pr70025.c b/gcc/testsuite/gcc.dg/torture/pr70025.c
index dafae0b..e7594cf 100644
--- a/gcc/testsuite/gcc.dg/torture/pr70025.c
+++ b/gcc/testsuite/gcc.dg/torture/pr70025.c
@@ -1,11 +1,13 @@
 /* PR middle-end/70025 */
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
 /* { dg-additional-options "-mtune=z10" { target s390*-*-* } } */
 
+#include <stdint.h>
+
 typedef char (*F) (unsigned long, void *);
 typedef union { struct A { char a1, a2, a3, a4; unsigned long a5; F a6; void *a7; } b; char c[1]; } B;
 struct C { const char *c1; unsigned long c2; };
-typedef struct D { unsigned long d1; int d2; const char *d3; unsigned long d4, d5; struct C d6[49]; char d7[8]; } E[1];
+typedef struct D { unsigned long d1; int_least32_t d2; const char *d3; unsigned long d4, d5; struct C d6[49]; char d7[8]; } E[1];
 
 __attribute__ ((noinline, noclone))
 void foo (register E p)
diff --git a/gcc/testsuite/gcc.dg/torture/pr70083.c b/gcc/testsuite/gcc.dg/torture/pr70083.c
index 0cf2892..6cee931 100644
--- a/gcc/testsuite/gcc.dg/torture/pr70083.c
+++ b/gcc/testsuite/gcc.dg/torture/pr70083.c
@@ -1,8 +1,10 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-Wno-psabi" } */
 
+#include <stdint.h>
+
 typedef short v16hi __attribute__ ((vector_size (32)));
-typedef int v8si __attribute__ ((vector_size (32)));
+typedef int32_t v8si __attribute__ ((vector_size (32)));
 typedef long long v4di __attribute__ ((vector_size (32)));
 
 int
diff --git a/gcc/testsuite/gcc.dg/torture/pr70123.c b/gcc/testsuite/gcc.dg/torture/pr70123.c
index 55b6077..2eb1f4e 100644
--- a/gcc/testsuite/gcc.dg/torture/pr70123.c
+++ b/gcc/testsuite/gcc.dg/torture/pr70123.c
@@ -1,5 +1,6 @@
 /* { dg-do run } */
 /* { dg-options "-fPIC" { target fpic } } */
+/* { dg-skip-if "Not enough registers" { "ia16-*-*" } } */
 __attribute__ ((noinline, noclone)) int
 bar (int flag, const char *__restrict format, ...)
 {
diff --git a/gcc/testsuite/gcc.dg/torture/pr70421.c b/gcc/testsuite/gcc.dg/torture/pr70421.c
index 8f97acd..9cb307d 100644
--- a/gcc/testsuite/gcc.dg/torture/pr70421.c
+++ b/gcc/testsuite/gcc.dg/torture/pr70421.c
@@ -1,11 +1,13 @@
 /* PR target/70421 */
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
 /* { dg-additional-options "-Wno-psabi -w" } */
 
-typedef unsigned V __attribute__ ((vector_size (64)));
+#include <stdint.h>
 
-unsigned __attribute__ ((noinline, noclone))
-foo (unsigned x, V u, V v)
+typedef uint32_t V __attribute__ ((vector_size (64)));
+
+uint_least32_t __attribute__ ((noinline, noclone))
+foo (uint_least32_t x, V u, V v)
 {
   v[1] ^= v[2];
   x ^= ((V) v)[u[0]];
@@ -15,7 +17,7 @@ foo (unsigned x, V u, V v)
 int
 main ()
 {
-  unsigned x = foo (0x10, (V) { 1 }, (V) { 0x100, 0x1000, 0x10000 });
+  uint_least32_t x = foo (0x10, (V) { 1 }, (V) { 0x100, 0x1000, 0x10000 });
   if (x != 0x11010)
     __builtin_abort ();
   return 0;
diff --git a/gcc/testsuite/gcc.dg/torture/pr70542.c b/gcc/testsuite/gcc.dg/torture/pr70542.c
index ed7ab9d..b0158cf 100644
--- a/gcc/testsuite/gcc.dg/torture/pr70542.c
+++ b/gcc/testsuite/gcc.dg/torture/pr70542.c
@@ -1,7 +1,9 @@
 /* PR rtl-optimization/70542 */
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
 
-int a[113], d[113];
+#include <stdint.h>
+
+int_least32_t a[113], d[113];
 short b[113], c[113], e[113];
 
 int
diff --git a/gcc/testsuite/gcc.dg/torture/pr70935.c b/gcc/testsuite/gcc.dg/torture/pr70935.c
index eb7f034..d83df4c 100644
--- a/gcc/testsuite/gcc.dg/torture/pr70935.c
+++ b/gcc/testsuite/gcc.dg/torture/pr70935.c
@@ -1,6 +1,8 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-O3 -g" } */
 
+#include <stdint.h>
+
 int d0, sj, v0, rp, zi;
 
 void
@@ -8,7 +10,8 @@ zn(void)
 {
   if (v0 != 0)
     {
-      int *js, *r3;
+      intptr_t *js;
+      int *r3;
       int pm, gc;
 
       for (gc = 0; gc < 1; ++gc)
@@ -18,7 +21,7 @@ zn(void)
             ;
         }
       r3 = &pm;
-      *js = (long)&gc;
+      *js = (intptr_t)&gc;
 ka:
       for (d0 = 0; d0 < 2; ++d0)
         {
diff --git a/gcc/testsuite/gcc.dg/torture/stackalign/builtin-apply-2.c b/gcc/testsuite/gcc.dg/torture/stackalign/builtin-apply-2.c
index ffd865b..ce5c82d 100644
--- a/gcc/testsuite/gcc.dg/torture/stackalign/builtin-apply-2.c
+++ b/gcc/testsuite/gcc.dg/torture/stackalign/builtin-apply-2.c
@@ -16,7 +16,10 @@
 
 #define INTEGER_ARG  5
 
-#if defined(__ARM_PCS) || defined(__epiphany__)
+#if defined(__ia16__)
+/* All args on stack but pointers and ints are 2 bytes each.  */
+#define STACK_ARGUMENTS_SIZE 28
+#elif defined(__ARM_PCS) || defined(__epiphany__)
 /* For Base AAPCS, NAME is passed in r0.  D is passed in r2 and r3.
    E, F and G are passed on stack.  So the size of the stack argument
    data is 20.  */
diff --git a/gcc/testsuite/gcc.dg/torture/stackalign/builtin-apply-3.c b/gcc/testsuite/gcc.dg/torture/stackalign/builtin-apply-3.c
index 37c5209..4b8c492 100644
--- a/gcc/testsuite/gcc.dg/torture/stackalign/builtin-apply-3.c
+++ b/gcc/testsuite/gcc.dg/torture/stackalign/builtin-apply-3.c
@@ -10,6 +10,12 @@
 
 #define INTEGER_ARG  5
 
+#ifdef __ia16__
+#define ARGS_SIZE 2
+#else
+#define ARGS_SIZE 16
+#endif
+
 extern void abort(void);
 
 void foo(int arg)
@@ -21,7 +27,7 @@ void foo(int arg)
 void bar(int arg)
 {
   foo(arg);
-  __builtin_apply(foo, __builtin_apply_args(), 16);
+  __builtin_apply(foo, __builtin_apply_args(), ARGS_SIZE);
 }
 
 int main(void)
diff --git a/gcc/testsuite/gcc.dg/trampoline-1.c b/gcc/testsuite/gcc.dg/trampoline-1.c
index 37a582c..65a4dd3 100644
--- a/gcc/testsuite/gcc.dg/trampoline-1.c
+++ b/gcc/testsuite/gcc.dg/trampoline-1.c
@@ -13,6 +13,16 @@
 extern void abort(void);
 extern double fabs(double);
 
+#if defined(STACK_SIZE)
+#if STACK_SIZE < 30000
+#define MAX 9
+#endif
+#endif
+
+#ifndef MAX
+#define MAX 10
+#endif
+
 void foo (void)
 {
   const int correct[1100] = {1, 0, -2, 0, 1, 0, 1, -1, -10, -30, -67};
@@ -40,7 +50,7 @@ void foo (void)
       return b ();
   }
 
-  for (i=0; i<=10; i++)
+  for (i=0; i<=MAX; i++)
   {
     if (fabs(a( i, x1, x2, x3, x4, x5 ) - correct [i]) > 0.1)
       abort();
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c
index f7b5dfa..179f61f 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c
@@ -33,4 +33,4 @@ void test55 (int x, int y)
    that the && should be emitted (based on BRANCH_COST).  Fix this
    by teaching dom to look through && and register all components
    as true.  */
-/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail { ! "alpha*-*-* arm*-*-* aarch64*-*-* powerpc*-*-* cris-*-* crisv32-*-* hppa*-*-* i?86-*-* mmix-*-* mips*-*-* m68k*-*-* moxie-*-* nds32*-*-* s390*-*-* sh*-*-* sparc*-*-* spu-*-* visium-*-* x86_64-*-*" } } } } */
+/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail { ! "alpha*-*-* arm*-*-* aarch64*-*-* powerpc*-*-* cris-*-* crisv32-*-* hppa*-*-* i?86-*-* ia16-*-* mmix-*-* mips*-*-* m68k*-*-* moxie-*-* nds32*-*-* s390*-*-* sh*-*-* sparc*-*-* spu-*-* visium-*-* x86_64-*-*" } } } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/alias-32.c b/gcc/testsuite/gcc.dg/tree-ssa/alias-32.c
index 7ac8e81..cca07fd 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/alias-32.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/alias-32.c
@@ -1,10 +1,16 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fdump-tree-cddce1" } */
 
-int bar (short *p)
+#ifdef __INT_LEAST32_TYPE__
+#define int_least32_t __INT_LEAST32_TYPE__
+#else
+#define int_least32_t int
+#endif
+
+int_least32_t bar (short *p)
 {
-  int res = *p;
-  struct { int *q1; int *q2; } q;
+  int_least32_t res = *p;
+  struct { int_least32_t *q1; int_least32_t *q2; } q;
   q.q1 = __builtin_aligned_alloc (128, 128 * sizeof (int));
   q.q2 = __builtin_aligned_alloc (128, 128 * sizeof (int));
   *q.q1 = 1;
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/gen-vect-11.c b/gcc/testsuite/gcc.dg/tree-ssa/gen-vect-11.c
index bb5f248..306f565 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/gen-vect-11.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/gen-vect-11.c
@@ -30,4 +30,4 @@ int main ()
 }
 
 
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target { ! avr-*-* } } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target { ! "avr-*-* ia16-*-*" } } } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/gen-vect-25.c b/gcc/testsuite/gcc.dg/tree-ssa/gen-vect-25.c
index 5e3ef8d..e310619 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/gen-vect-25.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/gen-vect-25.c
@@ -54,5 +54,5 @@ int main (void)
   return main_1 (n + 2, (int *) &n);
 }
 
-/* { dg-final { scan-tree-dump-times "vectorized 2 loops" 1 "vect" { target { ! avr-*-* } } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 2 loops" 1 "vect" { target { ! "avr-*-* ia16-*-*" } } } } */
 /* { dg-final { scan-tree-dump-times "Vectorizing an unaligned access" 0 "vect" { target { ! avr-*-* } } } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/integer-addr.c b/gcc/testsuite/gcc.dg/tree-ssa/integer-addr.c
index a8a9de4..de40197 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/integer-addr.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/integer-addr.c
@@ -1,7 +1,11 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fdump-tree-optimized -fno-strict-aliasing" } */
 /* Test with fixed address */
+#if __SIZEOF_POINTER__ < 4
+static int *foo =  (int *) 0x7800;
+#else
 static int *foo =  (int *) (unsigned long) 0x7800000;
+#endif
 
 int func(void) __attribute__ ((noinline));
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/loop-35.c b/gcc/testsuite/gcc.dg/tree-ssa/loop-35.c
index 4e9d03a..6caa483 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/loop-35.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/loop-35.c
@@ -67,5 +67,5 @@ void test4(struct a *A, unsigned LONG b)
     }
 }
 /* long index not hoisted for avr target PR 36561 */
-/* { dg-final { scan-tree-dump-times "Executing store motion of" 8 "lim2" { xfail { "avr-*-*" } } } } */
-/* { dg-final { scan-tree-dump-times "Executing store motion of" 6 "lim2" { target { "avr-*-*" } } } } */
+/* { dg-final { scan-tree-dump-times "Executing store motion of" 8 "lim2" { xfail { "avr-*-*" "ia16-*-*" } } } } */
+/* { dg-final { scan-tree-dump-times "Executing store motion of" 6 "lim2" { target { "avr-*-*" "ia16-*-*" } } } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr15826.c b/gcc/testsuite/gcc.dg/tree-ssa/pr15826.c
index 99ac0e2..e478044 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr15826.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr15826.c
@@ -33,4 +33,4 @@ andrew (struct s *p)
   return i;
 }
 
-/* { dg-final { scan-tree-dump-times " & | goto " 0 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " goto " 0 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr23455.c b/gcc/testsuite/gcc.dg/tree-ssa/pr23455.c
index fec3540..657dcfd 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr23455.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr23455.c
@@ -25,5 +25,5 @@ bi_windup(unsigned int *outbuf, unsigned int bi_buf)
 /* We should eliminate one load of outcnt, which will in turn let us eliminate
    one multiply of outcnt which will in turn let us eliminate
    one add involving outcnt and outbuf.  */
-/* { dg-final { scan-tree-dump-times "Eliminated: 3" 1 "pre" {target { ! avr-*-* } } } } */
-/* { dg-final { scan-tree-dump-times "Eliminated: 4" 1 "pre" {target {   avr-*-* } } } } */
+/* { dg-final { scan-tree-dump-times "Eliminated: 3" 1 "pre" {target { ! "avr-*-* ia16-*-*" } } } } */
+/* { dg-final { scan-tree-dump-times "Eliminated: 4" 1 "pre" {target {   avr-*-* ia16-*-* } } } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr42585.c b/gcc/testsuite/gcc.dg/tree-ssa/pr42585.c
index b2aa174..bdaf68f 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr42585.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr42585.c
@@ -35,5 +35,5 @@ Cyc_string_ungetc (int ignore, struct _fat_ptr *sptr)
 /* Whether the structs are totally scalarized or not depends on the
    MOVE_RATIO macro definition in the back end.  The scalarization will
    not take place when using small values for MOVE_RATIO.  */
-/* { dg-final { scan-tree-dump-times "struct _fat_ptr _ans" 0 "optimized" { target { ! "aarch64*-*-* alpha*-*-* arm*-*-* avr-*-* nds32*-*-* powerpc*-*-* s390*-*-* sh*-*-*" } } } } */
-/* { dg-final { scan-tree-dump-times "struct _fat_ptr _T2" 0 "optimized" { target { ! "aarch64*-*-* alpha*-*-* arm*-*-* avr-*-* nds32*-*-* powerpc*-*-* s390*-*-* sh*-*-*" } } } } */
+/* { dg-final { scan-tree-dump-times "struct _fat_ptr _ans" 0 "optimized" { target { ! "aarch64*-*-* alpha*-*-* arm*-*-* avr-*-* ia16-*-* nds32*-*-* powerpc*-*-* s390*-*-* sh*-*-*" } } } } */
+/* { dg-final { scan-tree-dump-times "struct _fat_ptr _T2" 0 "optimized" { target { ! "aarch64*-*-* alpha*-*-* arm*-*-* avr-*-* ia16-*-* nds32*-*-* powerpc*-*-* s390*-*-* sh*-*-*" } } } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c b/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c
index 0b25466..53a7583 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c
@@ -1,13 +1,15 @@
 
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-O2 -fdump-tree-vrp1" } */
 
-int funsigned (unsigned a)
+#include <stdint.h>
+
+int funsigned (uint32_t a)
 {
   return 0x1ffffffffL / a == 0;
 }
 
-int funsigned2 (unsigned a)
+int funsigned2 (uint32_t a)
 {
   if (a < 1) return 1;
   return (-1 * 0x1ffffffffL) / a == 0;
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr65136.c b/gcc/testsuite/gcc.dg/tree-ssa/pr65136.c
index b07dbb7..079f822 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr65136.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr65136.c
@@ -1,7 +1,9 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-O2 -fdump-rtl-expand-details" } */
 
-int foo(unsigned int cc )
+#include <stdint.h>
+
+int foo(uint_least32_t cc )
 {
 
   while ( cc >> 16 )
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr66449.c b/gcc/testsuite/gcc.dg/tree-ssa/pr66449.c
index 986b3fb..5a274f5 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr66449.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr66449.c
@@ -1,9 +1,11 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-O3" } */
 
-void *fn1(void *p1, void *p2, long p3)
+#include <stdint.h>
+
+void *fn1(void *p1, void *p2, intptr_t p3)
 {
-  long a = (long)p1, b = (long)p2, c = p3;
+  intptr_t a = (intptr_t)p1, b = (intptr_t)p2, c = p3;
 
   while (c)
     {
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr66726.c b/gcc/testsuite/gcc.dg/tree-ssa/pr66726.c
index a4c7418..9b53b98 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr66726.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr66726.c
@@ -10,6 +10,6 @@ oof (int mode)
   return (64 < mode_size[mode] ? 64 : mode_size[mode]);
 }
 
-/* { dg-final { scan-tree-dump-times "factor conversion out" 1 "phiopt1" } } */
+/* { dg-final { scan-tree-dump-times "factor conversion out" 1 "phiopt1" { target { ! ia16-*-* } } } } */
 /* { dg-final { scan-tree-dump-times "MIN_EXPR" 1 "phiopt1" } } */
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr68529-3.c b/gcc/testsuite/gcc.dg/tree-ssa/pr68529-3.c
index 583b4a6..65dc5a8 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr68529-3.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr68529-3.c
@@ -1,4 +1,4 @@
-/* { dg-do compile } */
+/* { dg-do compile { target int32plus } } */
 /* { dg-options "-O2 -ftree-loop-distribution -ftree-loop-distribute-patterns -fdump-tree-ldist-details" } */
 
 void bar(char *s);
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr70919.c b/gcc/testsuite/gcc.dg/tree-ssa/pr70919.c
index bed0ab3..d83b370 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr70919.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr70919.c
@@ -1,10 +1,12 @@
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
 /* { dg-options "-O" } */
 
+#include <stdint.h>
+
 #pragma pack(1)
 struct S0
 {
-  int f0:24;
+  int_least32_t f0:24;
 };
 
 struct S1
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-13.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-13.c
index 7997725..107b549 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-13.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-13.c
@@ -10,4 +10,4 @@ double foo(double a)
 }
 
 /* { dg-final { scan-tree-dump-not "\\\+ 0.0" "reassoc1" } } */
-/* { dg-final { scan-tree-dump "return a_..D.;" "optimized" } } */
+/* { dg-final { scan-tree-dump "return a_..D.;" "optimized" { target { ! ia16-*-* } } } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/scev-8.c b/gcc/testsuite/gcc.dg/tree-ssa/scev-8.c
index 766f674..ba8e651 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/scev-8.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/scev-8.c
@@ -59,4 +59,4 @@ foo4 (unsigned char s, unsigned char l)
 }
 
 /* Address of array references are not scevs.  */
-/* { dg-final { scan-tree-dump-not "use \[0-9\]\n  address" "ivopts" } } */
+/* { dg-final { scan-tree-dump-not "use \[0-9\]\n  address" "ivopts" { target { ! ia16-*-* } } } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/sra-20.c b/gcc/testsuite/gcc.dg/tree-ssa/sra-20.c
index 5002c24..b6d0d41 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/sra-20.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/sra-20.c
@@ -1,12 +1,16 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-O1 -Wall" } */
 /* PR/70013, SRA of constant-pool loads removes initialization of part of d.  */
+
+#include <stdint.h>
+#include <inttypes.h>
+
 #pragma pack (1)
 struct S0 {
-  unsigned f0 : 17;
+  uint_least32_t f0 : 17;
 };
 
-int c;
+int_least32_t c;
 
 int
 main (int argc, char **argv)
@@ -15,6 +19,6 @@ main (int argc, char **argv)
   struct S0 e = d[1];
 
   c = d[0].f0;
-  __builtin_printf ("%x\n", e.f0);
+  __builtin_printf (PRIxLEAST32 "\n", e.f0);
   return 0;
 }
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-8.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-8.c
index 9be75aa..a50cd6e 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-8.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-8.c
@@ -1,6 +1,8 @@
 /* PR 64878 */
 /* { dg-options "-O2" } */
-/* { dg-do run } */
+/* { dg-do run { target { stdint_types } } } */
+
+#include <stdint.h>
 
 struct A { int a1; };
 struct B { char *b1; int b2; int b3; };
@@ -300,7 +302,7 @@ f2 (struct C *x)
 	  else
 	    {
 	      o = f2 (x);
-	      if (((unsigned long) o > (unsigned long) -4000L))
+	      if (((uintptr_t) o > (uintptr_t) -4000L))
 		{
 		  e = 5;
 		  goto out;
@@ -384,7 +386,7 @@ f2 (struct C *x)
 	  break;
 	case 19:
 	  o = f2 (x);
-	  if (((unsigned long) o > (unsigned long) -4000L))
+	  if (((uintptr_t) o > (uintptr_t) -4000L))
 	    {
 	      e = 6;
 	      goto out;
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-11.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-11.c
index 0f0b51e..ccfb428 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-11.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-11.c
@@ -13,4 +13,4 @@ int foo (int v[], int a)
   return r;
 }
 
-/* { dg-final { scan-tree-dump "MEM\\\[.* \\+ 252B\\\]" "optimized"} } */
+/* { dg-final { scan-tree-dump "MEM\\\[.* \\+ 252B\\\]" "optimized" { target { ! ia16-*-* } } } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-12.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-12.c
index f6658a1..df96bc2 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-12.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-12.c
@@ -14,4 +14,4 @@ int foo (int v1[], int v2[])
   return r;
 }
 
-/* { dg-final { scan-tree-dump "MEM\\\[.* \\+ 252B\\\]" "optimized"} } */
+/* { dg-final { scan-tree-dump "MEM\\\[.* \\+ 252B\\\]" "optimized" { target { ! ia16-*-* } } } } */
diff --git a/gcc/testsuite/gcc.dg/uninit-19.c b/gcc/testsuite/gcc.dg/uninit-19.c
index b138a2c..3f78b68 100644
--- a/gcc/testsuite/gcc.dg/uninit-19.c
+++ b/gcc/testsuite/gcc.dg/uninit-19.c
@@ -22,5 +22,5 @@ fn2 ()
   fn1 (l, &d, &e, &g, &i, &h, &k, n);  /* 22.  */
 }
 
-/* { dg-warning "may be used uninitialized" "" { target { { nonpic } || { hppa*64*-*-* } } } 13 } */
-/* { dg-warning "may be used uninitialized" "" { target { ! { { nonpic } || { hppa*64*-*-* } } } } 22 } */
+/* { dg-warning "may be used uninitialized" "" { target { { { nonpic } && { ! { "ia16-*-*" } } } || { hppa*64*-*-* } } } 13 } */
+/* { dg-warning "may be used uninitialized" "" { target { ! { { { nonpic } && { ! { "ia16-*-*" } } } || { hppa*64*-*-* } } } } 22 } */
diff --git a/gcc/testsuite/gcc.dg/vrp-min-max-2.c b/gcc/testsuite/gcc.dg/vrp-min-max-2.c
index a3ccc66..3352a47 100644
--- a/gcc/testsuite/gcc.dg/vrp-min-max-2.c
+++ b/gcc/testsuite/gcc.dg/vrp-min-max-2.c
@@ -1,7 +1,9 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { stdint_types } } } */
 /* { dg-options "-O2 -fdump-tree-vrp2" } */
 
-int Foo (int X)
+#include <stdint.h>
+
+int_least32_t Foo (int_least32_t X)
 {
   if (X < 0)
     X = 0;
diff --git a/gcc/testsuite/gcc.dg/zero_sign_ext_test.c b/gcc/testsuite/gcc.dg/zero_sign_ext_test.c
index 6a52678..83b0275 100644
--- a/gcc/testsuite/gcc.dg/zero_sign_ext_test.c
+++ b/gcc/testsuite/gcc.dg/zero_sign_ext_test.c
@@ -4,10 +4,10 @@ extern void abort (void);
 /* { dg-do run } */
 
 #define TYPE_MAX(type, sign)	\
-  ((!sign) ? ((1 << (sizeof (type) * 8 - 1)) - 1) :	\
-   ((1 << (sizeof (type) * 8)) - 1))
+  ((!sign) ? ((1L << (sizeof (type) * 8 - 1)) - 1) :	\
+   ((1L << (sizeof (type) * 8)) - 1))
 #define TYPE_MIN(type, sign)	\
-  ((!sign) ? -(1 << (sizeof (type) * 8 - 1)) : 0)
+  ((!sign) ? -(1L << (sizeof (type) * 8 - 1)) : 0)
 
 #define TEST_FN(NAME, ARG_TYPE, RET_TYPE, CAST_TYPE, VAL, VR_MIN, VR_MAX)\
   __attribute__((noinline, noclone)) RET_TYPE				\
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-1.c b/gcc/testsuite/gcc.target/ia16/far-addr-1.c
new file mode 100644
index 0000000..c26af68
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-1.c
@@ -0,0 +1,18 @@
+/* { dg-do assemble } */
+/* { dg-options "-O3 -fno-inline --save-temps" } */
+
+/* Test for basic far pointer functionality.  Also test that the preprocessor
+   macro __FAR is defined.  */
+
+unsigned long
+irq0_clock_ticks (void)
+{
+#ifdef __FAR
+  volatile unsigned long __far *p =
+    (volatile unsigned long __far *) 0x0040006C;
+  return *p;
+#else
+# error
+#endif
+}
+/* { dg-final { scan-assembler "movw\[ \\t\](%es:|.*,\[ \\t\]%ds)" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-10.c b/gcc/testsuite/gcc.target/ia16/far-addr-10.c
new file mode 100644
index 0000000..0bc3ff8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-10.c
@@ -0,0 +1,15 @@
+/* { dg-do assemble } */
+/* { dg-options "-O1 --save-temps" } */
+
+/* Test for a far pointer processing bug reported by Bart Oldeman --- see
+   https://github.com/tkchia/gcc-ia16/issues/2 .  */
+
+struct string_int {
+  char str[1];
+  int number;
+};
+
+int p_number_not_zero(struct string_int __far *p)
+{
+  return p->number != 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-11.c b/gcc/testsuite/gcc.target/ia16/far-addr-11.c
new file mode 100644
index 0000000..7a7d3e0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-11.c
@@ -0,0 +1,10 @@
+/* { dg-do assemble } */
+/* { dg-options "-O1 --save-temps" } */
+
+/* Test for a pointer processing bug reported by Bart Oldeman --- see
+   https://github.com/tkchia/gcc-ia16/issues/5 .  */
+
+void scan(int __far *p)
+{
+  for(; *p; p++);
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-12.c b/gcc/testsuite/gcc.target/ia16/far-addr-12.c
new file mode 100644
index 0000000..2216f9d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-12.c
@@ -0,0 +1,14 @@
+/* { dg-do assemble } */
+/* { dg-options "-O1 --save-temps" } */
+
+/* Test for a pointer processing bug reported by Bart Oldeman --- see
+   https://github.com/tkchia/gcc-ia16/issues/6 .  */
+
+struct x2 {
+  char x[2];
+} psp;
+
+int get_p_x_i(struct x2 __far *p, int i)
+{
+  return p->x[i];
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-13.c b/gcc/testsuite/gcc.target/ia16/far-addr-13.c
new file mode 100644
index 0000000..3dc59e0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-13.c
@@ -0,0 +1,16 @@
+/* { dg-do assemble } */
+/* { dg-options "-Os --save-temps" } */
+
+/* First test case for a pointer processing bug reported by Bart Oldeman ---
+   see https://github.com/tkchia/gcc-ia16/issues/7 .  */
+
+struct x2 {
+  char x[2];
+} psp;
+
+extern void foo(char __far *p);
+
+void foo_p_x_i(struct x2 __far *p, int i)
+{
+  foo(&p->x[i]);
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-14.c b/gcc/testsuite/gcc.target/ia16/far-addr-14.c
new file mode 100644
index 0000000..c76a722
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-14.c
@@ -0,0 +1,10 @@
+/* { dg-do assemble } */
+/* { dg-options "-Og --save-temps" } */
+
+/* Second test case for a pointer processing bug reported by Bart Oldeman
+   --- see https://github.com/tkchia/gcc-ia16/issues/7 .  */
+
+char p_i(char __far *p, int i)
+{
+  return p[i];
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-15.c b/gcc/testsuite/gcc.target/ia16/far-addr-15.c
new file mode 100644
index 0000000..e59abf4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-15.c
@@ -0,0 +1,24 @@
+/* { dg-do assemble } */
+/* { dg-options "-O0 --save-temps" } */
+
+/* Casting an array within a far structure to a pointer.  Bug was reported
+   by Bart Oldeman --- https://github.com/tkchia/gcc-ia16/issues/3 .
+
+   The bug was caused by c_build_qualified_type (...) (in gcc/c/c-typeck.c)
+   failing to propagate the address space information of an array's element
+   type to the array type itself.
+
+   A similar routine exists on the C++ side, but (as of Nov 2017) the GNU
+   C++ compiler does not yet support named address spaces, so will not
+   currently trigger this bug.  */
+
+struct string1 {
+  char str[1];
+};
+
+void farstr(char __far *);
+
+void call_farstr(struct string1 __far *p)
+{
+  farstr(p->str);
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-16.c b/gcc/testsuite/gcc.target/ia16/far-addr-16.c
new file mode 100644
index 0000000..a262fc0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-16.c
@@ -0,0 +1,121 @@
+/* { dg-do run } */
+/* { dg-options "-mcmodel=tiny -O3 -fno-inline --save-temps" } */
+
+/* Check if far pointers wrap around right (i.e. only the offsets wrap) when
+   we use pointer arithmetic to access fields in far structures.  */
+
+#define MK_FP(seg, off) \
+	((void __far *) ((unsigned long) (unsigned) (seg) << 16 | \
+					 (unsigned) (off)))
+#define FLUFF_AMOUNT	0x0badu
+
+int printf (const char *, ...);
+void abort (void);
+
+struct s1
+{
+  unsigned p, q, r, s;
+};
+
+struct s2
+{
+  unsigned fluff[FLUFF_AMOUNT], p, q, r, s;
+};
+
+static unsigned
+ss (void)
+{
+  unsigned x;
+  __asm ("movw %%ss, %0" : "=r" (x));
+  return x;
+}
+
+void __far *
+addr_1 (void)
+{
+  return MK_FP (0xf000, 0xff00);
+}
+
+void __far *
+addr_2 (void)
+{
+  return MK_FP (0xfff0, -FLUFF_AMOUNT * sizeof (unsigned));
+}
+
+void __far *
+addr_3 (void)
+{
+  return MK_FP (ss (), 0x100);
+}
+
+void __far *
+addr_4 (void)
+{
+  return MK_FP (ss (), 0x100 - FLUFF_AMOUNT * sizeof (unsigned));
+}
+
+int
+main (void)
+{
+  struct s1 __far *as1 = addr_1 ();
+  struct s2 __far *as2 = addr_2 ();
+  struct s1 __far *as3 = addr_3 ();
+  struct s2 __far *as4 = addr_4 ();
+  unsigned p1, q1, r1, s1, p2, q2, r2, s2, p3, q3, r3, s3, p4, q4, r4, s4;
+
+  printf ("as1 = %#lx, as2 = %#lx\n",
+	  (unsigned long) as1, (unsigned long) as2);
+
+  p1 = as1->p;
+  p2 = as2->p;
+  printf ("p1 = %#x, p2 = %#x\n", p1, p2);
+  if (p1 != p2)
+    abort ();
+
+  q1 = as1->q;
+  q2 = as2->q;
+  printf ("q1 = %#x, q2 = %#x\n", q1, q2);
+  if (q1 != q2)
+    abort ();
+
+  r1 = as1->r;
+  r2 = as2->r;
+  printf ("r1 = %#x, r2 = %#x\n", r1, r2);
+  if (r1 != r2)
+    abort ();
+
+  s1 = as1->s;
+  s2 = as2->s;
+  printf ("s1 = %#x, s2 = %#x\n", s1, s2);
+  if (s1 != s2)
+    abort ();
+
+  printf ("as3 = %#lx, as4 = %#lx\n",
+	  (unsigned long) as3, (unsigned long) as4);
+
+  p3 = as3->p;
+  p4 = as4->p;
+  printf ("p3 = %#x, p4 = %#x\n", p3, p4);
+  if (p3 != p4)
+    abort ();
+
+  q3 = as3->q;
+  q4 = as4->q;
+  printf ("q3 = %#x, q4 = %#x\n", q3, q4);
+  if (q3 != q4)
+    abort ();
+
+  r3 = as3->r;
+  r4 = as4->r;
+  printf ("r3 = %#x, r4 = %#x\n", r3, r4);
+  if (r3 != r4)
+    abort ();
+
+  s3 = as3->s;
+  s4 = as4->s;
+  printf ("s3 = %#x, s4 = %#x\n", s3, s4);
+  if (s3 != s4)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-17.c b/gcc/testsuite/gcc.target/ia16/far-addr-17.c
new file mode 100644
index 0000000..55c181f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-17.c
@@ -0,0 +1,18 @@
+/* { dg-do assemble } */
+/* { dg-options "-Os --save-temps" } */
+
+/* Test for a far pointer processing bug reported by Bart Oldeman --- see
+   https://github.com/tkchia/gcc-ia16/issues/8 .
+
+   GCC's induction variable optimization pass (`-fivopts') sometimes creates
+   nonsense "far" addresses --- with no segment override --- and passes them
+   to TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS, in order to estimate the costs
+   of using various types of addresses.  So we need to make sure that
+   TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS can gracefully handle such things.  */
+
+unsigned my_strlen(char __far * fname)
+{
+  unsigned length = 0;
+  while (fname[length]) length++;
+  return length;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-18.c b/gcc/testsuite/gcc.target/ia16/far-addr-18.c
new file mode 100644
index 0000000..8848ce0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-18.c
@@ -0,0 +1,18 @@
+/* { dg-do assemble } */
+/* { dg-options "-Os --save-temps" } */
+
+/* Test for a far pointer processing bug reported by Bart Oldeman --- see
+   https://github.com/tkchia/gcc-ia16/issues/9 .
+
+   (And thus did the local register allocation (LRA) pass say to me, "d00d,
+   you're doing it wrong.")  -- tkchia 20171114  */
+
+struct int_struct
+{
+  int i;
+};
+
+void incp(struct int_struct __far *p)
+{
+  p->i++;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-19.c b/gcc/testsuite/gcc.target/ia16/far-addr-19.c
new file mode 100644
index 0000000..47dca48
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-19.c
@@ -0,0 +1,51 @@
+/* { dg-do run } */
+/* { dg-options "-O3 -fno-inline --save-temps" } */
+
+/* Test if the compiler successfully constructs the composite type (N1570
+   6.2.7) of a function involving the far address space, given several
+   declarations of the same function.  */
+
+void abort (void);
+int printf (const char *, ...);
+
+int f (unsigned __far matrix[][8], volatile unsigned __far vector[128]);
+int f (unsigned __far matrix[16][8], volatile unsigned __far vector[]);
+
+int f (unsigned __far matrix[16][8], volatile unsigned __far vector[128])
+{
+  unsigned i, j, k;
+
+  if (sizeof (matrix[0]) != 8 * sizeof (unsigned))
+    abort ();
+
+  if (sizeof (&matrix[0][0]) != sizeof (void __far *))
+    abort ();
+
+  if (sizeof (&matrix[0]) != sizeof (void __far *))
+    abort ();
+
+  if (sizeof (vector[0]) != sizeof (unsigned))
+    abort ();
+
+  if (sizeof (&vector[0]) != sizeof (void __far *))
+    abort ();
+
+  for (i = 0, k = 0; i < 16; ++i)
+    {
+      for (j = 0; j < 8; ++j, ++k)
+	{
+	  printf ("%04x ", matrix[i][j]);
+	  if (matrix[i][j] != vector[k])
+	    abort ();
+	}
+      printf ("\n");
+    }
+}
+
+int main (void)
+{
+  f ((unsigned __far (*)[8]) 0xf000ff00ul,
+     (volatile unsigned __far *) 0xfff00000ul);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-2.c b/gcc/testsuite/gcc.target/ia16/far-addr-2.c
new file mode 100644
index 0000000..9832684
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-2.c
@@ -0,0 +1,68 @@
+/* { dg-do run } */
+/* { dg-options "-O3 --save-temps" } */
+
+/* What happens when we add a displacement to a long integer _before_
+   converting it to a far pointer?  Make sure that the compiler does not try
+   to wrongly "optimize" this by placing the displacement in the final IA-16
+   address expression. */
+
+int printf (const char *, ...);
+void abort (void);
+
+static inline unsigned long
+read_displaced (unsigned long addr, unsigned disp)
+{
+  unsigned long addr2;
+
+  __asm ("" : "=k" (addr2) : "0" (addr));
+  return *(volatile unsigned long __far *) (addr2 + disp);
+}
+
+static void
+test (const char *wx_name, unsigned long wx, unsigned long w0)
+{
+  if (wx == w0)
+    printf ("%s == w0\n", wx_name);
+  else
+    {
+      printf ("%s != w0 {%#lx != %#lx}\n", wx_name, wx, w0);
+      abort ();
+    }
+}
+
+int
+main (void)
+{
+  unsigned long w0, w1, w2, w3, w4, w5, w6, w7;
+
+  /* Read longword at 0x0008:0x0000. */
+  w0 = *(volatile unsigned long __far *) 0x80000;
+
+  /* Read longword at (__far *) (0x78000 + 0x8000), which should be the same
+     as 0x80000, since we are doing the addition as integers first. */
+  w1 = read_displaced (0x78000ul, 0x8000u);
+  test ("w1", w1, w0);
+
+  /* Read longword at (__far *) (0x78001 + 0x7fff), which should also be the
+     same as 0x80000. */
+  w2 = read_displaced (0x78001ul, 0x7fffu);
+  test ("w2", w2, w0);
+
+  /* And so on... */
+  w3 = read_displaced (0x70001ul, 0xffffu);
+  test ("w3", w3, w0);
+
+  w4 = read_displaced (0x7ff80ul, 0x80u);
+  test ("w4", w4, w0);
+
+  w5 = read_displaced (0x7ff81ul, 0x7fu);
+  test ("w5", w5, w0);
+
+  w6 = read_displaced (0x7ff01ul, 0xffu);
+  test ("w6", w6, w0);
+
+  w7 = read_displaced (0x7fffful, 1u);
+  test ("w7", w7, w0);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-20.c b/gcc/testsuite/gcc.target/ia16/far-addr-20.c
new file mode 100644
index 0000000..59c12fe
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-20.c
@@ -0,0 +1,20 @@
+/* { dg-do assemble } */
+/* { dg-options "-Os --save-temps" } */
+
+/* Test for a far pointer + induction variable optimization bug reported by
+   Bart Oldeman --- see https://github.com/tkchia/gcc-ia16/issues/10 .  */
+
+const char __far *get_end(const char __far * fname, unsigned length)
+{
+  while (length && *++fname)
+    length--;
+  return fname;
+}
+
+void pad_spaces(char __far *s)
+{
+  int i;
+  /* pad with spaces */
+  for (i = 10; s[i] == '\0'; i--)
+    s[i] = ' ';
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-21.c b/gcc/testsuite/gcc.target/ia16/far-addr-21.c
new file mode 100644
index 0000000..e9d40ad
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-21.c
@@ -0,0 +1,48 @@
+/* { dg-do run } */
+/* { dg-options "-Waddress -Os --save-temps" } */
+
+/* First test case for whether GCC warns properly for things like `char
+   __far *p, *q;' which are parsed differently by old DOS compilers.  Issue
+   found by Bart Oldeman --- https://github.com/tkchia/gcc-ia16/issues/11.  */
+
+void abort (void);
+
+int
+main (void)
+{
+  /* Far pointer declarations.  */
+  char __far *p1;	/* { dg-bogus	"will also go in .*__far.* space" } */
+  char __far *p2;	/* { dg-bogus	"will also go in .*__far.* space" } */
+
+  /* Generic pointer declarations.  */
+  char *p3, *p4;	/* { dg-bogus	"will also go in .*__far.* space" } */
+
+  /* Is p6 a far pointer?  GCC grammar says yes, Watcom says no.  */
+  long __far *p5, *p6;	/* { dg-warning	"will also go in .*__far.* space" } */
+
+  /* Watcom does not grok `__far char' at all, so this can have only one
+     meaning --- the GCC one.  */
+  __far char *p7, *p8;	/* { dg-bogus	"will also go in .*__far.* space" } */
+
+  /* No danger of misinterpretation here.  The `declaration-specifiers' here
+     are simply the word `char'.  So p9 is a far pointer to a generic
+     pointer, and p10 is a generic pointer to another generic pointer.  */
+  char * __far *p9, **p10; /* { dg-bogus "will also go in .*__far.* space" } */
+
+  if (sizeof (p6) != sizeof (long __far *))
+    abort ();
+
+  if (sizeof (p9) != sizeof (void __far *))
+    abort ();
+
+  if (sizeof (*p9) != sizeof (void *))
+    abort ();
+
+  if (sizeof (p10) != sizeof (void *))
+    abort ();
+
+  if (sizeof (*p10) != sizeof (void *))
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-22.c b/gcc/testsuite/gcc.target/ia16/far-addr-22.c
new file mode 100644
index 0000000..807bd2d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-22.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-options "-Waddress -Os --save-temps" } */
+
+/* Second test case for https://github.com/tkchia/gcc-ia16/issues/11.  */
+
+#include <stdarg.h>
+
+struct sigaction;
+void abort (void);
+
+int
+main (void)
+{
+  /* Are f2(.) and f3(.) far pointers?  */
+  extern unsigned __far
+    **f1 (int thang, const struct sigaction *sa, struct sigaction *osa, \
+	  void *(* restrict)[8][8], va_list ap, ...),
+    *f2 (char),		/* { dg-warning "will also go in .*__far.* space" } */
+    *f3 (float);
+
+  if (sizeof (f2 ('x')) != sizeof (unsigned __far *))
+    abort ();
+
+  if (sizeof (f3 (3.1415927)) != sizeof (unsigned __far *))
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-23.c b/gcc/testsuite/gcc.target/ia16/far-addr-23.c
new file mode 100644
index 0000000..c4483ea
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-23.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options "-Waddress -Os --save-temps" } */
+
+/* Third test case for https://github.com/tkchia/gcc-ia16/issues/11.  */
+
+void abort (void);
+
+int
+main (void)
+{
+  /* We test two things here --- whether the warning is triggered for
+     `typedef's, and whether the warning is triggered when we have two
+     `__far's in a row just before the declarators begin.  */
+  typedef char __far __far
+    *t1, *t2;		/* { dg-warning "will also go in .*__far.* space" } */
+
+  if (sizeof (t1) != sizeof (void __far *))
+    abort ();
+
+  if (sizeof (t2) != sizeof (void __far *))
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-24.c b/gcc/testsuite/gcc.target/ia16/far-addr-24.c
new file mode 100644
index 0000000..60f4991
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-24.c
@@ -0,0 +1,47 @@
+/* { dg-do assemble } */
+/* { dg-options "-Os -fcall-used-es --save-temps" } */
+
+/* First test for a far pointer processing bug reported by Bart Oldeman ---
+   see https://github.com/tkchia/gcc-ia16/issues/14 .
+
+      "	tst14.c: In function ‘bar’:
+	tst14.c:11:1: internal compiler error: in reload_combine_note_use, at
+	postreload.c:1536
+	 }
+	 ^
+	0x84eac98 reload_combine_note_use
+		../../gcc-ia16/gcc/postreload.c:1536
+	0x84eaa47 reload_combine_note_use
+		../../gcc-ia16/gcc/postreload.c:1603
+	0x84eaa82 reload_combine_note_use
+		../../gcc-ia16/gcc/postreload.c:1598
+	0x84eaa82 reload_combine_note_use
+		../../gcc-ia16/gcc/postreload.c:1598
+	0x84eaa82 reload_combine_note_use
+		../../gcc-ia16/gcc/postreload.c:1598
+	0x84eaa82 reload_combine_note_use
+		../../gcc-ia16/gcc/postreload.c:1598
+	0x84eaa47 reload_combine_note_use
+		../../gcc-ia16/gcc/postreload.c:1603
+	0x84ec61a reload_combine
+		../../gcc-ia16/gcc/postreload.c:1386
+	0x84ed58f reload_cse_regs
+		../../gcc-ia16/gcc/postreload.c:68
+	0x84ed58f execute
+		../../gcc-ia16/gcc/postreload.c:2343
+	Please submit a full bug report,
+	with preprocessed source if appropriate.
+	Please include the complete backtrace with any bug report.
+	See <http://gcc.gnu.org/bugs.html> for instructions. "  */
+
+extern int foo(int, int);
+
+struct ab {
+  int a, b;
+};
+
+int bar(struct ab __far * x)
+{
+  x->a += foo(2, 16);
+  return 16 % x->b;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-25.c b/gcc/testsuite/gcc.target/ia16/far-addr-25.c
new file mode 100644
index 0000000..714ada2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-25.c
@@ -0,0 +1,16 @@
+/* { dg-do assemble } */
+/* { dg-options "-Os -fcall-used-es --save-temps" } */
+
+/* Second test for a far pointer processing bug reported by Bart Oldeman ---
+   see https://github.com/tkchia/gcc-ia16/issues/14 .  */
+
+extern int foo(int, int);
+
+struct ab {
+  int a, b;
+};
+
+int bar(struct ab __far * x)
+{
+  return 16 % x->b;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-26-new.c b/gcc/testsuite/gcc.target/ia16/far-addr-26-new.c
new file mode 100644
index 0000000..2478fc4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-26-new.c
@@ -0,0 +1,93 @@
+/* { dg-do run } */
+/* { dg-options "-Os -fno-inline -fno-toplevel-reorder --save-temps" } */
+
+/* Check that size optimizations work correctly when compiling a loop.  Also
+   try to check that there are no size regressions.  */
+
+int printf (const char *, ...);
+void abort (void);
+
+unsigned long
+hash1 (void)
+{
+  unsigned __far *p = (unsigned __far *) 0xfff00000ul;
+  unsigned i;
+  unsigned long h = 0;
+  for (i = 0; i < 0x80u; ++i)
+    h = 5 * h ^ *p++;
+  return h;
+}
+
+__attribute__ ((optimize ("O0")))
+unsigned long
+hash2 (void)
+{
+  unsigned __far *p = (unsigned __far *) 0xfff00000ul;
+  unsigned i;
+  unsigned long h = 0;
+  for (i = 0; i < 0x80u; ++i)
+    h = 5 * h ^ *p++;
+  return h;
+}
+
+int
+main (void)
+{
+  unsigned long h1 = hash1 (), h2 = hash2 ();
+  unsigned hash1_size = (char *) hash2 - (char *) hash1;
+  printf ("%#lx %#lx\n", h1, h2);
+  if (h1 != h2)
+    abort ();
+  if (hash1_size == 0)
+    {
+      printf ("cannot get size of hash1 ()\n");
+      abort ();
+    }
+  /*
+	hash1:
+		pushw	%si
+		pushw	%di
+		pushw	%es
+		pushw	%bp
+		movw	%sp,	%bp
+		pushw	%ds
+		pushw	%ds
+		movw	$128,	%si
+		xorw	%ax,	%ax
+		movw	%ax,	%es
+		movw	%ax,	%cx
+		movw	%ax,	%bx
+		movw	$-16,	%ax
+		movw	%ax,	%ds
+		movw	$5,	%di
+	.L2:
+		movw	$5,	%ax
+		mulw	%cx
+		movw	%ax,	%cx
+		movw	%es,	%ax
+		mulw	%di
+		movw	%ax,	-4(%bp)
+		movw	%dx,	-2(%bp)
+		addw	%dx,	%cx
+		xorw	(%bx),	%ax
+		movw	%ax,	%es
+		addw	$2,	%bx
+		decw	%si
+		jne	.L2
+		movw	%cx,	%dx
+		movw	%bp,	%sp
+		popw	%bp
+		popw	%es
+		popw	%di
+		popw	%si
+		pushw	%ss
+		popw	%ds
+		ret
+   */
+  if (hash1_size > 0x43)
+    {
+      printf ("hash1 () is too large: %#x bytes\n", hash1_size);
+      abort ();
+    }
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-27-new.c b/gcc/testsuite/gcc.target/ia16/far-addr-27-new.c
new file mode 100644
index 0000000..207e790
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-27-new.c
@@ -0,0 +1,48 @@
+/* { dg-do run } */
+/* { dg-options "-Os -fno-inline -fno-toplevel-reorder --save-temps" } */
+
+/* Check that size optimizations work correctly when compiling a simple
+   function involving a far pointer.  Also try to check that there are no
+   size regressions.  */
+
+int printf (const char *, ...);
+void abort (void);
+
+void incfar (int __far *a)
+{
+  *a += 2;
+}
+
+void dummy (void)
+{
+}
+
+int main (void)
+{
+  unsigned incfar_size = (char *) dummy - (char *) incfar;
+  if (incfar_size == 0)
+    {
+      printf ("cannot get size of incfar (.)\n");
+      abort ();
+    }
+  /*
+	incfar:
+		pushw	%bp
+		movw	%sp,	%bp
+		ldsw	4(%bp),	%bx
+		addw	$2,	(%bx)
+		popw	%bp
+		pushw	%ss
+		popw	%ds
+		ret
+   */
+  if (incfar_size > 0xd)
+    {
+      printf ("incfar (.) is too large: %#x bytes\n", incfar_size);
+      abort ();
+    }
+  return 0;
+}
+
+/* { dg-final { scan-assembler-times "l\[de\]sw" 1 } } */
+/* { dg-final { scan-assembler-not "mov\[ \\t\].*,\[ \\t\]%\[de\]s" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-28-new.c b/gcc/testsuite/gcc.target/ia16/far-addr-28-new.c
new file mode 100644
index 0000000..29cb0b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-28-new.c
@@ -0,0 +1,13 @@
+/* { dg-do assemble } */
+/* { dg-options "-O3 -fno-inline --save-temps" } */
+
+/* Check that speed optimizations work correctly when compiling a simple
+   function involving a far pointer.  */
+
+void incfar (int __far *a)
+{
+  *a += 2;
+}
+
+/* { dg-final { scan-assembler-times "l\[de\]sw" 1 } } */
+/* { dg-final { scan-assembler-not "mov\[ \\t\].*,\[ \\t\]%\[de\]s" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-3.c b/gcc/testsuite/gcc.target/ia16/far-addr-3.c
new file mode 100644
index 0000000..a692b41
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-3.c
@@ -0,0 +1,13 @@
+/* { dg-do assemble } */
+/* { dg-options "-O3 -fno-inline --save-temps" } */
+
+/* Do not allow far address space variables to be created, if we are using
+   the default tiny memory model.  */
+
+int __far var = 1;	/* { dg-error " cannot create .*far.* static " } */
+
+int
+main (void)
+{
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-30.c b/gcc/testsuite/gcc.target/ia16/far-addr-30.c
new file mode 100644
index 0000000..5caf55a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-30.c
@@ -0,0 +1,22 @@
+/* { dg-do assemble } */
+/* { dg-options "-O3 -fno-inline --save-temps" } */
+
+/* Do not allow far address space variables to be manipulated, if we are
+   using the default tiny memory model.  */
+
+int printf (const char *, ...);
+
+static int __far var = 1;
+
+int __far *
+p_var (void)
+{
+  return &var;	/* { dg-error " cannot take address of .*far.* static " } */
+}
+
+int
+main (void)
+{
+  printf ("%d\n", *p_var ());
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-4.c b/gcc/testsuite/gcc.target/ia16/far-addr-4.c
new file mode 100644
index 0000000..ca17ab1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-4.c
@@ -0,0 +1,109 @@
+/* { dg-do run } */
+/* { dg-options "-O3 -fno-inline --save-temps" } */
+
+/* Arithmetic on a far pointer that causes the offset component to wrap
+   around.  This should really just leave the segment component alone, like
+   classical IA-16 compilers do.  */
+
+int puts (const char *);
+void abort (void);
+
+static inline unsigned long
+read_displaced (unsigned long addr, unsigned disp)
+{
+  unsigned long addr2;
+
+  __asm ("" : "=k" (addr2) : "0" (addr));
+  return ((volatile unsigned long __far *) addr2) [disp];
+}
+
+static inline unsigned long
+read_neg_displaced (unsigned long addr, unsigned disp)
+{
+  unsigned long addr2;
+
+  __asm ("" : "=k" (addr2) : "0" (addr));
+  return *((volatile unsigned long __far *) addr2 - disp);
+}
+
+int
+main (void)
+{
+  unsigned long w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13;
+
+  /* Read longword at 0x0008:0x0000. */
+  w0 = *(volatile unsigned long __far *) 0x80000;
+
+  /* Read longword at ((__far *) 0x88000 + 0x8000), which should be the same
+     as 0x80000. */
+  w1 = read_displaced (0x88000ul, 0x8000u / sizeof (unsigned long));
+  if (w1 != w0)
+    abort ();
+  puts ("w1 == w0");
+
+  /* And so on... */
+  w2 = read_displaced (0x88004ul, 0x7ffcu / sizeof (unsigned long));
+  if (w2 != w0)
+    abort ();
+  puts ("w2 == w0");
+
+  w3 = read_displaced (0x80004ul, 0xfffcu / sizeof (unsigned long));
+  if (w3 != w0)
+    abort ();
+  puts ("w3 == w0");
+
+  w4 = read_displaced (0x8ff80ul, 0x80u / sizeof (unsigned long));
+  if (w4 != w0)
+    abort ();
+  puts ("w4 == w0");
+
+  w5 = read_displaced (0x8ff84ul, 0x7cu / sizeof (unsigned long));
+  if (w5 != w0)
+    abort ();
+  puts ("w5 == w0");
+
+  w6 = read_displaced (0x8ff04ul, 0xfcu / sizeof (unsigned long));
+  if (w6 != w0)
+    abort ();
+  puts ("w6 == w0");
+
+  w7 = read_displaced (0x8fffcul, 4u / sizeof (unsigned long));
+  if (w7 != w0)
+    abort ();
+  puts ("w7 == w0");
+
+  /* Read longword at ((__far *) 0 - 0xff80), which should be the same
+     as 0x80, and 0:0x80 == 0x8:0.  */
+  w8 = read_neg_displaced (0ul, 0xff80u / sizeof (unsigned long));
+  if (w8 != w0)
+    abort ();
+  puts ("w8 == w0");
+
+  /* And so on... */
+  w9 = read_neg_displaced (4ul, 0xff84u / sizeof (unsigned long));
+  if (w9 != w0)
+    abort ();
+  puts ("w9 == w0");
+
+  w10 = read_neg_displaced (8ul, 0xff88u / sizeof (unsigned long));
+  if (w10 != w0)
+    abort ();
+  puts ("w10 == w0");
+
+  w11 = read_neg_displaced (0x10ul, 0xff90u / sizeof (unsigned long));
+  if (w11 != w0)
+    abort ();
+  puts ("w11 == w0");
+
+  w12 = read_neg_displaced (0x20ul, 0xffa0u / sizeof (unsigned long));
+  if (w12 != w0)
+    abort ();
+  puts ("w12 == w0");
+
+  w13 = read_neg_displaced (0x40ul, 0xffc0u / sizeof (unsigned long));
+  if (w13 != w0)
+    abort ();
+  puts ("w13 == w0");
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-5.c b/gcc/testsuite/gcc.target/ia16/far-addr-5.c
new file mode 100644
index 0000000..bf010e4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-5.c
@@ -0,0 +1,46 @@
+/* { dg-do run } */
+/* { dg-options "-O3 --save-temps" } */
+
+/* Do something non-trivial with far pointers.
+
+   Assume that we are running with a PC-compatible ROM BIOS.  If we obtain
+   the clock tick count at 0x0040:0x006c and compare it to the clock tick
+   count obtained by the BIOS software interrupt $0x1a, they should be the
+   same (after a few tries, at least).
+
+   Reference:  www.ctyme.com/intr/rb-2271.htm  */
+
+static unsigned long
+irq0_clock_ticks1 (void)
+{
+  unsigned ticks_hi, ticks_lo, midnight;
+  unsigned long ticks;
+  __asm ("int $0x1a"
+    : "=c" (ticks_hi), "=d" (ticks_lo), "=a" (midnight)
+    : "2" (0x0000u)
+    : "bx", "cc", "memory");
+  ticks = (unsigned long) ticks_hi << 16 | ticks_lo;
+  return ticks;
+}
+
+static unsigned long
+irq0_clock_ticks2 (void)
+{
+  volatile unsigned long __far *p =
+    (volatile unsigned long __far *) 0x0040006c;
+  return *p;
+}
+
+int
+main (void)
+{
+  unsigned i;
+  for (i = 0; i < 100; ++i)
+    {
+      unsigned long ticks1 = irq0_clock_ticks1 ();
+      unsigned long ticks2 = irq0_clock_ticks2 ();
+      if (ticks1 == ticks2)
+	return 0;
+    }
+  return 1;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-6.c b/gcc/testsuite/gcc.target/ia16/far-addr-6.c
new file mode 100644
index 0000000..b099c12
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-6.c
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-options "-O3 -fno-inline --save-temps" } */
+
+/* Can we cast a generic pointer to a far pointer --- and back?  */
+
+#define VALUE1	0x1337b33fu
+#define VALUE2	0xb3effe3du
+#define VALUE3	0xcafe13e7u
+
+int printf (const char *, ...);
+void abort (void);
+
+static volatile unsigned long var = VALUE1;
+
+volatile unsigned long __far *
+p_var (void)
+{
+  return (volatile unsigned long __far *) &var;
+}
+
+int main (void)
+{
+  volatile unsigned long __far *p = p_var ();
+  volatile unsigned long *q;
+
+  if (*p != VALUE1)
+    abort ();
+
+  var = VALUE2;
+  if (*p != VALUE2)
+    abort ();
+
+  q = (volatile unsigned long *)p;
+  *p = VALUE3;
+  if (*q != VALUE3)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-7.c b/gcc/testsuite/gcc.target/ia16/far-addr-7.c
new file mode 100644
index 0000000..d18fa43
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-7.c
@@ -0,0 +1,52 @@
+/* { dg-do run } */
+/* { dg-options "-O3 -fno-inline --save-temps" } */
+
+/* Using a far pointer to `volatile' loop through an area of (emulated) BIOS
+   ROM.  The optimized routine should give the exact same results as the
+   unoptimized routine.  Furthermore, reading from 0xfff0:0x0000 should give
+   the same results as reading from 0xf000:0xff00.  */
+
+int printf (const char *, ...);
+
+__attribute__ ((optimize ("O3")))
+unsigned long
+hash1 (void)
+{
+  volatile unsigned __far *p = (volatile unsigned __far *) 0xfff00000ul;
+  unsigned i;
+  unsigned long h = 0;
+  for (i = 0; i < 0x80u; ++i)
+    h = 5 * h ^ *p++;
+  return h;
+}
+
+__attribute__ ((optimize ("O0")))
+unsigned long
+hash2 (void)
+{
+  volatile unsigned __far *p = (volatile unsigned __far *) 0xfff00000ul;
+  unsigned i;
+  unsigned long h = 0;
+  for (i = 0; i < 0x80u; ++i)
+    h = 5 * h ^ *p++;
+  return h;
+}
+
+unsigned long
+hash3 (void)
+{
+  volatile unsigned __far *p = (volatile unsigned __far *) 0xf000ff00ul;
+  unsigned i;
+  unsigned long h = 0;
+  for (i = 0; i < 0x80u; ++i)
+    h = 5 * h ^ *p++;
+  return h;
+}
+
+int
+main (void)
+{
+  unsigned long h1 = hash1 (), h2 = hash2 (), h3 = hash3 ();
+  printf ("%#lx %#lx %#lx\n", h1, h2, h3);
+  return h1 == h2 && h1 == h3 ? 0 : 1;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-8.c b/gcc/testsuite/gcc.target/ia16/far-addr-8.c
new file mode 100644
index 0000000..eca0d5c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-8.c
@@ -0,0 +1,64 @@
+/* { dg-do run } */
+/* { dg-options "-O3 -fno-inline --save-temps" } */
+
+/* Far pointers to non-volatile things.  For the same read-only memory area,
+   using pointers to non-`volatile' should give the same results as using
+   pointers to `volatile'.
+
+   We also include further tests where the _pointers_ themselves are made
+   volatile (not necessarily the things pointed to).  */
+
+int printf (const char *, ...);
+
+unsigned long
+hash1 (void)
+{
+  unsigned __far *p = (unsigned __far *) 0xfff00000ul;
+  unsigned i;
+  unsigned long h = 0;
+  for (i = 0; i < 0x80u; ++i)
+    h = 5 * h ^ *p++;
+  return h;
+}
+
+unsigned long
+hash2 (void)
+{
+  volatile unsigned __far *p = (volatile unsigned __far *) 0xfff00000ul;
+  unsigned i;
+  unsigned long h = 0;
+  for (i = 0; i < 0x80u; ++i)
+    h = 5 * h ^ *p++;
+  return h;
+}
+
+unsigned long
+hash3 (void)
+{
+  unsigned __far * volatile p = (unsigned __far *) 0xfff00000ul;
+  unsigned i;
+  unsigned long h = 0;
+  for (i = 0; i < 0x80u; ++i)
+    h = 5 * h ^ *p++;
+  return h;
+}
+
+unsigned long
+hash4 (void)
+{
+  volatile unsigned __far * volatile p =
+    (volatile unsigned __far *) 0xfff00000ul;
+  unsigned i;
+  unsigned long h = 0;
+  for (i = 0; i < 0x80u; ++i)
+    h = 5 * h ^ *p++;
+  return h;
+}
+
+int
+main (void)
+{
+  unsigned long h1 = hash1 (), h2 = hash2 (), h3 = hash3 (), h4 = hash4 ();
+  printf ("%#lx %#lx %#lx %#lx\n", h1, h2, h3, h4);
+  return h1 == h2 && h1 == h3 && h1 == h4 ? 0 : 1;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/far-addr-9.c b/gcc/testsuite/gcc.target/ia16/far-addr-9.c
new file mode 100644
index 0000000..a8b11f6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/far-addr-9.c
@@ -0,0 +1,10 @@
+/* { dg-do assemble } */
+/* { dg-options "-O0 --save-temps" } */
+
+/* Test for a pointer arithmetic bug reported by Bart Oldeman --- see
+   https://github.com/tkchia/gcc-ia16/issues/4 .  */
+
+char __far *inc(char __far *p)
+{
+  return &p[1];
+}
diff --git a/gcc/testsuite/gcc.target/ia16/ia16.exp b/gcc/testsuite/gcc.target/ia16/ia16.exp
new file mode 100644
index 0000000..5ce1291
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/ia16.exp
@@ -0,0 +1,46 @@
+#  Modified from gcc/testsuite/gcc.target/aarch64/aarch64.exp
+#  (contributed by ARM Ltd.) by TK Chia.
+
+#  Copyright (C) 2009-2016 Free Software Foundation, Inc.
+#
+#  This file is part of GCC.
+#
+#  GCC 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 3, or (at your option)
+#  any later version.
+#
+#  GCC 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 GCC; see the file COPYING3.  If not see
+#  <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Exit immediately if this isn't an IA-16 target.
+if {![istarget ia16-*-elf] } then {
+  return
+}
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+    set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cCS\]]] \
+	"" $DEFAULT_CFLAGS
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/gcc.target/ia16/model-1.c b/gcc/testsuite/gcc.target/ia16/model-1.c
new file mode 100644
index 0000000..bd1938a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/model-1.c
@@ -0,0 +1,75 @@
+/* { dg-do run } */
+/* { dg-options "-O3 -mcmodel=tiny --save-temps" } */
+
+/* Test that the tiny code model (`-mcmodel=tiny') works.  */
+
+#ifndef __IA16_CMODEL_TINY__
+# error
+#endif
+#ifndef __TINY__
+# error
+#endif
+#ifdef __IA16_CMODEL_SMALL__
+# error
+#endif
+#ifdef __SMALL__
+# error
+#endif
+
+int puts (const char *);
+void abort (void);
+
+#define FP_SEG(fp) \
+	((unsigned) ((unsigned long) (void __far *) (fp) >> 16))
+
+static unsigned
+cs (void)
+{
+  unsigned x;
+  __asm ("movw %%cs, %0" : "=r" (x));
+  return x;
+}
+
+static unsigned
+ss (void)
+{
+  unsigned x;
+  __asm ("movw %%ss, %0" : "=r" (x));
+  return x;
+}
+
+int
+main (int argc, char **argv, char **envp)
+{
+  static int some_var = 0;
+  unsigned main_seg;
+
+  if (cs () != ss ())
+    abort ();
+
+  main_seg = FP_SEG (main);
+
+  if (main_seg != FP_SEG (&some_var))
+    abort ();
+
+  if (main_seg != FP_SEG (puts))
+    abort ();
+
+  if (main_seg != FP_SEG (abort))
+    abort ();
+
+  if (main_seg != FP_SEG (&argc))
+    abort ();
+
+  if (main_seg != FP_SEG (&argv[0]))
+    abort ();
+
+  if (main_seg != FP_SEG (&argv[0][0]))
+    abort ();
+
+  if (main_seg != FP_SEG (&envp[0]))
+    abort ();
+
+  puts ("Hello world!");
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/model-2.c b/gcc/testsuite/gcc.target/ia16/model-2.c
new file mode 100644
index 0000000..8f02f40
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/model-2.c
@@ -0,0 +1,76 @@
+/* { dg-do run } */
+/* { dg-options "-O3 -mcmodel=small --save-temps" } */
+
+/* Test that the small code model (`-mcmodel=small') works.  */
+
+#ifdef __IA16_CMODEL_TINY__
+# error
+#endif
+#ifdef __TINY__
+# error
+#endif
+#ifndef __IA16_CMODEL_SMALL__
+# error
+#endif
+#ifndef __SMALL__
+# error
+#endif
+
+int puts (const char *);
+void abort (void);
+
+#define FP_SEG(fp) \
+	((unsigned) ((unsigned long) (void __far *) (fp) >> 16))
+
+static unsigned
+cs (void)
+{
+  unsigned x;
+  __asm ("movw %%cs, %0" : "=r" (x));
+  return x;
+}
+
+static unsigned
+ss (void)
+{
+  unsigned x;
+  __asm ("movw %%ss, %0" : "=r" (x));
+  return x;
+}
+
+int
+main (int argc, char **argv, char **envp)
+{
+  static int some_var = 0;
+  unsigned main_seg, var_seg;
+
+  if (cs () == ss ())
+    abort ();
+
+  main_seg = FP_SEG (main);
+  var_seg = FP_SEG (&some_var);
+
+  if (main_seg == var_seg)
+    abort ();
+
+  if (main_seg != FP_SEG (puts))
+    abort ();
+
+  if (main_seg != FP_SEG (abort))
+    abort ();
+
+  if (var_seg != FP_SEG (&argc))
+    abort ();
+
+  if (var_seg != FP_SEG (&argv[0]))
+    abort ();
+
+  if (var_seg != FP_SEG (&argv[0][0]))
+    abort ();
+
+  if (var_seg != FP_SEG (&envp[0]))
+    abort ();
+
+  puts ("Hello world!");
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/prot-mode-2.c b/gcc/testsuite/gcc.target/ia16/prot-mode-2.c
new file mode 100644
index 0000000..c18c442
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/prot-mode-2.c
@@ -0,0 +1,38 @@
+/* { dg-options "-mprotected-mode -Os -std=gnu11 --save-temps" } */
+/* { dg-do run } */
+
+/* Test whether a PHImode value can be passed as a register parameter to a
+   `regparmcall' function.  */
+
+extern void abort (void);
+
+/* These two typedef's really refer to the same type...  */
+typedef unsigned __attribute__ ((mode (PHI))) PHI_t;
+typedef __typeof__ (__builtin_ia16_selector (8)) SEG_t;
+
+__attribute__ ((regparmcall, noinline)) void
+foo (PHI_t a1, SEG_t a2, long a3)
+{
+  void *frame = __builtin_frame_address (0);
+
+  /* If a1 and a2 are passed in registers, they will be pushed onto our
+     newly-created stack frame, _before_ the frame address.  If a1 and a2
+     are passed as stack arguments, they will appear after the frame
+     address.  */
+  if ((void *) &a1 >= frame)
+    abort ();
+
+  if ((void *) &a2 >= frame)
+    abort ();
+
+  /* a3 should be passed as a stack argument.  */
+  if ((void *) &a3 <= frame)
+    abort ();
+}
+
+int
+main (void)
+{
+  foo (1, 2, 3);
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/regparmcall-1.c b/gcc/testsuite/gcc.target/ia16/regparmcall-1.c
new file mode 100644
index 0000000..29d9f25
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/regparmcall-1.c
@@ -0,0 +1,61 @@
+/* { dg-do run } */
+/* { dg-options "-mregparmcall -Os --save-temps" } */
+
+/* Test whether the `-mregparmcall' switch works correctly and links with the
+   correct libgcc and newlib multilibs.  */
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+volatile unsigned long long quotient = 0x55bde67343803983ull,
+			    divisor = 0x1670107447a23170ull;
+
+unsigned
+inc (unsigned x)
+{
+  return x + 1;
+}
+
+int
+main (int argc, char **argv)
+{
+  unsigned i;
+  int fd;
+
+  /* If this code is linked against the wrong libgcc, this loop will
+     eventually cause a stack overflow and corrupt the data area.  */
+  for (i = 0; i < 10000; ++i)
+    {
+      unsigned long long mod = quotient % divisor;
+      if (mod != 0x126db5166c99a533ull)
+	abort ();
+    }
+
+  /* Try to open the binary for this program itself to run further tests. 
+     If the opening fails, just skip the tests...  */
+  fd = open (argv[0], O_RDONLY);
+  if (fd == -1)
+    return 0;
+
+  /* If this code is linked against the wrong newlib, or if this code and
+     newlib are compiled with different ideas of what `-mregparmcall' means,
+     this loop will eventually cause a stack overflow and corrupt the data
+     area.  */
+  for (i = 0; i < 10000; ++i)
+    {
+      if ((unsigned) lseek (fd, (off_t) 1000, SEEK_CUR) != (i + 1) * 1000)
+	abort ();
+    }
+
+  close (fd);
+  return 0;
+}
+
+/* inc (.) should not pop one shortword: */
+/* { dg-final { scan-assembler-not "ret\[ \\t\]\\\$2" } } */
+
+/* main (...) should not adjust the stack after calling __umoddi3 (...) or
+   lseek (...): */
+/* { dg-final { scan-assembler-not "addw\[ \\t\]\\\$\[\^4\].*,\[ \\t\]%sp" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/regparmcall-2.c b/gcc/testsuite/gcc.target/ia16/regparmcall-2.c
new file mode 100644
index 0000000..c9f1d87
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/regparmcall-2.c
@@ -0,0 +1,71 @@
+/* { dg-do run } */
+/* { dg-options "-mregparmcall -Os -fno-inline -fno-toplevel-reorder --save-temps" } */
+
+/* Check that stack spills near the prologue which can be profitably
+   rewritten into pushes are indeed rewritten, when compiling a simple
+   `regparmcall' function.  This tests for an issue reported by Bart Oldeman
+   --- https://github.com/tkchia/gcc-ia16/issues/48 .  */
+
+int printf (const char *, ...);
+void abort (void);
+int rand (void);
+int foo (int);
+
+int foo (int b)
+{
+  return rand () ^ b;
+}
+
+int bar (int a, int b)
+{
+  int baz = foo (b);
+  return a || baz < b;
+}
+
+void dummy (void)
+{
+}
+
+int main (void)
+{
+  unsigned bar_size = (char *) dummy - (char *) bar;
+  if (bar_size == 0)
+    {
+      printf ("cannot get size of bar (, )\n");
+      abort ();
+    }
+  /*
+	bar:
+		pushw	%si
+		pushw	%bp
+		movw	%sp,	%bp
+		pushw	%dx		// N.B.
+		xchgw	%ax,	%si
+		movw	%dx,	%ax
+		call	foo
+		cmpw	$1,	%si
+		sbbb	%ch,	%ch
+		incb	%ch
+		movw	-2(%bp),	%dx
+		xorb	%cl,	%cl
+		cmpw	%ax,	%dx
+		jle	.L2
+		movb	$1,	%cl
+	.L2:
+		orb	%cl,	%ch
+		movb	%ch,	%al
+		xorb	%ah,	%ah
+		movw	%bp,	%sp
+		popw	%bp
+		popw	%si
+		ret
+   */
+  if (bar_size > 0x28)
+    {
+      printf ("bar (, ) is too large: %#x bytes\n", bar_size);
+      abort ();
+    }
+  return 0;
+}
+
+/* { dg-final { scan-assembler-not "movw\[ \\t\]*%dx,\[ \\t\]*\[-0-9\]*\\(%bp\\)" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/rtd-1.c b/gcc/testsuite/gcc.target/ia16/rtd-1.c
new file mode 100644
index 0000000..6005134
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/rtd-1.c
@@ -0,0 +1,43 @@
+/* { dg-do run } */
+/* { dg-options "-mrtd -Os --save-temps" } */
+
+/* Test whether the `-mrtd' switch works correctly and links with the correct
+   libgcc multilib.  This test should not require newlib to also be compiled
+   with `-mrtd'.  */
+
+extern void abort (void);
+
+volatile unsigned long long quotient = 0x55bde67343803983ull,
+			    divisor = 0x1670107447a23170ull;
+
+unsigned
+inc (unsigned x)
+{
+  return x + 1;
+}
+
+int
+main (int argc, char **argv, ...)
+{
+  unsigned i;
+
+  /* If this code is linked against the wrong libgcc, this loop will
+     eventually cause a stack overflow and corrupt the data area.  */
+  for (i = 0; i < 10000; ++i)
+    {
+      unsigned long long mod = quotient % divisor;
+      if (mod != 0x126db5166c99a533ull)
+	abort ();
+    }
+
+  return 0;
+}
+
+/* inc (.) should pop one shortword: */
+/* { dg-final { scan-assembler "ret\[ \\t\]\\\$2" } } */
+
+/* main (...) should _not_ pop two shortwords: */
+/* { dg-final { scan-assembler-not "ret\[ \\t\]\\\$4" } } */
+
+/* main (...) should not adjust the stack after calling __umoddi3: */
+/* { dg-final { scan-assembler-not "addw\[ \\t\]\\$.*,\[ \\t\]%sp" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/rtd-2.c b/gcc/testsuite/gcc.target/ia16/rtd-2.c
new file mode 100644
index 0000000..7ee8ccc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/rtd-2.c
@@ -0,0 +1,42 @@
+/* { dg-do run } */
+/* { dg-options "-Os --save-temps" } */
+
+/* Test whether `__attribute__ ((stdcall))' works correctly, and still gets
+   the program linked with the correct (non-stdcall) libgcc multilib.  */
+
+extern void abort (void);
+
+volatile unsigned long long quotient = 0x55bde67343803983ull,
+			    divisor = 0x1670107447a23170ull;
+
+__attribute__ ((stdcall)) unsigned
+inc (unsigned x)
+{
+  return x + 1;
+}
+
+int
+main (int argc, char **argv)
+{
+  unsigned i;
+
+  /* If this code is linked against the wrong libgcc, this loop will
+     eventually cause a stack overflow and corrupt the data area.  */
+  for (i = 0; i < 10000; ++i)
+    {
+      unsigned long long mod = quotient % divisor;
+      if (mod != 0x126db5166c99a533ull)
+	abort ();
+    }
+
+  return 0;
+}
+
+/* inc (.) should pop one shortword: */
+/* { dg-final { scan-assembler "ret\[ \\t\]\\\$2" } } */
+
+/* main (...) should _not_ pop two shortwords: */
+/* { dg-final { scan-assembler-not "ret\[ \\t\]\\\$4" } } */
+
+/* main (...) should adjust the stack after calling __umoddi3: */
+/* { dg-final { scan-assembler "addw\[ \\t\]\\$.*,\[ \\t\]%sp" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/rtd-3.c b/gcc/testsuite/gcc.target/ia16/rtd-3.c
new file mode 100644
index 0000000..9deb59b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/rtd-3.c
@@ -0,0 +1,40 @@
+/* { dg-do run } */
+/* { dg-options "-mrtd -Os --save-temps" } */
+
+/* Test whether the `-mrtd' switch in conjunction with __attribute__
+   ((cdecl)) works correctly and links with the correct libgcc multilib.  */
+
+extern void abort (void);
+
+volatile unsigned long long quotient = 0x55bde67343803983ull,
+			    divisor = 0x1670107447a23170ull;
+
+unsigned
+inc (unsigned x)
+{
+  return x + 1;
+}
+
+__attribute__ ((cdecl)) int
+main (int argc, char **argv)
+{
+  unsigned i;
+
+  for (i = 0; i < 10000; ++i)
+    {
+      unsigned long long mod = quotient % divisor;
+      if (mod != 0x126db5166c99a533ull)
+	abort ();
+    }
+
+  return 0;
+}
+
+/* inc (.) should pop one shortword: */
+/* { dg-final { scan-assembler "ret\[ \\t\]\\\$2" } } */
+
+/* main (...) should _not_ pop two shortwords: */
+/* { dg-final { scan-assembler-not "ret\[ \\t\]\\\$4" } } */
+
+/* main (...) should not adjust the stack after calling __umoddi3: */
+/* { dg-final { scan-assembler-not "addw\[ \\t\]\\$.*,\[ \\t\]%sp" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/rtd-4-new.c b/gcc/testsuite/gcc.target/ia16/rtd-4-new.c
new file mode 100644
index 0000000..41530fd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/rtd-4-new.c
@@ -0,0 +1,19 @@
+/* { dg-do assemble } */
+/* { dg-options "-mrtd -Os -fno-optimize-sibling-calls --save-temps" } */
+
+/* Test for a bug where the `-mrtd' switch was not actually honoured.  Issue
+   found by Bart Oldeman --- https://github.com/tkchia/gcc-ia16/issues/20.  */
+
+extern char *strdup (const char *);
+
+char *
+Estrdup (const char * const str)
+{
+  return strdup(str);
+}
+
+/* Estrdup (.) should _not_ adjust the stack after calling strdup (.): */
+/* { dg-final { scan-assembler-not "addw\[ \\t\]\\$.*,\[ \\t\]%sp" } } */
+
+/* Estrdup (.) _should_ pop one shortword: */
+/* { dg-final { scan-assembler "ret\[ \\t\]\\\$2" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/seg-reg-1.c b/gcc/testsuite/gcc.target/ia16/seg-reg-1.c
new file mode 100644
index 0000000..14b71b0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/seg-reg-1.c
@@ -0,0 +1,27 @@
+/* { dg-do run } */
+/* { dg-options "-O3 -fno-inline --save-temps" } */
+
+/* Test that the "Q" register constraint works properly.  */
+
+void abort (void);
+
+unsigned
+f (void)
+{
+  unsigned x;
+  __asm(".ifnc \"%%ds\", \"%0\"; "
+	".ifnc \"%%es\", \"%0\"; "
+	".err; "
+	".endif; "
+	".endif"
+    : "=Q" (x) : "0" (0x1337));
+  return x;
+}
+
+int
+main (void)
+{
+  if (f () != 0x1337)
+    abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/seg-reg-2.c b/gcc/testsuite/gcc.target/ia16/seg-reg-2.c
new file mode 100644
index 0000000..6d6e53e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/seg-reg-2.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-options "-O3 -fno-inline --save-temps" } */
+
+/* Test that the "e" register constraint works properly.  */
+
+void abort (void);
+
+int
+f (void)
+{
+  int x;
+  __asm(".ifnc \"%%es\", \"%0\"; "
+	".err; "
+	".endif"
+    : "=e" (x) : "0" (0xbe3f));
+  return x;
+}
+
+int
+main (void)
+{
+  if (f () != 0xbe3f)
+    abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/seg-reloc-1.c b/gcc/testsuite/gcc.target/ia16/seg-reloc-1.c
new file mode 100644
index 0000000..1a8d952
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/seg-reloc-1.c
@@ -0,0 +1,55 @@
+/* { dg-do run } */
+/* { dg-options "-Os -mcmodel=small --save-temps" } */
+
+/* Test that MZ relocations with addends link and work properly under the
+   small code model.  This tests for an issue reported by Bart Oldeman ---
+   https://github.com/tkchia/gcc-ia16/issues/22 .  */
+
+void abort (void);
+int puts (const char *);
+extern int errno;
+
+static unsigned
+cs (void)
+{
+  unsigned x;
+  __asm ("movw %%cs, %0" : "=r" (x));
+  return x;
+}
+
+static unsigned
+ss (void)
+{
+  unsigned x;
+  __asm ("movw %%ss, %0" : "=r" (x));
+  return x;
+}
+
+int
+main (int argc, char **argv, char **envp)
+{
+  unsigned p, q, r, s;
+
+  __asm ("movw $main@SEGMENT16+0x674e, %0" : "=r" (p));
+
+  if (p != cs () + 0x674e)
+    abort ();
+
+  __asm ("movw $main@SEGMENT16-0x2329, %0" : "=r" (q));
+
+  if (q != cs () - 0x2329)
+    abort ();
+
+  __asm ("movw $errno@SEGMENT16+0x3ded, %0" : "=r" (r));
+
+  if (r != ss () + 0x3ded)
+    abort ();
+
+  __asm ("movw $errno@SEGMENT16-0x7973, %0" : "=r" (s));
+
+  if (s != ss () - 0x7973)
+    abort ();
+
+  puts ("Hello world!");
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/seg-reloc-2.c b/gcc/testsuite/gcc.target/ia16/seg-reloc-2.c
new file mode 100644
index 0000000..12a073a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/seg-reloc-2.c
@@ -0,0 +1,89 @@
+/* { dg-do run } */
+/* { dg-options "-Os -mcmodel=small --save-temps" } */
+
+/* Test that MZ relocations with addends link and work properly under the
+   small code model, even in the presence of far functions and
+   __attribute__ ((far_section)) functions.  */
+
+void abort (void);
+int puts (const char *);
+extern int errno;
+
+/* This should go in the same segment as main ().  */
+__attribute__ ((noinline))
+static unsigned
+cs (void) __far
+{
+  unsigned x;
+  __asm volatile ("movw %%cs, %0 # 1" : "=r" (x) : : "memory");
+  return x;
+}
+
+/* This should _not_ go in the same segment as main ().  */
+__attribute__ ((noinline, far_section))
+static unsigned
+other_cs (void) __far
+{
+  unsigned x;
+  __asm volatile ("movw %%cs, %0 # 2" : "=r" (x) : : "memory");
+  return x;
+}
+
+static unsigned
+ss (void)
+{
+  unsigned x;
+  __asm volatile ("movw %%ss, %0" : "=r" (x) : : "memory");
+  return x;
+}
+
+int
+main (int argc, char **argv, char **envp)
+{
+  unsigned p, q, r, s, t, u;
+
+  __asm ("movw $main@SEGMENT16+0x674e, %0" : "=r" (p));
+
+  if (p != cs () + 0x674e)
+    abort ();
+  if (p == other_cs () + 0x674e)
+    abort ();
+
+  __asm ("movw $main@SEGMENT16-0x2329, %0" : "=r" (q));
+
+  if (q != cs () - 0x2329)
+    abort ();
+  if (q == other_cs () - 0x2329)
+    abort ();
+
+  __asm ("movw $other_cs@SEGMENT16+0x0e42, %0" : "=r" (r));
+
+  if (r != other_cs () + 0x0e42)
+    abort ();
+  if (r == cs () + 0x0e42)
+    abort ();
+
+  __asm ("movw $other_cs@SEGMENT16-0x300c, %0" : "=r" (s));
+
+  if (s != other_cs () - 0x300c)
+    abort ();
+  if (s == cs () - 0x300c)
+    abort ();
+
+  __asm ("movw $errno@SEGMENT16+0x3ded, %0" : "=r" (t));
+
+  if (t != ss () + 0x3ded)
+    abort ();
+
+  __asm ("movw $errno@SEGMENT16-0x7973, %0" : "=r" (u));
+
+  if (u != ss () - 0x7973)
+    abort ();
+
+  puts ("Hello world!");
+  return 0;
+}
+
+/* Make sure we call other_cs () through `lcall' instructions.  */
+/* { dg-final { scan-assembler "lcall\[ \\t\]\\\$.*,\[ \\t]\\\$other_cs" } } */
+/* { dg-final { scan-assembler-not "\[^l\]call\[ \\t\]other_cs" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/target-macros-1.c b/gcc/testsuite/gcc.target/ia16/target-macros-1.c
new file mode 100644
index 0000000..351f058
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/target-macros-1.c
@@ -0,0 +1,66 @@
+/* { dg-do compile } */
+/* { dg-options "-march=any" } */
+
+/* Test whether architecture-specific macros are defined and undefined
+   correctly when `-march=any' is specified.  */
+
+/* These macros absolutely must be undefined.  */
+#ifdef __IA16_FEATURE_SHIFT_IMM
+# error
+#endif
+#ifdef __IA16_FEATURE_PUSH_IMM
+# error
+#endif
+#ifdef __IA16_FEATURE_IMUL_IMM
+# error
+#endif
+#ifdef __IA16_FEATURE_PUSHA
+# error
+#endif
+#ifdef __IA16_FEATURE_ENTER_LEAVE
+# error
+#endif
+#ifdef __IA16_FEATURE_SHIFT_MASKED
+# error
+#endif
+#ifdef __IA16_FEATURE_AAD_IMM
+# error
+#endif
+#ifdef __IA16_FEATURE_FSTSW_AX
+# error
+#endif
+#ifdef __IA16_ARCH_ANY_186
+# error
+#endif
+#ifdef __IA16_ARCH_I8086
+# error
+#endif
+#ifdef __IA16_ARCH_I8088
+# error
+#endif
+#ifdef __IA16_ARCH_NEC_V30
+# error
+#endif
+#ifdef __IA16_ARCH_NEC_V20
+# error
+#endif
+#ifdef __IA16_ARCH_I80186
+# error
+#endif
+#ifdef __IA16_ARCH_I80188
+# error
+#endif
+#ifdef __IA16_ARCH_I80286
+# error
+#endif
+
+/* These macros absolutely must be defined.  */
+#ifndef __IA16_ARCH_ANY
+# error
+#endif
+
+int
+main (void)
+{
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/target-macros-2.c b/gcc/testsuite/gcc.target/ia16/target-macros-2.c
new file mode 100644
index 0000000..e82b31c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/target-macros-2.c
@@ -0,0 +1,63 @@
+/* { dg-do compile } */
+/* { dg-options "-march=i8086" } */
+
+/* Test whether architecture-specific macros are defined and undefined
+   correctly when `-march=i8086' is specified.  */
+
+/* These macros absolutely must be undefined.  */
+#ifdef __IA16_FEATURE_SHIFT_IMM
+# error
+#endif
+#ifdef __IA16_FEATURE_PUSH_IMM
+# error
+#endif
+#ifdef __IA16_FEATURE_IMUL_IMM
+# error
+#endif
+#ifdef __IA16_FEATURE_PUSHA
+# error
+#endif
+#ifdef __IA16_FEATURE_ENTER_LEAVE
+# error
+#endif
+#ifdef __IA16_FEATURE_SHIFT_MASKED
+# error
+#endif
+#ifdef __IA16_FEATURE_FSTSW_AX
+# error
+#endif
+#ifdef __IA16_ARCH_ANY_186
+# error
+#endif
+#ifdef __IA16_ARCH_NEC_V30
+# error
+#endif
+#ifdef __IA16_ARCH_NEC_V20
+# error
+#endif
+#ifdef __IA16_ARCH_I80186
+# error
+#endif
+#ifdef __IA16_ARCH_I80188
+# error
+#endif
+#ifdef __IA16_ARCH_I80286
+# error
+#endif
+
+/* These macros absolutely must be defined.  */
+#ifndef __IA16_FEATURE_AAD_IMM
+# error
+#endif
+#ifndef __IA16_ARCH_I8086
+# error
+#endif
+
+/* (Other macros such as __IA16_ARCH_I8088 may be either defined or
+   undefined without affecting the correctness of operations too much...) */
+
+int
+main (void)
+{
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/target-macros-3.c b/gcc/testsuite/gcc.target/ia16/target-macros-3.c
new file mode 100644
index 0000000..54da505
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/target-macros-3.c
@@ -0,0 +1,57 @@
+/* { dg-do compile } */
+/* { dg-options "-march=any_186" } */
+
+/* Test whether architecture-specific macros are defined and undefined
+   correctly when `-march=any_186' is specified.  */
+
+/* These macros absolutely must be undefined.  */
+#ifdef __IA16_FEATURE_SHIFT_MASKED
+# error
+#endif
+#ifdef __IA16_FEATURE_AAD_IMM
+# error
+#endif
+#ifdef __IA16_FEATURE_FSTSW_AX
+# error
+#endif
+#ifdef __IA16_ARCH_NEC_V30
+# error
+#endif
+#ifdef __IA16_ARCH_NEC_V20
+# error
+#endif
+#ifdef __IA16_ARCH_I80186
+# error
+#endif
+#ifdef __IA16_ARCH_I80188
+# error
+#endif
+#ifdef __IA16_ARCH_I80286
+# error
+#endif
+
+/* These macros absolutely must be defined.  */
+#ifndef __IA16_FEATURE_SHIFT_IMM
+# error
+#endif
+#ifndef __IA16_FEATURE_PUSH_IMM
+# error
+#endif
+#ifndef __IA16_FEATURE_IMUL_IMM
+# error
+#endif
+#ifndef __IA16_FEATURE_PUSHA
+# error
+#endif
+#ifndef __IA16_FEATURE_ENTER_LEAVE
+# error
+#endif
+#ifndef __IA16_ARCH_ANY_186
+# error
+#endif
+
+int
+main (void)
+{
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/target-macros-4.c b/gcc/testsuite/gcc.target/ia16/target-macros-4.c
new file mode 100644
index 0000000..3eb342e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/target-macros-4.c
@@ -0,0 +1,48 @@
+/* { dg-do compile } */
+/* { dg-options "-march=i80286" } */
+
+/* Test whether architecture-specific macros are defined and undefined
+   correctly when `-march=i80286' is specified.  */
+
+/* These macros absolutely must be undefined.  */
+#ifdef __IA16_ARCH_NEC_V30
+# error
+#endif
+#ifdef __IA16_ARCH_NEC_V20
+# error
+#endif
+
+/* These macros absolutely must be defined.  */
+#ifndef __IA16_FEATURE_SHIFT_IMM
+# error
+#endif
+#ifndef __IA16_FEATURE_PUSH_IMM
+# error
+#endif
+#ifndef __IA16_FEATURE_IMUL_IMM
+# error
+#endif
+#ifndef __IA16_FEATURE_PUSHA
+# error
+#endif
+#ifndef __IA16_FEATURE_ENTER_LEAVE
+# error
+#endif
+#ifndef __IA16_FEATURE_SHIFT_MASKED
+# error
+#endif
+#ifndef __IA16_FEATURE_AAD_IMM
+# error
+#endif
+#ifndef __IA16_FEATURE_FSTSW_AX
+# error
+#endif
+#ifndef __IA16_ARCH_I80286
+# error
+#endif
+
+int
+main (void)
+{
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/asm-1.c b/gcc/testsuite/gcc.target/ia16/torture/asm-1.c
new file mode 100644
index 0000000..760c811
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/asm-1.c
@@ -0,0 +1,20 @@
+/* { dg-do assemble } */
+/* { dg-skip-if "" lto } */
+/* { dg-xfail-if "" *-*-* } */
+/* { dg-options "--std=gnu11 --save-temps" } */
+
+/* XFAIL: GCC should not treat e.g. "ax" in the clobber list as meaning that
+   only %al is clobbered.
+
+   I found this bug in gcc-ia16 20180822, while fixing another bug in FreeDOS
+   command.com (https://github.com/FDOS/freecom/pull/2#event-1808796470).
+   -- tkchia  */
+
+void
+close_fd (int fd)
+{
+  /* This should fail with "`asm' operand has impossible constraints".  */
+  __asm volatile ("int $0x21" : /* no outputs */
+			      : "Rah" ((char) 0x3e), "b" (fd)
+			      : "ax");
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/attribute-1.c b/gcc/testsuite/gcc.target/ia16/torture/attribute-1.c
new file mode 100644
index 0000000..1fe25eb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/attribute-1.c
@@ -0,0 +1,11 @@
+/* { dg-do assemble } */
+/* { dg-xfail-if "" *-*-* } */
+/* { dg-options "--std=gnu11 --save-temps" } */
+
+/* XFAIL: the `cdecl' and `stdcall' attributes do not mix.  */
+
+__attribute__ ((cdecl, stdcall)) unsigned
+inc (unsigned x)
+{
+  return x + 1;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/attribute-2.c b/gcc/testsuite/gcc.target/ia16/torture/attribute-2.c
new file mode 100644
index 0000000..01e9f8a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/attribute-2.c
@@ -0,0 +1,11 @@
+/* { dg-do assemble } */
+/* { dg-xfail-if "" *-*-* } */
+/* { dg-options "--std=gnu11 --save-temps" } */
+
+/* XFAIL: the `cdecl' and `stdcall' attributes do not mix.  */
+
+__attribute__ ((stdcall, cdecl)) unsigned
+inc (unsigned x)
+{
+  return x + 1;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/attribute-abi-ds-1.c b/gcc/testsuite/gcc.target/ia16/torture/attribute-abi-ds-1.c
new file mode 100644
index 0000000..fa48e53
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/attribute-abi-ds-1.c
@@ -0,0 +1,80 @@
+/* { dg-options "-std=gnu11 -fno-inline --save-temps" } */
+/* { dg-do run } */
+
+/* Test that the `assume_ds_data' and `no_assume_ds_data' attributes work
+   properly under `-mcallee-assume-ds-data-segment'.  */
+
+int puts (const char *);
+void abort (void);
+
+volatile int qux = 1;
+
+__attribute__ ((assume_ds_data)) void
+foo (unsigned p)
+{
+  qux = 10;
+  __asm volatile ("# 1" : : "Rds" (__builtin_ia16_selector (p)));
+  qux = 11;
+}
+
+__attribute__ ((no_assume_ds_data)) void
+bar (unsigned p)
+{
+  qux = 6;
+
+  foo (p);
+
+  if (qux != 11)
+    abort ();
+  qux = 7;
+
+  __asm volatile ("# 2" : : "Rds" (__builtin_ia16_selector (p)));
+
+  if (qux != 7)
+    abort ();
+  qux = 8;
+
+  foo (p);
+
+  if (qux != 11)
+    abort ();
+  qux = 9;
+}
+
+void
+baz (unsigned p)
+{
+  if (qux != 1)
+    abort ();
+  qux = 2;
+
+  bar (p);
+
+  if (qux != 9)
+    abort ();
+  qux = 3;
+
+  __asm volatile ("# 3" : : "Rds" (__builtin_ia16_selector (p)));
+
+  if (qux != 3)
+    abort ();
+  qux = 4;
+
+  bar (p);
+
+  if (qux != 9)
+    abort ();
+  qux = 5;
+}
+
+int
+main (void)
+{
+  baz (0xc000);
+
+  if (qux != 5)
+    abort ();
+
+  puts ("Hello world!");
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/attribute-abi-ds-2.c b/gcc/testsuite/gcc.target/ia16/torture/attribute-abi-ds-2.c
new file mode 100644
index 0000000..06ebadf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/attribute-abi-ds-2.c
@@ -0,0 +1,80 @@
+/* { dg-options "-std=gnu11 -mno-callee-assume-ds-data-segment -fno-inline -fno-builtin-puts -fno-builtin-abort --save-temps" } */
+/* { dg-do run } */
+
+/* Test that the `assume_ds_data' and `no_assume_ds_data' attributes work
+   properly under `-mno-callee-assume-ds-data-segment'.  */
+
+int puts (const char *) __attribute__ ((assume_ds_data));
+void abort (void) __attribute__ ((assume_ds_data));
+
+volatile int qux = 1;
+
+__attribute__ ((assume_ds_data)) void
+foo (unsigned p)
+{
+  qux = 10;
+  __asm volatile ("# 1" : : "Rds" (__builtin_ia16_selector (p)));
+  qux = 11;
+}
+
+__attribute__ ((no_assume_ds_data)) void
+bar (unsigned p)
+{
+  qux = 6;
+
+  foo (p);
+
+  if (qux != 11)
+    abort ();
+  qux = 7;
+
+  __asm volatile ("# 2" : : "Rds" (__builtin_ia16_selector (p)));
+
+  if (qux != 7)
+    abort ();
+  qux = 8;
+
+  foo (p);
+
+  if (qux != 11)
+    abort ();
+  qux = 9;
+}
+
+void
+baz (unsigned p)
+{
+  if (qux != 1)
+    abort ();
+  qux = 2;
+
+  bar (p);
+
+  if (qux != 9)
+    abort ();
+  qux = 3;
+
+  __asm volatile ("# 3" : : "Rds" (__builtin_ia16_selector (p)));
+
+  if (qux != 3)
+    abort ();
+  qux = 4;
+
+  bar (p);
+
+  if (qux != 9)
+    abort ();
+  qux = 5;
+}
+
+__attribute__ ((assume_ds_data)) int
+main (void)
+{
+  baz (0xc000);
+
+  if (qux != 5)
+    abort ();
+
+  puts ("Hello world!");
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/attribute-abi-ds-3.c b/gcc/testsuite/gcc.target/ia16/torture/attribute-abi-ds-3.c
new file mode 100644
index 0000000..bd47258
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/attribute-abi-ds-3.c
@@ -0,0 +1,74 @@
+/* { dg-options "-ffixed-ds -std=gnu11 -Wall -fno-inline --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that a warning is issued when an `no_assume_ds_data' function calls
+   an `assume_ds_data' function and %ds is a fixed register.  */
+
+int puts (const char *);
+void abort (void);
+
+volatile int qux = 1;
+
+__attribute__ ((assume_ds_data)) void
+foo (unsigned p)
+{
+  qux = 10;
+  __asm volatile ("# 1" : : "e" (__builtin_ia16_selector (p)));
+  qux = 11;
+}
+
+__attribute__ ((no_assume_ds_data)) void
+bar (unsigned p)
+{
+  qux = 6;
+
+  foo (p);	/* { dg-warning "%ds is fixed" } */
+
+  if (qux != 11)
+    abort ();	/* { dg-warning "%ds is fixed" } */
+  qux = 7;
+
+  __asm volatile ("# 2" : : "e" (__builtin_ia16_selector (p)));
+  qux = 8;
+
+  foo (p);	/* { dg-warning "%ds is fixed" } */
+  qux = 9;
+}
+
+void
+baz (unsigned p)
+{
+  if (qux != 1)
+    abort ();
+  qux = 2;
+
+  bar (p);
+
+  if (qux != 9)
+    abort ();
+  qux = 3;
+
+  __asm volatile ("# 3" : : "e" (__builtin_ia16_selector (p)));
+
+  if (qux != 3)
+    abort ();
+  qux = 4;
+
+  bar (p);
+
+  if (qux != 9)
+    abort ();
+  qux = 5;
+}
+
+int
+main (void)
+{
+  baz (0xc000);
+
+  if (qux != 5)
+    abort ();
+
+  puts ("Hello world!");
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/attribute-abi-ds-4.c b/gcc/testsuite/gcc.target/ia16/torture/attribute-abi-ds-4.c
new file mode 100644
index 0000000..384d19c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/attribute-abi-ds-4.c
@@ -0,0 +1,68 @@
+/* { dg-options "-std=gnu11 -fcall-saved-ds -fno-inline -Wall --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that the `assume_ds_data' and `no_assume_ds_data' attributes trigger
+   warnings when %ds is a call-saved register.  */
+
+int puts (const char *);
+void abort (void);
+
+volatile int qux = 1;
+
+__attribute__ ((assume_ds_data)) void
+foo (unsigned p)
+{			/* { dg-warning "%ds is a call-saved register" } */
+  qux = 10;
+  __asm volatile ("# 1" : : "Rds" (__builtin_ia16_selector (p)));
+  qux = 11;
+}
+
+__attribute__ ((no_assume_ds_data)) void
+bar (unsigned p)
+{			/* { dg-warning "%ds is a call-saved register" } */
+  qux = 6;
+
+  foo (p);
+
+  if (qux != 11)
+    abort ();
+  qux = 7;
+
+  __asm volatile ("# 2" : : "Rds" (__builtin_ia16_selector (p)));
+
+  if (qux != 7)
+    abort ();
+  qux = 8;
+
+  foo (p);
+
+  if (qux != 11)
+    abort ();
+  qux = 9;
+}
+
+void
+baz (unsigned p)
+{
+  if (qux != 1)
+    abort ();
+  qux = 2;
+
+  bar (p);
+
+  if (qux != 9)
+    abort ();
+  qux = 3;
+
+  __asm volatile ("# 3" : : "Rds" (__builtin_ia16_selector (p)));
+
+  if (qux != 3)
+    abort ();
+  qux = 4;
+
+  bar (p);
+
+  if (qux != 9)
+    abort ();
+  qux = 5;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/attribute-incompat-1.c b/gcc/testsuite/gcc.target/ia16/torture/attribute-incompat-1.c
new file mode 100644
index 0000000..83bdc31
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/attribute-incompat-1.c
@@ -0,0 +1,72 @@
+/* { dg-options "-std=gnu11 -Wall --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that warnings are issued when one tries to assign a function pointer
+   to a pointer variable with incompatible function attributes.
+
+   Also check if certain pairs of different type attribute sets which should
+   be compatible are, in fact, considered compatible.  */
+
+#if defined __IA16_CALLCVT_CDECL
+int (*p1) (int) __attribute__ ((cdecl));
+int (*p2) (int) __attribute__ ((stdcall));
+int (*p3) (int) __attribute__ ((regparmcall));
+#elif defined __IA16_CALLCVT_STDCALL
+int (*p1) (int) __attribute__ ((stdcall));
+int (*p2) (int) __attribute__ ((regparmcall));
+int (*p3) (int) __attribute__ ((cdecl));
+#else
+int (*p1) (int) __attribute__ ((regparmcall));
+int (*p2) (int) __attribute__ ((cdecl));
+int (*p3) (int) __attribute__ ((stdcall));
+#endif
+int (*p4) (int) __attribute__ ((assume_ds_data));
+int (*p5) (int) __attribute__ ((no_assume_ds_data));
+int (*p6) (int) __far;
+int (*p7) (int) __far __attribute__ ((near_section));
+int (*p8) (int) __far __attribute__ ((far_section));
+
+void f1 (int (*p) (int))
+{
+  p1 = p;
+}
+
+void f2 (int (*p) (int))
+{
+  p2 = p;  /* { dg-warning "assignment from incompatible pointer type" } */
+}
+
+void f3 (int (*p) (int))
+{
+  p3 = p;  /* { dg-warning "assignment from incompatible pointer type" } */
+}
+
+void f4 (int (*p) (int))
+{
+  p4 = p;
+}
+
+void f5 (int (*p) (int))
+{
+  p5 = p;  /* { dg-warning "assignment from incompatible pointer type" } */
+}
+
+void f6 (int (*p) (int) __far)
+{
+  p6 = p;
+}
+
+void f6a (int (*p) (int) __far __attribute__ ((far_section)))
+{
+  p6 = p;
+}
+
+void f7 (int (*p) (int) __far)
+{
+  p7 = p;  /* { dg-warning "assignment from incompatible pointer type" } */
+}
+
+void f8 (int (*p) (int) __far)
+{
+  p8 = p;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/attribute-ignore-1.c b/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/attribute-ignore-1.c
new file mode 100644
index 0000000..094aaf9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/attribute-ignore-1.c
@@ -0,0 +1,39 @@
+/* { dg-options "-std=gnu11 -Wall --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that the `near_section' and `far_section' attributes are ignored for
+   non-far function declarations.  */
+
+int (*p1) (int)
+  __attribute__ ((near_section));  /* { dg-warning "directive ignored" } */
+int (*p2) (int)
+  __attribute__ ((far_section));   /* { dg-warning "directive ignored" } */
+int __far (*p3) (int)
+  __attribute__ ((near_section));  /* { dg-bogus "directive ignored" } */
+int __far (*p4) (int)
+  __attribute__ ((far_section));   /* { dg-bogus "directive ignored" } */
+
+void
+f1 (int (*p) (int))
+{
+  p1 = p;  /* { dg-bogus "assignment from incompatible pointer type" } */
+}
+
+void
+f2 (int (*p) (int))
+{
+  p2 = p;  /* { dg-bogus "assignment from incompatible pointer type" } */
+}
+void
+f3 (int (*p) (int)
+    __attribute__ ((far_section)))  /* { dg-warning "directive ignored" } */
+{
+  p1 = p;  /* { dg-bogus "assignment from incompatible pointer type" } */
+}
+
+void
+f4 (int (*p) (int)
+    __attribute__ ((near_section)))  /* { dg-warning "directive ignored" } */
+{
+  p2 = p;  /* { dg-bogus "assignment from incompatible pointer type" } */
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/far-addr-func-10.c b/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/far-addr-func-10.c
new file mode 100644
index 0000000..f5ddeaa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/far-addr-func-10.c
@@ -0,0 +1,24 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that far function calls work even with when the far function pointers
+   hide out in weird places.  */
+
+struct s
+{
+  double d;
+  union
+    {
+      int (*fpf) (long) __far;
+      int (*npf) (long);
+    } u;
+  int i;
+};
+
+int
+foo (struct s * (*bar) (float), float baz, long qux)
+{
+  return bar (baz)->u.fpf (qux);
+}
+
+/* { dg-final { scan-assembler-times "lcall\[ \\t\]\\*" 1 } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/far-addr-func-8.c b/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/far-addr-func-8.c
new file mode 100644
index 0000000..ef33d9f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/far-addr-func-8.c
@@ -0,0 +1,18 @@
+/* { dg-options "-std=gnu11 -mno-far-function-if-far-return-type --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that we do _not_ consider a function to be far, even if the return
+   type is far, if the `-mfar-function-if-far-return-type' option is
+   explicitly turned off.  */
+
+extern int foo (long) __far __attribute__ ((near_section));
+
+int __far
+bar (long x)
+{
+  return foo (x) + 1;
+}
+
+/* { dg-final { scan-assembler "ret" } } */
+/* { dg-final { scan-assembler-not "lret" } } */
+/* { dg-final { scan-assembler "pushw\\t%cs" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/far-addr-func-9.c b/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/far-addr-func-9.c
new file mode 100644
index 0000000..5f8ed40
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/far-addr-func-9.c
@@ -0,0 +1,18 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that a __far immediately after an old-style function declarator in
+   a function definition is _not_ interpreted as saying that the function
+   itself is far.  */
+
+void
+swap (x, y)
+  __far int *x, *y;
+{
+  int t = *x;
+  *x = *y;
+  *y = t;
+}
+
+/* { dg-final { scan-assembler "ret" } } */
+/* { dg-final { scan-assembler-not "lret" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/ia16-torture-cmodel-near-text.exp b/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/ia16-torture-cmodel-near-text.exp
new file mode 100644
index 0000000..c2388ae
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/ia16-torture-cmodel-near-text.exp
@@ -0,0 +1,178 @@
+#   Copyright (C) 2008-2019 Free Software Foundation, Inc.
+
+# 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 3 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 GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `gcc-dg.exp' driver, looping over
+# optimization options.
+
+# Exit immediately if this isn't an IA-16 target.
+if { ![istarget ia16-*-*] } then {
+  return
+}
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+    set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# Initialize `dg'.
+dg-init
+
+    set IA16_TORTURE_OPTIONS [list \
+	{ -O0 } \
+	{ -O0 -mprotected-mode } \
+	{ -O0 -mrtd } \
+	{ -O0 -mregparmcall } \
+	{ -O0 -mcmodel=small } \
+	{ -O0 -mcmodel=small -mmsdos-handle-v1 } \
+	{ -O0 -mcmodel=small -mprotected-mode } \
+	{ -O0 -mcmodel=small -mrtd } \
+	{ -O0 -mcmodel=small -mrtd -mmsdos-handle-v1 } \
+	{ -O0 -mcmodel=small -mregparmcall } \
+	{ -O0 -mcmodel=small -mregparmcall -mmsdos-handle-v1 } \
+	{ -O1 } \
+	{ -O1 -funroll-loops } \
+	{ -O1 -frename-registers } \
+	{ -O1 -funroll-loops -fno-rename-registers } \
+	{ -O1 -mrtd } \
+	{ -O1 -mregparmcall } \
+	{ -O1 -mprotected-mode } \
+	{ -O1 -mprotected-mode -funroll-loops } \
+	{ -O1 -mprotected-mode -frename-registers } \
+	{ -O1 -mprotected-mode -funroll-loops -fno-rename-registers } \
+	{ -O1 -mprotected-mode -mrtd } \
+	{ -O1 -mprotected-mode -mregparmcall } \
+	{ -O1 -mcmodel=small } \
+	{ -O1 -mcmodel=small -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -funroll-loops } \
+	{ -O1 -mcmodel=small -frename-registers } \
+	{ -O1 -mcmodel=small -funroll-loops -fno-rename-registers } \
+	{ -O1 -mcmodel=small -mrtd } \
+	{ -O1 -mcmodel=small -mrtd -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -mregparmcall } \
+	{ -O1 -mcmodel=small -mregparmcall -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -mprotected-mode } \
+	{ -O1 -mcmodel=small -mprotected-mode -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -mprotected-mode -funroll-loops } \
+	{ -O1 -mcmodel=small -mprotected-mode -frename-registers } \
+	{ -O1 -mcmodel=small -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O1 -mcmodel=small -mprotected-mode -mrtd } \
+	{ -O1 -mcmodel=small -mprotected-mode -mrtd -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -mprotected-mode -mregparmcall } \
+	{ -O1 -mcmodel=small -mprotected-mode -mregparmcall \
+	  -mmsdos-handle-v1 } \
+	{ -O2 } \
+	{ -O2 -funroll-loops } \
+	{ -O2 -frename-registers } \
+	{ -O2 -funroll-loops -fno-rename-registers } \
+	{ -O2 -mrtd } \
+	{ -O2 -mregparmcall } \
+	{ -O2 -mprotected-mode } \
+	{ -O2 -mprotected-mode -funroll-loops } \
+	{ -O2 -mprotected-mode -frename-registers } \
+	{ -O2 -mprotected-mode -funroll-loops -fno-rename-registers } \
+	{ -O2 -mprotected-mode -mrtd } \
+	{ -O2 -mprotected-mode -mregparmcall } \
+	{ -O2 -mcmodel=small } \
+	{ -O2 -mcmodel=small -funroll-loops } \
+	{ -O2 -mcmodel=small -frename-registers } \
+	{ -O2 -mcmodel=small -funroll-loops -fno-rename-registers } \
+	{ -O2 -mcmodel=small -mrtd } \
+	{ -O2 -mcmodel=small -mregparmcall } \
+	{ -O2 -mcmodel=small -mprotected-mode } \
+	{ -O2 -mcmodel=small -mprotected-mode -funroll-loops } \
+	{ -O2 -mcmodel=small -mprotected-mode -frename-registers } \
+	{ -O2 -mcmodel=small -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O2 -mcmodel=small -mprotected-mode -mrtd } \
+	{ -O2 -mcmodel=small -mprotected-mode -mregparmcall } \
+	{ -Os } \
+	{ -Os -funroll-loops } \
+	{ -Os -frename-registers } \
+	{ -Os -funroll-loops -fno-rename-registers } \
+	{ -Os -mrtd } \
+	{ -Os -mregparmcall } \
+	{ -Os -flto } \
+	{ -Os -finline-functions } \
+	{ -Os -mprotected-mode } \
+	{ -Os -mprotected-mode -funroll-loops } \
+	{ -Os -mprotected-mode -frename-registers } \
+	{ -Os -mprotected-mode -funroll-loops -fno-rename-registers } \
+	{ -Os -mprotected-mode -mrtd } \
+	{ -Os -mprotected-mode -mregparmcall } \
+	{ -Os -mprotected-mode -flto } \
+	{ -Os -mprotected-mode -finline-functions } \
+	{ -Os -mcmodel=small } \
+	{ -Os -mcmodel=small -funroll-loops } \
+	{ -Os -mcmodel=small -frename-registers } \
+	{ -Os -mcmodel=small -funroll-loops -fno-rename-registers } \
+	{ -Os -mcmodel=small -mrtd } \
+	{ -Os -mcmodel=small -mregparmcall } \
+	{ -Os -mcmodel=small -flto } \
+	{ -Os -mcmodel=small -finline-functions } \
+	{ -Os -mcmodel=small -mprotected-mode } \
+	{ -Os -mcmodel=small -mprotected-mode -funroll-loops } \
+	{ -Os -mcmodel=small -mprotected-mode -frename-registers } \
+	{ -Os -mcmodel=small -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -Os -mcmodel=small -mprotected-mode -mrtd } \
+	{ -Os -mcmodel=small -mprotected-mode -mregparmcall } \
+	{ -Os -mcmodel=small -mprotected-mode -flto } \
+	{ -Os -mcmodel=small -mprotected-mode -finline-functions } \
+	{ -O3 } \
+	{ -O3 -funroll-loops } \
+	{ -O3 -frename-registers } \
+	{ -O3 -funroll-loops -fno-rename-registers } \
+	{ -O3 -mrtd } \
+	{ -O3 -mregparmcall } \
+	{ -O3 -mprotected-mode } \
+	{ -O3 -mprotected-mode -funroll-loops } \
+	{ -O3 -mprotected-mode -frename-registers } \
+	{ -O3 -mprotected-mode -funroll-loops -fno-rename-registers } \
+	{ -O3 -mprotected-mode -mrtd } \
+	{ -O3 -mprotected-mode -mregparmcall } \
+	{ -O3 -mcmodel=small } \
+	{ -O3 -mcmodel=small -funroll-loops } \
+	{ -O3 -mcmodel=small -frename-registers } \
+	{ -O3 -mcmodel=small -funroll-loops -fno-rename-registers } \
+	{ -O3 -mcmodel=small -mrtd } \
+	{ -O3 -mcmodel=small -mregparmcall } \
+	{ -O3 -mcmodel=small -mprotected-mode } \
+	{ -O3 -mcmodel=small -mprotected-mode -funroll-loops } \
+	{ -O3 -mcmodel=small -mprotected-mode -frename-registers } \
+	{ -O3 -mcmodel=small -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O3 -mcmodel=small -mprotected-mode -mrtd } \
+	{ -O3 -mcmodel=small -mprotected-mode -mregparmcall } ]
+
+#Initialize use of torture lists. 
+torture-init
+
+set-torture-options $IA16_TORTURE_OPTIONS
+
+
+# Main loop.
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.{\[cS\],cpp}]] "" $DEFAULT_CFLAGS
+
+# Finalize use of torture lists.
+torture-finish
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/no-ss-data-1.c b/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/no-ss-data-1.c
new file mode 100644
index 0000000..567051f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/no-ss-data-1.c
@@ -0,0 +1,76 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-additional-sources "support/no-ss-data-main.S" } */
+/* { dg-do run } */
+
+/* Test that functions with %ss != .data can properly handle initializers of
+   local variables, and `switch' statements with jump tables in %ds.  */
+
+extern void abort (void);
+
+__attribute__ ((no_assume_ss_data, noinline)) static unsigned
+fib (unsigned i)
+{
+  switch (i)
+    {
+    case 0:
+      return 0;
+    case 1:
+    case 2:
+      return 1;
+    case 3:
+      return 2;
+    case 4:
+      return 3;
+    case 5:
+      return 5;
+    case 6:
+      return 8;
+    case 7:
+      return 13;
+    case 8:
+      return 21;
+    case 9:
+      return 34;
+    case 10:
+      return 55;
+    case 11:
+      return 89;
+    case 12:
+      return 144;
+    case 13:
+      return 233;
+    case 14:
+      return 377;
+    case 15:
+      return 610;
+    default:
+      abort ();
+    }
+}
+
+__attribute__ ((no_assume_ss_data)) int
+do_stuff (void)
+{
+  volatile char blah[] = "gaza frequens libycos duxit karthago triumphos";
+  char blurfl[] = "the five boxing wizards jump quickly";
+
+  if (fib (11) != 89)
+    abort ();
+
+  if (blah[fib (8)] != blah[fib (7)])
+    abort ();
+
+  if (blah[fib (9)] != 'g')
+    abort ();
+
+  if (blurfl[fib (9)] != blah[14])
+    abort ();
+
+  return 0;
+}
+
+int
+check_stuff (void)
+{
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/no-ss-data-2.c b/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/no-ss-data-2.c
new file mode 100644
index 0000000..8498b6f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/no-ss-data-2.c
@@ -0,0 +1,31 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-additional-sources "support/no-ss-data-main.S" } */
+/* { dg-do run } */
+
+/* Test that functions with %ss != .data can set and restore %ds properly.  */
+
+extern void abort (void);
+
+volatile unsigned cu_psp = 0;
+
+__attribute__ ((no_assume_ss_data)) int
+do_stuff (void)
+{
+  unsigned bx;
+  __asm volatile ("movw %%ds, %0" : "=b" (bx)
+				  : "Rds" (__builtin_ia16_selector (0x17c3)));
+  cu_psp = bx;
+  __asm volatile ("movw %%es, %0" : "=b" (bx)
+				  : "e" (__builtin_ia16_selector (0xe36d)));
+  cu_psp += bx;
+  return 0;
+}
+
+int
+check_stuff (void)
+{
+  if (cu_psp != 0xfb30)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/support/no-ss-data-main.S b/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/support/no-ss-data-main.S
new file mode 100644
index 0000000..4e4185c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-near-text/support/no-ss-data-main.S
@@ -0,0 +1,55 @@
+/* main () function for __attribute__ ((no_assume_ss_data)) test cases.  */
+
+	.arch	i8086, jumps
+	.code16
+
+	.set	EVIL_STACK_SIZE, 0x400	/* size of away-from-%ds stack */
+
+	.data
+
+cookie:	.hword	0x6bd4			/* cookie value to help us check that
+					   do_stuff () _really_ restores %ds
+					   correctly */
+
+	.bss
+
+	.balign	2
+	.skip	16			/* pad to make sure stack area does
+					   not begin data segment */
+evil_stack_start:
+	.skip	EVIL_STACK_SIZE
+evil_stack_end:
+
+	.text
+
+	.global	main
+main:
+	movw	$evil_stack_start, %ax
+	movw	%ax,	%dx
+	mov	$4,	%cl
+	shrw	%cl,	%dx
+	jz	.fail
+	movw	%ds,	%cx
+	addw	%cx,	%dx
+	andw	$0x000f, %ax
+	addw	$evil_stack_end-evil_stack_start, %ax
+	movw	%sp,	%bx
+	cli
+	movw	%dx,	%ss
+	movw	%ax,	%sp
+	sti
+	pushw	%bx			/* remember old %sp; old %ss = %ds */
+	call	do_stuff
+	testw	%ax,	%ax
+	jnz	.fail
+	popw	%bx
+	pushw	%ds
+	cli
+	popw	%ss
+	movw	%bx,	%sp
+	sti
+	cmpw	$0x6bd4, cookie
+	jnz	.fail
+	jmp	check_stuff
+.fail:
+	call	abort
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-only/attribute-far-section-1.c b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-only/attribute-far-section-1.c
new file mode 100644
index 0000000..b497bab
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-only/attribute-far-section-1.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options "--std=gnu11 -Wall --save-temps" } */
+
+/* Check that far_section -> near function calls work correctly.  */
+
+int printf (const char *, ...);
+int puts (const char *);
+int rand (void);
+
+__attribute__ ((noinline, far_section))
+__far int hello (const char *thang1, const char *thang2)
+{
+  printf ("Hello %s%s %d\n", thang1, thang2, rand ());
+  puts ("w00t!");
+  return 0;
+}
+
+char world[] = "world";
+char mark[] = "!";
+
+int main (void)
+{
+  return hello (world, mark);
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-only/ia16-torture-cmodel-small-only.exp b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-only/ia16-torture-cmodel-small-only.exp
new file mode 100644
index 0000000..d45db1d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-only/ia16-torture-cmodel-small-only.exp
@@ -0,0 +1,122 @@
+#   Copyright (C) 2008-2016 Free Software Foundation, Inc.
+
+# 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 3 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 GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `gcc-dg.exp' driver, looping over
+# optimization options.
+
+# Exit immediately if this isn't an IA-16 target.
+if { ![istarget ia16-*-*] } then {
+  return
+}
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+    set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# Initialize `dg'.
+dg-init
+
+    set IA16_TORTURE_OPTIONS [list \
+	{ -O0 -mcmodel=small } \
+	{ -O0 -mcmodel=small -mmsdos-handle-v1 } \
+	{ -O0 -mcmodel=small -mprotected-mode } \
+	{ -O0 -mcmodel=small -mrtd } \
+	{ -O0 -mcmodel=small -mrtd -mmsdos-handle-v1 } \
+	{ -O0 -mcmodel=small -mregparmcall } \
+	{ -O0 -mcmodel=small -mregparmcall -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small } \
+	{ -O1 -mcmodel=small -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -funroll-loops } \
+	{ -O1 -mcmodel=small -frename-registers } \
+	{ -O1 -mcmodel=small -funroll-loops -fno-rename-registers } \
+	{ -O1 -mcmodel=small -mrtd } \
+	{ -O1 -mcmodel=small -mrtd -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -mregparmcall } \
+	{ -O1 -mcmodel=small -mregparmcall -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -mprotected-mode } \
+	{ -O1 -mcmodel=small -mprotected-mode -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -mprotected-mode -funroll-loops } \
+	{ -O1 -mcmodel=small -mprotected-mode -frename-registers } \
+	{ -O1 -mcmodel=small -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O1 -mcmodel=small -mprotected-mode -mrtd } \
+	{ -O1 -mcmodel=small -mprotected-mode -mrtd -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -mprotected-mode -mregparmcall } \
+	{ -O1 -mcmodel=small -mprotected-mode -mregparmcall \
+	  -mmsdos-handle-v1 } \
+	{ -O2 -mcmodel=small } \
+	{ -O2 -mcmodel=small -funroll-loops } \
+	{ -O2 -mcmodel=small -frename-registers } \
+	{ -O2 -mcmodel=small -funroll-loops -fno-rename-registers } \
+	{ -O2 -mcmodel=small -mrtd } \
+	{ -O2 -mcmodel=small -mregparmcall } \
+	{ -O2 -mcmodel=small -mprotected-mode } \
+	{ -O2 -mcmodel=small -mprotected-mode -funroll-loops } \
+	{ -O2 -mcmodel=small -mprotected-mode -frename-registers } \
+	{ -O2 -mcmodel=small -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O2 -mcmodel=small -mprotected-mode -mrtd } \
+	{ -O2 -mcmodel=small -mprotected-mode -mregparmcall } \
+	{ -Os -mcmodel=small } \
+	{ -Os -mcmodel=small -funroll-loops } \
+	{ -Os -mcmodel=small -frename-registers } \
+	{ -Os -mcmodel=small -funroll-loops -fno-rename-registers } \
+	{ -Os -mcmodel=small -mrtd } \
+	{ -Os -mcmodel=small -mregparmcall } \
+	{ -Os -mcmodel=small -flto } \
+	{ -Os -mcmodel=small -finline-functions } \
+	{ -Os -mcmodel=small -mprotected-mode } \
+	{ -Os -mcmodel=small -mprotected-mode -funroll-loops } \
+	{ -Os -mcmodel=small -mprotected-mode -frename-registers } \
+	{ -Os -mcmodel=small -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -Os -mcmodel=small -mprotected-mode -mrtd } \
+	{ -Os -mcmodel=small -mprotected-mode -mregparmcall } \
+	{ -Os -mcmodel=small -mprotected-mode -flto } \
+	{ -Os -mcmodel=small -mprotected-mode -finline-functions } \
+	{ -O3 -mcmodel=small } \
+	{ -O3 -mcmodel=small -funroll-loops } \
+	{ -O3 -mcmodel=small -frename-registers } \
+	{ -O3 -mcmodel=small -funroll-loops -fno-rename-registers } \
+	{ -O3 -mcmodel=small -mrtd } \
+	{ -O3 -mcmodel=small -mregparmcall } \
+	{ -O3 -mcmodel=small -mprotected-mode } \
+	{ -O3 -mcmodel=small -mprotected-mode -funroll-loops } \
+	{ -O3 -mcmodel=small -mprotected-mode -frename-registers } \
+	{ -O3 -mcmodel=small -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O3 -mcmodel=small -mprotected-mode -mrtd } \
+	{ -O3 -mcmodel=small -mprotected-mode -mregparmcall } ]
+
+#Initialize use of torture lists. 
+torture-init
+
+set-torture-options $IA16_TORTURE_OPTIONS
+
+
+# Main loop.
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.{\[cS\],cpp}]] "" $DEFAULT_CFLAGS
+
+# Finalize use of torture lists.
+torture-finish
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/attribute-3.c b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/attribute-3.c
new file mode 100644
index 0000000..fda149d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/attribute-3.c
@@ -0,0 +1,15 @@
+/* { dg-do assemble } */
+/* { dg-options "--std=gnu11 --save-temps" } */
+
+/* Test that, when a `far_section' function calls a `near_section' function,
+   the resulting call instruction is a far call.  */
+
+unsigned __far foo (unsigned) __attribute__ ((near_section));
+
+__attribute__ ((far_section)) unsigned __far
+bar (unsigned x)
+{
+  return foo (x) + 1;
+}
+
+/* { dg-final { scan-assembler "lcall\[ \\t\].*,\[ \\t\]\\\$foo" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/attribute-4.c b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/attribute-4.c
new file mode 100644
index 0000000..a8afe73
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/attribute-4.c
@@ -0,0 +1,16 @@
+/* { dg-do assemble } */
+/* { dg-options "--std=gnu11 --save-temps" } */
+
+/* Test that, when a `far_section' function does a sibcall to a
+   `near_section' function, the resulting call instruction is a far call or
+   jump.  */
+
+unsigned __far foo (unsigned) __attribute__ ((near_section));
+
+__attribute__ ((far_section)) unsigned __far
+bar (unsigned x)
+{
+  return foo (x + 1);
+}
+
+/* { dg-final { scan-assembler "l(call|jmp)\[ \\t\].*,\[ \\t\]\\\$foo" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-fp-off-1.c b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-fp-off-1.c
new file mode 100644
index 0000000..f06b7ac
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-fp-off-1.c
@@ -0,0 +1,22 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that we can use __builtin_ia16_FP_OFF (.) in a static initializer,
+   on a pointer to an external function.
+
+   This test case is partly taken from the FreeDOS kernel code (in
+   kernel/main.c).  -- tkchia */
+
+#ifndef __BUILTIN_IA16_FP_OFF
+# error
+#endif
+
+void int0_handler (void) __far __attribute__ ((stdcall));
+
+struct vec {
+  unsigned char intno;
+  unsigned handleroff __attribute__ ((packed));
+} vectors[] = { 0, __builtin_ia16_FP_OFF (int0_handler) };
+
+/* { dg-final { scan-assembler "\.hword\[ \\t\]__ia16_alias" { target { ! lto } } } } */
+/* { dg-final { scan-assembler "\.(weakref|set)\[ \\t\]__ia16_alias.*,int0_handler" { target { ! lto } } } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-fp-off-2.c b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-fp-off-2.c
new file mode 100644
index 0000000..ae11ed8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-fp-off-2.c
@@ -0,0 +1,115 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do run } */
+
+/* Test that we can use __builtin_ia16_FP_OFF (.) in a static initializer,
+   on a pointer to an externally visible function defined in the same
+   translation unit.
+
+   This test case is partly taken from the FreeDOS kernel code (in
+   kernel/main.c).  -- tkchia */
+
+#ifndef __BUILTIN_IA16_FP_OFF
+# error
+#endif
+
+__attribute__ ((stdcall, far_section)) void
+int0_handler (void) __far
+{
+  __asm volatile ("# in int 0");
+}
+
+__attribute__ ((stdcall, far_section)) void
+int6_handler (void) __far
+{
+  __asm volatile ("# in int 6");
+}
+
+__attribute__ ((stdcall, far_section)) void
+int19_handler (void) __far
+{
+  __asm volatile ("# in int 19");
+}
+
+__attribute__ ((stdcall, far_section)) void
+int20_handler (void) __far
+{
+  __asm volatile ("# in int 20");
+}
+
+__attribute__ ((stdcall, far_section)) void
+int21_handler (void) __far
+{
+  __asm volatile ("# in int 21");
+}
+
+__attribute__ ((stdcall, far_section)) void
+int24_handler (void) __far
+{
+  __asm volatile ("# in int 24");
+}
+
+__attribute__ ((stdcall, far_section)) void
+int25_handler (void) __far
+{
+  __asm volatile ("# in int 25");
+}
+
+__attribute__ ((stdcall, far_section)) void
+int26_handler (void) __far
+{
+  __asm volatile ("# in int 26");
+}
+
+__attribute__ ((stdcall, far_section)) void
+int27_handler (void) __far
+{
+  __asm volatile ("# in int 27");
+}
+
+struct vec {
+  unsigned char intno;
+  unsigned handleroff __attribute__ ((packed));
+} vectors[] = { { 0x00, __builtin_ia16_FP_OFF (int0_handler) },
+		{ 0x06, __builtin_ia16_FP_OFF (int6_handler) },
+		{ 0x19, __builtin_ia16_FP_OFF (int19_handler) },
+		{ 0x20, __builtin_ia16_FP_OFF (int20_handler) },
+		{ 0x21, __builtin_ia16_FP_OFF (int21_handler) },
+		{ 0x24, __builtin_ia16_FP_OFF (int24_handler) },
+		{ 0x25, __builtin_ia16_FP_OFF (int25_handler) },
+		{ 0x26, __builtin_ia16_FP_OFF (int26_handler) },
+		{ 0x27, __builtin_ia16_FP_OFF (int27_handler) } };
+
+void abort (void);
+
+int
+main (void)
+{
+  if ((void *) vectors[0].handleroff != (void *) int0_handler)
+    abort ();
+
+  if ((void *) vectors[1].handleroff != (void *) int6_handler)
+    abort ();
+
+  if ((void *) vectors[2].handleroff != (void *) int19_handler)
+    abort ();
+
+  if ((void *) vectors[3].handleroff != (void *) int20_handler)
+    abort ();
+
+  if ((void *) vectors[4].handleroff != (void *) int21_handler)
+    abort ();
+
+  if ((void *) vectors[5].handleroff != (void *) int24_handler)
+    abort ();
+
+  if ((void *) vectors[6].handleroff != (void *) int25_handler)
+    abort ();
+
+  if ((void *) vectors[7].handleroff != (void *) int26_handler)
+    abort ();
+
+  if ((void *) vectors[8].handleroff != (void *) int27_handler)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-fp-off-3.c b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-fp-off-3.c
new file mode 100644
index 0000000..e40a387
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-fp-off-3.c
@@ -0,0 +1,33 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do run } */
+
+/* Test that we can use __builtin_ia16_FP_OFF (.) in a static initializer,
+   on a pointer to a locally visible function.
+
+   This test case is partly taken from the FreeDOS kernel code (in
+   kernel/main.c).  -- tkchia */
+
+#ifndef __BUILTIN_IA16_FP_OFF
+# error
+#endif
+
+__attribute__ ((stdcall, far_section)) static void
+int0_handler (void) __far
+{
+}
+
+struct vec {
+  unsigned char intno;
+  unsigned handleroff __attribute__ ((packed));
+} vectors[] = { 0, __builtin_ia16_FP_OFF (int0_handler) };
+
+void abort (void);
+
+int
+main (void)
+{
+  if ((void *) vectors[0].handleroff != (void *) int0_handler)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-fp-off-4.c b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-fp-off-4.c
new file mode 100644
index 0000000..9671d2b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-fp-off-4.c
@@ -0,0 +1,29 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do run } */
+
+/* Test that we can use __builtin_ia16_FP_OFF (.) in a static initializer,
+   on a pointer to an externally visible or locally visible variable.  */
+
+#ifndef __BUILTIN_IA16_FP_OFF
+# error
+#endif
+
+int __far var1;
+static int __far var2;
+
+unsigned var1_off = __builtin_ia16_FP_OFF (&var1);
+unsigned var2_off = __builtin_ia16_FP_OFF (&var2);
+
+void abort (void);
+
+int
+main (void)
+{
+  if ((void *) var1_off != (void *) &var1)
+    abort ();
+
+  if ((void *) var2_off != (void *) &var2)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-fp-off-5.c b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-fp-off-5.c
new file mode 100644
index 0000000..7fc049d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-fp-off-5.c
@@ -0,0 +1,13 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that we can use __builtin_ia16_FP_OFF (.) in a static initializer,
+   on a pointer to an external variable.  */
+
+#ifndef __BUILTIN_IA16_FP_OFF
+# error
+#endif
+
+extern int __far var1;
+
+unsigned var1_off = __builtin_ia16_FP_OFF (&var1);
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-func-11.c b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-func-11.c
new file mode 100644
index 0000000..d0972ea
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-func-11.c
@@ -0,0 +1,19 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that a call from a module to a far function (sans `__attribute__
+   ((near_section))') outside the module is done with an `lcall'
+   instruction.
+
+   (The code requires the small memory model or above, as the `lcall' will
+   very likely need a segment relocation.) */
+
+extern int foo (long) __far;
+
+int
+bar (long x)
+{
+  return foo (x) + 1;
+}
+
+/* { dg-final { scan-assembler "lcall\[ \\t\].*,\[ \\t\]\\\$foo" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-func-12.c b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-func-12.c
new file mode 100644
index 0000000..4775b01
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-func-12.c
@@ -0,0 +1,19 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that a call from a module to a far function (sans `__attribute__
+   ((near_section))') outside the module is done with an `lcall' or `ljmp'
+   instruction, if the call can be made a sibcall.
+
+   (The code requires the small memory model or above, as the `lcall' or
+   `ljmp' will very likely need a segment relocation.) */
+
+extern int foo (long) __far;
+
+int
+bar (long x)
+{
+  return foo (x * x);
+}
+
+/* { dg-final { scan-assembler "l(call|jmp)\[ \\t\].*,\[ \\t\]\\\$foo" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-func-16.c b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-func-16.c
new file mode 100644
index 0000000..9aa0e90
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-func-16.c
@@ -0,0 +1,17 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that, under the default -mfar-function-if-far-return-type setting,
+   a far function returning void declared using the classical syntax does
+   not give a "function with qualified void return type called" warning.
+
+   Reported by Bart Oldeman --- https://github.com/tkchia/gcc-ia16/issues/25 .
+ */
+
+extern void __far foo (void);
+
+void
+bar (void)
+{
+  foo ();	/* { dg-bogus "function with qualified void return type" } */
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-var-1.c b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-var-1.c
new file mode 100644
index 0000000..3819ad4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-var-1.c
@@ -0,0 +1,25 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do run } */
+
+/* Test that we can create far variables, and also fabricate pointers to
+   them, when using the small memory model or above.  */
+
+int printf (const char *, ...);
+void abort (void);
+
+__attribute__ ((noinline)) int __far *
+p_var (void)
+{
+  static int __far var = 1;
+  return &var;
+}
+
+int main (void)
+{
+  printf ("%lx\n", (unsigned long) p_var ());
+
+  if (*p_var () != 1)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-var-2.c b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-var-2.c
new file mode 100644
index 0000000..cd95c11
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-var-2.c
@@ -0,0 +1,33 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do run } */
+
+/* Test that we can manipulate far variables (even without creating pointers
+   to them), when using the small code model or above.  */
+
+void abort (void);
+
+int __far var = 1;
+
+__attribute__ ((noinline)) int
+foo (void)
+{
+  ++var;
+  return var;
+}
+
+int main (void)
+{
+  if (foo () != 2)
+    abort ();
+
+  if (foo () != 3)
+    abort ();
+
+  if (foo () != 4)
+    abort ();
+
+  if (foo () != 5)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-var-3.c b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-var-3.c
new file mode 100644
index 0000000..2f19a21
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/far-addr-var-3.c
@@ -0,0 +1,47 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do run } */
+
+/* Can we statically initialize far pointers to point to specific far
+   variables, under the small code model or above?  */
+
+void abort (void);
+
+int __far y = 42;
+const long __far z = 1;
+double __far w = 3.0;
+int __far foofoo = 6;
+int __far *py = &y;
+int __far *py1 = &y + 1;
+int __far *pym1 = &y - 1;
+
+__attribute__ ((noinline)) char __far *
+f (void)
+{
+  static char __far x = 1;
+  static char __far *px = &x;
+  x -= 2;
+  return px + x;
+}
+
+int main (void)
+{
+  if (f () [1] != -1)
+    abort ();
+
+  if (f () [3] != -3)
+    abort ();
+
+  if (f () [5] != -5)
+    abort ();
+
+  if (f () [7] != -7)
+    abort ();
+
+  if (py1[-1] != 42)
+    abort ();
+
+  if (pym1[1] != 42)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/ia16-torture-cmodel-small-or-above.exp b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/ia16-torture-cmodel-small-or-above.exp
new file mode 100644
index 0000000..82b6e46
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/cmodel-small-or-above/ia16-torture-cmodel-small-or-above.exp
@@ -0,0 +1,188 @@
+#   Copyright (C) 2008-2019 Free Software Foundation, Inc.
+
+# 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 3 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 GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `gcc-dg.exp' driver, looping over
+# optimization options.
+
+# Exit immediately if this isn't an IA-16 target.
+if { ![istarget ia16-*-*] } then {
+  return
+}
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+    set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# Initialize `dg'.
+dg-init
+
+    set IA16_TORTURE_OPTIONS [list \
+	{ -O0 -mcmodel=small } \
+	{ -O0 -mcmodel=small -mmsdos-handle-v1 } \
+	{ -O0 -mcmodel=small -mprotected-mode } \
+	{ -O0 -mcmodel=small -mrtd } \
+	{ -O0 -mcmodel=small -mrtd -mmsdos-handle-v1 } \
+	{ -O0 -mcmodel=small -mregparmcall } \
+	{ -O0 -mcmodel=small -mregparmcall -mmsdos-handle-v1 } \
+	{ -O0 -mcmodel=medium } \
+	{ -O0 -mcmodel=medium -mmsdos-handle-v1 } \
+	{ -O0 -mcmodel=medium -ffunction-sections -fdata-sections } \
+	{ -O0 -mcmodel=medium -mprotected-mode } \
+	{ -O0 -mcmodel=medium -mrtd } \
+	{ -O0 -mcmodel=medium -mregparmcall } \
+	{ -O1 -mcmodel=small } \
+	{ -O1 -mcmodel=small -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -funroll-loops } \
+	{ -O1 -mcmodel=small -frename-registers } \
+	{ -O1 -mcmodel=small -funroll-loops -fno-rename-registers } \
+	{ -O1 -mcmodel=small -mrtd } \
+	{ -O1 -mcmodel=small -mrtd -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -mregparmcall } \
+	{ -O1 -mcmodel=small -mregparmcall -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -mprotected-mode } \
+	{ -O1 -mcmodel=small -mprotected-mode -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -mprotected-mode -funroll-loops } \
+	{ -O1 -mcmodel=small -mprotected-mode -frename-registers } \
+	{ -O1 -mcmodel=small -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O1 -mcmodel=small -mprotected-mode -mrtd } \
+	{ -O1 -mcmodel=small -mprotected-mode -mrtd -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -mprotected-mode -mregparmcall } \
+	{ -O1 -mcmodel=small -mprotected-mode -mregparmcall \
+	  -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=medium } \
+	{ -O1 -mcmodel=medium -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=medium -ffunction-sections -fdata-sections } \
+	{ -O1 -mcmodel=medium -funroll-loops } \
+	{ -O1 -mcmodel=medium -frename-registers } \
+	{ -O1 -mcmodel=medium -funroll-loops -fno-rename-registers } \
+	{ -O1 -mcmodel=medium -mrtd } \
+	{ -O1 -mcmodel=medium -mregparmcall } \
+	{ -O1 -mcmodel=medium -mprotected-mode } \
+	{ -O1 -mcmodel=medium -mprotected-mode -funroll-loops } \
+	{ -O1 -mcmodel=medium -mprotected-mode -frename-registers } \
+	{ -O1 -mcmodel=medium -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O1 -mcmodel=medium -mprotected-mode -mrtd } \
+	{ -O1 -mcmodel=medium -mprotected-mode -mregparmcall } \
+	{ -O2 -mcmodel=small } \
+	{ -O2 -mcmodel=small -funroll-loops } \
+	{ -O2 -mcmodel=small -frename-registers } \
+	{ -O2 -mcmodel=small -funroll-loops -fno-rename-registers } \
+	{ -O2 -mcmodel=small -mrtd } \
+	{ -O2 -mcmodel=small -mregparmcall } \
+	{ -O2 -mcmodel=small -mprotected-mode } \
+	{ -O2 -mcmodel=small -mprotected-mode -funroll-loops } \
+	{ -O2 -mcmodel=small -mprotected-mode -frename-registers } \
+	{ -O2 -mcmodel=small -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O2 -mcmodel=small -mprotected-mode -mrtd } \
+	{ -O2 -mcmodel=small -mprotected-mode -mregparmcall } \
+	{ -O2 -mcmodel=medium } \
+	{ -O2 -mcmodel=medium -mmsdos-handle-v1 } \
+	{ -O2 -mcmodel=medium -ffunction-sections -fdata-sections } \
+	{ -O2 -mcmodel=medium -funroll-loops } \
+	{ -O2 -mcmodel=medium -frename-registers } \
+	{ -O2 -mcmodel=medium -funroll-loops -fno-rename-registers } \
+	{ -O2 -mcmodel=medium -mrtd } \
+	{ -O2 -mcmodel=medium -mregparmcall } \
+	{ -O2 -mcmodel=medium -mprotected-mode } \
+	{ -O2 -mcmodel=medium -mprotected-mode -funroll-loops } \
+	{ -O2 -mcmodel=medium -mprotected-mode -frename-registers } \
+	{ -O2 -mcmodel=medium -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O2 -mcmodel=medium -mprotected-mode -mrtd } \
+	{ -O2 -mcmodel=medium -mprotected-mode -mregparmcall } \
+	{ -Os -mcmodel=small } \
+	{ -Os -mcmodel=small -funroll-loops } \
+	{ -Os -mcmodel=small -frename-registers } \
+	{ -Os -mcmodel=small -funroll-loops -fno-rename-registers } \
+	{ -Os -mcmodel=small -mrtd } \
+	{ -Os -mcmodel=small -mregparmcall } \
+	{ -Os -mcmodel=small -flto } \
+	{ -Os -mcmodel=small -finline-functions } \
+	{ -Os -mcmodel=small -mprotected-mode } \
+	{ -Os -mcmodel=small -mprotected-mode -funroll-loops } \
+	{ -Os -mcmodel=small -mprotected-mode -frename-registers } \
+	{ -Os -mcmodel=small -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -Os -mcmodel=small -mprotected-mode -mrtd } \
+	{ -Os -mcmodel=small -mprotected-mode -mregparmcall } \
+	{ -Os -mcmodel=small -mprotected-mode -flto } \
+	{ -Os -mcmodel=small -mprotected-mode -finline-functions } \
+	{ -Os -mcmodel=medium } \
+	{ -Os -mcmodel=medium -mmsdos-handle-v1 } \
+	{ -Os -mcmodel=medium -ffunction-sections -fdata-sections } \
+	{ -Os -mcmodel=medium -funroll-loops } \
+	{ -Os -mcmodel=medium -frename-registers } \
+	{ -Os -mcmodel=medium -funroll-loops -fno-rename-registers } \
+	{ -Os -mcmodel=medium -mrtd } \
+	{ -Os -mcmodel=medium -mregparmcall } \
+	{ -Os -mcmodel=medium -mprotected-mode } \
+	{ -Os -mcmodel=medium -mprotected-mode -funroll-loops } \
+	{ -Os -mcmodel=medium -mprotected-mode -frename-registers } \
+	{ -Os -mcmodel=medium -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -Os -mcmodel=medium -mprotected-mode -mrtd } \
+	{ -Os -mcmodel=medium -mprotected-mode -mregparmcall } \
+	{ -O3 -mcmodel=small } \
+	{ -O3 -mcmodel=small -funroll-loops } \
+	{ -O3 -mcmodel=small -frename-registers } \
+	{ -O3 -mcmodel=small -funroll-loops -fno-rename-registers } \
+	{ -O3 -mcmodel=small -mrtd } \
+	{ -O3 -mcmodel=small -mregparmcall } \
+	{ -O3 -mcmodel=small -mprotected-mode } \
+	{ -O3 -mcmodel=small -mprotected-mode -funroll-loops } \
+	{ -O3 -mcmodel=small -mprotected-mode -frename-registers } \
+	{ -O3 -mcmodel=small -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O3 -mcmodel=small -mprotected-mode -mrtd } \
+	{ -O3 -mcmodel=small -mprotected-mode -mregparmcall } \
+	{ -O3 -mcmodel=medium } \
+	{ -O3 -mcmodel=medium -mmsdos-handle-v1 } \
+	{ -O3 -mcmodel=medium -ffunction-sections -fdata-sections } \
+	{ -O3 -mcmodel=medium -funroll-loops } \
+	{ -O3 -mcmodel=medium -frename-registers } \
+	{ -O3 -mcmodel=medium -funroll-loops -fno-rename-registers } \
+	{ -O3 -mcmodel=medium -mrtd } \
+	{ -O3 -mcmodel=medium -mregparmcall } \
+	{ -O3 -mcmodel=medium -mprotected-mode } \
+	{ -O3 -mcmodel=medium -mprotected-mode -funroll-loops } \
+	{ -O3 -mcmodel=medium -mprotected-mode -frename-registers } \
+	{ -O3 -mcmodel=medium -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O3 -mcmodel=medium -mprotected-mode -mrtd } \
+	{ -O3 -mcmodel=medium -mprotected-mode -mregparmcall } ]
+
+#Initialize use of torture lists. 
+torture-init
+
+set-torture-options $IA16_TORTURE_OPTIONS
+
+
+# Main loop.
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.{\[cS\],cpp}]] "" $DEFAULT_CFLAGS
+
+# Finalize use of torture lists.
+torture-finish
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/gcc.target/ia16/torture/far-addr-29.c b/gcc/testsuite/gcc.target/ia16/torture/far-addr-29.c
new file mode 100644
index 0000000..a2bb3d8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/far-addr-29.c
@@ -0,0 +1,27 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that we can pass an absolute-address far pointer as a parameter to a
+   function.
+
+   This test case is partly taken from the FreeDOS kernel code (in
+   kernel/main.c).  It triggered a bug in GCC which I introduced when I
+   added support for far static variables.  -- tkchia  */
+
+#define MK_FP(seg, ofs) \
+	((void __far *) ((unsigned long) (seg) << 16 | (unsigned) (ofs)))
+
+typedef struct {
+  unsigned char xx1[0x18];
+  unsigned char ps_files[0x14];
+  unsigned char xx2[0xd4];
+} psp;
+
+void fmemset (void __far *, int, unsigned) __attribute__ ((cdecl));
+
+void
+PSPInit (void)
+{
+  psp __far *p = MK_FP (0x60, 0);
+  fmemset (p->ps_files, 0xff, 20);
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/far-addr-31.c b/gcc/testsuite/gcc.target/ia16/torture/far-addr-31.c
new file mode 100644
index 0000000..2a198cd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/far-addr-31.c
@@ -0,0 +1,55 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that we can cast a far pointer to a near pointer without crashing the
+   compiler.
+
+      "	far-addr-31.c: In function `joinMCBs':
+	far-addr-31.c:52:1: error: unrecognizable insn:
+	 }
+	 ^
+	(insn 24 23 25 4 (set (subreg:HI (reg:SI 54) 0)
+	        (truncate:HI (reg/v/f:SI 26 [ p ]))) far-addr-31.c:45 -1
+	     (nil))
+	far-addr-31.c:52:1: internal compiler error: in extract_insn, at
+	 recog.c:2287 "
+
+   This test case is partly taken from a modified version of the FreeDOS
+   kernel code (in kernel/memmgr.c).  The FP_OFF (.) definition below
+   triggered a bug in GCC in the code for casting far pointers to near
+   pointers.  -- tkchia */
+
+#define MK_FP(seg, ofs) \
+	((void __far *) ((unsigned long) (seg) << 16 | (unsigned) (ofs)))
+#define FP_SEG(fp)	\
+	((unsigned) ((unsigned long) (void __far *) (fp) >> 16))
+#define FP_OFF(fp)	((unsigned) (void *) (fp))
+
+#define nxtMCBsize(mcb, size) \
+			MK_FP (FP_SEG (mcb) + (size) - 1, FP_OFF (mcb))
+#define nxtMCB(mcb)	nxtMCBsize ((mcb), (mcb)->m_size)
+#define mcbFree(mcb)	((mcb)->m_psp == 0)
+
+struct mcb
+{
+  unsigned char m_type;
+  unsigned m_psp, m_size;
+  unsigned char m_fill[3], m_name[8];
+} __attribute__ ((packed));
+
+int
+joinMCBs (unsigned para)
+{
+  struct mcb __far *p = (struct mcb __far *) MK_FP (para, 0);
+  struct mcb __far *q;
+  while (p->m_type == 0x4d)
+    {
+      q = nxtMCB (p);
+      if (! mcbFree (q))
+	break;
+      p->m_type = q->m_type;
+      p->m_size += q->m_size + 1;
+      q->m_size = 0xffff;
+    }
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/far-addr-fmemcpy-1.c b/gcc/testsuite/gcc.target/ia16/torture/far-addr-fmemcpy-1.c
new file mode 100644
index 0000000..f46a2d1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/far-addr-fmemcpy-1.c
@@ -0,0 +1,22 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do assemble } */
+
+/* Compiling a memcpy (...)-type routine that works over far pointers used
+   to cause a compiler crash at some optimization levels.  Reported by Bart
+   Oldeman --- https://github.com/tkchia/gcc-ia16/issues/16 .  */
+
+void
+_fmemcpy (void __far *s1, const void __far *s2, unsigned length)
+{
+  char __far *p;
+  const char __far *q;
+
+  if (length)
+    {
+      p = s1;
+      q = s2;
+      do
+	*p++ = *q++;
+      while (--length);
+    }
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/far-addr-fmemcpy-2.c b/gcc/testsuite/gcc.target/ia16/torture/far-addr-fmemcpy-2.c
new file mode 100644
index 0000000..77ba947
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/far-addr-fmemcpy-2.c
@@ -0,0 +1,39 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do assemble } */
+
+/* Can we copy a moderately big, constant-size structure from one far
+   address to another (or between a near address and a far address)?  See
+   https://github.com/tkchia/gcc-ia16/issues/12 .  */
+
+typedef struct { char f[64]; } T;
+typedef struct { char f[65]; } U;
+
+void foo (T __far *p, T __far *q)
+{
+  *p = *q;
+}
+
+void bar (T __far *p, T *q)
+{
+  *p = *q;
+}
+
+void baz (T *p, T __far *q)
+{
+  *p = *q;
+}
+
+void qux (U __far *p1, U __far *p2, U *p3, U __far *q1, U *q2, U __far *q3)
+{
+  *p1 = *q1;
+  *p2 = *q2;
+  *p3 = *q3;
+}
+
+/* Also check that near-to-near copies continue to work even when we have
+   implemented "movmemhi".  */
+void quux (T *p4, U *p5, T *q4, U *q5)
+{
+  *p4 = *q4;
+  *p5 = *q5;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-1.c b/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-1.c
new file mode 100644
index 0000000..6ca931f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-1.c
@@ -0,0 +1,15 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that a call to a function in __far space is done with an `lcall'.  */
+
+typedef int func_t (long);
+typedef func_t __far far_func_t;
+
+int
+bar (far_func_t *foo, long x)
+{
+  return foo (x);
+}
+
+/* { dg-final { scan-assembler "lcall\[ \\t\].*\\(%bp\\)" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-13.c b/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-13.c
new file mode 100644
index 0000000..bf796e9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-13.c
@@ -0,0 +1,16 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that a call from a module to a far function with `__attribute__
+   ((near_section))' is not done with an `lcall' instruction.  */
+
+extern int foo (long) __far __attribute__ ((near_section));
+
+int
+bar (long x)
+{
+  return foo (x) + 1;
+}
+
+/* { dg-final { scan-assembler-not "lcall\[ \\t\]" } } */
+/* { dg-final { scan-assembler "call\[ \\t\]foo" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-14.c b/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-14.c
new file mode 100644
index 0000000..bb17c81
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-14.c
@@ -0,0 +1,17 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that a call from a module to a far function with `__attribute__
+   ((near_section))' is done with a near `call' or `jmp' instruction, if the
+   call can be made a sibcall.  */
+
+extern int foo (long) __far __attribute__ ((near_section));
+
+int
+bar (long x)
+{
+  return foo (x * x);
+}
+
+/* { dg-final { scan-assembler-not "l(call|jmp)\[ \\t\]" } } */
+/* { dg-final { scan-assembler "(call|jmp)\[ \\t\]foo" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-15.c b/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-15.c
new file mode 100644
index 0000000..43c9ccd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-15.c
@@ -0,0 +1,17 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that we _do_ consider a function to be far, if the return type is far,
+   under the default configuration of -mfar-function-if-far-return-type.  */
+
+extern int __far foo (long) __attribute__ ((near_section));
+
+int __far
+bar (long x)
+{
+  return foo (x) + 1;
+}
+
+/* { dg-final { scan-assembler-not "\[ \\t\]ret" } } */
+/* { dg-final { scan-assembler "lret" } } */
+/* { dg-final { scan-assembler "pushw\\t%cs" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-2.c b/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-2.c
new file mode 100644
index 0000000..e9f10c8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-2.c
@@ -0,0 +1,15 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test if the compiler can emit an `lcall' with an absolute address.  */
+
+typedef void func_t (void);
+typedef func_t __far far_func_t;
+
+void
+reset_video (void)
+{
+  ((far_func_t *) 0xc0000003ul) ();
+}
+
+/* { dg-final { scan-assembler "lcall\[ \\t\]\\\$49152,\[ \\t]\\\$3" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-3.c b/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-3.c
new file mode 100644
index 0000000..e2f9891
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-3.c
@@ -0,0 +1,12 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that the postfix __far syntax for declaring far functions works.  */
+
+int
+bar (int (*foo) (long) __far, long x)
+{
+  return foo (x);
+}
+
+/* { dg-final { scan-assembler "lcall\[ \\t\].*\\(%bp\\)" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-4.c b/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-4.c
new file mode 100644
index 0000000..a664edf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-4.c
@@ -0,0 +1,12 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that the postfix __far syntax for declaring far functions works.  */
+
+void
+reset_video (void)
+{
+  ((void (*) (void) __far) 0xc0000003ul) ();
+}
+
+/* { dg-final { scan-assembler "lcall\[ \\t\]\\\$49152,\[ \\t]\\\$3" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-5.c b/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-5.c
new file mode 100644
index 0000000..d21fbb3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-5.c
@@ -0,0 +1,12 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that we can define far functions using the postfix __far syntax.  */
+
+int
+one (void) __far
+{
+  return 1;
+}
+
+/* { dg-final { scan-assembler "lret" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-6.c b/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-6.c
new file mode 100644
index 0000000..4d37cc6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-6.c
@@ -0,0 +1,12 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that we can define a function which is far _and_ stdcall.  */
+
+__attribute__ ((stdcall)) int
+add_one (long x) __far
+{
+  return x + 1;
+}
+
+/* { dg-final { scan-assembler "lret\[ \\t\]\\\$4" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-7.c b/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-7.c
new file mode 100644
index 0000000..94262d7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/far-addr-func-7.c
@@ -0,0 +1,13 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that we can define a function which is far _and_ cdecl.  */
+
+__attribute__ ((cdecl)) int
+add_one (long x) __far
+{
+  return x + 1;
+}
+
+/* { dg-final { scan-assembler "lret" } } */
+/* { dg-final { scan-assembler-not "lret\[ \\t\]\\\$4" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/ia16-torture.exp b/gcc/testsuite/gcc.target/ia16/torture/ia16-torture.exp
new file mode 100644
index 0000000..584f203
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/ia16-torture.exp
@@ -0,0 +1,244 @@
+#   Copyright (C) 2008-2019 Free Software Foundation, Inc.
+
+# 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 3 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 GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `gcc-dg.exp' driver, looping over
+# optimization options.
+
+# Exit immediately if this isn't an IA-16 target.
+if { ![istarget ia16-*-*] } then {
+  return
+}
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+    set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# Initialize `dg'.
+dg-init
+
+    set IA16_TORTURE_OPTIONS [list \
+	{ -O0 } \
+	{ -O0 -mprotected-mode } \
+	{ -O0 -mrtd } \
+	{ -O0 -mregparmcall } \
+	{ -O0 -mcmodel=small } \
+	{ -O0 -mcmodel=small -mmsdos-handle-v1 } \
+	{ -O0 -mcmodel=small -mprotected-mode } \
+	{ -O0 -mcmodel=small -mrtd } \
+	{ -O0 -mcmodel=small -mrtd -mmsdos-handle-v1 } \
+	{ -O0 -mcmodel=small -mregparmcall } \
+	{ -O0 -mcmodel=small -mregparmcall -mmsdos-handle-v1 } \
+	{ -O0 -mcmodel=medium } \
+	{ -O0 -mcmodel=medium -mmsdos-handle-v1 } \
+	{ -O0 -mcmodel=medium -ffunction-sections -fdata-sections } \
+	{ -O0 -mcmodel=medium -mprotected-mode } \
+	{ -O0 -mcmodel=medium -mrtd } \
+	{ -O0 -mcmodel=medium -mregparmcall } \
+	{ -O1 } \
+	{ -O1 -funroll-loops } \
+	{ -O1 -frename-registers } \
+	{ -O1 -funroll-loops -fno-rename-registers } \
+	{ -O1 -mrtd } \
+	{ -O1 -mregparmcall } \
+	{ -O1 -mprotected-mode } \
+	{ -O1 -mprotected-mode -funroll-loops } \
+	{ -O1 -mprotected-mode -frename-registers } \
+	{ -O1 -mprotected-mode -funroll-loops -fno-rename-registers } \
+	{ -O1 -mprotected-mode -mrtd } \
+	{ -O1 -mprotected-mode -mregparmcall } \
+	{ -O1 -mcmodel=small } \
+	{ -O1 -mcmodel=small -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -funroll-loops } \
+	{ -O1 -mcmodel=small -frename-registers } \
+	{ -O1 -mcmodel=small -funroll-loops -fno-rename-registers } \
+	{ -O1 -mcmodel=small -mrtd } \
+	{ -O1 -mcmodel=small -mrtd -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -mregparmcall } \
+	{ -O1 -mcmodel=small -mregparmcall -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -mprotected-mode } \
+	{ -O1 -mcmodel=small -mprotected-mode -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -mprotected-mode -funroll-loops } \
+	{ -O1 -mcmodel=small -mprotected-mode -frename-registers } \
+	{ -O1 -mcmodel=small -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O1 -mcmodel=small -mprotected-mode -mrtd } \
+	{ -O1 -mcmodel=small -mprotected-mode -mrtd -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -mprotected-mode -mregparmcall } \
+	{ -O1 -mcmodel=small -mprotected-mode -mregparmcall \
+	  -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=medium } \
+	{ -O1 -mcmodel=medium -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=medium -ffunction-sections -fdata-sections } \
+	{ -O1 -mcmodel=medium -funroll-loops } \
+	{ -O1 -mcmodel=medium -frename-registers } \
+	{ -O1 -mcmodel=medium -funroll-loops -fno-rename-registers } \
+	{ -O1 -mcmodel=medium -mrtd } \
+	{ -O1 -mcmodel=medium -mregparmcall } \
+	{ -O1 -mcmodel=medium -mprotected-mode } \
+	{ -O1 -mcmodel=medium -mprotected-mode -funroll-loops } \
+	{ -O1 -mcmodel=medium -mprotected-mode -frename-registers } \
+	{ -O1 -mcmodel=medium -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O1 -mcmodel=medium -mprotected-mode -mrtd } \
+	{ -O1 -mcmodel=medium -mprotected-mode -mregparmcall } \
+	{ -O2 } \
+	{ -O2 -funroll-loops } \
+	{ -O2 -frename-registers } \
+	{ -O2 -funroll-loops -fno-rename-registers } \
+	{ -O2 -mrtd } \
+	{ -O2 -mregparmcall } \
+	{ -O2 -mprotected-mode } \
+	{ -O2 -mprotected-mode -funroll-loops } \
+	{ -O2 -mprotected-mode -frename-registers } \
+	{ -O2 -mprotected-mode -funroll-loops -fno-rename-registers } \
+	{ -O2 -mprotected-mode -mrtd } \
+	{ -O2 -mprotected-mode -mregparmcall } \
+	{ -O2 -mcmodel=small } \
+	{ -O2 -mcmodel=small -funroll-loops } \
+	{ -O2 -mcmodel=small -frename-registers } \
+	{ -O2 -mcmodel=small -funroll-loops -fno-rename-registers } \
+	{ -O2 -mcmodel=small -mrtd } \
+	{ -O2 -mcmodel=small -mregparmcall } \
+	{ -O2 -mcmodel=small -mprotected-mode } \
+	{ -O2 -mcmodel=small -mprotected-mode -funroll-loops } \
+	{ -O2 -mcmodel=small -mprotected-mode -frename-registers } \
+	{ -O2 -mcmodel=small -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O2 -mcmodel=small -mprotected-mode -mrtd } \
+	{ -O2 -mcmodel=small -mprotected-mode -mregparmcall } \
+	{ -O2 -mcmodel=medium } \
+	{ -O2 -mcmodel=medium -mmsdos-handle-v1 } \
+	{ -O2 -mcmodel=medium -ffunction-sections -fdata-sections } \
+	{ -O2 -mcmodel=medium -funroll-loops } \
+	{ -O2 -mcmodel=medium -frename-registers } \
+	{ -O2 -mcmodel=medium -funroll-loops -fno-rename-registers } \
+	{ -O2 -mcmodel=medium -mrtd } \
+	{ -O2 -mcmodel=medium -mregparmcall } \
+	{ -O2 -mcmodel=medium -mprotected-mode } \
+	{ -O2 -mcmodel=medium -mprotected-mode -funroll-loops } \
+	{ -O2 -mcmodel=medium -mprotected-mode -frename-registers } \
+	{ -O2 -mcmodel=medium -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O2 -mcmodel=medium -mprotected-mode -mrtd } \
+	{ -O2 -mcmodel=medium -mprotected-mode -mregparmcall } \
+	{ -Os } \
+	{ -Os -funroll-loops } \
+	{ -Os -frename-registers } \
+	{ -Os -funroll-loops -fno-rename-registers } \
+	{ -Os -mrtd } \
+	{ -Os -mregparmcall } \
+	{ -Os -flto } \
+	{ -Os -finline-functions } \
+	{ -Os -mprotected-mode } \
+	{ -Os -mprotected-mode -funroll-loops } \
+	{ -Os -mprotected-mode -frename-registers } \
+	{ -Os -mprotected-mode -funroll-loops -fno-rename-registers } \
+	{ -Os -mprotected-mode -mrtd } \
+	{ -Os -mprotected-mode -mregparmcall } \
+	{ -Os -mprotected-mode -flto } \
+	{ -Os -mprotected-mode -finline-functions } \
+	{ -Os -mcmodel=small } \
+	{ -Os -mcmodel=small -funroll-loops } \
+	{ -Os -mcmodel=small -frename-registers } \
+	{ -Os -mcmodel=small -funroll-loops -fno-rename-registers } \
+	{ -Os -mcmodel=small -mrtd } \
+	{ -Os -mcmodel=small -mregparmcall } \
+	{ -Os -mcmodel=small -flto } \
+	{ -Os -mcmodel=small -finline-functions } \
+	{ -Os -mcmodel=small -mprotected-mode } \
+	{ -Os -mcmodel=small -mprotected-mode -funroll-loops } \
+	{ -Os -mcmodel=small -mprotected-mode -frename-registers } \
+	{ -Os -mcmodel=small -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -Os -mcmodel=small -mprotected-mode -mrtd } \
+	{ -Os -mcmodel=small -mprotected-mode -mregparmcall } \
+	{ -Os -mcmodel=small -mprotected-mode -flto } \
+	{ -Os -mcmodel=small -mprotected-mode -finline-functions } \
+	{ -Os -mcmodel=medium } \
+	{ -Os -mcmodel=medium -mmsdos-handle-v1 } \
+	{ -Os -mcmodel=medium -ffunction-sections -fdata-sections } \
+	{ -Os -mcmodel=medium -funroll-loops } \
+	{ -Os -mcmodel=medium -frename-registers } \
+	{ -Os -mcmodel=medium -funroll-loops -fno-rename-registers } \
+	{ -Os -mcmodel=medium -mrtd } \
+	{ -Os -mcmodel=medium -mregparmcall } \
+	{ -Os -mcmodel=medium -mprotected-mode } \
+	{ -Os -mcmodel=medium -mprotected-mode -funroll-loops } \
+	{ -Os -mcmodel=medium -mprotected-mode -frename-registers } \
+	{ -Os -mcmodel=medium -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -Os -mcmodel=medium -mprotected-mode -mrtd } \
+	{ -Os -mcmodel=medium -mprotected-mode -mregparmcall } \
+	{ -O3 } \
+	{ -O3 -funroll-loops } \
+	{ -O3 -frename-registers } \
+	{ -O3 -funroll-loops -fno-rename-registers } \
+	{ -O3 -mrtd } \
+	{ -O3 -mregparmcall } \
+	{ -O3 -mprotected-mode } \
+	{ -O3 -mprotected-mode -funroll-loops } \
+	{ -O3 -mprotected-mode -frename-registers } \
+	{ -O3 -mprotected-mode -funroll-loops -fno-rename-registers } \
+	{ -O3 -mprotected-mode -mrtd } \
+	{ -O3 -mprotected-mode -mregparmcall } \
+	{ -O3 -mcmodel=small } \
+	{ -O3 -mcmodel=small -funroll-loops } \
+	{ -O3 -mcmodel=small -frename-registers } \
+	{ -O3 -mcmodel=small -funroll-loops -fno-rename-registers } \
+	{ -O3 -mcmodel=small -mrtd } \
+	{ -O3 -mcmodel=small -mregparmcall } \
+	{ -O3 -mcmodel=small -mprotected-mode } \
+	{ -O3 -mcmodel=small -mprotected-mode -funroll-loops } \
+	{ -O3 -mcmodel=small -mprotected-mode -frename-registers } \
+	{ -O3 -mcmodel=small -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O3 -mcmodel=small -mprotected-mode -mrtd } \
+	{ -O3 -mcmodel=small -mprotected-mode -mregparmcall } \
+	{ -O3 -mcmodel=medium } \
+	{ -O3 -mcmodel=medium -mmsdos-handle-v1 } \
+	{ -O3 -mcmodel=medium -ffunction-sections -fdata-sections } \
+	{ -O3 -mcmodel=medium -funroll-loops } \
+	{ -O3 -mcmodel=medium -frename-registers } \
+	{ -O3 -mcmodel=medium -funroll-loops -fno-rename-registers } \
+	{ -O3 -mcmodel=medium -mrtd } \
+	{ -O3 -mcmodel=medium -mregparmcall } \
+	{ -O3 -mcmodel=medium -mprotected-mode } \
+	{ -O3 -mcmodel=medium -mprotected-mode -funroll-loops } \
+	{ -O3 -mcmodel=medium -mprotected-mode -frename-registers } \
+	{ -O3 -mcmodel=medium -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O3 -mcmodel=medium -mprotected-mode -mrtd } \
+	{ -O3 -mcmodel=medium -mprotected-mode -mregparmcall } ]
+
+#Initialize use of torture lists. 
+torture-init
+
+set-torture-options $IA16_TORTURE_OPTIONS
+
+
+# Main loop.
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.{\[cS\],cpp}]] "" $DEFAULT_CFLAGS
+
+# Finalize use of torture lists.
+torture-finish
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/gcc.target/ia16/torture/libgcc-1.c b/gcc/testsuite/gcc.target/ia16/torture/libgcc-1.c
new file mode 100644
index 0000000..bb151d3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/libgcc-1.c
@@ -0,0 +1,47 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do run } */
+
+/* Test whether the assembly language versions of the __udivsi3 and __umodsi3
+   helper functions in libgcc work correctly, under various calling
+   conventions.  */
+
+extern void abort (void);
+
+/* This code may fail in two ways:
+     * If linked against the wrong libgcc, the main () loop will eventually
+       cause a stack overflow and corrupt the data area.
+     * If the division is done wrong, the loop will call abort ().  Here I
+       test for a known issue reported by Gerd Grosse in the context of the
+       FreeDOS kernel (https://sourceforge.net/p/freedos/bugs/106/).  */
+
+volatile unsigned long quotient1 = 0xbdaf6f1bul, divisor1 = 0x083b9222ul,
+		       quotient2 = 0xffff01fful, divisor2 = 0x010101fful;
+
+int
+main (void)
+{
+  unsigned i;
+
+  for (i = 0; i < 10000; ++i)
+    {
+      unsigned long dividend, modulus;
+
+      dividend = quotient1 / divisor1;
+      if (dividend != 0x17ul)
+	abort ();
+
+      modulus = quotient1 % divisor1;
+      if (modulus != 0x554e0dul)
+	abort ();
+
+      dividend = quotient2 / divisor2;
+      if (dividend != 0xfeul)
+	abort ();
+
+      modulus = quotient2 % divisor2;
+      if (modulus != 0xff06fdul)
+	abort ();
+    }
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/libgcc-2.c b/gcc/testsuite/gcc.target/ia16/torture/libgcc-2.c
new file mode 100644
index 0000000..50cccb9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/libgcc-2.c
@@ -0,0 +1,64 @@
+/* { dg-do run } */
+/* { dg-options "-std=gnu11 --save-temps" } */
+
+/* Test whether the assembly language versions of the __divsi3 and __modsi3
+   helper functions in libgcc work correctly.
+
+   The code is adapted from the i386 test case gcc/testsuite/gcc.target/i386/
+   divmod-1.c .  */
+
+extern void abort (void);
+
+void
+__attribute__((noinline))
+test (long x, long y, long q, long r)
+{
+  if ((x / y) != q || (x % y) != r)
+    abort ();
+}
+
+int
+main ()
+{
+  test (7L, 6L, 1L, 1L);
+  test (-7L, -6L, 1L, -1L);
+  test (-7L, 6L, -1L, -1L);
+  test (7L, -6L, -1L, 1L);
+  test (17L, 3L, 5L, 2L);
+  test (-17L, -3L, 5L, -2L);
+  test (-17L, 3L, -5L, -2L);
+  test (17L, -3L, -5L, 2L);
+  test (65535L, 65534L, 1L, 1L);
+  test (-65535L, -65534L, 1L, -1L);
+  test (-65535L, 65534L, -1L, -1L);
+  test (65535L, -65534L, -1L, 1L);
+  test (65536L, 65534L, 1L, 2L);
+  test (-65536L, -65534L, 1L, -2L);
+  test (-65536L, 65534L, -1L, -2L);
+  test (65536L, -65534L, -1L, 2L);
+  test (65536L, 65536L, 1L, 0L);
+  test (-65536L, -65536L, 1L, 0L);
+  test (-65536L, 65536L, -1L, 0L);
+  test (65536L, -65536L, -1L, 0L);
+  test (65534L, 65536L, 0L, 65534L);
+  test (-65534L, -65536L, 0L, -65534L);
+  test (-65534L, 65536L, 0L, -65534L);
+  test (65534L, -65536L, 0L, 65534L);
+  test (65534L, 65535L, 0L, 65534L);
+  test (-65534L, -65535L, 0L, -65534L);
+  test (-65534L, 65535L, 0L, -65534L);
+  test (65534L, -65535L, 0L, 65534L);
+  test (65534L, 1L, 65534L, 0L);
+  test (-65534L, -1L, 65534L, 0L);
+  test (-65534L, 1L, -65534L, 0L);
+  test (65534L, -1L, -65534L, 0L);
+  test (65535L, 2L, 32767L, 1L);
+  test (-65535L, -2L, 32767L, -1L);
+  test (-65535L, 2L, -32767L, -1L);
+  test (65535L, -2L, -32767L, 1L);
+  test (1L, 65536L, 0L, 1L);
+  test (-1L, -65536L, 0L, -1L);
+  test (-1L, 65536L, 0L, -1L);
+  test (1L, -65536L, 0L, 1L);
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/nostdlib-1.c b/gcc/testsuite/gcc.target/ia16/torture/nostdlib-1.c
new file mode 100644
index 0000000..1161b35
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/nostdlib-1.c
@@ -0,0 +1,15 @@
+/* { dg-options "-nostdlib --save-temps" } */
+/* { dg-do run } */
+
+/* Test that we can use the -nostdlib option to build programs that do not
+   use the default startup modules and C libraries.  */
+
+#ifdef __IA16_CMODEL_IS_FAR_TEXT
+__attribute__ ((section (".text")))	/* FIXME: remove the need for this */
+#endif
+void
+_start (void)
+{
+  __asm volatile ("int $0x21" : : "a" (0x4c00u) : "memory");
+  __builtin_unreachable ();
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/optimize/asm-2.c b/gcc/testsuite/gcc.target/ia16/torture/optimize/asm-2.c
new file mode 100644
index 0000000..fb44ddd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/optimize/asm-2.c
@@ -0,0 +1,18 @@
+/* { dg-do assemble } */
+/* { dg-options "--std=gnu11 --save-temps" } */
+
+/* Test that GCC understands the "N" assembler operand constraint.  */
+
+static inline void
+outp (unsigned port, unsigned char value)
+{
+  __asm volatile ("outb %0, %1" : : "Ral" (value), "Nd" (port));
+}
+
+void
+eoi_pic2 (void)
+{
+  outp (0xa0, 0x20);
+}
+
+/* { dg-final { scan-assembler "outb %al, \\\$160" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/optimize/asm-3.c b/gcc/testsuite/gcc.target/ia16/torture/optimize/asm-3.c
new file mode 100644
index 0000000..54eb952
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/optimize/asm-3.c
@@ -0,0 +1,19 @@
+/* { dg-do assemble } */
+/* { dg-options "--std=gnu11 --save-temps" } */
+
+/* Test that GCC only uses the "N" assembler operand constraint when it is
+   appropriate.  */
+
+static inline void
+outp (unsigned port, unsigned char value)
+{
+  __asm volatile ("outb %0, %1" : : "Ral" (value), "Nd" (port));
+}
+
+void
+tx_com1 (void)
+{
+  outp (0x3f8, '!');
+}
+
+/* { dg-final { scan-assembler "outb %al, %dx" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/optimize/ia16-torture-optimize.exp b/gcc/testsuite/gcc.target/ia16/torture/optimize/ia16-torture-optimize.exp
new file mode 100644
index 0000000..1c4d0d1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/optimize/ia16-torture-optimize.exp
@@ -0,0 +1,227 @@
+#   Copyright (C) 2008-2019 Free Software Foundation, Inc.
+
+# 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 3 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 GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `gcc-dg.exp' driver, looping over
+# optimization options.
+
+# Exit immediately if this isn't an IA-16 target.
+if { ![istarget ia16-*-*] } then {
+  return
+}
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+    set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# Initialize `dg'.
+dg-init
+
+    set IA16_TORTURE_OPTIONS [list \
+	{ -O1 } \
+	{ -O1 -funroll-loops } \
+	{ -O1 -frename-registers } \
+	{ -O1 -funroll-loops -fno-rename-registers } \
+	{ -O1 -mrtd } \
+	{ -O1 -mregparmcall } \
+	{ -O1 -mprotected-mode } \
+	{ -O1 -mprotected-mode -funroll-loops } \
+	{ -O1 -mprotected-mode -frename-registers } \
+	{ -O1 -mprotected-mode -funroll-loops -fno-rename-registers } \
+	{ -O1 -mprotected-mode -mrtd } \
+	{ -O1 -mprotected-mode -mregparmcall } \
+	{ -O1 -mcmodel=small } \
+	{ -O1 -mcmodel=small -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -funroll-loops } \
+	{ -O1 -mcmodel=small -frename-registers } \
+	{ -O1 -mcmodel=small -funroll-loops -fno-rename-registers } \
+	{ -O1 -mcmodel=small -mrtd } \
+	{ -O1 -mcmodel=small -mrtd -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -mregparmcall } \
+	{ -O1 -mcmodel=small -mregparmcall -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -mprotected-mode } \
+	{ -O1 -mcmodel=small -mprotected-mode -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -mprotected-mode -funroll-loops } \
+	{ -O1 -mcmodel=small -mprotected-mode -frename-registers } \
+	{ -O1 -mcmodel=small -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O1 -mcmodel=small -mprotected-mode -mrtd } \
+	{ -O1 -mcmodel=small -mprotected-mode -mrtd -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=small -mprotected-mode -mregparmcall } \
+	{ -O1 -mcmodel=small -mprotected-mode -mregparmcall \
+	  -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=medium } \
+	{ -O1 -mcmodel=medium -mmsdos-handle-v1 } \
+	{ -O1 -mcmodel=medium -ffunction-sections -fdata-sections } \
+	{ -O1 -mcmodel=medium -funroll-loops } \
+	{ -O1 -mcmodel=medium -frename-registers } \
+	{ -O1 -mcmodel=medium -funroll-loops -fno-rename-registers } \
+	{ -O1 -mcmodel=medium -mrtd } \
+	{ -O1 -mcmodel=medium -mregparmcall } \
+	{ -O1 -mcmodel=medium -mprotected-mode } \
+	{ -O1 -mcmodel=medium -mprotected-mode -funroll-loops } \
+	{ -O1 -mcmodel=medium -mprotected-mode -frename-registers } \
+	{ -O1 -mcmodel=medium -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O1 -mcmodel=medium -mprotected-mode -mrtd } \
+	{ -O1 -mcmodel=medium -mprotected-mode -mregparmcall } \
+	{ -O2 } \
+	{ -O2 -funroll-loops } \
+	{ -O2 -frename-registers } \
+	{ -O2 -funroll-loops -fno-rename-registers } \
+	{ -O2 -mrtd } \
+	{ -O2 -mregparmcall } \
+	{ -O2 -mprotected-mode } \
+	{ -O2 -mprotected-mode -funroll-loops } \
+	{ -O2 -mprotected-mode -frename-registers } \
+	{ -O2 -mprotected-mode -funroll-loops -fno-rename-registers } \
+	{ -O2 -mprotected-mode -mrtd } \
+	{ -O2 -mprotected-mode -mregparmcall } \
+	{ -O2 -mcmodel=small } \
+	{ -O2 -mcmodel=small -funroll-loops } \
+	{ -O2 -mcmodel=small -frename-registers } \
+	{ -O2 -mcmodel=small -funroll-loops -fno-rename-registers } \
+	{ -O2 -mcmodel=small -mrtd } \
+	{ -O2 -mcmodel=small -mregparmcall } \
+	{ -O2 -mcmodel=small -mprotected-mode } \
+	{ -O2 -mcmodel=small -mprotected-mode -funroll-loops } \
+	{ -O2 -mcmodel=small -mprotected-mode -frename-registers } \
+	{ -O2 -mcmodel=small -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O2 -mcmodel=small -mprotected-mode -mrtd } \
+	{ -O2 -mcmodel=small -mprotected-mode -mregparmcall } \
+	{ -O2 -mcmodel=medium } \
+	{ -O2 -mcmodel=medium -mmsdos-handle-v1 } \
+	{ -O2 -mcmodel=medium -ffunction-sections -fdata-sections } \
+	{ -O2 -mcmodel=medium -funroll-loops } \
+	{ -O2 -mcmodel=medium -frename-registers } \
+	{ -O2 -mcmodel=medium -funroll-loops -fno-rename-registers } \
+	{ -O2 -mcmodel=medium -mrtd } \
+	{ -O2 -mcmodel=medium -mregparmcall } \
+	{ -O2 -mcmodel=medium -mprotected-mode } \
+	{ -O2 -mcmodel=medium -mprotected-mode -funroll-loops } \
+	{ -O2 -mcmodel=medium -mprotected-mode -frename-registers } \
+	{ -O2 -mcmodel=medium -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O2 -mcmodel=medium -mprotected-mode -mrtd } \
+	{ -O2 -mcmodel=medium -mprotected-mode -mregparmcall } \
+	{ -Os } \
+	{ -Os -funroll-loops } \
+	{ -Os -frename-registers } \
+	{ -Os -funroll-loops -fno-rename-registers } \
+	{ -Os -mrtd } \
+	{ -Os -mregparmcall } \
+	{ -Os -flto } \
+	{ -Os -finline-functions } \
+	{ -Os -mprotected-mode } \
+	{ -Os -mprotected-mode -funroll-loops } \
+	{ -Os -mprotected-mode -frename-registers } \
+	{ -Os -mprotected-mode -funroll-loops -fno-rename-registers } \
+	{ -Os -mprotected-mode -mrtd } \
+	{ -Os -mprotected-mode -mregparmcall } \
+	{ -Os -mprotected-mode -flto } \
+	{ -Os -mprotected-mode -finline-functions } \
+	{ -Os -mcmodel=small } \
+	{ -Os -mcmodel=small -funroll-loops } \
+	{ -Os -mcmodel=small -frename-registers } \
+	{ -Os -mcmodel=small -funroll-loops -fno-rename-registers } \
+	{ -Os -mcmodel=small -mrtd } \
+	{ -Os -mcmodel=small -mregparmcall } \
+	{ -Os -mcmodel=small -flto } \
+	{ -Os -mcmodel=small -finline-functions } \
+	{ -Os -mcmodel=small -mprotected-mode } \
+	{ -Os -mcmodel=small -mprotected-mode -funroll-loops } \
+	{ -Os -mcmodel=small -mprotected-mode -frename-registers } \
+	{ -Os -mcmodel=small -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -Os -mcmodel=small -mprotected-mode -mrtd } \
+	{ -Os -mcmodel=small -mprotected-mode -mregparmcall } \
+	{ -Os -mcmodel=small -mprotected-mode -flto } \
+	{ -Os -mcmodel=small -mprotected-mode -finline-functions } \
+	{ -Os -mcmodel=medium } \
+	{ -Os -mcmodel=medium -mmsdos-handle-v1 } \
+	{ -Os -mcmodel=medium -ffunction-sections -fdata-sections } \
+	{ -Os -mcmodel=medium -funroll-loops } \
+	{ -Os -mcmodel=medium -frename-registers } \
+	{ -Os -mcmodel=medium -funroll-loops -fno-rename-registers } \
+	{ -Os -mcmodel=medium -mrtd } \
+	{ -Os -mcmodel=medium -mregparmcall } \
+	{ -Os -mcmodel=medium -mprotected-mode } \
+	{ -Os -mcmodel=medium -mprotected-mode -funroll-loops } \
+	{ -Os -mcmodel=medium -mprotected-mode -frename-registers } \
+	{ -Os -mcmodel=medium -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -Os -mcmodel=medium -mprotected-mode -mrtd } \
+	{ -Os -mcmodel=medium -mprotected-mode -mregparmcall } \
+	{ -O3 } \
+	{ -O3 -funroll-loops } \
+	{ -O3 -frename-registers } \
+	{ -O3 -funroll-loops -fno-rename-registers } \
+	{ -O3 -mrtd } \
+	{ -O3 -mregparmcall } \
+	{ -O3 -mprotected-mode } \
+	{ -O3 -mprotected-mode -funroll-loops } \
+	{ -O3 -mprotected-mode -frename-registers } \
+	{ -O3 -mprotected-mode -funroll-loops -fno-rename-registers } \
+	{ -O3 -mprotected-mode -mrtd } \
+	{ -O3 -mprotected-mode -mregparmcall } \
+	{ -O3 -mcmodel=small } \
+	{ -O3 -mcmodel=small -funroll-loops } \
+	{ -O3 -mcmodel=small -frename-registers } \
+	{ -O3 -mcmodel=small -funroll-loops -fno-rename-registers } \
+	{ -O3 -mcmodel=small -mrtd } \
+	{ -O3 -mcmodel=small -mregparmcall } \
+	{ -O3 -mcmodel=small -mprotected-mode } \
+	{ -O3 -mcmodel=small -mprotected-mode -funroll-loops } \
+	{ -O3 -mcmodel=small -mprotected-mode -frename-registers } \
+	{ -O3 -mcmodel=small -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O3 -mcmodel=small -mprotected-mode -mrtd } \
+	{ -O3 -mcmodel=small -mprotected-mode -mregparmcall } \
+	{ -O3 -mcmodel=medium } \
+	{ -O3 -mcmodel=medium -mmsdos-handle-v1 } \
+	{ -O3 -mcmodel=medium -ffunction-sections -fdata-sections } \
+	{ -O3 -mcmodel=medium -funroll-loops } \
+	{ -O3 -mcmodel=medium -frename-registers } \
+	{ -O3 -mcmodel=medium -funroll-loops -fno-rename-registers } \
+	{ -O3 -mcmodel=medium -mrtd } \
+	{ -O3 -mcmodel=medium -mregparmcall } \
+	{ -O3 -mcmodel=medium -mprotected-mode } \
+	{ -O3 -mcmodel=medium -mprotected-mode -funroll-loops } \
+	{ -O3 -mcmodel=medium -mprotected-mode -frename-registers } \
+	{ -O3 -mcmodel=medium -mprotected-mode -funroll-loops \
+	  -fno-rename-registers } \
+	{ -O3 -mcmodel=medium -mprotected-mode -mrtd } \
+	{ -O3 -mcmodel=medium -mprotected-mode -mregparmcall } ]
+
+#Initialize use of torture lists. 
+torture-init
+
+set-torture-options $IA16_TORTURE_OPTIONS
+
+
+# Main loop.
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.{\[cS\],cpp}]] "" $DEFAULT_CFLAGS
+
+# Finalize use of torture lists.
+torture-finish
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/gcc.target/ia16/torture/optimize/opt-1.c b/gcc/testsuite/gcc.target/ia16/torture/optimize/opt-1.c
new file mode 100644
index 0000000..0ad1184
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/optimize/opt-1.c
@@ -0,0 +1,19 @@
+/* { dg-do assemble } */
+/* { dg-skip-if "" { *-*-* }  { "-O1" } { "" } } */
+/* { dg-options "-std=gnu11 --save-temps" } */
+
+/* Test whether the addition below is compiled into something like
+	addw	$2,	(%bx)
+   rather than
+	movw	(%bx),	%ax
+	addw	$2,	%ax
+	movw	%ax,	(%bx)
+   when optimizing.  This issue was reported by Bart Oldeman --- see
+   https://github.com/tkchia/gcc-ia16/issues/15 .  */
+
+void incnear(int *a)
+{
+  (*a)+=2;
+}
+
+/* { dg-final { scan-assembler "addw\[ \\t\]\\\$2,\[ \\t\]\\(%(bx|bp|si|di)\\)" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/optimize/opt-2.c b/gcc/testsuite/gcc.target/ia16/torture/optimize/opt-2.c
new file mode 100644
index 0000000..654b5fd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/optimize/opt-2.c
@@ -0,0 +1,33 @@
+/* { dg-do assemble } */
+/* { dg-options "-std=gnu11 --save-temps" } */
+
+/* Test for a bogus register spill just before sign-extending a value in %al
+   into %ax (especially when compiling with the -mregparmcall option):
+	movb	%al,	-1(%bp)
+	cbtw
+   This isue was reported by Bart Oldeman --- see https://github.com/tkchia/
+   gcc-ia16/issues/31 .  */
+
+struct j {
+  char j;
+};
+
+struct a {
+  unsigned char flag;
+  struct j __far *pj;
+};
+
+extern struct a __far *fnc (int i, int j);
+
+void
+foo (struct j __far * pj)
+{
+  struct a __far *p = fnc (0, pj->j);
+  if (p)
+    {
+      p->flag &= ~1;
+      p->pj = pj;
+    }
+}
+
+/* { dg-final { scan-assembler-not "movb\[ \\t\]%al,\[ \\t\].*\\(%bp\\)" } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/optimize/opt-3.c b/gcc/testsuite/gcc.target/ia16/torture/optimize/opt-3.c
new file mode 100644
index 0000000..24d94bb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/optimize/opt-3.c
@@ -0,0 +1,32 @@
+/* { dg-do assemble } */
+/* { dg-options "-std=gnu11 --save-temps" } */
+
+/* Test that left arithmetic shifts of a 32-bit integer by 1, 2, and 3 bits,
+   and shifts of a 64-bit integer by 1 bit, are done with the help of the
+   `rclw' instruction --- rather than using the GCC middle-end's rather
+   inefficient synthesis.
+
+   This isue was reported by Bart Oldeman --- see https://github.com/tkchia/
+   gcc-ia16/issues/34 .  */
+
+unsigned long shl1 (unsigned long x)
+{
+  return x << 1;
+}
+
+unsigned long shl2 (unsigned long x)
+{
+  return x << 2;
+}
+
+unsigned long shl3 (unsigned long x)
+{
+  return x << 3;
+}
+
+unsigned long long shl1ll (unsigned long long x)
+{
+  return x << 1;
+}
+
+/* { dg-final { scan-assembler-times "rclw" 9 } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/optimize/opt-4.c b/gcc/testsuite/gcc.target/ia16/torture/optimize/opt-4.c
new file mode 100644
index 0000000..a00556c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/optimize/opt-4.c
@@ -0,0 +1,33 @@
+/* { dg-do assemble } */
+/* { dg-options "-std=gnu11 --save-temps" } */
+
+/* Test that right arithmetic shifts of a 32-bit integer by 1, 2, and 3 bits,
+   and shifts of a 64-bit integer by 1 bit, are done with the help of the
+   `sarw' and `rcrw' instructions --- rather than using the GCC middle-end's
+   rather inefficient synthesis.
+
+   This isue was reported by Bart Oldeman --- see https://github.com/tkchia/
+   gcc-ia16/issues/34 .  */
+
+long sar1 (long x)
+{
+  return x >> 1;
+}
+
+long sar2 (long x)
+{
+  return x >> 2;
+}
+
+long sar3 (long x)
+{
+  return x >> 3;
+}
+
+long long sarl1ll (long long x)
+{
+  return x >> 1;
+}
+
+/* { dg-final { scan-assembler-times "sarw" 7 } } */
+/* { dg-final { scan-assembler-times "rcrw" 9 } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/optimize/opt-5.c b/gcc/testsuite/gcc.target/ia16/torture/optimize/opt-5.c
new file mode 100644
index 0000000..3de1aea
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/optimize/opt-5.c
@@ -0,0 +1,33 @@
+/* { dg-do assemble } */
+/* { dg-options "-std=gnu11 --save-temps" } */
+
+/* Test that right logical shifts of a 32-bit integer by 1, 2, and 3 bits,
+   and shifts of a 64-bit integer by 1 bit, are done with the help of the
+   `shrw' and `rcrw' instructions --- rather than using the GCC middle-end's
+   rather inefficient synthesis.
+
+   This isue was reported by Bart Oldeman --- see https://github.com/tkchia/
+   gcc-ia16/issues/34 .  */
+
+unsigned long shr1 (unsigned long x)
+{
+  return x >> 1;
+}
+
+unsigned long shr2 (unsigned long x)
+{
+  return x >> 2;
+}
+
+unsigned long shr3 (unsigned long x)
+{
+  return x >> 3;
+}
+
+unsigned long long shrl1ll (unsigned long long x)
+{
+  return x >> 1;
+}
+
+/* { dg-final { scan-assembler-times "shrw" 7 } } */
+/* { dg-final { scan-assembler-times "rcrw" 9 } } */
diff --git a/gcc/testsuite/gcc.target/ia16/torture/optimize/opt-6.c b/gcc/testsuite/gcc.target/ia16/torture/optimize/opt-6.c
new file mode 100644
index 0000000..99151d8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/optimize/opt-6.c
@@ -0,0 +1,53 @@
+/* { dg-do run } */
+/* { dg-options "-std=gnu11 --save-temps" } */
+
+/* Test that GCC does not produce erroneous code for 3-way comparisons
+   against zero.
+
+   This issue was reported by MFLD --- https://github.com/tkchia/gcc-ia16/
+   issues/40.  The code for this test case was mostly lifted from /bin/cat
+   for ELKS, by MTK et al. --- https://github.com/jbruchon/elks/blob/master/
+   elkscmd/file_utils/cat.c.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define CAT_BUF_SIZE 4096
+
+static char readbuf[CAT_BUF_SIZE];
+
+__attribute__((noinline))
+static int fake_read(int fd, char *buf, size_t n)
+{
+	int rv;
+	__asm volatile ("# read" : "=r" (rv)
+				 : "0" ((int)0), "r" (fd), "r" (buf), "r" (n)
+				 : "memory", "cc");
+	return 0;
+}
+
+__attribute__((noinline))
+static int fake_write(int fd, const char *buf, size_t n)
+{
+	int rv;
+	__asm volatile ("# write" : "=r" (rv)
+				  : "0" ((int)0), "r" (fd), "r" (buf), "r" (n)
+				  : "memory", "cc");
+	return 0;
+}
+
+static int dumpfile(int fd)
+{
+	int nred;
+
+	while ((nred = fake_read(fd, readbuf, CAT_BUF_SIZE)) > 0) {
+		fake_write(1, readbuf, nred);
+	}
+	if (nred < 0) return -1;
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	return dumpfile(0);
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/prot-mode-1.c b/gcc/testsuite/gcc.target/ia16/torture/prot-mode-1.c
new file mode 100644
index 0000000..a527716
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/prot-mode-1.c
@@ -0,0 +1,13 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do assemble } */
+
+/* Test that the __builtin_ia16_selector (.) function allows a value to be
+   loaded into a segment register for an __asm (...), whether or not
+   -mprotected-mode is enabled.  */
+
+void
+foo (unsigned sel1, unsigned sel2)
+{
+  __asm volatile ("" : : "Q" (__builtin_ia16_selector (sel1)),
+			 "Q" (__builtin_ia16_selector (sel2)));
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/regparmcall-3.c b/gcc/testsuite/gcc.target/ia16/torture/regparmcall-3.c
new file mode 100644
index 0000000..61daf64
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/regparmcall-3.c
@@ -0,0 +1,60 @@
+/* { dg-do assemble } */
+/* { dg-options "--std=gnu11 -Wall --save-temps" } */
+
+/* Do some basic tests to make sure that __attribute__ ((regparmcall)) does
+   not make GCC weird out.  */
+
+__attribute__ ((regparmcall)) int
+sort_of_printf (const char *, ...);
+
+typedef struct {
+  int x, y, z;
+} xyz_t;
+
+__attribute__ ((regparmcall)) xyz_t
+frob1 (xyz_t xyz)
+{
+  return xyz;
+}
+
+__attribute__ ((regparmcall)) unsigned long
+frob2 (unsigned x, unsigned long y, unsigned long z)
+{
+  return x + y + z;
+}
+
+__attribute__ ((regparmcall)) unsigned long long
+frob3 (unsigned long long x)
+{
+  return x + 1;
+}
+
+__attribute__ ((regparmcall)) unsigned long
+frob4 (unsigned long x, unsigned long y)
+{
+  return x + y;
+}
+
+__attribute__ ((regparmcall)) float
+frob5 (float x)
+{
+  return x + 1;
+}
+
+__attribute__ ((regparmcall)) double
+frob6 (double x)
+{
+  return x + 1;
+}
+
+__attribute__ ((regparmcall)) void
+frob7 (int x)
+{
+  sort_of_printf ("%d\n", x);
+}
+
+__attribute__ ((regparmcall)) unsigned long long
+frob8 (int x, ...)
+{
+  return x;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/torture/restore-ds-1.c b/gcc/testsuite/gcc.target/ia16/torture/restore-ds-1.c
new file mode 100644
index 0000000..f305257
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/torture/restore-ds-1.c
@@ -0,0 +1,39 @@
+/* { dg-options "-std=gnu11 --save-temps" } */
+/* { dg-do run } */
+
+/* Test that the restore_ds function attribute works.  */
+
+void abort (void);
+
+__attribute__ ((noinline, no_assume_ds_data, restore_ds)) static unsigned
+foo (void)
+{
+  unsigned v;
+  __asm volatile ("movw %%ds, %0" : "=r" (v)
+				  : "Rds" (__builtin_ia16_selector (0x73d5)));
+  return v;
+}
+
+__attribute__ ((noinline, no_assume_ds_data)) static unsigned
+bar (void)
+{
+  unsigned v;
+  __asm volatile ("movw %%ds, %0" : "=r" (v)
+				  : "Rds" (__builtin_ia16_selector (0x1709)));
+  return v;
+}
+
+int main (void)
+{
+  static volatile unsigned baz = 0xda16, qux = 0x350d;
+
+  if (foo () != 0x73d5)
+    abort ();
+  if (baz != 0xda16)
+    abort ();
+  if (bar () != 0x1709)
+    abort ();
+  if (qux != 0x350d)
+    abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/ia16/xlat-1.c b/gcc/testsuite/gcc.target/ia16/xlat-1.c
new file mode 100644
index 0000000..0a19abb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/ia16/xlat-1.c
@@ -0,0 +1,18 @@
+/* { dg-do assemble } */
+/* { dg-options "-O3 --save-temps" } */
+
+/* Test that `xlat' instructions are prefixed with the proper segment override
+   if %ds != %ss and if we are optimizing.  */
+
+void abort (void);
+
+unsigned char
+foo (unsigned char x)
+{
+  static unsigned char map[] = "0123456789abcdef";
+
+  __asm volatile ("" : : "a" (x), "b" (map), "Rds" (0));
+  return map[x];
+}
+
+/* { dg-final { scan-assembler "xlat\[ \\t\]%ss:" } } */
diff --git a/gcc/testsuite/lib/g++.exp b/gcc/testsuite/lib/g++.exp
index aebd500..fcf8605 100644
--- a/gcc/testsuite/lib/g++.exp
+++ b/gcc/testsuite/lib/g++.exp
@@ -309,6 +309,10 @@ proc g++_target_compile { source dest type options } {
 	lappend options "ldflags=$TEST_EXTRA_LIBS"
     }
 
+    if [target_info exists g++,stack_size] {
+        lappend options "additional_flags=-DSTACK_SIZE=[target_info g++,stack_size]"
+    }
+
     lappend options "additional_flags=[libio_include_flags]"
     lappend options "compiler=$GXX_UNDER_TEST"
     lappend options "timeout=[timeout_value]"
diff --git a/gcc/testsuite/lib/gcc-dg.exp b/gcc/testsuite/lib/gcc-dg.exp
index 9dd909b..ceefaec 100644
--- a/gcc/testsuite/lib/gcc-dg.exp
+++ b/gcc/testsuite/lib/gcc-dg.exp
@@ -335,8 +335,11 @@ proc gcc-dg-prune { system text } {
     if { !$allow_blank_lines } {
 	set num_blank_lines [llength [regexp -all -inline "\n\n" $text]]
 	if { $num_blank_lines } {
-	    global testname_with_flags
-	    fail "$testname_with_flags $num_blank_lines blank line(s) in output"
+	    set testcase ""
+	    if [info exists testname_with_flags] {
+		set testcase $testname_with_flags
+	    }
+	    fail "$testcase $num_blank_lines blank line(s) in output"
 	}
 	set allow_blank_lines 0
     }
diff --git a/gcc/testsuite/lib/prune.exp b/gcc/testsuite/lib/prune.exp
index ab6f369..f3f9bdb 100644
--- a/gcc/testsuite/lib/prune.exp
+++ b/gcc/testsuite/lib/prune.exp
@@ -28,6 +28,7 @@ proc prune_gcc_output { text } {
 
     #send_user "Before:$text\n"
 
+    regsub -all "(^|\n)\[^\n\]*: warning: target system does not support debug output\[^\n\]*" $text "" text
     regsub -all "(^|\n)(\[^\n\]*: )?In ((static member |lambda )?function|member|method|(copy )?constructor|destructor|instantiation|substitution|program|subroutine|block-data)\[^\n\]*" $text "" text
     regsub -all "(^|\n)\[^\n\]*(: )?At (top level|global scope):\[^\n\]*" $text "" text
     regsub -all "(^|\n)\[^\n\]*:   (recursively )?required \[^\n\]*" $text "" text
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index f0f5ac4..4d3b5af 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -569,6 +569,7 @@ proc check_profiling_available { test_what } {
 	     || [istarget crisv32-*-*]
 	     || [istarget fido-*-elf]
 	     || [istarget h8300-*-*]
+	     || [istarget ia16-*-*]
 	     || [istarget lm32-*-*]
 	     || [istarget m32c-*-elf]
 	     || [istarget m68k-*-elf]
diff --git a/gcc/tree-ssa-address.c b/gcc/tree-ssa-address.c
index 9e49f3d..a501633 100644
--- a/gcc/tree-ssa-address.c
+++ b/gcc/tree-ssa-address.c
@@ -247,7 +247,14 @@ addr_for_mem_ref (struct mem_address *addr, addr_space_t as,
       if (off)
 	*templ->off_p = off;
 
-      return templ->ref;
+      address = templ->ref;
+      if (pointer_mode != address_mode)
+	{
+	  address = convert_memory_address_addr_space (address_mode,
+						       address, as);
+	  templ->ref = address;
+	}
+      return address;
     }
 
   /* Otherwise really expand the expressions.  */
@@ -263,7 +270,7 @@ addr_for_mem_ref (struct mem_address *addr, addr_space_t as,
 
   gen_addr_rtx (pointer_mode, sym, bse, idx, st, off, &address, NULL, NULL);
   if (pointer_mode != address_mode)
-    address = convert_memory_address (address_mode, address);
+    address = convert_memory_address_addr_space (address_mode, address, as);
   return address;
 }
 
diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c
index a016e9f..22d84bc 100644
--- a/gcc/tree-ssa-loop-ivopts.c
+++ b/gcc/tree-ssa-loop-ivopts.c
@@ -1173,7 +1173,27 @@ find_bivs (struct ivopts_data *data)
       if (step)
 	{
 	  if (POINTER_TYPE_P (type))
-	    step = convert_to_ptrofftype (step);
+	    {
+#ifdef TARGET_ADDR_SPACE_WEIRD_P
+	      /* Special case hack for ia16-elf.  Apparently IA-16 far
+		 pointers (32-bit) do not yet interact well with this
+		 optimization, partly because they are bigger than the
+		 16-bit `sizetype'.
+
+		 Changing `sizetype' to 32-bit caused other problems --- GCC
+		 crashed while trying to compile libgcc.
+
+		 (Plus, _if_ far pointers are implemented properly, they
+		 will also have arithmetic rules that differ from normal
+		 `unsigned long' arithmetic.  And this will likely lead to
+		 even more weirdness down the road, unless we find a way to
+		 teach this compiler pass about those rules...)  */
+	      if (TARGET_ADDR_SPACE_WEIRD_P
+		  (TYPE_ADDR_SPACE (TREE_TYPE (type))))
+		continue;
+#endif
+	      step = convert_to_ptrofftype (step);
+	    }
 	  else
 	    step = fold_convert (type, step);
 	}
@@ -2832,6 +2852,13 @@ add_candidate_1 (struct ivopts_data *data,
   if (pos != IP_ORIGINAL)
     {
       orig_type = TREE_TYPE (base);
+#ifdef TARGET_ADDR_SPACE_WEIRD_P
+      /* Special case hack for ia16-elf.  */
+      if (POINTER_TYPE_P (orig_type)
+	  && TARGET_ADDR_SPACE_WEIRD_P (TYPE_ADDR_SPACE
+					(TREE_TYPE (orig_type))))
+	return NULL;
+#endif
       type = generic_type_for (orig_type);
       if (type != orig_type)
 	{
diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c
index 565cbcb..40446ad 100644
--- a/gcc/tree-vect-data-refs.c
+++ b/gcc/tree-vect-data-refs.c
@@ -4266,6 +4266,7 @@ vect_create_data_ref_ptr (gimple *stmt, tree aggr_type, struct loop *at_loop,
   gimple *incr;
   tree step;
   bb_vec_info bb_vinfo = STMT_VINFO_BB_VINFO (stmt_info);
+  machine_mode ptr_mode_as;
 
   gcc_assert (TREE_CODE (aggr_type) == ARRAY_TYPE
 	      || TREE_CODE (aggr_type) == VECTOR_TYPE);
@@ -4346,7 +4347,8 @@ vect_create_data_ref_ptr (gimple *stmt, tree aggr_type, struct loop *at_loop,
 	}
       while (orig_stmt);
     }
-  aggr_ptr_type = build_pointer_type_for_mode (aggr_type, ptr_mode,
+  ptr_mode_as = targetm.addr_space.pointer_mode (TYPE_ADDR_SPACE (aggr_type));
+  aggr_ptr_type = build_pointer_type_for_mode (aggr_type, ptr_mode_as,
 					       need_ref_all);
   aggr_ptr = vect_get_new_vect_var (aggr_ptr_type, vect_pointer_var, base_name);
 
diff --git a/gcc/tree.c b/gcc/tree.c
index 5c9f6f4..a0e27ac 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -4841,7 +4841,9 @@ build_type_attribute_qual_variant (tree ttype, tree attribute, int quals)
 	  return build_qualified_type (ttype, quals);
 	}
 
-      ttype = build_qualified_type (ttype, TYPE_UNQUALIFIED);
+      /* tkchia 20190924 */
+      ttype = build_qualified_type (ttype,
+				    TYPE_QUALS (TYPE_MAIN_VARIANT (ttype)));
       ntype = build_distinct_type_copy (ttype);
 
       TYPE_ATTRIBUTES (ntype) = attribute;
diff --git a/gcc/ubsan.c b/gcc/ubsan.c
index 56637d8..1093824 100644
--- a/gcc/ubsan.c
+++ b/gcc/ubsan.c
@@ -1471,7 +1471,7 @@ ubsan_use_new_style_p (location_t loc)
 
   expanded_location xloc = expand_location (loc);
   if (xloc.file == NULL || strncmp (xloc.file, "\1", 2) == 0
-      || xloc.file == '\0' || xloc.file[0] == '\xff'
+      || xloc.file[0] == '\0' || xloc.file[0] == '\xff'
       || xloc.file[1] == '\xff')
     return false;
 
diff --git a/include/longlong.h b/include/longlong.h
index 34ad9b4..10650a7 100644
--- a/include/longlong.h
+++ b/include/longlong.h
@@ -451,6 +451,40 @@ extern UDItype __umulsidi3 (USItype, USItype);
 #endif /* __zarch__ */
 #endif
 
+#if defined (__ia16__) && W_TYPE_SIZE == 16
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("addw %5,%1\n\tadcw %3,%0"		\
+	   : "=r" ((UHItype) (sh)),					\
+	     "=&r" ((UHItype) (sl))					\
+	   : "%0" ((UHItype) (ah)),					\
+	     "g" ((UHItype) (bh)),					\
+	     "%1" ((UHItype) (al)),					\
+	     "g" ((UHItype) (bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("subw %5,%1\n\tsbbw %3,%0"		\
+	   : "=r" ((UHItype) (sh)),					\
+	     "=&r" ((UHItype) (sl))					\
+	   : "0" ((UHItype) (ah)),					\
+	     "g" ((UHItype) (bh)),					\
+	     "1" ((UHItype) (al)),					\
+	     "g" ((UHItype) (bl)))
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("mulw %3"							\
+	   : "=a" ((UHItype) (w0)),					\
+	     "=d" ((UHItype) (w1))					\
+	   : "%0" ((UHItype) (u)),					\
+	     "rm" ((UHItype) (v)))
+#define udiv_qrnnd(q, r, n1, n0, dv) \
+  __asm__ ("divw %4"							\
+	   : "=a" ((UHItype) (q)),					\
+	     "=d" ((UHItype) (r))					\
+	   : "0" ((UHItype) (n0)),					\
+	     "1" ((UHItype) (n1)),					\
+	     "rm" ((UHItype) (dv)))
+#define UMUL_TIME 40
+#define UDIV_TIME 40
+#endif /* ia16 */
+
 #if (defined (__i386__) || defined (__i486__)) && W_TYPE_SIZE == 32
 #define add_ssaaaa(sh, sl, ah, al, bh, bl) \
   __asm__ ("add{l} {%5,%1|%1,%5}\n\tadc{l} {%3,%0|%0,%3}"		\
diff --git a/libada/Makefile.in b/libada/Makefile.in
index 89c566b..e8211ca 100644
--- a/libada/Makefile.in
+++ b/libada/Makefile.in
@@ -67,7 +67,7 @@ host_subdir = @host_subdir@
 GCC_DIR=$(MULTIBUILDTOP)../../$(host_subdir)/gcc
 
 target_noncanonical:=@target_noncanonical@
-version := $(shell cat $(srcdir)/../gcc/BASE-VER)
+version := $(shell @get_gcc_base_ver@ $(srcdir)/../gcc/BASE-VER)
 libsubdir := $(libdir)/gcc/$(target_noncanonical)/$(version)$(MULTISUBDIR)
 ADA_RTS_DIR=$(GCC_DIR)/ada/rts$(subst /,_,$(MULTISUBDIR))
 ADA_RTS_SUBDIR=./rts$(subst /,_,$(MULTISUBDIR))
diff --git a/libada/configure b/libada/configure
index 2296096..7f759da 100755
--- a/libada/configure
+++ b/libada/configure
@@ -553,6 +553,7 @@ PACKAGE_URL=
 ac_unique_file="Makefile.in"
 ac_subst_vars='LTLIBOBJS
 LIBOBJS
+get_gcc_base_ver
 have_getipinfo
 default_gnatlib_target
 LN_S
@@ -633,6 +634,7 @@ enable_maintainer_mode
 enable_multilib
 enable_shared
 with_system_libunwind
+with_gcc_major_version_only
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1261,6 +1263,8 @@ Optional Packages:
   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
   --with-build-libsubdir=DIR  Directory where to find libraries for build system
   --with-system-libunwind use installed libunwind
+  --with-gcc-major-version-only
+                          use only GCC major number in filesystem paths
 
 Some influential environment variables:
   CC          C compiler command
@@ -3008,6 +3012,21 @@ if test x$have_unwind_getipinfo = xyes; then
 fi
 
 
+# Determine what GCC version number to use in filesystem paths.
+
+  get_gcc_base_ver="cat"
+
+# Check whether --with-gcc-major-version-only was given.
+if test "${with_gcc_major_version_only+set}" = set; then :
+  withval=$with_gcc_major_version_only; if test x$with_gcc_major_version_only = xyes ; then
+        get_gcc_base_ver="sed -e 's/^\([0-9]*\).*\$\$/\1/'"
+      fi
+
+fi
+
+
+
+
 # Output: create a Makefile.
 ac_config_files="$ac_config_files Makefile"
 
diff --git a/libada/configure.ac b/libada/configure.ac
index 04e06fe..b2274de 100644
--- a/libada/configure.ac
+++ b/libada/configure.ac
@@ -144,6 +144,9 @@ if test x$have_unwind_getipinfo = xyes; then
 fi
 AC_SUBST(have_getipinfo)
 
+# Determine what GCC version number to use in filesystem paths.
+GCC_BASE_VER
+
 # Output: create a Makefile.
 AC_CONFIG_FILES([Makefile])
 
diff --git a/libatomic/Makefile.am b/libatomic/Makefile.am
index b351244..cf9c2b99 100644
--- a/libatomic/Makefile.am
+++ b/libatomic/Makefile.am
@@ -26,7 +26,7 @@ ACLOCAL_AMFLAGS = -I .. -I ../config
 SUBDIRS = testsuite
 
 ## May be used by toolexeclibdir.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 
 config_path= @config_path@
 search_path = $(addprefix $(top_srcdir)/config/, $(config_path)) \
diff --git a/libatomic/Makefile.in b/libatomic/Makefile.in
index a083d87..f6eeab3 100644
--- a/libatomic/Makefile.in
+++ b/libatomic/Makefile.in
@@ -259,6 +259,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
@@ -298,7 +299,7 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 ACLOCAL_AMFLAGS = -I .. -I ../config
 SUBDIRS = testsuite
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 search_path = $(addprefix $(top_srcdir)/config/, $(config_path)) \
 	$(top_srcdir) $(top_builddir)
 
diff --git a/libatomic/configure b/libatomic/configure
index 8526abf..0b8b60f 100755
--- a/libatomic/configure
+++ b/libatomic/configure
@@ -601,6 +601,7 @@ ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+get_gcc_base_ver
 ARCH_X86_64_FALSE
 ARCH_X86_64_TRUE
 ARCH_I386_FALSE
@@ -763,6 +764,7 @@ with_gnu_ld
 enable_libtool_lock
 enable_maintainer_mode
 enable_symvers
+with_gcc_major_version_only
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1415,6 +1417,8 @@ Optional Packages:
   --with-pic              try to use only PIC/non-PIC objects [default=use
                           both]
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+  --with-gcc-major-version-only
+                          use only GCC major number in filesystem paths
 
 Some influential environment variables:
   CC          C compiler command
@@ -9083,7 +9087,7 @@ _LT_EOF
 	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
 	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
 	else
-	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
 	fi
 	aix_use_runtimelinking=no
 
@@ -11111,7 +11115,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11114 "configure"
+#line 11118 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11217,7 +11221,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11220 "configure"
+#line 11224 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -15256,6 +15260,21 @@ else
 fi
 
 
+# Determine what GCC version number to use in filesystem paths.
+
+  get_gcc_base_ver="cat"
+
+# Check whether --with-gcc-major-version-only was given.
+if test "${with_gcc_major_version_only+set}" = set; then :
+  withval=$with_gcc_major_version_only; if test x$with_gcc_major_version_only = xyes ; then
+        get_gcc_base_ver="sed -e 's/^\([0-9]*\).*\$\$/\1/'"
+      fi
+
+fi
+
+
+
+
 if test ${multilib} = yes; then
   multilib_arg="--enable-multilib"
 else
diff --git a/libatomic/configure.ac b/libatomic/configure.ac
index cf40ea1..c4445b1 100644
--- a/libatomic/configure.ac
+++ b/libatomic/configure.ac
@@ -254,6 +254,9 @@ AM_CONDITIONAL(ARCH_I386,
 AM_CONDITIONAL(ARCH_X86_64,
 	       [test "$ARCH" = x86 && test x$libat_cv_wordsize = x8])
 
+# Determine what GCC version number to use in filesystem paths.
+GCC_BASE_VER
+
 if test ${multilib} = yes; then
   multilib_arg="--enable-multilib"
 else
diff --git a/libatomic/testsuite/Makefile.in b/libatomic/testsuite/Makefile.in
index 34f83e0..f0928b2 100644
--- a/libatomic/testsuite/Makefile.in
+++ b/libatomic/testsuite/Makefile.in
@@ -174,6 +174,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
diff --git a/libcc1/Makefile.in b/libcc1/Makefile.in
index 79d39d3..21fb153 100644
--- a/libcc1/Makefile.in
+++ b/libcc1/Makefile.in
@@ -236,6 +236,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 gcc_version = @gcc_version@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
diff --git a/libcc1/configure b/libcc1/configure
index bf112bb..d6f480f 100755
--- a/libcc1/configure
+++ b/libcc1/configure
@@ -610,6 +610,7 @@ WERROR
 WARN_FLAGS
 CONFIG_STATUS_DEPENDENCIES
 gcc_version
+get_gcc_base_ver
 visibility
 CXXCPP
 am__fastdepCXX_FALSE
@@ -747,6 +748,7 @@ with_pic
 enable_fast_install
 with_gnu_ld
 enable_libtool_lock
+with_gcc_major_version_only
 enable_werror_always
 enable_plugin
 '
@@ -1403,6 +1405,8 @@ Optional Packages:
   --with-pic              try to use only PIC/non-PIC objects [default=use
                           both]
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+  --with-gcc-major-version-only
+                          use only GCC major number in filesystem paths
 
 Some influential environment variables:
   CC          C compiler command
@@ -10540,7 +10544,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10543 "configure"
+#line 10547 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -10646,7 +10650,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10649 "configure"
+#line 10653 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -14305,7 +14309,25 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
-gcc_version=`cat $srcdir/../gcc/BASE-VER`
+
+  get_gcc_base_ver="cat"
+
+# Check whether --with-gcc-major-version-only was given.
+if test "${with_gcc_major_version_only+set}" = set; then :
+  withval=$with_gcc_major_version_only; if test x$with_gcc_major_version_only = xyes ; then
+        get_gcc_base_ver="sed -e 's/^\([0-9]*\).*\$\$/\1/'"
+      fi
+
+fi
+
+
+
+
+if test x$with_gcc_major_version_only = xyes ; then
+    gcc_version=`sed -e 's/^\([0-9]*\).*$/\1/' $srcdir/../gcc/BASE-VER`
+  else
+  gcc_version=`cat $srcdir/../gcc/BASE-VER`
+fi
 
 CONFIG_STATUS_DEPENDENCIES='$(top_srcdir)/../gcc/BASE-VER'
 
diff --git a/libcc1/configure.ac b/libcc1/configure.ac
index e2e3fda..e4ae20a 100644
--- a/libcc1/configure.ac
+++ b/libcc1/configure.ac
@@ -48,7 +48,15 @@ AC_SUBST(visibility)
 
 AC_CHECK_DECLS([basename])
 
-gcc_version=`cat $srcdir/../gcc/BASE-VER`
+GCC_BASE_VER
+
+if test x$with_gcc_major_version_only = xyes ; then
+  changequote(,)dnl
+  gcc_version=`sed -e 's/^\([0-9]*\).*$/\1/' $srcdir/../gcc/BASE-VER`
+  changequote([,])dnl
+else
+  gcc_version=`cat $srcdir/../gcc/BASE-VER`
+fi
 AC_SUBST(gcc_version)
 AC_SUBST([CONFIG_STATUS_DEPENDENCIES], ['$(top_srcdir)/../gcc/BASE-VER'])
 
diff --git a/libcilkrts/Makefile.am b/libcilkrts/Makefile.am
index 4f944dd..543c3fc 100644
--- a/libcilkrts/Makefile.am
+++ b/libcilkrts/Makefile.am
@@ -51,7 +51,7 @@ AM_CPPFLAGS = $(GENERAL_FLAGS)
 AM_LDFLAGS = $(XLDFLAGS)
 
 # May be used by toolexeclibdir.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 
 # Target list.
 nodist_toolexeclib_HEADERS = libcilkrts.spec
diff --git a/libcilkrts/Makefile.in b/libcilkrts/Makefile.in
index a25d1c6..bfcec16 100644
--- a/libcilkrts/Makefile.in
+++ b/libcilkrts/Makefile.in
@@ -143,9 +143,10 @@ am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \
 	$(top_srcdir)/../config/lead-dot.m4 \
 	$(top_srcdir)/../config/multi.m4 \
 	$(top_srcdir)/../config/override.m4 \
-	$(top_srcdir)/../libtool.m4 $(top_srcdir)/../ltoptions.m4 \
-	$(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \
-	$(top_srcdir)/../lt~obsolete.m4 $(top_srcdir)/configure.ac
+	$(top_srcdir)/../config/acx.m4 $(top_srcdir)/../libtool.m4 \
+	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
+	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
@@ -325,6 +326,7 @@ datarootdir = @datarootdir@
 docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
@@ -381,7 +383,7 @@ AM_CPPFLAGS = $(GENERAL_FLAGS)
 AM_LDFLAGS = $(XLDFLAGS)
 
 # May be used by toolexeclibdir.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 
 # Target list.
 nodist_toolexeclib_HEADERS = libcilkrts.spec
diff --git a/libcilkrts/aclocal.m4 b/libcilkrts/aclocal.m4
index a468681..71023b2 100644
--- a/libcilkrts/aclocal.m4
+++ b/libcilkrts/aclocal.m4
@@ -992,6 +992,7 @@ m4_include([../config/depstand.m4])
 m4_include([../config/lead-dot.m4])
 m4_include([../config/multi.m4])
 m4_include([../config/override.m4])
+m4_include([../config/acx.m4])
 m4_include([../libtool.m4])
 m4_include([../ltoptions.m4])
 m4_include([../ltsugar.m4])
diff --git a/libcilkrts/configure b/libcilkrts/configure
index 4e1d459..9b89da3 100644
--- a/libcilkrts/configure
+++ b/libcilkrts/configure
@@ -604,6 +604,7 @@ ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+get_gcc_base_ver
 link_cilkrts
 XLDFLAGS
 XCFLAGS
@@ -749,6 +750,7 @@ with_pic
 enable_fast_install
 with_gnu_ld
 enable_libtool_lock
+with_gcc_major_version_only
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1404,6 +1406,8 @@ Optional Packages:
   --with-pic              try to use only PIC/non-PIC objects [default=use
                           both]
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+  --with-gcc-major-version-only
+                          use only GCC major number in filesystem paths
 
 Some influential environment variables:
   CC          C compiler command
@@ -9036,7 +9040,7 @@ _LT_EOF
 	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
 	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
 	else
-	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
 	fi
 	aix_use_runtimelinking=no
 
@@ -11064,7 +11068,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11067 "configure"
+#line 11071 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11170,7 +11174,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11173 "configure"
+#line 11177 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -13522,7 +13526,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
     if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
       export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
     else
-      export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+      export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
     fi
     ;;
   pw32*)
@@ -14530,6 +14534,20 @@ else
 fi
 
 
+# Determine what GCC version number to use in filesystem paths.
+
+  get_gcc_base_ver="cat"
+
+# Check whether --with-gcc-major-version-only was given.
+if test "${with_gcc_major_version_only+set}" = set; then :
+  withval=$with_gcc_major_version_only; if test x$with_gcc_major_version_only = xyes ; then
+        get_gcc_base_ver="sed -e 's/^\([0-9]*\).*\$\$/\1/'"
+      fi
+
+fi
+
+
+
 
 # Must be last
 cat >confcache <<\_ACEOF
diff --git a/libcilkrts/configure.ac b/libcilkrts/configure.ac
index 8ad647e..cad6174 100644
--- a/libcilkrts/configure.ac
+++ b/libcilkrts/configure.ac
@@ -231,6 +231,8 @@ else
 fi
 AC_SUBST(link_cilkrts)
 
+# Determine what GCC version number to use in filesystem paths.
+GCC_BASE_VER
 
 # Must be last
 AC_OUTPUT
diff --git a/libcpp/expr.c b/libcpp/expr.c
index 5cdca6f..ecea3d5 100644
--- a/libcpp/expr.c
+++ b/libcpp/expr.c
@@ -683,10 +683,10 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token,
 
 	  if (CPP_OPTION (pfile, c99))
             cpp_warning_with_line (pfile, CPP_W_LONG_LONG, virtual_location,
-				   0, message);
+				   0, "%s", message);
           else
             cpp_pedwarning_with_line (pfile, CPP_W_LONG_LONG,
-				      virtual_location, 0, message);
+				      virtual_location, 0, "%s", message);
         }
 
       result |= CPP_N_INTEGER;
diff --git a/libcpp/macro.c b/libcpp/macro.c
index c251553..8e2b1fb 100644
--- a/libcpp/macro.c
+++ b/libcpp/macro.c
@@ -3090,7 +3090,7 @@ create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
 	     function-like macros, but not at the end.  */
 	  if (following_paste_op)
 	    {
-	      cpp_error (pfile, CPP_DL_ERROR, paste_op_error_msg);
+	      cpp_error (pfile, CPP_DL_ERROR, "%s", paste_op_error_msg);
 	      return false;
 	    }
 	  break;
@@ -3103,7 +3103,7 @@ create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
 	     function-like macros, but not at the beginning.  */
 	  if (macro->count == 1)
 	    {
-	      cpp_error (pfile, CPP_DL_ERROR, paste_op_error_msg);
+	      cpp_error (pfile, CPP_DL_ERROR, "%s", paste_op_error_msg);
 	      return false;
 	    }
 
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index f09b39b..47f071a 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -214,7 +214,7 @@ export slibdir
 export toolexecdir
 export toolexeclibdir
 
-version := $(shell cat $(srcdir)/../gcc/BASE-VER)
+version := $(shell @get_gcc_base_ver@ $(srcdir)/../gcc/BASE-VER)
 
 ifeq ($(decimal_float),yes)
 ifeq ($(enable_decimal_float),bid)
diff --git a/libgcc/config.host b/libgcc/config.host
index 124f2ce..952522f 100644
--- a/libgcc/config.host
+++ b/libgcc/config.host
@@ -123,6 +123,10 @@ i[34567]86-*-*)
 x86_64-*-*)
 	cpu_type=i386
 	;;
+ia16-*-*)
+	cpu_type=i8086
+	tmake_file=t-fdpbit
+	;;
 ia64-*-*)
 	;;
 hppa*-*-*)
@@ -753,6 +757,10 @@ x86_64-*-mingw*)
 i[34567]86-*-interix[3-9]*)
 	tmake_file="$tmake_file i386/t-interix i386/t-chkstk"
 	;;
+ia16-*-*)
+	extra_parts="crtbegin.o crtend.o"
+	tmake_file="$tmake_file ia16/t-ia16"
+	;;
 ia64*-*-elf*)
 	extra_parts="$extra_parts crtbeginS.o crtendS.o crtfastmath.o"
 	tmake_file="ia64/t-ia64 ia64/t-ia64-elf ia64/t-eh-ia64 t-crtfm"
diff --git a/libgcc/config/ia16/ashlsi3.S b/libgcc/config/ia16/ashlsi3.S
new file mode 100644
index 0000000..ca0687d
--- /dev/null
+++ b/libgcc/config/ia16/ashlsi3.S
@@ -0,0 +1,99 @@
+/* IA-16 implementation of 32-bit left shifts
+
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Written By TK Chia
+
+This file 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 3, or (at your option) any
+later version.
+
+This file 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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+#include "ia16-preamble.h"
+
+	.global	__ashlsi3
+	.type	__ashlsi3, @function
+__ashlsi3:
+#ifndef __IA16_CMODEL_IS_FAR_TEXT
+# ifdef __IA16_CALLCVT_CDECL
+#   ifdef __OPTIMIZE_SIZE__
+	popw	%bx
+	popw	%ax
+	popw	%dx
+	popw	%cx
+	pushw	%cx
+	pushw	%dx
+	pushw	%ax
+	pushw	%bx
+#   else
+	movw	%sp,	%bx
+	movw	2(%bx),	%ax
+	movw	4(%bx),	%dx
+	movb	6(%bx),	%cl
+#   endif
+# elif defined __IA16_CALLCVT_STDCALL
+	popw	%bx
+	popw	%ax
+	popw	%dx
+	popw	%cx
+	pushw	%bx
+# endif
+#else
+# ifdef __IA16_CALLCVT_CDECL
+	movw	%sp,	%bx
+	movw	4(%bx),	%ax
+	movw	6(%bx),	%dx
+	movb	8(%bx),	%cl
+# elif defined __IA16_CALLCVT_STDCALL
+	popw	%dx
+	popw	%cx
+	popw	%ax
+	movw	%sp,	%bx
+	xchgw	%dx,	(%bx)
+	xchgw	%cx,	2(%bx)
+# endif
+#endif
+	andw	$0x1f,	%cx
+# ifdef __OPTIMIZE_SIZE__
+	jcxz	1f
+0:
+	shlw	%ax
+	rclw	%dx
+	loop	0b
+# else
+	testb	$0x10,	%cl
+	jz	0f
+	movw	%ax,	%dx
+	xorw	%ax,	%ax
+	subb	$0x10,	%cl
+	shlw	%cl,	%dx
+NT_(	ret	)
+FT_(	lret	)
+0:
+	movw	%ax,	%bx
+	shlw	%cl,	%ax
+	/* Quickly figure out the bits we want to shift from the low
+	   shortword into the high shortword.  We can do this by taking the
+	   "difference" between the `shlw' and `rolw' results.  */
+	rolw	%cl,	%bx
+	xorw	%ax,	%bx
+	/* Then combine them with the bits from the high shortword.  */
+	shlw	%cl,	%dx
+	orw	%bx,	%dx
+#endif
+1:
+NT_(	ret	)
+FT_(	lret	)
diff --git a/libgcc/config/ia16/divsi3.S b/libgcc/config/ia16/divsi3.S
new file mode 100644
index 0000000..84bdb01
--- /dev/null
+++ b/libgcc/config/ia16/divsi3.S
@@ -0,0 +1,2 @@
+#define L_divsi3
+#include "ia16-divmodsi.h"
diff --git a/libgcc/config/ia16/gtdf2.S b/libgcc/config/ia16/gtdf2.S
new file mode 100644
index 0000000..020723b
--- /dev/null
+++ b/libgcc/config/ia16/gtdf2.S
@@ -0,0 +1,32 @@
+/* IA-16 forwarder routines for double-precision floating point comparisons
+
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Written By TK Chia
+
+This file 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 3, or (at your option) any
+later version.
+
+This file 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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+#include "ia16-preamble.h"
+
+	.global	__gtdf2
+	.type	__gtdf2, @function
+__gtdf2:
+NT_(	jmp	__gedf2			)
+FT_(	SR_(.+3, __gedf2)		)
+FT_(	ljmp	$0,	$__gedf2	)
diff --git a/libgcc/config/ia16/gtsf2.S b/libgcc/config/ia16/gtsf2.S
new file mode 100644
index 0000000..4ffae88
--- /dev/null
+++ b/libgcc/config/ia16/gtsf2.S
@@ -0,0 +1,32 @@
+/* IA-16 forwarder routines for single-precision floating point comparisons
+
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Written By TK Chia
+
+This file 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 3, or (at your option) any
+later version.
+
+This file 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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+#include "ia16-preamble.h"
+
+	.global	__gtsf2
+	.type	__gtsf2, @function
+__gtsf2:
+NT_(	jmp	__gesf2			)
+FT_(	SR_(.+3, __gesf2)		)
+FT_(	ljmp	$0,	$__gesf2	)
diff --git a/libgcc/config/ia16/ia16-divmodsi.h b/libgcc/config/ia16/ia16-divmodsi.h
new file mode 100644
index 0000000..64ab4af
--- /dev/null
+++ b/libgcc/config/ia16/ia16-divmodsi.h
@@ -0,0 +1,118 @@
+/* IA-16 implementations of __udivsi3, __umodsi3, __divsi3, and __modsi3, in
+   terms of internal routines
+
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Written By TK Chia
+
+This file 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 3, or (at your option) any
+later version.
+
+This file 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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+#include "ia16-preamble.h"
+
+#ifdef L_udivsi3
+	.global	__udivsi3
+	.type	__udivsi3, @function
+__udivsi3:
+#elif defined L_umodsi3
+	.global	__umodsi3
+	.type	__umodsi3, @function
+__umodsi3:
+#elif defined L_divsi3
+	.global	__divsi3
+	.type	__divsi3, @function
+__divsi3:
+#else
+	.global	__modsi3
+	.type	__modsi3, @function
+__modsi3:
+#endif
+#ifndef __IA16_CMODEL_IS_FAR_TEXT
+# if defined __IA16_CALLCVT_CDECL
+	movw	%sp,	%bx
+	movw	2(%bx),	%ax
+	movw	4(%bx),	%dx
+	movw	8(%bx),	%cx
+	movw	6(%bx),	%bx
+# elif defined __IA16_CALLCVT_STDCALL
+	/* Pop arguments but "push" the return address back.  */
+	popw	%cx
+	movw	%sp,	%bx
+	xchgw	%cx,	6(%bx)
+	popw	%ax
+	popw	%dx
+	popw	%bx
+# elif defined __IA16_CALLCVT_REGPARMCALL
+	popw	%cx
+	movw	%sp,	%bx
+	xchgw	%cx,	2(%bx)
+	popw	%bx
+# else
+#   error "unknown calling convention!"
+# endif
+	/* Then invoke our helper routine.  */
+# ifdef L_udivsi3
+	jmp	__ia16_ldivmodu
+# elif defined L_umodsi3
+	call	__ia16_ldivmodu
+	movw	%cx,	%dx
+	movw	%bx,	%ax
+	ret
+# elif defined L_divsi3
+	jmp	__ia16_ldivmods
+# else
+	call	__ia16_ldivmods
+	movw	%cx,	%dx
+	movw	%bx,	%ax
+	ret
+# endif
+#else
+# if defined __IA16_CALLCVT_CDECL || defined __IA16_CALLCVT_STDCALL
+	movw	%sp,	%bx
+	movw	4(%bx),	%ax
+	movw	6(%bx),	%dx
+	movw	10(%bx), %cx
+	movw	8(%bx),	%bx
+# elif defined __IA16_CALLCVT_REGPARMCALL
+	movw	%sp,	%bx
+	movw	6(%bx), %cx
+	movw	4(%bx),	%bx
+# else
+#   error "unknown calling convention!"
+# endif
+# ifdef L_udivsi3
+	call	__ia16_ldivmodu
+# elif defined L_umodsi3
+	call	__ia16_ldivmodu
+	movw	%cx,	%dx
+	movw	%bx,	%ax
+# elif defined L_divsi3
+	call	__ia16_ldivmods
+# else
+	call	__ia16_ldivmods
+	movw	%cx,	%dx
+	movw	%bx,	%ax
+# endif
+# ifdef __IA16_CALLCVT_CDECL
+	lret
+# elif defined __IA16_CALLCVT_STDCALL
+	lret	$8
+# else
+	lret	$4
+# endif
+#endif
diff --git a/libgcc/config/ia16/ia16-far-call-pop-thunks.S b/libgcc/config/ia16/ia16-far-call-pop-thunks.S
new file mode 100644
index 0000000..53cbbc9
--- /dev/null
+++ b/libgcc/config/ia16/ia16-far-call-pop-thunks.S
@@ -0,0 +1,76 @@
+/* IA-16 far -> near call thunks with argument popping
+
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Written By TK Chia
+
+This file 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 3, or (at your option) any
+later version.
+
+This file 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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+#include "ia16-preamble.h"
+
+	/* These routine must go into the near text segment, if at all.  */
+	.text
+
+	.global	__ia16_far_call_pop_thunk.bx.si.si
+	.type	__ia16_far_call_pop_thunk.bx.si.si, @function
+	.global	__ia16_far_call_pop_thunk.bx.di.di
+	.type	__ia16_far_call_pop_thunk.bx.di.di, @function
+__ia16_far_call_pop_thunk.bx.si.si:
+	pushw	%si			/* remember stack arguments size */
+	pushw	%bp
+	movw	%sp,	%bp
+	pushw	%bx			/* preserve %bx, %cx, and %ax */
+	pushw	%cx
+	pushw	%ax
+	movw	%si,	%cx		/* move stack args. size to %cx */
+	jmp	0f
+__ia16_far_call_pop_thunk.bx.di.di:
+	pushw	%di
+	pushw	%bp
+	movw	%sp,	%bp
+	pushw	%bx
+	pushw	%cx
+	pushw	%ax
+	movw	%di,	%cx
+0:					/* re-push stack arguments */
+	jcxz	2f
+	leaw	6(%bp),	%bx
+	addw	%cx,	%bx
+	movw	%bx,	%ax
+	shrw	%cx
+1:
+	pushw	%ss:(%bx)
+	decw	%bx
+	decw	%bx
+	loop	1b
+	xchgw	%ax,	%bx		/* overwrite original stack */
+	movw	6(%bp),	%ax		/*   arguments with return address */
+	movw	%ax,	%ss:(%bx)
+	movw	4(%bp),	%ax
+	movw	%ax,	%ss:-2(%bx)
+2:
+	movw	-6(%bp), %ax		/* reload %ax and %cx for callee */
+	movw	-4(%bp), %cx
+	callw	*-2(%bp)		/* call function */
+	movw	%bp,	%sp		/* tear down stack frame */
+	popw	%bp
+	popw	%bx
+	addw	%bx,	%sp		/* pop stack arguments --- except
+					   for the return address we wrote */
+	lretw				/* return! */
diff --git a/libgcc/config/ia16/ia16-far-call-thunks.S b/libgcc/config/ia16/ia16-far-call-thunks.S
new file mode 100644
index 0000000..a72a413
--- /dev/null
+++ b/libgcc/config/ia16/ia16-far-call-thunks.S
@@ -0,0 +1,62 @@
+/* IA-16 far -> near call thunks without argument popping
+
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Written By TK Chia
+
+This file 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 3, or (at your option) any
+later version.
+
+This file 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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+#include "ia16-preamble.h"
+
+	/* These routines must go into the near text segment, if at all.  */
+	.text
+
+	.global	__ia16_far_call_thunk.bx.si
+	.type	__ia16_far_call_thunk.bx.si, @function
+	.global	__ia16_far_call_thunk.bx.di
+	.type	__ia16_far_call_thunk.bx.di, @function
+__ia16_far_call_thunk.bx.si:
+	pushw	%bp			/* set up stack frame */
+	movw	%sp,	%bp
+	pushw	%bx			/* preserve %bx and %cx */
+	pushw	%cx
+	movw	%si,	%cx		/* move stack args. size to %cx */
+	jmp	0f
+__ia16_far_call_thunk.bx.di:
+	pushw	%bp
+	movw	%sp,	%bp
+	pushw	%bx
+	pushw	%cx
+	movw	%di,	%cx
+0:					/* re-push stack arguments */
+	jcxz	2f
+	leaw	4(%bp),	%bx
+	addw	%cx,	%bx
+	shrw	%cx
+1:
+	pushw	%ss:(%bx)
+	decw	%bx
+	decw	%bx
+	loop	1b
+2:
+	movw	-4(%bp), %cx		/* reload %cx for callee */
+	callw	*-2(%bp)		/* call function */
+	movw	%bp,	%sp		/* tear down stack frame and return */
+	popw	%bp
+	lretw
diff --git a/libgcc/config/ia16/ia16-ldivmods.S b/libgcc/config/ia16/ia16-ldivmods.S
new file mode 100644
index 0000000..63bff9b
--- /dev/null
+++ b/libgcc/config/ia16/ia16-ldivmods.S
@@ -0,0 +1,74 @@
+#include "ia16-preamble.h"
+
+	/*
+	 *	"When integers are divided, the result of the / operator is
+	 *	 the algebraic quotient with any fractional part discarded."
+	 *
+	 *	(footnote) "This is often called `truncation towards zero.'"
+	 *		-- N1570 draft of ISO/IEC 9899:2011 ("C11")
+	 *
+	 * CMU's SEI CERT C Coding Standard document (https://wiki.sei.cmu.edu/
+	 * confluence/pages/viewpage.action?pageId=87152120) further
+	 * elaborates on what this means:
+	 *
+	 *	"In C89 (and historical K&R implementations), the meaning of
+	 *	 the remainder operator for negative operands was
+	 *	 implementation-defined.  This behavior was changed in C99, and
+	 *	 the change remains in C11.  ...
+	 *
+	 *	"The result [of the modulo operator, %] has the same sign as
+	 *	 the dividend (the first operand in the expression)."
+	 */
+	.global	__ia16_ldivmods
+	.type	__ia16_ldivmods, @function
+__ia16_ldivmods:
+	testw	%cx,	%cx
+	js	.n_divor
+	testw	%dx,	%dx
+	js	.p_divor_n_divnd
+	/* Both divisor and dividend are positive.  */
+	jmp	__ia16_ldivmodu
+.p_divor_n_divnd:
+	/*
+	 * Divisor is positive, dividend is negative.  Negate the dividend,
+	 * then negate the results.
+	 *
+	 *	(-17L) / 3L == -(17L / 3L) == -5L
+	 *	(-17L) % 3L == -(17L % 3L) == -2L
+	 */
+	call	.negate_dxax
+	call	__ia16_ldivmodu
+	call	.negate_cxbx
+	jmp	.negate_dxax
+.n_divor:
+	call	.negate_cxbx
+	test	%dx,	%dx
+	js	.n_divor_n_divnd
+	/*
+	 * Divisor is negative, dividend is positive.  Negate the divisor,
+	 * then negate only the quotient.
+	 *
+	 *	17L / (-3L) == -(17L / 3L) == -5L
+	 *	17L % (-3L) == 17L % 3L == 2L
+	 */
+	call	__ia16_ldivmodu
+.negate_dxax:
+	negw	%ax
+	adcw	$0,	%dx
+	negw	%dx
+	ret
+.n_divor_n_divnd:
+	/*
+	 * Both the divisor and dividend are negative.  Negate both
+	 * operands, then negate only the remainder.
+	 *
+	 *	(-17L) / (-3L) == 17L / 3L == 5L
+	 *	(-17L) % (-3L) == -(17L % 3L) == -2L
+	 */
+	call	.negate_dxax
+	call	__ia16_ldivmodu
+.negate_cxbx:
+	negw	%bx
+	adcw	$0,	%cx
+	negw	%cx
+	ret
diff --git a/libgcc/config/ia16/ia16-ldivmodu.S b/libgcc/config/ia16/ia16-ldivmodu.S
new file mode 100644
index 0000000..e1482eb
--- /dev/null
+++ b/libgcc/config/ia16/ia16-ldivmodu.S
@@ -0,0 +1,63 @@
+#include "ia16-preamble.h"
+
+	/*
+	 * 32-bit division routine (https://github.com/FDOS/kernel/blob/
+	 * e6d427834fb5f414ecb984b87454d5df39f2f571/kernel/ludivmul.inc)
+	 * adapted by Bart Oldeman from code by Norbert Juffa, translated
+	 * into AT&T assembly syntax.  -- tkchia
+	 *
+	 *	"divide dx:ax / cx:bx, quotient in dx:ax, remainder in cx:bx"
+	 */
+	.global	__ia16_ldivmodu
+	.type	__ia16_ldivmodu, @function
+__ia16_ldivmodu:
+	testw	%cx,	%cx
+	jnz	.big_divisor
+	cmpw	%bx,	%dx
+	jb	.one_div
+	xchgw	%ax,	%cx
+	xchgw	%ax,	%dx
+	divw	%bx
+	xchgw	%ax,	%cx
+.one_div:
+	divw	%bx
+	movw	%dx,	%bx
+	movw	%cx,	%dx
+	xorw	%cx,	%cx
+	ret
+.big_divisor:
+	pushw	%si
+	pushw	%di
+	pushw	%dx
+	pushw	%ax
+	movw	%bx,	%si
+	movw	%cx,	%di
+.shift_loop:
+	shrw	%dx
+	rcrw	%ax
+	shrw	%cx
+	rcrw	%bx
+	jnz	.shift_loop
+	divw	%bx
+	popw	%bx
+	movw	%ax,	%cx
+	mulw	%di
+	popw	%dx
+	subw	%ax,	%dx
+	pushw	%dx
+	movw	%cx,	%ax
+	mulw	%si
+	subw	%ax,	%bx
+	movw	%cx,	%ax
+	popw	%cx
+	sbbw	%dx,	%cx
+	sbbw	%dx,	%dx
+	andw	%dx,	%si
+	andw	%dx,	%di
+	addw	%si,	%bx
+	adcw	%di,	%cx
+	addw	%dx,	%ax
+	xorw	%dx,	%dx
+	popw	%di
+	popw	%si
+	ret
diff --git a/libgcc/config/ia16/ia16-preamble.h b/libgcc/config/ia16/ia16-preamble.h
new file mode 100644
index 0000000..35a8617
--- /dev/null
+++ b/libgcc/config/ia16/ia16-preamble.h
@@ -0,0 +1,56 @@
+/* Common preamble for IA-16 assembly modules in libgcc
+
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Written By TK Chia
+
+This file 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 3, or (at your option) any
+later version.
+
+This file 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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+	.arch i8086,jumps
+	.code16
+	.att_syntax prefix
+
+#ifdef __IA16_CMODEL_IS_FAR_TEXT
+	/*
+	 * Under a far-text memory model (e.g. medium model), place all our
+	 * assembly language libgcc routines in the same far text segment. 
+	 * This allows the libgcc API routines to invoke internal routines
+	 * using near calls.
+	 */
+	.section .fartext.f.libgcc2.a.LIB2ADD$, "ax", @progbits
+	/*
+	 * FT_ (INSN) conditionally assembles an instruction INSN iff we are
+	 * building for a far-text memory model.  NT_ (INSN) does the opposite.
+	 *
+	 * SR_ (PLACE, SYM) installs an IA-16 segment relocation for SYM's
+	 * segment, at the place PLACE.
+	 */
+# define FT_(insn...)		insn
+# define NT_(insn...)
+#else
+	.text
+# define FT_(insn...)
+# define NT_(insn...)		insn
+#endif
+#ifdef __IA16_ABI_SEGELF
+# define SR__(place, aux)	.reloc (place), R_386_SEG16, #aux
+# define SR_(place, sym)	SR__(place, sym##!)
+#else
+# define SR_(place, sym)	.reloc (place), R_386_OZSEG16, sym
+#endif
diff --git a/libgcc/config/ia16/lshrsi3.S b/libgcc/config/ia16/lshrsi3.S
new file mode 100644
index 0000000..b8a845c
--- /dev/null
+++ b/libgcc/config/ia16/lshrsi3.S
@@ -0,0 +1,95 @@
+/* IA-16 implementation of 32-bit right logicall shifts
+
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Written By TK Chia
+
+This file 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 3, or (at your option) any
+later version.
+
+This file 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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+#include "ia16-preamble.h"
+
+	.global	__lshrsi3
+	.type	__lshrsi3, @function
+__lshrsi3:
+#ifndef __IA16_CMODEL_IS_FAR_TEXT
+# ifdef __IA16_CALLCVT_CDECL
+#   ifdef __OPTIMIZE_SIZE__
+	popw	%bx
+	popw	%ax
+	popw	%dx
+	popw	%cx
+	pushw	%cx
+	pushw	%dx
+	pushw	%ax
+	pushw	%bx
+#   else
+	movw	%sp,	%bx
+	movw	2(%bx),	%ax
+	movw	4(%bx),	%dx
+	movb	6(%bx),	%cl
+#   endif
+# elif defined __IA16_CALLCVT_STDCALL
+	popw	%bx
+	popw	%ax
+	popw	%dx
+	popw	%cx
+	pushw	%bx
+# endif
+#else
+# ifdef __IA16_CALLCVT_CDECL
+	movw	%sp,	%bx
+	movw	4(%bx),	%ax
+	movw	6(%bx),	%dx
+	movb	8(%bx),	%cl
+# elif defined __IA16_CALLCVT_STDCALL
+	popw	%dx
+	popw	%cx
+	popw	%ax
+	movw	%sp,	%bx
+	xchgw	%dx,	(%bx)
+	xchgw	%cx,	2(%bx)
+# endif
+#endif
+	andw	$0x1f,	%cx
+#ifdef __OPTIMIZE_SIZE__
+	jcxz	1f
+0:
+	shrw	%dx
+	rcrw	%ax
+	loop	0b
+#else
+	testb	$0x10,	%cl
+	jz	0f
+	movw	%dx,	%ax
+	xorw	%dx,	%dx
+	subb	$0x10,	%cl
+	shrw	%cl,	%ax
+NT_(	ret	)
+FT_(	lret	)
+0:
+	movw	%dx,	%bx
+	shrw	%cl,	%dx
+	rorw	%cl,	%bx
+	xorw	%dx,	%bx
+	shrw	%cl,	%ax
+	orw	%bx,	%ax
+#endif
+1:
+NT_(	ret	)
+FT_(	lret	)
diff --git a/libgcc/config/ia16/modsi3.S b/libgcc/config/ia16/modsi3.S
new file mode 100644
index 0000000..a8b58ab
--- /dev/null
+++ b/libgcc/config/ia16/modsi3.S
@@ -0,0 +1,2 @@
+#define L_modsi3
+#include "ia16-divmodsi.h"
diff --git a/libgcc/config/ia16/nedf2-ltdf2-ledf2.S b/libgcc/config/ia16/nedf2-ltdf2-ledf2.S
new file mode 100644
index 0000000..8c6fffa
--- /dev/null
+++ b/libgcc/config/ia16/nedf2-ltdf2-ledf2.S
@@ -0,0 +1,38 @@
+/* IA-16 forwarder routines for double-precision floating point comparisons
+
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Written By TK Chia
+
+This file 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 3, or (at your option) any
+later version.
+
+This file 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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+#include "ia16-preamble.h"
+
+	.global	__nedf2
+	.global	__ltdf2
+	.global	__ledf2
+	.type	__nedf2, @function
+	.type	__ltdf2, @function
+	.type	__ledf2, @function
+__nedf2:
+__ltdf2:
+__ledf2:
+NT_(	jmp	__eqdf2			)
+FT_(	SR_(.+3, __eqdf2)		)
+FT_(	ljmp	$0,	$__eqdf2	)
diff --git a/libgcc/config/ia16/nesf2-ltsf2-lesf2.S b/libgcc/config/ia16/nesf2-ltsf2-lesf2.S
new file mode 100644
index 0000000..efb3b50
--- /dev/null
+++ b/libgcc/config/ia16/nesf2-ltsf2-lesf2.S
@@ -0,0 +1,43 @@
+/* IA-16 forwarder routines for single-precision floating point comparisons
+
+   Copyright (C) 2019 Free Software Foundation, Inc.
+   Written By TK Chia
+
+This file 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 3, or (at your option) any
+later version.
+
+This file 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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+#include "ia16-preamble.h"
+
+	/*
+	 * It would be better if ELF supports aliases to external symbols
+	 * (blog.omega-prime.co.uk/2011/07/06/the-sad-state-of-symbol-aliases/)
+	 * --- then we can get rid of even the jump.  -- tkchia 20190322
+	 */
+	.global	__nesf2
+	.global	__ltsf2
+	.global	__lesf2
+	.type	__nesf2, @function
+	.type	__ltsf2, @function
+	.type	__lesf2, @function
+__nesf2:
+__ltsf2:
+__lesf2:
+NT_(	jmp	__eqsf2			)
+FT_(	SR_(.+3, __eqsf2)		)
+FT_(	ljmp	$0,	$__eqsf2	)
diff --git a/libgcc/config/ia16/t-ia16 b/libgcc/config/ia16/t-ia16
new file mode 100644
index 0000000..2b0841b
--- /dev/null
+++ b/libgcc/config/ia16/t-ia16
@@ -0,0 +1,76 @@
+# 16.1 Target Makefile Fragments
+
+ifneq ($(filter -Os -mprotected-mode -melks%,$(CC) $(CFLAGS)),)
+  HOST_LIBGCC2_CFLAGS += -Os
+endif
+FPBIT_CFLAGS = -DSMALL_MACHINE
+DPBIT_CFLAGS = -DSMALL_MACHINE
+
+# Extra 32-bit integer functions.
+intfuncs32 = _ashrXX3 _cmpXX2 _ucmpXX2
+siintfuncs32 = $(subst XX,si,$(intfuncs32))
+diintfuncs32 = $(subst XX,di,$(intfuncs32))
+
+iter-items := $(siintfuncs)
+iter-labels := $(diintfuncs)
+iter-sizes := $(patsubst %,2,$(siintfuncs))
+
+include $(srcdir)/empty.mk $(patsubst %,$(srcdir)/siditi-object.mk,$(iter-items))
+
+libgcc-objects += $(patsubst %,%$(objext),$(siintfuncs32))
+ifeq ($(enable_shared),yes)
+libgcc-s-objects += $(patsubst %,%_s$(objext),$(siintfuncs32))
+endif
+
+# Extra 16-bit integer functions.
+intfuncs16 = _absvXX2 _addvXX3 _subvXX3 _mulvXX3 _negvXX2 _ffsXX2 _clzXX2 \
+	     _ctzXX2 _popcountXX2 _clrsbXX2
+hiintfuncs16 = $(subst XX,hi,$(intfuncs16))
+siintfuncs16 = $(subst XX,si,$(intfuncs16))
+
+iter-items := $(siintfuncs32) $(hiintfuncs16)
+iter-labels := $(diintfuncs32) $(siintfuncs16)
+iter-sizes := $(patsubst %,2,$(siintfuncs16)) $(patsubst %,2,$(hiintfuncs16))
+
+include $(srcdir)/empty.mk $(patsubst %,$(srcdir)/siditi-object.mk,$(iter-items))
+
+libgcc-objects += $(patsubst %,%$(objext),$(hiintfuncs16))
+ifeq ($(enable_shared),yes)
+libgcc-s-objects += $(patsubst %,%_s$(objext),$(hiintfuncs16))
+endif
+
+# These might cause a divide overflow trap and so are compiled with
+# unwinder info.
+#lib2_divmodsi_funcs = _divXX3 _modXX3 _udivXX3 _umodXX3 _udivmodXX4
+lib2_divmodsi_funcs = _udivmodXX4
+
+lib2-divmodsi-o = $(patsubst %,%$(objext),$(subst XX,si,$(lib2_divmodsi_funcs)))
+$(lib2-divmodsi-o): %$(objext): $(srcdir)/libgcc2.c
+	$(gcc_compile) -DL$(subst si,di,$*) -c $< \
+	  $(LIB2_DIVMOD_EXCEPTION_FLAGS) $(vis_hide) \
+	-DLIBGCC2_UNITS_PER_WORD=2
+libgcc-objects += $(lib2-divmodsi-o)
+
+# Assembly language implementations of some routines.
+LIB2FUNCS_EXCLUDE += _udivsi3 _umodsi3 _divsi3 _modsi3 \
+		     _ashlsi3 _lshrsi3 \
+		     _ne_sf _gt_sf _le_sf _lt_sf _ne_df _gt_df _le_df _lt_df
+LIB2ADD += $(srcdir)/config/ia16/udivsi3.S \
+	   $(srcdir)/config/ia16/umodsi3.S \
+	   $(srcdir)/config/ia16/ia16-ldivmodu.S \
+	   $(srcdir)/config/ia16/divsi3.S \
+	   $(srcdir)/config/ia16/modsi3.S \
+	   $(srcdir)/config/ia16/ia16-ldivmods.S \
+	   $(srcdir)/config/ia16/ashlsi3.S \
+	   $(srcdir)/config/ia16/lshrsi3.S \
+	   $(srcdir)/config/ia16/nesf2-ltsf2-lesf2.S \
+	   $(srcdir)/config/ia16/gtsf2.S \
+	   $(srcdir)/config/ia16/nedf2-ltdf2-ledf2.S \
+	   $(srcdir)/config/ia16/gtdf2.S \
+	   $(srcdir)/config/ia16/ia16-far-call-thunks.S \
+	   $(srcdir)/config/ia16/ia16-far-call-pop-thunks.S
+
+$(patsubst $(srcdir)/config/ia16/%.S,%$(objext),$(LIB2ADD)) : \
+	%.o: $(srcdir)/config/ia16/%.S \
+	     $(srcdir)/config/ia16/ia16-preamble.h \
+	     $(srcdir)/config/ia16/ia16-divmodsi.h
diff --git a/libgcc/config/ia16/udivsi3.S b/libgcc/config/ia16/udivsi3.S
new file mode 100644
index 0000000..72b472b
--- /dev/null
+++ b/libgcc/config/ia16/udivsi3.S
@@ -0,0 +1,2 @@
+#define L_udivsi3
+#include "ia16-divmodsi.h"
diff --git a/libgcc/config/ia16/umodsi3.S b/libgcc/config/ia16/umodsi3.S
new file mode 100644
index 0000000..43d68fe
--- /dev/null
+++ b/libgcc/config/ia16/umodsi3.S
@@ -0,0 +1,2 @@
+#define L_umodsi3
+#include "ia16-divmodsi.h"
diff --git a/libgcc/configure b/libgcc/configure
index e7d6c75..3b1384c 100644
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -558,6 +558,7 @@ LIBOBJS
 asm_hidden_op
 extra_parts
 cpu_type
+get_gcc_base_ver
 thread_header
 tm_defines
 tm_file
@@ -673,6 +674,7 @@ with_system_libunwind
 enable_explicit_exception_frame_registration
 with_glibc_version
 enable_tls
+with_gcc_major_version_only
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1327,6 +1329,8 @@ Optional Packages:
   --with-system-libunwind use installed libunwind
   --with-glibc-version=M.N
                           assume GCC used with glibc version M.N or later
+  --with-gcc-major-version-only
+                          use only GCC major number in filesystem paths
 
 Some influential environment variables:
   CC          C compiler command
@@ -5081,6 +5085,21 @@ esac
 
 
 
+# Determine what GCC version number to use in filesystem paths.
+
+  get_gcc_base_ver="cat"
+
+# Check whether --with-gcc-major-version-only was given.
+if test "${with_gcc_major_version_only+set}" = set; then :
+  withval=$with_gcc_major_version_only; if test x$with_gcc_major_version_only = xyes ; then
+        get_gcc_base_ver="sed -e 's/^\([0-9]*\).*\$\$/\1/'"
+      fi
+
+fi
+
+
+
+
 # Substitute configuration variables
 
 
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 269997f..24a5a0d 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -544,6 +544,9 @@ AC_SUBST(tm_defines)
 # Map from thread model to thread header.
 GCC_AC_THREAD_HEADER([$target_thread_file])
 
+# Determine what GCC version number to use in filesystem paths.
+GCC_BASE_VER
+
 # Substitute configuration variables
 AC_SUBST(cpu_type)
 AC_SUBST(extra_parts)
diff --git a/libgfortran/Makefile.am b/libgfortran/Makefile.am
index 39d3e11..a8ecf85 100644
--- a/libgfortran/Makefile.am
+++ b/libgfortran/Makefile.am
@@ -4,7 +4,7 @@
 ACLOCAL_AMFLAGS = -I .. -I ../config
 
 ## May be used by toolexeclibdir.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 
 ## Symbol versioning (copied from libssp).
 if LIBGFOR_USE_SYMVER
diff --git a/libgfortran/Makefile.in b/libgfortran/Makefile.in
index 7ed080c..e5c1688 100644
--- a/libgfortran/Makefile.in
+++ b/libgfortran/Makefile.in
@@ -543,6 +543,7 @@ enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
 extra_ldflags_libgfortran = @extra_ldflags_libgfortran@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
@@ -584,7 +585,7 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 ACLOCAL_AMFLAGS = -I .. -I ../config
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 @LIBGFOR_USE_SYMVER_FALSE@version_arg = 
 @LIBGFOR_USE_SYMVER_GNU_TRUE@@LIBGFOR_USE_SYMVER_TRUE@version_arg = -Wl,--version-script=$(srcdir)/gfortran.map
 @LIBGFOR_USE_SYMVER_SUN_TRUE@@LIBGFOR_USE_SYMVER_TRUE@version_arg = -Wl,-M,gfortran.map-sun
diff --git a/libgfortran/configure b/libgfortran/configure
index f746f6f..731e76f 100755
--- a/libgfortran/configure
+++ b/libgfortran/configure
@@ -605,6 +605,7 @@ ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+get_gcc_base_ver
 IEEE_FLAGS
 IEEE_SUPPORT
 IEEE_SUPPORT_FALSE
@@ -776,6 +777,7 @@ with_gnu_ld
 enable_libtool_lock
 enable_largefile
 enable_libquadmath_support
+with_gcc_major_version_only
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1434,6 +1436,8 @@ Optional Packages:
   --with-pic              try to use only PIC/non-PIC objects [default=use
                           both]
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+  --with-gcc-major-version-only
+                          use only GCC major number in filesystem paths
 
 Some influential environment variables:
   CC          C compiler command
@@ -10308,7 +10312,7 @@ _LT_EOF
 	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
 	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
 	else
-	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
 	fi
 	aix_use_runtimelinking=no
 
@@ -12363,7 +12367,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12366 "configure"
+#line 12370 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12469,7 +12473,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12472 "configure"
+#line 12476 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -14157,7 +14161,7 @@ _LT_EOF
 	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
 	  export_symbols_cmds_FC='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
 	else
-	  export_symbols_cmds_FC='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	  export_symbols_cmds_FC='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
 	fi
 	aix_use_runtimelinking=no
 
@@ -26172,6 +26176,21 @@ $as_echo "#define HAVE_CRLF 1" >>confdefs.h
 
 fi
 
+# Determine what GCC version number to use in filesystem paths.
+
+  get_gcc_base_ver="cat"
+
+# Check whether --with-gcc-major-version-only was given.
+if test "${with_gcc_major_version_only+set}" = set; then :
+  withval=$with_gcc_major_version_only; if test x$with_gcc_major_version_only = xyes ; then
+        get_gcc_base_ver="sed -e 's/^\([0-9]*\).*\$\$/\1/'"
+      fi
+
+fi
+
+
+
+
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
 # tests run on this system so they can be shared between configure
diff --git a/libgfortran/configure.ac b/libgfortran/configure.ac
index 8f377bb..5c68a2d 100644
--- a/libgfortran/configure.ac
+++ b/libgfortran/configure.ac
@@ -607,6 +607,9 @@ LIBGFOR_CHECK_UNLINK_OPEN_FILE
 # Check whether line terminator is LF or CRLF
 LIBGFOR_CHECK_CRLF
 
+# Determine what GCC version number to use in filesystem paths.
+GCC_BASE_VER
+
 AC_CACHE_SAVE
 
 if test ${multilib} = yes; then
diff --git a/libgomp/Makefile.am b/libgomp/Makefile.am
index a3e1c2b..d346827 100644
--- a/libgomp/Makefile.am
+++ b/libgomp/Makefile.am
@@ -4,7 +4,7 @@ ACLOCAL_AMFLAGS = -I .. -I ../config
 SUBDIRS = testsuite
 
 ## May be used by toolexeclibdir.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 
 config_path = @config_path@
 search_path = $(addprefix $(top_srcdir)/config/, $(config_path)) $(top_srcdir) \
diff --git a/libgomp/Makefile.in b/libgomp/Makefile.in
index 88c8517..082582e 100644
--- a/libgomp/Makefile.in
+++ b/libgomp/Makefile.in
@@ -17,7 +17,7 @@
 
 # Plugins for offload execution, Makefile.am fragment.
 #
-# Copyright (C) 2014-2016 Free Software Foundation, Inc.
+# Copyright (C) 2014-2017 Free Software Foundation, Inc.
 #
 # Contributed by Mentor Embedded.
 #
@@ -359,6 +359,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
@@ -402,7 +403,7 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 ACLOCAL_AMFLAGS = -I .. -I ../config
 SUBDIRS = testsuite
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 search_path = $(addprefix $(top_srcdir)/config/, $(config_path)) $(top_srcdir) \
 	      $(top_srcdir)/../include
 
diff --git a/libgomp/configure b/libgomp/configure
index 8d03eb6..bbebc95 100755
--- a/libgomp/configure
+++ b/libgomp/configure
@@ -601,6 +601,7 @@ ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+get_gcc_base_ver
 OMP_NEST_LOCK_25_KIND
 OMP_LOCK_25_KIND
 OMP_NEST_LOCK_25_ALIGN
@@ -798,6 +799,7 @@ with_hsa_kmt_lib
 enable_linux_futex
 enable_tls
 enable_symvers
+with_gcc_major_version_only
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1477,6 +1479,8 @@ Optional Packages:
                           specify directory for the installed HSA run-time
                           library
   --with-hsa-kmt-lib=PATH specify directory for installed HSA KMT library.
+  --with-gcc-major-version-only
+                          use only GCC major number in filesystem paths
 
 Some influential environment variables:
   CC          C compiler command
@@ -11145,7 +11149,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11148 "configure"
+#line 11152 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11251,7 +11255,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11254 "configure"
+#line 11258 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -16747,6 +16751,21 @@ fi
 
 CFLAGS="$save_CFLAGS"
 
+# Determine what GCC version number to use in filesystem paths.
+
+  get_gcc_base_ver="cat"
+
+# Check whether --with-gcc-major-version-only was given.
+if test "${with_gcc_major_version_only+set}" = set; then :
+  withval=$with_gcc_major_version_only; if test x$with_gcc_major_version_only = xyes ; then
+        get_gcc_base_ver="sed -e 's/^\([0-9]*\).*\$\$/\1/'"
+      fi
+
+fi
+
+
+
+
 ac_config_files="$ac_config_files omp.h omp_lib.h omp_lib.f90 libgomp_f.h"
 
 ac_config_files="$ac_config_files Makefile testsuite/Makefile libgomp.spec"
diff --git a/libgomp/configure.ac b/libgomp/configure.ac
index 2e41ca8..0983198 100644
--- a/libgomp/configure.ac
+++ b/libgomp/configure.ac
@@ -366,6 +366,9 @@ AC_SUBST(OMP_LOCK_25_KIND)
 AC_SUBST(OMP_NEST_LOCK_25_KIND)
 CFLAGS="$save_CFLAGS"
 
+# Determine what GCC version number to use in filesystem paths.
+GCC_BASE_VER
+
 AC_CONFIG_FILES(omp.h omp_lib.h omp_lib.f90 libgomp_f.h)
 AC_CONFIG_FILES(Makefile testsuite/Makefile libgomp.spec)
 AC_CONFIG_FILES([testsuite/libgomp-test-support.pt.exp:testsuite/libgomp-test-support.exp.in])
diff --git a/libgomp/testsuite/Makefile.in b/libgomp/testsuite/Makefile.in
index 4dbb406..ca7ab98 100644
--- a/libgomp/testsuite/Makefile.in
+++ b/libgomp/testsuite/Makefile.in
@@ -202,6 +202,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
diff --git a/libitm/Makefile.am b/libitm/Makefile.am
index 1dce82d..5b4aad8 100644
--- a/libitm/Makefile.am
+++ b/libitm/Makefile.am
@@ -4,7 +4,7 @@ ACLOCAL_AMFLAGS = -I .. -I ../config
 SUBDIRS = testsuite
 
 ## May be used by toolexeclibdir.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 
 abi_version = -fabi-version=4
 
diff --git a/libitm/Makefile.in b/libitm/Makefile.in
index 138eeb1..2c7ed47 100644
--- a/libitm/Makefile.in
+++ b/libitm/Makefile.in
@@ -292,6 +292,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
@@ -331,7 +332,7 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 ACLOCAL_AMFLAGS = -I .. -I ../config
 SUBDIRS = testsuite
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 abi_version = -fabi-version=4
 search_path = $(addprefix $(top_srcdir)/config/, $(config_path)) $(top_srcdir)
 fincludedir = $(libdir)/gcc/$(target_alias)/$(gcc_version)/finclude
diff --git a/libitm/configure b/libitm/configure
index 55332bb..ba71318 100644
--- a/libitm/configure
+++ b/libitm/configure
@@ -601,6 +601,7 @@ ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+get_gcc_base_ver
 ARCH_FUTEX_FALSE
 ARCH_FUTEX_TRUE
 ARCH_X86_AVX_FALSE
@@ -776,6 +777,7 @@ enable_maintainer_mode
 enable_linux_futex
 enable_tls
 enable_symvers
+with_gcc_major_version_only
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1431,6 +1433,8 @@ Optional Packages:
   --with-pic              try to use only PIC/non-PIC objects [default=use
                           both]
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+  --with-gcc-major-version-only
+                          use only GCC major number in filesystem paths
 
 Some influential environment variables:
   CC          C compiler command
@@ -9762,7 +9766,7 @@ _LT_EOF
 	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
 	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
 	else
-	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
 	fi
 	aix_use_runtimelinking=no
 
@@ -11790,7 +11794,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11793 "configure"
+#line 11797 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11896,7 +11900,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11899 "configure"
+#line 11903 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -14248,7 +14252,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
     if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
       export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
     else
-      export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+      export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
     fi
     ;;
   pw32*)
@@ -17636,6 +17640,21 @@ else
 fi
 
 
+# Determine what GCC version number to use in filesystem paths.
+
+  get_gcc_base_ver="cat"
+
+# Check whether --with-gcc-major-version-only was given.
+if test "${with_gcc_major_version_only+set}" = set; then :
+  withval=$with_gcc_major_version_only; if test x$with_gcc_major_version_only = xyes ; then
+        get_gcc_base_ver="sed -e 's/^\([0-9]*\).*\$\$/\1/'"
+      fi
+
+fi
+
+
+
+
 ac_config_files="$ac_config_files Makefile testsuite/Makefile libitm.spec"
 
 cat >confcache <<\_ACEOF
diff --git a/libitm/configure.ac b/libitm/configure.ac
index 3875aa0..7c0bbb0 100644
--- a/libitm/configure.ac
+++ b/libitm/configure.ac
@@ -286,5 +286,8 @@ AM_CONDITIONAL([ARCH_X86], [test "$ARCH" = x86])
 AM_CONDITIONAL([ARCH_X86_AVX], [test "$libitm_cv_as_avx" = yes])
 AM_CONDITIONAL([ARCH_FUTEX], [test $enable_linux_futex = yes])
 
+# Determine what GCC version number to use in filesystem paths.
+GCC_BASE_VER
+
 AC_CONFIG_FILES(Makefile testsuite/Makefile libitm.spec)
 AC_OUTPUT
diff --git a/libitm/testsuite/Makefile.in b/libitm/testsuite/Makefile.in
index 4d79781..a9967e5 100644
--- a/libitm/testsuite/Makefile.in
+++ b/libitm/testsuite/Makefile.in
@@ -184,6 +184,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
diff --git a/libmpx/Makefile.am b/libmpx/Makefile.am
index bd0a8b6..9ec6ec7 100644
--- a/libmpx/Makefile.am
+++ b/libmpx/Makefile.am
@@ -9,7 +9,7 @@ nodist_toolexeclib_HEADERS = libmpx.spec
 endif
 
 ## May be used by toolexeclibdir.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 
 # Work around what appears to be a GNU make bug handling MAKEFLAGS
 # values defined in terms of make variables, as is the case for CC and
diff --git a/libmpx/Makefile.in b/libmpx/Makefile.in
index d644af3..9b1d7a6 100644
--- a/libmpx/Makefile.in
+++ b/libmpx/Makefile.in
@@ -255,7 +255,7 @@ top_srcdir = @top_srcdir@
 ACLOCAL_AMFLAGS = -I .. -I ../config
 @LIBMPX_SUPPORTED_TRUE@SUBDIRS = mpxrt $(am__append_1)
 @LIBMPX_SUPPORTED_TRUE@nodist_toolexeclib_HEADERS = libmpx.spec
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 
 # Work around what appears to be a GNU make bug handling MAKEFLAGS
 # values defined in terms of make variables, as is the case for CC and
diff --git a/libmpx/configure b/libmpx/configure
index 16d0dd8..675e5f8 100644
--- a/libmpx/configure
+++ b/libmpx/configure
@@ -9202,7 +9202,7 @@ _LT_EOF
 	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
 	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
 	else
-	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
 	fi
 	aix_use_runtimelinking=no
 
@@ -11585,6 +11585,9 @@ else
   multilib_arg=
 fi
 
+# Determine what GCC version number to use in filesystem paths.
+GCC_BASE_VER
+
 ac_config_files="$ac_config_files Makefile libmpx.spec"
 
 ac_config_headers="$ac_config_headers config.h"
diff --git a/libmpx/configure.ac b/libmpx/configure.ac
index 18ba687..baa882b 100644
--- a/libmpx/configure.ac
+++ b/libmpx/configure.ac
@@ -125,6 +125,9 @@ else
   multilib_arg=
 fi
 
+# Determine what GCC version number to use in filesystem paths.
+GCC_BASE_VER
+
 AC_CONFIG_FILES([Makefile libmpx.spec])
 AC_CONFIG_HEADERS(config.h)
 AC_CONFIG_FILES(AC_FOREACH([DIR], [mpxrt mpxwrap], [DIR/Makefile ]),
diff --git a/libobjc/Makefile.in b/libobjc/Makefile.in
index b61823c..e89eaa9 100644
--- a/libobjc/Makefile.in
+++ b/libobjc/Makefile.in
@@ -31,7 +31,7 @@ VPATH = @glibcpp_srcdir@
 prefix = @prefix@
 exec_prefix = @exec_prefix@
 target_noncanonical = @target_noncanonical@
-gcc_version := $(shell cat $(srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(srcdir)/../gcc/BASE-VER)
 host_subdir = @host_subdir@
 top_srcdir = @top_srcdir@
 multi_basedir = @multi_basedir@
diff --git a/libobjc/configure b/libobjc/configure
index 55fcc33..e664203 100755
--- a/libobjc/configure
+++ b/libobjc/configure
@@ -600,6 +600,7 @@ ac_includes_default="\
 
 ac_subst_vars='LTLIBOBJS
 LIBOBJS
+get_gcc_base_ver
 SET_MAKE
 CPP
 OTOOL64
@@ -721,6 +722,7 @@ enable_fast_install
 with_gnu_ld
 enable_libtool_lock
 enable_tls
+with_gcc_major_version_only
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1365,6 +1367,8 @@ Optional Packages:
   --with-pic              try to use only PIC/non-PIC objects [default=use
                           both]
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+  --with-gcc-major-version-only
+                          use only GCC major number in filesystem paths
 
 Some influential environment variables:
   CC          C compiler command
@@ -8543,7 +8547,7 @@ _LT_EOF
 	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
 	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
 	else
-	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
 	fi
 	aix_use_runtimelinking=no
 
@@ -10598,7 +10602,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10601 "configure"
+#line 10605 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -10704,7 +10708,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10707 "configure"
+#line 10711 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11499,6 +11503,21 @@ $as_echo "#define HAVE_BITFIELD_TYPE_MATTERS 1" >>confdefs.h
   fi
 
 
+# Determine what GCC version number to use in filesystem paths.
+
+  get_gcc_base_ver="cat"
+
+# Check whether --with-gcc-major-version-only was given.
+if test "${with_gcc_major_version_only+set}" = set; then :
+  withval=$with_gcc_major_version_only; if test x$with_gcc_major_version_only = xyes ; then
+        get_gcc_base_ver="sed -e 's/^\([0-9]*\).*\$\$/\1/'"
+      fi
+
+fi
+
+
+
+
 # ------
 # Output
 # ------
diff --git a/libobjc/configure.ac b/libobjc/configure.ac
index 9dbc16c..1c0a33c 100644
--- a/libobjc/configure.ac
+++ b/libobjc/configure.ac
@@ -214,6 +214,9 @@ GCC_CHECK_TLS
 
 gt_BITFIELD_TYPE_MATTERS
 
+# Determine what GCC version number to use in filesystem paths.
+GCC_BASE_VER
+
 # ------
 # Output
 # ------
diff --git a/liboffloadmic/Makefile.am b/liboffloadmic/Makefile.am
index b145451..0df6944 100644
--- a/liboffloadmic/Makefile.am
+++ b/liboffloadmic/Makefile.am
@@ -42,7 +42,7 @@ libgomp_dir = $(build_dir)/../libgomp
 source_dir = $(top_srcdir)/runtime
 
 # May be used by toolexeclibdir.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 libsubincludedir = $(libdir)/gcc/$(target_alias)/$(gcc_version)/include
 
 # Target list.
diff --git a/liboffloadmic/Makefile.in b/liboffloadmic/Makefile.in
index 74fb3d2..b2cd7d5 100644
--- a/liboffloadmic/Makefile.in
+++ b/liboffloadmic/Makefile.in
@@ -93,9 +93,10 @@ am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \
 	$(top_srcdir)/../config/lead-dot.m4 \
 	$(top_srcdir)/../config/multi.m4 \
 	$(top_srcdir)/../config/override.m4 \
-	$(top_srcdir)/../libtool.m4 $(top_srcdir)/../ltoptions.m4 \
-	$(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \
-	$(top_srcdir)/../lt~obsolete.m4 $(top_srcdir)/configure.ac
+	$(top_srcdir)/../config/acx.m4 $(top_srcdir)/../libtool.m4 \
+	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
+	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
 am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
@@ -355,6 +356,7 @@ datarootdir = @datarootdir@
 docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
@@ -408,7 +410,7 @@ libgomp_dir = $(build_dir)/../libgomp
 source_dir = $(top_srcdir)/runtime
 
 # May be used by toolexeclibdir.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 libsubincludedir = $(libdir)/gcc/$(target_alias)/$(gcc_version)/include
 @LIBOFFLOADMIC_HOST_FALSE@nodist_toolexeclib_HEADERS = liboffloadmic_target.spec
 
diff --git a/liboffloadmic/aclocal.m4 b/liboffloadmic/aclocal.m4
index a468681..71023b2 100644
--- a/liboffloadmic/aclocal.m4
+++ b/liboffloadmic/aclocal.m4
@@ -992,6 +992,7 @@ m4_include([../config/depstand.m4])
 m4_include([../config/lead-dot.m4])
 m4_include([../config/multi.m4])
 m4_include([../config/override.m4])
+m4_include([../config/acx.m4])
 m4_include([../libtool.m4])
 m4_include([../ltoptions.m4])
 m4_include([../ltsugar.m4])
diff --git a/liboffloadmic/configure b/liboffloadmic/configure
index bcec118..01c7648 100644
--- a/liboffloadmic/configure
+++ b/liboffloadmic/configure
@@ -602,6 +602,7 @@ ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+get_gcc_base_ver
 link_offloadmic_target
 link_offloadmic_host
 lt_cv_dlopen_libs
@@ -744,6 +745,7 @@ with_pic
 enable_fast_install
 with_gnu_ld
 enable_libtool_lock
+with_gcc_major_version_only
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1398,6 +1400,8 @@ Optional Packages:
   --with-pic              try to use only PIC/non-PIC objects [default=use
                           both]
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+  --with-gcc-major-version-only
+                          use only GCC major number in filesystem paths
 
 Some influential environment variables:
   CC          C compiler command
@@ -9076,7 +9080,7 @@ _LT_EOF
 	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
 	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
 	else
-	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
 	fi
 	aix_use_runtimelinking=no
 
@@ -11104,7 +11108,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11107 "configure"
+#line 11111 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11210,7 +11214,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11213 "configure"
+#line 11217 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -13562,7 +13566,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
     if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
       export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
     else
-      export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+      export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
     fi
     ;;
   pw32*)
@@ -14481,6 +14485,21 @@ fi
 
 
 
+# Determine what GCC version number to use in filesystem paths.
+
+  get_gcc_base_ver="cat"
+
+# Check whether --with-gcc-major-version-only was given.
+if test "${with_gcc_major_version_only+set}" = set; then :
+  withval=$with_gcc_major_version_only; if test x$with_gcc_major_version_only = xyes ; then
+        get_gcc_base_ver="sed -e 's/^\([0-9]*\).*\$\$/\1/'"
+      fi
+
+fi
+
+
+
+
 # Must be last
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
@@ -17076,7 +17095,7 @@ ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
       ac_sub_configure=$ac_srcdir/configure.gnu
     elif test -f "$ac_srcdir/configure"; then
       ac_sub_configure=$ac_srcdir/configure
-    elif test -f "$ac_srcdir/configure.ac"; then
+    elif test -f "$ac_srcdir/configure.in"; then
       # This should be Cygnus configure.
       ac_sub_configure=$ac_aux_dir/configure
     else
diff --git a/liboffloadmic/configure.ac b/liboffloadmic/configure.ac
index 81fae8f..64728f1 100644
--- a/liboffloadmic/configure.ac
+++ b/liboffloadmic/configure.ac
@@ -128,5 +128,8 @@ fi
 AC_SUBST(link_offloadmic_host)
 AC_SUBST(link_offloadmic_target)
 
+# Determine what GCC version number to use in filesystem paths.
+GCC_BASE_VER
+
 # Must be last
 AC_OUTPUT
diff --git a/libquadmath/Makefile.am b/libquadmath/Makefile.am
index 5c4d3e2..ec23c66 100644
--- a/libquadmath/Makefile.am
+++ b/libquadmath/Makefile.am
@@ -9,7 +9,7 @@ ACLOCAL_AMFLAGS = -I .. -I ../config
 AM_CPPFLAGS = -I $(top_srcdir)/../include
 
 ## May be used by toolexeclibdir.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 
 ## Symbol versioning (copied from libssp).
 if LIBQUAD_USE_SYMVER
diff --git a/libquadmath/Makefile.in b/libquadmath/Makefile.in
index 94e8014..428e015 100644
--- a/libquadmath/Makefile.in
+++ b/libquadmath/Makefile.in
@@ -300,6 +300,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
@@ -340,7 +341,7 @@ top_srcdir = @top_srcdir@
 AUTOMAKE_OPTIONS = 1.8 foreign
 @BUILD_LIBQUADMATH_TRUE@ACLOCAL_AMFLAGS = -I .. -I ../config
 @BUILD_LIBQUADMATH_TRUE@AM_CPPFLAGS = -I $(top_srcdir)/../include
-@BUILD_LIBQUADMATH_TRUE@gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+@BUILD_LIBQUADMATH_TRUE@gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 @BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_FALSE@version_arg = 
 @BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_GNU_TRUE@@LIBQUAD_USE_SYMVER_TRUE@version_arg = -Wl,--version-script=$(srcdir)/quadmath.map
 @BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@version_arg = -Wl,-M,quadmath.map-sun
diff --git a/libquadmath/configure b/libquadmath/configure
index 851302e..eccb8b1 100755
--- a/libquadmath/configure
+++ b/libquadmath/configure
@@ -601,6 +601,7 @@ ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+get_gcc_base_ver
 GENINSRC_FALSE
 GENINSRC_TRUE
 BUILD_LIBQUADMATH_FALSE
@@ -750,6 +751,7 @@ enable_libtool_lock
 enable_maintainer_mode
 enable_symvers
 enable_generated_files_in_srcdir
+with_gcc_major_version_only
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1406,6 +1408,8 @@ Optional Packages:
   --with-pic              try to use only PIC/non-PIC objects [default=use
                           both]
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+  --with-gcc-major-version-only
+                          use only GCC major number in filesystem paths
 
 Some influential environment variables:
   CC          C compiler command
@@ -8513,7 +8517,7 @@ _LT_EOF
 	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
 	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
 	else
-	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
 	fi
 	aix_use_runtimelinking=no
 
@@ -10568,7 +10572,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10571 "configure"
+#line 10575 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -10674,7 +10678,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10677 "configure"
+#line 10681 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12918,6 +12922,20 @@ else
 fi
 
 
+# Determine what GCC version number to use in filesystem paths.
+
+  get_gcc_base_ver="cat"
+
+# Check whether --with-gcc-major-version-only was given.
+if test "${with_gcc_major_version_only+set}" = set; then :
+  withval=$with_gcc_major_version_only; if test x$with_gcc_major_version_only = xyes ; then
+        get_gcc_base_ver="sed -e 's/^\([0-9]*\).*\$\$/\1/'"
+      fi
+
+fi
+
+
+
 
 ac_config_files="$ac_config_files Makefile"
 
diff --git a/libquadmath/configure.ac b/libquadmath/configure.ac
index eb4fe8c..6d03c78 100644
--- a/libquadmath/configure.ac
+++ b/libquadmath/configure.ac
@@ -364,6 +364,8 @@ AS_HELP_STRING([--enable-generated-files-in-srcdir],
 AC_MSG_RESULT($enable_generated_files_in_srcdir)
 AM_CONDITIONAL(GENINSRC, test "$enable_generated_files_in_srcdir" = yes)
 
+# Determine what GCC version number to use in filesystem paths.
+GCC_BASE_VER
 
 AC_CONFIG_FILES(Makefile)
 AC_OUTPUT
diff --git a/libsanitizer/Makefile.am b/libsanitizer/Makefile.am
index 6b0c571..6afb2b0 100644
--- a/libsanitizer/Makefile.am
+++ b/libsanitizer/Makefile.am
@@ -24,7 +24,7 @@ endif
 endif
 
 ## May be used by toolexeclibdir.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 
 # Work around what appears to be a GNU make bug handling MAKEFLAGS
 # values defined in terms of make variables, as is the case for CC and
diff --git a/libsanitizer/Makefile.in b/libsanitizer/Makefile.in
index b362a89..7be5f1b 100644
--- a/libsanitizer/Makefile.in
+++ b/libsanitizer/Makefile.in
@@ -244,6 +244,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
@@ -290,7 +291,7 @@ nodist_saninclude_HEADERS = $(am__append_1)
 @SANITIZER_SUPPORTED_TRUE@SUBDIRS = sanitizer_common $(am__append_2) \
 @SANITIZER_SUPPORTED_TRUE@	$(am__append_3) lsan asan ubsan \
 @SANITIZER_SUPPORTED_TRUE@	$(am__append_4)
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 
 # Work around what appears to be a GNU make bug handling MAKEFLAGS
 # values defined in terms of make variables, as is the case for CC and
diff --git a/libsanitizer/asan/Makefile.in b/libsanitizer/asan/Makefile.in
index 881d1d3..b8e37dd 100644
--- a/libsanitizer/asan/Makefile.in
+++ b/libsanitizer/asan/Makefile.in
@@ -253,6 +253,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
diff --git a/libsanitizer/configure b/libsanitizer/configure
index 040ded0..6aff1e6 100755
--- a/libsanitizer/configure
+++ b/libsanitizer/configure
@@ -604,6 +604,7 @@ ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+get_gcc_base_ver
 TSAN_TARGET_DEPENDENT_OBJECTS
 LIBBACKTRACE_SUPPORTED_FALSE
 LIBBACKTRACE_SUPPORTED_TRUE
@@ -772,6 +773,7 @@ with_pic
 enable_fast_install
 with_gnu_ld
 enable_libtool_lock
+with_gcc_major_version_only
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1426,6 +1428,8 @@ Optional Packages:
   --with-pic              try to use only PIC/non-PIC objects [default=use
                           both]
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+  --with-gcc-major-version-only
+                          use only GCC major number in filesystem paths
 
 Some influential environment variables:
   CC          C compiler command
@@ -12028,7 +12032,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12031 "configure"
+#line 12035 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12134,7 +12138,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12137 "configure"
+#line 12141 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -16532,6 +16536,21 @@ fi
 
 
 
+# Determine what GCC version number to use in filesystem paths.
+
+  get_gcc_base_ver="cat"
+
+# Check whether --with-gcc-major-version-only was given.
+if test "${with_gcc_major_version_only+set}" = set; then :
+  withval=$with_gcc_major_version_only; if test x$with_gcc_major_version_only = xyes ; then
+        get_gcc_base_ver="sed -e 's/^\([0-9]*\).*\$\$/\1/'"
+      fi
+
+fi
+
+
+
+
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
 # tests run on this system so they can be shared between configure
diff --git a/libsanitizer/configure.ac b/libsanitizer/configure.ac
index 063b1d6..48aacd1 100644
--- a/libsanitizer/configure.ac
+++ b/libsanitizer/configure.ac
@@ -400,4 +400,7 @@ fi
 
 AC_SUBST([TSAN_TARGET_DEPENDENT_OBJECTS])
 
+# Determine what GCC version number to use in filesystem paths.
+GCC_BASE_VER
+
 AC_OUTPUT
diff --git a/libsanitizer/interception/Makefile.in b/libsanitizer/interception/Makefile.in
index c7ccb51..240eb1a 100644
--- a/libsanitizer/interception/Makefile.in
+++ b/libsanitizer/interception/Makefile.in
@@ -203,6 +203,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
diff --git a/libsanitizer/libbacktrace/Makefile.in b/libsanitizer/libbacktrace/Makefile.in
index 57eaaf0..00d6f9d 100644
--- a/libsanitizer/libbacktrace/Makefile.in
+++ b/libsanitizer/libbacktrace/Makefile.in
@@ -245,6 +245,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
diff --git a/libsanitizer/lsan/Makefile.in b/libsanitizer/lsan/Makefile.in
index 4802ed4..10c3eca 100644
--- a/libsanitizer/lsan/Makefile.in
+++ b/libsanitizer/lsan/Makefile.in
@@ -244,6 +244,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
diff --git a/libsanitizer/sanitizer_common/Makefile.in b/libsanitizer/sanitizer_common/Makefile.in
index 765efd1..bae5c37 100644
--- a/libsanitizer/sanitizer_common/Makefile.in
+++ b/libsanitizer/sanitizer_common/Makefile.in
@@ -232,6 +232,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
diff --git a/libsanitizer/tsan/Makefile.in b/libsanitizer/tsan/Makefile.in
index 14a4202..7974e6a 100644
--- a/libsanitizer/tsan/Makefile.in
+++ b/libsanitizer/tsan/Makefile.in
@@ -259,6 +259,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
diff --git a/libsanitizer/ubsan/Makefile.in b/libsanitizer/ubsan/Makefile.in
index f5b06d0..aaca356 100644
--- a/libsanitizer/ubsan/Makefile.in
+++ b/libsanitizer/ubsan/Makefile.in
@@ -242,6 +242,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
diff --git a/libssp/Makefile.am b/libssp/Makefile.am
index 5a2ecac..261b9a1 100644
--- a/libssp/Makefile.am
+++ b/libssp/Makefile.am
@@ -9,7 +9,7 @@ ACLOCAL_AMFLAGS = -I .. -I ../config
 MAINT_CHARSET = latin1
 
 # May be used by various substitution variables.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 
 if LIBSSP_USE_SYMVER
 if LIBSSP_USE_SYMVER_GNU
diff --git a/libssp/Makefile.in b/libssp/Makefile.in
index 4509e30..96b03ae 100644
--- a/libssp/Makefile.in
+++ b/libssp/Makefile.in
@@ -235,6 +235,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
@@ -278,7 +279,7 @@ ACLOCAL_AMFLAGS = -I .. -I ../config
 MAINT_CHARSET = latin1
 
 # May be used by various substitution variables.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 @LIBSSP_USE_SYMVER_FALSE@version_arg = 
 @LIBSSP_USE_SYMVER_GNU_TRUE@@LIBSSP_USE_SYMVER_TRUE@version_arg = -Wl,--version-script=$(srcdir)/ssp.map
 @LIBSSP_USE_SYMVER_SUN_TRUE@@LIBSSP_USE_SYMVER_TRUE@version_arg = -Wl,-M,ssp.map-sun
diff --git a/libssp/configure b/libssp/configure
index 44b00ba..19b7237 100755
--- a/libssp/configure
+++ b/libssp/configure
@@ -602,6 +602,7 @@ ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+get_gcc_base_ver
 toolexeclibdir
 toolexecdir
 enable_static
@@ -742,6 +743,7 @@ with_pic
 enable_fast_install
 with_gnu_ld
 enable_libtool_lock
+with_gcc_major_version_only
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1387,6 +1389,8 @@ Optional Packages:
   --with-pic              try to use only PIC/non-PIC objects [default=use
                           both]
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+  --with-gcc-major-version-only
+                          use only GCC major number in filesystem paths
 
 Some influential environment variables:
   CC          C compiler command
@@ -8612,7 +8616,7 @@ _LT_EOF
 	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
 	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
 	else
-	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
 	fi
 	aix_use_runtimelinking=no
 
@@ -10667,7 +10671,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10670 "configure"
+#line 10674 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -10773,7 +10777,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10776 "configure"
+#line 10780 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11071,6 +11075,21 @@ else
   multilib_arg=
 fi
 
+# Determine what GCC version number to use in filesystem paths.
+
+  get_gcc_base_ver="cat"
+
+# Check whether --with-gcc-major-version-only was given.
+if test "${with_gcc_major_version_only+set}" = set; then :
+  withval=$with_gcc_major_version_only; if test x$with_gcc_major_version_only = xyes ; then
+        get_gcc_base_ver="sed -e 's/^\([0-9]*\).*\$\$/\1/'"
+      fi
+
+fi
+
+
+
+
 ac_config_files="$ac_config_files Makefile ssp/ssp.h"
 
 cat >confcache <<\_ACEOF
diff --git a/libssp/configure.ac b/libssp/configure.ac
index 93dfa8d..9e4a22a 100644
--- a/libssp/configure.ac
+++ b/libssp/configure.ac
@@ -195,5 +195,8 @@ else
   multilib_arg=
 fi
 
+# Determine what GCC version number to use in filesystem paths.
+GCC_BASE_VER
+
 AC_CONFIG_FILES([Makefile ssp/ssp.h])
 AC_OUTPUT
diff --git a/libssp/ssp.c b/libssp/ssp.c
index 69805bc..0c12d48 100644
--- a/libssp/ssp.c
+++ b/libssp/ssp.c
@@ -58,6 +58,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #include <windows.h>
 #include <wincrypt.h>
 # define _PATH_TTY "CONOUT$"
+#elif defined (__MSDOS__)
+#include <time.h>
+#include <inttypes.h>
+# define _PATH_TTY "CON"
 #else
 # define _PATH_TTY "/dev/tty"
 #endif
@@ -90,6 +94,45 @@ __guard_setup (void)
         }
       CryptReleaseContext(hprovider, 0);
     }
+#elif defined (__MSDOS__) && defined (__ia16__)
+  {
+# ifdef __IA16_FEATURE_PROTECTED_MODE
+#   define LOOP_P()	1
+#   define TIME()	((uintptr_t) time (NULL))
+# else
+    /* Skip this timer wait loop if interrupts are disabled (or "disabled",
+       e.g. when running under 86sim).  */
+#   define LOOP_P()	({ \
+			  unsigned flags; \
+			  __asm volatile ("pushfw; popw %0" : "=r" (flags)); \
+			  (flags & 0x0200u) != 0; \
+			})
+#   define TIME()	(*(volatile uintptr_t __far *) 0x0000046cul)
+# endif
+    uintptr_t foo, bar, baz, qux;
+
+    __asm volatile ("" : "=r" (foo));
+    if (LOOP_P ())
+      {
+	qux = TIME ();
+	do
+	  ++foo;
+	while (TIME () == qux);
+      }
+    foo *= 0xa2edu;
+
+    __asm volatile ("movw %%ss, %0" : "=r" (bar));
+    bar *= 0xe335u;
+
+    baz = TIME ();
+    baz *= 0x3757u;
+
+    __stack_chk_guard = (void *) (foo ^ bar ^ baz);
+    if (__stack_chk_guard != 0)
+      return;
+  }
+# undef LOOP_P
+# undef TIME
 #else
   fd = open ("/dev/urandom", O_RDONLY);
   if (fd != -1)
diff --git a/libstdc++-v3/Makefile.in b/libstdc++-v3/Makefile.in
index 3159b71..d1e05a1 100644
--- a/libstdc++-v3/Makefile.in
+++ b/libstdc++-v3/Makefile.in
@@ -260,6 +260,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 glibcxx_MOFILES = @glibcxx_MOFILES@
 glibcxx_PCHFLAGS = @glibcxx_PCHFLAGS@
 glibcxx_POFILES = @glibcxx_POFILES@
@@ -316,7 +317,7 @@ toplevel_builddir = @toplevel_builddir@
 toplevel_srcdir = @toplevel_srcdir@
 
 # May be used by various substitution variables.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 MAINT_CHARSET = latin1
 mkinstalldirs = $(SHELL) $(toplevel_srcdir)/mkinstalldirs
 PWD_COMMAND = $${PWDCMD-pwd}
diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure
index 19173eb..3ac0116 100755
--- a/libstdc++-v3/configure
+++ b/libstdc++-v3/configure
@@ -602,6 +602,7 @@ ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+get_gcc_base_ver
 WARN_FLAGS
 OPTIMIZE_CXXFLAGS
 TOPLEVEL_INCLUDES
@@ -896,6 +897,7 @@ enable_libstdcxx_threads
 enable_libstdcxx_filesystem_ts
 with_gxx_include_dir
 enable_version_specific_runtime_libs
+with_gcc_major_version_only
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1615,6 +1617,8 @@ Optional Packages:
                           set the std::string ABI to use by default
   --with-gxx-include-dir=DIR
                           installation directory for include files
+  --with-gcc-major-version-only
+                          use only GCC major number in filesystem paths
 
 Some influential environment variables:
   CC          C compiler command
@@ -11596,7 +11600,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11599 "configure"
+#line 11603 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11702,7 +11706,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11705 "configure"
+#line 11709 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -15388,7 +15392,7 @@ $as_echo "$glibcxx_cv_atomic_long_long" >&6; }
   # Fake what AC_TRY_COMPILE does.
 
     cat > conftest.$ac_ext << EOF
-#line 15391 "configure"
+#line 15395 "configure"
 int main()
 {
   typedef bool atomic_type;
@@ -15423,7 +15427,7 @@ $as_echo "$glibcxx_cv_atomic_bool" >&6; }
     rm -f conftest*
 
     cat > conftest.$ac_ext << EOF
-#line 15426 "configure"
+#line 15430 "configure"
 int main()
 {
   typedef short atomic_type;
@@ -15458,7 +15462,7 @@ $as_echo "$glibcxx_cv_atomic_short" >&6; }
     rm -f conftest*
 
     cat > conftest.$ac_ext << EOF
-#line 15461 "configure"
+#line 15465 "configure"
 int main()
 {
   // NB: _Atomic_word not necessarily int.
@@ -15494,7 +15498,7 @@ $as_echo "$glibcxx_cv_atomic_int" >&6; }
     rm -f conftest*
 
     cat > conftest.$ac_ext << EOF
-#line 15497 "configure"
+#line 15501 "configure"
 int main()
 {
   typedef long long atomic_type;
@@ -15575,7 +15579,7 @@ $as_echo "$as_me: WARNING: Performance of certain classes will degrade as a resu
   # unnecessary for this test.
 
     cat > conftest.$ac_ext << EOF
-#line 15578 "configure"
+#line 15582 "configure"
 int main()
 {
   _Decimal32 d1;
@@ -15617,7 +15621,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
   # unnecessary for this test.
 
     cat > conftest.$ac_ext << EOF
-#line 15620 "configure"
+#line 15624 "configure"
 template<typename T1, typename T2>
   struct same
   { typedef T2 type; };
@@ -15651,7 +15655,7 @@ $as_echo "$enable_int128" >&6; }
     rm -f conftest*
 
     cat > conftest.$ac_ext << EOF
-#line 15654 "configure"
+#line 15658 "configure"
 template<typename T1, typename T2>
   struct same
   { typedef T2 type; };
@@ -28878,6 +28882,15 @@ else
 
     $as_echo "#define HAVE_ICONV 1" >>confdefs.h
 
+
+    # newlib-ia16 has strtold, which we can use to prevent c++locale.cc from
+    # pulling in sscanf, etc.  Messy hack.  -- tkchia 20180615
+    case "${host}" in
+      ia16-*-elf)
+        $as_echo "#define HAVE_STRTOLD 1" >>confdefs.h
+
+        ;;
+    esac
   else
 
 # Base decisions on target environment.
@@ -81429,6 +81442,21 @@ $as_echo "$gxx_include_dir" >&6; }
 
 
 
+# Determine what GCC version number to use in filesystem paths.
+
+  get_gcc_base_ver="cat"
+
+# Check whether --with-gcc-major-version-only was given.
+if test "${with_gcc_major_version_only+set}" = set; then :
+  withval=$with_gcc_major_version_only; if test x$with_gcc_major_version_only = xyes ; then
+        get_gcc_base_ver="sed -e 's/^\([0-9]*\).*\$\$/\1/'"
+      fi
+
+fi
+
+
+
+
 ac_config_files="$ac_config_files Makefile"
 
 ac_config_files="$ac_config_files scripts/testsuite_flags"
diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac
index 9e19e99..a33bc0b 100644
--- a/libstdc++-v3/configure.ac
+++ b/libstdc++-v3/configure.ac
@@ -323,6 +323,14 @@ else
     AC_DEFINE(HAVE_TANHF)
 
     AC_DEFINE(HAVE_ICONV)
+
+    # newlib-ia16 has strtold, which we can use to prevent c++locale.cc from
+    # pulling in sscanf, etc.  Messy hack.  -- tkchia 20180615
+    case "${host}" in
+      ia16-*-elf)
+        AC_DEFINE(HAVE_STRTOLD)
+        ;;
+    esac
   else
     GLIBCXX_CROSSCONFIG
   fi
@@ -498,6 +506,9 @@ GLIBCXX_EXPORT_INSTALL_INFO
 GLIBCXX_EXPORT_INCLUDES
 GLIBCXX_EXPORT_FLAGS
 
+# Determine what GCC version number to use in filesystem paths.
+GCC_BASE_VER
+
 dnl In autoconf 2.5x, AC_OUTPUT is replaced by four AC_CONFIG_* macros,
 dnl which can all be called multiple times as needed, plus one (different)
 dnl AC_OUTPUT macro.  This one lists the files to be created:
diff --git a/libstdc++-v3/doc/Makefile.in b/libstdc++-v3/doc/Makefile.in
index 3e729c1..86e9c1c 100644
--- a/libstdc++-v3/doc/Makefile.in
+++ b/libstdc++-v3/doc/Makefile.in
@@ -234,6 +234,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 glibcxx_MOFILES = @glibcxx_MOFILES@
 glibcxx_PCHFLAGS = @glibcxx_PCHFLAGS@
 glibcxx_POFILES = @glibcxx_POFILES@
@@ -298,7 +299,7 @@ toplevel_builddir = @toplevel_builddir@
 toplevel_srcdir = @toplevel_srcdir@
 
 # May be used by various substitution variables.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 MAINT_CHARSET = latin1
 mkinstalldirs = $(SHELL) $(toplevel_srcdir)/mkinstalldirs
 PWD_COMMAND = $${PWDCMD-pwd}
diff --git a/libstdc++-v3/fragment.am b/libstdc++-v3/fragment.am
index 03eb753..b380020 100644
--- a/libstdc++-v3/fragment.am
+++ b/libstdc++-v3/fragment.am
@@ -2,7 +2,7 @@
 ## This is used in all Makefile.am's.  Set defaults here.
 
 # May be used by various substitution variables.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 
 MAINT_CHARSET = latin1
 
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index 751f16b..a41ee56 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -232,6 +232,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 glibcxx_MOFILES = @glibcxx_MOFILES@
 glibcxx_PCHFLAGS = @glibcxx_PCHFLAGS@
 glibcxx_POFILES = @glibcxx_POFILES@
@@ -288,7 +289,7 @@ toplevel_builddir = @toplevel_builddir@
 toplevel_srcdir = @toplevel_srcdir@
 
 # May be used by various substitution variables.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 MAINT_CHARSET = latin1
 mkinstalldirs = $(SHELL) $(toplevel_srcdir)/mkinstalldirs
 PWD_COMMAND = $${PWDCMD-pwd}
diff --git a/libstdc++-v3/libsupc++/Makefile.in b/libstdc++-v3/libsupc++/Makefile.in
index f3648ac..187b4e1 100644
--- a/libstdc++-v3/libsupc++/Makefile.in
+++ b/libstdc++-v3/libsupc++/Makefile.in
@@ -303,6 +303,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 glibcxx_MOFILES = @glibcxx_MOFILES@
 glibcxx_PCHFLAGS = @glibcxx_PCHFLAGS@
 glibcxx_POFILES = @glibcxx_POFILES@
@@ -359,7 +360,7 @@ toplevel_builddir = @toplevel_builddir@
 toplevel_srcdir = @toplevel_srcdir@
 
 # May be used by various substitution variables.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 MAINT_CHARSET = latin1
 mkinstalldirs = $(SHELL) $(toplevel_srcdir)/mkinstalldirs
 PWD_COMMAND = $${PWDCMD-pwd}
diff --git a/libstdc++-v3/po/Makefile.in b/libstdc++-v3/po/Makefile.in
index 13993c8..02a96b3 100644
--- a/libstdc++-v3/po/Makefile.in
+++ b/libstdc++-v3/po/Makefile.in
@@ -232,6 +232,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 glibcxx_MOFILES = @glibcxx_MOFILES@
 glibcxx_PCHFLAGS = @glibcxx_PCHFLAGS@
 glibcxx_POFILES = @glibcxx_POFILES@
@@ -288,7 +289,7 @@ toplevel_builddir = @toplevel_builddir@
 toplevel_srcdir = @toplevel_srcdir@
 
 # May be used by various substitution variables.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 MAINT_CHARSET = latin1
 mkinstalldirs = $(SHELL) $(toplevel_srcdir)/mkinstalldirs
 PWD_COMMAND = $${PWDCMD-pwd}
diff --git a/libstdc++-v3/python/Makefile.in b/libstdc++-v3/python/Makefile.in
index 25b2ed4..c722b3d 100644
--- a/libstdc++-v3/python/Makefile.in
+++ b/libstdc++-v3/python/Makefile.in
@@ -262,6 +262,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 glibcxx_MOFILES = @glibcxx_MOFILES@
 glibcxx_PCHFLAGS = @glibcxx_PCHFLAGS@
 glibcxx_POFILES = @glibcxx_POFILES@
@@ -318,7 +319,7 @@ toplevel_builddir = @toplevel_builddir@
 toplevel_srcdir = @toplevel_srcdir@
 
 # May be used by various substitution variables.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 MAINT_CHARSET = latin1
 mkinstalldirs = $(SHELL) $(toplevel_srcdir)/mkinstalldirs
 PWD_COMMAND = $${PWDCMD-pwd}
diff --git a/libstdc++-v3/src/Makefile.in b/libstdc++-v3/src/Makefile.in
index 75a207a..03361fe 100644
--- a/libstdc++-v3/src/Makefile.in
+++ b/libstdc++-v3/src/Makefile.in
@@ -295,6 +295,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 glibcxx_MOFILES = @glibcxx_MOFILES@
 glibcxx_PCHFLAGS = @glibcxx_PCHFLAGS@
 glibcxx_POFILES = @glibcxx_POFILES@
@@ -351,7 +352,7 @@ toplevel_builddir = @toplevel_builddir@
 toplevel_srcdir = @toplevel_srcdir@
 
 # May be used by various substitution variables.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 MAINT_CHARSET = latin1
 mkinstalldirs = $(SHELL) $(toplevel_srcdir)/mkinstalldirs
 PWD_COMMAND = $${PWDCMD-pwd}
diff --git a/libstdc++-v3/src/c++11/Makefile.in b/libstdc++-v3/src/c++11/Makefile.in
index 5a24cb0..003e742 100644
--- a/libstdc++-v3/src/c++11/Makefile.in
+++ b/libstdc++-v3/src/c++11/Makefile.in
@@ -265,6 +265,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 glibcxx_MOFILES = @glibcxx_MOFILES@
 glibcxx_PCHFLAGS = @glibcxx_PCHFLAGS@
 glibcxx_POFILES = @glibcxx_POFILES@
@@ -321,7 +322,7 @@ toplevel_builddir = @toplevel_builddir@
 toplevel_srcdir = @toplevel_srcdir@
 
 # May be used by various substitution variables.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 MAINT_CHARSET = latin1
 mkinstalldirs = $(SHELL) $(toplevel_srcdir)/mkinstalldirs
 PWD_COMMAND = $${PWDCMD-pwd}
diff --git a/libstdc++-v3/src/c++11/codecvt.cc b/libstdc++-v3/src/c++11/codecvt.cc
index b60691c..3f513d5 100644
--- a/libstdc++-v3/src/c++11/codecvt.cc
+++ b/libstdc++-v3/src/c++11/codecvt.cc
@@ -177,7 +177,7 @@ namespace
       unsigned char c3 = from.next[2];
       if ((c3 & 0xC0) != 0x80)
 	return invalid_mb_sequence;
-      char32_t c = (c1 << 12) + (c2 << 6) + c3 - 0xE2080;
+      char32_t c = ((char32_t)c1 << 12) + (c2 << 6) + c3 - 0xE2080;
       if (c <= maxcode)
 	from.next += 3;
       return c;
@@ -199,7 +199,8 @@ namespace
       unsigned char c4 = from.next[3];
       if ((c4 & 0xC0) != 0x80)
 	return invalid_mb_sequence;
-      char32_t c = (c1 << 18) + (c2 << 12) + (c3 << 6) + c4 - 0x3C82080;
+      char32_t c = ((char32_t)c1 << 18) + ((char32_t)c2 << 12) + (c3 << 6)
+		   + c4 - 0x3C82080;
       if (c <= maxcode)
 	from.next += 4;
       return c;
diff --git a/libstdc++-v3/src/c++11/cow-stdexcept.cc b/libstdc++-v3/src/c++11/cow-stdexcept.cc
index 31a89df..9b0a79c 100644
--- a/libstdc++-v3/src/c++11/cow-stdexcept.cc
+++ b/libstdc++-v3/src/c++11/cow-stdexcept.cc
@@ -208,6 +208,8 @@ extern void* _ZGTtnaX (size_t sz) __attribute__((weak));
 extern void _ZGTtdlPv (void* ptr) __attribute__((weak));
 extern uint8_t _ITM_RU1(const uint8_t *p)
   ITM_REGPARM __attribute__((weak));
+extern uint16_t _ITM_RU2(const uint16_t *p)
+  ITM_REGPARM __attribute__((weak));
 extern uint32_t _ITM_RU4(const uint32_t *p)
   ITM_REGPARM __attribute__((weak));
 extern uint64_t _ITM_RU8(const uint64_t *p)
@@ -272,12 +274,15 @@ _txnal_cow_string_C1_for_exceptions(void* that, const char* s,
 static void* txnal_read_ptr(void* const * ptr)
 {
   static_assert(sizeof(uint64_t) == sizeof(void*)
-		|| sizeof(uint32_t) == sizeof(void*),
-		"Pointers must be 32 bits or 64 bits wide");
+		|| sizeof(uint32_t) == sizeof(void*)
+		|| sizeof(uint16_t) == sizeof(void*),
+		"Pointers must be 16 bit or 32 bits or 64 bits wide");
 #if __UINTPTR_MAX__ == __UINT64_MAX__
   return (void*)_ITM_RU8((const uint64_t*)ptr);
-#else
+#elif __UINTPTR__MAX__ == __UINT32_MAX__
   return (void*)_ITM_RU4((const uint32_t*)ptr);
+#else
+  return (void*)_ITM_RU2((const uint16_t*)ptr);
 #endif
 }
 
diff --git a/libstdc++-v3/src/c++98/Makefile.in b/libstdc++-v3/src/c++98/Makefile.in
index 3c3bbbd..ad14e56 100644
--- a/libstdc++-v3/src/c++98/Makefile.in
+++ b/libstdc++-v3/src/c++98/Makefile.in
@@ -266,6 +266,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 glibcxx_MOFILES = @glibcxx_MOFILES@
 glibcxx_PCHFLAGS = @glibcxx_PCHFLAGS@
 glibcxx_POFILES = @glibcxx_POFILES@
@@ -322,7 +323,7 @@ toplevel_builddir = @toplevel_builddir@
 toplevel_srcdir = @toplevel_srcdir@
 
 # May be used by various substitution variables.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 MAINT_CHARSET = latin1
 mkinstalldirs = $(SHELL) $(toplevel_srcdir)/mkinstalldirs
 PWD_COMMAND = $${PWDCMD-pwd}
diff --git a/libstdc++-v3/src/filesystem/Makefile.in b/libstdc++-v3/src/filesystem/Makefile.in
index bbc45a8..ec939c1 100644
--- a/libstdc++-v3/src/filesystem/Makefile.in
+++ b/libstdc++-v3/src/filesystem/Makefile.in
@@ -274,6 +274,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 glibcxx_MOFILES = @glibcxx_MOFILES@
 glibcxx_PCHFLAGS = @glibcxx_PCHFLAGS@
 glibcxx_POFILES = @glibcxx_POFILES@
@@ -330,7 +331,7 @@ toplevel_builddir = @toplevel_builddir@
 toplevel_srcdir = @toplevel_srcdir@
 
 # May be used by various substitution variables.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 MAINT_CHARSET = latin1
 mkinstalldirs = $(SHELL) $(toplevel_srcdir)/mkinstalldirs
 PWD_COMMAND = $${PWDCMD-pwd}
diff --git a/libstdc++-v3/testsuite/18_support/numeric_limits/max_digits10.cc b/libstdc++-v3/testsuite/18_support/numeric_limits/max_digits10.cc
index c9d2bb9..f1b0c46 100644
--- a/libstdc++-v3/testsuite/18_support/numeric_limits/max_digits10.cc
+++ b/libstdc++-v3/testsuite/18_support/numeric_limits/max_digits10.cc
@@ -1,5 +1,6 @@
 // { dg-options "-std=gnu++11" }
 // { dg-add-options ieee }
+// { dg-require-effective-target stdint_types }
 
 // 2010-02-25  Ed Smith-Rowland
 
@@ -25,6 +26,7 @@
 #include <limits>
 #include <cmath>
 #include <testsuite_hooks.h>
+#include <stdint.h>
 
 void
 test01()
@@ -57,12 +59,12 @@ test01()
 			      * 643 / 2136);
   VERIFY( std::numeric_limits<float>::max_digits10 == f_max_digits10 );
 
-  const int d_max_digits10 = (2 + std::numeric_limits<double>::digits
-			      * 643 / 2136);
+  const int_least32_t d_max_digits10 = (2 + std::numeric_limits<double>::digits
+			      * 643L / 2136);
   VERIFY( std::numeric_limits<double>::max_digits10 == d_max_digits10 );
 
-  const int ld_max_digits10 = (2 + std::numeric_limits<long double>::digits
-			       * 643 / 2136);
+  const int_least32_t ld_max_digits10 = (2 + std::numeric_limits<long double>::digits
+			       * 643L / 2136);
   VERIFY( std::numeric_limits<long double>::max_digits10 == ld_max_digits10 );
 }
 
diff --git a/libstdc++-v3/testsuite/19_diagnostics/headers/system_error/errc_std_c++0x.cc b/libstdc++-v3/testsuite/19_diagnostics/headers/system_error/errc_std_c++0x.cc
index 529b950..37bf570 100644
--- a/libstdc++-v3/testsuite/19_diagnostics/headers/system_error/errc_std_c++0x.cc
+++ b/libstdc++-v3/testsuite/19_diagnostics/headers/system_error/errc_std_c++0x.cc
@@ -104,7 +104,10 @@ void test01()
 
   TEST_ERRC(not_connected); 
   TEST_ERRC(not_enough_memory);
+
+#ifdef _GLIBCXX_HAVE_ENOTSUP
   TEST_ERRC(not_supported);
+#endif
 
 #ifdef _GLIBCXX_HAVE_ECANCELED
   TEST_ERRC(operation_canceled);
diff --git a/libstdc++-v3/testsuite/19_diagnostics/system_error/39880.cc b/libstdc++-v3/testsuite/19_diagnostics/system_error/39880.cc
index 8ea95ce..e8ee179 100644
--- a/libstdc++-v3/testsuite/19_diagnostics/system_error/39880.cc
+++ b/libstdc++-v3/testsuite/19_diagnostics/system_error/39880.cc
@@ -24,6 +24,6 @@
 void test01()
 {
   std::error_code ec;
-  if (ec == std::errc::not_supported)
+  if (ec == std::errc::not_enough_memory)
     { }
 }
diff --git a/libstdc++-v3/testsuite/20_util/extent/value.cc b/libstdc++-v3/testsuite/20_util/extent/value.cc
index 4fd5a8f..4d41a0f 100644
--- a/libstdc++-v3/testsuite/20_util/extent/value.cc
+++ b/libstdc++-v3/testsuite/20_util/extent/value.cc
@@ -34,7 +34,7 @@ void test01()
   static_assert(extent<int[2], 1>::value == 0, "");
   static_assert(extent<int[2][4], 1>::value == 4, "");
   static_assert(extent<int[][4], 1>::value == 4, "");
-  static_assert(extent<int[10][4][6][8][12][2], 4>::value == 12, "");
+  static_assert(extent<int[3][4][6][8][12][2], 4>::value == 12, "");
   static_assert(test_property<extent, ClassType, 0>(0), "");
   static_assert(test_property<extent, ClassType[2], 0>(2), "");
   static_assert(test_property<extent, ClassType[2][4], 0>(2), "");
@@ -43,5 +43,5 @@ void test01()
   static_assert(extent<ClassType[2], 1>::value == 0, "");
   static_assert(extent<ClassType[2][4], 1>::value == 4, "");
   static_assert(extent<ClassType[][4], 1>::value == 4, "");
-  static_assert(extent<ClassType[10][4][6][8][12][2], 4>::value == 12, "");
+  static_assert(extent<ClassType[3][4][6][8][12][2], 4>::value == 12, "");
 }
diff --git a/libstdc++-v3/testsuite/20_util/tuple/creation_functions/constexpr.cc b/libstdc++-v3/testsuite/20_util/tuple/creation_functions/constexpr.cc
index 2cca074..aa107fb 100644
--- a/libstdc++-v3/testsuite/20_util/tuple/creation_functions/constexpr.cc
+++ b/libstdc++-v3/testsuite/20_util/tuple/creation_functions/constexpr.cc
@@ -1,4 +1,4 @@
-// { dg-do compile }
+// { dg-do compile { target { stdint_types } } }
 // { dg-options "-std=gnu++11" }
 
 // Copyright (C) 2011-2016 Free Software Foundation, Inc.
@@ -24,6 +24,7 @@
 // changes this test may begin to fail.
 
 #include <tuple>
+#include <stdint.h>
 
 bool test __attribute__((unused)) = true;
 
@@ -60,9 +61,9 @@ test_forward_as_tuple()
   {
     static int i(22);
     static float f(22.222);
-    static int ii(77799);
+    static int_least32_t ii(77799);
 
-    typedef std::tuple<int&, float&, int&&> tuple_type;
+    typedef std::tuple<int&, float&, int_least32_t&&> tuple_type;
     constexpr tuple_type p1 __attribute__((unused))
       = std::forward_as_tuple(i, f, std::move(ii));
   }
@@ -83,9 +84,9 @@ test_tie()
   {
     static int i(22);
     static float f(22.222);
-    static const int ii(77799);
+    static const int_least32_t ii(77799);
 
-    typedef std::tuple<int&, float&, const int&> tuple_type;
+    typedef std::tuple<int&, float&, const int_least32_t&> tuple_type;
     constexpr tuple_type p1 __attribute__((unused))
       = std::tie(i, f, ii);
   }
diff --git a/libstdc++-v3/testsuite/25_algorithms/copy/streambuf_iterators/wchar_t/4.cc b/libstdc++-v3/testsuite/25_algorithms/copy/streambuf_iterators/wchar_t/4.cc
index 7d033c6..fa9cf65 100644
--- a/libstdc++-v3/testsuite/25_algorithms/copy/streambuf_iterators/wchar_t/4.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/copy/streambuf_iterators/wchar_t/4.cc
@@ -22,6 +22,12 @@
 #include <algorithm>
 #include <testsuite_hooks.h>
 
+#ifdef __ia16__
+#define MAX 1650
+#else
+#define MAX 16500
+#endif
+
 // In the occasion of libstdc++/25482
 void test01()
 {
@@ -33,10 +39,10 @@ void test01()
   wifstream fbuf_ref("istream_unformatted-1.txt"),
             fbuf("istream_unformatted-1.txt");
 
-  wchar_t buffer_ref[16500],
-          buffer[16500];
+  wchar_t buffer_ref[MAX],
+          buffer[MAX];
 
-  fbuf_ref.read(buffer_ref, 16500);
+  fbuf_ref.read(buffer_ref, MAX);
 
   in_iterator_type beg(fbuf);
   in_iterator_type end;
@@ -45,7 +51,7 @@ void test01()
   VERIFY( fbuf_ref.good() );
   VERIFY( fbuf.good() );
 
-  VERIFY( !wmemcmp(buffer, buffer_ref, 16500) );
+  VERIFY( !wmemcmp(buffer, buffer_ref, MAX) );
 }
 
 int main()
diff --git a/libstdc++-v3/testsuite/25_algorithms/nth_element/58800.cc b/libstdc++-v3/testsuite/25_algorithms/nth_element/58800.cc
index f72f5e7..d58c20e 100644
--- a/libstdc++-v3/testsuite/25_algorithms/nth_element/58800.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/nth_element/58800.cc
@@ -18,20 +18,22 @@
 // 25.3.2 [lib.alg.nth.element]
 
 // { dg-options "-std=gnu++11" }
+// { dg-require-effective-target stdint_types }
 
 #include <algorithm>
 #include <vector>
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
+#include <stdint.h>
 
 using __gnu_test::test_container;
 using __gnu_test::random_access_iterator_wrapper;
 
-typedef test_container<int, random_access_iterator_wrapper> Container;
+typedef test_container<int_least32_t, random_access_iterator_wrapper> Container;
 
 void test01()
 {
-  std::vector<int> v = {
+  std::vector<int_least32_t> v = {
     207089,
     202585,
     180067,
diff --git a/libstdc++-v3/testsuite/25_algorithms/random_shuffle/moveable.cc b/libstdc++-v3/testsuite/25_algorithms/random_shuffle/moveable.cc
index 3215197..4873e05 100644
--- a/libstdc++-v3/testsuite/25_algorithms/random_shuffle/moveable.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/random_shuffle/moveable.cc
@@ -34,7 +34,11 @@ using __gnu_test::rvalstruct;
 
 typedef test_container<rvalstruct, random_access_iterator_wrapper> Container;
 
+#ifdef __ia16__
+const unsigned int N = 1000;
+#else
 const unsigned int N = 10000;
+#endif
 int A[N]; // This is made global because we don't want it on the stack
 
 void fill_ascending()
diff --git a/libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/requirements/constexpr_data.cc b/libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/requirements/constexpr_data.cc
index 0eb4141..827c2c9 100644
--- a/libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/requirements/constexpr_data.cc
+++ b/libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/requirements/constexpr_data.cc
@@ -1,4 +1,4 @@
-// { dg-do compile }
+// { dg-do compile { target { stdint_types } } }
 // { dg-options "-std=gnu++11" }
 
 // Copyright (C) 2010-2016 Free Software Foundation, Inc.
@@ -20,6 +20,7 @@
 
 #include <random>
 #include <testsuite_common_types.h>
+#include <stdint.h>
 
 namespace __gnu_test
 {
@@ -53,7 +54,7 @@ namespace __gnu_test
 int main()
 {
   __gnu_test::constexpr_member_data test;
-  typedef std::linear_congruential_engine<unsigned int, 41, 0, 2147483647> type;
+  typedef std::linear_congruential_engine<uint_least32_t, 41, 0, 2147483647> type;
   test.operator()<type>();
   return 0;
 }
diff --git a/libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/requirements/constexpr_functions.cc b/libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/requirements/constexpr_functions.cc
index fa49f0d..b9dd44a 100644
--- a/libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/requirements/constexpr_functions.cc
+++ b/libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/requirements/constexpr_functions.cc
@@ -1,4 +1,4 @@
-// { dg-do compile }
+// { dg-do compile { target { stdint_types } } }
 // { dg-options "-std=gnu++11" }
 
 // Copyright (C) 2010-2016 Free Software Foundation, Inc.
@@ -20,6 +20,7 @@
 
 #include <random>
 #include <testsuite_common_types.h>
+#include <stdint.h>
 
 namespace __gnu_test
 {
@@ -49,7 +50,7 @@ namespace __gnu_test
 int main()
 {
   __gnu_test::constexpr_member_functions test;
-  typedef std::linear_congruential_engine<unsigned int, 41, 0, 2147483647> type;
+  typedef std::linear_congruential_engine<uint_least32_t, 41, 0, 2147483647> type;
   test.operator()<type>();
   return 0;
 }
diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/getline/wchar_t/5.cc b/libstdc++-v3/testsuite/27_io/basic_istream/getline/wchar_t/5.cc
index 1fb99d9..5372fd2 100644
--- a/libstdc++-v3/testsuite/27_io/basic_istream/getline/wchar_t/5.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_istream/getline/wchar_t/5.cc
@@ -50,7 +50,11 @@ check(wistream& stream, const wstring& str, unsigned nchunks, wchar_t delim)
 {
   bool test __attribute__((unused)) = true;
 
+#ifdef __ia16__
+  static wchar_t buf[1000];
+#else
   static wchar_t buf[1000000];
+#endif
   wstring::size_type index = 0, index_new = 0;
   unsigned n = 0;
 
diff --git a/libstdc++-v3/testsuite/27_io/basic_stringbuf/setbuf/wchar_t/4.cc b/libstdc++-v3/testsuite/27_io/basic_stringbuf/setbuf/wchar_t/4.cc
index baa7c5c..cb9ed9e 100644
--- a/libstdc++-v3/testsuite/27_io/basic_stringbuf/setbuf/wchar_t/4.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/setbuf/wchar_t/4.cc
@@ -19,7 +19,7 @@
 
 // 27.8.1.4 Overridden virtual functions
 
-// { dg-options "-DMAX_SIZE=4096" { target simulator } }
+// { dg-options "-DMAX_SIZE=4096" { target { simulator || ia16-*-* } } }
 
 #ifndef MAX_SIZE
 #define MAX_SIZE (1 << 18)
diff --git a/libstdc++-v3/testsuite/27_io/headers/cstdio/functions_std.cc b/libstdc++-v3/testsuite/27_io/headers/cstdio/functions_std.cc
index 029f0837..940a17a 100644
--- a/libstdc++-v3/testsuite/27_io/headers/cstdio/functions_std.cc
+++ b/libstdc++-v3/testsuite/27_io/headers/cstdio/functions_std.cc
@@ -34,7 +34,9 @@ namespace gnu
   using std::fseek; 
   using std::perror; 
   using std::rewind; 
+#if _GLIBCXX_USE_TMPNAM
   using std::tmpnam; 
+#endif
   using std::feof; 
   using std::fprintf; 
   using std::fsetpos; 
diff --git a/libstdc++-v3/testsuite/27_io/ios_base/types/fmtflags/case_label.cc b/libstdc++-v3/testsuite/27_io/ios_base/types/fmtflags/case_label.cc
index d786e10..a186901 100644
--- a/libstdc++-v3/testsuite/27_io/ios_base/types/fmtflags/case_label.cc
+++ b/libstdc++-v3/testsuite/27_io/ios_base/types/fmtflags/case_label.cc
@@ -75,6 +75,6 @@ case_labels(bitmask_type b)
     case ~__INT_MAX__:
       break;
     }
-  static_assert( sizeof(std::underlying_type_t<bitmask_type>) == sizeof(int),
+  static_assert( sizeof(std::underlying_type_t<bitmask_type>) >= sizeof(int),
       "underlying type has same range of values as int");
 }
diff --git a/libstdc++-v3/testsuite/27_io/ios_base/types/iostate/case_label.cc b/libstdc++-v3/testsuite/27_io/ios_base/types/iostate/case_label.cc
index 7d777b8..1349170 100644
--- a/libstdc++-v3/testsuite/27_io/ios_base/types/iostate/case_label.cc
+++ b/libstdc++-v3/testsuite/27_io/ios_base/types/iostate/case_label.cc
@@ -47,6 +47,6 @@ case_labels(bitmask_type b)
     case ~__INT_MAX__:
       break;
     }
-  static_assert( sizeof(std::underlying_type_t<bitmask_type>) == sizeof(int),
+  static_assert( sizeof(std::underlying_type_t<bitmask_type>) >= sizeof(int),
       "underlying type has same range of values as int");
 }
diff --git a/libstdc++-v3/testsuite/27_io/ios_base/types/openmode/case_label.cc b/libstdc++-v3/testsuite/27_io/ios_base/types/openmode/case_label.cc
index bb9e96e..088c65a 100644
--- a/libstdc++-v3/testsuite/27_io/ios_base/types/openmode/case_label.cc
+++ b/libstdc++-v3/testsuite/27_io/ios_base/types/openmode/case_label.cc
@@ -51,6 +51,6 @@ case_labels(bitmask_type b)
     case ~__INT_MAX__:
       break;
     }
-  static_assert( sizeof(std::underlying_type_t<bitmask_type>) == sizeof(int),
+  static_assert( sizeof(std::underlying_type_t<bitmask_type>) >= sizeof(int),
       "underlying type has same range of values as int");
 }
diff --git a/libstdc++-v3/testsuite/Makefile.in b/libstdc++-v3/testsuite/Makefile.in
index 963f35d..b278069 100644
--- a/libstdc++-v3/testsuite/Makefile.in
+++ b/libstdc++-v3/testsuite/Makefile.in
@@ -232,6 +232,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 glibcxx_MOFILES = @glibcxx_MOFILES@
 glibcxx_PCHFLAGS = @glibcxx_PCHFLAGS@
 glibcxx_POFILES = @glibcxx_POFILES@
@@ -291,7 +292,7 @@ RUNTESTDEFAULTFLAGS = --tool $$tool --srcdir $$srcdir
 EXPECT = expect
 
 # May be used by various substitution variables.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 MAINT_CHARSET = latin1
 mkinstalldirs = $(SHELL) $(toplevel_srcdir)/mkinstalldirs
 PWD_COMMAND = $${PWDCMD-pwd}
diff --git a/libstdc++-v3/testsuite/lib/libstdc++.exp b/libstdc++-v3/testsuite/lib/libstdc++.exp
index 18ee318..97ba89e 100644
--- a/libstdc++-v3/testsuite/lib/libstdc++.exp
+++ b/libstdc++-v3/testsuite/lib/libstdc++.exp
@@ -497,6 +497,8 @@ proc v3_target_compile { source dest type options } {
     lappend options "timeout=[timeout_value]"
 
     set comp_output [target_compile $source $dest $type $options]
+    regsub -all "(^|\n)\[^\n\]*: warning: target system does not support debug output\[^\n\]*" $comp_output "" comp_output
+    set comp_output [string trim $comp_output]
 
     return $comp_output
 }
diff --git a/libstdc++-v3/testsuite/lib/prune.exp b/libstdc++-v3/testsuite/lib/prune.exp
index 8b5b42d..9781d6c 100644
--- a/libstdc++-v3/testsuite/lib/prune.exp
+++ b/libstdc++-v3/testsuite/lib/prune.exp
@@ -33,6 +33,8 @@ proc libstdc++-dg-prune { system text } {
 
 #    send_user "Before:$text\n"
 
+    regsub -all "(^|\n)\[^\n\]*: warning: target system does not support debug output\[^\n\]*" $text "" text
+
     # Ignore caret diagnostics. Unfortunately dejaGNU trims leading
     # spaces, so one cannot rely on them being present.
     regsub -all "(^|\n)\[^\n\]+\n *\\^\n" $text "\n" text
diff --git a/libstdc++-v3/testsuite/special_functions/15_hermite/check_value.cc b/libstdc++-v3/testsuite/special_functions/15_hermite/check_value.cc
index a6b6a3f..6dfbdbe 100644
--- a/libstdc++-v3/testsuite/special_functions/15_hermite/check_value.cc
+++ b/libstdc++-v3/testsuite/special_functions/15_hermite/check_value.cc
@@ -1,4 +1,5 @@
 // { dg-options "-D__STDCPP_WANT_MATH_SPEC_FUNCS__" }
+// { dg-skip-if "Does not fit in 64kB" { "ia16-*-*" } }
 //
 // Copyright (C) 2016 Free Software Foundation, Inc.
 //
diff --git a/libstdc++-v3/testsuite/tr1/4_metaprogramming/extent/value.cc b/libstdc++-v3/testsuite/tr1/4_metaprogramming/extent/value.cc
index c2f01c0..35fffd5 100644
--- a/libstdc++-v3/testsuite/tr1/4_metaprogramming/extent/value.cc
+++ b/libstdc++-v3/testsuite/tr1/4_metaprogramming/extent/value.cc
@@ -37,7 +37,7 @@ void test01()
   VERIFY( (extent<int[2], 1>::value == 0) );
   VERIFY( (extent<int[2][4], 1>::value == 4) );
   VERIFY( (extent<int[][4], 1>::value == 4) );
-  VERIFY( (extent<int[10][4][6][8][12][2], 4>::value == 12) );
+  VERIFY( (extent<int[3][4][6][8][12][2], 4>::value == 12) );
   VERIFY( (test_property<extent, ClassType, 0>(0)) );
   VERIFY( (test_property<extent, ClassType[2], 0>(2)) );
   VERIFY( (test_property<extent, ClassType[2][4], 0>(2)) );
@@ -46,7 +46,7 @@ void test01()
   VERIFY( (extent<ClassType[2], 1>::value == 0) );
   VERIFY( (extent<ClassType[2][4], 1>::value == 4) );
   VERIFY( (extent<ClassType[][4], 1>::value == 4) );
-  VERIFY( (extent<ClassType[10][4][6][8][12][2], 4>::value == 12) );
+  VERIFY( (extent<ClassType[3][4][6][8][12][2], 4>::value == 12) );
 }
 
 int main()
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/discard_block/operators/equal.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/discard_block/operators/equal.cc
index 9059d31..b2fe3f9 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/discard_block/operators/equal.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/discard_block/operators/equal.cc
@@ -31,7 +31,7 @@ test01()
 
   discard_block
     <
-    subtract_with_carry<long, (1 << 24), 10, 24>,
+    subtract_with_carry<long, (1L << 24), 10, 24>,
     389, 24
     > u, v;
 
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/discard_block/operators/not_equal.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/discard_block/operators/not_equal.cc
index 646c6dc..61b6789 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/discard_block/operators/not_equal.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/discard_block/operators/not_equal.cc
@@ -31,13 +31,13 @@ test01()
 
   discard_block
     <
-    subtract_with_carry<long, (1 << 24), 10, 24>,
+    subtract_with_carry<long, (1L << 24), 10, 24>,
     389, 24
     > u(1);
 
   discard_block
     <
-    subtract_with_carry<long, (1 << 24), 10, 24>,
+    subtract_with_carry<long, (1L << 24), 10, 24>,
     389, 24
     > v(2);
 
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/discard_block/operators/serialize.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/discard_block/operators/serialize.cc
index 94fa030..3dd75ff 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/discard_block/operators/serialize.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/discard_block/operators/serialize.cc
@@ -34,7 +34,7 @@ test01()
   std::stringstream str;
   discard_block
     <
-    subtract_with_carry<long, (1 << 24), 10, 24>,
+    subtract_with_carry<long, (1L << 24), 10, 24>,
     389, 24
     > u, v;
   
diff --git a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/discard_block/requirements/typedefs.cc b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/discard_block/requirements/typedefs.cc
index 768ead5..db5d120 100644
--- a/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/discard_block/requirements/typedefs.cc
+++ b/libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/discard_block/requirements/typedefs.cc
@@ -31,7 +31,7 @@ test01()
   
   typedef discard_block
     <
-    subtract_with_carry<long, (1 << 24), 10, 24>,
+    subtract_with_carry<long, (1L << 24), 10, 24>,
     389, 24
     > test_type;
   
diff --git a/libvtv/Makefile.am b/libvtv/Makefile.am
index 8c47d1a..84c0ed9 100644
--- a/libvtv/Makefile.am
+++ b/libvtv/Makefile.am
@@ -28,7 +28,7 @@ endif
 ACLOCAL_AMFLAGS = -I .. -I ../config
 
 # May be used by toolexeclibdir.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 
 DEFS = @DEFS@
 AM_CPPFLAGS = -I$(top_srcdir)/../include
diff --git a/libvtv/Makefile.in b/libvtv/Makefile.in
index 0553927..59d0b11 100644
--- a/libvtv/Makefile.in
+++ b/libvtv/Makefile.in
@@ -273,6 +273,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
@@ -320,7 +321,7 @@ toplevel_srcdir = @toplevel_srcdir@
 ACLOCAL_AMFLAGS = -I .. -I ../config
 
 # May be used by toolexeclibdir.
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 AM_CPPFLAGS = -I$(top_srcdir)/../include
 AM_CFLAGS = $(XCFLAGS)
 AM_CCASFLAGS = $(XCFLAGS)
diff --git a/libvtv/configure b/libvtv/configure
index ea1a17f..40fb0f0 100755
--- a/libvtv/configure
+++ b/libvtv/configure
@@ -602,6 +602,7 @@ ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+get_gcc_base_ver
 VTV_NO_OBSTACK_FALSE
 VTV_NO_OBSTACK_TRUE
 VTV_CYGMIN_FALSE
@@ -759,6 +760,7 @@ with_pic
 enable_fast_install
 with_gnu_ld
 enable_libtool_lock
+with_gcc_major_version_only
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1409,6 +1411,8 @@ Optional Packages:
   --with-pic              try to use only PIC/non-PIC objects [default=use
                           both]
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+  --with-gcc-major-version-only
+                          use only GCC major number in filesystem paths
 
 Some influential environment variables:
   CC          C compiler command
@@ -12062,7 +12066,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12065 "configure"
+#line 12069 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12168,7 +12172,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12171 "configure"
+#line 12175 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -15505,6 +15509,21 @@ else
 fi
 
 
+# Determine what GCC version number to use in filesystem paths.
+
+  get_gcc_base_ver="cat"
+
+# Check whether --with-gcc-major-version-only was given.
+if test "${with_gcc_major_version_only+set}" = set; then :
+  withval=$with_gcc_major_version_only; if test x$with_gcc_major_version_only = xyes ; then
+        get_gcc_base_ver="sed -e 's/^\([0-9]*\).*\$\$/\1/'"
+      fi
+
+fi
+
+
+
+
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
 # tests run on this system so they can be shared between configure
diff --git a/libvtv/configure.ac b/libvtv/configure.ac
index 19c6508..33b1e79 100644
--- a/libvtv/configure.ac
+++ b/libvtv/configure.ac
@@ -190,4 +190,7 @@ AM_CONDITIONAL(VTV_CYGMIN, test $vtv_cygmin = yes)
 AC_CHECK_FUNCS([_obstack_begin])
 AM_CONDITIONAL(VTV_NO_OBSTACK, test $ac_cv_func__obstack_begin = no)
 
+# Determine what GCC version number to use in filesystem paths.
+GCC_BASE_VER
+
 AC_OUTPUT
diff --git a/libvtv/testsuite/Makefile.in b/libvtv/testsuite/Makefile.in
index e19e13e..7688f3c 100644
--- a/libvtv/testsuite/Makefile.in
+++ b/libvtv/testsuite/Makefile.in
@@ -174,6 +174,7 @@ dvidir = @dvidir@
 enable_shared = @enable_shared@
 enable_static = @enable_static@
 exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
diff --git a/lto-plugin/Makefile.am b/lto-plugin/Makefile.am
index a90a5da..28dc210 100644
--- a/lto-plugin/Makefile.am
+++ b/lto-plugin/Makefile.am
@@ -3,7 +3,7 @@
 ACLOCAL_AMFLAGS = -I .. -I ../config
 AUTOMAKE_OPTIONS = no-dependencies
 
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 target_noncanonical := @target_noncanonical@
 libexecsubdir := $(libexecdir)/gcc/$(real_target_noncanonical)/$(gcc_version)$(accel_dir_suffix)
 
diff --git a/lto-plugin/Makefile.in b/lto-plugin/Makefile.in
index 06ef5f3..c69cc32 100644
--- a/lto-plugin/Makefile.in
+++ b/lto-plugin/Makefile.in
@@ -214,6 +214,7 @@ docdir = @docdir@
 dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 gcc_build_dir = @gcc_build_dir@
+get_gcc_base_ver = @get_gcc_base_ver@
 host = @host@
 host_alias = @host_alias@
 host_cpu = @host_cpu@
@@ -254,7 +255,7 @@ top_srcdir = @top_srcdir@
 with_libiberty = @with_libiberty@
 ACLOCAL_AMFLAGS = -I .. -I ../config
 AUTOMAKE_OPTIONS = no-dependencies
-gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 libexecsubdir := $(libexecdir)/gcc/$(real_target_noncanonical)/$(gcc_version)$(accel_dir_suffix)
 AM_CPPFLAGS = -I$(top_srcdir)/../include $(DEFS)
 AM_CFLAGS = @ac_lto_plugin_warn_cflags@
diff --git a/lto-plugin/configure b/lto-plugin/configure
index 36201e6..cdea9ea 100755
--- a/lto-plugin/configure
+++ b/lto-plugin/configure
@@ -619,6 +619,7 @@ LD
 FGREP
 SED
 LIBTOOL
+get_gcc_base_ver
 real_target_noncanonical
 accel_dir_suffix
 gcc_build_dir
@@ -733,6 +734,7 @@ enable_maintainer_mode
 with_libiberty
 enable_dependency_tracking
 enable_largefile
+with_gcc_major_version_only
 enable_shared
 enable_static
 with_pic
@@ -1386,6 +1388,8 @@ Optional Packages:
   --with-build-libsubdir=DIR  Directory where to find libraries for build system
   --with-libiberty=PATH   specify the directory where to find libiberty
                           [../libiberty]
+  --with-gcc-major-version-only
+                          use only GCC major number in filesystem paths
   --with-pic              try to use only PIC/non-PIC objects [default=use
                           both]
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
@@ -5376,6 +5380,21 @@ fi
 
 
 
+# Determine what GCC version number to use in filesystem paths.
+
+  get_gcc_base_ver="cat"
+
+# Check whether --with-gcc-major-version-only was given.
+if test "${with_gcc_major_version_only+set}" = set; then :
+  withval=$with_gcc_major_version_only; if test x$with_gcc_major_version_only = xyes ; then
+        get_gcc_base_ver="sed -e 's/^\([0-9]*\).*\$\$/\1/'"
+      fi
+
+fi
+
+
+
+
 case `pwd` in
   *\ * | *\	*)
     { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
@@ -9422,7 +9441,7 @@ _LT_EOF
 	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
 	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
 	else
-	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
 	fi
 	aix_use_runtimelinking=no
 
@@ -11450,7 +11469,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11453 "configure"
+#line 11472 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11556,7 +11575,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11559 "configure"
+#line 11578 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
diff --git a/lto-plugin/configure.ac b/lto-plugin/configure.ac
index b6dc534..aa68632 100644
--- a/lto-plugin/configure.ac
+++ b/lto-plugin/configure.ac
@@ -45,6 +45,9 @@ fi
 AC_SUBST(accel_dir_suffix)
 AC_SUBST(real_target_noncanonical)
 
+# Determine what GCC version number to use in filesystem paths.
+GCC_BASE_VER
+
 AM_PROG_LIBTOOL
 ACX_LT_HOST_FLAGS
 AC_SUBST(target_noncanonical)
