diff options
author | CoprDistGit <infra@openeuler.org> | 2023-10-17 02:15:03 +0000 |
---|---|---|
committer | CoprDistGit <infra@openeuler.org> | 2023-10-17 02:15:03 +0000 |
commit | d82826d1a1c7ea45a761dfbf76b879712c7332ec (patch) | |
tree | 973a28470803b27c914f813f43d43f8932763ea3 | |
parent | b868000cf68cec0c9cd45fbf89a83173dea7c5eb (diff) |
automatic import of gccopeneuler22.03_LTS
123 files changed, 76208 insertions, 632 deletions
@@ -0,0 +1 @@ +/gcc-10.3.0.tar.xz diff --git a/0001-libquadmath-Enable-libquadmath-on-kunpeng.patch b/0001-libquadmath-Enable-libquadmath-on-kunpeng.patch new file mode 100644 index 0000000..33dd94e --- /dev/null +++ b/0001-libquadmath-Enable-libquadmath-on-kunpeng.patch @@ -0,0 +1,473 @@ +From 85740d3cc56fda699beae689b5d73233d16097af Mon Sep 17 00:00:00 2001 +From: bule <bule1@huawei.com> +Date: Thu, 8 Jul 2021 11:52:47 +0800 +Subject: [PATCH 01/13] [libquadmath] Enable libquadmath on kunpeng + +This enable libquadmath on kunpeng platform to convenient +users that migrating from x86 platform. libquadmath uses "__float128" +as quad precision floating point type and with math functions with "q" +suffix like "cosq". For those who do not need to adapt to x86 platform, +you can use "long double" as quad precision floating point type and math +functions with "l" suffix like "cosl" in libm for quad precision math. + +diff --git a/libquadmath/Makefile.in b/libquadmath/Makefile.in +index 8c011212258..66df9c922f8 100644 +--- a/libquadmath/Makefile.in ++++ b/libquadmath/Makefile.in +@@ -90,7 +90,7 @@ POST_UNINSTALL = : + build_triplet = @build@ + host_triplet = @host@ + target_triplet = @target@ +-@BUILD_LIBQUADMATH_FALSE@libquadmath_la_DEPENDENCIES = ++#libquadmath_la_DEPENDENCIES = + subdir = . + ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 + am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \ +@@ -147,68 +147,68 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(infodir)" \ + "$(DESTDIR)$(libsubincludedir)" + LTLIBRARIES = $(toolexeclib_LTLIBRARIES) + am__dirstamp = $(am__leading_dot)dirstamp +-@BUILD_LIBQUADMATH_TRUE@am_libquadmath_la_OBJECTS = math/x2y2m1q.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/acoshq.lo math/fmodq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/acosq.lo math/frexpq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/rem_pio2q.lo math/asinhq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/hypotq.lo math/remainderq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/asinq.lo math/rintq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/atan2q.lo math/isinfq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/roundq.lo math/atanhq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/isnanq.lo math/scalblnq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/atanq.lo math/j0q.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/scalbnq.lo math/cbrtq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/j1q.lo math/signbitq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/ceilq.lo math/jnq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/sincos_table.lo math/complex.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/ldexpq.lo math/sincosq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/copysignq.lo math/lgammaq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/sincosq_kernel.lo math/coshq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/llroundq.lo math/sinhq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/cosq.lo math/log10q.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/sinq.lo math/cosq_kernel.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/log1pq.lo math/sinq_kernel.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/erfq.lo math/logq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/sqrtq.lo math/expm1q.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/lroundq.lo math/tanhq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/expq.lo math/modfq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/tanq.lo math/fabsq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/nanq.lo math/tgammaq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/finiteq.lo math/nextafterq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/truncq.lo math/floorq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/powq.lo math/fmaq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/logbq.lo math/exp2q.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/issignalingq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/lgammaq_neg.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/lgammaq_product.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/tanq_kernel.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/tgammaq_product.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/casinhq_kernel.lo math/cacoshq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/cacosq.lo math/casinhq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/casinq.lo math/catanhq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/catanq.lo math/cimagq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/conjq.lo math/cprojq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/crealq.lo math/fdimq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/fmaxq.lo math/fminq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/ilogbq.lo math/llrintq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/log2q.lo math/lrintq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/nearbyintq.lo math/remquoq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/ccoshq.lo math/cexpq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/clog10q.lo math/clogq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/csinq.lo math/csinhq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/csqrtq.lo math/ctanq.lo \ +-@BUILD_LIBQUADMATH_TRUE@ math/ctanhq.lo printf/addmul_1.lo \ +-@BUILD_LIBQUADMATH_TRUE@ printf/add_n.lo printf/cmp.lo \ +-@BUILD_LIBQUADMATH_TRUE@ printf/divrem.lo printf/flt1282mpn.lo \ +-@BUILD_LIBQUADMATH_TRUE@ printf/fpioconst.lo printf/lshift.lo \ +-@BUILD_LIBQUADMATH_TRUE@ printf/mul_1.lo printf/mul_n.lo \ +-@BUILD_LIBQUADMATH_TRUE@ printf/mul.lo printf/printf_fphex.lo \ +-@BUILD_LIBQUADMATH_TRUE@ printf/printf_fp.lo \ +-@BUILD_LIBQUADMATH_TRUE@ printf/quadmath-printf.lo \ +-@BUILD_LIBQUADMATH_TRUE@ printf/rshift.lo printf/submul_1.lo \ +-@BUILD_LIBQUADMATH_TRUE@ printf/sub_n.lo strtod/strtoflt128.lo \ +-@BUILD_LIBQUADMATH_TRUE@ strtod/mpn2flt128.lo \ +-@BUILD_LIBQUADMATH_TRUE@ strtod/tens_in_limb.lo ++am_libquadmath_la_OBJECTS = math/x2y2m1q.lo \ ++ math/acoshq.lo math/fmodq.lo \ ++ math/acosq.lo math/frexpq.lo \ ++ math/rem_pio2q.lo math/asinhq.lo \ ++ math/hypotq.lo math/remainderq.lo \ ++ math/asinq.lo math/rintq.lo \ ++ math/atan2q.lo math/isinfq.lo \ ++ math/roundq.lo math/atanhq.lo \ ++ math/isnanq.lo math/scalblnq.lo \ ++ math/atanq.lo math/j0q.lo \ ++ math/scalbnq.lo math/cbrtq.lo \ ++ math/j1q.lo math/signbitq.lo \ ++ math/ceilq.lo math/jnq.lo \ ++ math/sincos_table.lo math/complex.lo \ ++ math/ldexpq.lo math/sincosq.lo \ ++ math/copysignq.lo math/lgammaq.lo \ ++ math/sincosq_kernel.lo math/coshq.lo \ ++ math/llroundq.lo math/sinhq.lo \ ++ math/cosq.lo math/log10q.lo \ ++ math/sinq.lo math/cosq_kernel.lo \ ++ math/log1pq.lo math/sinq_kernel.lo \ ++ math/erfq.lo math/logq.lo \ ++ math/sqrtq.lo math/expm1q.lo \ ++ math/lroundq.lo math/tanhq.lo \ ++ math/expq.lo math/modfq.lo \ ++ math/tanq.lo math/fabsq.lo \ ++ math/nanq.lo math/tgammaq.lo \ ++ math/finiteq.lo math/nextafterq.lo \ ++ math/truncq.lo math/floorq.lo \ ++ math/powq.lo math/fmaq.lo \ ++ math/logbq.lo math/exp2q.lo \ ++ math/issignalingq.lo \ ++ math/lgammaq_neg.lo \ ++ math/lgammaq_product.lo \ ++ math/tanq_kernel.lo \ ++ math/tgammaq_product.lo \ ++ math/casinhq_kernel.lo math/cacoshq.lo \ ++ math/cacosq.lo math/casinhq.lo \ ++ math/casinq.lo math/catanhq.lo \ ++ math/catanq.lo math/cimagq.lo \ ++ math/conjq.lo math/cprojq.lo \ ++ math/crealq.lo math/fdimq.lo \ ++ math/fmaxq.lo math/fminq.lo \ ++ math/ilogbq.lo math/llrintq.lo \ ++ math/log2q.lo math/lrintq.lo \ ++ math/nearbyintq.lo math/remquoq.lo \ ++ math/ccoshq.lo math/cexpq.lo \ ++ math/clog10q.lo math/clogq.lo \ ++ math/csinq.lo math/csinhq.lo \ ++ math/csqrtq.lo math/ctanq.lo \ ++ math/ctanhq.lo printf/addmul_1.lo \ ++ printf/add_n.lo printf/cmp.lo \ ++ printf/divrem.lo printf/flt1282mpn.lo \ ++ printf/fpioconst.lo printf/lshift.lo \ ++ printf/mul_1.lo printf/mul_n.lo \ ++ printf/mul.lo printf/printf_fphex.lo \ ++ printf/printf_fp.lo \ ++ printf/quadmath-printf.lo \ ++ printf/rshift.lo printf/submul_1.lo \ ++ printf/sub_n.lo strtod/strtoflt128.lo \ ++ strtod/mpn2flt128.lo \ ++ strtod/tens_in_limb.lo + libquadmath_la_OBJECTS = $(am_libquadmath_la_OBJECTS) + AM_V_lt = $(am__v_lt_@AM_V@) + am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +@@ -218,8 +218,8 @@ libquadmath_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libquadmath_la_LDFLAGS) $(LDFLAGS) -o \ + $@ +-@BUILD_LIBQUADMATH_TRUE@am_libquadmath_la_rpath = -rpath \ +-@BUILD_LIBQUADMATH_TRUE@ $(toolexeclibdir) ++am_libquadmath_la_rpath = -rpath \ ++ $(toolexeclibdir) + AM_V_P = $(am__v_P_@AM_V@) + am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) + am__v_P_0 = false +@@ -337,7 +337,7 @@ CFLAGS = @CFLAGS@ + CPP = @CPP@ + CPPFLAGS = @CPPFLAGS@ + CYGPATH_W = @CYGPATH_W@ +-DEFS = @DEFS@ ++DEFS = @DEFS@ -D__float128="long double" + DEPDIR = @DEPDIR@ + DSYMUTIL = @DSYMUTIL@ + DUMPBIN = @DUMPBIN@ +@@ -409,7 +409,7 @@ datadir = @datadir@ + datarootdir = @datarootdir@ + docdir = @docdir@ + dvidir = @dvidir@ +-enable_shared = @enable_shared@ ++enable_shared = yes + enable_static = @enable_static@ + exec_prefix = @exec_prefix@ + get_gcc_base_ver = @get_gcc_base_ver@ +@@ -451,109 +451,109 @@ top_build_prefix = @top_build_prefix@ + top_builddir = @top_builddir@ + top_srcdir = @top_srcdir@ + AUTOMAKE_OPTIONS = foreign info-in-builddir +-@BUILD_LIBQUADMATH_TRUE@ACLOCAL_AMFLAGS = -I .. -I ../config +-@BUILD_LIBQUADMATH_TRUE@AM_CPPFLAGS = -I $(top_srcdir)/../include +-@BUILD_LIBQUADMATH_TRUE@AM_CFLAGS = $(XCFLAGS) +-@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 +-@BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_FALSE@version_dep = +-@BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_GNU_TRUE@@LIBQUAD_USE_SYMVER_TRUE@version_dep = $(srcdir)/quadmath.map +-@BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@version_dep = quadmath.map-sun +-@BUILD_LIBQUADMATH_TRUE@toolexeclib_LTLIBRARIES = libquadmath.la +-@BUILD_LIBQUADMATH_TRUE@libquadmath_la_LIBADD = +-@BUILD_LIBQUADMATH_TRUE@libquadmath_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \ +-@BUILD_LIBQUADMATH_TRUE@ $(version_arg) $(lt_host_flags) -lm +- +-@BUILD_LIBQUADMATH_TRUE@libquadmath_la_DEPENDENCIES = $(version_dep) $(libquadmath_la_LIBADD) +-@BUILD_LIBQUADMATH_TRUE@nodist_libsubinclude_HEADERS = quadmath.h quadmath_weak.h +-@BUILD_LIBQUADMATH_TRUE@libsubincludedir = $(libdir)/gcc/$(target_alias)/$(gcc_version)/include +-@BUILD_LIBQUADMATH_TRUE@libquadmath_la_SOURCES = \ +-@BUILD_LIBQUADMATH_TRUE@ math/x2y2m1q.c math/acoshq.c math/fmodq.c \ +-@BUILD_LIBQUADMATH_TRUE@ math/acosq.c math/frexpq.c \ +-@BUILD_LIBQUADMATH_TRUE@ math/rem_pio2q.c math/asinhq.c math/hypotq.c math/remainderq.c \ +-@BUILD_LIBQUADMATH_TRUE@ math/asinq.c math/rintq.c math/atan2q.c math/isinfq.c \ +-@BUILD_LIBQUADMATH_TRUE@ math/roundq.c math/atanhq.c math/isnanq.c math/scalblnq.c math/atanq.c \ +-@BUILD_LIBQUADMATH_TRUE@ math/j0q.c math/scalbnq.c math/cbrtq.c math/j1q.c math/signbitq.c \ +-@BUILD_LIBQUADMATH_TRUE@ math/ceilq.c math/jnq.c math/sincos_table.c math/complex.c math/ldexpq.c \ +-@BUILD_LIBQUADMATH_TRUE@ math/sincosq.c math/copysignq.c math/lgammaq.c math/sincosq_kernel.c \ +-@BUILD_LIBQUADMATH_TRUE@ math/coshq.c math/llroundq.c math/sinhq.c math/cosq.c math/log10q.c \ +-@BUILD_LIBQUADMATH_TRUE@ math/sinq.c math/cosq_kernel.c math/log1pq.c math/sinq_kernel.c \ +-@BUILD_LIBQUADMATH_TRUE@ math/erfq.c math/logq.c math/sqrtq.c math/expm1q.c math/lroundq.c \ +-@BUILD_LIBQUADMATH_TRUE@ math/tanhq.c math/expq.c math/modfq.c math/tanq.c math/fabsq.c \ +-@BUILD_LIBQUADMATH_TRUE@ math/nanq.c math/tgammaq.c math/finiteq.c math/nextafterq.c \ +-@BUILD_LIBQUADMATH_TRUE@ math/truncq.c math/floorq.c math/powq.c math/fmaq.c math/logbq.c \ +-@BUILD_LIBQUADMATH_TRUE@ math/exp2q.c math/issignalingq.c math/lgammaq_neg.c math/lgammaq_product.c \ +-@BUILD_LIBQUADMATH_TRUE@ math/tanq_kernel.c math/tgammaq_product.c math/casinhq_kernel.c \ +-@BUILD_LIBQUADMATH_TRUE@ math/cacoshq.c math/cacosq.c math/casinhq.c math/casinq.c \ +-@BUILD_LIBQUADMATH_TRUE@ math/catanhq.c math/catanq.c math/cimagq.c math/conjq.c math/cprojq.c \ +-@BUILD_LIBQUADMATH_TRUE@ math/crealq.c math/fdimq.c math/fmaxq.c math/fminq.c math/ilogbq.c \ +-@BUILD_LIBQUADMATH_TRUE@ math/llrintq.c math/log2q.c math/lrintq.c math/nearbyintq.c math/remquoq.c \ +-@BUILD_LIBQUADMATH_TRUE@ math/ccoshq.c math/cexpq.c math/clog10q.c math/clogq.c math/csinq.c \ +-@BUILD_LIBQUADMATH_TRUE@ math/csinhq.c math/csqrtq.c math/ctanq.c math/ctanhq.c \ +-@BUILD_LIBQUADMATH_TRUE@ printf/addmul_1.c printf/add_n.c printf/cmp.c printf/divrem.c \ +-@BUILD_LIBQUADMATH_TRUE@ printf/flt1282mpn.c printf/fpioconst.c printf/lshift.c printf/mul_1.c \ +-@BUILD_LIBQUADMATH_TRUE@ printf/mul_n.c printf/mul.c printf/printf_fphex.c printf/printf_fp.c \ +-@BUILD_LIBQUADMATH_TRUE@ printf/quadmath-printf.c printf/rshift.c printf/submul_1.c printf/sub_n.c \ +-@BUILD_LIBQUADMATH_TRUE@ strtod/strtoflt128.c strtod/mpn2flt128.c strtod/tens_in_limb.c ++ACLOCAL_AMFLAGS = -I .. -I ../config ++AM_CPPFLAGS = -I $(top_srcdir)/../include ++AM_CFLAGS = $(XCFLAGS) ++gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER) ++@LIBQUAD_USE_SYMVER_FALSE@version_arg = ++@LIBQUAD_USE_SYMVER_GNU_TRUE@@LIBQUAD_USE_SYMVER_TRUE@version_arg = -Wl,--version-script=$(srcdir)/quadmath.map ++@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@version_arg = -Wl,-M,quadmath.map-sun ++@LIBQUAD_USE_SYMVER_FALSE@version_dep = ++@LIBQUAD_USE_SYMVER_GNU_TRUE@@LIBQUAD_USE_SYMVER_TRUE@version_dep = $(srcdir)/quadmath.map ++@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@version_dep = quadmath.map-sun ++toolexeclib_LTLIBRARIES = libquadmath.la ++libquadmath_la_LIBADD = ++libquadmath_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \ ++ $(version_arg) $(lt_host_flags) -lm ++ ++libquadmath_la_DEPENDENCIES = $(version_dep) $(libquadmath_la_LIBADD) ++nodist_libsubinclude_HEADERS = quadmath.h quadmath_weak.h ++libsubincludedir = $(libdir)/gcc/$(target_alias)/$(gcc_version)/include ++libquadmath_la_SOURCES = \ ++ math/x2y2m1q.c math/acoshq.c math/fmodq.c \ ++ math/acosq.c math/frexpq.c \ ++ math/rem_pio2q.c math/asinhq.c math/hypotq.c math/remainderq.c \ ++ math/asinq.c math/rintq.c math/atan2q.c math/isinfq.c \ ++ math/roundq.c math/atanhq.c math/isnanq.c math/scalblnq.c math/atanq.c \ ++ math/j0q.c math/scalbnq.c math/cbrtq.c math/j1q.c math/signbitq.c \ ++ math/ceilq.c math/jnq.c math/sincos_table.c math/complex.c math/ldexpq.c \ ++ math/sincosq.c math/copysignq.c math/lgammaq.c math/sincosq_kernel.c \ ++ math/coshq.c math/llroundq.c math/sinhq.c math/cosq.c math/log10q.c \ ++ math/sinq.c math/cosq_kernel.c math/log1pq.c math/sinq_kernel.c \ ++ math/erfq.c math/logq.c math/sqrtq.c math/expm1q.c math/lroundq.c \ ++ math/tanhq.c math/expq.c math/modfq.c math/tanq.c math/fabsq.c \ ++ math/nanq.c math/tgammaq.c math/finiteq.c math/nextafterq.c \ ++ math/truncq.c math/floorq.c math/powq.c math/fmaq.c math/logbq.c \ ++ math/exp2q.c math/issignalingq.c math/lgammaq_neg.c math/lgammaq_product.c \ ++ math/tanq_kernel.c math/tgammaq_product.c math/casinhq_kernel.c \ ++ math/cacoshq.c math/cacosq.c math/casinhq.c math/casinq.c \ ++ math/catanhq.c math/catanq.c math/cimagq.c math/conjq.c math/cprojq.c \ ++ math/crealq.c math/fdimq.c math/fmaxq.c math/fminq.c math/ilogbq.c \ ++ math/llrintq.c math/log2q.c math/lrintq.c math/nearbyintq.c math/remquoq.c \ ++ math/ccoshq.c math/cexpq.c math/clog10q.c math/clogq.c math/csinq.c \ ++ math/csinhq.c math/csqrtq.c math/ctanq.c math/ctanhq.c \ ++ printf/addmul_1.c printf/add_n.c printf/cmp.c printf/divrem.c \ ++ printf/flt1282mpn.c printf/fpioconst.c printf/lshift.c printf/mul_1.c \ ++ printf/mul_n.c printf/mul.c printf/printf_fphex.c printf/printf_fp.c \ ++ printf/quadmath-printf.c printf/rshift.c printf/submul_1.c printf/sub_n.c \ ++ strtod/strtoflt128.c strtod/mpn2flt128.c strtod/tens_in_limb.c + + + # 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 + # friends when we are called from the top level Makefile. +-@BUILD_LIBQUADMATH_TRUE@AM_MAKEFLAGS = \ +-@BUILD_LIBQUADMATH_TRUE@ "AR_FLAGS=$(AR_FLAGS)" \ +-@BUILD_LIBQUADMATH_TRUE@ "CC_FOR_BUILD=$(CC_FOR_BUILD)" \ +-@BUILD_LIBQUADMATH_TRUE@ "CFLAGS=$(CFLAGS)" \ +-@BUILD_LIBQUADMATH_TRUE@ "CXXFLAGS=$(CXXFLAGS)" \ +-@BUILD_LIBQUADMATH_TRUE@ "CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \ +-@BUILD_LIBQUADMATH_TRUE@ "CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \ +-@BUILD_LIBQUADMATH_TRUE@ "INSTALL=$(INSTALL)" \ +-@BUILD_LIBQUADMATH_TRUE@ "INSTALL_DATA=$(INSTALL_DATA)" \ +-@BUILD_LIBQUADMATH_TRUE@ "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \ +-@BUILD_LIBQUADMATH_TRUE@ "INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \ +-@BUILD_LIBQUADMATH_TRUE@ "JC1FLAGS=$(JC1FLAGS)" \ +-@BUILD_LIBQUADMATH_TRUE@ "LDFLAGS=$(LDFLAGS)" \ +-@BUILD_LIBQUADMATH_TRUE@ "LIBCFLAGS=$(LIBCFLAGS)" \ +-@BUILD_LIBQUADMATH_TRUE@ "LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \ +-@BUILD_LIBQUADMATH_TRUE@ "MAKE=$(MAKE)" \ +-@BUILD_LIBQUADMATH_TRUE@ "MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \ +-@BUILD_LIBQUADMATH_TRUE@ "PICFLAG=$(PICFLAG)" \ +-@BUILD_LIBQUADMATH_TRUE@ "PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \ +-@BUILD_LIBQUADMATH_TRUE@ "SHELL=$(SHELL)" \ +-@BUILD_LIBQUADMATH_TRUE@ "RUNTESTFLAGS=$(RUNTESTFLAGS)" \ +-@BUILD_LIBQUADMATH_TRUE@ "exec_prefix=$(exec_prefix)" \ +-@BUILD_LIBQUADMATH_TRUE@ "infodir=$(infodir)" \ +-@BUILD_LIBQUADMATH_TRUE@ "libdir=$(libdir)" \ +-@BUILD_LIBQUADMATH_TRUE@ "prefix=$(prefix)" \ +-@BUILD_LIBQUADMATH_TRUE@ "includedir=$(includedir)" \ +-@BUILD_LIBQUADMATH_TRUE@ "AR=$(AR)" \ +-@BUILD_LIBQUADMATH_TRUE@ "AS=$(AS)" \ +-@BUILD_LIBQUADMATH_TRUE@ "CC=$(CC)" \ +-@BUILD_LIBQUADMATH_TRUE@ "CXX=$(CXX)" \ +-@BUILD_LIBQUADMATH_TRUE@ "LD=$(LD)" \ +-@BUILD_LIBQUADMATH_TRUE@ "LIBCFLAGS=$(LIBCFLAGS)" \ +-@BUILD_LIBQUADMATH_TRUE@ "NM=$(NM)" \ +-@BUILD_LIBQUADMATH_TRUE@ "PICFLAG=$(PICFLAG)" \ +-@BUILD_LIBQUADMATH_TRUE@ "RANLIB=$(RANLIB)" \ +-@BUILD_LIBQUADMATH_TRUE@ "DESTDIR=$(DESTDIR)" ++AM_MAKEFLAGS = \ ++ "AR_FLAGS=$(AR_FLAGS)" \ ++ "CC_FOR_BUILD=$(CC_FOR_BUILD)" \ ++ "CFLAGS=$(CFLAGS)" \ ++ "CXXFLAGS=$(CXXFLAGS)" \ ++ "CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \ ++ "CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \ ++ "INSTALL=$(INSTALL)" \ ++ "INSTALL_DATA=$(INSTALL_DATA)" \ ++ "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \ ++ "INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \ ++ "JC1FLAGS=$(JC1FLAGS)" \ ++ "LDFLAGS=$(LDFLAGS)" \ ++ "LIBCFLAGS=$(LIBCFLAGS)" \ ++ "LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \ ++ "MAKE=$(MAKE)" \ ++ "MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \ ++ "PICFLAG=$(PICFLAG)" \ ++ "PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \ ++ "SHELL=$(SHELL)" \ ++ "RUNTESTFLAGS=$(RUNTESTFLAGS)" \ ++ "exec_prefix=$(exec_prefix)" \ ++ "infodir=$(infodir)" \ ++ "libdir=$(libdir)" \ ++ "prefix=$(prefix)" \ ++ "includedir=$(includedir)" \ ++ "AR=$(AR)" \ ++ "AS=$(AS)" \ ++ "CC=$(CC)" \ ++ "CXX=$(CXX)" \ ++ "LD=$(LD)" \ ++ "LIBCFLAGS=$(LIBCFLAGS)" \ ++ "NM=$(NM)" \ ++ "PICFLAG=$(PICFLAG)" \ ++ "RANLIB=$(RANLIB)" \ ++ "DESTDIR=$(DESTDIR)" + + + # Subdir rules rely on $(FLAGS_TO_PASS) +-@BUILD_LIBQUADMATH_TRUE@FLAGS_TO_PASS = $(AM_MAKEFLAGS) +-@BUILD_LIBQUADMATH_TRUE@MAKEOVERRIDES = +-@BUILD_LIBQUADMATH_TRUE@@GENINSRC_FALSE@STAMP_GENINSRC = ++FLAGS_TO_PASS = $(AM_MAKEFLAGS) ++MAKEOVERRIDES = ++@GENINSRC_FALSE@STAMP_GENINSRC = + + # AM_CONDITIONAL on configure option --generated-files-in-srcdir +-@BUILD_LIBQUADMATH_TRUE@@GENINSRC_TRUE@STAMP_GENINSRC = stamp-geninsrc +-@BUILD_LIBQUADMATH_TRUE@ALL_LOCAL_DEPS = $(STAMP_GENINSRC) +-@BUILD_INFO_FALSE@@BUILD_LIBQUADMATH_TRUE@STAMP_BUILD_INFO = ++@GENINSRC_TRUE@STAMP_GENINSRC = stamp-geninsrc ++ALL_LOCAL_DEPS = $(STAMP_GENINSRC) ++@BUILD_INFO_FALSE@STAMP_BUILD_INFO = + + # AM_CONDITIONAL on configure check ACX_CHECK_PROG_VER([MAKEINFO]) +-@BUILD_INFO_TRUE@@BUILD_LIBQUADMATH_TRUE@STAMP_BUILD_INFO = stamp-build-info +-@BUILD_LIBQUADMATH_TRUE@CLEANFILES = $(STAMP_GENINSRC) $(STAMP_BUILD_INFO) +-@BUILD_LIBQUADMATH_TRUE@MAINTAINERCLEANFILES = $(srcdir)/libquadmath.info ++@BUILD_INFO_TRUE@STAMP_BUILD_INFO = stamp-build-info ++CLEANFILES = $(STAMP_GENINSRC) $(STAMP_BUILD_INFO) ++MAINTAINERCLEANFILES = $(srcdir)/libquadmath.info + + # Automake Documentation: + # If your package has Texinfo files in many directories, you can use the +@@ -564,8 +564,8 @@ TEXINFO_TEX = ../gcc/doc/include/texinfo.tex + + # Defines info, dvi, pdf and html targets + MAKEINFOFLAGS = -I $(srcdir)/../gcc/doc/include +-@BUILD_LIBQUADMATH_FALSE@info_TEXINFOS = +-@BUILD_LIBQUADMATH_TRUE@info_TEXINFOS = libquadmath.texi ++info_TEXINFOS = ++info_TEXINFOS = libquadmath.texi + libquadmath_TEXINFOS = libquadmath-vers.texi + MULTISRCTOP = + MULTIBUILDTOP = +@@ -1187,6 +1187,7 @@ distclean-tags: + -rm -f cscope.out cscope.in.out cscope.po.out cscope.files + check-am: all-am + check: check-am ++#all-local + all-am: Makefile $(INFO_DEPS) $(LTLIBRARIES) $(HEADERS) config.h \ + all-local + installdirs: +@@ -1425,22 +1426,22 @@ uninstall-am: uninstall-dvi-am uninstall-html-am uninstall-info-am \ + + .PRECIOUS: Makefile + +-@BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@quadmath.map-sun : $(srcdir)/quadmath.map \ +-@BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ $(top_srcdir)/../contrib/make_sunver.pl \ +-@BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ $(libquadmath_la_OBJECTS) $(libquadmath_la_LIBADD) +-@BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ perl $(top_srcdir)/../contrib/make_sunver.pl \ +-@BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ $(srcdir)/quadmath.map \ +-@BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ `echo $(libquadmath_la_OBJECTS) $(libquadmath_la_LIBADD) | \ +-@BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ sed 's,\([^/ ]*\)\.l\([ao]\),.libs/\1.\2,g'` \ +-@BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ > $@ || (rm -f $@ ; exit 1) +- +-@BUILD_LIBQUADMATH_TRUE@stamp-geninsrc: libquadmath.info +-@BUILD_LIBQUADMATH_TRUE@ cp -p $(top_builddir)/libquadmath.info $(srcdir)/libquadmath.info +-@BUILD_LIBQUADMATH_TRUE@ @touch $@ +- +-@BUILD_LIBQUADMATH_TRUE@stamp-build-info: libquadmath.texi $(libquadmath_TEXINFOS) +-@BUILD_LIBQUADMATH_TRUE@ $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) -o libquadmath.info $(srcdir)/libquadmath.texi +-@BUILD_LIBQUADMATH_TRUE@ @touch $@ ++@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@quadmath.map-sun : $(srcdir)/quadmath.map \ ++@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ $(top_srcdir)/../contrib/make_sunver.pl \ ++@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ $(libquadmath_la_OBJECTS) $(libquadmath_la_LIBADD) ++@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ perl $(top_srcdir)/../contrib/make_sunver.pl \ ++@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ $(srcdir)/quadmath.map \ ++@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ `echo $(libquadmath_la_OBJECTS) $(libquadmath_la_LIBADD) | \ ++@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ sed 's,\([^/ ]*\)\.l\([ao]\),.libs/\1.\2,g'` \ ++@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ > $@ || (rm -f $@ ; exit 1) ++ ++stamp-geninsrc: libquadmath.info ++ cp -p $(top_builddir)/libquadmath.info $(srcdir)/libquadmath.info ++ @touch $@ ++ ++stamp-build-info: libquadmath.texi $(libquadmath_TEXINFOS) ++ $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) -o libquadmath.info $(srcdir)/libquadmath.texi ++ @touch $@ + + all-local: $(ALL_LOCAL_DEPS) + +diff --git a/libquadmath/quadmath.h b/libquadmath/quadmath.h +index 81eb957d2fa..faa5977cbc9 100644 +--- a/libquadmath/quadmath.h ++++ b/libquadmath/quadmath.h +@@ -27,6 +27,9 @@ Boston, MA 02110-1301, USA. */ + extern "C" { + #endif + ++#ifdef AARCH64_QUADMATH ++typedef long double __float128; ++#endif + /* Define the complex type corresponding to __float128 + ("_Complex __float128" is not allowed) */ + #if (!defined(_ARCH_PPC)) || defined(__LONG_DOUBLE_IEEE128__) +@@ -160,10 +163,9 @@ extern int quadmath_snprintf (char *str, size_t size, + #define FLT128_MAX_10_EXP 4932 + + +-#define HUGE_VALQ __builtin_huge_valq() + /* The following alternative is valid, but brings the warning: + (floating constant exceeds range of ‘__float128’) */ +-/* #define HUGE_VALQ (__extension__ 0x1.0p32767Q) */ ++ #define HUGE_VALQ (__extension__ 0x1.0p32767Q) + + #define M_Eq 2.718281828459045235360287471352662498Q /* e */ + #define M_LOG2Eq 1.442695040888963407359924681001892137Q /* log_2 e */ +-- +2.21.0.windows.1 + diff --git a/0002-Backport-cselim-Extend-to-check-non-trapping-for-mor.patch b/0002-Backport-cselim-Extend-to-check-non-trapping-for-mor.patch new file mode 100644 index 0000000..c5df4d9 --- /dev/null +++ b/0002-Backport-cselim-Extend-to-check-non-trapping-for-mor.patch @@ -0,0 +1,318 @@ +From d1e1ec0cd539f96be5a86b369b8c20b36ce9567f Mon Sep 17 00:00:00 2001 +From: yangyang <yangyang305@huawei.com> +Date: Thu, 8 Jul 2021 14:38:39 +0800 +Subject: [PATCH 02/13] [Backport] cselim: Extend to check non-trapping for + more references + +Reference: https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=54ecfb182bc32140722022c1d9818dee4bdc0e45 + +If there is a dominating store, a store to the same reference can not be +trapped. But previously, it only supports such check on MEM_REFs. +So this patch extends it to support ARRAY_REFs and COMPONENT_REFs. + +This patch also supports a special case: if there is a dominating load of +local variable without address escape, a store is not trapped, as local +stack is always writable. Other loads are ignored for simplicity, as they +don't help to check if a store can be trapped (the memory may be read-only). + +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr89430-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr89430-1.c +index ce242ba569b..8ee1850ac63 100644 +--- a/gcc/testsuite/gcc.dg/tree-ssa/pr89430-1.c ++++ b/gcc/testsuite/gcc.dg/tree-ssa/pr89430-1.c +@@ -9,4 +9,4 @@ unsigned test(unsigned k, unsigned b) { + return a[0]+a[1]; + } + +-/* { dg-final { scan-tree-dump "Conditional store replacement" "cselim" { xfail *-*-* } } } */ ++/* { dg-final { scan-tree-dump "Conditional store replacement" "cselim" } } */ +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr89430-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr89430-2.c +index 90ae36bfce2..9b96875ac7a 100644 +--- a/gcc/testsuite/gcc.dg/tree-ssa/pr89430-2.c ++++ b/gcc/testsuite/gcc.dg/tree-ssa/pr89430-2.c +@@ -11,4 +11,4 @@ unsigned test(unsigned k, unsigned b) { + return a[0]+a[1]; + } + +-/* { dg-final { scan-tree-dump "Conditional store replacement" "cselim" { xfail *-*-* } } } */ ++/* { dg-final { scan-tree-dump "Conditional store replacement" "cselim" } } */ +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr89430-5.c b/gcc/testsuite/gcc.dg/tree-ssa/pr89430-5.c +index c633cbe947d..b2d04119381 100644 +--- a/gcc/testsuite/gcc.dg/tree-ssa/pr89430-5.c ++++ b/gcc/testsuite/gcc.dg/tree-ssa/pr89430-5.c +@@ -13,4 +13,4 @@ int test(int b, int k) { + return a.data[0] + a.data[1]; + } + +-/* { dg-final { scan-tree-dump "Conditional store replacement" "cselim" { xfail *-*-* } } } */ ++/* { dg-final { scan-tree-dump "Conditional store replacement" "cselim" } } */ +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr89430-6.c b/gcc/testsuite/gcc.dg/tree-ssa/pr89430-6.c +index 7cad563128d..8d3c4f7cc6a 100644 +--- a/gcc/testsuite/gcc.dg/tree-ssa/pr89430-6.c ++++ b/gcc/testsuite/gcc.dg/tree-ssa/pr89430-6.c +@@ -16,4 +16,4 @@ int test(int b, int k) { + return a.data[0].x + a.data[1].x; + } + +-/* { dg-final { scan-tree-dump "Conditional store replacement" "cselim" { xfail *-*-* } } } */ ++/* { dg-final { scan-tree-dump "Conditional store replacement" "cselim" } } */ +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr89430-7-comp-ref.c b/gcc/testsuite/gcc.dg/tree-ssa/pr89430-7-comp-ref.c +new file mode 100644 +index 00000000000..c35a2afc70b +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/pr89430-7-comp-ref.c +@@ -0,0 +1,17 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -fdump-tree-cselim-details" } */ ++ ++typedef union { ++ int i; ++ float f; ++} U; ++ ++int foo(U *u, int b, int i) ++{ ++ u->i = 0; ++ if (b) ++ u->i = i; ++ return u->i; ++} ++ ++/* { dg-final { scan-tree-dump "Conditional store replacement" "cselim" } } */ +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr89430-8-mem-ref-size.c b/gcc/testsuite/gcc.dg/tree-ssa/pr89430-8-mem-ref-size.c +new file mode 100644 +index 00000000000..f9e66aefb13 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/pr89430-8-mem-ref-size.c +@@ -0,0 +1,15 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -fdump-tree-cselim-details" } */ ++ ++int *t; ++ ++int f1 (int tt) ++{ ++ int *t1 = t; ++ *t1 = -5; ++ if (*t1 < tt) ++ *((unsigned *) t1) = 5; ++ return *t1; ++} ++ ++/* { dg-final { scan-tree-dump "Conditional store replacement" "cselim" } } */ +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-17.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-17.c +index 09313716598..a06f339f0bb 100644 +--- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-17.c ++++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-17.c +@@ -1,5 +1,5 @@ + /* { dg-do compile } */ +-/* { dg-options "-O2 -fdump-tree-pre-stats" } */ ++/* { dg-options "-O2 -fdump-tree-pre-stats -fno-tree-cselim" } */ + + typedef union { + int i; +diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c +index b1e0dce93d8..3b5b6907679 100644 +--- a/gcc/tree-ssa-phiopt.c ++++ b/gcc/tree-ssa-phiopt.c +@@ -1986,26 +1986,33 @@ abs_replacement (basic_block cond_bb, basic_block middle_bb, + + ??? We currently are very conservative and assume that a load might + trap even if a store doesn't (write-only memory). This probably is +- overly conservative. */ ++ overly conservative. + +-/* A hash-table of SSA_NAMEs, and in which basic block an MEM_REF +- through it was seen, which would constitute a no-trap region for +- same accesses. */ +-struct name_to_bb ++ We currently support a special case that for !TREE_ADDRESSABLE automatic ++ variables, it could ignore whether something is a load or store because the ++ local stack should be always writable. */ ++ ++/* A hash-table of references (MEM_REF/ARRAY_REF/COMPONENT_REF), and in which ++ basic block an *_REF through it was seen, which would constitute a ++ no-trap region for same accesses. ++ ++ Size is needed to support 2 MEM_REFs of different types, like ++ MEM<double>(s_1) and MEM<long>(s_1), which would compare equal with ++ OEP_ADDRESS_OF. */ ++struct ref_to_bb + { +- unsigned int ssa_name_ver; ++ tree exp; ++ HOST_WIDE_INT size; + unsigned int phase; +- bool store; +- HOST_WIDE_INT offset, size; + basic_block bb; + }; + + /* Hashtable helpers. */ + +-struct ssa_names_hasher : free_ptr_hash <name_to_bb> ++struct refs_hasher : free_ptr_hash<ref_to_bb> + { +- static inline hashval_t hash (const name_to_bb *); +- static inline bool equal (const name_to_bb *, const name_to_bb *); ++ static inline hashval_t hash (const ref_to_bb *); ++ static inline bool equal (const ref_to_bb *, const ref_to_bb *); + }; + + /* Used for quick clearing of the hash-table when we see calls. +@@ -2015,28 +2022,29 @@ static unsigned int nt_call_phase; + /* The hash function. */ + + inline hashval_t +-ssa_names_hasher::hash (const name_to_bb *n) ++refs_hasher::hash (const ref_to_bb *n) + { +- return n->ssa_name_ver ^ (((hashval_t) n->store) << 31) +- ^ (n->offset << 6) ^ (n->size << 3); ++ inchash::hash hstate; ++ inchash::add_expr (n->exp, hstate, OEP_ADDRESS_OF); ++ hstate.add_hwi (n->size); ++ return hstate.end (); + } + + /* The equality function of *P1 and *P2. */ + + inline bool +-ssa_names_hasher::equal (const name_to_bb *n1, const name_to_bb *n2) ++refs_hasher::equal (const ref_to_bb *n1, const ref_to_bb *n2) + { +- return n1->ssa_name_ver == n2->ssa_name_ver +- && n1->store == n2->store +- && n1->offset == n2->offset +- && n1->size == n2->size; ++ return operand_equal_p (n1->exp, n2->exp, OEP_ADDRESS_OF) ++ && n1->size == n2->size; + } + + class nontrapping_dom_walker : public dom_walker + { + public: + nontrapping_dom_walker (cdi_direction direction, hash_set<tree> *ps) +- : dom_walker (direction), m_nontrapping (ps), m_seen_ssa_names (128) {} ++ : dom_walker (direction), m_nontrapping (ps), m_seen_refs (128) ++ {} + + virtual edge before_dom_children (basic_block); + virtual void after_dom_children (basic_block); +@@ -2053,7 +2061,7 @@ private: + hash_set<tree> *m_nontrapping; + + /* The hash table for remembering what we've seen. */ +- hash_table<ssa_names_hasher> m_seen_ssa_names; ++ hash_table<refs_hasher> m_seen_refs; + }; + + /* Called by walk_dominator_tree, when entering the block BB. */ +@@ -2102,65 +2110,68 @@ nontrapping_dom_walker::after_dom_children (basic_block bb) + } + + /* We see the expression EXP in basic block BB. If it's an interesting +- expression (an MEM_REF through an SSA_NAME) possibly insert the +- expression into the set NONTRAP or the hash table of seen expressions. +- STORE is true if this expression is on the LHS, otherwise it's on +- the RHS. */ ++ expression of: ++ 1) MEM_REF ++ 2) ARRAY_REF ++ 3) COMPONENT_REF ++ possibly insert the expression into the set NONTRAP or the hash table ++ of seen expressions. STORE is true if this expression is on the LHS, ++ otherwise it's on the RHS. */ + void + nontrapping_dom_walker::add_or_mark_expr (basic_block bb, tree exp, bool store) + { + HOST_WIDE_INT size; + +- if (TREE_CODE (exp) == MEM_REF +- && TREE_CODE (TREE_OPERAND (exp, 0)) == SSA_NAME +- && tree_fits_shwi_p (TREE_OPERAND (exp, 1)) ++ if ((TREE_CODE (exp) == MEM_REF || TREE_CODE (exp) == ARRAY_REF ++ || TREE_CODE (exp) == COMPONENT_REF) + && (size = int_size_in_bytes (TREE_TYPE (exp))) > 0) + { +- tree name = TREE_OPERAND (exp, 0); +- struct name_to_bb map; +- name_to_bb **slot; +- struct name_to_bb *n2bb; ++ struct ref_to_bb map; ++ ref_to_bb **slot; ++ struct ref_to_bb *r2bb; + basic_block found_bb = 0; + +- /* Try to find the last seen MEM_REF through the same +- SSA_NAME, which can trap. */ +- map.ssa_name_ver = SSA_NAME_VERSION (name); +- map.phase = 0; +- map.bb = 0; +- map.store = store; +- map.offset = tree_to_shwi (TREE_OPERAND (exp, 1)); +- map.size = size; ++ if (!store) ++ { ++ tree base = get_base_address (exp); ++ /* Only record a LOAD of a local variable without address-taken, as ++ the local stack is always writable. This allows cselim on a STORE ++ with a dominating LOAD. */ ++ if (!auto_var_p (base) || TREE_ADDRESSABLE (base)) ++ return; ++ } + +- slot = m_seen_ssa_names.find_slot (&map, INSERT); +- n2bb = *slot; +- if (n2bb && n2bb->phase >= nt_call_phase) +- found_bb = n2bb->bb; ++ /* Try to find the last seen *_REF, which can trap. */ ++ map.exp = exp; ++ map.size = size; ++ slot = m_seen_refs.find_slot (&map, INSERT); ++ r2bb = *slot; ++ if (r2bb && r2bb->phase >= nt_call_phase) ++ found_bb = r2bb->bb; + +- /* If we've found a trapping MEM_REF, _and_ it dominates EXP +- (it's in a basic block on the path from us to the dominator root) ++ /* If we've found a trapping *_REF, _and_ it dominates EXP ++ (it's in a basic block on the path from us to the dominator root) + then we can't trap. */ + if (found_bb && (((size_t)found_bb->aux) & 1) == 1) + { + m_nontrapping->add (exp); + } + else +- { ++ { + /* EXP might trap, so insert it into the hash table. */ +- if (n2bb) ++ if (r2bb) + { +- n2bb->phase = nt_call_phase; +- n2bb->bb = bb; ++ r2bb->phase = nt_call_phase; ++ r2bb->bb = bb; + } + else + { +- n2bb = XNEW (struct name_to_bb); +- n2bb->ssa_name_ver = SSA_NAME_VERSION (name); +- n2bb->phase = nt_call_phase; +- n2bb->bb = bb; +- n2bb->store = store; +- n2bb->offset = map.offset; +- n2bb->size = size; +- *slot = n2bb; ++ r2bb = XNEW (struct ref_to_bb); ++ r2bb->phase = nt_call_phase; ++ r2bb->bb = bb; ++ r2bb->exp = exp; ++ r2bb->size = size; ++ *slot = r2bb; + } + } + } +-- +2.21.0.windows.1 + diff --git a/0003-version-Set-version-to-10.3.1.patch b/0003-version-Set-version-to-10.3.1.patch new file mode 100644 index 0000000..d069bdd --- /dev/null +++ b/0003-version-Set-version-to-10.3.1.patch @@ -0,0 +1,31 @@ +From 309f459021a3681d728e5cf644a288ecf2b95175 Mon Sep 17 00:00:00 2001 +From: zhanghaijian <z.zhanghaijian@huawei.com> +Date: Mon, 12 Jul 2021 09:42:11 +0800 +Subject: [PATCH 03/13] [version] Set version to 10.3.1 + +Set version to 10.3.1 and clear DATESTAMP_s. + +diff --git a/gcc/BASE-VER b/gcc/BASE-VER +index 0719d810258..a9368325816 100644 +--- a/gcc/BASE-VER ++++ b/gcc/BASE-VER +@@ -1 +1 @@ +-10.3.0 ++10.3.1 +diff --git a/gcc/Makefile.in b/gcc/Makefile.in +index 646db219460..fdc2857d44a 100644 +--- a/gcc/Makefile.in ++++ b/gcc/Makefile.in +@@ -885,8 +885,7 @@ PATCHLEVEL_c := \ + # significant - do not remove it. + BASEVER_s := "\"$(BASEVER_c)\"" + DEVPHASE_s := "\"$(if $(DEVPHASE_c), ($(DEVPHASE_c)))\"" +-DATESTAMP_s := \ +- "\"$(if $(DEVPHASE_c)$(filter-out 0,$(PATCHLEVEL_c)), $(DATESTAMP_c))\"" ++DATESTAMP_s := "\"\"" + PKGVERSION_s:= "\"@PKGVERSION@\"" + BUGURL_s := "\"@REPORT_BUGS_TO@\"" + +-- +2.21.0.windows.1 + diff --git a/0004-Backport-tree-optimization-Avoid-issueing-loads-in-S.patch b/0004-Backport-tree-optimization-Avoid-issueing-loads-in-S.patch new file mode 100644 index 0000000..54b4116 --- /dev/null +++ b/0004-Backport-tree-optimization-Avoid-issueing-loads-in-S.patch @@ -0,0 +1,138 @@ +From bdb0f40cea4aa1a92ead381b645363ae0571c065 Mon Sep 17 00:00:00 2001 +From: zhanghaijian <z.zhanghaijian@huawei.com> +Date: Mon, 12 Jul 2021 10:36:15 +0800 +Subject: [PATCH 04/13] [Backport]tree-optimization: Avoid issueing loads in SM + when possible + +Reference:https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=f9e1ea10e657af9fb02fafecf1a600740fd34409 + +Currently store-motion emits a load of the value in the loop +preheader even when the original loop does not contain any read +of the reference. This avoids doing this. In the conditional +store-motion case we need to mark the sunk stores with no-warning +since the control dependence is too tricky to figure out for +the uninit warning. + +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr39612.c b/gcc/testsuite/gcc.dg/tree-ssa/pr39612.c +new file mode 100755 +index 00000000000..884f905148f +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/pr39612.c +@@ -0,0 +1,21 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -fdump-tree-lim2-details -Wuninitialized" } */ ++ ++void foo(int *); ++void f2(int dst[3], int R) ++{ ++ int i, inter[2]; ++ ++ for (i = 1; i < R; i++) { ++ if (i & 8) ++ { ++ inter[0] = 1; ++ inter[1] = 1; ++ } ++ } ++ ++ foo(inter); ++} ++ ++/* { dg-final { scan-tree-dump-times "Executing store motion" 2 "lim2" } } */ ++/* { dg-final { scan-tree-dump-not " = inter\\\[\[0-1\]\\\];" "lim2" } } */ +diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c +index abd5f702b91..b3fd1647fbd 100644 +--- a/gcc/tree-ssa-loop-im.c ++++ b/gcc/tree-ssa-loop-im.c +@@ -127,6 +127,8 @@ public: + + bitmap stored; /* The set of loops in that this memory location + is stored to. */ ++ bitmap loaded; /* The set of loops in that this memory location ++ is loaded from. */ + vec<mem_ref_loc> accesses_in_loop; + /* The locations of the accesses. Vector + indexed by the loop number. */ +@@ -1395,6 +1397,7 @@ mem_ref_alloc (ao_ref *mem, unsigned hash, unsigned id) + ref->ref_decomposed = false; + ref->hash = hash; + ref->stored = NULL; ++ ref->loaded = NULL; + bitmap_initialize (&ref->indep_loop, &lim_bitmap_obstack); + bitmap_initialize (&ref->dep_loop, &lim_bitmap_obstack); + ref->accesses_in_loop.create (1); +@@ -1435,6 +1438,27 @@ mark_ref_stored (im_mem_ref *ref, class loop *loop) + loop = loop_outer (loop); + } + ++/* Set the LOOP bit in REF loaded bitmap and allocate that if ++ necessary. Return whether a bit was changed. */ ++ ++static bool ++set_ref_loaded_in_loop (im_mem_ref *ref, class loop *loop) ++{ ++ if (!ref->loaded) ++ ref->loaded = BITMAP_ALLOC (&lim_bitmap_obstack); ++ return bitmap_set_bit (ref->loaded, loop->num); ++} ++ ++/* Marks reference REF as loaded in LOOP. */ ++ ++static void ++mark_ref_loaded (im_mem_ref *ref, class loop *loop) ++{ ++ while (loop != current_loops->tree_root ++ && set_ref_loaded_in_loop (ref, loop)) ++ loop = loop_outer (loop); ++} ++ + /* Gathers memory references in statement STMT in LOOP, storing the + information about them in the memory_accesses structure. Marks + the vops accessed through unrecognized statements there as +@@ -1571,6 +1595,8 @@ gather_mem_refs_stmt (class loop *loop, gimple *stmt) + bitmap_set_bit (&memory_accesses.refs_stored_in_loop[loop->num], ref->id); + mark_ref_stored (ref, loop); + } ++ else ++ mark_ref_loaded (ref, loop); + init_lim_data (stmt)->ref = ref->id; + return; + } +@@ -1968,6 +1994,8 @@ execute_sm_if_changed (edge ex, tree mem, tree tmp_var, tree flag, + gsi = gsi_start_bb (then_bb); + /* Insert actual store. */ + stmt = gimple_build_assign (unshare_expr (mem), tmp_var); ++ /* Make sure to not warn about maybe-uninit uses of tmp_var here. */ ++ gimple_set_no_warning (stmt, true); + gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); + + edge e1 = single_succ_edge (new_bb); +@@ -2115,14 +2143,17 @@ execute_sm (class loop *loop, vec<edge> exits, im_mem_ref *ref) + by move_computations after all dependencies. */ + gsi = gsi_for_stmt (first_mem_ref_loc (loop, ref)->stmt); + +- /* FIXME/TODO: For the multi-threaded variant, we could avoid this +- load altogether, since the store is predicated by a flag. We +- could, do the load only if it was originally in the loop. */ +- load = gimple_build_assign (tmp_var, unshare_expr (ref->mem.ref)); +- lim_data = init_lim_data (load); +- lim_data->max_loop = loop; +- lim_data->tgt_loop = loop; +- gsi_insert_before (&gsi, load, GSI_SAME_STMT); ++ /* Avoid doing a load if there was no load of the ref in the loop. ++ Esp. when the ref is not always stored we cannot optimize it ++ away later. */ ++ if (ref->loaded && bitmap_bit_p (ref->loaded, loop->num)) ++ { ++ load = gimple_build_assign (tmp_var, unshare_expr (ref->mem.ref)); ++ lim_data = init_lim_data (load); ++ lim_data->max_loop = loop; ++ lim_data->tgt_loop = loop; ++ gsi_insert_before (&gsi, load, GSI_SAME_STMT); ++ } + + if (multi_threaded_model_p) + { +-- +2.21.0.windows.1 + diff --git a/0005-Backport-tree-optimization-Fix-load-eliding-in-SM.patch b/0005-Backport-tree-optimization-Fix-load-eliding-in-SM.patch new file mode 100644 index 0000000..0ab01ea --- /dev/null +++ b/0005-Backport-tree-optimization-Fix-load-eliding-in-SM.patch @@ -0,0 +1,66 @@ +From dc238e97a75835231939e77e8568ccd9bc5187d5 Mon Sep 17 00:00:00 2001 +From: zhanghaijian <z.zhanghaijian@huawei.com> +Date: Mon, 12 Jul 2021 10:46:16 +0800 +Subject: [PATCH 05/13] [Backport]tree-optimization: Fix load eliding in SM + +Reference: https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=0424a5ece5307cc22bbc0fe97edf4707d7a798ed + +This fixes the case of not using the multithreaded model when +only conditionally storing to the destination. We cannot elide +the load in this case. + +diff --git a/gcc/testsuite/gcc.dg/torture/pr94949.c b/gcc/testsuite/gcc.dg/torture/pr94949.c +new file mode 100755 +index 00000000000..6182d77b3cd +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/torture/pr94949.c +@@ -0,0 +1,17 @@ ++/* { dg-do run } */ ++/* { dg-additional-options "-fallow-store-data-races" } */ ++ ++static int x = 1; ++static volatile int y = -1; ++int ++main() ++{ ++ for (int i = 0; i < 128; ++i) ++ { ++ if (i == y) ++ x = i; ++ } ++ if (x != 1) ++ __builtin_abort (); ++ return 0; ++} +diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c +index b3fd1647fbd..8c33735b1fa 100644 +--- a/gcc/tree-ssa-loop-im.c ++++ b/gcc/tree-ssa-loop-im.c +@@ -2128,9 +2128,9 @@ execute_sm (class loop *loop, vec<edge> exits, im_mem_ref *ref) + fmt_data.orig_loop = loop; + for_each_index (&ref->mem.ref, force_move_till, &fmt_data); + ++ bool always_stored = ref_always_accessed_p (loop, ref, true); + if (bb_in_transaction (loop_preheader_edge (loop)->src) +- || (! flag_store_data_races +- && ! ref_always_accessed_p (loop, ref, true))) ++ || (! flag_store_data_races && ! always_stored)) + multi_threaded_model_p = true; + + if (multi_threaded_model_p) +@@ -2145,8 +2145,10 @@ execute_sm (class loop *loop, vec<edge> exits, im_mem_ref *ref) + + /* Avoid doing a load if there was no load of the ref in the loop. + Esp. when the ref is not always stored we cannot optimize it +- away later. */ +- if (ref->loaded && bitmap_bit_p (ref->loaded, loop->num)) ++ away later. But when it is not always stored we must use a conditional ++ store then. */ ++ if ((!always_stored && !multi_threaded_model_p) ++ || (ref->loaded && bitmap_bit_p (ref->loaded, loop->num))) + { + load = gimple_build_assign (tmp_var, unshare_expr (ref->mem.ref)); + lim_data = init_lim_data (load); +-- +2.21.0.windows.1 + diff --git a/0006-simdmath-Enable-simdmath-on-kunpeng.patch b/0006-simdmath-Enable-simdmath-on-kunpeng.patch new file mode 100644 index 0000000..9d7bb57 --- /dev/null +++ b/0006-simdmath-Enable-simdmath-on-kunpeng.patch @@ -0,0 +1,289 @@ +From cfd6920125f7968f0c1f5cb225f9fbd5bc8988b9 Mon Sep 17 00:00:00 2001 +From: bule <bule1@huawei.com> +Date: Tue, 13 Jul 2021 15:26:54 +0800 +Subject: [PATCH 06/13] [simdmath] Enable simdmath on kunpeng + +This enable simd math function supported by libmathlib on fortran/c/c++. +Use -fsimdmath to turn on the generation of simdmath function. The +supported functions can be found in simdmath.h. Add more simd declaration +if you need more kinds of math functions. -msimdmath-64 is used to turn +on 64-bit simd math functions which is not supported by libmathlib. +Therefore, this option is default to off. + +diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c +index c51d6d34726..dc1a8984871 100644 +--- a/gcc/c-family/c-opts.c ++++ b/gcc/c-family/c-opts.c +@@ -780,6 +780,10 @@ c_common_post_options (const char **pfilename) + if (cpp_opts->deps.style == DEPS_NONE) + check_deps_environment_vars (); + ++ if (flag_simdmath) ++ { ++ defer_opt (OPT_include, "simdmath.h"); ++ } + handle_deferred_opts (); + + sanitize_cpp_opts (); +diff --git a/gcc/common.opt b/gcc/common.opt +index ec5235c3a41..8eb05570418 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -1977,6 +1977,10 @@ fmath-errno + Common Report Var(flag_errno_math) Init(1) Optimization SetByCombined + Set errno after built-in math functions. + ++fsimdmath ++Common Report Var(flag_simdmath) Init(0) Optimization ++Enable auto-vectorize math functions for mathlib. This option will turn on -fno-math-errno and -fopenmp-simd. ++ + fmax-errors= + Common Joined RejectNegative UInteger Var(flag_max_errors) + -fmax-errors=<number> Maximum number of errors to report. +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 9b400c49ac6..79dc8f186f4 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -23077,8 +23077,12 @@ aarch64_simd_clone_compute_vecsize_and_simdlen (struct cgraph_node *node, + elt_bits = GET_MODE_BITSIZE (SCALAR_TYPE_MODE (base_type)); + if (clonei->simdlen == 0) + { +- count = 2; +- vec_bits = (num == 0 ? 64 : 128); ++ /* Currently mathlib or sleef hasn't provide function for V2SF mode ++ simdclone of single precision functions. (e.g._ZCVnN2v_expf) ++ Therefore this mode is disabled by default to avoid link error. ++ Use -msimdmath-64 option to enable this mode. */ ++ count = flag_simdmath_64 ? 2 : 1; ++ vec_bits = ((num == 0 && flag_simdmath_64) ? 64 : 128); + clonei->simdlen = vec_bits / elt_bits; + } + else +diff --git a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt +index 1b3d942e0f5..4539156d6f4 100644 +--- a/gcc/config/aarch64/aarch64.opt ++++ b/gcc/config/aarch64/aarch64.opt +@@ -190,6 +190,12 @@ precision of square root results to about 16 bits for + single precision and to 32 bits for double precision. + If enabled, it implies -mlow-precision-recip-sqrt. + ++msimdmath-64 ++Target Var(flag_simdmath_64) Optimization ++Allow compiler to generate V2SF 64 bits simdclone of math functions, ++which is not currently supported in mathlib or sleef. ++Therefore this option is disabled by default. ++ + mlow-precision-div + Target Var(flag_mlow_precision_div) Optimization + Enable the division approximation. Enabling this reduces +diff --git a/gcc/fortran/scanner.c b/gcc/fortran/scanner.c +index 6f93508f934..42fd5a8be1e 100644 +--- a/gcc/fortran/scanner.c ++++ b/gcc/fortran/scanner.c +@@ -2737,6 +2737,10 @@ gfc_new_file (void) + && !load_file (flag_pre_include, NULL, false)) + exit (FATAL_EXIT_CODE); + ++ if (flag_simdmath ++ && !load_file ("simdmath_f.h", NULL, false)) ++ exit (FATAL_EXIT_CODE); ++ + if (gfc_cpp_enabled ()) + { + result = gfc_cpp_preprocess (gfc_source_file); +diff --git a/gcc/opts.c b/gcc/opts.c +index 73162528938..e31aa560564 100644 +--- a/gcc/opts.c ++++ b/gcc/opts.c +@@ -189,6 +189,7 @@ static const char use_diagnosed_msg[] = N_("Uses of this option are diagnosed.") + + typedef char *char_p; /* For DEF_VEC_P. */ + ++static void set_simdmath_flags (struct gcc_options *opts, int set); + static void set_debug_level (enum debug_info_type type, int extended, + const char *arg, struct gcc_options *opts, + struct gcc_options *opts_set, +@@ -2469,6 +2470,10 @@ common_handle_option (struct gcc_options *opts, + dc->min_margin_width = value; + break; + ++ case OPT_fsimdmath: ++ set_simdmath_flags (opts, value); ++ break; ++ + case OPT_fdump_: + /* Deferred. */ + break; +@@ -2847,6 +2852,18 @@ common_handle_option (struct gcc_options *opts, + return true; + } + ++/* The following routines are used to set -fno-math-errno and -fopenmp-simd ++ to enable vector mathlib. */ ++static void ++set_simdmath_flags (struct gcc_options *opts, int set) ++{ ++ if (set) ++ { ++ opts->x_flag_errno_math = 0; ++ opts->x_flag_openmp_simd = 1; ++ } ++} ++ + /* Used to set the level of strict aliasing warnings in OPTS, + when no level is specified (i.e., when -Wstrict-aliasing, and not + -Wstrict-aliasing=level was given). +diff --git a/libgomp/Makefile.am b/libgomp/Makefile.am +index 669b9e4defd..0d9cc96481c 100644 +--- a/libgomp/Makefile.am ++++ b/libgomp/Makefile.am +@@ -74,10 +74,10 @@ libgomp_la_SOURCES += openacc.f90 + endif + + nodist_noinst_HEADERS = libgomp_f.h +-nodist_libsubinclude_HEADERS = omp.h openacc.h acc_prof.h ++nodist_libsubinclude_HEADERS = omp.h openacc.h acc_prof.h simdmath.h + if USE_FORTRAN + nodist_finclude_HEADERS = omp_lib.h omp_lib.f90 omp_lib.mod omp_lib_kinds.mod \ +- openacc_lib.h openacc.f90 openacc.mod openacc_kinds.mod ++ openacc_lib.h openacc.f90 openacc.mod openacc_kinds.mod simdmath_f.h + endif + + LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS)) +diff --git a/libgomp/Makefile.in b/libgomp/Makefile.in +index ae5d9d54705..dd4b334895e 100644 +--- a/libgomp/Makefile.in ++++ b/libgomp/Makefile.in +@@ -148,7 +148,7 @@ am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno + mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs + CONFIG_HEADER = config.h +-CONFIG_CLEAN_FILES = omp.h omp_lib.h omp_lib.f90 libgomp_f.h \ ++CONFIG_CLEAN_FILES = omp.h omp_lib.h simdmath.h simdmath_f.h omp_lib.f90 libgomp_f.h \ + libgomp.spec + CONFIG_CLEAN_VPATH_FILES = + am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +@@ -609,9 +609,9 @@ libgomp_la_SOURCES = alloc.c atomic.c barrier.c critical.c env.c \ + @PLUGIN_GCN_TRUE@libgomp_plugin_gcn_la_LIBADD = libgomp.la $(PLUGIN_GCN_LIBS) + @PLUGIN_GCN_TRUE@libgomp_plugin_gcn_la_LIBTOOLFLAGS = --tag=disable-static + nodist_noinst_HEADERS = libgomp_f.h +-nodist_libsubinclude_HEADERS = omp.h openacc.h acc_prof.h ++nodist_libsubinclude_HEADERS = omp.h openacc.h acc_prof.h simdmath.h + @USE_FORTRAN_TRUE@nodist_finclude_HEADERS = omp_lib.h omp_lib.f90 omp_lib.mod omp_lib_kinds.mod \ +-@USE_FORTRAN_TRUE@ openacc_lib.h openacc.f90 openacc.mod openacc_kinds.mod ++@USE_FORTRAN_TRUE@ openacc_lib.h openacc.f90 openacc.mod openacc_kinds.mod simdmath_f.h + + LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS)) + LINK = $(LIBTOOL) --tag CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ +@@ -702,6 +702,10 @@ omp.h: $(top_builddir)/config.status $(srcdir)/omp.h.in + cd $(top_builddir) && $(SHELL) ./config.status $@ + omp_lib.h: $(top_builddir)/config.status $(srcdir)/omp_lib.h.in + cd $(top_builddir) && $(SHELL) ./config.status $@ ++simdmath_f.h: $(top_builddir)/config.status $(srcdir)/simdmath_f.h.in ++ cd $(top_builddir) && $(SHELL) ./config.status $@ ++simdmath.h: $(top_builddir)/config.status $(srcdir)/simdmath.h.in ++ cd $(top_builddir) && $(SHELL) ./config.status $@ + omp_lib.f90: $(top_builddir)/config.status $(srcdir)/omp_lib.f90.in + cd $(top_builddir) && $(SHELL) ./config.status $@ + libgomp_f.h: $(top_builddir)/config.status $(srcdir)/libgomp_f.h.in +diff --git a/libgomp/configure b/libgomp/configure +index 5240f7e9d39..b03036c2738 100644 +--- a/libgomp/configure ++++ b/libgomp/configure +@@ -17050,7 +17050,7 @@ fi + + + +-ac_config_files="$ac_config_files omp.h omp_lib.h omp_lib.f90 libgomp_f.h" ++ac_config_files="$ac_config_files omp.h omp_lib.h simdmath.h simdmath_f.h omp_lib.f90 libgomp_f.h" + + ac_config_files="$ac_config_files Makefile testsuite/Makefile libgomp.spec" + +@@ -18205,6 +18205,8 @@ do + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "omp.h") CONFIG_FILES="$CONFIG_FILES omp.h" ;; + "omp_lib.h") CONFIG_FILES="$CONFIG_FILES omp_lib.h" ;; ++ "simdmath.h") CONFIG_FILES="$CONFIG_FILES simdmath.h" ;; ++ "simdmath_f.h") CONFIG_FILES="$CONFIG_FILES simdmath_f.h" ;; + "omp_lib.f90") CONFIG_FILES="$CONFIG_FILES omp_lib.f90" ;; + "libgomp_f.h") CONFIG_FILES="$CONFIG_FILES libgomp_f.h" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; +diff --git a/libgomp/configure.ac b/libgomp/configure.ac +index ef5d293c31e..569c2065a66 100644 +--- a/libgomp/configure.ac ++++ b/libgomp/configure.ac +@@ -433,7 +433,7 @@ 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(omp.h omp_lib.h simdmath.h simdmath_f.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]) + AC_CONFIG_FILES([testsuite/libgomp-site-extra.exp]) +diff --git a/libgomp/simdmath.h.in b/libgomp/simdmath.h.in +new file mode 100644 +index 00000000000..ab91a4ec317 +--- /dev/null ++++ b/libgomp/simdmath.h.in +@@ -0,0 +1,40 @@ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#pragma omp declare simd simdlen(2) notinbranch ++double cos (double x); ++ ++#pragma omp declare simd simdlen(4) notinbranch ++float cosf (float x); ++ ++#pragma omp declare simd simdlen(2) notinbranch ++double sin (double x); ++ ++#pragma omp declare simd simdlen(4) notinbranch ++float sinf (float x); ++ ++#pragma omp declare simd simdlen(2) notinbranch ++double exp (double x); ++ ++#pragma omp declare simd simdlen(4) notinbranch ++float expf (float x); ++ ++#pragma omp declare simd simdlen(2) notinbranch ++double log (double x); ++ ++#pragma omp declare simd simdlen(4) notinbranch ++float logf (float x); ++ ++#pragma omp declare simd simdlen(2) notinbranch ++double pow (double x, double y); ++ ++#pragma omp declare simd simdlen(4) notinbranch ++float powf (float x, float y); ++ ++#pragma omp declare simd simdlen(4) notinbranch ++float exp2f (float x); ++ ++#ifdef __cplusplus ++} // extern "C" ++#endif +diff --git a/libgomp/simdmath_f.h.in b/libgomp/simdmath_f.h.in +new file mode 100644 +index 00000000000..550595015db +--- /dev/null ++++ b/libgomp/simdmath_f.h.in +@@ -0,0 +1,11 @@ ++!GCC$ builtin (cos) attributes simd (notinbranch) ++!GCC$ builtin (cosf) attributes simd (notinbranch) ++!GCC$ builtin (sin) attributes simd (notinbranch) ++!GCC$ builtin (sinf) attributes simd (notinbranch) ++!GCC$ builtin (exp) attributes simd (notinbranch) ++!GCC$ builtin (expf) attributes simd (notinbranch) ++!GCC$ builtin (exp2f) attributes simd (notinbranch) ++!GCC$ builtin (log) attributes simd (notinbranch) ++!GCC$ builtin (logf) attributes simd (notinbranch) ++!GCC$ builtin (pow) attributes simd (notinbranch) ++!GCC$ builtin (powf) attributes simd (notinbranch) +-- +2.21.0.windows.1 + diff --git a/0007-Vect-Enable-skipping-vectorization-on-reduction-chai.patch b/0007-Vect-Enable-skipping-vectorization-on-reduction-chai.patch new file mode 100644 index 0000000..ffe5327 --- /dev/null +++ b/0007-Vect-Enable-skipping-vectorization-on-reduction-chai.patch @@ -0,0 +1,68 @@ +From 07033bcc5b9e4c03846cd84b4587cd493fcf7d53 Mon Sep 17 00:00:00 2001 +From: zhoukaipeng <zhoukaipeng3@huawei.com> +Date: Wed, 14 Jul 2021 11:24:06 +0800 +Subject: [PATCH 07/13] [Vect] Enable skipping vectorization on reduction + chains + +Sometimes either vectorization on reduction chains or reductions is +possible. But the latter is better. The option "-ftree-vect-analyze +-slp-group" skips the former. + +diff --git a/gcc/common.opt b/gcc/common.opt +index 8eb05570418..55d4eb5a351 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -2968,6 +2968,10 @@ ftree-slp-vectorize + Common Report Var(flag_tree_slp_vectorize) Optimization EnabledBy(ftree-vectorize) + Enable basic block vectorization (SLP) on trees. + ++ftree-vect-analyze-slp-group ++Common Report Var(flag_tree_slp_group) Init(0) ++Disable SLP vectorization for reduction chain on tree. ++ + fvect-cost-model= + Common Joined RejectNegative Enum(vect_cost_model) Var(flag_vect_cost_model) Init(VECT_COST_MODEL_DEFAULT) Optimization + -fvect-cost-model=[unlimited|dynamic|cheap] Specifies the cost model for vectorization. +diff --git a/gcc/testsuite/gcc.dg/vect/vect-reduc-12.c b/gcc/testsuite/gcc.dg/vect/vect-reduc-12.c +new file mode 100644 +index 00000000000..913f1ef28df +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/vect/vect-reduc-12.c +@@ -0,0 +1,20 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-details -funsafe-math-optimizations -fno-tree-reassoc -ftree-vect-analyze-slp-group" } */ ++void f(double *a, double *res, double m) { ++ double res1, res0; ++ res1 = 0; ++ res0 = 0; ++ for (int i = 0; i < 1000; i+=8) { ++ res0 += a[i] * m; ++ res1 += a[i+1] * m; ++ res0 += a[i+2] * m; ++ res1 += a[i+3] * m; ++ res0 += a[i+4] * m; ++ res1 += a[i+5] * m; ++ res0 += a[i+6] * m; ++ res1 += a[i+7] * m; ++ } ++ res[0] += res0; ++ res[1] += res1; ++} ++/* { dg-final { scan-tree-dump "vectorized 1 loops" "vect" } } */ +diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c +index adc579ff544..476b3237054 100644 +--- a/gcc/tree-vect-slp.c ++++ b/gcc/tree-vect-slp.c +@@ -2480,7 +2480,8 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size) + { + /* Find SLP sequences starting from reduction chains. */ + FOR_EACH_VEC_ELT (loop_vinfo->reduction_chains, i, first_element) +- if (! vect_analyze_slp_instance (vinfo, bst_map, first_element, ++ if (flag_tree_slp_group ++ || ! vect_analyze_slp_instance (vinfo, bst_map, first_element, + max_tree_size)) + { + /* Dissolve reduction chain group. */ +-- +2.21.0.windows.1 + diff --git a/0008-Backport-tree-optimization-Add-checks-to-avoid-spoil.patch b/0008-Backport-tree-optimization-Add-checks-to-avoid-spoil.patch new file mode 100644 index 0000000..9b8c4f8 --- /dev/null +++ b/0008-Backport-tree-optimization-Add-checks-to-avoid-spoil.patch @@ -0,0 +1,97 @@ +From 79d1ed2d7f166a498662f6111a4defc55f0061c7 Mon Sep 17 00:00:00 2001 +From: yangyang <yangyang305@huawei.com> +Date: Thu, 15 Jul 2021 09:27:27 +0800 +Subject: [PATCH 08/13] [Backport]tree-optimization: Add checks to avoid + spoiling if-conversion + +Reference: https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=33d114f570b4a3583421c700396fd5945acebc28 + +Add some checks in pass_splits_paths, so that pass_split_paths can recognize +the missed if-conversion opportunity and do not duplicate the corresponding +block. + +diff --git a/gcc/gimple-ssa-split-paths.c b/gcc/gimple-ssa-split-paths.c +index b3efd43c7ef..9c32da76369 100644 +--- a/gcc/gimple-ssa-split-paths.c ++++ b/gcc/gimple-ssa-split-paths.c +@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3. If not see + #include "gimple-ssa.h" + #include "tree-phinodes.h" + #include "ssa-iterators.h" ++#include "fold-const.h" + + /* Given LATCH, the latch block in a loop, see if the shape of the + path reaching LATCH is suitable for being split by duplication. +@@ -254,6 +255,44 @@ is_feasible_trace (basic_block bb) + } + } + ++ /* Canonicalize the form. */ ++ if (single_pred_p (pred1) && single_pred (pred1) == pred2 ++ && num_stmts_in_pred1 == 0) ++ std::swap (pred1, pred2); ++ ++ /* This is meant to catch another kind of cases that are likely opportunities ++ for if-conversion. After canonicalizing, PRED2 must be an empty block and ++ PRED1 must be the only predecessor of PRED2. Moreover, PRED1 is supposed ++ to end with a cond_stmt which has the same args with the PHI in BB. */ ++ if (single_pred_p (pred2) && single_pred (pred2) == pred1 ++ && num_stmts_in_pred2 == 0) ++ { ++ gimple *cond_stmt = last_stmt (pred1); ++ if (cond_stmt && gimple_code (cond_stmt) == GIMPLE_COND) ++ { ++ tree lhs = gimple_cond_lhs (cond_stmt); ++ tree rhs = gimple_cond_rhs (cond_stmt); ++ ++ gimple_stmt_iterator gsi; ++ for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) ++ { ++ gimple *phi = gsi_stmt (gsi); ++ if ((operand_equal_p (gimple_phi_arg_def (phi, 0), lhs) ++ && operand_equal_p (gimple_phi_arg_def (phi, 1), rhs)) ++ || (operand_equal_p (gimple_phi_arg_def (phi, 0), rhs) ++ && (operand_equal_p (gimple_phi_arg_def (phi, 1), lhs)))) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, ++ "Block %d appears to be optimized to a join " ++ "point for if-convertable half-diamond.\n", ++ bb->index); ++ return false; ++ } ++ } ++ } ++ } ++ + /* If the joiner has no PHIs with useful uses there is zero chance + of CSE/DCE/jump-threading possibilities exposed by duplicating it. */ + bool found_useful_phi = false; +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/split-path-12.c b/gcc/testsuite/gcc.dg/tree-ssa/split-path-12.c +new file mode 100644 +index 00000000000..19a130d9bf1 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/split-path-12.c +@@ -0,0 +1,19 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -fsplit-paths -fdump-tree-split-paths-details " } */ ++ ++double ++foo(double *d1, double *d2, double *d3, int num, double *ip) ++{ ++ double dmax[3]; ++ ++ for (int i = 0; i < num; i++) { ++ dmax[0] = d1[i] < dmax[0] ? dmax[0] : d1[i]; ++ dmax[1] = d2[i] < dmax[1] ? dmax[1] : d2[i]; ++ dmax[2] = d3[i] < dmax[2] ? dmax[2] : d3[i]; ++ ip[i] = dmax[2]; ++ } ++ ++ return dmax[0] + dmax[1] + dmax[2]; ++} ++ ++/* { dg-final { scan-tree-dump "appears to be optimized to a join point for if-convertable half-diamond" "split-paths" } } */ +-- +2.21.0.windows.1 + diff --git a/0009-Backport-expand-Simplify-removing-subregs-when-expan.patch b/0009-Backport-expand-Simplify-removing-subregs-when-expan.patch new file mode 100644 index 0000000..434c669 --- /dev/null +++ b/0009-Backport-expand-Simplify-removing-subregs-when-expan.patch @@ -0,0 +1,141 @@ +From 7bc78d0ab13c37e2b11adb385d9916181ec4cc20 Mon Sep 17 00:00:00 2001 +From: zhanghaijian <z.zhanghaijian@huawei.com> +Date: Thu, 15 Jul 2021 09:04:55 +0800 +Subject: [PATCH 09/13] [Backport]expand: Simplify removing subregs when + expanding a copy [PR95254] + +Reference: https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=9a182ef9ee011935d827ab5c6c9a7cd8e22257d8 + +In rtl expand, if we have a copy that matches one of the following patterns: + (set (subreg:M1 (reg:M2 ...)) (subreg:M1 (reg:M2 ...))) + (set (subreg:M1 (reg:M2 ...)) (mem:M1 ADDR)) + (set (mem:M1 ADDR) (subreg:M1 (reg:M2 ...))) + (set (subreg:M1 (reg:M2 ...)) (constant C)) +where mode M1 is equal in size to M2, try to detect whether the mode change +involves an implicit round trip through memory. If so, see if we can avoid +that by removing the subregs and doing the move in mode M2 instead. + +diff --git a/gcc/expr.c b/gcc/expr.c +index 991b26f3341..d66fdd4e93d 100644 +--- a/gcc/expr.c ++++ b/gcc/expr.c +@@ -3814,6 +3814,78 @@ emit_move_insn (rtx x, rtx y) + gcc_assert (mode != BLKmode + && (GET_MODE (y) == mode || GET_MODE (y) == VOIDmode)); + ++ /* If we have a copy that looks like one of the following patterns: ++ (set (subreg:M1 (reg:M2 ...)) (subreg:M1 (reg:M2 ...))) ++ (set (subreg:M1 (reg:M2 ...)) (mem:M1 ADDR)) ++ (set (mem:M1 ADDR) (subreg:M1 (reg:M2 ...))) ++ (set (subreg:M1 (reg:M2 ...)) (constant C)) ++ where mode M1 is equal in size to M2, try to detect whether the ++ mode change involves an implicit round trip through memory. ++ If so, see if we can avoid that by removing the subregs and ++ doing the move in mode M2 instead. */ ++ ++ rtx x_inner = NULL_RTX; ++ rtx y_inner = NULL_RTX; ++ ++#define CANDIDATE_SUBREG_P(subreg) \ ++ (REG_P (SUBREG_REG (subreg)) \ ++ && known_eq (GET_MODE_SIZE (GET_MODE (SUBREG_REG (subreg))), \ ++ GET_MODE_SIZE (GET_MODE (subreg))) \ ++ && optab_handler (mov_optab, GET_MODE (SUBREG_REG (subreg))) \ ++ != CODE_FOR_nothing) ++ ++#define CANDIDATE_MEM_P(innermode, mem) \ ++ (!targetm.can_change_mode_class ((innermode), GET_MODE (mem), ALL_REGS) \ ++ && !push_operand ((mem), GET_MODE (mem)) \ ++ /* Not a candiate if innermode requires too much alignment. */ \ ++ && (MEM_ALIGN (mem) >= GET_MODE_ALIGNMENT (innermode) \ ++ || targetm.slow_unaligned_access (GET_MODE (mem), \ ++ MEM_ALIGN (mem)) \ ++ || !targetm.slow_unaligned_access ((innermode), \ ++ MEM_ALIGN (mem)))) ++ ++ if (SUBREG_P (x) && CANDIDATE_SUBREG_P (x)) ++ x_inner = SUBREG_REG (x); ++ ++ if (SUBREG_P (y) && CANDIDATE_SUBREG_P (y)) ++ y_inner = SUBREG_REG (y); ++ ++ if (x_inner != NULL_RTX ++ && y_inner != NULL_RTX ++ && GET_MODE (x_inner) == GET_MODE (y_inner) ++ && !targetm.can_change_mode_class (GET_MODE (x_inner), mode, ALL_REGS)) ++ { ++ x = x_inner; ++ y = y_inner; ++ mode = GET_MODE (x_inner); ++ } ++ else if (x_inner != NULL_RTX ++ && MEM_P (y) ++ && CANDIDATE_MEM_P (GET_MODE (x_inner), y)) ++ { ++ x = x_inner; ++ y = adjust_address (y, GET_MODE (x_inner), 0); ++ mode = GET_MODE (x_inner); ++ } ++ else if (y_inner != NULL_RTX ++ && MEM_P (x) ++ && CANDIDATE_MEM_P (GET_MODE (y_inner), x)) ++ { ++ x = adjust_address (x, GET_MODE (y_inner), 0); ++ y = y_inner; ++ mode = GET_MODE (y_inner); ++ } ++ else if (x_inner != NULL_RTX ++ && CONSTANT_P (y) ++ && !targetm.can_change_mode_class (GET_MODE (x_inner), ++ mode, ALL_REGS) ++ && (y_inner = simplify_subreg (GET_MODE (x_inner), y, mode, 0))) ++ { ++ x = x_inner; ++ y = y_inner; ++ mode = GET_MODE (x_inner); ++ } ++ + if (CONSTANT_P (y)) + { + if (optimize +diff --git a/gcc/testsuite/gcc.target/aarch64/pr95254.c b/gcc/testsuite/gcc.target/aarch64/pr95254.c +new file mode 100644 +index 00000000000..10bfc868197 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/pr95254.c +@@ -0,0 +1,19 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -ftree-slp-vectorize -march=armv8.2-a+sve -msve-vector-bits=256" } */ ++ ++typedef short __attribute__((vector_size (8))) v4hi; ++ ++typedef union U4HI { v4hi v; short a[4]; } u4hi; ++ ++short b[4]; ++ ++void pass_v4hi (v4hi v) ++{ ++ int i; ++ u4hi u; ++ u.v = v; ++ for (i = 0; i < 4; i++) ++ b[i] = u.a[i]; ++}; ++ ++/* { dg-final { scan-assembler-not "ptrue" } } */ +diff --git a/gcc/testsuite/gcc.target/i386/pr67609.c b/gcc/testsuite/gcc.target/i386/pr67609.c +index 518071bdd86..398cdba5d5f 100644 +--- a/gcc/testsuite/gcc.target/i386/pr67609.c ++++ b/gcc/testsuite/gcc.target/i386/pr67609.c +@@ -1,7 +1,7 @@ + /* { dg-do compile } */ + /* { dg-options "-O2 -msse2" } */ + /* { dg-require-effective-target lp64 } */ +-/* { dg-final { scan-assembler "movdqa" } } */ ++/* { dg-final { scan-assembler "movq\t%xmm0" } } */ + + #include <emmintrin.h> + __m128d reg; +-- +2.21.0.windows.1 + diff --git a/0010-Backport-tree-optimization-94963-avoid-bogus-uninit-.patch b/0010-Backport-tree-optimization-94963-avoid-bogus-uninit-.patch new file mode 100644 index 0000000..e5dbbf2 --- /dev/null +++ b/0010-Backport-tree-optimization-94963-avoid-bogus-uninit-.patch @@ -0,0 +1,98 @@ +From b8b3e29e4cceae2bab6e0774b1af994dbe713d97 Mon Sep 17 00:00:00 2001 +From: zhanghaijian <z.zhanghaijian@huawei.com> +Date: Thu, 15 Jul 2021 09:13:11 +0800 +Subject: [PATCH 10/13] [Backport]tree-optimization/94963 - avoid bogus uninit + warning with store-motion + +Reference: https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=371905d12259c180efb9b1f1b5716e969feb60f9 + +Eliding the load for store-motion causes an uninitialized variable +flowing into the loop, conditionally initialized and used. The +uninit warning cannot relate the flag used to guard the initialization +and use with the actual initialization so the following robustifies +the previous approach of marking the conditional store as not to +be warned on by instead initializing the variable on loop entry +from an uninitialized variable we mark as not to be warned for. + +diff --git a/gcc/testsuite/gcc.dg/pr94963.c b/gcc/testsuite/gcc.dg/pr94963.c +new file mode 100644 +index 00000000000..09c0524fb3a +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/pr94963.c +@@ -0,0 +1,35 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -Wall" } */ ++ ++typedef struct ++{ ++ int p1; ++ int p2; ++ int p3; ++} P; ++struct S ++{ ++ int field; ++}; ++extern int v2; ++extern void foo (struct S *map); ++static struct S var; ++const P *pv; ++int ps; ++void ++f (void) ++{ ++ if (pv != 0) ++ for (const P *ph = pv; ph < &pv[ps]; ++ph) ++ switch (ph->p1) ++ { ++ case 1: ++ v2 = ph->p2; ++ break; ++ case 2: ++ var.field = ph->p3; ++ break; ++ } ++ if (var.field != 0) /* { dg-bogus "uninitialized" } */ ++ foo (&var); ++} +diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c +index 8c33735b1fa..d74a46ef352 100644 +--- a/gcc/tree-ssa-loop-im.c ++++ b/gcc/tree-ssa-loop-im.c +@@ -1994,8 +1994,6 @@ execute_sm_if_changed (edge ex, tree mem, tree tmp_var, tree flag, + gsi = gsi_start_bb (then_bb); + /* Insert actual store. */ + stmt = gimple_build_assign (unshare_expr (mem), tmp_var); +- /* Make sure to not warn about maybe-uninit uses of tmp_var here. */ +- gimple_set_no_warning (stmt, true); + gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); + + edge e1 = single_succ_edge (new_bb); +@@ -2149,13 +2147,19 @@ execute_sm (class loop *loop, vec<edge> exits, im_mem_ref *ref) + store then. */ + if ((!always_stored && !multi_threaded_model_p) + || (ref->loaded && bitmap_bit_p (ref->loaded, loop->num))) ++ load = gimple_build_assign (tmp_var, unshare_expr (ref->mem.ref)); ++ else + { +- load = gimple_build_assign (tmp_var, unshare_expr (ref->mem.ref)); +- lim_data = init_lim_data (load); +- lim_data->max_loop = loop; +- lim_data->tgt_loop = loop; +- gsi_insert_before (&gsi, load, GSI_SAME_STMT); ++ /* If not emitting a load mark the uninitialized state on the ++ loop entry as not to be warned for. */ ++ tree uninit = create_tmp_reg (TREE_TYPE (tmp_var)); ++ TREE_NO_WARNING (uninit) = 1; ++ load = gimple_build_assign (tmp_var, uninit); + } ++ lim_data = init_lim_data (load); ++ lim_data->max_loop = loop; ++ lim_data->tgt_loop = loop; ++ gsi_insert_before (&gsi, load, GSI_SAME_STMT); + + if (multi_threaded_model_p) + { +-- +2.21.0.windows.1 + diff --git a/0011-simdmath-Enable-64-bits-simd-when-test-simd_pcs_attr.patch b/0011-simdmath-Enable-64-bits-simd-when-test-simd_pcs_attr.patch new file mode 100644 index 0000000..b9f642c --- /dev/null +++ b/0011-simdmath-Enable-64-bits-simd-when-test-simd_pcs_attr.patch @@ -0,0 +1,23 @@ +From 78cf3b95d7b895cfe8d6f1c2a48ebc08a662eef0 Mon Sep 17 00:00:00 2001 +From: bule <bule1@huawei.com> +Date: Sat, 17 Jul 2021 16:38:10 +0800 +Subject: [PATCH 11/13] [simdmath] Enable 64-bits simd when test + simd_pcs_attribute-3 + +Enable 64-bits simd when test simd_pcs_attribute-3. The 64-bits simd +is default to off without specify the -msimdmath-64. + +diff --git a/gcc/testsuite/gcc.target/aarch64/simd_pcs_attribute-3.c b/gcc/testsuite/gcc.target/aarch64/simd_pcs_attribute-3.c +index 95f6a6803e8..e0e0efa9d7e 100644 +--- a/gcc/testsuite/gcc.target/aarch64/simd_pcs_attribute-3.c ++++ b/gcc/testsuite/gcc.target/aarch64/simd_pcs_attribute-3.c +@@ -1,5 +1,5 @@ + /* { dg-do compile } */ +-/* { dg-options "-Ofast" } */ ++/* { dg-options "-Ofast -msimdmath-64" } */ + + __attribute__ ((__simd__)) + __attribute__ ((__nothrow__ , __leaf__ , __const__)) +-- +2.21.0.windows.1 + diff --git a/0012-fp-model-Enable-fp-model-on-kunpeng.patch b/0012-fp-model-Enable-fp-model-on-kunpeng.patch new file mode 100644 index 0000000..3e99f88 --- /dev/null +++ b/0012-fp-model-Enable-fp-model-on-kunpeng.patch @@ -0,0 +1,397 @@ +From 26ea42402eede6a441c9d74ec6b6086e5bf0bf79 Mon Sep 17 00:00:00 2001 +From: bule <bule1@huawei.com> +Date: Mon, 19 Jul 2021 12:04:08 +0800 +Subject: [PATCH 12/13] [fp-model] Enable fp-model on kunpeng + +Enable fp-model options on kunpeng for precision control. + +diff --git a/gcc/common.opt b/gcc/common.opt +index 55d4eb5a351..79c9ef6615b 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -1545,6 +1545,32 @@ ffp-int-builtin-inexact + Common Report Var(flag_fp_int_builtin_inexact) Init(1) Optimization + Allow built-in functions ceil, floor, round, trunc to raise \"inexact\" exceptions. + ++fftz ++Common Report Var(flag_ftz) Optimization ++Control fpcr register for flush to zero. ++ ++fp-model= ++Common Joined RejectNegative Enum(fp_model) Var(flag_fp_model) Init(FP_MODEL_NORMAL) Optimization ++-fp-model=[normal|fast|precise|except|strict] Perform floating-point precision control. ++ ++Enum ++Name(fp_model) Type(enum fp_model) UnknownError(unknown floating point precision model %qs) ++ ++EnumValue ++Enum(fp_model) String(normal) Value(FP_MODEL_NORMAL) ++ ++EnumValue ++Enum(fp_model) String(fast) Value(FP_MODEL_FAST) ++ ++EnumValue ++Enum(fp_model) String(precise) Value(FP_MODEL_PRECISE) ++ ++EnumValue ++Enum(fp_model) String(except) Value(FP_MODEL_EXCEPT) ++ ++EnumValue ++Enum(fp_model) String(strict) Value(FP_MODEL_STRICT) ++ + ; Nonzero means don't put addresses of constant functions in registers. + ; Used for compiling the Unix kernel, where strange substitutions are + ; done on the assembly output. +diff --git a/gcc/config/aarch64/aarch64-linux.h b/gcc/config/aarch64/aarch64-linux.h +index e587e2e9ad6..331b12c8702 100644 +--- a/gcc/config/aarch64/aarch64-linux.h ++++ b/gcc/config/aarch64/aarch64-linux.h +@@ -50,7 +50,8 @@ + #define LINK_SPEC LINUX_TARGET_LINK_SPEC AARCH64_ERRATA_LINK_SPEC + + #define GNU_USER_TARGET_MATHFILE_SPEC \ +- "%{Ofast|ffast-math|funsafe-math-optimizations:crtfastmath.o%s}" ++ "%{Ofast|ffast-math|funsafe-math-optimizations|fp-model=fast|fftz:\ ++ %{!fno-ftz:crtfastmath.o%s}}" + + #undef ENDFILE_SPEC + #define ENDFILE_SPEC \ +diff --git a/gcc/flag-types.h b/gcc/flag-types.h +index 852ea76eaa2..5832298251e 100644 +--- a/gcc/flag-types.h ++++ b/gcc/flag-types.h +@@ -223,6 +223,15 @@ enum fp_contract_mode { + FP_CONTRACT_FAST = 2 + }; + ++/* Floating-point precision mode. */ ++enum fp_model { ++ FP_MODEL_NORMAL = 0, ++ FP_MODEL_FAST = 1, ++ FP_MODEL_PRECISE = 2, ++ FP_MODEL_EXCEPT = 3, ++ FP_MODEL_STRICT = 4 ++}; ++ + /* Scalar storage order kind. */ + enum scalar_storage_order_kind { + SSO_NATIVE = 0, +diff --git a/gcc/fortran/options.c b/gcc/fortran/options.c +index 4cc8a908417..c59dcf63781 100644 +--- a/gcc/fortran/options.c ++++ b/gcc/fortran/options.c +@@ -250,6 +250,7 @@ form_from_filename (const char *filename) + return f_form; + } + ++static void gfc_handle_fpe_option (const char *arg, bool trap); + + /* Finalize commandline options. */ + +@@ -277,6 +278,13 @@ gfc_post_options (const char **pfilename) + if (flag_protect_parens == -1) + flag_protect_parens = !optimize_fast; + ++ /* If fp-model=precise/strict, turn on all ffpe-trap and ffpe-summary. */ ++ if (flag_fp_model == FP_MODEL_EXCEPT || flag_fp_model == FP_MODEL_STRICT) ++ { ++ gfc_handle_fpe_option ("all", false); ++ gfc_handle_fpe_option ("invalid,zero,overflow,underflow", true); ++ } ++ + /* -Ofast sets implies -fstack-arrays unless an explicit size is set for + stack arrays. */ + if (flag_stack_arrays == -1 && flag_max_stack_var_size == -2) +diff --git a/gcc/opts-common.c b/gcc/opts-common.c +index de9510abd64..bf82b05c8a2 100644 +--- a/gcc/opts-common.c ++++ b/gcc/opts-common.c +@@ -26,7 +26,8 @@ along with GCC; see the file COPYING3. If not see + #include "diagnostic.h" + #include "spellcheck.h" + +-static void prune_options (struct cl_decoded_option **, unsigned int *); ++static void prune_options (struct cl_decoded_option **, unsigned int *, ++ unsigned int); + + /* An option that is undocumented, that takes a joined argument, and + that doesn't fit any of the classes of uses (language/common, +@@ -988,7 +989,7 @@ decode_cmdline_options_to_array (unsigned int argc, const char **argv, + + *decoded_options = opt_array; + *decoded_options_count = num_decoded_options; +- prune_options (decoded_options, decoded_options_count); ++ prune_options (decoded_options, decoded_options_count, lang_mask); + } + + /* Return true if NEXT_OPT_IDX cancels OPT_IDX. Return false if the +@@ -1009,11 +1010,109 @@ cancel_option (int opt_idx, int next_opt_idx, int orig_next_opt_idx) + return false; + } + ++/* Check whether opt_idx exists in decoded_options array bewteen index ++ start and end. If found, return its index in decoded_options, ++ else return end. */ ++static unsigned int ++find_opt_idx (const struct cl_decoded_option *decoded_options, ++ unsigned int decoded_options_count, ++ unsigned int start, unsigned int end, unsigned int opt_idx) ++{ ++ gcc_assert (end <= decoded_options_count); ++ gcc_assert (opt_idx < cl_options_count); ++ unsigned int k; ++ for (k = start; k < end; k++) ++ { ++ if (decoded_options[k].opt_index == opt_idx) ++ { ++ return k; ++ } ++ } ++ return k; ++} ++ ++/* remove the opt_index element from decoded_options array. */ ++static unsigned int ++remove_option (struct cl_decoded_option *decoded_options, ++ unsigned int decoded_options_count, ++ unsigned int opt_index) ++{ ++ gcc_assert (opt_index < decoded_options_count); ++ unsigned int i; ++ for (i = opt_index; i < decoded_options_count - 1; i++) ++ { ++ decoded_options[i] = decoded_options[i + 1]; ++ } ++ return decoded_options_count - 1; ++} ++ ++/* Handle the priority between fp-model, Ofast, and ++ ffast-math. */ ++static unsigned int ++handle_fp_model_driver (struct cl_decoded_option *decoded_options, ++ unsigned int decoded_options_count, ++ unsigned int fp_model_index, ++ unsigned int lang_mask) ++{ ++ struct cl_decoded_option fp_model_opt = decoded_options[fp_model_index]; ++ enum fp_model model = (enum fp_model) fp_model_opt.value; ++ if (model == FP_MODEL_PRECISE || model == FP_MODEL_STRICT) ++ { ++ /* If found Ofast, override Ofast with O3. */ ++ unsigned int Ofast_index; ++ Ofast_index = find_opt_idx (decoded_options, decoded_options_count, ++ 0, decoded_options_count, OPT_Ofast); ++ while (Ofast_index != decoded_options_count) ++ { ++ const char *tmp_argv = "-O3"; ++ decode_cmdline_option (&tmp_argv, lang_mask, ++ &decoded_options[Ofast_index]); ++ warning (0, "%<-Ofast%> is degraded to %<-O3%> due to %qs", ++ fp_model_opt.orig_option_with_args_text); ++ Ofast_index = find_opt_idx (decoded_options, decoded_options_count, ++ 0, decoded_options_count, OPT_Ofast); ++ } ++ /* If found ffast-math before fp-model=precise/strict ++ it, cancel it. */ ++ unsigned int ffast_math_index; ++ ffast_math_index ++ = find_opt_idx (decoded_options, decoded_options_count, 0, ++ fp_model_index, OPT_ffast_math); ++ if (ffast_math_index != fp_model_index) ++ { ++ decoded_options_count ++ = remove_option (decoded_options, decoded_options_count, ++ ffast_math_index); ++ warning (0, "%<-ffast-math%> before %qs is canceled", ++ fp_model_opt.orig_option_with_args_text); ++ } ++ } ++ if (model == FP_MODEL_FAST) ++ { ++ /* If found -fno-fast-math after fp-model=fast, cancel this one. */ ++ unsigned int fno_fast_math_index; ++ fno_fast_math_index ++ = find_opt_idx (decoded_options, decoded_options_count, fp_model_index, ++ decoded_options_count, OPT_ffast_math); ++ if (fno_fast_math_index != decoded_options_count ++ && decoded_options[fno_fast_math_index].value == 0) ++ { ++ decoded_options_count ++ = remove_option (decoded_options, decoded_options_count, ++ fp_model_index); ++ warning (0, ++ "%<-fp-model=fast%> before %<-fno-fast-math%> is canceled"); ++ } ++ } ++ return decoded_options_count; ++} ++ + /* Filter out options canceled by the ones after them. */ + + static void + prune_options (struct cl_decoded_option **decoded_options, +- unsigned int *decoded_options_count) ++ unsigned int *decoded_options_count, ++ unsigned int lang_mask) + { + unsigned int old_decoded_options_count = *decoded_options_count; + struct cl_decoded_option *old_decoded_options = *decoded_options; +@@ -1024,7 +1123,12 @@ prune_options (struct cl_decoded_option **decoded_options, + const struct cl_option *option; + unsigned int fdiagnostics_color_idx = 0; + ++ if (!diagnostic_ready_p ()) ++ diagnostic_initialize (global_dc, 0); ++ + /* Remove arguments which are negated by others after them. */ ++ ++ unsigned int fp_model_index = old_decoded_options_count; + new_decoded_options_count = 0; + for (i = 0; i < old_decoded_options_count; i++) + { +@@ -1048,6 +1152,34 @@ prune_options (struct cl_decoded_option **decoded_options, + fdiagnostics_color_idx = i; + continue; + ++ case OPT_fp_model_: ++ /* Only the last fp-model option will take effect. */ ++ unsigned int next_fp_model_idx; ++ next_fp_model_idx = find_opt_idx (old_decoded_options, ++ old_decoded_options_count, ++ i + 1, ++ old_decoded_options_count, ++ OPT_fp_model_); ++ if (next_fp_model_idx != old_decoded_options_count) ++ { ++ /* Found more than one fp-model, cancel this one. */ ++ if (old_decoded_options[i].value ++ != old_decoded_options[next_fp_model_idx].value) ++ { ++ warning (0, "%qs is overrided by %qs", ++ old_decoded_options[i]. ++ orig_option_with_args_text, ++ old_decoded_options[next_fp_model_idx]. ++ orig_option_with_args_text); ++ } ++ break; ++ } ++ else ++ { ++ /* Found the last fp-model option. */ ++ fp_model_index = new_decoded_options_count; ++ } ++ /* FALLTHRU. */ + default: + gcc_assert (opt_idx < cl_options_count); + option = &cl_options[opt_idx]; +@@ -1087,6 +1219,14 @@ keep: + break; + } + } ++ if (fp_model_index < new_decoded_options_count) ++ { ++ new_decoded_options_count ++ = handle_fp_model_driver (new_decoded_options, ++ new_decoded_options_count, ++ fp_model_index, ++ lang_mask); ++ } + + if (fdiagnostics_color_idx >= 1) + { +diff --git a/gcc/opts.c b/gcc/opts.c +index e31aa560564..6924a973a5b 100644 +--- a/gcc/opts.c ++++ b/gcc/opts.c +@@ -195,6 +195,7 @@ static void set_debug_level (enum debug_info_type type, int extended, + struct gcc_options *opts_set, + location_t loc); + static void set_fast_math_flags (struct gcc_options *opts, int set); ++static void set_fp_model_flags (struct gcc_options *opts, int set); + static void decode_d_option (const char *arg, struct gcc_options *opts, + location_t loc, diagnostic_context *dc); + static void set_unsafe_math_optimizations_flags (struct gcc_options *opts, +@@ -2482,6 +2483,10 @@ common_handle_option (struct gcc_options *opts, + set_fast_math_flags (opts, value); + break; + ++ case OPT_fp_model_: ++ set_fp_model_flags (opts, value); ++ break; ++ + case OPT_funsafe_math_optimizations: + set_unsafe_math_optimizations_flags (opts, value); + break; +@@ -2908,6 +2913,69 @@ set_fast_math_flags (struct gcc_options *opts, int set) + } + } + ++/* Handle fp-model options. */ ++static void ++set_fp_model_flags (struct gcc_options *opts, int set) ++{ ++ enum fp_model model = (enum fp_model) set; ++ switch (model) ++ { ++ case FP_MODEL_FAST: ++ /* Equivalent to open ffast-math. */ ++ set_fast_math_flags (opts, 1); ++ break; ++ ++ case FP_MODEL_PRECISE: ++ /* Equivalent to close ffast-math. */ ++ set_fast_math_flags (opts, 0); ++ /* Turn on -frounding-math -fsignaling-nans. */ ++ if (!opts->frontend_set_flag_signaling_nans) ++ opts->x_flag_signaling_nans = 1; ++ if (!opts->frontend_set_flag_rounding_math) ++ opts->x_flag_rounding_math = 1; ++ opts->x_flag_expensive_optimizations = 0; ++ opts->x_flag_code_hoisting = 0; ++ opts->x_flag_predictive_commoning = 0; ++ opts->x_flag_fp_contract_mode = FP_CONTRACT_OFF; ++ break; ++ ++ case FP_MODEL_EXCEPT: ++ if (!opts->frontend_set_flag_signaling_nans) ++ opts->x_flag_signaling_nans = 1; ++ if (!opts->frontend_set_flag_errno_math) ++ opts->x_flag_errno_math = 1; ++ if (!opts->frontend_set_flag_trapping_math) ++ opts->x_flag_trapping_math = 1; ++ opts->x_flag_fp_int_builtin_inexact = 1; ++ /* Also turn on ffpe-trap in fortran. */ ++ break; ++ ++ case FP_MODEL_STRICT: ++ /* Turn on both precise and except. */ ++ if (!opts->frontend_set_flag_signaling_nans) ++ opts->x_flag_signaling_nans = 1; ++ if (!opts->frontend_set_flag_rounding_math) ++ opts->x_flag_rounding_math = 1; ++ opts->x_flag_expensive_optimizations = 0; ++ opts->x_flag_code_hoisting = 0; ++ opts->x_flag_predictive_commoning = 0; ++ if (!opts->frontend_set_flag_errno_math) ++ opts->x_flag_errno_math = 1; ++ if (!opts->frontend_set_flag_trapping_math) ++ opts->x_flag_trapping_math = 1; ++ opts->x_flag_fp_int_builtin_inexact = 1; ++ opts->x_flag_fp_contract_mode = FP_CONTRACT_OFF; ++ break; ++ ++ case FP_MODEL_NORMAL: ++ /* Do nothing. */ ++ break; ++ ++ default: ++ gcc_unreachable (); ++ } ++} ++ + /* When -funsafe-math-optimizations is set the following + flags are set as well. */ + static void +-- +2.21.0.windows.1 + diff --git a/0013-LoopElim-Redundant-loop-elimination-optimization.patch b/0013-LoopElim-Redundant-loop-elimination-optimization.patch new file mode 100644 index 0000000..d50107e --- /dev/null +++ b/0013-LoopElim-Redundant-loop-elimination-optimization.patch @@ -0,0 +1,499 @@ +From 0d14a2b7a3defc82ed16c99a18c2bc2e6be9f5b1 Mon Sep 17 00:00:00 2001 +From: xiezhiheng <xiezhiheng@huawei.com> +Date: Fri, 16 Jul 2021 23:21:38 -0400 +Subject: [PATCH 13/13] [LoopElim] Redundant loop elimination optimization + +Introduce redundant loop elimination optimization controlled +by -floop-elim. And it's often used with -ffinite-loops. + +diff --git a/gcc/common.opt b/gcc/common.opt +index 79c9ef6615b..b2b0aac7fdf 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -1169,6 +1169,10 @@ fcompare-elim + Common Report Var(flag_compare_elim_after_reload) Optimization + Perform comparison elimination after register allocation has finished. + ++floop-elim ++Common Report Var(flag_loop_elim) Init(0) Optimization ++Perform redundant loop elimination. ++ + fconserve-stack + Common Var(flag_conserve_stack) Optimization + Do not perform optimizations increasing noticeably stack usage. +diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c +index 3b5b6907679..591b6435f78 100644 +--- a/gcc/tree-ssa-phiopt.c ++++ b/gcc/tree-ssa-phiopt.c +@@ -69,6 +69,7 @@ static hash_set<tree> * get_non_trapping (); + static void replace_phi_edge_with_variable (basic_block, edge, gimple *, tree); + static void hoist_adjacent_loads (basic_block, basic_block, + basic_block, basic_block); ++static bool do_phiopt_pattern (basic_block, basic_block, basic_block); + static bool gate_hoist_loads (void); + + /* This pass tries to transform conditional stores into unconditional +@@ -257,6 +258,10 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) + hoist_adjacent_loads (bb, bb1, bb2, bb3); + continue; + } ++ else if (flag_loop_elim && do_phiopt_pattern (bb, bb1, bb2)) ++ { ++ continue; ++ } + else + continue; + +@@ -2819,6 +2824,449 @@ hoist_adjacent_loads (basic_block bb0, basic_block bb1, + } + } + ++static bool check_uses (tree, hash_set<tree> *); ++ ++/* Check SSA_NAME is used in ++ if (SSA_NAME == 0) ++ ... ++ or ++ if (SSA_NAME != 0) ++ ... ++*/ ++static bool ++check_uses_cond (const_tree ssa_name, gimple *stmt, ++ hash_set<tree> *hset ATTRIBUTE_UNUSED) ++{ ++ tree_code code = gimple_cond_code (stmt); ++ if (code != EQ_EXPR && code != NE_EXPR) ++ { ++ return false; ++ } ++ ++ tree lhs = gimple_cond_lhs (stmt); ++ tree rhs = gimple_cond_rhs (stmt); ++ if ((lhs == ssa_name && integer_zerop (rhs)) ++ || (rhs == ssa_name && integer_zerop (lhs))) ++ { ++ return true; ++ } ++ ++ return false; ++} ++ ++/* Check SSA_NAME is used in ++ _tmp = SSA_NAME == 0; ++ or ++ _tmp = SSA_NAME != 0; ++ or ++ _tmp = SSA_NAME | _tmp2; ++*/ ++static bool ++check_uses_assign (const_tree ssa_name, gimple *stmt, hash_set<tree> *hset) ++{ ++ tree_code code = gimple_assign_rhs_code (stmt); ++ tree lhs, rhs1, rhs2; ++ ++ switch (code) ++ { ++ case EQ_EXPR: ++ case NE_EXPR: ++ rhs1 = gimple_assign_rhs1 (stmt); ++ rhs2 = gimple_assign_rhs2 (stmt); ++ if ((rhs1 == ssa_name && integer_zerop (rhs2)) ++ || (rhs2 == ssa_name && integer_zerop (rhs1))) ++ { ++ return true; ++ } ++ break; ++ ++ case BIT_IOR_EXPR: ++ lhs = gimple_assign_lhs (stmt); ++ if (hset->contains (lhs)) ++ { ++ return false; ++ } ++ /* We should check the use of _tmp further. */ ++ return check_uses (lhs, hset); ++ ++ default: ++ break; ++ } ++ return false; ++} ++ ++/* Check SSA_NAME is used in ++ # result = PHI <SSA_NAME (bb1), 0 (bb2), 0 (bb3)> ++*/ ++static bool ++check_uses_phi (const_tree ssa_name, gimple *stmt, hash_set<tree> *hset) ++{ ++ for (unsigned i = 0; i < gimple_phi_num_args (stmt); i++) ++ { ++ tree arg = gimple_phi_arg_def (stmt, i); ++ if (!integer_zerop (arg) && arg != ssa_name) ++ { ++ return false; ++ } ++ } ++ ++ tree result = gimple_phi_result (stmt); ++ ++ /* It is used to avoid infinite recursion, ++ <bb 1> ++ if (cond) ++ goto <bb 2> ++ else ++ goto <bb 3> ++ ++ <bb 2> ++ # _tmp2 = PHI <0 (bb 1), _tmp3 (bb 3)> ++ {BODY} ++ if (cond) ++ goto <bb 3> ++ else ++ goto <bb 4> ++ ++ <bb 3> ++ # _tmp3 = PHI <0 (bb 1), _tmp2 (bb 2)> ++ {BODY} ++ if (cond) ++ goto <bb 2> ++ else ++ goto <bb 4> ++ ++ <bb 4> ++ ... ++ */ ++ if (hset->contains (result)) ++ { ++ return false; ++ } ++ ++ return check_uses (result, hset); ++} ++ ++/* Check the use of SSA_NAME, it should only be used in comparison ++ operation and PHI node. HSET is used to record the ssa_names ++ that have been already checked. */ ++static bool ++check_uses (tree ssa_name, hash_set<tree> *hset) ++{ ++ imm_use_iterator imm_iter; ++ use_operand_p use_p; ++ ++ if (TREE_CODE (ssa_name) != SSA_NAME) ++ { ++ return false; ++ } ++ ++ if (SSA_NAME_VAR (ssa_name) ++ && is_global_var (SSA_NAME_VAR (ssa_name))) ++ { ++ return false; ++ } ++ ++ hset->add (ssa_name); ++ ++ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, ssa_name) ++ { ++ gimple *stmt = USE_STMT (use_p); ++ ++ /* Ignore debug gimple statements. */ ++ if (is_gimple_debug (stmt)) ++ { ++ continue; ++ } ++ ++ switch (gimple_code (stmt)) ++ { ++ case GIMPLE_COND: ++ if (!check_uses_cond (ssa_name, stmt, hset)) ++ { ++ return false; ++ } ++ break; ++ ++ case GIMPLE_ASSIGN: ++ if (!check_uses_assign (ssa_name, stmt, hset)) ++ { ++ return false; ++ } ++ break; ++ ++ case GIMPLE_PHI: ++ if (!check_uses_phi (ssa_name, stmt, hset)) ++ { ++ return false; ++ } ++ break; ++ ++ default: ++ return false; ++ } ++ } ++ return true; ++} ++ ++static bool ++check_def_gimple (gimple *def1, gimple *def2, const_tree result) ++{ ++ /* def1 and def2 should be POINTER_PLUS_EXPR. */ ++ if (!is_gimple_assign (def1) || !is_gimple_assign (def2) ++ || gimple_assign_rhs_code (def1) != POINTER_PLUS_EXPR ++ || gimple_assign_rhs_code (def2) != POINTER_PLUS_EXPR) ++ { ++ return false; ++ } ++ ++ tree rhs12 = gimple_assign_rhs2 (def1); ++ ++ tree rhs21 = gimple_assign_rhs1 (def2); ++ tree rhs22 = gimple_assign_rhs2 (def2); ++ ++ if (rhs21 != result) ++ { ++ return false; ++ } ++ ++ /* We should have a positive pointer-plus constant to ensure ++ that the pointer value is continuously increasing. */ ++ if (TREE_CODE (rhs12) != INTEGER_CST || TREE_CODE (rhs22) != INTEGER_CST ++ || compare_tree_int (rhs12, 0) <= 0 || compare_tree_int (rhs22, 0) <= 0) ++ { ++ return false; ++ } ++ ++ return true; ++} ++ ++static bool ++check_loop_body (basic_block bb0, basic_block bb2, const_tree result) ++{ ++ gimple *g01 = first_stmt (bb0); ++ if (!g01 || !is_gimple_assign (g01) ++ || gimple_assign_rhs_code (g01) != MEM_REF ++ || TREE_OPERAND (gimple_assign_rhs1 (g01), 0) != result) ++ { ++ return false; ++ } ++ ++ gimple *g02 = g01->next; ++ /* GIMPLE_COND would be the last gimple in a basic block, ++ and have no other side effects on RESULT. */ ++ if (!g02 || gimple_code (g02) != GIMPLE_COND) ++ { ++ return false; ++ } ++ ++ if (first_stmt (bb2) != last_stmt (bb2)) ++ { ++ return false; ++ } ++ ++ return true; ++} ++ ++/* Pattern is like ++ <pre bb> ++ arg1 = base (rhs11) + cst (rhs12); [def1] ++ goto <bb 0> ++ ++ <bb 2> ++ arg2 = result (rhs21) + cst (rhs22); [def2] ++ ++ <bb 0> ++ # result = PHI <arg1 (pre bb), arg2 (bb 2)> ++ _v = *result; [g01] ++ if (_v == 0) [g02] ++ goto <bb 1> ++ else ++ goto <bb 2> ++ ++ <bb 1> ++ _1 = result - base; [g1] ++ _2 = _1 /[ex] cst; [g2] ++ _3 = (unsigned int) _2; [g3] ++ if (_3 == 0) ++ ... ++*/ ++static bool ++check_bb_order (basic_block bb0, basic_block &bb1, basic_block &bb2, ++ gphi *phi_stmt, gimple *&output) ++{ ++ /* Start check from PHI node in BB0. */ ++ if (gimple_phi_num_args (phi_stmt) != 2 ++ || virtual_operand_p (gimple_phi_result (phi_stmt))) ++ { ++ return false; ++ } ++ ++ tree result = gimple_phi_result (phi_stmt); ++ tree arg1 = gimple_phi_arg_def (phi_stmt, 0); ++ tree arg2 = gimple_phi_arg_def (phi_stmt, 1); ++ ++ if (TREE_CODE (arg1) != SSA_NAME ++ || TREE_CODE (arg2) != SSA_NAME ++ || SSA_NAME_IS_DEFAULT_DEF (arg1) ++ || SSA_NAME_IS_DEFAULT_DEF (arg2)) ++ { ++ return false; ++ } ++ ++ gimple *def1 = SSA_NAME_DEF_STMT (arg1); ++ gimple *def2 = SSA_NAME_DEF_STMT (arg2); ++ ++ /* Swap bb1 and bb2 if pattern is like ++ if (_v != 0) ++ goto <bb 2> ++ else ++ goto <bb 1> ++ */ ++ if (gimple_bb (def2) == bb1 && EDGE_SUCC (bb1, 0)->dest == bb0) ++ { ++ std::swap (bb1, bb2); ++ } ++ ++ /* prebb[def1] --> bb0 <-- bb2[def2] */ ++ if (!gimple_bb (def1) ++ || EDGE_SUCC (gimple_bb (def1), 0)->dest != bb0 ++ || gimple_bb (def2) != bb2 || EDGE_SUCC (bb2, 0)->dest != bb0) ++ { ++ return false; ++ } ++ ++ /* Check whether define gimple meets the pattern requirements. */ ++ if (!check_def_gimple (def1, def2, result)) ++ { ++ return false; ++ } ++ ++ if (!check_loop_body (bb0, bb2, result)) ++ { ++ return false; ++ } ++ ++ output = def1; ++ return true; ++} ++ ++/* Check pattern ++ <bb 1> ++ _1 = result - base; [g1] ++ _2 = _1 /[ex] cst; [g2] ++ _3 = (unsigned int) _2; [g3] ++ if (_3 == 0) ++ ... ++*/ ++static bool ++check_gimple_order (basic_block bb1, const_tree base, const_tree cst, ++ const_tree result, gimple *&output) ++{ ++ gimple *g1 = first_stmt (bb1); ++ if (!g1 || !is_gimple_assign (g1) ++ || gimple_assign_rhs_code (g1) != POINTER_DIFF_EXPR ++ || gimple_assign_rhs1 (g1) != result ++ || gimple_assign_rhs2 (g1) != base) ++ { ++ return false; ++ } ++ ++ gimple *g2 = g1->next; ++ if (!g2 || !is_gimple_assign (g2) ++ || gimple_assign_rhs_code (g2) != EXACT_DIV_EXPR ++ || gimple_assign_lhs (g1) != gimple_assign_rhs1 (g2) ++ || TREE_CODE (gimple_assign_rhs2 (g2)) != INTEGER_CST) ++ { ++ return false; ++ } ++ ++ /* INTEGER_CST cst in gimple def1. */ ++ HOST_WIDE_INT num1 = TREE_INT_CST_LOW (cst); ++ /* INTEGER_CST cst in gimple g2. */ ++ HOST_WIDE_INT num2 = TREE_INT_CST_LOW (gimple_assign_rhs2 (g2)); ++ /* _2 must be at least a positive number. */ ++ if (num2 == 0 || num1 / num2 <= 0) ++ { ++ return false; ++ } ++ ++ gimple *g3 = g2->next; ++ if (!g3 || !is_gimple_assign (g3) ++ || gimple_assign_rhs_code (g3) != NOP_EXPR ++ || gimple_assign_lhs (g2) != gimple_assign_rhs1 (g3) ++ || TREE_CODE (gimple_assign_lhs (g3)) != SSA_NAME) ++ { ++ return false; ++ } ++ ++ /* _3 should only be used in comparison operation or PHI node. */ ++ hash_set<tree> *hset = new hash_set<tree>; ++ if (!check_uses (gimple_assign_lhs (g3), hset)) ++ { ++ delete hset; ++ return false; ++ } ++ delete hset; ++ ++ output = g3; ++ return true; ++} ++ ++static bool ++do_phiopt_pattern (basic_block bb0, basic_block bb1, basic_block bb2) ++{ ++ gphi_iterator gsi; ++ ++ for (gsi = gsi_start_phis (bb0); !gsi_end_p (gsi); gsi_next (&gsi)) ++ { ++ gphi *phi_stmt = gsi.phi (); ++ gimple *def1 = NULL; ++ tree base, cst, result; ++ ++ if (!check_bb_order (bb0, bb1, bb2, phi_stmt, def1)) ++ { ++ continue; ++ } ++ ++ base = gimple_assign_rhs1 (def1); ++ cst = gimple_assign_rhs2 (def1); ++ result = gimple_phi_result (phi_stmt); ++ ++ gimple *stmt = NULL; ++ if (!check_gimple_order (bb1, base, cst, result, stmt)) ++ { ++ continue; ++ } ++ ++ gcc_assert (stmt); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "PHIOPT pattern optimization (1) - Rewrite:\n"); ++ print_gimple_stmt (dump_file, stmt, 0); ++ fprintf (dump_file, "to\n"); ++ } ++ ++ /* Rewrite statement ++ _3 = (unsigned int) _2; ++ to ++ _3 = (unsigned int) 1; ++ */ ++ tree type = TREE_TYPE (gimple_assign_rhs1 (stmt)); ++ gimple_assign_set_rhs1 (stmt, build_int_cst (type, 1)); ++ update_stmt (stmt); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ print_gimple_stmt (dump_file, stmt, 0); ++ fprintf (dump_file, "\n"); ++ } ++ ++ return true; ++ } ++ return false; ++} ++ + /* Determine whether we should attempt to hoist adjacent loads out of + diamond patterns in pass_phiopt. Always hoist loads if + -fhoist-adjacent-loads is specified and the target machine has +-- +2.21.0.windows.1 + diff --git a/0014-Backport-StructReorg-Structure-reorganization-optimi.patch b/0014-Backport-StructReorg-Structure-reorganization-optimi.patch new file mode 100644 index 0000000..1565e4a --- /dev/null +++ b/0014-Backport-StructReorg-Structure-reorganization-optimi.patch @@ -0,0 +1,5966 @@ +From 9e44d351dec892bf862134720f5906dffb39456e Mon Sep 17 00:00:00 2001 +From: xiezhiheng <xiezhiheng@huawei.com> +Date: Wed, 14 Jul 2021 21:32:57 -0400 +Subject: [PATCH 14/22] [Backport][StructReorg] Structure reorganization + optimization + +Reference: https://gcc.gnu.org/git/?p=gcc-old.git;a=commit;h=6e1bd1c900533c627b5e4fbbecb41dcd7974b522 + +Introduce structure reorganization optimization, that change C-like +structures layout in order to better utilize spatial locality. This +transformation is affective for programs containing arrays of structures. + +diff --git a/gcc/Makefile.in b/gcc/Makefile.in +index fdc2857d44a..23394c64bc3 100644 +--- a/gcc/Makefile.in ++++ b/gcc/Makefile.in +@@ -1398,6 +1398,7 @@ OBJS = \ + incpath.o \ + init-regs.o \ + internal-fn.o \ ++ ipa-struct-reorg/ipa-struct-reorg.o \ + ipa-cp.o \ + ipa-sra.o \ + ipa-devirt.o \ +diff --git a/gcc/common.opt b/gcc/common.opt +index b2b0aac7fdf..d096ff9c314 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -1866,8 +1866,8 @@ Common Ignore + Does nothing. Preserved for backward compatibility. + + fipa-struct-reorg +-Common Ignore +-Does nothing. Preserved for backward compatibility. ++Common Report Var(flag_ipa_struct_reorg) Init(0) Optimization ++Perform structure layout optimizations. + + fipa-vrp + Common Report Var(flag_ipa_vrp) Optimization +diff --git a/gcc/configure b/gcc/configure +index 8fe9c91fd7c..27beb6b1e9c 100644 +--- a/gcc/configure ++++ b/gcc/configure +@@ -32168,7 +32168,7 @@ $as_echo "$as_me: executing $ac_file commands" >&6;} + "depdir":C) $SHELL $ac_aux_dir/mkinstalldirs $DEPDIR ;; + "gccdepdir":C) + ${CONFIG_SHELL-/bin/sh} $ac_aux_dir/mkinstalldirs build/$DEPDIR +- for lang in $subdirs c-family common analyzer ++ for lang in $subdirs c-family common analyzer ipa-struct-reorg + do + ${CONFIG_SHELL-/bin/sh} $ac_aux_dir/mkinstalldirs $lang/$DEPDIR + done ;; +diff --git a/gcc/configure.ac b/gcc/configure.ac +index 84dceb8074a..82a0ce995f1 100644 +--- a/gcc/configure.ac ++++ b/gcc/configure.ac +@@ -1245,7 +1245,7 @@ AC_CHECK_HEADERS(ext/hash_map) + ZW_CREATE_DEPDIR + AC_CONFIG_COMMANDS([gccdepdir],[ + ${CONFIG_SHELL-/bin/sh} $ac_aux_dir/mkinstalldirs build/$DEPDIR +- for lang in $subdirs c-family common analyzer ++ for lang in $subdirs c-family common analyzer ipa-struct-reorg + do + ${CONFIG_SHELL-/bin/sh} $ac_aux_dir/mkinstalldirs $lang/$DEPDIR + done], [subdirs="$subdirs" ac_aux_dir=$ac_aux_dir DEPDIR=$DEPDIR]) +diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi +index eabeec944e7..7b4578e3e44 100644 +--- a/gcc/doc/invoke.texi ++++ b/gcc/doc/invoke.texi +@@ -478,6 +478,7 @@ Objective-C and Objective-C++ Dialects}. + -finline-functions -finline-functions-called-once -finline-limit=@var{n} @gol + -finline-small-functions -fipa-cp -fipa-cp-clone @gol + -fipa-bit-cp -fipa-vrp -fipa-pta -fipa-profile -fipa-pure-const @gol ++-fipa-struct-reorg @gol + -fipa-reference -fipa-reference-addressable @gol + -fipa-stack-alignment -fipa-icf -fira-algorithm=@var{algorithm} @gol + -flive-patching=@var{level} @gol +@@ -10223,6 +10224,19 @@ Enabled by default at @option{-O} and higher. + Reduce stack alignment on call sites if possible. + Enabled by default. + ++@item -fipa-struct-reorg ++@opindex fipa-struct-reorg ++Perform structure reorganization optimization, that change C-like structures ++layout in order to better utilize spatial locality. This transformation is ++affective for programs containing arrays of structures. Available in two ++compilation modes: profile-based (enabled with @option{-fprofile-generate}) ++or static (which uses built-in heuristics). It works only in whole program ++mode, so it requires @option{-fwhole-program} to be ++enabled. Structures considered @samp{cold} by this transformation are not ++affected (see @option{--param struct-reorg-cold-struct-ratio=@var{value}}). ++ ++With this flag, the program debug info reflects a new structure layout. ++ + @item -fipa-pta + @opindex fipa-pta + Perform interprocedural pointer analysis and interprocedural modification +@@ -11981,6 +11995,15 @@ In each case, the @var{value} is an integer. The following choices + of @var{name} are recognized for all targets: + + @table @gcctabopt ++@item struct-reorg-cold-struct-ratio ++The threshold ratio (as a percentage) between a structure frequency ++and the frequency of the hottest structure in the program. This parameter ++is used by struct-reorg optimization enabled by @option{-fipa-struct-reorg}. ++We say that if the ratio of a structure frequency, calculated by profiling, ++to the hottest structure frequency in the program is less than this ++parameter, then structure reorganization is not applied to this structure. ++The default is 10. ++ + @item predictable-branch-outcome + When branch is predicted to be taken with probability lower than this threshold + (in percent), then it is considered well predictable. +diff --git a/gcc/ipa-param-manipulation.c b/gcc/ipa-param-manipulation.c +index fbeea454084..6ba905fe1ee 100644 +--- a/gcc/ipa-param-manipulation.c ++++ b/gcc/ipa-param-manipulation.c +@@ -49,7 +49,8 @@ static const char *ipa_param_prefixes[IPA_PARAM_PREFIX_COUNT] + = {"SYNTH", + "ISRA", + "simd", +- "mask"}; ++ "mask", ++ "struct_reorg"}; + + /* Names of parameters for dumping. Keep in sync with enum ipa_parm_op. */ + +diff --git a/gcc/ipa-param-manipulation.h b/gcc/ipa-param-manipulation.h +index 0b038ea57f1..dcda81dc8f8 100644 +--- a/gcc/ipa-param-manipulation.h ++++ b/gcc/ipa-param-manipulation.h +@@ -131,6 +131,7 @@ enum ipa_param_name_prefix_indices + IPA_PARAM_PREFIX_ISRA, + IPA_PARAM_PREFIX_SIMD, + IPA_PARAM_PREFIX_MASK, ++ IPA_PARAM_PREFIX_REORG, + IPA_PARAM_PREFIX_COUNT + }; + +@@ -194,7 +195,7 @@ struct GTY(()) ipa_adjusted_param + + /* Index into ipa_param_prefixes specifying a prefix to be used with + DECL_NAMEs of newly synthesized parameters. */ +- unsigned param_prefix_index : 2; ++ unsigned param_prefix_index : 3; + + /* Storage order of the original parameter (for the cases when the new + parameter is a component of an original one). */ +diff --git a/gcc/ipa-struct-reorg/escapes.def b/gcc/ipa-struct-reorg/escapes.def +new file mode 100644 +index 00000000000..929279c8faf +--- /dev/null ++++ b/gcc/ipa-struct-reorg/escapes.def +@@ -0,0 +1,60 @@ ++/* Copyright (C) 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/>. */ ++ ++/* Before including this file, you should define a macro: ++ DEF_ESCAPE (ENUM, TEXT) ++ ++ This macro will be called once for each escape reason. The ++ ENUM will be of type "escape_type". The TEXT is describing ++ the reason for the escape. ++*/ ++DEF_ESCAPE (escape_marked_as_used, "Type used in variable marked as used") ++DEF_ESCAPE (escape_via_global_var, "Type used via a external visible variable") ++DEF_ESCAPE (escape_via_global_init, "Type used via a global init of a variable") ++DEF_ESCAPE (escape_non_supported_allocator, "Type used by allocation which is not currently supported") ++DEF_ESCAPE (escape_dependent_type_escapes, "Type uses a type which escapes or is used by a type which escapes") ++DEF_ESCAPE (escape_var_arg_function, "Types escapes via a variable argument function") ++DEF_ESCAPE (escape_bitfields, "Types has bitfields") ++DEF_ESCAPE (escape_recusive_type, "Type has a recusive relationship") ++DEF_ESCAPE (escape_variable_sized_array, "Type has a variable sized type") ++DEF_ESCAPE (escape_external_function, "Type escapes via an external function call") ++DEF_ESCAPE (escape_visible_function, "Type escapes via expternally visible function call") ++DEF_ESCAPE (escape_pointer_function, "Type escapes via an function pointer call") ++DEF_ESCAPE (escape_unkown_field, "Type escapes via an unkown field accessed") ++DEF_ESCAPE (escape_union, "Type escapes via an union") ++DEF_ESCAPE (escape_inline_asm, "Type escapes via inline-asm") ++DEF_ESCAPE (escape_non_multiply_size, "Type escapes a pointer plus which is not a multiplicate of the size") ++DEF_ESCAPE (escape_cast_void, "Type escapes a cast to/from void*") ++DEF_ESCAPE (escape_cast_another_ptr, "Type escapes a cast to a different pointer") ++DEF_ESCAPE (escape_cast_int, "Type escapes a cast from/to intergral type") ++DEF_ESCAPE (escape_int_const, "Type escapes via integer constant") ++DEF_ESCAPE (escape_vce, "Type escapes via a VIEW_CONVERT_EXPR") ++DEF_ESCAPE (escape_array_access, "Type escapes via an array access") ++DEF_ESCAPE (escape_noclonable_function, "Type escapes via a non-clonable function") ++DEF_ESCAPE (escape_rescusive_type, "Recusive type") ++DEF_ESCAPE (escape_user_alignment, "Type has an user alignment set") ++DEF_ESCAPE (escape_volatile, "Type has an variable which is volatile") ++DEF_ESCAPE (escape_non_eq, "Type has a comparison other than equals or not equals") ++DEF_ESCAPE (escape_addr, "Type escapes via taking the address of field") ++DEF_ESCAPE (escape_cannot_change_signature, "Type used in a call that cannot change signature") ++DEF_ESCAPE (escape_non_optimize, "Type used by a function which turns off struct reorg") ++DEF_ESCAPE (escape_array, "Type is used in an array [not handled yet]") ++DEF_ESCAPE (escape_ptr_ptr, "Type is used in a pointer to a pointer [not handled yet]") ++DEF_ESCAPE (escape_return, "Type escapes via a return [not handled yet]") ++ ++#undef DEF_ESCAPE +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +new file mode 100644 +index 00000000000..8d1ddc82877 +--- /dev/null ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -0,0 +1,3918 @@ ++/* Struct-reorg optimizations. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ Contributed by Andrew Pinski <apinski@cavium.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, 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/>. */ ++ ++/* This pass implements the structure reorganization organization (struct-reorg). ++ Right now it handles just splitting off the hottest fields for a struct of 2 fields: ++ struct s { ++ type1 field1; // Hot field ++ type2 field2; ++ }; ++ s *v; ++ into: ++ struct s_hot { ++ type1 field1; ++ }; ++ struct c_cold { ++ type2 field2; ++ }; ++ s_hot *v_hot; ++ s_cold *v_cold; ++ ++ TODO: This pass can be extended to more fields, and other alogrothims like reordering. ++ ++ This pass operate in four stages: ++ 1. All of the field accesses, declarations (struct types and pointers to that type) ++ and struct types are scanned and recorded. This includes global declarations. ++ Also record all allocation and freeing sites; this is needed for the rewriting ++ phase. ++ ++ FIXME: If there is a top-level inline-asm, the pass immediately returns. ++ ++ 2. Prune out the types which are considered escaping. ++ Examples of types which are considered escaping: ++ 1. A declaration has been marked as having the attribute used or has user defined ++ alignment (type too). ++ 2. Accesses are via a BIT_FIELD_REF. FIXME: Handle VECTOR_TYPE for this case. ++ 3. The "allocation" site is not a known builtin function. ++ 4. Casting to/from an integer. ++ ++ 3. Analyze the types for which optimization to do. ++ a. Split the fields into two different structs. ++ (FIXME: two field case handled only) ++ Look at all structs which contain two fields, if one of the fields is hotter ++ then split it and put it on the rewritting for accesses. ++ Allocations and freeing are marked to split into two functions; all uses of ++ that type will now be considered as two. ++ b. Reorder fields hottest to the coldest. TODO: Implement. ++ ++ 4. Rewrite each access and allocation and free which is marked as rewriting. ++ ++ */ ++ ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "tm.h" ++#include "tree.h" ++#include "tree-pass.h" ++#include "cgraph.h" ++#include "diagnostic-core.h" ++#include "function.h" ++#include "basic-block.h" ++#include "gimple.h" ++#include "vec.h" ++#include "tree-pretty-print.h" ++#include "gimple-pretty-print.h" ++#include "gimple-iterator.h" ++#include "cfg.h" ++#include "ssa.h" ++#include "tree-dfa.h" ++#include "fold-const.h" ++#include "tree-inline.h" ++#include "stor-layout.h" ++#include "tree-into-ssa.h" ++#include "tree-cfg.h" ++#include "alloc-pool.h" ++#include "symbol-summary.h" ++#include "alloc-pool.h" ++#include "ipa-prop.h" ++#include "ipa-struct-reorg.h" ++#include "tree-eh.h" ++#include "bitmap.h" ++#include "ipa-param-manipulation.h" ++#include "tree-ssa-live.h" /* For remove_unused_locals. */ ++ ++#define VOID_POINTER_P(type) (POINTER_TYPE_P (type) && VOID_TYPE_P (TREE_TYPE (type))) ++ ++namespace { ++ ++using namespace struct_reorg; ++ ++/* Return true iff TYPE is stdarg va_list type. */ ++ ++static inline bool ++is_va_list_type (tree type) ++{ ++ return TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (va_list_type_node); ++} ++ ++static const char * ++get_type_name (tree type) ++{ ++ const char *tname = NULL; ++ ++ if (type == NULL) ++ { ++ return NULL; ++ } ++ ++ if (TYPE_NAME (type) != NULL) ++ { ++ if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) ++ { ++ tname = IDENTIFIER_POINTER (TYPE_NAME (type)); ++ } ++ else if (DECL_NAME (TYPE_NAME (type)) != NULL) ++ { ++ tname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); ++ } ++ } ++ return tname; ++} ++ ++/* Return the inner most type for arrays and pointers of TYPE. */ ++ ++tree ++inner_type (tree type) ++{ ++ while (POINTER_TYPE_P (type) ++ || TREE_CODE (type) == ARRAY_TYPE) ++ type = TREE_TYPE (type); ++ return type; ++} ++ ++/* Return true if TYPE is a type which struct reorg should handled. */ ++ ++bool ++handled_type (tree type) ++{ ++ type = inner_type (type); ++ if (TREE_CODE (type) == RECORD_TYPE) ++ return !is_va_list_type (type); ++ return false; ++} ++ ++} // anon namespace ++ ++namespace struct_reorg { ++ ++/* Constructor of srfunction. */ ++ ++srfunction::srfunction (cgraph_node *n) ++ : node (n), ++ old (NULL), ++ newnode (NULL), ++ newf (NULL) ++{ ++} ++ ++/* Add an ARG to the list of arguments for the function. */ ++ ++void ++srfunction::add_arg(srdecl *arg) ++{ ++ args.safe_push(arg); ++} ++ ++/* Dump the SRFUNCTION to the file FILE. */ ++ ++void ++srfunction::dump (FILE *file) ++{ ++ if (node) ++ { ++ fprintf (file, "function : "); ++ print_generic_expr (file, node->decl); ++ fprintf (file, " with arguments: "); ++ for (unsigned i = 0; i < args.length (); i++) ++ { ++ if (i == 0) ++ fprintf (file, "\n "); ++ else ++ fprintf (file, "\n, "); ++ args[i]->dump (file); ++ } ++ ++ fprintf (file, "\nuses globals: "); ++ for(unsigned i = 0; i < globals.length (); i++) ++ { ++ fprintf (file, "\n "); ++ globals[i]->dump (file); ++ } ++ ++ fprintf (file, "\ndecls: "); ++ } ++ else ++ fprintf (file, "globals : "); ++ ++ for(unsigned i = 0; i < decls.length (); i++) ++ { ++ fprintf (file, "\n "); ++ decls[i]->dump (file); ++ } ++} ++ ++/* Simple dump the SRFUNCTION to the file FILE; used so it is not recusive. */ ++ ++void ++srfunction::simple_dump (FILE *file) ++{ ++ print_generic_expr (file, node->decl); ++} ++ ++ ++/* Constructor of FIELD. */ ++ ++srfield::srfield (tree field, srtype *base) ++ : offset(int_byte_position (field)), ++ fieldtype (TREE_TYPE (field)), ++ fielddecl (field), ++ base(base), ++ type(NULL), ++ clusternum(0) ++{ ++ for(int i = 0;i < max_split; i++) ++ newfield[i] = NULL_TREE; ++} ++ ++/* Constructor of TYPE. */ ++ ++srtype::srtype (tree type) ++ : type (type), ++ chain_type (false), ++ escapes (does_not_escape), ++ visited (false) ++{ ++ for (int i = 0; i < max_split; i++) ++ newtype[i] = NULL_TREE; ++ ++ for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) ++ { ++ if (TREE_CODE (field) == FIELD_DECL) ++ { ++ if (DECL_BIT_FIELD (field)) ++ { ++ escapes = escape_bitfields; ++ continue; ++ } ++ else if (!DECL_SIZE (field) ++ || TREE_CODE (DECL_SIZE (field)) != INTEGER_CST) ++ { ++ escapes = escape_variable_sized_array; ++ break; ++ } ++ srfield *t = new srfield (field, this); ++ fields.safe_push(t); ++ } ++ } ++} ++ ++/* Mark the type as escaping type E at statement STMT. */ ++ ++void ++srtype::mark_escape (escape_type e, gimple *stmt) ++{ ++ /* Once the type has escaped, it should never ++ change back to non escaping. */ ++ gcc_assert (e != does_not_escape); ++ if (has_escaped ()) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nO type: "); ++ simple_dump (dump_file); ++ fprintf (dump_file, " has already escaped."); ++ fprintf (dump_file, " old = \"%s\" ", escape_type_string[escapes - 1]); ++ fprintf (dump_file, " new = \"%s\"\n", escape_type_string[e - 1]); ++ if (stmt) ++ print_gimple_stmt (dump_file, stmt, 0); ++ fprintf (dump_file, "\n"); ++ } ++ return; ++ } ++ escapes = e; ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nN type: "); ++ simple_dump (dump_file); ++ fprintf (dump_file, " new = \"%s\"\n", escape_reason ()); ++ if (stmt) ++ print_gimple_stmt (dump_file, stmt, 0); ++ fprintf (dump_file, "\n"); ++ } ++} ++ ++/* Add FIELD to the list of fields that use this type. */ ++ ++void ++srtype::add_field_site (srfield *field) ++{ ++ field_sites.safe_push(field); ++} ++ ++ ++/* Constructor of DECL. */ ++ ++srdecl::srdecl (srtype *tp, tree decl, int argnum) ++ : type (tp), ++ decl (decl), ++ func (NULL_TREE), ++ argumentnum (argnum), ++ visited (false) ++{ ++ if (TREE_CODE (decl) == SSA_NAME) ++ func = current_function_decl; ++ else if (!is_global_var (decl)) ++ func = DECL_CONTEXT (decl); ++ for(int i = 0;i < max_split; i++) ++ newdecl[i] = NULL_TREE; ++} ++ ++/* Find DECL in the function. */ ++ ++srdecl * ++srfunction::find_decl (tree decl) ++{ ++ for (unsigned i = 0; i < decls.length (); i++) ++ if (decls[i]->decl == decl) ++ return decls[i]; ++ return NULL; ++} ++ ++/* Record DECL of the TYPE with argument num ARG. */ ++ ++srdecl * ++srfunction::record_decl (srtype *type, tree decl, int arg) ++{ ++ // Search for the decl to see if it is already there. ++ srdecl *decl1 = find_decl (decl); ++ ++ if (decl1) ++ return decl1; ++ ++ gcc_assert (type); ++ ++ decl1 = new srdecl (type, decl, arg); ++ decls.safe_push(decl1); ++ return decl1; ++} ++ ++/* Find the field at OFF offset. */ ++ ++srfield * ++srtype::find_field (unsigned HOST_WIDE_INT off) ++{ ++ unsigned int i; ++ srfield *field; ++ ++ /* FIXME: handle array/struct field inside the current struct. */ ++ /* NOTE This does not need to be fixed to handle libquatumn */ ++ FOR_EACH_VEC_ELT (fields, i, field) ++ { ++ if (off == field->offset) ++ return field; ++ } ++ return NULL; ++} ++ ++/* Add the function FN to the list of functions if it ++ is there not already. */ ++ ++void ++srtype::add_function (srfunction *fn) ++{ ++ unsigned decluid; ++ unsigned i; ++ decluid = DECL_UID (fn->node->decl); ++ ++ srfunction *fn1; ++ // Search for the decl to see if it is already there. ++ FOR_EACH_VEC_ELT (functions, i, fn1) ++ { ++ if (DECL_UID (fn1->node->decl) == decluid) ++ return; ++ } ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "Recording new function: %u.\n", decluid); ++ ++ functions.safe_push(fn); ++} ++ ++/* Dump out the type structure to FILE. */ ++ ++void ++srtype::dump (FILE *f) ++{ ++ unsigned int i; ++ srfield *field; ++ srfunction *fn; ++ sraccess *access; ++ ++ if (chain_type) ++ fprintf (f, "chain decl "); ++ ++ fprintf (f, "type : "); ++ print_generic_expr (f, type); ++ fprintf (f, "(%d) { ", TYPE_UID (type)); ++ if (escapes != does_not_escape) ++ fprintf (f, " escapes = \"%s\"\n", escape_reason ()); ++ fprintf (f, " fields = { "); ++ FOR_EACH_VEC_ELT (fields, i, field) ++ { ++ if (i == 0) ++ fprintf (f, "\n "); ++ else ++ fprintf (f, "\n, "); ++ field->dump (f); ++ } ++ fprintf (f, " }\n "); ++ fprintf (f, "\n accesses = {"); ++ FOR_EACH_VEC_ELT (accesses, i, access) ++ { ++ fprintf (f, "\n"); ++ access->dump (f); ++ } ++ fprintf (f, " }\n "); ++ fprintf (f, "\n functions = {"); ++ FOR_EACH_VEC_ELT (functions, i, fn) ++ { ++ fprintf (f, " \n"); ++ fn->simple_dump (f); ++ } ++ fprintf (f, "\n }\n"); ++ fprintf (f, "\n field_sites = {"); ++ FOR_EACH_VEC_ELT (field_sites, i, field) ++ { ++ fprintf (f, " \n"); ++ field->simple_dump (f); ++ } ++ fprintf (f, "\n }\n"); ++ fprintf (f, "}\n"); ++} ++ ++/* A simplified dump out the type structure to FILE. */ ++ ++void ++srtype::simple_dump (FILE *f) ++{ ++ print_generic_expr (f, type); ++} ++ ++/* Analyze the type and decide what to be done with it. */ ++ ++void ++srtype::analyze (void) ++{ ++ /* Chain decl types can't be split ++ so don't try. */ ++ if (chain_type) ++ return; ++ ++ /* If there is only one field then there is nothing ++ to be done. */ ++ if (fields.length () == 1) ++ return; ++ ++ /* For now we unconditionally split only structures with 2 fields ++ into 2 different structures. In future we intend to add profile ++ info and/or static heuristics to differentiate splitting process. */ ++ if (fields.length () == 2) ++ fields[1]->clusternum = 1; ++ ++ /* Otherwise we do nothing. */ ++ if (fields.length () >= 3) ++ { ++ return; ++ } ++} ++ ++/* Create the new fields for this field. */ ++ ++void ++srfield::create_new_fields (tree newtype[max_split], ++ tree newfields[max_split], ++ tree newlast[max_split]) ++{ ++ tree nt[max_split]; ++ ++ for (unsigned i = 0; i < max_split; i++) ++ nt[i] = NULL; ++ ++ if (type == NULL) ++ nt[0] = fieldtype; ++ else ++ memcpy (nt, type->newtype, sizeof(type->newtype)); ++ ++ for (unsigned i = 0; i < max_split && nt[i] != NULL; i++) ++ { ++ tree field = make_node (FIELD_DECL); ++ if (nt[1] != NULL && DECL_NAME (fielddecl)) ++ { ++ const char *tname = IDENTIFIER_POINTER (DECL_NAME (fielddecl)); ++ char id[10]; ++ char *name; ++ ++ sprintf(id, "%d", i); ++ name = concat (tname, ".reorg.", id, NULL); ++ DECL_NAME (field) = get_identifier (name); ++ free (name); ++ } ++ else ++ DECL_NAME (field) = DECL_NAME (fielddecl); ++ ++ TREE_TYPE (field) = reconstruct_complex_type (TREE_TYPE (fielddecl), nt[i]); ++ DECL_SOURCE_LOCATION (field) = DECL_SOURCE_LOCATION (fielddecl); ++ SET_DECL_ALIGN (field, DECL_ALIGN (fielddecl)); ++ DECL_USER_ALIGN (field) = DECL_USER_ALIGN (fielddecl); ++ TREE_ADDRESSABLE (field) = TREE_ADDRESSABLE (fielddecl); ++ DECL_NONADDRESSABLE_P (field) = !TREE_ADDRESSABLE (fielddecl); ++ TREE_THIS_VOLATILE (field) = TREE_THIS_VOLATILE (fielddecl); ++ DECL_CONTEXT (field) = newtype[clusternum]; ++ ++ if (newfields[clusternum] == NULL) ++ newfields[clusternum] = newlast[clusternum] = field; ++ else ++ { ++ DECL_CHAIN (newlast[clusternum]) = field; ++ newlast[clusternum] = field; ++ } ++ newfield[i] = field; ++ } ++ ++} ++ ++/* Create the new TYPE corresponding to THIS type. */ ++ ++bool ++srtype::create_new_type (void) ++{ ++ /* If the type has been visited, ++ then return if a new type was ++ created or not. */ ++ if (visited) ++ return has_new_type (); ++ ++ visited = true; ++ ++ if (escapes != does_not_escape) ++ { ++ newtype[0] = type; ++ return false; ++ } ++ ++ bool createnewtype = false; ++ unsigned maxclusters = 0; ++ ++ /* Create a new type for each field. */ ++ for (unsigned i = 0; i < fields.length (); i++) ++ { ++ srfield *field = fields[i]; ++ if (field->type) ++ createnewtype |= field->type->create_new_type (); ++ if (field->clusternum > maxclusters) ++ maxclusters = field->clusternum; ++ } ++ ++ /* If the fields' types did have a change or ++ we are not splitting the struct into two clusters, ++ then just return false and don't change the type. */ ++ if (!createnewtype && maxclusters == 0) ++ { ++ newtype[0] = type; ++ return false; ++ } ++ ++ /* Should have at most max_split clusters. */ ++ gcc_assert (maxclusters < max_split); ++ ++ tree newfields[max_split]; ++ tree newlast[max_split]; ++ ++ maxclusters++; ++ ++ const char *tname = NULL; ++ ++ if (TYPE_NAME (type) != NULL) ++ { ++ if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) ++ tname = IDENTIFIER_POINTER (TYPE_NAME (type)); ++ else if (DECL_NAME (TYPE_NAME (type)) != NULL) ++ tname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); ++ } ++ ++ for (unsigned i = 0; i < maxclusters; i++) ++ { ++ newfields[i] = NULL_TREE; ++ newlast[i] = NULL_TREE; ++ newtype[i] = make_node (RECORD_TYPE); ++ ++ char *name = NULL; ++ char id[10]; ++ sprintf(id, "%d", i); ++ if (tname) ++ { ++ name = concat (tname, ".reorg.", id, NULL); ++ TYPE_NAME (newtype[i]) = get_identifier (name); ++ free (name); ++ } ++ } ++ ++ for (unsigned i = 0; i < fields.length (); i++) ++ { ++ srfield *f = fields[i]; ++ f->create_new_fields (newtype, newfields, newlast); ++ } ++ ++ ++ /* No reason to warn about these structs since the warning would ++ have happened already. */ ++ int save_warn_padded = warn_padded; ++ warn_padded = 0; ++ ++ for (unsigned i = 0; i < maxclusters; i++) ++ { ++ TYPE_FIELDS (newtype[i]) = newfields[i]; ++ layout_type (newtype[i]); ++ } ++ ++ warn_padded = save_warn_padded; ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "Created %d types:\n", maxclusters); ++ for (unsigned i = 0; i < maxclusters; i++) ++ { ++ print_generic_expr (dump_file, newtype[i]); ++ fprintf (dump_file, "\n"); ++ } ++ } ++ ++ return true; ++} ++ ++/* Helper function to copy some attributes from ORIG_DECL to the NEW_DECL. */ ++ ++static inline void ++copy_var_attributes (tree new_decl, tree orig_decl) ++{ ++ DECL_ARTIFICIAL (new_decl) = 1; ++ DECL_EXTERNAL (new_decl) = DECL_EXTERNAL (orig_decl); ++ TREE_STATIC (new_decl) = TREE_STATIC (orig_decl); ++ TREE_PUBLIC (new_decl) = TREE_PUBLIC (orig_decl); ++ TREE_USED (new_decl) = TREE_USED (orig_decl); ++ DECL_CONTEXT (new_decl) = DECL_CONTEXT (orig_decl); ++ TREE_THIS_VOLATILE (new_decl) = TREE_THIS_VOLATILE (orig_decl); ++ TREE_ADDRESSABLE (new_decl) = TREE_ADDRESSABLE (orig_decl); ++ TREE_READONLY (new_decl) = TREE_READONLY (orig_decl); ++ if (is_global_var (orig_decl)) ++ set_decl_tls_model (new_decl, DECL_TLS_MODEL (orig_decl)); ++} ++ ++/* Create all of the new decls (SSA_NAMES included) for THIS function. */ ++ ++void ++srfunction::create_new_decls (void) ++{ ++ /* If this function has been cloned, we don't need to ++ create the new decls. */ ++ if (newnode) ++ return; ++ ++ if (node) ++ set_cfun (DECL_STRUCT_FUNCTION (node->decl)); ++ ++ for (unsigned i = 0; i < decls.length (); i++) ++ { ++ srdecl *decl = decls[i]; ++ srtype *type = decl->type; ++ /* If the type of the decl does not change, ++ then don't create a new decl. */ ++ if (!type->has_new_type ()) ++ { ++ decl->newdecl[0] = decl->decl; ++ continue; ++ } ++ ++ /* Handle SSA_NAMEs. */ ++ if (TREE_CODE (decl->decl) == SSA_NAME) ++ { ++ tree newtype1[max_split]; ++ tree inner = SSA_NAME_VAR (decl->decl); ++ tree newinner[max_split]; ++ memset (newinner, 0, sizeof(newinner)); ++ for (unsigned j = 0; j < max_split && type->newtype[j]; j++) ++ newtype1[j] = reconstruct_complex_type (TREE_TYPE (decls[i]->decl), type->newtype[j]); ++ if (inner) ++ { ++ srdecl *in = find_decl (inner); ++ gcc_assert (in); ++ memcpy (newinner, in->newdecl, sizeof(newinner)); ++ } ++ tree od = decls[i]->decl; ++ /* Create the new ssa names and copy some attributes from the old one. */ ++ for (unsigned j = 0; j < max_split && type->newtype[j]; j++) ++ { ++ tree nd = make_ssa_name (newinner[j] ? newinner[j] : newtype1[j]); ++ decl->newdecl[j] = nd; ++ /* If the old decl was a default defition, handle it specially. */ ++ if (SSA_NAME_IS_DEFAULT_DEF (od)) ++ { ++ SSA_NAME_IS_DEFAULT_DEF (nd) = true; ++ SSA_NAME_DEF_STMT (nd) = gimple_build_nop (); ++ ++ /* Set the default definition for the ssaname if needed. */ ++ if (inner) ++ { ++ gcc_assert (newinner[j]); ++ set_ssa_default_def (cfun, newinner[j], nd); ++ } ++ } ++ SSA_NAME_OCCURS_IN_ABNORMAL_PHI (nd) ++ = SSA_NAME_OCCURS_IN_ABNORMAL_PHI (od); ++ statistics_counter_event (cfun, "Create new ssa_name", 1); ++ } ++ } ++ else if (TREE_CODE (decls[i]->decl) == VAR_DECL) ++ { ++ tree orig_var = decl->decl; ++ const char *tname = NULL; ++ if (DECL_NAME (orig_var)) ++ tname = IDENTIFIER_POINTER (DECL_NAME (orig_var)); ++ for (unsigned j = 0; j < max_split && type->newtype[j]; j++) ++ { ++ tree new_name = NULL; ++ char *name = NULL; ++ char id[10]; ++ sprintf(id, "%d", j); ++ if (tname) ++ { ++ name = concat (tname, ".reorg.", id, NULL); ++ new_name = get_identifier (name); ++ free (name); ++ } ++ tree newtype1 = reconstruct_complex_type (TREE_TYPE (orig_var), type->newtype[j]); ++ decl->newdecl[j] = build_decl (DECL_SOURCE_LOCATION (orig_var), ++ VAR_DECL, new_name, newtype1); ++ copy_var_attributes (decl->newdecl[j], orig_var); ++ if (!is_global_var (orig_var)) ++ add_local_decl (cfun, decl->newdecl[j]); ++ else ++ varpool_node::add (decl->newdecl[j]); ++ statistics_counter_event (cfun, "Create new var decl", 1); ++ } ++ } ++ /* Paramater decls are already handled in create_new_functions. */ ++ else if (TREE_CODE (decls[i]->decl) == PARM_DECL) ++ ; ++ else ++ internal_error ("Unhandled decl type stored"); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "Created New decls for decl:\n"); ++ fprintf (dump_file, "\n"); ++ decls[i]->dump (dump_file); ++ fprintf (dump_file, "\n"); ++ for (unsigned j = 0; j < max_split && decls[i]->newdecl[j]; j++) ++ { ++ print_generic_expr (dump_file, decls[i]->newdecl[j]); ++ fprintf (dump_file, "\n"); ++ } ++ fprintf (dump_file, "\n"); ++ } ++ } ++ ++ set_cfun (NULL); ++ ++} ++ ++/* Dump out the field structure to FILE. */ ++ ++void ++srfield::dump (FILE *f) ++{ ++ fprintf (f, "field (%d) { ", DECL_UID (fielddecl)); ++ fprintf (f, "base = "); ++ base->simple_dump (f); ++ fprintf (f, ", offset = " HOST_WIDE_INT_PRINT_DEC, offset); ++ fprintf (f, ", type = "); ++ print_generic_expr (f, fieldtype); ++ if (type) ++ { ++ fprintf (f, "( srtype = "); ++ type->simple_dump (f); ++ fprintf (f, ")"); ++ } ++ fprintf (f, "\n}\n"); ++} ++ ++ ++/* A simplified dump out the field structure to FILE. */ ++ ++void ++srfield::simple_dump (FILE *f) ++{ ++ fprintf (f, "field (%d)", DECL_UID (fielddecl)); ++} ++ ++/* Dump out the access structure to FILE. */ ++ ++void ++sraccess::dump (FILE *f) ++{ ++ fprintf (f, "access { "); ++ fprintf (f, "type = '("); ++ type->simple_dump (f); ++ fprintf (f, ")'"); ++ if (field) ++ { ++ fprintf (f, ", field = '("); ++ field->simple_dump (f); ++ fprintf (f, ")'"); ++ } ++ else ++ fprintf (f, ", whole type"); ++ fprintf (f, " in function: %s/%d", node->name (), node->order); ++ fprintf (f, ", stmt:\n"); ++ print_gimple_stmt (f, stmt, 0); ++ fprintf (f, "\n }\n"); ++ ++} ++ ++/* Dump out the decl structure to FILE. */ ++ ++void ++srdecl::dump (FILE *file) ++{ ++ if (!func) ++ fprintf (file, "global "); ++ if (argumentnum != -1) ++ fprintf (file, "argument(%d) ", argumentnum); ++ fprintf (file, "decl: "); ++ print_generic_expr (file, decl); ++ fprintf (file, " type: "); ++ type->simple_dump (file); ++} ++ ++} // namespace struct_reorg ++ ++namespace { ++ ++struct ipa_struct_reorg ++{ ++ // Constructors ++ ipa_struct_reorg(void) ++ : current_function (NULL), ++ done_recording(false) ++ { ++ } ++ ++ // public methods ++ unsigned execute(void); ++ void mark_type_as_escape (tree type, escape_type, gimple *stmt = NULL); ++private: ++ // fields ++ auto_vec_del<srtype> types; ++ auto_vec_del<srfunction> functions; ++ srglobal globals; ++ srfunction *current_function; ++ ++ bool done_recording; ++ ++ // private methods ++ void dump_types (FILE *f); ++ void dump_types_escaped (FILE *f); ++ void dump_functions (FILE *f); ++ void record_accesses (void); ++ void detect_cycles (void); ++ bool walk_field_for_cycles (srtype*); ++ void prune_escaped_types (void); ++ void propagate_escape (void); ++ void analyze_types (void); ++ void clear_visited (void); ++ bool create_new_types (void); ++ void restore_field_type (void); ++ void create_new_decls (void); ++ srdecl *find_decl (tree); ++ void create_new_functions (void); ++ void create_new_args (cgraph_node *new_node); ++ unsigned rewrite_functions (void); ++ srdecl *record_var (tree decl, escape_type escapes = does_not_escape, int arg = -1); ++ srfunction *record_function (cgraph_node *node); ++ srfunction *find_function (cgraph_node *node); ++ srtype *record_type (tree type); ++ void process_union (tree type); ++ srtype *find_type (tree type); ++ void maybe_record_stmt (cgraph_node *, gimple *); ++ void maybe_record_assign (cgraph_node *, gassign *); ++ void maybe_record_call (cgraph_node *, gcall *); ++ void maybe_record_allocation_site (cgraph_node *, gimple *); ++ void record_stmt_expr (tree expr, cgraph_node *node, gimple *stmt); ++ void mark_expr_escape(tree, escape_type, gimple *stmt); ++ tree allocate_size (srtype *t, gimple *stmt); ++ ++ void mark_decls_in_as_not_needed (tree fn); ++ ++ bool rewrite_stmt (gimple*, gimple_stmt_iterator *); ++ bool rewrite_assign (gassign *, gimple_stmt_iterator *); ++ bool rewrite_call (gcall *, gimple_stmt_iterator *); ++ bool rewrite_cond (gcond *, gimple_stmt_iterator *); ++ bool rewrite_debug (gimple *, gimple_stmt_iterator *); ++ bool rewrite_phi (gphi *); ++ bool rewrite_expr (tree expr, tree newexpr[max_split], bool ignore_missing_decl = false); ++ bool rewrite_lhs_rhs (tree lhs, tree rhs, tree newlhs[max_split], tree newrhs[max_split]); ++ bool get_type_field (tree expr, tree &base, bool &indirect, srtype *&type, srfield *&field, bool &realpart, bool &imagpart, bool &address, bool should_create = false, bool can_escape = false); ++ bool wholeaccess (tree expr, tree base, tree accesstype, srtype *t); ++ ++ void check_definition (srdecl *decl, vec<srdecl*>&); ++ void check_uses (srdecl *decl, vec<srdecl*>&); ++ void check_use (srdecl *decl, gimple *stmt, vec<srdecl*>&); ++ void check_type_and_push (tree newdecl, srtype *type, vec<srdecl*> &worklist, gimple *stmt); ++ void check_other_side (srdecl *decl, tree other, gimple *stmt, vec<srdecl*> &worklist); ++ ++ void find_vars (gimple *stmt); ++ void find_var (tree expr, gimple *stmt); ++ void mark_types_asm (gasm *astmt); ++ ++ bool has_rewritten_type (srfunction*); ++ void maybe_mark_or_record_other_side (tree side, tree other, gimple *stmt); ++}; ++ ++/* Dump all of the recorded types to file F. */ ++ ++void ++ipa_struct_reorg::dump_types (FILE *f) ++{ ++ unsigned i; ++ srtype *type; ++ FOR_EACH_VEC_ELT (types, i, type) ++ { ++ type->dump(f); ++ } ++ fprintf (f, "\n"); ++} ++ ++/* Dump all of the recorded types to file F. */ ++ ++void ++ipa_struct_reorg::dump_types_escaped (FILE *f) ++{ ++ unsigned i; ++ srtype *type; ++ FOR_EACH_VEC_ELT (types, i, type) ++ { ++ if (type->has_escaped ()) ++ { ++ type->simple_dump (f); ++ fprintf (f, " has escaped: \"%s\"\n", type->escape_reason()); ++ } ++ } ++ fprintf (f, "\n"); ++} ++ ++ ++/* Dump all of the record functions to file F. */ ++ ++void ++ipa_struct_reorg::dump_functions (FILE *f) ++{ ++ unsigned i; ++ srfunction *fn; ++ ++ fprintf (f, "\n\n"); ++ globals.dump (f); ++ fprintf (f, "\n\n"); ++ FOR_EACH_VEC_ELT (functions, i, fn) ++ { ++ fn->dump(f); ++ fprintf (f, "\n"); ++ } ++ fprintf (f, "\n\n"); ++} ++ ++/* Find the recorded srtype corresponding to TYPE. */ ++ ++srtype * ++ipa_struct_reorg::find_type (tree type) ++{ ++ unsigned i; ++ /* Get the main variant as we are going ++ to find that type only. */ ++ type = TYPE_MAIN_VARIANT (type); ++ ++ srtype *type1; ++ // Search for the type to see if it is already there. ++ FOR_EACH_VEC_ELT (types, i, type1) ++ { ++ if (types_compatible_p (type1->type, type)) ++ return type1; ++ } ++ return NULL; ++} ++ ++/* Is TYPE a volatile type or one which points ++ to a volatile type. */ ++ ++bool isvolatile_type (tree type) ++{ ++ if (TYPE_VOLATILE (type)) ++ return true; ++ while (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE) ++ { ++ type = TREE_TYPE (type); ++ if (TYPE_VOLATILE (type)) ++ return true; ++ } ++ return false; ++} ++ ++/* Is TYPE an array type or points to an array type. */ ++ ++bool isarraytype (tree type) ++{ ++ if (TREE_CODE (type) == ARRAY_TYPE) ++ return true; ++ while (POINTER_TYPE_P (type)) ++ { ++ type = TREE_TYPE (type); ++ if (TREE_CODE (type) == ARRAY_TYPE) ++ return true; ++ } ++ return false; ++} ++ ++/* Is TYPE a pointer to another pointer. */ ++ ++bool isptrptr (tree type) ++{ ++ bool firstptr = false; ++ while (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE) ++ { ++ if (POINTER_TYPE_P (type)) ++ { ++ if (firstptr) ++ return true; ++ firstptr = true; ++ } ++ type = TREE_TYPE (type); ++ } ++ return false; ++} ++ ++/* Return the escape type which corresponds to if ++ this is an volatile type, an array type or a pointer ++ to a pointer type. */ ++ ++escape_type escape_type_volatile_array_or_ptrptr (tree type) ++{ ++ if (isvolatile_type (type)) ++ return escape_volatile; ++ if (isarraytype (type)) ++ return escape_array; ++ if (isptrptr (type)) ++ return escape_ptr_ptr; ++ return does_not_escape; ++} ++ ++/* Record TYPE if not already recorded. */ ++ ++srtype * ++ipa_struct_reorg::record_type (tree type) ++{ ++ unsigned typeuid; ++ ++ /* Get the main variant as we are going ++ to record that type only. */ ++ type = TYPE_MAIN_VARIANT (type); ++ typeuid = TYPE_UID (type); ++ ++ srtype *type1; ++ ++ type1 = find_type (type); ++ if (type1) ++ return type1; ++ ++ /* If already done recording just return NULL. */ ++ if (done_recording) ++ return NULL; ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "Recording new type: %u.\n", typeuid); ++ ++ type1 = new srtype (type); ++ types.safe_push(type1); ++ ++ /* If the type has an user alignment set, ++ that means the user most likely already setup the type. */ ++ if (TYPE_USER_ALIGN (type)) ++ type1->mark_escape (escape_user_alignment, NULL); ++ ++ for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) ++ { ++ if (TREE_CODE (field) == FIELD_DECL) ++ { ++ tree t = TREE_TYPE (field); ++ process_union (t); ++ if (TREE_CODE (inner_type (t)) == UNION_TYPE ++ || TREE_CODE (inner_type (t)) == QUAL_UNION_TYPE) ++ { ++ type1->mark_escape (escape_union, NULL); ++ } ++ if (isvolatile_type (t)) ++ type1->mark_escape (escape_volatile, NULL); ++ escape_type e = escape_type_volatile_array_or_ptrptr (t); ++ if (e != does_not_escape) ++ type1->mark_escape (e, NULL); ++ if (handled_type (t)) ++ { ++ srtype *t1 = record_type (inner_type (t)); ++ srfield *f = type1->find_field (int_byte_position (field)); ++ /* We might have an variable sized type which we don't set the handle. */ ++ if (f) ++ { ++ f->type = t1; ++ t1->add_field_site (f); ++ } ++ if (t1 == type1) ++ type1->mark_escape (escape_rescusive_type, NULL); ++ } ++ } ++ } ++ ++ return type1; ++} ++ ++/* Mark TYPE as escaping with ESCAPES as the reason. */ ++ ++void ++ipa_struct_reorg::mark_type_as_escape (tree type, escape_type escapes, gimple *stmt) ++{ ++ if (handled_type (type)) ++ { ++ srtype *stype = record_type (inner_type (type)); ++ ++ if (!stype) ++ return; ++ ++ stype->mark_escape (escapes, stmt); ++ } ++} ++ ++/* Maybe process the union of type TYPE, such that marking all of the fields' ++ types as being escaping. */ ++ ++void ++ipa_struct_reorg::process_union (tree type) ++{ ++ static hash_set<tree> unions_recorded; ++ ++ type = inner_type (type); ++ if (TREE_CODE (type) != UNION_TYPE ++ && TREE_CODE (type) != QUAL_UNION_TYPE) ++ return; ++ ++ type = TYPE_MAIN_VARIANT (type); ++ ++ /* We already processed this type. */ ++ if (unions_recorded.add (type)) ++ return; ++ ++ for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) ++ { ++ if (TREE_CODE (field) == FIELD_DECL) ++ { ++ mark_type_as_escape (TREE_TYPE (field), escape_union); ++ process_union (TREE_TYPE (field)); ++ } ++ } ++} ++ ++/* Used by record_var function as a callback to walk_tree. ++ Mark the type as escaping if it has expressions which ++ cannot be converted for global initializations. */ ++ ++static tree ++record_init_types (tree *tp, int *walk_subtrees, void *data) ++{ ++ ipa_struct_reorg *c = (ipa_struct_reorg *)data; ++ switch (TREE_CODE (*tp)) ++ { ++ CASE_CONVERT: ++ case COMPONENT_REF: ++ case VIEW_CONVERT_EXPR: ++ case ARRAY_REF: ++ { ++ tree typeouter = TREE_TYPE (*tp); ++ tree typeinner = TREE_TYPE (TREE_OPERAND (*tp, 0)); ++ c->mark_type_as_escape (typeouter, escape_via_global_init); ++ c->mark_type_as_escape (typeinner, escape_via_global_init); ++ break; ++ } ++ case INTEGER_CST: ++ if (!integer_zerop (*tp)) ++ c->mark_type_as_escape (TREE_TYPE (*tp), escape_via_global_init); ++ break; ++ case VAR_DECL: ++ case PARM_DECL: ++ case FIELD_DECL: ++ c->mark_type_as_escape (TREE_TYPE (*tp), escape_via_global_init); ++ *walk_subtrees = false; ++ break; ++ default: ++ *walk_subtrees = true; ++ break; ++ } ++ return NULL_TREE; ++} ++ ++/* Record var DECL; optionally specify the escape reason and the argument ++ number in a function. */ ++ ++srdecl * ++ipa_struct_reorg::record_var (tree decl, escape_type escapes, int arg) ++{ ++ srtype *type; ++ srdecl *sd = NULL; ++ ++ process_union (TREE_TYPE (decl)); ++ ++ /* */ ++ if (handled_type (TREE_TYPE (decl))) ++ { ++ type = record_type (inner_type (TREE_TYPE (decl))); ++ escape_type e; ++ ++ if (done_recording && !type) ++ return NULL; ++ ++ gcc_assert (type); ++ if (TREE_CODE (decl) == VAR_DECL && is_global_var (decl)) ++ sd = globals.record_decl (type, decl, arg); ++ else ++ { ++ gcc_assert (current_function); ++ sd = current_function->record_decl (type, decl, arg); ++ } ++ ++ /* If the variable has the "used" attribute, then treat the type as escaping. */ ++ if (escapes != does_not_escape) ++ e = escapes; ++ else if (TREE_CODE (decl) != SSA_NAME && DECL_PRESERVE_P (decl)) ++ e = escape_marked_as_used; ++ else if (TREE_THIS_VOLATILE (decl)) ++ e = escape_volatile; ++ else if (TREE_CODE (decl) != SSA_NAME && DECL_USER_ALIGN (decl)) ++ e = escape_user_alignment; ++ else if (TREE_CODE (decl) != SSA_NAME && TREE_STATIC (decl) && TREE_PUBLIC (decl)) ++ e = escape_via_global_var; ++ /* We don't have an initlizer. */ ++ else if (TREE_CODE (decl) != SSA_NAME && DECL_INITIAL (decl) == error_mark_node) ++ e = escape_via_global_var; ++ else ++ e = escape_type_volatile_array_or_ptrptr (TREE_TYPE (decl)); ++ ++ if (e != does_not_escape) ++ type->mark_escape (e, NULL); ++ } ++ ++ /* Record the initial usage of variables as types escapes. */ ++ if (TREE_CODE (decl) != SSA_NAME && TREE_STATIC (decl) && DECL_INITIAL (decl)) ++ { ++ walk_tree_without_duplicates (&DECL_INITIAL (decl), record_init_types, this); ++ if (!integer_zerop (DECL_INITIAL (decl)) ++ && DECL_INITIAL (decl) != error_mark_node) ++ mark_type_as_escape (TREE_TYPE (decl), escape_via_global_init); ++ } ++ return sd; ++} ++ ++/* Find void* ssa_names which are used inside MEM[] or if we have &a.c, ++ mark the type as escaping. */ ++ ++void ++ipa_struct_reorg::find_var (tree expr, gimple *stmt) ++{ ++ /* If we have VCE<a> mark the outer type as escaping and the inner one ++ Also mark the inner most operand. */ ++ if (TREE_CODE (expr) == VIEW_CONVERT_EXPR) ++ { ++ mark_type_as_escape (TREE_TYPE (expr), escape_vce, stmt); ++ mark_type_as_escape (TREE_TYPE (TREE_OPERAND (expr, 0)), ++ escape_vce, stmt); ++ } ++ ++ /* If we have &b.c then we need to mark the type of b ++ as escaping as tracking a will be hard. */ ++ if (TREE_CODE (expr) == ADDR_EXPR ++ || TREE_CODE (expr) == VIEW_CONVERT_EXPR) ++ { ++ tree r = TREE_OPERAND (expr, 0); ++ if (handled_component_p (r) ++ || TREE_CODE (r) == MEM_REF) ++ { ++ while (handled_component_p (r) ++ || TREE_CODE (r) == MEM_REF) ++ { ++ if (TREE_CODE (r) == VIEW_CONVERT_EXPR) ++ { ++ mark_type_as_escape (TREE_TYPE (r), escape_vce, stmt); ++ mark_type_as_escape (TREE_TYPE (TREE_OPERAND (r, 0)), ++ escape_vce, stmt); ++ } ++ if (TREE_CODE (r) == MEM_REF) ++ mark_type_as_escape (TREE_TYPE (TREE_OPERAND (r, 1)), ++ escape_addr, stmt); ++ r = TREE_OPERAND (r, 0); ++ } ++ mark_expr_escape (r, escape_addr, stmt); ++ } ++ } ++ ++ tree base; ++ bool indirect; ++ srtype *type; ++ srfield *field; ++ bool realpart, imagpart, address; ++ get_type_field (expr, base, indirect, type, field, ++ realpart, imagpart, address, true, true); ++} ++ ++ ++void ++ipa_struct_reorg::find_vars (gimple *stmt) ++{ ++ gasm *astmt; ++ switch (gimple_code (stmt)) ++ { ++ case GIMPLE_ASSIGN: ++ if (gimple_assign_rhs_class (stmt) == GIMPLE_SINGLE_RHS ++ || gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) ++ { ++ tree lhs = gimple_assign_lhs (stmt); ++ tree rhs = gimple_assign_rhs1 (stmt); ++ find_var (gimple_assign_lhs (stmt), stmt); ++ find_var (gimple_assign_rhs1 (stmt), stmt); ++ if (TREE_CODE (lhs) == SSA_NAME ++ && VOID_POINTER_P (TREE_TYPE (lhs)) ++ && handled_type (TREE_TYPE (rhs))) ++ { ++ srtype *t = find_type (inner_type (TREE_TYPE (rhs))); ++ srdecl *d = find_decl (lhs); ++ if (!d && t) ++ current_function->record_decl (t, lhs, -1); ++ } ++ if (TREE_CODE (rhs) == SSA_NAME ++ && VOID_POINTER_P (TREE_TYPE (rhs)) ++ && handled_type (TREE_TYPE (lhs))) ++ { ++ srtype *t = find_type (inner_type (TREE_TYPE (lhs))); ++ srdecl *d = find_decl (rhs); ++ if (!d && t) ++ current_function->record_decl (t, rhs, -1); ++ } ++ } ++ break; ++ ++ case GIMPLE_CALL: ++ if (gimple_call_lhs (stmt)) ++ find_var (gimple_call_lhs (stmt), stmt); ++ ++ if (gimple_call_chain (stmt)) ++ find_var (gimple_call_chain (stmt), stmt); ++ ++ for (unsigned i = 0; i < gimple_call_num_args (stmt); i++) ++ find_var (gimple_call_arg (stmt, i), stmt); ++ break; ++ ++ case GIMPLE_ASM: ++ astmt = as_a <gasm*>(stmt); ++ for (unsigned i = 0; i < gimple_asm_ninputs (astmt); i++) ++ find_var (TREE_VALUE (gimple_asm_input_op (astmt, i)), stmt); ++ for (unsigned i = 0; i < gimple_asm_noutputs (astmt); i++) ++ find_var (TREE_VALUE (gimple_asm_output_op (astmt, i)), stmt); ++ mark_types_asm (astmt); ++ break; ++ ++ case GIMPLE_RETURN: ++ { ++ tree expr = gimple_return_retval (as_a<greturn*>(stmt)); ++ if (expr) ++ find_var (expr, stmt); ++ /* return &a; should mark the type of a as escaping through a return. */ ++ if (expr && TREE_CODE (expr) == ADDR_EXPR) ++ { ++ expr = TREE_OPERAND (expr, 0); ++ srdecl *d = find_decl (expr); ++ if (d) ++ d->type->mark_escape (escape_return, stmt); ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++/* Maybe record access of statement for further analaysis. */ ++ ++void ++ipa_struct_reorg::maybe_record_stmt (cgraph_node *node, gimple *stmt) ++{ ++ switch (gimple_code (stmt)) ++ { ++ case GIMPLE_ASSIGN: ++ maybe_record_assign (node, as_a <gassign *> (stmt)); ++ break; ++ case GIMPLE_CALL: ++ maybe_record_call (node, as_a <gcall *> (stmt)); ++ break; ++ case GIMPLE_DEBUG: ++ break; ++ case GIMPLE_GOTO: ++ case GIMPLE_SWITCH: ++ break; ++ default: ++ break; ++ } ++} ++ ++/* This function checks whether ARG is a result of multiplication ++ of some number by STRUCT_SIZE. If yes, the function returns true ++ and this number is filled into NUM. */ ++ ++static bool ++is_result_of_mult (tree arg, tree *num, tree struct_size) ++{ ++ if (!struct_size ++ || TREE_CODE (struct_size) != INTEGER_CST ++ || integer_zerop (struct_size)) ++ return false; ++ ++ /* If we have a integer, just check if it is a multiply of STRUCT_SIZE. */ ++ if (TREE_CODE (arg) == INTEGER_CST) ++ { ++ if (integer_zerop (size_binop (FLOOR_MOD_EXPR, arg, struct_size))) ++ { ++ *num = size_binop (FLOOR_DIV_EXPR, arg, struct_size); ++ return true; ++ } ++ return false; ++ } ++ gimple *size_def_stmt = SSA_NAME_DEF_STMT (arg); ++ ++ /* If the allocation statement was of the form ++ D.2229_10 = <alloc_func> (D.2228_9); ++ then size_def_stmt can be D.2228_9 = num.3_8 * 8; */ ++ ++ while (size_def_stmt && is_gimple_assign (size_def_stmt)) ++ { ++ tree lhs = gimple_assign_lhs (size_def_stmt); ++ ++ /* We expect temporary here. */ ++ if (!is_gimple_reg (lhs)) ++ return false; ++ ++ // FIXME: this should handle SHIFT also. ++ if (gimple_assign_rhs_code (size_def_stmt) == PLUS_EXPR) ++ { ++ tree num1, num2; ++ tree arg0 = gimple_assign_rhs1 (size_def_stmt); ++ tree arg1 = gimple_assign_rhs2 (size_def_stmt); ++ if (!is_result_of_mult (arg0, &num1, struct_size)) ++ return false; ++ if (!is_result_of_mult (arg1, &num2, struct_size)) ++ return false; ++ *num = size_binop (PLUS_EXPR, num1, num2); ++ return true; ++ } ++ if (gimple_assign_rhs_code (size_def_stmt) == MULT_EXPR) ++ { ++ tree arg0 = gimple_assign_rhs1 (size_def_stmt); ++ tree arg1 = gimple_assign_rhs2 (size_def_stmt); ++ tree num1; ++ ++ if (is_result_of_mult (arg0, &num1, struct_size)) ++ { ++ *num = size_binop (MULT_EXPR, arg1, num1); ++ return true; ++ } ++ if (is_result_of_mult (arg1, &num1, struct_size)) ++ { ++ *num = size_binop (MULT_EXPR, arg0, num1); ++ return true; ++ } ++ ++ *num = NULL_TREE; ++ return false; ++ } ++ else if (gimple_assign_rhs_code (size_def_stmt) == SSA_NAME) ++ { ++ arg = gimple_assign_rhs1 (size_def_stmt); ++ size_def_stmt = SSA_NAME_DEF_STMT (arg); ++ } ++ else ++ { ++ *num = NULL_TREE; ++ return false; ++ } ++ } ++ ++ *num = NULL_TREE; ++ return false; ++} ++ ++/* Return TRUE if STMT is an allocation statement that is handled. */ ++ ++static bool ++handled_allocation_stmt (gimple *stmt) ++{ ++ if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC) ++ || gimple_call_builtin_p (stmt, BUILT_IN_MALLOC) ++ || gimple_call_builtin_p (stmt, BUILT_IN_CALLOC) ++ || gimple_call_builtin_p (stmt, BUILT_IN_ALIGNED_ALLOC) ++ || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA) ++ || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA_WITH_ALIGN)) ++ return true; ++ return false; ++} ++ ++ ++/* Returns the allocated size / T size for STMT. That is the number of ++ elements in the array allocated. */ ++ ++tree ++ipa_struct_reorg::allocate_size (srtype *type, gimple *stmt) ++{ ++ if (!stmt ++ || gimple_code (stmt) != GIMPLE_CALL ++ || !handled_allocation_stmt (stmt)) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nNot a allocate statment:\n"); ++ print_gimple_stmt (dump_file, stmt, 0); ++ fprintf (dump_file, "\n"); ++ } ++ return NULL; ++ } ++ ++ if (type->has_escaped ()) ++ return NULL; ++ ++ tree struct_size = TYPE_SIZE_UNIT (type->type); ++ ++ tree size = gimple_call_arg (stmt, 0); ++ ++ if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC) ++ || gimple_call_builtin_p (stmt, BUILT_IN_ALIGNED_ALLOC)) ++ size = gimple_call_arg (stmt, 1); ++ else if (gimple_call_builtin_p (stmt, BUILT_IN_CALLOC)) ++ { ++ tree arg1; ++ arg1 = gimple_call_arg (stmt, 1); ++ /* Check that second argument is a constant equal to the size of structure. */ ++ if (operand_equal_p (arg1, struct_size, 0)) ++ return size; ++ /* Check that first argument is a constant equal to the size of structure. */ ++ if (operand_equal_p (size, struct_size, 0)) ++ return arg1; ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\ncalloc the correct size:\n"); ++ print_gimple_stmt (dump_file, stmt, 0); ++ fprintf (dump_file, "\n"); ++ } ++ return NULL; ++ } ++ ++ tree num; ++ if (!is_result_of_mult (size, &num, struct_size)) ++ return NULL; ++ ++ return num; ++ ++} ++ ++ ++void ++ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other, gimple *stmt) ++{ ++ gcc_assert (TREE_CODE (side) == SSA_NAME || TREE_CODE (side) == ADDR_EXPR); ++ srtype *type = NULL; ++ if (handled_type (TREE_TYPE (other))) ++ type = record_type (inner_type (TREE_TYPE (other))); ++ if (TREE_CODE (side) == ADDR_EXPR) ++ side = TREE_OPERAND (side, 0); ++ srdecl *d = find_decl (side); ++ if (!type) ++ { ++ if (!d) ++ return; ++ if (TREE_CODE (side) == SSA_NAME ++ && VOID_POINTER_P (TREE_TYPE (side))) ++ return; ++ d->type->mark_escape (escape_cast_another_ptr, stmt); ++ return; ++ } ++ ++ if (!d) ++ { ++ if (VOID_POINTER_P (TREE_TYPE (side)) ++ && TREE_CODE (side) == SSA_NAME) ++ current_function->record_decl (type, side, -1); ++ else ++ type->mark_escape (escape_cast_another_ptr, stmt); ++ } ++ else if (type != d->type) ++ { ++ type->mark_escape (escape_cast_another_ptr, stmt); ++ d->type->mark_escape (escape_cast_another_ptr, stmt); ++ } ++} ++ ++/* Record accesses in an assignment statement STMT. */ ++ ++void ++ipa_struct_reorg::maybe_record_assign (cgraph_node *node, gassign *stmt) ++{ ++ ++ /* */ ++ ++ if (gimple_clobber_p (stmt)) ++ { ++ record_stmt_expr (gimple_assign_lhs (stmt), node, stmt); ++ return; ++ } ++ ++ if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) ++ { ++ tree lhs = gimple_assign_lhs (stmt); ++ tree rhs1 = gimple_assign_rhs1 (stmt); ++ tree rhs2 = gimple_assign_rhs2 (stmt); ++ tree num; ++ if (!handled_type (TREE_TYPE (lhs))) ++ return; ++ /* Check if rhs2 is a multiplication of the size of the type. */ ++ if (is_result_of_mult (rhs2, &num, TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (lhs))))) ++ { ++ record_stmt_expr (lhs, node, stmt); ++ record_stmt_expr (rhs1, node, stmt); ++ } ++ else ++ { ++ mark_expr_escape (lhs, escape_non_multiply_size, stmt); ++ mark_expr_escape (rhs1, escape_non_multiply_size, stmt); ++ } ++ return; ++ } ++ /* Copies, References, Taking addresses. */ ++ if (gimple_assign_rhs_class (stmt) == GIMPLE_SINGLE_RHS) ++ { ++ tree lhs = gimple_assign_lhs (stmt); ++ tree rhs = gimple_assign_rhs1 (stmt); ++ /* If we have a = &b.c then we need to mark the type of b ++ as escaping as tracking a will be hard. */ ++ if (TREE_CODE (rhs) == ADDR_EXPR) ++ { ++ tree r = TREE_OPERAND (rhs, 0); ++ if (handled_component_p (r)) ++ { ++ while (handled_component_p (r)) ++ r = TREE_OPERAND (r, 0); ++ mark_expr_escape (r, escape_addr, stmt); ++ return; ++ } ++ } ++ if ((TREE_CODE (rhs) == SSA_NAME || TREE_CODE (rhs) == ADDR_EXPR)) ++ maybe_mark_or_record_other_side (rhs, lhs, stmt); ++ if (TREE_CODE (lhs) == SSA_NAME) ++ maybe_mark_or_record_other_side (lhs, rhs, stmt); ++ } ++} ++ ++tree ++get_ref_base_and_offset (tree &e, HOST_WIDE_INT &offset, bool &realpart, bool &imagpart, tree &accesstype) ++{ ++ offset = 0; ++ realpart = false; ++ imagpart = false; ++ accesstype = NULL_TREE; ++ if (TREE_CODE (e) == REALPART_EXPR) ++ { ++ e = TREE_OPERAND (e, 0); ++ realpart = true; ++ } ++ if (TREE_CODE (e) == IMAGPART_EXPR) ++ { ++ e = TREE_OPERAND (e, 0); ++ imagpart = true; ++ } ++ tree expr = e; ++ while (true) ++ { ++ switch (TREE_CODE (expr)) ++ { ++ case COMPONENT_REF: ++ { ++ tree field = TREE_OPERAND (expr, 1); ++ tree field_off = byte_position (field); ++ if (TREE_CODE (field_off) != INTEGER_CST) ++ return NULL; ++ offset += tree_to_shwi (field_off); ++ expr = TREE_OPERAND (expr, 0); ++ accesstype = NULL; ++ break; ++ } ++ case MEM_REF: ++ { ++ tree field_off = TREE_OPERAND (expr, 1); ++ gcc_assert (TREE_CODE (field_off) == INTEGER_CST); ++ /* So we can mark the types as escaping if different. */ ++ accesstype = TREE_TYPE (field_off); ++ offset += tree_to_uhwi (field_off); ++ return TREE_OPERAND (expr, 0); ++ } ++ default: ++ return expr; ++ } ++ } ++} ++ ++/* Return true if EXPR was accessing the whole type T. */ ++ ++bool ++ipa_struct_reorg::wholeaccess (tree expr, tree base, tree accesstype, srtype *t) ++{ ++ if (expr == base) ++ return true; ++ ++ if (TREE_CODE (expr) == ADDR_EXPR && TREE_OPERAND (expr, 0) == base) ++ return true; ++ ++ if (!accesstype) ++ return false; ++ ++ if (!types_compatible_p (TREE_TYPE (expr), TREE_TYPE (accesstype))) ++ return false; ++ ++ if (!handled_type (TREE_TYPE (expr))) ++ return false; ++ ++ srtype *other_type = find_type (inner_type (TREE_TYPE (expr))); ++ ++ if (t == other_type) ++ return true; ++ ++ return false; ++} ++ ++bool ++ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, srtype *&type, srfield *&field, bool &realpart, bool &imagpart, bool &address, bool should_create, bool can_escape) ++{ ++ HOST_WIDE_INT offset; ++ tree accesstype; ++ address = false; ++ bool mark_as_bit_field = false; ++ ++ if (TREE_CODE (expr) == BIT_FIELD_REF) ++ { ++ expr = TREE_OPERAND (expr, 0); ++ mark_as_bit_field = true; ++ } ++ ++ base = get_ref_base_and_offset (expr, offset, realpart, imagpart, accesstype); ++ ++ /* Variable access, unkown type. */ ++ if (base == NULL) ++ return false; ++ ++ if (TREE_CODE (base) == ADDR_EXPR) ++ { ++ address = true; ++ base = TREE_OPERAND (base, 0); ++ } ++ ++ if (offset != 0 && accesstype) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "Non zero offset (%d) with MEM.\n", (int)offset); ++ print_generic_expr (dump_file, expr); ++ fprintf (dump_file, "\n"); ++ print_generic_expr (dump_file, base); ++ fprintf (dump_file, "\n"); ++ } ++ } ++ ++ srdecl *d = find_decl (base); ++ srtype *t; ++ ++ if (integer_zerop (base)) ++ { ++ gcc_assert (!d); ++ if (!accesstype) ++ return false; ++ t = find_type (inner_type (inner_type (accesstype))); ++ if (!t && should_create && handled_type (accesstype)) ++ t = record_type (inner_type (accesstype)); ++ if (!t) ++ return false; ++ } ++ else if (!d && accesstype) ++ { ++ if (!should_create) ++ return false; ++ if (!handled_type (accesstype)) ++ return false; ++ t = find_type (inner_type (inner_type (accesstype))); ++ if (!t) ++ t = record_type (inner_type (accesstype)); ++ if (!t || t->has_escaped ()) ++ return false; ++ /* If base is not void* mark the type as escaping. */ ++ if (!VOID_POINTER_P (TREE_TYPE (base))) ++ { ++ gcc_assert (can_escape); ++ t->mark_escape (escape_cast_another_ptr, NULL); ++ return false; ++ } ++ if (TREE_CODE (base) == SSA_NAME) ++ current_function->record_decl (t, base, -1); ++ } ++ else if (!d) ++ return false; ++ else ++ t = d->type; ++ ++ if (t->has_escaped ()) ++ return false; ++ ++ if (mark_as_bit_field) ++ { ++ gcc_assert (can_escape); ++ t->mark_escape (escape_bitfields, NULL); ++ return false; ++ } ++ ++ if (wholeaccess (expr, base, accesstype, t)) ++ { ++ field = NULL; ++ type = t; ++ indirect = accesstype != NULL; ++ return true; ++ } ++ ++ srfield *f = t->find_field (offset); ++ if (!f) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nunkown field\n"); ++ print_generic_expr (dump_file, expr); ++ fprintf (dump_file, "\n"); ++ print_generic_expr (dump_file, base); ++ fprintf (dump_file, "\n"); ++ } ++ gcc_assert (can_escape); ++ t->mark_escape (escape_unkown_field, NULL); ++ return false; ++ } ++ if (!types_compatible_p (f->fieldtype, TREE_TYPE (expr))) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nfieldtype = "); ++ print_generic_expr (dump_file, f->fieldtype); ++ fprintf (dump_file, "\naccess type = "); ++ print_generic_expr (dump_file, TREE_TYPE (expr)); ++ fprintf (dump_file, "original expr = "); ++ print_generic_expr (dump_file, expr); ++ fprintf (dump_file, "\n"); ++ } ++ gcc_assert (can_escape); ++ t->mark_escape (escape_unkown_field, NULL); ++ return false; ++ } ++ field = f; ++ type = t; ++ indirect = accesstype != NULL; ++ return true; ++} ++ ++/* Mark the type used in EXPR as escaping. */ ++ ++void ++ipa_struct_reorg::mark_expr_escape (tree expr, escape_type escapes, gimple *stmt) ++{ ++ tree base; ++ bool indirect; ++ srtype *type; ++ srfield *field; ++ bool realpart, imagpart, address; ++ if (!get_type_field (expr, base, indirect, type, field, realpart, imagpart, address)) ++ return; ++ ++ type->mark_escape (escapes, stmt); ++} ++ ++/* Record accesses in a call statement STMT. */ ++ ++void ++ipa_struct_reorg::maybe_record_call (cgraph_node *node, gcall *stmt) ++{ ++ tree argtype; ++ tree fndecl; ++ escape_type escapes = does_not_escape; ++ bool free_or_realloc = gimple_call_builtin_p (stmt, BUILT_IN_FREE) ++ || gimple_call_builtin_p (stmt, BUILT_IN_REALLOC); ++ ++ /* We check allocation sites in a different location. */ ++ if (handled_allocation_stmt (stmt)) ++ return; ++ ++ ++ /* A few cases here: ++ 1) assigned from the lhs ++ 2) Used in argument ++ If a function being called is global (or indirect) ++ then we reject the types as being escaping. */ ++ ++ if (tree chain = gimple_call_chain (stmt)) ++ record_stmt_expr (chain, node, stmt); ++ ++ /* Assigned from LHS. */ ++ if (tree lhs = gimple_call_lhs (stmt)) ++ { ++ /* FIXME: handle return types.. */ ++ mark_type_as_escape (TREE_TYPE (lhs), escape_return); ++ } ++ ++ /* If we have an internal call, just record the stmt. */ ++ if (gimple_call_internal_p (stmt)) ++ { ++ for (unsigned i = 0; i < gimple_call_num_args (stmt); i++) ++ record_stmt_expr (gimple_call_arg (stmt, i), node, stmt); ++ return; ++ } ++ ++ fndecl = gimple_call_fndecl (stmt); ++ ++ /* If we have an indrect call, just mark the types as escape. */ ++ if (!fndecl) ++ escapes = escape_pointer_function; ++ /* Non local functions cause escape except for calls to free ++ and realloc. ++ FIXME: should support function annotations too. */ ++ else if (!free_or_realloc ++ && !cgraph_node::local_info_node (fndecl)->local) ++ escapes = escape_external_function; ++ else if (!free_or_realloc ++ && !cgraph_node::local_info_node (fndecl)->can_change_signature) ++ escapes = escape_cannot_change_signature; ++ /* FIXME: we should be able to handle functions in other partitions. */ ++ else if (symtab_node::get(fndecl)->in_other_partition) ++ escapes = escape_external_function; ++ ++ if (escapes != does_not_escape) ++ { ++ for (unsigned i = 0; i < gimple_call_num_args (stmt); i++) ++ mark_type_as_escape (TREE_TYPE (gimple_call_arg (stmt, i)), ++ escapes); ++ return; ++ } ++ ++ argtype = TYPE_ARG_TYPES (gimple_call_fntype (stmt)); ++ for (unsigned i = 0; i < gimple_call_num_args (stmt); i++) ++ { ++ tree arg = gimple_call_arg (stmt, i); ++ if (argtype) ++ { ++ tree argtypet = TREE_VALUE (argtype); ++ if (!free_or_realloc ++ && VOID_POINTER_P (argtypet)) ++ mark_type_as_escape (TREE_TYPE (arg), escape_cast_void); ++ else ++ record_stmt_expr (arg, node, stmt); ++ } ++ else ++ mark_type_as_escape (TREE_TYPE (arg), escape_var_arg_function); ++ ++ argtype = argtype ? TREE_CHAIN (argtype) : NULL_TREE; ++ } ++ ++} ++ ++ ++void ++ipa_struct_reorg::record_stmt_expr (tree expr, cgraph_node *node, gimple *stmt) ++{ ++ tree base; ++ bool indirect; ++ srtype *type; ++ srfield *field; ++ bool realpart, imagpart, address; ++ if (!get_type_field (expr, base, indirect, type, field, realpart, imagpart, address)) ++ return; ++ ++ if (!opt_for_fn (current_function_decl, flag_ipa_struct_reorg)) ++ type->mark_escape (escape_non_optimize, stmt); ++ ++ /* Record it. */ ++ type->add_access (new sraccess (stmt, node, type, field)); ++} ++ ++/* Find function corresponding to NODE. */ ++ ++srfunction * ++ipa_struct_reorg::find_function (cgraph_node *node) ++{ ++ for (unsigned i = 0; i < functions.length (); i++) ++ if (functions[i]->node == node) ++ return functions[i]; ++ return NULL; ++} ++ ++void ++ipa_struct_reorg::check_type_and_push (tree newdecl, srtype *type, vec<srdecl*> &worklist, gimple *stmt) ++{ ++ if (integer_zerop (newdecl)) ++ return; ++ ++ if (TREE_CODE (newdecl) == ADDR_EXPR) ++ { ++ srdecl *d = find_decl (TREE_OPERAND (newdecl, 0)); ++ if (!d) ++ { ++ type->mark_escape (escape_cast_another_ptr, stmt); ++ return; ++ } ++ if (d->type == type) ++ return; ++ ++ srtype *type1 = d->type; ++ type->mark_escape (escape_cast_another_ptr, stmt); ++ type1->mark_escape (escape_cast_another_ptr, stmt); ++ return; ++ } ++ ++ srdecl *d = find_decl (newdecl); ++ if (!d) ++ { ++ if (TREE_CODE (newdecl) == INTEGER_CST) ++ { ++ type->mark_escape (escape_int_const, stmt); ++ return; ++ } ++ /* If we have a non void* or a decl (which is hard to track), ++ then mark the type as escaping. */ ++ if (!VOID_POINTER_P (TREE_TYPE (newdecl)) ++ || DECL_P (newdecl)) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nunkown decl: "); ++ print_generic_expr (dump_file, newdecl); ++ fprintf (dump_file, " in type:\n"); ++ print_generic_expr (dump_file, TREE_TYPE (newdecl)); ++ fprintf (dump_file, "\n"); ++ } ++ type->mark_escape (escape_cast_another_ptr, stmt); ++ return; ++ } ++ /* At this point there should only be unkown void* ssa names. */ ++ gcc_assert (TREE_CODE (newdecl) == SSA_NAME); ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nrecording unkown decl: "); ++ print_generic_expr (dump_file, newdecl); ++ fprintf (dump_file, " as type:\n"); ++ type->simple_dump (dump_file); ++ fprintf (dump_file, "\n"); ++ } ++ d = current_function->record_decl (type, newdecl, -1); ++ worklist.safe_push (d); ++ return; ++ } ++ ++ /* Only add to the worklist if the decl is a SSA_NAME. */ ++ if (TREE_CODE (newdecl) == SSA_NAME) ++ worklist.safe_push (d); ++ if (d->type == type) ++ return; ++ ++ srtype *type1 = d->type; ++ type->mark_escape (escape_cast_another_ptr, stmt); ++ type1->mark_escape (escape_cast_another_ptr, stmt); ++ ++} ++ ++/* ++ 2) Check SSA_NAMEs for non type usages (source or use) (worlist of srdecl) ++ a) if the SSA_NAME is sourced from a pointer plus, record the pointer and ++ check to make sure the addition was a multiple of the size. ++ check the pointer type too. ++ b) If the name is sourced from an allocation check the allocation ++ i) Add SSA_NAME (void*) to the worklist if allocated from realloc ++ c) if the name is from a param, make sure the param type was of the original type ++ d) if the name is from a cast/assignment, make sure it is used as that type or void* ++ i) If void* then push the ssa_name into worklist ++*/ ++void ++ipa_struct_reorg::check_definition (srdecl *decl, vec<srdecl*> &worklist) ++{ ++ tree ssa_name = decl->decl; ++ srtype *type = decl->type; ++ ++ /* c) if the name is from a param, make sure the param type was ++ of the original type */ ++ if (SSA_NAME_IS_DEFAULT_DEF (ssa_name)) ++ { ++ tree var = SSA_NAME_VAR (ssa_name); ++ if (var ++ && TREE_CODE (var) == PARM_DECL ++ && VOID_POINTER_P (TREE_TYPE (ssa_name))) ++ type->mark_escape (escape_cast_void, NULL); ++ return; ++ } ++ gimple *stmt = SSA_NAME_DEF_STMT (ssa_name); ++ ++ /* ++ b) If the name is sourced from an allocation check the allocation ++ i) Add SSA_NAME (void*) to the worklist if allocated from realloc ++ */ ++ if (gimple_code (stmt) == GIMPLE_CALL) ++ { ++ /* For realloc, check the type of the argument. */ ++ if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC)) ++ check_type_and_push (gimple_call_arg (stmt, 0), type, worklist, stmt); ++ ++ if (!handled_allocation_stmt (stmt) ++ || !allocate_size (type, stmt)) ++ type->mark_escape (escape_return, stmt); ++ return; ++ } ++ /* If the SSA_NAME is sourced from an inline-asm, just mark the type as escaping. */ ++ if (gimple_code (stmt) == GIMPLE_ASM) ++ { ++ type->mark_escape (escape_inline_asm, stmt); ++ return; ++ } ++ ++ /* If the SSA_NAME is sourced from a PHI check add each name to the worklist and ++ check to make sure they are used correctly. */ ++ if (gimple_code (stmt) == GIMPLE_PHI) ++ { ++ for (unsigned i = 0; i < gimple_phi_num_args (stmt); i++) ++ check_type_and_push (gimple_phi_arg_def (stmt, i), type, worklist, stmt); ++ return; ++ } ++ ++ gcc_assert (gimple_code (stmt) == GIMPLE_ASSIGN); ++ /* ++ a) if the SSA_NAME is sourced from a pointer plus, record the pointer and ++ check to make sure the addition was a multiple of the size. ++ check the pointer type too. ++ */ ++ ++ tree rhs = gimple_assign_rhs1 (stmt); ++ if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) ++ { ++ tree rhs2 = gimple_assign_rhs2 (stmt); ++ tree num; ++ if (!is_result_of_mult (rhs2, &num, TYPE_SIZE_UNIT (type->type))) ++ type->mark_escape (escape_non_multiply_size, stmt); ++ ++ if (TREE_CODE (rhs) == SSA_NAME) ++ check_type_and_push (rhs, type, worklist, stmt); ++ return; ++ } ++ ++ /* Casts between pointers and integer are escaping. */ ++ if (gimple_assign_cast_p (stmt)) ++ { ++ type->mark_escape (escape_cast_int, stmt); ++ return; ++ } ++ ++ /* ++ d) if the name is from a cast/assignment, make sure it is used as that type or void* ++ i) If void* then push the ssa_name into worklist ++ */ ++ gcc_assert (gimple_assign_single_p (stmt)); ++ check_other_side (decl, rhs, stmt, worklist); ++} ++ ++/* Mark the types used by the inline-asm as escaping. It is unkown what happens inside ++ an inline-asm. */ ++ ++void ++ipa_struct_reorg::mark_types_asm (gasm *astmt) ++{ ++ for (unsigned i = 0; i < gimple_asm_ninputs (astmt); i++) ++ { ++ tree v = TREE_VALUE (gimple_asm_input_op (astmt, i)); ++ /* If we have &b, just strip the & here. */ ++ if (TREE_CODE (v) == ADDR_EXPR) ++ v = TREE_OPERAND (v, 0); ++ mark_expr_escape (v, escape_inline_asm, astmt); ++ } ++ for (unsigned i = 0; i < gimple_asm_noutputs (astmt); i++) ++ { ++ tree v = TREE_VALUE (gimple_asm_output_op (astmt, i)); ++ /* If we have &b, just strip the & here. */ ++ if (TREE_CODE (v) == ADDR_EXPR) ++ v = TREE_OPERAND (v, 0); ++ mark_expr_escape (v, escape_inline_asm, astmt); ++ } ++} ++ ++void ++ipa_struct_reorg::check_other_side (srdecl *decl, tree other, gimple *stmt, vec<srdecl*> &worklist) ++{ ++ srtype *type = decl->type; ++ ++ if (TREE_CODE (other) == SSA_NAME ++ || DECL_P (other) ++ || TREE_CODE (other) == INTEGER_CST) ++ { ++ check_type_and_push (other, type, worklist, stmt); ++ return; ++ } ++ ++ tree t = TREE_TYPE (other); ++ if (!handled_type (t)) ++ { ++ type->mark_escape (escape_cast_another_ptr, stmt); ++ return; ++ } ++ ++ srtype *t1 = find_type (inner_type (t)); ++ if (t1 == type) ++ { ++ tree base; ++ bool indirect; ++ srtype *type1; ++ srfield *field; ++ bool realpart, imagpart, address; ++ if (!get_type_field (other, base, indirect, type1, field, realpart, imagpart, address)) ++ type->mark_escape (escape_cast_another_ptr, stmt); ++ ++ return; ++ } ++ ++ if (t1) ++ t1->mark_escape (escape_cast_another_ptr, stmt); ++ ++ type->mark_escape (escape_cast_another_ptr, stmt); ++} ++ ++ ++void ++ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist) ++{ ++ srtype *type = decl->type; ++ ++ if (gimple_code (stmt) == GIMPLE_RETURN) ++ { ++ type->mark_escape (escape_return, stmt); ++ return; ++ } ++ /* If the SSA_NAME PHI check and add the src to the worklist and ++ check to make sure they are used correctly. */ ++ if (gimple_code (stmt) == GIMPLE_PHI) ++ { ++ check_type_and_push (gimple_phi_result (stmt), type, worklist, stmt); ++ return; ++ } ++ ++ if (gimple_code (stmt) == GIMPLE_ASM) ++ { ++ mark_types_asm (as_a <gasm*>(stmt)); ++ return; ++ } ++ ++ if (gimple_code (stmt) == GIMPLE_COND) ++ { ++ tree rhs1 = gimple_cond_lhs (stmt); ++ tree rhs2 = gimple_cond_rhs (stmt); ++ tree orhs = rhs1; ++ if (gimple_cond_code (stmt) != EQ_EXPR ++ && gimple_cond_code (stmt) != NE_EXPR) ++ { ++ mark_expr_escape (rhs1, escape_non_eq, stmt); ++ mark_expr_escape (rhs2, escape_non_eq, stmt); ++ } ++ if (rhs1 == decl->decl) ++ orhs = rhs2; ++ if (integer_zerop (orhs)) ++ return; ++ if (TREE_CODE (orhs) != SSA_NAME) ++ mark_expr_escape (rhs1, escape_non_eq, stmt); ++ check_type_and_push (orhs, type, worklist, stmt); ++ return; ++ } ++ ++ ++ /* Casts between pointers and integer are escaping. */ ++ if (gimple_assign_cast_p (stmt)) ++ { ++ type->mark_escape (escape_cast_int, stmt); ++ return; ++ } ++ ++ /* We might have a_1 = ptr_2 == ptr_3; */ ++ if (is_gimple_assign (stmt) ++ && TREE_CODE_CLASS (gimple_assign_rhs_code (stmt)) == tcc_comparison) ++ { ++ tree rhs1 = gimple_assign_rhs1 (stmt); ++ tree rhs2 = gimple_assign_rhs2 (stmt); ++ tree orhs = rhs1; ++ if (gimple_assign_rhs_code (stmt) != EQ_EXPR ++ && gimple_assign_rhs_code (stmt) != NE_EXPR) ++ { ++ mark_expr_escape (rhs1, escape_non_eq, stmt); ++ mark_expr_escape (rhs2, escape_non_eq, stmt); ++ } ++ if (rhs1 == decl->decl) ++ orhs = rhs2; ++ if (integer_zerop (orhs)) ++ return; ++ if (TREE_CODE (orhs) != SSA_NAME) ++ mark_expr_escape (rhs1, escape_non_eq, stmt); ++ check_type_and_push (orhs, type, worklist, stmt); ++ return; ++ } ++ ++ if (gimple_assign_single_p (stmt)) ++ { ++ tree lhs = gimple_assign_lhs (stmt); ++ tree rhs = gimple_assign_rhs1 (stmt); ++ /* Check if we have a_1 = b_2; that a_1 is in the correct type. */ ++ if (decl->decl == rhs) ++ { ++ check_other_side (decl, lhs, stmt, worklist); ++ return; ++ } ++ } ++ ++ if (is_gimple_assign (stmt) ++ && gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) ++ { ++ tree rhs2 = gimple_assign_rhs2 (stmt); ++ tree lhs = gimple_assign_lhs (stmt); ++ tree num; ++ check_other_side (decl, lhs, stmt, worklist); ++ if (!is_result_of_mult (rhs2, &num, TYPE_SIZE_UNIT (type->type))) ++ type->mark_escape (escape_non_multiply_size, stmt); ++ } ++ ++} ++ ++/* ++ 2) Check SSA_NAMEs for non type usages (source or use) (worlist of srdecl) ++ d) if the name is used in a cast/assignment, make sure it is used as that type or void* ++ i) If void* then push the ssa_name into worklist ++ e) if used in conditional check the other side ++ i) If the conditional is non NE/EQ then mark the type as non rejecting ++ f) Check if the use in a Pointer PLUS EXPR Is used by mulitplication of its size ++ */ ++void ++ipa_struct_reorg::check_uses (srdecl *decl, vec<srdecl*> &worklist) ++{ ++ tree ssa_name = decl->decl; ++ imm_use_iterator imm_iter; ++ use_operand_p use_p; ++ ++ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, ssa_name) ++ { ++ gimple *stmt = USE_STMT (use_p); ++ ++ if (is_gimple_debug (stmt)) ++ continue; ++ ++ check_use (decl, stmt, worklist); ++ } ++} ++ ++/* Record function corresponding to NODE. */ ++ ++srfunction * ++ipa_struct_reorg::record_function (cgraph_node *node) ++{ ++ function *fn; ++ tree parm, var; ++ unsigned int i; ++ srfunction *sfn; ++ escape_type escapes = does_not_escape; ++ ++ sfn = new srfunction (node); ++ functions.safe_push (sfn); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "\nRecording accesses and types from function: %s/%u\n", ++ node->name (), node->order); ++ ++ /* Nodes without a body are not interesting. Especially do not ++ visit clones at this point for now - we get duplicate decls ++ there for inline clones at least. */ ++ if (!node->has_gimple_body_p () || node->inlined_to) ++ return sfn; ++ ++ node->get_body (); ++ fn = DECL_STRUCT_FUNCTION (node->decl); ++ ++ if (!fn) ++ return sfn; ++ ++ current_function = sfn; ++ ++ if (DECL_PRESERVE_P (node->decl)) ++ escapes = escape_marked_as_used; ++ else if (!node->local) ++ escapes = escape_visible_function; ++ else if (!node->can_change_signature) ++ escapes = escape_cannot_change_signature; ++ else if (!tree_versionable_function_p (node->decl)) ++ escapes = escape_noclonable_function; ++ else if (!opt_for_fn (node->decl, flag_ipa_struct_reorg)) ++ escapes = escape_non_optimize; ++ ++ basic_block bb; ++ gimple_stmt_iterator si; ++ ++ /* Record the static chain decl. */ ++ if (fn->static_chain_decl) ++ { ++ srdecl *sd = record_var (fn->static_chain_decl, ++ escapes, ++ -2); ++ if (sd) ++ { ++ /* Specify that this type is used by the static ++ chain so it cannot be split. */ ++ sd->type->chain_type = true; ++ sfn->add_arg (sd); ++ sd->type->add_function (sfn); ++ } ++ } ++ ++ /* Record the arguments. */ ++ for (parm = DECL_ARGUMENTS (node->decl), i = 0; ++ parm; ++ parm = DECL_CHAIN (parm), i++) ++ { ++ srdecl *sd = record_var (parm, escapes, i); ++ if (sd) ++ { ++ sfn->add_arg (sd); ++ sd->type->add_function (sfn); ++ } ++ } ++ ++ /* Mark the return type as escaping */ ++ { ++ tree return_type = TREE_TYPE (TREE_TYPE (node->decl)); ++ mark_type_as_escape (return_type, escape_return, NULL); ++ } ++ ++ /* If the cfg does not exist for the function, don't process the function. */ ++ if (!fn->cfg) ++ { ++ current_function = NULL; ++ return sfn; ++ } ++ ++ /* The following order is done for recording stage: ++ 0) Record all variables/SSA_NAMES that are of struct type ++ 1) Record MEM_REF/COMPONENT_REFs ++ a) Record SSA_NAMEs (void*) and record that as the accessed type. ++ */ ++ ++ push_cfun (fn); ++ ++ FOR_EACH_LOCAL_DECL (cfun, i, var) ++ { ++ if (TREE_CODE (var) != VAR_DECL) ++ continue; ++ ++ record_var (var); ++ } ++ ++ for (i = 1; i < num_ssa_names; ++i) ++ { ++ tree name = ssa_name (i); ++ if (!name ++ || has_zero_uses (name) ++ || virtual_operand_p (name)) ++ continue; ++ ++ record_var (name); ++ } ++ ++ /* Find the variables which are used via MEM_REF and are void* types. */ ++ FOR_EACH_BB_FN (bb, cfun) ++ { ++ for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si)) ++ { ++ gimple *stmt = gsi_stmt (si); ++ find_vars (stmt); ++ } ++ } ++ ++ auto_vec<srdecl *> worklist; ++ for (unsigned i = 0; i < current_function->decls.length (); i++) ++ { ++ srdecl *decl = current_function->decls[i]; ++ if (TREE_CODE (decl->decl) == SSA_NAME) ++ { ++ decl->visited = false; ++ worklist.safe_push (decl); ++ } ++ } ++ ++ /* ++ 2) Check SSA_NAMEs for non type usages (source or use) (worlist of srdecl) ++ a) if the SSA_NAME is sourced from a pointer plus, record the pointer and ++ check to make sure the addition was a multiple of the size. ++ check the pointer type too. ++ b) If the name is sourced from an allocation check the allocation ++ i) Add SSA_NAME (void*) to the worklist if allocated from realloc ++ c) if the name is from a param, make sure the param type was of the original type ++ d) if the name is used in a cast/assignment, make sure it is used as that type or void* ++ i) If void* then push the ssa_name into worklist ++ e) if used in conditional check the other side ++ i) If the conditional is non NE/EQ then mark the type as non rejecting ++ f) Check if the use in a POinter PLUS EXPR Is used by mulitplication of its size ++ */ ++ ++ while (!worklist.is_empty ()) ++ { ++ srdecl *decl = worklist.pop (); ++ if (decl->visited) ++ continue; ++ decl->visited = true; ++ check_definition (decl, worklist); ++ check_uses (decl, worklist); ++ } ++ ++ FOR_EACH_BB_FN (bb, cfun) ++ { ++ for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si)) ++ { ++ gimple *stmt = gsi_stmt (si); ++ maybe_record_stmt (node, stmt); ++ } ++ } ++ ++ pop_cfun (); ++ current_function = NULL; ++ return sfn; ++} ++ ++ ++/* Record all accesses for all types including global variables. */ ++ ++void ++ipa_struct_reorg::record_accesses (void) ++{ ++ varpool_node *var; ++ cgraph_node *cnode; ++ ++ /* Record global (non-auto) variables first. */ ++ FOR_EACH_VARIABLE (var) ++ { ++ if (!var->real_symbol_p ()) ++ continue; ++ ++ /* Record all variables including the accesses inside a variable. */ ++ escape_type escapes = does_not_escape; ++ if (var->externally_visible || !var->definition) ++ escapes = escape_via_global_var; ++ if (var->in_other_partition) ++ escapes = escape_via_global_var; ++ if (!var->externally_visible && var->definition) ++ var->get_constructor (); ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "Recording global variable: "); ++ print_generic_expr (dump_file, var->decl); ++ fprintf (dump_file, "\n"); ++ } ++ record_var (var->decl, escapes); ++ } ++ ++ FOR_EACH_FUNCTION (cnode) ++ { ++ if (!cnode->real_symbol_p ()) ++ continue; ++ ++ /* Record accesses inside a function. */ ++ if(cnode->definition) ++ record_function (cnode); ++ } ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "all types (before pruning):\n"); ++ dump_types (dump_file); ++ fprintf (dump_file, "all functions (before pruning):\n"); ++ dump_functions (dump_file); ++ } ++ done_recording = true; ++} ++ ++/* A helper function to detect cycles (recusive) types. ++ Return TRUE if TYPE was a rescusive type. */ ++ ++bool ++ipa_struct_reorg::walk_field_for_cycles (srtype *type) ++{ ++ unsigned i; ++ srfield *field; ++ ++ type->visited = true; ++ if (type->escaped_rescusive ()) ++ return true; ++ ++ if (type->has_escaped ()) ++ return false; ++ ++ FOR_EACH_VEC_ELT (type->fields, i, field) ++ { ++ if (!field->type) ++ ; ++ else if (field->type->visited ++ || walk_field_for_cycles (field->type)) ++ { ++ type->mark_escape (escape_rescusive_type, NULL); ++ return true; ++ } ++ } ++ ++ return false; ++} ++ ++/* Clear visited on all types. */ ++ ++void ++ipa_struct_reorg::clear_visited (void) ++{ ++ for (unsigned i = 0; i < types.length (); i++) ++ types[i]->visited = false; ++} ++ ++/* Detect recusive types and mark them as escaping. */ ++ ++void ++ipa_struct_reorg::detect_cycles (void) ++{ ++ for (unsigned i = 0; i < types.length (); i++) ++ { ++ if (types[i]->has_escaped ()) ++ continue; ++ ++ clear_visited (); ++ walk_field_for_cycles (types[i]); ++ } ++} ++ ++/* Propagate escaping to depdenent types. */ ++ ++void ++ipa_struct_reorg::propagate_escape (void) ++{ ++ ++ unsigned i; ++ srtype *type; ++ bool changed = false; ++ ++ do ++ { ++ changed = false; ++ FOR_EACH_VEC_ELT (types, i, type) ++ { ++ for (tree field = TYPE_FIELDS (type->type); ++ field; ++ field = DECL_CHAIN (field)) ++ { ++ if (TREE_CODE (field) == FIELD_DECL ++ && handled_type (TREE_TYPE (field))) ++ { ++ tree t = inner_type (TREE_TYPE (field)); ++ srtype *type1 = find_type (t); ++ if (!type1) ++ continue; ++ if (type1->has_escaped () ++ && !type->has_escaped ()) ++ { ++ type->mark_escape (escape_dependent_type_escapes, NULL); ++ changed = true; ++ } ++ if (type->has_escaped () ++ && !type1->has_escaped ()) ++ { ++ type1->mark_escape (escape_dependent_type_escapes, NULL); ++ changed = true; ++ } ++ } ++ } ++ } ++ } while (changed); ++} ++ ++/* Prune the escaped types and their decls from what was recorded. */ ++ ++void ++ipa_struct_reorg::prune_escaped_types (void) ++{ ++ detect_cycles (); ++ propagate_escape (); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "all types (after prop but before pruning):\n"); ++ dump_types (dump_file); ++ fprintf (dump_file, "all functions (after prop but before pruning):\n"); ++ dump_functions (dump_file); ++ } ++ ++ if (dump_file) ++ dump_types_escaped (dump_file); ++ ++ ++ /* Prune the function arguments which escape ++ and functions which have no types as arguments. */ ++ for (unsigned i = 0; i < functions.length (); ) ++ { ++ srfunction *function = functions[i]; ++ ++ /* Prune function arguments of types that escape. */ ++ for (unsigned j = 0; j < function->args.length ();) ++ { ++ if (function->args[j]->type->has_escaped ()) ++ function->args.ordered_remove (j); ++ else ++ j++; ++ } ++ ++ /* Prune global variables that the function uses of types that escape. */ ++ for (unsigned j = 0; j < function->globals.length ();) ++ { ++ if (function->globals[j]->type->has_escaped ()) ++ function->globals.ordered_remove (j); ++ else ++ j++; ++ } ++ ++ /* Prune variables that the function uses of types that escape. */ ++ for (unsigned j = 0; j < function->decls.length ();) ++ { ++ srdecl *decl = function->decls[j]; ++ if (decl->type->has_escaped ()) ++ { ++ function->decls.ordered_remove (j); ++ delete decl; ++ } ++ else ++ j++; ++ } ++ ++ /* Prune functions which don't refer to any variables any more. */ ++ if (function->args.is_empty () ++ && function->decls.is_empty () ++ && function->globals.is_empty ()) ++ { ++ delete function; ++ functions.ordered_remove (i); ++ } ++ else ++ i++; ++ } ++ ++ /* Prune globals of types that escape, all references to those decls ++ will have been removed in the first loop. */ ++ for (unsigned j = 0; j < globals.decls.length ();) ++ { ++ srdecl *decl = globals.decls[j]; ++ if (decl->type->has_escaped ()) ++ { ++ globals.decls.ordered_remove (j); ++ delete decl; ++ } ++ else ++ j++; ++ } ++ ++ /* Prune types that escape, all references to those types ++ will have been removed in the above loops. */ ++ for (unsigned i = 0; i < types.length (); ) ++ { ++ srtype *type = types[i]; ++ if (type->has_escaped ()) ++ { ++ /* All references to this type should have been removed now. */ ++ delete type; ++ types.ordered_remove (i); ++ } ++ else ++ i++; ++ } ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "all types (after pruning):\n"); ++ dump_types (dump_file); ++ fprintf (dump_file, "all functions (after pruning):\n"); ++ dump_functions (dump_file); ++ } ++} ++ ++/* Analyze all of the types. */ ++ ++void ++ipa_struct_reorg::analyze_types (void) ++{ ++ for (unsigned i = 0; i < types.length (); i++) ++ { ++ if (!types[i]->has_escaped ()) ++ types[i]->analyze(); ++ } ++} ++ ++/* When struct A has a struct B member, B's type info ++ is not stored in ++ TYPE_FIELDS (TREE_TYPE (TYPE_FIELDS (typeA))) ++ Try to restore B's type information. */ ++void ++ipa_struct_reorg::restore_field_type (void) ++{ ++ for (unsigned i = 0; i < types.length (); i++) ++ { ++ for (unsigned j = 0; j < types[i]->fields.length (); j++) ++ { ++ srfield *field = types[i]->fields[j]; ++ if (TREE_CODE (inner_type (field->fieldtype)) == RECORD_TYPE) ++ { ++ /* If field type has TYPE_FIELDS information, ++ we do not need to do this. */ ++ if (TYPE_FIELDS (field->type->type) != NULL) ++ { ++ continue; ++ } ++ for (unsigned k = 0; k < types.length (); k++) ++ { ++ if (i == k) ++ { ++ continue; ++ } ++ const char *type1 = get_type_name (field->type->type); ++ const char *type2 = get_type_name (types[k]->type); ++ if (type1 == NULL || type2 == NULL) ++ { ++ continue; ++ } ++ if (type1 == type2 ++ && TYPE_FIELDS (types[k]->type)) ++ { ++ field->type = types[k]; ++ } ++ } ++ } ++ } ++ } ++} ++ ++/* Create all new types we want to create. */ ++ ++bool ++ipa_struct_reorg::create_new_types (void) ++{ ++ int newtypes = 0; ++ clear_visited (); ++ for (unsigned i = 0; i < types.length (); i++) ++ newtypes += types[i]->create_new_type (); ++ ++ if (dump_file) ++ { ++ if (newtypes) ++ fprintf (dump_file, "\nNumber of structures to transform is %d\n", newtypes); ++ else ++ fprintf (dump_file, "\nNo structures to transform.\n"); ++ } ++ ++ return newtypes != 0; ++} ++ ++/* Create all the new decls except for the new arguments ++ which create_new_functions would have created. */ ++ ++void ++ipa_struct_reorg::create_new_decls (void) ++{ ++ globals.create_new_decls (); ++ for (unsigned i = 0; i < functions.length (); i++) ++ functions[i]->create_new_decls (); ++} ++ ++/* Create the new arguments for the function corresponding to NODE. */ ++ ++void ++ipa_struct_reorg::create_new_args (cgraph_node *new_node) ++{ ++ tree decl = new_node->decl; ++ auto_vec<tree> params; ++ push_function_arg_decls (¶ms, decl); ++ vec<ipa_adjusted_param, va_gc> *adjs = NULL; ++ vec_safe_reserve (adjs, params.length ()); ++ for (unsigned i = 0; i < params.length (); i++) ++ { ++ struct ipa_adjusted_param adj; ++ tree parm = params[i]; ++ memset (&adj, 0, sizeof (adj)); ++ adj.base_index = i; ++ adj.prev_clone_index = i; ++ srtype *t = find_type (inner_type (TREE_TYPE (parm))); ++ if (!t ++ || t->has_escaped () ++ || !t->has_new_type ()) ++ { ++ adj.op = IPA_PARAM_OP_COPY; ++ vec_safe_push (adjs, adj); ++ continue; ++ } ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "Creating a new argument for: "); ++ print_generic_expr (dump_file, params[i]); ++ fprintf (dump_file, " in function: "); ++ print_generic_expr (dump_file, decl); ++ fprintf (dump_file, "\n"); ++ } ++ adj.op = IPA_PARAM_OP_NEW; ++ adj.param_prefix_index = IPA_PARAM_PREFIX_REORG; ++ for (unsigned j = 0; j < max_split && t->newtype[j]; j++) ++ { ++ adj.type = reconstruct_complex_type (TREE_TYPE (parm), t->newtype[j]); ++ vec_safe_push (adjs, adj); ++ } ++ } ++ ipa_param_body_adjustments *adjustments ++ = new ipa_param_body_adjustments (adjs, decl); ++ adjustments->modify_formal_parameters (); ++ auto_vec<tree> new_params; ++ push_function_arg_decls (&new_params, decl); ++ unsigned veclen = vec_safe_length (adjs); ++ for (unsigned i = 0; i < veclen; i++) ++ { ++ if ((*adjs)[i].op != IPA_PARAM_OP_NEW) ++ continue; ++ tree decl = params[(*adjs)[i].base_index]; ++ srdecl *d = find_decl (decl); ++ if (!d) ++ continue; ++ unsigned j = 0; ++ while (j < max_split && d->newdecl[j]) ++ j++; ++ d->newdecl[j] = new_params[i]; ++ } ++ ++ function *fn = DECL_STRUCT_FUNCTION (decl); ++ ++ if (!fn->static_chain_decl) ++ return; ++ srdecl *chain = find_decl (fn->static_chain_decl); ++ if (!chain) ++ return; ++ ++ srtype *type = chain->type; ++ tree orig_var = chain->decl; ++ const char *tname = NULL; ++ if (DECL_NAME (orig_var)) ++ tname = IDENTIFIER_POINTER (DECL_NAME (orig_var)); ++ gcc_assert (!type->newtype[1]); ++ tree new_name = NULL; ++ char *name = NULL; ++ if (tname) ++ { ++ name = concat (tname, ".reorg.0", NULL); ++ new_name = get_identifier (name); ++ free (name); ++ } ++ tree newtype1 = reconstruct_complex_type (TREE_TYPE (orig_var), type->newtype[0]); ++ chain->newdecl[0] = build_decl (DECL_SOURCE_LOCATION (orig_var), ++ PARM_DECL, new_name, newtype1); ++ copy_var_attributes (chain->newdecl[0], orig_var); ++ fn->static_chain_decl = chain->newdecl[0]; ++ ++} ++ ++/* Find the refered DECL in the current function or globals. ++ If this is a global decl, record that as being used ++ in the current function. */ ++ ++srdecl * ++ipa_struct_reorg::find_decl (tree decl) ++{ ++ srdecl *d; ++ d = globals.find_decl (decl); ++ if (d) ++ { ++ /* Record the global usage in the current function. */ ++ if (!done_recording && current_function) ++ { ++ bool add = true; ++ /* No reason to add it to the current function if it is ++ already recorded as such. */ ++ for (unsigned i = 0; i < current_function->globals.length (); i++) ++ { ++ if (current_function->globals[i] == d) ++ { ++ add = false; ++ break; ++ } ++ } ++ if (add) ++ current_function->globals.safe_push (d); ++ } ++ return d; ++ } ++ if (current_function) ++ return current_function->find_decl (decl); ++ return NULL; ++} ++ ++/* Create new function clones for the cases where the arguments ++ need to be changed. */ ++ ++void ++ipa_struct_reorg::create_new_functions (void) ++{ ++ for (unsigned i = 0; i < functions.length (); i++) ++ { ++ srfunction *f = functions[i]; ++ bool anyargchanges = false; ++ cgraph_node *new_node; ++ cgraph_node *node = f->node; ++ int newargs = 0; ++ if (f->old) ++ continue; ++ ++ if (f->args.length () == 0) ++ continue; ++ ++ for (unsigned j = 0; j < f->args.length (); j++) ++ { ++ srdecl *d = f->args[j]; ++ srtype *t = d->type; ++ if (t->has_new_type ()) ++ { ++ newargs += t->newtype[1] != NULL; ++ anyargchanges = true; ++ } ++ } ++ if (!anyargchanges) ++ continue; ++ ++ if (dump_file) ++ { ++ fprintf (dump_file, "Creating a clone of function: "); ++ f->simple_dump (dump_file); ++ fprintf (dump_file, "\n"); ++ } ++ statistics_counter_event (NULL, "Create new function", 1); ++ new_node = node->create_version_clone_with_body (vNULL, NULL, ++ NULL, NULL, NULL, ++ "struct_reorg"); ++ new_node->can_change_signature = node->can_change_signature; ++ new_node->make_local (); ++ f->newnode = new_node; ++ srfunction *n = record_function (new_node); ++ current_function = n; ++ n->old = f; ++ f->newf = n; ++ /* Create New arguments. */ ++ create_new_args (new_node); ++ current_function = NULL; ++ } ++} ++ ++bool ++ipa_struct_reorg::rewrite_lhs_rhs (tree lhs, tree rhs, tree newlhs[max_split], tree newrhs[max_split]) ++{ ++ bool l = rewrite_expr (lhs, newlhs); ++ bool r = rewrite_expr (rhs, newrhs); ++ ++ /* Handle NULL pointer specially. */ ++ if (l && !r && integer_zerop (rhs)) ++ { ++ r = true; ++ for (unsigned i = 0; i < max_split && newlhs[i]; i++) ++ newrhs[i] = fold_convert (TREE_TYPE (newlhs[i]), rhs); ++ } ++ ++ return l || r; ++} ++ ++bool ++ipa_struct_reorg::rewrite_expr (tree expr, tree newexpr[max_split], bool ignore_missing_decl) ++{ ++ tree base; ++ bool indirect; ++ srtype *t; ++ srfield *f; ++ bool realpart, imagpart; ++ bool address; ++ ++ tree newbase[max_split]; ++ memset (newexpr, 0, sizeof(tree[max_split])); ++ ++ if (TREE_CODE (expr) == CONSTRUCTOR) ++ { ++ srtype *t = find_type (TREE_TYPE (expr)); ++ if (!t) ++ return false; ++ gcc_assert (CONSTRUCTOR_NELTS (expr) == 0); ++ if (!t->has_new_type ()) ++ return false; ++ for (unsigned i = 0; i < max_split && t->newtype[i]; i++) ++ newexpr[i] = build_constructor (t->newtype[i], NULL); ++ return true; ++ } ++ ++ if (!get_type_field (expr, base, indirect, t, f, realpart, imagpart, address)) ++ return false; ++ ++ /* If the type is not changed, then just return false. */ ++ if (!t->has_new_type ()) ++ return false; ++ ++ /* NULL pointer handling is "special". */ ++ if (integer_zerop (base)) ++ { ++ gcc_assert (indirect && !address); ++ for (unsigned i = 0; i < max_split && t->newtype[i]; i++) ++ { ++ tree newtype1 = reconstruct_complex_type (TREE_TYPE (base), t->newtype[i]); ++ newbase[i] = fold_convert (newtype1, base); ++ } ++ } ++ else ++ { ++ srdecl *d = find_decl (base); ++ ++ if (!d && dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "Can't find decl:\n"); ++ print_generic_expr (dump_file, base); ++ fprintf (dump_file, "\ntype:\n"); ++ t->dump (dump_file); ++ } ++ if (!d && ignore_missing_decl) ++ return true; ++ gcc_assert (d); ++ memcpy (newbase, d->newdecl, sizeof(d->newdecl)); ++ } ++ ++ if (f == NULL) ++ { ++ memcpy (newexpr, newbase, sizeof(newbase)); ++ for (unsigned i = 0; i < max_split && newexpr[i]; i++) ++ { ++ if (address) ++ newexpr[i] = build_fold_addr_expr (newexpr[i]); ++ if (indirect) ++ newexpr[i] = build_simple_mem_ref (newexpr[i]); ++ if (imagpart) ++ newexpr[i] = build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (newexpr[i])), newexpr[i]); ++ if (realpart) ++ newexpr[i] = build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (newexpr[i])), newexpr[i]); ++ } ++ return true; ++ } ++ ++ tree newdecl = newbase[f->clusternum]; ++ for (unsigned i = 0; i < max_split && f->newfield[i]; i++) ++ { ++ tree newbase1 = newdecl; ++ if (address) ++ newbase1 = build_fold_addr_expr (newbase1); ++ if (indirect) ++ newbase1 = build_simple_mem_ref (newbase1); ++ newexpr[i] = build3 (COMPONENT_REF, TREE_TYPE (f->newfield[i]), ++ newbase1, f->newfield[i], NULL_TREE); ++ if (imagpart) ++ newexpr[i] = build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (newexpr[i])), newexpr[i]); ++ if (realpart) ++ newexpr[i] = build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (newexpr[i])), newexpr[i]); ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "cluster: %d. decl = ", (int)f->clusternum); ++ print_generic_expr (dump_file, newbase1); ++ fprintf (dump_file, "\nnewexpr = "); ++ print_generic_expr (dump_file, newexpr[i]); ++ fprintf (dump_file, "\n"); ++ } ++ } ++ return true; ++} ++ ++bool ++ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) ++{ ++ bool remove = false; ++ if (gimple_clobber_p (stmt)) ++ { ++ tree lhs = gimple_assign_lhs (stmt); ++ tree newlhs[max_split]; ++ if (!rewrite_expr (lhs, newlhs)) ++ return false; ++ for (unsigned i = 0; i < max_split && newlhs[i]; i++) ++ { ++ tree clobber = build_constructor (TREE_TYPE (newlhs[i]), NULL); ++ TREE_THIS_VOLATILE (clobber) = true; ++ gimple *newstmt = gimple_build_assign (newlhs[i], clobber); ++ gsi_insert_before (gsi, newstmt, GSI_SAME_STMT); ++ remove = true; ++ } ++ return remove; ++ } ++ ++ if (gimple_assign_rhs_code (stmt) == EQ_EXPR ++ || gimple_assign_rhs_code (stmt) == NE_EXPR) ++ { ++ tree rhs1 = gimple_assign_rhs1 (stmt); ++ tree rhs2 = gimple_assign_rhs2 (stmt); ++ tree newrhs1[max_split]; ++ tree newrhs2[max_split]; ++ tree_code rhs_code = gimple_assign_rhs_code (stmt); ++ tree_code code = rhs_code == EQ_EXPR ? BIT_AND_EXPR : BIT_IOR_EXPR; ++ if (!rewrite_lhs_rhs (rhs1, rhs2, newrhs1, newrhs2)) ++ return false; ++ tree newexpr = NULL_TREE; ++ for (unsigned i = 0; i < max_split && newrhs1[i]; i++) ++ { ++ tree expr = gimplify_build2 (gsi, rhs_code, boolean_type_node, newrhs1[i], newrhs2[i]); ++ if (!newexpr) ++ newexpr = expr; ++ else ++ newexpr = gimplify_build2 (gsi, code, boolean_type_node, newexpr, expr); ++ } ++ ++ if (newexpr) ++ { ++ newexpr = fold_convert (TREE_TYPE (gimple_assign_lhs (stmt)), newexpr); ++ gimple_assign_set_rhs_from_tree (gsi, newexpr); ++ update_stmt (stmt); ++ } ++ return false; ++ } ++ ++ if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) ++ { ++ tree lhs = gimple_assign_lhs (stmt); ++ tree rhs1 = gimple_assign_rhs1 (stmt); ++ tree rhs2 = gimple_assign_rhs2 (stmt); ++ tree newlhs[max_split]; ++ tree newrhs[max_split]; ++ ++ if (!rewrite_lhs_rhs (lhs, rhs1, newlhs, newrhs)) ++ return false; ++ tree size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (lhs))); ++ tree num; ++ /* Check if rhs2 is a multiplication of the size of the type. */ ++ if (!is_result_of_mult (rhs2, &num, size)) ++ internal_error ("the rhs of pointer was not a multiplicate and it slipped through."); ++ ++ num = gimplify_build1 (gsi, NOP_EXPR, sizetype, num); ++ for (unsigned i = 0; i < max_split && newlhs[i]; i++) ++ { ++ gimple *new_stmt; ++ ++ tree newsize = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (newlhs[i]))); ++ newsize = gimplify_build2 (gsi, MULT_EXPR, sizetype, num, newsize); ++ new_stmt = gimple_build_assign (newlhs[i], POINTER_PLUS_EXPR, newrhs[i], newsize); ++ gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT); ++ remove = true; ++ } ++ return remove; ++ } ++ if (gimple_assign_rhs_class (stmt) == GIMPLE_SINGLE_RHS) ++ { ++ tree lhs = gimple_assign_lhs (stmt); ++ tree rhs = gimple_assign_rhs1 (stmt); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "rewriting stamtenet:\n"); ++ print_gimple_stmt (dump_file, stmt, 0); ++ fprintf (dump_file, "\n"); ++ } ++ tree newlhs[max_split]; ++ tree newrhs[max_split]; ++ if (!rewrite_lhs_rhs (lhs, rhs, newlhs, newrhs)) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "\nDid nothing to statement.\n"); ++ return false; ++ } ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "\nreplaced with:\n"); ++ for (unsigned i = 0; i < max_split && (newlhs[i] || newrhs[i]); i++) ++ { ++ gimple *newstmt = gimple_build_assign (newlhs[i] ? newlhs[i] : lhs, newrhs[i] ? newrhs[i] : rhs); ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ print_gimple_stmt (dump_file, newstmt, 0); ++ fprintf (dump_file, "\n"); ++ } ++ gsi_insert_before (gsi, newstmt, GSI_SAME_STMT); ++ remove = true; ++ } ++ return remove; ++ } ++ ++ return remove; ++} ++ ++/* Rewrite function call statement STMT. Return TRUE if the statement ++ is to be removed. */ ++ ++bool ++ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi) ++{ ++ /* Handled allocation calls are handled seperately from normal ++ function calls. */ ++ if (handled_allocation_stmt (stmt)) ++ { ++ tree lhs = gimple_call_lhs (stmt); ++ tree newrhs1[max_split]; ++ srdecl *decl = find_decl (lhs); ++ if (!decl || !decl->type) ++ return false; ++ srtype *type = decl->type; ++ tree num = allocate_size (type, stmt); ++ gcc_assert (num); ++ memset (newrhs1, 0, sizeof(newrhs1)); ++ ++ /* The realloc call needs to have its first argument rewritten. */ ++ if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC)) ++ { ++ tree rhs1 = gimple_call_arg (stmt, 0); ++ if (integer_zerop (rhs1)) ++ { ++ for (unsigned i = 0; i < max_split; i++) ++ newrhs1[i] = rhs1; ++ } ++ else if (!rewrite_expr (rhs1, newrhs1)) ++ internal_error ("rewrite failed for realloc"); ++ } ++ ++ /* Go through each new lhs. */ ++ for (unsigned i = 0; i < max_split && decl->newdecl[i]; i++) ++ { ++ tree newsize = TYPE_SIZE_UNIT (type->type); ++ gimple *g; ++ /* Every allocation except for calloc needs the size multiplied out. */ ++ if (!gimple_call_builtin_p (stmt, BUILT_IN_CALLOC)) ++ newsize = gimplify_build2 (gsi, MULT_EXPR, sizetype, num, newsize); ++ ++ if (gimple_call_builtin_p (stmt, BUILT_IN_MALLOC) ++ || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA)) ++ g = gimple_build_call (gimple_call_fndecl (stmt), ++ 1, newsize); ++ else if (gimple_call_builtin_p (stmt, BUILT_IN_CALLOC)) ++ g = gimple_build_call (gimple_call_fndecl (stmt), ++ 2, num, newsize); ++ else if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC)) ++ g = gimple_build_call (gimple_call_fndecl (stmt), ++ 2, newrhs1[i], newsize); ++ else ++ gcc_assert (false); ++ gimple_call_set_lhs (g, decl->newdecl[i]); ++ gsi_insert_before (gsi, g, GSI_SAME_STMT); ++ } ++ return true; ++ } ++ ++ /* The function call free needs to be handled special. */ ++ if (gimple_call_builtin_p (stmt, BUILT_IN_FREE)) ++ { ++ tree expr = gimple_call_arg (stmt, 0); ++ tree newexpr[max_split]; ++ if (!rewrite_expr (expr, newexpr)) ++ return false; ++ ++ if (newexpr[1] == NULL) ++ { ++ gimple_call_set_arg (stmt, 0, newexpr[0]); ++ update_stmt (stmt); ++ return false; ++ } ++ ++ for (unsigned i = 0; i < max_split && newexpr[i]; i++) ++ { ++ gimple *g = gimple_build_call (gimple_call_fndecl (stmt), ++ 1, newexpr[i]); ++ gsi_insert_before (gsi, g, GSI_SAME_STMT); ++ } ++ return true; ++ } ++ ++ /* Otherwise, look up the function to see if we have cloned it ++ and rewrite the arguments. */ ++ tree fndecl = gimple_call_fndecl (stmt); ++ ++ /* Indirect calls are already marked as escaping so ignore. */ ++ if (!fndecl) ++ return false; ++ ++ cgraph_node *node = cgraph_node::get (fndecl); ++ gcc_assert (node); ++ srfunction *f = find_function (node); ++ ++ /* Did not find the function or had not cloned it return saying don't ++ change the function call. */ ++ if (!f || !f->newf) ++ return false; ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "Changing arguments for function call :\n"); ++ print_gimple_expr (dump_file, stmt, 0); ++ fprintf (dump_file, "\n"); ++ } ++ ++ /* Move over to the new function. */ ++ f = f->newf; ++ ++ tree chain = gimple_call_chain (stmt); ++ unsigned nargs = gimple_call_num_args (stmt); ++ auto_vec<tree> vargs (nargs); ++ ++ if (chain) ++ { ++ tree newchains[max_split]; ++ if (rewrite_expr (chain, newchains)) ++ { ++ /* Chain decl's type cannot be split and but it can change. */ ++ gcc_assert (newchains[1] == NULL); ++ chain = newchains[0]; ++ } ++ } ++ ++ for (unsigned i = 0; i < nargs; i++) ++ vargs.quick_push (gimple_call_arg (stmt, i)); ++ ++ int extraargs = 0; ++ ++ for (unsigned i = 0; i < f->args.length (); i++) ++ { ++ srdecl *d = f->args[i]; ++ if (d->argumentnum == -2) ++ continue; ++ gcc_assert (d->argumentnum != -1); ++ tree arg = vargs[d->argumentnum + extraargs]; ++ tree newargs[max_split]; ++ if (!rewrite_expr (arg, newargs)) ++ continue; ++ ++ /* If this ARG has a replacement handle the replacement. */ ++ for (unsigned j = 0; j < max_split && d->newdecl[j]; j++) ++ { ++ gcc_assert (newargs[j]); ++ /* If this is the first replacement of the arugment, ++ then just replace it. */ ++ if (j == 0) ++ vargs[d->argumentnum + extraargs] = newargs[j]; ++ else ++ { ++ /* More than one replacement, we need to insert into the array. */ ++ extraargs++; ++ vargs.safe_insert(d->argumentnum + extraargs, newargs[j]); ++ } ++ } ++ } ++ ++ gcall *new_stmt; ++ ++ new_stmt = gimple_build_call_vec (f->node->decl, vargs); ++ ++ if (gimple_call_lhs (stmt)) ++ gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt)); ++ ++ gimple_set_vuse (new_stmt, gimple_vuse (stmt)); ++ gimple_set_vdef (new_stmt, gimple_vdef (stmt)); ++ ++ if (gimple_has_location (stmt)) ++ gimple_set_location (new_stmt, gimple_location (stmt)); ++ gimple_call_copy_flags (new_stmt, stmt); ++ gimple_call_set_chain (new_stmt, chain); ++ ++ gimple_set_modified (new_stmt, true); ++ ++ if (gimple_vdef (new_stmt) ++ && TREE_CODE (gimple_vdef (new_stmt)) == SSA_NAME) ++ SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt; ++ ++ gsi_replace (gsi, new_stmt, false); ++ ++ /* We need to defer cleaning EH info on the new statement to ++ fixup-cfg. We may not have dominator information at this point ++ and thus would end up with unreachable blocks and have no way ++ to communicate that we need to run CFG cleanup then. */ ++ int lp_nr = lookup_stmt_eh_lp (stmt); ++ if (lp_nr != 0) ++ { ++ remove_stmt_from_eh_lp (stmt); ++ add_stmt_to_eh_lp (new_stmt, lp_nr); ++ } ++ ++ ++ return false; ++} ++ ++/* Rewrite the conditional statement STMT. Return TRUE if the ++ old statement is to be removed. */ ++ ++bool ++ipa_struct_reorg::rewrite_cond (gcond *stmt, gimple_stmt_iterator *gsi) ++{ ++ tree_code rhs_code = gimple_cond_code (stmt); ++ ++ /* Handle only equals or not equals conditionals. */ ++ if (rhs_code != EQ_EXPR ++ && rhs_code != NE_EXPR) ++ return false; ++ tree rhs1 = gimple_cond_lhs (stmt); ++ tree rhs2 = gimple_cond_rhs (stmt); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "COND: Rewriting\n"); ++ print_gimple_stmt (dump_file, stmt, 0); ++ fprintf (dump_file, "\n"); ++ print_generic_expr (dump_file, rhs1); ++ fprintf (dump_file, "\n"); ++ print_generic_expr (dump_file, rhs2); ++ fprintf (dump_file, "\n"); ++ } ++ ++ tree newrhs1[max_split]; ++ tree newrhs2[max_split]; ++ tree_code code = rhs_code == EQ_EXPR ? BIT_AND_EXPR : BIT_IOR_EXPR; ++ if (!rewrite_lhs_rhs (rhs1, rhs2, newrhs1, newrhs2)) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "\nDid nothing to statement.\n"); ++ return false; ++ } ++ ++ tree newexpr = NULL_TREE; ++ for (unsigned i = 0; i < max_split && newrhs1[i]; i++) ++ { ++ tree expr = gimplify_build2 (gsi, rhs_code, boolean_type_node, newrhs1[i], newrhs2[i]); ++ if (!newexpr) ++ newexpr = expr; ++ else ++ newexpr = gimplify_build2 (gsi, code, boolean_type_node, newexpr, expr); ++ } ++ ++ if (newexpr) ++ { ++ gimple_cond_set_lhs (stmt, newexpr); ++ gimple_cond_set_rhs (stmt, boolean_true_node); ++ update_stmt (stmt); ++ } ++ return false; ++} ++ ++/* Rewrite debug statments if possible. Return TRUE if the statement ++ should be removed. */ ++ ++bool ++ipa_struct_reorg::rewrite_debug (gimple *stmt, gimple_stmt_iterator *) ++{ ++ bool remove = false; ++ if (gimple_debug_bind_p (stmt)) ++ { ++ tree var = gimple_debug_bind_get_var (stmt); ++ tree newvar[max_split]; ++ if (rewrite_expr (var, newvar, true)) ++ remove = true; ++ if (gimple_debug_bind_has_value_p (stmt)) ++ { ++ var = gimple_debug_bind_get_value (stmt); ++ if (TREE_CODE (var) == POINTER_PLUS_EXPR) ++ var = TREE_OPERAND (var, 0); ++ if (rewrite_expr (var, newvar, true)) ++ remove = true; ++ } ++ } ++ else if (gimple_debug_source_bind_p (stmt)) ++ { ++ tree var = gimple_debug_source_bind_get_var (stmt); ++ tree newvar[max_split]; ++ if (rewrite_expr (var, newvar, true)) ++ remove = true; ++ var = gimple_debug_source_bind_get_value (stmt); ++ if (TREE_CODE (var) == POINTER_PLUS_EXPR) ++ var = TREE_OPERAND (var, 0); ++ if (rewrite_expr (var, newvar, true)) ++ remove = true; ++ } ++ ++ return remove; ++} ++ ++/* Rewrite PHI nodes, return true if the PHI was replaced. */ ++ ++bool ++ipa_struct_reorg::rewrite_phi (gphi *phi) ++{ ++ tree newlhs[max_split]; ++ gphi *newphi[max_split]; ++ tree result = gimple_phi_result (phi); ++ gphi_iterator gsi; ++ ++ memset(newphi, 0, sizeof(newphi)); ++ ++ if (!rewrite_expr (result, newlhs)) ++ return false; ++ ++ if (newlhs[0] == NULL) ++ return false; ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nrewriting PHI:"); ++ print_gimple_stmt (dump_file, phi, 0); ++ } ++ ++ for (unsigned i = 0; i < max_split && newlhs[i]; i++) ++ newphi[i] = create_phi_node (newlhs[i], gimple_bb (phi)); ++ ++ for(unsigned i = 0; i < gimple_phi_num_args (phi); i++) ++ { ++ tree newrhs[max_split]; ++ phi_arg_d rhs = *gimple_phi_arg (phi, i); ++ rewrite_expr (rhs.def, newrhs); ++ for (unsigned j = 0; j < max_split && newlhs[j]; j++) ++ { ++ SET_PHI_ARG_DEF (newphi[j], i, newrhs[j]); ++ gimple_phi_arg_set_location (newphi[j], i, rhs.locus); ++ update_stmt (newphi[j]); ++ } ++ } ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\ninto\n:"); ++ for (unsigned i = 0; i < max_split && newlhs[i]; i++) ++ { ++ print_gimple_stmt (dump_file, newphi[i], 0); ++ fprintf (dump_file, "\n"); ++ } ++ } ++ ++ gsi = gsi_for_phi (phi); ++ remove_phi_node (&gsi, false); ++ ++ return true; ++} ++ ++/* Rewrite gimple statement STMT, return true if the STATEMENT ++ is to be removed. */ ++ ++bool ++ipa_struct_reorg::rewrite_stmt (gimple *stmt, gimple_stmt_iterator *gsi) ++{ ++ switch (gimple_code (stmt)) ++ { ++ case GIMPLE_ASSIGN: ++ return rewrite_assign (as_a <gassign *> (stmt), gsi); ++ case GIMPLE_CALL: ++ return rewrite_call (as_a <gcall *> (stmt), gsi); ++ case GIMPLE_COND: ++ return rewrite_cond (as_a <gcond *> (stmt), gsi); ++ break; ++ case GIMPLE_GOTO: ++ case GIMPLE_SWITCH: ++ break; ++ case GIMPLE_DEBUG: ++ case GIMPLE_ASM: ++ break; ++ default: ++ break; ++ } ++ return false; ++} ++ ++/* Does the function F uses any decl which has changed. */ ++ ++bool ++ipa_struct_reorg::has_rewritten_type (srfunction *f) ++{ ++ for (unsigned i = 0; i < f->decls.length (); i++) ++ { ++ srdecl *d = f->decls[i]; ++ if (d->newdecl[0] != d->decl) ++ return true; ++ } ++ ++ for (unsigned i = 0; i < f->globals.length (); i++) ++ { ++ srdecl *d = f->globals[i]; ++ if (d->newdecl[0] != d->decl) ++ return true; ++ } ++ return false; ++ ++} ++ ++/* Rewrite the functions if needed, return ++ the TODOs requested. */ ++ ++unsigned ++ipa_struct_reorg::rewrite_functions (void) ++{ ++ unsigned retval = 0; ++ ++ restore_field_type (); ++ /* Create new types, if we did not create any new types, ++ then don't rewrite any accesses. */ ++ if (!create_new_types ()) ++ return 0; ++ ++ if (functions.length ()) ++ { ++ retval = TODO_remove_functions; ++ create_new_functions (); ++ } ++ ++ create_new_decls (); ++ ++ for (unsigned i = 0; i < functions.length (); i++) ++ { ++ srfunction *f = functions[i]; ++ if (f->newnode) ++ continue; ++ ++ /* Function uses no rewriten types so don't cause a rewrite. */ ++ if (!has_rewritten_type (f)) ++ continue; ++ ++ cgraph_node *node = f->node; ++ basic_block bb; ++ ++ push_cfun (DECL_STRUCT_FUNCTION (node->decl)); ++ current_function = f; ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nBefore rewrite:\n"); ++ dump_function_to_file (current_function_decl, dump_file, dump_flags | TDF_VOPS); ++ } ++ FOR_EACH_BB_FN (bb, cfun) ++ { ++ for (gphi_iterator si = gsi_start_phis (bb); !gsi_end_p (si); ) ++ { ++ if (rewrite_phi (si.phi ())) ++ si = gsi_start_phis (bb); ++ else ++ gsi_next (&si); ++ } ++ ++ for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si); ) ++ { ++ gimple *stmt = gsi_stmt (si); ++ if (rewrite_stmt (stmt, &si)) ++ gsi_remove (&si, true); ++ else ++ gsi_next (&si); ++ } ++ } ++ ++ /* Debug statements need to happen after all other statements ++ have changed. */ ++ FOR_EACH_BB_FN (bb, cfun) ++ { ++ for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si); ) ++ { ++ gimple *stmt = gsi_stmt (si); ++ if (gimple_code (stmt) == GIMPLE_DEBUG ++ && rewrite_debug (stmt, &si)) ++ gsi_remove (&si, true); ++ else ++ gsi_next (&si); ++ } ++ } ++ ++ /* Release the old SSA_NAMES for old arguments. */ ++ if (f->old) ++ { ++ for (unsigned i = 0; i < f->args.length (); i++) ++ { ++ srdecl *d = f->args[i]; ++ if (d->newdecl[0] != d->decl) ++ { ++ tree ssa_name = ssa_default_def (cfun, d->decl); ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "Found "); ++ print_generic_expr (dump_file, ssa_name); ++ fprintf (dump_file, " to be released.\n"); ++ } ++ release_ssa_name (ssa_name); ++ } ++ } ++ } ++ ++ update_ssa (TODO_update_ssa_only_virtuals); ++ ++ if (flag_tree_pta) ++ compute_may_aliases (); ++ ++ remove_unused_locals (); ++ ++ cgraph_edge::rebuild_edges (); ++ ++ free_dominance_info (CDI_DOMINATORS); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nAfter rewrite:\n"); ++ dump_function_to_file (current_function_decl, dump_file, dump_flags | TDF_VOPS); ++ } ++ ++ pop_cfun (); ++ current_function = NULL; ++ } ++ ++ return retval | TODO_verify_all; ++} ++ ++unsigned int ++ipa_struct_reorg::execute (void) ++{ ++ /* FIXME: If there is a top-level inline-asm, the pass immediately returns. */ ++ if (symtab->first_asm_symbol ()) ++ return 0; ++ record_accesses (); ++ prune_escaped_types (); ++ analyze_types (); ++ ++ return rewrite_functions (); ++} ++ ++const pass_data pass_data_ipa_struct_reorg = ++{ ++ SIMPLE_IPA_PASS, /* type */ ++ "struct_reorg", /* name */ ++ OPTGROUP_NONE, /* optinfo_flags */ ++ TV_IPA_STRUCT_REORG, /* tv_id */ ++ 0, /* properties_required */ ++ 0, /* properties_provided */ ++ 0, /* properties_destroyed */ ++ 0, /* todo_flags_start */ ++ 0, /* todo_flags_finish */ ++}; ++ ++class pass_ipa_struct_reorg : public simple_ipa_opt_pass ++{ ++public: ++ pass_ipa_struct_reorg (gcc::context *ctxt) ++ : simple_ipa_opt_pass (pass_data_ipa_struct_reorg, ctxt) ++ {} ++ ++ /* opt_pass methods: */ ++ virtual bool gate (function *); ++ virtual unsigned int execute (function *) { return ipa_struct_reorg ().execute(); } ++ ++}; // class pass_ipa_struct_reorg ++ ++bool ++pass_ipa_struct_reorg::gate (function *) ++{ ++ return (optimize ++ && flag_ipa_struct_reorg ++ /* Don't bother doing anything if the program has errors. */ ++ && !seen_error ()); ++} ++ ++} // anon namespace ++ ++simple_ipa_opt_pass * ++make_pass_ipa_struct_reorg (gcc::context *ctxt) ++{ ++ return new pass_ipa_struct_reorg (ctxt); ++} +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.h b/gcc/ipa-struct-reorg/ipa-struct-reorg.h +new file mode 100644 +index 00000000000..f2163910896 +--- /dev/null ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.h +@@ -0,0 +1,235 @@ ++/* Struct-reorg optimizations. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ Contributed by Andrew Pinski <apinski@cavium.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, 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/>. */ ++ ++#ifndef IPA_STRUCT_REORG_H ++#define IPA_STRUCT_REORG_H ++ ++namespace struct_reorg { ++ ++const int max_split = 2; ++ ++template <typename type> ++struct auto_vec_del : auto_vec<type*> ++{ ++ ~auto_vec_del(); ++}; ++ ++template <typename T> ++auto_vec_del<T>::~auto_vec_del(void) ++{ ++ unsigned i; ++ T *t; ++ FOR_EACH_VEC_ELT (*this, i, t) ++ { ++ delete t; ++ } ++} ++ ++enum escape_type ++{ ++ does_not_escape, ++#define DEF_ESCAPE(ENUM, TEXT) ENUM, ++#include "escapes.def" ++ escape_max_escape ++}; ++ ++const char *escape_type_string[escape_max_escape - 1] = ++{ ++#define DEF_ESCAPE(ENUM, TEXT) TEXT, ++#include "escapes.def" ++}; ++ ++struct srfield; ++struct srtype; ++struct sraccess; ++struct srdecl; ++struct srfunction; ++ ++struct srfunction ++{ ++ cgraph_node *node; ++ auto_vec<srdecl*> args; ++ auto_vec<srdecl*> globals; ++ auto_vec_del<srdecl> decls; ++ srdecl *record_decl (srtype *, tree, int arg); ++ ++ srfunction *old; ++ cgraph_node *newnode; ++ srfunction *newf; ++ ++ // Constructors ++ srfunction (cgraph_node *n); ++ ++ // Methods ++ void add_arg (srdecl *arg); ++ void dump (FILE *file); ++ void simple_dump (FILE *file); ++ ++ bool check_args (void); ++ void create_new_decls (void); ++ srdecl *find_decl (tree); ++}; ++ ++struct srglobal : private srfunction ++{ ++ srglobal () ++ : srfunction (NULL) ++ { ++ } ++ ++ using srfunction::dump; ++ using srfunction::create_new_decls; ++ using srfunction::find_decl; ++ using srfunction::record_decl; ++ using srfunction::decls; ++}; ++ ++struct srtype ++{ ++ tree type; ++ auto_vec_del<srfield> fields; ++ ++ // array of fields that use this type. ++ auto_vec<srfield*> field_sites; ++ ++ // array of functions which use directly the type ++ auto_vec<srfunction*> functions; ++ ++ auto_vec_del<sraccess> accesses; ++ bool chain_type; ++ ++private: ++ escape_type escapes; ++public: ++ ++ tree newtype[max_split]; ++ bool visited; ++ ++ // Constructors ++ srtype(tree type); ++ ++ // Methods ++ void dump (FILE *file); ++ void simple_dump (FILE *file); ++ void add_function (srfunction *); ++ void add_access (sraccess *a) ++ { ++ accesses.safe_push (a); ++ } ++ void add_field_site (srfield *); ++ ++ srfield *find_field (unsigned HOST_WIDE_INT offset); ++ ++ bool create_new_type (void); ++ void analyze (void); ++ void mark_escape (escape_type, gimple *stmt); ++ bool has_escaped (void) ++ { ++ return escapes != does_not_escape; ++ } ++ const char *escape_reason (void) ++ { ++ if (!has_escaped()) ++ return NULL; ++ return escape_type_string[escapes-1]; ++ } ++ bool escaped_rescusive (void) ++ { ++ return escapes == escape_rescusive_type; ++ } ++ bool has_new_type (void) ++ { ++ return newtype[0] && newtype[0] != type; ++ } ++}; ++ ++struct srfield ++{ ++ unsigned HOST_WIDE_INT offset; ++ tree fieldtype; ++ tree fielddecl; ++ srtype *base; ++ srtype *type; ++ ++ unsigned clusternum; ++ ++ tree newfield[max_split]; ++ ++ // Constructors ++ srfield (tree field, srtype *base); ++ ++ // Methods ++ void dump (FILE *file); ++ void simple_dump (FILE *file); ++ ++ void create_new_fields (tree newtype[max_split], ++ tree newfields[max_split], ++ tree newlast[max_split]); ++}; ++ ++struct sraccess ++{ ++ gimple *stmt; ++ cgraph_node *node; ++ ++ srtype *type; ++ // NULL field means the whole type is accessed ++ srfield *field; ++ ++ // constructors ++ sraccess (gimple *s, cgraph_node *n, srtype *t, srfield *f = NULL) ++ : stmt (s), ++ node (n), ++ type (t), ++ field (f) ++ {} ++ ++ // Methods ++ void dump (FILE *file); ++}; ++ ++struct srdecl ++{ ++ srtype *type; ++ tree decl; ++ tree func; ++ /* -1 : not an argument ++ -2 : static chain */ ++ int argumentnum; ++ ++ bool visited; ++ ++ tree newdecl[max_split]; ++ ++ // Constructors ++ srdecl (srtype *type, tree decl, int argumentnum = -1); ++ ++ // Methods ++ void dump (FILE *file); ++ bool has_new_decl (void) ++ { ++ return newdecl[0] && newdecl[0] != decl; ++ } ++}; ++ ++ ++} // namespace struct_reorg ++ ++#endif +diff --git a/gcc/params.opt b/gcc/params.opt +index 4aec480798b..2db69cc87ea 100644 +--- a/gcc/params.opt ++++ b/gcc/params.opt +@@ -736,6 +736,10 @@ Enum(parloops_schedule_type) String(runtime) Value(PARLOOPS_SCHEDULE_RUNTIME) + Common Joined UInteger Var(param_partial_inlining_entry_probability) Init(70) Optimization IntegerRange(0, 100) Param + Maximum probability of the entry BB of split region (in percent relative to entry BB of the function) to make partial inlining happen. + ++-param=struct-reorg-cold-struct-ratio= ++Common Joined UInteger Var(param_struct_reorg_cold_struct_ratio) Init(10) IntegerRange(0, 100) Param Optimization ++The threshold ratio between current and hottest structure counts. ++ + -param=predictable-branch-outcome= + Common Joined UInteger Var(param_predictable_branch_outcome) Init(2) IntegerRange(0, 50) Param Optimization + Maximal estimated outcome of branch considered predictable. +diff --git a/gcc/passes.def b/gcc/passes.def +index adc88bb2929..fa744e25038 100644 +--- a/gcc/passes.def ++++ b/gcc/passes.def +@@ -173,6 +173,8 @@ along with GCC; see the file COPYING3. If not see + INSERT_PASSES_AFTER (all_late_ipa_passes) + NEXT_PASS (pass_materialize_all_clones); + NEXT_PASS (pass_ipa_pta); ++ /* FIXME: this should a normal IP pass */ ++ NEXT_PASS (pass_ipa_struct_reorg); + NEXT_PASS (pass_omp_simd_clone); + TERMINATE_PASS_LIST (all_late_ipa_passes) + +diff --git a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp +new file mode 100644 +index 00000000000..1bd0e18ea2e +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp +@@ -0,0 +1,35 @@ ++# Copyright (C) 1997-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/>. ++ ++load_lib gcc-dg.exp ++load_lib target-supports.exp ++ ++# Initialize `dg'. ++dg-init ++torture-init ++ ++set STRUCT_REORG_TORTURE_OPTIONS [list \ ++ { -O3 } \ ++ { -Ofast } ] ++ ++set-torture-options $STRUCT_REORG_TORTURE_OPTIONS {{}} ++ ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] \ ++ "" "-fipa-struct-reorg -fdump-ipa-all -flto-partition=one -fwhole-program" ++ ++# All done. ++torture-finish ++dg-finish +diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-1.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-1.c +new file mode 100644 +index 00000000000..6565fe8dd63 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-1.c +@@ -0,0 +1,24 @@ ++// { dg-do compile } ++// { dg-options "-O3 -flto-partition=one -fipa-struct-reorg -fdump-ipa-all" } ++ ++struct a ++{ ++ int t, t1; ++}; ++ ++static struct a *b; ++ ++void *xmalloc(int); ++ ++ ++void f(void) ++{ ++ b = xmalloc (sizeof(*b)); ++} ++ ++int g(void) ++{ ++ return b->t; ++} ++ ++/* { dg-final { scan-ipa-dump "No structures to transform." "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-2.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-2.c +new file mode 100644 +index 00000000000..44babd35b04 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-2.c +@@ -0,0 +1,29 @@ ++// { dg-do run } ++ ++#include <assert.h> ++ ++struct a ++{ ++ int t; ++ int t1; ++}; ++ ++__attribute__((noinline)) int f(int i, int j) ++{ ++ struct a *t; ++ struct a t1 = {i, j}; ++ t = &t1; ++ auto int g(void) __attribute__((noinline)); ++ int g(void) ++ { ++ return t->t + t->t1; ++ } ++ return g(); ++} ++ ++int main() ++{ ++ assert (f(1, 2) == 3); ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-3.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-3.c +new file mode 100644 +index 00000000000..5864ad46fd3 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-3.c +@@ -0,0 +1,23 @@ ++// { dg-do compile } ++// { dg-options "-O3 -flto-partition=one -fipa-struct-reorg -fdump-ipa-all" } ++ ++#include <stdlib.h> ++typedef struct { ++ long laststart_offset; ++ unsigned regnum; ++} compile_stack_elt_t; ++typedef struct { ++ compile_stack_elt_t *stack; ++ unsigned size; ++} compile_stack_type; ++void f (const char *p, const char *pend, int c) ++{ ++ compile_stack_type compile_stack; ++ while (p != pend) ++ if (c) ++ compile_stack.stack = realloc (compile_stack.stack, ++ (compile_stack.size << 1) ++ * sizeof (compile_stack_elt_t)); ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-4.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-4.c +new file mode 100644 +index 00000000000..e5a8a6c847f +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-4.c +@@ -0,0 +1,59 @@ ++/* { dg-do run } */ ++ ++extern void abort (void); ++ ++struct S ++{ ++ int b; ++ int *c; ++}; ++static int d, e; ++ ++static struct S s; ++ ++static int * ++__attribute__((noinline, const)) ++foo (void) ++{ ++ return &s.b; ++} ++ ++int * ++__attribute__((noinline)) ++bar (int **f) ++{ ++ s.c = &d; ++ *f = &e; ++ /* As nothing ever takes the address of any int * field in struct S, ++ the write to *f can't alias with the s.c field. */ ++ return s.c; ++} ++ ++int ++__attribute__((noinline)) ++baz (int *x) ++{ ++ s.b = 1; ++ *x = 4; ++ /* Function foo takes address of an int field in struct S, ++ so *x can alias with the s.b field (and it does in this testcase). */ ++ return s.b; ++} ++ ++int ++__attribute__((noinline)) ++t (void) ++{ ++ int *f = (int *) 0; ++ return 10 * (bar (&f) != &d) + baz (foo ()); ++} ++ ++int ++main (void) ++{ ++ if (t () != 4) ++ abort (); ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "No structures to transform." "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_global_array.c b/gcc/testsuite/gcc.dg/struct/w_prof_global_array.c +new file mode 100644 +index 00000000000..733413a94d0 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/w_prof_global_array.c +@@ -0,0 +1,29 @@ ++#include <stdlib.h> ++typedef struct ++{ ++ int a; ++ float b; ++}str_t; ++ ++#define N 1000 ++str_t A[N]; ++ ++int ++main () ++{ ++ int i; ++ ++ for (i = 0; i < N; i++) ++ { ++ A[i].a = 0; ++ } ++ ++ for (i = 0; i < N; i++) ++ if (A[i].a != 0) ++ abort (); ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_global_var.c b/gcc/testsuite/gcc.dg/struct/w_prof_global_var.c +new file mode 100644 +index 00000000000..0ef686e74e7 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/w_prof_global_var.c +@@ -0,0 +1,42 @@ ++#include <stdlib.h> ++typedef struct ++{ ++ int a; ++ float b; ++}str_t; ++ ++#ifdef STACK_SIZE ++#if STACK_SIZE > 8000 ++#define N 1000 ++#else ++#define N (STACK_SIZE/8) ++#endif ++#else ++#define N 1000 ++#endif ++ ++str_t *p; ++ ++int ++main () ++{ ++ int i, sum; ++ ++ p = malloc (N * sizeof (str_t)); ++ if (p == NULL) ++ return 0; ++ for (i = 0; i < N; i++) ++ p[i].b = i; ++ ++ for (i = 0; i < N; i++) ++ p[i].a = p[i].b + 1; ++ ++ for (i = 0; i < N; i++) ++ if (p[i].a != p[i].b + 1) ++ abort (); ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_local_array.c b/gcc/testsuite/gcc.dg/struct/w_prof_local_array.c +new file mode 100644 +index 00000000000..23a53be5386 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/w_prof_local_array.c +@@ -0,0 +1,37 @@ ++#include <stdlib.h> ++typedef struct ++{ ++ int a; ++ float b; ++}str_t; ++ ++#ifdef STACK_SIZE ++#if STACK_SIZE > 8000 ++#define N 1000 ++#else ++#define N (STACK_SIZE/8) ++#endif ++#else ++#define N 1000 ++#endif ++ ++int ++main () ++{ ++ int i; ++ str_t A[N]; ++ ++ for (i = 0; i < N; i++) ++ { ++ A[i].a = 0; ++ } ++ ++ for (i = 0; i < N; i++) ++ if (A[i].a != 0) ++ abort (); ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_local_var.c b/gcc/testsuite/gcc.dg/struct/w_prof_local_var.c +new file mode 100644 +index 00000000000..0cbb172f269 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/w_prof_local_var.c +@@ -0,0 +1,40 @@ ++#include <stdlib.h> ++typedef struct ++{ ++ int a; ++ float b; ++}str_t; ++ ++#ifdef STACK_SIZE ++#if STACK_SIZE > 8000 ++#define N 1000 ++#else ++#define N (STACK_SIZE/8) ++#endif ++#else ++#define N 1000 ++#endif ++ ++int ++main () ++{ ++ int i, sum; ++ ++ str_t * p = malloc (N * sizeof (str_t)); ++ if (p == NULL) ++ return 0; ++ for (i = 0; i < N; i++) ++ p[i].b = i; ++ ++ for (i = 0; i < N; i++) ++ p[i].a = p[i].b + 1; ++ ++ for (i = 0; i < N; i++) ++ if (p[i].a != p[i].b + 1) ++ abort (); ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_single_str_global.c b/gcc/testsuite/gcc.dg/struct/w_prof_single_str_global.c +new file mode 100644 +index 00000000000..f900b1349ac +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/w_prof_single_str_global.c +@@ -0,0 +1,31 @@ ++#include <stdlib.h> ++typedef struct ++{ ++ int a; ++ int b; ++}str_t; ++ ++#define N 3 ++ ++str_t str; ++ ++int ++main () ++{ ++ int i; ++ int res = 1<<(1<<N); ++ str.a = 2; ++ ++ for (i = 0; i < N; i++) ++ str.a = str.a * str.a; ++ ++ if (str.a != res) ++ abort (); ++ ++ /* POSIX ignores all but the 8 low-order bits, but other ++ environments may not. */ ++ return (str.a & 255); ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_two_strs.c b/gcc/testsuite/gcc.dg/struct/w_prof_two_strs.c +new file mode 100644 +index 00000000000..13b4cdc7088 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/w_prof_two_strs.c +@@ -0,0 +1,64 @@ ++#include <stdlib.h> ++ ++typedef struct ++{ ++ int a; ++ float b; ++}str_t1; ++ ++typedef struct ++{ ++ int c; ++ float d; ++}str_t2; ++ ++#ifdef STACK_SIZE ++#if STACK_SIZE > 16000 ++#define N 1000 ++#else ++#define N (STACK_SIZE/16) ++#endif ++#else ++#define N 1000 ++#endif ++ ++str_t1 *p1; ++str_t2 *p2; ++int num; ++ ++void ++foo (void) ++{ ++ int i; ++ ++ for (i=0; i < num; i++) ++ p2[i].c = 2; ++} ++ ++int ++main () ++{ ++ int i, r; ++ ++ r = rand (); ++ num = r > N ? N : r; ++ p1 = malloc (num * sizeof (str_t1)); ++ p2 = malloc (num * sizeof (str_t2)); ++ ++ if (p1 == NULL || p2 == NULL) ++ return 0; ++ ++ for (i = 0; i < num; i++) ++ p1[i].a = 1; ++ ++ foo (); ++ ++ for (i = 0; i < num; i++) ++ if (p1[i].a != 1 || p2[i].c != 2) ++ abort (); ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/w_ratio_cold_str.c b/gcc/testsuite/gcc.dg/struct/w_ratio_cold_str.c +new file mode 100644 +index 00000000000..dcc545964fd +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/w_ratio_cold_str.c +@@ -0,0 +1,43 @@ ++#include <stdlib.h> ++typedef struct ++{ ++ int a; ++ int b; ++}str_t1; ++ ++typedef struct ++{ ++ float a; ++ float b; ++}str_t2; ++ ++#define N1 1000 ++#define N2 100 ++str_t1 A1[N1]; ++str_t2 A2[N2]; ++ ++int ++main () ++{ ++ int i; ++ ++ for (i = 0; i < N1; i++) ++ A1[i].a = 0; ++ ++ for (i = 0; i < N2; i++) ++ A2[i].a = 0; ++ ++ for (i = 0; i < N1; i++) ++ if (A1[i].a != 0) ++ abort (); ++ ++ for (i = 0; i < N2; i++) ++ if (A2[i].a != 0) ++ abort (); ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* Arrays are not handled. */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_array_field.c b/gcc/testsuite/gcc.dg/struct/wo_prof_array_field.c +new file mode 100644 +index 00000000000..6d6375fc1ea +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_array_field.c +@@ -0,0 +1,26 @@ ++/* { dg-do compile } */ ++/* { dg-do run } */ ++ ++#include <stdlib.h> ++typedef struct basic ++{ ++ int a; ++ int b[10]; ++} type_struct; ++ ++type_struct *str1; ++ ++int main() ++{ ++ int i; ++ ++ str1 = malloc (10 * sizeof (type_struct)); ++ ++ for (i=0; i<=9; i++) ++ str1[i].a = str1[i].b[0]; ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_array_through_pointer.c b/gcc/testsuite/gcc.dg/struct/wo_prof_array_through_pointer.c +new file mode 100644 +index 00000000000..9d32134089f +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_array_through_pointer.c +@@ -0,0 +1,38 @@ ++/* { dg-do compile } */ ++/* { dg-do run } */ ++ ++#include <stdlib.h> ++typedef struct ++{ ++ int a; ++ float b; ++}str_t; ++ ++#ifdef STACK_SIZE ++#if STACK_SIZE > 8000 ++#define N 1000 ++#else ++#define N (STACK_SIZE/8) ++#endif ++#else ++#define N 1000 ++#endif ++ ++int ++main () ++{ ++ int i; ++ str_t A[N]; ++ str_t *p = A; ++ ++ for (i = 0; i < N; i++) ++ p[i].a = 0; ++ ++ for (i = 0; i < N; i++) ++ if (p[i].a != 0) ++ abort (); ++ ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_double_malloc.c b/gcc/testsuite/gcc.dg/struct/wo_prof_double_malloc.c +new file mode 100644 +index 00000000000..d79992a5302 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_double_malloc.c +@@ -0,0 +1,29 @@ ++/* { dg-do compile } */ ++/* { dg-do run } */ ++ ++#include <stdlib.h> ++ ++typedef struct test_struct ++{ ++ int a; ++ int b; ++} type_struct; ++ ++typedef type_struct **struct_pointer2; ++ ++struct_pointer2 str1; ++ ++int main() ++{ ++ int i, j; ++ ++ str1 = malloc (2 * sizeof (type_struct *)); ++ ++ for (i = 0; i <= 1; i++) ++ str1[i] = malloc (2 * sizeof (type_struct)); ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_empty_str.c b/gcc/testsuite/gcc.dg/struct/wo_prof_empty_str.c +new file mode 100644 +index 00000000000..ee9b0d76595 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_empty_str.c +@@ -0,0 +1,44 @@ ++/* { dg-do run } */ ++ ++#include <stdlib.h> ++ ++struct S { int a; struct V *b; }; ++typedef struct { int c; } T; ++typedef struct { int d; int e; } U; ++ ++void * ++fn (void *x) ++{ ++ return x; ++} ++ ++int ++foo (struct S *s) ++{ ++ T x; ++ ++ T y = *(T *)fn (&x); ++ return y.c; ++} ++ ++int ++bar (struct S *s) ++{ ++ U x; ++ ++ U y = *(U *)fn (&x); ++ return y.d + s->a; ++} ++ ++int ++main () ++{ ++ struct S s; ++ ++ foo(&s) + bar (&s); ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "No structures to transform" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_arg_to_local.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_arg_to_local.c +new file mode 100644 +index 00000000000..9ebb2b4cc96 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_arg_to_local.c +@@ -0,0 +1,44 @@ ++/* { dg-do run } */ ++ ++#include <stdlib.h> ++struct str ++{ ++ int a; ++ float b; ++}; ++ ++#ifdef STACK_SIZE ++#if STACK_SIZE > 8000 ++#define N 1000 ++#else ++#define N (STACK_SIZE/8) ++#endif ++#else ++#define N 1000 ++#endif ++ ++int ++foo (struct str * p_str) ++{ ++ static int sum = 0; ++ ++ sum = sum + p_str->a; ++ return sum; ++} ++ ++int ++main () ++{ ++ int i, sum; ++ struct str * p = malloc (N * sizeof (struct str)); ++ if (p == NULL) ++ return 0; ++ for (i = 0; i < N; i++) ++ sum = foo (p+i); ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ ++ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_return-1.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_return-1.c +new file mode 100644 +index 00000000000..d0dce8b536f +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_return-1.c +@@ -0,0 +1,33 @@ ++/* { dg-do run } */ ++/* { dg-additional-options "-fno-ipa-sra" } */ ++ ++#include <stdlib.h> ++ ++struct A { ++ int d; ++ int d1; ++}; ++ ++struct A a; ++ ++struct A *foo () __attribute__((noinline)); ++struct A *foo () ++{ ++ a.d = 5; ++ return &a; ++} ++ ++int ++main () ++{ ++ a.d = 0; ++ foo (); ++ ++ if (a.d != 5) ++ abort (); ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "has escaped. .Type escapes via a return" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_return.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_return.c +new file mode 100644 +index 00000000000..71167182d50 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_return.c +@@ -0,0 +1,32 @@ ++/* { dg-do run } */ ++/* { dg-additional-options "-fno-ipa-sra" } */ ++ ++#include <stdlib.h> ++ ++struct A { ++ int d; ++}; ++ ++struct A a; ++ ++struct A foo () __attribute__((noinline)); ++struct A foo () ++{ ++ a.d = 5; ++ return a; ++} ++ ++int ++main () ++{ ++ a.d = 0; ++ foo (); ++ ++ if (a.d != 5) ++ abort (); ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "has escaped: \"Type escapes via a return" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_str_init.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_str_init.c +new file mode 100644 +index 00000000000..74fa11f3940 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_str_init.c +@@ -0,0 +1,31 @@ ++/* { dg-do compile } */ ++/* { dg-do run } */ ++ ++#include <stdlib.h> ++typedef struct ++{ ++ int a; ++ int b; ++}str_t; ++ ++#define N 2 ++ ++str_t A[2] = {{1,1},{2,2}}; ++ ++int ++main () ++{ ++ int i; ++ ++ for (i = 0; i < N; i++) ++ A[i].b = A[i].a; ++ ++ for (i = 0; i < N; i++) ++ if (A[i].b != A[i].a) ++ abort (); ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "No structures to transform." "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_array.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_array.c +new file mode 100644 +index 00000000000..60d2466e1da +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_array.c +@@ -0,0 +1,33 @@ ++/* { dg-do compile } */ ++/* { dg-do run } */ ++ ++#include <stdlib.h> ++typedef struct ++{ ++ int a; ++ float b; ++}str_t; ++ ++#define N 1000 ++ ++typedef struct ++{ ++ str_t A[N]; ++ int c; ++}str_with_substr_t; ++ ++str_with_substr_t a; ++ ++int ++main () ++{ ++ int i; ++ ++ for (i = 0; i < N; i++) ++ a.A[i].b = 0; ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_pointer.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_pointer.c +new file mode 100644 +index 00000000000..baf617816d6 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_pointer.c +@@ -0,0 +1,48 @@ ++/* { dg-do compile } */ ++/* { dg-do run } */ ++ ++#include <stdlib.h> ++typedef struct ++{ ++ int a; ++ float b; ++}str_t; ++ ++#ifdef STACK_SIZE ++#if STACK_SIZE > 16000 ++#define N 1000 ++#else ++#define N (STACK_SIZE/16) ++#endif ++#else ++#define N 1000 ++#endif ++ ++typedef struct ++{ ++ str_t * sub_str; ++ int c; ++}str_with_substr_t; ++ ++int foo; ++ ++int ++main (void) ++{ ++ int i; ++ str_with_substr_t A[N]; ++ str_t a[N]; ++ ++ for (i=0; i < N; i++) ++ A[i].sub_str = &(a[i]); ++ ++ for (i=0; i < N; i++) ++ A[i].sub_str->a = 5; ++ ++ foo = A[56].sub_str->a; ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "has escaped...Type is used in an array" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_value.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_value.c +new file mode 100644 +index 00000000000..33fce3b2350 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_value.c +@@ -0,0 +1,45 @@ ++/* { dg-do compile } */ ++/* { dg-do run } */ ++ ++#include <stdlib.h> ++typedef struct ++{ ++ int a; ++ float b; ++}str_t; ++ ++#ifdef STACK_SIZE ++#if STACK_SIZE > 8000 ++#define N 1000 ++#else ++#define N (STACK_SIZE/8) ++#endif ++#else ++#define N 1000 ++#endif ++ ++ ++typedef struct ++{ ++ str_t sub_str; ++ int c; ++}str_with_substr_t; ++ ++int ++main () ++{ ++ int i; ++ str_with_substr_t A[N]; ++ ++ for (i = 0; i < N; i++) ++ A[i].sub_str.a = 5; ++ ++ for (i = 0; i < N; i++) ++ if (A[i].sub_str.a != 5) ++ abort (); ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "has escaped...Type is used in an array" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_global_array.c b/gcc/testsuite/gcc.dg/struct/wo_prof_global_array.c +new file mode 100644 +index 00000000000..1c5a3aa15e5 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_global_array.c +@@ -0,0 +1,32 @@ ++/* { dg-do compile } */ ++/* { dg-do run } */ ++ ++#include <stdlib.h> ++typedef struct ++{ ++ int a; ++ float b; ++}str_t; ++ ++#define N 1000 ++str_t A[N]; ++ ++int ++main () ++{ ++ int i; ++ ++ for (i = 0; i < N; i++) ++ { ++ A[i].a = 0; ++ } ++ ++ for (i = 0; i < N; i++) ++ if (A[i].a != 0) ++ abort (); ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_global_var.c b/gcc/testsuite/gcc.dg/struct/wo_prof_global_var.c +new file mode 100644 +index 00000000000..a0d1467fe9c +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_global_var.c +@@ -0,0 +1,45 @@ ++/* { dg-do compile } */ ++/* { dg-do run } */ ++ ++#include <stdlib.h> ++typedef struct ++{ ++ int a; ++ float b; ++}str_t; ++ ++#ifdef STACK_SIZE ++#if STACK_SIZE > 8000 ++#define N 1000 ++#else ++#define N (STACK_SIZE/8) ++#endif ++#else ++#define N 1000 ++#endif ++ ++str_t *p; ++ ++int ++main () ++{ ++ int i, sum; ++ ++ p = malloc (N * sizeof (str_t)); ++ if (p == NULL) ++ return 0; ++ for (i = 0; i < N; i++) ++ p[i].b = i; ++ ++ for (i = 0; i < N; i++) ++ p[i].b = p[i].a + 1; ++ ++ for (i = 0; i < N; i++) ++ if (p[i].b != p[i].a + 1) ++ abort (); ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_local_array.c b/gcc/testsuite/gcc.dg/struct/wo_prof_local_array.c +new file mode 100644 +index 00000000000..6c24e1c8b05 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_local_array.c +@@ -0,0 +1,40 @@ ++/* { dg-do compile } */ ++/* { dg-do run } */ ++ ++#include <stdlib.h> ++typedef struct ++{ ++ int a; ++ float b; ++}str_t; ++ ++#ifdef STACK_SIZE ++#if STACK_SIZE > 8000 ++#define N 1000 ++#else ++#define N (STACK_SIZE/8) ++#endif ++#else ++#define N 1000 ++#endif ++ ++int ++main () ++{ ++ int i; ++ str_t A[N]; ++ ++ for (i = 0; i < N; i++) ++ { ++ A[i].a = 0; ++ } ++ ++ for (i = 0; i < N; i++) ++ if (A[i].a != 0) ++ abort (); ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_local_var.c b/gcc/testsuite/gcc.dg/struct/wo_prof_local_var.c +new file mode 100644 +index 00000000000..8f2f8143f65 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_local_var.c +@@ -0,0 +1,43 @@ ++/* { dg-do compile } */ ++/* { dg-do run } */ ++ ++#include <stdlib.h> ++typedef struct ++{ ++ int a; ++ float b; ++}str_t; ++ ++#ifdef STACK_SIZE ++#if STACK_SIZE > 8000 ++#define N 1000 ++#else ++#define N (STACK_SIZE/8) ++#endif ++#else ++#define N 1000 ++#endif ++ ++int ++main () ++{ ++ int i, sum; ++ ++ str_t * p = malloc (N * sizeof (str_t)); ++ if (p == NULL) ++ return 0; ++ for (i = 0; i < N; i++) ++ p[i].b = i; ++ ++ for (i = 0; i < N; i++) ++ p[i].b = p[i].a + 1; ++ ++ for (i = 0; i < N; i++) ++ if (p[i].b != p[i].a + 1) ++ abort (); ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var-1.c b/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var-1.c +new file mode 100644 +index 00000000000..98bf01a6d07 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var-1.c +@@ -0,0 +1,47 @@ ++/* { dg-do compile } */ ++/* { dg-do run } */ ++ ++#include <stdlib.h> ++typedef struct ++{ ++ int a; ++ float b; ++}str_t; ++ ++#ifdef STACK_SIZE ++#if STACK_SIZE > 8000 ++#define N 1000 ++#else ++#define N (STACK_SIZE/8) ++#endif ++#else ++#define N 1000 ++#endif ++ ++int ++main () ++{ ++ long i, num; ++ ++ num = rand(); ++ num = num > N ? N : num; ++ str_t * p = malloc (num * sizeof (str_t)); ++ ++ if (p == 0) ++ return 0; ++ ++ for (i = 1; i <= num; i++) ++ p[i-1].b = i; ++ ++ for (i = 1; i <= num; i++) ++ p[i-1].a = p[i-1].b + 1; ++ ++ for (i = 0; i < num; i++) ++ if (p[i].a != p[i].b + 1) ++ abort (); ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var.c b/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var.c +new file mode 100644 +index 00000000000..66b0f967c80 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var.c +@@ -0,0 +1,47 @@ ++/* { dg-do compile } */ ++/* { dg-do run } */ ++ ++#include <stdlib.h> ++typedef struct ++{ ++ int a; ++ float b; ++}str_t; ++ ++#ifdef STACK_SIZE ++#if STACK_SIZE > 8000 ++#define N 1000 ++#else ++#define N (STACK_SIZE/8) ++#endif ++#else ++#define N 1000 ++#endif ++ ++int ++main () ++{ ++ int i, num; ++ ++ num = rand(); ++ num = num > N ? N : num; ++ str_t * p = malloc (num * sizeof (str_t)); ++ ++ if (p == 0) ++ return 0; ++ ++ for (i = 0; i < num; i++) ++ p[i].b = i; ++ ++ for (i = 0; i < num; i++) ++ p[i].a = p[i].b + 1; ++ ++ for (i = 0; i < num; i++) ++ if (p[i].a != p[i].b + 1) ++ abort (); ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_mult_field_peeling.c b/gcc/testsuite/gcc.dg/struct/wo_prof_mult_field_peeling.c +new file mode 100644 +index 00000000000..d28bcfb0237 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_mult_field_peeling.c +@@ -0,0 +1,42 @@ ++/* { dg-do compile } */ ++/* { dg-do run } */ ++ ++#include <stdlib.h> ++typedef struct ++{ ++ int a; ++ float b; ++ int c; ++ float d; ++}str_t; ++ ++#ifdef STACK_SIZE ++#if STACK_SIZE > 1600 ++#define N 100 ++#else ++#define N (STACK_SIZE/16) ++#endif ++#else ++#define N 100 ++#endif ++ ++int ++main () ++{ ++ int i; ++ str_t *p = malloc (N * sizeof (str_t)); ++ if (p == NULL) ++ return 0; ++ for (i = 0; i < N; i++) ++ p[i].a = 5; ++ ++ for (i = 0; i < N; i++) ++ if (p[i].a != 5) ++ abort (); ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* Two more fields structure is not splitted. */ ++/* { dg-final { scan-ipa-dump "No structures to transform." "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_global.c b/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_global.c +new file mode 100644 +index 00000000000..37a6a43a859 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_global.c +@@ -0,0 +1,34 @@ ++/* { dg-do compile } */ ++/* { dg-do run } */ ++ ++#include <stdlib.h> ++typedef struct ++{ ++ int a; ++ int b; ++}str_t; ++ ++#define N 3 ++ ++str_t str; ++ ++int ++main () ++{ ++ int i; ++ int res = 1<<(1<<N); ++ str.a = 2; ++ ++ for (i = 0; i < N; i++) ++ str.a = str.a * str.a; ++ ++ if (str.a != res) ++ abort (); ++ ++ /* POSIX ignores all but the 8 low-order bits, but other ++ environments may not. */ ++ return (str.a & 255); ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_local.c b/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_local.c +new file mode 100644 +index 00000000000..ca9a8efcf8f +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_local.c +@@ -0,0 +1,34 @@ ++/* { dg-do compile } */ ++/* { dg-do run } */ ++ ++#include <stdlib.h> ++typedef struct ++{ ++ int a; ++ int b; ++}str_t; ++ ++#define N 3 ++ ++int ++main () ++{ ++ int i; ++ int res = 1<<(1<<N); ++ str_t str; ++ ++ str.a = 2; ++ ++ for (i = 0; i < N; i++) ++ str.a = str.a * str.a; ++ ++ if (str.a != res) ++ abort (); ++ ++ /* POSIX ignores all but the 8 low-order bits, but other ++ environments may not. */ ++ return (str.a & 255); ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "No structures to transform" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_pointer.c b/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_pointer.c +new file mode 100644 +index 00000000000..baa95bddf6f +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_pointer.c +@@ -0,0 +1,38 @@ ++/* { dg-do compile } */ ++/* { dg-do run } */ ++ ++#include <stdlib.h> ++typedef struct ++{ ++ int a; ++ int *b; ++}str_t; ++ ++#define N 3 ++ ++str_t *p; ++ ++int ++main () ++{ ++ str_t str; ++ int i; ++ int res = 1 << (1 << N); ++ p = &str; ++ str.a = 2; ++ ++ p->b = &(p->a); ++ ++ for (i=0; i < N; i++) ++ p->a = *(p->b)*(*(p->b)); ++ ++ if (p->a != res) ++ abort (); ++ ++ /* POSIX ignores all but the 8 low-order bits, but other ++ environments may not. */ ++ return (p->a & 255); ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "has escaped...Type escapes a cast to a different" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_two_strs.c b/gcc/testsuite/gcc.dg/struct/wo_prof_two_strs.c +new file mode 100644 +index 00000000000..cba92e99555 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_two_strs.c +@@ -0,0 +1,67 @@ ++/* { dg-do compile } */ ++/* { dg-do run } */ ++ ++#include <stdlib.h> ++ ++typedef struct ++{ ++ int a; ++ float b; ++}str_t1; ++ ++typedef struct ++{ ++ int c; ++ float d; ++}str_t2; ++ ++#ifdef STACK_SIZE ++#if STACK_SIZE > 16000 ++#define N 1000 ++#else ++#define N (STACK_SIZE/16) ++#endif ++#else ++#define N 1000 ++#endif ++ ++str_t1 *p1; ++str_t2 *p2; ++int num; ++ ++void ++foo (void) ++{ ++ int i; ++ ++ for (i=0; i < num; i++) ++ p2[i].c = 2; ++} ++ ++int ++main () ++{ ++ int i, r; ++ ++ r = rand (); ++ num = r > N ? N : r; ++ p1 = malloc (num * sizeof (str_t1)); ++ p2 = malloc (num * sizeof (str_t2)); ++ ++ if (p1 == NULL || p2 == NULL) ++ return 0; ++ ++ for (i = 0; i < num; i++) ++ p1[i].a = 1; ++ ++ foo (); ++ ++ for (i = 0; i < num; i++) ++ if (p1[i].a != 1 || p2[i].c != 2) ++ abort (); ++ ++ return 0; ++} ++ ++/*--------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */ +diff --git a/gcc/timevar.def b/gcc/timevar.def +index 29479205c41..d6a05562c2f 100644 +--- a/gcc/timevar.def ++++ b/gcc/timevar.def +@@ -80,6 +80,7 @@ DEFTIMEVAR (TV_IPA_CONSTANT_PROP , "ipa cp") + DEFTIMEVAR (TV_IPA_INLINING , "ipa inlining heuristics") + DEFTIMEVAR (TV_IPA_FNSPLIT , "ipa function splitting") + DEFTIMEVAR (TV_IPA_COMDATS , "ipa comdats") ++DEFTIMEVAR (TV_IPA_STRUCT_REORG , "ipa struct reorg optimization") + DEFTIMEVAR (TV_IPA_OPT , "ipa various optimizations") + DEFTIMEVAR (TV_IPA_LTO_DECOMPRESS , "lto stream decompression") + DEFTIMEVAR (TV_IPA_LTO_COMPRESS , "lto stream compression") +diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h +index a97c7bd36fb..d8355754ffa 100644 +--- a/gcc/tree-pass.h ++++ b/gcc/tree-pass.h +@@ -509,6 +509,7 @@ extern ipa_opt_pass_d *make_pass_ipa_odr (gcc::context *ctxt); + extern ipa_opt_pass_d *make_pass_ipa_reference (gcc::context *ctxt); + extern ipa_opt_pass_d *make_pass_ipa_hsa (gcc::context *ctxt); + extern ipa_opt_pass_d *make_pass_ipa_pure_const (gcc::context *ctxt); ++extern simple_ipa_opt_pass *make_pass_ipa_struct_reorg (gcc::context *ctxt); + extern simple_ipa_opt_pass *make_pass_ipa_pta (gcc::context *ctxt); + extern simple_ipa_opt_pass *make_pass_ipa_tm (gcc::context *ctxt); + extern simple_ipa_opt_pass *make_pass_target_clone (gcc::context *ctxt); +-- +2.21.0.windows.1 + diff --git a/0015-CompleteStructReorg-Complete-Structure-Reorganizatio.patch b/0015-CompleteStructReorg-Complete-Structure-Reorganizatio.patch new file mode 100644 index 0000000..742056e --- /dev/null +++ b/0015-CompleteStructReorg-Complete-Structure-Reorganizatio.patch @@ -0,0 +1,2134 @@ +From 644c3b8f01f2249dd552cda9e2429b479ebe0af8 Mon Sep 17 00:00:00 2001 +From: xiezhiheng <xiezhiheng@huawei.com> +Date: Thu, 15 Jul 2021 21:44:03 -0400 +Subject: [PATCH 15/22] [CompleteStructReorg] Complete Structure Reorganization + +Introduce complete structure reorganization based on original +structure reorganization optimization, which change array of +structure to structure of array in order to better utilize +spatial locality. + +diff --git a/gcc/ipa-struct-reorg/escapes.def b/gcc/ipa-struct-reorg/escapes.def +index 929279c8faf..9020cc48952 100644 +--- a/gcc/ipa-struct-reorg/escapes.def ++++ b/gcc/ipa-struct-reorg/escapes.def +@@ -56,5 +56,7 @@ DEF_ESCAPE (escape_non_optimize, "Type used by a function which turns off struct + DEF_ESCAPE (escape_array, "Type is used in an array [not handled yet]") + DEF_ESCAPE (escape_ptr_ptr, "Type is used in a pointer to a pointer [not handled yet]") + DEF_ESCAPE (escape_return, "Type escapes via a return [not handled yet]") ++DEF_ESCAPE (escape_separate_instance, "Type escapes via a separate instance") ++DEF_ESCAPE (escape_unhandled_rewrite, "Type escapes via a unhandled rewrite stmt") + + #undef DEF_ESCAPE +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +index 8d1ddc82877..5a19ea0bb40 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -96,6 +96,7 @@ along with GCC; see the file COPYING3. If not see + #include "ipa-struct-reorg.h" + #include "tree-eh.h" + #include "bitmap.h" ++#include "cfgloop.h" + #include "ipa-param-manipulation.h" + #include "tree-ssa-live.h" /* For remove_unused_locals. */ + +@@ -104,6 +105,7 @@ along with GCC; see the file COPYING3. If not see + namespace { + + using namespace struct_reorg; ++using namespace struct_relayout; + + /* Return true iff TYPE is stdarg va_list type. */ + +@@ -159,6 +161,14 @@ handled_type (tree type) + return false; + } + ++enum srmode ++{ ++ NORMAL = 0, ++ COMPLETE_STRUCT_RELAYOUT ++}; ++ ++static bool is_result_of_mult (tree arg, tree *num, tree struct_size); ++ + } // anon namespace + + namespace struct_reorg { +@@ -248,7 +258,8 @@ srtype::srtype (tree type) + : type (type), + chain_type (false), + escapes (does_not_escape), +- visited (false) ++ visited (false), ++ has_alloc_array (0) + { + for (int i = 0; i < max_split; i++) + newtype[i] = NULL_TREE; +@@ -448,13 +459,6 @@ srtype::dump (FILE *f) + fn->simple_dump (f); + } + fprintf (f, "\n }\n"); +- fprintf (f, "\n field_sites = {"); +- FOR_EACH_VEC_ELT (field_sites, i, field) +- { +- fprintf (f, " \n"); +- field->simple_dump (f); +- } +- fprintf (f, "\n }\n"); + fprintf (f, "}\n"); + } + +@@ -598,15 +602,7 @@ srtype::create_new_type (void) + + maxclusters++; + +- const char *tname = NULL; +- +- if (TYPE_NAME (type) != NULL) +- { +- if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) +- tname = IDENTIFIER_POINTER (TYPE_NAME (type)); +- else if (DECL_NAME (TYPE_NAME (type)) != NULL) +- tname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); +- } ++ const char *tname = get_type_name (type); + + for (unsigned i = 0; i < maxclusters; i++) + { +@@ -620,7 +616,8 @@ srtype::create_new_type (void) + if (tname) + { + name = concat (tname, ".reorg.", id, NULL); +- TYPE_NAME (newtype[i]) = get_identifier (name); ++ TYPE_NAME (newtype[i]) = build_decl (UNKNOWN_LOCATION, TYPE_DECL, ++ get_identifier (name), newtype[i]); + free (name); + } + } +@@ -641,6 +638,10 @@ srtype::create_new_type (void) + { + TYPE_FIELDS (newtype[i]) = newfields[i]; + layout_type (newtype[i]); ++ if (TYPE_NAME (newtype[i]) != NULL) ++ { ++ layout_decl (TYPE_NAME (newtype[i]), 0); ++ } + } + + warn_padded = save_warn_padded; +@@ -805,12 +806,6 @@ srfield::dump (FILE *f) + fprintf (f, ", offset = " HOST_WIDE_INT_PRINT_DEC, offset); + fprintf (f, ", type = "); + print_generic_expr (f, fieldtype); +- if (type) +- { +- fprintf (f, "( srtype = "); +- type->simple_dump (f); +- fprintf (f, ")"); +- } + fprintf (f, "\n}\n"); + } + +@@ -820,7 +815,10 @@ srfield::dump (FILE *f) + void + srfield::simple_dump (FILE *f) + { +- fprintf (f, "field (%d)", DECL_UID (fielddecl)); ++ if (fielddecl) ++ { ++ fprintf (f, "field (%d)", DECL_UID (fielddecl)); ++ } + } + + /* Dump out the access structure to FILE. */ +@@ -864,21 +862,123 @@ srdecl::dump (FILE *file) + + } // namespace struct_reorg + ++namespace struct_relayout { ++ ++/* Complete Structure Relayout Optimization. ++ It reorganizes all structure members, and puts same member together. ++ struct s { ++ long a; ++ int b; ++ struct s* c; ++ }; ++ Array looks like ++ abcabcabcabc... ++ will be transformed to ++ aaaa...bbbb...cccc... ++*/ ++ ++#define GPTR_SIZE(i) \ ++ TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (gptr[i]))) ++ ++unsigned transformed = 0; ++ ++unsigned ++csrtype::calculate_field_num (tree field_offset) ++{ ++ if (field_offset == NULL) ++ { ++ return 0; ++ } ++ ++ HOST_WIDE_INT off = int_byte_position (field_offset); ++ unsigned i = 1; ++ for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) ++ { ++ if (off == int_byte_position (field)) ++ { ++ return i; ++ } ++ i++; ++ } ++ return 0; ++} ++ ++void ++csrtype::init_type_info (void) ++{ ++ if (!type) ++ { ++ return; ++ } ++ new_size = old_size = tree_to_uhwi (TYPE_SIZE_UNIT (type)); ++ ++ /* Close enough to pad to improve performance. ++ 33~63 should pad to 64 but 33~48 (first half) are too far away, and ++ 65~127 should pad to 128 but 65~96 (first half) are too far away. */ ++ if (old_size > 48 && old_size < 64) ++ { ++ new_size = 64; ++ } ++ if (old_size > 96 && old_size < 128) ++ { ++ new_size = 128; ++ } ++ ++ /* For performance reasons, only allow structure size ++ that is a power of 2 and not too big. */ ++ if (new_size != 1 && new_size != 2 ++ && new_size != 4 && new_size != 8 ++ && new_size != 16 && new_size != 32 ++ && new_size != 64 && new_size != 128) ++ { ++ new_size = 0; ++ field_count = 0; ++ return; ++ } ++ ++ unsigned i = 0; ++ for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) ++ { ++ if (TREE_CODE (field) == FIELD_DECL) ++ { ++ i++; ++ } ++ } ++ field_count = i; ++ ++ struct_size = build_int_cstu (TREE_TYPE (TYPE_SIZE_UNIT (type)), ++ new_size); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "Type: "); ++ print_generic_expr (dump_file, type); ++ fprintf (dump_file, " has %d members.\n", field_count); ++ fprintf (dump_file, "Modify struct size from %ld to %ld.\n", ++ old_size, new_size); ++ } ++} ++ ++} // namespace struct_relayout ++ + namespace { + ++/* Structure definition for ipa_struct_reorg and ipa_struct_relayout. */ ++ + struct ipa_struct_reorg + { ++public: + // Constructors + ipa_struct_reorg(void) + : current_function (NULL), +- done_recording(false) ++ done_recording (false), ++ current_mode (NORMAL) + { + } + +- // public methods +- unsigned execute(void); ++ unsigned execute (enum srmode mode); + void mark_type_as_escape (tree type, escape_type, gimple *stmt = NULL); +-private: ++ + // fields + auto_vec_del<srtype> types; + auto_vec_del<srfunction> functions; +@@ -886,8 +986,8 @@ private: + srfunction *current_function; + + bool done_recording; ++ srmode current_mode; + +- // private methods + void dump_types (FILE *f); + void dump_types_escaped (FILE *f); + void dump_functions (FILE *f); +@@ -917,6 +1017,7 @@ private: + void maybe_record_allocation_site (cgraph_node *, gimple *); + void record_stmt_expr (tree expr, cgraph_node *node, gimple *stmt); + void mark_expr_escape(tree, escape_type, gimple *stmt); ++ bool handled_allocation_stmt (gimple *stmt); + tree allocate_size (srtype *t, gimple *stmt); + + void mark_decls_in_as_not_needed (tree fn); +@@ -932,6 +1033,7 @@ private: + bool get_type_field (tree expr, tree &base, bool &indirect, srtype *&type, srfield *&field, bool &realpart, bool &imagpart, bool &address, bool should_create = false, bool can_escape = false); + bool wholeaccess (tree expr, tree base, tree accesstype, srtype *t); + ++ void check_alloc_num (gimple *stmt, srtype *type); + void check_definition (srdecl *decl, vec<srdecl*>&); + void check_uses (srdecl *decl, vec<srdecl*>&); + void check_use (srdecl *decl, gimple *stmt, vec<srdecl*>&); +@@ -944,8 +1046,644 @@ private: + + bool has_rewritten_type (srfunction*); + void maybe_mark_or_record_other_side (tree side, tree other, gimple *stmt); ++ unsigned execute_struct_relayout (void); ++}; ++ ++struct ipa_struct_relayout ++{ ++public: ++ // fields ++ tree gptr[max_relayout_split + 1]; ++ csrtype ctype; ++ ipa_struct_reorg *sr; ++ cgraph_node *current_node; ++ ++ // Constructors ++ ipa_struct_relayout (tree type, ipa_struct_reorg *sr_) ++ { ++ ctype.type = type; ++ sr = sr_; ++ current_node = NULL; ++ for (int i = 0; i < max_relayout_split + 1; i++) ++ { ++ gptr[i] = NULL; ++ } ++ } ++ ++ // Methods ++ tree create_new_vars (tree type, const char *name); ++ void create_global_ptrs (void); ++ unsigned int rewrite (void); ++ void rewrite_stmt_in_function (void); ++ bool rewrite_debug (gimple *stmt, gimple_stmt_iterator *gsi); ++ bool rewrite_stmt (gimple *stmt, gimple_stmt_iterator *gsi); ++ bool handled_allocation_stmt (gcall *stmt); ++ void init_global_ptrs (gcall *stmt, gimple_stmt_iterator *gsi); ++ bool check_call_uses (gcall *stmt); ++ bool rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi); ++ tree create_ssa (tree node, gimple_stmt_iterator *gsi); ++ bool is_candidate (tree xhs); ++ tree rewrite_address (tree xhs, gimple_stmt_iterator *gsi); ++ tree rewrite_offset (tree offset, HOST_WIDE_INT num); ++ bool rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi); ++ bool maybe_rewrite_cst (tree cst, gimple_stmt_iterator *gsi, ++ HOST_WIDE_INT ×); ++ unsigned int execute (void); + }; + ++} // anon namespace ++ ++namespace { ++ ++/* Methods for ipa_struct_relayout. */ ++ ++static void ++set_var_attributes (tree var) ++{ ++ if (!var) ++ { ++ return; ++ } ++ gcc_assert (TREE_CODE (var) == VAR_DECL); ++ ++ DECL_ARTIFICIAL (var) = 1; ++ DECL_EXTERNAL (var) = 0; ++ TREE_STATIC (var) = 1; ++ TREE_PUBLIC (var) = 0; ++ TREE_USED (var) = 1; ++ DECL_CONTEXT (var) = NULL; ++ TREE_THIS_VOLATILE (var) = 0; ++ TREE_ADDRESSABLE (var) = 0; ++ TREE_READONLY (var) = 0; ++ if (is_global_var (var)) ++ { ++ set_decl_tls_model (var, TLS_MODEL_NONE); ++ } ++} ++ ++tree ++ipa_struct_relayout::create_new_vars (tree type, const char *name) ++{ ++ gcc_assert (type); ++ tree new_type = build_pointer_type (type); ++ ++ tree new_name = NULL; ++ if (name) ++ { ++ new_name = get_identifier (name); ++ } ++ ++ tree new_var = build_decl (UNKNOWN_LOCATION, VAR_DECL, new_name, new_type); ++ ++ /* set new_var's attributes. */ ++ set_var_attributes (new_var); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "Created new var: "); ++ print_generic_expr (dump_file, new_var); ++ fprintf (dump_file, "\n"); ++ } ++ return new_var; ++} ++ ++void ++ipa_struct_relayout::create_global_ptrs (void) ++{ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "Create global gptrs: {\n"); ++ } ++ ++ char *gptr0_name = NULL; ++ const char *type_name = get_type_name (ctype.type); ++ ++ if (type_name) ++ { ++ gptr0_name = concat (type_name, "_gptr0", NULL); ++ } ++ tree var_gptr0 = create_new_vars (ctype.type, gptr0_name); ++ gptr[0] = var_gptr0; ++ varpool_node::add (var_gptr0); ++ ++ unsigned i = 1; ++ for (tree field = TYPE_FIELDS (ctype.type); field; ++ field = DECL_CHAIN (field)) ++ { ++ if (TREE_CODE (field) == FIELD_DECL) ++ { ++ tree type = TREE_TYPE (field); ++ ++ char *name = NULL; ++ char id[10] = {0}; ++ sprintf (id, "%d", i); ++ const char *decl_name = IDENTIFIER_POINTER (DECL_NAME (field)); ++ ++ if (type_name && decl_name) ++ { ++ name = concat (type_name, "_", decl_name, "_gptr", id, NULL); ++ } ++ tree var = create_new_vars (type, name); ++ ++ gptr[i] = var; ++ varpool_node::add (var); ++ i++; ++ } ++ } ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nTotally create %d gptrs. }\n\n", i); ++ } ++ gcc_assert (ctype.field_count == i - 1); ++} ++ ++void ++ipa_struct_relayout::rewrite_stmt_in_function (void) ++{ ++ gcc_assert (cfun); ++ ++ basic_block bb = NULL; ++ gimple_stmt_iterator si; ++ FOR_EACH_BB_FN (bb, cfun) ++ { ++ for (si = gsi_start_bb (bb); !gsi_end_p (si);) ++ { ++ gimple *stmt = gsi_stmt (si); ++ if (rewrite_stmt (stmt, &si)) ++ { ++ gsi_remove (&si, true); ++ } ++ else ++ { ++ gsi_next (&si); ++ } ++ } ++ } ++ ++ /* Debug statements need to happen after all other statements ++ have changed. */ ++ FOR_EACH_BB_FN (bb, cfun) ++ { ++ for (si = gsi_start_bb (bb); !gsi_end_p (si);) ++ { ++ gimple *stmt = gsi_stmt (si); ++ if (gimple_code (stmt) == GIMPLE_DEBUG ++ && rewrite_debug (stmt, &si)) ++ { ++ gsi_remove (&si, true); ++ } ++ else ++ { ++ gsi_next (&si); ++ } ++ } ++ } ++} ++ ++unsigned int ++ipa_struct_relayout::rewrite (void) ++{ ++ cgraph_node *cnode = NULL; ++ function *fn = NULL; ++ FOR_EACH_FUNCTION (cnode) ++ { ++ if (!cnode->real_symbol_p () || !cnode->has_gimple_body_p ()) ++ { ++ continue; ++ } ++ if (cnode->definition) ++ { ++ fn = DECL_STRUCT_FUNCTION (cnode->decl); ++ if (fn == NULL) ++ { ++ continue; ++ } ++ ++ current_node = cnode; ++ push_cfun (fn); ++ ++ rewrite_stmt_in_function (); ++ ++ update_ssa (TODO_update_ssa_only_virtuals); ++ ++ if (flag_tree_pta) ++ { ++ compute_may_aliases (); ++ } ++ ++ remove_unused_locals (); ++ ++ cgraph_edge::rebuild_edges (); ++ ++ free_dominance_info (CDI_DOMINATORS); ++ ++ pop_cfun (); ++ current_node = NULL; ++ } ++ } ++ return TODO_verify_all; ++} ++ ++bool ++ipa_struct_relayout::rewrite_debug (gimple *stmt, gimple_stmt_iterator *gsi) ++{ ++ /* Delete debug gimple now. */ ++ return true; ++} ++ ++bool ++ipa_struct_relayout::rewrite_stmt (gimple *stmt, gimple_stmt_iterator *gsi) ++{ ++ switch (gimple_code (stmt)) ++ { ++ case GIMPLE_ASSIGN: ++ return rewrite_assign (as_a <gassign *> (stmt), gsi); ++ case GIMPLE_CALL: ++ return rewrite_call (as_a <gcall *> (stmt), gsi); ++ default: ++ break; ++ } ++ return false; ++} ++ ++bool ++ipa_struct_relayout::handled_allocation_stmt (gcall *stmt) ++{ ++ if (gimple_call_builtin_p (stmt, BUILT_IN_CALLOC)) ++ { ++ return true; ++ } ++ return false; ++} ++ ++void ++ipa_struct_relayout::init_global_ptrs (gcall *stmt, gimple_stmt_iterator *gsi) ++{ ++ gcc_assert (handled_allocation_stmt (stmt)); ++ ++ tree lhs = gimple_call_lhs (stmt); ++ ++ /* Case that gimple is at the end of bb. */ ++ if (gsi_one_before_end_p (*gsi)) ++ { ++ gassign *gptr0 = gimple_build_assign (gptr[0], lhs); ++ gsi_insert_after (gsi, gptr0, GSI_SAME_STMT); ++ } ++ gsi_next (gsi); ++ ++ /* Emit gimple gptr0 = _X and gptr1 = _X. */ ++ gassign *gptr0 = gimple_build_assign (gptr[0], lhs); ++ gsi_insert_before (gsi, gptr0, GSI_SAME_STMT); ++ gassign *gptr1 = gimple_build_assign (gptr[1], lhs); ++ gsi_insert_before (gsi, gptr1, GSI_SAME_STMT); ++ ++ /* Emit gimple gptr_[i] = gptr_[i-1] + _Y[gap]. */ ++ for (unsigned i = 2; i <= ctype.field_count; i++) ++ { ++ gimple *new_stmt = NULL; ++ tree gptr_i_prev_ssa = create_ssa (gptr[i-1], gsi); ++ tree gptr_i_ssa = make_ssa_name (TREE_TYPE (gptr[i-1])); ++ ++ /* Emit gimple _Y[gap] = N * sizeof (member). */ ++ tree member_gap = gimplify_build2 (gsi, MULT_EXPR, ++ long_unsigned_type_node, ++ gimple_call_arg (stmt, 0), ++ GPTR_SIZE (i-1)); ++ ++ new_stmt = gimple_build_assign (gptr_i_ssa, POINTER_PLUS_EXPR, ++ gptr_i_prev_ssa, member_gap); ++ gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT); ++ ++ gassign *gptr_i = gimple_build_assign (gptr[i], gptr_i_ssa); ++ gsi_insert_before (gsi, gptr_i, GSI_SAME_STMT); ++ } ++ gsi_prev (gsi); ++} ++ ++bool ++ipa_struct_relayout::check_call_uses (gcall *stmt) ++{ ++ gcc_assert (current_node); ++ srfunction *fn = sr->find_function (current_node); ++ tree lhs = gimple_call_lhs (stmt); ++ ++ if (fn == NULL) ++ { ++ return false; ++ } ++ ++ srdecl *d = fn->find_decl (lhs); ++ if (d == NULL) ++ { ++ return false; ++ } ++ if (types_compatible_p (d->type->type, ctype.type)) ++ { ++ return true; ++ } ++ ++ return false; ++} ++ ++bool ++ipa_struct_relayout::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi) ++{ ++ if (handled_allocation_stmt (stmt)) ++ { ++ /* Rewrite stmt _X = calloc (N, sizeof (struct)). */ ++ tree size = gimple_call_arg (stmt, 1); ++ if (TREE_CODE (size) != INTEGER_CST) ++ { ++ return false; ++ } ++ if (tree_to_uhwi (size) != ctype.old_size) ++ { ++ return false; ++ } ++ if (!check_call_uses (stmt)) ++ { ++ return false; ++ } ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "Rewrite allocation call:\n"); ++ print_gimple_stmt (dump_file, stmt, 0); ++ fprintf (dump_file, "to\n"); ++ } ++ ++ /* Modify sizeof (struct). */ ++ gimple_call_set_arg (stmt, 1, ctype.struct_size); ++ update_stmt (stmt); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ print_gimple_stmt (dump_file, stmt, 0); ++ fprintf (dump_file, "\n"); ++ } ++ ++ init_global_ptrs (stmt, gsi); ++ } ++ return false; ++} ++ ++tree ++ipa_struct_relayout::create_ssa (tree node, gimple_stmt_iterator *gsi) ++{ ++ gcc_assert (TREE_CODE (node) == VAR_DECL); ++ tree node_ssa = make_ssa_name (TREE_TYPE (node)); ++ gassign *stmt = gimple_build_assign (node_ssa, node); ++ gsi_insert_before (gsi, stmt, GSI_SAME_STMT); ++ return node_ssa; ++} ++ ++bool ++ipa_struct_relayout::is_candidate (tree xhs) ++{ ++ if (TREE_CODE (xhs) != COMPONENT_REF) ++ { ++ return false; ++ } ++ tree mem = TREE_OPERAND (xhs, 0); ++ if (TREE_CODE (mem) == MEM_REF) ++ { ++ tree type = TREE_TYPE (mem); ++ if (types_compatible_p (type, ctype.type)) ++ { ++ return true; ++ } ++ } ++ return false; ++} ++ ++tree ++ipa_struct_relayout::rewrite_address (tree xhs, gimple_stmt_iterator *gsi) ++{ ++ tree mem_ref = TREE_OPERAND (xhs, 0); ++ tree pointer = TREE_OPERAND (mem_ref, 0); ++ tree pointer_offset = TREE_OPERAND (mem_ref, 1); ++ tree field = TREE_OPERAND (xhs, 1); ++ ++ tree pointer_ssa = fold_convert (long_unsigned_type_node, pointer); ++ tree gptr0_ssa = fold_convert (long_unsigned_type_node, gptr[0]); ++ ++ /* Emit gimple _X1 = ptr - gptr0. */ ++ tree step1 = gimplify_build2 (gsi, MINUS_EXPR, long_unsigned_type_node, ++ pointer_ssa, gptr0_ssa); ++ ++ /* Emit gimple _X2 = _X1 / sizeof (struct). */ ++ tree step2 = gimplify_build2 (gsi, TRUNC_DIV_EXPR, long_unsigned_type_node, ++ step1, ctype.struct_size); ++ ++ unsigned field_num = ctype.calculate_field_num (field); ++ gcc_assert (field_num > 0 && field_num <= ctype.field_count); ++ ++ /* Emit gimple _X3 = _X2 * sizeof (member). */ ++ tree step3 = gimplify_build2 (gsi, MULT_EXPR, long_unsigned_type_node, ++ step2, GPTR_SIZE (field_num)); ++ ++ /* Emit gimple _X4 = gptr[I]. */ ++ tree gptr_field_ssa = create_ssa (gptr[field_num], gsi); ++ tree new_address = make_ssa_name (TREE_TYPE (gptr[field_num])); ++ gassign *new_stmt = gimple_build_assign (new_address, POINTER_PLUS_EXPR, ++ gptr_field_ssa, step3); ++ gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT); ++ ++ /* MEM_REF with nonzero offset like ++ MEM[ptr + sizeof (struct)] = 0B ++ should be transformed to ++ MEM[gptr + sizeof (member)] = 0B ++ */ ++ HOST_WIDE_INT size ++ = tree_to_shwi (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (new_address)))); ++ tree new_size = rewrite_offset (pointer_offset, size); ++ if (new_size) ++ { ++ TREE_OPERAND (mem_ref, 1) = new_size; ++ } ++ ++ /* Update mem_ref pointer. */ ++ TREE_OPERAND (mem_ref, 0) = new_address; ++ ++ /* Update mem_ref TREE_TYPE. */ ++ TREE_TYPE (mem_ref) = TREE_TYPE (TREE_TYPE (new_address)); ++ ++ return mem_ref; ++} ++ ++tree ++ipa_struct_relayout::rewrite_offset (tree offset, HOST_WIDE_INT num) ++{ ++ if (TREE_CODE (offset) == INTEGER_CST) ++ { ++ bool sign = false; ++ HOST_WIDE_INT off = TREE_INT_CST_LOW (offset); ++ if (off == 0) ++ { ++ return NULL; ++ } ++ if (off < 0) ++ { ++ off = -off; ++ sign = true; ++ } ++ if (off % ctype.old_size == 0) ++ { ++ HOST_WIDE_INT times = off / ctype.old_size; ++ times = sign ? -times : times; ++ return build_int_cst (TREE_TYPE (offset), num * times); ++ } ++ } ++ return NULL; ++} ++ ++#define REWRITE_ASSIGN_TREE_IN_STMT(node) \ ++do \ ++{ \ ++ tree node = gimple_assign_##node (stmt); \ ++ if (node && is_candidate (node)) \ ++ { \ ++ tree mem_ref = rewrite_address (node, gsi); \ ++ gimple_assign_set_##node (stmt, mem_ref); \ ++ update_stmt (stmt); \ ++ } \ ++} while (0) ++ ++/* COMPONENT_REF = exp => MEM_REF = exp ++ / \ / \ ++ MEM_REF field gptr offset ++ / \ ++ pointer offset ++*/ ++bool ++ipa_struct_relayout::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) ++{ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "Maybe rewrite assign:\n"); ++ print_gimple_stmt (dump_file, stmt, 0); ++ fprintf (dump_file, "to\n"); ++ } ++ ++ switch (gimple_num_ops (stmt)) ++ { ++ case 4: REWRITE_ASSIGN_TREE_IN_STMT (rhs3); // FALLTHRU ++ case 3: ++ { ++ REWRITE_ASSIGN_TREE_IN_STMT (rhs2); ++ tree rhs2 = gimple_assign_rhs2 (stmt); ++ if (rhs2 && TREE_CODE (rhs2) == INTEGER_CST) ++ { ++ /* Handle pointer++ and pointer-- or ++ factor is euqal to struct size. */ ++ HOST_WIDE_INT times = 1; ++ if (maybe_rewrite_cst (rhs2, gsi, times)) ++ { ++ tree tmp = build_int_cst ( ++ TREE_TYPE (TYPE_SIZE_UNIT (ctype.type)), ++ ctype.new_size * times); ++ gimple_assign_set_rhs2 (stmt, tmp); ++ update_stmt (stmt); ++ } ++ } ++ } // FALLTHRU ++ case 2: REWRITE_ASSIGN_TREE_IN_STMT (rhs1); // FALLTHRU ++ case 1: REWRITE_ASSIGN_TREE_IN_STMT (lhs); // FALLTHRU ++ case 0: break; ++ default: gcc_unreachable (); ++ } ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ print_gimple_stmt (dump_file, stmt, 0); ++ fprintf (dump_file, "\n"); ++ } ++ return false; ++} ++ ++bool ++ipa_struct_relayout::maybe_rewrite_cst (tree cst, gimple_stmt_iterator *gsi, ++ HOST_WIDE_INT ×) ++{ ++ bool ret = false; ++ gcc_assert (TREE_CODE (cst) == INTEGER_CST); ++ ++ gimple *stmt = gsi_stmt (*gsi); ++ if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) ++ { ++ tree lhs = gimple_assign_lhs (stmt); ++ tree rhs1 = gimple_assign_rhs1 (stmt); ++ if (types_compatible_p (inner_type (TREE_TYPE (rhs1)), ctype.type) ++ || types_compatible_p (inner_type (TREE_TYPE (lhs)), ctype.type)) ++ { ++ tree num = NULL; ++ if (is_result_of_mult (cst, &num, TYPE_SIZE_UNIT (ctype.type))) ++ { ++ times = TREE_INT_CST_LOW (num); ++ return true; ++ } ++ } ++ } ++ ++ if (gimple_assign_rhs_code (stmt) == MULT_EXPR) ++ { ++ if (gsi_one_before_end_p (*gsi)) ++ { ++ return false; ++ } ++ gsi_next (gsi); ++ gimple *stmt2 = gsi_stmt (*gsi); ++ ++ if (gimple_code (stmt2) == GIMPLE_ASSIGN ++ && gimple_assign_rhs_code (stmt2) == POINTER_PLUS_EXPR) ++ { ++ tree lhs = gimple_assign_lhs (stmt2); ++ tree rhs1 = gimple_assign_rhs1 (stmt2); ++ if (types_compatible_p (inner_type (TREE_TYPE (rhs1)), ctype.type) ++ || types_compatible_p (inner_type (TREE_TYPE (lhs)), ctype.type)) ++ { ++ tree num = NULL; ++ if (is_result_of_mult (cst, &num, TYPE_SIZE_UNIT (ctype.type))) ++ { ++ times = TREE_INT_CST_LOW (num); ++ ret = true; ++ } ++ } ++ } ++ gsi_prev (gsi); ++ return ret; ++ } ++ return false; ++} ++ ++unsigned int ++ipa_struct_relayout::execute (void) ++{ ++ ctype.init_type_info (); ++ if (ctype.field_count < min_relayout_split ++ || ctype.field_count > max_relayout_split) ++ { ++ return 0; ++ } ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "Complete Struct Relayout Type: "); ++ print_generic_expr (dump_file, ctype.type); ++ fprintf (dump_file, "\n"); ++ } ++ transformed++; ++ ++ create_global_ptrs (); ++ return rewrite (); ++} ++ ++} // anon namespace ++ ++namespace { ++ ++/* Methods for ipa_struct_reorg. */ ++ + /* Dump all of the recorded types to file F. */ + + void +@@ -1141,8 +1879,10 @@ ipa_struct_reorg::record_type (tree type) + f->type = t1; + t1->add_field_site (f); + } +- if (t1 == type1) +- type1->mark_escape (escape_rescusive_type, NULL); ++ if (t1 == type1 && current_mode != COMPLETE_STRUCT_RELAYOUT) ++ { ++ type1->mark_escape (escape_rescusive_type, NULL); ++ } + } + } + } +@@ -1279,6 +2019,14 @@ ipa_struct_reorg::record_var (tree decl, escape_type escapes, int arg) + else + e = escape_type_volatile_array_or_ptrptr (TREE_TYPE (decl)); + ++ /* Separate instance is hard to trace in complete struct ++ relayout optimization. */ ++ if (current_mode == COMPLETE_STRUCT_RELAYOUT ++ && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE) ++ { ++ e = escape_separate_instance; ++ } ++ + if (e != does_not_escape) + type->mark_escape (e, NULL); + } +@@ -1315,6 +2063,7 @@ ipa_struct_reorg::find_var (tree expr, gimple *stmt) + || TREE_CODE (expr) == VIEW_CONVERT_EXPR) + { + tree r = TREE_OPERAND (expr, 0); ++ tree orig_type = TREE_TYPE (expr); + if (handled_component_p (r) + || TREE_CODE (r) == MEM_REF) + { +@@ -1328,8 +2077,18 @@ ipa_struct_reorg::find_var (tree expr, gimple *stmt) + escape_vce, stmt); + } + if (TREE_CODE (r) == MEM_REF) +- mark_type_as_escape (TREE_TYPE (TREE_OPERAND (r, 1)), +- escape_addr, stmt); ++ { ++ mark_type_as_escape (TREE_TYPE (TREE_OPERAND (r, 1)), ++ escape_addr, stmt); ++ tree inner_type = TREE_TYPE (TREE_OPERAND (r, 0)); ++ if (orig_type != inner_type) ++ { ++ mark_type_as_escape (orig_type, ++ escape_cast_another_ptr, stmt); ++ mark_type_as_escape (inner_type, ++ escape_cast_another_ptr, stmt); ++ } ++ } + r = TREE_OPERAND (r, 0); + } + mark_expr_escape (r, escape_addr, stmt); +@@ -1354,7 +2113,8 @@ ipa_struct_reorg::find_vars (gimple *stmt) + { + case GIMPLE_ASSIGN: + if (gimple_assign_rhs_class (stmt) == GIMPLE_SINGLE_RHS +- || gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) ++ || gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR ++ || gimple_assign_rhs_code (stmt) == NOP_EXPR) + { + tree lhs = gimple_assign_lhs (stmt); + tree rhs = gimple_assign_rhs1 (stmt); +@@ -1379,6 +2139,32 @@ ipa_struct_reorg::find_vars (gimple *stmt) + current_function->record_decl (t, rhs, -1); + } + } ++ else ++ { ++ /* Because we won't handle these stmts in rewrite phase, ++ just mark these types as escaped. */ ++ switch (gimple_num_ops (stmt)) ++ { ++ case 4: mark_type_as_escape ( ++ TREE_TYPE (gimple_assign_rhs3 (stmt)), ++ escape_unhandled_rewrite, stmt); ++ // FALLTHRU ++ case 3: mark_type_as_escape ( ++ TREE_TYPE (gimple_assign_rhs2 (stmt)), ++ escape_unhandled_rewrite, stmt); ++ // FALLTHRU ++ case 2: mark_type_as_escape ( ++ TREE_TYPE (gimple_assign_rhs1 (stmt)), ++ escape_unhandled_rewrite, stmt); ++ // FALLTHRU ++ case 1: mark_type_as_escape ( ++ TREE_TYPE (gimple_assign_lhs (stmt)), ++ escape_unhandled_rewrite, stmt); ++ // FALLTHRU ++ case 0: break; ++ default: gcc_unreachable (); ++ } ++ } + break; + + case GIMPLE_CALL: +@@ -1460,9 +2246,23 @@ is_result_of_mult (tree arg, tree *num, tree struct_size) + /* If we have a integer, just check if it is a multiply of STRUCT_SIZE. */ + if (TREE_CODE (arg) == INTEGER_CST) + { +- if (integer_zerop (size_binop (FLOOR_MOD_EXPR, arg, struct_size))) ++ bool sign = false; ++ HOST_WIDE_INT size = TREE_INT_CST_LOW (arg); ++ if (size < 0) ++ { ++ size = -size; ++ sign = true; ++ } ++ tree arg2 = build_int_cst (TREE_TYPE (arg), size); ++ if (integer_zerop (size_binop (FLOOR_MOD_EXPR, arg2, struct_size))) + { +- *num = size_binop (FLOOR_DIV_EXPR, arg, struct_size); ++ tree number = size_binop (FLOOR_DIV_EXPR, arg2, struct_size); ++ if (sign) ++ { ++ number = build_int_cst (TREE_TYPE (number), ++ -tree_to_shwi (number)); ++ } ++ *num = number; + return true; + } + return false; +@@ -1532,15 +2332,19 @@ is_result_of_mult (tree arg, tree *num, tree struct_size) + + /* Return TRUE if STMT is an allocation statement that is handled. */ + +-static bool +-handled_allocation_stmt (gimple *stmt) ++bool ++ipa_struct_reorg::handled_allocation_stmt (gimple *stmt) + { +- if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC) +- || gimple_call_builtin_p (stmt, BUILT_IN_MALLOC) +- || gimple_call_builtin_p (stmt, BUILT_IN_CALLOC) +- || gimple_call_builtin_p (stmt, BUILT_IN_ALIGNED_ALLOC) +- || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA) +- || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA_WITH_ALIGN)) ++ if (current_mode == COMPLETE_STRUCT_RELAYOUT ++ && gimple_call_builtin_p (stmt, BUILT_IN_CALLOC)) ++ return true; ++ if (current_mode != COMPLETE_STRUCT_RELAYOUT ++ && (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC) ++ || gimple_call_builtin_p (stmt, BUILT_IN_MALLOC) ++ || gimple_call_builtin_p (stmt, BUILT_IN_CALLOC) ++ || gimple_call_builtin_p (stmt, BUILT_IN_ALIGNED_ALLOC) ++ || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA) ++ || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA_WITH_ALIGN))) + return true; + return false; + } +@@ -1582,7 +2386,8 @@ ipa_struct_reorg::allocate_size (srtype *type, gimple *stmt) + /* Check that second argument is a constant equal to the size of structure. */ + if (operand_equal_p (arg1, struct_size, 0)) + return size; +- /* Check that first argument is a constant equal to the size of structure. */ ++ /* ??? Check that first argument is a constant ++ equal to the size of structure. */ + if (operand_equal_p (size, struct_size, 0)) + return arg1; + if (dump_file && (dump_flags & TDF_DETAILS)) +@@ -1699,6 +2504,29 @@ ipa_struct_reorg::maybe_record_assign (cgraph_node *node, gassign *stmt) + } + } + ++bool ++check_mem_ref_offset (tree expr) ++{ ++ tree num = NULL; ++ bool ret = false; ++ ++ if (TREE_CODE (expr) != MEM_REF) ++ { ++ return false; ++ } ++ ++ /* Try to find the structure size. */ ++ tree field_off = TREE_OPERAND (expr, 1); ++ tree tmp = TREE_OPERAND (expr, 0); ++ if (TREE_CODE (tmp) == ADDR_EXPR) ++ { ++ tmp = TREE_OPERAND (tmp, 0); ++ } ++ tree size = TYPE_SIZE_UNIT (inner_type (TREE_TYPE (tmp))); ++ ret = is_result_of_mult (field_off, &num, size); ++ return ret; ++} ++ + tree + get_ref_base_and_offset (tree &e, HOST_WIDE_INT &offset, bool &realpart, bool &imagpart, tree &accesstype) + { +@@ -1738,7 +2566,10 @@ get_ref_base_and_offset (tree &e, HOST_WIDE_INT &offset, bool &realpart, bool &i + gcc_assert (TREE_CODE (field_off) == INTEGER_CST); + /* So we can mark the types as escaping if different. */ + accesstype = TREE_TYPE (field_off); +- offset += tree_to_uhwi (field_off); ++ if (!check_mem_ref_offset (expr)) ++ { ++ offset += tree_to_uhwi (field_off); ++ } + return TREE_OPERAND (expr, 0); + } + default: +@@ -2115,6 +2946,39 @@ ipa_struct_reorg::check_type_and_push (tree newdecl, srtype *type, vec<srdecl*> + + } + ++void ++ipa_struct_reorg::check_alloc_num (gimple *stmt, srtype *type) ++{ ++ if (current_mode == COMPLETE_STRUCT_RELAYOUT ++ && handled_allocation_stmt (stmt)) ++ { ++ tree arg0 = gimple_call_arg (stmt, 0); ++ basic_block bb = gimple_bb (stmt); ++ cgraph_node *node = current_function->node; ++ if (integer_onep (arg0)) ++ { ++ /* Actually NOT an array, but may ruin other array. */ ++ type->has_alloc_array = -1; ++ } ++ else if (bb->loop_father != NULL ++ && loop_outer (bb->loop_father) != NULL) ++ { ++ /* The allocation is in a loop. */ ++ type->has_alloc_array = -2; ++ } ++ else if (node->callers != NULL) ++ { ++ type->has_alloc_array = -3; ++ } ++ else ++ { ++ type->has_alloc_array = type->has_alloc_array < 0 ++ ? type->has_alloc_array ++ : type->has_alloc_array + 1; ++ } ++ } ++} ++ + /* + 2) Check SSA_NAMEs for non type usages (source or use) (worlist of srdecl) + a) if the SSA_NAME is sourced from a pointer plus, record the pointer and +@@ -2158,6 +3022,7 @@ ipa_struct_reorg::check_definition (srdecl *decl, vec<srdecl*> &worklist) + if (!handled_allocation_stmt (stmt) + || !allocate_size (type, stmt)) + type->mark_escape (escape_return, stmt); ++ check_alloc_num (stmt, type); + return; + } + /* If the SSA_NAME is sourced from an inline-asm, just mark the type as escaping. */ +@@ -2196,6 +3061,24 @@ ipa_struct_reorg::check_definition (srdecl *decl, vec<srdecl*> &worklist) + return; + } + ++ if (gimple_assign_rhs_code (stmt) == MAX_EXPR ++ || gimple_assign_rhs_code (stmt) == MIN_EXPR ++ || gimple_assign_rhs_code (stmt) == BIT_IOR_EXPR ++ || gimple_assign_rhs_code (stmt) == BIT_XOR_EXPR ++ || gimple_assign_rhs_code (stmt) == BIT_AND_EXPR) ++ { ++ tree rhs2 = gimple_assign_rhs2 (stmt); ++ if (TREE_CODE (rhs) == SSA_NAME) ++ { ++ check_type_and_push (rhs, type, worklist, stmt); ++ } ++ if (TREE_CODE (rhs2) == SSA_NAME) ++ { ++ check_type_and_push (rhs2, type, worklist, stmt); ++ } ++ return; ++ } ++ + /* Casts between pointers and integer are escaping. */ + if (gimple_assign_cast_p (stmt)) + { +@@ -2258,6 +3141,13 @@ ipa_struct_reorg::check_other_side (srdecl *decl, tree other, gimple *stmt, vec< + srtype *t1 = find_type (inner_type (t)); + if (t1 == type) + { ++ /* In Complete Struct Relayout opti, if lhs type is the same ++ as rhs type, we could return without any harm. */ ++ if (current_mode == COMPLETE_STRUCT_RELAYOUT) ++ { ++ return; ++ } ++ + tree base; + bool indirect; + srtype *type1; +@@ -2305,8 +3195,11 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist) + tree rhs1 = gimple_cond_lhs (stmt); + tree rhs2 = gimple_cond_rhs (stmt); + tree orhs = rhs1; +- if (gimple_cond_code (stmt) != EQ_EXPR +- && gimple_cond_code (stmt) != NE_EXPR) ++ enum tree_code code = gimple_cond_code (stmt); ++ if (code != EQ_EXPR && code != NE_EXPR ++ && (current_mode != COMPLETE_STRUCT_RELAYOUT ++ || (code != LT_EXPR && code != LE_EXPR ++ && code != GT_EXPR && code != GE_EXPR))) + { + mark_expr_escape (rhs1, escape_non_eq, stmt); + mark_expr_escape (rhs2, escape_non_eq, stmt); +@@ -2336,8 +3229,11 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist) + tree rhs1 = gimple_assign_rhs1 (stmt); + tree rhs2 = gimple_assign_rhs2 (stmt); + tree orhs = rhs1; +- if (gimple_assign_rhs_code (stmt) != EQ_EXPR +- && gimple_assign_rhs_code (stmt) != NE_EXPR) ++ enum tree_code code = gimple_assign_rhs_code (stmt); ++ if (code != EQ_EXPR && code != NE_EXPR ++ && (current_mode != COMPLETE_STRUCT_RELAYOUT ++ || (code != LT_EXPR && code != LE_EXPR ++ && code != GT_EXPR && code != GE_EXPR))) + { + mark_expr_escape (rhs1, escape_non_eq, stmt); + mark_expr_escape (rhs2, escape_non_eq, stmt); +@@ -2618,6 +3514,12 @@ ipa_struct_reorg::record_accesses (void) + /* Record accesses inside a function. */ + if(cnode->definition) + record_function (cnode); ++ else ++ { ++ tree return_type = TREE_TYPE (TREE_TYPE (cnode->decl)); ++ mark_type_as_escape (return_type, escape_return, NULL); ++ } ++ + } + + if (dump_file && (dump_flags & TDF_DETAILS)) +@@ -2734,8 +3636,11 @@ ipa_struct_reorg::propagate_escape (void) + void + ipa_struct_reorg::prune_escaped_types (void) + { +- detect_cycles (); +- propagate_escape (); ++ if (current_mode != COMPLETE_STRUCT_RELAYOUT) ++ { ++ detect_cycles (); ++ propagate_escape (); ++ } + + if (dump_file && (dump_flags & TDF_DETAILS)) + { +@@ -3862,16 +4767,82 @@ ipa_struct_reorg::rewrite_functions (void) + } + + unsigned int +-ipa_struct_reorg::execute (void) ++ipa_struct_reorg::execute_struct_relayout (void) + { +- /* FIXME: If there is a top-level inline-asm, the pass immediately returns. */ +- if (symtab->first_asm_symbol ()) +- return 0; +- record_accesses (); +- prune_escaped_types (); +- analyze_types (); ++ unsigned retval = 0; ++ for (unsigned i = 0; i < types.length (); i++) ++ { ++ tree type = types[i]->type; ++ if (TYPE_FIELDS (type) == NULL) ++ { ++ continue; ++ } ++ if (types[i]->has_alloc_array != 1) ++ { ++ continue; ++ } ++ if (types[i]->chain_type) ++ { ++ continue; ++ } ++ retval |= ipa_struct_relayout (type, this).execute (); ++ } + +- return rewrite_functions (); ++ if (dump_file) ++ { ++ if (transformed) ++ { ++ fprintf (dump_file, "\nNumber of structures to transform in " ++ "Complete Structure Relayout is %d\n", transformed); ++ } ++ else ++ { ++ fprintf (dump_file, "\nNo structures to transform in " ++ "Complete Structure Relayout.\n"); ++ } ++ } ++ ++ return retval; ++} ++ ++unsigned int ++ipa_struct_reorg::execute (enum srmode mode) ++{ ++ unsigned int ret = 0; ++ ++ if (mode == NORMAL) ++ { ++ current_mode = NORMAL; ++ /* If there is a top-level inline-asm, ++ the pass immediately returns. */ ++ if (symtab->first_asm_symbol ()) ++ { ++ return 0; ++ } ++ record_accesses (); ++ prune_escaped_types (); ++ analyze_types (); ++ ++ ret = rewrite_functions (); ++ } ++ else if (mode == COMPLETE_STRUCT_RELAYOUT) ++ { ++ if (dump_file) ++ { ++ fprintf (dump_file, "\n\nTry Complete Struct Relayout:\n"); ++ } ++ current_mode = COMPLETE_STRUCT_RELAYOUT; ++ if (symtab->first_asm_symbol ()) ++ { ++ return 0; ++ } ++ record_accesses (); ++ prune_escaped_types (); ++ ++ ret = execute_struct_relayout (); ++ } ++ ++ return ret; + } + + const pass_data pass_data_ipa_struct_reorg = +@@ -3896,17 +4867,27 @@ public: + + /* opt_pass methods: */ + virtual bool gate (function *); +- virtual unsigned int execute (function *) { return ipa_struct_reorg ().execute(); } ++ virtual unsigned int execute (function *) ++ { ++ unsigned int ret = 0; ++ ret = ipa_struct_reorg ().execute (NORMAL); ++ if (!ret) ++ { ++ ret = ipa_struct_reorg ().execute (COMPLETE_STRUCT_RELAYOUT); ++ } ++ return ret; ++ } + + }; // class pass_ipa_struct_reorg + + bool + pass_ipa_struct_reorg::gate (function *) + { +- return (optimize ++ return (optimize >= 3 + && flag_ipa_struct_reorg + /* Don't bother doing anything if the program has errors. */ +- && !seen_error ()); ++ && !seen_error () ++ && flag_lto_partition == LTO_PARTITION_ONE); + } + + } // anon namespace +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.h b/gcc/ipa-struct-reorg/ipa-struct-reorg.h +index f2163910896..d8fe399bdf8 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.h ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.h +@@ -121,6 +121,7 @@ public: + + tree newtype[max_split]; + bool visited; ++ int has_alloc_array; + + // Constructors + srtype(tree type); +@@ -232,4 +233,34 @@ struct srdecl + + } // namespace struct_reorg + ++ ++namespace struct_relayout { ++ ++const int min_relayout_split = 8; ++const int max_relayout_split = 16; ++ ++struct csrtype ++{ ++ tree type; ++ unsigned HOST_WIDE_INT old_size; ++ unsigned HOST_WIDE_INT new_size; ++ unsigned field_count; ++ tree struct_size; ++ ++ // Constructors ++ csrtype () ++ : type (NULL), ++ old_size (0), ++ new_size (0), ++ field_count (0), ++ struct_size (NULL) ++ {} ++ ++ // Methods ++ unsigned calculate_field_num (tree field_offset); ++ void init_type_info (void); ++}; ++ ++} // namespace struct_relayout ++ + #endif +diff --git a/gcc/testsuite/g++.dg/struct/no-body-function.cpp b/gcc/testsuite/g++.dg/struct/no-body-function.cpp +new file mode 100644 +index 00000000000..4e56e73fcae +--- /dev/null ++++ b/gcc/testsuite/g++.dg/struct/no-body-function.cpp +@@ -0,0 +1,18 @@ ++/* { dg-do compile } */ ++/* { dg-options "-std=gnu++17 -Wno-builtin-declaration-mismatch -O3 -fwhole-program -flto-partition=one -fipa-struct-reorg -S" } */ ++ ++struct S { ++ int x; ++ double y; ++}; ++S f(); ++ ++const auto [x0, y0] = f(); ++const auto [x1, y1] = f(); ++ ++static union { ++int a; ++double b; ++}; ++ ++const auto [x2, y2] = f(); +diff --git a/gcc/testsuite/g++.dg/struct/struct-reorg-1.cpp b/gcc/testsuite/g++.dg/struct/struct-reorg-1.cpp +new file mode 100644 +index 00000000000..6ab71abe140 +--- /dev/null ++++ b/gcc/testsuite/g++.dg/struct/struct-reorg-1.cpp +@@ -0,0 +1,13 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O3 -fwhole-program -flto-partition=one -fipa-struct-reorg -fdump-ipa-struct_reorg-details -S" } */ ++ ++struct Foo { int foo; int a; }; ++Foo& ignoreSetMutex = *(new Foo); ++ ++struct Goo { int goo; int a; }; ++ ++int main () ++{ ++ Goo* a; ++ return a->goo = 90; ++} +diff --git a/gcc/testsuite/g++.dg/struct/struct-reorg-2.cpp b/gcc/testsuite/g++.dg/struct/struct-reorg-2.cpp +new file mode 100644 +index 00000000000..72b7db8a9ce +--- /dev/null ++++ b/gcc/testsuite/g++.dg/struct/struct-reorg-2.cpp +@@ -0,0 +1,17 @@ ++/* { dg-do run } */ ++/* { dg-options "-O3 -fwhole-program -flto-partition=one -fipa-struct-reorg -fdump-ipa-struct_reorg-details" } */ ++ ++#include <stdlib.h> ++ ++struct testg { ++ int b; ++ float c; ++}; ++ ++testg *testgvar; ++int main () ++{ ++ testgvar = (testg*) calloc(10, sizeof(testg)); ++ int b = testgvar->b; ++ return b; ++} +diff --git a/gcc/testsuite/g++.dg/struct/struct-reorg-3.cpp b/gcc/testsuite/g++.dg/struct/struct-reorg-3.cpp +new file mode 100644 +index 00000000000..771164a96e7 +--- /dev/null ++++ b/gcc/testsuite/g++.dg/struct/struct-reorg-3.cpp +@@ -0,0 +1,24 @@ ++/* { dg-do run } */ ++/* { dg-options "-O3 -fwhole-program -flto-partition=one -fipa-struct-reorg -fdump-ipa-struct_reorg-details" } */ ++ ++#include <stdlib.h> ++ ++struct testg { ++ int b; ++ float c; ++ double d; ++ double e; ++ double f; ++ double h; ++ double i; ++ double j; ++ int k; ++}; ++ ++testg *testgvar; ++int main () ++{ ++ testgvar = (testg*) calloc(10, sizeof(testg)); ++ int b = testgvar->b; ++ return b; ++} +diff --git a/gcc/testsuite/g++.dg/struct/struct-reorg.exp b/gcc/testsuite/g++.dg/struct/struct-reorg.exp +new file mode 100644 +index 00000000000..4307f69e2cd +--- /dev/null ++++ b/gcc/testsuite/g++.dg/struct/struct-reorg.exp +@@ -0,0 +1,26 @@ ++# Copyright (C) 2021-2021 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/>. ++ ++load_lib g++-dg.exp ++ ++# Initialize `dg'. ++dg-init ++ ++g++-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.cpp]] \ ++ "" "" ++ ++# All done. ++dg-finish +diff --git a/gcc/testsuite/gcc.dg/struct/complete_struct_relayout.c b/gcc/testsuite/gcc.dg/struct/complete_struct_relayout.c +new file mode 100644 +index 00000000000..811030bf167 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/complete_struct_relayout.c +@@ -0,0 +1,60 @@ ++// { dg-do run } ++ ++#include <stdlib.h> ++#include <stdio.h> ++ ++typedef struct node node_t; ++typedef struct node* node_p; ++ ++struct node { ++ unsigned long a; ++ unsigned long b; ++ node_p c; ++ node_p d; ++ long e; ++ long f; ++ long g; ++ long h; ++ long i; ++ long j; ++ long k; ++ long l; ++ int m; ++ int n; ++}; ++ ++const int MAX = 10000; ++node_p n; ++ ++int ++main () ++{ ++ n = (node_p) calloc (MAX, sizeof (node_t)); ++ ++ for (int i = 0; i < MAX; i++) ++ { ++ n[i].a = 100; ++ } ++ for (int i = 0; i < MAX; i++) ++ { ++ if (n[i].a != 100) ++ { ++ abort (); ++ } ++ } ++ ++ for (int i = 0; i < MAX; i++) ++ { ++ n[i].l = n[i].a; ++ } ++ for (int i = 0; i < MAX; i++) ++ { ++ if (n[i].l != 100) ++ { ++ abort (); ++ } ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in Complete Structure Relayout is 1" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/csr_allocation-1.c b/gcc/testsuite/gcc.dg/struct/csr_allocation-1.c +new file mode 100644 +index 00000000000..63bb695ae14 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/csr_allocation-1.c +@@ -0,0 +1,46 @@ ++#include <stdlib.h> ++#include <stdio.h> ++ ++typedef struct node node_t; ++typedef struct node* node_p; ++ ++struct node { ++ unsigned long a; ++ unsigned long b; ++ node_p c; ++ node_p d; ++ long e; ++ long f; ++ long g; ++ long h; ++ long i; ++ long j; ++ long k; ++ long l; ++ int m; ++ int n; ++}; ++ ++const int MAX = 1; ++node_p n; ++ ++int ++main () ++{ ++ n = (node_p) calloc (MAX, sizeof (node_t)); ++ ++ for (int i = 0; i < MAX; i++) ++ { ++ n[i].a = 100; ++ } ++ for (int i = 0; i < MAX; i++) ++ { ++ if (n[i].a != 100) ++ { ++ abort (); ++ } ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "No structures to transform in Complete Structure Relayout." "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/csr_allocation-2.c b/gcc/testsuite/gcc.dg/struct/csr_allocation-2.c +new file mode 100644 +index 00000000000..0f75d5d121c +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/csr_allocation-2.c +@@ -0,0 +1,59 @@ ++#include <stdlib.h> ++#include <stdio.h> ++ ++typedef struct node node_t; ++typedef struct node* node_p; ++ ++struct node { ++ unsigned long a; ++ unsigned long b; ++ node_p c; ++ node_p d; ++ long e; ++ long f; ++ long g; ++ long h; ++ long i; ++ long j; ++ long k; ++ long l; ++ int m; ++ int n; ++}; ++ ++const int MAX = 10; ++node_p n; ++node_p m; ++ ++int main() ++{ ++ int i; ++ for (i = 0; i < MAX / 5; i++) ++ { ++ n = (node_p) calloc(MAX, sizeof(node_t)); ++ if (i == 0) ++ { ++ m = n; ++ } ++ } ++ ++ for (int i = 0; i < MAX; i++) ++ { ++ n[i].a = 100; ++ } ++ for (int i = 0; i < MAX; i++) ++ { ++ m[i].a = 50; ++ } ++ ++ for (int i = 0; i < MAX; i++) ++ { ++ if (n[i].a != 100) ++ { ++ abort (); ++ } ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "No structures to transform in Complete Structure Relayout." "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/csr_allocation-3.c b/gcc/testsuite/gcc.dg/struct/csr_allocation-3.c +new file mode 100644 +index 00000000000..3dcb674c6e9 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/csr_allocation-3.c +@@ -0,0 +1,77 @@ ++#include <stdlib.h> ++#include <stdio.h> ++ ++typedef struct node node_t; ++typedef struct node* node_p; ++ ++struct node { ++ unsigned long a; ++ unsigned long b; ++ node_p c; ++ node_p d; ++ long e; ++ long f; ++ long g; ++ long h; ++ long i; ++ long j; ++ long k; ++ long l; ++ int m; ++ int n; ++}; ++ ++const int MAX = 10; ++node_p n; ++node_p m; ++ ++void test (int, int) __attribute__((noinline)); ++ ++void ++test (int num, int flag) ++{ ++ if (num <= 0) ++ { ++ return; ++ } ++ n = (node_p) calloc (num, sizeof (node_t)); ++ if (flag) ++ { ++ m = n; ++ } ++ return; ++} ++ ++int ++main () ++{ ++ test (MAX, 1); ++ test (MAX, 0); ++ ++ for (int i = 0; i < MAX; i++) ++ { ++ n[i].a = 100; ++ } ++ for (int i = 0; i < MAX; i++) ++ { ++ m[i].a = 50; ++ } ++ ++ for (int i = 0; i < MAX; i++) ++ { ++ if (n[i].a != 100) ++ { ++ abort (); ++ } ++ } ++ for (int i = 0; i < MAX; i++) ++ { ++ if (m[i].a != 50) ++ { ++ abort (); ++ } ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "No structures to transform in Complete Structure Relayout." "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/csr_cast_int.c b/gcc/testsuite/gcc.dg/struct/csr_cast_int.c +new file mode 100644 +index 00000000000..6907158c9b0 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/csr_cast_int.c +@@ -0,0 +1,52 @@ ++// { dg-do run } ++ ++#include <stdlib.h> ++#include <stdio.h> ++ ++typedef struct node node_t; ++typedef struct node* node_p; ++ ++struct node { ++ unsigned long a; ++ unsigned long b; ++ node_p c; ++ node_p d; ++ long e; ++ long f; ++ long g; ++ long h; ++ long i; ++ long j; ++ long k; ++ long l; ++ int m; ++ int n; ++}; ++ ++const int MAX = 100; ++node_p n; ++unsigned long y; ++ ++int ++main () ++{ ++ n = (node_p) calloc (MAX, sizeof (node_t)); ++ ++ for (int i = 0; i < MAX; i++) ++ { ++ n[i].b = 50; ++ } ++ ++ node_p x = &n[5]; ++ y = (unsigned long) x; ++ y += 8; ++ ++ if (*((unsigned long*) y) != 50) ++ { ++ abort (); ++ } ++ ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "struct node has escaped: \"Type escapes a cast from/to intergral type\"" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/csr_separate_instance.c b/gcc/testsuite/gcc.dg/struct/csr_separate_instance.c +new file mode 100644 +index 00000000000..9e5e05838e6 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/csr_separate_instance.c +@@ -0,0 +1,48 @@ ++#include <stdlib.h> ++#include <stdio.h> ++ ++typedef struct node node_t; ++typedef struct node* node_p; ++ ++struct node { ++ unsigned long a; ++ unsigned long b; ++ node_p c; ++ node_p d; ++ long e; ++ long f; ++ long g; ++ long h; ++ long i; ++ long j; ++ long k; ++ long l; ++ int m; ++ int n; ++}; ++ ++const int MAX = 10000; ++node_p n; ++node_t t; ++ ++int ++main () ++{ ++ n = (node_p) calloc (MAX, sizeof (node_t)); ++ t.a = 100; ++ ++ for (int i = 0; i < MAX; i++) ++ { ++ n[i].a = t.a; ++ } ++ for (int i = 0; i < MAX; i++) ++ { ++ if (n[i].a != 100) ++ { ++ abort (); ++ } ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "struct node has escaped: \"Type escapes via a separate instance\"" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/sr_address_of_field.c b/gcc/testsuite/gcc.dg/struct/sr_address_of_field.c +new file mode 100644 +index 00000000000..9d58edab80a +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/sr_address_of_field.c +@@ -0,0 +1,37 @@ ++/* { dg-do run } */ ++ ++static struct S { ++ int *p1; ++ int *p2; ++} s; ++ ++typedef __UINTPTR_TYPE__ uintptr_t; ++ ++int ++foo () ++{ ++ int i = 1; ++ int j = 2; ++ struct S s; ++ int **p; ++ s.p1 = &i; ++ s.p2 = &j; ++ p = &s.p1; ++ uintptr_t pi = (uintptr_t) p; ++ pi = pi + sizeof (int *); ++ p = (int **)pi; ++ **p = 3; ++ return j; ++} ++ ++int ++main () ++{ ++ if (foo () != 3) ++ { ++ __builtin_abort (); ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "struct S has escaped: \"Type escapes via taking the address of field\"" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/sr_convert_mem.c b/gcc/testsuite/gcc.dg/struct/sr_convert_mem.c +new file mode 100644 +index 00000000000..a99ee0de484 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/sr_convert_mem.c +@@ -0,0 +1,23 @@ ++/* { dg-do compile } */ ++ ++struct T1 { ++ long var1; ++ int var2; ++}; ++ ++struct T2 { ++ long var1; ++ int var2; ++}; ++ ++void test (void*); ++ ++__attribute__((used)) void ++foo (struct T2 *t2) ++{ ++ struct T1* t1 = (void *)(&t2[1]); ++ void* data = (void *)(&t1[1]); ++ ++ test(data); ++ return; ++} +diff --git a/gcc/testsuite/gcc.dg/struct/sr_maxmin_expr.c b/gcc/testsuite/gcc.dg/struct/sr_maxmin_expr.c +new file mode 100644 +index 00000000000..fb135ef0bb5 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/sr_maxmin_expr.c +@@ -0,0 +1,25 @@ ++// { dg-do compile } ++ ++#include <stdlib.h> ++ ++struct S { ++ unsigned long a; ++ unsigned long b; ++}; ++ ++struct S* s; ++struct S* t = (struct S*) 1000; ++ ++int ++main () ++{ ++ s = (struct S*) calloc (1000, sizeof (struct S)); ++ s = s > t ? s : t; ++ if (s == 0) ++ { ++ abort (); ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "No structures to transform." "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/sr_pointer_and.c b/gcc/testsuite/gcc.dg/struct/sr_pointer_and.c +new file mode 100644 +index 00000000000..9a4b10d9aef +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/sr_pointer_and.c +@@ -0,0 +1,17 @@ ++/* { dg-do compile } */ ++ ++struct test {long val; struct test* next; }; ++ ++unsigned long P_DATA; ++ ++void func (struct test*); ++ ++__attribute__((used)) static void ++foo (struct test* pt) ++{ ++ struct test t; ++ ++ t.next = (void *)((unsigned long)pt->next & P_DATA); ++ func(&t); ++ return; ++} +diff --git a/gcc/testsuite/gcc.dg/struct/sr_pointer_minus.c b/gcc/testsuite/gcc.dg/struct/sr_pointer_minus.c +new file mode 100644 +index 00000000000..9a82da0d6e1 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/sr_pointer_minus.c +@@ -0,0 +1,33 @@ ++// { dg-do compile } ++ ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node* node_p; ++ ++struct node { ++ unsigned long a; ++ unsigned long b; ++}; ++ ++int max; ++int x; ++ ++node_p n; ++node_p z; ++ ++int ++main () ++{ ++ n = (node_p) calloc (max, sizeof (node_t)); ++ ++ node_p xp = &n[x]; ++ ++ if (xp - z == 10) ++ { ++ abort (); ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "struct node has escaped: \"Type escapes via a unhandled rewrite stmt\"" "struct_reorg" } } */ +-- +2.21.0.windows.1 + diff --git a/0016-StructReorg-Bugfix-in-certain-scenarios.patch b/0016-StructReorg-Bugfix-in-certain-scenarios.patch new file mode 100644 index 0000000..f16f352 --- /dev/null +++ b/0016-StructReorg-Bugfix-in-certain-scenarios.patch @@ -0,0 +1,486 @@ +From 2194d59a20be1ab627089d2f0c082b5a0a217f52 Mon Sep 17 00:00:00 2001 +From: xiezhiheng <xiezhiheng@huawei.com> +Date: Tue, 3 Aug 2021 03:49:52 -0400 +Subject: [PATCH 16/22] [StructReorg] Bugfix in certain scenarios + +Some bugfix in certain scenarios, +1. disable type simplify in LTO within optimizations +2. only enable optimizations in C language +3. use new to initialize allocated memory in symbol-summary.h +4. cover escape scenarios not considered + +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +index 5a19ea0bb40..1cb544ec3b0 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -97,6 +97,7 @@ along with GCC; see the file COPYING3. If not see + #include "tree-eh.h" + #include "bitmap.h" + #include "cfgloop.h" ++#include "langhooks.h" + #include "ipa-param-manipulation.h" + #include "tree-ssa-live.h" /* For remove_unused_locals. */ + +@@ -161,6 +162,44 @@ handled_type (tree type) + return false; + } + ++/* Check whether in C language or LTO with only C language. */ ++bool ++lang_c_p (void) ++{ ++ const char *language_string = lang_hooks.name; ++ ++ if (!language_string) ++ { ++ return false; ++ } ++ ++ if (strcmp (language_string, "GNU GIMPLE") == 0) ++ { ++ unsigned i = 0; ++ tree t = NULL; ++ const char *unit_string = NULL; ++ ++ FOR_EACH_VEC_SAFE_ELT (all_translation_units, i, t) ++ { ++ unit_string = TRANSLATION_UNIT_LANGUAGE (t); ++ if (!unit_string ++ || (strncmp (unit_string, "GNU C", 5) != 0) ++ || (!ISDIGIT (unit_string[5]))) ++ { ++ return false; ++ } ++ } ++ return true; ++ } ++ else if (strncmp (language_string, "GNU C", 5) == 0 ++ && ISDIGIT (language_string[5])) ++ { ++ return true; ++ } ++ ++ return false; ++} ++ + enum srmode + { + NORMAL = 0, +@@ -999,7 +1038,6 @@ public: + void analyze_types (void); + void clear_visited (void); + bool create_new_types (void); +- void restore_field_type (void); + void create_new_decls (void); + srdecl *find_decl (tree); + void create_new_functions (void); +@@ -2127,7 +2165,12 @@ ipa_struct_reorg::find_vars (gimple *stmt) + srtype *t = find_type (inner_type (TREE_TYPE (rhs))); + srdecl *d = find_decl (lhs); + if (!d && t) +- current_function->record_decl (t, lhs, -1); ++ { ++ current_function->record_decl (t, lhs, -1); ++ tree var = SSA_NAME_VAR (lhs); ++ if (var && VOID_POINTER_P (TREE_TYPE (var))) ++ current_function->record_decl (t, var, -1); ++ } + } + if (TREE_CODE (rhs) == SSA_NAME + && VOID_POINTER_P (TREE_TYPE (rhs)) +@@ -2136,7 +2179,12 @@ ipa_struct_reorg::find_vars (gimple *stmt) + srtype *t = find_type (inner_type (TREE_TYPE (lhs))); + srdecl *d = find_decl (rhs); + if (!d && t) +- current_function->record_decl (t, rhs, -1); ++ { ++ current_function->record_decl (t, rhs, -1); ++ tree var = SSA_NAME_VAR (rhs); ++ if (var && VOID_POINTER_P (TREE_TYPE (var))) ++ current_function->record_decl (t, var, -1); ++ } + } + } + else +@@ -2816,8 +2864,14 @@ ipa_struct_reorg::maybe_record_call (cgraph_node *node, gcall *stmt) + if (escapes != does_not_escape) + { + for (unsigned i = 0; i < gimple_call_num_args (stmt); i++) +- mark_type_as_escape (TREE_TYPE (gimple_call_arg (stmt, i)), +- escapes); ++ { ++ mark_type_as_escape (TREE_TYPE (gimple_call_arg (stmt, i)), ++ escapes); ++ srdecl *d = current_function->find_decl ( ++ gimple_call_arg (stmt, i)); ++ if (d) ++ d->type->mark_escape (escapes, stmt); ++ } + return; + } + +@@ -3753,49 +3807,6 @@ ipa_struct_reorg::analyze_types (void) + } + } + +-/* When struct A has a struct B member, B's type info +- is not stored in +- TYPE_FIELDS (TREE_TYPE (TYPE_FIELDS (typeA))) +- Try to restore B's type information. */ +-void +-ipa_struct_reorg::restore_field_type (void) +-{ +- for (unsigned i = 0; i < types.length (); i++) +- { +- for (unsigned j = 0; j < types[i]->fields.length (); j++) +- { +- srfield *field = types[i]->fields[j]; +- if (TREE_CODE (inner_type (field->fieldtype)) == RECORD_TYPE) +- { +- /* If field type has TYPE_FIELDS information, +- we do not need to do this. */ +- if (TYPE_FIELDS (field->type->type) != NULL) +- { +- continue; +- } +- for (unsigned k = 0; k < types.length (); k++) +- { +- if (i == k) +- { +- continue; +- } +- const char *type1 = get_type_name (field->type->type); +- const char *type2 = get_type_name (types[k]->type); +- if (type1 == NULL || type2 == NULL) +- { +- continue; +- } +- if (type1 == type2 +- && TYPE_FIELDS (types[k]->type)) +- { +- field->type = types[k]; +- } +- } +- } +- } +- } +-} +- + /* Create all new types we want to create. */ + + bool +@@ -4652,7 +4663,6 @@ ipa_struct_reorg::rewrite_functions (void) + { + unsigned retval = 0; + +- restore_field_type (); + /* Create new types, if we did not create any new types, + then don't rewrite any accesses. */ + if (!create_new_types ()) +@@ -4887,7 +4897,10 @@ pass_ipa_struct_reorg::gate (function *) + && flag_ipa_struct_reorg + /* Don't bother doing anything if the program has errors. */ + && !seen_error () +- && flag_lto_partition == LTO_PARTITION_ONE); ++ && flag_lto_partition == LTO_PARTITION_ONE ++ /* Only enable struct optimizations in C since other ++ languages' grammar forbid. */ ++ && lang_c_p ()); + } + + } // anon namespace +diff --git a/gcc/symbol-summary.h b/gcc/symbol-summary.h +index fa1df5c8015..a223b4dadea 100644 +--- a/gcc/symbol-summary.h ++++ b/gcc/symbol-summary.h +@@ -59,6 +59,12 @@ protected: + /* Allocates new data that are stored within map. */ + T* allocate_new () + { ++ /* In structure optimizatons, we call new to ensure that ++ the allocated memory is initialized to 0. */ ++ if (flag_ipa_struct_reorg) ++ return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T () ++ : new T (); ++ + /* Call gcc_internal_because we do not want to call finalizer for + a type T. We call dtor explicitly. */ + return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T () +@@ -71,7 +77,12 @@ protected: + if (is_ggc ()) + ggc_delete (item); + else +- m_allocator.remove (item); ++ { ++ if (flag_ipa_struct_reorg) ++ delete item; ++ else ++ m_allocator.remove (item); ++ } + } + + /* Unregister all call-graph hooks. */ +diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-5.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-5.c +new file mode 100644 +index 00000000000..273baa9a368 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-5.c +@@ -0,0 +1,31 @@ ++/* { dg-do compile } */ ++/* { dg-additional-options "-flto -fno-use-linker-plugin" } */ ++ ++struct D ++{ ++ int n; ++ int c [8]; ++}; ++ ++struct A ++{ ++ int i; ++ char *p; ++}; ++ ++struct B ++{ ++ struct A *a; ++ struct D *d; ++}; ++ ++int dtInsert1 (struct B *b) ++{ ++ struct A a = { 0, 0 }; ++ struct D *d; ++ b->a = &a; ++ d = b->d; ++ &d->c [d->n]; ++ return 0; ++} ++ +diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-6.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-6.c +new file mode 100644 +index 00000000000..455f9b501d6 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-6.c +@@ -0,0 +1,54 @@ ++/* { dg-do compile } */ ++/* { dg-additional-options "-flto -fno-use-linker-plugin" } */ ++ ++typedef struct basic_block_def *basic_block; ++typedef struct gimple_seq_node_d *gimple_seq_node; ++typedef struct gimple_seq_d *gimple_seq; ++typedef struct ++{ ++ gimple_seq_node ptr; ++ gimple_seq seq; ++ basic_block bb; ++} gimple_stmt_iterator; ++typedef void *gimple; ++extern void exit(int); ++struct gimple_seq_node_d ++{ ++ gimple stmt; ++ struct gimple_seq_node_d *next; ++}; ++struct gimple_seq_d ++{ ++}; ++static __inline__ gimple_stmt_iterator ++gsi_start (gimple_seq seq) ++{ ++ gimple_stmt_iterator i; ++ i.seq = seq; ++ return i; ++} ++static __inline__ unsigned char ++gsi_end_p (gimple_stmt_iterator i) ++{ ++ return i.ptr == ((void *)0); ++} ++static __inline__ void ++gsi_next (gimple_stmt_iterator *i) ++{ ++ i->ptr = i->ptr->next; ++} ++static __inline__ gimple ++gsi_stmt (gimple_stmt_iterator i) ++{ ++ return i.ptr->stmt; ++} ++void ++c_warn_unused_result (gimple_seq seq) ++{ ++ gimple_stmt_iterator i; ++ for (i = gsi_start (seq); !gsi_end_p (i); gsi_next (&i)) ++ { ++ gimple g = gsi_stmt (i); ++ if (!g) exit(0); ++ } ++} +diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-7.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-7.c +new file mode 100644 +index 00000000000..afc0bd86ca5 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-7.c +@@ -0,0 +1,38 @@ ++/* { dg-do run } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++struct gki_elem { ++ char *key; ++ int idx; ++}; ++ ++typedef struct { ++ struct gki_elem *table; ++ ++ int primelevel; ++ int nhash; ++ int nkeys; ++} GKI; ++ ++void * ++sre_malloc(size_t size) ++{ ++ void *ptr = malloc (size); ++ return ptr; ++} ++ ++__attribute__((noinline)) int ++GKIStoreKey(GKI *hash) ++{ ++ hash->table = sre_malloc(sizeof(struct gki_elem)); ++} ++ ++int ++main () ++{ ++ GKI *hash = malloc (sizeof(GKI)); ++ GKIStoreKey(hash); ++ return 0; ++} +diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-8.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-8.c +new file mode 100644 +index 00000000000..9bcfaf3681b +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-8.c +@@ -0,0 +1,25 @@ ++/* { dg-do run } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++ ++typedef struct { ++ unsigned char blue; ++ unsigned char green; ++} Pixel; ++ ++typedef struct { ++ unsigned short colormaplength; ++ Pixel *colormapdata; ++} TargaImage; ++ ++TargaImage *img; ++ ++int main() { ++ img = (TargaImage *) malloc( sizeof(TargaImage) ); ++ if (img->colormaplength > 0) { ++ img->colormapdata = (Pixel *) malloc(sizeof(Pixel) * img->colormaplength); ++ memset(img->colormapdata, 0, (sizeof(Pixel) * img->colormaplength) ); ++ } ++} +diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-9.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-9.c +new file mode 100644 +index 00000000000..052f4e3bdc1 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-9.c +@@ -0,0 +1,54 @@ ++/* { dg-do run } */ ++ ++extern void abort(void); ++ ++struct packed_ushort { ++ unsigned short ucs; ++} __attribute__((packed)); ++ ++struct source { ++ int pos, length; ++}; ++ ++static int flag; ++ ++static void __attribute__((noinline)) fetch(struct source *p) ++{ ++ p->length = 128; ++} ++ ++static struct packed_ushort __attribute__((noinline)) next(struct source *p) ++{ ++ struct packed_ushort rv; ++ ++ if (p->pos >= p->length) { ++ if (flag) { ++ flag = 0; ++ fetch(p); ++ return next(p); ++ } ++ flag = 1; ++ rv.ucs = 0xffff; ++ return rv; ++ } ++ rv.ucs = 0; ++ return rv; ++} ++ ++int main(void) ++{ ++ struct source s; ++ int i; ++ ++ s.pos = 0; ++ s.length = 0; ++ flag = 0; ++ ++ for (i = 0; i < 16; i++) { ++ struct packed_ushort rv = next(&s); ++ if ((i == 0 && rv.ucs != 0xffff) ++ || (i > 0 && rv.ucs != 0)) ++ abort(); ++ } ++ return 0; ++} +diff --git a/gcc/tree.c b/gcc/tree.c +index 3c17694c703..5c1374d6fb1 100644 +--- a/gcc/tree.c ++++ b/gcc/tree.c +@@ -5216,6 +5216,12 @@ fld_worklist_push (tree t, class free_lang_data_d *fld) + static tree + fld_simplified_type_name (tree type) + { ++ /* Simplify type will cause that struct A and struct A within ++ struct B are different type pointers, so skip it in structure ++ optimizations. */ ++ if (flag_ipa_struct_reorg) ++ return TYPE_NAME (type); ++ + if (!TYPE_NAME (type) || TREE_CODE (TYPE_NAME (type)) != TYPE_DECL) + return TYPE_NAME (type); + /* Drop TYPE_DECLs in TYPE_NAME in favor of the identifier in the +@@ -5454,6 +5460,11 @@ fld_simplified_type (tree t, class free_lang_data_d *fld) + { + if (!t) + return t; ++ /* Simplify type will cause that struct A and struct A within ++ struct B are different type pointers, so skip it in structure ++ optimizations. */ ++ if (flag_ipa_struct_reorg) ++ return t; + if (POINTER_TYPE_P (t)) + return fld_incomplete_type_of (t, fld); + /* FIXME: This triggers verification error, see PR88140. */ +-- +2.21.0.windows.1 + diff --git a/0017-mcmodel-Enable-mcmodel-medium-on-kunpeng.patch b/0017-mcmodel-Enable-mcmodel-medium-on-kunpeng.patch new file mode 100644 index 0000000..6651392 --- /dev/null +++ b/0017-mcmodel-Enable-mcmodel-medium-on-kunpeng.patch @@ -0,0 +1,622 @@ +From 4d76b521d9bb539556011304b8a76dea1e2657a1 Mon Sep 17 00:00:00 2001 +From: bule <bule1@huawei.com> +Date: Fri, 6 Aug 2021 10:20:54 +0800 +Subject: [PATCH 17/22] [mcmodel] Enable mcmodel=medium on kunpeng + +Enable mcmodel=medium on kunpeng + +diff --git a/gcc/combine.c b/gcc/combine.c +index 35505cc5311..497e53289ca 100644 +--- a/gcc/combine.c ++++ b/gcc/combine.c +@@ -1923,6 +1923,12 @@ can_combine_p (rtx_insn *insn, rtx_insn *i3, rtx_insn *pred ATTRIBUTE_UNUSED, + break; + + case SET: ++ /* If the set is a symbol loaded by medium code model unspec ++ escape this combine. */ ++ if (GET_CODE (SET_SRC (elt)) == UNSPEC ++ && XVECLEN (SET_SRC (elt), 0) != 0 ++ && targetm.medium_symbol_p (SET_SRC (elt))) ++ return 0; + /* Ignore SETs whose result isn't used but not those that + have side-effects. */ + if (find_reg_note (insn, REG_UNUSED, SET_DEST (elt)) +diff --git a/gcc/config/aarch64/aarch64-opts.h b/gcc/config/aarch64/aarch64-opts.h +index ee7bed34924..21828803480 100644 +--- a/gcc/config/aarch64/aarch64-opts.h ++++ b/gcc/config/aarch64/aarch64-opts.h +@@ -66,6 +66,10 @@ enum aarch64_code_model { + /* -fpic for small memory model. + GOT size to 28KiB (4K*8-4K) or 3580 entries. */ + AARCH64_CMODEL_SMALL_SPIC, ++ /* Using movk insn sequence to do 64bit PC relative relocation. */ ++ AARCH64_CMODEL_MEDIUM, ++ /* Using movk insn sequence to do 64bit PC relative got relocation. */ ++ AARCH64_CMODEL_MEDIUM_PIC, + /* No assumptions about addresses of code and data. + The PIC variant is not yet implemented. */ + AARCH64_CMODEL_LARGE +diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h +index bebd1b36228..226f3a8ff01 100644 +--- a/gcc/config/aarch64/aarch64-protos.h ++++ b/gcc/config/aarch64/aarch64-protos.h +@@ -95,9 +95,11 @@ + */ + enum aarch64_symbol_type + { ++ SYMBOL_MEDIUM_ABSOLUTE, + SYMBOL_SMALL_ABSOLUTE, + SYMBOL_SMALL_GOT_28K, + SYMBOL_SMALL_GOT_4G, ++ SYMBOL_MEDIUM_GOT_4G, + SYMBOL_SMALL_TLSGD, + SYMBOL_SMALL_TLSDESC, + SYMBOL_SMALL_TLSIE, +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 79dc8f186f4..f78942b04c6 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -3127,6 +3127,29 @@ aarch64_load_symref_appropriately (rtx dest, rtx imm, + emit_insn (gen_add_losym (dest, tmp_reg, imm)); + return; + } ++ case SYMBOL_MEDIUM_ABSOLUTE: ++ { ++ rtx tmp_reg = dest; ++ machine_mode mode = GET_MODE (dest); ++ ++ gcc_assert (mode == Pmode || mode == ptr_mode); ++ if (can_create_pseudo_p ()) ++ tmp_reg = gen_reg_rtx (mode); ++ ++ if (mode == DImode) ++ { ++ emit_insn (gen_load_symbol_medium_di (dest, tmp_reg, imm)); ++ } ++ else ++ { ++ emit_insn (gen_load_symbol_medium_si (dest, tmp_reg, imm)); ++ } ++ if (REG_P (dest)) ++ { ++ set_unique_reg_note (get_last_insn (), REG_EQUAL, copy_rtx (imm)); ++ } ++ return; ++ } + + case SYMBOL_TINY_ABSOLUTE: + emit_insn (gen_rtx_SET (dest, imm)); +@@ -3249,6 +3272,60 @@ aarch64_load_symref_appropriately (rtx dest, rtx imm, + return; + } + ++ case SYMBOL_MEDIUM_GOT_4G: ++ { ++ rtx tmp_reg = dest; ++ machine_mode mode = GET_MODE (dest); ++ if (can_create_pseudo_p ()) ++ { ++ tmp_reg = gen_reg_rtx (mode); ++ } ++ rtx insn; ++ rtx mem; ++ rtx s = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); ++ ++ if (mode == DImode) ++ { ++ emit_insn (gen_load_symbol_medium_di (tmp_reg, dest, s)); ++ } ++ else ++ { ++ emit_insn (gen_load_symbol_medium_si (tmp_reg, dest, s)); ++ } ++ if (REG_P (dest)) ++ { ++ set_unique_reg_note (get_last_insn (), REG_EQUAL, copy_rtx (s)); ++ } ++ ++ if (mode == ptr_mode) ++ { ++ if (mode == DImode) ++ { ++ emit_insn (gen_get_gotoff_di (dest, imm)); ++ insn = gen_ldr_got_medium_di (dest, tmp_reg, dest); ++ } ++ else ++ { ++ emit_insn (gen_get_gotoff_si (dest, imm)); ++ insn = gen_ldr_got_medium_si (dest, tmp_reg, dest); ++ } ++ mem = XVECEXP (SET_SRC (insn), 0, 0); ++ } ++ else ++ { ++ gcc_assert (mode == Pmode); ++ emit_insn (gen_get_gotoff_di (dest, imm)); ++ insn = gen_ldr_got_medium_sidi (dest, tmp_reg, dest); ++ mem = XVECEXP (XEXP (SET_SRC (insn), 0), 0, 0); ++ } ++ ++ gcc_assert (GET_CODE (mem) == MEM); ++ MEM_READONLY_P (mem) = 1; ++ MEM_NOTRAP_P (mem) = 1; ++ emit_insn (insn); ++ return; ++ } ++ + case SYMBOL_SMALL_TLSGD: + { + rtx_insn *insns; +@@ -5256,11 +5333,12 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm) + + return; + +- case SYMBOL_SMALL_TLSGD: +- case SYMBOL_SMALL_TLSDESC: ++ case SYMBOL_SMALL_TLSGD: ++ case SYMBOL_SMALL_TLSDESC: + case SYMBOL_SMALL_TLSIE: + case SYMBOL_SMALL_GOT_28K: + case SYMBOL_SMALL_GOT_4G: ++ case SYMBOL_MEDIUM_GOT_4G: + case SYMBOL_TINY_GOT: + case SYMBOL_TINY_TLSIE: + if (const_offset != 0) +@@ -5279,6 +5357,7 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm) + case SYMBOL_TLSLE24: + case SYMBOL_TLSLE32: + case SYMBOL_TLSLE48: ++ case SYMBOL_MEDIUM_ABSOLUTE: + aarch64_load_symref_appropriately (dest, imm, sty); + return; + +@@ -9389,7 +9468,14 @@ aarch64_classify_address (struct aarch64_address_info *info, + if (GET_CODE (sym) == SYMBOL_REF + && offset.is_constant (&const_offset) + && (aarch64_classify_symbol (sym, const_offset) +- == SYMBOL_SMALL_ABSOLUTE)) ++ == SYMBOL_SMALL_ABSOLUTE ++ /* Fix fail on dbl_mov_immediate_1.c. If end up here with ++ MEDIUM_ABSOLUTE, the symbol is a constant number that is ++ forced to memory in reload pass, which is ok to go on with ++ the original design that subtitude the mov to ++ 'adrp and ldr :losum'. */ ++ || aarch64_classify_symbol (sym, const_offset) ++ == SYMBOL_MEDIUM_ABSOLUTE)) + { + /* The symbol and offset must be aligned to the access size. */ + unsigned int align; +@@ -11346,7 +11432,13 @@ static inline bool + aarch64_can_use_per_function_literal_pools_p (void) + { + return (aarch64_pcrelative_literal_loads +- || aarch64_cmodel == AARCH64_CMODEL_LARGE); ++ || aarch64_cmodel == AARCH64_CMODEL_LARGE ++ /* Fix const9.C so that constants goes to function_literal_pools. ++ According to the orignal design of aarch64 mcmodel=medium, we ++ don't care where this symbol is put. For the benefit of code size ++ and behaviour consistent with other mcmodel, put it into ++ function_literal_pools. */ ++ || aarch64_cmodel == AARCH64_CMODEL_MEDIUM); + } + + static bool +@@ -13003,6 +13095,13 @@ cost_plus: + if (speed) + *cost += extra_cost->alu.arith; + } ++ else if (aarch64_cmodel == AARCH64_CMODEL_MEDIUM ++ || aarch64_cmodel == AARCH64_CMODEL_MEDIUM_PIC) ++ { ++ /* 4 movs adr sub add 2movs ldr. */ ++ if (speed) ++ *cost += 7*extra_cost->alu.arith; ++ } + + if (flag_pic) + { +@@ -13010,6 +13109,8 @@ cost_plus: + *cost += COSTS_N_INSNS (1); + if (speed) + *cost += extra_cost->ldst.load; ++ if (aarch64_cmodel == AARCH64_CMODEL_MEDIUM_PIC) ++ *cost += 2*extra_cost->alu.arith; + } + return true; + +@@ -14373,6 +14474,7 @@ initialize_aarch64_tls_size (struct gcc_options *opts) + if (aarch64_tls_size > 32) + aarch64_tls_size = 32; + break; ++ case AARCH64_CMODEL_MEDIUM: + case AARCH64_CMODEL_LARGE: + /* The maximum TLS size allowed under large is 16E. + FIXME: 16E should be 64bit, we only support 48bit offset now. */ +@@ -15266,6 +15368,12 @@ initialize_aarch64_code_model (struct gcc_options *opts) + #endif + } + break; ++ case AARCH64_CMODEL_MEDIUM: ++ if (opts->x_flag_pic) ++ { ++ aarch64_cmodel = AARCH64_CMODEL_MEDIUM_PIC; ++ } ++ break; + case AARCH64_CMODEL_LARGE: + if (opts->x_flag_pic) + sorry ("code model %qs with %<-f%s%>", "large", +@@ -15276,6 +15384,7 @@ initialize_aarch64_code_model (struct gcc_options *opts) + case AARCH64_CMODEL_TINY_PIC: + case AARCH64_CMODEL_SMALL_PIC: + case AARCH64_CMODEL_SMALL_SPIC: ++ case AARCH64_CMODEL_MEDIUM_PIC: + gcc_unreachable (); + } + } +@@ -15286,6 +15395,7 @@ static void + aarch64_option_save (struct cl_target_option *ptr, struct gcc_options *opts) + { + ptr->x_aarch64_override_tune_string = opts->x_aarch64_override_tune_string; ++ ptr->x_aarch64_data_threshold = opts->x_aarch64_data_threshold; + ptr->x_aarch64_branch_protection_string + = opts->x_aarch64_branch_protection_string; + } +@@ -15301,6 +15411,7 @@ aarch64_option_restore (struct gcc_options *opts, struct cl_target_option *ptr) + opts->x_explicit_arch = ptr->x_explicit_arch; + selected_arch = aarch64_get_arch (ptr->x_explicit_arch); + opts->x_aarch64_override_tune_string = ptr->x_aarch64_override_tune_string; ++ opts->x_aarch64_data_threshold = ptr->x_aarch64_data_threshold; + opts->x_aarch64_branch_protection_string + = ptr->x_aarch64_branch_protection_string; + if (opts->x_aarch64_branch_protection_string) +@@ -16169,6 +16280,8 @@ aarch64_classify_symbol (rtx x, HOST_WIDE_INT offset) + + case AARCH64_CMODEL_SMALL_SPIC: + case AARCH64_CMODEL_SMALL_PIC: ++ case AARCH64_CMODEL_MEDIUM_PIC: ++ case AARCH64_CMODEL_MEDIUM: + case AARCH64_CMODEL_SMALL: + return SYMBOL_SMALL_ABSOLUTE; + +@@ -16205,6 +16318,7 @@ aarch64_classify_symbol (rtx x, HOST_WIDE_INT offset) + return SYMBOL_TINY_ABSOLUTE; + + case AARCH64_CMODEL_SMALL: ++ AARCH64_SMALL_ROUTINE: + /* Same reasoning as the tiny code model, but the offset cap here is + 1MB, allowing +/-3.9GB for the offset to the symbol. */ + +@@ -16228,7 +16342,50 @@ aarch64_classify_symbol (rtx x, HOST_WIDE_INT offset) + ? SYMBOL_SMALL_GOT_28K : SYMBOL_SMALL_GOT_4G); + return SYMBOL_SMALL_ABSOLUTE; + ++ case AARCH64_CMODEL_MEDIUM: ++ { ++ tree decl_local = SYMBOL_REF_DECL (x); ++ if (decl_local != NULL ++ && tree_fits_uhwi_p (DECL_SIZE_UNIT (decl_local))) ++ { ++ HOST_WIDE_INT size = tree_to_uhwi (DECL_SIZE_UNIT (decl_local)); ++ /* If the data is smaller than the threshold, goto ++ the small code model. Else goto the large code ++ model. */ ++ if (size >= HOST_WIDE_INT (aarch64_data_threshold)) ++ goto AARCH64_LARGE_ROUTINE; ++ } ++ goto AARCH64_SMALL_ROUTINE; ++ } ++ ++ case AARCH64_CMODEL_MEDIUM_PIC: ++ { ++ tree decl_local = SYMBOL_REF_DECL (x); ++ if (decl_local != NULL ++ && tree_fits_uhwi_p (DECL_SIZE_UNIT (decl_local))) ++ { ++ HOST_WIDE_INT size = tree_to_uhwi (DECL_SIZE_UNIT (decl_local)); ++ if (size < HOST_WIDE_INT (aarch64_data_threshold)) ++ { ++ if (!aarch64_symbol_binds_local_p (x)) ++ { ++ /* flag_pic is 2 only when -fPIC is on, when we should ++ use 4G GOT. */ ++ return flag_pic == 2 ? SYMBOL_SMALL_GOT_4G ++ : SYMBOL_SMALL_GOT_28K ; ++ } ++ return SYMBOL_SMALL_ABSOLUTE; ++ } ++ } ++ if (!aarch64_symbol_binds_local_p (x)) ++ { ++ return SYMBOL_MEDIUM_GOT_4G; ++ } ++ return SYMBOL_MEDIUM_ABSOLUTE; ++ } ++ + case AARCH64_CMODEL_LARGE: ++ AARCH64_LARGE_ROUTINE: + /* This is alright even in PIC code as the constant + pool reference is always PC relative and within + the same translation unit. */ +@@ -19352,6 +19509,8 @@ aarch64_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED, int global) + case AARCH64_CMODEL_SMALL: + case AARCH64_CMODEL_SMALL_PIC: + case AARCH64_CMODEL_SMALL_SPIC: ++ case AARCH64_CMODEL_MEDIUM: ++ case AARCH64_CMODEL_MEDIUM_PIC: + /* text+got+data < 4Gb. 4-byte signed relocs are sufficient + for everything. */ + type = DW_EH_PE_sdata4; +@@ -22605,7 +22764,14 @@ aarch64_empty_mask_is_expensive (unsigned) + bool + aarch64_use_pseudo_pic_reg (void) + { +- return aarch64_cmodel == AARCH64_CMODEL_SMALL_SPIC; ++ /* flag_pic is 2 when -fPIC is on, where we do not need the pseudo ++ pic reg. In medium code mode, when combine with -fpie/-fpic, there are ++ possibility that some symbol size smaller than the -mlarge-data-threshold ++ will still use SMALL_SPIC relocation, which need the pseudo pic reg. ++ Fix spill_1.c fail. */ ++ return aarch64_cmodel == AARCH64_CMODEL_SMALL_SPIC ++ || (aarch64_cmodel == AARCH64_CMODEL_MEDIUM_PIC ++ && flag_pic != 2); + } + + /* Implement TARGET_UNSPEC_MAY_TRAP_P. */ +@@ -22615,6 +22781,7 @@ aarch64_unspec_may_trap_p (const_rtx x, unsigned flags) + { + switch (XINT (x, 1)) + { ++ case UNSPEC_GOTMEDIUMPIC4G: + case UNSPEC_GOTSMALLPIC: + case UNSPEC_GOTSMALLPIC28K: + case UNSPEC_GOTTINYPIC: +@@ -22976,6 +23143,18 @@ aarch64_estimated_poly_value (poly_int64 val) + return val.coeffs[0] + val.coeffs[1] * over_128 / 128; + } + ++/* Implement TARGET_MEDIUM_SYMBOL_P. ++ Return true if x is a symbol loaded by UNSPEC_LOAD_SYMBOL_MEDIUM. */ ++bool ++aarch64_medium_symbol_p (rtx x) ++{ ++ if (GET_CODE (x) != UNSPEC) ++ { ++ return false; ++ } ++ return XINT (x, 1) == UNSPEC_LOAD_SYMBOL_MEDIUM; ++} ++ + + /* Return true for types that could be supported as SIMD return or + argument types. */ +@@ -24015,6 +24194,9 @@ aarch64_libgcc_floating_mode_supported_p + #undef TARGET_ESTIMATED_POLY_VALUE + #define TARGET_ESTIMATED_POLY_VALUE aarch64_estimated_poly_value + ++#undef TARGET_MEDIUM_SYMBOL_P ++#define TARGET_MEDIUM_SYMBOL_P aarch64_medium_symbol_p ++ + #undef TARGET_ATTRIBUTE_TABLE + #define TARGET_ATTRIBUTE_TABLE aarch64_attribute_table + +diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h +index 51148846345..8fc92d13dcb 100644 +--- a/gcc/config/aarch64/aarch64.h ++++ b/gcc/config/aarch64/aarch64.h +@@ -33,6 +33,10 @@ + + #define REGISTER_TARGET_PRAGMAS() aarch64_register_pragmas () + ++/* Default threshold 64-bit relocation data ++ with aarch64 medium memory model. */ ++#define AARCH64_DEFAULT_LARGE_DATA_THRESHOLD 65536 ++ + /* Target machine storage layout. */ + + #define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE) \ +diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md +index 58445dea941..ee80261f1ac 100644 +--- a/gcc/config/aarch64/aarch64.md ++++ b/gcc/config/aarch64/aarch64.md +@@ -224,6 +224,9 @@ + UNSPEC_RSQRTS + UNSPEC_NZCV + UNSPEC_XPACLRI ++ UNSPEC_GOTMEDIUMPIC4G ++ UNSPEC_GET_GOTOFF ++ UNSPEC_LOAD_SYMBOL_MEDIUM + UNSPEC_LD1_SVE + UNSPEC_ST1_SVE + UNSPEC_LDNT1_SVE +@@ -6792,6 +6795,39 @@ + [(set_attr "type" "load_4")] + ) + ++(define_insn "get_gotoff_<mode>" ++ [(set (match_operand:GPI 0 "register_operand" "=r") ++ (unspec:GPI [(match_operand 1 "aarch64_valid_symref" "S")] ++ UNSPEC_GET_GOTOFF))] ++ "" ++ "movz\\t%x0, :gotoff_g1:%A1\;movk\\t%x0, :gotoff_g0_nc:%A1" ++ [(set_attr "type" "multiple") ++ (set_attr "length" "8")] ++) ++ ++(define_insn "ldr_got_medium_<mode>" ++ [(set (match_operand:PTR 0 "register_operand" "=r") ++ (unspec:PTR [(mem:PTR (lo_sum:PTR ++ (match_operand:PTR 1 "register_operand" "r") ++ (match_operand:PTR 2 "register_operand" "r")))] ++ UNSPEC_GOTMEDIUMPIC4G))] ++ "" ++ "ldr\\t%0, [%1, %2]" ++ [(set_attr "type" "load_4")] ++) ++ ++(define_insn "ldr_got_medium_sidi" ++ [(set (match_operand:DI 0 "register_operand" "=r") ++ (zero_extend:DI ++ (unspec:SI [(mem:SI (lo_sum:DI ++ (match_operand:DI 1 "register_operand" "r") ++ (match_operand:DI 2 "register_operand" "r")))] ++ UNSPEC_GOTMEDIUMPIC4G)))] ++ "TARGET_ILP32" ++ "ldr\\t%0, [%1, %2]" ++ [(set_attr "type" "load_4")] ++) ++ + (define_insn "ldr_got_small_28k_<mode>" + [(set (match_operand:PTR 0 "register_operand" "=r") + (unspec:PTR [(mem:PTR (lo_sum:PTR +@@ -6955,6 +6991,23 @@ + (set_attr "length" "12")] + ) + ++(define_insn "load_symbol_medium_<mode>" ++ [(set (match_operand:GPI 0 "register_operand" "=r") ++ (unspec:GPI [(match_operand 2 "aarch64_valid_symref" "S")] ++ UNSPEC_LOAD_SYMBOL_MEDIUM)) ++ (clobber (match_operand:GPI 1 "register_operand" "=r"))] ++ "" ++ "movz\\t%x0, :prel_g3:%A2\;\\ ++movk\\t%x0, :prel_g2_nc:%A2\;\\ ++movk\\t%x0, :prel_g1_nc:%A2\;\\ ++movk\\t%x0, :prel_g0_nc:%A2\;\\ ++adr\\t%x1, .\;\\ ++sub\\t%x1, %x1, 0x4\;\\ ++add\\t%x0, %x0, %x1" ++ [(set_attr "type" "multiple") ++ (set_attr "length" "28")] ++) ++ + (define_expand "tlsdesc_small_<mode>" + [(unspec:PTR [(match_operand 0 "aarch64_valid_symref")] UNSPEC_TLSDESC)] + "TARGET_TLS_DESC" +diff --git a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt +index 4539156d6f4..bb888461ab0 100644 +--- a/gcc/config/aarch64/aarch64.opt ++++ b/gcc/config/aarch64/aarch64.opt +@@ -27,6 +27,10 @@ enum aarch64_processor explicit_tune_core = aarch64_none + TargetVariable + enum aarch64_arch explicit_arch = aarch64_no_arch + ++;; -mlarge-data-threshold= ++TargetSave ++int x_aarch64_data_threshold ++ + TargetSave + const char *x_aarch64_override_tune_string + +@@ -60,9 +64,16 @@ Enum(cmodel) String(tiny) Value(AARCH64_CMODEL_TINY) + EnumValue + Enum(cmodel) String(small) Value(AARCH64_CMODEL_SMALL) + ++EnumValue ++Enum(cmodel) String(medium) Value(AARCH64_CMODEL_MEDIUM) ++ + EnumValue + Enum(cmodel) String(large) Value(AARCH64_CMODEL_LARGE) + ++mlarge-data-threshold= ++Target RejectNegative Joined UInteger Var(aarch64_data_threshold) Init(AARCH64_DEFAULT_LARGE_DATA_THRESHOLD) ++-mlarge-data-threshold=<number> Data greater than given threshold will be assume that it should be relocated using 64-bit relocation. ++ + mbig-endian + Target Report RejectNegative Mask(BIG_END) + Assume target CPU is configured as big endian. +diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi +index fcb7245e95c..0508fce57a7 100644 +--- a/gcc/doc/tm.texi ++++ b/gcc/doc/tm.texi +@@ -6983,6 +6983,11 @@ things like cost calculations or profiling frequencies. The default + implementation returns the lowest possible value of @var{val}. + @end deftypefn + ++@deftypefn {Target Hook} bool TARGET_MEDIUM_SYMBOL_P (rtx @var{x}) ++Return true if the input rtx is a symbol loaded by kunpeng medium code ++model. ++@end deftypefn ++ + @node Scheduling + @section Adjusting the Instruction Scheduler + +diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in +index c17209daa51..3b70ea4841a 100644 +--- a/gcc/doc/tm.texi.in ++++ b/gcc/doc/tm.texi.in +@@ -4701,6 +4701,8 @@ Define this macro if a non-short-circuit operation produced by + + @hook TARGET_ESTIMATED_POLY_VALUE + ++@hook TARGET_MEDIUM_SYMBOL_P ++ + @node Scheduling + @section Adjusting the Instruction Scheduler + +diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c +index d61cadb5208..bad8208cd22 100644 +--- a/gcc/dwarf2out.c ++++ b/gcc/dwarf2out.c +@@ -14501,14 +14501,17 @@ const_ok_for_output_1 (rtx rtl) + /* If delegitimize_address couldn't do anything with the UNSPEC, and + the target hook doesn't explicitly allow it in debug info, assume + we can't express it in the debug info. */ +- /* Don't complain about TLS UNSPECs, those are just too hard to +- delegitimize. Note this could be a non-decl SYMBOL_REF such as +- one in a constant pool entry, so testing SYMBOL_REF_TLS_MODEL +- rather than DECL_THREAD_LOCAL_P is not just an optimization. */ ++ /* Don't complain about TLS UNSPECs and aarch64 medium code model ++ related UNSPECs, those are just too hard to delegitimize. Note ++ this could be a non-decl SYMBOL_REF such as one in a constant ++ pool entry, so testing SYMBOL_REF_TLS_MODEL rather than ++ DECL_THREAD_LOCAL_P is not just an optimization. */ + if (flag_checking + && (XVECLEN (rtl, 0) == 0 + || GET_CODE (XVECEXP (rtl, 0, 0)) != SYMBOL_REF +- || SYMBOL_REF_TLS_MODEL (XVECEXP (rtl, 0, 0)) == TLS_MODEL_NONE)) ++ || (!targetm.medium_symbol_p (rtl) ++ && SYMBOL_REF_TLS_MODEL (XVECEXP (rtl, 0, 0)) ++ == TLS_MODEL_NONE))) + inform (current_function_decl + ? DECL_SOURCE_LOCATION (current_function_decl) + : UNKNOWN_LOCATION, +diff --git a/gcc/target.def b/gcc/target.def +index f5a6d507e91..2020564118b 100644 +--- a/gcc/target.def ++++ b/gcc/target.def +@@ -3869,6 +3869,13 @@ implementation returns the lowest possible value of @var{val}.", + HOST_WIDE_INT, (poly_int64 val), + default_estimated_poly_value) + ++DEFHOOK ++(medium_symbol_p, ++ "Return true if the input rtx is a symbol loaded by kunpeng medium code\n\ ++model.", ++ bool, (rtx x), ++ default_medium_symbol_p) ++ + /* Permit speculative instructions in delay slots during delayed-branch + scheduling. */ + DEFHOOK +diff --git a/gcc/targhooks.c b/gcc/targhooks.c +index 7cb04f30bdb..43a9f0cdf5b 100644 +--- a/gcc/targhooks.c ++++ b/gcc/targhooks.c +@@ -1708,6 +1708,13 @@ default_estimated_poly_value (poly_int64 x) + return x.coeffs[0]; + } + ++/* The default implementation of TARGET_MEDIUM_SYMBOL_P. */ ++bool ++default_medium_symbol_p (rtx x ATTRIBUTE_UNUSED) ++{ ++ return false; ++} ++ + /* For hooks which use the MOVE_RATIO macro, this gives the legacy default + behavior. SPEED_P is true if we are compiling for speed. */ + +-- +2.21.0.windows.1 + diff --git a/0018-StructReorderFields-Structure-reorder-fields.patch b/0018-StructReorderFields-Structure-reorder-fields.patch new file mode 100644 index 0000000..689f066 --- /dev/null +++ b/0018-StructReorderFields-Structure-reorder-fields.patch @@ -0,0 +1,5370 @@ +From bc86209da93f71d9fd48cb65ad3200b6c88cf75b Mon Sep 17 00:00:00 2001 +From: huangxiaoquan <huangxiaoquan1@huawei.com> +Date: Tue, 20 Jul 2021 10:09:08 +0800 +Subject: [PATCH 18/22] [StructReorderFields] Structure reorder fields + +Introduce structure fields reordering optimization, that change +fields ordering of C-like structures in order to better utilize spatial +locality. + +diff --git a/gcc/common.opt b/gcc/common.opt +index d096ff9c314..73c24f28d22 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -1865,6 +1865,10 @@ fipa-matrix-reorg + Common Ignore + Does nothing. Preserved for backward compatibility. + ++fipa-reorder-fields ++Common Report Var(flag_ipa_reorder_fields) Init(0) Optimization ++Perform structure fields reorder optimizations. ++ + fipa-struct-reorg + Common Report Var(flag_ipa_struct_reorg) Init(0) Optimization + Perform structure layout optimizations. +diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi +index 7b4578e3e44..4b0fd2ffb38 100644 +--- a/gcc/doc/invoke.texi ++++ b/gcc/doc/invoke.texi +@@ -478,6 +478,7 @@ Objective-C and Objective-C++ Dialects}. + -finline-functions -finline-functions-called-once -finline-limit=@var{n} @gol + -finline-small-functions -fipa-cp -fipa-cp-clone @gol + -fipa-bit-cp -fipa-vrp -fipa-pta -fipa-profile -fipa-pure-const @gol ++-fipa-reorder-fields @gol + -fipa-struct-reorg @gol + -fipa-reference -fipa-reference-addressable @gol + -fipa-stack-alignment -fipa-icf -fira-algorithm=@var{algorithm} @gol +@@ -10224,6 +10225,14 @@ Enabled by default at @option{-O} and higher. + Reduce stack alignment on call sites if possible. + Enabled by default. + ++@item -fipa-reorder-fields ++@opindex fipa-reorder-fields ++Introduce structure fields reordering optimization, that change fields ++ordering of C-like structures in order to better utilize spatial locality. ++This transformation is affective for programs containing arrays of structures. ++It works only in whole program mode, so it requires @option{-fwhole-program} ++to be enabled. ++ + @item -fipa-struct-reorg + @opindex fipa-struct-reorg + Perform structure reorganization optimization, that change C-like structures +diff --git a/gcc/ipa-struct-reorg/escapes.def b/gcc/ipa-struct-reorg/escapes.def +index 9020cc48952..03adc30811a 100644 +--- a/gcc/ipa-struct-reorg/escapes.def ++++ b/gcc/ipa-struct-reorg/escapes.def +@@ -58,5 +58,8 @@ DEF_ESCAPE (escape_ptr_ptr, "Type is used in a pointer to a pointer [not handled + DEF_ESCAPE (escape_return, "Type escapes via a return [not handled yet]") + DEF_ESCAPE (escape_separate_instance, "Type escapes via a separate instance") + DEF_ESCAPE (escape_unhandled_rewrite, "Type escapes via a unhandled rewrite stmt") ++DEF_ESCAPE (escape_via_orig_escape, "Type escapes via a original escape type") ++DEF_ESCAPE (escape_instance_field, "Type escapes via a field of instance") ++DEF_ESCAPE (escape_via_empty_no_orig, "Type escapes via empty and no original") + + #undef DEF_ESCAPE +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +index 1cb544ec3b0..384aa81583c 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -198,27 +198,66 @@ lang_c_p (void) + } + + return false; ++ ++/* Get the number of pointer layers. */ ++ ++int ++get_ptr_layers (tree expr) ++{ ++ int layers = 0; ++ while (POINTER_TYPE_P (expr) || TREE_CODE (expr) == ARRAY_TYPE) ++ { ++ layers++; ++ expr = TREE_TYPE (expr); ++ } ++ return layers; ++} ++ ++/* Comparison pointer layers. */ ++ ++bool ++cmp_ptr_layers (tree a, tree b) ++{ ++ return get_ptr_layers (a) == get_ptr_layers (b); ++} ++ ++/* Return true if the ssa_name comes from the void* parameter. */ ++ ++bool ++is_from_void_ptr_parm (tree ssa_name) ++{ ++ gcc_assert (TREE_CODE (ssa_name) == SSA_NAME); ++ tree var = SSA_NAME_VAR (ssa_name); ++ return (var && TREE_CODE (var) == PARM_DECL ++ && VOID_POINTER_P (TREE_TYPE (ssa_name))); + } + + enum srmode + { + NORMAL = 0, +- COMPLETE_STRUCT_RELAYOUT ++ COMPLETE_STRUCT_RELAYOUT, ++ STRUCT_REORDER_FIELDS + }; + + static bool is_result_of_mult (tree arg, tree *num, tree struct_size); ++bool isptrptr (tree type); ++ ++srmode current_mode; + + } // anon namespace + + namespace struct_reorg { + ++hash_map <tree, auto_vec <tree> > fields_to_finish; ++ + /* Constructor of srfunction. */ + + srfunction::srfunction (cgraph_node *n) + : node (n), + old (NULL), + newnode (NULL), +- newf (NULL) ++ newf (NULL), ++ is_safe_func (false) + { + } + +@@ -370,12 +409,13 @@ srtype::add_field_site (srfield *field) + + /* Constructor of DECL. */ + +-srdecl::srdecl (srtype *tp, tree decl, int argnum) ++srdecl::srdecl (srtype *tp, tree decl, int argnum, tree orig_type) + : type (tp), + decl (decl), + func (NULL_TREE), + argumentnum (argnum), +- visited (false) ++ visited (false), ++ orig_type (orig_type) + { + if (TREE_CODE (decl) == SSA_NAME) + func = current_function_decl; +@@ -399,17 +439,25 @@ srfunction::find_decl (tree decl) + /* Record DECL of the TYPE with argument num ARG. */ + + srdecl * +-srfunction::record_decl (srtype *type, tree decl, int arg) ++srfunction::record_decl (srtype *type, tree decl, int arg, tree orig_type) + { +- // Search for the decl to see if it is already there. ++ /* Search for the decl to see if it is already there. */ + srdecl *decl1 = find_decl (decl); + + if (decl1) +- return decl1; ++ { ++ /* Added the orig_type information. */ ++ if (!decl1->orig_type && orig_type && isptrptr (orig_type)) ++ { ++ decl1->orig_type = orig_type; ++ } ++ return decl1; ++ } + + gcc_assert (type); + +- decl1 = new srdecl (type, decl, arg); ++ orig_type = isptrptr (TREE_TYPE (decl)) ? TREE_TYPE (decl) : orig_type; ++ decl1 = new srdecl (type, decl, arg, isptrptr (orig_type)? orig_type : NULL); + decls.safe_push(decl1); + return decl1; + } +@@ -473,31 +521,29 @@ srtype::dump (FILE *f) + print_generic_expr (f, type); + fprintf (f, "(%d) { ", TYPE_UID (type)); + if (escapes != does_not_escape) +- fprintf (f, " escapes = \"%s\"\n", escape_reason ()); +- fprintf (f, " fields = { "); ++ { ++ fprintf (f, "escapes = \"%s\"", escape_reason ()); ++ } ++ fprintf (f, "\nfields = {\n"); + FOR_EACH_VEC_ELT (fields, i, field) + { +- if (i == 0) +- fprintf (f, "\n "); +- else +- fprintf (f, "\n, "); + field->dump (f); + } +- fprintf (f, " }\n "); +- fprintf (f, "\n accesses = {"); ++ fprintf (f, "}\n "); ++ ++ fprintf (f, "\naccesses = {\n"); + FOR_EACH_VEC_ELT (accesses, i, access) + { +- fprintf (f, "\n"); + access->dump (f); + } +- fprintf (f, " }\n "); +- fprintf (f, "\n functions = {"); ++ fprintf (f, "}\n "); ++ ++ fprintf (f, "\nfunctions = {\n"); + FOR_EACH_VEC_ELT (functions, i, fn) + { +- fprintf (f, " \n"); + fn->simple_dump (f); + } +- fprintf (f, "\n }\n"); ++ fprintf (f, "}\n"); + fprintf (f, "}\n"); + } + +@@ -507,6 +553,10 @@ void + srtype::simple_dump (FILE *f) + { + print_generic_expr (f, type); ++ if (current_mode == STRUCT_REORDER_FIELDS) ++ { ++ fprintf (f, "(%d)", TYPE_UID (type)); ++ } + } + + /* Analyze the type and decide what to be done with it. */ +@@ -544,6 +594,12 @@ srfield::create_new_fields (tree newtype[max_split], + tree newfields[max_split], + tree newlast[max_split]) + { ++ if (current_mode == STRUCT_REORDER_FIELDS) ++ { ++ create_new_reorder_fields (newtype, newfields, newlast); ++ return; ++ } ++ + tree nt[max_split]; + + for (unsigned i = 0; i < max_split; i++) +@@ -592,6 +648,117 @@ srfield::create_new_fields (tree newtype[max_split], + + } + ++/* Reorder fields. */ ++ ++void ++srfield::reorder_fields (tree newfields[max_split], tree newlast[max_split], ++ tree &field) ++{ ++ /* Reorder fields in descending. ++ newfields: always stores the first member of the chain ++ and with the largest size. ++ field: indicates the node to be inserted. */ ++ if (newfields[clusternum] == NULL) ++ { ++ newfields[clusternum] = field; ++ newlast[clusternum] = field; ++ } ++ else ++ { ++ tree tmp = newfields[clusternum]; ++ if (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (field))) ++ > tree_to_uhwi (TYPE_SIZE (TREE_TYPE (tmp)))) ++ { ++ DECL_CHAIN (field) = tmp; ++ newfields[clusternum] = field; ++ } ++ else ++ { ++ while (DECL_CHAIN (tmp) ++ && (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (field))) ++ <= tree_to_uhwi ( ++ TYPE_SIZE (TREE_TYPE (DECL_CHAIN (tmp)))))) ++ { ++ tmp = DECL_CHAIN (tmp); ++ } ++ ++ /* now tmp size > field size ++ insert field: tmp -> xx ==> tmp -> field -> xx. */ ++ DECL_CHAIN (field) = DECL_CHAIN (tmp); // field -> xx ++ DECL_CHAIN (tmp) = field; // tmp -> field ++ } ++ } ++} ++ ++/* Create the new reorder fields for this field. ++ newtype[max_split]: srtype's member variable, ++ newfields[max_split]: created by create_new_type func, ++ newlast[max_split]: created by create_new_type func. */ ++ ++void ++srfield::create_new_reorder_fields (tree newtype[max_split], ++ tree newfields[max_split], ++ tree newlast[max_split]) ++{ ++ /* newtype, corresponding to newtype[max_split] in srtype. */ ++ tree nt = NULL_TREE; ++ if (type == NULL) ++ { ++ /* Common var. */ ++ nt = fieldtype; ++ } ++ else ++ { ++ /* RECORD_TYPE var. */ ++ if (type->has_escaped ()) ++ { ++ nt = type->type; ++ } ++ else ++ { ++ nt = type->newtype[0]; ++ } ++ } ++ tree field = make_node (FIELD_DECL); ++ ++ /* Used for recursive types. ++ fields_to_finish: hase_map in the format of "type: {fieldA, fieldB}", ++ key : indicates the original type, ++ vaule: filed that need to be updated to newtype. */ ++ if (nt == NULL) ++ { ++ nt = make_node (RECORD_TYPE); ++ auto_vec <tree> &fields ++ = fields_to_finish.get_or_insert (inner_type (type->type)); ++ fields.safe_push (field); ++ } ++ ++ DECL_NAME (field) = DECL_NAME (fielddecl); ++ if (type == NULL) ++ { ++ /* Common members do not need to reconstruct. ++ Otherwise, int* -> int** or void* -> void**. */ ++ TREE_TYPE (field) = nt; ++ } ++ else ++ { ++ TREE_TYPE (field) ++ = reconstruct_complex_type (TREE_TYPE (fielddecl), nt); ++ } ++ DECL_SOURCE_LOCATION (field) = DECL_SOURCE_LOCATION (fielddecl); ++ SET_DECL_ALIGN (field, DECL_ALIGN (fielddecl)); ++ DECL_USER_ALIGN (field) = DECL_USER_ALIGN (fielddecl); ++ TREE_ADDRESSABLE (field) = TREE_ADDRESSABLE (fielddecl); ++ DECL_NONADDRESSABLE_P (field) = !TREE_ADDRESSABLE (fielddecl); ++ TREE_THIS_VOLATILE (field) = TREE_THIS_VOLATILE (fielddecl); ++ DECL_CONTEXT (field) = newtype[clusternum]; ++ ++ reorder_fields (newfields, newlast, field); ++ ++ /* srfield member variable, which stores the new field decl. */ ++ newfield[0] = field; ++} ++ + /* Create the new TYPE corresponding to THIS type. */ + + bool +@@ -627,7 +794,8 @@ srtype::create_new_type (void) + /* If the fields' types did have a change or + we are not splitting the struct into two clusters, + then just return false and don't change the type. */ +- if (!createnewtype && maxclusters == 0) ++ if (!createnewtype && maxclusters == 0 ++ && current_mode != STRUCT_REORDER_FIELDS) + { + newtype[0] = type; + return false; +@@ -636,6 +804,7 @@ srtype::create_new_type (void) + /* Should have at most max_split clusters. */ + gcc_assert (maxclusters < max_split); + ++ /* Record the first member of the field chain. */ + tree newfields[max_split]; + tree newlast[max_split]; + +@@ -654,7 +823,8 @@ srtype::create_new_type (void) + sprintf(id, "%d", i); + if (tname) + { +- name = concat (tname, ".reorg.", id, NULL); ++ name = concat (tname, current_mode == STRUCT_REORDER_FIELDS ++ ? ".reorder." : ".reorg.", id, NULL); + TYPE_NAME (newtype[i]) = build_decl (UNKNOWN_LOCATION, TYPE_DECL, + get_identifier (name), newtype[i]); + free (name); +@@ -691,6 +861,7 @@ srtype::create_new_type (void) + for (unsigned i = 0; i < maxclusters; i++) + { + print_generic_expr (dump_file, newtype[i]); ++ fprintf (dump_file, "(%d)", TYPE_UID (newtype[i])); + fprintf (dump_file, "\n"); + } + } +@@ -749,7 +920,12 @@ srfunction::create_new_decls (void) + tree newinner[max_split]; + memset (newinner, 0, sizeof(newinner)); + for (unsigned j = 0; j < max_split && type->newtype[j]; j++) +- newtype1[j] = reconstruct_complex_type (TREE_TYPE (decls[i]->decl), type->newtype[j]); ++ { ++ newtype1[j] = reconstruct_complex_type ( ++ isptrptr (decls[i]->orig_type) ? decls[i]->orig_type ++ : TREE_TYPE (decls[i]->decl), ++ type->newtype[j]); ++ } + if (inner) + { + srdecl *in = find_decl (inner); +@@ -794,7 +970,8 @@ srfunction::create_new_decls (void) + sprintf(id, "%d", j); + if (tname) + { +- name = concat (tname, ".reorg.", id, NULL); ++ name = concat (tname, current_mode == STRUCT_REORDER_FIELDS ++ ? ".reorder." : ".reorg.", id, NULL); + new_name = get_identifier (name); + free (name); + } +@@ -818,7 +995,6 @@ srfunction::create_new_decls (void) + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Created New decls for decl:\n"); +- fprintf (dump_file, "\n"); + decls[i]->dump (dump_file); + fprintf (dump_file, "\n"); + for (unsigned j = 0; j < max_split && decls[i]->newdecl[j]; j++) +@@ -845,7 +1021,7 @@ srfield::dump (FILE *f) + fprintf (f, ", offset = " HOST_WIDE_INT_PRINT_DEC, offset); + fprintf (f, ", type = "); + print_generic_expr (f, fieldtype); +- fprintf (f, "\n}\n"); ++ fprintf (f, "}\n"); + } + + +@@ -880,7 +1056,7 @@ sraccess::dump (FILE *f) + fprintf (f, " in function: %s/%d", node->name (), node->order); + fprintf (f, ", stmt:\n"); + print_gimple_stmt (f, stmt, 0); +- fprintf (f, "\n }\n"); ++ fprintf (f, "}\n"); + + } + +@@ -1010,8 +1186,7 @@ public: + // Constructors + ipa_struct_reorg(void) + : current_function (NULL), +- done_recording (false), +- current_mode (NORMAL) ++ done_recording (false) + { + } + +@@ -1023,11 +1198,12 @@ public: + auto_vec_del<srfunction> functions; + srglobal globals; + srfunction *current_function; ++ hash_set <cgraph_node *> safe_functions; + + bool done_recording; +- srmode current_mode; + + void dump_types (FILE *f); ++ void dump_newtypes (FILE *f); + void dump_types_escaped (FILE *f); + void dump_functions (FILE *f); + void record_accesses (void); +@@ -1035,6 +1211,8 @@ public: + bool walk_field_for_cycles (srtype*); + void prune_escaped_types (void); + void propagate_escape (void); ++ void propagate_escape_via_original (void); ++ void propagate_escape_via_empty_with_no_original (void); + void analyze_types (void); + void clear_visited (void); + bool create_new_types (void); +@@ -1044,8 +1222,11 @@ public: + void create_new_args (cgraph_node *new_node); + unsigned rewrite_functions (void); + srdecl *record_var (tree decl, escape_type escapes = does_not_escape, int arg = -1); ++ void record_safe_func_with_void_ptr_parm (void); + srfunction *record_function (cgraph_node *node); + srfunction *find_function (cgraph_node *node); ++ void record_field_type (tree field, srtype *base_srtype); ++ void record_struct_field_types (tree base_type, srtype *base_srtype); + srtype *record_type (tree type); + void process_union (tree type); + srtype *find_type (tree type); +@@ -1056,7 +1237,7 @@ public: + void record_stmt_expr (tree expr, cgraph_node *node, gimple *stmt); + void mark_expr_escape(tree, escape_type, gimple *stmt); + bool handled_allocation_stmt (gimple *stmt); +- tree allocate_size (srtype *t, gimple *stmt); ++ tree allocate_size (srtype *t, srdecl *decl, gimple *stmt); + + void mark_decls_in_as_not_needed (tree fn); + +@@ -1068,15 +1249,22 @@ public: + bool rewrite_phi (gphi *); + bool rewrite_expr (tree expr, tree newexpr[max_split], bool ignore_missing_decl = false); + bool rewrite_lhs_rhs (tree lhs, tree rhs, tree newlhs[max_split], tree newrhs[max_split]); +- bool get_type_field (tree expr, tree &base, bool &indirect, srtype *&type, srfield *&field, bool &realpart, bool &imagpart, bool &address, bool should_create = false, bool can_escape = false); ++ bool get_type_field (tree expr, tree &base, bool &indirect, srtype *&type, ++ srfield *&field, bool &realpart, bool &imagpart, ++ bool &address, bool& escape_from_base, ++ bool should_create = false, bool can_escape = false); + bool wholeaccess (tree expr, tree base, tree accesstype, srtype *t); + + void check_alloc_num (gimple *stmt, srtype *type); ++ void check_definition_assign (srdecl *decl, vec<srdecl*> &worklist); ++ void check_definition_call (srdecl *decl, vec<srdecl*> &worklist); + void check_definition (srdecl *decl, vec<srdecl*>&); + void check_uses (srdecl *decl, vec<srdecl*>&); + void check_use (srdecl *decl, gimple *stmt, vec<srdecl*>&); +- void check_type_and_push (tree newdecl, srtype *type, vec<srdecl*> &worklist, gimple *stmt); ++ void check_type_and_push (tree newdecl, srdecl *decl, ++ vec<srdecl*> &worklist, gimple *stmt); + void check_other_side (srdecl *decl, tree other, gimple *stmt, vec<srdecl*> &worklist); ++ void check_ptr_layers (tree a_expr, tree b_expr, gimple* stmt); + + void find_vars (gimple *stmt); + void find_var (tree expr, gimple *stmt); +@@ -1731,9 +1919,45 @@ ipa_struct_reorg::dump_types (FILE *f) + srtype *type; + FOR_EACH_VEC_ELT (types, i, type) + { ++ fprintf (f, "======= the %dth type: ======\n", i); + type->dump(f); ++ fprintf (f, "\n"); ++ } ++} ++ ++/* Dump all of the created newtypes to file F. */ ++ ++void ++ipa_struct_reorg::dump_newtypes (FILE *f) ++{ ++ unsigned i = 0; ++ srtype *type = NULL; ++ FOR_EACH_VEC_ELT (types, i, type) ++ { ++ if (type->has_escaped ()) ++ { ++ continue; ++ } ++ fprintf (f, "======= the %dth newtype: ======\n", i); ++ fprintf (f, "type : "); ++ print_generic_expr (f, type->newtype[0]); ++ fprintf (f, "(%d) ", TYPE_UID (type->newtype[0])); ++ fprintf (f, "{ "); ++ fprintf (f, "\nfields = {\n"); ++ ++ for (tree field = TYPE_FIELDS (TYPE_MAIN_VARIANT (type->newtype[0])); ++ field; field = DECL_CHAIN (field)) ++ { ++ fprintf (f, "field (%d) ", DECL_UID (field)); ++ fprintf (f, "{"); ++ fprintf (f, "type = "); ++ print_generic_expr (f, TREE_TYPE (field)); ++ fprintf (f, "}\n"); ++ } ++ fprintf (f, "}\n "); ++ ++ fprintf (f, "\n"); + } +- fprintf (f, "\n"); + } + + /* Dump all of the recorded types to file F. */ +@@ -1763,7 +1987,6 @@ ipa_struct_reorg::dump_functions (FILE *f) + unsigned i; + srfunction *fn; + +- fprintf (f, "\n\n"); + globals.dump (f); + fprintf (f, "\n\n"); + FOR_EACH_VEC_ELT (functions, i, fn) +@@ -1829,6 +2052,10 @@ bool isarraytype (tree type) + + bool isptrptr (tree type) + { ++ if (type == NULL) ++ { ++ return false; ++ } + bool firstptr = false; + while (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE) + { +@@ -1843,129 +2070,808 @@ bool isptrptr (tree type) + return false; + } + +-/* Return the escape type which corresponds to if +- this is an volatile type, an array type or a pointer +- to a pointer type. */ ++/* Adding node to map and stack. */ + +-escape_type escape_type_volatile_array_or_ptrptr (tree type) ++bool ++add_node (tree node, int layers, hash_map <tree, int> &map, ++ auto_vec <tree> &stack) + { +- if (isvolatile_type (type)) +- return escape_volatile; +- if (isarraytype (type)) +- return escape_array; +- if (isptrptr (type)) +- return escape_ptr_ptr; +- return does_not_escape; ++ if (TREE_CODE (node) != SSA_NAME) ++ { ++ return false; ++ } ++ if (map.get (node) == NULL) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, " "); ++ fprintf (dump_file, "add node: \t\t"); ++ print_generic_expr (dump_file, node); ++ fprintf (dump_file, ",\t\tptr layers: %d: \n", layers); ++ } ++ map.put (node, layers); ++ stack.safe_push (node); ++ } ++ else if (*map.get (node) != layers) ++ { ++ return false; ++ } ++ return true; + } + +-/* Record TYPE if not already recorded. */ ++/* Check the number of pointer layers of the gimple phi in definition. */ + +-srtype * +-ipa_struct_reorg::record_type (tree type) ++bool ++check_def_phi (tree def_node, hash_map <tree, int> &ptr_layers) + { +- unsigned typeuid; +- +- /* Get the main variant as we are going +- to record that type only. */ +- type = TYPE_MAIN_VARIANT (type); +- typeuid = TYPE_UID (type); ++ bool res = true; ++ gimple *def_stmt = SSA_NAME_DEF_STMT (def_node); ++ for (unsigned j = 0; j < gimple_phi_num_args (def_stmt); j++) ++ { ++ tree phi_node = gimple_phi_arg_def (def_stmt, j); ++ if (integer_zerop (phi_node)) ++ { ++ continue; ++ } ++ if (ptr_layers.get (phi_node) == NULL) ++ { ++ return false; ++ } ++ res &= *ptr_layers.get (def_node) == *ptr_layers.get (phi_node); ++ } ++ return res; ++} + +- srtype *type1; ++/* Check the number of pointer layers of the gimple assign in definition. */ + +- type1 = find_type (type); +- if (type1) +- return type1; ++bool ++check_def_assign (tree def_node, hash_map <tree, int> &ptr_layers) ++{ ++ bool res = true; ++ gimple *def_stmt = SSA_NAME_DEF_STMT (def_node); ++ gimple_rhs_class rhs_class = gimple_assign_rhs_class (def_stmt); ++ tree_code rhs_code = gimple_assign_rhs_code (def_stmt); ++ tree rhs1 = gimple_assign_rhs1 (def_stmt); ++ tree rhs1_base = TREE_CODE (rhs1) == MEM_REF ? TREE_OPERAND (rhs1, 0) : rhs1; ++ if (ptr_layers.get (rhs1_base) == NULL) ++ { ++ return false; ++ } ++ if (rhs_class == GIMPLE_SINGLE_RHS || rhs_class == GIMPLE_UNARY_RHS) ++ { ++ if (TREE_CODE (rhs1) == SSA_NAME) ++ { ++ res = *ptr_layers.get (def_node) == *ptr_layers.get (rhs1); ++ } ++ else if (TREE_CODE (rhs1) == MEM_REF) ++ { ++ res = *ptr_layers.get (def_node) ++ == *ptr_layers.get (TREE_OPERAND (rhs1, 0)); ++ } ++ else ++ { ++ return false; ++ } ++ } ++ else if (rhs_class == GIMPLE_BINARY_RHS) ++ { ++ if (rhs_code == POINTER_PLUS_EXPR) ++ { ++ res = *ptr_layers.get (def_node) == *ptr_layers.get (rhs1); ++ } ++ else if (rhs_code == BIT_AND_EXPR) ++ { ++ res = *ptr_layers.get (def_node) == *ptr_layers.get (rhs1); ++ } ++ else ++ { ++ return false; ++ } ++ } ++ else ++ { ++ return false; ++ } ++ return res; ++} + +- /* If already done recording just return NULL. */ +- if (done_recording) +- return NULL; ++/* Check node definition. */ + ++bool ++check_node_def (hash_map <tree, int> &ptr_layers) ++{ ++ bool res = true; + if (dump_file && (dump_flags & TDF_DETAILS)) +- fprintf (dump_file, "Recording new type: %u.\n", typeuid); +- +- type1 = new srtype (type); +- types.safe_push(type1); +- +- /* If the type has an user alignment set, +- that means the user most likely already setup the type. */ +- if (TYPE_USER_ALIGN (type)) +- type1->mark_escape (escape_user_alignment, NULL); +- +- for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + { +- if (TREE_CODE (field) == FIELD_DECL) +- { +- tree t = TREE_TYPE (field); +- process_union (t); +- if (TREE_CODE (inner_type (t)) == UNION_TYPE +- || TREE_CODE (inner_type (t)) == QUAL_UNION_TYPE) ++ fprintf (dump_file, "\n======== check node definition ========\n"); ++ } ++ for (unsigned i = 1; i < num_ssa_names; ++i) ++ { ++ tree name = ssa_name (i); ++ if (name && ptr_layers.get (name) != NULL) ++ { ++ gimple *def_stmt = SSA_NAME_DEF_STMT (name); ++ if (dump_file && (dump_flags & TDF_DETAILS) ++ && gimple_code (def_stmt) != GIMPLE_DEBUG) ++ { ++ print_gimple_stmt (dump_file, def_stmt, 0); ++ } ++ ++ if (gimple_code (def_stmt) == GIMPLE_PHI) + { +- type1->mark_escape (escape_union, NULL); ++ res = check_def_phi (name, ptr_layers); + } +- if (isvolatile_type (t)) +- type1->mark_escape (escape_volatile, NULL); +- escape_type e = escape_type_volatile_array_or_ptrptr (t); +- if (e != does_not_escape) +- type1->mark_escape (e, NULL); +- if (handled_type (t)) ++ else if (gimple_code (def_stmt) == GIMPLE_ASSIGN) + { +- srtype *t1 = record_type (inner_type (t)); +- srfield *f = type1->find_field (int_byte_position (field)); +- /* We might have an variable sized type which we don't set the handle. */ +- if (f) +- { +- f->type = t1; +- t1->add_field_site (f); +- } +- if (t1 == type1 && current_mode != COMPLETE_STRUCT_RELAYOUT) +- { +- type1->mark_escape (escape_rescusive_type, NULL); +- } ++ res = check_def_assign (name, ptr_layers); + } +- } ++ else if (gimple_code (def_stmt) == GIMPLE_NOP) ++ { ++ continue; ++ } ++ else ++ { ++ return false; ++ } ++ } + } +- +- return type1; ++ return res; + } + +-/* Mark TYPE as escaping with ESCAPES as the reason. */ ++/* Check pointer usage. */ + +-void +-ipa_struct_reorg::mark_type_as_escape (tree type, escape_type escapes, gimple *stmt) ++bool ++check_record_ptr_usage (gimple *use_stmt, tree ¤t_node, ++ hash_map <tree, int> &ptr_layers, ++ auto_vec <tree> &ssa_name_stack) + { +- if (handled_type (type)) ++ gimple_rhs_class rhs_class = gimple_assign_rhs_class (use_stmt); ++ tree rhs1 = gimple_assign_rhs1 (use_stmt); ++ tree lhs = gimple_assign_lhs (use_stmt); ++ if (rhs_class != GIMPLE_SINGLE_RHS ++ || (TREE_CODE (rhs1) != COMPONENT_REF && TREE_CODE (rhs1) != SSA_NAME) ++ || (TREE_CODE (lhs) != MEM_REF && TREE_CODE (lhs) != SSA_NAME)) + { +- srtype *stype = record_type (inner_type (type)); +- +- if (!stype) +- return; ++ return false; ++ } + +- stype->mark_escape (escapes, stmt); ++ bool res = true; ++ /* MEM[(long int *)a_1] = _57; (record). ++ If lhs is ssa_name, lhs cannot be the current node. ++ _283 = _282->flow; (No record). */ ++ if (TREE_CODE (rhs1) == SSA_NAME) ++ { ++ tree tmp = (rhs1 != current_node) ? rhs1 : lhs; ++ if (TREE_CODE (tmp) == MEM_REF) ++ { ++ res = add_node (TREE_OPERAND (tmp, 0), ++ *ptr_layers.get (current_node) + 1, ++ ptr_layers, ssa_name_stack); ++ } ++ else ++ { ++ res = add_node (tmp, *ptr_layers.get (current_node), ++ ptr_layers, ssa_name_stack); ++ } ++ } ++ else if (TREE_CODE (lhs) == SSA_NAME && TREE_CODE (rhs1) == COMPONENT_REF) ++ { ++ res = !(POINTER_TYPE_P (TREE_TYPE (rhs1))); + } ++ else ++ { ++ res = false; ++ } ++ return res; + } + +-/* Maybe process the union of type TYPE, such that marking all of the fields' +- types as being escaping. */ ++/* Check and record a single node. */ + +-void +-ipa_struct_reorg::process_union (tree type) ++bool ++check_record_single_node (gimple *use_stmt, tree ¤t_node, ++ hash_map <tree, int> &ptr_layers, ++ auto_vec <tree> &ssa_name_stack) + { +- static hash_set<tree> unions_recorded; +- +- type = inner_type (type); +- if (TREE_CODE (type) != UNION_TYPE +- && TREE_CODE (type) != QUAL_UNION_TYPE) +- return; +- +- type = TYPE_MAIN_VARIANT (type); +- +- /* We already processed this type. */ +- if (unions_recorded.add (type)) +- return; ++ gimple_rhs_class rhs_class = gimple_assign_rhs_class (use_stmt); ++ tree rhs1 = gimple_assign_rhs1 (use_stmt); ++ tree lhs = gimple_assign_lhs (use_stmt); ++ gcc_assert (rhs_class == GIMPLE_SINGLE_RHS || rhs_class == GIMPLE_UNARY_RHS); + +- for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) ++ if ((TREE_CODE (rhs1) != SSA_NAME && TREE_CODE (rhs1) != MEM_REF) ++ || (TREE_CODE (lhs) != SSA_NAME && TREE_CODE (lhs) != MEM_REF)) + { +- if (TREE_CODE (field) == FIELD_DECL) ++ return false; ++ } ++ ++ bool res = true; ++ if (TREE_CODE (lhs) == SSA_NAME && TREE_CODE (rhs1) == MEM_REF) ++ { ++ /* _257 = MEM[(struct arc_t * *)_17]. */ ++ res = add_node (lhs, *ptr_layers.get (current_node) - 1, ++ ptr_layers, ssa_name_stack); ++ } ++ else if (TREE_CODE (lhs) == MEM_REF && TREE_CODE (rhs1) == SSA_NAME) ++ { ++ /* MEM[(long int *)a_1] = _57. */ ++ if (rhs1 == current_node) ++ { ++ res = add_node (TREE_OPERAND (lhs, 0), ++ *ptr_layers.get (current_node) + 1, ++ ptr_layers, ssa_name_stack); ++ } ++ else ++ { ++ res = add_node (rhs1, *ptr_layers.get (current_node) - 1, ++ ptr_layers, ssa_name_stack); ++ } ++ } ++ else if (TREE_CODE (lhs) == SSA_NAME && TREE_CODE (rhs1) == SSA_NAME) ++ { ++ res = add_node (lhs, *ptr_layers.get (current_node), ++ ptr_layers, ssa_name_stack); ++ } ++ else ++ { ++ res = false; ++ } ++ ++ return res; ++} ++ ++/* Check and record multiple nodes. */ ++ ++bool ++check_record_mult_node (gimple *use_stmt, tree ¤t_node, ++ hash_map <tree, int> &ptr_layers, ++ auto_vec <tree> &ssa_name_stack) ++{ ++ gimple_rhs_class rhs_class = gimple_assign_rhs_class (use_stmt); ++ tree_code rhs_code = gimple_assign_rhs_code (use_stmt); ++ tree rhs1 = gimple_assign_rhs1 (use_stmt); ++ tree lhs = gimple_assign_lhs (use_stmt); ++ tree rhs2 = gimple_assign_rhs2 (use_stmt); ++ gcc_assert (rhs_class == GIMPLE_BINARY_RHS); ++ ++ if ((rhs_code != POINTER_PLUS_EXPR && rhs_code != POINTER_DIFF_EXPR ++ && rhs_code != BIT_AND_EXPR) ++ || (TREE_CODE (lhs) != SSA_NAME && TREE_CODE (rhs1) != SSA_NAME)) ++ { ++ return false; ++ } ++ ++ bool res = true; ++ if (rhs_code == POINTER_PLUS_EXPR) ++ { ++ res = add_node (lhs == current_node ? rhs1 : lhs, ++ *ptr_layers.get (current_node), ++ ptr_layers, ssa_name_stack); ++ } ++ else if (rhs_code == POINTER_DIFF_EXPR) ++ { ++ res = add_node (rhs1 != current_node ? rhs1 : rhs2, ++ *ptr_layers.get (current_node), ++ ptr_layers, ssa_name_stack); ++ } ++ else if (rhs_code == BIT_AND_EXPR) ++ { ++ if (TREE_CODE (rhs2) != INTEGER_CST) ++ { ++ return false; ++ } ++ res = add_node (lhs == current_node ? rhs1 : lhs, ++ *ptr_layers.get (current_node), ++ ptr_layers, ssa_name_stack); ++ } ++ return res; ++} ++ ++/* Check whether gimple assign is correctly used and record node. */ ++ ++bool ++check_record_assign (tree ¤t_node, gimple *use_stmt, ++ hash_map <tree, int> &ptr_layers, ++ auto_vec <tree> &ssa_name_stack) ++{ ++ gimple_rhs_class rhs_class = gimple_assign_rhs_class (use_stmt); ++ if (*ptr_layers.get (current_node) == 1) ++ { ++ return check_record_ptr_usage (use_stmt, current_node, ++ ptr_layers, ssa_name_stack); ++ } ++ else if (*ptr_layers.get (current_node) > 1) ++ { ++ if (rhs_class != GIMPLE_BINARY_RHS ++ && rhs_class != GIMPLE_UNARY_RHS ++ && rhs_class != GIMPLE_SINGLE_RHS) ++ { ++ return false; ++ } ++ ++ if (rhs_class == GIMPLE_SINGLE_RHS || rhs_class == GIMPLE_UNARY_RHS) ++ { ++ return check_record_single_node (use_stmt, current_node, ++ ptr_layers, ssa_name_stack); ++ } ++ else if (rhs_class == GIMPLE_BINARY_RHS) ++ { ++ return check_record_mult_node (use_stmt, current_node, ++ ptr_layers, ssa_name_stack); ++ } ++ } ++ else ++ return false; ++ ++ return true; ++} ++ ++/* Check whether gimple phi is correctly used and record node. */ ++ ++bool ++check_record_phi (tree ¤t_node, gimple *use_stmt, ++ hash_map <tree, int> &ptr_layers, ++ auto_vec <tree> &ssa_name_stack) ++{ ++ bool res = true; ++ res &= add_node (gimple_phi_result (use_stmt), *ptr_layers.get (current_node), ++ ptr_layers, ssa_name_stack); ++ ++ for (unsigned i = 0; i < gimple_phi_num_args (use_stmt); i++) ++ { ++ if (integer_zerop (gimple_phi_arg_def (use_stmt, i))) ++ { ++ continue; ++ } ++ res &= add_node (gimple_phi_arg_def (use_stmt, i), ++ *ptr_layers.get (current_node), ++ ptr_layers, ssa_name_stack); ++ } ++ return res; ++} ++ ++/* Check the use of callee. */ ++ ++bool ++check_callee (cgraph_node *node, gimple *stmt, ++ hash_map <tree, int> &ptr_layers, int input_layers) ++{ ++ /* caller main () ++ { spec_qsort.constprop (_649, _651); } ++ def spec_qsort.constprop (void * a, size_t n) ++ { spec_qsort.constprop (a_1, _139); } */ ++ /* In safe functions, only call itself is allowed. */ ++ if (node->get_edge (stmt)->callee != node) ++ { ++ return false; ++ } ++ tree input_node = gimple_call_arg (stmt, 0); ++ if (ptr_layers.get (input_node) == NULL ++ || *ptr_layers.get (input_node) != input_layers) ++ { ++ return false; ++ } ++ if (SSA_NAME_VAR (input_node) != DECL_ARGUMENTS (node->decl)) ++ { ++ return false; ++ } ++ ++ for (unsigned i = 1; i < gimple_call_num_args (stmt); i++) ++ { ++ if (ptr_layers.get (gimple_call_arg (stmt, i)) != NULL) ++ { ++ return false; ++ } ++ } ++ return true; ++} ++ ++/* Check the usage of input nodes and related nodes. */ ++ ++bool ++check_node_use (cgraph_node *node, tree current_node, ++ hash_map <tree, int> &ptr_layers, ++ auto_vec <tree> &ssa_name_stack, ++ int input_layers) ++{ ++ imm_use_iterator imm_iter; ++ gimple *use_stmt = NULL; ++ bool res = true; ++ /* Use FOR_EACH_IMM_USE_STMT as an indirect edge ++ to search for possible related nodes and push to stack. */ ++ FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, current_node) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS) ++ && gimple_code (use_stmt) != GIMPLE_DEBUG) ++ { ++ fprintf (dump_file, "%*s", 4, ""); ++ print_gimple_stmt (dump_file, use_stmt, 0); ++ } ++ /* For other types of gimple, do not record the node. */ ++ if (res) ++ { ++ if (gimple_code (use_stmt) == GIMPLE_PHI) ++ { ++ res = check_record_phi (current_node, use_stmt, ++ ptr_layers, ssa_name_stack); ++ } ++ else if (gimple_code (use_stmt) == GIMPLE_ASSIGN) ++ { ++ res = check_record_assign (current_node, use_stmt, ++ ptr_layers, ssa_name_stack); ++ } ++ else if (gimple_code (use_stmt) == GIMPLE_CALL) ++ { ++ res = check_callee (node, use_stmt, ptr_layers, input_layers); ++ } ++ else if (gimple_code (use_stmt) == GIMPLE_RETURN) ++ { ++ res = false; ++ } ++ } ++ } ++ return res; ++} ++ ++/* Preparing the First Node for DFS. */ ++ ++bool ++set_init_node (cgraph_node *node, cgraph_edge *caller, ++ hash_map <tree, int> &ptr_layers, ++ auto_vec <tree> &ssa_name_stack, int &input_layers) ++{ ++ /* set input_layer ++ caller spec_qsort.constprop (_649, _651) ++ |-- Obtains the actual ptr layer ++ from the input node. */ ++ if (caller->call_stmt == NULL ++ || gimple_call_num_args (caller->call_stmt) == 0) ++ { ++ return false; ++ } ++ tree input = gimple_call_arg (caller->call_stmt, 0); ++ if (!(POINTER_TYPE_P (TREE_TYPE (input)) ++ || TREE_CODE (TREE_TYPE (input)) == ARRAY_TYPE) ++ || !handled_type (TREE_TYPE (input))) ++ { ++ return false; ++ } ++ input_layers = get_ptr_layers (TREE_TYPE (input)); ++ ++ /* set initial node ++ def spec_qsort.constprop (void * a, size_t n) ++ |-- Find the initial ssa_name ++ from the parameter node. */ ++ tree parm = DECL_ARGUMENTS (node->decl); ++ for (unsigned j = 1; j < num_ssa_names; ++j) ++ { ++ tree name = ssa_name (j); ++ if (!name || has_zero_uses (name) || virtual_operand_p (name)) ++ { ++ continue; ++ } ++ if (SSA_NAME_VAR (name) == parm ++ && gimple_code (SSA_NAME_DEF_STMT (name)) == GIMPLE_NOP) ++ { ++ if (!add_node (name, input_layers, ptr_layers, ssa_name_stack)) ++ { ++ return false; ++ } ++ } ++ } ++ return !ssa_name_stack.is_empty (); ++} ++ ++/* Check the usage of each call. */ ++ ++bool ++check_each_call (cgraph_node *node, cgraph_edge *caller) ++{ ++ hash_map <tree, int> ptr_layers; ++ auto_vec <tree> ssa_name_stack; ++ int input_layers = 0; ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "======== check each call : %s/%u ========\n", ++ node->name (), node->order); ++ } ++ if (!set_init_node (node, caller, ptr_layers, ssa_name_stack, input_layers)) ++ { ++ return false; ++ } ++ int i = 0; ++ while (!ssa_name_stack.is_empty ()) ++ { ++ tree current_node = ssa_name_stack.pop (); ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\ncur node %d: \t", i++); ++ print_generic_expr (dump_file, current_node); ++ fprintf (dump_file, ",\t\tptr layers: %d: \n", ++ *ptr_layers.get (current_node)); ++ } ++ if (get_ptr_layers (TREE_TYPE (current_node)) ++ > *ptr_layers.get (current_node)) ++ { ++ return false; ++ } ++ if (!check_node_use (node, current_node, ptr_layers, ssa_name_stack, ++ input_layers)) ++ { ++ return false; ++ } ++ } ++ ++ if (!check_node_def (ptr_layers)) ++ { ++ return false; ++ } ++ return true; ++} ++ ++/* Filter out function: void func (void*, int n), ++ and the function has no static variable, no structure-related variable, ++ and no global variable is used. */ ++ ++bool ++filter_func (cgraph_node *node) ++{ ++ tree parm = DECL_ARGUMENTS (node->decl); ++ if (!(parm && VOID_POINTER_P (TREE_TYPE (parm)) ++ && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (node->decl))))) ++ { ++ return false; ++ } ++ ++ for (parm = DECL_CHAIN (parm); parm; parm = DECL_CHAIN (parm)) ++ { ++ if (TREE_CODE (TREE_TYPE (parm)) != INTEGER_TYPE) ++ { ++ return false; ++ } ++ } ++ ++ if (DECL_STRUCT_FUNCTION (node->decl)->static_chain_decl) ++ { ++ return false; ++ } ++ ++ tree var = NULL_TREE; ++ unsigned int i = 0; ++ bool res = true; ++ FOR_EACH_LOCAL_DECL (cfun, i, var) ++ { ++ if (TREE_CODE (var) == VAR_DECL && handled_type (TREE_TYPE (var))) ++ { ++ res = false; ++ } ++ } ++ if (!res) ++ { ++ return false; ++ } ++ ++ for (unsigned j = 1; j < num_ssa_names; ++j) ++ { ++ tree name = ssa_name (j); ++ if (!name || has_zero_uses (name) || virtual_operand_p (name)) ++ { ++ continue; ++ } ++ tree var = SSA_NAME_VAR (name); ++ if (var && TREE_CODE (var) == VAR_DECL && is_global_var (var)) ++ { ++ return false; ++ } ++ } ++ return true; ++} ++ ++/* Check whether the function with the void* parameter and uses the input node ++ safely. ++ In these functions only component_ref can be used to dereference the last ++ layer of the input structure pointer. The hack operation pointer offset ++ after type cast cannot be used. ++*/ ++ ++bool ++is_safe_func_with_void_ptr_parm (cgraph_node *node) ++{ ++ if (!filter_func (node)) ++ { ++ return false; ++ } ++ ++ /* Distinguish Recursive Callers ++ normal_callers: main () ++ { spec_qsort.constprop (_649, _651); } ++ definition: spec_qsort.constprop (void * a, size_t n) ++ recursive_callers: { spec_qsort.constprop (a_1, _139); } */ ++ vec <cgraph_edge *> callers = node->collect_callers (); ++ auto_vec <cgraph_edge *> normal_callers; ++ for (unsigned i = 0; i < callers.length (); i++) ++ { ++ if (callers[i]->caller != node) ++ { ++ normal_callers.safe_push (callers[i]); ++ } ++ } ++ if (normal_callers.length () == 0) ++ { ++ return false; ++ } ++ ++ for (unsigned i = 0; i < normal_callers.length (); i++) ++ { ++ if (!check_each_call (node, normal_callers[i])) ++ { ++ return false; ++ } ++ } ++ return true; ++} ++ ++/* Return the escape type which corresponds to if ++ this is an volatile type, an array type or a pointer ++ to a pointer type. */ ++ ++escape_type escape_type_volatile_array_or_ptrptr (tree type) ++{ ++ if (isvolatile_type (type)) ++ return escape_volatile; ++ if (isarraytype (type)) ++ return escape_array; ++ if (isptrptr (type) && (current_mode != STRUCT_REORDER_FIELDS)) ++ return escape_ptr_ptr; ++ return does_not_escape; ++} ++ ++/* Record field type. */ ++ ++void ++ipa_struct_reorg::record_field_type (tree field, srtype *base_srtype) ++{ ++ tree field_type = TREE_TYPE (field); ++ /* The uid of the type in the structure is different ++ from that outside the structure. */ ++ srtype *field_srtype = record_type (inner_type (field_type)); ++ srfield *field_srfield = base_srtype->find_field (int_byte_position (field)); ++ /* We might have an variable sized type which we don't set the handle. */ ++ if (field_srfield) ++ { ++ field_srfield->type = field_srtype; ++ field_srtype->add_field_site (field_srfield); ++ } ++ if (field_srtype == base_srtype && current_mode != COMPLETE_STRUCT_RELAYOUT ++ && current_mode != STRUCT_REORDER_FIELDS) ++ { ++ base_srtype->mark_escape (escape_rescusive_type, NULL); ++ } ++ /* Types of non-pointer field are difficult to track the correctness ++ of the rewrite when it used by the escaped type. */ ++ if (current_mode == STRUCT_REORDER_FIELDS ++ && TREE_CODE (field_type) == RECORD_TYPE) ++ { ++ field_srtype->mark_escape (escape_instance_field, NULL); ++ } ++} ++ ++/* Record structure all field types. */ ++ ++void ++ipa_struct_reorg::record_struct_field_types (tree base_type, ++ srtype *base_srtype) ++{ ++ for (tree field = TYPE_FIELDS (base_type); field; field = DECL_CHAIN (field)) ++ { ++ if (TREE_CODE (field) == FIELD_DECL) ++ { ++ tree field_type = TREE_TYPE (field); ++ process_union (field_type); ++ if (TREE_CODE (inner_type (field_type)) == UNION_TYPE ++ || TREE_CODE (inner_type (field_type)) == QUAL_UNION_TYPE) ++ { ++ base_srtype->mark_escape (escape_union, NULL); ++ } ++ if (isvolatile_type (field_type)) ++ { ++ base_srtype->mark_escape (escape_volatile, NULL); ++ } ++ escape_type e = escape_type_volatile_array_or_ptrptr (field_type); ++ if (e != does_not_escape) ++ { ++ base_srtype->mark_escape (e, NULL); ++ } ++ /* Types of non-pointer field are difficult to track the correctness ++ of the rewrite when it used by the escaped type. */ ++ if (current_mode == STRUCT_REORDER_FIELDS ++ && TREE_CODE (field_type) == RECORD_TYPE) ++ { ++ base_srtype->mark_escape (escape_instance_field, NULL); ++ } ++ if (handled_type (field_type)) ++ { ++ record_field_type (field, base_srtype); ++ } ++ } ++ } ++} ++ ++/* Record TYPE if not already recorded. */ ++ ++srtype * ++ipa_struct_reorg::record_type (tree type) ++{ ++ unsigned typeuid; ++ ++ /* Get the main variant as we are going ++ to record that type only. */ ++ type = TYPE_MAIN_VARIANT (type); ++ typeuid = TYPE_UID (type); ++ ++ srtype *type1; ++ ++ type1 = find_type (type); ++ if (type1) ++ return type1; ++ ++ /* If already done recording just return NULL. */ ++ if (done_recording) ++ return NULL; ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "Recording new type: %u.\n", typeuid); ++ ++ type1 = new srtype (type); ++ types.safe_push (type1); ++ ++ /* If the type has an user alignment set, ++ that means the user most likely already setup the type. */ ++ if (TYPE_USER_ALIGN (type)) ++ type1->mark_escape (escape_user_alignment, NULL); ++ ++ record_struct_field_types (type, type1); ++ ++ return type1; ++} ++ ++/* Mark TYPE as escaping with ESCAPES as the reason. */ ++ ++void ++ipa_struct_reorg::mark_type_as_escape (tree type, escape_type escapes, ++ gimple *stmt) ++{ ++ if (handled_type (type)) ++ { ++ srtype *stype = record_type (inner_type (type)); ++ ++ if (!stype) ++ return; ++ ++ stype->mark_escape (escapes, stmt); ++ } ++} ++ ++/* Maybe process the union of type TYPE, such that marking all of the fields' ++ types as being escaping. */ ++ ++void ++ipa_struct_reorg::process_union (tree type) ++{ ++ static hash_set<tree> unions_recorded; ++ ++ type = inner_type (type); ++ if (TREE_CODE (type) != UNION_TYPE ++ && TREE_CODE (type) != QUAL_UNION_TYPE) ++ return; ++ ++ type = TYPE_MAIN_VARIANT (type); ++ ++ /* We already processed this type. */ ++ if (unions_recorded.add (type)) ++ return; ++ ++ for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) ++ { ++ if (TREE_CODE (field) == FIELD_DECL) + { + mark_type_as_escape (TREE_TYPE (field), escape_union); + process_union (TREE_TYPE (field)); +@@ -2022,7 +2928,8 @@ ipa_struct_reorg::record_var (tree decl, escape_type escapes, int arg) + + process_union (TREE_TYPE (decl)); + +- /* */ ++ /* Only the structure type RECORD_TYPE is recorded. ++ Therefore, the void* type is filtered out. */ + if (handled_type (TREE_TYPE (decl))) + { + type = record_type (inner_type (TREE_TYPE (decl))); +@@ -2059,7 +2966,8 @@ ipa_struct_reorg::record_var (tree decl, escape_type escapes, int arg) + + /* Separate instance is hard to trace in complete struct + relayout optimization. */ +- if (current_mode == COMPLETE_STRUCT_RELAYOUT ++ if ((current_mode == COMPLETE_STRUCT_RELAYOUT ++ || current_mode == STRUCT_REORDER_FIELDS) + && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE) + { + e = escape_separate_instance; +@@ -2138,8 +3046,10 @@ ipa_struct_reorg::find_var (tree expr, gimple *stmt) + srtype *type; + srfield *field; + bool realpart, imagpart, address; ++ bool escape_from_base = false; ++ /* The should_create flag is true, the declaration can be recorded. */ + get_type_field (expr, base, indirect, type, field, +- realpart, imagpart, address, true, true); ++ realpart, imagpart, address, escape_from_base, true, true); + } + + +@@ -2157,10 +3067,26 @@ ipa_struct_reorg::find_vars (gimple *stmt) + tree lhs = gimple_assign_lhs (stmt); + tree rhs = gimple_assign_rhs1 (stmt); + find_var (gimple_assign_lhs (stmt), stmt); ++ /* _2 = MEM[(struct arc_t * *)_1]; ++ records the right value _1 declaration. */ + find_var (gimple_assign_rhs1 (stmt), stmt); +- if (TREE_CODE (lhs) == SSA_NAME ++ ++ /* Add a safe func mechanism. */ ++ bool l_find = true; ++ bool r_find = true; ++ if (current_mode == STRUCT_REORDER_FIELDS) ++ { ++ l_find = !(current_function->is_safe_func ++ && TREE_CODE (lhs) == SSA_NAME ++ && is_from_void_ptr_parm (lhs)); ++ r_find = !(current_function->is_safe_func ++ && TREE_CODE (rhs) == SSA_NAME ++ && is_from_void_ptr_parm (rhs)); ++ } ++ ++ if ((TREE_CODE (lhs) == SSA_NAME) + && VOID_POINTER_P (TREE_TYPE (lhs)) +- && handled_type (TREE_TYPE (rhs))) ++ && handled_type (TREE_TYPE (rhs)) && l_find) + { + srtype *t = find_type (inner_type (TREE_TYPE (rhs))); + srdecl *d = find_decl (lhs); +@@ -2172,9 +3098,11 @@ ipa_struct_reorg::find_vars (gimple *stmt) + current_function->record_decl (t, var, -1); + } + } ++ /* void * _1; struct arc * _2; ++ _2 = _1 + _3; _1 = calloc (100, 40). */ + if (TREE_CODE (rhs) == SSA_NAME + && VOID_POINTER_P (TREE_TYPE (rhs)) +- && handled_type (TREE_TYPE (lhs))) ++ && handled_type (TREE_TYPE (lhs)) && r_find) + { + srtype *t = find_type (inner_type (TREE_TYPE (lhs))); + srdecl *d = find_decl (rhs); +@@ -2187,6 +3115,26 @@ ipa_struct_reorg::find_vars (gimple *stmt) + } + } + } ++ else if ((current_mode == STRUCT_REORDER_FIELDS) ++ && (gimple_assign_rhs_code (stmt) == LE_EXPR ++ || gimple_assign_rhs_code (stmt) == LT_EXPR ++ || gimple_assign_rhs_code (stmt) == GE_EXPR ++ || gimple_assign_rhs_code (stmt) == GT_EXPR)) ++ { ++ find_var (gimple_assign_lhs (stmt), stmt); ++ find_var (gimple_assign_rhs1 (stmt), stmt); ++ find_var (gimple_assign_rhs2 (stmt), stmt); ++ } ++ /* _23 = _21 - old_arcs_12. */ ++ else if ((current_mode == STRUCT_REORDER_FIELDS) ++ && gimple_assign_rhs_code (stmt) == POINTER_DIFF_EXPR ++ && types_compatible_p ( ++ TYPE_MAIN_VARIANT (TREE_TYPE (gimple_assign_rhs1 (stmt))), ++ TYPE_MAIN_VARIANT (TREE_TYPE (gimple_assign_rhs2 (stmt))))) ++ { ++ find_var (gimple_assign_rhs1 (stmt), stmt); ++ find_var (gimple_assign_rhs2 (stmt), stmt); ++ } + else + { + /* Because we won't handle these stmts in rewrite phase, +@@ -2279,8 +3227,122 @@ ipa_struct_reorg::maybe_record_stmt (cgraph_node *node, gimple *stmt) + } + } + ++/* Calculate the multiplier. */ ++ ++static bool ++calculate_mult_num (tree arg, tree *num, tree struct_size) ++{ ++ gcc_assert (TREE_CODE (arg) == INTEGER_CST); ++ bool sign = false; ++ HOST_WIDE_INT size = TREE_INT_CST_LOW (arg); ++ if (size < 0) ++ { ++ size = -size; ++ sign = true; ++ } ++ tree arg2 = build_int_cst (TREE_TYPE (arg), size); ++ if (integer_zerop (size_binop (FLOOR_MOD_EXPR, arg2, struct_size))) ++ { ++ tree number = size_binop (FLOOR_DIV_EXPR, arg2, struct_size); ++ if (sign) ++ { ++ number = build_int_cst (TREE_TYPE (number), -tree_to_shwi (number)); ++ } ++ *num = number; ++ return true; ++ } ++ return false; ++} ++ ++/* Trace and calculate the multiplier of PLUS_EXPR. */ ++ ++static bool ++trace_calculate_plus (gimple *size_def_stmt, tree *num, tree struct_size) ++{ ++ gcc_assert (gimple_assign_rhs_code (size_def_stmt) == PLUS_EXPR); ++ ++ tree num1 = NULL_TREE; ++ tree num2 = NULL_TREE; ++ tree arg0 = gimple_assign_rhs1 (size_def_stmt); ++ tree arg1 = gimple_assign_rhs2 (size_def_stmt); ++ if (!is_result_of_mult (arg0, &num1, struct_size) || num1 == NULL_TREE) ++ { ++ return false; ++ } ++ if (!is_result_of_mult (arg1, &num2, struct_size) || num2 == NULL_TREE) ++ { ++ return false; ++ } ++ *num = size_binop (PLUS_EXPR, num1, num2); ++ return true; ++} ++ ++/* Trace and calculate the multiplier of MULT_EXPR. */ ++ ++static bool ++trace_calculate_mult (gimple *size_def_stmt, tree *num, tree struct_size) ++{ ++ gcc_assert (gimple_assign_rhs_code (size_def_stmt) == MULT_EXPR); ++ ++ tree arg0 = gimple_assign_rhs1 (size_def_stmt); ++ tree arg1 = gimple_assign_rhs2 (size_def_stmt); ++ tree num1 = NULL_TREE; ++ ++ if (is_result_of_mult (arg0, &num1, struct_size) && num1 != NULL_TREE) ++ { ++ *num = size_binop (MULT_EXPR, arg1, num1); ++ return true; ++ } ++ if (is_result_of_mult (arg1, &num1, struct_size) && num1 != NULL_TREE) ++ { ++ *num = size_binop (MULT_EXPR, arg0, num1); ++ return true; ++ } ++ *num = NULL_TREE; ++ return false; ++} ++ ++/* Trace and calculate the multiplier of NEGATE_EXPR. */ ++ ++static bool ++trace_calculate_negate (gimple *size_def_stmt, tree *num, tree struct_size) ++{ ++ gcc_assert (gimple_assign_rhs_code (size_def_stmt) == NEGATE_EXPR); ++ ++ /* _480 = -_479; _479 = _478 * 72. */ ++ tree num1 = NULL_TREE; ++ tree arg0 = gimple_assign_rhs1 (size_def_stmt); ++ if (!is_result_of_mult (arg0, &num1, struct_size) || num1 == NULL_TREE) ++ { ++ return false; ++ } ++ tree num0 = build_int_cst (TREE_TYPE (num1), -1); ++ *num = size_binop (MULT_EXPR, num0, num1); ++ return true; ++} ++ ++/* Trace and calculate the multiplier of POINTER_DIFF_EXPR. */ ++ ++static bool ++trace_calculate_diff (gimple *size_def_stmt, tree *num) ++{ ++ gcc_assert (gimple_assign_rhs_code (size_def_stmt) == NOP_EXPR); ++ ++ /* _25 = (long unsigned int) _23; _23 = _21 - old_arcs_12. */ ++ tree arg = gimple_assign_rhs1 (size_def_stmt); ++ size_def_stmt = SSA_NAME_DEF_STMT (arg); ++ if (size_def_stmt && is_gimple_assign (size_def_stmt) ++ && gimple_assign_rhs_code (size_def_stmt) == POINTER_DIFF_EXPR) ++ { ++ *num = NULL_TREE; ++ return true; ++ } ++ *num = NULL_TREE; ++ return false; ++} ++ + /* This function checks whether ARG is a result of multiplication +- of some number by STRUCT_SIZE. If yes, the function returns true ++ of some number by STRUCT_SIZE. If yes, the function returns true + and this number is filled into NUM. */ + + static bool +@@ -2291,30 +3353,12 @@ is_result_of_mult (tree arg, tree *num, tree struct_size) + || integer_zerop (struct_size)) + return false; + +- /* If we have a integer, just check if it is a multiply of STRUCT_SIZE. */ ++ /* If we have a integer, just check if it is a multiply of STRUCT_SIZE. */ + if (TREE_CODE (arg) == INTEGER_CST) + { +- bool sign = false; +- HOST_WIDE_INT size = TREE_INT_CST_LOW (arg); +- if (size < 0) +- { +- size = -size; +- sign = true; +- } +- tree arg2 = build_int_cst (TREE_TYPE (arg), size); +- if (integer_zerop (size_binop (FLOOR_MOD_EXPR, arg2, struct_size))) +- { +- tree number = size_binop (FLOOR_DIV_EXPR, arg2, struct_size); +- if (sign) +- { +- number = build_int_cst (TREE_TYPE (number), +- -tree_to_shwi (number)); +- } +- *num = number; +- return true; +- } +- return false; ++ return calculate_mult_num (arg, num, struct_size); + } ++ + gimple *size_def_stmt = SSA_NAME_DEF_STMT (arg); + + /* If the allocation statement was of the form +@@ -2330,43 +3374,28 @@ is_result_of_mult (tree arg, tree *num, tree struct_size) + return false; + + // FIXME: this should handle SHIFT also. +- if (gimple_assign_rhs_code (size_def_stmt) == PLUS_EXPR) +- { +- tree num1, num2; +- tree arg0 = gimple_assign_rhs1 (size_def_stmt); +- tree arg1 = gimple_assign_rhs2 (size_def_stmt); +- if (!is_result_of_mult (arg0, &num1, struct_size)) +- return false; +- if (!is_result_of_mult (arg1, &num2, struct_size)) +- return false; +- *num = size_binop (PLUS_EXPR, num1, num2); +- return true; ++ tree_code rhs_code = gimple_assign_rhs_code (size_def_stmt); ++ if (rhs_code == PLUS_EXPR) ++ { ++ return trace_calculate_plus (size_def_stmt, num, struct_size); + } +- if (gimple_assign_rhs_code (size_def_stmt) == MULT_EXPR) ++ else if (rhs_code == MULT_EXPR) + { +- tree arg0 = gimple_assign_rhs1 (size_def_stmt); +- tree arg1 = gimple_assign_rhs2 (size_def_stmt); +- tree num1; +- +- if (is_result_of_mult (arg0, &num1, struct_size)) +- { +- *num = size_binop (MULT_EXPR, arg1, num1); +- return true; +- } +- if (is_result_of_mult (arg1, &num1, struct_size)) +- { +- *num = size_binop (MULT_EXPR, arg0, num1); +- return true; +- } +- +- *num = NULL_TREE; +- return false; ++ return trace_calculate_mult (size_def_stmt, num, struct_size); + } +- else if (gimple_assign_rhs_code (size_def_stmt) == SSA_NAME) ++ else if (rhs_code == SSA_NAME) + { + arg = gimple_assign_rhs1 (size_def_stmt); + size_def_stmt = SSA_NAME_DEF_STMT (arg); + } ++ else if (rhs_code == NEGATE_EXPR && current_mode == STRUCT_REORDER_FIELDS) ++ { ++ return trace_calculate_negate (size_def_stmt, num, struct_size); ++ } ++ else if (rhs_code == NOP_EXPR && current_mode == STRUCT_REORDER_FIELDS) ++ { ++ return trace_calculate_diff (size_def_stmt, num); ++ } + else + { + *num = NULL_TREE; +@@ -2383,10 +3412,17 @@ is_result_of_mult (tree arg, tree *num, tree struct_size) + bool + ipa_struct_reorg::handled_allocation_stmt (gimple *stmt) + { +- if (current_mode == COMPLETE_STRUCT_RELAYOUT ++ if ((current_mode == STRUCT_REORDER_FIELDS) ++ && (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC) ++ || gimple_call_builtin_p (stmt, BUILT_IN_MALLOC) ++ || gimple_call_builtin_p (stmt, BUILT_IN_CALLOC))) ++ { ++ return true; ++ } ++ if ((current_mode == COMPLETE_STRUCT_RELAYOUT) + && gimple_call_builtin_p (stmt, BUILT_IN_CALLOC)) + return true; +- if (current_mode != COMPLETE_STRUCT_RELAYOUT ++ if ((current_mode == NORMAL) + && (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC) + || gimple_call_builtin_p (stmt, BUILT_IN_MALLOC) + || gimple_call_builtin_p (stmt, BUILT_IN_CALLOC) +@@ -2402,7 +3438,7 @@ ipa_struct_reorg::handled_allocation_stmt (gimple *stmt) + elements in the array allocated. */ + + tree +-ipa_struct_reorg::allocate_size (srtype *type, gimple *stmt) ++ipa_struct_reorg::allocate_size (srtype *type, srdecl *decl, gimple *stmt) + { + if (!stmt + || gimple_code (stmt) != GIMPLE_CALL +@@ -2422,6 +3458,12 @@ ipa_struct_reorg::allocate_size (srtype *type, gimple *stmt) + + tree struct_size = TYPE_SIZE_UNIT (type->type); + ++ /* Specify the correct size to relax multi-layer pointer. */ ++ if (TREE_CODE (decl->decl) == SSA_NAME && isptrptr (decl->orig_type)) ++ { ++ struct_size = TYPE_SIZE_UNIT (decl->orig_type); ++ } ++ + tree size = gimple_call_arg (stmt, 0); + + if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC) +@@ -2435,7 +3477,9 @@ ipa_struct_reorg::allocate_size (srtype *type, gimple *stmt) + if (operand_equal_p (arg1, struct_size, 0)) + return size; + /* ??? Check that first argument is a constant +- equal to the size of structure. */ ++ equal to the size of structure. */ ++ /* If the allocated number is equal to the value of struct_size, ++ the value of arg1 is changed to the allocated number. */ + if (operand_equal_p (size, struct_size, 0)) + return arg1; + if (dump_file && (dump_flags & TDF_DETAILS)) +@@ -2479,17 +3523,38 @@ ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other, gimple + + if (!d) + { ++ /* MEM[(struct arc *)_1].head = _2; _2 = calloc (100, 104). */ + if (VOID_POINTER_P (TREE_TYPE (side)) + && TREE_CODE (side) == SSA_NAME) +- current_function->record_decl (type, side, -1); ++ { ++ /* The type is other, the declaration is side. */ ++ current_function->record_decl (type, side, -1, ++ find_decl (other) ? find_decl (other)->orig_type : NULL); ++ } + else +- type->mark_escape (escape_cast_another_ptr, stmt); ++ { ++ /* *_1 = &MEM[(void *)&x + 8B]. */ ++ type->mark_escape (escape_cast_another_ptr, stmt); ++ } + } + else if (type != d->type) + { + type->mark_escape (escape_cast_another_ptr, stmt); + d->type->mark_escape (escape_cast_another_ptr, stmt); + } ++ /* x_1 = y.x_nodes; void *x; ++ Directly mark the structure pointer type assigned ++ to the void* variable as escape. */ ++ else if (current_mode == STRUCT_REORDER_FIELDS ++ && TREE_CODE (side) == SSA_NAME ++ && VOID_POINTER_P (TREE_TYPE (side)) ++ && SSA_NAME_VAR (side) ++ && VOID_POINTER_P (TREE_TYPE (SSA_NAME_VAR (side)))) ++ { ++ mark_type_as_escape (TREE_TYPE (other), escape_cast_void, stmt); ++ } ++ ++ check_ptr_layers (side, other, stmt); + } + + /* Record accesses in an assignment statement STMT. */ +@@ -2515,7 +3580,11 @@ ipa_struct_reorg::maybe_record_assign (cgraph_node *node, gassign *stmt) + if (!handled_type (TREE_TYPE (lhs))) + return; + /* Check if rhs2 is a multiplication of the size of the type. */ +- if (is_result_of_mult (rhs2, &num, TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (lhs))))) ++ /* The size adjustment and judgment of multi-layer pointers ++ are added. */ ++ if (is_result_of_mult (rhs2, &num, isptrptr (TREE_TYPE (lhs)) ++ ? TYPE_SIZE_UNIT (TREE_TYPE (lhs)) ++ : TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (lhs))))) + { + record_stmt_expr (lhs, node, stmt); + record_stmt_expr (rhs1, node, stmt); +@@ -2553,9 +3622,8 @@ ipa_struct_reorg::maybe_record_assign (cgraph_node *node, gassign *stmt) + } + + bool +-check_mem_ref_offset (tree expr) ++check_mem_ref_offset (tree expr, tree *num) + { +- tree num = NULL; + bool ret = false; + + if (TREE_CODE (expr) != MEM_REF) +@@ -2570,13 +3638,18 @@ check_mem_ref_offset (tree expr) + { + tmp = TREE_OPERAND (tmp, 0); + } +- tree size = TYPE_SIZE_UNIT (inner_type (TREE_TYPE (tmp))); +- ret = is_result_of_mult (field_off, &num, size); ++ /* Specify the correct size for the multi-layer pointer. */ ++ tree size = isptrptr (TREE_TYPE (tmp)) ++ ? TYPE_SIZE_UNIT (TREE_TYPE (tmp)) ++ : TYPE_SIZE_UNIT (inner_type (TREE_TYPE (tmp))); ++ ret = is_result_of_mult (field_off, num, size); + return ret; + } + + tree +-get_ref_base_and_offset (tree &e, HOST_WIDE_INT &offset, bool &realpart, bool &imagpart, tree &accesstype) ++get_ref_base_and_offset (tree &e, HOST_WIDE_INT &offset, ++ bool &realpart, bool &imagpart, ++ tree &accesstype, tree *num) + { + offset = 0; + realpart = false; +@@ -2599,22 +3672,29 @@ get_ref_base_and_offset (tree &e, HOST_WIDE_INT &offset, bool &realpart, bool &i + { + case COMPONENT_REF: + { ++ /* x.a = _1; If expr is the lvalue of stmt, ++ then field type is FIELD_DECL - POINTER_TYPE - RECORD_TYPE. */ + tree field = TREE_OPERAND (expr, 1); + tree field_off = byte_position (field); + if (TREE_CODE (field_off) != INTEGER_CST) + return NULL; + offset += tree_to_shwi (field_off); ++ /* x.a = _1; If expr is the lvalue of stmt, ++ then expr type is VAR_DECL - RECORD_TYPE (fetch x) */ + expr = TREE_OPERAND (expr, 0); + accesstype = NULL; + break; + } + case MEM_REF: + { ++ /* _2 = MEM[(struct s * *)_1]; ++ If expr is the right value of stmt,then field_off type is ++ INTEGER_CST - POINTER_TYPE - POINTER_TYPE - RECORD_TYPE. */ + tree field_off = TREE_OPERAND (expr, 1); + gcc_assert (TREE_CODE (field_off) == INTEGER_CST); + /* So we can mark the types as escaping if different. */ + accesstype = TREE_TYPE (field_off); +- if (!check_mem_ref_offset (expr)) ++ if (!check_mem_ref_offset (expr, num)) + { + offset += tree_to_uhwi (field_off); + } +@@ -2655,8 +3735,13 @@ ipa_struct_reorg::wholeaccess (tree expr, tree base, tree accesstype, srtype *t) + } + + bool +-ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, srtype *&type, srfield *&field, bool &realpart, bool &imagpart, bool &address, bool should_create, bool can_escape) ++ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, ++ srtype *&type, srfield *&field, ++ bool &realpart, bool &imagpart, bool &address, ++ bool& escape_from_base, bool should_create, ++ bool can_escape) + { ++ tree num = NULL_TREE; + HOST_WIDE_INT offset; + tree accesstype; + address = false; +@@ -2668,7 +3753,9 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, srtype + mark_as_bit_field = true; + } + +- base = get_ref_base_and_offset (expr, offset, realpart, imagpart, accesstype); ++ /* ref is classified into two types: COMPONENT_REF or MER_REF. */ ++ base = get_ref_base_and_offset (expr, offset, realpart, imagpart, ++ accesstype, &num); + + /* Variable access, unkown type. */ + if (base == NULL) +@@ -2706,6 +3793,8 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, srtype + if (!t) + return false; + } ++ /* If no such decl is finded ++ or orig_type is not added to this decl, then add it. */ + else if (!d && accesstype) + { + if (!should_create) +@@ -2717,15 +3806,54 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, srtype + t = record_type (inner_type (accesstype)); + if (!t || t->has_escaped ()) + return false; +- /* If base is not void* mark the type as escaping. */ +- if (!VOID_POINTER_P (TREE_TYPE (base))) ++ /* If base is not void* mark the type as escaping. ++ release INTEGER_TYPE cast to struct pointer. ++ (If t has escpaed above, then directly returns ++ and doesn't mark escape follow.). */ ++ /* _607 = MEM[(struct arc_t * *)pl_100]. ++ then base pl_100:ssa_name - pointer_type - integer_type. */ ++ if (current_mode == STRUCT_REORDER_FIELDS) ++ { ++ bool is_int_ptr = POINTER_TYPE_P (TREE_TYPE (base)) ++ && (TREE_CODE (inner_type (TREE_TYPE (base))) ++ == INTEGER_TYPE); ++ if (!(VOID_POINTER_P (TREE_TYPE (base)) ++ || (current_function->is_safe_func && is_int_ptr))) ++ { ++ gcc_assert (can_escape); ++ t->mark_escape (escape_cast_another_ptr, NULL); ++ return false; ++ } ++ if (TREE_CODE (base) == SSA_NAME ++ && !(current_function->is_safe_func && is_int_ptr)) ++ { ++ /* Add a safe func mechanism. */ ++ if (!(current_function->is_safe_func ++ && is_from_void_ptr_parm (base))) ++ { ++ /* Add auxiliary information of the multi-layer pointer ++ type. */ ++ current_function->record_decl (t, base, -1, ++ isptrptr (accesstype) ? accesstype : NULL); ++ } ++ } ++ } ++ else + { +- gcc_assert (can_escape); +- t->mark_escape (escape_cast_another_ptr, NULL); +- return false; ++ if (!(VOID_POINTER_P (TREE_TYPE (base)))) ++ { ++ gcc_assert (can_escape); ++ t->mark_escape (escape_cast_another_ptr, NULL); ++ return false; ++ } ++ if (TREE_CODE (base) == SSA_NAME) ++ { ++ /* Add auxiliary information of the multi-layer pointer ++ type. */ ++ current_function->record_decl (t, base, -1, ++ isptrptr (accesstype) ? accesstype : NULL); ++ } + } +- if (TREE_CODE (base) == SSA_NAME) +- current_function->record_decl (t, base, -1); + } + else if (!d) + return false; +@@ -2733,7 +3861,10 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, srtype + t = d->type; + + if (t->has_escaped ()) ++ { ++ escape_from_base = true; + return false; ++ } + + if (mark_as_bit_field) + { +@@ -2759,7 +3890,6 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, srtype + print_generic_expr (dump_file, expr); + fprintf (dump_file, "\n"); + print_generic_expr (dump_file, base); +- fprintf (dump_file, "\n"); + } + gcc_assert (can_escape); + t->mark_escape (escape_unkown_field, NULL); +@@ -2773,9 +3903,8 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, srtype + print_generic_expr (dump_file, f->fieldtype); + fprintf (dump_file, "\naccess type = "); + print_generic_expr (dump_file, TREE_TYPE (expr)); +- fprintf (dump_file, "original expr = "); ++ fprintf (dump_file, "\noriginal expr = "); + print_generic_expr (dump_file, expr); +- fprintf (dump_file, "\n"); + } + gcc_assert (can_escape); + t->mark_escape (escape_unkown_field, NULL); +@@ -2797,7 +3926,9 @@ ipa_struct_reorg::mark_expr_escape (tree expr, escape_type escapes, gimple *stmt + srtype *type; + srfield *field; + bool realpart, imagpart, address; +- if (!get_type_field (expr, base, indirect, type, field, realpart, imagpart, address)) ++ bool escape_from_base = false; ++ if (!get_type_field (expr, base, indirect, type, field, ++ realpart, imagpart, address, escape_from_base)) + return; + + type->mark_escape (escapes, stmt); +@@ -2875,6 +4006,7 @@ ipa_struct_reorg::maybe_record_call (cgraph_node *node, gcall *stmt) + return; + } + ++ /* get func param it's tree_list. */ + argtype = TYPE_ARG_TYPES (gimple_call_fntype (stmt)); + for (unsigned i = 0; i < gimple_call_num_args (stmt); i++) + { +@@ -2882,9 +4014,16 @@ ipa_struct_reorg::maybe_record_call (cgraph_node *node, gcall *stmt) + if (argtype) + { + tree argtypet = TREE_VALUE (argtype); +- if (!free_or_realloc ++ /* callee_func (_1, _2); ++ Check the callee func, instead of current func. */ ++ if (!(free_or_realloc ++ || (current_mode == STRUCT_REORDER_FIELDS ++ && safe_functions.contains ( ++ node->get_edge (stmt)->callee))) + && VOID_POINTER_P (argtypet)) +- mark_type_as_escape (TREE_TYPE (arg), escape_cast_void); ++ { ++ mark_type_as_escape (TREE_TYPE (arg), escape_cast_void, stmt); ++ } + else + record_stmt_expr (arg, node, stmt); + } +@@ -2905,11 +4044,26 @@ ipa_struct_reorg::record_stmt_expr (tree expr, cgraph_node *node, gimple *stmt) + srtype *type; + srfield *field; + bool realpart, imagpart, address; +- if (!get_type_field (expr, base, indirect, type, field, realpart, imagpart, address)) ++ bool escape_from_base = false; ++ if (!get_type_field (expr, base, indirect, type, field, ++ realpart, imagpart, address, escape_from_base)) + return; + +- if (!opt_for_fn (current_function_decl, flag_ipa_struct_reorg)) +- type->mark_escape (escape_non_optimize, stmt); ++ if (current_mode == STRUCT_REORDER_FIELDS) ++ { ++ if (!opt_for_fn (current_function_decl, flag_ipa_reorder_fields)) ++ { ++ type->mark_escape (escape_non_optimize, stmt); ++ } ++ } ++ else ++ { ++ if (!opt_for_fn (current_function_decl, flag_ipa_struct_reorg)) ++ { ++ type->mark_escape (escape_non_optimize, stmt); ++ } ++ } ++ + + /* Record it. */ + type->add_access (new sraccess (stmt, node, type, field)); +@@ -2927,8 +4081,10 @@ ipa_struct_reorg::find_function (cgraph_node *node) + } + + void +-ipa_struct_reorg::check_type_and_push (tree newdecl, srtype *type, vec<srdecl*> &worklist, gimple *stmt) ++ipa_struct_reorg::check_type_and_push (tree newdecl, srdecl *decl, ++ vec<srdecl*> &worklist, gimple *stmt) + { ++ srtype *type = decl->type; + if (integer_zerop (newdecl)) + return; + +@@ -2940,8 +4096,9 @@ ipa_struct_reorg::check_type_and_push (tree newdecl, srtype *type, vec<srdecl*> + type->mark_escape (escape_cast_another_ptr, stmt); + return; + } +- if (d->type == type) +- return; ++ if (d->type == type ++ && cmp_ptr_layers (TREE_TYPE (newdecl), TREE_TYPE (decl->decl))) ++ return; + + srtype *type1 = d->type; + type->mark_escape (escape_cast_another_ptr, stmt); +@@ -2991,7 +4148,9 @@ ipa_struct_reorg::check_type_and_push (tree newdecl, srtype *type, vec<srdecl*> + /* Only add to the worklist if the decl is a SSA_NAME. */ + if (TREE_CODE (newdecl) == SSA_NAME) + worklist.safe_push (d); +- if (d->type == type) ++ tree a_decl = d->orig_type ? d->orig_type : TREE_TYPE (newdecl); ++ tree b_decl = decl->orig_type ? decl->orig_type : TREE_TYPE (decl->decl); ++ if (d->type == type && cmp_ptr_layers (a_decl, b_decl)) + return; + + srtype *type1 = d->type; +@@ -3033,6 +4192,111 @@ ipa_struct_reorg::check_alloc_num (gimple *stmt, srtype *type) + } + } + ++/* Check the definition of gimple assign. */ ++ ++void ++ipa_struct_reorg::check_definition_assign (srdecl *decl, vec<srdecl*> &worklist) ++{ ++ tree ssa_name = decl->decl; ++ srtype *type = decl->type; ++ gimple *stmt = SSA_NAME_DEF_STMT (ssa_name); ++ gcc_assert (gimple_code (stmt) == GIMPLE_ASSIGN); ++ /* a) if the SSA_NAME is sourced from a pointer plus, record the pointer and ++ check to make sure the addition was a multiple of the size. ++ check the pointer type too. */ ++ tree rhs = gimple_assign_rhs1 (stmt); ++ if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) ++ { ++ tree rhs2 = gimple_assign_rhs2 (stmt); ++ tree num = NULL_TREE; ++ /* Specify the correct size for the multi-layer pointer. */ ++ if (!is_result_of_mult (rhs2, &num, isptrptr (decl->orig_type) ++ ? TYPE_SIZE_UNIT (decl->orig_type) ++ : TYPE_SIZE_UNIT (type->type))) ++ { ++ type->mark_escape (escape_non_multiply_size, stmt); ++ } ++ ++ if (TREE_CODE (rhs) == SSA_NAME) ++ { ++ check_type_and_push (rhs, decl, worklist, stmt); ++ } ++ return; ++ } ++ ++ if (gimple_assign_rhs_code (stmt) == MAX_EXPR ++ || gimple_assign_rhs_code (stmt) == MIN_EXPR ++ || gimple_assign_rhs_code (stmt) == BIT_IOR_EXPR ++ || gimple_assign_rhs_code (stmt) == BIT_XOR_EXPR ++ || gimple_assign_rhs_code (stmt) == BIT_AND_EXPR) ++ { ++ tree rhs2 = gimple_assign_rhs2 (stmt); ++ if (TREE_CODE (rhs) == SSA_NAME) ++ { ++ check_type_and_push (rhs, decl, worklist, stmt); ++ } ++ if (TREE_CODE (rhs2) == SSA_NAME) ++ { ++ check_type_and_push (rhs2, decl, worklist, stmt); ++ } ++ return; ++ } ++ ++ /* Casts between pointers and integer are escaping. */ ++ if (gimple_assign_cast_p (stmt)) ++ { ++ type->mark_escape (escape_cast_int, stmt); ++ return; ++ } ++ ++ /* d) if the name is from a cast/assignment, make sure it is used as ++ that type or void* ++ i) If void* then push the ssa_name into worklist. */ ++ gcc_assert (gimple_assign_single_p (stmt)); ++ check_other_side (decl, rhs, stmt, worklist); ++ check_ptr_layers (decl->decl, rhs, stmt); ++} ++ ++/* Check the definition of gimple call. */ ++ ++void ++ipa_struct_reorg::check_definition_call (srdecl *decl, vec<srdecl*> &worklist) ++{ ++ tree ssa_name = decl->decl; ++ srtype *type = decl->type; ++ gimple *stmt = SSA_NAME_DEF_STMT (ssa_name); ++ gcc_assert (gimple_code (stmt) == GIMPLE_CALL); ++ ++ /* For realloc, check the type of the argument. */ ++ if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC)) ++ { ++ check_type_and_push (gimple_call_arg (stmt, 0), decl, worklist, stmt); ++ } ++ ++ if (current_mode == STRUCT_REORDER_FIELDS) ++ { ++ if (!handled_allocation_stmt (stmt)) ++ { ++ type->mark_escape (escape_return, stmt); ++ } ++ if (!allocate_size (type, decl, stmt)) ++ { ++ type->mark_escape (escape_non_multiply_size, stmt); ++ } ++ } ++ else ++ { ++ if (!handled_allocation_stmt (stmt) ++ || !allocate_size (type, decl, stmt)) ++ { ++ type->mark_escape (escape_return, stmt); ++ } ++ } ++ ++ check_alloc_num (stmt, type); ++ return; ++} ++ + /* + 2) Check SSA_NAMEs for non type usages (source or use) (worlist of srdecl) + a) if the SSA_NAME is sourced from a pointer plus, record the pointer and +@@ -3058,9 +4322,16 @@ ipa_struct_reorg::check_definition (srdecl *decl, vec<srdecl*> &worklist) + if (var + && TREE_CODE (var) == PARM_DECL + && VOID_POINTER_P (TREE_TYPE (ssa_name))) +- type->mark_escape (escape_cast_void, NULL); ++ { ++ type->mark_escape (escape_cast_void, SSA_NAME_DEF_STMT (ssa_name)); ++ } + return; + } ++ if (current_mode == STRUCT_REORDER_FIELDS && SSA_NAME_VAR (ssa_name) ++ && VOID_POINTER_P (TREE_TYPE (SSA_NAME_VAR (ssa_name)))) ++ { ++ type->mark_escape (escape_cast_void, SSA_NAME_DEF_STMT (ssa_name)); ++ } + gimple *stmt = SSA_NAME_DEF_STMT (ssa_name); + + /* +@@ -3069,15 +4340,7 @@ ipa_struct_reorg::check_definition (srdecl *decl, vec<srdecl*> &worklist) + */ + if (gimple_code (stmt) == GIMPLE_CALL) + { +- /* For realloc, check the type of the argument. */ +- if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC)) +- check_type_and_push (gimple_call_arg (stmt, 0), type, worklist, stmt); +- +- if (!handled_allocation_stmt (stmt) +- || !allocate_size (type, stmt)) +- type->mark_escape (escape_return, stmt); +- check_alloc_num (stmt, type); +- return; ++ check_definition_call (decl, worklist); + } + /* If the SSA_NAME is sourced from an inline-asm, just mark the type as escaping. */ + if (gimple_code (stmt) == GIMPLE_ASM) +@@ -3091,61 +4354,16 @@ ipa_struct_reorg::check_definition (srdecl *decl, vec<srdecl*> &worklist) + if (gimple_code (stmt) == GIMPLE_PHI) + { + for (unsigned i = 0; i < gimple_phi_num_args (stmt); i++) +- check_type_and_push (gimple_phi_arg_def (stmt, i), type, worklist, stmt); +- return; +- } +- +- gcc_assert (gimple_code (stmt) == GIMPLE_ASSIGN); +- /* +- a) if the SSA_NAME is sourced from a pointer plus, record the pointer and +- check to make sure the addition was a multiple of the size. +- check the pointer type too. +- */ +- +- tree rhs = gimple_assign_rhs1 (stmt); +- if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) +- { +- tree rhs2 = gimple_assign_rhs2 (stmt); +- tree num; +- if (!is_result_of_mult (rhs2, &num, TYPE_SIZE_UNIT (type->type))) +- type->mark_escape (escape_non_multiply_size, stmt); +- +- if (TREE_CODE (rhs) == SSA_NAME) +- check_type_and_push (rhs, type, worklist, stmt); +- return; +- } +- +- if (gimple_assign_rhs_code (stmt) == MAX_EXPR +- || gimple_assign_rhs_code (stmt) == MIN_EXPR +- || gimple_assign_rhs_code (stmt) == BIT_IOR_EXPR +- || gimple_assign_rhs_code (stmt) == BIT_XOR_EXPR +- || gimple_assign_rhs_code (stmt) == BIT_AND_EXPR) +- { +- tree rhs2 = gimple_assign_rhs2 (stmt); +- if (TREE_CODE (rhs) == SSA_NAME) +- { +- check_type_and_push (rhs, type, worklist, stmt); +- } +- if (TREE_CODE (rhs2) == SSA_NAME) + { +- check_type_and_push (rhs2, type, worklist, stmt); ++ check_type_and_push (gimple_phi_arg_def (stmt, i), ++ decl, worklist, stmt); + } + return; + } +- +- /* Casts between pointers and integer are escaping. */ +- if (gimple_assign_cast_p (stmt)) ++ if (gimple_code (stmt) == GIMPLE_ASSIGN) + { +- type->mark_escape (escape_cast_int, stmt); +- return; ++ check_definition_assign (decl, worklist); + } +- +- /* +- d) if the name is from a cast/assignment, make sure it is used as that type or void* +- i) If void* then push the ssa_name into worklist +- */ +- gcc_assert (gimple_assign_single_p (stmt)); +- check_other_side (decl, rhs, stmt, worklist); + } + + /* Mark the types used by the inline-asm as escaping. It is unkown what happens inside +@@ -3177,11 +4395,10 @@ ipa_struct_reorg::check_other_side (srdecl *decl, tree other, gimple *stmt, vec< + { + srtype *type = decl->type; + +- if (TREE_CODE (other) == SSA_NAME +- || DECL_P (other) ++ if (TREE_CODE (other) == SSA_NAME || DECL_P (other) + || TREE_CODE (other) == INTEGER_CST) + { +- check_type_and_push (other, type, worklist, stmt); ++ check_type_and_push (other, decl, worklist, stmt); + return; + } + +@@ -3207,8 +4424,29 @@ ipa_struct_reorg::check_other_side (srdecl *decl, tree other, gimple *stmt, vec< + srtype *type1; + srfield *field; + bool realpart, imagpart, address; +- if (!get_type_field (other, base, indirect, type1, field, realpart, imagpart, address)) +- type->mark_escape (escape_cast_another_ptr, stmt); ++ bool escape_from_base = false; ++ if (!get_type_field (other, base, indirect, type1, field, ++ realpart, imagpart, address, escape_from_base)) ++ { ++ if (current_mode == STRUCT_REORDER_FIELDS) ++ { ++ /* release INTEGER_TYPE cast to struct pointer. */ ++ bool cast_from_int_ptr = current_function->is_safe_func && base ++ && find_decl (base) == NULL && POINTER_TYPE_P (TREE_TYPE (base)) ++ && (TREE_CODE (inner_type (TREE_TYPE (base))) == INTEGER_TYPE); ++ ++ /* Add a safe func mechanism. */ ++ bool from_void_ptr_parm = current_function->is_safe_func ++ && TREE_CODE (base) == SSA_NAME && is_from_void_ptr_parm (base); ++ ++ /* release type is used by a type which escapes. */ ++ if (escape_from_base || cast_from_int_ptr || from_void_ptr_parm) ++ { ++ return; ++ } ++ } ++ type->mark_escape (escape_cast_another_ptr, stmt); ++ } + + return; + } +@@ -3220,6 +4458,71 @@ ipa_struct_reorg::check_other_side (srdecl *decl, tree other, gimple *stmt, vec< + } + + ++/* Get the expr base. */ ++ ++void ++get_base (tree &base, tree expr) ++{ ++ if (TREE_CODE (expr) == MEM_REF) ++ { ++ base = TREE_OPERAND (expr, 0); ++ } ++ else if (TREE_CODE (expr) == COMPONENT_REF) ++ { ++ base = TREE_OPERAND (expr, 0); ++ base = (TREE_CODE (base) == MEM_REF) ? TREE_OPERAND (base, 0) : base; ++ } ++ else if (TREE_CODE (expr) == ADDR_EXPR) ++ { ++ base = TREE_OPERAND (expr, 0); ++ } ++} ++ ++/* Check whether the number of pointer layers of exprs is equal, ++ marking unequals as escape. */ ++ ++void ++ipa_struct_reorg::check_ptr_layers (tree a_expr, tree b_expr, gimple* stmt) ++{ ++ if (current_mode != STRUCT_REORDER_FIELDS || current_function->is_safe_func ++ || !(POINTER_TYPE_P (TREE_TYPE (a_expr))) ++ || !(POINTER_TYPE_P (TREE_TYPE (b_expr))) ++ || !handled_type (TREE_TYPE (a_expr)) ++ || !handled_type (TREE_TYPE (b_expr))) ++ { ++ return; ++ } ++ ++ tree a_base = a_expr; ++ tree b_base = b_expr; ++ get_base (a_base, a_expr); ++ get_base (b_base, b_expr); ++ ++ srdecl *a = find_decl (a_base); ++ srdecl *b = find_decl (b_base); ++ if (a && b == NULL && TREE_CODE (b_expr) != INTEGER_CST) ++ { ++ a->type->mark_escape (escape_cast_another_ptr, stmt); ++ return; ++ } ++ else if (b && a == NULL && TREE_CODE (a_expr) != INTEGER_CST) ++ { ++ b->type->mark_escape (escape_cast_another_ptr, stmt); ++ return; ++ } ++ else if (a == NULL && b == NULL) ++ { ++ return; ++ } ++ ++ if (cmp_ptr_layers (TREE_TYPE (a_expr), TREE_TYPE (b_expr))) ++ { ++ return; ++ } ++ a->type->mark_escape (escape_cast_another_ptr, stmt); ++ b->type->mark_escape (escape_cast_another_ptr, stmt); ++} ++ + void + ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist) + { +@@ -3234,7 +4537,7 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist) + check to make sure they are used correctly. */ + if (gimple_code (stmt) == GIMPLE_PHI) + { +- check_type_and_push (gimple_phi_result (stmt), type, worklist, stmt); ++ check_type_and_push (gimple_phi_result (stmt), decl, worklist, stmt); + return; + } + +@@ -3250,10 +4553,15 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist) + tree rhs2 = gimple_cond_rhs (stmt); + tree orhs = rhs1; + enum tree_code code = gimple_cond_code (stmt); +- if (code != EQ_EXPR && code != NE_EXPR +- && (current_mode != COMPLETE_STRUCT_RELAYOUT +- || (code != LT_EXPR && code != LE_EXPR +- && code != GT_EXPR && code != GE_EXPR))) ++ if ((current_mode == NORMAL && (code != EQ_EXPR && code != NE_EXPR)) ++ || (current_mode == COMPLETE_STRUCT_RELAYOUT ++ && (code != EQ_EXPR && code != NE_EXPR ++ && code != LT_EXPR && code != LE_EXPR ++ && code != GT_EXPR && code != GE_EXPR)) ++ || (current_mode == STRUCT_REORDER_FIELDS ++ && (code != EQ_EXPR && code != NE_EXPR ++ && code != LT_EXPR && code != LE_EXPR ++ && code != GT_EXPR && code != GE_EXPR))) + { + mark_expr_escape (rhs1, escape_non_eq, stmt); + mark_expr_escape (rhs2, escape_non_eq, stmt); +@@ -3264,7 +4572,7 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist) + return; + if (TREE_CODE (orhs) != SSA_NAME) + mark_expr_escape (rhs1, escape_non_eq, stmt); +- check_type_and_push (orhs, type, worklist, stmt); ++ check_type_and_push (orhs, decl, worklist, stmt); + return; + } + +@@ -3284,9 +4592,14 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist) + tree rhs2 = gimple_assign_rhs2 (stmt); + tree orhs = rhs1; + enum tree_code code = gimple_assign_rhs_code (stmt); +- if (code != EQ_EXPR && code != NE_EXPR +- && (current_mode != COMPLETE_STRUCT_RELAYOUT +- || (code != LT_EXPR && code != LE_EXPR ++ if ((current_mode == NORMAL && (code != EQ_EXPR && code != NE_EXPR)) ++ || (current_mode == COMPLETE_STRUCT_RELAYOUT ++ && (code != EQ_EXPR && code != NE_EXPR ++ && code != LT_EXPR && code != LE_EXPR ++ && code != GT_EXPR && code != GE_EXPR)) ++ || (current_mode == STRUCT_REORDER_FIELDS ++ && (code != EQ_EXPR && code != NE_EXPR ++ && code != LT_EXPR && code != LE_EXPR + && code != GT_EXPR && code != GE_EXPR))) + { + mark_expr_escape (rhs1, escape_non_eq, stmt); +@@ -3298,7 +4611,7 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist) + return; + if (TREE_CODE (orhs) != SSA_NAME) + mark_expr_escape (rhs1, escape_non_eq, stmt); +- check_type_and_push (orhs, type, worklist, stmt); ++ check_type_and_push (orhs, decl, worklist, stmt); + return; + } + +@@ -3312,6 +4625,7 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist) + check_other_side (decl, lhs, stmt, worklist); + return; + } ++ check_ptr_layers (lhs, rhs, stmt); + } + + if (is_gimple_assign (stmt) +@@ -3321,10 +4635,26 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist) + tree lhs = gimple_assign_lhs (stmt); + tree num; + check_other_side (decl, lhs, stmt, worklist); +- if (!is_result_of_mult (rhs2, &num, TYPE_SIZE_UNIT (type->type))) ++ check_ptr_layers (lhs, decl->decl, stmt); ++ /* Specify the correct size for the multi-layer pointer. */ ++ if (!is_result_of_mult (rhs2, &num, isptrptr (decl->orig_type) ++ ? TYPE_SIZE_UNIT (decl->orig_type) ++ : TYPE_SIZE_UNIT (type->type))) + type->mark_escape (escape_non_multiply_size, stmt); + } + ++ if (is_gimple_assign (stmt) ++ && gimple_assign_rhs_code (stmt) == POINTER_DIFF_EXPR) ++ { ++ tree rhs1 = gimple_assign_rhs1 (stmt); ++ tree rhs2 = gimple_assign_rhs2 (stmt); ++ tree other = rhs1 == decl->decl ? rhs2 : rhs1; ++ ++ check_other_side (decl, other, stmt, worklist); ++ check_ptr_layers (decl->decl, other, stmt); ++ return; ++ } ++ + } + + /* +@@ -3388,17 +4718,51 @@ ipa_struct_reorg::record_function (cgraph_node *node) + if (DECL_PRESERVE_P (node->decl)) + escapes = escape_marked_as_used; + else if (!node->local) +- escapes = escape_visible_function; ++ { ++ if (current_mode != STRUCT_REORDER_FIELDS) ++ { ++ escapes = escape_visible_function; ++ } ++ if (current_mode == STRUCT_REORDER_FIELDS && node->externally_visible) ++ { ++ escapes = escape_visible_function; ++ } ++ } + else if (!node->can_change_signature) + escapes = escape_cannot_change_signature; + else if (!tree_versionable_function_p (node->decl)) + escapes = escape_noclonable_function; +- else if (!opt_for_fn (node->decl, flag_ipa_struct_reorg)) +- escapes = escape_non_optimize; ++ ++ if (current_mode == STRUCT_REORDER_FIELDS) ++ { ++ if (!opt_for_fn (node->decl, flag_ipa_reorder_fields)) ++ { ++ escapes = escape_non_optimize; ++ } ++ } ++ else if (current_mode == NORMAL || current_mode == COMPLETE_STRUCT_RELAYOUT) ++ { ++ if (!opt_for_fn (node->decl, flag_ipa_struct_reorg)) ++ { ++ escapes = escape_non_optimize; ++ } ++ } + + basic_block bb; + gimple_stmt_iterator si; + ++ /* Add a safe func mechanism. */ ++ if (current_mode == STRUCT_REORDER_FIELDS) ++ { ++ current_function->is_safe_func = safe_functions.contains (node); ++ if (dump_file) ++ { ++ fprintf (dump_file, "\nfunction %s/%u: is_safe_func = %d\n", ++ node->name (), node->order, ++ current_function->is_safe_func); ++ } ++ } ++ + /* Record the static chain decl. */ + if (fn->static_chain_decl) + { +@@ -3529,6 +4893,49 @@ ipa_struct_reorg::record_function (cgraph_node *node) + } + + ++/* For a function that contains the void* parameter and passes the structure ++ pointer, check whether the function uses the input node safely. ++ For these functions, the void* parameter and related ssa_name are not ++ recorded in record_function (), and the input structure type is not escaped. ++*/ ++ ++void ++ipa_struct_reorg::record_safe_func_with_void_ptr_parm () ++{ ++ cgraph_node *node = NULL; ++ FOR_EACH_FUNCTION (node) ++ { ++ if (!node->real_symbol_p ()) ++ { ++ continue; ++ } ++ if (node->definition) ++ { ++ if (!node->has_gimple_body_p () || node->inlined_to) ++ { ++ continue; ++ } ++ node->get_body (); ++ function *fn = DECL_STRUCT_FUNCTION (node->decl); ++ if (!fn) ++ { ++ continue; ++ } ++ push_cfun (fn); ++ if (is_safe_func_with_void_ptr_parm (node)) ++ { ++ safe_functions.add (node); ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nfunction %s/%u is safe function.\n", ++ node->name (), node->order); ++ } ++ } ++ pop_cfun (); ++ } ++ } ++} ++ + /* Record all accesses for all types including global variables. */ + + void +@@ -3560,6 +4967,12 @@ ipa_struct_reorg::record_accesses (void) + record_var (var->decl, escapes); + } + ++ /* Add a safe func mechanism. */ ++ if (current_mode == STRUCT_REORDER_FIELDS) ++ { ++ record_safe_func_with_void_ptr_parm (); ++ } ++ + FOR_EACH_FUNCTION (cnode) + { + if (!cnode->real_symbol_p ()) +@@ -3578,11 +4991,14 @@ ipa_struct_reorg::record_accesses (void) + + if (dump_file && (dump_flags & TDF_DETAILS)) + { +- fprintf (dump_file, "all types (before pruning):\n"); ++ fprintf (dump_file, "\n"); ++ fprintf (dump_file, "==============================================\n\n"); ++ fprintf (dump_file, "======== all types (before pruning): ========\n\n"); + dump_types (dump_file); +- fprintf (dump_file, "all functions (before pruning):\n"); ++ fprintf (dump_file, "======= all functions (before pruning): =======\n"); + dump_functions (dump_file); + } ++ /* If record_var () is called later, new types will not be recorded. */ + done_recording = true; + } + +@@ -3606,6 +5022,7 @@ ipa_struct_reorg::walk_field_for_cycles (srtype *type) + { + if (!field->type) + ; ++ /* If there are two members of the same structure pointer type? */ + else if (field->type->visited + || walk_field_for_cycles (field->type)) + { +@@ -3685,22 +5102,99 @@ ipa_struct_reorg::propagate_escape (void) + } while (changed); + } + ++/* If the original type (with members) has escaped, corresponding to the ++ struct pointer type (empty member) in the structure fields ++ should also marked as escape. */ ++ ++void ++ipa_struct_reorg::propagate_escape_via_original (void) ++{ ++ for (unsigned i = 0; i < types.length (); i++) ++ { ++ for (unsigned j = 0; j < types[i]->fields.length (); j++) ++ { ++ srfield *field = types[i]->fields[j]; ++ if (handled_type (field->fieldtype) && field->type) ++ { ++ for (unsigned k = 0; k < types.length (); k++) ++ { ++ const char *type1 = get_type_name (field->type->type); ++ const char *type2 = get_type_name (types[k]->type); ++ if (type1 == NULL || type2 == NULL) ++ { ++ continue; ++ } ++ if (type1 == type2 && types[k]->has_escaped ()) ++ { ++ if (!field->type->has_escaped ()) ++ { ++ field->type->mark_escape ( ++ escape_via_orig_escape, NULL); ++ } ++ break; ++ } ++ } ++ } ++ } ++ } ++} ++ ++/* Marks the fileds as empty and does not have the original structure type ++ is escape. */ ++ ++void ++ipa_struct_reorg::propagate_escape_via_empty_with_no_original (void) ++{ ++ for (unsigned i = 0; i < types.length (); i++) ++ { ++ if (types[i]->fields.length () == 0) ++ { ++ for (unsigned j = 0; j < types.length (); j++) ++ { ++ if (i != j && types[j]->fields.length ()) ++ { ++ const char *type1 = get_type_name (types[i]->type); ++ const char *type2 = get_type_name (types[j]->type); ++ if (type1 != NULL && type2 != NULL && type1 == type2) ++ { ++ break; ++ } ++ } ++ if (j == types.length () - 1) ++ { ++ types[i]->mark_escape (escape_via_empty_no_orig, NULL); ++ } ++ } ++ } ++ } ++} ++ + /* Prune the escaped types and their decls from what was recorded. */ + + void + ipa_struct_reorg::prune_escaped_types (void) + { +- if (current_mode != COMPLETE_STRUCT_RELAYOUT) ++ if (current_mode != COMPLETE_STRUCT_RELAYOUT ++ && current_mode != STRUCT_REORDER_FIELDS) + { ++ /* Detect recusive types and mark them as escaping. */ + detect_cycles (); ++ /* If contains or is contained by the escape type, ++ mark them as escaping. */ + propagate_escape (); + } ++ if (current_mode == STRUCT_REORDER_FIELDS) ++ { ++ propagate_escape_via_original (); ++ propagate_escape_via_empty_with_no_original (); ++ } + + if (dump_file && (dump_flags & TDF_DETAILS)) + { +- fprintf (dump_file, "all types (after prop but before pruning):\n"); ++ fprintf (dump_file, "==============================================\n\n"); ++ fprintf (dump_file, "all types (after prop but before pruning): \n\n"); + dump_types (dump_file); +- fprintf (dump_file, "all functions (after prop but before pruning):\n"); ++ fprintf (dump_file, "all functions (after prop but before pruning): \n"); + dump_functions (dump_file); + } + +@@ -3748,7 +5242,8 @@ ipa_struct_reorg::prune_escaped_types (void) + /* Prune functions which don't refer to any variables any more. */ + if (function->args.is_empty () + && function->decls.is_empty () +- && function->globals.is_empty ()) ++ && function->globals.is_empty () ++ && current_mode != STRUCT_REORDER_FIELDS) + { + delete function; + functions.ordered_remove (i); +@@ -3773,24 +5268,33 @@ ipa_struct_reorg::prune_escaped_types (void) + + /* Prune types that escape, all references to those types + will have been removed in the above loops. */ +- for (unsigned i = 0; i < types.length (); ) ++ /* The escape type is not deleted in STRUCT_REORDER_FIELDS, ++ Then the type that contains the escaped type fields ++ can find complete information. */ ++ if (current_mode != STRUCT_REORDER_FIELDS) + { +- srtype *type = types[i]; +- if (type->has_escaped ()) ++ for (unsigned i = 0; i < types.length ();) + { +- /* All references to this type should have been removed now. */ +- delete type; +- types.ordered_remove (i); ++ srtype *type = types[i]; ++ if (type->has_escaped ()) ++ { ++ /* All references to this type should have been removed now. */ ++ delete type; ++ types.ordered_remove (i); ++ } ++ else ++ { ++ i++; ++ } + } +- else +- i++; + } + + if (dump_file && (dump_flags & TDF_DETAILS)) + { +- fprintf (dump_file, "all types (after pruning):\n"); ++ fprintf (dump_file, "==============================================\n\n"); ++ fprintf (dump_file, "========= all types (after pruning): =========\n\n"); + dump_types (dump_file); +- fprintf (dump_file, "all functions (after pruning):\n"); ++ fprintf (dump_file, "======== all functions (after pruning): ========\n"); + dump_functions (dump_file); + } + } +@@ -3817,6 +5321,28 @@ ipa_struct_reorg::create_new_types (void) + for (unsigned i = 0; i < types.length (); i++) + newtypes += types[i]->create_new_type (); + ++ if (current_mode == STRUCT_REORDER_FIELDS) ++ { ++ for (unsigned i = 0; i < types.length (); i++) ++ { ++ auto_vec <tree> *fields = fields_to_finish.get (types[i]->type); ++ if (fields) ++ { ++ for (unsigned j = 0; j < fields->length (); j++) ++ { ++ tree field = (*fields)[j]; ++ TREE_TYPE (field) ++ = reconstruct_complex_type (TREE_TYPE (field), ++ types[i]->newtype[0]); ++ } ++ } ++ } ++ for (unsigned i = 0; i < types.length (); i++) ++ { ++ layout_type (types[i]->newtype[0]); ++ } ++ } ++ + if (dump_file) + { + if (newtypes) +@@ -3919,7 +5445,8 @@ ipa_struct_reorg::create_new_args (cgraph_node *new_node) + char *name = NULL; + if (tname) + { +- name = concat (tname, ".reorg.0", NULL); ++ name = concat (tname, current_mode == STRUCT_REORDER_FIELDS ++ ? ".reorder.0" : ".reorg.0", NULL); + new_name = get_identifier (name); + free (name); + } +@@ -4005,9 +5532,10 @@ ipa_struct_reorg::create_new_functions (void) + fprintf (dump_file, "\n"); + } + statistics_counter_event (NULL, "Create new function", 1); +- new_node = node->create_version_clone_with_body (vNULL, NULL, +- NULL, NULL, NULL, +- "struct_reorg"); ++ new_node = node->create_version_clone_with_body ( ++ vNULL, NULL, NULL, NULL, NULL, ++ current_mode == STRUCT_REORDER_FIELDS ++ ? "struct_reorder" : "struct_reorg"); + new_node->can_change_signature = node->can_change_signature; + new_node->make_local (); + f->newnode = new_node; +@@ -4047,6 +5575,7 @@ ipa_struct_reorg::rewrite_expr (tree expr, tree newexpr[max_split], bool ignore_ + srfield *f; + bool realpart, imagpart; + bool address; ++ bool escape_from_base = false; + + tree newbase[max_split]; + memset (newexpr, 0, sizeof(tree[max_split])); +@@ -4064,7 +5593,8 @@ ipa_struct_reorg::rewrite_expr (tree expr, tree newexpr[max_split], bool ignore_ + return true; + } + +- if (!get_type_field (expr, base, indirect, t, f, realpart, imagpart, address)) ++ if (!get_type_field (expr, base, indirect, t, f, realpart, imagpart, ++ address, escape_from_base)) + return false; + + /* If the type is not changed, then just return false. */ +@@ -4122,7 +5652,40 @@ ipa_struct_reorg::rewrite_expr (tree expr, tree newexpr[max_split], bool ignore_ + if (address) + newbase1 = build_fold_addr_expr (newbase1); + if (indirect) +- newbase1 = build_simple_mem_ref (newbase1); ++ { ++ if (current_mode == STRUCT_REORDER_FIELDS) ++ { ++ /* Supports the MEM_REF offset. ++ _1 = MEM[(struct arc *)ap_4 + 72B].flow; ++ Old rewrite:_1 = ap.reorder.0_8->flow; ++ New rewrite:_1 ++ = MEM[(struct arc.reorder.0 *)ap.reorder.0_8 + 64B].flow; ++ */ ++ HOST_WIDE_INT offset_tmp = 0; ++ HOST_WIDE_INT mem_offset = 0; ++ bool realpart_tmp = false; ++ bool imagpart_tmp = false; ++ tree accesstype_tmp = NULL_TREE; ++ tree num = NULL_TREE; ++ get_ref_base_and_offset (expr, offset_tmp, ++ realpart_tmp, imagpart_tmp, ++ accesstype_tmp, &num); ++ ++ tree ptype = TREE_TYPE (newbase1); ++ /* Specify the correct size for the multi-layer pointer. */ ++ tree size = isptrptr (ptype) ? TYPE_SIZE_UNIT (ptype) : ++ TYPE_SIZE_UNIT (inner_type (ptype)); ++ mem_offset = (num != NULL) ++ ? TREE_INT_CST_LOW (num) * tree_to_shwi (size) ++ : 0; ++ newbase1 = build2 (MEM_REF, TREE_TYPE (ptype), newbase1, ++ build_int_cst (ptype, mem_offset)); ++ } ++ else ++ { ++ newbase1 = build_simple_mem_ref (newbase1); ++ } ++ } + newexpr[i] = build3 (COMPONENT_REF, TREE_TYPE (f->newfield[i]), + newbase1, f->newfield[i], NULL_TREE); + if (imagpart) +@@ -4162,8 +5725,12 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + return remove; + } + +- if (gimple_assign_rhs_code (stmt) == EQ_EXPR +- || gimple_assign_rhs_code (stmt) == NE_EXPR) ++ if ((current_mode != STRUCT_REORDER_FIELDS ++ && (gimple_assign_rhs_code (stmt) == EQ_EXPR ++ || gimple_assign_rhs_code (stmt) == NE_EXPR)) ++ || (current_mode == STRUCT_REORDER_FIELDS ++ && (TREE_CODE_CLASS (gimple_assign_rhs_code (stmt)) ++ == tcc_comparison))) + { + tree rhs1 = gimple_assign_rhs1 (stmt); + tree rhs2 = gimple_assign_rhs2 (stmt); +@@ -4171,6 +5738,12 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + tree newrhs2[max_split]; + tree_code rhs_code = gimple_assign_rhs_code (stmt); + tree_code code = rhs_code == EQ_EXPR ? BIT_AND_EXPR : BIT_IOR_EXPR; ++ if (current_mode == STRUCT_REORDER_FIELDS ++ && rhs_code != EQ_EXPR && rhs_code != NE_EXPR) ++ { ++ code = rhs_code; ++ } ++ + if (!rewrite_lhs_rhs (rhs1, rhs2, newrhs1, newrhs2)) + return false; + tree newexpr = NULL_TREE; +@@ -4208,19 +5781,88 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + if (!is_result_of_mult (rhs2, &num, size)) + internal_error ("the rhs of pointer was not a multiplicate and it slipped through."); + +- num = gimplify_build1 (gsi, NOP_EXPR, sizetype, num); ++ /* Add the judgment of num, support for POINTER_DIFF_EXPR. ++ _6 = _4 + _5; ++ _5 = (long unsigned int) _3; ++ _3 = _1 - old_2. */ ++ if (current_mode != STRUCT_REORDER_FIELDS ++ || (current_mode == STRUCT_REORDER_FIELDS && (num != NULL))) ++ { ++ num = gimplify_build1 (gsi, NOP_EXPR, sizetype, num); ++ } + for (unsigned i = 0; i < max_split && newlhs[i]; i++) + { + gimple *new_stmt; + +- tree newsize = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (newlhs[i]))); +- newsize = gimplify_build2 (gsi, MULT_EXPR, sizetype, num, newsize); +- new_stmt = gimple_build_assign (newlhs[i], POINTER_PLUS_EXPR, newrhs[i], newsize); ++ if (num != NULL) ++ { ++ tree newsize = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (newlhs[i]))); ++ newsize = gimplify_build2 (gsi, MULT_EXPR, sizetype, num, ++ newsize); ++ new_stmt = gimple_build_assign (newlhs[i], POINTER_PLUS_EXPR, ++ newrhs[i], newsize); ++ } ++ else ++ { ++ new_stmt = gimple_build_assign (newlhs[i], POINTER_PLUS_EXPR, ++ newrhs[i], rhs2); ++ } + gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT); + remove = true; + } + return remove; + } ++ ++ /* Support POINTER_DIFF_EXPR rewriting. */ ++ if (current_mode == STRUCT_REORDER_FIELDS ++ && gimple_assign_rhs_code (stmt) == POINTER_DIFF_EXPR) ++ { ++ tree rhs1 = gimple_assign_rhs1 (stmt); ++ tree rhs2 = gimple_assign_rhs2 (stmt); ++ tree newrhs1[max_split]; ++ tree newrhs2[max_split]; ++ ++ bool r1 = rewrite_expr (rhs1, newrhs1); ++ bool r2 = rewrite_expr (rhs2, newrhs2); ++ ++ if (r1 != r2) ++ { ++ /* Handle NULL pointer specially. */ ++ if (r1 && !r2 && integer_zerop (rhs2)) ++ { ++ r2 = true; ++ for (unsigned i = 0; i < max_split && newrhs1[i]; i++) ++ { ++ newrhs2[i] = fold_convert (TREE_TYPE (newrhs1[i]), rhs2); ++ } ++ } ++ else if (r2 && !r1 && integer_zerop (rhs1)) ++ { ++ r1 = true; ++ for (unsigned i = 0; i < max_split && newrhs2[i]; i++) ++ { ++ newrhs1[i] = fold_convert (TREE_TYPE (newrhs2[i]), rhs1); ++ } ++ } ++ else ++ { ++ return false; ++ } ++ } ++ else if (!r1 && !r2) ++ return false; ++ ++ /* The two operands always have pointer/reference type. */ ++ for (unsigned i = 0; i < max_split && newrhs1[i] && newrhs2[i]; i++) ++ { ++ gimple_assign_set_rhs1 (stmt, newrhs1[i]); ++ gimple_assign_set_rhs2 (stmt, newrhs2[i]); ++ update_stmt (stmt); ++ } ++ remove = false; ++ return remove; ++ } ++ + if (gimple_assign_rhs_class (stmt) == GIMPLE_SINGLE_RHS) + { + tree lhs = gimple_assign_lhs (stmt); +@@ -4228,21 +5870,20 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + + if (dump_file && (dump_flags & TDF_DETAILS)) + { +- fprintf (dump_file, "rewriting stamtenet:\n"); ++ fprintf (dump_file, "\nrewriting stamtenet:\n"); + print_gimple_stmt (dump_file, stmt, 0); +- fprintf (dump_file, "\n"); + } + tree newlhs[max_split]; + tree newrhs[max_split]; + if (!rewrite_lhs_rhs (lhs, rhs, newlhs, newrhs)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) +- fprintf (dump_file, "\nDid nothing to statement.\n"); ++ fprintf (dump_file, "Did nothing to statement.\n"); + return false; + } + + if (dump_file && (dump_flags & TDF_DETAILS)) +- fprintf (dump_file, "\nreplaced with:\n"); ++ fprintf (dump_file, "replaced with:\n"); + for (unsigned i = 0; i < max_split && (newlhs[i] || newrhs[i]); i++) + { + gimple *newstmt = gimple_build_assign (newlhs[i] ? newlhs[i] : lhs, newrhs[i] ? newrhs[i] : rhs); +@@ -4276,7 +5917,7 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi) + if (!decl || !decl->type) + return false; + srtype *type = decl->type; +- tree num = allocate_size (type, stmt); ++ tree num = allocate_size (type, decl, stmt); + gcc_assert (num); + memset (newrhs1, 0, sizeof(newrhs1)); + +@@ -4296,7 +5937,10 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi) + /* Go through each new lhs. */ + for (unsigned i = 0; i < max_split && decl->newdecl[i]; i++) + { +- tree newsize = TYPE_SIZE_UNIT (type->type); ++ /* Specify the correct size for the multi-layer pointer. */ ++ tree newsize = isptrptr (decl->orig_type) ++ ? TYPE_SIZE_UNIT (decl->orig_type) ++ : TYPE_SIZE_UNIT (type->newtype[i]); + gimple *g; + /* Every allocation except for calloc needs the size multiplied out. */ + if (!gimple_call_builtin_p (stmt, BUILT_IN_CALLOC)) +@@ -4356,6 +6000,25 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi) + gcc_assert (node); + srfunction *f = find_function (node); + ++ /* Add a safe func mechanism. */ ++ if (current_mode == STRUCT_REORDER_FIELDS && f && f->is_safe_func) ++ { ++ tree expr = gimple_call_arg (stmt, 0); ++ tree newexpr[max_split]; ++ if (!rewrite_expr (expr, newexpr)) ++ { ++ return false; ++ } ++ ++ if (newexpr[1] == NULL) ++ { ++ gimple_call_set_arg (stmt, 0, newexpr[0]); ++ update_stmt (stmt); ++ return false; ++ } ++ return false; ++ } ++ + /* Did not find the function or had not cloned it return saying don't + change the function call. */ + if (!f || !f->newf) +@@ -4440,7 +6103,7 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi) + && TREE_CODE (gimple_vdef (new_stmt)) == SSA_NAME) + SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt; + +- gsi_replace (gsi, new_stmt, false); ++ gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT); + + /* We need to defer cleaning EH info on the new statement to + fixup-cfg. We may not have dominator information at this point +@@ -4453,8 +6116,7 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi) + add_stmt_to_eh_lp (new_stmt, lp_nr); + } + +- +- return false; ++ return true; + } + + /* Rewrite the conditional statement STMT. Return TRUE if the +@@ -4466,48 +6128,58 @@ ipa_struct_reorg::rewrite_cond (gcond *stmt, gimple_stmt_iterator *gsi) + tree_code rhs_code = gimple_cond_code (stmt); + + /* Handle only equals or not equals conditionals. */ +- if (rhs_code != EQ_EXPR +- && rhs_code != NE_EXPR) ++ if ((current_mode != STRUCT_REORDER_FIELDS ++ && (rhs_code != EQ_EXPR && rhs_code != NE_EXPR)) ++ || (current_mode == STRUCT_REORDER_FIELDS ++ && TREE_CODE_CLASS (rhs_code) != tcc_comparison)) + return false; +- tree rhs1 = gimple_cond_lhs (stmt); +- tree rhs2 = gimple_cond_rhs (stmt); ++ tree lhs = gimple_cond_lhs (stmt); ++ tree rhs = gimple_cond_rhs (stmt); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { +- fprintf (dump_file, "COND: Rewriting\n"); ++ fprintf (dump_file, "\nCOND: Rewriting\n"); + print_gimple_stmt (dump_file, stmt, 0); ++ print_generic_expr (dump_file, lhs); + fprintf (dump_file, "\n"); +- print_generic_expr (dump_file, rhs1); +- fprintf (dump_file, "\n"); +- print_generic_expr (dump_file, rhs2); ++ print_generic_expr (dump_file, rhs); + fprintf (dump_file, "\n"); + } + +- tree newrhs1[max_split]; +- tree newrhs2[max_split]; +- tree_code code = rhs_code == EQ_EXPR ? BIT_AND_EXPR : BIT_IOR_EXPR; +- if (!rewrite_lhs_rhs (rhs1, rhs2, newrhs1, newrhs2)) ++ tree newlhs[max_split] = {}; ++ tree newrhs[max_split] = {}; ++ if (!rewrite_lhs_rhs (lhs, rhs, newlhs, newrhs)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) +- fprintf (dump_file, "\nDid nothing to statement.\n"); ++ { ++ fprintf (dump_file, "Did nothing to statement.\n"); ++ } + return false; + } + +- tree newexpr = NULL_TREE; +- for (unsigned i = 0; i < max_split && newrhs1[i]; i++) +- { +- tree expr = gimplify_build2 (gsi, rhs_code, boolean_type_node, newrhs1[i], newrhs2[i]); +- if (!newexpr) +- newexpr = expr; +- else +- newexpr = gimplify_build2 (gsi, code, boolean_type_node, newexpr, expr); +- } +- +- if (newexpr) ++ /* Old rewrite:if (x_1 != 0B) ++ -> _1 = x.reorder.0_1 != 0B; if (_1 != 1) ++ The logic is incorrect. ++ New rewrite:if (x_1 != 0B) ++ -> if (x.reorder.0_1 != 0B);*/ ++ for (unsigned i = 0; i < max_split && (newlhs[i] || newrhs[i]); i++) + { +- gimple_cond_set_lhs (stmt, newexpr); +- gimple_cond_set_rhs (stmt, boolean_true_node); ++ if (newlhs[i]) ++ { ++ gimple_cond_set_lhs (stmt, newlhs[i]); ++ } ++ if (newrhs[i]) ++ { ++ gimple_cond_set_rhs (stmt, newrhs[i]); ++ } + update_stmt (stmt); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "replaced with:\n"); ++ print_gimple_stmt (dump_file, stmt, 0); ++ fprintf (dump_file, "\n"); ++ } + } + return false; + } +@@ -4518,6 +6190,11 @@ ipa_struct_reorg::rewrite_cond (gcond *stmt, gimple_stmt_iterator *gsi) + bool + ipa_struct_reorg::rewrite_debug (gimple *stmt, gimple_stmt_iterator *) + { ++ if (current_mode == STRUCT_REORDER_FIELDS) ++ { ++ /* Delete debug gimple now. */ ++ return true; ++ } + bool remove = false; + if (gimple_debug_bind_p (stmt)) + { +@@ -4570,7 +6247,7 @@ ipa_struct_reorg::rewrite_phi (gphi *phi) + + if (dump_file && (dump_flags & TDF_DETAILS)) + { +- fprintf (dump_file, "\nrewriting PHI:"); ++ fprintf (dump_file, "\nrewriting PHI:\n"); + print_gimple_stmt (dump_file, phi, 0); + } + +@@ -4581,7 +6258,17 @@ ipa_struct_reorg::rewrite_phi (gphi *phi) + { + tree newrhs[max_split]; + phi_arg_d rhs = *gimple_phi_arg (phi, i); +- rewrite_expr (rhs.def, newrhs); ++ ++ /* Handling the NULL phi Node. */ ++ bool r = rewrite_expr (rhs.def, newrhs); ++ if (!r && integer_zerop (rhs.def)) ++ { ++ for (unsigned i = 0; i < max_split && newlhs[i]; i++) ++ { ++ newrhs[i] = fold_convert (TREE_TYPE (newlhs[i]), rhs.def); ++ } ++ } ++ + for (unsigned j = 0; j < max_split && newlhs[j]; j++) + { + SET_PHI_ARG_DEF (newphi[j], i, newrhs[j]); +@@ -4592,7 +6279,7 @@ ipa_struct_reorg::rewrite_phi (gphi *phi) + + if (dump_file && (dump_flags & TDF_DETAILS)) + { +- fprintf (dump_file, "\ninto\n:"); ++ fprintf (dump_file, "into:\n"); + for (unsigned i = 0; i < max_split && newlhs[i]; i++) + { + print_gimple_stmt (dump_file, newphi[i], 0); +@@ -4666,12 +6353,58 @@ ipa_struct_reorg::rewrite_functions (void) + /* Create new types, if we did not create any new types, + then don't rewrite any accesses. */ + if (!create_new_types ()) +- return 0; ++ { ++ if (current_mode == STRUCT_REORDER_FIELDS) ++ { ++ for (unsigned i = 0; i < functions.length (); i++) ++ { ++ srfunction *f = functions[i]; ++ cgraph_node *node = f->node; ++ push_cfun (DECL_STRUCT_FUNCTION (node->decl)); ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nNo rewrite:\n"); ++ dump_function_to_file (current_function_decl, dump_file, ++ dump_flags | TDF_VOPS); ++ } ++ pop_cfun (); ++ } ++ } ++ return 0; ++ } ++ ++ if (current_mode == STRUCT_REORDER_FIELDS && dump_file) ++ { ++ fprintf (dump_file, "=========== all created newtypes: ===========\n\n"); ++ dump_newtypes (dump_file); ++ } + + if (functions.length ()) + { + retval = TODO_remove_functions; + create_new_functions (); ++ if (current_mode == STRUCT_REORDER_FIELDS) ++ { ++ prune_escaped_types (); ++ } ++ } ++ ++ if (current_mode == STRUCT_REORDER_FIELDS) ++ { ++ for (unsigned i = 0; i < functions.length (); i++) ++ { ++ srfunction *f = functions[i]; ++ cgraph_node *node = f->node; ++ push_cfun (DECL_STRUCT_FUNCTION (node->decl)); ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "==== Before create decls: %dth_%s ====\n\n", ++ i, f->node->name ()); ++ dump_function_to_file (current_function_decl, dump_file, ++ dump_flags | TDF_VOPS); ++ } ++ pop_cfun (); ++ } + } + + create_new_decls (); +@@ -4694,8 +6427,12 @@ ipa_struct_reorg::rewrite_functions (void) + + if (dump_file && (dump_flags & TDF_DETAILS)) + { +- fprintf (dump_file, "\nBefore rewrite:\n"); +- dump_function_to_file (current_function_decl, dump_file, dump_flags | TDF_VOPS); ++ fprintf (dump_file, "\nBefore rewrite: %dth_%s\n", ++ i, f->node->name ()); ++ dump_function_to_file (current_function_decl, dump_file, ++ dump_flags | TDF_VOPS); ++ fprintf (dump_file, "\n======== Start to rewrite: %dth_%s ========\n", ++ i, f->node->name ()); + } + FOR_EACH_BB_FN (bb, cfun) + { +@@ -4763,10 +6500,12 @@ ipa_struct_reorg::rewrite_functions (void) + + free_dominance_info (CDI_DOMINATORS); + +- if (dump_file && (dump_flags & TDF_DETAILS)) ++ if (dump_file) + { +- fprintf (dump_file, "\nAfter rewrite:\n"); +- dump_function_to_file (current_function_decl, dump_file, dump_flags | TDF_VOPS); ++ fprintf (dump_file, "\nAfter rewrite: %dth_%s\n", ++ i, f->node->name ()); ++ dump_function_to_file (current_function_decl, dump_file, ++ dump_flags | TDF_VOPS); + } + + pop_cfun (); +@@ -4820,9 +6559,9 @@ ipa_struct_reorg::execute (enum srmode mode) + { + unsigned int ret = 0; + +- if (mode == NORMAL) ++ if (mode == NORMAL || mode == STRUCT_REORDER_FIELDS) + { +- current_mode = NORMAL; ++ current_mode = mode; + /* If there is a top-level inline-asm, + the pass immediately returns. */ + if (symtab->first_asm_symbol ()) +@@ -4831,7 +6570,10 @@ ipa_struct_reorg::execute (enum srmode mode) + } + record_accesses (); + prune_escaped_types (); +- analyze_types (); ++ if (current_mode == NORMAL) ++ { ++ analyze_types (); ++ } + + ret = rewrite_functions (); + } +@@ -4903,6 +6645,47 @@ pass_ipa_struct_reorg::gate (function *) + && lang_c_p ()); + } + ++const pass_data pass_data_ipa_reorder_fields = ++{ ++ SIMPLE_IPA_PASS, // type ++ "reorder_fields", // name ++ OPTGROUP_NONE, // optinfo_flags ++ TV_IPA_REORDER_FIELDS, // tv_id ++ 0, // properties_required ++ 0, // properties_provided ++ 0, // properties_destroyed ++ 0, // todo_flags_start ++ 0, // todo_flags_finish ++}; ++ ++class pass_ipa_reorder_fields : public simple_ipa_opt_pass ++{ ++public: ++ pass_ipa_reorder_fields (gcc::context *ctxt) ++ : simple_ipa_opt_pass (pass_data_ipa_reorder_fields, ctxt) ++ {} ++ ++ /* opt_pass methods: */ ++ virtual bool gate (function *); ++ virtual unsigned int execute (function *) ++ { ++ unsigned int ret = 0; ++ ret = ipa_struct_reorg ().execute (STRUCT_REORDER_FIELDS); ++ return ret; ++ } ++ ++}; // class pass_ipa_reorder_fields ++ ++bool ++pass_ipa_reorder_fields::gate (function *) ++{ ++ return (optimize >= 3 ++ && flag_ipa_reorder_fields ++ /* Don't bother doing anything if the program has errors. */ ++ && !seen_error () ++ && flag_lto_partition == LTO_PARTITION_ONE); ++} ++ + } // anon namespace + + simple_ipa_opt_pass * +@@ -4910,3 +6693,9 @@ make_pass_ipa_struct_reorg (gcc::context *ctxt) + { + return new pass_ipa_struct_reorg (ctxt); + } ++ ++simple_ipa_opt_pass * ++make_pass_ipa_reorder_fields (gcc::context *ctxt) ++{ ++ return new pass_ipa_reorder_fields (ctxt); ++} +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.h b/gcc/ipa-struct-reorg/ipa-struct-reorg.h +index d8fe399bdf8..8fb6ce9c448 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.h ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.h +@@ -68,12 +68,14 @@ struct srfunction + auto_vec<srdecl*> args; + auto_vec<srdecl*> globals; + auto_vec_del<srdecl> decls; +- srdecl *record_decl (srtype *, tree, int arg); ++ srdecl *record_decl (srtype *, tree, int arg, tree orig_type = NULL); + + srfunction *old; + cgraph_node *newnode; + srfunction *newf; + ++ bool is_safe_func; ++ + // Constructors + srfunction (cgraph_node *n); + +@@ -183,6 +185,11 @@ struct srfield + void create_new_fields (tree newtype[max_split], + tree newfields[max_split], + tree newlast[max_split]); ++ void reorder_fields (tree newfields[max_split], tree newlast[max_split], ++ tree &field); ++ void create_new_reorder_fields (tree newtype[max_split], ++ tree newfields[max_split], ++ tree newlast[max_split]); + }; + + struct sraccess +@@ -219,8 +226,11 @@ struct srdecl + + tree newdecl[max_split]; + ++ /* Auxiliary record complete original type information of the void* type. */ ++ tree orig_type; ++ + // Constructors +- srdecl (srtype *type, tree decl, int argumentnum = -1); ++ srdecl (srtype *type, tree decl, int argumentnum = -1, tree orgtype = NULL); + + // Methods + void dump (FILE *file); +diff --git a/gcc/passes.def b/gcc/passes.def +index fa744e25038..63303ab65bb 100644 +--- a/gcc/passes.def ++++ b/gcc/passes.def +@@ -173,6 +173,7 @@ along with GCC; see the file COPYING3. If not see + INSERT_PASSES_AFTER (all_late_ipa_passes) + NEXT_PASS (pass_materialize_all_clones); + NEXT_PASS (pass_ipa_pta); ++ NEXT_PASS (pass_ipa_reorder_fields); + /* FIXME: this should a normal IP pass */ + NEXT_PASS (pass_ipa_struct_reorg); + NEXT_PASS (pass_omp_simd_clone); +diff --git a/gcc/testsuite/gcc.dg/struct/rf_DTE_struct_instance_field.c b/gcc/testsuite/gcc.dg/struct/rf_DTE_struct_instance_field.c +new file mode 100644 +index 00000000000..b95be2dabc2 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_DTE_struct_instance_field.c +@@ -0,0 +1,75 @@ ++// escape_instance_field, "Type escapes via a field of instance". ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++typedef struct network ++{ ++ arc_p arcs; ++ arc_p sorted_arcs; ++ int x; ++ node_p nodes; ++ node_p stop_nodes; ++ node_t node; ++} network_t; ++ ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++ network_t* net_add; ++ node_t node; ++}; ++ ++ ++const int MAX = 100; ++ ++/* let it escape_array, "Type is used in an array [not handled yet]". */ ++network_t* net[2]; ++ ++int ++main () ++{ ++ net[0] = (network_t*) calloc (1, sizeof(network_t)); ++ net[0]->arcs = (arc_p) calloc (MAX, sizeof (arc_t)); ++ ++ /* Contains an escape type and has structure instance field. */ ++ net[0]->arcs->node = net[0]->node; ++ ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "No structures to transform." "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c b/gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c +new file mode 100644 +index 00000000000..3d243313ba9 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c +@@ -0,0 +1,94 @@ ++// Verify in escape_dependent_type_escapes, ++// the multi-layer dereference is rewriting correctly,and the memory access ++// is correct. ++ ++// release ++// escape_dependent_type_escapes, ++// "Type uses a type which escapes or is used by a type which escapes" ++// avoid escape_cast_another_ptr, "Type escapes a cast to a different pointer" ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++typedef struct network ++{ ++ arc_p arcs; ++ arc_p sorted_arcs; ++ int x; ++ node_p nodes; ++ node_p stop_nodes; ++} network_t; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++ network_t* net_add; ++}; ++ ++ ++const int MAX = 100; ++ ++/* let it escape_array, "Type is used in an array [not handled yet]". */ ++network_t* net[2]; ++arc_p stop_arcs = NULL; ++ ++int ++main () ++{ ++ net[0] = (network_t*) calloc (1, sizeof(network_t)); ++ net[0]->arcs = (arc_p) calloc (MAX, sizeof (arc_t)); ++ stop_arcs = (arc_p) calloc (MAX, sizeof (arc_t)); ++ ++ net[0]->arcs->id = 100; ++ ++ for (unsigned i = 0; i < 3; i++) ++ { ++ net[0]->arcs->id = net[0]->arcs->id + 2; ++ stop_arcs->cost = net[0]->arcs->id / 2; ++ stop_arcs->net_add = net[0]; ++ printf("stop_arcs->cost = %ld\n", stop_arcs->cost); ++ net[0]->arcs++; ++ stop_arcs++; ++ } ++ ++ if( net[1] != 0 && stop_arcs != 0) ++ { ++ return -1; ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_create_fields_bug.c b/gcc/testsuite/gcc.dg/struct/rf_create_fields_bug.c +new file mode 100644 +index 00000000000..886706ae913 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_create_fields_bug.c +@@ -0,0 +1,82 @@ ++// bugfix: ++// Common members do not need to reconstruct. ++// Otherwise, eg:int* -> int** and void* -> void**. ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <assert.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t* cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t** org_cost; ++}; ++ ++struct a ++{ ++ int t; ++ int t1; ++}; ++ ++__attribute__((noinline)) int ++f(int i, int j) ++{ ++ struct a *t = NULL; ++ struct a t1 = {i, j}; ++ t = &t1; ++ auto int g(void) __attribute__((noinline)); ++ int g(void) ++ { ++ return t->t + t->t1; ++ } ++ return g(); ++} ++ ++arc_t **ap = NULL; ++const int MAX = 100; ++ ++int ++main() ++{ ++ if (f(1, 2) != 3) ++ { ++ abort (); ++ } ++ ap = (arc_t**) malloc(MAX * sizeof(arc_t*)); ++ (*ap)[0].id = 300; ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_create_new_func_bug.c b/gcc/testsuite/gcc.dg/struct/rf_create_new_func_bug.c +new file mode 100644 +index 00000000000..f3785f392e3 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_create_new_func_bug.c +@@ -0,0 +1,56 @@ ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++#define MallocOrDie(x) sre_malloc((x)) ++ ++struct gki_elem { ++ char *key; ++ int idx; ++ struct gki_elem *nxt; ++}; ++ ++typedef struct { ++ struct gki_elem **table; ++ ++ int primelevel; ++ int nhash; ++ int nkeys; ++} GKI; ++ ++void ++Die(char *format, ...) ++{ ++ exit(1); ++} ++ ++void * ++sre_malloc(size_t size) ++{ ++ void *ptr; ++ ++ if ((ptr = malloc (size)) == NULL) ++ { ++ Die("malloc of %ld bytes failed", size); ++ } ++ return ptr; ++} ++ ++ ++__attribute__((noinline)) int ++GKIStoreKey(GKI *hash, char *key) ++{ ++ hash->table[0] = MallocOrDie(sizeof(struct gki_elem)); ++} ++ ++int ++main () ++{ ++ GKI *hash; ++ char *key; ++ GKIStoreKey(hash, key); ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_ele_minus_verify.c b/gcc/testsuite/gcc.dg/struct/rf_ele_minus_verify.c +new file mode 100644 +index 00000000000..1415d759ad6 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_ele_minus_verify.c +@@ -0,0 +1,60 @@ ++// verify newarc[cmp-1].flow ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++}; ++ ++const int MAX = 100; ++arc_p ap = NULL; ++ ++int ++main () ++{ ++ ap = (arc_p) calloc(MAX, sizeof(arc_t)); ++ printf("%d\n", ap[0].id); ++ for (int i = 1; i < MAX; i++) ++ { ++ ap[i-1].id = 500; ++ } ++ printf("%d\n", ap[0].id); ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_escape_by_base.c b/gcc/testsuite/gcc.dg/struct/rf_escape_by_base.c +new file mode 100644 +index 00000000000..003da0b57bf +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_escape_by_base.c +@@ -0,0 +1,83 @@ ++// release type is used by a type which escapes. ++// avoid escape_cast_another_ptr, "Type escapes a cast to a different pointer" ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++typedef struct network ++{ ++ arc_p arcs; ++ arc_p sorted_arcs; ++ int x; ++ node_p nodes; ++ node_p stop_nodes; ++} network_t; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++}; ++ ++const int MAX = 100; ++network_t* net = NULL; ++arc_p stop_arcs = NULL; ++int cnt = 0; ++ ++int ++main () ++{ ++ net = (network_t*) calloc (1, 20); ++ net->arcs = (arc_p) calloc (MAX, sizeof (arc_t)); ++ stop_arcs = (arc_p) calloc (MAX, sizeof (arc_t)); ++ if(!(net->arcs)) ++ { ++ return -1; ++ } ++ ++ for( int i = 0; i < MAX; i++, net->arcs = stop_arcs) ++ { ++ cnt++; ++ } ++ ++ net = (network_t*) calloc (1, 20); ++ if( !(net->arcs) ) ++ { ++ return -1; ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c b/gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c +new file mode 100644 +index 00000000000..10dcf098c3c +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c +@@ -0,0 +1,72 @@ ++// release escape_cast_another_ptr, "Type escapes a cast to a different pointer" ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++}; ++ ++typedef int cmp_t(const void *, const void *); ++ ++__attribute__((noinline)) void ++spec_qsort(void *a, cmp_t *cmp) ++{ ++ char *pb = NULL; ++ while (cmp(pb, a)) ++ { ++ pb += 1; ++ } ++} ++ ++static int arc_compare( arc_t **a1, int a2 ) ++{ ++ if( (*a1)->id < a2 ) ++ { ++ return -1; ++ } ++ return 1; ++} ++ ++int ++main() ++{ ++ spec_qsort(NULL, (int (*)(const void *, const void *))arc_compare); ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_mem_ref_offset.c b/gcc/testsuite/gcc.dg/struct/rf_mem_ref_offset.c +new file mode 100644 +index 00000000000..8d1a9a114c1 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_mem_ref_offset.c +@@ -0,0 +1,58 @@ ++/* Supports the MEM_REF offset. ++ _1 = MEM[(struct arc *)ap_4 + 72B].flow; ++ Old rewrite:_1 = ap.reorder.0_8->flow; ++ New rewrite:_1 = MEM[(struct arc.reorder.0 *)ap.reorder.0_8 + 64B].flow. */ ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++}; ++ ++int ++main () ++{ ++ const int MAX = 100; ++ /* A similar scenario can be reproduced only by using local variables. */ ++ arc_p ap = NULL; ++ ap = (arc_p) calloc(MAX, sizeof(arc_t)); ++ printf("%d\n", ap[1].flow); ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c b/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c +new file mode 100644 +index 00000000000..8d687c58b30 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c +@@ -0,0 +1,110 @@ ++// 针对 ++/* ++Compile options: /home/hxq/hcc_gcc9.3.0_org_debug/bin/gcc -O3 -g ++-flto -flto-partition=one -fipa-reorder-fields -fipa-struct-reorg ++-v -save-temps -fdump-ipa-all-details test.c -o test ++ ++in COMPLETE_STRUCT_RELAYOUT pass: ++N type: struct node.reorder.0 new = "Type escapes a cast to a different pointer" ++copy$head_26 = test_arc.reorder.0_49->head; ++ ++type : struct arc.reorder.0(1599) { ++fields = { ++field (5382) {type = cost_t} ++field (5383) {type = struct node.reorder.0 *} // but node has escaped. ++field (5384) {type = struct node.reorder.0 *} ++field (5386) {type = struct arc.reorder.0 *} ++field (5387) {type = struct arc.reorder.0 *} ++field (5388) {type = flow_t} ++field (5389) {type = cost_t} ++field (5381) {type = int} ++field (5385) {type = short int} ++} ++ ++// The types of the two types are inconsistent after the rewriting. ++newarc_2(D)->tail = tail_1(D); ++vs ++struct_reorder.0_61(D)->tail = tail_1(D); ++*/ ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++typedef struct network ++{ ++ arc_p arcs; ++ arc_p sorted_arcs; ++ int x; ++ node_p nodes; ++ node_p stop_nodes; ++} network_t; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++}; ++ ++__attribute__((noinline)) void ++replace_weaker_arc( arc_t *newarc, node_t *tail, node_t *head) ++{ ++ printf("test"); ++} ++ ++__attribute__((noinline)) int64_t ++switch_arcs(arc_t** deleted_arcs, arc_t* arcnew) ++{ ++ int64_t count = 0; ++ arc_t *test_arc, copy; ++ ++ if (!test_arc->ident) ++ { ++ copy = *test_arc; ++ count++; ++ *test_arc = arcnew[0]; ++ replace_weaker_arc(arcnew, copy.tail, copy.head); ++ } ++ return count; ++} ++ ++ ++int ++main () ++{ ++ switch_arcs(NULL, NULL); ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c b/gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c +new file mode 100644 +index 00000000000..190b9418275 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c +@@ -0,0 +1,87 @@ ++// escape_cast_void, "Type escapes a cast to/from void*" ++// stop_393 = net.stop_nodes; void *stop; ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++typedef struct network ++{ ++ arc_p arcs, sorted_arcs; ++ int x; ++ node_p nodes, stop_nodes; ++} network_t; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++}; ++ ++const int MAX = 100; ++network_t* net = NULL; ++int cnt = 0; ++ ++__attribute__((noinline)) int ++primal_feasible (network_t *net) ++{ ++ void* stop; ++ node_t *node; ++ ++ node = net->nodes; ++ stop = (void *)net->stop_nodes; ++ for( node++; node < (node_t *)stop; node++ ) ++ { ++ printf( "PRIMAL NETWORK SIMPLEX: " ); ++ } ++ return 0; ++} ++ ++int ++main () ++{ ++ net = (network_t*) calloc (1, 20); ++ net->nodes = calloc (MAX, sizeof (node_t)); ++ net->stop_nodes = calloc (MAX, sizeof (node_t)); ++ cnt = primal_feasible( net ); ++ ++ net = (network_t*) calloc (1, 20); ++ if( !(net->arcs) ) ++ { ++ return -1; ++ } ++ return cnt; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c +new file mode 100644 +index 00000000000..3a3c10b70ba +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c +@@ -0,0 +1,71 @@ ++// support POINTER_DIFF_EXPR & NOP_EXPR to avoid ++// escape_unhandled_rewrite, "Type escapes via a unhandled rewrite stmt" ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++typedef struct network ++{ ++ arc_p arcs; ++ arc_p sorted_arcs; ++ int x; ++ node_p nodes; ++ node_p stop_nodes; ++} network_t; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++}; ++ ++int ++main () ++{ ++ arc_t *old_arcs; ++ node_t *node; ++ node_t *stop; ++ size_t off; ++ network_t* net; ++ ++ for( ; node->number < stop->number; node++ ) ++ { ++ off = node->basic_arc - old_arcs; ++ node->basic_arc = (arc_t *)(net->arcs + off); ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 3" "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_negate_expr.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_negate_expr.c +new file mode 100644 +index 00000000000..7b7d110df4c +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_negate_expr.c +@@ -0,0 +1,55 @@ ++// support NEGATE_EXPR rewriting ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++}; ++ ++int ++main () ++{ ++ int64_t susp = 0; ++ const int MAX = 100; ++ arc_p ap = (arc_p) calloc(MAX, sizeof(arc_t)); ++ ap -= susp; ++ printf("%d\n", ap[1].flow); ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c +new file mode 100644 +index 00000000000..01a33f66962 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c +@@ -0,0 +1,55 @@ ++// release escape_ptr_ptr, "Type is used in a pointer to a pointer [not handled yet]"; ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++}; ++ ++const int MAX = 100; ++arc_t **ap = NULL; ++ ++int ++main () ++{ ++ ap = (arc_t**) malloc(MAX * sizeof(arc_t*)); ++ (*ap)[0].id = 300; ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c +new file mode 100644 +index 00000000000..a38556533f1 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c +@@ -0,0 +1,58 @@ ++// release escape_ptr_ptr, "Type is used in a pointer to a pointer [not handled yet]" ++ ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++}; ++ ++const int MAX = 100; ++arc_p **ap; ++ ++ ++int ++main () ++{ ++ ap = (arc_p**) calloc(MAX, sizeof(arc_p*)); ++ (**ap)[0].id = 500; ++ ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_rescusive_type.c b/gcc/testsuite/gcc.dg/struct/rf_rescusive_type.c +new file mode 100644 +index 00000000000..5c17ee528c8 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_rescusive_type.c +@@ -0,0 +1,57 @@ ++// release escape_rescusive_type, "Recusive type" ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++}; ++ ++const int MAX = 100; ++arc_p ap = NULL; ++ ++int ++main () ++{ ++ ap = (arc_p) calloc (MAX, sizeof (arc_t)); ++ ap[0].id = 100; ++ ap[0].head = (node_p) calloc (MAX, sizeof (node_t)); ++ ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_rewrite_assign_more_cmp.c b/gcc/testsuite/gcc.dg/struct/rf_rewrite_assign_more_cmp.c +new file mode 100644 +index 00000000000..710517ee9e2 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_rewrite_assign_more_cmp.c +@@ -0,0 +1,65 @@ ++// support more gimple assign rhs code ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++}; ++ ++__attribute__((noinline)) int ++compare(arc_p p1, arc_p p2) ++{ ++ return p1 < p2; ++} ++ ++int n = 0; ++int m = 0; ++ ++int ++main () ++{ ++ scanf ("%d %d", &n, &m); ++ arc_p p = calloc (10, sizeof (struct arc)); ++ if (compare (&p[n], &p[m])) ++ { ++ printf ("ss!"); ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_bug.c b/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_bug.c +new file mode 100644 +index 00000000000..6ed0a5d2d6b +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_bug.c +@@ -0,0 +1,72 @@ ++// rewrite_cond bugfix; ++/* ++if (iterator_600 != 0B) ++old rewrite: _1369 = iterator.reorder.0_1249 != 0B; if (_1369 != 1) ++new rewrite: if (iterator.reorder.0_1249 != 0B) ++*/ ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++typedef struct list_elem ++{ ++ arc_t* arc; ++ struct list_elem* next; ++}list_elem; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++}; ++ ++int i = 0; ++ ++int ++main () ++{ ++ register list_elem *first_list_elem; ++ register list_elem* iterator; ++ iterator = first_list_elem->next; ++ while (iterator) ++ { ++ iterator = iterator->next; ++ i++; ++ } ++ ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 3" "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_more_cmp.c b/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_more_cmp.c +new file mode 100644 +index 00000000000..5a2dd964fc2 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_more_cmp.c +@@ -0,0 +1,58 @@ ++// support if (_150 >= _154) ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++}; ++ ++int ++main() ++{ ++ arc_p **ap = (arc_p**) malloc(1 * sizeof(arc_p*)); ++ arc_p **arcs_pointer_sorted = (arc_p**) malloc(1 * sizeof(arc_p*)); ++ arcs_pointer_sorted[0] = (arc_p*) calloc (1, sizeof(arc_p)); ++ ++ if (arcs_pointer_sorted >= ap) ++ { ++ return -1; ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_rewrite_phi_bug.c b/gcc/testsuite/gcc.dg/struct/rf_rewrite_phi_bug.c +new file mode 100644 +index 00000000000..faa90b42ddc +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_rewrite_phi_bug.c +@@ -0,0 +1,81 @@ ++/* ++Exclude the rewriting error caused by ++first_list_elem = (list_elem *)NULL; ++rewriting PHI:first_list_elem_700 = PHI <0B(144), 0B(146)> ++into: ++first_list_elem.reorder.0_55 = PHI <(144), (146)> ++*/ ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++typedef struct list_elem ++{ ++ arc_t* arc; ++ struct list_elem* next; ++}list_elem; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout, firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail, head; ++ short ident; ++ arc_p nextout, nextin; ++ int64_t flow; ++ int64_t org_cost; ++}; ++ ++const int MAX = 100; ++ ++list_elem* new_list_elem; ++list_elem* first_list_elem; ++ ++int ++main () ++{ ++ int i = 0; ++ list_elem *first_list_elem; ++ list_elem *new_list_elem; ++ arc_t *arcout; ++ for( ; i < MAX && arcout->ident == -1; i++); ++ ++ first_list_elem = (list_elem *)NULL; ++ for( ; i < MAX; i++) ++ { ++ new_list_elem = (list_elem*) calloc(1, sizeof(list_elem)); ++ new_list_elem->next = first_list_elem; ++ first_list_elem = new_list_elem; ++ } ++ if (first_list_elem != 0) ++ { ++ return -1; ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 3" "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_shwi.c b/gcc/testsuite/gcc.dg/struct/rf_shwi.c +new file mode 100644 +index 00000000000..2bb326ff200 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_shwi.c +@@ -0,0 +1,23 @@ ++/* { dg-do compile } */ ++ ++struct foo {int dx; long dy; int dz; }; ++struct goo {long offset; struct foo* pfoo; }; ++ ++void* func (long); ++ ++__attribute__((used)) static void ++test(struct goo* g) ++{ ++ void* pvoid; ++ struct foo* f; ++ ++ for (f = g->pfoo; f->dx; f++) ++ { ++ if (f->dy) ++ break; ++ } ++ f--; ++ ++ pvoid = func(f->dz + g->offset); ++ return; ++} +diff --git a/gcc/testsuite/gcc.dg/struct/rf_visible_func.c b/gcc/testsuite/gcc.dg/struct/rf_visible_func.c +new file mode 100644 +index 00000000000..8f2da99ccdf +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_visible_func.c +@@ -0,0 +1,92 @@ ++// release escape_visible_function, "Type escapes via expternally visible function call" ++// compile options: gcc -O3 -fno-inline -fwhole-program ++// -flto-partition=one -fipa-struct-reorg arc_compare.c -fdump-ipa-all -S -v ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++}; ++ ++__attribute__((noinline)) static int ++arc_compare( arc_t **a1, arc_t **a2 ) ++{ ++ if( (*a1)->flow > (*a2)->flow ) ++ { ++ return 1; ++ } ++ if( (*a1)->flow < (*a2)->flow ) ++ { ++ return -1; ++ } ++ if( (*a1)->id < (*a2)->id ) ++ { ++ return -1; ++ } ++ ++ return 1; ++} ++ ++__attribute__((noinline)) void ++spec_qsort(void *array, int nitems, int size, ++ int (*cmp)(const void*,const void*)) ++{ ++ for (int i = 0; i < nitems - 1; i++) ++ { ++ if (cmp (array , array)) ++ { ++ printf ("CMP 1\n"); ++ } ++ else ++ { ++ printf ("CMP 2\n"); ++ } ++ } ++} ++ ++typedef int cmp_t(const void *, const void *); ++ ++int ++main () ++{ ++ void *p = calloc (100, sizeof (arc_t **)); ++ spec_qsort (p, 100, 0, (int (*)(const void *, const void *))arc_compare); ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_void_ptr_param_func.c b/gcc/testsuite/gcc.dg/struct/rf_void_ptr_param_func.c +new file mode 100644 +index 00000000000..723142c5975 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_void_ptr_param_func.c +@@ -0,0 +1,54 @@ ++// Add a safe func mechanism. ++// avoid escape_unkown_field, "Type escapes via an unkown field accessed" ++// avoid escape_cast_void, "Type escapes a cast to/from void*" eg: GIMPLE_NOP ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++}; ++ ++void ++__attribute__((noinline)) spec_qsort (void *a, size_t es) ++{ ++ char *pa; ++ char *pb; ++ int cmp_result; ++ ++ while ((*(arc_t **)a)->id < *((int *)a)) ++ { ++ if (cmp_result == 0) ++ { ++ spec_qsort (a, es); ++ pa = (char *)a - es; ++ a += es; ++ *(long *)pb = *(long *)pa; ++ } ++ else ++ { ++ a -= pa - pb; ++ } ++ } ++} ++ ++int ++main() ++{ ++ arc_p **arcs_pointer_sorted; ++ spec_qsort (arcs_pointer_sorted[0], sizeof (arc_p)); ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp +index 1bd0e18ea2e..c8db4675f11 100644 +--- a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp ++++ b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp +@@ -27,8 +27,25 @@ set STRUCT_REORG_TORTURE_OPTIONS [list \ + + set-torture-options $STRUCT_REORG_TORTURE_OPTIONS {{}} + +-gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] \ ++# -fipa-struct-reorg ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/wo_prof_*.c]] \ ++ "" "-fipa-struct-reorg -fdump-ipa-all -flto-partition=one -fwhole-program" ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/w_ratio_*.c]] \ + "" "-fipa-struct-reorg -fdump-ipa-all -flto-partition=one -fwhole-program" ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/w_prof_*.c]] \ ++ "" "-fipa-struct-reorg -fdump-ipa-all -flto-partition=one -fwhole-program" ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/struct_reorg*.c]] \ ++ "" "-fipa-struct-reorg -fdump-ipa-all -flto-partition=one -fwhole-program" ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/sr_*.c]] \ ++ "" "-fipa-struct-reorg -fdump-ipa-all -flto-partition=one -fwhole-program" ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/csr_*.c]] \ ++ "" "-fipa-struct-reorg -fdump-ipa-all -flto-partition=one -fwhole-program" ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/complete_struct_relayout.c]] \ ++ "" "-fipa-struct-reorg -fdump-ipa-all -flto-partition=one -fwhole-program" ++ ++# -fipa-reorder-fields ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/rf*.c]] \ ++ "" "-fipa-reorder-fields -fdump-ipa-all -flto-partition=one -fwhole-program" + + # All done. + torture-finish +diff --git a/gcc/timevar.def b/gcc/timevar.def +index d6a05562c2f..ee25eccbb67 100644 +--- a/gcc/timevar.def ++++ b/gcc/timevar.def +@@ -80,6 +80,7 @@ DEFTIMEVAR (TV_IPA_CONSTANT_PROP , "ipa cp") + DEFTIMEVAR (TV_IPA_INLINING , "ipa inlining heuristics") + DEFTIMEVAR (TV_IPA_FNSPLIT , "ipa function splitting") + DEFTIMEVAR (TV_IPA_COMDATS , "ipa comdats") ++DEFTIMEVAR (TV_IPA_REORDER_FIELDS , "ipa struct reorder fields optimization") + DEFTIMEVAR (TV_IPA_STRUCT_REORG , "ipa struct reorg optimization") + DEFTIMEVAR (TV_IPA_OPT , "ipa various optimizations") + DEFTIMEVAR (TV_IPA_LTO_DECOMPRESS , "lto stream decompression") +diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h +index d8355754ffa..eb32c5d441b 100644 +--- a/gcc/tree-pass.h ++++ b/gcc/tree-pass.h +@@ -509,6 +509,7 @@ extern ipa_opt_pass_d *make_pass_ipa_odr (gcc::context *ctxt); + extern ipa_opt_pass_d *make_pass_ipa_reference (gcc::context *ctxt); + extern ipa_opt_pass_d *make_pass_ipa_hsa (gcc::context *ctxt); + extern ipa_opt_pass_d *make_pass_ipa_pure_const (gcc::context *ctxt); ++extern simple_ipa_opt_pass *make_pass_ipa_reorder_fields (gcc::context *ctxt); + extern simple_ipa_opt_pass *make_pass_ipa_struct_reorg (gcc::context *ctxt); + extern simple_ipa_opt_pass *make_pass_ipa_pta (gcc::context *ctxt); + extern simple_ipa_opt_pass *make_pass_ipa_tm (gcc::context *ctxt); +-- +2.21.0.windows.1 + diff --git a/0019-StructReorderFields-Fix-bugs-and-improve-mechanism.patch b/0019-StructReorderFields-Fix-bugs-and-improve-mechanism.patch new file mode 100644 index 0000000..b5370ff --- /dev/null +++ b/0019-StructReorderFields-Fix-bugs-and-improve-mechanism.patch @@ -0,0 +1,296 @@ +From 5392e41dcb7d58a80f2864b3c3f600c538fba799 Mon Sep 17 00:00:00 2001 +From: huangxiaoquan <huangxiaoquan1@huawei.com> +Date: Wed, 4 Aug 2021 14:21:08 +0800 +Subject: [PATCH 19/22] [StructReorderFields] Fix bugs and improve mechanism + +Fix bugs and improve mechanism: + +1. Fixed a bug in multi-layer pointer recording. +2. Use new to initialize allocated memory in symbol-summary.h. +3. Only enable optimizations in C language. + +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +index 384aa81583c..fe364f742d8 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -173,31 +173,30 @@ lang_c_p (void) + return false; + } + +- if (strcmp (language_string, "GNU GIMPLE") == 0) ++ if (lang_GNU_C ()) ++ { ++ return true; ++ } ++ else if (strcmp (language_string, "GNU GIMPLE") == 0) // for LTO check + { + unsigned i = 0; +- tree t = NULL; +- const char *unit_string = NULL; ++ tree t = NULL_TREE; + + FOR_EACH_VEC_SAFE_ELT (all_translation_units, i, t) + { +- unit_string = TRANSLATION_UNIT_LANGUAGE (t); +- if (!unit_string +- || (strncmp (unit_string, "GNU C", 5) != 0) +- || (!ISDIGIT (unit_string[5]))) ++ language_string = TRANSLATION_UNIT_LANGUAGE (t); ++ if (language_string == NULL ++ || strncmp (language_string, "GNU C", 5) ++ || (language_string[5] != '\0' ++ && !(ISDIGIT (language_string[5])))) + { + return false; + } + } + return true; + } +- else if (strncmp (language_string, "GNU C", 5) == 0 +- && ISDIGIT (language_string[5])) +- { +- return true; +- } +- + return false; ++} + + /* Get the number of pointer layers. */ + +@@ -1262,7 +1261,7 @@ public: + void check_uses (srdecl *decl, vec<srdecl*>&); + void check_use (srdecl *decl, gimple *stmt, vec<srdecl*>&); + void check_type_and_push (tree newdecl, srdecl *decl, +- vec<srdecl*> &worklist, gimple *stmt); ++ vec<srdecl*> &worklist, gimple *stmt); + void check_other_side (srdecl *decl, tree other, gimple *stmt, vec<srdecl*> &worklist); + void check_ptr_layers (tree a_expr, tree b_expr, gimple* stmt); + +@@ -3010,11 +3009,9 @@ ipa_struct_reorg::find_var (tree expr, gimple *stmt) + { + tree r = TREE_OPERAND (expr, 0); + tree orig_type = TREE_TYPE (expr); +- if (handled_component_p (r) +- || TREE_CODE (r) == MEM_REF) ++ if (handled_component_p (r) || TREE_CODE (r) == MEM_REF) + { +- while (handled_component_p (r) +- || TREE_CODE (r) == MEM_REF) ++ while (handled_component_p (r) || TREE_CODE (r) == MEM_REF) + { + if (TREE_CODE (r) == VIEW_CONVERT_EXPR) + { +@@ -3092,10 +3089,12 @@ ipa_struct_reorg::find_vars (gimple *stmt) + srdecl *d = find_decl (lhs); + if (!d && t) + { +- current_function->record_decl (t, lhs, -1); ++ current_function->record_decl (t, lhs, -1, ++ isptrptr (TREE_TYPE (rhs)) ? TREE_TYPE (rhs) : NULL); + tree var = SSA_NAME_VAR (lhs); + if (var && VOID_POINTER_P (TREE_TYPE (var))) +- current_function->record_decl (t, var, -1); ++ current_function->record_decl (t, var, -1, ++ isptrptr (TREE_TYPE (rhs)) ? TREE_TYPE (rhs) : NULL); + } + } + /* void * _1; struct arc * _2; +@@ -3108,10 +3107,12 @@ ipa_struct_reorg::find_vars (gimple *stmt) + srdecl *d = find_decl (rhs); + if (!d && t) + { +- current_function->record_decl (t, rhs, -1); ++ current_function->record_decl (t, rhs, -1, ++ isptrptr (TREE_TYPE (lhs)) ? TREE_TYPE (lhs) : NULL); + tree var = SSA_NAME_VAR (rhs); + if (var && VOID_POINTER_P (TREE_TYPE (var))) +- current_function->record_decl (t, var, -1); ++ current_function->record_decl (t, var, -1, ++ isptrptr (TREE_TYPE (lhs)) ? TREE_TYPE (lhs) : NULL); + } + } + } +@@ -3529,7 +3530,7 @@ ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other, gimple + { + /* The type is other, the declaration is side. */ + current_function->record_decl (type, side, -1, +- find_decl (other) ? find_decl (other)->orig_type : NULL); ++ isptrptr (TREE_TYPE (other)) ? TREE_TYPE (other) : NULL); + } + else + { +@@ -5111,31 +5112,23 @@ ipa_struct_reorg::propagate_escape_via_original (void) + { + for (unsigned i = 0; i < types.length (); i++) + { +- for (unsigned j = 0; j < types[i]->fields.length (); j++) +- { +- srfield *field = types[i]->fields[j]; +- if (handled_type (field->fieldtype) && field->type) +- { +- for (unsigned k = 0; k < types.length (); k++) +- { +- const char *type1 = get_type_name (field->type->type); +- const char *type2 = get_type_name (types[k]->type); +- if (type1 == NULL || type2 == NULL) +- { +- continue; +- } +- if (type1 == type2 && types[k]->has_escaped ()) +- { +- if (!field->type->has_escaped ()) +- { +- field->type->mark_escape ( +- escape_via_orig_escape, NULL); +- } +- break; +- } +- } +- } +- } ++ for (unsigned j = 0; j < types.length (); j++) ++ { ++ const char *type1 = get_type_name (types[i]->type); ++ const char *type2 = get_type_name (types[j]->type); ++ if (type1 == NULL || type2 == NULL) ++ { ++ continue; ++ } ++ if (type1 == type2 && types[j]->has_escaped ()) ++ { ++ if (!types[i]->has_escaped ()) ++ { ++ types[i]->mark_escape (escape_via_orig_escape, NULL); ++ } ++ break; ++ } ++ } + } + } + +@@ -6683,7 +6676,10 @@ pass_ipa_reorder_fields::gate (function *) + && flag_ipa_reorder_fields + /* Don't bother doing anything if the program has errors. */ + && !seen_error () +- && flag_lto_partition == LTO_PARTITION_ONE); ++ && flag_lto_partition == LTO_PARTITION_ONE ++ /* Only enable struct optimizations in C since other ++ languages' grammar forbid. */ ++ && lang_c_p ()); + } + + } // anon namespace +diff --git a/gcc/symbol-summary.h b/gcc/symbol-summary.h +index a223b4dadea..ddf5e35776e 100644 +--- a/gcc/symbol-summary.h ++++ b/gcc/symbol-summary.h +@@ -61,10 +61,9 @@ protected: + { + /* In structure optimizatons, we call new to ensure that + the allocated memory is initialized to 0. */ +- if (flag_ipa_struct_reorg) ++ if (flag_ipa_reorder_fields || flag_ipa_struct_reorg) + return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T () + : new T (); +- + /* Call gcc_internal_because we do not want to call finalizer for + a type T. We call dtor explicitly. */ + return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T () +@@ -78,7 +77,7 @@ protected: + ggc_delete (item); + else + { +- if (flag_ipa_struct_reorg) ++ if (flag_ipa_reorder_fields || flag_ipa_struct_reorg) + delete item; + else + m_allocator.remove (item); +diff --git a/gcc/testsuite/gcc.dg/struct/rf_mul_layer_ptr_record_bug.c b/gcc/testsuite/gcc.dg/struct/rf_mul_layer_ptr_record_bug.c +new file mode 100644 +index 00000000000..23765fc5615 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_mul_layer_ptr_record_bug.c +@@ -0,0 +1,30 @@ ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct T_HASH_ENTRY ++{ ++ unsigned int hash; ++ unsigned int klen; ++ char *key; ++} iHashEntry; ++ ++typedef struct T_HASH ++{ ++ unsigned int size; ++ unsigned int fill; ++ unsigned int keys; ++ ++ iHashEntry **array; ++} uHash; ++ ++uHash *retval; ++ ++int ++main() { ++ retval->array = (iHashEntry **)calloc(sizeof(iHashEntry *), retval->size); ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c b/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c +index 8d687c58b30..54e737ee856 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c +@@ -1,6 +1,6 @@ +-// 针对 ++// For testing: + /* +-Compile options: /home/hxq/hcc_gcc9.3.0_org_debug/bin/gcc -O3 -g ++Compile options: gcc -O3 -g + -flto -flto-partition=one -fipa-reorder-fields -fipa-struct-reorg + -v -save-temps -fdump-ipa-all-details test.c -o test + +@@ -94,12 +94,11 @@ switch_arcs(arc_t** deleted_arcs, arc_t* arcnew) + copy = *test_arc; + count++; + *test_arc = arcnew[0]; +- replace_weaker_arc(arcnew, copy.tail, copy.head); ++ replace_weaker_arc(arcnew, NULL, NULL); + } + return count; + } + +- + int + main () + { +diff --git a/gcc/tree.c b/gcc/tree.c +index 5c1374d6fb1..89fa469c359 100644 +--- a/gcc/tree.c ++++ b/gcc/tree.c +@@ -5219,7 +5219,7 @@ fld_simplified_type_name (tree type) + /* Simplify type will cause that struct A and struct A within + struct B are different type pointers, so skip it in structure + optimizations. */ +- if (flag_ipa_struct_reorg) ++ if (flag_ipa_reorder_fields || flag_ipa_struct_reorg) + return TYPE_NAME (type); + + if (!TYPE_NAME (type) || TREE_CODE (TYPE_NAME (type)) != TYPE_DECL) +@@ -5463,7 +5463,7 @@ fld_simplified_type (tree t, class free_lang_data_d *fld) + /* Simplify type will cause that struct A and struct A within + struct B are different type pointers, so skip it in structure + optimizations. */ +- if (flag_ipa_struct_reorg) ++ if (flag_ipa_reorder_fields || flag_ipa_struct_reorg) + return t; + if (POINTER_TYPE_P (t)) + return fld_incomplete_type_of (t, fld); +-- +2.21.0.windows.1 + diff --git a/0020-Backport-vect-Fix-an-ICE-in-vect_recog_mask_conversi.patch b/0020-Backport-vect-Fix-an-ICE-in-vect_recog_mask_conversi.patch new file mode 100644 index 0000000..44b98b5 --- /dev/null +++ b/0020-Backport-vect-Fix-an-ICE-in-vect_recog_mask_conversi.patch @@ -0,0 +1,128 @@ +From 633dd654347b6146d6e94d6434e7028617019134 Mon Sep 17 00:00:00 2001 +From: zhanghaijian <z.zhanghaijian@huawei.com> +Date: Mon, 9 Aug 2021 20:18:26 +0800 +Subject: [PATCH 20/22] [Backport]vect: Fix an ICE in + vect_recog_mask_conversion_pattern + +Reference:https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=91d80cf4bd2827dd9c40fe6a7c719c909d79083d + +When processing the cond expression, vect_recog_mask_conversion_pattern +doesn't consider the situation that two operands of rhs1 are different +vectypes, leading to a vect ICE. This patch adds the identification and +handling of the situation to fix the problem. + +diff --git a/gcc/testsuite/gcc.target/aarch64/pr96757.c b/gcc/testsuite/gcc.target/aarch64/pr96757.c +new file mode 100644 +index 00000000000..122e39dca0e +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/pr96757.c +@@ -0,0 +1,23 @@ ++/* PR target/96757 */ ++/* { dg-do compile } */ ++/* { dg-options "-O3" } */ ++ ++short ++fun1(short i, short j) ++{ ++ return i * j; ++} ++ ++int ++fun(int a, int b, int c) ++{ ++ int *v, z, k, m; ++ short f, d; ++ for (int i=0; i<c; i++) ++ { ++ f= 4 <= d; ++ k= a > m; ++ z = f > k; ++ *v += fun1(z,b); ++ } ++} +diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c +index 310165084a3..84d7ddb170f 100644 +--- a/gcc/tree-vect-patterns.c ++++ b/gcc/tree-vect-patterns.c +@@ -4237,6 +4237,8 @@ vect_recog_mask_conversion_pattern (stmt_vec_info stmt_vinfo, tree *type_out) + tree vectype1, vectype2; + stmt_vec_info pattern_stmt_info; + vec_info *vinfo = stmt_vinfo->vinfo; ++ tree rhs1_op0 = NULL_TREE, rhs1_op1 = NULL_TREE; ++ tree rhs1_op0_type = NULL_TREE, rhs1_op1_type = NULL_TREE; + + /* Check for MASK_LOAD ans MASK_STORE calls requiring mask conversion. */ + if (is_gimple_call (last_stmt) +@@ -4336,9 +4338,37 @@ vect_recog_mask_conversion_pattern (stmt_vec_info stmt_vinfo, tree *type_out) + + it is better for b1 and b2 to use the mask type associated + with int elements rather bool (byte) elements. */ +- rhs1_type = integer_type_for_mask (TREE_OPERAND (rhs1, 0), vinfo); +- if (!rhs1_type) +- rhs1_type = TREE_TYPE (TREE_OPERAND (rhs1, 0)); ++ rhs1_op0 = TREE_OPERAND (rhs1, 0); ++ rhs1_op1 = TREE_OPERAND (rhs1, 1); ++ if (!rhs1_op0 || !rhs1_op1) ++ return NULL; ++ rhs1_op0_type = integer_type_for_mask (rhs1_op0, vinfo); ++ rhs1_op1_type = integer_type_for_mask (rhs1_op1, vinfo); ++ ++ if (!rhs1_op0_type) ++ rhs1_type = TREE_TYPE (rhs1_op0); ++ else if (!rhs1_op1_type) ++ rhs1_type = TREE_TYPE (rhs1_op1); ++ else if (TYPE_PRECISION (rhs1_op0_type) ++ != TYPE_PRECISION (rhs1_op1_type)) ++ { ++ int tmp0 = (int) TYPE_PRECISION (rhs1_op0_type) ++ - (int) TYPE_PRECISION (TREE_TYPE (lhs)); ++ int tmp1 = (int) TYPE_PRECISION (rhs1_op1_type) ++ - (int) TYPE_PRECISION (TREE_TYPE (lhs)); ++ if ((tmp0 > 0 && tmp1 > 0) || (tmp0 < 0 && tmp1 < 0)) ++ { ++ if (abs (tmp0) > abs (tmp1)) ++ rhs1_type = rhs1_op1_type; ++ else ++ rhs1_type = rhs1_op0_type; ++ } ++ else ++ rhs1_type = build_nonstandard_integer_type ++ (TYPE_PRECISION (TREE_TYPE (lhs)), 1); ++ } ++ else ++ rhs1_type = rhs1_op0_type; + } + else + return NULL; +@@ -4356,8 +4386,8 @@ vect_recog_mask_conversion_pattern (stmt_vec_info stmt_vinfo, tree *type_out) + name from the outset. */ + if (known_eq (TYPE_VECTOR_SUBPARTS (vectype1), + TYPE_VECTOR_SUBPARTS (vectype2)) +- && (TREE_CODE (rhs1) == SSA_NAME +- || rhs1_type == TREE_TYPE (TREE_OPERAND (rhs1, 0)))) ++ && !rhs1_op0_type ++ && !rhs1_op1_type) + return NULL; + + /* If rhs1 is invariant and we can promote it leave the COND_EXPR +@@ -4390,7 +4420,16 @@ vect_recog_mask_conversion_pattern (stmt_vec_info stmt_vinfo, tree *type_out) + if (TREE_CODE (rhs1) != SSA_NAME) + { + tmp = vect_recog_temp_ssa_var (TREE_TYPE (rhs1), NULL); +- pattern_stmt = gimple_build_assign (tmp, rhs1); ++ if (rhs1_op0_type ++ && TYPE_PRECISION (rhs1_op0_type) != TYPE_PRECISION (rhs1_type)) ++ rhs1_op0 = build_mask_conversion (rhs1_op0, ++ vectype2, stmt_vinfo); ++ if (rhs1_op1_type ++ && TYPE_PRECISION (rhs1_op1_type) != TYPE_PRECISION (rhs1_type)) ++ rhs1_op1 = build_mask_conversion (rhs1_op1, ++ vectype2, stmt_vinfo); ++ pattern_stmt = gimple_build_assign (tmp, TREE_CODE (rhs1), ++ rhs1_op0, rhs1_op1); + rhs1 = tmp; + append_pattern_def_seq (stmt_vinfo, pattern_stmt, vectype2, + rhs1_type); +-- +2.21.0.windows.1 + diff --git a/0021-mcmodel-Bugfix-for-mcmodel-medium-on-x86.patch b/0021-mcmodel-Bugfix-for-mcmodel-medium-on-x86.patch new file mode 100644 index 0000000..063da4e --- /dev/null +++ b/0021-mcmodel-Bugfix-for-mcmodel-medium-on-x86.patch @@ -0,0 +1,23 @@ +From 023c92ac45b727768599a95f7da748158a270753 Mon Sep 17 00:00:00 2001 +From: bule <bule1@huawei.com> +Date: Mon, 16 Aug 2021 11:20:35 +0800 +Subject: [PATCH 21/22] [mcmodel] Bugfix for mcmodel=medium on x86 + +Declare default_medium_symbol_p in targhooks.h which otherwise +cause the build failure on x86 platform. + +diff --git a/gcc/targhooks.h b/gcc/targhooks.h +index 72f3064e8f8..95c136edc79 100644 +--- a/gcc/targhooks.h ++++ b/gcc/targhooks.h +@@ -218,6 +218,7 @@ extern int default_register_move_cost (machine_mode, reg_class_t, + reg_class_t); + extern bool default_slow_unaligned_access (machine_mode, unsigned int); + extern HOST_WIDE_INT default_estimated_poly_value (poly_int64); ++extern bool default_medium_symbol_p (rtx); + + extern bool default_use_by_pieces_infrastructure_p (unsigned HOST_WIDE_INT, + unsigned int, +-- +2.21.0.windows.1 + diff --git a/0022-StructReorderFields-Fix-pointer-layer-check-bug.patch b/0022-StructReorderFields-Fix-pointer-layer-check-bug.patch new file mode 100644 index 0000000..effad4e --- /dev/null +++ b/0022-StructReorderFields-Fix-pointer-layer-check-bug.patch @@ -0,0 +1,167 @@ +From 1c69390a01d3bf7226fce2a670a0f71731744b04 Mon Sep 17 00:00:00 2001 +From: huangxiaoquan <huangxiaoquan1@huawei.com> +Date: Tue, 17 Aug 2021 15:50:31 +0800 +Subject: [PATCH 22/22] [StructReorderFields] Fix pointer layer check bug + +In the pointer layer check, the NULL pointer check is added +for the escape type mark. + +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +index fe364f742d8..85986ce5803 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -2235,9 +2235,9 @@ check_record_ptr_usage (gimple *use_stmt, tree ¤t_node, + } + + bool res = true; +- /* MEM[(long int *)a_1] = _57; (record). ++ /* MEM[(long int *)a_1] = _1; (record). + If lhs is ssa_name, lhs cannot be the current node. +- _283 = _282->flow; (No record). */ ++ _2 = _1->flow; (No record). */ + if (TREE_CODE (rhs1) == SSA_NAME) + { + tree tmp = (rhs1 != current_node) ? rhs1 : lhs; +@@ -2285,13 +2285,13 @@ check_record_single_node (gimple *use_stmt, tree ¤t_node, + bool res = true; + if (TREE_CODE (lhs) == SSA_NAME && TREE_CODE (rhs1) == MEM_REF) + { +- /* _257 = MEM[(struct arc_t * *)_17]. */ ++ /* add such as: _2 = MEM[(struct arc_t * *)_1]. */ + res = add_node (lhs, *ptr_layers.get (current_node) - 1, + ptr_layers, ssa_name_stack); + } + else if (TREE_CODE (lhs) == MEM_REF && TREE_CODE (rhs1) == SSA_NAME) + { +- /* MEM[(long int *)a_1] = _57. */ ++ /* add such as: MEM[(long int *)a_1] = _1. */ + if (rhs1 == current_node) + { + res = add_node (TREE_OPERAND (lhs, 0), +@@ -3097,7 +3097,8 @@ ipa_struct_reorg::find_vars (gimple *stmt) + isptrptr (TREE_TYPE (rhs)) ? TREE_TYPE (rhs) : NULL); + } + } +- /* void * _1; struct arc * _2; ++ /* find void ssa_name such as: ++ void * _1; struct arc * _2; + _2 = _1 + _3; _1 = calloc (100, 40). */ + if (TREE_CODE (rhs) == SSA_NAME + && VOID_POINTER_P (TREE_TYPE (rhs)) +@@ -3126,7 +3127,7 @@ ipa_struct_reorg::find_vars (gimple *stmt) + find_var (gimple_assign_rhs1 (stmt), stmt); + find_var (gimple_assign_rhs2 (stmt), stmt); + } +- /* _23 = _21 - old_arcs_12. */ ++ /* find void ssa_name from stmt such as: _2 = _1 - old_arcs_1. */ + else if ((current_mode == STRUCT_REORDER_FIELDS) + && gimple_assign_rhs_code (stmt) == POINTER_DIFF_EXPR + && types_compatible_p ( +@@ -3310,7 +3311,7 @@ trace_calculate_negate (gimple *size_def_stmt, tree *num, tree struct_size) + { + gcc_assert (gimple_assign_rhs_code (size_def_stmt) == NEGATE_EXPR); + +- /* _480 = -_479; _479 = _478 * 72. */ ++ /* support NEGATE_EXPR trace: _3 = -_2; _2 = _1 * 72. */ + tree num1 = NULL_TREE; + tree arg0 = gimple_assign_rhs1 (size_def_stmt); + if (!is_result_of_mult (arg0, &num1, struct_size) || num1 == NULL_TREE) +@@ -3329,7 +3330,8 @@ trace_calculate_diff (gimple *size_def_stmt, tree *num) + { + gcc_assert (gimple_assign_rhs_code (size_def_stmt) == NOP_EXPR); + +- /* _25 = (long unsigned int) _23; _23 = _21 - old_arcs_12. */ ++ /* support POINTER_DIFF_EXPR trace: ++ _3 = (long unsigned int) _2; _2 = _1 - old_arcs_1. */ + tree arg = gimple_assign_rhs1 (size_def_stmt); + size_def_stmt = SSA_NAME_DEF_STMT (arg); + if (size_def_stmt && is_gimple_assign (size_def_stmt) +@@ -3811,8 +3813,8 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, + release INTEGER_TYPE cast to struct pointer. + (If t has escpaed above, then directly returns + and doesn't mark escape follow.). */ +- /* _607 = MEM[(struct arc_t * *)pl_100]. +- then base pl_100:ssa_name - pointer_type - integer_type. */ ++ /* _1 = MEM[(struct arc_t * *)a_1]. ++ then base a_1: ssa_name - pointer_type - integer_type. */ + if (current_mode == STRUCT_REORDER_FIELDS) + { + bool is_int_ptr = POINTER_TYPE_P (TREE_TYPE (base)) +@@ -4520,8 +4522,15 @@ ipa_struct_reorg::check_ptr_layers (tree a_expr, tree b_expr, gimple* stmt) + { + return; + } +- a->type->mark_escape (escape_cast_another_ptr, stmt); +- b->type->mark_escape (escape_cast_another_ptr, stmt); ++ ++ if (a) ++ { ++ a->type->mark_escape (escape_cast_another_ptr, stmt); ++ } ++ if (b) ++ { ++ b->type->mark_escape (escape_cast_another_ptr, stmt); ++ } + } + + void +@@ -5649,9 +5658,9 @@ ipa_struct_reorg::rewrite_expr (tree expr, tree newexpr[max_split], bool ignore_ + if (current_mode == STRUCT_REORDER_FIELDS) + { + /* Supports the MEM_REF offset. +- _1 = MEM[(struct arc *)ap_4 + 72B].flow; +- Old rewrite:_1 = ap.reorder.0_8->flow; +- New rewrite:_1 ++ _1 = MEM[(struct arc *)ap_1 + 72B].flow; ++ Old rewrite: _1 = ap.reorder.0_8->flow; ++ New rewrite: _1 + = MEM[(struct arc.reorder.0 *)ap.reorder.0_8 + 64B].flow; + */ + HOST_WIDE_INT offset_tmp = 0; +@@ -6150,10 +6159,10 @@ ipa_struct_reorg::rewrite_cond (gcond *stmt, gimple_stmt_iterator *gsi) + return false; + } + +- /* Old rewrite:if (x_1 != 0B) ++ /* Old rewrite: if (x_1 != 0B) + -> _1 = x.reorder.0_1 != 0B; if (_1 != 1) + The logic is incorrect. +- New rewrite:if (x_1 != 0B) ++ New rewrite: if (x_1 != 0B) + -> if (x.reorder.0_1 != 0B);*/ + for (unsigned i = 0; i < max_split && (newlhs[i] || newrhs[i]); i++) + { +diff --git a/gcc/testsuite/gcc.dg/struct/rf_check_ptr_layers_bug.c b/gcc/testsuite/gcc.dg/struct/rf_check_ptr_layers_bug.c +new file mode 100644 +index 00000000000..a5477dcc9be +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_check_ptr_layers_bug.c +@@ -0,0 +1,24 @@ ++/* check_ptr_layers bugfix.*/ ++/* { dg-do compile } */ ++struct { ++ char a; ++} **b = 0, *e = 0; ++long c; ++char d = 9; ++int f; ++ ++void g() ++{ ++ for (; f;) ++ if (c) ++ (*e).a++; ++ if (!d) ++ for (;;) ++ b &&c; ++} ++int ++main() ++{ ++ g(); ++} ++/* { dg-final { scan-ipa-dump "No structures to transform." "reorder_fields" } } */ +\ No newline at end of file +-- +2.21.0.windows.1 + diff --git a/0023-StructReorderFields-Add-pointer-offset-check.patch b/0023-StructReorderFields-Add-pointer-offset-check.patch new file mode 100644 index 0000000..896b7d5 --- /dev/null +++ b/0023-StructReorderFields-Add-pointer-offset-check.patch @@ -0,0 +1,87 @@ +From 83a35da4910fc7d8f29ced3e0ff8adddeb537731 Mon Sep 17 00:00:00 2001 +From: huangxiaoquan <huangxiaoquan1@huawei.com> +Date: Fri, 27 Aug 2021 14:53:18 +0800 +Subject: [PATCH 23/24] [StructReorderFields] Add pointer offset check + +The pointer offset check is added for the expr that is dereferenced +in the memory, and escapes struct pointer offset operations involving +field order. + +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +index 85986ce5803..b0d4fe80797 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -3876,6 +3876,17 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, + return false; + } + ++ /* Escape the operation of fetching field with pointer offset such as: ++ *(&(t->right)) = malloc (0); -> MEM[(struct node * *)_1 + 8B] = malloc (0); ++ */ ++ if (current_mode != NORMAL ++ && (TREE_CODE (expr) == MEM_REF) && (offset != 0)) ++ { ++ gcc_assert (can_escape); ++ t->mark_escape (escape_non_multiply_size, NULL); ++ return false; ++ } ++ + if (wholeaccess (expr, base, accesstype, t)) + { + field = NULL; +diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c b/gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c +index 190b9418275..2ae46fb3112 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c +@@ -84,4 +84,4 @@ main () + return cnt; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "No structures to transform." "reorder_fields" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c +new file mode 100644 +index 00000000000..317aafa5f72 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c +@@ -0,0 +1,34 @@ ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++struct node ++{ ++ struct node *left, *right; ++ double a, b, c, d, e, f; ++} ++*a; ++int b, c; ++void ++CreateNode (struct node **p1) ++{ ++ *p1 = calloc (10, sizeof (struct node)); ++} ++ ++int ++main () ++{ ++ a->left = 0; ++ struct node *t = a; ++ CreateNode (&t->right); ++ ++ struct node p = *a; ++ b = 1; ++ if (p.left) ++ b = 0; ++ if (b) ++ printf (" Tree.\n"); ++} ++ ++/* { dg-final { scan-ipa-dump "No structures to transform." "reorder_fields" } } */ +\ No newline at end of file +-- +2.21.0.windows.1 + diff --git a/0024-StructReorderFields-Add-lto-and-whole-program-gate.patch b/0024-StructReorderFields-Add-lto-and-whole-program-gate.patch new file mode 100644 index 0000000..b8043fa --- /dev/null +++ b/0024-StructReorderFields-Add-lto-and-whole-program-gate.patch @@ -0,0 +1,90 @@ +From 0ee0f0ebeb098787cb9698887c237606b6ab10c6 Mon Sep 17 00:00:00 2001 +From: huangxiaoquan <huangxiaoquan1@huawei.com> +Date: Wed, 1 Sep 2021 17:07:22 +0800 +Subject: [PATCH 24/24] [StructReorderFields] Add lto and whole-program gate + +Only enable struct reorder fields optimizations in lto or whole-program. +This prevents some .c files from being struct reorder fields optimized +while some of them are not optimized during project compilation. + +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +index b0d4fe80797..2bf41e0d83b 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -6655,7 +6655,9 @@ pass_ipa_struct_reorg::gate (function *) + && flag_lto_partition == LTO_PARTITION_ONE + /* Only enable struct optimizations in C since other + languages' grammar forbid. */ +- && lang_c_p ()); ++ && lang_c_p () ++ /* Only enable struct optimizations in lto or whole_program. */ ++ && (in_lto_p || flag_whole_program)); + } + + const pass_data pass_data_ipa_reorder_fields = +@@ -6699,7 +6701,9 @@ pass_ipa_reorder_fields::gate (function *) + && flag_lto_partition == LTO_PARTITION_ONE + /* Only enable struct optimizations in C since other + languages' grammar forbid. */ +- && lang_c_p ()); ++ && lang_c_p () ++ /* Only enable struct optimizations in lto or whole_program. */ ++ && (in_lto_p || flag_whole_program)); + } + + } // anon namespace +diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-1.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-1.c +index 6565fe8dd63..23444fe8b0d 100644 +--- a/gcc/testsuite/gcc.dg/struct/struct_reorg-1.c ++++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-1.c +@@ -1,5 +1,5 @@ + // { dg-do compile } +-// { dg-options "-O3 -flto-partition=one -fipa-struct-reorg -fdump-ipa-all" } ++// { dg-options "-O3 -flto-partition=one -fipa-struct-reorg -fdump-ipa-all -fwhole-program" } + + struct a + { +@@ -21,4 +21,10 @@ int g(void) + return b->t; + } + ++int main() ++{ ++ f (); ++ return g (); ++} ++ + /* { dg-final { scan-ipa-dump "No structures to transform." "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-3.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-3.c +index 5864ad46fd3..2d1f95c9935 100644 +--- a/gcc/testsuite/gcc.dg/struct/struct_reorg-3.c ++++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-3.c +@@ -1,5 +1,5 @@ + // { dg-do compile } +-// { dg-options "-O3 -flto-partition=one -fipa-struct-reorg -fdump-ipa-all" } ++// { dg-options "-O3 -flto-partition=one -fipa-struct-reorg -fdump-ipa-all -fwhole-program" } + + #include <stdlib.h> + typedef struct { +@@ -10,7 +10,7 @@ typedef struct { + compile_stack_elt_t *stack; + unsigned size; + } compile_stack_type; +-void f (const char *p, const char *pend, int c) ++__attribute__((noinline)) void f (const char *p, const char *pend, int c) + { + compile_stack_type compile_stack; + while (p != pend) +@@ -20,4 +20,9 @@ void f (const char *p, const char *pend, int c) + * sizeof (compile_stack_elt_t)); + } + ++int main() ++{ ++ f (NULL, NULL, 1); ++} ++ + /* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ +-- +2.21.0.windows.1 + diff --git a/0025-AutoPrefetch-Support-cache-misses-profile.patch b/0025-AutoPrefetch-Support-cache-misses-profile.patch new file mode 100644 index 0000000..1daa2db --- /dev/null +++ b/0025-AutoPrefetch-Support-cache-misses-profile.patch @@ -0,0 +1,669 @@ +From 26e4ba63112f55c27b7dd3d5f8c4497ef9a2f459 Mon Sep 17 00:00:00 2001 +From: benniaobufeijiushiji <linda7@huawei.com> +Date: Thu, 6 Jan 2022 15:33:29 +0800 +Subject: [PATCH 25/28] [AutoPrefetch] Support cache misses profile + +Add pass ex-afdo after pass afdo in auto-profile.c. +Add flag -fcache-misses-profile. +Read profile of different types of perf events and build maps for +function and gimple location to its count of each perf event. +Currently, instruction execution and cahce misses are supported. +--- + gcc/auto-profile.c | 415 +++++++++++++++++++++++++++++++++++++++++++++ + gcc/auto-profile.h | 28 +++ + gcc/common.opt | 14 ++ + gcc/opts.c | 26 +++ + gcc/passes.def | 1 + + gcc/timevar.def | 1 + + gcc/toplev.c | 6 + + gcc/tree-pass.h | 2 + + 8 files changed, 493 insertions(+) + +diff --git a/gcc/auto-profile.c b/gcc/auto-profile.c +index 7d09887c9..aced8fca5 100644 +--- a/gcc/auto-profile.c ++++ b/gcc/auto-profile.c +@@ -49,6 +49,9 @@ along with GCC; see the file COPYING3. If not see + #include "auto-profile.h" + #include "tree-pretty-print.h" + #include "gimple-pretty-print.h" ++#include <map> ++#include <vector> ++#include <algorithm> + + /* The following routines implements AutoFDO optimization. + +@@ -95,6 +98,7 @@ along with GCC; see the file COPYING3. If not see + */ + + #define DEFAULT_AUTO_PROFILE_FILE "fbdata.afdo" ++#define DEFAULT_CACHE_MISSES_PROFILE_FILE "cmsdata.gcov" + #define AUTO_PROFILE_VERSION 1 + + namespace autofdo +@@ -117,6 +121,14 @@ private: + bool annotated_; + }; + ++/* pair <func_decl, count> */ ++static bool ++event_count_cmp (std::pair<unsigned, gcov_type> &a, ++ std::pair<unsigned, gcov_type> &b) ++{ ++ return a.second > b.second; ++} ++ + /* Represent a source location: (function_decl, lineno). */ + typedef std::pair<tree, unsigned> decl_lineno; + +@@ -338,6 +350,206 @@ static autofdo_source_profile *afdo_source_profile; + /* gcov_summary structure to store the profile_info. */ + static gcov_summary *afdo_profile_info; + ++/* Check opts->x_flags and put file name into EVENT_FILES. */ ++ ++static bool ++get_all_profile_names (const char **event_files) ++{ ++ if (!(flag_auto_profile || flag_cache_misses_profile)) ++ { ++ return false; ++ } ++ ++ event_files[INST_EXEC] = auto_profile_file; ++ ++ if (cache_misses_profile_file == NULL) ++ { ++ cache_misses_profile_file = DEFAULT_CACHE_MISSES_PROFILE_FILE; ++ } ++ event_files[CACHE_MISSES] = cache_misses_profile_file; ++ ++ return true; ++} ++ ++static void read_profile (void); ++ ++/* Maintain multiple profile data of different events with event_loc_count_map ++ and event_func_count_map. */ ++ ++class extend_auto_profile ++{ ++public: ++ bool auto_profile_exist (enum event_type type); ++ gcov_type get_loc_count (location_t, event_type); ++ gcov_type get_func_count (unsigned, event_type); ++ struct rank_info get_func_rank (unsigned, enum event_type); ++ /* There should be only one instance of class EXTEND_AUTO_PROFILE. */ ++ static extend_auto_profile *create () ++ { ++ extend_auto_profile *map = new extend_auto_profile (); ++ if (map->read ()) ++ { ++ return map; ++ } ++ delete map; ++ return NULL; ++ } ++private: ++ /* Basic maps of extend_auto_profile. */ ++ typedef std::map<location_t, gcov_type> loc_count_map; ++ typedef std::map<unsigned, gcov_type> func_count_map; ++ ++ /* Map of function_uid to its descending order rank of counts. */ ++ typedef std::map<unsigned, unsigned> rank_map; ++ ++ /* Mapping hardware events to corresponding basic maps. */ ++ typedef std::map<event_type, loc_count_map> event_loc_count_map; ++ typedef std::map<event_type, func_count_map> event_func_count_map; ++ typedef std::map<event_type, rank_map> event_rank_map; ++ ++ extend_auto_profile () {} ++ bool read (); ++ void set_loc_count (); ++ void process_extend_source_profile (); ++ void read_extend_afdo_file (const char*, event_type); ++ void rank_all_func (); ++ void dump_event (); ++ event_loc_count_map event_loc_map; ++ event_func_count_map event_func_map; ++ event_rank_map func_rank; ++ event_type profile_type; ++}; ++ ++/* Member functions for extend_auto_profile. */ ++ ++bool ++extend_auto_profile::auto_profile_exist (enum event_type type) ++{ ++ switch (type) ++ { ++ case INST_EXEC: ++ return event_func_map.count (INST_EXEC) != 0 ++ || event_loc_map.count (INST_EXEC) != 0; ++ case CACHE_MISSES: ++ return event_func_map.count (CACHE_MISSES) != 0 ++ || event_loc_map.count (CACHE_MISSES) != 0; ++ default: ++ return false; ++ } ++} ++ ++void ++extend_auto_profile::dump_event () ++{ ++ if (dump_file) ++ { ++ switch (profile_type) ++ { ++ case INST_EXEC: ++ fprintf (dump_file, "Processing event instruction execution.\n"); ++ break; ++ case CACHE_MISSES: ++ fprintf (dump_file, "Processing event cache misses.\n"); ++ break; ++ default: ++ break; ++ } ++ } ++} ++ ++/* Return true if any profile data was read. */ ++ ++bool ++extend_auto_profile::read () ++{ ++ const char *event_files[EVENT_NUMBER] = {NULL}; ++ if (!get_all_profile_names (event_files)) ++ { ++ return false; ++ } ++ ++ /* Backup AFDO_STRING_TABLE and AFDO_SOURCE_PROFILE since we will create ++ new ones for each event_type. */ ++ autofdo::string_table *string_table_afdo = afdo_string_table; ++ autofdo::autofdo_source_profile *source_profile_afdo = afdo_source_profile; ++ ++ for (unsigned i = 0; i < EVENT_NUMBER; i++) ++ { ++ if (event_files[i] == NULL) ++ { ++ continue; ++ } ++ profile_type = (enum event_type) i; ++ dump_event (); ++ gcov_close (); ++ auto_profile_file = event_files[i]; ++ read_profile (); ++ gcov_close (); ++ ++ process_extend_source_profile (); ++ ++ delete afdo_source_profile; ++ delete afdo_string_table; ++ } ++ ++ /* Restore AFDO_STRING_TABLE and AFDO_SOURCE_PROFILE. Function ++ END_AUTO_PROFILE will free them at the end of compilation. */ ++ afdo_string_table = string_table_afdo; ++ afdo_source_profile = source_profile_afdo; ++ return true; ++} ++ ++/* Helper functions. */ ++ ++gcov_type ++extend_auto_profile::get_loc_count (location_t loc, event_type type) ++{ ++ event_loc_count_map::iterator event_iter = event_loc_map.find (type); ++ if (event_iter != event_loc_map.end ()) ++ { ++ loc_count_map::iterator loc_iter = event_iter->second.find (loc); ++ if (loc_iter != event_iter->second.end ()) ++ { ++ return loc_iter->second; ++ } ++ } ++ return 0; ++} ++ ++struct rank_info ++extend_auto_profile::get_func_rank (unsigned decl_uid, enum event_type type) ++{ ++ struct rank_info info = {0, 0}; ++ event_rank_map::iterator event_iter = func_rank.find (type); ++ if (event_iter != func_rank.end ()) ++ { ++ rank_map::iterator func_iter = event_iter->second.find (decl_uid); ++ if (func_iter != event_iter->second.end ()) ++ { ++ info.rank = func_iter->second; ++ info.total = event_iter->second.size (); ++ } ++ } ++ return info; ++} ++ ++gcov_type ++extend_auto_profile::get_func_count (unsigned decl_uid, event_type type) ++{ ++ event_func_count_map::iterator event_iter = event_func_map.find (type); ++ if (event_iter != event_func_map.end ()) ++ { ++ func_count_map::iterator func_iter = event_iter->second.find (decl_uid); ++ if (func_iter != event_iter->second.end ()) ++ { ++ return func_iter->second; ++ } ++ } ++ return 0; ++} ++ ++static extend_auto_profile *extend_profile; ++ + /* Helper functions. */ + + /* Return the original name of NAME: strip the suffix that starts +@@ -1654,6 +1866,131 @@ auto_profile (void) + + return TODO_rebuild_cgraph_edges; + } ++ ++void ++extend_auto_profile::rank_all_func () ++{ ++ std::vector<std::pair<unsigned, gcov_type> > func_sorted; ++ event_func_count_map::iterator event_iter ++ = event_func_map.find (profile_type); ++ if (event_iter != event_func_map.end ()) ++ { ++ func_count_map::iterator func_iter; ++ for (func_iter = event_iter->second.begin (); ++ func_iter != event_iter->second.end (); func_iter++) ++ { ++ func_sorted.push_back (std::make_pair (func_iter->first, ++ func_iter->second)); ++ } ++ ++ std::sort (func_sorted.begin (), func_sorted.end (), event_count_cmp); ++ ++ for (unsigned i = 0; i < func_sorted.size (); ++i) ++ { ++ func_rank[profile_type][func_sorted[i].first] = i + 1; ++ } ++ } ++} ++ ++/* Iterate stmts in cfun and maintain its count to EVENT_LOC_MAP. */ ++ ++void ++extend_auto_profile::set_loc_count () ++{ ++ basic_block bb; ++ FOR_EACH_BB_FN (bb, cfun) ++ { ++ gimple_stmt_iterator gsi; ++ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) ++ { ++ count_info info; ++ gimple *stmt = gsi_stmt (gsi); ++ if (gimple_clobber_p (stmt) || is_gimple_debug (stmt)) ++ { ++ continue; ++ } ++ if (afdo_source_profile->get_count_info (stmt, &info)) ++ { ++ location_t loc = gimple_location (stmt); ++ event_loc_map[profile_type][loc] += info.count; ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "stmt "); ++ print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); ++ fprintf (dump_file, "counts %ld\n", ++ event_loc_map[profile_type][loc]); ++ } ++ } ++ } ++ } ++} ++ ++/* Process data in extend_auto_source_profile, save them into two maps. ++ 1. gimple_location to count. ++ 2. function_index to count. */ ++void ++extend_auto_profile::process_extend_source_profile () ++{ ++ struct cgraph_node *node; ++ if (symtab->state == FINISHED) ++ { ++ return; ++ } ++ FOR_EACH_FUNCTION (node) ++ { ++ if (!gimple_has_body_p (node->decl) || node->inlined_to) ++ { ++ continue; ++ } ++ ++ /* Don't profile functions produced for builtin stuff. */ ++ if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION) ++ { ++ continue; ++ } ++ ++ function *fn = DECL_STRUCT_FUNCTION (node->decl); ++ push_cfun (fn); ++ ++ const function_instance *s ++ = afdo_source_profile->get_function_instance_by_decl ( ++ current_function_decl); ++ ++ if (s == NULL) ++ { ++ pop_cfun (); ++ continue; ++ } ++ unsigned int decl_uid = DECL_UID (current_function_decl); ++ gcov_type count = s->total_count (); ++ if (dump_file) ++ { ++ fprintf (dump_file, "Extend auto-profile for function %s.\n", ++ node->dump_name ()); ++ } ++ event_func_map[profile_type][decl_uid] += count; ++ set_loc_count (); ++ pop_cfun (); ++ } ++ rank_all_func (); ++} ++ ++/* Main entry of extend_auto_profile. */ ++ ++static void ++extend_source_profile () ++{ ++ extend_profile = autofdo::extend_auto_profile::create (); ++ if (dump_file) ++ { ++ if (extend_profile == NULL) ++ { ++ fprintf (dump_file, "No profile file is found.\n"); ++ return; ++ } ++ fprintf (dump_file, "Extend profile info generated.\n"); ++ } ++} + } /* namespace autofdo. */ + + /* Read the profile from the profile data file. */ +@@ -1682,6 +2019,42 @@ end_auto_profile (void) + profile_info = NULL; + } + ++/* Extern function to get profile info in other passes. */ ++ ++bool ++profile_exist (enum event_type type) ++{ ++ return autofdo::extend_profile != NULL ++ && autofdo::extend_profile->auto_profile_exist (type); ++} ++ ++gcov_type ++event_get_loc_count (location_t loc, event_type type) ++{ ++ return autofdo::extend_profile->get_loc_count (loc, type); ++} ++ ++gcov_type ++event_get_func_count (unsigned decl_uid, event_type type) ++{ ++ return autofdo::extend_profile->get_func_count (decl_uid, type); ++} ++ ++struct rank_info ++event_get_func_rank (unsigned decl_uid, enum event_type type) ++{ ++ return autofdo::extend_profile->get_func_rank (decl_uid, type); ++} ++ ++void ++free_extend_profile_info () ++{ ++ if (autofdo::extend_profile != NULL) ++ { ++ delete autofdo::extend_profile; ++ } ++} ++ + /* Returns TRUE if EDGE is hot enough to be inlined early. */ + + bool +@@ -1743,8 +2116,50 @@ public: + + } // anon namespace + ++namespace ++{ ++const pass_data pass_data_ipa_extend_auto_profile = ++{ ++ SIMPLE_IPA_PASS, /* type */ ++ "ex-afdo", /* name */ ++ OPTGROUP_NONE, /* optinfo_flags */ ++ TV_IPA_EXTEND_AUTO_PROFILE, /* tv_id */ ++ 0, /* properties_required */ ++ 0, /* properties_provided */ ++ 0, /* properties_destroyed */ ++ 0, /* todo_flags_start */ ++ 0, /* todo_flags_finish */ ++}; ++ ++class pass_ipa_extend_auto_profile : public simple_ipa_opt_pass ++{ ++public: ++ pass_ipa_extend_auto_profile (gcc::context *ctxt) ++ : simple_ipa_opt_pass (pass_data_ipa_extend_auto_profile, ctxt) ++ {} ++ ++ /* opt_pass methods: */ ++ virtual bool gate (function *) {return (flag_ipa_extend_auto_profile > 0);} ++ virtual unsigned int execute (function *); ++ ++}; ++ ++unsigned int ++pass_ipa_extend_auto_profile::execute (function *fun) ++{ ++ autofdo::extend_source_profile (); ++ return 0; ++} ++} // anon namespace ++ + simple_ipa_opt_pass * + make_pass_ipa_auto_profile (gcc::context *ctxt) + { + return new pass_ipa_auto_profile (ctxt); + } ++ ++simple_ipa_opt_pass * ++make_pass_ipa_extend_auto_profile (gcc::context *ctxt) ++{ ++ return new pass_ipa_extend_auto_profile (ctxt); ++} +\ No newline at end of file +diff --git a/gcc/auto-profile.h b/gcc/auto-profile.h +index f5cff091d..230d7e68a 100644 +--- a/gcc/auto-profile.h ++++ b/gcc/auto-profile.h +@@ -21,6 +21,13 @@ along with GCC; see the file COPYING3. If not see + #ifndef AUTO_PROFILE_H + #define AUTO_PROFILE_H + ++enum event_type ++{ ++ INST_EXEC = 0, ++ CACHE_MISSES, ++ EVENT_NUMBER ++}; ++ + /* Read, process, finalize AutoFDO data structures. */ + extern void read_autofdo_file (void); + extern void end_auto_profile (void); +@@ -28,4 +35,25 @@ extern void end_auto_profile (void); + /* Returns TRUE if EDGE is hot enough to be inlined early. */ + extern bool afdo_callsite_hot_enough_for_early_inline (struct cgraph_edge *); + ++/* Chcek if profile exists before using this profile. */ ++extern bool profile_exist (enum event_type); ++ ++/* Given func decl_uid or gimple location and event_type, return count. ++ Count is 0 if function or gimple is not sampled. */ ++extern gcov_type event_get_func_count (unsigned, enum event_type); ++extern gcov_type event_get_loc_count (location_t, enum event_type); ++ ++struct rank_info ++{ ++ unsigned total; ++ unsigned rank; ++}; ++ ++/* Given function decl_uid and event type, return rank_info. Rank_info ++ is {0, 0} if function was not sampled. */ ++extern struct rank_info event_get_func_rank (unsigned, enum event_type); ++ ++/* Free memory allocated by autofdo::extern_profile. */ ++extern void free_extend_profile_info (); ++ + #endif /* AUTO_PROFILE_H */ +diff --git a/gcc/common.opt b/gcc/common.opt +index 73c24f28d..37cbbd8c0 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -1074,6 +1074,16 @@ Common Joined RejectNegative Var(auto_profile_file) + Use sample profile information for call graph node weights. The profile + file is specified in the argument. + ++fcache-misses-profile ++Common Report Var(flag_cache_misses_profile) ++Use sample profile information for source code cache miss count. The default ++profile file is cmsdata.gcov in `pwd`. ++ ++fcache-misses-profile= ++Common Joined RejectNegative Var(cache_misses_profile_file) ++Use sample profile information for source code cache miss count. The profile ++file is specified in the argument. ++ + ; -fcheck-bounds causes gcc to generate array bounds checks. + ; For C, C++ and ObjC: defaults off. + ; For Java: defaults to on. +@@ -1873,6 +1883,10 @@ fipa-struct-reorg + Common Report Var(flag_ipa_struct_reorg) Init(0) Optimization + Perform structure layout optimizations. + ++fipa-extend-auto-profile ++Common Report Var(flag_ipa_extend_auto_profile) ++Use sample profile information for source code. ++ + fipa-vrp + Common Report Var(flag_ipa_vrp) Optimization + Perform IPA Value Range Propagation. +diff --git a/gcc/opts.c b/gcc/opts.c +index 6924a973a..642327296 100644 +--- a/gcc/opts.c ++++ b/gcc/opts.c +@@ -1742,6 +1742,13 @@ enable_fdo_optimizations (struct gcc_options *opts, + SET_OPTION_IF_UNSET (opts, opts_set, flag_tree_loop_distribution, value); + } + ++static void ++set_cache_misses_profile_params (struct gcc_options *opts, ++ struct gcc_options *opts_set) ++{ ++ SET_OPTION_IF_UNSET (opts, opts_set, flag_prefetch_loop_arrays, 1); ++} ++ + /* -f{,no-}sanitize{,-recover}= suboptions. */ + const struct sanitizer_opts_s sanitizer_opts[] = + { +@@ -2604,6 +2611,25 @@ common_handle_option (struct gcc_options *opts, + param_early_inliner_max_iterations, 10); + break; + ++ case OPT_fipa_extend_auto_profile: ++ opts->x_flag_ipa_extend_auto_profile = opts->x_flag_cache_misses_profile ++ ? true : value; ++ break; ++ ++ case OPT_fcache_misses_profile_: ++ opts->x_cache_misses_profile_file = xstrdup (arg); ++ opts->x_flag_cache_misses_profile = true; ++ value = true; ++ /* No break here - do -fcache-misses-profile processing. */ ++ /* FALLTHRU */ ++ case OPT_fcache_misses_profile: ++ opts->x_flag_ipa_extend_auto_profile = value; ++ if (value) ++ { ++ set_cache_misses_profile_params (opts, opts_set); ++ } ++ break; ++ + case OPT_fprofile_generate_: + opts->x_profile_data_prefix = xstrdup (arg); + value = true; +diff --git a/gcc/passes.def b/gcc/passes.def +index 63303ab65..e9c91d26e 100644 +--- a/gcc/passes.def ++++ b/gcc/passes.def +@@ -133,6 +133,7 @@ along with GCC; see the file COPYING3. If not see + + NEXT_PASS (pass_target_clone); + NEXT_PASS (pass_ipa_auto_profile); ++ NEXT_PASS (pass_ipa_extend_auto_profile); + NEXT_PASS (pass_ipa_tree_profile); + PUSH_INSERT_PASSES_WITHIN (pass_ipa_tree_profile) + NEXT_PASS (pass_feedback_split_functions); +diff --git a/gcc/timevar.def b/gcc/timevar.def +index ee25eccbb..e873747a8 100644 +--- a/gcc/timevar.def ++++ b/gcc/timevar.def +@@ -82,6 +82,7 @@ DEFTIMEVAR (TV_IPA_FNSPLIT , "ipa function splitting") + DEFTIMEVAR (TV_IPA_COMDATS , "ipa comdats") + DEFTIMEVAR (TV_IPA_REORDER_FIELDS , "ipa struct reorder fields optimization") + DEFTIMEVAR (TV_IPA_STRUCT_REORG , "ipa struct reorg optimization") ++DEFTIMEVAR (TV_IPA_EXTEND_AUTO_PROFILE, "ipa extend auto profile") + DEFTIMEVAR (TV_IPA_OPT , "ipa various optimizations") + DEFTIMEVAR (TV_IPA_LTO_DECOMPRESS , "lto stream decompression") + DEFTIMEVAR (TV_IPA_LTO_COMPRESS , "lto stream compression") +diff --git a/gcc/toplev.c b/gcc/toplev.c +index eaed6f6c7..51e6bd400 100644 +--- a/gcc/toplev.c ++++ b/gcc/toplev.c +@@ -577,6 +577,12 @@ compile_file (void) + targetm.asm_out.output_ident (ident_str); + } + ++ /* Extend auto profile finalization. */ ++ if (flag_ipa_extend_auto_profile) ++ { ++ free_extend_profile_info (); ++ } ++ + /* Auto profile finalization. */ + if (flag_auto_profile) + end_auto_profile (); +diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h +index eb32c5d44..be6387768 100644 +--- a/gcc/tree-pass.h ++++ b/gcc/tree-pass.h +@@ -511,6 +511,8 @@ extern ipa_opt_pass_d *make_pass_ipa_hsa (gcc::context *ctxt); + extern ipa_opt_pass_d *make_pass_ipa_pure_const (gcc::context *ctxt); + extern simple_ipa_opt_pass *make_pass_ipa_reorder_fields (gcc::context *ctxt); + extern simple_ipa_opt_pass *make_pass_ipa_struct_reorg (gcc::context *ctxt); ++extern simple_ipa_opt_pass *make_pass_ipa_extend_auto_profile (gcc::context ++ *ctxt); + extern simple_ipa_opt_pass *make_pass_ipa_pta (gcc::context *ctxt); + extern simple_ipa_opt_pass *make_pass_ipa_tm (gcc::context *ctxt); + extern simple_ipa_opt_pass *make_pass_target_clone (gcc::context *ctxt); +-- +2.27.0.windows.1 + diff --git a/0026-AutoFDO-Enable-discriminator-and-MCF-algorithm-on-Au.patch b/0026-AutoFDO-Enable-discriminator-and-MCF-algorithm-on-Au.patch new file mode 100644 index 0000000..bbc98c6 --- /dev/null +++ b/0026-AutoFDO-Enable-discriminator-and-MCF-algorithm-on-Au.patch @@ -0,0 +1,353 @@ +From eb58d920a95696d8d5a7db9a6d640d4494fb023f Mon Sep 17 00:00:00 2001 +From: liyancheng <412998149@qq.com> +Date: Tue, 25 Jan 2022 16:57:28 +0800 +Subject: [PATCH 26/28] [AutoFDO] Enable discriminator and MCF algorithm on + AutoFDO + +1. Support discriminator for distinguishes among several + basic blocks that share a common locus, allowing for + more accurate autofdo. + +2. Using option -fprofile-correction for calling MCF algorithm + to smooth non conservative BB counts. +--- + gcc/auto-profile.c | 172 ++++++++++++++++++++++++++++++++++++++++++++- + gcc/cfghooks.c | 7 ++ + gcc/ipa-cp.c | 21 ++++++ + gcc/opts.c | 5 +- + gcc/tree-inline.c | 14 ++++ + 5 files changed, 215 insertions(+), 4 deletions(-) + +diff --git a/gcc/auto-profile.c b/gcc/auto-profile.c +index aced8fca5..e6164b91b 100644 +--- a/gcc/auto-profile.c ++++ b/gcc/auto-profile.c +@@ -678,6 +678,17 @@ string_table::get_index (const char *name) const + if (name == NULL) + return -1; + string_index_map::const_iterator iter = map_.find (name); ++ /* Function name may be duplicate. Try to distinguish by the ++ #file_name#function_name defined by the autofdo tool chain. */ ++ if (iter == map_.end ()) ++ { ++ char* file_name = get_original_name (lbasename (dump_base_name)); ++ char* file_func_name ++ = concat ("#", file_name, "#", name, NULL); ++ iter = map_.find (file_func_name); ++ free (file_name); ++ free (file_func_name); ++ } + if (iter == map_.end ()) + return -1; + +@@ -866,7 +877,7 @@ function_instance::read_function_instance (function_instance_stack *stack, + + for (unsigned i = 0; i < num_pos_counts; i++) + { +- unsigned offset = gcov_read_unsigned () & 0xffff0000; ++ unsigned offset = gcov_read_unsigned (); + unsigned num_targets = gcov_read_unsigned (); + gcov_type count = gcov_read_counter (); + s->pos_counts[offset].count = count; +@@ -945,6 +956,10 @@ autofdo_source_profile::get_count_info (gimple *stmt, count_info *info) const + function_instance *s = get_function_instance_by_inline_stack (stack); + if (s == NULL) + return false; ++ if (s->get_count_info (stack[0].second + stmt->bb->discriminator, info)) ++ { ++ return true; ++ } + return s->get_count_info (stack[0].second, info); + } + +@@ -1583,6 +1598,68 @@ afdo_propagate (bb_set *annotated_bb) + } + } + ++/* Process the following scene when the branch probability ++ inversion when do function afdo_propagate (). E.g. ++ BB_NUM (sample count) ++ BB1 (1000) ++ / \ ++ BB2 (10) BB3 (0) ++ \ / ++ BB4 ++ In afdo_propagate(), count of BB3 is calculated by ++ COUNT (BB3) = 990 (990 = COUNT (BB1) - COUNT (BB2) = 1000 - 10) ++ ++ In fact, BB3 may be colder than BB2 by sample count. ++ ++ This function allocate source BB count to each succ BB by sample ++ rate, E.g. ++ BB2_COUNT = BB1_COUNT * (BB2_COUNT / (BB2_COUNT + BB3_COUNT)) */ ++ ++static void ++afdo_preprocess_bb_count () ++{ ++ basic_block bb; ++ FOR_ALL_BB_FN (bb, cfun) ++ { ++ if (bb->count.ipa_p () && EDGE_COUNT (bb->succs) > 1 ++ && bb->count > profile_count::zero ().afdo ()) ++ { ++ basic_block bb1 = EDGE_SUCC (bb, 0)->dest; ++ basic_block bb2 = EDGE_SUCC (bb, 1)->dest; ++ if (single_succ_p (bb1) && single_succ_p (bb2) ++ && EDGE_SUCC (bb1, 0)->dest == EDGE_SUCC (bb2, 0)->dest) ++ { ++ gcov_type max_count = 0; ++ gcov_type total_count = 0; ++ edge e; ++ edge_iterator ei; ++ FOR_EACH_EDGE (e, ei, bb->succs) ++ { ++ if (!e->dest->count.ipa_p ()) ++ { ++ continue; ++ } ++ max_count = MAX(max_count, e->dest->count.to_gcov_type ()); ++ total_count += e->dest->count.to_gcov_type (); ++ } ++ /* Only bb_count > max_count * 2, branch probability will ++ inversion. */ ++ if (max_count > 0 ++ && bb->count.to_gcov_type () > max_count * 2) ++ { ++ FOR_EACH_EDGE (e, ei, bb->succs) ++ { ++ gcov_type target_count = bb->count.to_gcov_type () ++ * e->dest->count.to_gcov_type () / total_count; ++ e->dest->count ++ = profile_count::from_gcov_type (target_count).afdo (); ++ } ++ } ++ } ++ } ++ } ++} ++ + /* Propagate counts on control flow graph and calculate branch + probabilities. */ + +@@ -1608,6 +1685,7 @@ afdo_calculate_branch_prob (bb_set *annotated_bb) + } + + afdo_find_equiv_class (annotated_bb); ++ afdo_preprocess_bb_count (); + afdo_propagate (annotated_bb); + + FOR_EACH_BB_FN (bb, cfun) +@@ -1711,6 +1789,82 @@ afdo_vpt_for_early_inline (stmt_set *promoted_stmts) + return false; + } + ++/* Preparation before executing MCF algorithm. */ ++ ++static void ++afdo_init_mcf () ++{ ++ basic_block bb; ++ edge e; ++ edge_iterator ei; ++ ++ if (dump_file) ++ { ++ fprintf (dump_file, "\n init calling mcf_smooth_cfg (). \n"); ++ } ++ ++ /* Step1: when use mcf, BB id must be continous, ++ so we need compact_blocks (). */ ++ compact_blocks (); ++ ++ /* Step2: allocate memory for MCF input data. */ ++ bb_gcov_counts.safe_grow_cleared (cfun->cfg->x_last_basic_block); ++ edge_gcov_counts = new hash_map<edge, gcov_type>; ++ ++ /* Step3: init MCF input data from cfg. */ ++ FOR_ALL_BB_FN (bb, cfun) ++ { ++ /* Init BB count for MCF. */ ++ bb_gcov_count (bb) = bb->count.to_gcov_type (); ++ ++ gcov_type total_count = 0; ++ FOR_EACH_EDGE (e, ei, bb->succs) ++ { ++ total_count += e->dest->count.to_gcov_type (); ++ } ++ ++ /* If there is no sample in each successor blocks, source ++ BB samples are allocated to each edge by branch static prob. */ ++ ++ FOR_EACH_EDGE (e, ei, bb->succs) ++ { ++ if (total_count == 0) ++ { ++ edge_gcov_count (e) = e->src->count.to_gcov_type () ++ * e->probability.to_reg_br_prob_base () / REG_BR_PROB_BASE; ++ } ++ else ++ { ++ edge_gcov_count (e) = e->src->count.to_gcov_type () ++ * e->dest->count.to_gcov_type () / total_count; ++ } ++ } ++ } ++} ++ ++/* Free the resources used by MCF and reset BB count from MCF result, ++ branch probability has been updated in mcf_smooth_cfg (). */ ++ ++static void ++afdo_process_after_mcf () ++{ ++ basic_block bb; ++ /* Reset BB count from MCF result. */ ++ FOR_EACH_BB_FN (bb, cfun) ++ { ++ if (bb_gcov_count (bb)) ++ { ++ bb->count ++ = profile_count::from_gcov_type (bb_gcov_count (bb)).afdo (); ++ } ++ } ++ ++ /* Clean up MCF resource. */ ++ bb_gcov_counts.release (); ++ delete edge_gcov_counts; ++ edge_gcov_counts = NULL; ++} ++ + /* Annotate auto profile to the control flow graph. Do not annotate value + profile for stmts in PROMOTED_STMTS. */ + +@@ -1762,8 +1916,20 @@ afdo_annotate_cfg (const stmt_set &promoted_stmts) + afdo_source_profile->mark_annotated (cfun->function_end_locus); + if (max_count > profile_count::zero ()) + { +- /* Calculate, propagate count and probability information on CFG. */ +- afdo_calculate_branch_prob (&annotated_bb); ++ /* 1 means -fprofile-correction is enabled manually, and MCF ++ algorithm will be used to calculate count and probability. ++ Otherwise, use the default calculate algorithm. */ ++ if (flag_profile_correction == 1) ++ { ++ afdo_init_mcf (); ++ mcf_smooth_cfg (); ++ afdo_process_after_mcf (); ++ } ++ else ++ { ++ /* Calculate, propagate count and probability information on CFG. */ ++ afdo_calculate_branch_prob (&annotated_bb); ++ } + } + update_max_bb_count (); + profile_status_for_fn (cfun) = PROFILE_READ; +diff --git a/gcc/cfghooks.c b/gcc/cfghooks.c +index ea558b469..4ea490a8a 100644 +--- a/gcc/cfghooks.c ++++ b/gcc/cfghooks.c +@@ -526,6 +526,9 @@ split_block_1 (basic_block bb, void *i) + return NULL; + + new_bb->count = bb->count; ++ /* Copy discriminator from original bb for distinguishes among ++ several basic blocks that share a common locus, allowing for ++ more accurate autofdo. */ + new_bb->discriminator = bb->discriminator; + + if (dom_info_available_p (CDI_DOMINATORS)) +@@ -1091,6 +1094,10 @@ duplicate_block (basic_block bb, edge e, basic_block after, copy_bb_data *id) + move_block_after (new_bb, after); + + new_bb->flags = (bb->flags & ~BB_DUPLICATED); ++ /* Copy discriminator from original bb for distinguishes among ++ several basic blocks that share a common locus, allowing for ++ more accurate autofdo. */ ++ new_bb->discriminator = bb->discriminator; + FOR_EACH_EDGE (s, ei, bb->succs) + { + /* Since we are creating edges from a new block to successors +diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c +index b1f0881bd..c208070c9 100644 +--- a/gcc/ipa-cp.c ++++ b/gcc/ipa-cp.c +@@ -4365,6 +4365,27 @@ update_profiling_info (struct cgraph_node *orig_node, + orig_node_count.dump (dump_file); + fprintf (dump_file, "\n"); + } ++ ++ /* When autofdo uses PMU as the sampling unit, the count of ++ cgraph_node->count cannot be obtained directly and will ++ be zero. It using for apply_scale will cause the node ++ count incorrectly overestimated. So set orig_new_node_count ++ equal to orig_node_count, which is same as known error ++ handling. */ ++ if (orig_node->count == profile_count::zero ().afdo () ++ && new_node->count == profile_count::zero ().global0adjusted ()) ++ { ++ orig_new_node_count = (orig_sum + new_sum).apply_scale (12, 10); ++ ++ if (dump_file) ++ { ++ fprintf (dump_file, " node %s with zero count from afdo ", ++ new_node->dump_name ()); ++ fprintf (dump_file, " proceeding by pretending it was "); ++ orig_new_node_count.dump (dump_file); ++ fprintf (dump_file, "\n"); ++ } ++ } + } + + remainder = orig_node_count.combine_with_ipa_count (orig_node_count.ipa () +diff --git a/gcc/opts.c b/gcc/opts.c +index 642327296..7a39f618b 100644 +--- a/gcc/opts.c ++++ b/gcc/opts.c +@@ -2606,7 +2606,10 @@ common_handle_option (struct gcc_options *opts, + /* FALLTHRU */ + case OPT_fauto_profile: + enable_fdo_optimizations (opts, opts_set, value); +- SET_OPTION_IF_UNSET (opts, opts_set, flag_profile_correction, value); ++ /* 2 is special and means flag_profile_correction trun on by ++ -fauto-profile. */ ++ SET_OPTION_IF_UNSET (opts, opts_set, flag_profile_correction, ++ (value ? 2 : 0)); + SET_OPTION_IF_UNSET (opts, opts_set, + param_early_inliner_max_iterations, 10); + break; +diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c +index efde5d158..8405a959c 100644 +--- a/gcc/tree-inline.c ++++ b/gcc/tree-inline.c +@@ -2015,6 +2015,10 @@ copy_bb (copy_body_data *id, basic_block bb, + basic_block_info automatically. */ + copy_basic_block = create_basic_block (NULL, (basic_block) prev->aux); + copy_basic_block->count = bb->count.apply_scale (num, den); ++ /* Copy discriminator from original bb for distinguishes among ++ several basic blocks that share a common locus, allowing for ++ more accurate autofdo. */ ++ copy_basic_block->discriminator = bb->discriminator; + + copy_gsi = gsi_start_bb (copy_basic_block); + +@@ -3028,6 +3032,16 @@ copy_cfg_body (copy_body_data * id, + den += e->count (); + ENTRY_BLOCK_PTR_FOR_FN (cfun)->count = den; + } ++ /* When autofdo uses PMU as the sampling unit, the number of ++ ENTRY_BLOCK_PTR_FOR_FN cannot be obtained directly and will ++ be zero. It using for adjust_for_ipa_scaling will cause the ++ inlined BB count incorrectly overestimated. So set den equal ++ to num, which is the source inline BB count to avoid ++ overestimated. */ ++ if (den == profile_count::zero ().afdo ()) ++ { ++ den = num; ++ } + + profile_count::adjust_for_ipa_scaling (&num, &den); + +-- +2.27.0.windows.1 + diff --git a/0027-Autoprefetch-Support-auto-feedback-prefetch.patch b/0027-Autoprefetch-Support-auto-feedback-prefetch.patch new file mode 100644 index 0000000..c3dcf50 --- /dev/null +++ b/0027-Autoprefetch-Support-auto-feedback-prefetch.patch @@ -0,0 +1,1000 @@ +From 6b944bed1158d3454b1db27aeab4ec1f2b8e5866 Mon Sep 17 00:00:00 2001 +From: huangxiaoquan <huangxiaoquan1@huawei.com> +Date: Thu, 27 Jan 2022 18:24:53 +0800 +Subject: [PATCH 27/28] [Autoprefetch] Support auto feedback prefetch + +1.Add option -fprefetch-loop-arrays=[value]. + +2.A prefetch distance analysis algorithm based on branch weight + is proposed to improve the accuracy of prefetch distance. + +3.Propose automatic feedback prefetching: + use the cache-miss profile information to guide the insertion of + prefetching instructions. +--- + gcc/auto-profile.c | 5 +- + gcc/common.opt | 5 + + gcc/opts.c | 7 + + gcc/params.opt | 16 + + gcc/tree-ssa-loop-prefetch.c | 735 ++++++++++++++++++++++++++++++++++- + 5 files changed, 748 insertions(+), 20 deletions(-) + +diff --git a/gcc/auto-profile.c b/gcc/auto-profile.c +index e6164b91b..f221978fc 100644 +--- a/gcc/auto-profile.c ++++ b/gcc/auto-profile.c +@@ -21,6 +21,8 @@ along with GCC; see the file COPYING3. If not see + #include "config.h" + #define INCLUDE_MAP + #define INCLUDE_SET ++#define INCLUDE_ALGORITHM ++#define INCLUDE_VECTOR + #include "system.h" + #include "coretypes.h" + #include "backend.h" +@@ -49,9 +51,6 @@ along with GCC; see the file COPYING3. If not see + #include "auto-profile.h" + #include "tree-pretty-print.h" + #include "gimple-pretty-print.h" +-#include <map> +-#include <vector> +-#include <algorithm> + + /* The following routines implements AutoFDO optimization. + +diff --git a/gcc/common.opt b/gcc/common.opt +index 37cbbd8c0..9488bd90f 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -2201,6 +2201,11 @@ fprefetch-loop-arrays + Common Report Var(flag_prefetch_loop_arrays) Init(-1) Optimization + Generate prefetch instructions, if available, for arrays in loops. + ++fprefetch-loop-arrays= ++Common Joined RejectNegative UInteger Var(prefetch_level) Init(0) IntegerRange(0, 3) ++Generate prefetch instructions, if available, for arrays in loops. The prefetch ++level can control the optimize level to array prefetch. ++ + fprofile + Common Report Var(profile_flag) + Enable basic program profiling code. +diff --git a/gcc/opts.c b/gcc/opts.c +index 7a39f618b..f49f5ee58 100644 +--- a/gcc/opts.c ++++ b/gcc/opts.c +@@ -1747,6 +1747,8 @@ set_cache_misses_profile_params (struct gcc_options *opts, + struct gcc_options *opts_set) + { + SET_OPTION_IF_UNSET (opts, opts_set, flag_prefetch_loop_arrays, 1); ++ SET_OPTION_IF_UNSET (opts, opts_set, prefetch_level, 2); ++ SET_OPTION_IF_UNSET (opts, opts_set, param_simultaneous_prefetches, 100); + } + + /* -f{,no-}sanitize{,-recover}= suboptions. */ +@@ -2645,6 +2647,11 @@ common_handle_option (struct gcc_options *opts, + SET_OPTION_IF_UNSET (opts, opts_set, flag_ipa_bit_cp, value); + break; + ++ case OPT_fprefetch_loop_arrays_: ++ opts->x_prefetch_level = value; ++ opts->x_flag_prefetch_loop_arrays = true; ++ break; ++ + case OPT_fpatchable_function_entry_: + { + char *patch_area_arg = xstrdup (arg); +diff --git a/gcc/params.opt b/gcc/params.opt +index 2db69cc87..9d1faa7ab 100644 +--- a/gcc/params.opt ++++ b/gcc/params.opt +@@ -968,4 +968,20 @@ Bound on number of runtime checks inserted by the vectorizer's loop versioning f + Common Joined UInteger Var(param_vect_max_version_for_alignment_checks) Init(6) Param Optimization + Bound on number of runtime checks inserted by the vectorizer's loop versioning for alignment check. + ++-param=param-prefetch-func-topn= ++Common Joined UInteger Var(param_prefetch_func_topn) Init(3) Param Optimization ++TopN functions of cache miss counts to be analyzed in prefetching. ++ ++-param=param-prefetch-ref-topn= ++Common Joined UInteger Var(param_prefetch_ref_topn) Init(5) Param Optimization ++TopN ref of cache miss counts to be analyzed in prefetching. ++ ++-param=param-high-loop-execution-rate= ++Common Joined UInteger Var(param_high_loop_execution_rate) Init(95) IntegerRange(0, 100) Param Optimization ++High execution rate loops to be analyzed in prefetch (in%). ++ ++-param=param-prefetch-func-counts-threshold= ++Common Joined UInteger Var(param_prefetch_func_counts_threshold) Init(100) Param Optimization ++Threshold functions of cache miss counts to be analyzed in prefetching. ++ + ; This comment is to ensure we retain the blank line above. +diff --git a/gcc/tree-ssa-loop-prefetch.c b/gcc/tree-ssa-loop-prefetch.c +index d19ece641..3a5aef0fc 100644 +--- a/gcc/tree-ssa-loop-prefetch.c ++++ b/gcc/tree-ssa-loop-prefetch.c +@@ -18,6 +18,9 @@ along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + + #include "config.h" ++#define INCLUDE_ALGORITHM ++#define INCLUDE_MAP ++#define INCLUDE_VECTOR + #include "system.h" + #include "coretypes.h" + #include "backend.h" +@@ -48,6 +51,11 @@ along with GCC; see the file COPYING3. If not see + #include "tree-data-ref.h" + #include "diagnostic-core.h" + #include "dbgcnt.h" ++#include "gimple-pretty-print.h" ++#include "tree-cfg.h" ++#include "auto-profile.h" ++#include "cgraph.h" ++#include "print-tree.h" + + /* This pass inserts prefetch instructions to optimize cache usage during + accesses to arrays in loops. It processes loops sequentially and: +@@ -253,6 +261,22 @@ struct mem_ref_group + #define PREFETCH_MAX_MEM_REFS_PER_LOOP 200 + #endif + ++#ifndef PREFETCH_FUNC_TOPN ++#define PREFETCH_FUNC_TOPN param_prefetch_func_topn ++#endif ++ ++#ifndef PREFETCH_FUNC_COUNTS_THRESHOLD ++#define PREFETCH_FUNC_COUNTS_THRESHOLD param_prefetch_func_counts_threshold ++#endif ++ ++#ifndef PREFETCH_REF_TOPN ++#define PREFETCH_REF_TOPN param_prefetch_ref_topn ++#endif ++ ++#ifndef LOOP_EXECUTION_RATE ++#define LOOP_EXECUTION_RATE param_high_loop_execution_rate ++#endif ++ + /* The memory reference. */ + + struct mem_ref +@@ -279,6 +303,131 @@ struct mem_ref + nontemporal one. */ + }; + ++/* Probability information of basic blocks and branches. */ ++struct bb_bp ++{ ++ basic_block bb; ++ basic_block true_edge_bb; ++ basic_block false_edge_bb; ++ float true_edge_prob; ++ float false_edge_prob; ++ float bb_prob; ++}; ++ ++typedef struct bb_bp bb_bp; ++ ++enum PREFETCH_MODE ++{ ++ ORIGINAL_MODE=0, /* Original prefetch method. */ ++ REFINE_BB_AHEAD, ++ /* Prefetch distance algorithm for removing ++ irrelevant bb. */ ++ BRANCH_WEIGHTED_AHEAD, ++ /* Branch weighted prefetch ++ distance algorithm. */ ++ INDIRECT_MODE /* Indirect array prefetch mode. */ ++}; ++ ++typedef std::map <unsigned int, unsigned int> uid_rank_map; ++typedef std::map <location_t, unsigned int> loc_rank_map; ++typedef std::vector <std::pair<location_t, gcov_type> > loc_gcov_type_vec; ++typedef std::map <location_t, std::vector<gimple *> > loc_gimple_vec_map; ++ ++static loc_rank_map ref_rank; ++ ++/* Callback function for event_count comparison. */ ++ ++static bool ++event_count_cmp (std::pair<unsigned int, gcov_type> &a, ++ std::pair<unsigned int, gcov_type> &b) ++{ ++ return a.second > b.second; ++} ++ ++/* Prepared mappings from location to counts and from location ++ to stmt list. */ ++ ++static void ++prepare_loc_count_info (function *fun, loc_gcov_type_vec &ref_sorted, ++ loc_gimple_vec_map &loc_stmt, event_type event) ++{ ++ basic_block bb = NULL; ++ gimple_stmt_iterator bsi; ++ gimple *stmt; ++ tree lhs = NULL_TREE; ++ tree rhs = NULL_TREE; ++ ++ FOR_EACH_BB_FN (bb, fun) ++ { ++ for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi)) ++ { ++ stmt = gsi_stmt (bsi); ++ if (gimple_code (stmt) != GIMPLE_ASSIGN) ++ { ++ continue; ++ } ++ if (!gimple_vuse (stmt)) ++ { ++ continue; ++ } ++ lhs = gimple_assign_lhs (stmt); ++ rhs = gimple_assign_rhs1 (stmt); ++ if (REFERENCE_CLASS_P (rhs) || REFERENCE_CLASS_P (lhs)) ++ { ++ gcov_type loc_count = ++ event_get_loc_count (gimple_location (stmt), event); ++ if (loc_count > 0) ++ { ++ /* There may be multiple gimple correspond to the same ++ location. */ ++ if (loc_stmt.count (gimple_location (stmt)) == 0) ++ { ++ ref_sorted.push_back (std::make_pair (gimple_location (stmt), ++ loc_count)); ++ } ++ loc_stmt[gimple_location (stmt)].push_back (stmt); ++ } ++ } ++ } ++ } ++} ++ ++/* Sort references by event_count and dump loc count information after ++ sorting. */ ++ ++static void ++sort_ref_by_event_count (function *fun, event_type event) ++{ ++ loc_gcov_type_vec ref_sorted; ++ loc_gimple_vec_map loc_stmt; ++ ++ prepare_loc_count_info (fun, ref_sorted, loc_stmt, event); ++ sort (ref_sorted.begin (), ref_sorted.end (), event_count_cmp); ++ ++ for (unsigned i = 0; i < ref_sorted.size (); ++i) ++ { ++ ref_rank[ref_sorted[i].first] = i + 1; ++ /* Print the stmt and count of the topn ref. */ ++ if (i < PREFETCH_REF_TOPN && dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "stmt: \n"); ++ for (unsigned j = 0; j < loc_stmt[ref_sorted[i].first].size (); ++ ++j) ++ { ++ print_gimple_stmt (dump_file, ++ loc_stmt[ref_sorted[i].first][j], 0); ++ } ++ gcov_type loc_count = ++ event_get_loc_count (ref_sorted[i].first, event); ++ fprintf (dump_file, "stmt loc %u counts is %lu: " ++ "rank %d in top %d, (candidate analysis)\n\n", ++ ref_sorted[i].first, loc_count, ++ ref_rank[ref_sorted[i].first], PREFETCH_REF_TOPN); ++ } ++ } ++ return; ++} ++ + /* Dumps information about memory reference */ + static void + dump_mem_details (FILE *file, tree base, tree step, +@@ -479,6 +628,30 @@ idx_analyze_ref (tree base, tree *index, void *data) + return true; + } + ++/* Dumps information about ar_data structure. */ ++ ++static void ++dump_ar_data_details (FILE *file, tree ref, struct ar_data &ar_data) ++{ ++ print_generic_expr (file, ref, TDF_SLIM); ++ fprintf (file, "\n"); ++ if (*(ar_data.step)) ++ { ++ fprintf (file, " step "); ++ if (cst_and_fits_in_hwi (*(ar_data.step))) ++ fprintf (file, HOST_WIDE_INT_PRINT_DEC, ++ int_cst_value (*(ar_data.step))); ++ else ++ print_generic_expr (file, *(ar_data.step), TDF_SLIM); ++ } ++ fprintf (file, "\n"); ++ if (*(ar_data.delta)) ++ { ++ fprintf (file, " delta " HOST_WIDE_INT_PRINT_DEC "\n", ++ *(ar_data.delta)); ++ } ++} ++ + /* Tries to express REF_P in shape &BASE + STEP * iter + DELTA, where DELTA and + STEP are integer constants and iter is number of iterations of LOOP. The + reference occurs in statement STMT. Strips nonaddressable component +@@ -526,7 +699,17 @@ analyze_ref (class loop *loop, tree *ref_p, tree *base, + ar_data.stmt = stmt; + ar_data.step = step; + ar_data.delta = delta; +- return for_each_index (base, idx_analyze_ref, &ar_data); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ dump_ar_data_details (dump_file, ref, ar_data); ++ } ++ bool idx_flag = for_each_index (base, idx_analyze_ref, &ar_data); ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "idx_flag = %d \n\n", idx_flag); ++ } ++ return idx_flag; + } + + /* Record a memory reference REF to the list REFS. The reference occurs in +@@ -601,6 +784,55 @@ gather_memory_references_ref (class loop *loop, struct mem_ref_group **refs, + return true; + } + ++/* Determine whether to collect the memory references based on the ++ ranking of ref cache miss counts. */ ++ ++static bool ++should_gather_memory_references (gimple *stmt) ++{ ++ if (!(profile_exist (CACHE_MISSES))) ++ { ++ return true; ++ } ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "stmt:"); ++ print_gimple_stmt (dump_file, stmt, 0); ++ fprintf (dump_file, "\n"); ++ } ++ if (ref_rank.count (gimple_location (stmt)) == 0) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "stmt location no found, skip prefetch " ++ "analysis\n"); ++ } ++ return false; ++ } ++ gcov_type loc_count = event_get_loc_count (gimple_location (stmt), CACHE_MISSES); ++ if (ref_rank[gimple_location (stmt)] > PREFETCH_REF_TOPN) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "stmt loc %u counts is %lu:" ++ "rank %d exceed topn %d, skip prefetch " ++ "analysis\n", ++ gimple_location (stmt), loc_count, ++ ref_rank[gimple_location (stmt)], PREFETCH_REF_TOPN); ++ } ++ return false; ++ } ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "stmt loc %u counts is %lu: rank %d in top %d," ++ "continue prefetch analysis\n", ++ gimple_location (stmt), loc_count, ++ ref_rank[gimple_location (stmt)], PREFETCH_REF_TOPN); ++ } ++ return true; ++} ++ + /* Record the suitable memory references in LOOP. NO_OTHER_REFS is set to + true if there are no other memory references inside the loop. */ + +@@ -626,6 +858,13 @@ gather_memory_references (class loop *loop, bool *no_other_refs, unsigned *ref_c + if (bb->loop_father != loop) + continue; + ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "==== the %dth loop bb body ====\n", i); ++ gimple_dump_bb (dump_file, bb, 0, dump_flags); ++ fprintf (dump_file, "\n"); ++ } ++ + for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi)) + { + stmt = gsi_stmt (bsi); +@@ -642,20 +881,31 @@ gather_memory_references (class loop *loop, bool *no_other_refs, unsigned *ref_c + if (! gimple_vuse (stmt)) + continue; + ++ if (!should_gather_memory_references (stmt)) ++ continue; ++ + lhs = gimple_assign_lhs (stmt); + rhs = gimple_assign_rhs1 (stmt); + + if (REFERENCE_CLASS_P (rhs)) + { +- *no_other_refs &= gather_memory_references_ref (loop, &refs, +- rhs, false, stmt); +- *ref_count += 1; ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "====> the %dth ref \n", *ref_count); ++ } ++ *no_other_refs &= gather_memory_references_ref (loop, &refs, rhs, ++ false, stmt); ++ *ref_count += 1; + } + if (REFERENCE_CLASS_P (lhs)) + { +- *no_other_refs &= gather_memory_references_ref (loop, &refs, +- lhs, true, stmt); +- *ref_count += 1; ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "====> the %dth ref \n", *ref_count); ++ } ++ *no_other_refs &= gather_memory_references_ref (loop, &refs, lhs, ++ true, stmt); ++ *ref_count += 1; + } + } + } +@@ -1168,9 +1418,9 @@ issue_prefetch_ref (struct mem_ref *ref, unsigned unroll_factor, unsigned ahead) + bool nontemporal = ref->reuse_distance >= L2_CACHE_SIZE_BYTES; + + if (dump_file && (dump_flags & TDF_DETAILS)) +- fprintf (dump_file, "Issued%s prefetch for reference %u:%u.\n", +- nontemporal ? " nontemporal" : "", +- ref->group->uid, ref->uid); ++ fprintf (dump_file, "Issued%s prefetch for reference %u:%u.\n", ++ nontemporal ? " nontemporal" : "", ++ ref->group->uid, ref->uid); + + bsi = gsi_for_stmt (ref->stmt); + +@@ -1875,6 +2125,306 @@ insn_to_prefetch_ratio_too_small_p (unsigned ninsns, unsigned prefetch_count, + return false; + } + ++/* Obtain the edge probability information of each basic block in the loop. */ ++ ++static float ++get_edge_prob (edge e) ++{ ++ /* Limit the minimum probability value. */ ++ const float MINNUM_PROB = 0.00001f; ++ float fvalue = 1; ++ ++ profile_probability probability = e->probability; ++ if (probability.initialized_p ()) ++ { ++ fvalue = probability.to_reg_br_prob_base () / float (REG_BR_PROB_BASE); ++ if (fvalue < MINNUM_PROB && probability.to_reg_br_prob_base ()) ++ { ++ fvalue = MINNUM_PROB; ++ } ++ } ++ return fvalue; ++} ++ ++ ++/* Dump the bb information in a loop. */ ++ ++static void ++dump_loop_bb (struct loop *loop) ++{ ++ basic_block *body = get_loop_body_in_dom_order (loop); ++ basic_block bb = NULL; ++ ++ for (unsigned i = 0; i < loop->num_nodes; i++) ++ { ++ bb = body[i]; ++ if (bb->loop_father != loop) ++ { ++ continue; ++ } ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "===== the %dth loop bb body ======= \n", i); ++ gimple_dump_bb (dump_file, bb, 0, dump_flags); ++ fprintf (dump_file, "\n"); ++ } ++ } ++ free (body); ++} ++ ++ ++/* Obtain the branch probability information of each basic block ++ in the loop. */ ++ ++static void ++get_bb_branch_prob (hash_map <basic_block, bb_bp> &bb_branch_prob, ++ struct loop *loop) ++{ ++ basic_block *body = get_loop_body (loop); ++ basic_block bb = NULL; ++ for (unsigned i = 0; i < loop->num_nodes; i++) ++ { ++ bb = body[i]; ++ if (bb->loop_father != loop) ++ { ++ continue; ++ } ++ bb_bp &branch_prob = bb_branch_prob.get_or_insert (bb); ++ branch_prob.bb = bb; ++ branch_prob.true_edge_bb = NULL; ++ branch_prob.false_edge_bb = NULL; ++ branch_prob.true_edge_prob = 0; ++ branch_prob.false_edge_prob = 0; ++ branch_prob.bb_prob = 0; ++ ++ gimple *stmt = last_stmt (bb); ++ if (stmt && gimple_code (stmt) == GIMPLE_COND) ++ { ++ if (EDGE_COUNT (bb->succs) != 2) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "The number of successful edges of bb" ++ "is abnormal\n"); ++ continue; ++ } ++ edge true_edge = NULL; ++ edge false_edge = NULL; ++ extract_true_false_edges_from_block (bb, &true_edge, &false_edge); ++ ++ /* If it is exiting bb, and the destination bb of the edge does not ++ belong to the current loop, the information of the edge is not ++ recorded. */ ++ if (true_edge->dest->loop_father == loop) ++ { ++ branch_prob.true_edge_bb = true_edge->dest; ++ branch_prob.true_edge_prob = get_edge_prob (true_edge); ++ } ++ if (false_edge->dest->loop_father == loop) ++ { ++ branch_prob.false_edge_bb = false_edge->dest; ++ branch_prob.false_edge_prob = get_edge_prob (false_edge); ++ } ++ } ++ ++ edge e = find_fallthru_edge (bb->succs); ++ if (e) ++ { ++ branch_prob.true_edge_bb = e->dest; ++ branch_prob.true_edge_prob = get_edge_prob (e); ++ } ++ } ++} ++ ++/* Traverse each bb in the loop and prune fake loops. */ ++ ++static bool ++traverse_prune_bb_branch (hash_map <basic_block, bb_bp> &bb_branch_prob, ++ int& max_path, hash_set <basic_block> &path_node, ++ basic_block current_bb, basic_block latch_bb) ++{ ++ /* Limit the maximum number of analysis paths. */ ++ if (max_path <= 0 || current_bb == NULL) ++ return false; ++ ++ /* Do not join edges that do not form a complete loop. */ ++ bb_bp *bb_bp_node = bb_branch_prob.get (current_bb); ++ if (bb_bp_node == NULL || (bb_bp_node->true_edge_bb == NULL ++ && bb_bp_node->false_edge_bb == NULL)) ++ return false; ++ ++ if (current_bb == latch_bb) ++ { ++ max_path--; ++ return true; ++ } ++ ++ /* Do not join edges that return to non-dominate nodes. */ ++ if (path_node.contains (bb_bp_node->true_edge_bb) ++ || path_node.contains (bb_bp_node->false_edge_bb)) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "fake loop: in bb%d\n", current_bb->index); ++ return false; ++ } ++ ++ path_node.add (current_bb); ++ if (bb_bp_node->true_edge_bb) ++ { ++ if (traverse_prune_bb_branch (bb_branch_prob, max_path, ++ path_node, bb_bp_node->true_edge_bb, latch_bb) == false) ++ return false; ++ } ++ if (bb_bp_node->false_edge_bb) ++ { ++ if (traverse_prune_bb_branch (bb_branch_prob, max_path, ++ path_node, bb_bp_node->false_edge_bb, latch_bb) == false) ++ return false; ++ } ++ path_node.remove (current_bb); ++ ++ max_path--; ++ return true; ++} ++ ++/* Traverse and calculate the probability of basic block. */ ++ ++static void ++traverse_calculate_bb_prob (hash_map <basic_block, bb_bp> &bb_branch_prob, ++ basic_block current_bb, basic_block latch_bb, ++ float prob) ++{ ++ /* Limit bb block access probability, the probability is ++ less than 100% and include delta. */ ++ const float MAX_BB_PROBABILITY = 1.001f; ++ ++ if (current_bb == NULL) ++ { ++ return; ++ } ++ bb_bp *bb_bp_node = bb_branch_prob.get (current_bb); ++ bb_bp_node->bb_prob += prob; ++ ++ gcc_assert (bb_bp_node->bb_prob <= MAX_BB_PROBABILITY); ++ ++ if (bb_bp_node == NULL || (bb_bp_node->true_edge_bb == NULL ++ && bb_bp_node->false_edge_bb == NULL)) ++ { ++ return; ++ } ++ if (current_bb == latch_bb) ++ { ++ return; ++ } ++ ++ bool assign = (bb_bp_node->true_edge_bb && bb_bp_node->false_edge_bb); ++ if (bb_bp_node->true_edge_bb) ++ { ++ float assign_prob = assign ? bb_bp_node->true_edge_prob * prob : prob; ++ traverse_calculate_bb_prob (bb_branch_prob, ++ bb_bp_node->true_edge_bb, latch_bb, assign_prob); ++ } ++ if (bb_bp_node->false_edge_bb) ++ { ++ float assign_prob = assign ? bb_bp_node->false_edge_prob * prob : prob; ++ traverse_calculate_bb_prob (bb_branch_prob, ++ bb_bp_node->false_edge_bb, latch_bb, assign_prob); ++ } ++ return; ++} ++ ++/* Obtain the probability of basic block. */ ++ ++static bool ++get_bb_prob (hash_map <basic_block, bb_bp> &bb_branch_prob, struct loop *loop) ++{ ++ /* The upper limit of the branch path in the loop is 10000. */ ++ const int MAX_BB_BRANCH_PATH = 10000; ++ ++ if (loop->header == NULL || loop->latch == NULL ++ || loop->header == loop->latch) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "get_bb_prob failed: without the header bb or " ++ "latch bb\n"); ++ return false; ++ } ++ ++ bb_bp *latch_branch_prob = bb_branch_prob.get (loop->latch); ++ bb_bp *header_branch_prob = bb_branch_prob.get (loop->header); ++ if (header_branch_prob == NULL || latch_branch_prob == NULL ++ || (latch_branch_prob->true_edge_bb != header_branch_prob->bb ++ && latch_branch_prob->false_edge_bb != header_branch_prob->bb)) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "get_bb_prob failed: loop data exception\n"); ++ return false; ++ } ++ ++ hash_set <basic_block> path_node; ++ int max_path = MAX_BB_BRANCH_PATH; ++ if (traverse_prune_bb_branch (bb_branch_prob, max_path, path_node, ++ header_branch_prob->bb, loop->latch) == false) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "traverse_prune_bb_branch false.\n"); ++ return false; ++ } ++ traverse_calculate_bb_prob (bb_branch_prob, ++ header_branch_prob->bb, loop->latch, 1); ++ ++ return true; ++} ++ ++/* Computes an estimated number of insns in LOOP, weighted by WEIGHTS. */ ++ ++static unsigned ++estimate_num_loop_insns (struct loop *loop, eni_weights *weights) ++{ ++ basic_block *body = get_loop_body_in_dom_order (loop); ++ gimple_stmt_iterator gsi; ++ float size = 0; ++ basic_block bb = NULL; ++ hash_map <basic_block, bb_bp> bb_branch_prob; ++ ++ if (prefetch_level >= BRANCH_WEIGHTED_AHEAD) ++ { ++ get_bb_branch_prob (bb_branch_prob, loop); ++ if (get_bb_prob (bb_branch_prob, loop) == false) ++ { ++ dump_loop_bb (loop); ++ return 0; ++ } ++ } ++ ++ for (unsigned i = 0; i < loop->num_nodes; i++) ++ { ++ bb = body[i]; ++ /* For nested loops, the bb of the inner loop is not calculated. */ ++ if (bb->loop_father != loop) ++ { ++ continue; ++ } ++ ++ float size_tmp = 0; ++ for (gsi = gsi_start_bb (body[i]); !gsi_end_p (gsi); gsi_next (&gsi)) ++ { ++ size_tmp += estimate_num_insns (gsi_stmt (gsi), weights); ++ } ++ ++ if (prefetch_level >= BRANCH_WEIGHTED_AHEAD) ++ { ++ float bb_prob = bb_branch_prob.get (bb)->bb_prob; ++ size += size_tmp * bb_prob; ++ } ++ else ++ { ++ size += size_tmp; ++ } ++ } ++ free (body); ++ ++ return unsigned (size); ++} + + /* Issue prefetch instructions for array references in LOOP. Returns + true if the LOOP was unrolled. */ +@@ -1899,7 +2449,15 @@ loop_prefetch_arrays (class loop *loop) + + /* FIXME: the time should be weighted by the probabilities of the blocks in + the loop body. */ +- time = tree_num_loop_insns (loop, &eni_time_weights); ++ ++ if (prefetch_level >= REFINE_BB_AHEAD) ++ { ++ time = estimate_num_loop_insns (loop, &eni_time_weights); ++ } ++ else ++ { ++ time = tree_num_loop_insns (loop, &eni_time_weights); ++ } + if (time == 0) + return false; + +@@ -1913,7 +2471,14 @@ loop_prefetch_arrays (class loop *loop) + if (trip_count_to_ahead_ratio_too_small_p (ahead, est_niter)) + return false; + +- ninsns = tree_num_loop_insns (loop, &eni_size_weights); ++ if (prefetch_level >= REFINE_BB_AHEAD) ++ { ++ ninsns = estimate_num_loop_insns (loop, &eni_size_weights); ++ } ++ else ++ { ++ ninsns = tree_num_loop_insns (loop, &eni_size_weights); ++ } + + /* Step 1: gather the memory references. */ + refs = gather_memory_references (loop, &no_other_refs, &mem_ref_count); +@@ -1978,10 +2543,49 @@ fail: + return unrolled; + } + ++/* Determine if it is a high execution rate loop. */ ++ ++static bool ++is_high_exec_rate_loop (struct loop *loop) ++{ ++ vec<edge> exit_edges = get_loop_exit_edges (loop); ++ if (exit_edges == vNULL) ++ { ++ return false; ++ } ++ ++ unsigned i = 0; ++ gcov_type exit_count = 0; ++ edge e = NULL; ++ float loop_exec_rate = 0; ++ gcov_type header_bb_count = loop->header->count.to_gcov_type (); ++ FOR_EACH_VEC_ELT (exit_edges, i, e) ++ { ++ gcov_type exiting_bb_count = e->src->count.to_gcov_type (); ++ float exit_edge_prob = get_edge_prob (e); ++ exit_count += exit_edge_prob * exiting_bb_count; ++ ++ loop_exec_rate = 1.0 - ((double) exit_count / header_bb_count); ++ ++ if (loop_exec_rate < (float) LOOP_EXECUTION_RATE / 100.0) ++ { ++ return false; ++ } ++ } ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "loop with high execution rate: %f >= %f\n\n", ++ loop_exec_rate, (float) LOOP_EXECUTION_RATE / 100.0); ++ dump_loop_bb (loop); ++ } ++ return true; ++} ++ + /* Issue prefetch instructions for array references in loops. */ + + unsigned int +-tree_ssa_prefetch_arrays (void) ++tree_ssa_prefetch_arrays (function *fun) + { + class loop *loop; + bool unrolled = false; +@@ -2012,6 +2616,12 @@ tree_ssa_prefetch_arrays (void) + param_min_insn_to_prefetch_ratio); + fprintf (dump_file, " min insn-to-mem ratio: %d \n", + param_prefetch_min_insn_to_mem_ratio); ++ fprintf (dump_file, " prefetch_func_topn: %d \n", ++ param_prefetch_func_topn); ++ fprintf (dump_file, " prefetch_ref_topn: %d \n", ++ param_prefetch_ref_topn); ++ fprintf (dump_file, " high_loop_execution_rate: %d \n", ++ LOOP_EXECUTION_RATE); + fprintf (dump_file, "\n"); + } + +@@ -2028,13 +2638,42 @@ tree_ssa_prefetch_arrays (void) + set_builtin_decl (BUILT_IN_PREFETCH, decl, false); + } + +- FOR_EACH_LOOP (loop, LI_FROM_INNERMOST) ++ enum li_flags LI = LI_FROM_INNERMOST; ++ ++ if (profile_exist (CACHE_MISSES)) ++ { ++ LI = LI_ONLY_INNERMOST; ++ } ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "Processing model %d:\n", LI); ++ } ++ ++ if (profile_exist (CACHE_MISSES)) ++ { ++ sort_ref_by_event_count (fun, CACHE_MISSES); ++ } ++ ++ FOR_EACH_LOOP (loop, LI) + { + if (dump_file && (dump_flags & TDF_DETAILS)) +- fprintf (dump_file, "Processing loop %d:\n", loop->num); ++ { ++ fprintf (dump_file, "======================================\n"); ++ fprintf (dump_file, "Processing loop %d:\n", loop->num); ++ fprintf (dump_file, "======================================\n"); ++ flow_loop_dump (loop, dump_file, NULL, 1); ++ fprintf (dump_file, "\n\n"); ++ } + +- unrolled |= loop_prefetch_arrays (loop); ++ if (profile_exist (CACHE_MISSES)) ++ { ++ if (!is_high_exec_rate_loop (loop)) ++ { ++ continue; ++ } ++ } + ++ unrolled |= loop_prefetch_arrays (loop); + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "\n\n"); + } +@@ -2049,6 +2688,56 @@ tree_ssa_prefetch_arrays (void) + return todo_flags; + } + ++/* Determine whether to analyze the function according to ++ the sorting of the function containing cache-miss counts. */ ++ ++static bool ++should_analyze_func_p (void) ++{ ++ gcov_type decl_uid = DECL_UID (current_function_decl); ++ struct rank_info func_rank_info = ++ event_get_func_rank (decl_uid, CACHE_MISSES); ++ if (func_rank_info.total == 0) ++ { ++ return false; ++ } ++ gcov_type func_count = event_get_func_count (decl_uid, CACHE_MISSES); ++ if (func_count == 0) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "function uid %d cannot find profile data " ++ "and skip prefetch analysis\n", ++ decl_uid); ++ } ++ return false; ++ } ++ if (func_rank_info.rank > PREFETCH_FUNC_TOPN ++ || func_count < PREFETCH_FUNC_COUNTS_THRESHOLD) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "function uid %d total counts is %lu: " ++ "rank %d > topn %d, counts %lu < threshold %lu " ++ "skip prefetch analysis\n", ++ decl_uid, func_count, ++ func_rank_info.rank, PREFETCH_FUNC_TOPN, ++ func_count, PREFETCH_FUNC_COUNTS_THRESHOLD); ++ } ++ return false; ++ } ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "function uid %d total counts is %lu: " ++ "rank %d in topn %d, counts %lu > threshold %lu " ++ "continue prefetch analysis\n", ++ decl_uid, func_count, ++ func_rank_info.rank, PREFETCH_FUNC_TOPN, ++ func_count, PREFETCH_FUNC_COUNTS_THRESHOLD); ++ } ++ return true; ++} ++ + /* Prefetching. */ + + namespace { +@@ -2085,6 +2774,18 @@ pass_loop_prefetch::execute (function *fun) + if (number_of_loops (fun) <= 1) + return 0; + ++ /* Filter only when combined with cache-miss. When the should_analyze_func_p ++ analysis fails (for example, the function without cache-miss count), ++ in order to ensure the accuracy of the prefetch analysis, the function ++ does not perform native prefetch processing. */ ++ if (profile_exist (CACHE_MISSES)) ++ { ++ if (!should_analyze_func_p ()) ++ { ++ return 0; ++ } ++ } ++ + if ((PREFETCH_BLOCK & (PREFETCH_BLOCK - 1)) != 0) + { + static bool warned = false; +@@ -2099,7 +2800,7 @@ pass_loop_prefetch::execute (function *fun) + return 0; + } + +- return tree_ssa_prefetch_arrays (); ++ return tree_ssa_prefetch_arrays (fun); + } + + } // anon namespace +-- +2.27.0.windows.1 + diff --git a/0028-AutoPrefetch-Handle-the-case-that-the-basic-block-br.patch b/0028-AutoPrefetch-Handle-the-case-that-the-basic-block-br.patch new file mode 100644 index 0000000..48c2e52 --- /dev/null +++ b/0028-AutoPrefetch-Handle-the-case-that-the-basic-block-br.patch @@ -0,0 +1,151 @@ +From 3d20b13bc2e5af8d52e221a33881423e38c3dfdd Mon Sep 17 00:00:00 2001 +From: dingguangya <dingguangya1@huawei.com> +Date: Thu, 17 Feb 2022 21:53:31 +0800 +Subject: [PATCH 28/28] [AutoPrefetch] Handle the case that the basic block + branch probability is invalid + + When the node branch probability value is not initialized, + the branch probability must be set to 0 to ensure that + the calculation of the basic block execution probability + must be less than or equal to 100%. +--- + .../gcc.dg/autoprefetch/autoprefetch.exp | 27 +++++++++++++++++++ + .../autoprefetch/branch-weighted-prefetch.c | 22 +++++++++++++++ + .../autoprefetch/get-edge-prob-non-init.c | 24 +++++++++++++++++ + gcc/tree-ssa-loop-prefetch.c | 17 +++++++++++- + 4 files changed, 89 insertions(+), 1 deletion(-) + create mode 100644 gcc/testsuite/gcc.dg/autoprefetch/autoprefetch.exp + create mode 100644 gcc/testsuite/gcc.dg/autoprefetch/branch-weighted-prefetch.c + create mode 100644 gcc/testsuite/gcc.dg/autoprefetch/get-edge-prob-non-init.c + +diff --git a/gcc/testsuite/gcc.dg/autoprefetch/autoprefetch.exp b/gcc/testsuite/gcc.dg/autoprefetch/autoprefetch.exp +new file mode 100644 +index 000000000..a7408e338 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/autoprefetch/autoprefetch.exp +@@ -0,0 +1,27 @@ ++# Copyright (C) 1997-2022 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/>. ++ ++load_lib gcc-dg.exp ++load_lib target-supports.exp ++ ++# Initialize `dg'. ++dg-init ++ ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] \ ++ "" "-fprefetch-loop-arrays" ++ ++# All done. ++dg-finish +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/autoprefetch/branch-weighted-prefetch.c b/gcc/testsuite/gcc.dg/autoprefetch/branch-weighted-prefetch.c +new file mode 100644 +index 000000000..c63c5e5cb +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/autoprefetch/branch-weighted-prefetch.c +@@ -0,0 +1,22 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -fprefetch-loop-arrays=2 --param min-insn-to-prefetch-ratio=5 --param simultaneous-prefetches=100 -fdump-tree-aprefetch-details -fdump-tree-optimized" } */ ++#define N 10000000 ++ ++long long a[N]; ++ ++long long func () ++{ ++ long long i; ++ long long sum = 0; ++ ++ for (i = 0; i < N; i+=1) { ++ if (i < 100000) ++ sum += a[i]; ++ else ++ continue; ++ } ++ ++ return sum; ++} ++/* { dg-final { scan-tree-dump-times "Ahead 40" 1 "aprefetch" } } */ ++/* { dg-final { scan-tree-dump-times "builtin_prefetch" 1 "optimized" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/autoprefetch/get-edge-prob-non-init.c b/gcc/testsuite/gcc.dg/autoprefetch/get-edge-prob-non-init.c +new file mode 100644 +index 000000000..f55481008 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/autoprefetch/get-edge-prob-non-init.c +@@ -0,0 +1,24 @@ ++/* { dg-do compile } */ ++/* { dg-options "-Ofast -fprefetch-loop-arrays=2 -fdump-tree-aprefetch-details" } */ ++ ++int a, c, f; ++static int *b = &a; ++int *d; ++int e[0]; ++void g() { ++ int h; ++ for (;;) { ++ h = 1; ++ for (; h >= 0; h--) { ++ c = 2; ++ for (; c; c--) ++ if (e[0]) ++ if (e[c]) ++ *b = 0; ++ f || (*d = 0); ++ } ++ } ++} ++int main() {} ++ ++/* { dg-final } */ +diff --git a/gcc/tree-ssa-loop-prefetch.c b/gcc/tree-ssa-loop-prefetch.c +index 3a5aef0fc..673f453a4 100644 +--- a/gcc/tree-ssa-loop-prefetch.c ++++ b/gcc/tree-ssa-loop-prefetch.c +@@ -2132,7 +2132,7 @@ get_edge_prob (edge e) + { + /* Limit the minimum probability value. */ + const float MINNUM_PROB = 0.00001f; +- float fvalue = 1; ++ float fvalue = 0; + + profile_probability probability = e->probability; + if (probability.initialized_p ()) +@@ -2143,6 +2143,21 @@ get_edge_prob (edge e) + fvalue = MINNUM_PROB; + } + } ++ else ++ { ++ /* When the node branch probability value is not initialized, the branch ++ probability must be set to 0 to ensure that the calculation of the ++ basic block execution probability must be less than or equal to 100%. ++ i.e, ++ ... ++ <bb 3> [local count: 20000] ++ if (f_2 != 0) ++ goto <bb 6>; [INV] ++ else ++ goto <bb 7>; [100.00%] ++ ... */ ++ fvalue = 0; ++ } + return fvalue; + } + +-- +2.27.0.windows.1 + diff --git a/0029-AutoBOLT-Support-saving-feedback-count-info-to-ELF-s.patch b/0029-AutoBOLT-Support-saving-feedback-count-info-to-ELF-s.patch new file mode 100644 index 0000000..42053fc --- /dev/null +++ b/0029-AutoBOLT-Support-saving-feedback-count-info-to-ELF-s.patch @@ -0,0 +1,548 @@ +From c34a02199b1dfd362e81e78cb90fbd11e02eb93e Mon Sep 17 00:00:00 2001 +From: liyancheng <412998149@qq.com> +Date: Mon, 14 Feb 2022 14:34:41 +0800 +Subject: [PATCH 29/32] [AutoBOLT] Support saving feedback count info to ELF + segment 1/3 + +Add flag -fauto-bolt to save the feedback count info from PGO or +AutoFDO to segment .text.fdo. The bolt plugin will read and parse +it into the profile of llvm-bolt. +--- + gcc/common.opt | 8 + + gcc/final.c | 400 +++++++++++++++++++++++++++++++++++++++++++++++++ + gcc/opts.c | 61 ++++++++ + 3 files changed, 469 insertions(+) + +diff --git a/gcc/common.opt b/gcc/common.opt +index 9488bd90f..5eaa667b3 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -2403,6 +2403,14 @@ freorder-functions + Common Report Var(flag_reorder_functions) Optimization + Reorder functions to improve code placement. + ++fauto-bolt ++Common Report Var(flag_auto_bolt) ++Generate profile from AutoFDO or PGO and do BOLT optimization after linkage. ++ ++fauto-bolt= ++Common Joined RejectNegative ++Specify the feedback data directory required by BOLT-plugin. The default is the current directory. ++ + frerun-cse-after-loop + Common Report Var(flag_rerun_cse_after_loop) Optimization + Add a common subexpression elimination pass after loop optimizations. +diff --git a/gcc/final.c b/gcc/final.c +index a3601964a..b9affd3a7 100644 +--- a/gcc/final.c ++++ b/gcc/final.c +@@ -81,6 +81,7 @@ along with GCC; see the file COPYING3. If not see + #include "rtl-iter.h" + #include "print-rtl.h" + #include "function-abi.h" ++#include "insn-codes.h" + + #ifdef XCOFF_DEBUGGING_INFO + #include "xcoffout.h" /* Needed for external data declarations. */ +@@ -4640,6 +4641,399 @@ leaf_renumber_regs_insn (rtx in_rtx) + } + #endif + ++ ++#define ASM_FDO_SECTION_PREFIX ".text.fdo." ++ ++#define ASM_FDO_CALLER_FLAG ".fdo.caller " ++#define ASM_FDO_CALLER_SIZE_FLAG ".fdo.caller.size " ++#define ASM_FDO_CALLER_BIND_FLAG ".fdo.caller.bind " ++ ++#define ASM_FDO_CALLEE_FLAG ".fdo.callee " ++ ++/* Return the relative offset address of the start instruction of BB, ++ return -1 if it is empty instruction. */ ++ ++static int ++get_bb_start_addr (basic_block bb) ++{ ++ rtx_insn *insn; ++ FOR_BB_INSNS (bb, insn) ++ { ++ if (!INSN_P (insn)) ++ { ++ continue; ++ } ++ ++ int insn_code = recog_memoized (insn); ++ ++ /* The instruction NOP in llvm-bolt belongs to the previous ++ BB, so it needs to be skipped. */ ++ if (insn_code != CODE_FOR_nop) ++ { ++ return INSN_ADDRESSES (INSN_UID (insn)); ++ } ++ } ++ return -1; ++} ++ ++/* Return the relative offset address of the end instruction of BB, ++ return -1 if it is empty or call instruction. */ ++ ++static int ++get_bb_end_addr (basic_block bb) ++{ ++ rtx_insn *insn; ++ int num_succs = EDGE_COUNT (bb->succs); ++ FOR_BB_INSNS_REVERSE (bb, insn) ++ { ++ if (!INSN_P (insn)) ++ { ++ continue; ++ } ++ /* The jump target of call is not in this function, so ++ it should be excluded. */ ++ if (CALL_P (insn)) ++ { ++ return -1; ++ } ++ if ((num_succs == 1) ++ || ((num_succs == 2) && any_condjump_p (insn))) ++ { ++ return INSN_ADDRESSES (INSN_UID (insn)); ++ } ++ else ++ { ++ return -1; ++ } ++ } ++ return -1; ++} ++ ++/* Return the end address of cfun. */ ++ ++static int ++get_function_end_addr () ++{ ++ rtx_insn *insn = get_last_insn (); ++ for (; insn != get_insns (); insn = PREV_INSN (insn)) ++ { ++ if (!INSN_P (insn)) ++ { ++ continue; ++ } ++ return INSN_ADDRESSES (INSN_UID (insn)); ++ } ++ ++ return -1; ++} ++ ++/* Return the function profile status string. */ ++ ++static const char * ++get_function_profile_status () ++{ ++ const char *profile_status[] = { ++ "PROFILE_ABSENT", ++ "PROFILE_GUESSED", ++ "PROFILE_READ", ++ "PROFILE_LAST" /* Last value, used by profile streaming. */ ++ }; ++ ++ return profile_status[profile_status_for_fn (cfun)]; ++} ++ ++/* Return the count from the feedback data, such as PGO or AFDO. */ ++ ++inline static gcov_type ++get_fdo_count (profile_count count) ++{ ++ return count.quality () >= GUESSED ++ ? count.to_gcov_type () : 0; ++} ++ ++/* Return the profile quality string. */ ++ ++static const char * ++get_fdo_count_quality (profile_count count) ++{ ++ const char *profile_quality[] = { ++ "UNINITIALIZED_PROFILE", ++ "GUESSED_LOCAL", ++ "GUESSED_GLOBAL0", ++ "GUESSED_GLOBAL0_ADJUSTED", ++ "GUESSED", ++ "AFDO", ++ "ADJUSTED", ++ "PRECISE" ++ }; ++ ++ return profile_quality[count.quality ()]; ++} ++ ++static const char * ++alias_local_functions (const char *fnname) ++{ ++ if (TREE_PUBLIC (cfun->decl)) ++ { ++ return fnname; ++ } ++ ++ return concat (fnname, "/", lbasename (dump_base_name), NULL); ++} ++ ++/* Return function bind type string. */ ++ ++static const char * ++simple_get_function_bind () ++{ ++ const char *function_bind[] = { ++ "GLOBAL", ++ "WEAK", ++ "LOCAL", ++ "UNKNOWN" ++ }; ++ ++ if (TREE_PUBLIC (cfun->decl)) ++ { ++ if (!(DECL_WEAK (cfun->decl))) ++ { ++ return function_bind[0]; ++ } ++ else ++ { ++ return function_bind[1]; ++ } ++ } ++ else ++ { ++ return function_bind[2]; ++ } ++ ++ return function_bind[3]; ++} ++ ++/* Dump the callee functions insn in bb by CALL_P (insn). */ ++ ++static void ++dump_direct_callee_info_to_asm (basic_block bb, gcov_type call_count) ++{ ++ rtx_insn *insn; ++ FOR_BB_INSNS (bb, insn) ++ { ++ if (insn && CALL_P (insn)) ++ { ++ tree callee = get_call_fndecl (insn); ++ ++ if (callee) ++ { ++ fprintf (asm_out_file, "\t.string \"%x\"\n", ++ INSN_ADDRESSES (INSN_UID (insn))); ++ ++ fprintf (asm_out_file, "\t.string \"%s%s\"\n", ++ ASM_FDO_CALLEE_FLAG, ++ alias_local_functions (get_fnname_from_decl (callee))); ++ ++ fprintf (asm_out_file, ++ "\t.string \"" HOST_WIDE_INT_PRINT_DEC "\"\n", ++ call_count); ++ ++ if (dump_file) ++ { ++ fprintf (dump_file, "call: %x --> %s\n", ++ INSN_ADDRESSES (INSN_UID (insn)), ++ alias_local_functions ++ (get_fnname_from_decl (callee))); ++ } ++ } ++ } ++ } ++} ++ ++/* Dump the edge info into asm. */ ++ ++static void ++dump_edge_jump_info_to_asm (basic_block bb, gcov_type bb_count) ++{ ++ edge e; ++ edge_iterator ei; ++ gcov_type edge_total_count = 0; ++ ++ FOR_EACH_EDGE (e, ei, bb->succs) ++ { ++ gcov_type edge_count = get_fdo_count (e->count ()); ++ edge_total_count += edge_count; ++ ++ int edge_start_addr = get_bb_end_addr (e->src); ++ int edge_end_addr = get_bb_start_addr (e->dest); ++ ++ if (edge_start_addr == -1 || edge_end_addr == -1) ++ { ++ continue; ++ } ++ ++ /* This is a reserved assert for the original design. If this ++ assert is found, use the address of the previous instruction ++ as edge_start_addr. */ ++ gcc_assert (edge_start_addr != edge_end_addr); ++ ++ if (dump_file) ++ { ++ fprintf (dump_file, "edge: %x --> %x = (%ld)\n", ++ edge_start_addr, edge_end_addr, edge_count); ++ } ++ ++ if (edge_count > 0) ++ { ++ fprintf (asm_out_file, "\t.string \"%x\"\n", edge_start_addr); ++ fprintf (asm_out_file, "\t.string \"%x\"\n", edge_end_addr); ++ fprintf (asm_out_file, "\t.string \"" HOST_WIDE_INT_PRINT_DEC "\"\n", ++ edge_count); ++ } ++ } ++ ++ gcov_type call_count = MAX (edge_total_count, bb_count); ++ if (call_count > 0) ++ { ++ dump_direct_callee_info_to_asm (bb, call_count); ++ } ++} ++ ++/* Dump the bb info into asm. */ ++ ++static void ++dump_bb_info_to_asm (basic_block bb, gcov_type bb_count) ++{ ++ int bb_start_addr = get_bb_start_addr (bb); ++ if (bb_start_addr != -1) ++ { ++ fprintf (asm_out_file, "\t.string \"%x\"\n", bb_start_addr); ++ fprintf (asm_out_file, "\t.string \"" HOST_WIDE_INT_PRINT_DEC "\"\n", ++ bb_count); ++ } ++} ++ ++/* Dump the function info into asm. */ ++ ++static void ++dump_function_info_to_asm (const char *fnname) ++{ ++ fprintf (asm_out_file, "\t.string \"%s%s\"\n", ++ ASM_FDO_CALLER_FLAG, alias_local_functions (fnname)); ++ fprintf (asm_out_file, "\t.string \"%s%d\"\n", ++ ASM_FDO_CALLER_SIZE_FLAG, get_function_end_addr ()); ++ fprintf (asm_out_file, "\t.string \"%s%s\"\n", ++ ASM_FDO_CALLER_BIND_FLAG, simple_get_function_bind ()); ++ ++ if (dump_file) ++ { ++ fprintf (dump_file, "\n FUNC_NAME: %s\n", ++ alias_local_functions (fnname)); ++ fprintf (dump_file, " file: %s\n", ++ dump_base_name); ++ fprintf (dump_file, " profile_status: %s\n", ++ get_function_profile_status ()); ++ fprintf (dump_file, " size: %x\n", ++ get_function_end_addr ()); ++ fprintf (dump_file, " function_bind: %s\n", ++ simple_get_function_bind ()); ++ } ++} ++ ++/* Dump function profile info form AutoFDO or PGO to asm. */ ++ ++static void ++dump_fdo_info_to_asm (const char *fnname) ++{ ++ basic_block bb; ++ ++ dump_function_info_to_asm (fnname); ++ ++ FOR_EACH_BB_FN (bb, cfun) ++ { ++ gcov_type bb_count = get_fdo_count (bb->count); ++ if (bb_count == 0) ++ { ++ continue; ++ } ++ ++ if (dump_file) ++ { ++ fprintf (dump_file, "BB: %x --> %x = (%ld) [%s]\n", ++ get_bb_start_addr (bb), get_bb_end_addr (bb), ++ bb_count, get_fdo_count_quality (bb->count)); ++ } ++ ++ if (flag_profile_use) ++ { ++ dump_edge_jump_info_to_asm (bb, bb_count); ++ } ++ else if (flag_auto_profile) ++ { ++ dump_bb_info_to_asm (bb, bb_count); ++ } ++ } ++} ++ ++/* When -fauto-bolt option is turned on, the .text.fdo. section ++ will be generated in the *.s file if there is feedback information ++ from PGO or AutoFDO. This section will parserd in BOLT-plugin. */ ++ ++static void ++dump_profile_to_elf_sections () ++{ ++ if (!flag_function_sections) ++ { ++ error ("-fauto-bolt should work with -ffunction-sections"); ++ return; ++ } ++ if (!flag_ipa_ra) ++ { ++ error ("-fauto-bolt should work with -fipa-ra"); ++ return; ++ } ++ if (flag_align_jumps) ++ { ++ error ("-fauto-bolt is not supported with -falign-jumps"); ++ return; ++ } ++ if (flag_align_labels) ++ { ++ error ("-fauto-bolt is not supported with -falign-labels"); ++ return; ++ } ++ if (flag_align_loops) ++ { ++ error ("-fauto-bolt is not supported with -falign-loops"); ++ return; ++ } ++ ++ /* Return if no feedback data. */ ++ if (!flag_profile_use && !flag_auto_profile) ++ { ++ error ("-fauto-bolt should use with -fprofile-use or -fauto-profile"); ++ return; ++ } ++ ++ /* Avoid empty functions. */ ++ if (TREE_CODE (cfun->decl) != FUNCTION_DECL) ++ { ++ return; ++ } ++ int flags = SECTION_DEBUG | SECTION_EXCLUDE; ++ const char *fnname = get_fnname_from_decl (current_function_decl); ++ char *profile_fnname = NULL; ++ ++ asprintf (&profile_fnname,"%s%s", ASM_FDO_SECTION_PREFIX, fnname); ++ switch_to_section (get_section (profile_fnname, flags , NULL)); ++ dump_fdo_info_to_asm (fnname); ++ ++ if (profile_fnname) ++ { ++ free (profile_fnname); ++ profile_fnname = NULL; ++ } ++} ++ + /* Turn the RTL into assembly. */ + static unsigned int + rest_of_handle_final (void) +@@ -4707,6 +5101,12 @@ rest_of_handle_final (void) + targetm.asm_out.destructor (XEXP (DECL_RTL (current_function_decl), 0), + decl_fini_priority_lookup + (current_function_decl)); ++ ++ if (flag_auto_bolt) ++ { ++ dump_profile_to_elf_sections (); ++ } ++ + return 0; + } + +diff --git a/gcc/opts.c b/gcc/opts.c +index f49f5ee58..0b389ae1d 100644 +--- a/gcc/opts.c ++++ b/gcc/opts.c +@@ -1166,6 +1166,10 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, + if (opts->x_flag_vtable_verify && opts->x_flag_lto) + sorry ("vtable verification is not supported with LTO"); + ++ /* Currently -fauto-bolt is not supported for LTO. */ ++ if (opts->x_flag_auto_bolt && opts->x_flag_lto) ++ sorry ("%<-fauto-bolt%> is not supported with LTO"); ++ + /* Control IPA optimizations based on different -flive-patching level. */ + if (opts->x_flag_live_patching) + control_options_for_live_patching (opts, opts_set, +@@ -1183,6 +1187,58 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, + = (opts->x_flag_unroll_loops + || opts->x_flag_peel_loops + || opts->x_optimize >= 3); ++ ++ if (opts->x_flag_auto_bolt) ++ { ++ /* Record the function section to facilitate the feedback ++ data storage. */ ++ if (!opts->x_flag_function_sections) ++ { ++ inform (loc, ++ "%<-fauto-bolt%> should work with %<-ffunction-sections%>," ++ " enabling %<-ffunction-sections%>"); ++ opts->x_flag_function_sections = true; ++ } ++ ++ /* Cancel the internal alignment of the function. The binary ++ optimizer bolt will cancel the internal alignment optimization ++ of the function, so the alignment is meaningless at this time, ++ and if not, it will bring trouble to the calculation of the ++ offset address of the instruction. */ ++ if (opts->x_flag_align_jumps) ++ { ++ inform (loc, ++ "%<-fauto-bolt%> should not work with %<-falign-jumps%>," ++ " disabling %<-falign-jumps%>"); ++ opts->x_flag_align_jumps = false; ++ } ++ ++ if (opts->x_flag_align_labels) ++ { ++ inform (loc, ++ "%<-fauto-bolt%> should not work with %<-falign-labels%>," ++ " disabling %<-falign-labels%>"); ++ opts->x_flag_align_labels = false; ++ } ++ ++ if (opts->x_flag_align_loops) ++ { ++ inform (loc, ++ "%<-fauto-bolt%> should not work with %<-falign-loops%>," ++ " disabling %<-falign-loops%>"); ++ opts->x_flag_align_loops = false; ++ } ++ ++ /* When parsing instructions in RTL phase, we need to know ++ the call information of instructions to avoid being optimized. */ ++ if (!opts->x_flag_ipa_ra) ++ { ++ inform (loc, ++ "%<-fauto-bolt%> should work with %<-fipa-ra%>," ++ " enabling %<-fipa-ra%>"); ++ opts->x_flag_ipa_ra = true; ++ } ++ } + } + + #define LEFT_COLUMN 27 +@@ -2881,6 +2937,11 @@ common_handle_option (struct gcc_options *opts, + check_alignment_argument (loc, arg, "functions"); + break; + ++ case OPT_fauto_bolt_: ++ case OPT_fauto_bolt: ++ /* Deferred. */ ++ break; ++ + default: + /* If the flag was handled in a standard way, assume the lack of + processing here is intentional. */ +-- +2.27.0 + diff --git a/0030-AutoBOLT-Add-bolt-linker-plugin-2-3.patch b/0030-AutoBOLT-Add-bolt-linker-plugin-2-3.patch new file mode 100644 index 0000000..b3455e4 --- /dev/null +++ b/0030-AutoBOLT-Add-bolt-linker-plugin-2-3.patch @@ -0,0 +1,21748 @@ +From e2d5ed57fef0f731d253947a60035464b02f6c21 Mon Sep 17 00:00:00 2001 +From: liyancheng <412998149@qq.com> +Date: Mon, 14 Feb 2022 14:59:18 +0800 +Subject: [PATCH 30/32] [AutoBOLT] Add bolt linker plugin 2/3 + +Add option -fbolt-use for perform bolt optimization. +Add option -fbolt-target to specify bolt optimization target. +Add option -fbolt-option to specify bolt optimization options. + +Add the bolt linker plugin to read the profile count info when +processing the .text.fdo segment in each .o, and generate the +profile required by llvm-bolt at the end of linkage. Finally, +use profile from -fauto-bolt or -fbolt-use to complete bolt +optimization. +--- + bolt-plugin/Makefile.am | 42 + + bolt-plugin/Makefile.in | 685 ++ + bolt-plugin/aclocal.m4 | 1163 +++ + bolt-plugin/bolt-plugin.cc | 1152 +++ + bolt-plugin/config.h.in | 121 + + bolt-plugin/configure | 18379 +++++++++++++++++++++++++++++++++++ + bolt-plugin/configure.ac | 59 + + gcc/common.opt | 16 + + gcc/opts.c | 23 + + 9 files changed, 21640 insertions(+) + create mode 100644 bolt-plugin/Makefile.am + create mode 100644 bolt-plugin/Makefile.in + create mode 100644 bolt-plugin/aclocal.m4 + create mode 100644 bolt-plugin/bolt-plugin.cc + create mode 100644 bolt-plugin/config.h.in + create mode 100755 bolt-plugin/configure + create mode 100644 bolt-plugin/configure.ac + +diff --git a/bolt-plugin/Makefile.am b/bolt-plugin/Makefile.am +new file mode 100644 +index 000000000..1fb93bd6e +--- /dev/null ++++ b/bolt-plugin/Makefile.am +@@ -0,0 +1,42 @@ ++## Process this file with automake to produce Makefile.in. ++ ++ACLOCAL_AMFLAGS = -I .. -I ../config ++AUTOMAKE_OPTIONS = no-dependencies ++ ++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) ++ ++AM_CPPFLAGS = -I$(top_srcdir)/../include $(DEFS) -std=c++11 ++AM_CXXFLAGS = @ac_bolt_plugin_warn_cflags@ -std=c++11 ++AM_LDFLAGS = @ac_bolt_plugin_ldflags@ ++AM_LIBTOOLFLAGS = --tag=disable-static ++override CXXFLAGS := $(filter-out -fsanitize=address,$(CXXFLAGS)) ++override LDFLAGS := $(filter-out -fsanitize=address,$(LDFLAGS)) ++ ++libexecsub_LTLIBRARIES = libbolt_plugin.la ++gcc_build_dir = @gcc_build_dir@ ++in_gcc_libs = $(foreach lib, $(libexecsub_LTLIBRARIES), $(gcc_build_dir)/$(lib)) ++ ++libbolt_plugin_la_SOURCES = bolt-plugin.cc ++# Note that we intentionally override the bindir supplied by ACX_LT_HOST_FLAGS. ++libbolt_plugin_la_LDFLAGS = $(AM_LDFLAGS) \ ++ $(lt_host_flags) -module -bindir $(libexecsubdir) ++# Can be simplified when libiberty becomes a normal convenience library. ++libiberty = $(with_libiberty)/libiberty.a ++libiberty_noasan = $(with_libiberty)/noasan/libiberty.a ++libiberty_pic = $(with_libiberty)/pic/libiberty.a ++Wc=-Wc, ++libbolt_plugin_la_LIBADD = \ ++ $(if $(wildcard $(libiberty_noasan)),$(Wc)$(libiberty_noasan), \ ++ $(if $(wildcard $(libiberty_pic)),$(Wc)$(libiberty_pic),)) ++libbolt_plugin_la_LDFLAGS += \ ++ $(if $(wildcard $(libiberty_noasan)),, \ ++ $(if $(wildcard $(libiberty_pic)),,-Wc,$(libiberty))) ++libbolt_plugin_la_DEPENDENCIES = \ ++ $(if $(wildcard $(libiberty_noasan)),$(libiberty_noasan), \ ++ $(if $(wildcard $(libiberty_pic)),$(libiberty_pic),)) ++LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS)) ++libbolt_plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ ++ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) ${AM_CPPFLAGS} $(CXXFLAGS) \ ++ $(libbolt_plugin_la_LDFLAGS) $(LTLDFLAGS) -o $@ +diff --git a/bolt-plugin/Makefile.in b/bolt-plugin/Makefile.in +new file mode 100644 +index 000000000..3336fe48c +--- /dev/null ++++ b/bolt-plugin/Makefile.in +@@ -0,0 +1,685 @@ ++# Makefile.in generated by automake 1.16.1 from Makefile.am. ++# @configure_input@ ++ ++# Copyright (C) 1994-2018 Free Software Foundation, Inc. ++ ++# This Makefile.in is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY, to the extent permitted by law; without ++# even the implied warranty of MERCHANTABILITY or FITNESS FOR A ++# PARTICULAR PURPOSE. ++ ++@SET_MAKE@ ++ ++VPATH = @srcdir@ ++am__is_gnu_make = { \ ++ if test -z '$(MAKELEVEL)'; then \ ++ false; \ ++ elif test -n '$(MAKE_HOST)'; then \ ++ true; \ ++ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ ++ true; \ ++ else \ ++ false; \ ++ fi; \ ++} ++am__make_running_with_option = \ ++ case $${target_option-} in \ ++ ?) ;; \ ++ *) echo "am__make_running_with_option: internal error: invalid" \ ++ "target option '$${target_option-}' specified" >&2; \ ++ exit 1;; \ ++ esac; \ ++ has_opt=no; \ ++ sane_makeflags=$$MAKEFLAGS; \ ++ if $(am__is_gnu_make); then \ ++ sane_makeflags=$$MFLAGS; \ ++ else \ ++ case $$MAKEFLAGS in \ ++ *\\[\ \ ]*) \ ++ bs=\\; \ ++ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ ++ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ ++ esac; \ ++ fi; \ ++ skip_next=no; \ ++ strip_trailopt () \ ++ { \ ++ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ ++ }; \ ++ for flg in $$sane_makeflags; do \ ++ test $$skip_next = yes && { skip_next=no; continue; }; \ ++ case $$flg in \ ++ *=*|--*) continue;; \ ++ -*I) strip_trailopt 'I'; skip_next=yes;; \ ++ -*I?*) strip_trailopt 'I';; \ ++ -*O) strip_trailopt 'O'; skip_next=yes;; \ ++ -*O?*) strip_trailopt 'O';; \ ++ -*l) strip_trailopt 'l'; skip_next=yes;; \ ++ -*l?*) strip_trailopt 'l';; \ ++ -[dEDm]) skip_next=yes;; \ ++ -[JT]) skip_next=yes;; \ ++ esac; \ ++ case $$flg in \ ++ *$$target_option*) has_opt=yes; break;; \ ++ esac; \ ++ done; \ ++ test $$has_opt = yes ++am__make_dryrun = (target_option=n; $(am__make_running_with_option)) ++am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) ++pkgdatadir = $(datadir)/@PACKAGE@ ++pkgincludedir = $(includedir)/@PACKAGE@ ++pkglibdir = $(libdir)/@PACKAGE@ ++pkglibexecdir = $(libexecdir)/@PACKAGE@ ++am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd ++install_sh_DATA = $(install_sh) -c -m 644 ++install_sh_PROGRAM = $(install_sh) -c ++install_sh_SCRIPT = $(install_sh) -c ++INSTALL_HEADER = $(INSTALL_DATA) ++transform = $(program_transform_name) ++NORMAL_INSTALL = : ++PRE_INSTALL = : ++POST_INSTALL = : ++NORMAL_UNINSTALL = : ++PRE_UNINSTALL = : ++POST_UNINSTALL = : ++build_triplet = @build@ ++host_triplet = @host@ ++target_triplet = @target@ ++subdir = . ++ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 ++am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \ ++ $(top_srcdir)/../config/depstand.m4 \ ++ $(top_srcdir)/../config/lead-dot.m4 \ ++ $(top_srcdir)/../config/lthostflags.m4 \ ++ $(top_srcdir)/../config/override.m4 \ ++ $(top_srcdir)/../config/warnings.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) ++DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ ++ $(am__configure_deps) ++am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ ++ configure.lineno config.status.lineno ++mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs ++CONFIG_HEADER = config.h ++CONFIG_CLEAN_FILES = ++CONFIG_CLEAN_VPATH_FILES = ++am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; ++am__vpath_adj = case $$p in \ ++ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ ++ *) f=$$p;; \ ++ esac; ++am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; ++am__install_max = 40 ++am__nobase_strip_setup = \ ++ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` ++am__nobase_strip = \ ++ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" ++am__nobase_list = $(am__nobase_strip_setup); \ ++ for p in $$list; do echo "$$p $$p"; done | \ ++ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ ++ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ ++ if (++n[$$2] == $(am__install_max)) \ ++ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ ++ END { for (dir in files) print dir, files[dir] }' ++am__base_list = \ ++ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ ++ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' ++am__uninstall_files_from_dir = { \ ++ test -z "$$files" \ ++ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ ++ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ ++ $(am__cd) "$$dir" && rm -f $$files; }; \ ++ } ++am__installdirs = "$(DESTDIR)$(libexecsubdir)" ++LTLIBRARIES = $(libexecsub_LTLIBRARIES) ++am_libbolt_plugin_la_OBJECTS = bolt-plugin.lo ++libbolt_plugin_la_OBJECTS = $(am_libbolt_plugin_la_OBJECTS) ++AM_V_P = $(am__v_P_@AM_V@) ++am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) ++am__v_P_0 = false ++am__v_P_1 = : ++AM_V_GEN = $(am__v_GEN_@AM_V@) ++am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) ++am__v_GEN_0 = @echo " GEN " $@; ++am__v_GEN_1 = ++AM_V_at = $(am__v_at_@AM_V@) ++am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) ++am__v_at_0 = @ ++am__v_at_1 = ++DEFAULT_INCLUDES = -I.@am__isrc@ ++depcomp = ++am__maybe_remake_depfiles = ++CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ ++ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) ++AM_V_lt = $(am__v_lt_@AM_V@) ++am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) ++am__v_lt_0 = --silent ++am__v_lt_1 = ++LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ ++ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ ++ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ ++ $(AM_CXXFLAGS) $(CXXFLAGS) ++AM_V_CXX = $(am__v_CXX_@AM_V@) ++am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) ++am__v_CXX_0 = @echo " CXX " $@; ++am__v_CXX_1 = ++CXXLD = $(CXX) ++CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ ++ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ ++ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ ++AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) ++am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) ++am__v_CXXLD_0 = @echo " CXXLD " $@; ++am__v_CXXLD_1 = ++SOURCES = $(libbolt_plugin_la_SOURCES) ++am__can_run_installinfo = \ ++ case $$AM_UPDATE_INFO_DIR in \ ++ n|no|NO) false;; \ ++ *) (install-info --version) >/dev/null 2>&1;; \ ++ esac ++am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ ++ $(LISP)config.h.in ++# Read a list of newline-separated strings from the standard input, ++# and print each of them once, without duplicates. Input order is ++# *not* preserved. ++am__uniquify_input = $(AWK) '\ ++ BEGIN { nonempty = 0; } \ ++ { items[$$0] = 1; nonempty = 1; } \ ++ END { if (nonempty) { for (i in items) print i; }; } \ ++' ++# Make sure the list of sources is unique. This is necessary because, ++# e.g., the same source file might be shared among _SOURCES variables ++# for different programs/libraries. ++am__define_uniq_tagged_files = \ ++ list='$(am__tagged_files)'; \ ++ unique=`for i in $$list; do \ ++ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ ++ done | $(am__uniquify_input)` ++ETAGS = etags ++CTAGS = ctags ++CSCOPE = cscope ++AM_RECURSIVE_TARGETS = cscope ++ACLOCAL = @ACLOCAL@ ++AMTAR = @AMTAR@ ++AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ ++AR = @AR@ ++AUTOCONF = @AUTOCONF@ ++AUTOHEADER = @AUTOHEADER@ ++AUTOMAKE = @AUTOMAKE@ ++AWK = @AWK@ ++CC = @CC@ ++CCDEPMODE = @CCDEPMODE@ ++CFLAGS = @CFLAGS@ ++CPP = @CPP@ ++CPPFLAGS = @CPPFLAGS@ ++CXX = @CXX@ ++CXXCPP = @CXXCPP@ ++CXXDEPMODE = @CXXDEPMODE@ ++CXXFLAGS = @CXXFLAGS@ ++CYGPATH_W = @CYGPATH_W@ ++DEFS = @DEFS@ ++DEPDIR = @DEPDIR@ ++DSYMUTIL = @DSYMUTIL@ ++DUMPBIN = @DUMPBIN@ ++ECHO_C = @ECHO_C@ ++ECHO_N = @ECHO_N@ ++ECHO_T = @ECHO_T@ ++EGREP = @EGREP@ ++EXEEXT = @EXEEXT@ ++FGREP = @FGREP@ ++GREP = @GREP@ ++INSTALL = @INSTALL@ ++INSTALL_DATA = @INSTALL_DATA@ ++INSTALL_PROGRAM = @INSTALL_PROGRAM@ ++INSTALL_SCRIPT = @INSTALL_SCRIPT@ ++INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ ++LD = @LD@ ++LDFLAGS = @LDFLAGS@ ++LIBOBJS = @LIBOBJS@ ++LIBS = @LIBS@ ++LIBTOOL = @LIBTOOL@ ++LIPO = @LIPO@ ++LN_S = @LN_S@ ++LTLIBOBJS = @LTLIBOBJS@ ++MAINT = @MAINT@ ++MAKEINFO = @MAKEINFO@ ++MKDIR_P = @MKDIR_P@ ++NM = @NM@ ++NMEDIT = @NMEDIT@ ++OBJDUMP = @OBJDUMP@ ++OBJEXT = @OBJEXT@ ++OTOOL = @OTOOL@ ++OTOOL64 = @OTOOL64@ ++PACKAGE = @PACKAGE@ ++PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ ++PACKAGE_NAME = @PACKAGE_NAME@ ++PACKAGE_STRING = @PACKAGE_STRING@ ++PACKAGE_TARNAME = @PACKAGE_TARNAME@ ++PACKAGE_URL = @PACKAGE_URL@ ++PACKAGE_VERSION = @PACKAGE_VERSION@ ++PATH_SEPARATOR = @PATH_SEPARATOR@ ++RANLIB = @RANLIB@ ++SED = @SED@ ++SET_MAKE = @SET_MAKE@ ++SHELL = @SHELL@ ++STRIP = @STRIP@ ++VERSION = @VERSION@ ++abs_builddir = @abs_builddir@ ++abs_srcdir = @abs_srcdir@ ++abs_top_builddir = @abs_top_builddir@ ++abs_top_srcdir = @abs_top_srcdir@ ++ac_bolt_plugin_ldflags = @ac_bolt_plugin_ldflags@ ++ac_bolt_plugin_warn_cflags = @ac_bolt_plugin_warn_cflags@ ++ac_ct_CC = @ac_ct_CC@ ++ac_ct_CXX = @ac_ct_CXX@ ++ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ ++accel_dir_suffix = @accel_dir_suffix@ ++am__include = @am__include@ ++am__leading_dot = @am__leading_dot@ ++am__quote = @am__quote@ ++am__tar = @am__tar@ ++am__untar = @am__untar@ ++bindir = @bindir@ ++build = @build@ ++build_alias = @build_alias@ ++build_cpu = @build_cpu@ ++build_libsubdir = @build_libsubdir@ ++build_os = @build_os@ ++build_subdir = @build_subdir@ ++build_vendor = @build_vendor@ ++builddir = @builddir@ ++datadir = @datadir@ ++datarootdir = @datarootdir@ ++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@ ++host_os = @host_os@ ++host_subdir = @host_subdir@ ++host_vendor = @host_vendor@ ++htmldir = @htmldir@ ++includedir = @includedir@ ++infodir = @infodir@ ++install_sh = @install_sh@ ++libdir = @libdir@ ++libexecdir = @libexecdir@ ++localedir = @localedir@ ++localstatedir = @localstatedir@ ++lt_host_flags = @lt_host_flags@ ++mandir = @mandir@ ++mkdir_p = @mkdir_p@ ++oldincludedir = @oldincludedir@ ++pdfdir = @pdfdir@ ++prefix = @prefix@ ++program_transform_name = @program_transform_name@ ++psdir = @psdir@ ++real_target_noncanonical = @real_target_noncanonical@ ++sbindir = @sbindir@ ++sharedstatedir = @sharedstatedir@ ++srcdir = @srcdir@ ++sysconfdir = @sysconfdir@ ++target = @target@ ++target_alias = @target_alias@ ++target_cpu = @target_cpu@ ++target_noncanonical := @target_noncanonical@ ++target_os = @target_os@ ++target_subdir = @target_subdir@ ++target_vendor = @target_vendor@ ++top_build_prefix = @top_build_prefix@ ++top_builddir = @top_builddir@ ++top_srcdir = @top_srcdir@ ++with_libiberty = @with_libiberty@ ++ACLOCAL_AMFLAGS = -I .. -I ../config ++AUTOMAKE_OPTIONS = no-dependencies ++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) -std=c++11 ++AM_CXXFLAGS = @ac_bolt_plugin_warn_cflags@ -std=c++11 ++AM_LDFLAGS = @ac_bolt_plugin_ldflags@ ++AM_LIBTOOLFLAGS = --tag=disable-static ++libexecsub_LTLIBRARIES = libbolt_plugin.la ++in_gcc_libs = $(foreach lib, $(libexecsub_LTLIBRARIES), $(gcc_build_dir)/$(lib)) ++libbolt_plugin_la_SOURCES = bolt-plugin.cc ++# Note that we intentionally override the bindir supplied by ACX_LT_HOST_FLAGS. ++libbolt_plugin_la_LDFLAGS = $(AM_LDFLAGS) $(lt_host_flags) -module \ ++ -bindir $(libexecsubdir) $(if $(wildcard \ ++ $(libiberty_noasan)),, $(if $(wildcard \ ++ $(libiberty_pic)),,-Wc,$(libiberty))) ++# Can be simplified when libiberty becomes a normal convenience library. ++libiberty = $(with_libiberty)/libiberty.a ++libiberty_noasan = $(with_libiberty)/noasan/libiberty.a ++libiberty_pic = $(with_libiberty)/pic/libiberty.a ++Wc = -Wc, ++libbolt_plugin_la_LIBADD = \ ++ $(if $(wildcard $(libiberty_noasan)),$(Wc)$(libiberty_noasan), \ ++ $(if $(wildcard $(libiberty_pic)),$(Wc)$(libiberty_pic),)) ++ ++libbolt_plugin_la_DEPENDENCIES = \ ++ $(if $(wildcard $(libiberty_noasan)),$(libiberty_noasan), \ ++ $(if $(wildcard $(libiberty_pic)),$(libiberty_pic),)) ++ ++LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS)) ++libbolt_plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ ++ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) ${AM_CPPFLAGS} $(CXXFLAGS) \ ++ $(libbolt_plugin_la_LDFLAGS) $(LTLDFLAGS) -o $@ ++ ++all: config.h ++ $(MAKE) $(AM_MAKEFLAGS) all-am ++ ++.SUFFIXES: ++.SUFFIXES: .cc .lo .o .obj ++am--refresh: Makefile ++ @: ++$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) ++ @for dep in $?; do \ ++ case '$(am__configure_deps)' in \ ++ *$$dep*) \ ++ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign --ignore-deps'; \ ++ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign --ignore-deps \ ++ && exit 0; \ ++ exit 1;; \ ++ esac; \ ++ done; \ ++ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps Makefile'; \ ++ $(am__cd) $(top_srcdir) && \ ++ $(AUTOMAKE) --foreign --ignore-deps Makefile ++Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status ++ @case '$?' in \ ++ *config.status*) \ ++ echo ' $(SHELL) ./config.status'; \ ++ $(SHELL) ./config.status;; \ ++ *) \ ++ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ ++ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ ++ esac; ++ ++$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) ++ $(SHELL) ./config.status --recheck ++ ++$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) ++ $(am__cd) $(srcdir) && $(AUTOCONF) ++$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) ++ $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) ++$(am__aclocal_m4_deps): ++ ++config.h: stamp-h1 ++ @test -f $@ || rm -f stamp-h1 ++ @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 ++ ++stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status ++ @rm -f stamp-h1 ++ cd $(top_builddir) && $(SHELL) ./config.status config.h ++$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) ++ ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) ++ rm -f stamp-h1 ++ touch $@ ++ ++distclean-hdr: ++ -rm -f config.h stamp-h1 ++ ++install-libexecsubLTLIBRARIES: $(libexecsub_LTLIBRARIES) ++ @$(NORMAL_INSTALL) ++ @list='$(libexecsub_LTLIBRARIES)'; test -n "$(libexecsubdir)" || list=; \ ++ list2=; for p in $$list; do \ ++ if test -f $$p; then \ ++ list2="$$list2 $$p"; \ ++ else :; fi; \ ++ done; \ ++ test -z "$$list2" || { \ ++ echo " $(MKDIR_P) '$(DESTDIR)$(libexecsubdir)'"; \ ++ $(MKDIR_P) "$(DESTDIR)$(libexecsubdir)" || exit 1; \ ++ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libexecsubdir)'"; \ ++ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libexecsubdir)"; \ ++ } ++ ++uninstall-libexecsubLTLIBRARIES: ++ @$(NORMAL_UNINSTALL) ++ @list='$(libexecsub_LTLIBRARIES)'; test -n "$(libexecsubdir)" || list=; \ ++ for p in $$list; do \ ++ $(am__strip_dir) \ ++ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libexecsubdir)/$$f'"; \ ++ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libexecsubdir)/$$f"; \ ++ done ++ ++clean-libexecsubLTLIBRARIES: ++ -test -z "$(libexecsub_LTLIBRARIES)" || rm -f $(libexecsub_LTLIBRARIES) ++ @list='$(libexecsub_LTLIBRARIES)'; \ ++ locs=`for p in $$list; do echo $$p; done | \ ++ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ ++ sort -u`; \ ++ test -z "$$locs" || { \ ++ echo rm -f $${locs}; \ ++ rm -f $${locs}; \ ++ } ++ ++libbolt_plugin.la: $(libbolt_plugin_la_OBJECTS) $(libbolt_plugin_la_DEPENDENCIES) $(EXTRA_libbolt_plugin_la_DEPENDENCIES) ++ $(AM_V_GEN)$(libbolt_plugin_la_LINK) -rpath $(libexecsubdir) $(libbolt_plugin_la_OBJECTS) $(libbolt_plugin_la_LIBADD) $(LIBS) ++ ++mostlyclean-compile: ++ -rm -f *.$(OBJEXT) ++ ++distclean-compile: ++ -rm -f *.tab.c ++ ++.cc.o: ++ $(AM_V_CXX)$(CXXCOMPILE) -c -o $@ $< ++ ++.cc.obj: ++ $(AM_V_CXX)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ++ ++.cc.lo: ++ $(AM_V_CXX)$(LTCXXCOMPILE) -c -o $@ $< ++ ++mostlyclean-libtool: ++ -rm -f *.lo ++ ++clean-libtool: ++ -rm -rf .libs _libs ++ ++distclean-libtool: ++ -rm -f libtool config.lt ++ ++ID: $(am__tagged_files) ++ $(am__define_uniq_tagged_files); mkid -fID $$unique ++tags: tags-am ++TAGS: tags ++ ++tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) ++ set x; \ ++ here=`pwd`; \ ++ $(am__define_uniq_tagged_files); \ ++ shift; \ ++ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ ++ test -n "$$unique" || unique=$$empty_fix; \ ++ if test $$# -gt 0; then \ ++ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ ++ "$$@" $$unique; \ ++ else \ ++ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ ++ $$unique; \ ++ fi; \ ++ fi ++ctags: ctags-am ++ ++CTAGS: ctags ++ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) ++ $(am__define_uniq_tagged_files); \ ++ test -z "$(CTAGS_ARGS)$$unique" \ ++ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ ++ $$unique ++ ++GTAGS: ++ here=`$(am__cd) $(top_builddir) && pwd` \ ++ && $(am__cd) $(top_srcdir) \ ++ && gtags -i $(GTAGS_ARGS) "$$here" ++cscope: cscope.files ++ test ! -s cscope.files \ ++ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) ++clean-cscope: ++ -rm -f cscope.files ++cscope.files: clean-cscope cscopelist ++cscopelist: cscopelist-am ++ ++cscopelist-am: $(am__tagged_files) ++ list='$(am__tagged_files)'; \ ++ case "$(srcdir)" in \ ++ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ ++ *) sdir=$(subdir)/$(srcdir) ;; \ ++ esac; \ ++ for i in $$list; do \ ++ if test -f "$$i"; then \ ++ echo "$(subdir)/$$i"; \ ++ else \ ++ echo "$$sdir/$$i"; \ ++ fi; \ ++ done >> $(top_builddir)/cscope.files ++ ++distclean-tags: ++ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags ++ -rm -f cscope.out cscope.in.out cscope.po.out cscope.files ++check-am: all-am ++check: check-am ++all-am: Makefile $(LTLIBRARIES) config.h ++installdirs: ++ for dir in "$(DESTDIR)$(libexecsubdir)"; do \ ++ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ ++ done ++install: install-am ++install-exec: install-exec-am ++install-data: install-data-am ++uninstall: uninstall-am ++ ++install-am: all-am ++ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am ++ ++installcheck: installcheck-am ++install-strip: ++ if test -z '$(STRIP)'; then \ ++ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ ++ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ ++ install; \ ++ else \ ++ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ ++ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ ++ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ ++ fi ++mostlyclean-generic: ++ ++clean-generic: ++ ++distclean-generic: ++ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) ++ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) ++ ++maintainer-clean-generic: ++ @echo "This command is intended for maintainers to use" ++ @echo "it deletes files that may require special tools to rebuild." ++clean: clean-am ++ ++clean-am: clean-generic clean-libexecsubLTLIBRARIES clean-libtool \ ++ mostlyclean-am ++ ++distclean: distclean-am ++ -rm -f $(am__CONFIG_DISTCLEAN_FILES) ++ -rm -f Makefile ++distclean-am: clean-am distclean-compile distclean-generic \ ++ distclean-hdr distclean-libtool distclean-tags ++ ++dvi: dvi-am ++ ++dvi-am: ++ ++html: html-am ++ ++html-am: ++ ++info: info-am ++ ++info-am: ++ ++install-data-am: ++ ++install-dvi: install-dvi-am ++ ++install-dvi-am: ++ ++install-exec-am: install-libexecsubLTLIBRARIES ++ ++install-html: install-html-am ++ ++install-html-am: ++ ++install-info: install-info-am ++ ++install-info-am: ++ ++install-man: ++ ++install-pdf: install-pdf-am ++ ++install-pdf-am: ++ ++install-ps: install-ps-am ++ ++install-ps-am: ++ ++installcheck-am: ++ ++maintainer-clean: maintainer-clean-am ++ -rm -f $(am__CONFIG_DISTCLEAN_FILES) ++ -rm -rf $(top_srcdir)/autom4te.cache ++ -rm -f Makefile ++maintainer-clean-am: distclean-am maintainer-clean-generic ++ ++mostlyclean: mostlyclean-am ++ ++mostlyclean-am: mostlyclean-compile mostlyclean-generic \ ++ mostlyclean-libtool ++ ++pdf: pdf-am ++ ++pdf-am: ++ ++ps: ps-am ++ ++ps-am: ++ ++uninstall-am: uninstall-libexecsubLTLIBRARIES ++ ++.MAKE: all install-am install-strip ++ ++.PHONY: CTAGS GTAGS TAGS all all-am am--refresh check check-am clean \ ++ clean-cscope clean-generic clean-libexecsubLTLIBRARIES \ ++ clean-libtool cscope cscopelist-am ctags ctags-am distclean \ ++ distclean-compile distclean-generic distclean-hdr \ ++ distclean-libtool distclean-tags dvi dvi-am html html-am info \ ++ info-am install install-am install-data install-data-am \ ++ install-dvi install-dvi-am install-exec install-exec-am \ ++ install-html install-html-am install-info install-info-am \ ++ install-libexecsubLTLIBRARIES install-man install-pdf \ ++ install-pdf-am install-ps install-ps-am install-strip \ ++ installcheck installcheck-am installdirs maintainer-clean \ ++ maintainer-clean-generic mostlyclean mostlyclean-compile \ ++ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ ++ tags tags-am uninstall uninstall-am \ ++ uninstall-libexecsubLTLIBRARIES ++ ++.PRECIOUS: Makefile ++ ++override CXXFLAGS := $(filter-out -fsanitize=address,$(CXXFLAGS)) ++override LDFLAGS := $(filter-out -fsanitize=address,$(LDFLAGS)) ++ ++# Tell versions [3.59,3.63) of GNU make to not export all variables. ++# Otherwise a system limit (for SysV at least) may be exceeded. ++.NOEXPORT: +diff --git a/bolt-plugin/aclocal.m4 b/bolt-plugin/aclocal.m4 +new file mode 100644 +index 000000000..22bc33401 +--- /dev/null ++++ b/bolt-plugin/aclocal.m4 +@@ -0,0 +1,1163 @@ ++# generated automatically by aclocal 1.16.1 -*- Autoconf -*- ++ ++# Copyright (C) 1996-2018 Free Software Foundation, Inc. ++ ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY, to the extent permitted by law; without ++# even the implied warranty of MERCHANTABILITY or FITNESS FOR A ++# PARTICULAR PURPOSE. ++ ++m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) ++m4_ifndef([AC_AUTOCONF_VERSION], ++ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl ++m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, ++[m4_warning([this file was generated for autoconf 2.69. ++You have another version of autoconf. It may work, but is not guaranteed to. ++If you have problems, you may need to regenerate the build system entirely. ++To do so, use the procedure documented by the package, typically 'autoreconf'.])]) ++ ++# Copyright (C) 2002-2018 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# AM_AUTOMAKE_VERSION(VERSION) ++# ---------------------------- ++# Automake X.Y traces this macro to ensure aclocal.m4 has been ++# generated from the m4 files accompanying Automake X.Y. ++# (This private macro should not be called outside this file.) ++AC_DEFUN([AM_AUTOMAKE_VERSION], ++[am__api_version='1.16' ++dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to ++dnl require some minimum version. Point them to the right macro. ++m4_if([$1], [1.16.1], [], ++ [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ++]) ++ ++# _AM_AUTOCONF_VERSION(VERSION) ++# ----------------------------- ++# aclocal traces this macro to find the Autoconf version. ++# This is a private macro too. Using m4_define simplifies ++# the logic in aclocal, which can simply ignore this definition. ++m4_define([_AM_AUTOCONF_VERSION], []) ++ ++# AM_SET_CURRENT_AUTOMAKE_VERSION ++# ------------------------------- ++# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. ++# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. ++AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], ++[AM_AUTOMAKE_VERSION([1.16.1])dnl ++m4_ifndef([AC_AUTOCONF_VERSION], ++ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl ++_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) ++ ++# AM_AUX_DIR_EXPAND -*- Autoconf -*- ++ ++# Copyright (C) 2001-2018 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets ++# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to ++# '$srcdir', '$srcdir/..', or '$srcdir/../..'. ++# ++# Of course, Automake must honor this variable whenever it calls a ++# tool from the auxiliary directory. The problem is that $srcdir (and ++# therefore $ac_aux_dir as well) can be either absolute or relative, ++# depending on how configure is run. This is pretty annoying, since ++# it makes $ac_aux_dir quite unusable in subdirectories: in the top ++# source directory, any form will work fine, but in subdirectories a ++# relative path needs to be adjusted first. ++# ++# $ac_aux_dir/missing ++# fails when called from a subdirectory if $ac_aux_dir is relative ++# $top_srcdir/$ac_aux_dir/missing ++# fails if $ac_aux_dir is absolute, ++# fails when called from a subdirectory in a VPATH build with ++# a relative $ac_aux_dir ++# ++# The reason of the latter failure is that $top_srcdir and $ac_aux_dir ++# are both prefixed by $srcdir. In an in-source build this is usually ++# harmless because $srcdir is '.', but things will broke when you ++# start a VPATH build or use an absolute $srcdir. ++# ++# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, ++# iff we strip the leading $srcdir from $ac_aux_dir. That would be: ++# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` ++# and then we would define $MISSING as ++# MISSING="\${SHELL} $am_aux_dir/missing" ++# This will work as long as MISSING is not called from configure, because ++# unfortunately $(top_srcdir) has no meaning in configure. ++# However there are other variables, like CC, which are often used in ++# configure, and could therefore not use this "fixed" $ac_aux_dir. ++# ++# Another solution, used here, is to always expand $ac_aux_dir to an ++# absolute PATH. The drawback is that using absolute paths prevent a ++# configured tree to be moved without reconfiguration. ++ ++AC_DEFUN([AM_AUX_DIR_EXPAND], ++[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl ++# Expand $ac_aux_dir to an absolute path. ++am_aux_dir=`cd "$ac_aux_dir" && pwd` ++]) ++ ++# AM_CONDITIONAL -*- Autoconf -*- ++ ++# Copyright (C) 1997-2018 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# AM_CONDITIONAL(NAME, SHELL-CONDITION) ++# ------------------------------------- ++# Define a conditional. ++AC_DEFUN([AM_CONDITIONAL], ++[AC_PREREQ([2.52])dnl ++ m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], ++ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl ++AC_SUBST([$1_TRUE])dnl ++AC_SUBST([$1_FALSE])dnl ++_AM_SUBST_NOTMAKE([$1_TRUE])dnl ++_AM_SUBST_NOTMAKE([$1_FALSE])dnl ++m4_define([_AM_COND_VALUE_$1], [$2])dnl ++if $2; then ++ $1_TRUE= ++ $1_FALSE='#' ++else ++ $1_TRUE='#' ++ $1_FALSE= ++fi ++AC_CONFIG_COMMANDS_PRE( ++[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then ++ AC_MSG_ERROR([[conditional "$1" was never defined. ++Usually this means the macro was only invoked conditionally.]]) ++fi])]) ++ ++# Copyright (C) 1999-2018 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++ ++# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be ++# written in clear, in which case automake, when reading aclocal.m4, ++# will think it sees a *use*, and therefore will trigger all it's ++# C support machinery. Also note that it means that autoscan, seeing ++# CC etc. in the Makefile, will ask for an AC_PROG_CC use... ++ ++ ++# _AM_DEPENDENCIES(NAME) ++# ---------------------- ++# See how the compiler implements dependency checking. ++# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". ++# We try a few techniques and use that to set a single cache variable. ++# ++# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was ++# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular ++# dependency, and given that the user is not expected to run this macro, ++# just rely on AC_PROG_CC. ++AC_DEFUN([_AM_DEPENDENCIES], ++[AC_REQUIRE([AM_SET_DEPDIR])dnl ++AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl ++AC_REQUIRE([AM_MAKE_INCLUDE])dnl ++AC_REQUIRE([AM_DEP_TRACK])dnl ++ ++m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], ++ [$1], [CXX], [depcc="$CXX" am_compiler_list=], ++ [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], ++ [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], ++ [$1], [UPC], [depcc="$UPC" am_compiler_list=], ++ [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], ++ [depcc="$$1" am_compiler_list=]) ++ ++AC_CACHE_CHECK([dependency style of $depcc], ++ [am_cv_$1_dependencies_compiler_type], ++[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then ++ # We make a subdir and do the tests there. Otherwise we can end up ++ # making bogus files that we don't know about and never remove. For ++ # instance it was reported that on HP-UX the gcc test will end up ++ # making a dummy file named 'D' -- because '-MD' means "put the output ++ # in D". ++ rm -rf conftest.dir ++ mkdir conftest.dir ++ # Copy depcomp to subdir because otherwise we won't find it if we're ++ # using a relative directory. ++ cp "$am_depcomp" conftest.dir ++ cd conftest.dir ++ # We will build objects and dependencies in a subdirectory because ++ # it helps to detect inapplicable dependency modes. For instance ++ # both Tru64's cc and ICC support -MD to output dependencies as a ++ # side effect of compilation, but ICC will put the dependencies in ++ # the current directory while Tru64 will put them in the object ++ # directory. ++ mkdir sub ++ ++ am_cv_$1_dependencies_compiler_type=none ++ if test "$am_compiler_list" = ""; then ++ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` ++ fi ++ am__universal=false ++ m4_case([$1], [CC], ++ [case " $depcc " in #( ++ *\ -arch\ *\ -arch\ *) am__universal=true ;; ++ esac], ++ [CXX], ++ [case " $depcc " in #( ++ *\ -arch\ *\ -arch\ *) am__universal=true ;; ++ esac]) ++ ++ for depmode in $am_compiler_list; do ++ # Setup a source with many dependencies, because some compilers ++ # like to wrap large dependency lists on column 80 (with \), and ++ # we should not choose a depcomp mode which is confused by this. ++ # ++ # We need to recreate these files for each test, as the compiler may ++ # overwrite some of them when testing with obscure command lines. ++ # This happens at least with the AIX C compiler. ++ : > sub/conftest.c ++ for i in 1 2 3 4 5 6; do ++ echo '#include "conftst'$i'.h"' >> sub/conftest.c ++ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with ++ # Solaris 10 /bin/sh. ++ echo '/* dummy */' > sub/conftst$i.h ++ done ++ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf ++ ++ # We check with '-c' and '-o' for the sake of the "dashmstdout" ++ # mode. It turns out that the SunPro C++ compiler does not properly ++ # handle '-M -o', and we need to detect this. Also, some Intel ++ # versions had trouble with output in subdirs. ++ am__obj=sub/conftest.${OBJEXT-o} ++ am__minus_obj="-o $am__obj" ++ case $depmode in ++ gcc) ++ # This depmode causes a compiler race in universal mode. ++ test "$am__universal" = false || continue ++ ;; ++ nosideeffect) ++ # After this tag, mechanisms are not by side-effect, so they'll ++ # only be used when explicitly requested. ++ if test "x$enable_dependency_tracking" = xyes; then ++ continue ++ else ++ break ++ fi ++ ;; ++ msvc7 | msvc7msys | msvisualcpp | msvcmsys) ++ # This compiler won't grok '-c -o', but also, the minuso test has ++ # not run yet. These depmodes are late enough in the game, and ++ # so weak that their functioning should not be impacted. ++ am__obj=conftest.${OBJEXT-o} ++ am__minus_obj= ++ ;; ++ none) break ;; ++ esac ++ if depmode=$depmode \ ++ source=sub/conftest.c object=$am__obj \ ++ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ ++ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ ++ >/dev/null 2>conftest.err && ++ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && ++ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && ++ grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ++ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then ++ # icc doesn't choke on unknown options, it will just issue warnings ++ # or remarks (even with -Werror). So we grep stderr for any message ++ # that says an option was ignored or not supported. ++ # When given -MP, icc 7.0 and 7.1 complain thusly: ++ # icc: Command line warning: ignoring option '-M'; no argument required ++ # The diagnosis changed in icc 8.0: ++ # icc: Command line remark: option '-MP' not supported ++ if (grep 'ignoring option' conftest.err || ++ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else ++ am_cv_$1_dependencies_compiler_type=$depmode ++ break ++ fi ++ fi ++ done ++ ++ cd .. ++ rm -rf conftest.dir ++else ++ am_cv_$1_dependencies_compiler_type=none ++fi ++]) ++AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) ++AM_CONDITIONAL([am__fastdep$1], [ ++ test "x$enable_dependency_tracking" != xno \ ++ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ++]) ++ ++ ++# AM_SET_DEPDIR ++# ------------- ++# Choose a directory name for dependency files. ++# This macro is AC_REQUIREd in _AM_DEPENDENCIES. ++AC_DEFUN([AM_SET_DEPDIR], ++[AC_REQUIRE([AM_SET_LEADING_DOT])dnl ++AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ++]) ++ ++ ++# AM_DEP_TRACK ++# ------------ ++AC_DEFUN([AM_DEP_TRACK], ++[AC_ARG_ENABLE([dependency-tracking], [dnl ++AS_HELP_STRING( ++ [--enable-dependency-tracking], ++ [do not reject slow dependency extractors]) ++AS_HELP_STRING( ++ [--disable-dependency-tracking], ++ [speeds up one-time build])]) ++if test "x$enable_dependency_tracking" != xno; then ++ am_depcomp="$ac_aux_dir/depcomp" ++ AMDEPBACKSLASH='\' ++ am__nodep='_no' ++fi ++AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) ++AC_SUBST([AMDEPBACKSLASH])dnl ++_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl ++AC_SUBST([am__nodep])dnl ++_AM_SUBST_NOTMAKE([am__nodep])dnl ++]) ++ ++# Generate code to set up dependency tracking. -*- Autoconf -*- ++ ++# Copyright (C) 1999-2018 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# _AM_OUTPUT_DEPENDENCY_COMMANDS ++# ------------------------------ ++AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], ++[{ ++ # Older Autoconf quotes --file arguments for eval, but not when files ++ # are listed without --file. Let's play safe and only enable the eval ++ # if we detect the quoting. ++ # TODO: see whether this extra hack can be removed once we start ++ # requiring Autoconf 2.70 or later. ++ AS_CASE([$CONFIG_FILES], ++ [*\'*], [eval set x "$CONFIG_FILES"], ++ [*], [set x $CONFIG_FILES]) ++ shift ++ # Used to flag and report bootstrapping failures. ++ am_rc=0 ++ for am_mf ++ do ++ # Strip MF so we end up with the name of the file. ++ am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` ++ # Check whether this is an Automake generated Makefile which includes ++ # dependency-tracking related rules and includes. ++ # Grep'ing the whole file directly is not great: AIX grep has a line ++ # limit of 2048, but all sed's we know have understand at least 4000. ++ sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ ++ || continue ++ am_dirpart=`AS_DIRNAME(["$am_mf"])` ++ am_filepart=`AS_BASENAME(["$am_mf"])` ++ AM_RUN_LOG([cd "$am_dirpart" \ ++ && sed -e '/# am--include-marker/d' "$am_filepart" \ ++ | $MAKE -f - am--depfiles]) || am_rc=$? ++ done ++ if test $am_rc -ne 0; then ++ AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments ++ for automatic dependency tracking. Try re-running configure with the ++ '--disable-dependency-tracking' option to at least be able to build ++ the package (albeit without support for automatic dependency tracking).]) ++ fi ++ AS_UNSET([am_dirpart]) ++ AS_UNSET([am_filepart]) ++ AS_UNSET([am_mf]) ++ AS_UNSET([am_rc]) ++ rm -f conftest-deps.mk ++} ++])# _AM_OUTPUT_DEPENDENCY_COMMANDS ++ ++ ++# AM_OUTPUT_DEPENDENCY_COMMANDS ++# ----------------------------- ++# This macro should only be invoked once -- use via AC_REQUIRE. ++# ++# This code is only required when automatic dependency tracking is enabled. ++# This creates each '.Po' and '.Plo' makefile fragment that we'll need in ++# order to bootstrap the dependency handling code. ++AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], ++[AC_CONFIG_COMMANDS([depfiles], ++ [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], ++ [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) ++ ++# Do all the work for Automake. -*- Autoconf -*- ++ ++# Copyright (C) 1996-2018 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# This macro actually does too much. Some checks are only needed if ++# your package does certain things. But this isn't really a big deal. ++ ++dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. ++m4_define([AC_PROG_CC], ++m4_defn([AC_PROG_CC]) ++[_AM_PROG_CC_C_O ++]) ++ ++# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) ++# AM_INIT_AUTOMAKE([OPTIONS]) ++# ----------------------------------------------- ++# The call with PACKAGE and VERSION arguments is the old style ++# call (pre autoconf-2.50), which is being phased out. PACKAGE ++# and VERSION should now be passed to AC_INIT and removed from ++# the call to AM_INIT_AUTOMAKE. ++# We support both call styles for the transition. After ++# the next Automake release, Autoconf can make the AC_INIT ++# arguments mandatory, and then we can depend on a new Autoconf ++# release and drop the old call support. ++AC_DEFUN([AM_INIT_AUTOMAKE], ++[AC_PREREQ([2.65])dnl ++dnl Autoconf wants to disallow AM_ names. We explicitly allow ++dnl the ones we care about. ++m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl ++AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl ++AC_REQUIRE([AC_PROG_INSTALL])dnl ++if test "`cd $srcdir && pwd`" != "`pwd`"; then ++ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output ++ # is not polluted with repeated "-I." ++ AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl ++ # test to see if srcdir already configured ++ if test -f $srcdir/config.status; then ++ AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) ++ fi ++fi ++ ++# test whether we have cygpath ++if test -z "$CYGPATH_W"; then ++ if (cygpath --version) >/dev/null 2>/dev/null; then ++ CYGPATH_W='cygpath -w' ++ else ++ CYGPATH_W=echo ++ fi ++fi ++AC_SUBST([CYGPATH_W]) ++ ++# Define the identity of the package. ++dnl Distinguish between old-style and new-style calls. ++m4_ifval([$2], ++[AC_DIAGNOSE([obsolete], ++ [$0: two- and three-arguments forms are deprecated.]) ++m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl ++ AC_SUBST([PACKAGE], [$1])dnl ++ AC_SUBST([VERSION], [$2])], ++[_AM_SET_OPTIONS([$1])dnl ++dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. ++m4_if( ++ m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), ++ [ok:ok],, ++ [m4_fatal([AC_INIT should be called with package and version arguments])])dnl ++ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl ++ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl ++ ++_AM_IF_OPTION([no-define],, ++[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) ++ AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl ++ ++# Some tools Automake needs. ++AC_REQUIRE([AM_SANITY_CHECK])dnl ++AC_REQUIRE([AC_ARG_PROGRAM])dnl ++AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) ++AM_MISSING_PROG([AUTOCONF], [autoconf]) ++AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) ++AM_MISSING_PROG([AUTOHEADER], [autoheader]) ++AM_MISSING_PROG([MAKEINFO], [makeinfo]) ++AC_REQUIRE([AM_PROG_INSTALL_SH])dnl ++AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl ++AC_REQUIRE([AC_PROG_MKDIR_P])dnl ++# For better backward compatibility. To be removed once Automake 1.9.x ++# dies out for good. For more background, see: ++# <https://lists.gnu.org/archive/html/automake/2012-07/msg00001.html> ++# <https://lists.gnu.org/archive/html/automake/2012-07/msg00014.html> ++AC_SUBST([mkdir_p], ['$(MKDIR_P)']) ++# We need awk for the "check" target (and possibly the TAP driver). The ++# system "awk" is bad on some platforms. ++AC_REQUIRE([AC_PROG_AWK])dnl ++AC_REQUIRE([AC_PROG_MAKE_SET])dnl ++AC_REQUIRE([AM_SET_LEADING_DOT])dnl ++_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], ++ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], ++ [_AM_PROG_TAR([v7])])]) ++_AM_IF_OPTION([no-dependencies],, ++[AC_PROVIDE_IFELSE([AC_PROG_CC], ++ [_AM_DEPENDENCIES([CC])], ++ [m4_define([AC_PROG_CC], ++ m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl ++AC_PROVIDE_IFELSE([AC_PROG_CXX], ++ [_AM_DEPENDENCIES([CXX])], ++ [m4_define([AC_PROG_CXX], ++ m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl ++AC_PROVIDE_IFELSE([AC_PROG_OBJC], ++ [_AM_DEPENDENCIES([OBJC])], ++ [m4_define([AC_PROG_OBJC], ++ m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl ++AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], ++ [_AM_DEPENDENCIES([OBJCXX])], ++ [m4_define([AC_PROG_OBJCXX], ++ m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ++]) ++AC_REQUIRE([AM_SILENT_RULES])dnl ++dnl The testsuite driver may need to know about EXEEXT, so add the ++dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This ++dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. ++AC_CONFIG_COMMANDS_PRE(dnl ++[m4_provide_if([_AM_COMPILER_EXEEXT], ++ [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl ++ ++# POSIX will say in a future version that running "rm -f" with no argument ++# is OK; and we want to be able to make that assumption in our Makefile ++# recipes. So use an aggressive probe to check that the usage we want is ++# actually supported "in the wild" to an acceptable degree. ++# See automake bug#10828. ++# To make any issue more visible, cause the running configure to be aborted ++# by default if the 'rm' program in use doesn't match our expectations; the ++# user can still override this though. ++if rm -f && rm -fr && rm -rf; then : OK; else ++ cat >&2 <<'END' ++Oops! ++ ++Your 'rm' program seems unable to run without file operands specified ++on the command line, even when the '-f' option is present. This is contrary ++to the behaviour of most rm programs out there, and not conforming with ++the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542> ++ ++Please tell bug-automake@gnu.org about your system, including the value ++of your $PATH and any error possibly output before this message. This ++can help us improve future automake versions. ++ ++END ++ if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then ++ echo 'Configuration will proceed anyway, since you have set the' >&2 ++ echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 ++ echo >&2 ++ else ++ cat >&2 <<'END' ++Aborting the configuration process, to ensure you take notice of the issue. ++ ++You can download and install GNU coreutils to get an 'rm' implementation ++that behaves properly: <https://www.gnu.org/software/coreutils/>. ++ ++If you want to complete the configuration process using your problematic ++'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM ++to "yes", and re-run configure. ++ ++END ++ AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) ++ fi ++fi ++dnl The trailing newline in this macro's definition is deliberate, for ++dnl backward compatibility and to allow trailing 'dnl'-style comments ++dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ++]) ++ ++dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not ++dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further ++dnl mangled by Autoconf and run in a shell conditional statement. ++m4_define([_AC_COMPILER_EXEEXT], ++m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) ++ ++# When config.status generates a header, we must update the stamp-h file. ++# This file resides in the same directory as the config header ++# that is generated. The stamp files are numbered to have different names. ++ ++# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the ++# loop where config.status creates the headers, so we can generate ++# our stamp files there. ++AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], ++[# Compute $1's index in $config_headers. ++_am_arg=$1 ++_am_stamp_count=1 ++for _am_header in $config_headers :; do ++ case $_am_header in ++ $_am_arg | $_am_arg:* ) ++ break ;; ++ * ) ++ _am_stamp_count=`expr $_am_stamp_count + 1` ;; ++ esac ++done ++echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) ++ ++# Copyright (C) 2001-2018 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# AM_PROG_INSTALL_SH ++# ------------------ ++# Define $install_sh. ++AC_DEFUN([AM_PROG_INSTALL_SH], ++[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl ++if test x"${install_sh+set}" != xset; then ++ case $am_aux_dir in ++ *\ * | *\ *) ++ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; ++ *) ++ install_sh="\${SHELL} $am_aux_dir/install-sh" ++ esac ++fi ++AC_SUBST([install_sh])]) ++ ++# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- ++# From Jim Meyering ++ ++# Copyright (C) 1996-2018 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# AM_MAINTAINER_MODE([DEFAULT-MODE]) ++# ---------------------------------- ++# Control maintainer-specific portions of Makefiles. ++# Default is to disable them, unless 'enable' is passed literally. ++# For symmetry, 'disable' may be passed as well. Anyway, the user ++# can override the default with the --enable/--disable switch. ++AC_DEFUN([AM_MAINTAINER_MODE], ++[m4_case(m4_default([$1], [disable]), ++ [enable], [m4_define([am_maintainer_other], [disable])], ++ [disable], [m4_define([am_maintainer_other], [enable])], ++ [m4_define([am_maintainer_other], [enable]) ++ m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) ++AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) ++ dnl maintainer-mode's default is 'disable' unless 'enable' is passed ++ AC_ARG_ENABLE([maintainer-mode], ++ [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode], ++ am_maintainer_other[ make rules and dependencies not useful ++ (and sometimes confusing) to the casual installer])], ++ [USE_MAINTAINER_MODE=$enableval], ++ [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) ++ AC_MSG_RESULT([$USE_MAINTAINER_MODE]) ++ AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) ++ MAINT=$MAINTAINER_MODE_TRUE ++ AC_SUBST([MAINT])dnl ++] ++) ++ ++# Check to see how 'make' treats includes. -*- Autoconf -*- ++ ++# Copyright (C) 2001-2018 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# AM_MAKE_INCLUDE() ++# ----------------- ++# Check whether make has an 'include' directive that can support all ++# the idioms we need for our automatic dependency tracking code. ++AC_DEFUN([AM_MAKE_INCLUDE], ++[AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) ++cat > confinc.mk << 'END' ++am__doit: ++ @echo this is the am__doit target >confinc.out ++.PHONY: am__doit ++END ++am__include="#" ++am__quote= ++# BSD make does it like this. ++echo '.include "confinc.mk" # ignored' > confmf.BSD ++# Other make implementations (GNU, Solaris 10, AIX) do it like this. ++echo 'include confinc.mk # ignored' > confmf.GNU ++_am_result=no ++for s in GNU BSD; do ++ AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) ++ AS_CASE([$?:`cat confinc.out 2>/dev/null`], ++ ['0:this is the am__doit target'], ++ [AS_CASE([$s], ++ [BSD], [am__include='.include' am__quote='"'], ++ [am__include='include' am__quote=''])]) ++ if test "$am__include" != "#"; then ++ _am_result="yes ($s style)" ++ break ++ fi ++done ++rm -f confinc.* confmf.* ++AC_MSG_RESULT([${_am_result}]) ++AC_SUBST([am__include])]) ++AC_SUBST([am__quote])]) ++ ++# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- ++ ++# Copyright (C) 1997-2018 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# AM_MISSING_PROG(NAME, PROGRAM) ++# ------------------------------ ++AC_DEFUN([AM_MISSING_PROG], ++[AC_REQUIRE([AM_MISSING_HAS_RUN]) ++$1=${$1-"${am_missing_run}$2"} ++AC_SUBST($1)]) ++ ++# AM_MISSING_HAS_RUN ++# ------------------ ++# Define MISSING if not defined so far and test if it is modern enough. ++# If it is, set am_missing_run to use it, otherwise, to nothing. ++AC_DEFUN([AM_MISSING_HAS_RUN], ++[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl ++AC_REQUIRE_AUX_FILE([missing])dnl ++if test x"${MISSING+set}" != xset; then ++ case $am_aux_dir in ++ *\ * | *\ *) ++ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; ++ *) ++ MISSING="\${SHELL} $am_aux_dir/missing" ;; ++ esac ++fi ++# Use eval to expand $SHELL ++if eval "$MISSING --is-lightweight"; then ++ am_missing_run="$MISSING " ++else ++ am_missing_run= ++ AC_MSG_WARN(['missing' script is too old or missing]) ++fi ++]) ++ ++# Helper functions for option handling. -*- Autoconf -*- ++ ++# Copyright (C) 2001-2018 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# _AM_MANGLE_OPTION(NAME) ++# ----------------------- ++AC_DEFUN([_AM_MANGLE_OPTION], ++[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) ++ ++# _AM_SET_OPTION(NAME) ++# -------------------- ++# Set option NAME. Presently that only means defining a flag for this option. ++AC_DEFUN([_AM_SET_OPTION], ++[m4_define(_AM_MANGLE_OPTION([$1]), [1])]) ++ ++# _AM_SET_OPTIONS(OPTIONS) ++# ------------------------ ++# OPTIONS is a space-separated list of Automake options. ++AC_DEFUN([_AM_SET_OPTIONS], ++[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) ++ ++# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) ++# ------------------------------------------- ++# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. ++AC_DEFUN([_AM_IF_OPTION], ++[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) ++ ++# Copyright (C) 1999-2018 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# _AM_PROG_CC_C_O ++# --------------- ++# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC ++# to automatically call this. ++AC_DEFUN([_AM_PROG_CC_C_O], ++[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl ++AC_REQUIRE_AUX_FILE([compile])dnl ++AC_LANG_PUSH([C])dnl ++AC_CACHE_CHECK( ++ [whether $CC understands -c and -o together], ++ [am_cv_prog_cc_c_o], ++ [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) ++ # Make sure it works both with $CC and with simple cc. ++ # Following AC_PROG_CC_C_O, we do the test twice because some ++ # compilers refuse to overwrite an existing .o file with -o, ++ # though they will create one. ++ am_cv_prog_cc_c_o=yes ++ for am_i in 1 2; do ++ if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ ++ && test -f conftest2.$ac_objext; then ++ : OK ++ else ++ am_cv_prog_cc_c_o=no ++ break ++ fi ++ done ++ rm -f core conftest* ++ unset am_i]) ++if test "$am_cv_prog_cc_c_o" != yes; then ++ # Losing compiler, so override with the script. ++ # FIXME: It is wrong to rewrite CC. ++ # But if we don't then we get into trouble of one sort or another. ++ # A longer-term fix would be to have automake use am__CC in this case, ++ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" ++ CC="$am_aux_dir/compile $CC" ++fi ++AC_LANG_POP([C])]) ++ ++# For backward compatibility. ++AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) ++ ++# Copyright (C) 2001-2018 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# AM_RUN_LOG(COMMAND) ++# ------------------- ++# Run COMMAND, save the exit status in ac_status, and log it. ++# (This has been adapted from Autoconf's _AC_RUN_LOG macro.) ++AC_DEFUN([AM_RUN_LOG], ++[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ++ ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD ++ (exit $ac_status); }]) ++ ++# Check to make sure that the build environment is sane. -*- Autoconf -*- ++ ++# Copyright (C) 1996-2018 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# AM_SANITY_CHECK ++# --------------- ++AC_DEFUN([AM_SANITY_CHECK], ++[AC_MSG_CHECKING([whether build environment is sane]) ++# Reject unsafe characters in $srcdir or the absolute working directory ++# name. Accept space and tab only in the latter. ++am_lf=' ++' ++case `pwd` in ++ *[[\\\"\#\$\&\'\`$am_lf]]*) ++ AC_MSG_ERROR([unsafe absolute working directory name]);; ++esac ++case $srcdir in ++ *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) ++ AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; ++esac ++ ++# Do 'set' in a subshell so we don't clobber the current shell's ++# arguments. Must try -L first in case configure is actually a ++# symlink; some systems play weird games with the mod time of symlinks ++# (eg FreeBSD returns the mod time of the symlink's containing ++# directory). ++if ( ++ am_has_slept=no ++ for am_try in 1 2; do ++ echo "timestamp, slept: $am_has_slept" > conftest.file ++ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` ++ if test "$[*]" = "X"; then ++ # -L didn't work. ++ set X `ls -t "$srcdir/configure" conftest.file` ++ fi ++ if test "$[*]" != "X $srcdir/configure conftest.file" \ ++ && test "$[*]" != "X conftest.file $srcdir/configure"; then ++ ++ # If neither matched, then we have a broken ls. This can happen ++ # if, for instance, CONFIG_SHELL is bash and it inherits a ++ # broken ls alias from the environment. This has actually ++ # happened. Such a system could not be considered "sane". ++ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken ++ alias in your environment]) ++ fi ++ if test "$[2]" = conftest.file || test $am_try -eq 2; then ++ break ++ fi ++ # Just in case. ++ sleep 1 ++ am_has_slept=yes ++ done ++ test "$[2]" = conftest.file ++ ) ++then ++ # Ok. ++ : ++else ++ AC_MSG_ERROR([newly created file is older than distributed files! ++Check your system clock]) ++fi ++AC_MSG_RESULT([yes]) ++# If we didn't sleep, we still need to ensure time stamps of config.status and ++# generated files are strictly newer. ++am_sleep_pid= ++if grep 'slept: no' conftest.file >/dev/null 2>&1; then ++ ( sleep 1 ) & ++ am_sleep_pid=$! ++fi ++AC_CONFIG_COMMANDS_PRE( ++ [AC_MSG_CHECKING([that generated files are newer than configure]) ++ if test -n "$am_sleep_pid"; then ++ # Hide warnings about reused PIDs. ++ wait $am_sleep_pid 2>/dev/null ++ fi ++ AC_MSG_RESULT([done])]) ++rm -f conftest.file ++]) ++ ++# Copyright (C) 2009-2018 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# AM_SILENT_RULES([DEFAULT]) ++# -------------------------- ++# Enable less verbose build rules; with the default set to DEFAULT ++# ("yes" being less verbose, "no" or empty being verbose). ++AC_DEFUN([AM_SILENT_RULES], ++[AC_ARG_ENABLE([silent-rules], [dnl ++AS_HELP_STRING( ++ [--enable-silent-rules], ++ [less verbose build output (undo: "make V=1")]) ++AS_HELP_STRING( ++ [--disable-silent-rules], ++ [verbose build output (undo: "make V=0")])dnl ++]) ++case $enable_silent_rules in @%:@ ((( ++ yes) AM_DEFAULT_VERBOSITY=0;; ++ no) AM_DEFAULT_VERBOSITY=1;; ++ *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; ++esac ++dnl ++dnl A few 'make' implementations (e.g., NonStop OS and NextStep) ++dnl do not support nested variable expansions. ++dnl See automake bug#9928 and bug#10237. ++am_make=${MAKE-make} ++AC_CACHE_CHECK([whether $am_make supports nested variables], ++ [am_cv_make_support_nested_variables], ++ [if AS_ECHO([['TRUE=$(BAR$(V)) ++BAR0=false ++BAR1=true ++V=1 ++am__doit: ++ @$(TRUE) ++.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then ++ am_cv_make_support_nested_variables=yes ++else ++ am_cv_make_support_nested_variables=no ++fi]) ++if test $am_cv_make_support_nested_variables = yes; then ++ dnl Using '$V' instead of '$(V)' breaks IRIX make. ++ AM_V='$(V)' ++ AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' ++else ++ AM_V=$AM_DEFAULT_VERBOSITY ++ AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY ++fi ++AC_SUBST([AM_V])dnl ++AM_SUBST_NOTMAKE([AM_V])dnl ++AC_SUBST([AM_DEFAULT_V])dnl ++AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl ++AC_SUBST([AM_DEFAULT_VERBOSITY])dnl ++AM_BACKSLASH='\' ++AC_SUBST([AM_BACKSLASH])dnl ++_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ++]) ++ ++# Copyright (C) 2001-2018 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# AM_PROG_INSTALL_STRIP ++# --------------------- ++# One issue with vendor 'install' (even GNU) is that you can't ++# specify the program used to strip binaries. This is especially ++# annoying in cross-compiling environments, where the build's strip ++# is unlikely to handle the host's binaries. ++# Fortunately install-sh will honor a STRIPPROG variable, so we ++# always use install-sh in "make install-strip", and initialize ++# STRIPPROG with the value of the STRIP variable (set by the user). ++AC_DEFUN([AM_PROG_INSTALL_STRIP], ++[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl ++# Installed binaries are usually stripped using 'strip' when the user ++# run "make install-strip". However 'strip' might not be the right ++# tool to use in cross-compilation environments, therefore Automake ++# will honor the 'STRIP' environment variable to overrule this program. ++dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. ++if test "$cross_compiling" != no; then ++ AC_CHECK_TOOL([STRIP], [strip], :) ++fi ++INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" ++AC_SUBST([INSTALL_STRIP_PROGRAM])]) ++ ++# Copyright (C) 2006-2018 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# _AM_SUBST_NOTMAKE(VARIABLE) ++# --------------------------- ++# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. ++# This macro is traced by Automake. ++AC_DEFUN([_AM_SUBST_NOTMAKE]) ++ ++# AM_SUBST_NOTMAKE(VARIABLE) ++# -------------------------- ++# Public sister of _AM_SUBST_NOTMAKE. ++AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) ++ ++# Check how to create a tarball. -*- Autoconf -*- ++ ++# Copyright (C) 2004-2018 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# _AM_PROG_TAR(FORMAT) ++# -------------------- ++# Check how to create a tarball in format FORMAT. ++# FORMAT should be one of 'v7', 'ustar', or 'pax'. ++# ++# Substitute a variable $(am__tar) that is a command ++# writing to stdout a FORMAT-tarball containing the directory ++# $tardir. ++# tardir=directory && $(am__tar) > result.tar ++# ++# Substitute a variable $(am__untar) that extract such ++# a tarball read from stdin. ++# $(am__untar) < result.tar ++# ++AC_DEFUN([_AM_PROG_TAR], ++[# Always define AMTAR for backward compatibility. Yes, it's still used ++# in the wild :-( We should find a proper way to deprecate it ... ++AC_SUBST([AMTAR], ['$${TAR-tar}']) ++ ++# We'll loop over all known methods to create a tar archive until one works. ++_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' ++ ++m4_if([$1], [v7], ++ [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], ++ ++ [m4_case([$1], ++ [ustar], ++ [# The POSIX 1988 'ustar' format is defined with fixed-size fields. ++ # There is notably a 21 bits limit for the UID and the GID. In fact, ++ # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 ++ # and bug#13588). ++ am_max_uid=2097151 # 2^21 - 1 ++ am_max_gid=$am_max_uid ++ # The $UID and $GID variables are not portable, so we need to resort ++ # to the POSIX-mandated id(1) utility. Errors in the 'id' calls ++ # below are definitely unexpected, so allow the users to see them ++ # (that is, avoid stderr redirection). ++ am_uid=`id -u || echo unknown` ++ am_gid=`id -g || echo unknown` ++ AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) ++ if test $am_uid -le $am_max_uid; then ++ AC_MSG_RESULT([yes]) ++ else ++ AC_MSG_RESULT([no]) ++ _am_tools=none ++ fi ++ AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) ++ if test $am_gid -le $am_max_gid; then ++ AC_MSG_RESULT([yes]) ++ else ++ AC_MSG_RESULT([no]) ++ _am_tools=none ++ fi], ++ ++ [pax], ++ [], ++ ++ [m4_fatal([Unknown tar format])]) ++ ++ AC_MSG_CHECKING([how to create a $1 tar archive]) ++ ++ # Go ahead even if we have the value already cached. We do so because we ++ # need to set the values for the 'am__tar' and 'am__untar' variables. ++ _am_tools=${am_cv_prog_tar_$1-$_am_tools} ++ ++ for _am_tool in $_am_tools; do ++ case $_am_tool in ++ gnutar) ++ for _am_tar in tar gnutar gtar; do ++ AM_RUN_LOG([$_am_tar --version]) && break ++ done ++ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' ++ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' ++ am__untar="$_am_tar -xf -" ++ ;; ++ plaintar) ++ # Must skip GNU tar: if it does not support --format= it doesn't create ++ # ustar tarball either. ++ (tar --version) >/dev/null 2>&1 && continue ++ am__tar='tar chf - "$$tardir"' ++ am__tar_='tar chf - "$tardir"' ++ am__untar='tar xf -' ++ ;; ++ pax) ++ am__tar='pax -L -x $1 -w "$$tardir"' ++ am__tar_='pax -L -x $1 -w "$tardir"' ++ am__untar='pax -r' ++ ;; ++ cpio) ++ am__tar='find "$$tardir" -print | cpio -o -H $1 -L' ++ am__tar_='find "$tardir" -print | cpio -o -H $1 -L' ++ am__untar='cpio -i -H $1 -d' ++ ;; ++ none) ++ am__tar=false ++ am__tar_=false ++ am__untar=false ++ ;; ++ esac ++ ++ # If the value was cached, stop now. We just wanted to have am__tar ++ # and am__untar set. ++ test -n "${am_cv_prog_tar_$1}" && break ++ ++ # tar/untar a dummy directory, and stop if the command works. ++ rm -rf conftest.dir ++ mkdir conftest.dir ++ echo GrepMe > conftest.dir/file ++ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) ++ rm -rf conftest.dir ++ if test -s conftest.tar; then ++ AM_RUN_LOG([$am__untar <conftest.tar]) ++ AM_RUN_LOG([cat conftest.dir/file]) ++ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break ++ fi ++ done ++ rm -rf conftest.dir ++ ++ AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) ++ AC_MSG_RESULT([$am_cv_prog_tar_$1])]) ++ ++AC_SUBST([am__tar]) ++AC_SUBST([am__untar]) ++]) # _AM_PROG_TAR ++ ++m4_include([../config/acx.m4]) ++m4_include([../config/depstand.m4]) ++m4_include([../config/lead-dot.m4]) ++m4_include([../config/lthostflags.m4]) ++m4_include([../config/override.m4]) ++m4_include([../config/warnings.m4]) ++m4_include([../libtool.m4]) ++m4_include([../ltoptions.m4]) ++m4_include([../ltsugar.m4]) ++m4_include([../ltversion.m4]) ++m4_include([../lt~obsolete.m4]) +diff --git a/bolt-plugin/bolt-plugin.cc b/bolt-plugin/bolt-plugin.cc +new file mode 100644 +index 000000000..f357b00dd +--- /dev/null ++++ b/bolt-plugin/bolt-plugin.cc +@@ -0,0 +1,1152 @@ ++/* bolt plugin for gold and/or GNU ld. ++ Copyright (C) 2022-2022 Free Software Foundation, Inc. ++ Contributed by Majin and Liyancheng. ++ ++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, or (at your option) ++any later version. ++ ++This program is distributed in the hope that it will be useful, but ++WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; see the file COPYING3. If not see ++<http://www.gnu.org/licenses/>. */ ++ ++/* The plugin has only one external function: onload. Gold passes it an ++ array of function that the plugin uses to communicate back to gold. ++ ++ With the functions provided by gold, the plugin can be notified when ++ gold first analyzes a file and passes a symbol table back to gold. The ++ plugin is also notified when all symbols have been read and it is time ++ to generate machine code for the necessary symbols. ++ ++ More information at http://gcc.gnu.org/wiki/whopr/driver. */ ++ ++/* Firstly, this plugin read profile info from .text.fdo.func_name section from ++ each claim file and parse it into BOLT profile. ++ ++ The section read from the claim file will follow the following example. ++ .section .text.fdo.sort_array // Section name ++ .string ".fdo.caller sort_array" // Function name ++ .string ".fdo.caller.size 492" // Function size ++ .string ".fdo.caller.bind GLOBAL" // Bind type ++ .string "58" // branch source address ++ .string "0" // branch destination address ++ .string "336" // count ++ ++ The above is the case where the profile data comes from PGO. ++ If the data comes from AutoFDO, branch source address will be ++ BB address and branch destination address will be disabled. e.g. ++ .string "58" // BB address ++ .string "336" // count ++ ++ The BOLT profile file format follows the syntax below which defined in ++ llvm-bolt. ++ ++ Branch info mode when profile collect from PGO: ++ <is symbol?> <closest elf symbol or DSO name> <relative FROM address> ++ <is symbol?> <closest elf symbol or DSO name> <relative TO address> ++ <number of mispredictions> <number of branches> ++ ++ Examples: ++ ++ 1 main 58 1 main 78 0 100 ++ ++ BB info mode when profile collect from AutoFDO: ++ <is symbol?> <closest elf symbol or DSO name> <relative address> <count> ++ ++ Examples: ++ ++ 1 main 58 100 ++ ++ Secondly, it also receive BOLT profile generated by perf2bolt. ++ ++ Finally, this plugin calls llvm-bolt to do optimizations after linkage. ++ ++*/ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++#if HAVE_STDINT_H ++#include <stdint.h> ++#endif ++#include <assert.h> ++#include <errno.h> ++#include <string.h> ++#include <stdlib.h> ++#include <stdio.h> ++#include <inttypes.h> ++#include <sys/stat.h> ++#include <unistd.h> ++#include <fcntl.h> ++#include <sys/types.h> ++#ifdef HAVE_SYS_WAIT_H ++#include <sys/wait.h> ++#endif ++#include <filenames.h> ++#include <hashtab.h> ++#include "simple-object.h" ++#include "plugin-api.h" ++ ++namespace LIBIBERTY ++{ ++#include <libiberty.h> ++} ++using LIBIBERTY::xmalloc; ++using LIBIBERTY::lbasename; ++using LIBIBERTY::xstrdup; ++using LIBIBERTY::concat; ++using LIBIBERTY::lrealpath; ++ ++#include <vector> ++#include <string> ++#include <map> ++#include <set> ++ ++using std::vector; ++using std::string; ++using std::map; ++using std::set; ++ ++static ld_plugin_register_claim_file register_claim_file = NULL; ++static ld_plugin_register_all_symbols_read register_all_symbols_read = NULL; ++static ld_plugin_register_cleanup register_cleanup = NULL; ++static ld_plugin_message message = NULL; ++ ++static enum ld_plugin_output_file_type linker_output; ++ ++extern "C" ++{ ++ enum ld_plugin_status onload (struct ld_plugin_tv *tv); ++} ++ ++/* C99 bool type cannot coerce parm 'gate' range, so use int here. */ ++ ++static void ++check_gate (int gate, enum ld_plugin_level level, const char *text) ++{ ++ if (gate) ++ { ++ return; ++ } ++ ++ if (message) ++ { ++ message (level, text); ++ } ++ else ++ { ++ /* Print msg to stderr if there is no nicer way to inform the user. */ ++ fprintf (stderr, "%s\n", text); ++ if (level == LDPL_FATAL) ++ { ++ abort (); ++ } ++ } ++} ++ ++/* This wrapper allows macro CHECK to be called with a non-integer argument ++ GATE. For pointer cases, GATE should be no-Null. */ ++ ++#define CHECK(GATE, LEVEL, TEXT) check_gate (((GATE) != 0), (LEVEL), (TEXT)) ++ ++#define __MSG_INFO__ ++#define __MSG_WARN__ ++#define __MSG_ERROR__ ++ ++#ifdef __MSG_INFO__ ++#define MSG_INFO(...) \ ++ if (message) \ ++ { \ ++ message (LDPL_INFO, "BOLT-PLUGIN-INFO: " __VA_ARGS__); \ ++ } \ ++ else \ ++ { \ ++ fprintf (stderr, "BOLT-PLUGIN-INFO: " __VA_ARGS__); \ ++ } ++#else ++#define MSG_INFO(...) ++#endif ++ ++#ifdef __MSG_WARN__ ++#define MSG_WARN(...) \ ++ if (message) \ ++ { \ ++ message (LDPL_WARNING, "BOLT-PLUGIN-WARNING: " __VA_ARGS__); \ ++ } \ ++ else \ ++ { \ ++ fprintf (stderr, "BOLT-PLUGIN-WARNING: " __VA_ARGS__); \ ++ } ++#else ++#define MSG_WARN(...) ++#endif ++ ++#ifdef __MSG_ERROR__ ++#define MSG_ERROR(...) \ ++ if (message) \ ++ { \ ++ message (LDPL_FATAL, "BOLT-PLUGIN-ERROR: " __VA_ARGS__); \ ++ } \ ++ else \ ++ { \ ++ fprintf (stderr, "BOLT-PLUGIN-ERROR: " __VA_ARGS__); \ ++ abort (); \ ++ } ++#else ++#define MSG_ERROR(...) ++#endif ++ ++#if HAVE_DOS_BASED_FILE_SYSTEM ++const char *separator = "\\"; ++#else ++const char *separator = "/"; ++#endif ++ ++/* Encapsulates object file data during symbol scan. */ ++struct plugin_objfile ++{ ++ simple_object_read *objfile; ++ const struct ld_plugin_input_file *file; ++}; ++ ++struct jump_info ++{ ++ string des_func_name; ++ string src_addr_offset; ++ string dst_addr_offset; ++ string count; ++}; ++ ++struct func_info ++{ ++ string function_name; ++ string bind_type; /* "GLOBAL","WEAK","LOCAL","UNKNOWN". */ ++ string size; ++ vector<jump_info> edges; ++}; ++ ++/* Define feedback data type. */ ++enum feedback_type ++{ ++ NULL_TYPE, /* No feedback data. */ ++ PGO_TYPE, /* Feedback data from PGO. */ ++ AFDO_TYPE, /* Feedback data from AutoFDO. */ ++ BOLT_TYPE, /* Feedback data from BOLT. */ ++}; ++ ++#define DEFAULT_BOLT_OUT_DIR (get_current_dir_name ()) ++#define DEFAULT_BOLT_OUT_NAME "default.fdata" ++#define DEFAULT_BOLT_OUT_NAME_SUFFIX ".fdata" ++ ++/* The FDO section's special prefix names. */ ++#define ASM_FDO_SECTION_PREFIX ".text.fdo." ++#define ASM_FDO_CALLER_FLAG ".fdo.caller " ++#define ASM_FDO_CALLER_BIND_FLAG ".fdo.caller.bind " ++#define ASM_FDO_CALLER_SIZE_FLAG ".fdo.caller.size " ++#define ASM_FDO_CALLEE_FLAG ".fdo.callee " ++ ++static int linker_output_set; ++ ++/* BOLT profile name generated by -fauto-bolt or ++ read from -fbolt-use. */ ++static string bolt_profile_name; ++ ++/* Path to save configuration file generated by -fauto-bolt. */ ++static string bolt_dir_path; ++ ++/* BOLT profile file FD generated by -fauto-bolt. */ ++static FILE *bolt_file_fd = NULL; ++ ++/* Temporary binary or dynamic file with reloc info. */ ++static string tmp_out_file_name = "a.out"; ++ ++/* Binary or dynamic file after BOLT. */ ++static string bolt_opt_target; ++ ++/* Format of bolt_optimize_options should be "reorder-functions=hfsort+ ...", ++ command 'llvm-bolt' has been added here. */ ++static string bolt_optimize_options ("llvm-bolt "); ++ ++static enum feedback_type fdo_type = feedback_type::NULL_TYPE; ++ ++static vector<string> gcc_options; ++ ++/* Map of <weak_function_name, vector<function_info>> */ ++static map<string, vector<struct func_info>> weak_functions; ++ ++/* Returns 1 if two strings have the same prefix. */ ++ ++inline static int ++is_prefix_of (const char *prefix, const char *str) ++{ ++ return strncmp (prefix, str, strlen (prefix)) == 0; ++} ++ ++static bool ++file_exist (const char *file_name) ++{ ++ if (file_name == nullptr) ++ { ++ MSG_ERROR ("file_exist get empty input file name."); ++ return false; ++ } ++ struct stat buffer; ++ if (stat (file_name, &buffer) == 0) ++ { ++ return true; ++ } ++ ++ MSG_WARN ("file_exist check failed: %s does not exist!", file_name); ++ return false; ++} ++ ++/* Popen run cmd, use safe character set for whitelist verification. */ ++ ++static void ++popen_run (const string& cmd) ++{ ++ for (const char &ch : cmd) ++ { ++ if ((ch >= '0' && ch <= '9') ++ || (ch >= 'A' && ch <= 'Z') ++ || (ch >= 'a' && ch <= 'z') ++ || (ch == ' ' || ch == '_') ++ || (ch == '-' || ch == '/') ++ || (ch == '.' || ch == '+') ++ || (ch == '=' || ch == '#')) ++ { ++ continue; ++ } ++ else ++ { ++ MSG_WARN ("Unsafe command: %s", cmd.c_str ()); ++ MSG_ERROR ("The command can only contain the following characters " ++ "0-9, A-Z, a-z, '_', '-', '/', ' ', '.', '+', '=', '#' "); ++ } ++ } ++ MSG_INFO ("Execute command: %s", cmd.c_str ()); ++ FILE *fd = popen (cmd.c_str (), "r"); ++ if (fd == nullptr) ++ { ++ MSG_WARN ("Execute command faild!"); ++ } ++ else ++ { ++ char result_buf[1024]; ++ while (fgets (result_buf, sizeof (result_buf), fd) != NULL) ++ { ++ if (result_buf[strlen (result_buf) - 1] == '\n') ++ { ++ result_buf[strlen (result_buf) - 1] = '\0'; ++ } ++ MSG_INFO ("%s", result_buf); ++ } ++ pclose (fd); ++ } ++} ++ ++/* Generate bolt optimize command. */ ++ ++static string ++generate_bolt_cmd () ++{ ++ string new_binary = tmp_out_file_name + ".bolt"; ++ string cmd; ++ ++ /* bolt_optimize_options != "llvm-bolt " ++ means that the user uses custom input options. */ ++ if (bolt_optimize_options != "llvm-bolt ") ++ { ++ cmd = bolt_optimize_options + " " + tmp_out_file_name ++ + " -o " + new_binary ++ + " -data=" + bolt_profile_name; ++ } ++ else ++ { ++ if (fdo_type == feedback_type::AFDO_TYPE) ++ { ++ cmd = string ("llvm-bolt -reorder-functions=hfsort+ ") ++ + tmp_out_file_name + " -o " + new_binary ++ + " -data=" + bolt_profile_name; ++ } ++ else if (fdo_type == feedback_type::PGO_TYPE ++ || fdo_type == feedback_type::BOLT_TYPE) ++ { ++ cmd = string ("llvm-bolt -reorder-blocks=cache+ ") ++ + string (" -reorder-functions=hfsort+ ") ++ + string (" -split-functions=3 -split-all-cold ") ++ + string (" -dyno-stats -icf=1 -use-gnu-stack ") ++ + tmp_out_file_name + " -o " + new_binary ++ + " -data=" + bolt_profile_name; ++ } ++ else ++ { ++ MSG_ERROR ("Invalid profile type!"); ++ return string (); ++ } ++ MSG_INFO ("Using the default llvm-bolt optimization option," ++ " manually specify this option by -fbolt-option. "); ++ } ++ return cmd; ++} ++ ++/* Execute BOLT optimization, backup original binary with .orig . */ ++ ++static void ++do_bolt_opt () ++{ ++ string cmd = generate_bolt_cmd (); ++ if (cmd.empty ()) ++ { ++ return; ++ } ++ popen_run (cmd); ++ string new_binary = tmp_out_file_name + ".bolt"; ++ if (file_exist (new_binary.c_str ())) ++ { ++ cmd = "mv -f " + tmp_out_file_name + " " + tmp_out_file_name + ".orig"; ++ popen_run (cmd); ++ ++ cmd = "cp -f " + new_binary + " " + tmp_out_file_name; ++ popen_run (cmd); ++ } ++ else ++ { ++ MSG_ERROR ("BOLT optimization fail!" ++ " Try installing llvm-bolt or" ++ " enabling relocation info with flag -Wl,-q"); ++ } ++} ++ ++/* If -fbolt-target is set and this binary is the target, return true. */ ++ ++inline static bool ++is_bolt_opt_target () ++{ ++ if (!bolt_opt_target.empty () ++ && strcmp (lbasename (tmp_out_file_name.c_str ()), ++ lbasename (bolt_opt_target.c_str ())) != 0) ++ { ++ MSG_INFO ("BOLT optmization target is %s, processing %s, skip.", ++ bolt_opt_target.c_str (), tmp_out_file_name.c_str ()); ++ return false; ++ } ++ return true; ++} ++ ++/* Remove temporary files after linkage, and do BOLT optimization. */ ++ ++static enum ld_plugin_status ++cleanup_handler () ++{ ++ if (bolt_file_fd) ++ { ++ fclose (bolt_file_fd); ++ } ++ ++ if (file_exist (tmp_out_file_name.c_str ()) ++ && file_exist (bolt_profile_name.c_str ()) ++ && is_bolt_opt_target ()) ++ { ++ do_bolt_opt (); ++ } ++ ++ return LDPS_OK; ++} ++ ++/* Open BOLT profile file generated by -fauto-bolt. */ ++ ++static void ++open_bolt_profile_file (const char *file_name) ++{ ++ if (file_name == NULL) ++ { ++ MSG_ERROR ("Empty BOLT profile name, exit!"); ++ } ++ ++ if (bolt_file_fd == NULL) ++ { ++ MSG_INFO ("Generate profile file for BOLT: %s", file_name); ++ bolt_file_fd = fopen (file_name, "wt"); ++ if (!bolt_file_fd) ++ { ++ MSG_ERROR ("Failed to open the file: %s." ++ " Please check whether the target path exists.", ++ file_name); ++ } ++ return; ++ } ++ else ++ { ++ MSG_WARN ("BOLT profile file: %s is open, skip.", file_name); ++ } ++} ++ ++/* In BOLT profile, function with same name represent as func_name/file_name/1, ++ also, `/` has been added in gcc/final.c, so add /1 if this function is same ++ name function. */ ++ ++static string ++add_suffix (string str) ++{ ++ if (str.empty () || (strstr (str.c_str (), "/") == NULL)) ++ { ++ return str; ++ } ++ ++ return str + "/1"; ++} ++ ++/* Dump function info to BOLT profile, bolt_file_fd does not need ++ to be closed here. */ ++ ++static void ++dump_func_to_bolt_profile_file (const struct func_info &func) ++{ ++ if (func.edges.empty ()) ++ { ++ return; ++ } ++ ++ if (!bolt_file_fd) ++ { ++ open_bolt_profile_file (bolt_profile_name.c_str ()); ++ ++ /* Check whether the feedback data is from AutoFDO. */ ++ if (fdo_type == feedback_type::AFDO_TYPE) ++ { ++ fprintf (bolt_file_fd, "no_lbr cycles:u:\n"); ++ } ++ } ++ ++ for (const auto &edge: func.edges) ++ { ++ if (fdo_type == feedback_type::PGO_TYPE) ++ { ++ fprintf (bolt_file_fd, "1 %s %s 1 %s %s 0 %s\n", ++ add_suffix (func.function_name).c_str (), ++ edge.src_addr_offset.c_str (), ++ add_suffix (edge.des_func_name).c_str (), ++ edge.dst_addr_offset.c_str (), edge.count.c_str ()); ++ } ++ else if (fdo_type == feedback_type::AFDO_TYPE) ++ { ++ fprintf (bolt_file_fd, "1 %s %s %s\n", ++ add_suffix (func.function_name).c_str (), ++ edge.src_addr_offset.c_str (), ++ edge.count.c_str ()); ++ } ++ } ++ ++ fflush (bolt_file_fd); ++} ++ ++/* Called by the linker when all symbols have been read. */ ++ ++static enum ld_plugin_status ++all_symbols_read_handler () ++{ ++ for (const auto &functions: weak_functions) ++ { ++ /* More than one weak function. */ ++ if (functions.second.size () > 1) ++ { ++ MSG_WARN ("The weak function: %s is confusing, take the first one.", ++ functions.first.c_str ()); ++ } ++ ++ dump_func_to_bolt_profile_file (functions.second[0]); ++ } ++ return LDPS_OK; ++} ++ ++/* Move pointer p to end and return end. */ ++ ++static char * ++get_next_content (char *p, char *end) ++{ ++ while (*p && p < end) ++ { ++ p++; ++ } ++ p++; ++ ++ return p; ++} ++ ++/* Process function head info. */ ++ ++static char * ++process_function_head (char *data , char *end, struct func_info *func) ++{ ++ CHECK (is_prefix_of (ASM_FDO_CALLER_FLAG, data), LDPL_FATAL, ++ "The function name is missing."); ++ func->function_name = xstrdup (data + strlen (ASM_FDO_CALLER_FLAG)); ++ data = get_next_content (data, end); ++ ++ CHECK (is_prefix_of (ASM_FDO_CALLER_SIZE_FLAG, data), LDPL_FATAL, ++ "The function size is missing."); ++ func->size = xstrdup (data + strlen (ASM_FDO_CALLER_SIZE_FLAG)); ++ data = get_next_content (data, end); ++ ++ CHECK (is_prefix_of (ASM_FDO_CALLER_BIND_FLAG, data), LDPL_FATAL, ++ "The function bind type is missing."); ++ func->bind_type = xstrdup (data + strlen (ASM_FDO_CALLER_BIND_FLAG)); ++ data = get_next_content (data, end); ++ return data; ++} ++ ++/* Read profile info from the symbol table located between data and end. */ ++ ++static void ++process_section (char *data, char *end) ++{ ++ struct func_info func; ++ ++ data = process_function_head (data, end, &func); ++ ++ while (*data && data < end) ++ { ++ struct jump_info jump; ++ ++ CHECK (data, LDPL_FATAL, "data is NULL"); ++ jump.src_addr_offset = xstrdup (data); ++ ++ data = get_next_content (data, end); ++ CHECK (data, LDPL_FATAL, "data is NULL"); ++ if (is_prefix_of (ASM_FDO_CALLEE_FLAG, data)) ++ { ++ jump.des_func_name = xstrdup (data + strlen (ASM_FDO_CALLEE_FLAG)); ++ jump.dst_addr_offset = "0"; ++ data = get_next_content (data, end); ++ CHECK (data, LDPL_FATAL, "data is NULL"); ++ } ++ else if (fdo_type == feedback_type::PGO_TYPE) ++ { ++ jump.des_func_name = func.function_name; ++ jump.dst_addr_offset = xstrdup (data); ++ data = get_next_content (data, end); ++ CHECK (data, LDPL_FATAL, "data is NULL"); ++ } ++ else ++ { ++ jump.des_func_name = func.function_name; ++ } ++ ++ jump.count = xstrdup (data); ++ data = get_next_content (data, end); ++ ++ func.edges.push_back (jump); ++ } ++ ++ if (is_prefix_of ("WEAK", func.bind_type.c_str ())) ++ { ++ weak_functions[func.function_name].push_back (func); ++ } ++ else ++ { ++ dump_func_to_bolt_profile_file (func); ++ } ++} ++ ++/* Process error when calling function process_symtab. */ ++ ++static int ++process_symtab_error (struct plugin_objfile *obj, char *secdatastart) ++{ ++ MSG_ERROR ("%s: corrupt object file.", obj->file->name); ++ ++ /* Force claim_file_handler to abandon this file. */ ++ if (secdatastart != NULL) ++ { ++ free (secdatastart); ++ } ++ return 0; ++} ++ ++/* Process one section of an object file. Return to 1 to continue processing ++ other sections which define in simple_object_find_sections. */ ++ ++static int ++process_symtab (void *data, const char *name, off_t offset, off_t length) ++{ ++ if (data == NULL) ++ { ++ MSG_WARN ("Empty symtab! skip it."); ++ return 0; ++ } ++ if (name == NULL) ++ { ++ MSG_WARN ("Empty symtab name! skip it."); ++ return 0; ++ } ++ struct plugin_objfile *obj = (struct plugin_objfile *)data; ++ char *secdatastart; ++ char *secdata; ++ ++ if (!is_prefix_of (ASM_FDO_SECTION_PREFIX, name)) ++ { ++ return 1; ++ } ++ ++ secdata = secdatastart = (char *)xmalloc (length * sizeof (char)); ++ offset += obj->file->offset; ++ if (offset != lseek (obj->file->fd, offset, SEEK_SET)) ++ { ++ return process_symtab_error (obj, secdatastart); ++ } ++ ++ do ++ { ++ ssize_t got = read (obj->file->fd, secdata, length); ++ ++ if (got == 0) ++ { ++ break; ++ } ++ else if (got > 0) ++ { ++ secdata += got; ++ length -= got; ++ } ++ else if (errno != EINTR) ++ { ++ return process_symtab_error (obj, secdatastart); ++ } ++ } ++ while (length > 0); ++ ++ if (length > 0) ++ { ++ return process_symtab_error (obj, secdatastart); ++ } ++ ++ process_section (secdatastart, secdata); ++ free (secdatastart); ++ return 1; ++} ++ ++/* Callback used by gold to check if the plugin will claim FILE. Writes ++ the result in CLAIMED. */ ++ ++static enum ld_plugin_status ++claim_file_handler (const struct ld_plugin_input_file *file, int *claimed) ++{ ++ struct plugin_objfile obj; ++ int err; ++ const char *errmsg = NULL; ++ /* If file is empty, bolt plugin do nothing and return ok. */ ++ if (file == NULL) ++ { ++ return LDPS_OK; ++ } ++ /* BOLT plugin does not need claimd number, so set *claimed to 0. */ ++ *claimed = 0; ++ ++ obj.file = file; ++ obj.objfile = simple_object_start_read (file->fd, file->offset, NULL, ++ &errmsg, &err); ++ ++ /* No file, but also no error code means unrecognized format, ++ skip it. */ ++ if (!obj.objfile && !err) ++ { ++ return LDPS_OK; ++ } ++ ++ if (obj.objfile) ++ { ++ simple_object_find_sections (obj.objfile, process_symtab, &obj, &err); ++ simple_object_release_read (obj.objfile); ++ } ++ ++ return LDPS_OK; ++} ++ ++/* Mangle filename path of BASE and output new allocated pointer with ++ mangled path. */ ++ ++static string ++mangle_path (const string &base) ++{ ++ if (base.empty ()) ++ { ++ return base; ++ } ++ ++ /* Convert '/' to '#', convert '..' to '^', ++ convert ':' to '~' on DOS based file system. */ ++ ++ string new_path; ++ int base_len = base.size (); ++ int l = 0; ++ int r = 0; ++ while (l < base_len) ++ { ++ while (r < base_len && base[r] != '/') ++ { ++ r++; ++ } ++ ++ int len = r - l; ++ if (len == 2 && base[r - 2] == '.' && base[r - 1] == '.') ++ { ++ new_path += '^'; ++ } ++ else ++ { ++ new_path += base.substr (l, r - l); ++ } ++ if (r < base_len) ++ { ++ new_path += '#'; ++ } ++ ++ r++; ++ l = r; ++ } ++ return new_path; ++} ++ ++/* Generate BOLT profile name from file_name. */ ++ ++static string ++generate_bolt_profile_name (string file_name) ++{ ++ if (!IS_ABSOLUTE_PATH (file_name.c_str ())) ++ { ++ if (!bolt_dir_path.empty ()) ++ { ++ file_name = concat (get_current_dir_name (), ++ separator, file_name.c_str (), NULL); ++ file_name = mangle_path (file_name); ++ } ++ else ++ { ++ bolt_dir_path = DEFAULT_BOLT_OUT_DIR; ++ } ++ } ++ file_name = concat (bolt_dir_path.c_str (), separator, file_name.c_str (), ++ NULL); ++ return file_name; ++} ++ ++/* Match option_prefix from gcc_options, return the index of gcc_options. */ ++ ++static int ++match_gcc_option (const char *option_prefix) ++{ ++ if (option_prefix == NULL) ++ { ++ return -1; ++ } ++ ++ for (size_t i = 0; i < gcc_options.size (); i++) ++ { ++ if (is_prefix_of (option_prefix, gcc_options[i].c_str ())) ++ { ++ return i; ++ } ++ } ++ ++ return -1; ++} ++ ++/* Get options form environment COLLECT_GCC_OPTIONS. */ ++ ++static void ++get_options_from_collect_gcc_options (const char *collect_gcc, ++ const char *collect_gcc_options) ++{ ++ /* When using GCC, collect_gcc will not be empty. */ ++ if (collect_gcc == NULL || collect_gcc_options == NULL) ++ { ++ return; ++ } ++ ++ size_t len = strlen (collect_gcc_options); ++ size_t r = 0; ++ while (r < len && collect_gcc_options[r] != '\0') ++ { ++ if (collect_gcc_options[r] == '\'') ++ { ++ string option; ++ ++r; ++ do ++ { ++ if (collect_gcc_options[r] == '\0') ++ { ++ MSG_ERROR ("Malformed COLLECT_GCC_OPTIONS"); ++ } ++ else if (is_prefix_of ("'\\''", &collect_gcc_options[r])) ++ { ++ option.push_back ('\''); ++ r += 4; ++ } ++ else if (collect_gcc_options[r] == '\'') ++ { ++ break; ++ } ++ else ++ { ++ option.push_back (collect_gcc_options[r]); ++ ++r; ++ } ++ } ++ while (1); ++ ++ if (!option.empty ()) ++ { ++ gcc_options.push_back (option); ++ } ++ } ++ ++r; ++ } ++} ++ ++/* Substitute comma with space in RAW_STRING, used for parser ++ -fbolt-option. */ ++ ++static string ++parser_bolt_optimize_option (string raw_string) ++{ ++ for (auto &ch : raw_string) ++ { ++ if (ch == ',') ++ { ++ ch = ' '; ++ } ++ } ++ ++ return raw_string; ++} ++ ++/* Process option -fauto-bolt. */ ++ ++static void ++process_auto_bolt_option (const string &flag_auto_bolt) ++{ ++ const int auto_bolt_index = match_gcc_option (flag_auto_bolt.c_str ()); ++ ++ if (auto_bolt_index != -1) ++ { ++ if (gcc_options[auto_bolt_index] == "-fauto-bolt") ++ { ++ MSG_INFO ("Use default output directory %s, ", DEFAULT_BOLT_OUT_DIR); ++ MSG_INFO ("Specify it using -fauto-bolt= if needed."); ++ } ++ else ++ { ++ string flag_auto_bolt_equal = "-fauto-bolt="; ++ bolt_dir_path = lrealpath (gcc_options[auto_bolt_index].substr ( ++ flag_auto_bolt_equal.size ()).c_str ()); ++ MSG_INFO ("Get bolt profile path: %s", bolt_dir_path.c_str ()); ++ } ++ bolt_profile_name = generate_bolt_profile_name(bolt_profile_name); ++ } ++} ++ ++/* Process option -fbolt-use=. */ ++ ++static void ++process_bolt_use_option (const string &flag_bolt_use) ++{ ++ const int bolt_use_index = match_gcc_option (flag_bolt_use.c_str ()); ++ ++ if (bolt_use_index != -1) ++ { ++ /* bolt_profile_name may be initialized in ++ function process_output_option. */ ++ bolt_profile_name = gcc_options[bolt_use_index].substr ( ++ flag_bolt_use.size ()).c_str (); ++ if (bolt_profile_name.empty ()) ++ { ++ bolt_profile_name = DEFAULT_BOLT_OUT_NAME; ++ } ++ MSG_INFO ("Get bolt profile: %s", bolt_profile_name.c_str ()); ++ } ++} ++ ++/* Process option -fbolt-target=. */ ++ ++static void ++process_bolt_target_option (const string &flag_bolt_target) ++{ ++ const int bolt_target_index = match_gcc_option (flag_bolt_target.c_str ()); ++ if (bolt_target_index != -1) ++ { ++ bolt_opt_target = gcc_options[bolt_target_index].substr ( ++ flag_bolt_target.size ()).c_str (); ++ MSG_INFO ("Get bolt target: %s", bolt_opt_target.c_str ()); ++ } ++} ++ ++/* Process option -fbolt-option=. */ ++ ++static void ++process_bolt_option (const string &flag_bolt_optimize_options) ++{ ++ const int bolt_optimize_options_index ++ = match_gcc_option (flag_bolt_optimize_options.c_str ()); ++ ++ if (bolt_optimize_options_index != -1) ++ { ++ bolt_optimize_options.append (parser_bolt_optimize_option ( ++ gcc_options[bolt_optimize_options_index].substr ( ++ flag_bolt_optimize_options.size ()).c_str ())); ++ ++ MSG_INFO ("Get bolt optimize options is %s", ++ bolt_optimize_options.c_str ()); ++ } ++} ++ ++/* If -o is specified, set binary name and bolt profile name. This ++ function must be called before the process_bolt_use_option function. */ ++ ++static void ++process_output_option (const string &flag_o) ++{ ++ const int o_index = match_gcc_option (flag_o.c_str ()); ++ if (o_index != -1) ++ { ++ tmp_out_file_name = gcc_options[o_index + 1]; ++ /* bolt_profile_name may be overridden in ++ function process_auto_bolt_option and ++ process_bolt_use_option. */ ++ bolt_profile_name = gcc_options[o_index + 1]; ++ bolt_profile_name.append (DEFAULT_BOLT_OUT_NAME_SUFFIX); ++ } ++ else ++ { ++ bolt_profile_name = DEFAULT_BOLT_OUT_NAME; ++ MSG_INFO ("Use default file name %s, specify it using -o if needed.", ++ DEFAULT_BOLT_OUT_NAME); ++ } ++} ++ ++/* Parse the plugin options. */ ++ ++static void ++process_gcc_option () ++{ ++ string flag_profile_use = "-fprofile-use"; ++ string flag_auto_profile = "-fauto-profile"; ++ string flag_auto_bolt = "-fauto-bolt"; ++ string flag_bolt_use = "-fbolt-use="; ++ string flag_bolt_target = "-fbolt-target="; ++ string flag_bolt_optimize_options = "-fbolt-option="; ++ string flag_o = "-o"; ++ ++ char *collect_gcc = getenv ("COLLECT_GCC"); ++ char *collect_gcc_option = getenv ("COLLECT_GCC_OPTIONS"); ++ ++ get_options_from_collect_gcc_options (collect_gcc, collect_gcc_option); ++ ++ /* Function process_output_option should be processed before ++ process_auto_bolt_option to obtain correct bolt_profile_name. */ ++ process_output_option (flag_o); ++ process_auto_bolt_option (flag_auto_bolt); ++ process_bolt_use_option (flag_bolt_use); ++ process_bolt_target_option (flag_bolt_target); ++ process_bolt_option (flag_bolt_optimize_options); ++ ++ if (match_gcc_option (flag_profile_use.c_str ()) != -1) ++ { ++ fdo_type = feedback_type::PGO_TYPE; ++ } ++ else if (match_gcc_option (flag_auto_profile.c_str ()) != -1) ++ { ++ fdo_type = feedback_type::AFDO_TYPE; ++ } ++ ++ if (match_gcc_option (flag_bolt_use.c_str ()) != -1) ++ { ++ fdo_type = feedback_type::BOLT_TYPE; ++ } ++ ++ if (fdo_type == feedback_type::NULL_TYPE) ++ { ++ MSG_ERROR ("No feedback data, maybe use -fprofile-use " ++ "-fbolt-use or -fauto-profile."); ++ } ++} ++ ++/* Register callback function including all_symbols_read_handler, ++ cleanup_handler and claim_file_handler. */ ++ ++static void ++register_callback_function () ++{ ++ enum ld_plugin_status status; ++ ++ if (linker_output_set && linker_output != LDPO_EXEC) ++ { ++ MSG_INFO ("This linker[%d] is not for exec, just skip.", linker_output); ++ return; ++ } ++ ++ CHECK (register_claim_file, LDPL_FATAL, "register_claim_file not found"); ++ status = register_claim_file (claim_file_handler); ++ CHECK (status == LDPS_OK, LDPL_FATAL, ++ "could not register the claim_file callback"); ++ ++ if (register_cleanup) ++ { ++ status = register_cleanup (cleanup_handler); ++ CHECK (status == LDPS_OK, LDPL_FATAL, ++ "could not register the cleanup callback"); ++ } ++ ++ if (register_all_symbols_read) ++ { ++ status = register_all_symbols_read (all_symbols_read_handler); ++ CHECK (status == LDPS_OK, LDPL_FATAL, ++ "could not register the all_symbols_read callback"); ++ } ++} ++ ++/* Called by gold after loading the plugin. TV is the transfer vector. */ ++ ++enum ld_plugin_status ++onload (struct ld_plugin_tv *tv) ++{ ++ struct ld_plugin_tv *p; ++ ++ p = tv; ++ while (p->tv_tag) ++ { ++ switch (p->tv_tag) ++ { ++ case LDPT_MESSAGE: ++ message = p->tv_u.tv_message; ++ break; ++ case LDPT_REGISTER_CLAIM_FILE_HOOK: ++ register_claim_file = p->tv_u.tv_register_claim_file; ++ break; ++ case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK: ++ register_all_symbols_read = p->tv_u.tv_register_all_symbols_read; ++ break; ++ case LDPT_REGISTER_CLEANUP_HOOK: ++ register_cleanup = p->tv_u.tv_register_cleanup; ++ break; ++ case LDPT_LINKER_OUTPUT: ++ linker_output = (enum ld_plugin_output_file_type)p->tv_u.tv_val; ++ linker_output_set = 1; ++ break; ++ default: ++ break; ++ } ++ p++; ++ } ++ ++ register_callback_function (); ++ process_gcc_option (); ++ ++ return LDPS_OK; ++} +diff --git a/bolt-plugin/config.h.in b/bolt-plugin/config.h.in +new file mode 100644 +index 000000000..ddbde7619 +--- /dev/null ++++ b/bolt-plugin/config.h.in +@@ -0,0 +1,121 @@ ++/* config.h.in. Generated from configure.ac by autoheader. */ ++ ++/* Define to 1 if you have the <dlfcn.h> header file. */ ++#undef HAVE_DLFCN_H ++ ++/* Define to 1 if you have the <inttypes.h> header file. */ ++#undef HAVE_INTTYPES_H ++ ++/* Define to 1 if you have the <memory.h> header file. */ ++#undef HAVE_MEMORY_H ++ ++/* Define to 1 if you have the <stdint.h> header file. */ ++#undef HAVE_STDINT_H ++ ++/* Define to 1 if you have the <stdlib.h> header file. */ ++#undef HAVE_STDLIB_H ++ ++/* Define to 1 if you have the <strings.h> header file. */ ++#undef HAVE_STRINGS_H ++ ++/* Define to 1 if you have the <string.h> header file. */ ++#undef HAVE_STRING_H ++ ++/* Define to 1 if you have the <sys/stat.h> header file. */ ++#undef HAVE_SYS_STAT_H ++ ++/* Define to 1 if you have the <sys/types.h> header file. */ ++#undef HAVE_SYS_TYPES_H ++ ++/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */ ++#undef HAVE_SYS_WAIT_H ++ ++/* Define to 1 if you have the <unistd.h> header file. */ ++#undef HAVE_UNISTD_H ++ ++/* Define to the sub-directory in which libtool stores uninstalled libraries. ++ */ ++#undef LT_OBJDIR ++ ++/* Name of package */ ++#undef PACKAGE ++ ++/* Define to the address where bug reports for this package should be sent. */ ++#undef PACKAGE_BUGREPORT ++ ++/* Define to the full name of this package. */ ++#undef PACKAGE_NAME ++ ++/* Define to the full name and version of this package. */ ++#undef PACKAGE_STRING ++ ++/* Define to the one symbol short name of this package. */ ++#undef PACKAGE_TARNAME ++ ++/* Define to the home page for this package. */ ++#undef PACKAGE_URL ++ ++/* Define to the version of this package. */ ++#undef PACKAGE_VERSION ++ ++/* Define to 1 if you have the ANSI C header files. */ ++#undef STDC_HEADERS ++ ++/* Enable extensions on AIX 3, Interix. */ ++#ifndef _ALL_SOURCE ++# undef _ALL_SOURCE ++#endif ++/* Enable GNU extensions on systems that have them. */ ++#ifndef _GNU_SOURCE ++# undef _GNU_SOURCE ++#endif ++/* Enable threading extensions on Solaris. */ ++#ifndef _POSIX_PTHREAD_SEMANTICS ++# undef _POSIX_PTHREAD_SEMANTICS ++#endif ++/* Enable extensions on HP NonStop. */ ++#ifndef _TANDEM_SOURCE ++# undef _TANDEM_SOURCE ++#endif ++/* Enable general extensions on Solaris. */ ++#ifndef __EXTENSIONS__ ++# undef __EXTENSIONS__ ++#endif ++ ++ ++/* Version number of package */ ++#undef VERSION ++ ++/* Enable large inode numbers on Mac OS X 10.5. */ ++#ifndef _DARWIN_USE_64_BIT_INODE ++# define _DARWIN_USE_64_BIT_INODE 1 ++#endif ++ ++/* Number of bits in a file offset, on hosts where this is settable. */ ++#undef _FILE_OFFSET_BITS ++ ++/* Define for large files, on AIX-style hosts. */ ++#undef _LARGE_FILES ++ ++/* Define to 1 if on MINIX. */ ++#undef _MINIX ++ ++/* Define to 2 if the system does not provide POSIX.1 features except with ++ this defined. */ ++#undef _POSIX_1_SOURCE ++ ++/* Define to 1 if you need to in order for `stat' and other things to work. */ ++#undef _POSIX_SOURCE ++ ++/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>, ++ <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the ++ #define below would cause a syntax error. */ ++#undef _UINT64_T ++ ++/* Define to the type of a signed integer type of width exactly 64 bits if ++ such a type exists and the standard includes do not define it. */ ++#undef int64_t ++ ++/* Define to the type of an unsigned integer type of width exactly 64 bits if ++ such a type exists and the standard includes do not define it. */ ++#undef uint64_t +diff --git a/bolt-plugin/configure b/bolt-plugin/configure +new file mode 100755 +index 000000000..62cf7c714 +--- /dev/null ++++ b/bolt-plugin/configure +@@ -0,0 +1,18379 @@ ++#! /bin/sh ++# Guess values for system-dependent variables and create Makefiles. ++# Generated by GNU Autoconf 2.69 for bolt plugin for ld 0.1. ++# ++# ++# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. ++# ++# ++# This configure script is free software; the Free Software Foundation ++# gives unlimited permission to copy, distribute and modify it. ++## -------------------- ## ++## M4sh Initialization. ## ++## -------------------- ## ++ ++# Be more Bourne compatible ++DUALCASE=1; export DUALCASE # for MKS sh ++if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : ++ emulate sh ++ NULLCMD=: ++ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which ++ # is contrary to our usage. Disable this feature. ++ alias -g '${1+"$@"}'='"$@"' ++ setopt NO_GLOB_SUBST ++else ++ case `(set -o) 2>/dev/null` in #( ++ *posix*) : ++ set -o posix ;; #( ++ *) : ++ ;; ++esac ++fi ++ ++ ++as_nl=' ++' ++export as_nl ++# Printing a long string crashes Solaris 7 /usr/bin/printf. ++as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ++as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo ++as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo ++# Prefer a ksh shell builtin over an external printf program on Solaris, ++# but without wasting forks for bash or zsh. ++if test -z "$BASH_VERSION$ZSH_VERSION" \ ++ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then ++ as_echo='print -r --' ++ as_echo_n='print -rn --' ++elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then ++ as_echo='printf %s\n' ++ as_echo_n='printf %s' ++else ++ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then ++ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' ++ as_echo_n='/usr/ucb/echo -n' ++ else ++ as_echo_body='eval expr "X$1" : "X\\(.*\\)"' ++ as_echo_n_body='eval ++ arg=$1; ++ case $arg in #( ++ *"$as_nl"*) ++ expr "X$arg" : "X\\(.*\\)$as_nl"; ++ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; ++ esac; ++ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ++ ' ++ export as_echo_n_body ++ as_echo_n='sh -c $as_echo_n_body as_echo' ++ fi ++ export as_echo_body ++ as_echo='sh -c $as_echo_body as_echo' ++fi ++ ++# The user is always right. ++if test "${PATH_SEPARATOR+set}" != set; then ++ PATH_SEPARATOR=: ++ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { ++ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || ++ PATH_SEPARATOR=';' ++ } ++fi ++ ++ ++# IFS ++# We need space, tab and new line, in precisely that order. Quoting is ++# there to prevent editors from complaining about space-tab. ++# (If _AS_PATH_WALK were called with IFS unset, it would disable word ++# splitting by setting IFS to empty value.) ++IFS=" "" $as_nl" ++ ++# Find who we are. Look in the path if we contain no directory separator. ++as_myself= ++case $0 in #(( ++ *[\\/]* ) as_myself=$0 ;; ++ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break ++ done ++IFS=$as_save_IFS ++ ++ ;; ++esac ++# We did not find ourselves, most probably we were run as `sh COMMAND' ++# in which case we are not to be found in the path. ++if test "x$as_myself" = x; then ++ as_myself=$0 ++fi ++if test ! -f "$as_myself"; then ++ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 ++ exit 1 ++fi ++ ++# Unset variables that we do not need and which cause bugs (e.g. in ++# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" ++# suppresses any "Segmentation fault" message there. '((' could ++# trigger a bug in pdksh 5.2.14. ++for as_var in BASH_ENV ENV MAIL MAILPATH ++do eval test x\${$as_var+set} = xset \ ++ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : ++done ++PS1='$ ' ++PS2='> ' ++PS4='+ ' ++ ++# NLS nuisances. ++LC_ALL=C ++export LC_ALL ++LANGUAGE=C ++export LANGUAGE ++ ++# CDPATH. ++(unset CDPATH) >/dev/null 2>&1 && unset CDPATH ++ ++# Use a proper internal environment variable to ensure we don't fall ++ # into an infinite loop, continuously re-executing ourselves. ++ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then ++ _as_can_reexec=no; export _as_can_reexec; ++ # We cannot yet assume a decent shell, so we have to provide a ++# neutralization value for shells without unset; and this also ++# works around shells that cannot unset nonexistent variables. ++# Preserve -v and -x to the replacement shell. ++BASH_ENV=/dev/null ++ENV=/dev/null ++(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV ++case $- in # (((( ++ *v*x* | *x*v* ) as_opts=-vx ;; ++ *v* ) as_opts=-v ;; ++ *x* ) as_opts=-x ;; ++ * ) as_opts= ;; ++esac ++exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} ++# Admittedly, this is quite paranoid, since all the known shells bail ++# out after a failed `exec'. ++$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 ++as_fn_exit 255 ++ fi ++ # We don't want this to propagate to other subprocesses. ++ { _as_can_reexec=; unset _as_can_reexec;} ++if test "x$CONFIG_SHELL" = x; then ++ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : ++ emulate sh ++ NULLCMD=: ++ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which ++ # is contrary to our usage. Disable this feature. ++ alias -g '\${1+\"\$@\"}'='\"\$@\"' ++ setopt NO_GLOB_SUBST ++else ++ case \`(set -o) 2>/dev/null\` in #( ++ *posix*) : ++ set -o posix ;; #( ++ *) : ++ ;; ++esac ++fi ++" ++ as_required="as_fn_return () { (exit \$1); } ++as_fn_success () { as_fn_return 0; } ++as_fn_failure () { as_fn_return 1; } ++as_fn_ret_success () { return 0; } ++as_fn_ret_failure () { return 1; } ++ ++exitcode=0 ++as_fn_success || { exitcode=1; echo as_fn_success failed.; } ++as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } ++as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } ++as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } ++if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : ++ ++else ++ exitcode=1; echo positional parameters were not saved. ++fi ++test x\$exitcode = x0 || exit 1 ++test -x / || exit 1" ++ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO ++ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO ++ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && ++ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 ++test \$(( 1 + 1 )) = 2 || exit 1 ++ ++ test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( ++ ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ++ ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO ++ ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO ++ PATH=/empty FPATH=/empty; export PATH FPATH ++ test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ ++ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1" ++ if (eval "$as_required") 2>/dev/null; then : ++ as_have_required=yes ++else ++ as_have_required=no ++fi ++ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : ++ ++else ++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++as_found=false ++for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ as_found=: ++ case $as_dir in #( ++ /*) ++ for as_base in sh bash ksh sh5; do ++ # Try only shells that exist, to save several forks. ++ as_shell=$as_dir/$as_base ++ if { test -f "$as_shell" || test -f "$as_shell.exe"; } && ++ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : ++ CONFIG_SHELL=$as_shell as_have_required=yes ++ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : ++ break 2 ++fi ++fi ++ done;; ++ esac ++ as_found=false ++done ++$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && ++ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : ++ CONFIG_SHELL=$SHELL as_have_required=yes ++fi; } ++IFS=$as_save_IFS ++ ++ ++ if test "x$CONFIG_SHELL" != x; then : ++ export CONFIG_SHELL ++ # We cannot yet assume a decent shell, so we have to provide a ++# neutralization value for shells without unset; and this also ++# works around shells that cannot unset nonexistent variables. ++# Preserve -v and -x to the replacement shell. ++BASH_ENV=/dev/null ++ENV=/dev/null ++(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV ++case $- in # (((( ++ *v*x* | *x*v* ) as_opts=-vx ;; ++ *v* ) as_opts=-v ;; ++ *x* ) as_opts=-x ;; ++ * ) as_opts= ;; ++esac ++exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} ++# Admittedly, this is quite paranoid, since all the known shells bail ++# out after a failed `exec'. ++$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 ++exit 255 ++fi ++ ++ if test x$as_have_required = xno; then : ++ $as_echo "$0: This script requires a shell more modern than all" ++ $as_echo "$0: the shells that I found on your system." ++ if test x${ZSH_VERSION+set} = xset ; then ++ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" ++ $as_echo "$0: be upgraded to zsh 4.3.4 or later." ++ else ++ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, ++$0: including any error possibly output before this ++$0: message. Then install a modern shell, or manually run ++$0: the script under such a shell if you do have one." ++ fi ++ exit 1 ++fi ++fi ++fi ++SHELL=${CONFIG_SHELL-/bin/sh} ++export SHELL ++# Unset more variables known to interfere with behavior of common tools. ++CLICOLOR_FORCE= GREP_OPTIONS= ++unset CLICOLOR_FORCE GREP_OPTIONS ++ ++## --------------------- ## ++## M4sh Shell Functions. ## ++## --------------------- ## ++# as_fn_unset VAR ++# --------------- ++# Portably unset VAR. ++as_fn_unset () ++{ ++ { eval $1=; unset $1;} ++} ++as_unset=as_fn_unset ++ ++# as_fn_set_status STATUS ++# ----------------------- ++# Set $? to STATUS, without forking. ++as_fn_set_status () ++{ ++ return $1 ++} # as_fn_set_status ++ ++# as_fn_exit STATUS ++# ----------------- ++# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. ++as_fn_exit () ++{ ++ set +e ++ as_fn_set_status $1 ++ exit $1 ++} # as_fn_exit ++ ++# as_fn_mkdir_p ++# ------------- ++# Create "$as_dir" as a directory, including parents if necessary. ++as_fn_mkdir_p () ++{ ++ ++ case $as_dir in #( ++ -*) as_dir=./$as_dir;; ++ esac ++ test -d "$as_dir" || eval $as_mkdir_p || { ++ as_dirs= ++ while :; do ++ case $as_dir in #( ++ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( ++ *) as_qdir=$as_dir;; ++ esac ++ as_dirs="'$as_qdir' $as_dirs" ++ as_dir=`$as_dirname -- "$as_dir" || ++$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ ++ X"$as_dir" : 'X\(//\)[^/]' \| \ ++ X"$as_dir" : 'X\(//\)$' \| \ ++ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || ++$as_echo X"$as_dir" | ++ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\/\)[^/].*/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\/\)$/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\).*/{ ++ s//\1/ ++ q ++ } ++ s/.*/./; q'` ++ test -d "$as_dir" && break ++ done ++ test -z "$as_dirs" || eval "mkdir $as_dirs" ++ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" ++ ++ ++} # as_fn_mkdir_p ++ ++# as_fn_executable_p FILE ++# ----------------------- ++# Test if FILE is an executable regular file. ++as_fn_executable_p () ++{ ++ test -f "$1" && test -x "$1" ++} # as_fn_executable_p ++# as_fn_append VAR VALUE ++# ---------------------- ++# Append the text in VALUE to the end of the definition contained in VAR. Take ++# advantage of any shell optimizations that allow amortized linear growth over ++# repeated appends, instead of the typical quadratic growth present in naive ++# implementations. ++if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : ++ eval 'as_fn_append () ++ { ++ eval $1+=\$2 ++ }' ++else ++ as_fn_append () ++ { ++ eval $1=\$$1\$2 ++ } ++fi # as_fn_append ++ ++# as_fn_arith ARG... ++# ------------------ ++# Perform arithmetic evaluation on the ARGs, and store the result in the ++# global $as_val. Take advantage of shells that can avoid forks. The arguments ++# must be portable across $(()) and expr. ++if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : ++ eval 'as_fn_arith () ++ { ++ as_val=$(( $* )) ++ }' ++else ++ as_fn_arith () ++ { ++ as_val=`expr "$@" || test $? -eq 1` ++ } ++fi # as_fn_arith ++ ++ ++# as_fn_error STATUS ERROR [LINENO LOG_FD] ++# ---------------------------------------- ++# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are ++# provided, also output the error to LOG_FD, referencing LINENO. Then exit the ++# script with STATUS, using 1 if that was 0. ++as_fn_error () ++{ ++ as_status=$1; test $as_status -eq 0 && as_status=1 ++ if test "$4"; then ++ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack ++ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 ++ fi ++ $as_echo "$as_me: error: $2" >&2 ++ as_fn_exit $as_status ++} # as_fn_error ++ ++if expr a : '\(a\)' >/dev/null 2>&1 && ++ test "X`expr 00001 : '.*\(...\)'`" = X001; then ++ as_expr=expr ++else ++ as_expr=false ++fi ++ ++if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then ++ as_basename=basename ++else ++ as_basename=false ++fi ++ ++if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then ++ as_dirname=dirname ++else ++ as_dirname=false ++fi ++ ++as_me=`$as_basename -- "$0" || ++$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ ++ X"$0" : 'X\(//\)$' \| \ ++ X"$0" : 'X\(/\)' \| . 2>/dev/null || ++$as_echo X/"$0" | ++ sed '/^.*\/\([^/][^/]*\)\/*$/{ ++ s//\1/ ++ q ++ } ++ /^X\/\(\/\/\)$/{ ++ s//\1/ ++ q ++ } ++ /^X\/\(\/\).*/{ ++ s//\1/ ++ q ++ } ++ s/.*/./; q'` ++ ++# Avoid depending upon Character Ranges. ++as_cr_letters='abcdefghijklmnopqrstuvwxyz' ++as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' ++as_cr_Letters=$as_cr_letters$as_cr_LETTERS ++as_cr_digits='0123456789' ++as_cr_alnum=$as_cr_Letters$as_cr_digits ++ ++ ++ as_lineno_1=$LINENO as_lineno_1a=$LINENO ++ as_lineno_2=$LINENO as_lineno_2a=$LINENO ++ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && ++ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { ++ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) ++ sed -n ' ++ p ++ /[$]LINENO/= ++ ' <$as_myself | ++ sed ' ++ s/[$]LINENO.*/&-/ ++ t lineno ++ b ++ :lineno ++ N ++ :loop ++ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ ++ t loop ++ s/-\n.*// ++ ' >$as_me.lineno && ++ chmod +x "$as_me.lineno" || ++ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } ++ ++ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have ++ # already done that, so ensure we don't try to do so again and fall ++ # in an infinite loop. This has already happened in practice. ++ _as_can_reexec=no; export _as_can_reexec ++ # Don't try to exec as it changes $[0], causing all sort of problems ++ # (the dirname of $[0] is not the place where we might find the ++ # original and so on. Autoconf is especially sensitive to this). ++ . "./$as_me.lineno" ++ # Exit status is that of the last command. ++ exit ++} ++ ++ECHO_C= ECHO_N= ECHO_T= ++case `echo -n x` in #((((( ++-n*) ++ case `echo 'xy\c'` in ++ *c*) ECHO_T=' ';; # ECHO_T is single tab character. ++ xy) ECHO_C='\c';; ++ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ++ ECHO_T=' ';; ++ esac;; ++*) ++ ECHO_N='-n';; ++esac ++ ++rm -f conf$$ conf$$.exe conf$$.file ++if test -d conf$$.dir; then ++ rm -f conf$$.dir/conf$$.file ++else ++ rm -f conf$$.dir ++ mkdir conf$$.dir 2>/dev/null ++fi ++if (echo >conf$$.file) 2>/dev/null; then ++ if ln -s conf$$.file conf$$ 2>/dev/null; then ++ as_ln_s='ln -s' ++ # ... but there are two gotchas: ++ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. ++ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. ++ # In both cases, we have to default to `cp -pR'. ++ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || ++ as_ln_s='cp -pR' ++ elif ln conf$$.file conf$$ 2>/dev/null; then ++ as_ln_s=ln ++ else ++ as_ln_s='cp -pR' ++ fi ++else ++ as_ln_s='cp -pR' ++fi ++rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file ++rmdir conf$$.dir 2>/dev/null ++ ++if mkdir -p . 2>/dev/null; then ++ as_mkdir_p='mkdir -p "$as_dir"' ++else ++ test -d ./-p && rmdir ./-p ++ as_mkdir_p=false ++fi ++ ++as_test_x='test -x' ++as_executable_p=as_fn_executable_p ++ ++# Sed expression to map a string onto a valid CPP name. ++as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" ++ ++# Sed expression to map a string onto a valid variable name. ++as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" ++ ++SHELL=${CONFIG_SHELL-/bin/sh} ++ ++ ++test -n "$DJDIR" || exec 7<&0 </dev/null ++exec 6>&1 ++ ++# Name of the host. ++# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, ++# so uname gets run too. ++ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` ++ ++# ++# Initializations. ++# ++ac_default_prefix=/usr/local ++ac_clean_files= ++ac_config_libobj_dir=. ++LIBOBJS= ++cross_compiling=no ++subdirs= ++MFLAGS= ++MAKEFLAGS= ++ ++# Identity of this package. ++PACKAGE_NAME='bolt plugin for ld' ++PACKAGE_TARNAME='bolt-plugin' ++PACKAGE_VERSION='0.1' ++PACKAGE_STRING='bolt plugin for ld 0.1' ++PACKAGE_BUGREPORT='' ++PACKAGE_URL='' ++ ++# Factoring default headers for most tests. ++ac_includes_default="\ ++#include <stdio.h> ++#ifdef HAVE_SYS_TYPES_H ++# include <sys/types.h> ++#endif ++#ifdef HAVE_SYS_STAT_H ++# include <sys/stat.h> ++#endif ++#ifdef STDC_HEADERS ++# include <stdlib.h> ++# include <stddef.h> ++#else ++# ifdef HAVE_STDLIB_H ++# include <stdlib.h> ++# endif ++#endif ++#ifdef HAVE_STRING_H ++# if !defined STDC_HEADERS && defined HAVE_MEMORY_H ++# include <memory.h> ++# endif ++# include <string.h> ++#endif ++#ifdef HAVE_STRINGS_H ++# include <strings.h> ++#endif ++#ifdef HAVE_INTTYPES_H ++# include <inttypes.h> ++#endif ++#ifdef HAVE_STDINT_H ++# include <stdint.h> ++#endif ++#ifdef HAVE_UNISTD_H ++# include <unistd.h> ++#endif" ++ ++ac_subst_vars='am__EXEEXT_FALSE ++am__EXEEXT_TRUE ++LTLIBOBJS ++LIBOBJS ++target_noncanonical ++lt_host_flags ++CXXCPP ++OTOOL64 ++OTOOL ++LIPO ++NMEDIT ++DSYMUTIL ++RANLIB ++AR ++OBJDUMP ++LN_S ++NM ++ac_ct_DUMPBIN ++DUMPBIN ++LD ++FGREP ++SED ++LIBTOOL ++get_gcc_base_ver ++real_target_noncanonical ++accel_dir_suffix ++gcc_build_dir ++ac_bolt_plugin_ldflags ++ac_bolt_plugin_warn_cflags ++am__fastdepCXX_FALSE ++am__fastdepCXX_TRUE ++CXXDEPMODE ++ac_ct_CXX ++CXXFLAGS ++CXX ++EGREP ++GREP ++CPP ++am__fastdepCC_FALSE ++am__fastdepCC_TRUE ++CCDEPMODE ++am__nodep ++AMDEPBACKSLASH ++AMDEP_FALSE ++AMDEP_TRUE ++am__include ++DEPDIR ++OBJEXT ++EXEEXT ++ac_ct_CC ++CPPFLAGS ++LDFLAGS ++CFLAGS ++CC ++with_libiberty ++MAINT ++MAINTAINER_MODE_FALSE ++MAINTAINER_MODE_TRUE ++AM_BACKSLASH ++AM_DEFAULT_VERBOSITY ++AM_DEFAULT_V ++AM_V ++am__untar ++am__tar ++AMTAR ++am__leading_dot ++SET_MAKE ++AWK ++mkdir_p ++MKDIR_P ++INSTALL_STRIP_PROGRAM ++STRIP ++install_sh ++MAKEINFO ++AUTOHEADER ++AUTOMAKE ++AUTOCONF ++ACLOCAL ++VERSION ++PACKAGE ++CYGPATH_W ++am__isrc ++INSTALL_DATA ++INSTALL_SCRIPT ++INSTALL_PROGRAM ++target_subdir ++host_subdir ++build_subdir ++build_libsubdir ++target_os ++target_vendor ++target_cpu ++target ++host_os ++host_vendor ++host_cpu ++host ++build_os ++build_vendor ++build_cpu ++build ++target_alias ++host_alias ++build_alias ++LIBS ++ECHO_T ++ECHO_N ++ECHO_C ++DEFS ++mandir ++localedir ++libdir ++psdir ++pdfdir ++dvidir ++htmldir ++infodir ++docdir ++oldincludedir ++includedir ++localstatedir ++sharedstatedir ++sysconfdir ++datadir ++datarootdir ++libexecdir ++sbindir ++bindir ++program_transform_name ++prefix ++exec_prefix ++PACKAGE_URL ++PACKAGE_BUGREPORT ++PACKAGE_STRING ++PACKAGE_VERSION ++PACKAGE_TARNAME ++PACKAGE_NAME ++PATH_SEPARATOR ++SHELL ++am__quote' ++ac_subst_files='' ++ac_user_opts=' ++enable_option_checking ++with_build_libsubdir ++enable_silent_rules ++enable_maintainer_mode ++with_libiberty ++enable_dependency_tracking ++enable_largefile ++with_gcc_major_version_only ++enable_shared ++enable_static ++with_pic ++enable_fast_install ++with_gnu_ld ++enable_libtool_lock ++' ++ ac_precious_vars='build_alias ++host_alias ++target_alias ++CC ++CFLAGS ++LDFLAGS ++LIBS ++CPPFLAGS ++CPP ++CXX ++CXXFLAGS ++CCC ++CXXCPP' ++ ++ ++# Initialize some variables set by options. ++ac_init_help= ++ac_init_version=false ++ac_unrecognized_opts= ++ac_unrecognized_sep= ++# The variables have the same names as the options, with ++# dashes changed to underlines. ++cache_file=/dev/null ++exec_prefix=NONE ++no_create= ++no_recursion= ++prefix=NONE ++program_prefix=NONE ++program_suffix=NONE ++program_transform_name=s,x,x, ++silent= ++site= ++srcdir= ++verbose= ++x_includes=NONE ++x_libraries=NONE ++ ++# Installation directory options. ++# These are left unexpanded so users can "make install exec_prefix=/foo" ++# and all the variables that are supposed to be based on exec_prefix ++# by default will actually change. ++# Use braces instead of parens because sh, perl, etc. also accept them. ++# (The list follows the same order as the GNU Coding Standards.) ++bindir='${exec_prefix}/bin' ++sbindir='${exec_prefix}/sbin' ++libexecdir='${exec_prefix}/libexec' ++datarootdir='${prefix}/share' ++datadir='${datarootdir}' ++sysconfdir='${prefix}/etc' ++sharedstatedir='${prefix}/com' ++localstatedir='${prefix}/var' ++includedir='${prefix}/include' ++oldincludedir='/usr/include' ++docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' ++infodir='${datarootdir}/info' ++htmldir='${docdir}' ++dvidir='${docdir}' ++pdfdir='${docdir}' ++psdir='${docdir}' ++libdir='${exec_prefix}/lib' ++localedir='${datarootdir}/locale' ++mandir='${datarootdir}/man' ++ ++ac_prev= ++ac_dashdash= ++for ac_option ++do ++ # If the previous option needs an argument, assign it. ++ if test -n "$ac_prev"; then ++ eval $ac_prev=\$ac_option ++ ac_prev= ++ continue ++ fi ++ ++ case $ac_option in ++ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; ++ *=) ac_optarg= ;; ++ *) ac_optarg=yes ;; ++ esac ++ ++ # Accept the important Cygnus configure options, so we can diagnose typos. ++ ++ case $ac_dashdash$ac_option in ++ --) ++ ac_dashdash=yes ;; ++ ++ -bindir | --bindir | --bindi | --bind | --bin | --bi) ++ ac_prev=bindir ;; ++ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) ++ bindir=$ac_optarg ;; ++ ++ -build | --build | --buil | --bui | --bu) ++ ac_prev=build_alias ;; ++ -build=* | --build=* | --buil=* | --bui=* | --bu=*) ++ build_alias=$ac_optarg ;; ++ ++ -cache-file | --cache-file | --cache-fil | --cache-fi \ ++ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ++ ac_prev=cache_file ;; ++ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ ++ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) ++ cache_file=$ac_optarg ;; ++ ++ --config-cache | -C) ++ cache_file=config.cache ;; ++ ++ -datadir | --datadir | --datadi | --datad) ++ ac_prev=datadir ;; ++ -datadir=* | --datadir=* | --datadi=* | --datad=*) ++ datadir=$ac_optarg ;; ++ ++ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ ++ | --dataroo | --dataro | --datar) ++ ac_prev=datarootdir ;; ++ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ ++ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) ++ datarootdir=$ac_optarg ;; ++ ++ -disable-* | --disable-*) ++ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` ++ # Reject names that are not valid shell variable names. ++ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && ++ as_fn_error $? "invalid feature name: $ac_useropt" ++ ac_useropt_orig=$ac_useropt ++ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` ++ case $ac_user_opts in ++ *" ++"enable_$ac_useropt" ++"*) ;; ++ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ++ ac_unrecognized_sep=', ';; ++ esac ++ eval enable_$ac_useropt=no ;; ++ ++ -docdir | --docdir | --docdi | --doc | --do) ++ ac_prev=docdir ;; ++ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) ++ docdir=$ac_optarg ;; ++ ++ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ++ ac_prev=dvidir ;; ++ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) ++ dvidir=$ac_optarg ;; ++ ++ -enable-* | --enable-*) ++ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` ++ # Reject names that are not valid shell variable names. ++ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && ++ as_fn_error $? "invalid feature name: $ac_useropt" ++ ac_useropt_orig=$ac_useropt ++ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` ++ case $ac_user_opts in ++ *" ++"enable_$ac_useropt" ++"*) ;; ++ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ++ ac_unrecognized_sep=', ';; ++ esac ++ eval enable_$ac_useropt=\$ac_optarg ;; ++ ++ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ ++ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ ++ | --exec | --exe | --ex) ++ ac_prev=exec_prefix ;; ++ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ ++ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ ++ | --exec=* | --exe=* | --ex=*) ++ exec_prefix=$ac_optarg ;; ++ ++ -gas | --gas | --ga | --g) ++ # Obsolete; use --with-gas. ++ with_gas=yes ;; ++ ++ -help | --help | --hel | --he | -h) ++ ac_init_help=long ;; ++ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ++ ac_init_help=recursive ;; ++ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ++ ac_init_help=short ;; ++ ++ -host | --host | --hos | --ho) ++ ac_prev=host_alias ;; ++ -host=* | --host=* | --hos=* | --ho=*) ++ host_alias=$ac_optarg ;; ++ ++ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ++ ac_prev=htmldir ;; ++ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ ++ | --ht=*) ++ htmldir=$ac_optarg ;; ++ ++ -includedir | --includedir | --includedi | --included | --include \ ++ | --includ | --inclu | --incl | --inc) ++ ac_prev=includedir ;; ++ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ ++ | --includ=* | --inclu=* | --incl=* | --inc=*) ++ includedir=$ac_optarg ;; ++ ++ -infodir | --infodir | --infodi | --infod | --info | --inf) ++ ac_prev=infodir ;; ++ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) ++ infodir=$ac_optarg ;; ++ ++ -libdir | --libdir | --libdi | --libd) ++ ac_prev=libdir ;; ++ -libdir=* | --libdir=* | --libdi=* | --libd=*) ++ libdir=$ac_optarg ;; ++ ++ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ ++ | --libexe | --libex | --libe) ++ ac_prev=libexecdir ;; ++ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ ++ | --libexe=* | --libex=* | --libe=*) ++ libexecdir=$ac_optarg ;; ++ ++ -localedir | --localedir | --localedi | --localed | --locale) ++ ac_prev=localedir ;; ++ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) ++ localedir=$ac_optarg ;; ++ ++ -localstatedir | --localstatedir | --localstatedi | --localstated \ ++ | --localstate | --localstat | --localsta | --localst | --locals) ++ ac_prev=localstatedir ;; ++ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ ++ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) ++ localstatedir=$ac_optarg ;; ++ ++ -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ++ ac_prev=mandir ;; ++ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) ++ mandir=$ac_optarg ;; ++ ++ -nfp | --nfp | --nf) ++ # Obsolete; use --without-fp. ++ with_fp=no ;; ++ ++ -no-create | --no-create | --no-creat | --no-crea | --no-cre \ ++ | --no-cr | --no-c | -n) ++ no_create=yes ;; ++ ++ -no-recursion | --no-recursion | --no-recursio | --no-recursi \ ++ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ++ no_recursion=yes ;; ++ ++ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ ++ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ ++ | --oldin | --oldi | --old | --ol | --o) ++ ac_prev=oldincludedir ;; ++ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ ++ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ ++ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) ++ oldincludedir=$ac_optarg ;; ++ ++ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ++ ac_prev=prefix ;; ++ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) ++ prefix=$ac_optarg ;; ++ ++ -program-prefix | --program-prefix | --program-prefi | --program-pref \ ++ | --program-pre | --program-pr | --program-p) ++ ac_prev=program_prefix ;; ++ -program-prefix=* | --program-prefix=* | --program-prefi=* \ ++ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) ++ program_prefix=$ac_optarg ;; ++ ++ -program-suffix | --program-suffix | --program-suffi | --program-suff \ ++ | --program-suf | --program-su | --program-s) ++ ac_prev=program_suffix ;; ++ -program-suffix=* | --program-suffix=* | --program-suffi=* \ ++ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) ++ program_suffix=$ac_optarg ;; ++ ++ -program-transform-name | --program-transform-name \ ++ | --program-transform-nam | --program-transform-na \ ++ | --program-transform-n | --program-transform- \ ++ | --program-transform | --program-transfor \ ++ | --program-transfo | --program-transf \ ++ | --program-trans | --program-tran \ ++ | --progr-tra | --program-tr | --program-t) ++ ac_prev=program_transform_name ;; ++ -program-transform-name=* | --program-transform-name=* \ ++ | --program-transform-nam=* | --program-transform-na=* \ ++ | --program-transform-n=* | --program-transform-=* \ ++ | --program-transform=* | --program-transfor=* \ ++ | --program-transfo=* | --program-transf=* \ ++ | --program-trans=* | --program-tran=* \ ++ | --progr-tra=* | --program-tr=* | --program-t=*) ++ program_transform_name=$ac_optarg ;; ++ ++ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ++ ac_prev=pdfdir ;; ++ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) ++ pdfdir=$ac_optarg ;; ++ ++ -psdir | --psdir | --psdi | --psd | --ps) ++ ac_prev=psdir ;; ++ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) ++ psdir=$ac_optarg ;; ++ ++ -q | -quiet | --quiet | --quie | --qui | --qu | --q \ ++ | -silent | --silent | --silen | --sile | --sil) ++ silent=yes ;; ++ ++ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ++ ac_prev=sbindir ;; ++ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ ++ | --sbi=* | --sb=*) ++ sbindir=$ac_optarg ;; ++ ++ -sharedstatedir | --sharedstatedir | --sharedstatedi \ ++ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ ++ | --sharedst | --shareds | --shared | --share | --shar \ ++ | --sha | --sh) ++ ac_prev=sharedstatedir ;; ++ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ ++ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ ++ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ ++ | --sha=* | --sh=*) ++ sharedstatedir=$ac_optarg ;; ++ ++ -site | --site | --sit) ++ ac_prev=site ;; ++ -site=* | --site=* | --sit=*) ++ site=$ac_optarg ;; ++ ++ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ++ ac_prev=srcdir ;; ++ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) ++ srcdir=$ac_optarg ;; ++ ++ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ ++ | --syscon | --sysco | --sysc | --sys | --sy) ++ ac_prev=sysconfdir ;; ++ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ ++ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) ++ sysconfdir=$ac_optarg ;; ++ ++ -target | --target | --targe | --targ | --tar | --ta | --t) ++ ac_prev=target_alias ;; ++ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) ++ target_alias=$ac_optarg ;; ++ ++ -v | -verbose | --verbose | --verbos | --verbo | --verb) ++ verbose=yes ;; ++ ++ -version | --version | --versio | --versi | --vers | -V) ++ ac_init_version=: ;; ++ ++ -with-* | --with-*) ++ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` ++ # Reject names that are not valid shell variable names. ++ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && ++ as_fn_error $? "invalid package name: $ac_useropt" ++ ac_useropt_orig=$ac_useropt ++ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` ++ case $ac_user_opts in ++ *" ++"with_$ac_useropt" ++"*) ;; ++ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ++ ac_unrecognized_sep=', ';; ++ esac ++ eval with_$ac_useropt=\$ac_optarg ;; ++ ++ -without-* | --without-*) ++ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` ++ # Reject names that are not valid shell variable names. ++ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && ++ as_fn_error $? "invalid package name: $ac_useropt" ++ ac_useropt_orig=$ac_useropt ++ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` ++ case $ac_user_opts in ++ *" ++"with_$ac_useropt" ++"*) ;; ++ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ++ ac_unrecognized_sep=', ';; ++ esac ++ eval with_$ac_useropt=no ;; ++ ++ --x) ++ # Obsolete; use --with-x. ++ with_x=yes ;; ++ ++ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ ++ | --x-incl | --x-inc | --x-in | --x-i) ++ ac_prev=x_includes ;; ++ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ ++ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) ++ x_includes=$ac_optarg ;; ++ ++ -x-libraries | --x-libraries | --x-librarie | --x-librari \ ++ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ++ ac_prev=x_libraries ;; ++ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ ++ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) ++ x_libraries=$ac_optarg ;; ++ ++ -*) as_fn_error $? "unrecognized option: \`$ac_option' ++Try \`$0 --help' for more information" ++ ;; ++ ++ *=*) ++ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` ++ # Reject names that are not valid shell variable names. ++ case $ac_envvar in #( ++ '' | [0-9]* | *[!_$as_cr_alnum]* ) ++ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; ++ esac ++ eval $ac_envvar=\$ac_optarg ++ export $ac_envvar ;; ++ ++ *) ++ # FIXME: should be removed in autoconf 3.0. ++ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 ++ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && ++ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 ++ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ++ ;; ++ ++ esac ++done ++ ++if test -n "$ac_prev"; then ++ ac_option=--`echo $ac_prev | sed 's/_/-/g'` ++ as_fn_error $? "missing argument to $ac_option" ++fi ++ ++if test -n "$ac_unrecognized_opts"; then ++ case $enable_option_checking in ++ no) ;; ++ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; ++ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; ++ esac ++fi ++ ++# Check all directory arguments for consistency. ++for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ ++ datadir sysconfdir sharedstatedir localstatedir includedir \ ++ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ ++ libdir localedir mandir ++do ++ eval ac_val=\$$ac_var ++ # Remove trailing slashes. ++ case $ac_val in ++ */ ) ++ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` ++ eval $ac_var=\$ac_val;; ++ esac ++ # Be sure to have absolute directory names. ++ case $ac_val in ++ [\\/$]* | ?:[\\/]* ) continue;; ++ NONE | '' ) case $ac_var in *prefix ) continue;; esac;; ++ esac ++ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" ++done ++ ++# There might be people who depend on the old broken behavior: `$host' ++# used to hold the argument of --host etc. ++# FIXME: To remove some day. ++build=$build_alias ++host=$host_alias ++target=$target_alias ++ ++# FIXME: To remove some day. ++if test "x$host_alias" != x; then ++ if test "x$build_alias" = x; then ++ cross_compiling=maybe ++ elif test "x$build_alias" != "x$host_alias"; then ++ cross_compiling=yes ++ fi ++fi ++ ++ac_tool_prefix= ++test -n "$host_alias" && ac_tool_prefix=$host_alias- ++ ++test "$silent" = yes && exec 6>/dev/null ++ ++ ++ac_pwd=`pwd` && test -n "$ac_pwd" && ++ac_ls_di=`ls -di .` && ++ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || ++ as_fn_error $? "working directory cannot be determined" ++test "X$ac_ls_di" = "X$ac_pwd_ls_di" || ++ as_fn_error $? "pwd does not report name of working directory" ++ ++ ++# Find the source files, if location was not specified. ++if test -z "$srcdir"; then ++ ac_srcdir_defaulted=yes ++ # Try the directory containing this script, then the parent directory. ++ ac_confdir=`$as_dirname -- "$as_myself" || ++$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ ++ X"$as_myself" : 'X\(//\)[^/]' \| \ ++ X"$as_myself" : 'X\(//\)$' \| \ ++ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || ++$as_echo X"$as_myself" | ++ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\/\)[^/].*/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\/\)$/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\).*/{ ++ s//\1/ ++ q ++ } ++ s/.*/./; q'` ++ srcdir=$ac_confdir ++ if test ! -r "$srcdir/$ac_unique_file"; then ++ srcdir=.. ++ fi ++else ++ ac_srcdir_defaulted=no ++fi ++if test ! -r "$srcdir/$ac_unique_file"; then ++ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." ++ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" ++fi ++ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ++ac_abs_confdir=`( ++ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" ++ pwd)` ++# When building in place, set srcdir=. ++if test "$ac_abs_confdir" = "$ac_pwd"; then ++ srcdir=. ++fi ++# Remove unnecessary trailing slashes from srcdir. ++# Double slashes in file names in object file debugging info ++# mess up M-x gdb in Emacs. ++case $srcdir in ++*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; ++esac ++for ac_var in $ac_precious_vars; do ++ eval ac_env_${ac_var}_set=\${${ac_var}+set} ++ eval ac_env_${ac_var}_value=\$${ac_var} ++ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} ++ eval ac_cv_env_${ac_var}_value=\$${ac_var} ++done ++ ++# ++# Report the --help message. ++# ++if test "$ac_init_help" = "long"; then ++ # Omit some internal or obsolete options to make the list less imposing. ++ # This message is too long to be a string in the A/UX 3.1 sh. ++ cat <<_ACEOF ++\`configure' configures bolt plugin for ld 0.1 to adapt to many kinds of systems. ++ ++Usage: $0 [OPTION]... [VAR=VALUE]... ++ ++To assign environment variables (e.g., CC, CFLAGS...), specify them as ++VAR=VALUE. See below for descriptions of some of the useful variables. ++ ++Defaults for the options are specified in brackets. ++ ++Configuration: ++ -h, --help display this help and exit ++ --help=short display options specific to this package ++ --help=recursive display the short help of all the included packages ++ -V, --version display version information and exit ++ -q, --quiet, --silent do not print \`checking ...' messages ++ --cache-file=FILE cache test results in FILE [disabled] ++ -C, --config-cache alias for \`--cache-file=config.cache' ++ -n, --no-create do not create output files ++ --srcdir=DIR find the sources in DIR [configure dir or \`..'] ++ ++Installation directories: ++ --prefix=PREFIX install architecture-independent files in PREFIX ++ [$ac_default_prefix] ++ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX ++ [PREFIX] ++ ++By default, \`make install' will install all the files in ++\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify ++an installation prefix other than \`$ac_default_prefix' using \`--prefix', ++for instance \`--prefix=\$HOME'. ++ ++For better control, use the options below. ++ ++Fine tuning of the installation directories: ++ --bindir=DIR user executables [EPREFIX/bin] ++ --sbindir=DIR system admin executables [EPREFIX/sbin] ++ --libexecdir=DIR program executables [EPREFIX/libexec] ++ --sysconfdir=DIR read-only single-machine data [PREFIX/etc] ++ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] ++ --localstatedir=DIR modifiable single-machine data [PREFIX/var] ++ --libdir=DIR object code libraries [EPREFIX/lib] ++ --includedir=DIR C header files [PREFIX/include] ++ --oldincludedir=DIR C header files for non-gcc [/usr/include] ++ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] ++ --datadir=DIR read-only architecture-independent data [DATAROOTDIR] ++ --infodir=DIR info documentation [DATAROOTDIR/info] ++ --localedir=DIR locale-dependent data [DATAROOTDIR/locale] ++ --mandir=DIR man documentation [DATAROOTDIR/man] ++ --docdir=DIR documentation root [DATAROOTDIR/doc/bolt-plugin] ++ --htmldir=DIR html documentation [DOCDIR] ++ --dvidir=DIR dvi documentation [DOCDIR] ++ --pdfdir=DIR pdf documentation [DOCDIR] ++ --psdir=DIR ps documentation [DOCDIR] ++_ACEOF ++ ++ cat <<\_ACEOF ++ ++Program names: ++ --program-prefix=PREFIX prepend PREFIX to installed program names ++ --program-suffix=SUFFIX append SUFFIX to installed program names ++ --program-transform-name=PROGRAM run sed PROGRAM on installed program names ++ ++System types: ++ --build=BUILD configure for building on BUILD [guessed] ++ --host=HOST cross-compile to build programs to run on HOST [BUILD] ++ --target=TARGET configure for building compilers for TARGET [HOST] ++_ACEOF ++fi ++ ++if test -n "$ac_init_help"; then ++ case $ac_init_help in ++ short | recursive ) echo "Configuration of bolt plugin for ld 0.1:";; ++ esac ++ cat <<\_ACEOF ++ ++Optional Features: ++ --disable-option-checking ignore unrecognized --enable/--with options ++ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) ++ --enable-FEATURE[=ARG] include FEATURE [ARG=yes] ++ --enable-silent-rules less verbose build output (undo: "make V=1") ++ --disable-silent-rules verbose build output (undo: "make V=0") ++ --enable-maintainer-mode ++ enable make rules and dependencies not useful (and ++ sometimes confusing) to the casual installer ++ --enable-dependency-tracking ++ do not reject slow dependency extractors ++ --disable-dependency-tracking ++ speeds up one-time build ++ --disable-largefile omit support for large files ++ --enable-shared[=PKGS] build shared libraries [default=yes] ++ --enable-static[=PKGS] build static libraries [default=yes] ++ --enable-fast-install[=PKGS] ++ optimize for fast installation [default=yes] ++ --disable-libtool-lock avoid locking (might break parallel builds) ++ ++Optional Packages: ++ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] ++ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) ++ --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] ++ ++Some influential environment variables: ++ CC C compiler command ++ CFLAGS C compiler flags ++ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a ++ nonstandard directory <lib dir> ++ LIBS libraries to pass to the linker, e.g. -l<library> ++ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if ++ you have headers in a nonstandard directory <include dir> ++ CPP C preprocessor ++ CXX C++ compiler command ++ CXXFLAGS C++ compiler flags ++ CXXCPP C++ preprocessor ++ ++Use these variables to override the choices made by `configure' or to help ++it to find libraries and programs with nonstandard names/locations. ++ ++Report bugs to the package provider. ++_ACEOF ++ac_status=$? ++fi ++ ++if test "$ac_init_help" = "recursive"; then ++ # If there are subdirs, report their specific --help. ++ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue ++ test -d "$ac_dir" || ++ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || ++ continue ++ ac_builddir=. ++ ++case "$ac_dir" in ++.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; ++*) ++ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` ++ # A ".." for each directory in $ac_dir_suffix. ++ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` ++ case $ac_top_builddir_sub in ++ "") ac_top_builddir_sub=. ac_top_build_prefix= ;; ++ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; ++ esac ;; ++esac ++ac_abs_top_builddir=$ac_pwd ++ac_abs_builddir=$ac_pwd$ac_dir_suffix ++# for backward compatibility: ++ac_top_builddir=$ac_top_build_prefix ++ ++case $srcdir in ++ .) # We are building in place. ++ ac_srcdir=. ++ ac_top_srcdir=$ac_top_builddir_sub ++ ac_abs_top_srcdir=$ac_pwd ;; ++ [\\/]* | ?:[\\/]* ) # Absolute name. ++ ac_srcdir=$srcdir$ac_dir_suffix; ++ ac_top_srcdir=$srcdir ++ ac_abs_top_srcdir=$srcdir ;; ++ *) # Relative name. ++ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ++ ac_top_srcdir=$ac_top_build_prefix$srcdir ++ ac_abs_top_srcdir=$ac_pwd/$srcdir ;; ++esac ++ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix ++ ++ cd "$ac_dir" || { ac_status=$?; continue; } ++ # Check for guested configure. ++ if test -f "$ac_srcdir/configure.gnu"; then ++ echo && ++ $SHELL "$ac_srcdir/configure.gnu" --help=recursive ++ elif test -f "$ac_srcdir/configure"; then ++ echo && ++ $SHELL "$ac_srcdir/configure" --help=recursive ++ else ++ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 ++ fi || ac_status=$? ++ cd "$ac_pwd" || { ac_status=$?; break; } ++ done ++fi ++ ++test -n "$ac_init_help" && exit $ac_status ++if $ac_init_version; then ++ cat <<\_ACEOF ++bolt plugin for ld configure 0.1 ++generated by GNU Autoconf 2.69 ++ ++Copyright (C) 2012 Free Software Foundation, Inc. ++This configure script is free software; the Free Software Foundation ++gives unlimited permission to copy, distribute and modify it. ++_ACEOF ++ exit ++fi ++ ++## ------------------------ ## ++## Autoconf initialization. ## ++## ------------------------ ## ++ ++# ac_fn_c_try_compile LINENO ++# -------------------------- ++# Try to compile conftest.$ac_ext, and return whether this succeeded. ++ac_fn_c_try_compile () ++{ ++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack ++ rm -f conftest.$ac_objext ++ if { { ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" ++$as_echo "$ac_try_echo"; } >&5 ++ (eval "$ac_compile") 2>conftest.err ++ ac_status=$? ++ if test -s conftest.err; then ++ grep -v '^ *+' conftest.err >conftest.er1 ++ cat conftest.er1 >&5 ++ mv -f conftest.er1 conftest.err ++ fi ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest.$ac_objext; then : ++ ac_retval=0 ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_retval=1 ++fi ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno ++ as_fn_set_status $ac_retval ++ ++} # ac_fn_c_try_compile ++ ++# ac_fn_c_try_cpp LINENO ++# ---------------------- ++# Try to preprocess conftest.$ac_ext, and return whether this succeeded. ++ac_fn_c_try_cpp () ++{ ++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack ++ if { { ac_try="$ac_cpp conftest.$ac_ext" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" ++$as_echo "$ac_try_echo"; } >&5 ++ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ++ ac_status=$? ++ if test -s conftest.err; then ++ grep -v '^ *+' conftest.err >conftest.er1 ++ cat conftest.er1 >&5 ++ mv -f conftest.er1 conftest.err ++ fi ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; } > conftest.i && { ++ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || ++ test ! -s conftest.err ++ }; then : ++ ac_retval=0 ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_retval=1 ++fi ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno ++ as_fn_set_status $ac_retval ++ ++} # ac_fn_c_try_cpp ++ ++# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES ++# ------------------------------------------------------- ++# Tests whether HEADER exists, giving a warning if it cannot be compiled using ++# the include files in INCLUDES and setting the cache variable VAR ++# accordingly. ++ac_fn_c_check_header_mongrel () ++{ ++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack ++ if eval \${$3+:} false; then : ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 ++$as_echo_n "checking for $2... " >&6; } ++if eval \${$3+:} false; then : ++ $as_echo_n "(cached) " >&6 ++fi ++eval ac_res=\$$3 ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 ++$as_echo "$ac_res" >&6; } ++else ++ # Is the header compilable? ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 ++$as_echo_n "checking $2 usability... " >&6; } ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++$4 ++#include <$2> ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ ac_header_compiler=yes ++else ++ ac_header_compiler=no ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 ++$as_echo "$ac_header_compiler" >&6; } ++ ++# Is the header present? ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 ++$as_echo_n "checking $2 presence... " >&6; } ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#include <$2> ++_ACEOF ++if ac_fn_c_try_cpp "$LINENO"; then : ++ ac_header_preproc=yes ++else ++ ac_header_preproc=no ++fi ++rm -f conftest.err conftest.i conftest.$ac_ext ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 ++$as_echo "$ac_header_preproc" >&6; } ++ ++# So? What about this header? ++case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( ++ yes:no: ) ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 ++$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 ++$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ++ ;; ++ no:yes:* ) ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 ++$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 ++$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 ++$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 ++$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 ++$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ++ ;; ++esac ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 ++$as_echo_n "checking for $2... " >&6; } ++if eval \${$3+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ eval "$3=\$ac_header_compiler" ++fi ++eval ac_res=\$$3 ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 ++$as_echo "$ac_res" >&6; } ++fi ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno ++ ++} # ac_fn_c_check_header_mongrel ++ ++# ac_fn_c_try_run LINENO ++# ---------------------- ++# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes ++# that executables *can* be run. ++ac_fn_c_try_run () ++{ ++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack ++ if { { ac_try="$ac_link" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" ++$as_echo "$ac_try_echo"; } >&5 ++ (eval "$ac_link") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' ++ { { case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" ++$as_echo "$ac_try_echo"; } >&5 ++ (eval "$ac_try") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; }; }; then : ++ ac_retval=0 ++else ++ $as_echo "$as_me: program exited with status $ac_status" >&5 ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_retval=$ac_status ++fi ++ rm -rf conftest.dSYM conftest_ipa8_conftest.oo ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno ++ as_fn_set_status $ac_retval ++ ++} # ac_fn_c_try_run ++ ++# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES ++# ------------------------------------------------------- ++# Tests whether HEADER exists and can be compiled using the include files in ++# INCLUDES, setting the cache variable VAR accordingly. ++ac_fn_c_check_header_compile () ++{ ++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 ++$as_echo_n "checking for $2... " >&6; } ++if eval \${$3+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++$4 ++#include <$2> ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ eval "$3=yes" ++else ++ eval "$3=no" ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++fi ++eval ac_res=\$$3 ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 ++$as_echo "$ac_res" >&6; } ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno ++ ++} # ac_fn_c_check_header_compile ++ ++# ac_fn_cxx_try_compile LINENO ++# ---------------------------- ++# Try to compile conftest.$ac_ext, and return whether this succeeded. ++ac_fn_cxx_try_compile () ++{ ++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack ++ rm -f conftest.$ac_objext ++ if { { ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" ++$as_echo "$ac_try_echo"; } >&5 ++ (eval "$ac_compile") 2>conftest.err ++ ac_status=$? ++ if test -s conftest.err; then ++ grep -v '^ *+' conftest.err >conftest.er1 ++ cat conftest.er1 >&5 ++ mv -f conftest.er1 conftest.err ++ fi ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; } && { ++ test -z "$ac_cxx_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest.$ac_objext; then : ++ ac_retval=0 ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_retval=1 ++fi ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno ++ as_fn_set_status $ac_retval ++ ++} # ac_fn_cxx_try_compile ++ ++# ac_fn_c_try_link LINENO ++# ----------------------- ++# Try to link conftest.$ac_ext, and return whether this succeeded. ++ac_fn_c_try_link () ++{ ++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack ++ rm -f conftest.$ac_objext conftest$ac_exeext ++ if { { ac_try="$ac_link" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" ++$as_echo "$ac_try_echo"; } >&5 ++ (eval "$ac_link") 2>conftest.err ++ ac_status=$? ++ if test -s conftest.err; then ++ grep -v '^ *+' conftest.err >conftest.er1 ++ cat conftest.er1 >&5 ++ mv -f conftest.er1 conftest.err ++ fi ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; } && { ++ test -z "$ac_c_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest$ac_exeext && { ++ test "$cross_compiling" = yes || ++ test -x conftest$ac_exeext ++ }; then : ++ ac_retval=0 ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_retval=1 ++fi ++ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information ++ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would ++ # interfere with the next link command; also delete a directory that is ++ # left behind by Apple's compiler. We do this before executing the actions. ++ rm -rf conftest.dSYM conftest_ipa8_conftest.oo ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno ++ as_fn_set_status $ac_retval ++ ++} # ac_fn_c_try_link ++ ++# ac_fn_c_check_func LINENO FUNC VAR ++# ---------------------------------- ++# Tests whether FUNC exists, setting the cache variable VAR accordingly ++ac_fn_c_check_func () ++{ ++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 ++$as_echo_n "checking for $2... " >&6; } ++if eval \${$3+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++/* Define $2 to an innocuous variant, in case <limits.h> declares $2. ++ For example, HP-UX 11i <limits.h> declares gettimeofday. */ ++#define $2 innocuous_$2 ++ ++/* System header to define __stub macros and hopefully few prototypes, ++ which can conflict with char $2 (); below. ++ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since ++ <limits.h> exists even on freestanding compilers. */ ++ ++#ifdef __STDC__ ++# include <limits.h> ++#else ++# include <assert.h> ++#endif ++ ++#undef $2 ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char $2 (); ++/* The GNU C library defines this for functions which it implements ++ to always fail with ENOSYS. Some functions are actually named ++ something starting with __ and the normal name is an alias. */ ++#if defined __stub_$2 || defined __stub___$2 ++choke me ++#endif ++ ++int ++main () ++{ ++return $2 (); ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ eval "$3=yes" ++else ++ eval "$3=no" ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++fi ++eval ac_res=\$$3 ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 ++$as_echo "$ac_res" >&6; } ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno ++ ++} # ac_fn_c_check_func ++ ++# ac_fn_cxx_try_cpp LINENO ++# ------------------------ ++# Try to preprocess conftest.$ac_ext, and return whether this succeeded. ++ac_fn_cxx_try_cpp () ++{ ++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack ++ if { { ac_try="$ac_cpp conftest.$ac_ext" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" ++$as_echo "$ac_try_echo"; } >&5 ++ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ++ ac_status=$? ++ if test -s conftest.err; then ++ grep -v '^ *+' conftest.err >conftest.er1 ++ cat conftest.er1 >&5 ++ mv -f conftest.er1 conftest.err ++ fi ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; } > conftest.i && { ++ test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || ++ test ! -s conftest.err ++ }; then : ++ ac_retval=0 ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_retval=1 ++fi ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno ++ as_fn_set_status $ac_retval ++ ++} # ac_fn_cxx_try_cpp ++ ++# ac_fn_cxx_try_link LINENO ++# ------------------------- ++# Try to link conftest.$ac_ext, and return whether this succeeded. ++ac_fn_cxx_try_link () ++{ ++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack ++ rm -f conftest.$ac_objext conftest$ac_exeext ++ if { { ac_try="$ac_link" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" ++$as_echo "$ac_try_echo"; } >&5 ++ (eval "$ac_link") 2>conftest.err ++ ac_status=$? ++ if test -s conftest.err; then ++ grep -v '^ *+' conftest.err >conftest.er1 ++ cat conftest.er1 >&5 ++ mv -f conftest.er1 conftest.err ++ fi ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; } && { ++ test -z "$ac_cxx_werror_flag" || ++ test ! -s conftest.err ++ } && test -s conftest$ac_exeext && { ++ test "$cross_compiling" = yes || ++ test -x conftest$ac_exeext ++ }; then : ++ ac_retval=0 ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_retval=1 ++fi ++ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information ++ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would ++ # interfere with the next link command; also delete a directory that is ++ # left behind by Apple's compiler. We do this before executing the actions. ++ rm -rf conftest.dSYM conftest_ipa8_conftest.oo ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno ++ as_fn_set_status $ac_retval ++ ++} # ac_fn_cxx_try_link ++ ++# ac_fn_c_find_intX_t LINENO BITS VAR ++# ----------------------------------- ++# Finds a signed integer type with width BITS, setting cache variable VAR ++# accordingly. ++ac_fn_c_find_intX_t () ++{ ++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5 ++$as_echo_n "checking for int$2_t... " >&6; } ++if eval \${$3+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ eval "$3=no" ++ # Order is important - never check a type that is potentially smaller ++ # than half of the expected target width. ++ for ac_type in int$2_t 'int' 'long int' \ ++ 'long long int' 'short int' 'signed char'; do ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++$ac_includes_default ++ enum { N = $2 / 2 - 1 }; ++int ++main () ++{ ++static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; ++test_array [0] = 0; ++return test_array [0]; ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++$ac_includes_default ++ enum { N = $2 / 2 - 1 }; ++int ++main () ++{ ++static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) ++ < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))]; ++test_array [0] = 0; ++return test_array [0]; ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ ++else ++ case $ac_type in #( ++ int$2_t) : ++ eval "$3=yes" ;; #( ++ *) : ++ eval "$3=\$ac_type" ;; ++esac ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ if eval test \"x\$"$3"\" = x"no"; then : ++ ++else ++ break ++fi ++ done ++fi ++eval ac_res=\$$3 ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 ++$as_echo "$ac_res" >&6; } ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno ++ ++} # ac_fn_c_find_intX_t ++ ++# ac_fn_c_find_uintX_t LINENO BITS VAR ++# ------------------------------------ ++# Finds an unsigned integer type with width BITS, setting cache variable VAR ++# accordingly. ++ac_fn_c_find_uintX_t () ++{ ++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 ++$as_echo_n "checking for uint$2_t... " >&6; } ++if eval \${$3+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ eval "$3=no" ++ # Order is important - never check a type that is potentially smaller ++ # than half of the expected target width. ++ for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ ++ 'unsigned long long int' 'unsigned short int' 'unsigned char'; do ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++$ac_includes_default ++int ++main () ++{ ++static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; ++test_array [0] = 0; ++return test_array [0]; ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ case $ac_type in #( ++ uint$2_t) : ++ eval "$3=yes" ;; #( ++ *) : ++ eval "$3=\$ac_type" ;; ++esac ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ if eval test \"x\$"$3"\" = x"no"; then : ++ ++else ++ break ++fi ++ done ++fi ++eval ac_res=\$$3 ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 ++$as_echo "$ac_res" >&6; } ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno ++ ++} # ac_fn_c_find_uintX_t ++cat >config.log <<_ACEOF ++This file contains any messages produced by compilers while ++running configure, to aid debugging if configure makes a mistake. ++ ++It was created by bolt plugin for ld $as_me 0.1, which was ++generated by GNU Autoconf 2.69. Invocation command line was ++ ++ $ $0 $@ ++ ++_ACEOF ++exec 5>>config.log ++{ ++cat <<_ASUNAME ++## --------- ## ++## Platform. ## ++## --------- ## ++ ++hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` ++uname -m = `(uname -m) 2>/dev/null || echo unknown` ++uname -r = `(uname -r) 2>/dev/null || echo unknown` ++uname -s = `(uname -s) 2>/dev/null || echo unknown` ++uname -v = `(uname -v) 2>/dev/null || echo unknown` ++ ++/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` ++/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` ++ ++/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` ++/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` ++/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` ++/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` ++/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` ++/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` ++/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` ++ ++_ASUNAME ++ ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ $as_echo "PATH: $as_dir" ++ done ++IFS=$as_save_IFS ++ ++} >&5 ++ ++cat >&5 <<_ACEOF ++ ++ ++## ----------- ## ++## Core tests. ## ++## ----------- ## ++ ++_ACEOF ++ ++ ++# Keep a trace of the command line. ++# Strip out --no-create and --no-recursion so they do not pile up. ++# Strip out --silent because we don't want to record it for future runs. ++# Also quote any args containing shell meta-characters. ++# Make two passes to allow for proper duplicate-argument suppression. ++ac_configure_args= ++ac_configure_args0= ++ac_configure_args1= ++ac_must_keep_next=false ++for ac_pass in 1 2 ++do ++ for ac_arg ++ do ++ case $ac_arg in ++ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; ++ -q | -quiet | --quiet | --quie | --qui | --qu | --q \ ++ | -silent | --silent | --silen | --sile | --sil) ++ continue ;; ++ *\'*) ++ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; ++ esac ++ case $ac_pass in ++ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; ++ 2) ++ as_fn_append ac_configure_args1 " '$ac_arg'" ++ if test $ac_must_keep_next = true; then ++ ac_must_keep_next=false # Got value, back to normal. ++ else ++ case $ac_arg in ++ *=* | --config-cache | -C | -disable-* | --disable-* \ ++ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ ++ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ ++ | -with-* | --with-* | -without-* | --without-* | --x) ++ case "$ac_configure_args0 " in ++ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; ++ esac ++ ;; ++ -* ) ac_must_keep_next=true ;; ++ esac ++ fi ++ as_fn_append ac_configure_args " '$ac_arg'" ++ ;; ++ esac ++ done ++done ++{ ac_configure_args0=; unset ac_configure_args0;} ++{ ac_configure_args1=; unset ac_configure_args1;} ++ ++# When interrupted or exit'd, cleanup temporary files, and complete ++# config.log. We remove comments because anyway the quotes in there ++# would cause problems or look ugly. ++# WARNING: Use '\'' to represent an apostrophe within the trap. ++# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. ++trap 'exit_status=$? ++ # Save into config.log some information that might help in debugging. ++ { ++ echo ++ ++ $as_echo "## ---------------- ## ++## Cache variables. ## ++## ---------------- ##" ++ echo ++ # The following way of writing the cache mishandles newlines in values, ++( ++ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do ++ eval ac_val=\$$ac_var ++ case $ac_val in #( ++ *${as_nl}*) ++ case $ac_var in #( ++ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 ++$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; ++ esac ++ case $ac_var in #( ++ _ | IFS | as_nl) ;; #( ++ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( ++ *) { eval $ac_var=; unset $ac_var;} ;; ++ esac ;; ++ esac ++ done ++ (set) 2>&1 | ++ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( ++ *${as_nl}ac_space=\ *) ++ sed -n \ ++ "s/'\''/'\''\\\\'\'''\''/g; ++ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ++ ;; #( ++ *) ++ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ++ ;; ++ esac | ++ sort ++) ++ echo ++ ++ $as_echo "## ----------------- ## ++## Output variables. ## ++## ----------------- ##" ++ echo ++ for ac_var in $ac_subst_vars ++ do ++ eval ac_val=\$$ac_var ++ case $ac_val in ++ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; ++ esac ++ $as_echo "$ac_var='\''$ac_val'\''" ++ done | sort ++ echo ++ ++ if test -n "$ac_subst_files"; then ++ $as_echo "## ------------------- ## ++## File substitutions. ## ++## ------------------- ##" ++ echo ++ for ac_var in $ac_subst_files ++ do ++ eval ac_val=\$$ac_var ++ case $ac_val in ++ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; ++ esac ++ $as_echo "$ac_var='\''$ac_val'\''" ++ done | sort ++ echo ++ fi ++ ++ if test -s confdefs.h; then ++ $as_echo "## ----------- ## ++## confdefs.h. ## ++## ----------- ##" ++ echo ++ cat confdefs.h ++ echo ++ fi ++ test "$ac_signal" != 0 && ++ $as_echo "$as_me: caught signal $ac_signal" ++ $as_echo "$as_me: exit $exit_status" ++ } >&5 ++ rm -f core *.core core.conftest.* && ++ rm -f -r conftest* confdefs* conf$$* $ac_clean_files && ++ exit $exit_status ++' 0 ++for ac_signal in 1 2 13 15; do ++ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal ++done ++ac_signal=0 ++ ++# confdefs.h avoids OS command line length limits that DEFS can exceed. ++rm -f -r conftest* confdefs.h ++ ++$as_echo "/* confdefs.h */" > confdefs.h ++ ++# Predefined preprocessor variables. ++ ++cat >>confdefs.h <<_ACEOF ++#define PACKAGE_NAME "$PACKAGE_NAME" ++_ACEOF ++ ++cat >>confdefs.h <<_ACEOF ++#define PACKAGE_TARNAME "$PACKAGE_TARNAME" ++_ACEOF ++ ++cat >>confdefs.h <<_ACEOF ++#define PACKAGE_VERSION "$PACKAGE_VERSION" ++_ACEOF ++ ++cat >>confdefs.h <<_ACEOF ++#define PACKAGE_STRING "$PACKAGE_STRING" ++_ACEOF ++ ++cat >>confdefs.h <<_ACEOF ++#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" ++_ACEOF ++ ++cat >>confdefs.h <<_ACEOF ++#define PACKAGE_URL "$PACKAGE_URL" ++_ACEOF ++ ++ ++# Let the site file select an alternate cache file if it wants to. ++# Prefer an explicitly selected file to automatically selected ones. ++ac_site_file1=NONE ++ac_site_file2=NONE ++if test -n "$CONFIG_SITE"; then ++ # We do not want a PATH search for config.site. ++ case $CONFIG_SITE in #(( ++ -*) ac_site_file1=./$CONFIG_SITE;; ++ */*) ac_site_file1=$CONFIG_SITE;; ++ *) ac_site_file1=./$CONFIG_SITE;; ++ esac ++elif test "x$prefix" != xNONE; then ++ ac_site_file1=$prefix/share/config.site ++ ac_site_file2=$prefix/etc/config.site ++else ++ ac_site_file1=$ac_default_prefix/share/config.site ++ ac_site_file2=$ac_default_prefix/etc/config.site ++fi ++for ac_site_file in "$ac_site_file1" "$ac_site_file2" ++do ++ test "x$ac_site_file" = xNONE && continue ++ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 ++$as_echo "$as_me: loading site script $ac_site_file" >&6;} ++ sed 's/^/| /' "$ac_site_file" >&5 ++ . "$ac_site_file" \ ++ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++as_fn_error $? "failed to load site script $ac_site_file ++See \`config.log' for more details" "$LINENO" 5; } ++ fi ++done ++ ++if test -r "$cache_file"; then ++ # Some versions of bash will fail to source /dev/null (special files ++ # actually), so we avoid doing that. DJGPP emulates it as a regular file. ++ if test /dev/null != "$cache_file" && test -f "$cache_file"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 ++$as_echo "$as_me: loading cache $cache_file" >&6;} ++ case $cache_file in ++ [\\/]* | ?:[\\/]* ) . "$cache_file";; ++ *) . "./$cache_file";; ++ esac ++ fi ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 ++$as_echo "$as_me: creating cache $cache_file" >&6;} ++ >$cache_file ++fi ++ ++# Check that the precious variables saved in the cache have kept the same ++# value. ++ac_cache_corrupted=false ++for ac_var in $ac_precious_vars; do ++ eval ac_old_set=\$ac_cv_env_${ac_var}_set ++ eval ac_new_set=\$ac_env_${ac_var}_set ++ eval ac_old_val=\$ac_cv_env_${ac_var}_value ++ eval ac_new_val=\$ac_env_${ac_var}_value ++ case $ac_old_set,$ac_new_set in ++ set,) ++ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 ++$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ++ ac_cache_corrupted=: ;; ++ ,set) ++ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 ++$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ++ ac_cache_corrupted=: ;; ++ ,);; ++ *) ++ if test "x$ac_old_val" != "x$ac_new_val"; then ++ # differences in whitespace do not lead to failure. ++ ac_old_val_w=`echo x $ac_old_val` ++ ac_new_val_w=`echo x $ac_new_val` ++ if test "$ac_old_val_w" != "$ac_new_val_w"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 ++$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ++ ac_cache_corrupted=: ++ else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 ++$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} ++ eval $ac_var=\$ac_old_val ++ fi ++ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 ++$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} ++ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 ++$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} ++ fi;; ++ esac ++ # Pass precious variables to config.status. ++ if test "$ac_new_set" = set; then ++ case $ac_new_val in ++ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; ++ *) ac_arg=$ac_var=$ac_new_val ;; ++ esac ++ case " $ac_configure_args " in ++ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. ++ *) as_fn_append ac_configure_args " '$ac_arg'" ;; ++ esac ++ fi ++done ++if $ac_cache_corrupted; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 ++$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} ++ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 ++fi ++## -------------------- ## ++## Main body of script. ## ++## -------------------- ## ++ ++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_aux_dir= ++for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do ++ if test -f "$ac_dir/install-sh"; then ++ ac_aux_dir=$ac_dir ++ ac_install_sh="$ac_aux_dir/install-sh -c" ++ break ++ elif test -f "$ac_dir/install.sh"; then ++ ac_aux_dir=$ac_dir ++ ac_install_sh="$ac_aux_dir/install.sh -c" ++ break ++ elif test -f "$ac_dir/shtool"; then ++ ac_aux_dir=$ac_dir ++ ac_install_sh="$ac_aux_dir/shtool install -c" ++ break ++ fi ++done ++if test -z "$ac_aux_dir"; then ++ as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 ++fi ++ ++# These three variables are undocumented and unsupported, ++# and are intended to be withdrawn in a future Autoconf release. ++# They can cause serious problems if a builder's source tree is in a directory ++# whose full name contains unusual characters. ++ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ++ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ++ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. ++ ++ ++# Make sure we can run config.sub. ++$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || ++ as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 ++$as_echo_n "checking build system type... " >&6; } ++if ${ac_cv_build+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_build_alias=$build_alias ++test "x$ac_build_alias" = x && ++ ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` ++test "x$ac_build_alias" = x && ++ as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ++ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || ++ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 ++$as_echo "$ac_cv_build" >&6; } ++case $ac_cv_build in ++*-*-*) ;; ++*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; ++esac ++build=$ac_cv_build ++ac_save_IFS=$IFS; IFS='-' ++set x $ac_cv_build ++shift ++build_cpu=$1 ++build_vendor=$2 ++shift; shift ++# Remember, the first character of IFS is used to create $*, ++# except with old shells: ++build_os=$* ++IFS=$ac_save_IFS ++case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac ++ ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 ++$as_echo_n "checking host system type... " >&6; } ++if ${ac_cv_host+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test "x$host_alias" = x; then ++ ac_cv_host=$ac_cv_build ++else ++ ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || ++ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 ++fi ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 ++$as_echo "$ac_cv_host" >&6; } ++case $ac_cv_host in ++*-*-*) ;; ++*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; ++esac ++host=$ac_cv_host ++ac_save_IFS=$IFS; IFS='-' ++set x $ac_cv_host ++shift ++host_cpu=$1 ++host_vendor=$2 ++shift; shift ++# Remember, the first character of IFS is used to create $*, ++# except with old shells: ++host_os=$* ++IFS=$ac_save_IFS ++case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac ++ ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 ++$as_echo_n "checking target system type... " >&6; } ++if ${ac_cv_target+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test "x$target_alias" = x; then ++ ac_cv_target=$ac_cv_host ++else ++ ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || ++ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 ++fi ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 ++$as_echo "$ac_cv_target" >&6; } ++case $ac_cv_target in ++*-*-*) ;; ++*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; ++esac ++target=$ac_cv_target ++ac_save_IFS=$IFS; IFS='-' ++set x $ac_cv_target ++shift ++target_cpu=$1 ++target_vendor=$2 ++shift; shift ++# Remember, the first character of IFS is used to create $*, ++# except with old shells: ++target_os=$* ++IFS=$ac_save_IFS ++case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac ++ ++ ++# The aliases save the names the user supplied, while $host etc. ++# will get canonicalized. ++test -n "$target_alias" && ++ test "$program_prefix$program_suffix$program_transform_name" = \ ++ NONENONEs,x,x, && ++ program_prefix=${target_alias}- ++ ++ case ${build_alias} in ++ "") build_noncanonical=${build} ;; ++ *) build_noncanonical=${build_alias} ;; ++esac ++ ++ case ${host_alias} in ++ "") host_noncanonical=${build_noncanonical} ;; ++ *) host_noncanonical=${host_alias} ;; ++esac ++ ++ case ${target_alias} in ++ "") target_noncanonical=${host_noncanonical} ;; ++ *) target_noncanonical=${target_alias} ;; ++esac ++ ++ ++# post-stage1 host modules use a different CC_FOR_BUILD so, in order to ++# have matching libraries, they should use host libraries: Makefile.tpl ++# arranges to pass --with-build-libsubdir=$(HOST_SUBDIR). ++# However, they still use the build modules, because the corresponding ++# host modules (e.g. bison) are only built for the host when bootstrap ++# finishes. So: ++# - build_subdir is where we find build modules, and never changes. ++# - build_libsubdir is where we find build libraries, and can be overridden. ++ ++# Prefix 'build-' so this never conflicts with target_subdir. ++build_subdir="build-${build_noncanonical}" ++ ++# Check whether --with-build-libsubdir was given. ++if test "${with_build_libsubdir+set}" = set; then : ++ withval=$with_build_libsubdir; build_libsubdir="$withval" ++else ++ build_libsubdir="$build_subdir" ++fi ++ ++# --srcdir=. covers the toplevel, while "test -d" covers the subdirectories ++if ( test $srcdir = . && test -d gcc ) \ ++ || test -d $srcdir/../host-${host_noncanonical}; then ++ host_subdir="host-${host_noncanonical}" ++else ++ host_subdir=. ++fi ++# No prefix. ++target_subdir=${target_noncanonical} ++ ++am__api_version='1.16' ++ ++# Find a good install program. We prefer a C program (faster), ++# so one script is as good as another. But avoid the broken or ++# incompatible versions: ++# SysV /etc/install, /usr/sbin/install ++# SunOS /usr/etc/install ++# IRIX /sbin/install ++# AIX /bin/install ++# AmigaOS /C/install, which installs bootblocks on floppy discs ++# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag ++# AFS /usr/afsws/bin/install, which mishandles nonexistent args ++# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" ++# OS/2's system install, which has a completely different semantic ++# ./install, which can be erroneously created by make from ./install.sh. ++# Reject install programs that cannot install multiple files. ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 ++$as_echo_n "checking for a BSD-compatible install... " >&6; } ++if test -z "$INSTALL"; then ++if ${ac_cv_path_install+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ # Account for people who put trailing slashes in PATH elements. ++case $as_dir/ in #(( ++ ./ | .// | /[cC]/* | \ ++ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ++ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ ++ /usr/ucb/* ) ;; ++ *) ++ # OSF1 and SCO ODT 3.0 have their own names for install. ++ # Don't use installbsd from OSF since it installs stuff as root ++ # by default. ++ for ac_prog in ginstall scoinst install; do ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then ++ if test $ac_prog = install && ++ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then ++ # AIX install. It has an incompatible calling convention. ++ : ++ elif test $ac_prog = install && ++ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then ++ # program-specific install script used by HP pwplus--don't use. ++ : ++ else ++ rm -rf conftest.one conftest.two conftest.dir ++ echo one > conftest.one ++ echo two > conftest.two ++ mkdir conftest.dir ++ if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && ++ test -s conftest.one && test -s conftest.two && ++ test -s conftest.dir/conftest.one && ++ test -s conftest.dir/conftest.two ++ then ++ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" ++ break 3 ++ fi ++ fi ++ fi ++ done ++ done ++ ;; ++esac ++ ++ done ++IFS=$as_save_IFS ++ ++rm -rf conftest.one conftest.two conftest.dir ++ ++fi ++ if test "${ac_cv_path_install+set}" = set; then ++ INSTALL=$ac_cv_path_install ++ else ++ # As a last resort, use the slow shell script. Don't cache a ++ # value for INSTALL within a source directory, because that will ++ # break other packages using the cache if that directory is ++ # removed, or if the value is a relative name. ++ INSTALL=$ac_install_sh ++ fi ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 ++$as_echo "$INSTALL" >&6; } ++ ++# Use test -z because SunOS4 sh mishandles braces in ${var-val}. ++# It thinks the first close brace ends the variable substitution. ++test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' ++ ++test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' ++ ++test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 ++$as_echo_n "checking whether build environment is sane... " >&6; } ++# Reject unsafe characters in $srcdir or the absolute working directory ++# name. Accept space and tab only in the latter. ++am_lf=' ++' ++case `pwd` in ++ *[\\\"\#\$\&\'\`$am_lf]*) ++ as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; ++esac ++case $srcdir in ++ *[\\\"\#\$\&\'\`$am_lf\ \ ]*) ++ as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; ++esac ++ ++# Do 'set' in a subshell so we don't clobber the current shell's ++# arguments. Must try -L first in case configure is actually a ++# symlink; some systems play weird games with the mod time of symlinks ++# (eg FreeBSD returns the mod time of the symlink's containing ++# directory). ++if ( ++ am_has_slept=no ++ for am_try in 1 2; do ++ echo "timestamp, slept: $am_has_slept" > conftest.file ++ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` ++ if test "$*" = "X"; then ++ # -L didn't work. ++ set X `ls -t "$srcdir/configure" conftest.file` ++ fi ++ if test "$*" != "X $srcdir/configure conftest.file" \ ++ && test "$*" != "X conftest.file $srcdir/configure"; then ++ ++ # If neither matched, then we have a broken ls. This can happen ++ # if, for instance, CONFIG_SHELL is bash and it inherits a ++ # broken ls alias from the environment. This has actually ++ # happened. Such a system could not be considered "sane". ++ as_fn_error $? "ls -t appears to fail. Make sure there is not a broken ++ alias in your environment" "$LINENO" 5 ++ fi ++ if test "$2" = conftest.file || test $am_try -eq 2; then ++ break ++ fi ++ # Just in case. ++ sleep 1 ++ am_has_slept=yes ++ done ++ test "$2" = conftest.file ++ ) ++then ++ # Ok. ++ : ++else ++ as_fn_error $? "newly created file is older than distributed files! ++Check your system clock" "$LINENO" 5 ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 ++$as_echo "yes" >&6; } ++# If we didn't sleep, we still need to ensure time stamps of config.status and ++# generated files are strictly newer. ++am_sleep_pid= ++if grep 'slept: no' conftest.file >/dev/null 2>&1; then ++ ( sleep 1 ) & ++ am_sleep_pid=$! ++fi ++ ++rm -f conftest.file ++ ++test "$program_prefix" != NONE && ++ program_transform_name="s&^&$program_prefix&;$program_transform_name" ++# Use a double $ so make ignores it. ++test "$program_suffix" != NONE && ++ program_transform_name="s&\$&$program_suffix&;$program_transform_name" ++# Double any \ or $. ++# By default was `s,x,x', remove it if useless. ++ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' ++program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` ++ ++# Expand $ac_aux_dir to an absolute path. ++am_aux_dir=`cd "$ac_aux_dir" && pwd` ++ ++if test x"${MISSING+set}" != xset; then ++ case $am_aux_dir in ++ *\ * | *\ *) ++ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; ++ *) ++ MISSING="\${SHELL} $am_aux_dir/missing" ;; ++ esac ++fi ++# Use eval to expand $SHELL ++if eval "$MISSING --is-lightweight"; then ++ am_missing_run="$MISSING " ++else ++ am_missing_run= ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 ++$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} ++fi ++ ++if test x"${install_sh+set}" != xset; then ++ case $am_aux_dir in ++ *\ * | *\ *) ++ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; ++ *) ++ install_sh="\${SHELL} $am_aux_dir/install-sh" ++ esac ++fi ++ ++# Installed binaries are usually stripped using 'strip' when the user ++# run "make install-strip". However 'strip' might not be the right ++# tool to use in cross-compilation environments, therefore Automake ++# will honor the 'STRIP' environment variable to overrule this program. ++if test "$cross_compiling" != no; then ++ if test -n "$ac_tool_prefix"; then ++ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. ++set dummy ${ac_tool_prefix}strip; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_STRIP+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$STRIP"; then ++ ac_cv_prog_STRIP="$STRIP" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_STRIP="${ac_tool_prefix}strip" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++STRIP=$ac_cv_prog_STRIP ++if test -n "$STRIP"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 ++$as_echo "$STRIP" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++fi ++if test -z "$ac_cv_prog_STRIP"; then ++ ac_ct_STRIP=$STRIP ++ # Extract the first word of "strip", so it can be a program name with args. ++set dummy strip; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_ac_ct_STRIP+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$ac_ct_STRIP"; then ++ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_ac_ct_STRIP="strip" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP ++if test -n "$ac_ct_STRIP"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 ++$as_echo "$ac_ct_STRIP" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ if test "x$ac_ct_STRIP" = x; then ++ STRIP=":" ++ else ++ case $cross_compiling:$ac_tool_warned in ++yes:) ++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 ++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ++ac_tool_warned=yes ;; ++esac ++ STRIP=$ac_ct_STRIP ++ fi ++else ++ STRIP="$ac_cv_prog_STRIP" ++fi ++ ++fi ++INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 ++$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } ++if test -z "$MKDIR_P"; then ++ if ${ac_cv_path_mkdir+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_prog in mkdir gmkdir; do ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue ++ case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( ++ 'mkdir (GNU coreutils) '* | \ ++ 'mkdir (coreutils) '* | \ ++ 'mkdir (fileutils) '4.1*) ++ ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext ++ break 3;; ++ esac ++ done ++ done ++ done ++IFS=$as_save_IFS ++ ++fi ++ ++ test -d ./--version && rmdir ./--version ++ if test "${ac_cv_path_mkdir+set}" = set; then ++ MKDIR_P="$ac_cv_path_mkdir -p" ++ else ++ # As a last resort, use the slow shell script. Don't cache a ++ # value for MKDIR_P within a source directory, because that will ++ # break other packages using the cache if that directory is ++ # removed, or if the value is a relative name. ++ MKDIR_P="$ac_install_sh -d" ++ fi ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 ++$as_echo "$MKDIR_P" >&6; } ++ ++for ac_prog in gawk mawk nawk awk ++do ++ # Extract the first word of "$ac_prog", so it can be a program name with args. ++set dummy $ac_prog; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_AWK+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$AWK"; then ++ ac_cv_prog_AWK="$AWK" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_AWK="$ac_prog" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++AWK=$ac_cv_prog_AWK ++if test -n "$AWK"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 ++$as_echo "$AWK" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++ test -n "$AWK" && break ++done ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 ++$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } ++set x ${MAKE-make} ++ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` ++if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ cat >conftest.make <<\_ACEOF ++SHELL = /bin/sh ++all: ++ @echo '@@@%%%=$(MAKE)=@@@%%%' ++_ACEOF ++# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. ++case `${MAKE-make} -f conftest.make 2>/dev/null` in ++ *@@@%%%=?*=@@@%%%*) ++ eval ac_cv_prog_make_${ac_make}_set=yes;; ++ *) ++ eval ac_cv_prog_make_${ac_make}_set=no;; ++esac ++rm -f conftest.make ++fi ++if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 ++$as_echo "yes" >&6; } ++ SET_MAKE= ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++ SET_MAKE="MAKE=${MAKE-make}" ++fi ++ ++rm -rf .tst 2>/dev/null ++mkdir .tst 2>/dev/null ++if test -d .tst; then ++ am__leading_dot=. ++else ++ am__leading_dot=_ ++fi ++rmdir .tst 2>/dev/null ++ ++# Check whether --enable-silent-rules was given. ++if test "${enable_silent_rules+set}" = set; then : ++ enableval=$enable_silent_rules; ++fi ++ ++case $enable_silent_rules in # ((( ++ yes) AM_DEFAULT_VERBOSITY=0;; ++ no) AM_DEFAULT_VERBOSITY=1;; ++ *) AM_DEFAULT_VERBOSITY=1;; ++esac ++am_make=${MAKE-make} ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 ++$as_echo_n "checking whether $am_make supports nested variables... " >&6; } ++if ${am_cv_make_support_nested_variables+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if $as_echo 'TRUE=$(BAR$(V)) ++BAR0=false ++BAR1=true ++V=1 ++am__doit: ++ @$(TRUE) ++.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then ++ am_cv_make_support_nested_variables=yes ++else ++ am_cv_make_support_nested_variables=no ++fi ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 ++$as_echo "$am_cv_make_support_nested_variables" >&6; } ++if test $am_cv_make_support_nested_variables = yes; then ++ AM_V='$(V)' ++ AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' ++else ++ AM_V=$AM_DEFAULT_VERBOSITY ++ AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY ++fi ++AM_BACKSLASH='\' ++ ++if test "`cd $srcdir && pwd`" != "`pwd`"; then ++ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output ++ # is not polluted with repeated "-I." ++ am__isrc=' -I$(srcdir)' ++ # test to see if srcdir already configured ++ if test -f $srcdir/config.status; then ++ as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 ++ fi ++fi ++ ++# test whether we have cygpath ++if test -z "$CYGPATH_W"; then ++ if (cygpath --version) >/dev/null 2>/dev/null; then ++ CYGPATH_W='cygpath -w' ++ else ++ CYGPATH_W=echo ++ fi ++fi ++ ++ ++# Define the identity of the package. ++ PACKAGE='bolt-plugin' ++ VERSION='0.1' ++ ++ ++cat >>confdefs.h <<_ACEOF ++#define PACKAGE "$PACKAGE" ++_ACEOF ++ ++ ++cat >>confdefs.h <<_ACEOF ++#define VERSION "$VERSION" ++_ACEOF ++ ++# Some tools Automake needs. ++ ++ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} ++ ++ ++AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} ++ ++ ++AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} ++ ++ ++AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} ++ ++ ++MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} ++ ++# For better backward compatibility. To be removed once Automake 1.9.x ++# dies out for good. For more background, see: ++# <https://lists.gnu.org/archive/html/automake/2012-07/msg00001.html> ++# <https://lists.gnu.org/archive/html/automake/2012-07/msg00014.html> ++mkdir_p='$(MKDIR_P)' ++ ++# We need awk for the "check" target (and possibly the TAP driver). The ++# system "awk" is bad on some platforms. ++# Always define AMTAR for backward compatibility. Yes, it's still used ++# in the wild :-( We should find a proper way to deprecate it ... ++AMTAR='$${TAR-tar}' ++ ++ ++# We'll loop over all known methods to create a tar archive until one works. ++_am_tools='gnutar pax cpio none' ++ ++am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' ++ ++ ++ ++ ++ ++ ++# POSIX will say in a future version that running "rm -f" with no argument ++# is OK; and we want to be able to make that assumption in our Makefile ++# recipes. So use an aggressive probe to check that the usage we want is ++# actually supported "in the wild" to an acceptable degree. ++# See automake bug#10828. ++# To make any issue more visible, cause the running configure to be aborted ++# by default if the 'rm' program in use doesn't match our expectations; the ++# user can still override this though. ++if rm -f && rm -fr && rm -rf; then : OK; else ++ cat >&2 <<'END' ++Oops! ++ ++Your 'rm' program seems unable to run without file operands specified ++on the command line, even when the '-f' option is present. This is contrary ++to the behaviour of most rm programs out there, and not conforming with ++the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542> ++ ++Please tell bug-automake@gnu.org about your system, including the value ++of your $PATH and any error possibly output before this message. This ++can help us improve future automake versions. ++ ++END ++ if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then ++ echo 'Configuration will proceed anyway, since you have set the' >&2 ++ echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 ++ echo >&2 ++ else ++ cat >&2 <<'END' ++Aborting the configuration process, to ensure you take notice of the issue. ++ ++You can download and install GNU coreutils to get an 'rm' implementation ++that behaves properly: <https://www.gnu.org/software/coreutils/>. ++ ++If you want to complete the configuration process using your problematic ++'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM ++to "yes", and re-run configure. ++ ++END ++ as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 ++ fi ++fi ++ ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 ++$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } ++ # Check whether --enable-maintainer-mode was given. ++if test "${enable_maintainer_mode+set}" = set; then : ++ enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval ++else ++ USE_MAINTAINER_MODE=no ++fi ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 ++$as_echo "$USE_MAINTAINER_MODE" >&6; } ++ if test $USE_MAINTAINER_MODE = yes; then ++ MAINTAINER_MODE_TRUE= ++ MAINTAINER_MODE_FALSE='#' ++else ++ MAINTAINER_MODE_TRUE='#' ++ MAINTAINER_MODE_FALSE= ++fi ++ ++ MAINT=$MAINTAINER_MODE_TRUE ++ ++ ++ ++# Check whether --with-libiberty was given. ++if test "${with_libiberty+set}" = set; then : ++ withval=$with_libiberty; ++else ++ with_libiberty=../libiberty ++fi ++ ++ ++DEPDIR="${am__leading_dot}deps" ++ ++ac_config_commands="$ac_config_commands depfiles" ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 ++$as_echo_n "checking whether ${MAKE-make} supports the include directive... " >&6; } ++cat > confinc.mk << 'END' ++am__doit: ++ @echo this is the am__doit target >confinc.out ++.PHONY: am__doit ++END ++am__include="#" ++am__quote= ++# BSD make does it like this. ++echo '.include "confinc.mk" # ignored' > confmf.BSD ++# Other make implementations (GNU, Solaris 10, AIX) do it like this. ++echo 'include confinc.mk # ignored' > confmf.GNU ++_am_result=no ++for s in GNU BSD; do ++ { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 ++ (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } ++ case $?:`cat confinc.out 2>/dev/null` in #( ++ '0:this is the am__doit target') : ++ case $s in #( ++ BSD) : ++ am__include='.include' am__quote='"' ;; #( ++ *) : ++ am__include='include' am__quote='' ;; ++esac ;; #( ++ *) : ++ ;; ++esac ++ if test "$am__include" != "#"; then ++ _am_result="yes ($s style)" ++ break ++ fi ++done ++rm -f confinc.* confmf.* ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 ++$as_echo "${_am_result}" >&6; } ++ ++# Check whether --enable-dependency-tracking was given. ++if test "${enable_dependency_tracking+set}" = set; then : ++ enableval=$enable_dependency_tracking; ++fi ++ ++if test "x$enable_dependency_tracking" != xno; then ++ am_depcomp="$ac_aux_dir/depcomp" ++ AMDEPBACKSLASH='\' ++ am__nodep='_no' ++fi ++ if test "x$enable_dependency_tracking" != xno; then ++ AMDEP_TRUE= ++ AMDEP_FALSE='#' ++else ++ AMDEP_TRUE='#' ++ AMDEP_FALSE= ++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 ++if test -n "$ac_tool_prefix"; then ++ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. ++set dummy ${ac_tool_prefix}gcc; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_CC+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$CC"; then ++ ac_cv_prog_CC="$CC" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_CC="${ac_tool_prefix}gcc" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++CC=$ac_cv_prog_CC ++if test -n "$CC"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 ++$as_echo "$CC" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++fi ++if test -z "$ac_cv_prog_CC"; then ++ ac_ct_CC=$CC ++ # Extract the first word of "gcc", so it can be a program name with args. ++set dummy gcc; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_ac_ct_CC+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$ac_ct_CC"; then ++ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_ac_ct_CC="gcc" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++ac_ct_CC=$ac_cv_prog_ac_ct_CC ++if test -n "$ac_ct_CC"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 ++$as_echo "$ac_ct_CC" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ if test "x$ac_ct_CC" = x; then ++ CC="" ++ else ++ case $cross_compiling:$ac_tool_warned in ++yes:) ++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 ++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ++ac_tool_warned=yes ;; ++esac ++ CC=$ac_ct_CC ++ fi ++else ++ CC="$ac_cv_prog_CC" ++fi ++ ++if test -z "$CC"; then ++ if test -n "$ac_tool_prefix"; then ++ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. ++set dummy ${ac_tool_prefix}cc; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_CC+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$CC"; then ++ ac_cv_prog_CC="$CC" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_CC="${ac_tool_prefix}cc" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++CC=$ac_cv_prog_CC ++if test -n "$CC"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 ++$as_echo "$CC" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++ fi ++fi ++if test -z "$CC"; then ++ # Extract the first word of "cc", so it can be a program name with args. ++set dummy cc; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_CC+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$CC"; then ++ ac_cv_prog_CC="$CC" # Let the user override the test. ++else ++ ac_prog_rejected=no ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ++ ac_prog_rejected=yes ++ continue ++ fi ++ ac_cv_prog_CC="cc" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++if test $ac_prog_rejected = yes; then ++ # We found a bogon in the path, so make sure we never use it. ++ set dummy $ac_cv_prog_CC ++ shift ++ if test $# != 0; then ++ # We chose a different compiler from the bogus one. ++ # However, it has the same basename, so the bogon will be chosen ++ # first if we set CC to just the basename; use the full file name. ++ shift ++ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" ++ fi ++fi ++fi ++fi ++CC=$ac_cv_prog_CC ++if test -n "$CC"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 ++$as_echo "$CC" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++fi ++if test -z "$CC"; then ++ if test -n "$ac_tool_prefix"; then ++ for ac_prog in cl.exe ++ do ++ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. ++set dummy $ac_tool_prefix$ac_prog; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_CC+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$CC"; then ++ ac_cv_prog_CC="$CC" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_CC="$ac_tool_prefix$ac_prog" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++CC=$ac_cv_prog_CC ++if test -n "$CC"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 ++$as_echo "$CC" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++ test -n "$CC" && break ++ done ++fi ++if test -z "$CC"; then ++ ac_ct_CC=$CC ++ for ac_prog in cl.exe ++do ++ # Extract the first word of "$ac_prog", so it can be a program name with args. ++set dummy $ac_prog; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_ac_ct_CC+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$ac_ct_CC"; then ++ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_ac_ct_CC="$ac_prog" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++ac_ct_CC=$ac_cv_prog_ac_ct_CC ++if test -n "$ac_ct_CC"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 ++$as_echo "$ac_ct_CC" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++ test -n "$ac_ct_CC" && break ++done ++ ++ if test "x$ac_ct_CC" = x; then ++ CC="" ++ else ++ case $cross_compiling:$ac_tool_warned in ++yes:) ++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 ++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ++ac_tool_warned=yes ;; ++esac ++ CC=$ac_ct_CC ++ fi ++fi ++ ++fi ++ ++ ++test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++as_fn_error $? "no acceptable C compiler found in \$PATH ++See \`config.log' for more details" "$LINENO" 5; } ++ ++# Provide some information about the compiler. ++$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 ++set X $ac_compile ++ac_compiler=$2 ++for ac_option in --version -v -V -qversion; do ++ { { ac_try="$ac_compiler $ac_option >&5" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" ++$as_echo "$ac_try_echo"; } >&5 ++ (eval "$ac_compiler $ac_option >&5") 2>conftest.err ++ ac_status=$? ++ if test -s conftest.err; then ++ sed '10a\ ++... rest of stderr output deleted ... ++ 10q' conftest.err >conftest.er1 ++ cat conftest.er1 >&5 ++ fi ++ rm -f conftest.er1 conftest.err ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; } ++done ++ ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++ac_clean_files_save=$ac_clean_files ++ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" ++# Try to create an executable without -o first, disregard a.out. ++# It will help us diagnose broken compilers, and finding out an intuition ++# of exeext. ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 ++$as_echo_n "checking whether the C compiler works... " >&6; } ++ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` ++ ++# The possible output files: ++ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ++ ++ac_rmfiles= ++for ac_file in $ac_files ++do ++ case $ac_file in ++ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; ++ * ) ac_rmfiles="$ac_rmfiles $ac_file";; ++ esac ++done ++rm -f $ac_rmfiles ++ ++if { { ac_try="$ac_link_default" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" ++$as_echo "$ac_try_echo"; } >&5 ++ (eval "$ac_link_default") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; }; then : ++ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. ++# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' ++# in a Makefile. We should not override ac_cv_exeext if it was cached, ++# so that the user can short-circuit this test for compilers unknown to ++# Autoconf. ++for ac_file in $ac_files '' ++do ++ test -f "$ac_file" || continue ++ case $ac_file in ++ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ++ ;; ++ [ab].out ) ++ # We found the default executable, but exeext='' is most ++ # certainly right. ++ break;; ++ *.* ) ++ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; ++ then :; else ++ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` ++ fi ++ # We set ac_cv_exeext here because the later test for it is not ++ # safe: cross compilers may not add the suffix if given an `-o' ++ # argument, so we may need to know it at that point already. ++ # Even if this section looks crufty: it has the advantage of ++ # actually working. ++ break;; ++ * ) ++ break;; ++ esac ++done ++test "$ac_cv_exeext" = no && ac_cv_exeext= ++ ++else ++ ac_file='' ++fi ++if test -z "$ac_file"; then : ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++$as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++as_fn_error 77 "C compiler cannot create executables ++See \`config.log' for more details" "$LINENO" 5; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 ++$as_echo "yes" >&6; } ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 ++$as_echo_n "checking for C compiler default output file name... " >&6; } ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 ++$as_echo "$ac_file" >&6; } ++ac_exeext=$ac_cv_exeext ++ ++rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ++ac_clean_files=$ac_clean_files_save ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 ++$as_echo_n "checking for suffix of executables... " >&6; } ++if { { ac_try="$ac_link" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" ++$as_echo "$ac_try_echo"; } >&5 ++ (eval "$ac_link") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; }; then : ++ # If both `conftest.exe' and `conftest' are `present' (well, observable) ++# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will ++# work properly (i.e., refer to `conftest.exe'), while it won't with ++# `rm'. ++for ac_file in conftest.exe conftest conftest.*; do ++ test -f "$ac_file" || continue ++ case $ac_file in ++ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; ++ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` ++ break;; ++ * ) break;; ++ esac ++done ++else ++ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++as_fn_error $? "cannot compute suffix of executables: cannot compile and link ++See \`config.log' for more details" "$LINENO" 5; } ++fi ++rm -f conftest conftest$ac_cv_exeext ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 ++$as_echo "$ac_cv_exeext" >&6; } ++ ++rm -f conftest.$ac_ext ++EXEEXT=$ac_cv_exeext ++ac_exeext=$EXEEXT ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#include <stdio.h> ++int ++main () ++{ ++FILE *f = fopen ("conftest.out", "w"); ++ return ferror (f) || fclose (f) != 0; ++ ++ ; ++ return 0; ++} ++_ACEOF ++ac_clean_files="$ac_clean_files conftest.out" ++# Check that the compiler produces executables we can run. If not, either ++# the compiler is broken, or we cross compile. ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 ++$as_echo_n "checking whether we are cross compiling... " >&6; } ++if test "$cross_compiling" != yes; then ++ { { ac_try="$ac_link" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" ++$as_echo "$ac_try_echo"; } >&5 ++ (eval "$ac_link") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; } ++ if { ac_try='./conftest$ac_cv_exeext' ++ { { case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" ++$as_echo "$ac_try_echo"; } >&5 ++ (eval "$ac_try") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; }; }; then ++ cross_compiling=no ++ else ++ if test "$cross_compiling" = maybe; then ++ cross_compiling=yes ++ else ++ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++as_fn_error $? "cannot run C compiled programs. ++If you meant to cross compile, use \`--host'. ++See \`config.log' for more details" "$LINENO" 5; } ++ fi ++ fi ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 ++$as_echo "$cross_compiling" >&6; } ++ ++rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ++ac_clean_files=$ac_clean_files_save ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 ++$as_echo_n "checking for suffix of object files... " >&6; } ++if ${ac_cv_objext+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++rm -f conftest.o conftest.obj ++if { { ac_try="$ac_compile" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" ++$as_echo "$ac_try_echo"; } >&5 ++ (eval "$ac_compile") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; }; then : ++ for ac_file in conftest.o conftest.obj conftest.*; do ++ test -f "$ac_file" || continue; ++ case $ac_file in ++ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; ++ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` ++ break;; ++ esac ++done ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++as_fn_error $? "cannot compute suffix of object files: cannot compile ++See \`config.log' for more details" "$LINENO" 5; } ++fi ++rm -f conftest.$ac_cv_objext conftest.$ac_ext ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 ++$as_echo "$ac_cv_objext" >&6; } ++OBJEXT=$ac_cv_objext ++ac_objext=$OBJEXT ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 ++$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } ++if ${ac_cv_c_compiler_gnu+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++#ifndef __GNUC__ ++ choke me ++#endif ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ ac_compiler_gnu=yes ++else ++ ac_compiler_gnu=no ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ac_cv_c_compiler_gnu=$ac_compiler_gnu ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 ++$as_echo "$ac_cv_c_compiler_gnu" >&6; } ++if test $ac_compiler_gnu = yes; then ++ GCC=yes ++else ++ GCC= ++fi ++ac_test_CFLAGS=${CFLAGS+set} ++ac_save_CFLAGS=$CFLAGS ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 ++$as_echo_n "checking whether $CC accepts -g... " >&6; } ++if ${ac_cv_prog_cc_g+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_save_c_werror_flag=$ac_c_werror_flag ++ ac_c_werror_flag=yes ++ ac_cv_prog_cc_g=no ++ CFLAGS="-g" ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ ac_cv_prog_cc_g=yes ++else ++ CFLAGS="" ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ ++else ++ ac_c_werror_flag=$ac_save_c_werror_flag ++ CFLAGS="-g" ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ ac_cv_prog_cc_g=yes ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ ac_c_werror_flag=$ac_save_c_werror_flag ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 ++$as_echo "$ac_cv_prog_cc_g" >&6; } ++if test "$ac_test_CFLAGS" = set; then ++ CFLAGS=$ac_save_CFLAGS ++elif test $ac_cv_prog_cc_g = yes; then ++ if test "$GCC" = yes; then ++ CFLAGS="-g -O2" ++ else ++ CFLAGS="-g" ++ fi ++else ++ if test "$GCC" = yes; then ++ CFLAGS="-O2" ++ else ++ CFLAGS= ++ fi ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 ++$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } ++if ${ac_cv_prog_cc_c89+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_cv_prog_cc_c89=no ++ac_save_CC=$CC ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#include <stdarg.h> ++#include <stdio.h> ++struct stat; ++/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ ++struct buf { int x; }; ++FILE * (*rcsopen) (struct buf *, struct stat *, int); ++static char *e (p, i) ++ char **p; ++ int i; ++{ ++ return p[i]; ++} ++static char *f (char * (*g) (char **, int), char **p, ...) ++{ ++ char *s; ++ va_list v; ++ va_start (v,p); ++ s = g (p, va_arg (v,int)); ++ va_end (v); ++ return s; ++} ++ ++/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has ++ function prototypes and stuff, but not '\xHH' hex character constants. ++ These don't provoke an error unfortunately, instead are silently treated ++ as 'x'. The following induces an error, until -std is added to get ++ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an ++ array size at least. It's necessary to write '\x00'==0 to get something ++ that's true only with -std. */ ++int osf4_cc_array ['\x00' == 0 ? 1 : -1]; ++ ++/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters ++ inside strings and character constants. */ ++#define FOO(x) 'x' ++int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; ++ ++int test (int i, double x); ++struct s1 {int (*f) (int a);}; ++struct s2 {int (*f) (double a);}; ++int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); ++int argc; ++char **argv; ++int ++main () ++{ ++return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ++ ; ++ return 0; ++} ++_ACEOF ++for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ ++ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" ++do ++ CC="$ac_save_CC $ac_arg" ++ if ac_fn_c_try_compile "$LINENO"; then : ++ ac_cv_prog_cc_c89=$ac_arg ++fi ++rm -f core conftest.err conftest.$ac_objext ++ test "x$ac_cv_prog_cc_c89" != "xno" && break ++done ++rm -f conftest.$ac_ext ++CC=$ac_save_CC ++ ++fi ++# AC_CACHE_VAL ++case "x$ac_cv_prog_cc_c89" in ++ x) ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 ++$as_echo "none needed" >&6; } ;; ++ xno) ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 ++$as_echo "unsupported" >&6; } ;; ++ *) ++ CC="$CC $ac_cv_prog_cc_c89" ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 ++$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; ++esac ++if test "x$ac_cv_prog_cc_c89" != xno; then : ++ ++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 ++ ++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 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 ++$as_echo_n "checking whether $CC understands -c and -o together... " >&6; } ++if ${am_cv_prog_cc_c_o+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++ # Make sure it works both with $CC and with simple cc. ++ # Following AC_PROG_CC_C_O, we do the test twice because some ++ # compilers refuse to overwrite an existing .o file with -o, ++ # though they will create one. ++ am_cv_prog_cc_c_o=yes ++ for am_i in 1 2; do ++ if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ++ ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } \ ++ && test -f conftest2.$ac_objext; then ++ : OK ++ else ++ am_cv_prog_cc_c_o=no ++ break ++ fi ++ done ++ rm -f core conftest* ++ unset am_i ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 ++$as_echo "$am_cv_prog_cc_c_o" >&6; } ++if test "$am_cv_prog_cc_c_o" != yes; then ++ # Losing compiler, so override with the script. ++ # FIXME: It is wrong to rewrite CC. ++ # But if we don't then we get into trouble of one sort or another. ++ # A longer-term fix would be to have automake use am__CC in this case, ++ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" ++ CC="$am_aux_dir/compile $CC" ++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 ++ ++ ++depcc="$CC" am_compiler_list= ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 ++$as_echo_n "checking dependency style of $depcc... " >&6; } ++if ${am_cv_CC_dependencies_compiler_type+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then ++ # We make a subdir and do the tests there. Otherwise we can end up ++ # making bogus files that we don't know about and never remove. For ++ # instance it was reported that on HP-UX the gcc test will end up ++ # making a dummy file named 'D' -- because '-MD' means "put the output ++ # in D". ++ rm -rf conftest.dir ++ mkdir conftest.dir ++ # Copy depcomp to subdir because otherwise we won't find it if we're ++ # using a relative directory. ++ cp "$am_depcomp" conftest.dir ++ cd conftest.dir ++ # We will build objects and dependencies in a subdirectory because ++ # it helps to detect inapplicable dependency modes. For instance ++ # both Tru64's cc and ICC support -MD to output dependencies as a ++ # side effect of compilation, but ICC will put the dependencies in ++ # the current directory while Tru64 will put them in the object ++ # directory. ++ mkdir sub ++ ++ am_cv_CC_dependencies_compiler_type=none ++ if test "$am_compiler_list" = ""; then ++ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` ++ fi ++ am__universal=false ++ case " $depcc " in #( ++ *\ -arch\ *\ -arch\ *) am__universal=true ;; ++ esac ++ ++ for depmode in $am_compiler_list; do ++ # Setup a source with many dependencies, because some compilers ++ # like to wrap large dependency lists on column 80 (with \), and ++ # we should not choose a depcomp mode which is confused by this. ++ # ++ # We need to recreate these files for each test, as the compiler may ++ # overwrite some of them when testing with obscure command lines. ++ # This happens at least with the AIX C compiler. ++ : > sub/conftest.c ++ for i in 1 2 3 4 5 6; do ++ echo '#include "conftst'$i'.h"' >> sub/conftest.c ++ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with ++ # Solaris 10 /bin/sh. ++ echo '/* dummy */' > sub/conftst$i.h ++ done ++ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf ++ ++ # We check with '-c' and '-o' for the sake of the "dashmstdout" ++ # mode. It turns out that the SunPro C++ compiler does not properly ++ # handle '-M -o', and we need to detect this. Also, some Intel ++ # versions had trouble with output in subdirs. ++ am__obj=sub/conftest.${OBJEXT-o} ++ am__minus_obj="-o $am__obj" ++ case $depmode in ++ gcc) ++ # This depmode causes a compiler race in universal mode. ++ test "$am__universal" = false || continue ++ ;; ++ nosideeffect) ++ # After this tag, mechanisms are not by side-effect, so they'll ++ # only be used when explicitly requested. ++ if test "x$enable_dependency_tracking" = xyes; then ++ continue ++ else ++ break ++ fi ++ ;; ++ msvc7 | msvc7msys | msvisualcpp | msvcmsys) ++ # This compiler won't grok '-c -o', but also, the minuso test has ++ # not run yet. These depmodes are late enough in the game, and ++ # so weak that their functioning should not be impacted. ++ am__obj=conftest.${OBJEXT-o} ++ am__minus_obj= ++ ;; ++ none) break ;; ++ esac ++ if depmode=$depmode \ ++ source=sub/conftest.c object=$am__obj \ ++ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ ++ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ ++ >/dev/null 2>conftest.err && ++ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && ++ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && ++ grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ++ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then ++ # icc doesn't choke on unknown options, it will just issue warnings ++ # or remarks (even with -Werror). So we grep stderr for any message ++ # that says an option was ignored or not supported. ++ # When given -MP, icc 7.0 and 7.1 complain thusly: ++ # icc: Command line warning: ignoring option '-M'; no argument required ++ # The diagnosis changed in icc 8.0: ++ # icc: Command line remark: option '-MP' not supported ++ if (grep 'ignoring option' conftest.err || ++ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else ++ am_cv_CC_dependencies_compiler_type=$depmode ++ break ++ fi ++ fi ++ done ++ ++ cd .. ++ rm -rf conftest.dir ++else ++ am_cv_CC_dependencies_compiler_type=none ++fi ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 ++$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } ++CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type ++ ++ if ++ test "x$enable_dependency_tracking" != xno \ ++ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then ++ am__fastdepCC_TRUE= ++ am__fastdepCC_FALSE='#' ++else ++ am__fastdepCC_TRUE='#' ++ am__fastdepCC_FALSE= ++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 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 ++$as_echo_n "checking how to run the C preprocessor... " >&6; } ++# On Suns, sometimes $CPP names a directory. ++if test -n "$CPP" && test -d "$CPP"; then ++ CPP= ++fi ++if test -z "$CPP"; then ++ if ${ac_cv_prog_CPP+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ # Double quotes because CPP needs to be expanded ++ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" ++ do ++ ac_preproc_ok=false ++for ac_c_preproc_warn_flag in '' yes ++do ++ # Use a header file that comes with gcc, so configuring glibc ++ # with a fresh cross-compiler works. ++ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since ++ # <limits.h> exists even on freestanding compilers. ++ # On the NeXT, cc -E runs the code through the compiler's parser, ++ # not just through cpp. "Syntax error" is here to catch this case. ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#ifdef __STDC__ ++# include <limits.h> ++#else ++# include <assert.h> ++#endif ++ Syntax error ++_ACEOF ++if ac_fn_c_try_cpp "$LINENO"; then : ++ ++else ++ # Broken: fails on valid input. ++continue ++fi ++rm -f conftest.err conftest.i conftest.$ac_ext ++ ++ # OK, works on sane cases. Now check whether nonexistent headers ++ # can be detected and how. ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#include <ac_nonexistent.h> ++_ACEOF ++if ac_fn_c_try_cpp "$LINENO"; then : ++ # Broken: success on invalid input. ++continue ++else ++ # Passes both tests. ++ac_preproc_ok=: ++break ++fi ++rm -f conftest.err conftest.i conftest.$ac_ext ++ ++done ++# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. ++rm -f conftest.i conftest.err conftest.$ac_ext ++if $ac_preproc_ok; then : ++ break ++fi ++ ++ done ++ ac_cv_prog_CPP=$CPP ++ ++fi ++ CPP=$ac_cv_prog_CPP ++else ++ ac_cv_prog_CPP=$CPP ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 ++$as_echo "$CPP" >&6; } ++ac_preproc_ok=false ++for ac_c_preproc_warn_flag in '' yes ++do ++ # Use a header file that comes with gcc, so configuring glibc ++ # with a fresh cross-compiler works. ++ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since ++ # <limits.h> exists even on freestanding compilers. ++ # On the NeXT, cc -E runs the code through the compiler's parser, ++ # not just through cpp. "Syntax error" is here to catch this case. ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#ifdef __STDC__ ++# include <limits.h> ++#else ++# include <assert.h> ++#endif ++ Syntax error ++_ACEOF ++if ac_fn_c_try_cpp "$LINENO"; then : ++ ++else ++ # Broken: fails on valid input. ++continue ++fi ++rm -f conftest.err conftest.i conftest.$ac_ext ++ ++ # OK, works on sane cases. Now check whether nonexistent headers ++ # can be detected and how. ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#include <ac_nonexistent.h> ++_ACEOF ++if ac_fn_c_try_cpp "$LINENO"; then : ++ # Broken: success on invalid input. ++continue ++else ++ # Passes both tests. ++ac_preproc_ok=: ++break ++fi ++rm -f conftest.err conftest.i conftest.$ac_ext ++ ++done ++# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. ++rm -f conftest.i conftest.err conftest.$ac_ext ++if $ac_preproc_ok; then : ++ ++else ++ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++as_fn_error $? "C preprocessor \"$CPP\" fails sanity check ++See \`config.log' for more details" "$LINENO" 5; } ++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 ++ ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 ++$as_echo_n "checking for grep that handles long lines and -e... " >&6; } ++if ${ac_cv_path_GREP+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -z "$GREP"; then ++ ac_path_GREP_found=false ++ # Loop through the user's path and test for each of PROGNAME-LIST ++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_prog in grep ggrep; do ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" ++ as_fn_executable_p "$ac_path_GREP" || continue ++# Check for GNU ac_path_GREP and select it if it is found. ++ # Check for GNU $ac_path_GREP ++case `"$ac_path_GREP" --version 2>&1` in ++*GNU*) ++ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; ++*) ++ ac_count=0 ++ $as_echo_n 0123456789 >"conftest.in" ++ while : ++ do ++ cat "conftest.in" "conftest.in" >"conftest.tmp" ++ mv "conftest.tmp" "conftest.in" ++ cp "conftest.in" "conftest.nl" ++ $as_echo 'GREP' >> "conftest.nl" ++ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break ++ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break ++ as_fn_arith $ac_count + 1 && ac_count=$as_val ++ if test $ac_count -gt ${ac_path_GREP_max-0}; then ++ # Best one so far, save it but keep looking for a better one ++ ac_cv_path_GREP="$ac_path_GREP" ++ ac_path_GREP_max=$ac_count ++ fi ++ # 10*(2^10) chars as input seems more than enough ++ test $ac_count -gt 10 && break ++ done ++ rm -f conftest.in conftest.tmp conftest.nl conftest.out;; ++esac ++ ++ $ac_path_GREP_found && break 3 ++ done ++ done ++ done ++IFS=$as_save_IFS ++ if test -z "$ac_cv_path_GREP"; then ++ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 ++ fi ++else ++ ac_cv_path_GREP=$GREP ++fi ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 ++$as_echo "$ac_cv_path_GREP" >&6; } ++ GREP="$ac_cv_path_GREP" ++ ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 ++$as_echo_n "checking for egrep... " >&6; } ++if ${ac_cv_path_EGREP+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 ++ then ac_cv_path_EGREP="$GREP -E" ++ else ++ if test -z "$EGREP"; then ++ ac_path_EGREP_found=false ++ # Loop through the user's path and test for each of PROGNAME-LIST ++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_prog in egrep; do ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" ++ as_fn_executable_p "$ac_path_EGREP" || continue ++# Check for GNU ac_path_EGREP and select it if it is found. ++ # Check for GNU $ac_path_EGREP ++case `"$ac_path_EGREP" --version 2>&1` in ++*GNU*) ++ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; ++*) ++ ac_count=0 ++ $as_echo_n 0123456789 >"conftest.in" ++ while : ++ do ++ cat "conftest.in" "conftest.in" >"conftest.tmp" ++ mv "conftest.tmp" "conftest.in" ++ cp "conftest.in" "conftest.nl" ++ $as_echo 'EGREP' >> "conftest.nl" ++ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break ++ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break ++ as_fn_arith $ac_count + 1 && ac_count=$as_val ++ if test $ac_count -gt ${ac_path_EGREP_max-0}; then ++ # Best one so far, save it but keep looking for a better one ++ ac_cv_path_EGREP="$ac_path_EGREP" ++ ac_path_EGREP_max=$ac_count ++ fi ++ # 10*(2^10) chars as input seems more than enough ++ test $ac_count -gt 10 && break ++ done ++ rm -f conftest.in conftest.tmp conftest.nl conftest.out;; ++esac ++ ++ $ac_path_EGREP_found && break 3 ++ done ++ done ++ done ++IFS=$as_save_IFS ++ if test -z "$ac_cv_path_EGREP"; then ++ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 ++ fi ++else ++ ac_cv_path_EGREP=$EGREP ++fi ++ ++ fi ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 ++$as_echo "$ac_cv_path_EGREP" >&6; } ++ EGREP="$ac_cv_path_EGREP" ++ ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 ++$as_echo_n "checking for ANSI C header files... " >&6; } ++if ${ac_cv_header_stdc+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#include <stdlib.h> ++#include <stdarg.h> ++#include <string.h> ++#include <float.h> ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ ac_cv_header_stdc=yes ++else ++ ac_cv_header_stdc=no ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ ++if test $ac_cv_header_stdc = yes; then ++ # SunOS 4.x string.h does not declare mem*, contrary to ANSI. ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#include <string.h> ++ ++_ACEOF ++if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | ++ $EGREP "memchr" >/dev/null 2>&1; then : ++ ++else ++ ac_cv_header_stdc=no ++fi ++rm -f conftest* ++ ++fi ++ ++if test $ac_cv_header_stdc = yes; then ++ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#include <stdlib.h> ++ ++_ACEOF ++if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | ++ $EGREP "free" >/dev/null 2>&1; then : ++ ++else ++ ac_cv_header_stdc=no ++fi ++rm -f conftest* ++ ++fi ++ ++if test $ac_cv_header_stdc = yes; then ++ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. ++ if test "$cross_compiling" = yes; then : ++ : ++else ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#include <ctype.h> ++#include <stdlib.h> ++#if ((' ' & 0x0FF) == 0x020) ++# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') ++# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) ++#else ++# define ISLOWER(c) \ ++ (('a' <= (c) && (c) <= 'i') \ ++ || ('j' <= (c) && (c) <= 'r') \ ++ || ('s' <= (c) && (c) <= 'z')) ++# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) ++#endif ++ ++#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) ++int ++main () ++{ ++ int i; ++ for (i = 0; i < 256; i++) ++ if (XOR (islower (i), ISLOWER (i)) ++ || toupper (i) != TOUPPER (i)) ++ return 2; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_run "$LINENO"; then : ++ ++else ++ ac_cv_header_stdc=no ++fi ++rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ ++ conftest.$ac_objext conftest.beam conftest.$ac_ext ++fi ++ ++fi ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 ++$as_echo "$ac_cv_header_stdc" >&6; } ++if test $ac_cv_header_stdc = yes; then ++ ++$as_echo "#define STDC_HEADERS 1" >>confdefs.h ++ ++fi ++ ++# On IRIX 5.3, sys/types and inttypes.h are conflicting. ++for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ ++ inttypes.h stdint.h unistd.h ++do : ++ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ++ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default ++" ++if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : ++ cat >>confdefs.h <<_ACEOF ++#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 ++_ACEOF ++ ++fi ++ ++done ++ ++ ++ ++ ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" ++if test "x$ac_cv_header_minix_config_h" = xyes; then : ++ MINIX=yes ++else ++ MINIX= ++fi ++ ++ ++ if test "$MINIX" = yes; then ++ ++$as_echo "#define _POSIX_SOURCE 1" >>confdefs.h ++ ++ ++$as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h ++ ++ ++$as_echo "#define _MINIX 1" >>confdefs.h ++ ++ fi ++ ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 ++$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } ++if ${ac_cv_safe_to_define___extensions__+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++# define __EXTENSIONS__ 1 ++ $ac_includes_default ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ ac_cv_safe_to_define___extensions__=yes ++else ++ ac_cv_safe_to_define___extensions__=no ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 ++$as_echo "$ac_cv_safe_to_define___extensions__" >&6; } ++ test $ac_cv_safe_to_define___extensions__ = yes && ++ $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h ++ ++ $as_echo "#define _ALL_SOURCE 1" >>confdefs.h ++ ++ $as_echo "#define _GNU_SOURCE 1" >>confdefs.h ++ ++ $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h ++ ++ $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h ++ ++ ++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 ++if test -n "$ac_tool_prefix"; then ++ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. ++set dummy ${ac_tool_prefix}gcc; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_CC+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$CC"; then ++ ac_cv_prog_CC="$CC" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_CC="${ac_tool_prefix}gcc" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++CC=$ac_cv_prog_CC ++if test -n "$CC"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 ++$as_echo "$CC" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++fi ++if test -z "$ac_cv_prog_CC"; then ++ ac_ct_CC=$CC ++ # Extract the first word of "gcc", so it can be a program name with args. ++set dummy gcc; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_ac_ct_CC+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$ac_ct_CC"; then ++ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_ac_ct_CC="gcc" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++ac_ct_CC=$ac_cv_prog_ac_ct_CC ++if test -n "$ac_ct_CC"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 ++$as_echo "$ac_ct_CC" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ if test "x$ac_ct_CC" = x; then ++ CC="" ++ else ++ case $cross_compiling:$ac_tool_warned in ++yes:) ++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 ++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ++ac_tool_warned=yes ;; ++esac ++ CC=$ac_ct_CC ++ fi ++else ++ CC="$ac_cv_prog_CC" ++fi ++ ++if test -z "$CC"; then ++ if test -n "$ac_tool_prefix"; then ++ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. ++set dummy ${ac_tool_prefix}cc; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_CC+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$CC"; then ++ ac_cv_prog_CC="$CC" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_CC="${ac_tool_prefix}cc" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++CC=$ac_cv_prog_CC ++if test -n "$CC"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 ++$as_echo "$CC" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++ fi ++fi ++if test -z "$CC"; then ++ # Extract the first word of "cc", so it can be a program name with args. ++set dummy cc; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_CC+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$CC"; then ++ ac_cv_prog_CC="$CC" # Let the user override the test. ++else ++ ac_prog_rejected=no ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ++ ac_prog_rejected=yes ++ continue ++ fi ++ ac_cv_prog_CC="cc" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++if test $ac_prog_rejected = yes; then ++ # We found a bogon in the path, so make sure we never use it. ++ set dummy $ac_cv_prog_CC ++ shift ++ if test $# != 0; then ++ # We chose a different compiler from the bogus one. ++ # However, it has the same basename, so the bogon will be chosen ++ # first if we set CC to just the basename; use the full file name. ++ shift ++ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" ++ fi ++fi ++fi ++fi ++CC=$ac_cv_prog_CC ++if test -n "$CC"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 ++$as_echo "$CC" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++fi ++if test -z "$CC"; then ++ if test -n "$ac_tool_prefix"; then ++ for ac_prog in cl.exe ++ do ++ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. ++set dummy $ac_tool_prefix$ac_prog; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_CC+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$CC"; then ++ ac_cv_prog_CC="$CC" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_CC="$ac_tool_prefix$ac_prog" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++CC=$ac_cv_prog_CC ++if test -n "$CC"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 ++$as_echo "$CC" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++ test -n "$CC" && break ++ done ++fi ++if test -z "$CC"; then ++ ac_ct_CC=$CC ++ for ac_prog in cl.exe ++do ++ # Extract the first word of "$ac_prog", so it can be a program name with args. ++set dummy $ac_prog; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_ac_ct_CC+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$ac_ct_CC"; then ++ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_ac_ct_CC="$ac_prog" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++ac_ct_CC=$ac_cv_prog_ac_ct_CC ++if test -n "$ac_ct_CC"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 ++$as_echo "$ac_ct_CC" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++ test -n "$ac_ct_CC" && break ++done ++ ++ if test "x$ac_ct_CC" = x; then ++ CC="" ++ else ++ case $cross_compiling:$ac_tool_warned in ++yes:) ++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 ++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ++ac_tool_warned=yes ;; ++esac ++ CC=$ac_ct_CC ++ fi ++fi ++ ++fi ++ ++ ++test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++as_fn_error $? "no acceptable C compiler found in \$PATH ++See \`config.log' for more details" "$LINENO" 5; } ++ ++# Provide some information about the compiler. ++$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 ++set X $ac_compile ++ac_compiler=$2 ++for ac_option in --version -v -V -qversion; do ++ { { ac_try="$ac_compiler $ac_option >&5" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" ++$as_echo "$ac_try_echo"; } >&5 ++ (eval "$ac_compiler $ac_option >&5") 2>conftest.err ++ ac_status=$? ++ if test -s conftest.err; then ++ sed '10a\ ++... rest of stderr output deleted ... ++ 10q' conftest.err >conftest.er1 ++ cat conftest.er1 >&5 ++ fi ++ rm -f conftest.er1 conftest.err ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; } ++done ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 ++$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } ++if ${ac_cv_c_compiler_gnu+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++#ifndef __GNUC__ ++ choke me ++#endif ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ ac_compiler_gnu=yes ++else ++ ac_compiler_gnu=no ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ac_cv_c_compiler_gnu=$ac_compiler_gnu ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 ++$as_echo "$ac_cv_c_compiler_gnu" >&6; } ++if test $ac_compiler_gnu = yes; then ++ GCC=yes ++else ++ GCC= ++fi ++ac_test_CFLAGS=${CFLAGS+set} ++ac_save_CFLAGS=$CFLAGS ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 ++$as_echo_n "checking whether $CC accepts -g... " >&6; } ++if ${ac_cv_prog_cc_g+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_save_c_werror_flag=$ac_c_werror_flag ++ ac_c_werror_flag=yes ++ ac_cv_prog_cc_g=no ++ CFLAGS="-g" ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ ac_cv_prog_cc_g=yes ++else ++ CFLAGS="" ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ ++else ++ ac_c_werror_flag=$ac_save_c_werror_flag ++ CFLAGS="-g" ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ ac_cv_prog_cc_g=yes ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ ac_c_werror_flag=$ac_save_c_werror_flag ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 ++$as_echo "$ac_cv_prog_cc_g" >&6; } ++if test "$ac_test_CFLAGS" = set; then ++ CFLAGS=$ac_save_CFLAGS ++elif test $ac_cv_prog_cc_g = yes; then ++ if test "$GCC" = yes; then ++ CFLAGS="-g -O2" ++ else ++ CFLAGS="-g" ++ fi ++else ++ if test "$GCC" = yes; then ++ CFLAGS="-O2" ++ else ++ CFLAGS= ++ fi ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 ++$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } ++if ${ac_cv_prog_cc_c89+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_cv_prog_cc_c89=no ++ac_save_CC=$CC ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#include <stdarg.h> ++#include <stdio.h> ++struct stat; ++/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ ++struct buf { int x; }; ++FILE * (*rcsopen) (struct buf *, struct stat *, int); ++static char *e (p, i) ++ char **p; ++ int i; ++{ ++ return p[i]; ++} ++static char *f (char * (*g) (char **, int), char **p, ...) ++{ ++ char *s; ++ va_list v; ++ va_start (v,p); ++ s = g (p, va_arg (v,int)); ++ va_end (v); ++ return s; ++} ++ ++/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has ++ function prototypes and stuff, but not '\xHH' hex character constants. ++ These don't provoke an error unfortunately, instead are silently treated ++ as 'x'. The following induces an error, until -std is added to get ++ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an ++ array size at least. It's necessary to write '\x00'==0 to get something ++ that's true only with -std. */ ++int osf4_cc_array ['\x00' == 0 ? 1 : -1]; ++ ++/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters ++ inside strings and character constants. */ ++#define FOO(x) 'x' ++int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; ++ ++int test (int i, double x); ++struct s1 {int (*f) (int a);}; ++struct s2 {int (*f) (double a);}; ++int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); ++int argc; ++char **argv; ++int ++main () ++{ ++return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ++ ; ++ return 0; ++} ++_ACEOF ++for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ ++ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" ++do ++ CC="$ac_save_CC $ac_arg" ++ if ac_fn_c_try_compile "$LINENO"; then : ++ ac_cv_prog_cc_c89=$ac_arg ++fi ++rm -f core conftest.err conftest.$ac_objext ++ test "x$ac_cv_prog_cc_c89" != "xno" && break ++done ++rm -f conftest.$ac_ext ++CC=$ac_save_CC ++ ++fi ++# AC_CACHE_VAL ++case "x$ac_cv_prog_cc_c89" in ++ x) ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 ++$as_echo "none needed" >&6; } ;; ++ xno) ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 ++$as_echo "unsupported" >&6; } ;; ++ *) ++ CC="$CC $ac_cv_prog_cc_c89" ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 ++$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; ++esac ++if test "x$ac_cv_prog_cc_c89" != xno; then : ++ ++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 ++ ++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 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 ++$as_echo_n "checking whether $CC understands -c and -o together... " >&6; } ++if ${am_cv_prog_cc_c_o+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++ # Make sure it works both with $CC and with simple cc. ++ # Following AC_PROG_CC_C_O, we do the test twice because some ++ # compilers refuse to overwrite an existing .o file with -o, ++ # though they will create one. ++ am_cv_prog_cc_c_o=yes ++ for am_i in 1 2; do ++ if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ++ ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } \ ++ && test -f conftest2.$ac_objext; then ++ : OK ++ else ++ am_cv_prog_cc_c_o=no ++ break ++ fi ++ done ++ rm -f core conftest* ++ unset am_i ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 ++$as_echo "$am_cv_prog_cc_c_o" >&6; } ++if test "$am_cv_prog_cc_c_o" != yes; then ++ # Losing compiler, so override with the script. ++ # FIXME: It is wrong to rewrite CC. ++ # But if we don't then we get into trouble of one sort or another. ++ # A longer-term fix would be to have automake use am__CC in this case, ++ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" ++ CC="$am_aux_dir/compile $CC" ++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 ++ ++ ++depcc="$CC" am_compiler_list= ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 ++$as_echo_n "checking dependency style of $depcc... " >&6; } ++if ${am_cv_CC_dependencies_compiler_type+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then ++ # We make a subdir and do the tests there. Otherwise we can end up ++ # making bogus files that we don't know about and never remove. For ++ # instance it was reported that on HP-UX the gcc test will end up ++ # making a dummy file named 'D' -- because '-MD' means "put the output ++ # in D". ++ rm -rf conftest.dir ++ mkdir conftest.dir ++ # Copy depcomp to subdir because otherwise we won't find it if we're ++ # using a relative directory. ++ cp "$am_depcomp" conftest.dir ++ cd conftest.dir ++ # We will build objects and dependencies in a subdirectory because ++ # it helps to detect inapplicable dependency modes. For instance ++ # both Tru64's cc and ICC support -MD to output dependencies as a ++ # side effect of compilation, but ICC will put the dependencies in ++ # the current directory while Tru64 will put them in the object ++ # directory. ++ mkdir sub ++ ++ am_cv_CC_dependencies_compiler_type=none ++ if test "$am_compiler_list" = ""; then ++ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` ++ fi ++ am__universal=false ++ case " $depcc " in #( ++ *\ -arch\ *\ -arch\ *) am__universal=true ;; ++ esac ++ ++ for depmode in $am_compiler_list; do ++ # Setup a source with many dependencies, because some compilers ++ # like to wrap large dependency lists on column 80 (with \), and ++ # we should not choose a depcomp mode which is confused by this. ++ # ++ # We need to recreate these files for each test, as the compiler may ++ # overwrite some of them when testing with obscure command lines. ++ # This happens at least with the AIX C compiler. ++ : > sub/conftest.c ++ for i in 1 2 3 4 5 6; do ++ echo '#include "conftst'$i'.h"' >> sub/conftest.c ++ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with ++ # Solaris 10 /bin/sh. ++ echo '/* dummy */' > sub/conftst$i.h ++ done ++ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf ++ ++ # We check with '-c' and '-o' for the sake of the "dashmstdout" ++ # mode. It turns out that the SunPro C++ compiler does not properly ++ # handle '-M -o', and we need to detect this. Also, some Intel ++ # versions had trouble with output in subdirs. ++ am__obj=sub/conftest.${OBJEXT-o} ++ am__minus_obj="-o $am__obj" ++ case $depmode in ++ gcc) ++ # This depmode causes a compiler race in universal mode. ++ test "$am__universal" = false || continue ++ ;; ++ nosideeffect) ++ # After this tag, mechanisms are not by side-effect, so they'll ++ # only be used when explicitly requested. ++ if test "x$enable_dependency_tracking" = xyes; then ++ continue ++ else ++ break ++ fi ++ ;; ++ msvc7 | msvc7msys | msvisualcpp | msvcmsys) ++ # This compiler won't grok '-c -o', but also, the minuso test has ++ # not run yet. These depmodes are late enough in the game, and ++ # so weak that their functioning should not be impacted. ++ am__obj=conftest.${OBJEXT-o} ++ am__minus_obj= ++ ;; ++ none) break ;; ++ esac ++ if depmode=$depmode \ ++ source=sub/conftest.c object=$am__obj \ ++ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ ++ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ ++ >/dev/null 2>conftest.err && ++ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && ++ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && ++ grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ++ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then ++ # icc doesn't choke on unknown options, it will just issue warnings ++ # or remarks (even with -Werror). So we grep stderr for any message ++ # that says an option was ignored or not supported. ++ # When given -MP, icc 7.0 and 7.1 complain thusly: ++ # icc: Command line warning: ignoring option '-M'; no argument required ++ # The diagnosis changed in icc 8.0: ++ # icc: Command line remark: option '-MP' not supported ++ if (grep 'ignoring option' conftest.err || ++ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else ++ am_cv_CC_dependencies_compiler_type=$depmode ++ break ++ fi ++ fi ++ done ++ ++ cd .. ++ rm -rf conftest.dir ++else ++ am_cv_CC_dependencies_compiler_type=none ++fi ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 ++$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } ++CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type ++ ++ if ++ test "x$enable_dependency_tracking" != xno \ ++ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then ++ am__fastdepCC_TRUE= ++ am__fastdepCC_FALSE='#' ++else ++ am__fastdepCC_TRUE='#' ++ am__fastdepCC_FALSE= ++fi ++ ++ ++ac_ext=cpp ++ac_cpp='$CXXCPP $CPPFLAGS' ++ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ++ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ++ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ++if test -z "$CXX"; then ++ if test -n "$CCC"; then ++ CXX=$CCC ++ else ++ if test -n "$ac_tool_prefix"; then ++ for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC ++ do ++ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. ++set dummy $ac_tool_prefix$ac_prog; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_CXX+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$CXX"; then ++ ac_cv_prog_CXX="$CXX" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++CXX=$ac_cv_prog_CXX ++if test -n "$CXX"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 ++$as_echo "$CXX" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++ test -n "$CXX" && break ++ done ++fi ++if test -z "$CXX"; then ++ ac_ct_CXX=$CXX ++ for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC ++do ++ # Extract the first word of "$ac_prog", so it can be a program name with args. ++set dummy $ac_prog; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_ac_ct_CXX+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$ac_ct_CXX"; then ++ ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_ac_ct_CXX="$ac_prog" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++ac_ct_CXX=$ac_cv_prog_ac_ct_CXX ++if test -n "$ac_ct_CXX"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 ++$as_echo "$ac_ct_CXX" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++ test -n "$ac_ct_CXX" && break ++done ++ ++ if test "x$ac_ct_CXX" = x; then ++ CXX="g++" ++ else ++ case $cross_compiling:$ac_tool_warned in ++yes:) ++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 ++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ++ac_tool_warned=yes ;; ++esac ++ CXX=$ac_ct_CXX ++ fi ++fi ++ ++ fi ++fi ++# Provide some information about the compiler. ++$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 ++set X $ac_compile ++ac_compiler=$2 ++for ac_option in --version -v -V -qversion; do ++ { { ac_try="$ac_compiler $ac_option >&5" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" ++$as_echo "$ac_try_echo"; } >&5 ++ (eval "$ac_compiler $ac_option >&5") 2>conftest.err ++ ac_status=$? ++ if test -s conftest.err; then ++ sed '10a\ ++... rest of stderr output deleted ... ++ 10q' conftest.err >conftest.er1 ++ cat conftest.er1 >&5 ++ fi ++ rm -f conftest.er1 conftest.err ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; } ++done ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 ++$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } ++if ${ac_cv_cxx_compiler_gnu+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++#ifndef __GNUC__ ++ choke me ++#endif ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_cxx_try_compile "$LINENO"; then : ++ ac_compiler_gnu=yes ++else ++ ac_compiler_gnu=no ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ac_cv_cxx_compiler_gnu=$ac_compiler_gnu ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 ++$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } ++if test $ac_compiler_gnu = yes; then ++ GXX=yes ++else ++ GXX= ++fi ++ac_test_CXXFLAGS=${CXXFLAGS+set} ++ac_save_CXXFLAGS=$CXXFLAGS ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 ++$as_echo_n "checking whether $CXX accepts -g... " >&6; } ++if ${ac_cv_prog_cxx_g+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_save_cxx_werror_flag=$ac_cxx_werror_flag ++ ac_cxx_werror_flag=yes ++ ac_cv_prog_cxx_g=no ++ CXXFLAGS="-g" ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_cxx_try_compile "$LINENO"; then : ++ ac_cv_prog_cxx_g=yes ++else ++ CXXFLAGS="" ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_cxx_try_compile "$LINENO"; then : ++ ++else ++ ac_cxx_werror_flag=$ac_save_cxx_werror_flag ++ CXXFLAGS="-g" ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_cxx_try_compile "$LINENO"; then : ++ ac_cv_prog_cxx_g=yes ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ ac_cxx_werror_flag=$ac_save_cxx_werror_flag ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 ++$as_echo "$ac_cv_prog_cxx_g" >&6; } ++if test "$ac_test_CXXFLAGS" = set; then ++ CXXFLAGS=$ac_save_CXXFLAGS ++elif test $ac_cv_prog_cxx_g = yes; then ++ if test "$GXX" = yes; then ++ CXXFLAGS="-g -O2" ++ else ++ CXXFLAGS="-g" ++ fi ++else ++ if test "$GXX" = yes; then ++ CXXFLAGS="-O2" ++ else ++ CXXFLAGS= ++ 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 ++ ++depcc="$CXX" am_compiler_list= ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 ++$as_echo_n "checking dependency style of $depcc... " >&6; } ++if ${am_cv_CXX_dependencies_compiler_type+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then ++ # We make a subdir and do the tests there. Otherwise we can end up ++ # making bogus files that we don't know about and never remove. For ++ # instance it was reported that on HP-UX the gcc test will end up ++ # making a dummy file named 'D' -- because '-MD' means "put the output ++ # in D". ++ rm -rf conftest.dir ++ mkdir conftest.dir ++ # Copy depcomp to subdir because otherwise we won't find it if we're ++ # using a relative directory. ++ cp "$am_depcomp" conftest.dir ++ cd conftest.dir ++ # We will build objects and dependencies in a subdirectory because ++ # it helps to detect inapplicable dependency modes. For instance ++ # both Tru64's cc and ICC support -MD to output dependencies as a ++ # side effect of compilation, but ICC will put the dependencies in ++ # the current directory while Tru64 will put them in the object ++ # directory. ++ mkdir sub ++ ++ am_cv_CXX_dependencies_compiler_type=none ++ if test "$am_compiler_list" = ""; then ++ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` ++ fi ++ am__universal=false ++ case " $depcc " in #( ++ *\ -arch\ *\ -arch\ *) am__universal=true ;; ++ esac ++ ++ for depmode in $am_compiler_list; do ++ # Setup a source with many dependencies, because some compilers ++ # like to wrap large dependency lists on column 80 (with \), and ++ # we should not choose a depcomp mode which is confused by this. ++ # ++ # We need to recreate these files for each test, as the compiler may ++ # overwrite some of them when testing with obscure command lines. ++ # This happens at least with the AIX C compiler. ++ : > sub/conftest.c ++ for i in 1 2 3 4 5 6; do ++ echo '#include "conftst'$i'.h"' >> sub/conftest.c ++ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with ++ # Solaris 10 /bin/sh. ++ echo '/* dummy */' > sub/conftst$i.h ++ done ++ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf ++ ++ # We check with '-c' and '-o' for the sake of the "dashmstdout" ++ # mode. It turns out that the SunPro C++ compiler does not properly ++ # handle '-M -o', and we need to detect this. Also, some Intel ++ # versions had trouble with output in subdirs. ++ am__obj=sub/conftest.${OBJEXT-o} ++ am__minus_obj="-o $am__obj" ++ case $depmode in ++ gcc) ++ # This depmode causes a compiler race in universal mode. ++ test "$am__universal" = false || continue ++ ;; ++ nosideeffect) ++ # After this tag, mechanisms are not by side-effect, so they'll ++ # only be used when explicitly requested. ++ if test "x$enable_dependency_tracking" = xyes; then ++ continue ++ else ++ break ++ fi ++ ;; ++ msvc7 | msvc7msys | msvisualcpp | msvcmsys) ++ # This compiler won't grok '-c -o', but also, the minuso test has ++ # not run yet. These depmodes are late enough in the game, and ++ # so weak that their functioning should not be impacted. ++ am__obj=conftest.${OBJEXT-o} ++ am__minus_obj= ++ ;; ++ none) break ;; ++ esac ++ if depmode=$depmode \ ++ source=sub/conftest.c object=$am__obj \ ++ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ ++ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ ++ >/dev/null 2>conftest.err && ++ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && ++ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && ++ grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ++ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then ++ # icc doesn't choke on unknown options, it will just issue warnings ++ # or remarks (even with -Werror). So we grep stderr for any message ++ # that says an option was ignored or not supported. ++ # When given -MP, icc 7.0 and 7.1 complain thusly: ++ # icc: Command line warning: ignoring option '-M'; no argument required ++ # The diagnosis changed in icc 8.0: ++ # icc: Command line remark: option '-MP' not supported ++ if (grep 'ignoring option' conftest.err || ++ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else ++ am_cv_CXX_dependencies_compiler_type=$depmode ++ break ++ fi ++ fi ++ done ++ ++ cd .. ++ rm -rf conftest.dir ++else ++ am_cv_CXX_dependencies_compiler_type=none ++fi ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 ++$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } ++CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type ++ ++ if ++ test "x$enable_dependency_tracking" != xno \ ++ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then ++ am__fastdepCXX_TRUE= ++ am__fastdepCXX_FALSE='#' ++else ++ am__fastdepCXX_TRUE='#' ++ am__fastdepCXX_FALSE= ++fi ++ ++ ++# Check whether --enable-largefile was given. ++if test "${enable_largefile+set}" = set; then : ++ enableval=$enable_largefile; ++fi ++ ++if test "$enable_largefile" != no; then ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 ++$as_echo_n "checking for special C compiler options needed for large files... " >&6; } ++if ${ac_cv_sys_largefile_CC+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_cv_sys_largefile_CC=no ++ if test "$GCC" != yes; then ++ ac_save_CC=$CC ++ while :; do ++ # IRIX 6.2 and later do not support large files by default, ++ # so use the C compiler's -n32 option if that helps. ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#include <sys/types.h> ++ /* Check that off_t can represent 2**63 - 1 correctly. ++ We can't simply define LARGE_OFF_T to be 9223372036854775807, ++ since some C++ compilers masquerading as C compilers ++ incorrectly reject 9223372036854775807. */ ++#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) ++ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 ++ && LARGE_OFF_T % 2147483647 == 1) ++ ? 1 : -1]; ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++ if ac_fn_c_try_compile "$LINENO"; then : ++ break ++fi ++rm -f core conftest.err conftest.$ac_objext ++ CC="$CC -n32" ++ if ac_fn_c_try_compile "$LINENO"; then : ++ ac_cv_sys_largefile_CC=' -n32'; break ++fi ++rm -f core conftest.err conftest.$ac_objext ++ break ++ done ++ CC=$ac_save_CC ++ rm -f conftest.$ac_ext ++ fi ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 ++$as_echo "$ac_cv_sys_largefile_CC" >&6; } ++ if test "$ac_cv_sys_largefile_CC" != no; then ++ CC=$CC$ac_cv_sys_largefile_CC ++ fi ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 ++$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } ++if ${ac_cv_sys_file_offset_bits+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ while :; do ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#include <sys/types.h> ++ /* Check that off_t can represent 2**63 - 1 correctly. ++ We can't simply define LARGE_OFF_T to be 9223372036854775807, ++ since some C++ compilers masquerading as C compilers ++ incorrectly reject 9223372036854775807. */ ++#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) ++ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 ++ && LARGE_OFF_T % 2147483647 == 1) ++ ? 1 : -1]; ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ ac_cv_sys_file_offset_bits=no; break ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#define _FILE_OFFSET_BITS 64 ++#include <sys/types.h> ++ /* Check that off_t can represent 2**63 - 1 correctly. ++ We can't simply define LARGE_OFF_T to be 9223372036854775807, ++ since some C++ compilers masquerading as C compilers ++ incorrectly reject 9223372036854775807. */ ++#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) ++ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 ++ && LARGE_OFF_T % 2147483647 == 1) ++ ? 1 : -1]; ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ ac_cv_sys_file_offset_bits=64; break ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ ac_cv_sys_file_offset_bits=unknown ++ break ++done ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 ++$as_echo "$ac_cv_sys_file_offset_bits" >&6; } ++case $ac_cv_sys_file_offset_bits in #( ++ no | unknown) ;; ++ *) ++cat >>confdefs.h <<_ACEOF ++#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits ++_ACEOF ++;; ++esac ++rm -rf conftest* ++ if test $ac_cv_sys_file_offset_bits = unknown; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 ++$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } ++if ${ac_cv_sys_large_files+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ while :; do ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#include <sys/types.h> ++ /* Check that off_t can represent 2**63 - 1 correctly. ++ We can't simply define LARGE_OFF_T to be 9223372036854775807, ++ since some C++ compilers masquerading as C compilers ++ incorrectly reject 9223372036854775807. */ ++#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) ++ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 ++ && LARGE_OFF_T % 2147483647 == 1) ++ ? 1 : -1]; ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ ac_cv_sys_large_files=no; break ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#define _LARGE_FILES 1 ++#include <sys/types.h> ++ /* Check that off_t can represent 2**63 - 1 correctly. ++ We can't simply define LARGE_OFF_T to be 9223372036854775807, ++ since some C++ compilers masquerading as C compilers ++ incorrectly reject 9223372036854775807. */ ++#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) ++ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 ++ && LARGE_OFF_T % 2147483647 == 1) ++ ? 1 : -1]; ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ ac_cv_sys_large_files=1; break ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ ac_cv_sys_large_files=unknown ++ break ++done ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 ++$as_echo "$ac_cv_sys_large_files" >&6; } ++case $ac_cv_sys_large_files in #( ++ no | unknown) ;; ++ *) ++cat >>confdefs.h <<_ACEOF ++#define _LARGE_FILES $ac_cv_sys_large_files ++_ACEOF ++;; ++esac ++rm -rf conftest* ++ 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 ++ ++ac_bolt_plugin_warn_cflags= ++save_CFLAGS="$CFLAGS" ++for real_option in -Wall; do ++ # Do the check with the no- prefix removed since gcc silently ++ # accepts any -Wno-* option on purpose ++ case $real_option in ++ -Wno-*) option=-W`expr x$real_option : 'x-Wno-\(.*\)'` ;; ++ *) option=$real_option ;; ++ esac ++ as_acx_Woption=`$as_echo "acx_cv_prog_cc_warning_$option" | $as_tr_sh` ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports $option" >&5 ++$as_echo_n "checking whether $CC supports $option... " >&6; } ++if eval \${$as_acx_Woption+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ CFLAGS="$option" ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ eval "$as_acx_Woption=yes" ++else ++ eval "$as_acx_Woption=no" ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ ++fi ++eval ac_res=\$$as_acx_Woption ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 ++$as_echo "$ac_res" >&6; } ++ if test `eval 'as_val=${'$as_acx_Woption'};$as_echo "$as_val"'` = yes; then : ++ ac_bolt_plugin_warn_cflags="$ac_bolt_plugin_warn_cflags${ac_bolt_plugin_warn_cflags:+ }$real_option" ++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 ++ ++ ++ ++# Check whether -static-libgcc is supported. ++saved_LDFLAGS="$LDFLAGS" ++LDFLAGS="$LDFLAGS -static-libgcc" ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -static-libgcc" >&5 ++$as_echo_n "checking for -static-libgcc... " >&6; } ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++ int main() {} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ have_static_libgcc=yes ++else ++ have_static_libgcc=no ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_static_libgcc" >&5 ++$as_echo "$have_static_libgcc" >&6; }; ++LDFLAGS="$saved_LDFLAGS" ++# Need -Wc to get it through libtool. ++if test "x$have_static_libgcc" = xyes; then ++ ac_bolt_plugin_ldflags="-Wc,-static-libgcc" ++fi ++ ++ ++if test x"$host_subdir" = x.; then ++ gcc_build_dir=../gcc ++else ++ gcc_build_dir=../../$host_subdir/gcc ++fi ++ ++ ++# Used for constructing correct paths for offload compilers. ++accel_dir_suffix= ++real_target_noncanonical=${target_noncanonical} ++if test x"$enable_as_accelerator_for" != x; then ++ accel_dir_suffix=/accel/${target_noncanonical} ++ real_target_noncanonical=${enable_as_accelerator_for} ++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 ++$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; ++esac ++ ++ ++ ++macro_version='2.2.7a' ++macro_revision='1.3134' ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ltmain="$ac_aux_dir/ltmain.sh" ++ ++# Backslashify metacharacters that are still active within ++# double-quoted strings. ++sed_quote_subst='s/\(["`$\\]\)/\\\1/g' ++ ++# Same as above, but do not quote variable references. ++double_quote_subst='s/\(["`\\]\)/\\\1/g' ++ ++# Sed substitution to delay expansion of an escaped shell variable in a ++# double_quote_subst'ed string. ++delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' ++ ++# Sed substitution to delay expansion of an escaped single quote. ++delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' ++ ++# Sed substitution to avoid accidental globbing in evaled expressions ++no_glob_subst='s/\*/\\\*/g' ++ ++ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ++ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ++ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 ++$as_echo_n "checking how to print strings... " >&6; } ++# Test print first, because it will be a builtin if present. ++if test "X`print -r -- -n 2>/dev/null`" = X-n && \ ++ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ++ ECHO='print -r --' ++elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ++ ECHO='printf %s\n' ++else ++ # Use this function as a fallback that always works. ++ func_fallback_echo () ++ { ++ eval 'cat <<_LTECHO_EOF ++$1 ++_LTECHO_EOF' ++ } ++ ECHO='func_fallback_echo' ++fi ++ ++# func_echo_all arg... ++# Invoke $ECHO with all args, space-separated. ++func_echo_all () ++{ ++ $ECHO "" ++} ++ ++case "$ECHO" in ++ printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 ++$as_echo "printf" >&6; } ;; ++ print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 ++$as_echo "print -r" >&6; } ;; ++ *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 ++$as_echo "cat" >&6; } ;; ++esac ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 ++$as_echo_n "checking for a sed that does not truncate output... " >&6; } ++if ${ac_cv_path_SED+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ ++ for ac_i in 1 2 3 4 5 6 7; do ++ ac_script="$ac_script$as_nl$ac_script" ++ done ++ echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed ++ { ac_script=; unset ac_script;} ++ if test -z "$SED"; then ++ ac_path_SED_found=false ++ # Loop through the user's path and test for each of PROGNAME-LIST ++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_prog in sed gsed; do ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" ++ as_fn_executable_p "$ac_path_SED" || continue ++# Check for GNU ac_path_SED and select it if it is found. ++ # Check for GNU $ac_path_SED ++case `"$ac_path_SED" --version 2>&1` in ++*GNU*) ++ ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; ++*) ++ ac_count=0 ++ $as_echo_n 0123456789 >"conftest.in" ++ while : ++ do ++ cat "conftest.in" "conftest.in" >"conftest.tmp" ++ mv "conftest.tmp" "conftest.in" ++ cp "conftest.in" "conftest.nl" ++ $as_echo '' >> "conftest.nl" ++ "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break ++ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break ++ as_fn_arith $ac_count + 1 && ac_count=$as_val ++ if test $ac_count -gt ${ac_path_SED_max-0}; then ++ # Best one so far, save it but keep looking for a better one ++ ac_cv_path_SED="$ac_path_SED" ++ ac_path_SED_max=$ac_count ++ fi ++ # 10*(2^10) chars as input seems more than enough ++ test $ac_count -gt 10 && break ++ done ++ rm -f conftest.in conftest.tmp conftest.nl conftest.out;; ++esac ++ ++ $ac_path_SED_found && break 3 ++ done ++ done ++ done ++IFS=$as_save_IFS ++ if test -z "$ac_cv_path_SED"; then ++ as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 ++ fi ++else ++ ac_cv_path_SED=$SED ++fi ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 ++$as_echo "$ac_cv_path_SED" >&6; } ++ SED="$ac_cv_path_SED" ++ rm -f conftest.sed ++ ++test -z "$SED" && SED=sed ++Xsed="$SED -e 1s/^X//" ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 ++$as_echo_n "checking for fgrep... " >&6; } ++if ${ac_cv_path_FGREP+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 ++ then ac_cv_path_FGREP="$GREP -F" ++ else ++ if test -z "$FGREP"; then ++ ac_path_FGREP_found=false ++ # Loop through the user's path and test for each of PROGNAME-LIST ++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_prog in fgrep; do ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" ++ as_fn_executable_p "$ac_path_FGREP" || continue ++# Check for GNU ac_path_FGREP and select it if it is found. ++ # Check for GNU $ac_path_FGREP ++case `"$ac_path_FGREP" --version 2>&1` in ++*GNU*) ++ ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; ++*) ++ ac_count=0 ++ $as_echo_n 0123456789 >"conftest.in" ++ while : ++ do ++ cat "conftest.in" "conftest.in" >"conftest.tmp" ++ mv "conftest.tmp" "conftest.in" ++ cp "conftest.in" "conftest.nl" ++ $as_echo 'FGREP' >> "conftest.nl" ++ "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break ++ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break ++ as_fn_arith $ac_count + 1 && ac_count=$as_val ++ if test $ac_count -gt ${ac_path_FGREP_max-0}; then ++ # Best one so far, save it but keep looking for a better one ++ ac_cv_path_FGREP="$ac_path_FGREP" ++ ac_path_FGREP_max=$ac_count ++ fi ++ # 10*(2^10) chars as input seems more than enough ++ test $ac_count -gt 10 && break ++ done ++ rm -f conftest.in conftest.tmp conftest.nl conftest.out;; ++esac ++ ++ $ac_path_FGREP_found && break 3 ++ done ++ done ++ done ++IFS=$as_save_IFS ++ if test -z "$ac_cv_path_FGREP"; then ++ as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 ++ fi ++else ++ ac_cv_path_FGREP=$FGREP ++fi ++ ++ fi ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 ++$as_echo "$ac_cv_path_FGREP" >&6; } ++ FGREP="$ac_cv_path_FGREP" ++ ++ ++test -z "$GREP" && GREP=grep ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++# Check whether --with-gnu-ld was given. ++if test "${with_gnu_ld+set}" = set; then : ++ withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes ++else ++ with_gnu_ld=no ++fi ++ ++ac_prog=ld ++if test "$GCC" = yes; then ++ # Check if gcc -print-prog-name=ld gives a path. ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 ++$as_echo_n "checking for ld used by $CC... " >&6; } ++ case $host in ++ *-*-mingw*) ++ # gcc leaves a trailing carriage return which upsets mingw ++ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; ++ *) ++ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; ++ esac ++ case $ac_prog in ++ # Accept absolute paths. ++ [\\/]* | ?:[\\/]*) ++ re_direlt='/[^/][^/]*/\.\./' ++ # Canonicalize the pathname of ld ++ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` ++ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ++ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` ++ done ++ test -z "$LD" && LD="$ac_prog" ++ ;; ++ "") ++ # If it fails, then pretend we aren't using GCC. ++ ac_prog=ld ++ ;; ++ *) ++ # If it is relative, then search for the first ld in PATH. ++ with_gnu_ld=unknown ++ ;; ++ esac ++elif test "$with_gnu_ld" = yes; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 ++$as_echo_n "checking for GNU ld... " >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 ++$as_echo_n "checking for non-GNU ld... " >&6; } ++fi ++if ${lt_cv_path_LD+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -z "$LD"; then ++ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ++ for ac_dir in $PATH; do ++ IFS="$lt_save_ifs" ++ test -z "$ac_dir" && ac_dir=. ++ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then ++ lt_cv_path_LD="$ac_dir/$ac_prog" ++ # Check to see if the program is GNU ld. I'd rather use --version, ++ # but apparently some variants of GNU ld only accept -v. ++ # Break only if it was the GNU/non-GNU ld that we prefer. ++ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in ++ *GNU* | *'with BFD'*) ++ test "$with_gnu_ld" != no && break ++ ;; ++ *) ++ test "$with_gnu_ld" != yes && break ++ ;; ++ esac ++ fi ++ done ++ IFS="$lt_save_ifs" ++else ++ lt_cv_path_LD="$LD" # Let the user override the test with a path. ++fi ++fi ++ ++LD="$lt_cv_path_LD" ++if test -n "$LD"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 ++$as_echo "$LD" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 ++$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } ++if ${lt_cv_prog_gnu_ld+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ # I'd rather use --version here, but apparently some GNU lds only accept -v. ++case `$LD -v 2>&1 </dev/null` in ++*GNU* | *'with BFD'*) ++ lt_cv_prog_gnu_ld=yes ++ ;; ++*) ++ lt_cv_prog_gnu_ld=no ++ ;; ++esac ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5 ++$as_echo "$lt_cv_prog_gnu_ld" >&6; } ++with_gnu_ld=$lt_cv_prog_gnu_ld ++ ++ ++ ++ ++ ++ ++ ++ ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 ++$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } ++if ${lt_cv_path_NM+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$NM"; then ++ # Let the user override the test. ++ lt_cv_path_NM="$NM" ++else ++ lt_nm_to_check="${ac_tool_prefix}nm" ++ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then ++ lt_nm_to_check="$lt_nm_to_check nm" ++ fi ++ for lt_tmp_nm in $lt_nm_to_check; do ++ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ++ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do ++ IFS="$lt_save_ifs" ++ test -z "$ac_dir" && ac_dir=. ++ tmp_nm="$ac_dir/$lt_tmp_nm" ++ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then ++ # Check to see if the nm accepts a BSD-compat flag. ++ # Adding the `sed 1q' prevents false positives on HP-UX, which says: ++ # nm: unknown option "B" ignored ++ # Tru64's nm complains that /dev/null is an invalid object file ++ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in ++ */dev/null* | *'Invalid file or object type'*) ++ lt_cv_path_NM="$tmp_nm -B" ++ break ++ ;; ++ *) ++ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in ++ */dev/null*) ++ lt_cv_path_NM="$tmp_nm -p" ++ break ++ ;; ++ *) ++ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but ++ continue # so that we can try to find one that supports BSD flags ++ ;; ++ esac ++ ;; ++ esac ++ fi ++ done ++ IFS="$lt_save_ifs" ++ done ++ : ${lt_cv_path_NM=no} ++fi ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 ++$as_echo "$lt_cv_path_NM" >&6; } ++if test "$lt_cv_path_NM" != "no"; then ++ NM="$lt_cv_path_NM" ++else ++ # Didn't find any BSD compatible name lister, look for dumpbin. ++ if test -n "$DUMPBIN"; then : ++ # Let the user override the test. ++ else ++ if test -n "$ac_tool_prefix"; then ++ for ac_prog in dumpbin "link -dump" ++ do ++ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. ++set dummy $ac_tool_prefix$ac_prog; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_DUMPBIN+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$DUMPBIN"; then ++ ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++DUMPBIN=$ac_cv_prog_DUMPBIN ++if test -n "$DUMPBIN"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 ++$as_echo "$DUMPBIN" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++ test -n "$DUMPBIN" && break ++ done ++fi ++if test -z "$DUMPBIN"; then ++ ac_ct_DUMPBIN=$DUMPBIN ++ for ac_prog in dumpbin "link -dump" ++do ++ # Extract the first word of "$ac_prog", so it can be a program name with args. ++set dummy $ac_prog; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$ac_ct_DUMPBIN"; then ++ ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN ++if test -n "$ac_ct_DUMPBIN"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 ++$as_echo "$ac_ct_DUMPBIN" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++ test -n "$ac_ct_DUMPBIN" && break ++done ++ ++ if test "x$ac_ct_DUMPBIN" = x; then ++ DUMPBIN=":" ++ else ++ case $cross_compiling:$ac_tool_warned in ++yes:) ++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 ++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ++ac_tool_warned=yes ;; ++esac ++ DUMPBIN=$ac_ct_DUMPBIN ++ fi ++fi ++ ++ case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in ++ *COFF*) ++ DUMPBIN="$DUMPBIN -symbols" ++ ;; ++ *) ++ DUMPBIN=: ++ ;; ++ esac ++ fi ++ ++ if test "$DUMPBIN" != ":"; then ++ NM="$DUMPBIN" ++ fi ++fi ++test -z "$NM" && NM=nm ++ ++ ++ ++ ++ ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 ++$as_echo_n "checking the name lister ($NM) interface... " >&6; } ++if ${lt_cv_nm_interface+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ lt_cv_nm_interface="BSD nm" ++ echo "int some_variable = 0;" > conftest.$ac_ext ++ (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) ++ (eval "$ac_compile" 2>conftest.err) ++ cat conftest.err >&5 ++ (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) ++ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) ++ cat conftest.err >&5 ++ (eval echo "\"\$as_me:$LINENO: output\"" >&5) ++ cat conftest.out >&5 ++ if $GREP 'External.*some_variable' conftest.out > /dev/null; then ++ lt_cv_nm_interface="MS dumpbin" ++ fi ++ rm -f conftest* ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 ++$as_echo "$lt_cv_nm_interface" >&6; } ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 ++$as_echo_n "checking whether ln -s works... " >&6; } ++LN_S=$as_ln_s ++if test "$LN_S" = "ln -s"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 ++$as_echo "yes" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 ++$as_echo "no, using $LN_S" >&6; } ++fi ++ ++# find the maximum length of command line arguments ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 ++$as_echo_n "checking the maximum length of command line arguments... " >&6; } ++if ${lt_cv_sys_max_cmd_len+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ i=0 ++ teststring="ABCD" ++ ++ case $build_os in ++ msdosdjgpp*) ++ # On DJGPP, this test can blow up pretty badly due to problems in libc ++ # (any single argument exceeding 2000 bytes causes a buffer overrun ++ # during glob expansion). Even if it were fixed, the result of this ++ # check would be larger than it should be. ++ lt_cv_sys_max_cmd_len=12288; # 12K is about right ++ ;; ++ ++ gnu*) ++ # Under GNU Hurd, this test is not required because there is ++ # no limit to the length of command line arguments. ++ # Libtool will interpret -1 as no limit whatsoever ++ lt_cv_sys_max_cmd_len=-1; ++ ;; ++ ++ cygwin* | mingw* | cegcc*) ++ # On Win9x/ME, this test blows up -- it succeeds, but takes ++ # about 5 minutes as the teststring grows exponentially. ++ # Worse, since 9x/ME are not pre-emptively multitasking, ++ # you end up with a "frozen" computer, even though with patience ++ # the test eventually succeeds (with a max line length of 256k). ++ # Instead, let's just punt: use the minimum linelength reported by ++ # all of the supported platforms: 8192 (on NT/2K/XP). ++ lt_cv_sys_max_cmd_len=8192; ++ ;; ++ ++ mint*) ++ # On MiNT this can take a long time and run out of memory. ++ lt_cv_sys_max_cmd_len=8192; ++ ;; ++ ++ amigaos*) ++ # On AmigaOS with pdksh, this test takes hours, literally. ++ # So we just punt and use a minimum line length of 8192. ++ lt_cv_sys_max_cmd_len=8192; ++ ;; ++ ++ netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) ++ # This has been around since 386BSD, at least. Likely further. ++ if test -x /sbin/sysctl; then ++ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` ++ elif test -x /usr/sbin/sysctl; then ++ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` ++ else ++ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs ++ fi ++ # And add a safety zone ++ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` ++ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ++ ;; ++ ++ interix*) ++ # We know the value 262144 and hardcode it with a safety zone (like BSD) ++ lt_cv_sys_max_cmd_len=196608 ++ ;; ++ ++ osf*) ++ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure ++ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not ++ # nice to cause kernel panics so lets avoid the loop below. ++ # First set a reasonable default. ++ lt_cv_sys_max_cmd_len=16384 ++ # ++ if test -x /sbin/sysconfig; then ++ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in ++ *1*) lt_cv_sys_max_cmd_len=-1 ;; ++ esac ++ fi ++ ;; ++ sco3.2v5*) ++ lt_cv_sys_max_cmd_len=102400 ++ ;; ++ sysv5* | sco5v6* | sysv4.2uw2*) ++ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` ++ if test -n "$kargmax"; then ++ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` ++ else ++ lt_cv_sys_max_cmd_len=32768 ++ fi ++ ;; ++ *) ++ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` ++ if test -n "$lt_cv_sys_max_cmd_len"; then ++ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` ++ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ++ else ++ # Make teststring a little bigger before we do anything with it. ++ # a 1K string should be a reasonable start. ++ for i in 1 2 3 4 5 6 7 8 ; do ++ teststring=$teststring$teststring ++ done ++ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} ++ # If test is not a shell built-in, we'll probably end up computing a ++ # maximum length that is only half of the actual maximum length, but ++ # we can't tell. ++ while { test "X"`func_fallback_echo "$teststring$teststring" 2>/dev/null` \ ++ = "X$teststring$teststring"; } >/dev/null 2>&1 && ++ test $i != 17 # 1/2 MB should be enough ++ do ++ i=`expr $i + 1` ++ teststring=$teststring$teststring ++ done ++ # Only check the string length outside the loop. ++ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` ++ teststring= ++ # Add a significant safety factor because C++ compilers can tack on ++ # massive amounts of additional arguments before passing them to the ++ # linker. It appears as though 1/2 is a usable value. ++ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` ++ fi ++ ;; ++ esac ++ ++fi ++ ++if test -n $lt_cv_sys_max_cmd_len ; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 ++$as_echo "$lt_cv_sys_max_cmd_len" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 ++$as_echo "none" >&6; } ++fi ++max_cmd_len=$lt_cv_sys_max_cmd_len ++ ++ ++ ++ ++ ++ ++: ${CP="cp -f"} ++: ${MV="mv -f"} ++: ${RM="rm -f"} ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 ++$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } ++# Try some XSI features ++xsi_shell=no ++( _lt_dummy="a/b/c" ++ test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ ++ = c,a/b,, \ ++ && eval 'test $(( 1 + 1 )) -eq 2 \ ++ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ ++ && xsi_shell=yes ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 ++$as_echo "$xsi_shell" >&6; } ++ ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 ++$as_echo_n "checking whether the shell understands \"+=\"... " >&6; } ++lt_shell_append=no ++( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ ++ >/dev/null 2>&1 \ ++ && lt_shell_append=yes ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 ++$as_echo "$lt_shell_append" >&6; } ++ ++ ++if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then ++ lt_unset=unset ++else ++ lt_unset=false ++fi ++ ++ ++ ++ ++ ++# test EBCDIC or ASCII ++case `echo X|tr X '\101'` in ++ A) # ASCII based system ++ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr ++ lt_SP2NL='tr \040 \012' ++ lt_NL2SP='tr \015\012 \040\040' ++ ;; ++ *) # EBCDIC based system ++ lt_SP2NL='tr \100 \n' ++ lt_NL2SP='tr \r\n \100\100' ++ ;; ++esac ++ ++ ++ ++ ++ ++ ++ ++ ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 ++$as_echo_n "checking for $LD option to reload object files... " >&6; } ++if ${lt_cv_ld_reload_flag+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ lt_cv_ld_reload_flag='-r' ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 ++$as_echo "$lt_cv_ld_reload_flag" >&6; } ++reload_flag=$lt_cv_ld_reload_flag ++case $reload_flag in ++"" | " "*) ;; ++*) reload_flag=" $reload_flag" ;; ++esac ++reload_cmds='$LD$reload_flag -o $output$reload_objs' ++case $host_os in ++ darwin*) ++ if test "$GCC" = yes; then ++ reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' ++ else ++ reload_cmds='$LD$reload_flag -o $output$reload_objs' ++ fi ++ ;; ++esac ++ ++ ++ ++ ++ ++ ++ ++ ++ ++if test -n "$ac_tool_prefix"; then ++ # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. ++set dummy ${ac_tool_prefix}objdump; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_OBJDUMP+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$OBJDUMP"; then ++ ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++OBJDUMP=$ac_cv_prog_OBJDUMP ++if test -n "$OBJDUMP"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 ++$as_echo "$OBJDUMP" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++fi ++if test -z "$ac_cv_prog_OBJDUMP"; then ++ ac_ct_OBJDUMP=$OBJDUMP ++ # Extract the first word of "objdump", so it can be a program name with args. ++set dummy objdump; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$ac_ct_OBJDUMP"; then ++ ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_ac_ct_OBJDUMP="objdump" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP ++if test -n "$ac_ct_OBJDUMP"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 ++$as_echo "$ac_ct_OBJDUMP" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ if test "x$ac_ct_OBJDUMP" = x; then ++ OBJDUMP="false" ++ else ++ case $cross_compiling:$ac_tool_warned in ++yes:) ++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 ++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ++ac_tool_warned=yes ;; ++esac ++ OBJDUMP=$ac_ct_OBJDUMP ++ fi ++else ++ OBJDUMP="$ac_cv_prog_OBJDUMP" ++fi ++ ++test -z "$OBJDUMP" && OBJDUMP=objdump ++ ++ ++ ++ ++ ++ ++ ++ ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 ++$as_echo_n "checking how to recognize dependent libraries... " >&6; } ++if ${lt_cv_deplibs_check_method+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ lt_cv_file_magic_cmd='$MAGIC_CMD' ++lt_cv_file_magic_test_file= ++lt_cv_deplibs_check_method='unknown' ++# Need to set the preceding variable on all platforms that support ++# interlibrary dependencies. ++# 'none' -- dependencies not supported. ++# `unknown' -- same as none, but documents that we really don't know. ++# 'pass_all' -- all dependencies passed with no checks. ++# 'test_compile' -- check by making test program. ++# 'file_magic [[regex]]' -- check by looking for files in library path ++# which responds to the $file_magic_cmd with a given extended regex. ++# If you have `file' or equivalent on your system and you're not sure ++# whether `pass_all' will *always* work, you probably want this one. ++ ++case $host_os in ++aix[4-9]*) ++ lt_cv_deplibs_check_method=pass_all ++ ;; ++ ++beos*) ++ lt_cv_deplibs_check_method=pass_all ++ ;; ++ ++bsdi[45]*) ++ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' ++ lt_cv_file_magic_cmd='/usr/bin/file -L' ++ lt_cv_file_magic_test_file=/shlib/libc.so ++ ;; ++ ++cygwin*) ++ # func_win32_libid is a shell function defined in ltmain.sh ++ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' ++ lt_cv_file_magic_cmd='func_win32_libid' ++ ;; ++ ++mingw* | pw32*) ++ # Base MSYS/MinGW do not provide the 'file' command needed by ++ # func_win32_libid shell function, so use a weaker test based on 'objdump', ++ # unless we find 'file', for example because we are cross-compiling. ++ # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. ++ if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then ++ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' ++ lt_cv_file_magic_cmd='func_win32_libid' ++ else ++ lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' ++ lt_cv_file_magic_cmd='$OBJDUMP -f' ++ fi ++ ;; ++ ++cegcc*) ++ # use the weaker test based on 'objdump'. See mingw*. ++ lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' ++ lt_cv_file_magic_cmd='$OBJDUMP -f' ++ ;; ++ ++darwin* | rhapsody*) ++ lt_cv_deplibs_check_method=pass_all ++ ;; ++ ++freebsd* | dragonfly*) ++ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then ++ case $host_cpu in ++ i*86 ) ++ # Not sure whether the presence of OpenBSD here was a mistake. ++ # Let's accept both of them until this is cleared up. ++ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' ++ lt_cv_file_magic_cmd=/usr/bin/file ++ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ++ ;; ++ esac ++ else ++ lt_cv_deplibs_check_method=pass_all ++ fi ++ ;; ++ ++gnu*) ++ lt_cv_deplibs_check_method=pass_all ++ ;; ++ ++haiku*) ++ lt_cv_deplibs_check_method=pass_all ++ ;; ++ ++hpux10.20* | hpux11*) ++ lt_cv_file_magic_cmd=/usr/bin/file ++ case $host_cpu in ++ ia64*) ++ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' ++ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ++ ;; ++ hppa*64*) ++ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' ++ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ++ ;; ++ *) ++ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' ++ lt_cv_file_magic_test_file=/usr/lib/libc.sl ++ ;; ++ esac ++ ;; ++ ++interix[3-9]*) ++ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here ++ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' ++ ;; ++ ++irix5* | irix6* | nonstopux*) ++ case $LD in ++ *-32|*"-32 ") libmagic=32-bit;; ++ *-n32|*"-n32 ") libmagic=N32;; ++ *-64|*"-64 ") libmagic=64-bit;; ++ *) libmagic=never-match;; ++ esac ++ lt_cv_deplibs_check_method=pass_all ++ ;; ++ ++# This must be Linux ELF. ++linux* | k*bsd*-gnu | kopensolaris*-gnu) ++ lt_cv_deplibs_check_method=pass_all ++ ;; ++ ++netbsd*) ++ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then ++ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' ++ else ++ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' ++ fi ++ ;; ++ ++newos6*) ++ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' ++ lt_cv_file_magic_cmd=/usr/bin/file ++ lt_cv_file_magic_test_file=/usr/lib/libnls.so ++ ;; ++ ++*nto* | *qnx*) ++ lt_cv_deplibs_check_method=pass_all ++ ;; ++ ++openbsd*) ++ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then ++ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' ++ else ++ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' ++ fi ++ ;; ++ ++osf3* | osf4* | osf5*) ++ lt_cv_deplibs_check_method=pass_all ++ ;; ++ ++rdos*) ++ lt_cv_deplibs_check_method=pass_all ++ ;; ++ ++solaris*) ++ lt_cv_deplibs_check_method=pass_all ++ ;; ++ ++sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) ++ lt_cv_deplibs_check_method=pass_all ++ ;; ++ ++sysv4 | sysv4.3*) ++ case $host_vendor in ++ motorola) ++ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' ++ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ++ ;; ++ ncr) ++ lt_cv_deplibs_check_method=pass_all ++ ;; ++ sequent) ++ lt_cv_file_magic_cmd='/bin/file' ++ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ++ ;; ++ sni) ++ lt_cv_file_magic_cmd='/bin/file' ++ lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" ++ lt_cv_file_magic_test_file=/lib/libc.so ++ ;; ++ siemens) ++ lt_cv_deplibs_check_method=pass_all ++ ;; ++ pc) ++ lt_cv_deplibs_check_method=pass_all ++ ;; ++ esac ++ ;; ++ ++tpf*) ++ lt_cv_deplibs_check_method=pass_all ++ ;; ++esac ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 ++$as_echo "$lt_cv_deplibs_check_method" >&6; } ++file_magic_cmd=$lt_cv_file_magic_cmd ++deplibs_check_method=$lt_cv_deplibs_check_method ++test -z "$deplibs_check_method" && deplibs_check_method=unknown ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++if test -n "$ac_tool_prefix"; then ++ # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. ++set dummy ${ac_tool_prefix}ar; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_AR+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$AR"; then ++ ac_cv_prog_AR="$AR" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_AR="${ac_tool_prefix}ar" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++AR=$ac_cv_prog_AR ++if test -n "$AR"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 ++$as_echo "$AR" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++fi ++if test -z "$ac_cv_prog_AR"; then ++ ac_ct_AR=$AR ++ # Extract the first word of "ar", so it can be a program name with args. ++set dummy ar; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_ac_ct_AR+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$ac_ct_AR"; then ++ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_ac_ct_AR="ar" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++ac_ct_AR=$ac_cv_prog_ac_ct_AR ++if test -n "$ac_ct_AR"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 ++$as_echo "$ac_ct_AR" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ if test "x$ac_ct_AR" = x; then ++ AR="false" ++ else ++ case $cross_compiling:$ac_tool_warned in ++yes:) ++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 ++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ++ac_tool_warned=yes ;; ++esac ++ AR=$ac_ct_AR ++ fi ++else ++ AR="$ac_cv_prog_AR" ++fi ++ ++test -z "$AR" && AR=ar ++test -z "$AR_FLAGS" && AR_FLAGS=cru ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++if test -n "$ac_tool_prefix"; then ++ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. ++set dummy ${ac_tool_prefix}strip; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_STRIP+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$STRIP"; then ++ ac_cv_prog_STRIP="$STRIP" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_STRIP="${ac_tool_prefix}strip" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++STRIP=$ac_cv_prog_STRIP ++if test -n "$STRIP"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 ++$as_echo "$STRIP" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++fi ++if test -z "$ac_cv_prog_STRIP"; then ++ ac_ct_STRIP=$STRIP ++ # Extract the first word of "strip", so it can be a program name with args. ++set dummy strip; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_ac_ct_STRIP+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$ac_ct_STRIP"; then ++ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_ac_ct_STRIP="strip" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP ++if test -n "$ac_ct_STRIP"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 ++$as_echo "$ac_ct_STRIP" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ if test "x$ac_ct_STRIP" = x; then ++ STRIP=":" ++ else ++ case $cross_compiling:$ac_tool_warned in ++yes:) ++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 ++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ++ac_tool_warned=yes ;; ++esac ++ STRIP=$ac_ct_STRIP ++ fi ++else ++ STRIP="$ac_cv_prog_STRIP" ++fi ++ ++test -z "$STRIP" && STRIP=: ++ ++ ++ ++ ++ ++ ++if test -n "$ac_tool_prefix"; then ++ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. ++set dummy ${ac_tool_prefix}ranlib; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_RANLIB+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$RANLIB"; then ++ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++RANLIB=$ac_cv_prog_RANLIB ++if test -n "$RANLIB"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 ++$as_echo "$RANLIB" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++fi ++if test -z "$ac_cv_prog_RANLIB"; then ++ ac_ct_RANLIB=$RANLIB ++ # Extract the first word of "ranlib", so it can be a program name with args. ++set dummy ranlib; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$ac_ct_RANLIB"; then ++ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_ac_ct_RANLIB="ranlib" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB ++if test -n "$ac_ct_RANLIB"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 ++$as_echo "$ac_ct_RANLIB" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ if test "x$ac_ct_RANLIB" = x; then ++ RANLIB=":" ++ else ++ case $cross_compiling:$ac_tool_warned in ++yes:) ++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 ++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ++ac_tool_warned=yes ;; ++esac ++ RANLIB=$ac_ct_RANLIB ++ fi ++else ++ RANLIB="$ac_cv_prog_RANLIB" ++fi ++ ++test -z "$RANLIB" && RANLIB=: ++ ++ ++ ++ ++ ++ ++# Determine commands to create old-style static archives. ++old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' ++old_postinstall_cmds='chmod 644 $oldlib' ++old_postuninstall_cmds= ++ ++if test -n "$RANLIB"; then ++ case $host_os in ++ openbsd*) ++ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" ++ ;; ++ *) ++ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" ++ ;; ++ esac ++ old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" ++fi ++ ++case $host_os in ++ darwin*) ++ lock_old_archive_extraction=yes ;; ++ *) ++ lock_old_archive_extraction=no ;; ++esac ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++# If no C compiler was specified, use CC. ++LTCC=${LTCC-"$CC"} ++ ++# If no C compiler flags were specified, use CFLAGS. ++LTCFLAGS=${LTCFLAGS-"$CFLAGS"} ++ ++# Allow CC to be a program name with arguments. ++compiler=$CC ++ ++ ++# Check for command to grab the raw symbol name followed by C symbol from nm. ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 ++$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } ++if ${lt_cv_sys_global_symbol_pipe+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ++# These are sane defaults that work on at least a few old systems. ++# [They come from Ultrix. What could be older than Ultrix?!! ;)] ++ ++# Character class describing NM global symbol codes. ++symcode='[BCDEGRST]' ++ ++# Regexp to match symbols that can be accessed directly from C. ++sympat='\([_A-Za-z][_A-Za-z0-9]*\)' ++ ++# Define system-specific variables. ++case $host_os in ++aix*) ++ symcode='[BCDT]' ++ ;; ++cygwin* | mingw* | pw32* | cegcc*) ++ symcode='[ABCDGISTW]' ++ ;; ++hpux*) ++ if test "$host_cpu" = ia64; then ++ symcode='[ABCDEGRST]' ++ fi ++ ;; ++irix* | nonstopux*) ++ symcode='[BCDEGRST]' ++ ;; ++osf*) ++ symcode='[BCDEGQRST]' ++ ;; ++solaris*) ++ symcode='[BDRT]' ++ ;; ++sco3.2v5*) ++ symcode='[DT]' ++ ;; ++sysv4.2uw2*) ++ symcode='[DT]' ++ ;; ++sysv5* | sco5v6* | unixware* | OpenUNIX*) ++ symcode='[ABDT]' ++ ;; ++sysv4) ++ symcode='[DFNSTU]' ++ ;; ++esac ++ ++# If we're using GNU nm, then use its standard symbol codes. ++case `$NM -V 2>&1` in ++*GNU* | *'with BFD'*) ++ symcode='[ABCDGIRSTW]' ;; ++esac ++ ++# Transform an extracted symbol line into a proper C declaration. ++# Some systems (esp. on ia64) link data and code symbols differently, ++# so use this general approach. ++lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" ++ ++# Transform an extracted symbol line into symbol name and symbol address ++lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" ++lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" ++ ++# Handle CRLF in mingw tool chain ++opt_cr= ++case $build_os in ++mingw*) ++ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ++ ;; ++esac ++ ++# Try without a prefix underscore, then with it. ++for ac_symprfx in "" "_"; do ++ ++ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. ++ symxfrm="\\1 $ac_symprfx\\2 \\2" ++ ++ # Write the raw and C identifiers. ++ if test "$lt_cv_nm_interface" = "MS dumpbin"; then ++ # Fake it for dumpbin and say T for any non-static function ++ # and D for any global variable. ++ # Also find C++ and __fastcall symbols from MSVC++, ++ # which start with @ or ?. ++ lt_cv_sys_global_symbol_pipe="$AWK '"\ ++" {last_section=section; section=\$ 3};"\ ++" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ ++" \$ 0!~/External *\|/{next};"\ ++" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ ++" {if(hide[section]) next};"\ ++" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ ++" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ ++" s[1]~/^[@?]/{print s[1], s[1]; next};"\ ++" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ ++" ' prfx=^$ac_symprfx" ++ else ++ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" ++ fi ++ ++ # Check to see that the pipe works correctly. ++ pipe_works=no ++ ++ rm -f conftest* ++ cat > conftest.$ac_ext <<_LT_EOF ++#ifdef __cplusplus ++extern "C" { ++#endif ++char nm_test_var; ++void nm_test_func(void); ++void nm_test_func(void){} ++#ifdef __cplusplus ++} ++#endif ++int main(){nm_test_var='a';nm_test_func();return(0);} ++_LT_EOF ++ ++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 ++ (eval $ac_compile) 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; }; then ++ # Now try to grab the symbols. ++ nlist=conftest.nm ++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 ++ (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; } && test -s "$nlist"; then ++ # Try sorting and uniquifying the output. ++ if sort "$nlist" | uniq > "$nlist"T; then ++ mv -f "$nlist"T "$nlist" ++ else ++ rm -f "$nlist"T ++ fi ++ ++ # Make sure that we snagged all the symbols we need. ++ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then ++ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then ++ cat <<_LT_EOF > conftest.$ac_ext ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++_LT_EOF ++ # Now generate the symbol file. ++ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' ++ ++ cat <<_LT_EOF >> conftest.$ac_ext ++ ++/* The mapping between symbol names and symbols. */ ++const struct { ++ const char *name; ++ void *address; ++} ++lt__PROGRAM__LTX_preloaded_symbols[] = ++{ ++ { "@PROGRAM@", (void *) 0 }, ++_LT_EOF ++ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext ++ cat <<\_LT_EOF >> conftest.$ac_ext ++ {0, (void *) 0} ++}; ++ ++/* This works around a problem in FreeBSD linker */ ++#ifdef FREEBSD_WORKAROUND ++static const void *lt_preloaded_setup() { ++ return lt__PROGRAM__LTX_preloaded_symbols; ++} ++#endif ++ ++#ifdef __cplusplus ++} ++#endif ++_LT_EOF ++ # Now try linking the two files. ++ mv conftest.$ac_objext conftstm.$ac_objext ++ lt_save_LIBS="$LIBS" ++ lt_save_CFLAGS="$CFLAGS" ++ LIBS="conftstm.$ac_objext" ++ CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" ++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 ++ (eval $ac_link) 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; } && test -s conftest${ac_exeext}; then ++ pipe_works=yes ++ fi ++ LIBS="$lt_save_LIBS" ++ CFLAGS="$lt_save_CFLAGS" ++ else ++ echo "cannot find nm_test_func in $nlist" >&5 ++ fi ++ else ++ echo "cannot find nm_test_var in $nlist" >&5 ++ fi ++ else ++ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 ++ fi ++ else ++ echo "$progname: failed program was:" >&5 ++ cat conftest.$ac_ext >&5 ++ fi ++ rm -rf conftest* conftst* ++ ++ # Do not use the global_symbol_pipe unless it works. ++ if test "$pipe_works" = yes; then ++ break ++ else ++ lt_cv_sys_global_symbol_pipe= ++ fi ++done ++ ++fi ++ ++if test -z "$lt_cv_sys_global_symbol_pipe"; then ++ lt_cv_sys_global_symbol_to_cdecl= ++fi ++if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 ++$as_echo "failed" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 ++$as_echo "ok" >&6; } ++fi ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++# Check whether --enable-libtool-lock was given. ++if test "${enable_libtool_lock+set}" = set; then : ++ enableval=$enable_libtool_lock; ++fi ++ ++test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes ++ ++# Some flags need to be propagated to the compiler or linker for good ++# libtool support. ++case $host in ++ia64-*-hpux*) ++ # Find out which ABI we are using. ++ echo 'int i;' > conftest.$ac_ext ++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 ++ (eval $ac_compile) 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; }; then ++ case `/usr/bin/file conftest.$ac_objext` in ++ *ELF-32*) ++ HPUX_IA64_MODE="32" ++ ;; ++ *ELF-64*) ++ HPUX_IA64_MODE="64" ++ ;; ++ esac ++ fi ++ rm -rf conftest* ++ ;; ++*-*-irix6*) ++ # Find out which ABI we are using. ++ echo '#line '$LINENO' "configure"' > conftest.$ac_ext ++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 ++ (eval $ac_compile) 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; }; then ++ if test "$lt_cv_prog_gnu_ld" = yes; then ++ case `/usr/bin/file conftest.$ac_objext` in ++ *32-bit*) ++ LD="${LD-ld} -melf32bsmip" ++ ;; ++ *N32*) ++ LD="${LD-ld} -melf32bmipn32" ++ ;; ++ *64-bit*) ++ LD="${LD-ld} -melf64bmip" ++ ;; ++ esac ++ else ++ case `/usr/bin/file conftest.$ac_objext` in ++ *32-bit*) ++ LD="${LD-ld} -32" ++ ;; ++ *N32*) ++ LD="${LD-ld} -n32" ++ ;; ++ *64-bit*) ++ LD="${LD-ld} -64" ++ ;; ++ esac ++ fi ++ fi ++ rm -rf conftest* ++ ;; ++ ++x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ ++s390*-*linux*|s390*-*tpf*|sparc*-*linux*) ++ # Find out which ABI we are using. ++ echo 'int i;' > conftest.$ac_ext ++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 ++ (eval $ac_compile) 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; }; then ++ case `/usr/bin/file conftest.o` in ++ *32-bit*) ++ case $host in ++ x86_64-*kfreebsd*-gnu) ++ LD="${LD-ld} -m elf_i386_fbsd" ++ ;; ++ x86_64-*linux*) ++ case `/usr/bin/file conftest.o` in ++ *x86-64*) ++ LD="${LD-ld} -m elf32_x86_64" ++ ;; ++ *) ++ LD="${LD-ld} -m elf_i386" ++ ;; ++ esac ++ ;; ++ powerpc64le-*linux*) ++ LD="${LD-ld} -m elf32lppclinux" ++ ;; ++ powerpc64-*linux*) ++ LD="${LD-ld} -m elf32ppclinux" ++ ;; ++ s390x-*linux*) ++ LD="${LD-ld} -m elf_s390" ++ ;; ++ sparc64-*linux*) ++ LD="${LD-ld} -m elf32_sparc" ++ ;; ++ esac ++ ;; ++ *64-bit*) ++ case $host in ++ x86_64-*kfreebsd*-gnu) ++ LD="${LD-ld} -m elf_x86_64_fbsd" ++ ;; ++ x86_64-*linux*) ++ LD="${LD-ld} -m elf_x86_64" ++ ;; ++ powerpcle-*linux*) ++ LD="${LD-ld} -m elf64lppc" ++ ;; ++ powerpc-*linux*) ++ LD="${LD-ld} -m elf64ppc" ++ ;; ++ s390*-*linux*|s390*-*tpf*) ++ LD="${LD-ld} -m elf64_s390" ++ ;; ++ sparc*-*linux*) ++ LD="${LD-ld} -m elf64_sparc" ++ ;; ++ esac ++ ;; ++ esac ++ fi ++ rm -rf conftest* ++ ;; ++ ++*-*-sco3.2v5*) ++ # On SCO OpenServer 5, we need -belf to get full-featured binaries. ++ SAVE_CFLAGS="$CFLAGS" ++ CFLAGS="$CFLAGS -belf" ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 ++$as_echo_n "checking whether the C compiler needs -belf... " >&6; } ++if ${lt_cv_cc_needs_belf+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ 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 ++ ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ lt_cv_cc_needs_belf=yes ++else ++ lt_cv_cc_needs_belf=no ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++ 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 ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 ++$as_echo "$lt_cv_cc_needs_belf" >&6; } ++ if test x"$lt_cv_cc_needs_belf" != x"yes"; then ++ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf ++ CFLAGS="$SAVE_CFLAGS" ++ fi ++ ;; ++sparc*-*solaris*) ++ # Find out which ABI we are using. ++ echo 'int i;' > conftest.$ac_ext ++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 ++ (eval $ac_compile) 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; }; then ++ case `/usr/bin/file conftest.o` in ++ *64-bit*) ++ case $lt_cv_prog_gnu_ld in ++ yes*) LD="${LD-ld} -m elf64_sparc" ;; ++ *) ++ if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then ++ LD="${LD-ld} -64" ++ fi ++ ;; ++ esac ++ ;; ++ esac ++ fi ++ rm -rf conftest* ++ ;; ++esac ++ ++need_locks="$enable_libtool_lock" ++ ++ ++ case $host_os in ++ rhapsody* | darwin*) ++ if test -n "$ac_tool_prefix"; then ++ # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. ++set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_DSYMUTIL+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$DSYMUTIL"; then ++ ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++DSYMUTIL=$ac_cv_prog_DSYMUTIL ++if test -n "$DSYMUTIL"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 ++$as_echo "$DSYMUTIL" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++fi ++if test -z "$ac_cv_prog_DSYMUTIL"; then ++ ac_ct_DSYMUTIL=$DSYMUTIL ++ # Extract the first word of "dsymutil", so it can be a program name with args. ++set dummy dsymutil; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$ac_ct_DSYMUTIL"; then ++ ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL ++if test -n "$ac_ct_DSYMUTIL"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 ++$as_echo "$ac_ct_DSYMUTIL" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ if test "x$ac_ct_DSYMUTIL" = x; then ++ DSYMUTIL=":" ++ else ++ case $cross_compiling:$ac_tool_warned in ++yes:) ++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 ++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ++ac_tool_warned=yes ;; ++esac ++ DSYMUTIL=$ac_ct_DSYMUTIL ++ fi ++else ++ DSYMUTIL="$ac_cv_prog_DSYMUTIL" ++fi ++ ++ if test -n "$ac_tool_prefix"; then ++ # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. ++set dummy ${ac_tool_prefix}nmedit; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_NMEDIT+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$NMEDIT"; then ++ ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++NMEDIT=$ac_cv_prog_NMEDIT ++if test -n "$NMEDIT"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 ++$as_echo "$NMEDIT" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++fi ++if test -z "$ac_cv_prog_NMEDIT"; then ++ ac_ct_NMEDIT=$NMEDIT ++ # Extract the first word of "nmedit", so it can be a program name with args. ++set dummy nmedit; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$ac_ct_NMEDIT"; then ++ ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_ac_ct_NMEDIT="nmedit" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT ++if test -n "$ac_ct_NMEDIT"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 ++$as_echo "$ac_ct_NMEDIT" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ if test "x$ac_ct_NMEDIT" = x; then ++ NMEDIT=":" ++ else ++ case $cross_compiling:$ac_tool_warned in ++yes:) ++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 ++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ++ac_tool_warned=yes ;; ++esac ++ NMEDIT=$ac_ct_NMEDIT ++ fi ++else ++ NMEDIT="$ac_cv_prog_NMEDIT" ++fi ++ ++ if test -n "$ac_tool_prefix"; then ++ # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. ++set dummy ${ac_tool_prefix}lipo; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_LIPO+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$LIPO"; then ++ ac_cv_prog_LIPO="$LIPO" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_LIPO="${ac_tool_prefix}lipo" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++LIPO=$ac_cv_prog_LIPO ++if test -n "$LIPO"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 ++$as_echo "$LIPO" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++fi ++if test -z "$ac_cv_prog_LIPO"; then ++ ac_ct_LIPO=$LIPO ++ # Extract the first word of "lipo", so it can be a program name with args. ++set dummy lipo; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_ac_ct_LIPO+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$ac_ct_LIPO"; then ++ ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_ac_ct_LIPO="lipo" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO ++if test -n "$ac_ct_LIPO"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 ++$as_echo "$ac_ct_LIPO" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ if test "x$ac_ct_LIPO" = x; then ++ LIPO=":" ++ else ++ case $cross_compiling:$ac_tool_warned in ++yes:) ++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 ++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ++ac_tool_warned=yes ;; ++esac ++ LIPO=$ac_ct_LIPO ++ fi ++else ++ LIPO="$ac_cv_prog_LIPO" ++fi ++ ++ if test -n "$ac_tool_prefix"; then ++ # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. ++set dummy ${ac_tool_prefix}otool; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_OTOOL+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$OTOOL"; then ++ ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_OTOOL="${ac_tool_prefix}otool" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++OTOOL=$ac_cv_prog_OTOOL ++if test -n "$OTOOL"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 ++$as_echo "$OTOOL" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++fi ++if test -z "$ac_cv_prog_OTOOL"; then ++ ac_ct_OTOOL=$OTOOL ++ # Extract the first word of "otool", so it can be a program name with args. ++set dummy otool; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$ac_ct_OTOOL"; then ++ ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_ac_ct_OTOOL="otool" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL ++if test -n "$ac_ct_OTOOL"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 ++$as_echo "$ac_ct_OTOOL" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ if test "x$ac_ct_OTOOL" = x; then ++ OTOOL=":" ++ else ++ case $cross_compiling:$ac_tool_warned in ++yes:) ++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 ++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ++ac_tool_warned=yes ;; ++esac ++ OTOOL=$ac_ct_OTOOL ++ fi ++else ++ OTOOL="$ac_cv_prog_OTOOL" ++fi ++ ++ if test -n "$ac_tool_prefix"; then ++ # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. ++set dummy ${ac_tool_prefix}otool64; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_OTOOL64+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$OTOOL64"; then ++ ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++OTOOL64=$ac_cv_prog_OTOOL64 ++if test -n "$OTOOL64"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 ++$as_echo "$OTOOL64" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++fi ++if test -z "$ac_cv_prog_OTOOL64"; then ++ ac_ct_OTOOL64=$OTOOL64 ++ # Extract the first word of "otool64", so it can be a program name with args. ++set dummy otool64; ac_word=$2 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 ++$as_echo_n "checking for $ac_word... " >&6; } ++if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -n "$ac_ct_OTOOL64"; then ++ ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. ++else ++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ for ac_exec_ext in '' $ac_executable_extensions; do ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ++ ac_cv_prog_ac_ct_OTOOL64="otool64" ++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 ++ break 2 ++ fi ++done ++ done ++IFS=$as_save_IFS ++ ++fi ++fi ++ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 ++if test -n "$ac_ct_OTOOL64"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 ++$as_echo "$ac_ct_OTOOL64" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ if test "x$ac_ct_OTOOL64" = x; then ++ OTOOL64=":" ++ else ++ case $cross_compiling:$ac_tool_warned in ++yes:) ++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 ++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ++ac_tool_warned=yes ;; ++esac ++ OTOOL64=$ac_ct_OTOOL64 ++ fi ++else ++ OTOOL64="$ac_cv_prog_OTOOL64" ++fi ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 ++$as_echo_n "checking for -single_module linker flag... " >&6; } ++if ${lt_cv_apple_cc_single_mod+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ lt_cv_apple_cc_single_mod=no ++ if test -z "${LT_MULTI_MODULE}"; then ++ # By default we will add the -single_module flag. You can override ++ # by either setting the environment variable LT_MULTI_MODULE ++ # non-empty at configure time, or by adding -multi_module to the ++ # link flags. ++ rm -rf libconftest.dylib* ++ echo "int foo(void){return 1;}" > conftest.c ++ echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ ++-dynamiclib -Wl,-single_module conftest.c" >&5 ++ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ ++ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err ++ _lt_result=$? ++ if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then ++ lt_cv_apple_cc_single_mod=yes ++ else ++ cat conftest.err >&5 ++ fi ++ rm -rf libconftest.dylib* ++ rm -f conftest.* ++ fi ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 ++$as_echo "$lt_cv_apple_cc_single_mod" >&6; } ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 ++$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } ++if ${lt_cv_ld_exported_symbols_list+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ lt_cv_ld_exported_symbols_list=no ++ save_LDFLAGS=$LDFLAGS ++ echo "_main" > conftest.sym ++ LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ lt_cv_ld_exported_symbols_list=yes ++else ++ lt_cv_ld_exported_symbols_list=no ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++ LDFLAGS="$save_LDFLAGS" ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 ++$as_echo "$lt_cv_ld_exported_symbols_list" >&6; } ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 ++$as_echo_n "checking for -force_load linker flag... " >&6; } ++if ${lt_cv_ld_force_load+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ lt_cv_ld_force_load=no ++ cat > conftest.c << _LT_EOF ++int forced_loaded() { return 2;} ++_LT_EOF ++ echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 ++ $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 ++ echo "$AR cru libconftest.a conftest.o" >&5 ++ $AR cru libconftest.a conftest.o 2>&5 ++ cat > conftest.c << _LT_EOF ++int main() { return 0;} ++_LT_EOF ++ echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 ++ $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err ++ _lt_result=$? ++ if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then ++ lt_cv_ld_force_load=yes ++ else ++ cat conftest.err >&5 ++ fi ++ rm -f conftest.err libconftest.a conftest conftest.c ++ rm -rf conftest.dSYM ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 ++$as_echo "$lt_cv_ld_force_load" >&6; } ++ case $host_os in ++ rhapsody* | darwin1.[012]) ++ _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; ++ darwin1.*) ++ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; ++ darwin*) # darwin 5.x on ++ # if running on 10.5 or later, the deployment target defaults ++ # to the OS version, if on x86, and 10.4, the deployment ++ # target defaults to 10.4. Don't you love it? ++ case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in ++ 10.0,*86*-darwin8*|10.0,*-darwin[91]*) ++ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; ++ 10.[012][,.]*) ++ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; ++ 10.*) ++ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; ++ esac ++ ;; ++ esac ++ if test "$lt_cv_apple_cc_single_mod" = "yes"; then ++ _lt_dar_single_mod='$single_module' ++ fi ++ if test "$lt_cv_ld_exported_symbols_list" = "yes"; then ++ _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' ++ else ++ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' ++ fi ++ if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then ++ _lt_dsymutil='~$DSYMUTIL $lib || :' ++ else ++ _lt_dsymutil= ++ fi ++ ;; ++ esac ++ ++for ac_header in dlfcn.h ++do : ++ ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default ++" ++if test "x$ac_cv_header_dlfcn_h" = xyes; then : ++ cat >>confdefs.h <<_ACEOF ++#define HAVE_DLFCN_H 1 ++_ACEOF ++ ++fi ++ ++done ++ ++ ++ ++ ++ ++ ++# Set options ++ ++ ++ ++ enable_dlopen=no ++ ++ ++ enable_win32_dll=no ++ ++ ++ # Check whether --enable-shared was given. ++if test "${enable_shared+set}" = set; then : ++ enableval=$enable_shared; p=${PACKAGE-default} ++ case $enableval in ++ yes) enable_shared=yes ;; ++ no) enable_shared=no ;; ++ *) ++ enable_shared=no ++ # Look at the argument we got. We use all the common list separators. ++ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," ++ for pkg in $enableval; do ++ IFS="$lt_save_ifs" ++ if test "X$pkg" = "X$p"; then ++ enable_shared=yes ++ fi ++ done ++ IFS="$lt_save_ifs" ++ ;; ++ esac ++else ++ enable_shared=yes ++fi ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ # Check whether --enable-static was given. ++if test "${enable_static+set}" = set; then : ++ enableval=$enable_static; p=${PACKAGE-default} ++ case $enableval in ++ yes) enable_static=yes ;; ++ no) enable_static=no ;; ++ *) ++ enable_static=no ++ # Look at the argument we got. We use all the common list separators. ++ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," ++ for pkg in $enableval; do ++ IFS="$lt_save_ifs" ++ if test "X$pkg" = "X$p"; then ++ enable_static=yes ++ fi ++ done ++ IFS="$lt_save_ifs" ++ ;; ++ esac ++else ++ enable_static=yes ++fi ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++# Check whether --with-pic was given. ++if test "${with_pic+set}" = set; then : ++ withval=$with_pic; pic_mode="$withval" ++else ++ pic_mode=default ++fi ++ ++ ++test -z "$pic_mode" && pic_mode=default ++ ++ ++ ++ ++ ++ ++ ++ # Check whether --enable-fast-install was given. ++if test "${enable_fast_install+set}" = set; then : ++ enableval=$enable_fast_install; p=${PACKAGE-default} ++ case $enableval in ++ yes) enable_fast_install=yes ;; ++ no) enable_fast_install=no ;; ++ *) ++ enable_fast_install=no ++ # Look at the argument we got. We use all the common list separators. ++ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," ++ for pkg in $enableval; do ++ IFS="$lt_save_ifs" ++ if test "X$pkg" = "X$p"; then ++ enable_fast_install=yes ++ fi ++ done ++ IFS="$lt_save_ifs" ++ ;; ++ esac ++else ++ enable_fast_install=yes ++fi ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++# This can be used to rebuild libtool when needed ++LIBTOOL_DEPS="$ltmain" ++ ++# Always use our own libtool. ++LIBTOOL='$(SHELL) $(top_builddir)/libtool' ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++test -z "$LN_S" && LN_S="ln -s" ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++if test -n "${ZSH_VERSION+set}" ; then ++ setopt NO_GLOB_SUBST ++fi ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 ++$as_echo_n "checking for objdir... " >&6; } ++if ${lt_cv_objdir+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ rm -f .libs 2>/dev/null ++mkdir .libs 2>/dev/null ++if test -d .libs; then ++ lt_cv_objdir=.libs ++else ++ # MS-DOS does not allow filenames that begin with a dot. ++ lt_cv_objdir=_libs ++fi ++rmdir .libs 2>/dev/null ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 ++$as_echo "$lt_cv_objdir" >&6; } ++objdir=$lt_cv_objdir ++ ++ ++ ++ ++ ++cat >>confdefs.h <<_ACEOF ++#define LT_OBJDIR "$lt_cv_objdir/" ++_ACEOF ++ ++ ++ ++ ++case $host_os in ++aix3*) ++ # AIX sometimes has problems with the GCC collect2 program. For some ++ # reason, if we set the COLLECT_NAMES environment variable, the problems ++ # vanish in a puff of smoke. ++ if test "X${COLLECT_NAMES+set}" != Xset; then ++ COLLECT_NAMES= ++ export COLLECT_NAMES ++ fi ++ ;; ++esac ++ ++# Global variables: ++ofile=libtool ++can_build_shared=yes ++ ++# All known linkers require a `.a' archive for static linking (except MSVC, ++# which needs '.lib'). ++libext=a ++ ++with_gnu_ld="$lt_cv_prog_gnu_ld" ++ ++old_CC="$CC" ++old_CFLAGS="$CFLAGS" ++ ++# Set sane defaults for various variables ++test -z "$CC" && CC=cc ++test -z "$LTCC" && LTCC=$CC ++test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS ++test -z "$LD" && LD=ld ++test -z "$ac_objext" && ac_objext=o ++ ++for cc_temp in $compiler""; do ++ case $cc_temp in ++ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; ++ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; ++ \-*) ;; ++ *) break;; ++ esac ++done ++cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` ++ ++ ++# Only perform the check for file, if the check method requires it ++test -z "$MAGIC_CMD" && MAGIC_CMD=file ++case $deplibs_check_method in ++file_magic*) ++ if test "$file_magic_cmd" = '$MAGIC_CMD'; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 ++$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } ++if ${lt_cv_path_MAGIC_CMD+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ case $MAGIC_CMD in ++[\\/*] | ?:[\\/]*) ++ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ++ ;; ++*) ++ lt_save_MAGIC_CMD="$MAGIC_CMD" ++ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ++ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" ++ for ac_dir in $ac_dummy; do ++ IFS="$lt_save_ifs" ++ test -z "$ac_dir" && ac_dir=. ++ if test -f $ac_dir/${ac_tool_prefix}file; then ++ lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" ++ if test -n "$file_magic_test_file"; then ++ case $deplibs_check_method in ++ "file_magic "*) ++ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` ++ MAGIC_CMD="$lt_cv_path_MAGIC_CMD" ++ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | ++ $EGREP "$file_magic_regex" > /dev/null; then ++ : ++ else ++ cat <<_LT_EOF 1>&2 ++ ++*** Warning: the command libtool uses to detect shared libraries, ++*** $file_magic_cmd, produces output that libtool cannot recognize. ++*** The result is that libtool may fail to recognize shared libraries ++*** as such. This will affect the creation of libtool libraries that ++*** depend on shared libraries, but programs linked with such libtool ++*** libraries will work regardless of this problem. Nevertheless, you ++*** may want to report the problem to your system manager and/or to ++*** bug-libtool@gnu.org ++ ++_LT_EOF ++ fi ;; ++ esac ++ fi ++ break ++ fi ++ done ++ IFS="$lt_save_ifs" ++ MAGIC_CMD="$lt_save_MAGIC_CMD" ++ ;; ++esac ++fi ++ ++MAGIC_CMD="$lt_cv_path_MAGIC_CMD" ++if test -n "$MAGIC_CMD"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 ++$as_echo "$MAGIC_CMD" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++ ++ ++ ++if test -z "$lt_cv_path_MAGIC_CMD"; then ++ if test -n "$ac_tool_prefix"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 ++$as_echo_n "checking for file... " >&6; } ++if ${lt_cv_path_MAGIC_CMD+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ case $MAGIC_CMD in ++[\\/*] | ?:[\\/]*) ++ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ++ ;; ++*) ++ lt_save_MAGIC_CMD="$MAGIC_CMD" ++ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ++ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" ++ for ac_dir in $ac_dummy; do ++ IFS="$lt_save_ifs" ++ test -z "$ac_dir" && ac_dir=. ++ if test -f $ac_dir/file; then ++ lt_cv_path_MAGIC_CMD="$ac_dir/file" ++ if test -n "$file_magic_test_file"; then ++ case $deplibs_check_method in ++ "file_magic "*) ++ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` ++ MAGIC_CMD="$lt_cv_path_MAGIC_CMD" ++ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | ++ $EGREP "$file_magic_regex" > /dev/null; then ++ : ++ else ++ cat <<_LT_EOF 1>&2 ++ ++*** Warning: the command libtool uses to detect shared libraries, ++*** $file_magic_cmd, produces output that libtool cannot recognize. ++*** The result is that libtool may fail to recognize shared libraries ++*** as such. This will affect the creation of libtool libraries that ++*** depend on shared libraries, but programs linked with such libtool ++*** libraries will work regardless of this problem. Nevertheless, you ++*** may want to report the problem to your system manager and/or to ++*** bug-libtool@gnu.org ++ ++_LT_EOF ++ fi ;; ++ esac ++ fi ++ break ++ fi ++ done ++ IFS="$lt_save_ifs" ++ MAGIC_CMD="$lt_save_MAGIC_CMD" ++ ;; ++esac ++fi ++ ++MAGIC_CMD="$lt_cv_path_MAGIC_CMD" ++if test -n "$MAGIC_CMD"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 ++$as_echo "$MAGIC_CMD" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++ ++ ++ else ++ MAGIC_CMD=: ++ fi ++fi ++ ++ fi ++ ;; ++esac ++ ++# Use C for the default configuration in the libtool script ++ ++lt_save_CC="$CC" ++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 ++ ++ ++# Source file extension for C test sources. ++ac_ext=c ++ ++# Object file extension for compiled C test sources. ++objext=o ++objext=$objext ++ ++# Code to be used in simple compile tests ++lt_simple_compile_test_code="int some_variable = 0;" ++ ++# Code to be used in simple link tests ++lt_simple_link_test_code='int main(){return(0);}' ++ ++ ++ ++ ++ ++ ++ ++# If no C compiler was specified, use CC. ++LTCC=${LTCC-"$CC"} ++ ++# If no C compiler flags were specified, use CFLAGS. ++LTCFLAGS=${LTCFLAGS-"$CFLAGS"} ++ ++# Allow CC to be a program name with arguments. ++compiler=$CC ++ ++# Save the default compiler, since it gets overwritten when the other ++# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. ++compiler_DEFAULT=$CC ++ ++# save warnings/boilerplate of simple test code ++ac_outfile=conftest.$ac_objext ++echo "$lt_simple_compile_test_code" >conftest.$ac_ext ++eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err ++_lt_compiler_boilerplate=`cat conftest.err` ++$RM conftest* ++ ++ac_outfile=conftest.$ac_objext ++echo "$lt_simple_link_test_code" >conftest.$ac_ext ++eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err ++_lt_linker_boilerplate=`cat conftest.err` ++$RM -r conftest* ++ ++ ++## CAVEAT EMPTOR: ++## There is no encapsulation within the following macros, do not change ++## the running order or otherwise move them around unless you know exactly ++## what you are doing... ++if test -n "$compiler"; then ++ ++lt_prog_compiler_no_builtin_flag= ++ ++if test "$GCC" = yes; then ++ case $cc_basename in ++ nvcc*) ++ lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; ++ *) ++ lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; ++ esac ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 ++$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } ++if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ lt_cv_prog_compiler_rtti_exceptions=no ++ ac_outfile=conftest.$ac_objext ++ echo "$lt_simple_compile_test_code" > conftest.$ac_ext ++ lt_compiler_flag="-fno-rtti -fno-exceptions" ++ # Insert the option either (1) after the last *FLAGS variable, or ++ # (2) before a word containing "conftest.", or (3) at the end. ++ # Note that $ac_compile itself does not contain backslashes and begins ++ # with a dollar sign (not a hyphen), so the echo should work correctly. ++ # The option is referenced via a variable to avoid confusing sed. ++ lt_compile=`echo "$ac_compile" | $SED \ ++ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ ++ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ ++ -e 's:$: $lt_compiler_flag:'` ++ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) ++ (eval "$lt_compile" 2>conftest.err) ++ ac_status=$? ++ cat conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ if (exit $ac_status) && test -s "$ac_outfile"; then ++ # The compiler can only warn and ignore the option if not recognized ++ # So say no if there are warnings other than the usual output. ++ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp ++ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 ++ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then ++ lt_cv_prog_compiler_rtti_exceptions=yes ++ fi ++ fi ++ $RM conftest* ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 ++$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } ++ ++if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then ++ lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" ++else ++ : ++fi ++ ++fi ++ ++ ++ ++ ++ ++ ++ lt_prog_compiler_wl= ++lt_prog_compiler_pic= ++lt_prog_compiler_static= ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 ++$as_echo_n "checking for $compiler option to produce PIC... " >&6; } ++ ++ if test "$GCC" = yes; then ++ lt_prog_compiler_wl='-Wl,' ++ lt_prog_compiler_static='-static' ++ ++ case $host_os in ++ aix*) ++ # All AIX code is PIC. ++ if test "$host_cpu" = ia64; then ++ # AIX 5 now supports IA64 processor ++ lt_prog_compiler_static='-Bstatic' ++ fi ++ lt_prog_compiler_pic='-fPIC' ++ ;; ++ ++ amigaos*) ++ case $host_cpu in ++ powerpc) ++ # see comment about AmigaOS4 .so support ++ lt_prog_compiler_pic='-fPIC' ++ ;; ++ m68k) ++ # FIXME: we need at least 68020 code to build shared libraries, but ++ # adding the `-m68020' flag to GCC prevents building anything better, ++ # like `-m68040'. ++ lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ++ ;; ++ esac ++ ;; ++ ++ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) ++ # PIC is the default for these OSes. ++ ;; ++ ++ mingw* | cygwin* | pw32* | os2* | cegcc*) ++ # This hack is so that the source file can tell whether it is being ++ # built for inclusion in a dll (and should export symbols for example). ++ # Although the cygwin gcc ignores -fPIC, still need this for old-style ++ # (--disable-auto-import) libraries ++ lt_prog_compiler_pic='-DDLL_EXPORT' ++ ;; ++ ++ darwin* | rhapsody*) ++ # PIC is the default on this platform ++ # Common symbols not allowed in MH_DYLIB files ++ lt_prog_compiler_pic='-fno-common' ++ ;; ++ ++ haiku*) ++ # PIC is the default for Haiku. ++ # The "-static" flag exists, but is broken. ++ lt_prog_compiler_static= ++ ;; ++ ++ hpux*) ++ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit ++ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag ++ # sets the default TLS model and affects inlining. ++ case $host_cpu in ++ hppa*64*) ++ # +Z the default ++ ;; ++ *) ++ lt_prog_compiler_pic='-fPIC' ++ ;; ++ esac ++ ;; ++ ++ interix[3-9]*) ++ # Interix 3.x gcc -fpic/-fPIC options generate broken code. ++ # Instead, we relocate shared libraries at runtime. ++ ;; ++ ++ msdosdjgpp*) ++ # Just because we use GCC doesn't mean we suddenly get shared libraries ++ # on systems that don't support them. ++ lt_prog_compiler_can_build_shared=no ++ enable_shared=no ++ ;; ++ ++ *nto* | *qnx*) ++ # QNX uses GNU C++, but need to define -shared option too, otherwise ++ # it will coredump. ++ lt_prog_compiler_pic='-fPIC -shared' ++ ;; ++ ++ sysv4*MP*) ++ if test -d /usr/nec; then ++ lt_prog_compiler_pic=-Kconform_pic ++ fi ++ ;; ++ ++ *) ++ lt_prog_compiler_pic='-fPIC' ++ ;; ++ esac ++ ++ case $cc_basename in ++ nvcc*) # Cuda Compiler Driver 2.2 ++ lt_prog_compiler_wl='-Xlinker ' ++ lt_prog_compiler_pic='-Xcompiler -fPIC' ++ ;; ++ esac ++ else ++ # PORTME Check for flag to pass linker flags through the system compiler. ++ case $host_os in ++ aix*) ++ lt_prog_compiler_wl='-Wl,' ++ if test "$host_cpu" = ia64; then ++ # AIX 5 now supports IA64 processor ++ lt_prog_compiler_static='-Bstatic' ++ else ++ lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' ++ fi ++ ;; ++ ++ mingw* | cygwin* | pw32* | os2* | cegcc*) ++ # This hack is so that the source file can tell whether it is being ++ # built for inclusion in a dll (and should export symbols for example). ++ lt_prog_compiler_pic='-DDLL_EXPORT' ++ ;; ++ ++ hpux9* | hpux10* | hpux11*) ++ lt_prog_compiler_wl='-Wl,' ++ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but ++ # not for PA HP-UX. ++ case $host_cpu in ++ hppa*64*|ia64*) ++ # +Z the default ++ ;; ++ *) ++ lt_prog_compiler_pic='+Z' ++ ;; ++ esac ++ # Is there a better lt_prog_compiler_static that works with the bundled CC? ++ lt_prog_compiler_static='${wl}-a ${wl}archive' ++ ;; ++ ++ irix5* | irix6* | nonstopux*) ++ lt_prog_compiler_wl='-Wl,' ++ # PIC (with -KPIC) is the default. ++ lt_prog_compiler_static='-non_shared' ++ ;; ++ ++ linux* | k*bsd*-gnu | kopensolaris*-gnu) ++ case $cc_basename in ++ # old Intel for x86_64 which still supported -KPIC. ++ ecc*) ++ lt_prog_compiler_wl='-Wl,' ++ lt_prog_compiler_pic='-KPIC' ++ lt_prog_compiler_static='-static' ++ ;; ++ # icc used to be incompatible with GCC. ++ # ICC 10 doesn't accept -KPIC any more. ++ icc* | ifort*) ++ lt_prog_compiler_wl='-Wl,' ++ lt_prog_compiler_pic='-fPIC' ++ lt_prog_compiler_static='-static' ++ ;; ++ # Lahey Fortran 8.1. ++ lf95*) ++ lt_prog_compiler_wl='-Wl,' ++ lt_prog_compiler_pic='--shared' ++ lt_prog_compiler_static='--static' ++ ;; ++ pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) ++ # Portland Group compilers (*not* the Pentium gcc compiler, ++ # which looks to be a dead project) ++ lt_prog_compiler_wl='-Wl,' ++ lt_prog_compiler_pic='-fpic' ++ lt_prog_compiler_static='-Bstatic' ++ ;; ++ ccc*) ++ lt_prog_compiler_wl='-Wl,' ++ # All Alpha code is PIC. ++ lt_prog_compiler_static='-non_shared' ++ ;; ++ xl* | bgxl* | bgf* | mpixl*) ++ # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene ++ lt_prog_compiler_wl='-Wl,' ++ lt_prog_compiler_pic='-qpic' ++ lt_prog_compiler_static='-qstaticlink' ++ ;; ++ *) ++ case `$CC -V 2>&1 | sed 5q` in ++ *Sun\ F* | *Sun*Fortran*) ++ # Sun Fortran 8.3 passes all unrecognized flags to the linker ++ lt_prog_compiler_pic='-KPIC' ++ lt_prog_compiler_static='-Bstatic' ++ lt_prog_compiler_wl='' ++ ;; ++ *Sun\ C*) ++ # Sun C 5.9 ++ lt_prog_compiler_pic='-KPIC' ++ lt_prog_compiler_static='-Bstatic' ++ lt_prog_compiler_wl='-Wl,' ++ ;; ++ esac ++ ;; ++ esac ++ ;; ++ ++ newsos6) ++ lt_prog_compiler_pic='-KPIC' ++ lt_prog_compiler_static='-Bstatic' ++ ;; ++ ++ *nto* | *qnx*) ++ # QNX uses GNU C++, but need to define -shared option too, otherwise ++ # it will coredump. ++ lt_prog_compiler_pic='-fPIC -shared' ++ ;; ++ ++ osf3* | osf4* | osf5*) ++ lt_prog_compiler_wl='-Wl,' ++ # All OSF/1 code is PIC. ++ lt_prog_compiler_static='-non_shared' ++ ;; ++ ++ rdos*) ++ lt_prog_compiler_static='-non_shared' ++ ;; ++ ++ solaris*) ++ lt_prog_compiler_pic='-KPIC' ++ lt_prog_compiler_static='-Bstatic' ++ case $cc_basename in ++ f77* | f90* | f95*) ++ lt_prog_compiler_wl='-Qoption ld ';; ++ *) ++ lt_prog_compiler_wl='-Wl,';; ++ esac ++ ;; ++ ++ sunos4*) ++ lt_prog_compiler_wl='-Qoption ld ' ++ lt_prog_compiler_pic='-PIC' ++ lt_prog_compiler_static='-Bstatic' ++ ;; ++ ++ sysv4 | sysv4.2uw2* | sysv4.3*) ++ lt_prog_compiler_wl='-Wl,' ++ lt_prog_compiler_pic='-KPIC' ++ lt_prog_compiler_static='-Bstatic' ++ ;; ++ ++ sysv4*MP*) ++ if test -d /usr/nec ;then ++ lt_prog_compiler_pic='-Kconform_pic' ++ lt_prog_compiler_static='-Bstatic' ++ fi ++ ;; ++ ++ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) ++ lt_prog_compiler_wl='-Wl,' ++ lt_prog_compiler_pic='-KPIC' ++ lt_prog_compiler_static='-Bstatic' ++ ;; ++ ++ unicos*) ++ lt_prog_compiler_wl='-Wl,' ++ lt_prog_compiler_can_build_shared=no ++ ;; ++ ++ uts4*) ++ lt_prog_compiler_pic='-pic' ++ lt_prog_compiler_static='-Bstatic' ++ ;; ++ ++ *) ++ lt_prog_compiler_can_build_shared=no ++ ;; ++ esac ++ fi ++ ++case $host_os in ++ # For platforms which do not support PIC, -DPIC is meaningless: ++ *djgpp*) ++ lt_prog_compiler_pic= ++ ;; ++ *) ++ lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ++ ;; ++esac ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5 ++$as_echo "$lt_prog_compiler_pic" >&6; } ++ ++ ++ ++ ++ ++ ++# ++# Check to make sure the PIC flag actually works. ++# ++if test -n "$lt_prog_compiler_pic"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 ++$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } ++if ${lt_cv_prog_compiler_pic_works+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ lt_cv_prog_compiler_pic_works=no ++ ac_outfile=conftest.$ac_objext ++ echo "$lt_simple_compile_test_code" > conftest.$ac_ext ++ lt_compiler_flag="$lt_prog_compiler_pic -DPIC" ++ # Insert the option either (1) after the last *FLAGS variable, or ++ # (2) before a word containing "conftest.", or (3) at the end. ++ # Note that $ac_compile itself does not contain backslashes and begins ++ # with a dollar sign (not a hyphen), so the echo should work correctly. ++ # The option is referenced via a variable to avoid confusing sed. ++ lt_compile=`echo "$ac_compile" | $SED \ ++ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ ++ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ ++ -e 's:$: $lt_compiler_flag:'` ++ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) ++ (eval "$lt_compile" 2>conftest.err) ++ ac_status=$? ++ cat conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ if (exit $ac_status) && test -s "$ac_outfile"; then ++ # The compiler can only warn and ignore the option if not recognized ++ # So say no if there are warnings other than the usual output. ++ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp ++ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 ++ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then ++ lt_cv_prog_compiler_pic_works=yes ++ fi ++ fi ++ $RM conftest* ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 ++$as_echo "$lt_cv_prog_compiler_pic_works" >&6; } ++ ++if test x"$lt_cv_prog_compiler_pic_works" = xyes; then ++ case $lt_prog_compiler_pic in ++ "" | " "*) ;; ++ *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; ++ esac ++else ++ lt_prog_compiler_pic= ++ lt_prog_compiler_can_build_shared=no ++fi ++ ++fi ++ ++ ++ ++ ++ ++ ++# ++# Check to make sure the static flag actually works. ++# ++wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 ++$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } ++if ${lt_cv_prog_compiler_static_works+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ lt_cv_prog_compiler_static_works=no ++ save_LDFLAGS="$LDFLAGS" ++ LDFLAGS="$LDFLAGS $lt_tmp_static_flag" ++ echo "$lt_simple_link_test_code" > conftest.$ac_ext ++ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then ++ # The linker can only warn and ignore the option if not recognized ++ # So say no if there are warnings ++ if test -s conftest.err; then ++ # Append any errors to the config.log. ++ cat conftest.err 1>&5 ++ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp ++ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 ++ if diff conftest.exp conftest.er2 >/dev/null; then ++ lt_cv_prog_compiler_static_works=yes ++ fi ++ else ++ lt_cv_prog_compiler_static_works=yes ++ fi ++ fi ++ $RM -r conftest* ++ LDFLAGS="$save_LDFLAGS" ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 ++$as_echo "$lt_cv_prog_compiler_static_works" >&6; } ++ ++if test x"$lt_cv_prog_compiler_static_works" = xyes; then ++ : ++else ++ lt_prog_compiler_static= ++fi ++ ++ ++ ++ ++ ++ ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 ++$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } ++if ${lt_cv_prog_compiler_c_o+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ lt_cv_prog_compiler_c_o=no ++ $RM -r conftest 2>/dev/null ++ mkdir conftest ++ cd conftest ++ mkdir out ++ echo "$lt_simple_compile_test_code" > conftest.$ac_ext ++ ++ lt_compiler_flag="-o out/conftest2.$ac_objext" ++ # Insert the option either (1) after the last *FLAGS variable, or ++ # (2) before a word containing "conftest.", or (3) at the end. ++ # Note that $ac_compile itself does not contain backslashes and begins ++ # with a dollar sign (not a hyphen), so the echo should work correctly. ++ lt_compile=`echo "$ac_compile" | $SED \ ++ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ ++ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ ++ -e 's:$: $lt_compiler_flag:'` ++ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) ++ (eval "$lt_compile" 2>out/conftest.err) ++ ac_status=$? ++ cat out/conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ if (exit $ac_status) && test -s out/conftest2.$ac_objext ++ then ++ # The compiler can only warn and ignore the option if not recognized ++ # So say no if there are warnings ++ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp ++ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 ++ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then ++ lt_cv_prog_compiler_c_o=yes ++ fi ++ fi ++ chmod u+w . 2>&5 ++ $RM conftest* ++ # SGI C++ compiler will create directory out/ii_files/ for ++ # template instantiation ++ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files ++ $RM out/* && rmdir out ++ cd .. ++ $RM -r conftest ++ $RM conftest* ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 ++$as_echo "$lt_cv_prog_compiler_c_o" >&6; } ++ ++ ++ ++ ++ ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 ++$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } ++if ${lt_cv_prog_compiler_c_o+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ lt_cv_prog_compiler_c_o=no ++ $RM -r conftest 2>/dev/null ++ mkdir conftest ++ cd conftest ++ mkdir out ++ echo "$lt_simple_compile_test_code" > conftest.$ac_ext ++ ++ lt_compiler_flag="-o out/conftest2.$ac_objext" ++ # Insert the option either (1) after the last *FLAGS variable, or ++ # (2) before a word containing "conftest.", or (3) at the end. ++ # Note that $ac_compile itself does not contain backslashes and begins ++ # with a dollar sign (not a hyphen), so the echo should work correctly. ++ lt_compile=`echo "$ac_compile" | $SED \ ++ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ ++ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ ++ -e 's:$: $lt_compiler_flag:'` ++ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) ++ (eval "$lt_compile" 2>out/conftest.err) ++ ac_status=$? ++ cat out/conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ if (exit $ac_status) && test -s out/conftest2.$ac_objext ++ then ++ # The compiler can only warn and ignore the option if not recognized ++ # So say no if there are warnings ++ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp ++ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 ++ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then ++ lt_cv_prog_compiler_c_o=yes ++ fi ++ fi ++ chmod u+w . 2>&5 ++ $RM conftest* ++ # SGI C++ compiler will create directory out/ii_files/ for ++ # template instantiation ++ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files ++ $RM out/* && rmdir out ++ cd .. ++ $RM -r conftest ++ $RM conftest* ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 ++$as_echo "$lt_cv_prog_compiler_c_o" >&6; } ++ ++ ++ ++ ++hard_links="nottested" ++if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then ++ # do not overwrite the value of need_locks provided by the user ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 ++$as_echo_n "checking if we can lock with hard links... " >&6; } ++ hard_links=yes ++ $RM conftest* ++ ln conftest.a conftest.b 2>/dev/null && hard_links=no ++ touch conftest.a ++ ln conftest.a conftest.b 2>&5 || hard_links=no ++ ln conftest.a conftest.b 2>/dev/null && hard_links=no ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 ++$as_echo "$hard_links" >&6; } ++ if test "$hard_links" = no; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 ++$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} ++ need_locks=warn ++ fi ++else ++ need_locks=no ++fi ++ ++ ++ ++ ++ ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 ++$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } ++ ++ runpath_var= ++ allow_undefined_flag= ++ always_export_symbols=no ++ archive_cmds= ++ archive_expsym_cmds= ++ compiler_needs_object=no ++ enable_shared_with_static_runtimes=no ++ export_dynamic_flag_spec= ++ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ++ hardcode_automatic=no ++ hardcode_direct=no ++ hardcode_direct_absolute=no ++ hardcode_libdir_flag_spec= ++ hardcode_libdir_flag_spec_ld= ++ hardcode_libdir_separator= ++ hardcode_minus_L=no ++ hardcode_shlibpath_var=unsupported ++ inherit_rpath=no ++ link_all_deplibs=unknown ++ module_cmds= ++ module_expsym_cmds= ++ old_archive_from_new_cmds= ++ old_archive_from_expsyms_cmds= ++ thread_safe_flag_spec= ++ whole_archive_flag_spec= ++ # include_expsyms should be a list of space-separated symbols to be *always* ++ # included in the symbol list ++ include_expsyms= ++ # exclude_expsyms can be an extended regexp of symbols to exclude ++ # it will be wrapped by ` (' and `)$', so one must not match beginning or ++ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', ++ # as well as any symbol that contains `d'. ++ exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' ++ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out ++ # platforms (ab)use it in PIC code, but their linkers get confused if ++ # the symbol is explicitly referenced. Since portable code cannot ++ # rely on this symbol name, it's probably fine to never include it in ++ # preloaded symbol tables. ++ # Exclude shared library initialization/finalization symbols. ++ extract_expsyms_cmds= ++ ++ case $host_os in ++ cygwin* | mingw* | pw32* | cegcc*) ++ # FIXME: the MSVC++ port hasn't been tested in a loooong time ++ # When not using gcc, we currently assume that we are using ++ # Microsoft Visual C++. ++ if test "$GCC" != yes; then ++ with_gnu_ld=no ++ fi ++ ;; ++ interix*) ++ # we just hope/assume this is gcc and not c89 (= MSVC++) ++ with_gnu_ld=yes ++ ;; ++ openbsd*) ++ with_gnu_ld=no ++ ;; ++ esac ++ ++ ld_shlibs=yes ++ ++ # On some targets, GNU ld is compatible enough with the native linker ++ # that we're better off using the native interface for both. ++ lt_use_gnu_ld_interface=no ++ if test "$with_gnu_ld" = yes; then ++ case $host_os in ++ aix*) ++ # The AIX port of GNU ld has always aspired to compatibility ++ # with the native linker. However, as the warning in the GNU ld ++ # block says, versions before 2.19.5* couldn't really create working ++ # shared libraries, regardless of the interface used. ++ case `$LD -v 2>&1` in ++ *\ \(GNU\ Binutils\)\ 2.19.5*) ;; ++ *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; ++ *\ \(GNU\ Binutils\)\ [3-9]*) ;; ++ *) ++ lt_use_gnu_ld_interface=yes ++ ;; ++ esac ++ ;; ++ *) ++ lt_use_gnu_ld_interface=yes ++ ;; ++ esac ++ fi ++ ++ if test "$lt_use_gnu_ld_interface" = yes; then ++ # If archive_cmds runs LD, not CC, wlarc should be empty ++ wlarc='${wl}' ++ ++ # Set some defaults for GNU ld with shared library support. These ++ # are reset later if shared libraries are not supported. Putting them ++ # here allows them to be overridden if necessary. ++ runpath_var=LD_RUN_PATH ++ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' ++ export_dynamic_flag_spec='${wl}--export-dynamic' ++ # ancient GNU ld didn't support --whole-archive et. al. ++ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then ++ whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' ++ else ++ whole_archive_flag_spec= ++ fi ++ supports_anon_versioning=no ++ case `$LD -v 2>&1` in ++ *GNU\ gold*) supports_anon_versioning=yes ;; ++ *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 ++ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... ++ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... ++ *\ 2.11.*) ;; # other 2.11 versions ++ *) supports_anon_versioning=yes ;; ++ esac ++ ++ # See if GNU ld supports shared libraries. ++ case $host_os in ++ aix[3-9]*) ++ # On AIX/PPC, the GNU linker is very broken ++ if test "$host_cpu" != ia64; then ++ ld_shlibs=no ++ cat <<_LT_EOF 1>&2 ++ ++*** Warning: the GNU linker, at least up to release 2.19, is reported ++*** to be unable to reliably create shared libraries on AIX. ++*** Therefore, libtool is disabling shared libraries support. If you ++*** really care for shared libraries, you may want to install binutils ++*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. ++*** You will then need to restart the configuration process. ++ ++_LT_EOF ++ fi ++ ;; ++ ++ amigaos*) ++ case $host_cpu in ++ powerpc) ++ # see comment about AmigaOS4 .so support ++ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' ++ archive_expsym_cmds='' ++ ;; ++ m68k) ++ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' ++ hardcode_libdir_flag_spec='-L$libdir' ++ hardcode_minus_L=yes ++ ;; ++ esac ++ ;; ++ ++ beos*) ++ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then ++ allow_undefined_flag=unsupported ++ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc ++ # support --undefined. This deserves some investigation. FIXME ++ archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' ++ else ++ ld_shlibs=no ++ fi ++ ;; ++ ++ cygwin* | mingw* | pw32* | cegcc*) ++ # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, ++ # as there is no search path for DLLs. ++ hardcode_libdir_flag_spec='-L$libdir' ++ export_dynamic_flag_spec='${wl}--export-all-symbols' ++ allow_undefined_flag=unsupported ++ always_export_symbols=no ++ enable_shared_with_static_runtimes=yes ++ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' ++ ++ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then ++ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' ++ # If the export-symbols file already is a .def file (1st line ++ # is EXPORTS), use it as is; otherwise, prepend... ++ archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then ++ cp $export_symbols $output_objdir/$soname.def; ++ else ++ echo EXPORTS > $output_objdir/$soname.def; ++ cat $export_symbols >> $output_objdir/$soname.def; ++ fi~ ++ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' ++ else ++ ld_shlibs=no ++ fi ++ ;; ++ ++ haiku*) ++ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' ++ link_all_deplibs=yes ++ ;; ++ ++ interix[3-9]*) ++ hardcode_direct=no ++ hardcode_shlibpath_var=no ++ hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ++ export_dynamic_flag_spec='${wl}-E' ++ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. ++ # Instead, shared libraries are loaded at an image base (0x10000000 by ++ # default) and relocated if they conflict, which is a slow very memory ++ # consuming and fragmenting process. To avoid this, we pick a random, ++ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link ++ # time. Moving up from 0x10000000 also allows more sbrk(2) space. ++ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ++ archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ++ ;; ++ ++ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) ++ tmp_diet=no ++ if test "$host_os" = linux-dietlibc; then ++ case $cc_basename in ++ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) ++ esac ++ fi ++ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ ++ && test "$tmp_diet" = no ++ then ++ tmp_addflag=' $pic_flag' ++ tmp_sharedflag='-shared' ++ case $cc_basename,$host_cpu in ++ pgcc*) # Portland Group C compiler ++ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ++ tmp_addflag=' $pic_flag' ++ ;; ++ pgf77* | pgf90* | pgf95* | pgfortran*) ++ # Portland Group f77 and f90 compilers ++ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ++ tmp_addflag=' $pic_flag -Mnomain' ;; ++ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 ++ tmp_addflag=' -i_dynamic' ;; ++ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 ++ tmp_addflag=' -i_dynamic -nofor_main' ;; ++ ifc* | ifort*) # Intel Fortran compiler ++ tmp_addflag=' -nofor_main' ;; ++ lf95*) # Lahey Fortran 8.1 ++ whole_archive_flag_spec= ++ tmp_sharedflag='--shared' ;; ++ xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) ++ tmp_sharedflag='-qmkshrobj' ++ tmp_addflag= ;; ++ nvcc*) # Cuda Compiler Driver 2.2 ++ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ++ compiler_needs_object=yes ++ ;; ++ esac ++ case `$CC -V 2>&1 | sed 5q` in ++ *Sun\ C*) # Sun C 5.9 ++ whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ++ compiler_needs_object=yes ++ tmp_sharedflag='-G' ;; ++ *Sun\ F*) # Sun Fortran 8.3 ++ tmp_sharedflag='-G' ;; ++ esac ++ archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' ++ ++ if test "x$supports_anon_versioning" = xyes; then ++ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ ++ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ ++ echo "local: *; };" >> $output_objdir/$libname.ver~ ++ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' ++ fi ++ ++ case $cc_basename in ++ xlf* | bgf* | bgxlf* | mpixlf*) ++ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself ++ whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' ++ hardcode_libdir_flag_spec= ++ hardcode_libdir_flag_spec_ld='-rpath $libdir' ++ archive_cmds='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' ++ if test "x$supports_anon_versioning" = xyes; then ++ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ ++ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ ++ echo "local: *; };" >> $output_objdir/$libname.ver~ ++ $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' ++ fi ++ ;; ++ esac ++ else ++ ld_shlibs=no ++ fi ++ ;; ++ ++ netbsd*) ++ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then ++ archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' ++ wlarc= ++ else ++ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' ++ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ++ fi ++ ;; ++ ++ solaris*) ++ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then ++ ld_shlibs=no ++ cat <<_LT_EOF 1>&2 ++ ++*** Warning: The releases 2.8.* of the GNU linker cannot reliably ++*** create shared libraries on Solaris systems. Therefore, libtool ++*** is disabling shared libraries support. We urge you to upgrade GNU ++*** binutils to release 2.9.1 or newer. Another option is to modify ++*** your PATH or compiler configuration so that the native linker is ++*** used, and then restart. ++ ++_LT_EOF ++ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then ++ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' ++ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ++ else ++ ld_shlibs=no ++ fi ++ ;; ++ ++ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) ++ case `$LD -v 2>&1` in ++ *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ++ ld_shlibs=no ++ cat <<_LT_EOF 1>&2 ++ ++*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not ++*** reliably create shared libraries on SCO systems. Therefore, libtool ++*** is disabling shared libraries support. We urge you to upgrade GNU ++*** binutils to release 2.16.91.0.3 or newer. Another option is to modify ++*** your PATH or compiler configuration so that the native linker is ++*** used, and then restart. ++ ++_LT_EOF ++ ;; ++ *) ++ # For security reasons, it is highly recommended that you always ++ # use absolute paths for naming shared libraries, and exclude the ++ # DT_RUNPATH tag from executables and libraries. But doing so ++ # requires that you compile everything twice, which is a pain. ++ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then ++ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' ++ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' ++ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ++ else ++ ld_shlibs=no ++ fi ++ ;; ++ esac ++ ;; ++ ++ sunos4*) ++ archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' ++ wlarc= ++ hardcode_direct=yes ++ hardcode_shlibpath_var=no ++ ;; ++ ++ *) ++ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then ++ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' ++ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ++ else ++ ld_shlibs=no ++ fi ++ ;; ++ esac ++ ++ if test "$ld_shlibs" = no; then ++ runpath_var= ++ hardcode_libdir_flag_spec= ++ export_dynamic_flag_spec= ++ whole_archive_flag_spec= ++ fi ++ else ++ # PORTME fill in a description of your system's linker (not GNU ld) ++ case $host_os in ++ aix3*) ++ allow_undefined_flag=unsupported ++ always_export_symbols=yes ++ archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' ++ # Note: this linker hardcodes the directories in LIBPATH if there ++ # are no directories specified by -L. ++ hardcode_minus_L=yes ++ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then ++ # Neither direct hardcoding nor static linking is supported with a ++ # broken collect2. ++ hardcode_direct=unsupported ++ fi ++ ;; ++ ++ aix[4-9]*) ++ if test "$host_cpu" = ia64; then ++ # On IA64, the linker does run time linking by default, so we don't ++ # have to do anything special. ++ aix_use_runtimelinking=no ++ exp_sym_flag='-Bexport' ++ no_entry_flag="" ++ else ++ # If we're using GNU nm, then we don't want the "-C" option. ++ # -C means demangle to AIX nm, but means don't demangle with GNU nm ++ # Also, AIX nm treats weak defined symbols like other global ++ # defined symbols, whereas GNU nm marks them as "W". ++ 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") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' ++ fi ++ aix_use_runtimelinking=no ++ ++ # Test if we are trying to use run time linking or normal ++ # AIX style linking. If -brtl is somewhere in LDFLAGS, we ++ # need to do runtime linking. ++ case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) ++ for ld_flag in $LDFLAGS; do ++ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then ++ aix_use_runtimelinking=yes ++ break ++ fi ++ done ++ ;; ++ esac ++ ++ exp_sym_flag='-bexport' ++ no_entry_flag='-bnoentry' ++ fi ++ ++ # When large executables or shared objects are built, AIX ld can ++ # have problems creating the table of contents. If linking a library ++ # or program results in "error TOC overflow" add -mminimal-toc to ++ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not ++ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. ++ ++ archive_cmds='' ++ hardcode_direct=yes ++ hardcode_direct_absolute=yes ++ hardcode_libdir_separator=':' ++ link_all_deplibs=yes ++ file_list_spec='${wl}-f,' ++ ++ if test "$GCC" = yes; then ++ case $host_os in aix4.[012]|aix4.[012].*) ++ # We only want to do this on AIX 4.2 and lower, the check ++ # below for broken collect2 doesn't work under 4.3+ ++ collect2name=`${CC} -print-prog-name=collect2` ++ if test -f "$collect2name" && ++ strings "$collect2name" | $GREP resolve_lib_name >/dev/null ++ then ++ # We have reworked collect2 ++ : ++ else ++ # We have old collect2 ++ hardcode_direct=unsupported ++ # It fails to find uninstalled libraries when the uninstalled ++ # path is not listed in the libpath. Setting hardcode_minus_L ++ # to unsupported forces relinking ++ hardcode_minus_L=yes ++ hardcode_libdir_flag_spec='-L$libdir' ++ hardcode_libdir_separator= ++ fi ++ ;; ++ esac ++ shared_flag='-shared' ++ if test "$aix_use_runtimelinking" = yes; then ++ shared_flag="$shared_flag "'${wl}-G' ++ fi ++ else ++ # not using gcc ++ if test "$host_cpu" = ia64; then ++ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release ++ # chokes on -Wl,-G. The following line is correct: ++ shared_flag='-G' ++ else ++ if test "$aix_use_runtimelinking" = yes; then ++ shared_flag='${wl}-G' ++ else ++ shared_flag='${wl}-bM:SRE' ++ fi ++ fi ++ fi ++ ++ export_dynamic_flag_spec='${wl}-bexpall' ++ # It seems that -bexpall does not export symbols beginning with ++ # underscore (_), so it is better to generate a list of symbols to export. ++ always_export_symbols=yes ++ if test "$aix_use_runtimelinking" = yes; then ++ # Warning - without using the other runtime loading flags (-brtl), ++ # -berok will link without error, but may produce a broken library. ++ allow_undefined_flag='-berok' ++ # Determine the default libpath from the value encoded in an ++ # empty executable. ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ ++lt_aix_libpath_sed=' ++ /Import File Strings/,/^$/ { ++ /^0/ { ++ s/^0 *\(.*\)$/\1/ ++ p ++ } ++ }' ++aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` ++# Check for a 64-bit object if we didn't find anything. ++if test -z "$aix_libpath"; then ++ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` ++fi ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi ++ ++ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" ++ archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" ++ else ++ if test "$host_cpu" = ia64; then ++ hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' ++ allow_undefined_flag="-z nodefs" ++ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" ++ else ++ # Determine the default libpath from the value encoded in an ++ # empty executable. ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ ++lt_aix_libpath_sed=' ++ /Import File Strings/,/^$/ { ++ /^0/ { ++ s/^0 *\(.*\)$/\1/ ++ p ++ } ++ }' ++aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` ++# Check for a 64-bit object if we didn't find anything. ++if test -z "$aix_libpath"; then ++ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` ++fi ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi ++ ++ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" ++ # Warning - without using the other run time loading flags, ++ # -berok will link without error, but may produce a broken library. ++ no_undefined_flag=' ${wl}-bernotok' ++ allow_undefined_flag=' ${wl}-berok' ++ if test "$with_gnu_ld" = yes; then ++ # We only use this code for GNU lds that support --whole-archive. ++ whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ++ else ++ # Exported symbols can be pulled into shared objects from archives ++ whole_archive_flag_spec='$convenience' ++ fi ++ archive_cmds_need_lc=yes ++ # This is similar to how AIX traditionally builds its shared libraries. ++ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' ++ fi ++ fi ++ ;; ++ ++ amigaos*) ++ case $host_cpu in ++ powerpc) ++ # see comment about AmigaOS4 .so support ++ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' ++ archive_expsym_cmds='' ++ ;; ++ m68k) ++ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' ++ hardcode_libdir_flag_spec='-L$libdir' ++ hardcode_minus_L=yes ++ ;; ++ esac ++ ;; ++ ++ bsdi[45]*) ++ export_dynamic_flag_spec=-rdynamic ++ ;; ++ ++ cygwin* | mingw* | pw32* | cegcc*) ++ # When not using gcc, we currently assume that we are using ++ # Microsoft Visual C++. ++ # hardcode_libdir_flag_spec is actually meaningless, as there is ++ # no search path for DLLs. ++ hardcode_libdir_flag_spec=' ' ++ allow_undefined_flag=unsupported ++ # Tell ltmain to make .lib files, not .a files. ++ libext=lib ++ # Tell ltmain to make .dll files, not .so files. ++ shrext_cmds=".dll" ++ # FIXME: Setting linknames here is a bad hack. ++ archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' ++ # The linker will automatically build a .lib file if we build a DLL. ++ old_archive_from_new_cmds='true' ++ # FIXME: Should let the user specify the lib program. ++ old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' ++ fix_srcfile_path='`cygpath -w "$srcfile"`' ++ enable_shared_with_static_runtimes=yes ++ ;; ++ ++ darwin* | rhapsody*) ++ ++ ++ archive_cmds_need_lc=no ++ hardcode_direct=no ++ hardcode_automatic=yes ++ hardcode_shlibpath_var=unsupported ++ if test "$lt_cv_ld_force_load" = "yes"; then ++ whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' ++ else ++ whole_archive_flag_spec='' ++ fi ++ link_all_deplibs=yes ++ allow_undefined_flag="$_lt_dar_allow_undefined" ++ case $cc_basename in ++ ifort*) _lt_dar_can_shared=yes ;; ++ *) _lt_dar_can_shared=$GCC ;; ++ esac ++ if test "$_lt_dar_can_shared" = "yes"; then ++ output_verbose_link_cmd=func_echo_all ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ ++ else ++ ld_shlibs=no ++ fi ++ ++ ;; ++ ++ dgux*) ++ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' ++ hardcode_libdir_flag_spec='-L$libdir' ++ hardcode_shlibpath_var=no ++ ;; ++ ++ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor ++ # support. Future versions do this automatically, but an explicit c++rt0.o ++ # does not break anything, and helps significantly (at the cost of a little ++ # extra space). ++ freebsd2.2*) ++ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' ++ hardcode_libdir_flag_spec='-R$libdir' ++ hardcode_direct=yes ++ hardcode_shlibpath_var=no ++ ;; ++ ++ # Unfortunately, older versions of FreeBSD 2 do not have this feature. ++ freebsd2.*) ++ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' ++ hardcode_direct=yes ++ hardcode_minus_L=yes ++ hardcode_shlibpath_var=no ++ ;; ++ ++ # FreeBSD 3 and greater uses gcc -shared to do shared libraries. ++ freebsd* | dragonfly*) ++ archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' ++ hardcode_libdir_flag_spec='-R$libdir' ++ hardcode_direct=yes ++ hardcode_shlibpath_var=no ++ ;; ++ ++ hpux9*) ++ if test "$GCC" = yes; then ++ archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' ++ else ++ archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' ++ fi ++ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' ++ hardcode_libdir_separator=: ++ hardcode_direct=yes ++ ++ # hardcode_minus_L: Not really in the search PATH, ++ # but as the default location of the library. ++ hardcode_minus_L=yes ++ export_dynamic_flag_spec='${wl}-E' ++ ;; ++ ++ hpux10*) ++ if test "$GCC" = yes && test "$with_gnu_ld" = no; then ++ archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ++ else ++ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' ++ fi ++ if test "$with_gnu_ld" = no; then ++ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' ++ hardcode_libdir_flag_spec_ld='+b $libdir' ++ hardcode_libdir_separator=: ++ hardcode_direct=yes ++ hardcode_direct_absolute=yes ++ export_dynamic_flag_spec='${wl}-E' ++ # hardcode_minus_L: Not really in the search PATH, ++ # but as the default location of the library. ++ hardcode_minus_L=yes ++ fi ++ ;; ++ ++ hpux11*) ++ if test "$GCC" = yes && test "$with_gnu_ld" = no; then ++ case $host_cpu in ++ hppa*64*) ++ archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ++ ;; ++ ia64*) ++ archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ++ ;; ++ *) ++ archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ++ ;; ++ esac ++ else ++ case $host_cpu in ++ hppa*64*) ++ archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ++ ;; ++ ia64*) ++ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ++ ;; ++ *) ++ ++ # Older versions of the 11.00 compiler do not understand -b yet ++ # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 ++$as_echo_n "checking if $CC understands -b... " >&6; } ++if ${lt_cv_prog_compiler__b+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ lt_cv_prog_compiler__b=no ++ save_LDFLAGS="$LDFLAGS" ++ LDFLAGS="$LDFLAGS -b" ++ echo "$lt_simple_link_test_code" > conftest.$ac_ext ++ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then ++ # The linker can only warn and ignore the option if not recognized ++ # So say no if there are warnings ++ if test -s conftest.err; then ++ # Append any errors to the config.log. ++ cat conftest.err 1>&5 ++ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp ++ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 ++ if diff conftest.exp conftest.er2 >/dev/null; then ++ lt_cv_prog_compiler__b=yes ++ fi ++ else ++ lt_cv_prog_compiler__b=yes ++ fi ++ fi ++ $RM -r conftest* ++ LDFLAGS="$save_LDFLAGS" ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 ++$as_echo "$lt_cv_prog_compiler__b" >&6; } ++ ++if test x"$lt_cv_prog_compiler__b" = xyes; then ++ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ++else ++ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' ++fi ++ ++ ;; ++ esac ++ fi ++ if test "$with_gnu_ld" = no; then ++ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' ++ hardcode_libdir_separator=: ++ ++ case $host_cpu in ++ hppa*64*|ia64*) ++ hardcode_direct=no ++ hardcode_shlibpath_var=no ++ ;; ++ *) ++ hardcode_direct=yes ++ hardcode_direct_absolute=yes ++ export_dynamic_flag_spec='${wl}-E' ++ ++ # hardcode_minus_L: Not really in the search PATH, ++ # but as the default location of the library. ++ hardcode_minus_L=yes ++ ;; ++ esac ++ fi ++ ;; ++ ++ irix5* | irix6* | nonstopux*) ++ if test "$GCC" = yes; then ++ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ++ # Try to use the -exported_symbol ld option, if it does not ++ # work, assume that -exports_file does not work either and ++ # implicitly export all symbols. ++ save_LDFLAGS="$LDFLAGS" ++ LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++int foo(void) {} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' ++ ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++ LDFLAGS="$save_LDFLAGS" ++ else ++ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' ++ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' ++ fi ++ archive_cmds_need_lc='no' ++ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' ++ hardcode_libdir_separator=: ++ inherit_rpath=yes ++ link_all_deplibs=yes ++ ;; ++ ++ netbsd*) ++ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then ++ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out ++ else ++ archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF ++ fi ++ hardcode_libdir_flag_spec='-R$libdir' ++ hardcode_direct=yes ++ hardcode_shlibpath_var=no ++ ;; ++ ++ newsos6) ++ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' ++ hardcode_direct=yes ++ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' ++ hardcode_libdir_separator=: ++ hardcode_shlibpath_var=no ++ ;; ++ ++ *nto* | *qnx*) ++ ;; ++ ++ openbsd*) ++ if test -f /usr/libexec/ld.so; then ++ hardcode_direct=yes ++ hardcode_shlibpath_var=no ++ hardcode_direct_absolute=yes ++ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then ++ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' ++ archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' ++ hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ++ export_dynamic_flag_spec='${wl}-E' ++ else ++ case $host_os in ++ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) ++ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' ++ hardcode_libdir_flag_spec='-R$libdir' ++ ;; ++ *) ++ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' ++ hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ++ ;; ++ esac ++ fi ++ else ++ ld_shlibs=no ++ fi ++ ;; ++ ++ os2*) ++ hardcode_libdir_flag_spec='-L$libdir' ++ hardcode_minus_L=yes ++ allow_undefined_flag=unsupported ++ archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' ++ old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ++ ;; ++ ++ osf3*) ++ if test "$GCC" = yes; then ++ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' ++ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ++ else ++ allow_undefined_flag=' -expect_unresolved \*' ++ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' ++ fi ++ archive_cmds_need_lc='no' ++ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' ++ hardcode_libdir_separator=: ++ ;; ++ ++ osf4* | osf5*) # as osf3* with the addition of -msym flag ++ if test "$GCC" = yes; then ++ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' ++ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ++ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' ++ else ++ allow_undefined_flag=' -expect_unresolved \*' ++ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' ++ archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ ++ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' ++ ++ # Both c and cxx compiler support -rpath directly ++ hardcode_libdir_flag_spec='-rpath $libdir' ++ fi ++ archive_cmds_need_lc='no' ++ hardcode_libdir_separator=: ++ ;; ++ ++ solaris*) ++ no_undefined_flag=' -z defs' ++ if test "$GCC" = yes; then ++ wlarc='${wl}' ++ archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ++ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ ++ $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ++ else ++ case `$CC -V 2>&1` in ++ *"Compilers 5.0"*) ++ wlarc='' ++ archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' ++ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ ++ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ++ ;; ++ *) ++ wlarc='${wl}' ++ archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' ++ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ ++ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ++ ;; ++ esac ++ fi ++ hardcode_libdir_flag_spec='-R$libdir' ++ hardcode_shlibpath_var=no ++ case $host_os in ++ solaris2.[0-5] | solaris2.[0-5].*) ;; ++ *) ++ # The compiler driver will combine and reorder linker options, ++ # but understands `-z linker_flag'. GCC discards it without `$wl', ++ # but is careful enough not to reorder. ++ # Supported since Solaris 2.6 (maybe 2.5.1?) ++ if test "$GCC" = yes; then ++ whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ++ else ++ whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ++ fi ++ ;; ++ esac ++ link_all_deplibs=yes ++ ;; ++ ++ sunos4*) ++ if test "x$host_vendor" = xsequent; then ++ # Use $CC to link under sequent, because it throws in some extra .o ++ # files that make .init and .fini sections work. ++ archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' ++ else ++ archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' ++ fi ++ hardcode_libdir_flag_spec='-L$libdir' ++ hardcode_direct=yes ++ hardcode_minus_L=yes ++ hardcode_shlibpath_var=no ++ ;; ++ ++ sysv4) ++ case $host_vendor in ++ sni) ++ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' ++ hardcode_direct=yes # is this really true??? ++ ;; ++ siemens) ++ ## LD is ld it makes a PLAMLIB ++ ## CC just makes a GrossModule. ++ archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' ++ reload_cmds='$CC -r -o $output$reload_objs' ++ hardcode_direct=no ++ ;; ++ motorola) ++ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' ++ hardcode_direct=no #Motorola manual says yes, but my tests say they lie ++ ;; ++ esac ++ runpath_var='LD_RUN_PATH' ++ hardcode_shlibpath_var=no ++ ;; ++ ++ sysv4.3*) ++ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' ++ hardcode_shlibpath_var=no ++ export_dynamic_flag_spec='-Bexport' ++ ;; ++ ++ sysv4*MP*) ++ if test -d /usr/nec; then ++ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' ++ hardcode_shlibpath_var=no ++ runpath_var=LD_RUN_PATH ++ hardcode_runpath_var=yes ++ ld_shlibs=yes ++ fi ++ ;; ++ ++ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) ++ no_undefined_flag='${wl}-z,text' ++ archive_cmds_need_lc=no ++ hardcode_shlibpath_var=no ++ runpath_var='LD_RUN_PATH' ++ ++ if test "$GCC" = yes; then ++ archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ++ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ++ else ++ archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ++ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ++ fi ++ ;; ++ ++ sysv5* | sco3.2v5* | sco5v6*) ++ # Note: We can NOT use -z defs as we might desire, because we do not ++ # link with -lc, and that would cause any symbols used from libc to ++ # always be unresolved, which means just about no library would ++ # ever link correctly. If we're not using GNU ld we use -z text ++ # though, which does catch some bad symbols but isn't as heavy-handed ++ # as -z defs. ++ no_undefined_flag='${wl}-z,text' ++ allow_undefined_flag='${wl}-z,nodefs' ++ archive_cmds_need_lc=no ++ hardcode_shlibpath_var=no ++ hardcode_libdir_flag_spec='${wl}-R,$libdir' ++ hardcode_libdir_separator=':' ++ link_all_deplibs=yes ++ export_dynamic_flag_spec='${wl}-Bexport' ++ runpath_var='LD_RUN_PATH' ++ ++ if test "$GCC" = yes; then ++ archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ++ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ++ else ++ archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ++ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ++ fi ++ ;; ++ ++ uts4*) ++ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' ++ hardcode_libdir_flag_spec='-L$libdir' ++ hardcode_shlibpath_var=no ++ ;; ++ ++ *) ++ ld_shlibs=no ++ ;; ++ esac ++ ++ if test x$host_vendor = xsni; then ++ case $host in ++ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) ++ export_dynamic_flag_spec='${wl}-Blargedynsym' ++ ;; ++ esac ++ fi ++ fi ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 ++$as_echo "$ld_shlibs" >&6; } ++test "$ld_shlibs" = no && can_build_shared=no ++ ++with_gnu_ld=$with_gnu_ld ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++# ++# Do we need to explicitly link libc? ++# ++case "x$archive_cmds_need_lc" in ++x|xyes) ++ # Assume -lc should be added ++ archive_cmds_need_lc=yes ++ ++ if test "$enable_shared" = yes && test "$GCC" = yes; then ++ case $archive_cmds in ++ *'~'*) ++ # FIXME: we may have to deal with multi-command sequences. ++ ;; ++ '$CC '*) ++ # Test whether the compiler implicitly links with -lc since on some ++ # systems, -lgcc has to come before -lc. If gcc already passes -lc ++ # to ld, don't add -lc before -lgcc. ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 ++$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } ++if ${lt_cv_archive_cmds_need_lc+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ $RM conftest* ++ echo "$lt_simple_compile_test_code" > conftest.$ac_ext ++ ++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 ++ (eval $ac_compile) 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; } 2>conftest.err; then ++ soname=conftest ++ lib=conftest ++ libobjs=conftest.$ac_objext ++ deplibs= ++ wl=$lt_prog_compiler_wl ++ pic_flag=$lt_prog_compiler_pic ++ compiler_flags=-v ++ linker_flags=-v ++ verstring= ++ output_objdir=. ++ libname=conftest ++ lt_save_allow_undefined_flag=$allow_undefined_flag ++ allow_undefined_flag= ++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 ++ (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; } ++ then ++ lt_cv_archive_cmds_need_lc=no ++ else ++ lt_cv_archive_cmds_need_lc=yes ++ fi ++ allow_undefined_flag=$lt_save_allow_undefined_flag ++ else ++ cat conftest.err 1>&5 ++ fi ++ $RM conftest* ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 ++$as_echo "$lt_cv_archive_cmds_need_lc" >&6; } ++ archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc ++ ;; ++ esac ++ fi ++ ;; ++esac ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 ++$as_echo_n "checking dynamic linker characteristics... " >&6; } ++ ++if test "$GCC" = yes; then ++ case $host_os in ++ darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; ++ *) lt_awk_arg="/^libraries:/" ;; ++ esac ++ case $host_os in ++ mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; ++ *) lt_sed_strip_eq="s,=/,/,g" ;; ++ esac ++ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` ++ case $lt_search_path_spec in ++ *\;*) ++ # if the path contains ";" then we assume it to be the separator ++ # otherwise default to the standard path separator (i.e. ":") - it is ++ # assumed that no part of a normal pathname contains ";" but that should ++ # okay in the real world where ";" in dirpaths is itself problematic. ++ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ++ ;; ++ *) ++ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ++ ;; ++ esac ++ # Ok, now we have the path, separated by spaces, we can step through it ++ # and add multilib dir if necessary. ++ lt_tmp_lt_search_path_spec= ++ lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` ++ for lt_sys_path in $lt_search_path_spec; do ++ if test -d "$lt_sys_path/$lt_multi_os_dir"; then ++ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" ++ else ++ test -d "$lt_sys_path" && \ ++ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" ++ fi ++ done ++ lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' ++BEGIN {RS=" "; FS="/|\n";} { ++ lt_foo=""; ++ lt_count=0; ++ for (lt_i = NF; lt_i > 0; lt_i--) { ++ if ($lt_i != "" && $lt_i != ".") { ++ if ($lt_i == "..") { ++ lt_count++; ++ } else { ++ if (lt_count == 0) { ++ lt_foo="/" $lt_i lt_foo; ++ } else { ++ lt_count--; ++ } ++ } ++ } ++ } ++ if (lt_foo != "") { lt_freq[lt_foo]++; } ++ if (lt_freq[lt_foo] == 1) { print lt_foo; } ++}'` ++ # AWK program above erroneously prepends '/' to C:/dos/paths ++ # for these hosts. ++ case $host_os in ++ mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ ++ $SED 's,/\([A-Za-z]:\),\1,g'` ;; ++ esac ++ sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` ++else ++ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" ++fi ++library_names_spec= ++libname_spec='lib$name' ++soname_spec= ++shrext_cmds=".so" ++postinstall_cmds= ++postuninstall_cmds= ++finish_cmds= ++finish_eval= ++shlibpath_var= ++shlibpath_overrides_runpath=unknown ++version_type=none ++dynamic_linker="$host_os ld.so" ++sys_lib_dlsearch_path_spec="/lib /usr/lib" ++need_lib_prefix=unknown ++hardcode_into_libs=no ++ ++# when you set need_version to no, make sure it does not cause -set_version ++# flags to be left without arguments ++need_version=unknown ++ ++case $host_os in ++aix3*) ++ version_type=linux ++ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' ++ shlibpath_var=LIBPATH ++ ++ # AIX 3 has no versioning support, so we append a major version to the name. ++ soname_spec='${libname}${release}${shared_ext}$major' ++ ;; ++ ++aix[4-9]*) ++ version_type=linux ++ need_lib_prefix=no ++ need_version=no ++ hardcode_into_libs=yes ++ if test "$host_cpu" = ia64; then ++ # AIX 5 supports IA64 ++ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' ++ shlibpath_var=LD_LIBRARY_PATH ++ else ++ # With GCC up to 2.95.x, collect2 would create an import file ++ # for dependence libraries. The import file would start with ++ # the line `#! .'. This would cause the generated library to ++ # depend on `.', always an invalid library. This was fixed in ++ # development snapshots of GCC prior to 3.0. ++ case $host_os in ++ aix4 | aix4.[01] | aix4.[01].*) ++ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' ++ echo ' yes ' ++ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then ++ : ++ else ++ can_build_shared=no ++ fi ++ ;; ++ esac ++ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct ++ # soname into executable. Probably we can add versioning support to ++ # collect2, so additional links can be useful in future. ++ if test "$aix_use_runtimelinking" = yes; then ++ # If using run time linking (on AIX 4.2 or later) use lib<name>.so ++ # instead of lib<name>.a to let people know that these are not ++ # typical AIX shared libraries. ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ else ++ # We preserve .a as extension for shared libraries through AIX4.2 ++ # and later when we are not doing run time linking. ++ library_names_spec='${libname}${release}.a $libname.a' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ fi ++ shlibpath_var=LIBPATH ++ fi ++ ;; ++ ++amigaos*) ++ case $host_cpu in ++ powerpc) ++ # Since July 2007 AmigaOS4 officially supports .so libraries. ++ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ ;; ++ m68k) ++ library_names_spec='$libname.ixlibrary $libname.a' ++ # Create ${libname}_ixlibrary.a entries in /sys/libs. ++ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ++ ;; ++ esac ++ ;; ++ ++beos*) ++ library_names_spec='${libname}${shared_ext}' ++ dynamic_linker="$host_os ld.so" ++ shlibpath_var=LIBRARY_PATH ++ ;; ++ ++bsdi[45]*) ++ version_type=linux ++ need_version=no ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' ++ shlibpath_var=LD_LIBRARY_PATH ++ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" ++ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" ++ # the default ld.so.conf also contains /usr/contrib/lib and ++ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow ++ # libtool to hard-code these into programs ++ ;; ++ ++cygwin* | mingw* | pw32* | cegcc*) ++ version_type=windows ++ shrext_cmds=".dll" ++ need_version=no ++ need_lib_prefix=no ++ ++ case $GCC,$host_os in ++ yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) ++ library_names_spec='$libname.dll.a' ++ # DLL is installed to $(libdir)/../bin by postinstall_cmds ++ postinstall_cmds='base_file=`basename \${file}`~ ++ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ ++ dldir=$destdir/`dirname \$dlpath`~ ++ test -d \$dldir || mkdir -p \$dldir~ ++ $install_prog $dir/$dlname \$dldir/$dlname~ ++ chmod a+x \$dldir/$dlname~ ++ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then ++ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; ++ fi' ++ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ ++ dlpath=$dir/\$dldll~ ++ $RM \$dlpath' ++ shlibpath_overrides_runpath=yes ++ ++ case $host_os in ++ cygwin*) ++ # Cygwin DLLs use 'cyg' prefix rather than 'lib' ++ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ++ ++ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" ++ ;; ++ mingw* | cegcc*) ++ # MinGW DLLs use traditional 'lib' prefix ++ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ++ ;; ++ pw32*) ++ # pw32 DLLs use 'pw' prefix rather than 'lib' ++ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ++ ;; ++ esac ++ ;; ++ ++ *) ++ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' ++ ;; ++ esac ++ dynamic_linker='Win32 ld.exe' ++ # FIXME: first we should search . and the directory the executable is in ++ shlibpath_var=PATH ++ ;; ++ ++darwin* | rhapsody*) ++ dynamic_linker="$host_os dyld" ++ version_type=darwin ++ need_lib_prefix=no ++ need_version=no ++ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' ++ soname_spec='${libname}${release}${major}$shared_ext' ++ shlibpath_overrides_runpath=yes ++ shlibpath_var=DYLD_LIBRARY_PATH ++ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' ++ ++ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" ++ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ++ ;; ++ ++dgux*) ++ version_type=linux ++ need_lib_prefix=no ++ need_version=no ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ shlibpath_var=LD_LIBRARY_PATH ++ ;; ++ ++freebsd* | dragonfly*) ++ # DragonFly does not have aout. When/if they implement a new ++ # versioning mechanism, adjust this. ++ if test -x /usr/bin/objformat; then ++ objformat=`/usr/bin/objformat` ++ else ++ case $host_os in ++ freebsd[23].*) objformat=aout ;; ++ *) objformat=elf ;; ++ esac ++ fi ++ version_type=freebsd-$objformat ++ case $version_type in ++ freebsd-elf*) ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' ++ need_version=no ++ need_lib_prefix=no ++ ;; ++ freebsd-*) ++ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' ++ need_version=yes ++ ;; ++ esac ++ shlibpath_var=LD_LIBRARY_PATH ++ case $host_os in ++ freebsd2.*) ++ shlibpath_overrides_runpath=yes ++ ;; ++ freebsd3.[01]* | freebsdelf3.[01]*) ++ shlibpath_overrides_runpath=yes ++ hardcode_into_libs=yes ++ ;; ++ freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ ++ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) ++ shlibpath_overrides_runpath=no ++ hardcode_into_libs=yes ++ ;; ++ *) # from 4.6 on, and DragonFly ++ shlibpath_overrides_runpath=yes ++ hardcode_into_libs=yes ++ ;; ++ esac ++ ;; ++ ++gnu*) ++ version_type=linux ++ need_lib_prefix=no ++ need_version=no ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ shlibpath_var=LD_LIBRARY_PATH ++ hardcode_into_libs=yes ++ ;; ++ ++haiku*) ++ version_type=linux ++ need_lib_prefix=no ++ need_version=no ++ dynamic_linker="$host_os runtime_loader" ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ shlibpath_var=LIBRARY_PATH ++ shlibpath_overrides_runpath=yes ++ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/beos/system/lib' ++ hardcode_into_libs=yes ++ ;; ++ ++hpux9* | hpux10* | hpux11*) ++ # Give a soname corresponding to the major version so that dld.sl refuses to ++ # link against other versions. ++ version_type=sunos ++ need_lib_prefix=no ++ need_version=no ++ case $host_cpu in ++ ia64*) ++ shrext_cmds='.so' ++ hardcode_into_libs=yes ++ dynamic_linker="$host_os dld.so" ++ shlibpath_var=LD_LIBRARY_PATH ++ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ if test "X$HPUX_IA64_MODE" = X32; then ++ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" ++ else ++ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" ++ fi ++ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ++ ;; ++ hppa*64*) ++ shrext_cmds='.sl' ++ hardcode_into_libs=yes ++ dynamic_linker="$host_os dld.sl" ++ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH ++ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" ++ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ++ ;; ++ *) ++ shrext_cmds='.sl' ++ dynamic_linker="$host_os dld.sl" ++ shlibpath_var=SHLIB_PATH ++ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ ;; ++ esac ++ # HP-UX runs *really* slowly unless shared libraries are mode 555, ... ++ postinstall_cmds='chmod 555 $lib' ++ # or fails outright, so override atomically: ++ install_override_mode=555 ++ ;; ++ ++interix[3-9]*) ++ version_type=linux ++ need_lib_prefix=no ++ need_version=no ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' ++ shlibpath_var=LD_LIBRARY_PATH ++ shlibpath_overrides_runpath=no ++ hardcode_into_libs=yes ++ ;; ++ ++irix5* | irix6* | nonstopux*) ++ case $host_os in ++ nonstopux*) version_type=nonstopux ;; ++ *) ++ if test "$lt_cv_prog_gnu_ld" = yes; then ++ version_type=linux ++ else ++ version_type=irix ++ fi ;; ++ esac ++ need_lib_prefix=no ++ need_version=no ++ soname_spec='${libname}${release}${shared_ext}$major' ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' ++ case $host_os in ++ irix5* | nonstopux*) ++ libsuff= shlibsuff= ++ ;; ++ *) ++ case $LD in # libtool.m4 will add one of these switches to LD ++ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") ++ libsuff= shlibsuff= libmagic=32-bit;; ++ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") ++ libsuff=32 shlibsuff=N32 libmagic=N32;; ++ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") ++ libsuff=64 shlibsuff=64 libmagic=64-bit;; ++ *) libsuff= shlibsuff= libmagic=never-match;; ++ esac ++ ;; ++ esac ++ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH ++ shlibpath_overrides_runpath=no ++ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" ++ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" ++ hardcode_into_libs=yes ++ ;; ++ ++# No shared lib support for Linux oldld, aout, or coff. ++linux*oldld* | linux*aout* | linux*coff*) ++ dynamic_linker=no ++ ;; ++ ++# This must be Linux ELF. ++linux* | k*bsd*-gnu | kopensolaris*-gnu) ++ version_type=linux ++ need_lib_prefix=no ++ need_version=no ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' ++ shlibpath_var=LD_LIBRARY_PATH ++ shlibpath_overrides_runpath=no ++ ++ # Some binutils ld are patched to set DT_RUNPATH ++ if ${lt_cv_shlibpath_overrides_runpath+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ lt_cv_shlibpath_overrides_runpath=no ++ save_LDFLAGS=$LDFLAGS ++ save_libdir=$libdir ++ eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ ++ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : ++ lt_cv_shlibpath_overrides_runpath=yes ++fi ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++ LDFLAGS=$save_LDFLAGS ++ libdir=$save_libdir ++ ++fi ++ ++ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath ++ ++ # This implies no fast_install, which is unacceptable. ++ # Some rework will be needed to allow for fast_install ++ # before this can be enabled. ++ hardcode_into_libs=yes ++ ++ # Append ld.so.conf contents to the search path ++ if test -f /etc/ld.so.conf; then ++ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` ++ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" ++ fi ++ ++ # We used to test for /lib/ld.so.1 and disable shared libraries on ++ # powerpc, because MkLinux only supported shared libraries with the ++ # GNU dynamic linker. Since this was broken with cross compilers, ++ # most powerpc-linux boxes support dynamic linking these days and ++ # people can always --disable-shared, the test was removed, and we ++ # assume the GNU/Linux dynamic linker is in use. ++ dynamic_linker='GNU/Linux ld.so' ++ ;; ++ ++netbsd*) ++ version_type=sunos ++ need_lib_prefix=no ++ need_version=no ++ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' ++ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' ++ dynamic_linker='NetBSD (a.out) ld.so' ++ else ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ dynamic_linker='NetBSD ld.elf_so' ++ fi ++ shlibpath_var=LD_LIBRARY_PATH ++ shlibpath_overrides_runpath=yes ++ hardcode_into_libs=yes ++ ;; ++ ++newsos6) ++ version_type=linux ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ shlibpath_var=LD_LIBRARY_PATH ++ shlibpath_overrides_runpath=yes ++ ;; ++ ++*nto* | *qnx*) ++ version_type=qnx ++ need_lib_prefix=no ++ need_version=no ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ shlibpath_var=LD_LIBRARY_PATH ++ shlibpath_overrides_runpath=no ++ hardcode_into_libs=yes ++ dynamic_linker='ldqnx.so' ++ ;; ++ ++openbsd*) ++ version_type=sunos ++ sys_lib_dlsearch_path_spec="/usr/lib" ++ need_lib_prefix=no ++ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. ++ case $host_os in ++ openbsd3.3 | openbsd3.3.*) need_version=yes ;; ++ *) need_version=no ;; ++ esac ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' ++ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' ++ shlibpath_var=LD_LIBRARY_PATH ++ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then ++ case $host_os in ++ openbsd2.[89] | openbsd2.[89].*) ++ shlibpath_overrides_runpath=no ++ ;; ++ *) ++ shlibpath_overrides_runpath=yes ++ ;; ++ esac ++ else ++ shlibpath_overrides_runpath=yes ++ fi ++ ;; ++ ++os2*) ++ libname_spec='$name' ++ shrext_cmds=".dll" ++ need_lib_prefix=no ++ library_names_spec='$libname${shared_ext} $libname.a' ++ dynamic_linker='OS/2 ld.exe' ++ shlibpath_var=LIBPATH ++ ;; ++ ++osf3* | osf4* | osf5*) ++ version_type=osf ++ need_lib_prefix=no ++ need_version=no ++ soname_spec='${libname}${release}${shared_ext}$major' ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ shlibpath_var=LD_LIBRARY_PATH ++ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" ++ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ++ ;; ++ ++rdos*) ++ dynamic_linker=no ++ ;; ++ ++solaris*) ++ version_type=linux ++ need_lib_prefix=no ++ need_version=no ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ shlibpath_var=LD_LIBRARY_PATH ++ shlibpath_overrides_runpath=yes ++ hardcode_into_libs=yes ++ # ldd complains unless libraries are executable ++ postinstall_cmds='chmod +x $lib' ++ ;; ++ ++sunos4*) ++ version_type=sunos ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' ++ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' ++ shlibpath_var=LD_LIBRARY_PATH ++ shlibpath_overrides_runpath=yes ++ if test "$with_gnu_ld" = yes; then ++ need_lib_prefix=no ++ fi ++ need_version=yes ++ ;; ++ ++sysv4 | sysv4.3*) ++ version_type=linux ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ shlibpath_var=LD_LIBRARY_PATH ++ case $host_vendor in ++ sni) ++ shlibpath_overrides_runpath=no ++ need_lib_prefix=no ++ runpath_var=LD_RUN_PATH ++ ;; ++ siemens) ++ need_lib_prefix=no ++ ;; ++ motorola) ++ need_lib_prefix=no ++ need_version=no ++ shlibpath_overrides_runpath=no ++ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ++ ;; ++ esac ++ ;; ++ ++sysv4*MP*) ++ if test -d /usr/nec ;then ++ version_type=linux ++ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' ++ soname_spec='$libname${shared_ext}.$major' ++ shlibpath_var=LD_LIBRARY_PATH ++ fi ++ ;; ++ ++sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) ++ version_type=freebsd-elf ++ need_lib_prefix=no ++ need_version=no ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ shlibpath_var=LD_LIBRARY_PATH ++ shlibpath_overrides_runpath=yes ++ hardcode_into_libs=yes ++ if test "$with_gnu_ld" = yes; then ++ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' ++ else ++ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' ++ case $host_os in ++ sco3.2v5*) ++ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ++ ;; ++ esac ++ fi ++ sys_lib_dlsearch_path_spec='/usr/lib' ++ ;; ++ ++tpf*) ++ # TPF is a cross-target only. Preferred cross-host = GNU/Linux. ++ version_type=linux ++ need_lib_prefix=no ++ need_version=no ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ shlibpath_var=LD_LIBRARY_PATH ++ shlibpath_overrides_runpath=no ++ hardcode_into_libs=yes ++ ;; ++ ++uts4*) ++ version_type=linux ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ shlibpath_var=LD_LIBRARY_PATH ++ ;; ++ ++*) ++ dynamic_linker=no ++ ;; ++esac ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 ++$as_echo "$dynamic_linker" >&6; } ++test "$dynamic_linker" = no && can_build_shared=no ++ ++variables_saved_for_relink="PATH $shlibpath_var $runpath_var" ++if test "$GCC" = yes; then ++ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" ++fi ++ ++if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then ++ sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" ++fi ++if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then ++ sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" ++fi ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 ++$as_echo_n "checking how to hardcode library paths into programs... " >&6; } ++hardcode_action= ++if test -n "$hardcode_libdir_flag_spec" || ++ test -n "$runpath_var" || ++ test "X$hardcode_automatic" = "Xyes" ; then ++ ++ # We can hardcode non-existent directories. ++ if test "$hardcode_direct" != no && ++ # If the only mechanism to avoid hardcoding is shlibpath_var, we ++ # have to relink, otherwise we might link with an installed library ++ # when we should be linking with a yet-to-be-installed one ++ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && ++ test "$hardcode_minus_L" != no; then ++ # Linking always hardcodes the temporary library directory. ++ hardcode_action=relink ++ else ++ # We can link without hardcoding, and we can hardcode nonexisting dirs. ++ hardcode_action=immediate ++ fi ++else ++ # We cannot hardcode anything, or else we can only hardcode existing ++ # directories. ++ hardcode_action=unsupported ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 ++$as_echo "$hardcode_action" >&6; } ++ ++if test "$hardcode_action" = relink || ++ test "$inherit_rpath" = yes; then ++ # Fast installation is not supported ++ enable_fast_install=no ++elif test "$shlibpath_overrides_runpath" = yes || ++ test "$enable_shared" = no; then ++ # Fast installation is not necessary ++ enable_fast_install=needless ++fi ++ ++ ++ ++ ++ ++ ++ if test "x$enable_dlopen" != xyes; then ++ enable_dlopen=unknown ++ enable_dlopen_self=unknown ++ enable_dlopen_self_static=unknown ++else ++ lt_cv_dlopen=no ++ lt_cv_dlopen_libs= ++ ++ case $host_os in ++ beos*) ++ lt_cv_dlopen="load_add_on" ++ lt_cv_dlopen_libs= ++ lt_cv_dlopen_self=yes ++ ;; ++ ++ mingw* | pw32* | cegcc*) ++ lt_cv_dlopen="LoadLibrary" ++ lt_cv_dlopen_libs= ++ ;; ++ ++ cygwin*) ++ lt_cv_dlopen="dlopen" ++ lt_cv_dlopen_libs= ++ ;; ++ ++ darwin*) ++ # if libdl is installed we need to link against it ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 ++$as_echo_n "checking for dlopen in -ldl... " >&6; } ++if ${ac_cv_lib_dl_dlopen+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_check_lib_save_LIBS=$LIBS ++LIBS="-ldl $LIBS" ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char dlopen (); ++int ++main () ++{ ++return dlopen (); ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ ac_cv_lib_dl_dlopen=yes ++else ++ ac_cv_lib_dl_dlopen=no ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++LIBS=$ac_check_lib_save_LIBS ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 ++$as_echo "$ac_cv_lib_dl_dlopen" >&6; } ++if test "x$ac_cv_lib_dl_dlopen" = xyes; then : ++ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" ++else ++ ++ lt_cv_dlopen="dyld" ++ lt_cv_dlopen_libs= ++ lt_cv_dlopen_self=yes ++ ++fi ++ ++ ;; ++ ++ *) ++ ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" ++if test "x$ac_cv_func_shl_load" = xyes; then : ++ lt_cv_dlopen="shl_load" ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 ++$as_echo_n "checking for shl_load in -ldld... " >&6; } ++if ${ac_cv_lib_dld_shl_load+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_check_lib_save_LIBS=$LIBS ++LIBS="-ldld $LIBS" ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char shl_load (); ++int ++main () ++{ ++return shl_load (); ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ ac_cv_lib_dld_shl_load=yes ++else ++ ac_cv_lib_dld_shl_load=no ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++LIBS=$ac_check_lib_save_LIBS ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 ++$as_echo "$ac_cv_lib_dld_shl_load" >&6; } ++if test "x$ac_cv_lib_dld_shl_load" = xyes; then : ++ lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" ++else ++ ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" ++if test "x$ac_cv_func_dlopen" = xyes; then : ++ lt_cv_dlopen="dlopen" ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 ++$as_echo_n "checking for dlopen in -ldl... " >&6; } ++if ${ac_cv_lib_dl_dlopen+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_check_lib_save_LIBS=$LIBS ++LIBS="-ldl $LIBS" ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char dlopen (); ++int ++main () ++{ ++return dlopen (); ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ ac_cv_lib_dl_dlopen=yes ++else ++ ac_cv_lib_dl_dlopen=no ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++LIBS=$ac_check_lib_save_LIBS ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 ++$as_echo "$ac_cv_lib_dl_dlopen" >&6; } ++if test "x$ac_cv_lib_dl_dlopen" = xyes; then : ++ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 ++$as_echo_n "checking for dlopen in -lsvld... " >&6; } ++if ${ac_cv_lib_svld_dlopen+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_check_lib_save_LIBS=$LIBS ++LIBS="-lsvld $LIBS" ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char dlopen (); ++int ++main () ++{ ++return dlopen (); ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ ac_cv_lib_svld_dlopen=yes ++else ++ ac_cv_lib_svld_dlopen=no ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++LIBS=$ac_check_lib_save_LIBS ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 ++$as_echo "$ac_cv_lib_svld_dlopen" >&6; } ++if test "x$ac_cv_lib_svld_dlopen" = xyes; then : ++ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 ++$as_echo_n "checking for dld_link in -ldld... " >&6; } ++if ${ac_cv_lib_dld_dld_link+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_check_lib_save_LIBS=$LIBS ++LIBS="-ldld $LIBS" ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char dld_link (); ++int ++main () ++{ ++return dld_link (); ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ ac_cv_lib_dld_dld_link=yes ++else ++ ac_cv_lib_dld_dld_link=no ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++LIBS=$ac_check_lib_save_LIBS ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 ++$as_echo "$ac_cv_lib_dld_dld_link" >&6; } ++if test "x$ac_cv_lib_dld_dld_link" = xyes; then : ++ lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" ++fi ++ ++ ++fi ++ ++ ++fi ++ ++ ++fi ++ ++ ++fi ++ ++ ++fi ++ ++ ;; ++ esac ++ ++ if test "x$lt_cv_dlopen" != xno; then ++ enable_dlopen=yes ++ else ++ enable_dlopen=no ++ fi ++ ++ case $lt_cv_dlopen in ++ dlopen) ++ save_CPPFLAGS="$CPPFLAGS" ++ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" ++ ++ save_LDFLAGS="$LDFLAGS" ++ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" ++ ++ save_LIBS="$LIBS" ++ LIBS="$lt_cv_dlopen_libs $LIBS" ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 ++$as_echo_n "checking whether a program can dlopen itself... " >&6; } ++if ${lt_cv_dlopen_self+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test "$cross_compiling" = yes; then : ++ lt_cv_dlopen_self=cross ++else ++ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 ++ lt_status=$lt_dlunknown ++ cat > conftest.$ac_ext <<_LT_EOF ++#line 12290 "configure" ++#include "confdefs.h" ++ ++#if HAVE_DLFCN_H ++#include <dlfcn.h> ++#endif ++ ++#include <stdio.h> ++ ++#ifdef RTLD_GLOBAL ++# define LT_DLGLOBAL RTLD_GLOBAL ++#else ++# ifdef DL_GLOBAL ++# define LT_DLGLOBAL DL_GLOBAL ++# else ++# define LT_DLGLOBAL 0 ++# endif ++#endif ++ ++/* We may have to define LT_DLLAZY_OR_NOW in the command line if we ++ find out it does not work in some platform. */ ++#ifndef LT_DLLAZY_OR_NOW ++# ifdef RTLD_LAZY ++# define LT_DLLAZY_OR_NOW RTLD_LAZY ++# else ++# ifdef DL_LAZY ++# define LT_DLLAZY_OR_NOW DL_LAZY ++# else ++# ifdef RTLD_NOW ++# define LT_DLLAZY_OR_NOW RTLD_NOW ++# else ++# ifdef DL_NOW ++# define LT_DLLAZY_OR_NOW DL_NOW ++# else ++# define LT_DLLAZY_OR_NOW 0 ++# endif ++# endif ++# endif ++# endif ++#endif ++ ++/* When -fvisbility=hidden is used, assume the code has been annotated ++ correspondingly for the symbols needed. */ ++#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) ++void fnord () __attribute__((visibility("default"))); ++#endif ++ ++void fnord () { int i=42; } ++int main () ++{ ++ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); ++ int status = $lt_dlunknown; ++ ++ if (self) ++ { ++ if (dlsym (self,"fnord")) status = $lt_dlno_uscore; ++ else ++ { ++ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; ++ else puts (dlerror ()); ++ } ++ /* dlclose (self); */ ++ } ++ else ++ puts (dlerror ()); ++ ++ return status; ++} ++_LT_EOF ++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 ++ (eval $ac_link) 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then ++ (./conftest; exit; ) >&5 2>/dev/null ++ lt_status=$? ++ case x$lt_status in ++ x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; ++ x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; ++ x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; ++ esac ++ else : ++ # compilation failed ++ lt_cv_dlopen_self=no ++ fi ++fi ++rm -fr conftest* ++ ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 ++$as_echo "$lt_cv_dlopen_self" >&6; } ++ ++ if test "x$lt_cv_dlopen_self" = xyes; then ++ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 ++$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } ++if ${lt_cv_dlopen_self_static+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test "$cross_compiling" = yes; then : ++ lt_cv_dlopen_self_static=cross ++else ++ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 ++ lt_status=$lt_dlunknown ++ cat > conftest.$ac_ext <<_LT_EOF ++#line 12396 "configure" ++#include "confdefs.h" ++ ++#if HAVE_DLFCN_H ++#include <dlfcn.h> ++#endif ++ ++#include <stdio.h> ++ ++#ifdef RTLD_GLOBAL ++# define LT_DLGLOBAL RTLD_GLOBAL ++#else ++# ifdef DL_GLOBAL ++# define LT_DLGLOBAL DL_GLOBAL ++# else ++# define LT_DLGLOBAL 0 ++# endif ++#endif ++ ++/* We may have to define LT_DLLAZY_OR_NOW in the command line if we ++ find out it does not work in some platform. */ ++#ifndef LT_DLLAZY_OR_NOW ++# ifdef RTLD_LAZY ++# define LT_DLLAZY_OR_NOW RTLD_LAZY ++# else ++# ifdef DL_LAZY ++# define LT_DLLAZY_OR_NOW DL_LAZY ++# else ++# ifdef RTLD_NOW ++# define LT_DLLAZY_OR_NOW RTLD_NOW ++# else ++# ifdef DL_NOW ++# define LT_DLLAZY_OR_NOW DL_NOW ++# else ++# define LT_DLLAZY_OR_NOW 0 ++# endif ++# endif ++# endif ++# endif ++#endif ++ ++/* When -fvisbility=hidden is used, assume the code has been annotated ++ correspondingly for the symbols needed. */ ++#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) ++void fnord () __attribute__((visibility("default"))); ++#endif ++ ++void fnord () { int i=42; } ++int main () ++{ ++ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); ++ int status = $lt_dlunknown; ++ ++ if (self) ++ { ++ if (dlsym (self,"fnord")) status = $lt_dlno_uscore; ++ else ++ { ++ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; ++ else puts (dlerror ()); ++ } ++ /* dlclose (self); */ ++ } ++ else ++ puts (dlerror ()); ++ ++ return status; ++} ++_LT_EOF ++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 ++ (eval $ac_link) 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then ++ (./conftest; exit; ) >&5 2>/dev/null ++ lt_status=$? ++ case x$lt_status in ++ x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; ++ x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; ++ x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; ++ esac ++ else : ++ # compilation failed ++ lt_cv_dlopen_self_static=no ++ fi ++fi ++rm -fr conftest* ++ ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 ++$as_echo "$lt_cv_dlopen_self_static" >&6; } ++ fi ++ ++ CPPFLAGS="$save_CPPFLAGS" ++ LDFLAGS="$save_LDFLAGS" ++ LIBS="$save_LIBS" ++ ;; ++ esac ++ ++ case $lt_cv_dlopen_self in ++ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; ++ *) enable_dlopen_self=unknown ;; ++ esac ++ ++ case $lt_cv_dlopen_self_static in ++ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; ++ *) enable_dlopen_self_static=unknown ;; ++ esac ++fi ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++striplib= ++old_striplib= ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 ++$as_echo_n "checking whether stripping libraries is possible... " >&6; } ++if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then ++ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" ++ test -z "$striplib" && striplib="$STRIP --strip-unneeded" ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 ++$as_echo "yes" >&6; } ++else ++# FIXME - insert some real tests, host_os isn't really good enough ++ case $host_os in ++ darwin*) ++ if test -n "$STRIP" ; then ++ striplib="$STRIP -x" ++ old_striplib="$STRIP -S" ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 ++$as_echo "yes" >&6; } ++ else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++ fi ++ ;; ++ *) ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++ ;; ++ esac ++fi ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ # Report which library types will actually be built ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 ++$as_echo_n "checking if libtool supports shared libraries... " >&6; } ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 ++$as_echo "$can_build_shared" >&6; } ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 ++$as_echo_n "checking whether to build shared libraries... " >&6; } ++ test "$can_build_shared" = "no" && enable_shared=no ++ ++ # On AIX, shared libraries and static libraries use the same namespace, and ++ # are all built from PIC. ++ case $host_os in ++ aix3*) ++ test "$enable_shared" = yes && enable_static=no ++ if test -n "$RANLIB"; then ++ archive_cmds="$archive_cmds~\$RANLIB \$lib" ++ postinstall_cmds='$RANLIB $lib' ++ fi ++ ;; ++ ++ aix[4-9]*) ++ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then ++ test "$enable_shared" = yes && enable_static=no ++ fi ++ ;; ++ esac ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 ++$as_echo "$enable_shared" >&6; } ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 ++$as_echo_n "checking whether to build static libraries... " >&6; } ++ # Make sure either enable_shared or enable_static is yes. ++ test "$enable_shared" = yes || enable_static=yes ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 ++$as_echo "$enable_static" >&6; } ++ ++ ++ ++ ++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 ++ ++CC="$lt_save_CC" ++ ++ if test -n "$CXX" && ( test "X$CXX" != "Xno" && ++ ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || ++ (test "X$CXX" != "Xg++"))) ; then ++ ac_ext=cpp ++ac_cpp='$CXXCPP $CPPFLAGS' ++ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ++ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ++ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 ++$as_echo_n "checking how to run the C++ preprocessor... " >&6; } ++if test -z "$CXXCPP"; then ++ if ${ac_cv_prog_CXXCPP+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ # Double quotes because CXXCPP needs to be expanded ++ for CXXCPP in "$CXX -E" "/lib/cpp" ++ do ++ ac_preproc_ok=false ++for ac_cxx_preproc_warn_flag in '' yes ++do ++ # Use a header file that comes with gcc, so configuring glibc ++ # with a fresh cross-compiler works. ++ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since ++ # <limits.h> exists even on freestanding compilers. ++ # On the NeXT, cc -E runs the code through the compiler's parser, ++ # not just through cpp. "Syntax error" is here to catch this case. ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#ifdef __STDC__ ++# include <limits.h> ++#else ++# include <assert.h> ++#endif ++ Syntax error ++_ACEOF ++if ac_fn_cxx_try_cpp "$LINENO"; then : ++ ++else ++ # Broken: fails on valid input. ++continue ++fi ++rm -f conftest.err conftest.i conftest.$ac_ext ++ ++ # OK, works on sane cases. Now check whether nonexistent headers ++ # can be detected and how. ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#include <ac_nonexistent.h> ++_ACEOF ++if ac_fn_cxx_try_cpp "$LINENO"; then : ++ # Broken: success on invalid input. ++continue ++else ++ # Passes both tests. ++ac_preproc_ok=: ++break ++fi ++rm -f conftest.err conftest.i conftest.$ac_ext ++ ++done ++# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. ++rm -f conftest.i conftest.err conftest.$ac_ext ++if $ac_preproc_ok; then : ++ break ++fi ++ ++ done ++ ac_cv_prog_CXXCPP=$CXXCPP ++ ++fi ++ CXXCPP=$ac_cv_prog_CXXCPP ++else ++ ac_cv_prog_CXXCPP=$CXXCPP ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 ++$as_echo "$CXXCPP" >&6; } ++ac_preproc_ok=false ++for ac_cxx_preproc_warn_flag in '' yes ++do ++ # Use a header file that comes with gcc, so configuring glibc ++ # with a fresh cross-compiler works. ++ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since ++ # <limits.h> exists even on freestanding compilers. ++ # On the NeXT, cc -E runs the code through the compiler's parser, ++ # not just through cpp. "Syntax error" is here to catch this case. ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#ifdef __STDC__ ++# include <limits.h> ++#else ++# include <assert.h> ++#endif ++ Syntax error ++_ACEOF ++if ac_fn_cxx_try_cpp "$LINENO"; then : ++ ++else ++ # Broken: fails on valid input. ++continue ++fi ++rm -f conftest.err conftest.i conftest.$ac_ext ++ ++ # OK, works on sane cases. Now check whether nonexistent headers ++ # can be detected and how. ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#include <ac_nonexistent.h> ++_ACEOF ++if ac_fn_cxx_try_cpp "$LINENO"; then : ++ # Broken: success on invalid input. ++continue ++else ++ # Passes both tests. ++ac_preproc_ok=: ++break ++fi ++rm -f conftest.err conftest.i conftest.$ac_ext ++ ++done ++# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. ++rm -f conftest.i conftest.err conftest.$ac_ext ++if $ac_preproc_ok; then : ++ ++else ++ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check ++See \`config.log' for more details" "$LINENO" 5; } ++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 ++ ++else ++ _lt_caught_CXX_error=yes ++fi ++ ++ac_ext=cpp ++ac_cpp='$CXXCPP $CPPFLAGS' ++ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ++ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ++ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ++ ++archive_cmds_need_lc_CXX=no ++allow_undefined_flag_CXX= ++always_export_symbols_CXX=no ++archive_expsym_cmds_CXX= ++compiler_needs_object_CXX=no ++export_dynamic_flag_spec_CXX= ++hardcode_direct_CXX=no ++hardcode_direct_absolute_CXX=no ++hardcode_libdir_flag_spec_CXX= ++hardcode_libdir_flag_spec_ld_CXX= ++hardcode_libdir_separator_CXX= ++hardcode_minus_L_CXX=no ++hardcode_shlibpath_var_CXX=unsupported ++hardcode_automatic_CXX=no ++inherit_rpath_CXX=no ++module_cmds_CXX= ++module_expsym_cmds_CXX= ++link_all_deplibs_CXX=unknown ++old_archive_cmds_CXX=$old_archive_cmds ++reload_flag_CXX=$reload_flag ++reload_cmds_CXX=$reload_cmds ++no_undefined_flag_CXX= ++whole_archive_flag_spec_CXX= ++enable_shared_with_static_runtimes_CXX=no ++ ++# Source file extension for C++ test sources. ++ac_ext=cpp ++ ++# Object file extension for compiled C++ test sources. ++objext=o ++objext_CXX=$objext ++ ++# No sense in running all these tests if we already determined that ++# the CXX compiler isn't working. Some variables (like enable_shared) ++# are currently assumed to apply to all compilers on this platform, ++# and will be corrupted by setting them based on a non-working compiler. ++if test "$_lt_caught_CXX_error" != yes; then ++ # Code to be used in simple compile tests ++ lt_simple_compile_test_code="int some_variable = 0;" ++ ++ # Code to be used in simple link tests ++ lt_simple_link_test_code='int main(int, char *[]) { return(0); }' ++ ++ # ltmain only uses $CC for tagged configurations so make sure $CC is set. ++ ++ ++ ++ ++ ++ ++# If no C compiler was specified, use CC. ++LTCC=${LTCC-"$CC"} ++ ++# If no C compiler flags were specified, use CFLAGS. ++LTCFLAGS=${LTCFLAGS-"$CFLAGS"} ++ ++# Allow CC to be a program name with arguments. ++compiler=$CC ++ ++ ++ # save warnings/boilerplate of simple test code ++ ac_outfile=conftest.$ac_objext ++echo "$lt_simple_compile_test_code" >conftest.$ac_ext ++eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err ++_lt_compiler_boilerplate=`cat conftest.err` ++$RM conftest* ++ ++ ac_outfile=conftest.$ac_objext ++echo "$lt_simple_link_test_code" >conftest.$ac_ext ++eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err ++_lt_linker_boilerplate=`cat conftest.err` ++$RM -r conftest* ++ ++ ++ # Allow CC to be a program name with arguments. ++ lt_save_CC=$CC ++ lt_save_LD=$LD ++ lt_save_GCC=$GCC ++ GCC=$GXX ++ lt_save_with_gnu_ld=$with_gnu_ld ++ lt_save_path_LD=$lt_cv_path_LD ++ if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then ++ lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx ++ else ++ $as_unset lt_cv_prog_gnu_ld ++ fi ++ if test -n "${lt_cv_path_LDCXX+set}"; then ++ lt_cv_path_LD=$lt_cv_path_LDCXX ++ else ++ $as_unset lt_cv_path_LD ++ fi ++ test -z "${LDCXX+set}" || LD=$LDCXX ++ CC=${CXX-"c++"} ++ compiler=$CC ++ compiler_CXX=$CC ++ for cc_temp in $compiler""; do ++ case $cc_temp in ++ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; ++ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; ++ \-*) ;; ++ *) break;; ++ esac ++done ++cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` ++ ++ ++ if test -n "$compiler"; then ++ # We don't want -fno-exception when compiling C++ code, so set the ++ # no_builtin_flag separately ++ if test "$GXX" = yes; then ++ lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' ++ else ++ lt_prog_compiler_no_builtin_flag_CXX= ++ fi ++ ++ if test "$GXX" = yes; then ++ # Set up default GNU C++ configuration ++ ++ ++ ++# Check whether --with-gnu-ld was given. ++if test "${with_gnu_ld+set}" = set; then : ++ withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes ++else ++ with_gnu_ld=no ++fi ++ ++ac_prog=ld ++if test "$GCC" = yes; then ++ # Check if gcc -print-prog-name=ld gives a path. ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 ++$as_echo_n "checking for ld used by $CC... " >&6; } ++ case $host in ++ *-*-mingw*) ++ # gcc leaves a trailing carriage return which upsets mingw ++ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; ++ *) ++ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; ++ esac ++ case $ac_prog in ++ # Accept absolute paths. ++ [\\/]* | ?:[\\/]*) ++ re_direlt='/[^/][^/]*/\.\./' ++ # Canonicalize the pathname of ld ++ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` ++ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ++ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` ++ done ++ test -z "$LD" && LD="$ac_prog" ++ ;; ++ "") ++ # If it fails, then pretend we aren't using GCC. ++ ac_prog=ld ++ ;; ++ *) ++ # If it is relative, then search for the first ld in PATH. ++ with_gnu_ld=unknown ++ ;; ++ esac ++elif test "$with_gnu_ld" = yes; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 ++$as_echo_n "checking for GNU ld... " >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 ++$as_echo_n "checking for non-GNU ld... " >&6; } ++fi ++if ${lt_cv_path_LD+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ if test -z "$LD"; then ++ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ++ for ac_dir in $PATH; do ++ IFS="$lt_save_ifs" ++ test -z "$ac_dir" && ac_dir=. ++ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then ++ lt_cv_path_LD="$ac_dir/$ac_prog" ++ # Check to see if the program is GNU ld. I'd rather use --version, ++ # but apparently some variants of GNU ld only accept -v. ++ # Break only if it was the GNU/non-GNU ld that we prefer. ++ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in ++ *GNU* | *'with BFD'*) ++ test "$with_gnu_ld" != no && break ++ ;; ++ *) ++ test "$with_gnu_ld" != yes && break ++ ;; ++ esac ++ fi ++ done ++ IFS="$lt_save_ifs" ++else ++ lt_cv_path_LD="$LD" # Let the user override the test with a path. ++fi ++fi ++ ++LD="$lt_cv_path_LD" ++if test -n "$LD"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 ++$as_echo "$LD" >&6; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++fi ++test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 ++$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } ++if ${lt_cv_prog_gnu_ld+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ # I'd rather use --version here, but apparently some GNU lds only accept -v. ++case `$LD -v 2>&1 </dev/null` in ++*GNU* | *'with BFD'*) ++ lt_cv_prog_gnu_ld=yes ++ ;; ++*) ++ lt_cv_prog_gnu_ld=no ++ ;; ++esac ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5 ++$as_echo "$lt_cv_prog_gnu_ld" >&6; } ++with_gnu_ld=$lt_cv_prog_gnu_ld ++ ++ ++ ++ ++ ++ ++ ++ # Check if GNU C++ uses GNU ld as the underlying linker, since the ++ # archiving commands below assume that GNU ld is being used. ++ if test "$with_gnu_ld" = yes; then ++ archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' ++ archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ++ ++ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' ++ export_dynamic_flag_spec_CXX='${wl}--export-dynamic' ++ ++ # If archive_cmds runs LD, not CC, wlarc should be empty ++ # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to ++ # investigate it a little bit more. (MM) ++ wlarc='${wl}' ++ ++ # ancient GNU ld didn't support --whole-archive et. al. ++ if eval "`$CC -print-prog-name=ld` --help 2>&1" | ++ $GREP 'no-whole-archive' > /dev/null; then ++ whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' ++ else ++ whole_archive_flag_spec_CXX= ++ fi ++ else ++ with_gnu_ld=no ++ wlarc= ++ ++ # A generic and very simple default shared library creation ++ # command for GNU C++ for the case where it uses the native ++ # linker, instead of GNU ld. If possible, this setting should ++ # overridden to take advantage of the native linker features on ++ # the platform it is being used on. ++ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' ++ fi ++ ++ # Commands to make compiler produce verbose output that lists ++ # what "hidden" libraries, object files and flags are used when ++ # linking a shared library. ++ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' ++ ++ else ++ GXX=no ++ with_gnu_ld=no ++ wlarc= ++ fi ++ ++ # PORTME: fill in a description of your system's C++ link characteristics ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 ++$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } ++ ld_shlibs_CXX=yes ++ case $host_os in ++ aix3*) ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ ;; ++ aix[4-9]*) ++ if test "$host_cpu" = ia64; then ++ # On IA64, the linker does run time linking by default, so we don't ++ # have to do anything special. ++ aix_use_runtimelinking=no ++ exp_sym_flag='-Bexport' ++ no_entry_flag="" ++ else ++ aix_use_runtimelinking=no ++ ++ # Test if we are trying to use run time linking or normal ++ # AIX style linking. If -brtl is somewhere in LDFLAGS, we ++ # need to do runtime linking. ++ case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) ++ for ld_flag in $LDFLAGS; do ++ case $ld_flag in ++ *-brtl*) ++ aix_use_runtimelinking=yes ++ break ++ ;; ++ esac ++ done ++ ;; ++ esac ++ ++ exp_sym_flag='-bexport' ++ no_entry_flag='-bnoentry' ++ fi ++ ++ # When large executables or shared objects are built, AIX ld can ++ # have problems creating the table of contents. If linking a library ++ # or program results in "error TOC overflow" add -mminimal-toc to ++ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not ++ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. ++ ++ archive_cmds_CXX='' ++ hardcode_direct_CXX=yes ++ hardcode_direct_absolute_CXX=yes ++ hardcode_libdir_separator_CXX=':' ++ link_all_deplibs_CXX=yes ++ file_list_spec_CXX='${wl}-f,' ++ ++ if test "$GXX" = yes; then ++ case $host_os in aix4.[012]|aix4.[012].*) ++ # We only want to do this on AIX 4.2 and lower, the check ++ # below for broken collect2 doesn't work under 4.3+ ++ collect2name=`${CC} -print-prog-name=collect2` ++ if test -f "$collect2name" && ++ strings "$collect2name" | $GREP resolve_lib_name >/dev/null ++ then ++ # We have reworked collect2 ++ : ++ else ++ # We have old collect2 ++ hardcode_direct_CXX=unsupported ++ # It fails to find uninstalled libraries when the uninstalled ++ # path is not listed in the libpath. Setting hardcode_minus_L ++ # to unsupported forces relinking ++ hardcode_minus_L_CXX=yes ++ hardcode_libdir_flag_spec_CXX='-L$libdir' ++ hardcode_libdir_separator_CXX= ++ fi ++ esac ++ shared_flag='-shared' ++ if test "$aix_use_runtimelinking" = yes; then ++ shared_flag="$shared_flag "'${wl}-G' ++ fi ++ else ++ # not using gcc ++ if test "$host_cpu" = ia64; then ++ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release ++ # chokes on -Wl,-G. The following line is correct: ++ shared_flag='-G' ++ else ++ if test "$aix_use_runtimelinking" = yes; then ++ shared_flag='${wl}-G' ++ else ++ shared_flag='${wl}-bM:SRE' ++ fi ++ fi ++ fi ++ ++ export_dynamic_flag_spec_CXX='${wl}-bexpall' ++ # It seems that -bexpall does not export symbols beginning with ++ # underscore (_), so it is better to generate a list of symbols to ++ # export. ++ always_export_symbols_CXX=yes ++ if test "$aix_use_runtimelinking" = yes; then ++ # Warning - without using the other runtime loading flags (-brtl), ++ # -berok will link without error, but may produce a broken library. ++ allow_undefined_flag_CXX='-berok' ++ # Determine the default libpath from the value encoded in an empty ++ # executable. ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_cxx_try_link "$LINENO"; then : ++ ++lt_aix_libpath_sed=' ++ /Import File Strings/,/^$/ { ++ /^0/ { ++ s/^0 *\(.*\)$/\1/ ++ p ++ } ++ }' ++aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` ++# Check for a 64-bit object if we didn't find anything. ++if test -z "$aix_libpath"; then ++ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` ++fi ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi ++ ++ hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" ++ ++ archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" ++ else ++ if test "$host_cpu" = ia64; then ++ hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' ++ allow_undefined_flag_CXX="-z nodefs" ++ archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" ++ else ++ # Determine the default libpath from the value encoded in an ++ # empty executable. ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_cxx_try_link "$LINENO"; then : ++ ++lt_aix_libpath_sed=' ++ /Import File Strings/,/^$/ { ++ /^0/ { ++ s/^0 *\(.*\)$/\1/ ++ p ++ } ++ }' ++aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` ++# Check for a 64-bit object if we didn't find anything. ++if test -z "$aix_libpath"; then ++ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` ++fi ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi ++ ++ hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" ++ # Warning - without using the other run time loading flags, ++ # -berok will link without error, but may produce a broken library. ++ no_undefined_flag_CXX=' ${wl}-bernotok' ++ allow_undefined_flag_CXX=' ${wl}-berok' ++ if test "$with_gnu_ld" = yes; then ++ # We only use this code for GNU lds that support --whole-archive. ++ whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ++ else ++ # Exported symbols can be pulled into shared objects from archives ++ whole_archive_flag_spec_CXX='$convenience' ++ fi ++ archive_cmds_need_lc_CXX=yes ++ # This is similar to how AIX traditionally builds its shared ++ # libraries. ++ archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' ++ fi ++ fi ++ ;; ++ ++ beos*) ++ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then ++ allow_undefined_flag_CXX=unsupported ++ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc ++ # support --undefined. This deserves some investigation. FIXME ++ archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' ++ else ++ ld_shlibs_CXX=no ++ fi ++ ;; ++ ++ chorus*) ++ case $cc_basename in ++ *) ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ ;; ++ esac ++ ;; ++ ++ cygwin* | mingw* | pw32* | cegcc*) ++ # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, ++ # as there is no search path for DLLs. ++ hardcode_libdir_flag_spec_CXX='-L$libdir' ++ export_dynamic_flag_spec_CXX='${wl}--export-all-symbols' ++ allow_undefined_flag_CXX=unsupported ++ always_export_symbols_CXX=no ++ enable_shared_with_static_runtimes_CXX=yes ++ ++ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then ++ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' ++ # If the export-symbols file already is a .def file (1st line ++ # is EXPORTS), use it as is; otherwise, prepend... ++ archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then ++ cp $export_symbols $output_objdir/$soname.def; ++ else ++ echo EXPORTS > $output_objdir/$soname.def; ++ cat $export_symbols >> $output_objdir/$soname.def; ++ fi~ ++ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' ++ else ++ ld_shlibs_CXX=no ++ fi ++ ;; ++ darwin* | rhapsody*) ++ ++ ++ archive_cmds_need_lc_CXX=no ++ hardcode_direct_CXX=no ++ hardcode_automatic_CXX=yes ++ hardcode_shlibpath_var_CXX=unsupported ++ if test "$lt_cv_ld_force_load" = "yes"; then ++ whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' ++ else ++ whole_archive_flag_spec_CXX='' ++ fi ++ link_all_deplibs_CXX=yes ++ allow_undefined_flag_CXX="$_lt_dar_allow_undefined" ++ case $cc_basename in ++ ifort*) _lt_dar_can_shared=yes ;; ++ *) _lt_dar_can_shared=$GCC ;; ++ esac ++ if test "$_lt_dar_can_shared" = "yes"; then ++ output_verbose_link_cmd=func_echo_all ++ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "$lt_cv_apple_cc_single_mod" != "yes"; then ++ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" ++ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi ++ ++ else ++ ld_shlibs_CXX=no ++ fi ++ ++ ;; ++ ++ dgux*) ++ case $cc_basename in ++ ec++*) ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ ;; ++ ghcx*) ++ # Green Hills C++ Compiler ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ ;; ++ *) ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ ;; ++ esac ++ ;; ++ ++ freebsd2.*) ++ # C++ shared libraries reported to be fairly broken before ++ # switch to ELF ++ ld_shlibs_CXX=no ++ ;; ++ ++ freebsd-elf*) ++ archive_cmds_need_lc_CXX=no ++ ;; ++ ++ freebsd* | dragonfly*) ++ # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF ++ # conventions ++ ld_shlibs_CXX=yes ++ ;; ++ ++ gnu*) ++ ;; ++ ++ haiku*) ++ archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' ++ link_all_deplibs_CXX=yes ++ ;; ++ ++ hpux9*) ++ hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' ++ hardcode_libdir_separator_CXX=: ++ export_dynamic_flag_spec_CXX='${wl}-E' ++ hardcode_direct_CXX=yes ++ hardcode_minus_L_CXX=yes # Not in the search PATH, ++ # but as the default ++ # location of the library. ++ ++ case $cc_basename in ++ CC*) ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ ;; ++ aCC*) ++ archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' ++ # Commands to make compiler produce verbose output that lists ++ # what "hidden" libraries, object files and flags are used when ++ # linking a shared library. ++ # ++ # There doesn't appear to be a way to prevent this compiler from ++ # explicitly linking system object files so we need to strip them ++ # from the output so that they don't get included in the library ++ # dependencies. ++ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ++ ;; ++ *) ++ if test "$GXX" = yes; then ++ archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' ++ else ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ fi ++ ;; ++ esac ++ ;; ++ ++ hpux10*|hpux11*) ++ if test $with_gnu_ld = no; then ++ hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' ++ hardcode_libdir_separator_CXX=: ++ ++ case $host_cpu in ++ hppa*64*|ia64*) ++ ;; ++ *) ++ export_dynamic_flag_spec_CXX='${wl}-E' ++ ;; ++ esac ++ fi ++ case $host_cpu in ++ hppa*64*|ia64*) ++ hardcode_direct_CXX=no ++ hardcode_shlibpath_var_CXX=no ++ ;; ++ *) ++ hardcode_direct_CXX=yes ++ hardcode_direct_absolute_CXX=yes ++ hardcode_minus_L_CXX=yes # Not in the search PATH, ++ # but as the default ++ # location of the library. ++ ;; ++ esac ++ ++ case $cc_basename in ++ CC*) ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ ;; ++ aCC*) ++ case $host_cpu in ++ hppa*64*) ++ archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ++ ;; ++ ia64*) ++ archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ++ ;; ++ *) ++ archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ++ ;; ++ esac ++ # Commands to make compiler produce verbose output that lists ++ # what "hidden" libraries, object files and flags are used when ++ # linking a shared library. ++ # ++ # There doesn't appear to be a way to prevent this compiler from ++ # explicitly linking system object files so we need to strip them ++ # from the output so that they don't get included in the library ++ # dependencies. ++ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ++ ;; ++ *) ++ if test "$GXX" = yes; then ++ if test $with_gnu_ld = no; then ++ case $host_cpu in ++ hppa*64*) ++ archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ++ ;; ++ ia64*) ++ archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ++ ;; ++ *) ++ archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ++ ;; ++ esac ++ fi ++ else ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ fi ++ ;; ++ esac ++ ;; ++ ++ interix[3-9]*) ++ hardcode_direct_CXX=no ++ hardcode_shlibpath_var_CXX=no ++ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' ++ export_dynamic_flag_spec_CXX='${wl}-E' ++ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. ++ # Instead, shared libraries are loaded at an image base (0x10000000 by ++ # default) and relocated if they conflict, which is a slow very memory ++ # consuming and fragmenting process. To avoid this, we pick a random, ++ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link ++ # time. Moving up from 0x10000000 also allows more sbrk(2) space. ++ archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ++ archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ++ ;; ++ irix5* | irix6*) ++ case $cc_basename in ++ CC*) ++ # SGI C++ ++ archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' ++ ++ # Archives containing C++ object files must be created using ++ # "CC -ar", where "CC" is the IRIX C++ compiler. This is ++ # necessary to make sure instantiated templates are included ++ # in the archive. ++ old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' ++ ;; ++ *) ++ if test "$GXX" = yes; then ++ if test "$with_gnu_ld" = no; then ++ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ++ else ++ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' ++ fi ++ fi ++ link_all_deplibs_CXX=yes ++ ;; ++ esac ++ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' ++ hardcode_libdir_separator_CXX=: ++ inherit_rpath_CXX=yes ++ ;; ++ ++ linux* | k*bsd*-gnu | kopensolaris*-gnu) ++ case $cc_basename in ++ KCC*) ++ # Kuck and Associates, Inc. (KAI) C++ Compiler ++ ++ # KCC will only create a shared library if the output file ++ # ends with ".so" (or ".sl" for HP-UX), so rename the library ++ # to its proper name (with version) after linking. ++ archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' ++ archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' ++ # Commands to make compiler produce verbose output that lists ++ # what "hidden" libraries, object files and flags are used when ++ # linking a shared library. ++ # ++ # There doesn't appear to be a way to prevent this compiler from ++ # explicitly linking system object files so we need to strip them ++ # from the output so that they don't get included in the library ++ # dependencies. ++ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ++ ++ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' ++ export_dynamic_flag_spec_CXX='${wl}--export-dynamic' ++ ++ # Archives containing C++ object files must be created using ++ # "CC -Bstatic", where "CC" is the KAI C++ compiler. ++ old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ++ ;; ++ icpc* | ecpc* ) ++ # Intel C++ ++ with_gnu_ld=yes ++ # version 8.0 and above of icpc choke on multiply defined symbols ++ # if we add $predep_objects and $postdep_objects, however 7.1 and ++ # earlier do not add the objects themselves. ++ case `$CC -V 2>&1` in ++ *"Version 7."*) ++ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' ++ archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ++ ;; ++ *) # Version 8.0 or newer ++ tmp_idyn= ++ case $host_cpu in ++ ia64*) tmp_idyn=' -i_dynamic';; ++ esac ++ archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' ++ archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ++ ;; ++ esac ++ archive_cmds_need_lc_CXX=no ++ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' ++ export_dynamic_flag_spec_CXX='${wl}--export-dynamic' ++ whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ++ ;; ++ pgCC* | pgcpp*) ++ # Portland Group C++ compiler ++ case `$CC -V` in ++ *pgCC\ [1-5].* | *pgcpp\ [1-5].*) ++ prelink_cmds_CXX='tpldir=Template.dir~ ++ rm -rf $tpldir~ ++ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ ++ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' ++ old_archive_cmds_CXX='tpldir=Template.dir~ ++ rm -rf $tpldir~ ++ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ ++ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ ++ $RANLIB $oldlib' ++ archive_cmds_CXX='tpldir=Template.dir~ ++ rm -rf $tpldir~ ++ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ ++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' ++ archive_expsym_cmds_CXX='tpldir=Template.dir~ ++ rm -rf $tpldir~ ++ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ ++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ++ ;; ++ *) # Version 6 and above use weak symbols ++ archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' ++ archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ++ ;; ++ esac ++ ++ hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' ++ export_dynamic_flag_spec_CXX='${wl}--export-dynamic' ++ whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ++ ;; ++ cxx*) ++ # Compaq C++ ++ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' ++ archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' ++ ++ runpath_var=LD_RUN_PATH ++ hardcode_libdir_flag_spec_CXX='-rpath $libdir' ++ hardcode_libdir_separator_CXX=: ++ ++ # Commands to make compiler produce verbose output that lists ++ # what "hidden" libraries, object files and flags are used when ++ # linking a shared library. ++ # ++ # There doesn't appear to be a way to prevent this compiler from ++ # explicitly linking system object files so we need to strip them ++ # from the output so that they don't get included in the library ++ # dependencies. ++ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ++ ;; ++ xl* | mpixl* | bgxl*) ++ # IBM XL 8.0 on PPC, with GNU ld ++ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' ++ export_dynamic_flag_spec_CXX='${wl}--export-dynamic' ++ archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' ++ if test "x$supports_anon_versioning" = xyes; then ++ archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~ ++ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ ++ echo "local: *; };" >> $output_objdir/$libname.ver~ ++ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' ++ fi ++ ;; ++ *) ++ case `$CC -V 2>&1 | sed 5q` in ++ *Sun\ C*) ++ # Sun C++ 5.9 ++ no_undefined_flag_CXX=' -zdefs' ++ archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ++ archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' ++ hardcode_libdir_flag_spec_CXX='-R$libdir' ++ whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ++ compiler_needs_object_CXX=yes ++ ++ # Not sure whether something based on ++ # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 ++ # would be better. ++ output_verbose_link_cmd='func_echo_all' ++ ++ # Archives containing C++ object files must be created using ++ # "CC -xar", where "CC" is the Sun C++ compiler. This is ++ # necessary to make sure instantiated templates are included ++ # in the archive. ++ old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' ++ ;; ++ esac ++ ;; ++ esac ++ ;; ++ ++ lynxos*) ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ ;; ++ ++ m88k*) ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ ;; ++ ++ mvs*) ++ case $cc_basename in ++ cxx*) ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ ;; ++ *) ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ ;; ++ esac ++ ;; ++ ++ netbsd*) ++ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then ++ archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' ++ wlarc= ++ hardcode_libdir_flag_spec_CXX='-R$libdir' ++ hardcode_direct_CXX=yes ++ hardcode_shlibpath_var_CXX=no ++ fi ++ # Workaround some broken pre-1.5 toolchains ++ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ++ ;; ++ ++ *nto* | *qnx*) ++ ld_shlibs_CXX=yes ++ ;; ++ ++ openbsd2*) ++ # C++ shared libraries are fairly broken ++ ld_shlibs_CXX=no ++ ;; ++ ++ openbsd*) ++ if test -f /usr/libexec/ld.so; then ++ hardcode_direct_CXX=yes ++ hardcode_shlibpath_var_CXX=no ++ hardcode_direct_absolute_CXX=yes ++ archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' ++ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' ++ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then ++ archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' ++ export_dynamic_flag_spec_CXX='${wl}-E' ++ whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' ++ fi ++ output_verbose_link_cmd=func_echo_all ++ else ++ ld_shlibs_CXX=no ++ fi ++ ;; ++ ++ osf3* | osf4* | osf5*) ++ case $cc_basename in ++ KCC*) ++ # Kuck and Associates, Inc. (KAI) C++ Compiler ++ ++ # KCC will only create a shared library if the output file ++ # ends with ".so" (or ".sl" for HP-UX), so rename the library ++ # to its proper name (with version) after linking. ++ archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' ++ ++ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' ++ hardcode_libdir_separator_CXX=: ++ ++ # Archives containing C++ object files must be created using ++ # the KAI C++ compiler. ++ case $host in ++ osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; ++ *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; ++ esac ++ ;; ++ RCC*) ++ # Rational C++ 2.4.1 ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ ;; ++ cxx*) ++ case $host in ++ osf3*) ++ allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' ++ archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' ++ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' ++ ;; ++ *) ++ allow_undefined_flag_CXX=' -expect_unresolved \*' ++ archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' ++ archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ ++ echo "-hidden">> $lib.exp~ ++ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ ++ $RM $lib.exp' ++ hardcode_libdir_flag_spec_CXX='-rpath $libdir' ++ ;; ++ esac ++ ++ hardcode_libdir_separator_CXX=: ++ ++ # Commands to make compiler produce verbose output that lists ++ # what "hidden" libraries, object files and flags are used when ++ # linking a shared library. ++ # ++ # There doesn't appear to be a way to prevent this compiler from ++ # explicitly linking system object files so we need to strip them ++ # from the output so that they don't get included in the library ++ # dependencies. ++ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ++ ;; ++ *) ++ if test "$GXX" = yes && test "$with_gnu_ld" = no; then ++ allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' ++ case $host in ++ osf3*) ++ archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ++ ;; ++ *) ++ archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ++ ;; ++ esac ++ ++ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' ++ hardcode_libdir_separator_CXX=: ++ ++ # Commands to make compiler produce verbose output that lists ++ # what "hidden" libraries, object files and flags are used when ++ # linking a shared library. ++ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' ++ ++ else ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ fi ++ ;; ++ esac ++ ;; ++ ++ psos*) ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ ;; ++ ++ sunos4*) ++ case $cc_basename in ++ CC*) ++ # Sun C++ 4.x ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ ;; ++ lcc*) ++ # Lucid ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ ;; ++ *) ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ ;; ++ esac ++ ;; ++ ++ solaris*) ++ case $cc_basename in ++ CC*) ++ # Sun C++ 4.2, 5.x and Centerline C++ ++ archive_cmds_need_lc_CXX=yes ++ no_undefined_flag_CXX=' -zdefs' ++ archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ++ archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ ++ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' ++ ++ hardcode_libdir_flag_spec_CXX='-R$libdir' ++ hardcode_shlibpath_var_CXX=no ++ case $host_os in ++ solaris2.[0-5] | solaris2.[0-5].*) ;; ++ *) ++ # The compiler driver will combine and reorder linker options, ++ # but understands `-z linker_flag'. ++ # Supported since Solaris 2.6 (maybe 2.5.1?) ++ whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' ++ ;; ++ esac ++ link_all_deplibs_CXX=yes ++ ++ output_verbose_link_cmd='func_echo_all' ++ ++ # Archives containing C++ object files must be created using ++ # "CC -xar", where "CC" is the Sun C++ compiler. This is ++ # necessary to make sure instantiated templates are included ++ # in the archive. ++ old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' ++ ;; ++ gcx*) ++ # Green Hills C++ Compiler ++ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' ++ ++ # The C++ compiler must be used to create the archive. ++ old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ++ ;; ++ *) ++ # GNU C++ compiler with Solaris linker ++ if test "$GXX" = yes && test "$with_gnu_ld" = no; then ++ no_undefined_flag_CXX=' ${wl}-z ${wl}defs' ++ if $CC --version | $GREP -v '^2\.7' > /dev/null; then ++ archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' ++ archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ ++ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' ++ ++ # Commands to make compiler produce verbose output that lists ++ # what "hidden" libraries, object files and flags are used when ++ # linking a shared library. ++ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' ++ else ++ # g++ 2.7 appears to require `-G' NOT `-shared' on this ++ # platform. ++ archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' ++ archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ ++ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' ++ ++ # Commands to make compiler produce verbose output that lists ++ # what "hidden" libraries, object files and flags are used when ++ # linking a shared library. ++ output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' ++ fi ++ ++ hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' ++ case $host_os in ++ solaris2.[0-5] | solaris2.[0-5].*) ;; ++ *) ++ whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ++ ;; ++ esac ++ fi ++ ;; ++ esac ++ ;; ++ ++ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) ++ no_undefined_flag_CXX='${wl}-z,text' ++ archive_cmds_need_lc_CXX=no ++ hardcode_shlibpath_var_CXX=no ++ runpath_var='LD_RUN_PATH' ++ ++ case $cc_basename in ++ CC*) ++ archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ++ archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ++ ;; ++ *) ++ archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ++ archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ++ ;; ++ esac ++ ;; ++ ++ sysv5* | sco3.2v5* | sco5v6*) ++ # Note: We can NOT use -z defs as we might desire, because we do not ++ # link with -lc, and that would cause any symbols used from libc to ++ # always be unresolved, which means just about no library would ++ # ever link correctly. If we're not using GNU ld we use -z text ++ # though, which does catch some bad symbols but isn't as heavy-handed ++ # as -z defs. ++ no_undefined_flag_CXX='${wl}-z,text' ++ allow_undefined_flag_CXX='${wl}-z,nodefs' ++ archive_cmds_need_lc_CXX=no ++ hardcode_shlibpath_var_CXX=no ++ hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir' ++ hardcode_libdir_separator_CXX=':' ++ link_all_deplibs_CXX=yes ++ export_dynamic_flag_spec_CXX='${wl}-Bexport' ++ runpath_var='LD_RUN_PATH' ++ ++ case $cc_basename in ++ CC*) ++ archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ++ archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ++ old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~ ++ '"$old_archive_cmds_CXX" ++ reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~ ++ '"$reload_cmds_CXX" ++ ;; ++ *) ++ archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ++ archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ++ ;; ++ esac ++ ;; ++ ++ tandem*) ++ case $cc_basename in ++ NCC*) ++ # NonStop-UX NCC 3.20 ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ ;; ++ *) ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ ;; ++ esac ++ ;; ++ ++ vxworks*) ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ ;; ++ ++ *) ++ # FIXME: insert proper C++ library support ++ ld_shlibs_CXX=no ++ ;; ++ esac ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 ++$as_echo "$ld_shlibs_CXX" >&6; } ++ test "$ld_shlibs_CXX" = no && can_build_shared=no ++ ++ GCC_CXX="$GXX" ++ LD_CXX="$LD" ++ ++ ## CAVEAT EMPTOR: ++ ## There is no encapsulation within the following macros, do not change ++ ## the running order or otherwise move them around unless you know exactly ++ ## what you are doing... ++ # Dependencies to place before and after the object being linked: ++predep_objects_CXX= ++postdep_objects_CXX= ++predeps_CXX= ++postdeps_CXX= ++compiler_lib_search_path_CXX= ++ ++cat > conftest.$ac_ext <<_LT_EOF ++class Foo ++{ ++public: ++ Foo (void) { a = 0; } ++private: ++ int a; ++}; ++_LT_EOF ++ ++if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 ++ (eval $ac_compile) 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; }; then ++ # Parse the compiler output and extract the necessary ++ # objects, libraries and library flags. ++ ++ # Sentinel used to keep track of whether or not we are before ++ # the conftest object file. ++ pre_test_object_deps_done=no ++ ++ for p in `eval "$output_verbose_link_cmd"`; do ++ case $p in ++ ++ -L* | -R* | -l*) ++ # Some compilers place space between "-{L,R}" and the path. ++ # Remove the space. ++ if test $p = "-L" || ++ test $p = "-R"; then ++ prev=$p ++ continue ++ else ++ prev= ++ fi ++ ++ if test "$pre_test_object_deps_done" = no; then ++ case $p in ++ -L* | -R*) ++ # Internal compiler library paths should come after those ++ # provided the user. The postdeps already come after the ++ # user supplied libs so there is no need to process them. ++ if test -z "$compiler_lib_search_path_CXX"; then ++ compiler_lib_search_path_CXX="${prev}${p}" ++ else ++ compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" ++ fi ++ ;; ++ # The "-l" case would never come before the object being ++ # linked, so don't bother handling this case. ++ esac ++ else ++ if test -z "$postdeps_CXX"; then ++ postdeps_CXX="${prev}${p}" ++ else ++ postdeps_CXX="${postdeps_CXX} ${prev}${p}" ++ fi ++ fi ++ ;; ++ ++ *.$objext) ++ # This assumes that the test object file only shows up ++ # once in the compiler output. ++ if test "$p" = "conftest.$objext"; then ++ pre_test_object_deps_done=yes ++ continue ++ fi ++ ++ if test "$pre_test_object_deps_done" = no; then ++ if test -z "$predep_objects_CXX"; then ++ predep_objects_CXX="$p" ++ else ++ predep_objects_CXX="$predep_objects_CXX $p" ++ fi ++ else ++ if test -z "$postdep_objects_CXX"; then ++ postdep_objects_CXX="$p" ++ else ++ postdep_objects_CXX="$postdep_objects_CXX $p" ++ fi ++ fi ++ ;; ++ ++ *) ;; # Ignore the rest. ++ ++ esac ++ done ++ ++ # Clean up. ++ rm -f a.out a.exe ++else ++ echo "libtool.m4: error: problem compiling CXX test program" ++fi ++ ++$RM -f confest.$objext ++ ++# PORTME: override above test on systems where it is broken ++case $host_os in ++interix[3-9]*) ++ # Interix 3.5 installs completely hosed .la files for C++, so rather than ++ # hack all around it, let's just trust "g++" to DTRT. ++ predep_objects_CXX= ++ postdep_objects_CXX= ++ postdeps_CXX= ++ ;; ++ ++linux*) ++ case `$CC -V 2>&1 | sed 5q` in ++ *Sun\ C*) ++ # Sun C++ 5.9 ++ ++ # The more standards-conforming stlport4 library is ++ # incompatible with the Cstd library. Avoid specifying ++ # it if it's in CXXFLAGS. Ignore libCrun as ++ # -library=stlport4 depends on it. ++ case " $CXX $CXXFLAGS " in ++ *" -library=stlport4 "*) ++ solaris_use_stlport4=yes ++ ;; ++ esac ++ ++ if test "$solaris_use_stlport4" != yes; then ++ postdeps_CXX='-library=Cstd -library=Crun' ++ fi ++ ;; ++ esac ++ ;; ++ ++solaris*) ++ case $cc_basename in ++ CC*) ++ # The more standards-conforming stlport4 library is ++ # incompatible with the Cstd library. Avoid specifying ++ # it if it's in CXXFLAGS. Ignore libCrun as ++ # -library=stlport4 depends on it. ++ case " $CXX $CXXFLAGS " in ++ *" -library=stlport4 "*) ++ solaris_use_stlport4=yes ++ ;; ++ esac ++ ++ # Adding this requires a known-good setup of shared libraries for ++ # Sun compiler versions before 5.6, else PIC objects from an old ++ # archive will be linked into the output, leading to subtle bugs. ++ if test "$solaris_use_stlport4" != yes; then ++ postdeps_CXX='-library=Cstd -library=Crun' ++ fi ++ ;; ++ esac ++ ;; ++esac ++ ++ ++case " $postdeps_CXX " in ++*" -lc "*) archive_cmds_need_lc_CXX=no ;; ++esac ++ compiler_lib_search_dirs_CXX= ++if test -n "${compiler_lib_search_path_CXX}"; then ++ compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` ++fi ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ lt_prog_compiler_wl_CXX= ++lt_prog_compiler_pic_CXX= ++lt_prog_compiler_static_CXX= ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 ++$as_echo_n "checking for $compiler option to produce PIC... " >&6; } ++ ++ # C++ specific cases for pic, static, wl, etc. ++ if test "$GXX" = yes; then ++ lt_prog_compiler_wl_CXX='-Wl,' ++ lt_prog_compiler_static_CXX='-static' ++ ++ case $host_os in ++ aix*) ++ # All AIX code is PIC. ++ if test "$host_cpu" = ia64; then ++ # AIX 5 now supports IA64 processor ++ lt_prog_compiler_static_CXX='-Bstatic' ++ fi ++ lt_prog_compiler_pic_CXX='-fPIC' ++ ;; ++ ++ amigaos*) ++ case $host_cpu in ++ powerpc) ++ # see comment about AmigaOS4 .so support ++ lt_prog_compiler_pic_CXX='-fPIC' ++ ;; ++ m68k) ++ # FIXME: we need at least 68020 code to build shared libraries, but ++ # adding the `-m68020' flag to GCC prevents building anything better, ++ # like `-m68040'. ++ lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' ++ ;; ++ esac ++ ;; ++ ++ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) ++ # PIC is the default for these OSes. ++ ;; ++ mingw* | cygwin* | os2* | pw32* | cegcc*) ++ # This hack is so that the source file can tell whether it is being ++ # built for inclusion in a dll (and should export symbols for example). ++ # Although the cygwin gcc ignores -fPIC, still need this for old-style ++ # (--disable-auto-import) libraries ++ lt_prog_compiler_pic_CXX='-DDLL_EXPORT' ++ ;; ++ darwin* | rhapsody*) ++ # PIC is the default on this platform ++ # Common symbols not allowed in MH_DYLIB files ++ lt_prog_compiler_pic_CXX='-fno-common' ++ ;; ++ *djgpp*) ++ # DJGPP does not support shared libraries at all ++ lt_prog_compiler_pic_CXX= ++ ;; ++ haiku*) ++ # PIC is the default for Haiku. ++ # The "-static" flag exists, but is broken. ++ lt_prog_compiler_static_CXX= ++ ;; ++ interix[3-9]*) ++ # Interix 3.x gcc -fpic/-fPIC options generate broken code. ++ # Instead, we relocate shared libraries at runtime. ++ ;; ++ sysv4*MP*) ++ if test -d /usr/nec; then ++ lt_prog_compiler_pic_CXX=-Kconform_pic ++ fi ++ ;; ++ hpux*) ++ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit ++ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag ++ # sets the default TLS model and affects inlining. ++ case $host_cpu in ++ hppa*64*) ++ ;; ++ *) ++ lt_prog_compiler_pic_CXX='-fPIC' ++ ;; ++ esac ++ ;; ++ *qnx* | *nto*) ++ # QNX uses GNU C++, but need to define -shared option too, otherwise ++ # it will coredump. ++ lt_prog_compiler_pic_CXX='-fPIC -shared' ++ ;; ++ *) ++ lt_prog_compiler_pic_CXX='-fPIC' ++ ;; ++ esac ++ else ++ case $host_os in ++ aix[4-9]*) ++ # All AIX code is PIC. ++ if test "$host_cpu" = ia64; then ++ # AIX 5 now supports IA64 processor ++ lt_prog_compiler_static_CXX='-Bstatic' ++ else ++ lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' ++ fi ++ ;; ++ chorus*) ++ case $cc_basename in ++ cxch68*) ++ # Green Hills C++ Compiler ++ # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ++ ;; ++ esac ++ ;; ++ dgux*) ++ case $cc_basename in ++ ec++*) ++ lt_prog_compiler_pic_CXX='-KPIC' ++ ;; ++ ghcx*) ++ # Green Hills C++ Compiler ++ lt_prog_compiler_pic_CXX='-pic' ++ ;; ++ *) ++ ;; ++ esac ++ ;; ++ freebsd* | dragonfly*) ++ # FreeBSD uses GNU C++ ++ ;; ++ hpux9* | hpux10* | hpux11*) ++ case $cc_basename in ++ CC*) ++ lt_prog_compiler_wl_CXX='-Wl,' ++ lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' ++ if test "$host_cpu" != ia64; then ++ lt_prog_compiler_pic_CXX='+Z' ++ fi ++ ;; ++ aCC*) ++ lt_prog_compiler_wl_CXX='-Wl,' ++ lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' ++ case $host_cpu in ++ hppa*64*|ia64*) ++ # +Z the default ++ ;; ++ *) ++ lt_prog_compiler_pic_CXX='+Z' ++ ;; ++ esac ++ ;; ++ *) ++ ;; ++ esac ++ ;; ++ interix*) ++ # This is c89, which is MS Visual C++ (no shared libs) ++ # Anyone wants to do a port? ++ ;; ++ irix5* | irix6* | nonstopux*) ++ case $cc_basename in ++ CC*) ++ lt_prog_compiler_wl_CXX='-Wl,' ++ lt_prog_compiler_static_CXX='-non_shared' ++ # CC pic flag -KPIC is the default. ++ ;; ++ *) ++ ;; ++ esac ++ ;; ++ linux* | k*bsd*-gnu | kopensolaris*-gnu) ++ case $cc_basename in ++ KCC*) ++ # KAI C++ Compiler ++ lt_prog_compiler_wl_CXX='--backend -Wl,' ++ lt_prog_compiler_pic_CXX='-fPIC' ++ ;; ++ ecpc* ) ++ # old Intel C++ for x86_64 which still supported -KPIC. ++ lt_prog_compiler_wl_CXX='-Wl,' ++ lt_prog_compiler_pic_CXX='-KPIC' ++ lt_prog_compiler_static_CXX='-static' ++ ;; ++ icpc* ) ++ # Intel C++, used to be incompatible with GCC. ++ # ICC 10 doesn't accept -KPIC any more. ++ lt_prog_compiler_wl_CXX='-Wl,' ++ lt_prog_compiler_pic_CXX='-fPIC' ++ lt_prog_compiler_static_CXX='-static' ++ ;; ++ pgCC* | pgcpp*) ++ # Portland Group C++ compiler ++ lt_prog_compiler_wl_CXX='-Wl,' ++ lt_prog_compiler_pic_CXX='-fpic' ++ lt_prog_compiler_static_CXX='-Bstatic' ++ ;; ++ cxx*) ++ # Compaq C++ ++ # Make sure the PIC flag is empty. It appears that all Alpha ++ # Linux and Compaq Tru64 Unix objects are PIC. ++ lt_prog_compiler_pic_CXX= ++ lt_prog_compiler_static_CXX='-non_shared' ++ ;; ++ xlc* | xlC* | bgxl[cC]* | mpixl[cC]*) ++ # IBM XL 8.0, 9.0 on PPC and BlueGene ++ lt_prog_compiler_wl_CXX='-Wl,' ++ lt_prog_compiler_pic_CXX='-qpic' ++ lt_prog_compiler_static_CXX='-qstaticlink' ++ ;; ++ *) ++ case `$CC -V 2>&1 | sed 5q` in ++ *Sun\ C*) ++ # Sun C++ 5.9 ++ lt_prog_compiler_pic_CXX='-KPIC' ++ lt_prog_compiler_static_CXX='-Bstatic' ++ lt_prog_compiler_wl_CXX='-Qoption ld ' ++ ;; ++ esac ++ ;; ++ esac ++ ;; ++ lynxos*) ++ ;; ++ m88k*) ++ ;; ++ mvs*) ++ case $cc_basename in ++ cxx*) ++ lt_prog_compiler_pic_CXX='-W c,exportall' ++ ;; ++ *) ++ ;; ++ esac ++ ;; ++ netbsd*) ++ ;; ++ *qnx* | *nto*) ++ # QNX uses GNU C++, but need to define -shared option too, otherwise ++ # it will coredump. ++ lt_prog_compiler_pic_CXX='-fPIC -shared' ++ ;; ++ osf3* | osf4* | osf5*) ++ case $cc_basename in ++ KCC*) ++ lt_prog_compiler_wl_CXX='--backend -Wl,' ++ ;; ++ RCC*) ++ # Rational C++ 2.4.1 ++ lt_prog_compiler_pic_CXX='-pic' ++ ;; ++ cxx*) ++ # Digital/Compaq C++ ++ lt_prog_compiler_wl_CXX='-Wl,' ++ # Make sure the PIC flag is empty. It appears that all Alpha ++ # Linux and Compaq Tru64 Unix objects are PIC. ++ lt_prog_compiler_pic_CXX= ++ lt_prog_compiler_static_CXX='-non_shared' ++ ;; ++ *) ++ ;; ++ esac ++ ;; ++ psos*) ++ ;; ++ solaris*) ++ case $cc_basename in ++ CC*) ++ # Sun C++ 4.2, 5.x and Centerline C++ ++ lt_prog_compiler_pic_CXX='-KPIC' ++ lt_prog_compiler_static_CXX='-Bstatic' ++ lt_prog_compiler_wl_CXX='-Qoption ld ' ++ ;; ++ gcx*) ++ # Green Hills C++ Compiler ++ lt_prog_compiler_pic_CXX='-PIC' ++ ;; ++ *) ++ ;; ++ esac ++ ;; ++ sunos4*) ++ case $cc_basename in ++ CC*) ++ # Sun C++ 4.x ++ lt_prog_compiler_pic_CXX='-pic' ++ lt_prog_compiler_static_CXX='-Bstatic' ++ ;; ++ lcc*) ++ # Lucid ++ lt_prog_compiler_pic_CXX='-pic' ++ ;; ++ *) ++ ;; ++ esac ++ ;; ++ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) ++ case $cc_basename in ++ CC*) ++ lt_prog_compiler_wl_CXX='-Wl,' ++ lt_prog_compiler_pic_CXX='-KPIC' ++ lt_prog_compiler_static_CXX='-Bstatic' ++ ;; ++ esac ++ ;; ++ tandem*) ++ case $cc_basename in ++ NCC*) ++ # NonStop-UX NCC 3.20 ++ lt_prog_compiler_pic_CXX='-KPIC' ++ ;; ++ *) ++ ;; ++ esac ++ ;; ++ vxworks*) ++ ;; ++ *) ++ lt_prog_compiler_can_build_shared_CXX=no ++ ;; ++ esac ++ fi ++ ++case $host_os in ++ # For platforms which do not support PIC, -DPIC is meaningless: ++ *djgpp*) ++ lt_prog_compiler_pic_CXX= ++ ;; ++ *) ++ lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" ++ ;; ++esac ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_CXX" >&5 ++$as_echo "$lt_prog_compiler_pic_CXX" >&6; } ++ ++ ++ ++# ++# Check to make sure the PIC flag actually works. ++# ++if test -n "$lt_prog_compiler_pic_CXX"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 ++$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } ++if ${lt_cv_prog_compiler_pic_works_CXX+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ lt_cv_prog_compiler_pic_works_CXX=no ++ ac_outfile=conftest.$ac_objext ++ echo "$lt_simple_compile_test_code" > conftest.$ac_ext ++ lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" ++ # Insert the option either (1) after the last *FLAGS variable, or ++ # (2) before a word containing "conftest.", or (3) at the end. ++ # Note that $ac_compile itself does not contain backslashes and begins ++ # with a dollar sign (not a hyphen), so the echo should work correctly. ++ # The option is referenced via a variable to avoid confusing sed. ++ lt_compile=`echo "$ac_compile" | $SED \ ++ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ ++ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ ++ -e 's:$: $lt_compiler_flag:'` ++ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) ++ (eval "$lt_compile" 2>conftest.err) ++ ac_status=$? ++ cat conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ if (exit $ac_status) && test -s "$ac_outfile"; then ++ # The compiler can only warn and ignore the option if not recognized ++ # So say no if there are warnings other than the usual output. ++ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp ++ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 ++ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then ++ lt_cv_prog_compiler_pic_works_CXX=yes ++ fi ++ fi ++ $RM conftest* ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 ++$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; } ++ ++if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then ++ case $lt_prog_compiler_pic_CXX in ++ "" | " "*) ;; ++ *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; ++ esac ++else ++ lt_prog_compiler_pic_CXX= ++ lt_prog_compiler_can_build_shared_CXX=no ++fi ++ ++fi ++ ++ ++ ++# ++# Check to make sure the static flag actually works. ++# ++wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 ++$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } ++if ${lt_cv_prog_compiler_static_works_CXX+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ lt_cv_prog_compiler_static_works_CXX=no ++ save_LDFLAGS="$LDFLAGS" ++ LDFLAGS="$LDFLAGS $lt_tmp_static_flag" ++ echo "$lt_simple_link_test_code" > conftest.$ac_ext ++ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then ++ # The linker can only warn and ignore the option if not recognized ++ # So say no if there are warnings ++ if test -s conftest.err; then ++ # Append any errors to the config.log. ++ cat conftest.err 1>&5 ++ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp ++ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 ++ if diff conftest.exp conftest.er2 >/dev/null; then ++ lt_cv_prog_compiler_static_works_CXX=yes ++ fi ++ else ++ lt_cv_prog_compiler_static_works_CXX=yes ++ fi ++ fi ++ $RM -r conftest* ++ LDFLAGS="$save_LDFLAGS" ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5 ++$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; } ++ ++if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then ++ : ++else ++ lt_prog_compiler_static_CXX= ++fi ++ ++ ++ ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 ++$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } ++if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ lt_cv_prog_compiler_c_o_CXX=no ++ $RM -r conftest 2>/dev/null ++ mkdir conftest ++ cd conftest ++ mkdir out ++ echo "$lt_simple_compile_test_code" > conftest.$ac_ext ++ ++ lt_compiler_flag="-o out/conftest2.$ac_objext" ++ # Insert the option either (1) after the last *FLAGS variable, or ++ # (2) before a word containing "conftest.", or (3) at the end. ++ # Note that $ac_compile itself does not contain backslashes and begins ++ # with a dollar sign (not a hyphen), so the echo should work correctly. ++ lt_compile=`echo "$ac_compile" | $SED \ ++ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ ++ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ ++ -e 's:$: $lt_compiler_flag:'` ++ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) ++ (eval "$lt_compile" 2>out/conftest.err) ++ ac_status=$? ++ cat out/conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ if (exit $ac_status) && test -s out/conftest2.$ac_objext ++ then ++ # The compiler can only warn and ignore the option if not recognized ++ # So say no if there are warnings ++ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp ++ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 ++ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then ++ lt_cv_prog_compiler_c_o_CXX=yes ++ fi ++ fi ++ chmod u+w . 2>&5 ++ $RM conftest* ++ # SGI C++ compiler will create directory out/ii_files/ for ++ # template instantiation ++ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files ++ $RM out/* && rmdir out ++ cd .. ++ $RM -r conftest ++ $RM conftest* ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 ++$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } ++ ++ ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 ++$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } ++if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ lt_cv_prog_compiler_c_o_CXX=no ++ $RM -r conftest 2>/dev/null ++ mkdir conftest ++ cd conftest ++ mkdir out ++ echo "$lt_simple_compile_test_code" > conftest.$ac_ext ++ ++ lt_compiler_flag="-o out/conftest2.$ac_objext" ++ # Insert the option either (1) after the last *FLAGS variable, or ++ # (2) before a word containing "conftest.", or (3) at the end. ++ # Note that $ac_compile itself does not contain backslashes and begins ++ # with a dollar sign (not a hyphen), so the echo should work correctly. ++ lt_compile=`echo "$ac_compile" | $SED \ ++ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ ++ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ ++ -e 's:$: $lt_compiler_flag:'` ++ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) ++ (eval "$lt_compile" 2>out/conftest.err) ++ ac_status=$? ++ cat out/conftest.err >&5 ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ if (exit $ac_status) && test -s out/conftest2.$ac_objext ++ then ++ # The compiler can only warn and ignore the option if not recognized ++ # So say no if there are warnings ++ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp ++ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 ++ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then ++ lt_cv_prog_compiler_c_o_CXX=yes ++ fi ++ fi ++ chmod u+w . 2>&5 ++ $RM conftest* ++ # SGI C++ compiler will create directory out/ii_files/ for ++ # template instantiation ++ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files ++ $RM out/* && rmdir out ++ cd .. ++ $RM -r conftest ++ $RM conftest* ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 ++$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } ++ ++ ++ ++ ++hard_links="nottested" ++if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then ++ # do not overwrite the value of need_locks provided by the user ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 ++$as_echo_n "checking if we can lock with hard links... " >&6; } ++ hard_links=yes ++ $RM conftest* ++ ln conftest.a conftest.b 2>/dev/null && hard_links=no ++ touch conftest.a ++ ln conftest.a conftest.b 2>&5 || hard_links=no ++ ln conftest.a conftest.b 2>/dev/null && hard_links=no ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 ++$as_echo "$hard_links" >&6; } ++ if test "$hard_links" = no; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 ++$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} ++ need_locks=warn ++ fi ++else ++ need_locks=no ++fi ++ ++ ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 ++$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } ++ ++ export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ++ case $host_os in ++ aix[4-9]*) ++ # If we're using GNU nm, then we don't want the "-C" option. ++ # -C means demangle to AIX nm, but means don't demangle with GNU nm ++ # Also, AIX nm treats weak defined symbols like other global defined ++ # symbols, whereas GNU nm marks them as "W". ++ 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") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' ++ fi ++ ;; ++ pw32*) ++ export_symbols_cmds_CXX="$ltdll_cmds" ++ ;; ++ cygwin* | mingw* | cegcc*) ++ export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;/^.*[ ]__nm__/s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' ++ ;; ++ *) ++ export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ++ ;; ++ esac ++ exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 ++$as_echo "$ld_shlibs_CXX" >&6; } ++test "$ld_shlibs_CXX" = no && can_build_shared=no ++ ++with_gnu_ld_CXX=$with_gnu_ld ++ ++ ++ ++ ++ ++ ++# ++# Do we need to explicitly link libc? ++# ++case "x$archive_cmds_need_lc_CXX" in ++x|xyes) ++ # Assume -lc should be added ++ archive_cmds_need_lc_CXX=yes ++ ++ if test "$enable_shared" = yes && test "$GCC" = yes; then ++ case $archive_cmds_CXX in ++ *'~'*) ++ # FIXME: we may have to deal with multi-command sequences. ++ ;; ++ '$CC '*) ++ # Test whether the compiler implicitly links with -lc since on some ++ # systems, -lgcc has to come before -lc. If gcc already passes -lc ++ # to ld, don't add -lc before -lgcc. ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 ++$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } ++if ${lt_cv_archive_cmds_need_lc_CXX+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ $RM conftest* ++ echo "$lt_simple_compile_test_code" > conftest.$ac_ext ++ ++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 ++ (eval $ac_compile) 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; } 2>conftest.err; then ++ soname=conftest ++ lib=conftest ++ libobjs=conftest.$ac_objext ++ deplibs= ++ wl=$lt_prog_compiler_wl_CXX ++ pic_flag=$lt_prog_compiler_pic_CXX ++ compiler_flags=-v ++ linker_flags=-v ++ verstring= ++ output_objdir=. ++ libname=conftest ++ lt_save_allow_undefined_flag=$allow_undefined_flag_CXX ++ allow_undefined_flag_CXX= ++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 ++ (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; } ++ then ++ lt_cv_archive_cmds_need_lc_CXX=no ++ else ++ lt_cv_archive_cmds_need_lc_CXX=yes ++ fi ++ allow_undefined_flag_CXX=$lt_save_allow_undefined_flag ++ else ++ cat conftest.err 1>&5 ++ fi ++ $RM conftest* ++ ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5 ++$as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; } ++ archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX ++ ;; ++ esac ++ fi ++ ;; ++esac ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 ++$as_echo_n "checking dynamic linker characteristics... " >&6; } ++ ++library_names_spec= ++libname_spec='lib$name' ++soname_spec= ++shrext_cmds=".so" ++postinstall_cmds= ++postuninstall_cmds= ++finish_cmds= ++finish_eval= ++shlibpath_var= ++shlibpath_overrides_runpath=unknown ++version_type=none ++dynamic_linker="$host_os ld.so" ++sys_lib_dlsearch_path_spec="/lib /usr/lib" ++need_lib_prefix=unknown ++hardcode_into_libs=no ++ ++# when you set need_version to no, make sure it does not cause -set_version ++# flags to be left without arguments ++need_version=unknown ++ ++case $host_os in ++aix3*) ++ version_type=linux ++ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' ++ shlibpath_var=LIBPATH ++ ++ # AIX 3 has no versioning support, so we append a major version to the name. ++ soname_spec='${libname}${release}${shared_ext}$major' ++ ;; ++ ++aix[4-9]*) ++ version_type=linux ++ need_lib_prefix=no ++ need_version=no ++ hardcode_into_libs=yes ++ if test "$host_cpu" = ia64; then ++ # AIX 5 supports IA64 ++ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' ++ shlibpath_var=LD_LIBRARY_PATH ++ else ++ # With GCC up to 2.95.x, collect2 would create an import file ++ # for dependence libraries. The import file would start with ++ # the line `#! .'. This would cause the generated library to ++ # depend on `.', always an invalid library. This was fixed in ++ # development snapshots of GCC prior to 3.0. ++ case $host_os in ++ aix4 | aix4.[01] | aix4.[01].*) ++ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' ++ echo ' yes ' ++ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then ++ : ++ else ++ can_build_shared=no ++ fi ++ ;; ++ esac ++ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct ++ # soname into executable. Probably we can add versioning support to ++ # collect2, so additional links can be useful in future. ++ if test "$aix_use_runtimelinking" = yes; then ++ # If using run time linking (on AIX 4.2 or later) use lib<name>.so ++ # instead of lib<name>.a to let people know that these are not ++ # typical AIX shared libraries. ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ else ++ # We preserve .a as extension for shared libraries through AIX4.2 ++ # and later when we are not doing run time linking. ++ library_names_spec='${libname}${release}.a $libname.a' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ fi ++ shlibpath_var=LIBPATH ++ fi ++ ;; ++ ++amigaos*) ++ case $host_cpu in ++ powerpc) ++ # Since July 2007 AmigaOS4 officially supports .so libraries. ++ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ ;; ++ m68k) ++ library_names_spec='$libname.ixlibrary $libname.a' ++ # Create ${libname}_ixlibrary.a entries in /sys/libs. ++ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ++ ;; ++ esac ++ ;; ++ ++beos*) ++ library_names_spec='${libname}${shared_ext}' ++ dynamic_linker="$host_os ld.so" ++ shlibpath_var=LIBRARY_PATH ++ ;; ++ ++bsdi[45]*) ++ version_type=linux ++ need_version=no ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' ++ shlibpath_var=LD_LIBRARY_PATH ++ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" ++ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" ++ # the default ld.so.conf also contains /usr/contrib/lib and ++ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow ++ # libtool to hard-code these into programs ++ ;; ++ ++cygwin* | mingw* | pw32* | cegcc*) ++ version_type=windows ++ shrext_cmds=".dll" ++ need_version=no ++ need_lib_prefix=no ++ ++ case $GCC,$host_os in ++ yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) ++ library_names_spec='$libname.dll.a' ++ # DLL is installed to $(libdir)/../bin by postinstall_cmds ++ postinstall_cmds='base_file=`basename \${file}`~ ++ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ ++ dldir=$destdir/`dirname \$dlpath`~ ++ test -d \$dldir || mkdir -p \$dldir~ ++ $install_prog $dir/$dlname \$dldir/$dlname~ ++ chmod a+x \$dldir/$dlname~ ++ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then ++ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; ++ fi' ++ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ ++ dlpath=$dir/\$dldll~ ++ $RM \$dlpath' ++ shlibpath_overrides_runpath=yes ++ ++ case $host_os in ++ cygwin*) ++ # Cygwin DLLs use 'cyg' prefix rather than 'lib' ++ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ++ ++ ;; ++ mingw* | cegcc*) ++ # MinGW DLLs use traditional 'lib' prefix ++ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ++ ;; ++ pw32*) ++ # pw32 DLLs use 'pw' prefix rather than 'lib' ++ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ++ ;; ++ esac ++ ;; ++ ++ *) ++ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' ++ ;; ++ esac ++ dynamic_linker='Win32 ld.exe' ++ # FIXME: first we should search . and the directory the executable is in ++ shlibpath_var=PATH ++ ;; ++ ++darwin* | rhapsody*) ++ dynamic_linker="$host_os dyld" ++ version_type=darwin ++ need_lib_prefix=no ++ need_version=no ++ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' ++ soname_spec='${libname}${release}${major}$shared_ext' ++ shlibpath_overrides_runpath=yes ++ shlibpath_var=DYLD_LIBRARY_PATH ++ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' ++ ++ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ++ ;; ++ ++dgux*) ++ version_type=linux ++ need_lib_prefix=no ++ need_version=no ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ shlibpath_var=LD_LIBRARY_PATH ++ ;; ++ ++freebsd* | dragonfly*) ++ # DragonFly does not have aout. When/if they implement a new ++ # versioning mechanism, adjust this. ++ if test -x /usr/bin/objformat; then ++ objformat=`/usr/bin/objformat` ++ else ++ case $host_os in ++ freebsd[23].*) objformat=aout ;; ++ *) objformat=elf ;; ++ esac ++ fi ++ version_type=freebsd-$objformat ++ case $version_type in ++ freebsd-elf*) ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' ++ need_version=no ++ need_lib_prefix=no ++ ;; ++ freebsd-*) ++ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' ++ need_version=yes ++ ;; ++ esac ++ shlibpath_var=LD_LIBRARY_PATH ++ case $host_os in ++ freebsd2.*) ++ shlibpath_overrides_runpath=yes ++ ;; ++ freebsd3.[01]* | freebsdelf3.[01]*) ++ shlibpath_overrides_runpath=yes ++ hardcode_into_libs=yes ++ ;; ++ freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ ++ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) ++ shlibpath_overrides_runpath=no ++ hardcode_into_libs=yes ++ ;; ++ *) # from 4.6 on, and DragonFly ++ shlibpath_overrides_runpath=yes ++ hardcode_into_libs=yes ++ ;; ++ esac ++ ;; ++ ++gnu*) ++ version_type=linux ++ need_lib_prefix=no ++ need_version=no ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ shlibpath_var=LD_LIBRARY_PATH ++ hardcode_into_libs=yes ++ ;; ++ ++haiku*) ++ version_type=linux ++ need_lib_prefix=no ++ need_version=no ++ dynamic_linker="$host_os runtime_loader" ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ shlibpath_var=LIBRARY_PATH ++ shlibpath_overrides_runpath=yes ++ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/beos/system/lib' ++ hardcode_into_libs=yes ++ ;; ++ ++hpux9* | hpux10* | hpux11*) ++ # Give a soname corresponding to the major version so that dld.sl refuses to ++ # link against other versions. ++ version_type=sunos ++ need_lib_prefix=no ++ need_version=no ++ case $host_cpu in ++ ia64*) ++ shrext_cmds='.so' ++ hardcode_into_libs=yes ++ dynamic_linker="$host_os dld.so" ++ shlibpath_var=LD_LIBRARY_PATH ++ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ if test "X$HPUX_IA64_MODE" = X32; then ++ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" ++ else ++ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" ++ fi ++ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ++ ;; ++ hppa*64*) ++ shrext_cmds='.sl' ++ hardcode_into_libs=yes ++ dynamic_linker="$host_os dld.sl" ++ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH ++ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" ++ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ++ ;; ++ *) ++ shrext_cmds='.sl' ++ dynamic_linker="$host_os dld.sl" ++ shlibpath_var=SHLIB_PATH ++ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ ;; ++ esac ++ # HP-UX runs *really* slowly unless shared libraries are mode 555, ... ++ postinstall_cmds='chmod 555 $lib' ++ # or fails outright, so override atomically: ++ install_override_mode=555 ++ ;; ++ ++interix[3-9]*) ++ version_type=linux ++ need_lib_prefix=no ++ need_version=no ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' ++ shlibpath_var=LD_LIBRARY_PATH ++ shlibpath_overrides_runpath=no ++ hardcode_into_libs=yes ++ ;; ++ ++irix5* | irix6* | nonstopux*) ++ case $host_os in ++ nonstopux*) version_type=nonstopux ;; ++ *) ++ if test "$lt_cv_prog_gnu_ld" = yes; then ++ version_type=linux ++ else ++ version_type=irix ++ fi ;; ++ esac ++ need_lib_prefix=no ++ need_version=no ++ soname_spec='${libname}${release}${shared_ext}$major' ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' ++ case $host_os in ++ irix5* | nonstopux*) ++ libsuff= shlibsuff= ++ ;; ++ *) ++ case $LD in # libtool.m4 will add one of these switches to LD ++ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") ++ libsuff= shlibsuff= libmagic=32-bit;; ++ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") ++ libsuff=32 shlibsuff=N32 libmagic=N32;; ++ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") ++ libsuff=64 shlibsuff=64 libmagic=64-bit;; ++ *) libsuff= shlibsuff= libmagic=never-match;; ++ esac ++ ;; ++ esac ++ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH ++ shlibpath_overrides_runpath=no ++ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" ++ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" ++ hardcode_into_libs=yes ++ ;; ++ ++# No shared lib support for Linux oldld, aout, or coff. ++linux*oldld* | linux*aout* | linux*coff*) ++ dynamic_linker=no ++ ;; ++ ++# This must be Linux ELF. ++linux* | k*bsd*-gnu | kopensolaris*-gnu) ++ version_type=linux ++ need_lib_prefix=no ++ need_version=no ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' ++ shlibpath_var=LD_LIBRARY_PATH ++ shlibpath_overrides_runpath=no ++ ++ # Some binutils ld are patched to set DT_RUNPATH ++ if ${lt_cv_shlibpath_overrides_runpath+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ lt_cv_shlibpath_overrides_runpath=no ++ save_LDFLAGS=$LDFLAGS ++ save_libdir=$libdir ++ eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ ++ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\"" ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_cxx_try_link "$LINENO"; then : ++ if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : ++ lt_cv_shlibpath_overrides_runpath=yes ++fi ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++ LDFLAGS=$save_LDFLAGS ++ libdir=$save_libdir ++ ++fi ++ ++ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath ++ ++ # This implies no fast_install, which is unacceptable. ++ # Some rework will be needed to allow for fast_install ++ # before this can be enabled. ++ hardcode_into_libs=yes ++ ++ # Append ld.so.conf contents to the search path ++ if test -f /etc/ld.so.conf; then ++ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` ++ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" ++ fi ++ ++ # We used to test for /lib/ld.so.1 and disable shared libraries on ++ # powerpc, because MkLinux only supported shared libraries with the ++ # GNU dynamic linker. Since this was broken with cross compilers, ++ # most powerpc-linux boxes support dynamic linking these days and ++ # people can always --disable-shared, the test was removed, and we ++ # assume the GNU/Linux dynamic linker is in use. ++ dynamic_linker='GNU/Linux ld.so' ++ ;; ++ ++netbsd*) ++ version_type=sunos ++ need_lib_prefix=no ++ need_version=no ++ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' ++ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' ++ dynamic_linker='NetBSD (a.out) ld.so' ++ else ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ dynamic_linker='NetBSD ld.elf_so' ++ fi ++ shlibpath_var=LD_LIBRARY_PATH ++ shlibpath_overrides_runpath=yes ++ hardcode_into_libs=yes ++ ;; ++ ++newsos6) ++ version_type=linux ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ shlibpath_var=LD_LIBRARY_PATH ++ shlibpath_overrides_runpath=yes ++ ;; ++ ++*nto* | *qnx*) ++ version_type=qnx ++ need_lib_prefix=no ++ need_version=no ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ shlibpath_var=LD_LIBRARY_PATH ++ shlibpath_overrides_runpath=no ++ hardcode_into_libs=yes ++ dynamic_linker='ldqnx.so' ++ ;; ++ ++openbsd*) ++ version_type=sunos ++ sys_lib_dlsearch_path_spec="/usr/lib" ++ need_lib_prefix=no ++ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. ++ case $host_os in ++ openbsd3.3 | openbsd3.3.*) need_version=yes ;; ++ *) need_version=no ;; ++ esac ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' ++ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' ++ shlibpath_var=LD_LIBRARY_PATH ++ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then ++ case $host_os in ++ openbsd2.[89] | openbsd2.[89].*) ++ shlibpath_overrides_runpath=no ++ ;; ++ *) ++ shlibpath_overrides_runpath=yes ++ ;; ++ esac ++ else ++ shlibpath_overrides_runpath=yes ++ fi ++ ;; ++ ++os2*) ++ libname_spec='$name' ++ shrext_cmds=".dll" ++ need_lib_prefix=no ++ library_names_spec='$libname${shared_ext} $libname.a' ++ dynamic_linker='OS/2 ld.exe' ++ shlibpath_var=LIBPATH ++ ;; ++ ++osf3* | osf4* | osf5*) ++ version_type=osf ++ need_lib_prefix=no ++ need_version=no ++ soname_spec='${libname}${release}${shared_ext}$major' ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ shlibpath_var=LD_LIBRARY_PATH ++ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" ++ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ++ ;; ++ ++rdos*) ++ dynamic_linker=no ++ ;; ++ ++solaris*) ++ version_type=linux ++ need_lib_prefix=no ++ need_version=no ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ shlibpath_var=LD_LIBRARY_PATH ++ shlibpath_overrides_runpath=yes ++ hardcode_into_libs=yes ++ # ldd complains unless libraries are executable ++ postinstall_cmds='chmod +x $lib' ++ ;; ++ ++sunos4*) ++ version_type=sunos ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' ++ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' ++ shlibpath_var=LD_LIBRARY_PATH ++ shlibpath_overrides_runpath=yes ++ if test "$with_gnu_ld" = yes; then ++ need_lib_prefix=no ++ fi ++ need_version=yes ++ ;; ++ ++sysv4 | sysv4.3*) ++ version_type=linux ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ shlibpath_var=LD_LIBRARY_PATH ++ case $host_vendor in ++ sni) ++ shlibpath_overrides_runpath=no ++ need_lib_prefix=no ++ runpath_var=LD_RUN_PATH ++ ;; ++ siemens) ++ need_lib_prefix=no ++ ;; ++ motorola) ++ need_lib_prefix=no ++ need_version=no ++ shlibpath_overrides_runpath=no ++ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ++ ;; ++ esac ++ ;; ++ ++sysv4*MP*) ++ if test -d /usr/nec ;then ++ version_type=linux ++ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' ++ soname_spec='$libname${shared_ext}.$major' ++ shlibpath_var=LD_LIBRARY_PATH ++ fi ++ ;; ++ ++sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) ++ version_type=freebsd-elf ++ need_lib_prefix=no ++ need_version=no ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ shlibpath_var=LD_LIBRARY_PATH ++ shlibpath_overrides_runpath=yes ++ hardcode_into_libs=yes ++ if test "$with_gnu_ld" = yes; then ++ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' ++ else ++ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' ++ case $host_os in ++ sco3.2v5*) ++ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ++ ;; ++ esac ++ fi ++ sys_lib_dlsearch_path_spec='/usr/lib' ++ ;; ++ ++tpf*) ++ # TPF is a cross-target only. Preferred cross-host = GNU/Linux. ++ version_type=linux ++ need_lib_prefix=no ++ need_version=no ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ shlibpath_var=LD_LIBRARY_PATH ++ shlibpath_overrides_runpath=no ++ hardcode_into_libs=yes ++ ;; ++ ++uts4*) ++ version_type=linux ++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ++ soname_spec='${libname}${release}${shared_ext}$major' ++ shlibpath_var=LD_LIBRARY_PATH ++ ;; ++ ++*) ++ dynamic_linker=no ++ ;; ++esac ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 ++$as_echo "$dynamic_linker" >&6; } ++test "$dynamic_linker" = no && can_build_shared=no ++ ++variables_saved_for_relink="PATH $shlibpath_var $runpath_var" ++if test "$GCC" = yes; then ++ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" ++fi ++ ++if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then ++ sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" ++fi ++if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then ++ sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" ++fi ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 ++$as_echo_n "checking how to hardcode library paths into programs... " >&6; } ++hardcode_action_CXX= ++if test -n "$hardcode_libdir_flag_spec_CXX" || ++ test -n "$runpath_var_CXX" || ++ test "X$hardcode_automatic_CXX" = "Xyes" ; then ++ ++ # We can hardcode non-existent directories. ++ if test "$hardcode_direct_CXX" != no && ++ # If the only mechanism to avoid hardcoding is shlibpath_var, we ++ # have to relink, otherwise we might link with an installed library ++ # when we should be linking with a yet-to-be-installed one ++ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no && ++ test "$hardcode_minus_L_CXX" != no; then ++ # Linking always hardcodes the temporary library directory. ++ hardcode_action_CXX=relink ++ else ++ # We can link without hardcoding, and we can hardcode nonexisting dirs. ++ hardcode_action_CXX=immediate ++ fi ++else ++ # We cannot hardcode anything, or else we can only hardcode existing ++ # directories. ++ hardcode_action_CXX=unsupported ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 ++$as_echo "$hardcode_action_CXX" >&6; } ++ ++if test "$hardcode_action_CXX" = relink || ++ test "$inherit_rpath_CXX" = yes; then ++ # Fast installation is not supported ++ enable_fast_install=no ++elif test "$shlibpath_overrides_runpath" = yes || ++ test "$enable_shared" = no; then ++ # Fast installation is not necessary ++ enable_fast_install=needless ++fi ++ ++ ++ ++ ++ ++ ++ ++ fi # test -n "$compiler" ++ ++ CC=$lt_save_CC ++ LDCXX=$LD ++ LD=$lt_save_LD ++ GCC=$lt_save_GCC ++ with_gnu_ld=$lt_save_with_gnu_ld ++ lt_cv_path_LDCXX=$lt_cv_path_LD ++ lt_cv_path_LD=$lt_save_path_LD ++ lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld ++ lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld ++fi # test "$_lt_caught_CXX_error" != yes ++ ++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_config_commands="$ac_config_commands libtool" ++ ++ ++ ++ ++# Only expand once: ++ ++ ++ ++ ++ ++case $host in ++ *-cygwin* | *-mingw*) ++ # 'host' will be top-level target in the case of a target lib, ++ # we must compare to with_cross_host to decide if this is a native ++ # or cross-compiler and select where to install dlls appropriately. ++ if test -n "$with_cross_host" && ++ test x"$with_cross_host" != x"no"; then ++ lt_host_flags='-no-undefined -bindir "$(toolexeclibdir)"'; ++ else ++ lt_host_flags='-no-undefined -bindir "$(bindir)"'; ++ fi ++ ;; ++ *) ++ lt_host_flags= ++ ;; ++esac ++ ++ ++ ++ ++ac_fn_c_find_intX_t "$LINENO" "64" "ac_cv_c_int64_t" ++case $ac_cv_c_int64_t in #( ++ no|yes) ;; #( ++ *) ++ ++cat >>confdefs.h <<_ACEOF ++#define int64_t $ac_cv_c_int64_t ++_ACEOF ++;; ++esac ++ ++ac_fn_c_find_uintX_t "$LINENO" "64" "ac_cv_c_uint64_t" ++case $ac_cv_c_uint64_t in #( ++ no|yes) ;; #( ++ *) ++ ++$as_echo "#define _UINT64_T 1" >>confdefs.h ++ ++ ++cat >>confdefs.h <<_ACEOF ++#define uint64_t $ac_cv_c_uint64_t ++_ACEOF ++;; ++ esac ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 ++$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } ++if ${ac_cv_header_sys_wait_h+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#include <sys/types.h> ++#include <sys/wait.h> ++#ifndef WEXITSTATUS ++# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) ++#endif ++#ifndef WIFEXITED ++# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) ++#endif ++ ++int ++main () ++{ ++ int s; ++ wait (&s); ++ s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ ac_cv_header_sys_wait_h=yes ++else ++ ac_cv_header_sys_wait_h=no ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 ++$as_echo "$ac_cv_header_sys_wait_h" >&6; } ++if test $ac_cv_header_sys_wait_h = yes; then ++ ++$as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h ++ ++fi ++ ++ac_config_files="$ac_config_files Makefile" ++ ++ac_config_headers="$ac_config_headers config.h" ++ ++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 ++# scripts and configure runs, see configure's option --config-cache. ++# It is not useful on other systems. If it contains results you don't ++# want to keep, you may remove or edit it. ++# ++# config.status only pays attention to the cache file if you give it ++# the --recheck option to rerun configure. ++# ++# `ac_cv_env_foo' variables (set or unset) will be overridden when ++# loading this file, other *unset* `ac_cv_foo' will be assigned the ++# following values. ++ ++_ACEOF ++ ++# The following way of writing the cache mishandles newlines in values, ++# but we know of no workaround that is simple, portable, and efficient. ++# So, we kill variables containing newlines. ++# Ultrix sh set writes to stderr and can't be redirected directly, ++# and sets the high bit in the cache file unless we assign to the vars. ++( ++ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do ++ eval ac_val=\$$ac_var ++ case $ac_val in #( ++ *${as_nl}*) ++ case $ac_var in #( ++ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 ++$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; ++ esac ++ case $ac_var in #( ++ _ | IFS | as_nl) ;; #( ++ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( ++ *) { eval $ac_var=; unset $ac_var;} ;; ++ esac ;; ++ esac ++ done ++ ++ (set) 2>&1 | ++ case $as_nl`(ac_space=' '; set) 2>&1` in #( ++ *${as_nl}ac_space=\ *) ++ # `set' does not quote correctly, so add quotes: double-quote ++ # substitution turns \\\\ into \\, and sed turns \\ into \. ++ sed -n \ ++ "s/'/'\\\\''/g; ++ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ++ ;; #( ++ *) ++ # `set' quotes correctly as required by POSIX, so do not add quotes. ++ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ++ ;; ++ esac | ++ sort ++) | ++ sed ' ++ /^ac_cv_env_/b end ++ t clear ++ :clear ++ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ ++ t end ++ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ ++ :end' >>confcache ++if diff "$cache_file" confcache >/dev/null 2>&1; then :; else ++ if test -w "$cache_file"; then ++ if test "x$cache_file" != "x/dev/null"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 ++$as_echo "$as_me: updating cache $cache_file" >&6;} ++ if test ! -f "$cache_file" || test -h "$cache_file"; then ++ cat confcache >"$cache_file" ++ else ++ case $cache_file in #( ++ */* | ?:*) ++ mv -f confcache "$cache_file"$$ && ++ mv -f "$cache_file"$$ "$cache_file" ;; #( ++ *) ++ mv -f confcache "$cache_file" ;; ++ esac ++ fi ++ fi ++ else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 ++$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} ++ fi ++fi ++rm -f confcache ++ ++test "x$prefix" = xNONE && prefix=$ac_default_prefix ++# Let make expand exec_prefix. ++test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' ++ ++DEFS=-DHAVE_CONFIG_H ++ ++ac_libobjs= ++ac_ltlibobjs= ++U= ++for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue ++ # 1. Remove the extension, and $U if already installed. ++ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ++ ac_i=`$as_echo "$ac_i" | sed "$ac_script"` ++ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR ++ # will be set to the directory where LIBOBJS objects are built. ++ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" ++ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' ++done ++LIBOBJS=$ac_libobjs ++ ++LTLIBOBJS=$ac_ltlibobjs ++ ++ ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 ++$as_echo_n "checking that generated files are newer than configure... " >&6; } ++ if test -n "$am_sleep_pid"; then ++ # Hide warnings about reused PIDs. ++ wait $am_sleep_pid 2>/dev/null ++ fi ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 ++$as_echo "done" >&6; } ++ if test -n "$EXEEXT"; then ++ am__EXEEXT_TRUE= ++ am__EXEEXT_FALSE='#' ++else ++ am__EXEEXT_TRUE='#' ++ am__EXEEXT_FALSE= ++fi ++ ++if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then ++ as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi ++if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then ++ as_fn_error $? "conditional \"AMDEP\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi ++if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then ++ as_fn_error $? "conditional \"am__fastdepCC\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi ++if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then ++ as_fn_error $? "conditional \"am__fastdepCC\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi ++if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then ++ as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi ++ ++: "${CONFIG_STATUS=./config.status}" ++ac_write_fail=0 ++ac_clean_files_save=$ac_clean_files ++ac_clean_files="$ac_clean_files $CONFIG_STATUS" ++{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 ++$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} ++as_write_fail=0 ++cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 ++#! $SHELL ++# Generated by $as_me. ++# Run this file to recreate the current configuration. ++# Compiler output produced by configure, useful for debugging ++# configure, is in config.log if it exists. ++ ++debug=false ++ac_cs_recheck=false ++ac_cs_silent=false ++ ++SHELL=\${CONFIG_SHELL-$SHELL} ++export SHELL ++_ASEOF ++cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ++## -------------------- ## ++## M4sh Initialization. ## ++## -------------------- ## ++ ++# Be more Bourne compatible ++DUALCASE=1; export DUALCASE # for MKS sh ++if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : ++ emulate sh ++ NULLCMD=: ++ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which ++ # is contrary to our usage. Disable this feature. ++ alias -g '${1+"$@"}'='"$@"' ++ setopt NO_GLOB_SUBST ++else ++ case `(set -o) 2>/dev/null` in #( ++ *posix*) : ++ set -o posix ;; #( ++ *) : ++ ;; ++esac ++fi ++ ++ ++as_nl=' ++' ++export as_nl ++# Printing a long string crashes Solaris 7 /usr/bin/printf. ++as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ++as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo ++as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo ++# Prefer a ksh shell builtin over an external printf program on Solaris, ++# but without wasting forks for bash or zsh. ++if test -z "$BASH_VERSION$ZSH_VERSION" \ ++ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then ++ as_echo='print -r --' ++ as_echo_n='print -rn --' ++elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then ++ as_echo='printf %s\n' ++ as_echo_n='printf %s' ++else ++ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then ++ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' ++ as_echo_n='/usr/ucb/echo -n' ++ else ++ as_echo_body='eval expr "X$1" : "X\\(.*\\)"' ++ as_echo_n_body='eval ++ arg=$1; ++ case $arg in #( ++ *"$as_nl"*) ++ expr "X$arg" : "X\\(.*\\)$as_nl"; ++ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; ++ esac; ++ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ++ ' ++ export as_echo_n_body ++ as_echo_n='sh -c $as_echo_n_body as_echo' ++ fi ++ export as_echo_body ++ as_echo='sh -c $as_echo_body as_echo' ++fi ++ ++# The user is always right. ++if test "${PATH_SEPARATOR+set}" != set; then ++ PATH_SEPARATOR=: ++ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { ++ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || ++ PATH_SEPARATOR=';' ++ } ++fi ++ ++ ++# IFS ++# We need space, tab and new line, in precisely that order. Quoting is ++# there to prevent editors from complaining about space-tab. ++# (If _AS_PATH_WALK were called with IFS unset, it would disable word ++# splitting by setting IFS to empty value.) ++IFS=" "" $as_nl" ++ ++# Find who we are. Look in the path if we contain no directory separator. ++as_myself= ++case $0 in #(( ++ *[\\/]* ) as_myself=$0 ;; ++ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR ++for as_dir in $PATH ++do ++ IFS=$as_save_IFS ++ test -z "$as_dir" && as_dir=. ++ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break ++ done ++IFS=$as_save_IFS ++ ++ ;; ++esac ++# We did not find ourselves, most probably we were run as `sh COMMAND' ++# in which case we are not to be found in the path. ++if test "x$as_myself" = x; then ++ as_myself=$0 ++fi ++if test ! -f "$as_myself"; then ++ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 ++ exit 1 ++fi ++ ++# Unset variables that we do not need and which cause bugs (e.g. in ++# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" ++# suppresses any "Segmentation fault" message there. '((' could ++# trigger a bug in pdksh 5.2.14. ++for as_var in BASH_ENV ENV MAIL MAILPATH ++do eval test x\${$as_var+set} = xset \ ++ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : ++done ++PS1='$ ' ++PS2='> ' ++PS4='+ ' ++ ++# NLS nuisances. ++LC_ALL=C ++export LC_ALL ++LANGUAGE=C ++export LANGUAGE ++ ++# CDPATH. ++(unset CDPATH) >/dev/null 2>&1 && unset CDPATH ++ ++ ++# as_fn_error STATUS ERROR [LINENO LOG_FD] ++# ---------------------------------------- ++# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are ++# provided, also output the error to LOG_FD, referencing LINENO. Then exit the ++# script with STATUS, using 1 if that was 0. ++as_fn_error () ++{ ++ as_status=$1; test $as_status -eq 0 && as_status=1 ++ if test "$4"; then ++ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack ++ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 ++ fi ++ $as_echo "$as_me: error: $2" >&2 ++ as_fn_exit $as_status ++} # as_fn_error ++ ++ ++# as_fn_set_status STATUS ++# ----------------------- ++# Set $? to STATUS, without forking. ++as_fn_set_status () ++{ ++ return $1 ++} # as_fn_set_status ++ ++# as_fn_exit STATUS ++# ----------------- ++# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. ++as_fn_exit () ++{ ++ set +e ++ as_fn_set_status $1 ++ exit $1 ++} # as_fn_exit ++ ++# as_fn_unset VAR ++# --------------- ++# Portably unset VAR. ++as_fn_unset () ++{ ++ { eval $1=; unset $1;} ++} ++as_unset=as_fn_unset ++# as_fn_append VAR VALUE ++# ---------------------- ++# Append the text in VALUE to the end of the definition contained in VAR. Take ++# advantage of any shell optimizations that allow amortized linear growth over ++# repeated appends, instead of the typical quadratic growth present in naive ++# implementations. ++if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : ++ eval 'as_fn_append () ++ { ++ eval $1+=\$2 ++ }' ++else ++ as_fn_append () ++ { ++ eval $1=\$$1\$2 ++ } ++fi # as_fn_append ++ ++# as_fn_arith ARG... ++# ------------------ ++# Perform arithmetic evaluation on the ARGs, and store the result in the ++# global $as_val. Take advantage of shells that can avoid forks. The arguments ++# must be portable across $(()) and expr. ++if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : ++ eval 'as_fn_arith () ++ { ++ as_val=$(( $* )) ++ }' ++else ++ as_fn_arith () ++ { ++ as_val=`expr "$@" || test $? -eq 1` ++ } ++fi # as_fn_arith ++ ++ ++if expr a : '\(a\)' >/dev/null 2>&1 && ++ test "X`expr 00001 : '.*\(...\)'`" = X001; then ++ as_expr=expr ++else ++ as_expr=false ++fi ++ ++if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then ++ as_basename=basename ++else ++ as_basename=false ++fi ++ ++if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then ++ as_dirname=dirname ++else ++ as_dirname=false ++fi ++ ++as_me=`$as_basename -- "$0" || ++$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ ++ X"$0" : 'X\(//\)$' \| \ ++ X"$0" : 'X\(/\)' \| . 2>/dev/null || ++$as_echo X/"$0" | ++ sed '/^.*\/\([^/][^/]*\)\/*$/{ ++ s//\1/ ++ q ++ } ++ /^X\/\(\/\/\)$/{ ++ s//\1/ ++ q ++ } ++ /^X\/\(\/\).*/{ ++ s//\1/ ++ q ++ } ++ s/.*/./; q'` ++ ++# Avoid depending upon Character Ranges. ++as_cr_letters='abcdefghijklmnopqrstuvwxyz' ++as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' ++as_cr_Letters=$as_cr_letters$as_cr_LETTERS ++as_cr_digits='0123456789' ++as_cr_alnum=$as_cr_Letters$as_cr_digits ++ ++ECHO_C= ECHO_N= ECHO_T= ++case `echo -n x` in #((((( ++-n*) ++ case `echo 'xy\c'` in ++ *c*) ECHO_T=' ';; # ECHO_T is single tab character. ++ xy) ECHO_C='\c';; ++ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ++ ECHO_T=' ';; ++ esac;; ++*) ++ ECHO_N='-n';; ++esac ++ ++rm -f conf$$ conf$$.exe conf$$.file ++if test -d conf$$.dir; then ++ rm -f conf$$.dir/conf$$.file ++else ++ rm -f conf$$.dir ++ mkdir conf$$.dir 2>/dev/null ++fi ++if (echo >conf$$.file) 2>/dev/null; then ++ if ln -s conf$$.file conf$$ 2>/dev/null; then ++ as_ln_s='ln -s' ++ # ... but there are two gotchas: ++ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. ++ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. ++ # In both cases, we have to default to `cp -pR'. ++ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || ++ as_ln_s='cp -pR' ++ elif ln conf$$.file conf$$ 2>/dev/null; then ++ as_ln_s=ln ++ else ++ as_ln_s='cp -pR' ++ fi ++else ++ as_ln_s='cp -pR' ++fi ++rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file ++rmdir conf$$.dir 2>/dev/null ++ ++ ++# as_fn_mkdir_p ++# ------------- ++# Create "$as_dir" as a directory, including parents if necessary. ++as_fn_mkdir_p () ++{ ++ ++ case $as_dir in #( ++ -*) as_dir=./$as_dir;; ++ esac ++ test -d "$as_dir" || eval $as_mkdir_p || { ++ as_dirs= ++ while :; do ++ case $as_dir in #( ++ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( ++ *) as_qdir=$as_dir;; ++ esac ++ as_dirs="'$as_qdir' $as_dirs" ++ as_dir=`$as_dirname -- "$as_dir" || ++$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ ++ X"$as_dir" : 'X\(//\)[^/]' \| \ ++ X"$as_dir" : 'X\(//\)$' \| \ ++ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || ++$as_echo X"$as_dir" | ++ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\/\)[^/].*/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\/\)$/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\).*/{ ++ s//\1/ ++ q ++ } ++ s/.*/./; q'` ++ test -d "$as_dir" && break ++ done ++ test -z "$as_dirs" || eval "mkdir $as_dirs" ++ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" ++ ++ ++} # as_fn_mkdir_p ++if mkdir -p . 2>/dev/null; then ++ as_mkdir_p='mkdir -p "$as_dir"' ++else ++ test -d ./-p && rmdir ./-p ++ as_mkdir_p=false ++fi ++ ++ ++# as_fn_executable_p FILE ++# ----------------------- ++# Test if FILE is an executable regular file. ++as_fn_executable_p () ++{ ++ test -f "$1" && test -x "$1" ++} # as_fn_executable_p ++as_test_x='test -x' ++as_executable_p=as_fn_executable_p ++ ++# Sed expression to map a string onto a valid CPP name. ++as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" ++ ++# Sed expression to map a string onto a valid variable name. ++as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" ++ ++ ++exec 6>&1 ++## ----------------------------------- ## ++## Main body of $CONFIG_STATUS script. ## ++## ----------------------------------- ## ++_ASEOF ++test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 ++ ++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ++# Save the log message, to keep $0 and so on meaningful, and to ++# report actual input values of CONFIG_FILES etc. instead of their ++# values after options handling. ++ac_log=" ++This file was extended by bolt plugin for ld $as_me 0.1, which was ++generated by GNU Autoconf 2.69. Invocation command line was ++ ++ CONFIG_FILES = $CONFIG_FILES ++ CONFIG_HEADERS = $CONFIG_HEADERS ++ CONFIG_LINKS = $CONFIG_LINKS ++ CONFIG_COMMANDS = $CONFIG_COMMANDS ++ $ $0 $@ ++ ++on `(hostname || uname -n) 2>/dev/null | sed 1q` ++" ++ ++_ACEOF ++ ++case $ac_config_files in *" ++"*) set x $ac_config_files; shift; ac_config_files=$*;; ++esac ++ ++case $ac_config_headers in *" ++"*) set x $ac_config_headers; shift; ac_config_headers=$*;; ++esac ++ ++ ++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ++# Files that config.status was made for. ++config_files="$ac_config_files" ++config_headers="$ac_config_headers" ++config_commands="$ac_config_commands" ++ ++_ACEOF ++ ++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ++ac_cs_usage="\ ++\`$as_me' instantiates files and other configuration actions ++from templates according to the current configuration. Unless the files ++and actions are specified as TAGs, all are instantiated by default. ++ ++Usage: $0 [OPTION]... [TAG]... ++ ++ -h, --help print this help, then exit ++ -V, --version print version number and configuration settings, then exit ++ --config print configuration, then exit ++ -q, --quiet, --silent ++ do not print progress messages ++ -d, --debug don't remove temporary files ++ --recheck update $as_me by reconfiguring in the same conditions ++ --file=FILE[:TEMPLATE] ++ instantiate the configuration file FILE ++ --header=FILE[:TEMPLATE] ++ instantiate the configuration header FILE ++ ++Configuration files: ++$config_files ++ ++Configuration headers: ++$config_headers ++ ++Configuration commands: ++$config_commands ++ ++Report bugs to the package provider." ++ ++_ACEOF ++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ++ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ++ac_cs_version="\\ ++bolt plugin for ld config.status 0.1 ++configured by $0, generated by GNU Autoconf 2.69, ++ with options \\"\$ac_cs_config\\" ++ ++Copyright (C) 2012 Free Software Foundation, Inc. ++This config.status script is free software; the Free Software Foundation ++gives unlimited permission to copy, distribute and modify it." ++ ++ac_pwd='$ac_pwd' ++srcdir='$srcdir' ++INSTALL='$INSTALL' ++MKDIR_P='$MKDIR_P' ++AWK='$AWK' ++test -n "\$AWK" || AWK=awk ++_ACEOF ++ ++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ++# The default lists apply if the user does not specify any file. ++ac_need_defaults=: ++while test $# != 0 ++do ++ case $1 in ++ --*=?*) ++ ac_option=`expr "X$1" : 'X\([^=]*\)='` ++ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ++ ac_shift=: ++ ;; ++ --*=) ++ ac_option=`expr "X$1" : 'X\([^=]*\)='` ++ ac_optarg= ++ ac_shift=: ++ ;; ++ *) ++ ac_option=$1 ++ ac_optarg=$2 ++ ac_shift=shift ++ ;; ++ esac ++ ++ case $ac_option in ++ # Handling of the options. ++ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ++ ac_cs_recheck=: ;; ++ --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) ++ $as_echo "$ac_cs_version"; exit ;; ++ --config | --confi | --conf | --con | --co | --c ) ++ $as_echo "$ac_cs_config"; exit ;; ++ --debug | --debu | --deb | --de | --d | -d ) ++ debug=: ;; ++ --file | --fil | --fi | --f ) ++ $ac_shift ++ case $ac_optarg in ++ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; ++ '') as_fn_error $? "missing file argument" ;; ++ esac ++ as_fn_append CONFIG_FILES " '$ac_optarg'" ++ ac_need_defaults=false;; ++ --header | --heade | --head | --hea ) ++ $ac_shift ++ case $ac_optarg in ++ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; ++ esac ++ as_fn_append CONFIG_HEADERS " '$ac_optarg'" ++ ac_need_defaults=false;; ++ --he | --h) ++ # Conflict between --help and --header ++ as_fn_error $? "ambiguous option: \`$1' ++Try \`$0 --help' for more information.";; ++ --help | --hel | -h ) ++ $as_echo "$ac_cs_usage"; exit ;; ++ -q | -quiet | --quiet | --quie | --qui | --qu | --q \ ++ | -silent | --silent | --silen | --sile | --sil | --si | --s) ++ ac_cs_silent=: ;; ++ ++ # This is an error. ++ -*) as_fn_error $? "unrecognized option: \`$1' ++Try \`$0 --help' for more information." ;; ++ ++ *) as_fn_append ac_config_targets " $1" ++ ac_need_defaults=false ;; ++ ++ esac ++ shift ++done ++ ++ac_configure_extra_args= ++ ++if $ac_cs_silent; then ++ exec 6>/dev/null ++ ac_configure_extra_args="$ac_configure_extra_args --silent" ++fi ++ ++_ACEOF ++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ++if \$ac_cs_recheck; then ++ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion ++ shift ++ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 ++ CONFIG_SHELL='$SHELL' ++ export CONFIG_SHELL ++ exec "\$@" ++fi ++ ++_ACEOF ++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ++exec 5>>config.log ++{ ++ echo ++ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ++## Running $as_me. ## ++_ASBOX ++ $as_echo "$ac_log" ++} >&5 ++ ++_ACEOF ++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ++# ++# INIT-COMMANDS ++# ++AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" ++ ++ ++# The HP-UX ksh and POSIX shell print the target directory to stdout ++# if CDPATH is set. ++(unset CDPATH) >/dev/null 2>&1 && unset CDPATH ++ ++sed_quote_subst='$sed_quote_subst' ++double_quote_subst='$double_quote_subst' ++delay_variable_subst='$delay_variable_subst' ++macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' ++macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' ++enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' ++enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' ++pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' ++enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' ++SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' ++ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' ++host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' ++host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' ++host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' ++build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' ++build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' ++build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' ++SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' ++Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' ++GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' ++EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' ++FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' ++LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' ++NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' ++LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' ++max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' ++ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' ++exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' ++lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' ++lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' ++lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' ++reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' ++reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' ++OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' ++deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' ++file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' ++AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' ++AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' ++STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' ++RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' ++old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' ++old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' ++old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' ++lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' ++CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' ++CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' ++compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' ++GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' ++lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' ++lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' ++lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' ++lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' ++objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' ++MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' ++lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' ++lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' ++lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' ++lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' ++lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' ++need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' ++DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' ++NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' ++LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' ++OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' ++OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' ++libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' ++shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' ++extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' ++archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' ++enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' ++export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' ++whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' ++compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' ++old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' ++old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' ++archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' ++archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' ++module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' ++module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' ++with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' ++allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' ++no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' ++hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' ++hardcode_libdir_flag_spec_ld='`$ECHO "$hardcode_libdir_flag_spec_ld" | $SED "$delay_single_quote_subst"`' ++hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' ++hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' ++hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' ++hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' ++hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' ++hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' ++inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' ++link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' ++fix_srcfile_path='`$ECHO "$fix_srcfile_path" | $SED "$delay_single_quote_subst"`' ++always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' ++export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' ++exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' ++include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' ++prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' ++file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' ++variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' ++need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' ++need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' ++version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' ++runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' ++shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' ++shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' ++libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' ++library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' ++soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' ++install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' ++postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' ++postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' ++finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' ++finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' ++hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' ++sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' ++sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' ++hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' ++enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' ++enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' ++enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' ++old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' ++striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' ++compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`' ++predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`' ++postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`' ++predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`' ++postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`' ++compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`' ++LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`' ++reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`' ++reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`' ++old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' ++compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`' ++GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`' ++lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`' ++lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`' ++lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`' ++lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`' ++lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`' ++archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`' ++enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`' ++export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' ++whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' ++compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`' ++old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`' ++old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`' ++archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' ++archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' ++module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`' ++module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' ++with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`' ++allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' ++no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' ++hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' ++hardcode_libdir_flag_spec_ld_CXX='`$ECHO "$hardcode_libdir_flag_spec_ld_CXX" | $SED "$delay_single_quote_subst"`' ++hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`' ++hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`' ++hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`' ++hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`' ++hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`' ++hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`' ++inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`' ++link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`' ++fix_srcfile_path_CXX='`$ECHO "$fix_srcfile_path_CXX" | $SED "$delay_single_quote_subst"`' ++always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`' ++export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`' ++exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`' ++include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`' ++prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`' ++file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`' ++hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`' ++compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`' ++predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`' ++postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`' ++predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`' ++postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`' ++compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`' ++ ++LTCC='$LTCC' ++LTCFLAGS='$LTCFLAGS' ++compiler='$compiler_DEFAULT' ++ ++# A function that is used when there is no print builtin or printf. ++func_fallback_echo () ++{ ++ eval 'cat <<_LTECHO_EOF ++\$1 ++_LTECHO_EOF' ++} ++ ++# Quote evaled strings. ++for var in SHELL \ ++ECHO \ ++SED \ ++GREP \ ++EGREP \ ++FGREP \ ++LD \ ++NM \ ++LN_S \ ++lt_SP2NL \ ++lt_NL2SP \ ++reload_flag \ ++OBJDUMP \ ++deplibs_check_method \ ++file_magic_cmd \ ++AR \ ++AR_FLAGS \ ++STRIP \ ++RANLIB \ ++CC \ ++CFLAGS \ ++compiler \ ++lt_cv_sys_global_symbol_pipe \ ++lt_cv_sys_global_symbol_to_cdecl \ ++lt_cv_sys_global_symbol_to_c_name_address \ ++lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ ++lt_prog_compiler_no_builtin_flag \ ++lt_prog_compiler_wl \ ++lt_prog_compiler_pic \ ++lt_prog_compiler_static \ ++lt_cv_prog_compiler_c_o \ ++need_locks \ ++DSYMUTIL \ ++NMEDIT \ ++LIPO \ ++OTOOL \ ++OTOOL64 \ ++shrext_cmds \ ++export_dynamic_flag_spec \ ++whole_archive_flag_spec \ ++compiler_needs_object \ ++with_gnu_ld \ ++allow_undefined_flag \ ++no_undefined_flag \ ++hardcode_libdir_flag_spec \ ++hardcode_libdir_flag_spec_ld \ ++hardcode_libdir_separator \ ++fix_srcfile_path \ ++exclude_expsyms \ ++include_expsyms \ ++file_list_spec \ ++variables_saved_for_relink \ ++libname_spec \ ++library_names_spec \ ++soname_spec \ ++install_override_mode \ ++finish_eval \ ++old_striplib \ ++striplib \ ++compiler_lib_search_dirs \ ++predep_objects \ ++postdep_objects \ ++predeps \ ++postdeps \ ++compiler_lib_search_path \ ++LD_CXX \ ++reload_flag_CXX \ ++compiler_CXX \ ++lt_prog_compiler_no_builtin_flag_CXX \ ++lt_prog_compiler_wl_CXX \ ++lt_prog_compiler_pic_CXX \ ++lt_prog_compiler_static_CXX \ ++lt_cv_prog_compiler_c_o_CXX \ ++export_dynamic_flag_spec_CXX \ ++whole_archive_flag_spec_CXX \ ++compiler_needs_object_CXX \ ++with_gnu_ld_CXX \ ++allow_undefined_flag_CXX \ ++no_undefined_flag_CXX \ ++hardcode_libdir_flag_spec_CXX \ ++hardcode_libdir_flag_spec_ld_CXX \ ++hardcode_libdir_separator_CXX \ ++fix_srcfile_path_CXX \ ++exclude_expsyms_CXX \ ++include_expsyms_CXX \ ++file_list_spec_CXX \ ++compiler_lib_search_dirs_CXX \ ++predep_objects_CXX \ ++postdep_objects_CXX \ ++predeps_CXX \ ++postdeps_CXX \ ++compiler_lib_search_path_CXX; do ++ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in ++ *[\\\\\\\`\\"\\\$]*) ++ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ++ ;; ++ *) ++ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ++ ;; ++ esac ++done ++ ++# Double-quote double-evaled strings. ++for var in reload_cmds \ ++old_postinstall_cmds \ ++old_postuninstall_cmds \ ++old_archive_cmds \ ++extract_expsyms_cmds \ ++old_archive_from_new_cmds \ ++old_archive_from_expsyms_cmds \ ++archive_cmds \ ++archive_expsym_cmds \ ++module_cmds \ ++module_expsym_cmds \ ++export_symbols_cmds \ ++prelink_cmds \ ++postinstall_cmds \ ++postuninstall_cmds \ ++finish_cmds \ ++sys_lib_search_path_spec \ ++sys_lib_dlsearch_path_spec \ ++reload_cmds_CXX \ ++old_archive_cmds_CXX \ ++old_archive_from_new_cmds_CXX \ ++old_archive_from_expsyms_cmds_CXX \ ++archive_cmds_CXX \ ++archive_expsym_cmds_CXX \ ++module_cmds_CXX \ ++module_expsym_cmds_CXX \ ++export_symbols_cmds_CXX \ ++prelink_cmds_CXX; do ++ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in ++ *[\\\\\\\`\\"\\\$]*) ++ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ++ ;; ++ *) ++ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ++ ;; ++ esac ++done ++ ++ac_aux_dir='$ac_aux_dir' ++xsi_shell='$xsi_shell' ++lt_shell_append='$lt_shell_append' ++ ++# See if we are running on zsh, and set the options which allow our ++# commands through without removal of \ escapes INIT. ++if test -n "\${ZSH_VERSION+set}" ; then ++ setopt NO_GLOB_SUBST ++fi ++ ++ ++ PACKAGE='$PACKAGE' ++ VERSION='$VERSION' ++ TIMESTAMP='$TIMESTAMP' ++ RM='$RM' ++ ofile='$ofile' ++ ++ ++ ++ ++ ++ ++_ACEOF ++ ++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ++ ++# Handling of arguments. ++for ac_config_target in $ac_config_targets ++do ++ case $ac_config_target in ++ "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; ++ "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; ++ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; ++ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; ++ ++ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; ++ esac ++done ++ ++ ++# If the user did not use the arguments to specify the items to instantiate, ++# then the envvar interface is used. Set only those that are not. ++# We use the long form for the default assignment because of an extremely ++# bizarre bug on SunOS 4.1.3. ++if $ac_need_defaults; then ++ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files ++ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers ++ test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands ++fi ++ ++# Have a temporary directory for convenience. Make it in the build tree ++# simply because there is no reason against having it here, and in addition, ++# creating and moving files from /tmp can sometimes cause problems. ++# Hook for its removal unless debugging. ++# Note that there is a small window in which the directory will not be cleaned: ++# after its creation but before its name has been assigned to `$tmp'. ++$debug || ++{ ++ tmp= ac_tmp= ++ trap 'exit_status=$? ++ : "${ac_tmp:=$tmp}" ++ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ++' 0 ++ trap 'as_fn_exit 1' 1 2 13 15 ++} ++# Create a (secure) tmp directory for tmp files. ++ ++{ ++ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && ++ test -d "$tmp" ++} || ++{ ++ tmp=./conf$$-$RANDOM ++ (umask 077 && mkdir "$tmp") ++} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ++ac_tmp=$tmp ++ ++# Set up the scripts for CONFIG_FILES section. ++# No need to generate them if there are no CONFIG_FILES. ++# This happens for instance with `./config.status config.h'. ++if test -n "$CONFIG_FILES"; then ++ ++ ++ac_cr=`echo X | tr X '\015'` ++# On cygwin, bash can eat \r inside `` if the user requested igncr. ++# But we know of no other shell where ac_cr would be empty at this ++# point, so we can use a bashism as a fallback. ++if test "x$ac_cr" = x; then ++ eval ac_cr=\$\'\\r\' ++fi ++ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` ++if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ++ ac_cs_awk_cr='\\r' ++else ++ ac_cs_awk_cr=$ac_cr ++fi ++ ++echo 'BEGIN {' >"$ac_tmp/subs1.awk" && ++_ACEOF ++ ++ ++{ ++ echo "cat >conf$$subs.awk <<_ACEOF" && ++ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && ++ echo "_ACEOF" ++} >conf$$subs.sh || ++ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ++ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ++ac_delim='%!_!# ' ++for ac_last_try in false false false false false :; do ++ . ./conf$$subs.sh || ++ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ++ ++ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` ++ if test $ac_delim_n = $ac_delim_num; then ++ break ++ elif $ac_last_try; then ++ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ++ else ++ ac_delim="$ac_delim!$ac_delim _$ac_delim!! " ++ fi ++done ++rm -f conf$$subs.sh ++ ++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ++cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && ++_ACEOF ++sed -n ' ++h ++s/^/S["/; s/!.*/"]=/ ++p ++g ++s/^[^!]*!// ++:repl ++t repl ++s/'"$ac_delim"'$// ++t delim ++:nl ++h ++s/\(.\{148\}\)..*/\1/ ++t more1 ++s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ ++p ++n ++b repl ++:more1 ++s/["\\]/\\&/g; s/^/"/; s/$/"\\/ ++p ++g ++s/.\{148\}// ++t nl ++:delim ++h ++s/\(.\{148\}\)..*/\1/ ++t more2 ++s/["\\]/\\&/g; s/^/"/; s/$/"/ ++p ++b ++:more2 ++s/["\\]/\\&/g; s/^/"/; s/$/"\\/ ++p ++g ++s/.\{148\}// ++t delim ++' <conf$$subs.awk | sed ' ++/^[^""]/{ ++ N ++ s/\n// ++} ++' >>$CONFIG_STATUS || ac_write_fail=1 ++rm -f conf$$subs.awk ++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ++_ACAWK ++cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && ++ for (key in S) S_is_set[key] = 1 ++ FS = "" ++ ++} ++{ ++ line = $ 0 ++ nfields = split(line, field, "@") ++ substed = 0 ++ len = length(field[1]) ++ for (i = 2; i < nfields; i++) { ++ key = field[i] ++ keylen = length(key) ++ if (S_is_set[key]) { ++ value = S[key] ++ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) ++ len += length(value) + length(field[++i]) ++ substed = 1 ++ } else ++ len += 1 + keylen ++ } ++ ++ print line ++} ++ ++_ACAWK ++_ACEOF ++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ++if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then ++ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" ++else ++ cat ++fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ ++ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 ++_ACEOF ++ ++# VPATH may cause trouble with some makes, so we remove sole $(srcdir), ++# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and ++# trailing colons and then remove the whole line if VPATH becomes empty ++# (actually we leave an empty line to preserve line numbers). ++if test "x$srcdir" = x.; then ++ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ ++h ++s/// ++s/^/:/ ++s/[ ]*$/:/ ++s/:\$(srcdir):/:/g ++s/:\${srcdir}:/:/g ++s/:@srcdir@:/:/g ++s/^:*// ++s/:*$// ++x ++s/\(=[ ]*\).*/\1/ ++G ++s/\n// ++s/^[^=]*=[ ]*$// ++}' ++fi ++ ++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ++fi # test -n "$CONFIG_FILES" ++ ++# Set up the scripts for CONFIG_HEADERS section. ++# No need to generate them if there are no CONFIG_HEADERS. ++# This happens for instance with `./config.status Makefile'. ++if test -n "$CONFIG_HEADERS"; then ++cat >"$ac_tmp/defines.awk" <<\_ACAWK || ++BEGIN { ++_ACEOF ++ ++# Transform confdefs.h into an awk script `defines.awk', embedded as ++# here-document in config.status, that substitutes the proper values into ++# config.h.in to produce config.h. ++ ++# Create a delimiter string that does not exist in confdefs.h, to ease ++# handling of long lines. ++ac_delim='%!_!# ' ++for ac_last_try in false false :; do ++ ac_tt=`sed -n "/$ac_delim/p" confdefs.h` ++ if test -z "$ac_tt"; then ++ break ++ elif $ac_last_try; then ++ as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 ++ else ++ ac_delim="$ac_delim!$ac_delim _$ac_delim!! " ++ fi ++done ++ ++# For the awk script, D is an array of macro values keyed by name, ++# likewise P contains macro parameters if any. Preserve backslash ++# newline sequences. ++ ++ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* ++sed -n ' ++s/.\{148\}/&'"$ac_delim"'/g ++t rset ++:rset ++s/^[ ]*#[ ]*define[ ][ ]*/ / ++t def ++d ++:def ++s/\\$// ++t bsnl ++s/["\\]/\\&/g ++s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ ++D["\1"]=" \3"/p ++s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p ++d ++:bsnl ++s/["\\]/\\&/g ++s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ ++D["\1"]=" \3\\\\\\n"\\/p ++t cont ++s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p ++t cont ++d ++:cont ++n ++s/.\{148\}/&'"$ac_delim"'/g ++t clear ++:clear ++s/\\$// ++t bsnlc ++s/["\\]/\\&/g; s/^/"/; s/$/"/p ++d ++:bsnlc ++s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p ++b cont ++' <confdefs.h | sed ' ++s/'"$ac_delim"'/"\\\ ++"/g' >>$CONFIG_STATUS || ac_write_fail=1 ++ ++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ++ for (key in D) D_is_set[key] = 1 ++ FS = "" ++} ++/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { ++ line = \$ 0 ++ split(line, arg, " ") ++ if (arg[1] == "#") { ++ defundef = arg[2] ++ mac1 = arg[3] ++ } else { ++ defundef = substr(arg[1], 2) ++ mac1 = arg[2] ++ } ++ split(mac1, mac2, "(") #) ++ macro = mac2[1] ++ prefix = substr(line, 1, index(line, defundef) - 1) ++ if (D_is_set[macro]) { ++ # Preserve the white space surrounding the "#". ++ print prefix "define", macro P[macro] D[macro] ++ next ++ } else { ++ # Replace #undef with comments. This is necessary, for example, ++ # in the case of _POSIX_SOURCE, which is predefined and required ++ # on some systems where configure will not decide to define it. ++ if (defundef == "undef") { ++ print "/*", prefix defundef, macro, "*/" ++ next ++ } ++ } ++} ++{ print } ++_ACAWK ++_ACEOF ++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ++ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 ++fi # test -n "$CONFIG_HEADERS" ++ ++ ++eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" ++shift ++for ac_tag ++do ++ case $ac_tag in ++ :[FHLC]) ac_mode=$ac_tag; continue;; ++ esac ++ case $ac_mode$ac_tag in ++ :[FHL]*:*);; ++ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; ++ :[FH]-) ac_tag=-:-;; ++ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; ++ esac ++ ac_save_IFS=$IFS ++ IFS=: ++ set x $ac_tag ++ IFS=$ac_save_IFS ++ shift ++ ac_file=$1 ++ shift ++ ++ case $ac_mode in ++ :L) ac_source=$1;; ++ :[FH]) ++ ac_file_inputs= ++ for ac_f ++ do ++ case $ac_f in ++ -) ac_f="$ac_tmp/stdin";; ++ *) # Look for the file first in the build tree, then in the source tree ++ # (if the path is not absolute). The absolute path cannot be DOS-style, ++ # because $ac_f cannot contain `:'. ++ test -f "$ac_f" || ++ case $ac_f in ++ [\\/$]*) false;; ++ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; ++ esac || ++ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; ++ esac ++ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac ++ as_fn_append ac_file_inputs " '$ac_f'" ++ done ++ ++ # Let's still pretend it is `configure' which instantiates (i.e., don't ++ # use $as_me), people would be surprised to read: ++ # /* config.h. Generated by config.status. */ ++ configure_input='Generated from '` ++ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' ++ `' by configure.' ++ if test x"$ac_file" != x-; then ++ configure_input="$ac_file. $configure_input" ++ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 ++$as_echo "$as_me: creating $ac_file" >&6;} ++ fi ++ # Neutralize special characters interpreted by sed in replacement strings. ++ case $configure_input in #( ++ *\&* | *\|* | *\\* ) ++ ac_sed_conf_input=`$as_echo "$configure_input" | ++ sed 's/[\\\\&|]/\\\\&/g'`;; #( ++ *) ac_sed_conf_input=$configure_input;; ++ esac ++ ++ case $ac_tag in ++ *:-:* | *:-) cat >"$ac_tmp/stdin" \ ++ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; ++ esac ++ ;; ++ esac ++ ++ ac_dir=`$as_dirname -- "$ac_file" || ++$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ ++ X"$ac_file" : 'X\(//\)[^/]' \| \ ++ X"$ac_file" : 'X\(//\)$' \| \ ++ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || ++$as_echo X"$ac_file" | ++ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\/\)[^/].*/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\/\)$/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\).*/{ ++ s//\1/ ++ q ++ } ++ s/.*/./; q'` ++ as_dir="$ac_dir"; as_fn_mkdir_p ++ ac_builddir=. ++ ++case "$ac_dir" in ++.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; ++*) ++ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` ++ # A ".." for each directory in $ac_dir_suffix. ++ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` ++ case $ac_top_builddir_sub in ++ "") ac_top_builddir_sub=. ac_top_build_prefix= ;; ++ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; ++ esac ;; ++esac ++ac_abs_top_builddir=$ac_pwd ++ac_abs_builddir=$ac_pwd$ac_dir_suffix ++# for backward compatibility: ++ac_top_builddir=$ac_top_build_prefix ++ ++case $srcdir in ++ .) # We are building in place. ++ ac_srcdir=. ++ ac_top_srcdir=$ac_top_builddir_sub ++ ac_abs_top_srcdir=$ac_pwd ;; ++ [\\/]* | ?:[\\/]* ) # Absolute name. ++ ac_srcdir=$srcdir$ac_dir_suffix; ++ ac_top_srcdir=$srcdir ++ ac_abs_top_srcdir=$srcdir ;; ++ *) # Relative name. ++ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ++ ac_top_srcdir=$ac_top_build_prefix$srcdir ++ ac_abs_top_srcdir=$ac_pwd/$srcdir ;; ++esac ++ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix ++ ++ ++ case $ac_mode in ++ :F) ++ # ++ # CONFIG_FILE ++ # ++ ++ case $INSTALL in ++ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; ++ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; ++ esac ++ ac_MKDIR_P=$MKDIR_P ++ case $MKDIR_P in ++ [\\/$]* | ?:[\\/]* ) ;; ++ */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; ++ esac ++_ACEOF ++ ++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ++# If the template does not know about datarootdir, expand it. ++# FIXME: This hack should be removed a few years after 2.60. ++ac_datarootdir_hack=; ac_datarootdir_seen= ++ac_sed_dataroot=' ++/datarootdir/ { ++ p ++ q ++} ++/@datadir@/p ++/@docdir@/p ++/@infodir@/p ++/@localedir@/p ++/@mandir@/p' ++case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in ++*datarootdir*) ac_datarootdir_seen=yes;; ++*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 ++$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} ++_ACEOF ++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ++ ac_datarootdir_hack=' ++ s&@datadir@&$datadir&g ++ s&@docdir@&$docdir&g ++ s&@infodir@&$infodir&g ++ s&@localedir@&$localedir&g ++ s&@mandir@&$mandir&g ++ s&\\\${datarootdir}&$datarootdir&g' ;; ++esac ++_ACEOF ++ ++# Neutralize VPATH when `$srcdir' = `.'. ++# Shell code in configure.ac might set extrasub. ++# FIXME: do we really want to maintain this feature? ++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ++ac_sed_extra="$ac_vpsub ++$extrasub ++_ACEOF ++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ++:t ++/@[a-zA-Z_][a-zA-Z_0-9]*@/!b ++s|@configure_input@|$ac_sed_conf_input|;t t ++s&@top_builddir@&$ac_top_builddir_sub&;t t ++s&@top_build_prefix@&$ac_top_build_prefix&;t t ++s&@srcdir@&$ac_srcdir&;t t ++s&@abs_srcdir@&$ac_abs_srcdir&;t t ++s&@top_srcdir@&$ac_top_srcdir&;t t ++s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t ++s&@builddir@&$ac_builddir&;t t ++s&@abs_builddir@&$ac_abs_builddir&;t t ++s&@abs_top_builddir@&$ac_abs_top_builddir&;t t ++s&@INSTALL@&$ac_INSTALL&;t t ++s&@MKDIR_P@&$ac_MKDIR_P&;t t ++$ac_datarootdir_hack ++" ++eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ ++ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ++ ++test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && ++ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && ++ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ ++ "$ac_tmp/out"`; test -z "$ac_out"; } && ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' ++which seems to be undefined. Please make sure it is defined" >&5 ++$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' ++which seems to be undefined. Please make sure it is defined" >&2;} ++ ++ rm -f "$ac_tmp/stdin" ++ case $ac_file in ++ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; ++ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; ++ esac \ ++ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ++ ;; ++ :H) ++ # ++ # CONFIG_HEADER ++ # ++ if test x"$ac_file" != x-; then ++ { ++ $as_echo "/* $configure_input */" \ ++ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" ++ } >"$ac_tmp/config.h" \ ++ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ++ if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 ++$as_echo "$as_me: $ac_file is unchanged" >&6;} ++ else ++ rm -f "$ac_file" ++ mv "$ac_tmp/config.h" "$ac_file" \ ++ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ++ fi ++ else ++ $as_echo "/* $configure_input */" \ ++ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ ++ || as_fn_error $? "could not create -" "$LINENO" 5 ++ fi ++# Compute "$ac_file"'s index in $config_headers. ++_am_arg="$ac_file" ++_am_stamp_count=1 ++for _am_header in $config_headers :; do ++ case $_am_header in ++ $_am_arg | $_am_arg:* ) ++ break ;; ++ * ) ++ _am_stamp_count=`expr $_am_stamp_count + 1` ;; ++ esac ++done ++echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || ++$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ ++ X"$_am_arg" : 'X\(//\)[^/]' \| \ ++ X"$_am_arg" : 'X\(//\)$' \| \ ++ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || ++$as_echo X"$_am_arg" | ++ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\/\)[^/].*/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\/\)$/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\).*/{ ++ s//\1/ ++ q ++ } ++ s/.*/./; q'`/stamp-h$_am_stamp_count ++ ;; ++ ++ :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 ++$as_echo "$as_me: executing $ac_file commands" >&6;} ++ ;; ++ esac ++ ++ ++ case $ac_file$ac_mode in ++ "depfiles":C) test x"$AMDEP_TRUE" != x"" || { ++ # Older Autoconf quotes --file arguments for eval, but not when files ++ # are listed without --file. Let's play safe and only enable the eval ++ # if we detect the quoting. ++ # TODO: see whether this extra hack can be removed once we start ++ # requiring Autoconf 2.70 or later. ++ case $CONFIG_FILES in #( ++ *\'*) : ++ eval set x "$CONFIG_FILES" ;; #( ++ *) : ++ set x $CONFIG_FILES ;; #( ++ *) : ++ ;; ++esac ++ shift ++ # Used to flag and report bootstrapping failures. ++ am_rc=0 ++ for am_mf ++ do ++ # Strip MF so we end up with the name of the file. ++ am_mf=`$as_echo "$am_mf" | sed -e 's/:.*$//'` ++ # Check whether this is an Automake generated Makefile which includes ++ # dependency-tracking related rules and includes. ++ # Grep'ing the whole file directly is not great: AIX grep has a line ++ # limit of 2048, but all sed's we know have understand at least 4000. ++ sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ ++ || continue ++ am_dirpart=`$as_dirname -- "$am_mf" || ++$as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ ++ X"$am_mf" : 'X\(//\)[^/]' \| \ ++ X"$am_mf" : 'X\(//\)$' \| \ ++ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || ++$as_echo X"$am_mf" | ++ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\/\)[^/].*/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\/\)$/{ ++ s//\1/ ++ q ++ } ++ /^X\(\/\).*/{ ++ s//\1/ ++ q ++ } ++ s/.*/./; q'` ++ am_filepart=`$as_basename -- "$am_mf" || ++$as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ ++ X"$am_mf" : 'X\(//\)$' \| \ ++ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || ++$as_echo X/"$am_mf" | ++ sed '/^.*\/\([^/][^/]*\)\/*$/{ ++ s//\1/ ++ q ++ } ++ /^X\/\(\/\/\)$/{ ++ s//\1/ ++ q ++ } ++ /^X\/\(\/\).*/{ ++ s//\1/ ++ q ++ } ++ s/.*/./; q'` ++ { echo "$as_me:$LINENO: cd "$am_dirpart" \ ++ && sed -e '/# am--include-marker/d' "$am_filepart" \ ++ | $MAKE -f - am--depfiles" >&5 ++ (cd "$am_dirpart" \ ++ && sed -e '/# am--include-marker/d' "$am_filepart" \ ++ | $MAKE -f - am--depfiles) >&5 2>&5 ++ ac_status=$? ++ echo "$as_me:$LINENO: \$? = $ac_status" >&5 ++ (exit $ac_status); } || am_rc=$? ++ done ++ if test $am_rc -ne 0; then ++ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++as_fn_error $? "Something went wrong bootstrapping makefile fragments ++ for automatic dependency tracking. Try re-running configure with the ++ '--disable-dependency-tracking' option to at least be able to build ++ the package (albeit without support for automatic dependency tracking). ++See \`config.log' for more details" "$LINENO" 5; } ++ fi ++ { am_dirpart=; unset am_dirpart;} ++ { am_filepart=; unset am_filepart;} ++ { am_mf=; unset am_mf;} ++ { am_rc=; unset am_rc;} ++ rm -f conftest-deps.mk ++} ++ ;; ++ "libtool":C) ++ ++ # See if we are running on zsh, and set the options which allow our ++ # commands through without removal of \ escapes. ++ if test -n "${ZSH_VERSION+set}" ; then ++ setopt NO_GLOB_SUBST ++ fi ++ ++ cfgfile="${ofile}T" ++ trap "$RM \"$cfgfile\"; exit 1" 1 2 15 ++ $RM "$cfgfile" ++ ++ cat <<_LT_EOF >> "$cfgfile" ++#! $SHELL ++ ++# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. ++# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION ++# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: ++# NOTE: Changes made to this file will be lost: look at ltmain.sh. ++# ++# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, ++# 2006, 2007, 2008, 2009 Free Software Foundation, Inc. ++# Written by Gordon Matzigkeit, 1996 ++# ++# This file is part of GNU Libtool. ++# ++# GNU Libtool is free software; you can redistribute it and/or ++# modify it under the terms of the GNU General Public License as ++# published by the Free Software Foundation; either version 2 of ++# the License, or (at your option) any later version. ++# ++# As a special exception to the GNU General Public License, ++# if you distribute this file as part of a program or library that ++# is built using GNU Libtool, you may include this file under the ++# same distribution terms that you use for the rest of that program. ++# ++# GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy ++# can be downloaded from http://www.gnu.org/licenses/gpl.html, or ++# obtained by writing to the Free Software Foundation, Inc., ++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ ++ ++# The names of the tagged configurations supported by this script. ++available_tags="CXX " ++ ++# ### BEGIN LIBTOOL CONFIG ++ ++# Which release of libtool.m4 was used? ++macro_version=$macro_version ++macro_revision=$macro_revision ++ ++# Whether or not to build shared libraries. ++build_libtool_libs=$enable_shared ++ ++# Whether or not to build static libraries. ++build_old_libs=$enable_static ++ ++# What type of objects to build. ++pic_mode=$pic_mode ++ ++# Whether or not to optimize for fast installation. ++fast_install=$enable_fast_install ++ ++# Shell to use when invoking shell scripts. ++SHELL=$lt_SHELL ++ ++# An echo program that protects backslashes. ++ECHO=$lt_ECHO ++ ++# The host system. ++host_alias=$host_alias ++host=$host ++host_os=$host_os ++ ++# The build system. ++build_alias=$build_alias ++build=$build ++build_os=$build_os ++ ++# A sed program that does not truncate output. ++SED=$lt_SED ++ ++# Sed that helps us avoid accidentally triggering echo(1) options like -n. ++Xsed="\$SED -e 1s/^X//" ++ ++# A grep program that handles long lines. ++GREP=$lt_GREP ++ ++# An ERE matcher. ++EGREP=$lt_EGREP ++ ++# A literal string matcher. ++FGREP=$lt_FGREP ++ ++# A BSD- or MS-compatible name lister. ++NM=$lt_NM ++ ++# Whether we need soft or hard links. ++LN_S=$lt_LN_S ++ ++# What is the maximum length of a command? ++max_cmd_len=$max_cmd_len ++ ++# Object file suffix (normally "o"). ++objext=$ac_objext ++ ++# Executable file suffix (normally ""). ++exeext=$exeext ++ ++# whether the shell understands "unset". ++lt_unset=$lt_unset ++ ++# turn spaces into newlines. ++SP2NL=$lt_lt_SP2NL ++ ++# turn newlines into spaces. ++NL2SP=$lt_lt_NL2SP ++ ++# An object symbol dumper. ++OBJDUMP=$lt_OBJDUMP ++ ++# Method to check whether dependent libraries are shared objects. ++deplibs_check_method=$lt_deplibs_check_method ++ ++# Command to use when deplibs_check_method == "file_magic". ++file_magic_cmd=$lt_file_magic_cmd ++ ++# The archiver. ++AR=$lt_AR ++AR_FLAGS=$lt_AR_FLAGS ++ ++# A symbol stripping program. ++STRIP=$lt_STRIP ++ ++# Commands used to install an old-style archive. ++RANLIB=$lt_RANLIB ++old_postinstall_cmds=$lt_old_postinstall_cmds ++old_postuninstall_cmds=$lt_old_postuninstall_cmds ++ ++# Whether to use a lock for old archive extraction. ++lock_old_archive_extraction=$lock_old_archive_extraction ++ ++# A C compiler. ++LTCC=$lt_CC ++ ++# LTCC compiler flags. ++LTCFLAGS=$lt_CFLAGS ++ ++# Take the output of nm and produce a listing of raw symbols and C names. ++global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe ++ ++# Transform the output of nm in a proper C declaration. ++global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl ++ ++# Transform the output of nm in a C name address pair. ++global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address ++ ++# Transform the output of nm in a C name address pair when lib prefix is needed. ++global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix ++ ++# The name of the directory that contains temporary libtool files. ++objdir=$objdir ++ ++# Used to examine libraries when file_magic_cmd begins with "file". ++MAGIC_CMD=$MAGIC_CMD ++ ++# Must we lock files when doing compilation? ++need_locks=$lt_need_locks ++ ++# Tool to manipulate archived DWARF debug symbol files on Mac OS X. ++DSYMUTIL=$lt_DSYMUTIL ++ ++# Tool to change global to local symbols on Mac OS X. ++NMEDIT=$lt_NMEDIT ++ ++# Tool to manipulate fat objects and archives on Mac OS X. ++LIPO=$lt_LIPO ++ ++# ldd/readelf like tool for Mach-O binaries on Mac OS X. ++OTOOL=$lt_OTOOL ++ ++# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. ++OTOOL64=$lt_OTOOL64 ++ ++# Old archive suffix (normally "a"). ++libext=$libext ++ ++# Shared library suffix (normally ".so"). ++shrext_cmds=$lt_shrext_cmds ++ ++# The commands to extract the exported symbol list from a shared archive. ++extract_expsyms_cmds=$lt_extract_expsyms_cmds ++ ++# Variables whose values should be saved in libtool wrapper scripts and ++# restored at link time. ++variables_saved_for_relink=$lt_variables_saved_for_relink ++ ++# Do we need the "lib" prefix for modules? ++need_lib_prefix=$need_lib_prefix ++ ++# Do we need a version for libraries? ++need_version=$need_version ++ ++# Library versioning type. ++version_type=$version_type ++ ++# Shared library runtime path variable. ++runpath_var=$runpath_var ++ ++# Shared library path variable. ++shlibpath_var=$shlibpath_var ++ ++# Is shlibpath searched before the hard-coded library search path? ++shlibpath_overrides_runpath=$shlibpath_overrides_runpath ++ ++# Format of library name prefix. ++libname_spec=$lt_libname_spec ++ ++# List of archive names. First name is the real one, the rest are links. ++# The last name is the one that the linker finds with -lNAME ++library_names_spec=$lt_library_names_spec ++ ++# The coded name of the library, if different from the real name. ++soname_spec=$lt_soname_spec ++ ++# Permission mode override for installation of shared libraries. ++install_override_mode=$lt_install_override_mode ++ ++# Command to use after installation of a shared archive. ++postinstall_cmds=$lt_postinstall_cmds ++ ++# Command to use after uninstallation of a shared archive. ++postuninstall_cmds=$lt_postuninstall_cmds ++ ++# Commands used to finish a libtool library installation in a directory. ++finish_cmds=$lt_finish_cmds ++ ++# As "finish_cmds", except a single script fragment to be evaled but ++# not shown. ++finish_eval=$lt_finish_eval ++ ++# Whether we should hardcode library paths into libraries. ++hardcode_into_libs=$hardcode_into_libs ++ ++# Compile-time system search path for libraries. ++sys_lib_search_path_spec=$lt_sys_lib_search_path_spec ++ ++# Run-time system search path for libraries. ++sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec ++ ++# Whether dlopen is supported. ++dlopen_support=$enable_dlopen ++ ++# Whether dlopen of programs is supported. ++dlopen_self=$enable_dlopen_self ++ ++# Whether dlopen of statically linked programs is supported. ++dlopen_self_static=$enable_dlopen_self_static ++ ++# Commands to strip libraries. ++old_striplib=$lt_old_striplib ++striplib=$lt_striplib ++ ++ ++# The linker used to build libraries. ++LD=$lt_LD ++ ++# How to create reloadable object files. ++reload_flag=$lt_reload_flag ++reload_cmds=$lt_reload_cmds ++ ++# Commands used to build an old-style archive. ++old_archive_cmds=$lt_old_archive_cmds ++ ++# A language specific compiler. ++CC=$lt_compiler ++ ++# Is the compiler the GNU compiler? ++with_gcc=$GCC ++ ++# Compiler flag to turn off builtin functions. ++no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag ++ ++# How to pass a linker flag through the compiler. ++wl=$lt_lt_prog_compiler_wl ++ ++# Additional compiler flags for building library objects. ++pic_flag=$lt_lt_prog_compiler_pic ++ ++# Compiler flag to prevent dynamic linking. ++link_static_flag=$lt_lt_prog_compiler_static ++ ++# Does compiler simultaneously support -c and -o options? ++compiler_c_o=$lt_lt_cv_prog_compiler_c_o ++ ++# Whether or not to add -lc for building shared libraries. ++build_libtool_need_lc=$archive_cmds_need_lc ++ ++# Whether or not to disallow shared libs when runtime libs are static. ++allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes ++ ++# Compiler flag to allow reflexive dlopens. ++export_dynamic_flag_spec=$lt_export_dynamic_flag_spec ++ ++# Compiler flag to generate shared objects directly from archives. ++whole_archive_flag_spec=$lt_whole_archive_flag_spec ++ ++# Whether the compiler copes with passing no objects directly. ++compiler_needs_object=$lt_compiler_needs_object ++ ++# Create an old-style archive from a shared archive. ++old_archive_from_new_cmds=$lt_old_archive_from_new_cmds ++ ++# Create a temporary old-style archive to link instead of a shared archive. ++old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds ++ ++# Commands used to build a shared archive. ++archive_cmds=$lt_archive_cmds ++archive_expsym_cmds=$lt_archive_expsym_cmds ++ ++# Commands used to build a loadable module if different from building ++# a shared archive. ++module_cmds=$lt_module_cmds ++module_expsym_cmds=$lt_module_expsym_cmds ++ ++# Whether we are building with GNU ld or not. ++with_gnu_ld=$lt_with_gnu_ld ++ ++# Flag that allows shared libraries with undefined symbols to be built. ++allow_undefined_flag=$lt_allow_undefined_flag ++ ++# Flag that enforces no undefined symbols. ++no_undefined_flag=$lt_no_undefined_flag ++ ++# Flag to hardcode \$libdir into a binary during linking. ++# This must work even if \$libdir does not exist ++hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec ++ ++# If ld is used when linking, flag to hardcode \$libdir into a binary ++# during linking. This must work even if \$libdir does not exist. ++hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld ++ ++# Whether we need a single "-rpath" flag with a separated argument. ++hardcode_libdir_separator=$lt_hardcode_libdir_separator ++ ++# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes ++# DIR into the resulting binary. ++hardcode_direct=$hardcode_direct ++ ++# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes ++# DIR into the resulting binary and the resulting library dependency is ++# "absolute",i.e impossible to change by setting \${shlibpath_var} if the ++# library is relocated. ++hardcode_direct_absolute=$hardcode_direct_absolute ++ ++# Set to "yes" if using the -LDIR flag during linking hardcodes DIR ++# into the resulting binary. ++hardcode_minus_L=$hardcode_minus_L ++ ++# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR ++# into the resulting binary. ++hardcode_shlibpath_var=$hardcode_shlibpath_var ++ ++# Set to "yes" if building a shared library automatically hardcodes DIR ++# into the library and all subsequent libraries and executables linked ++# against it. ++hardcode_automatic=$hardcode_automatic ++ ++# Set to yes if linker adds runtime paths of dependent libraries ++# to runtime path list. ++inherit_rpath=$inherit_rpath ++ ++# Whether libtool must link a program against all its dependency libraries. ++link_all_deplibs=$link_all_deplibs ++ ++# Fix the shell variable \$srcfile for the compiler. ++fix_srcfile_path=$lt_fix_srcfile_path ++ ++# Set to "yes" if exported symbols are required. ++always_export_symbols=$always_export_symbols ++ ++# The commands to list exported symbols. ++export_symbols_cmds=$lt_export_symbols_cmds ++ ++# Symbols that should not be listed in the preloaded symbols. ++exclude_expsyms=$lt_exclude_expsyms ++ ++# Symbols that must always be exported. ++include_expsyms=$lt_include_expsyms ++ ++# Commands necessary for linking programs (against libraries) with templates. ++prelink_cmds=$lt_prelink_cmds ++ ++# Specify filename containing input files. ++file_list_spec=$lt_file_list_spec ++ ++# How to hardcode a shared library path into an executable. ++hardcode_action=$hardcode_action ++ ++# The directories searched by this compiler when creating a shared library. ++compiler_lib_search_dirs=$lt_compiler_lib_search_dirs ++ ++# Dependencies to place before and after the objects being linked to ++# create a shared library. ++predep_objects=$lt_predep_objects ++postdep_objects=$lt_postdep_objects ++predeps=$lt_predeps ++postdeps=$lt_postdeps ++ ++# The library search path used internally by the compiler when linking ++# a shared library. ++compiler_lib_search_path=$lt_compiler_lib_search_path ++ ++# ### END LIBTOOL CONFIG ++ ++_LT_EOF ++ ++ case $host_os in ++ aix3*) ++ cat <<\_LT_EOF >> "$cfgfile" ++# AIX sometimes has problems with the GCC collect2 program. For some ++# reason, if we set the COLLECT_NAMES environment variable, the problems ++# vanish in a puff of smoke. ++if test "X${COLLECT_NAMES+set}" != Xset; then ++ COLLECT_NAMES= ++ export COLLECT_NAMES ++fi ++_LT_EOF ++ ;; ++ esac ++ ++ ++ltmain="$ac_aux_dir/ltmain.sh" ++ ++ ++ # We use sed instead of cat because bash on DJGPP gets confused if ++ # if finds mixed CR/LF and LF-only lines. Since sed operates in ++ # text mode, it properly converts lines to CR/LF. This bash problem ++ # is reportedly fixed, but why not run on old versions too? ++ sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ ++ || (rm -f "$cfgfile"; exit 1) ++ ++ case $xsi_shell in ++ yes) ++ cat << \_LT_EOF >> "$cfgfile" ++ ++# func_dirname file append nondir_replacement ++# Compute the dirname of FILE. If nonempty, add APPEND to the result, ++# otherwise set result to NONDIR_REPLACEMENT. ++func_dirname () ++{ ++ case ${1} in ++ */*) func_dirname_result="${1%/*}${2}" ;; ++ * ) func_dirname_result="${3}" ;; ++ esac ++} ++ ++# func_basename file ++func_basename () ++{ ++ func_basename_result="${1##*/}" ++} ++ ++# func_dirname_and_basename file append nondir_replacement ++# perform func_basename and func_dirname in a single function ++# call: ++# dirname: Compute the dirname of FILE. If nonempty, ++# add APPEND to the result, otherwise set result ++# to NONDIR_REPLACEMENT. ++# value returned in "$func_dirname_result" ++# basename: Compute filename of FILE. ++# value retuned in "$func_basename_result" ++# Implementation must be kept synchronized with func_dirname ++# and func_basename. For efficiency, we do not delegate to ++# those functions but instead duplicate the functionality here. ++func_dirname_and_basename () ++{ ++ case ${1} in ++ */*) func_dirname_result="${1%/*}${2}" ;; ++ * ) func_dirname_result="${3}" ;; ++ esac ++ func_basename_result="${1##*/}" ++} ++ ++# func_stripname prefix suffix name ++# strip PREFIX and SUFFIX off of NAME. ++# PREFIX and SUFFIX must not contain globbing or regex special ++# characters, hashes, percent signs, but SUFFIX may contain a leading ++# dot (in which case that matches only a dot). ++func_stripname () ++{ ++ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are ++ # positional parameters, so assign one to ordinary parameter first. ++ func_stripname_result=${3} ++ func_stripname_result=${func_stripname_result#"${1}"} ++ func_stripname_result=${func_stripname_result%"${2}"} ++} ++ ++# func_opt_split ++func_opt_split () ++{ ++ func_opt_split_opt=${1%%=*} ++ func_opt_split_arg=${1#*=} ++} ++ ++# func_lo2o object ++func_lo2o () ++{ ++ case ${1} in ++ *.lo) func_lo2o_result=${1%.lo}.${objext} ;; ++ *) func_lo2o_result=${1} ;; ++ esac ++} ++ ++# func_xform libobj-or-source ++func_xform () ++{ ++ func_xform_result=${1%.*}.lo ++} ++ ++# func_arith arithmetic-term... ++func_arith () ++{ ++ func_arith_result=$(( $* )) ++} ++ ++# func_len string ++# STRING may not start with a hyphen. ++func_len () ++{ ++ func_len_result=${#1} ++} ++ ++_LT_EOF ++ ;; ++ *) # Bourne compatible functions. ++ cat << \_LT_EOF >> "$cfgfile" ++ ++# func_dirname file append nondir_replacement ++# Compute the dirname of FILE. If nonempty, add APPEND to the result, ++# otherwise set result to NONDIR_REPLACEMENT. ++func_dirname () ++{ ++ # Extract subdirectory from the argument. ++ func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` ++ if test "X$func_dirname_result" = "X${1}"; then ++ func_dirname_result="${3}" ++ else ++ func_dirname_result="$func_dirname_result${2}" ++ fi ++} ++ ++# func_basename file ++func_basename () ++{ ++ func_basename_result=`$ECHO "${1}" | $SED "$basename"` ++} ++ ++ ++# func_stripname prefix suffix name ++# strip PREFIX and SUFFIX off of NAME. ++# PREFIX and SUFFIX must not contain globbing or regex special ++# characters, hashes, percent signs, but SUFFIX may contain a leading ++# dot (in which case that matches only a dot). ++# func_strip_suffix prefix name ++func_stripname () ++{ ++ case ${2} in ++ .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; ++ *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; ++ esac ++} ++ ++# sed scripts: ++my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q' ++my_sed_long_arg='1s/^-[^=]*=//' ++ ++# func_opt_split ++func_opt_split () ++{ ++ func_opt_split_opt=`$ECHO "${1}" | $SED "$my_sed_long_opt"` ++ func_opt_split_arg=`$ECHO "${1}" | $SED "$my_sed_long_arg"` ++} ++ ++# func_lo2o object ++func_lo2o () ++{ ++ func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` ++} ++ ++# func_xform libobj-or-source ++func_xform () ++{ ++ func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` ++} ++ ++# func_arith arithmetic-term... ++func_arith () ++{ ++ func_arith_result=`expr "$@"` ++} ++ ++# func_len string ++# STRING may not start with a hyphen. ++func_len () ++{ ++ func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` ++} ++ ++_LT_EOF ++esac ++ ++case $lt_shell_append in ++ yes) ++ cat << \_LT_EOF >> "$cfgfile" ++ ++# func_append var value ++# Append VALUE to the end of shell variable VAR. ++func_append () ++{ ++ eval "$1+=\$2" ++} ++_LT_EOF ++ ;; ++ *) ++ cat << \_LT_EOF >> "$cfgfile" ++ ++# func_append var value ++# Append VALUE to the end of shell variable VAR. ++func_append () ++{ ++ eval "$1=\$$1\$2" ++} ++ ++_LT_EOF ++ ;; ++ esac ++ ++ ++ sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ ++ || (rm -f "$cfgfile"; exit 1) ++ ++ mv -f "$cfgfile" "$ofile" || ++ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") ++ chmod +x "$ofile" ++ ++ ++ cat <<_LT_EOF >> "$ofile" ++ ++# ### BEGIN LIBTOOL TAG CONFIG: CXX ++ ++# The linker used to build libraries. ++LD=$lt_LD_CXX ++ ++# How to create reloadable object files. ++reload_flag=$lt_reload_flag_CXX ++reload_cmds=$lt_reload_cmds_CXX ++ ++# Commands used to build an old-style archive. ++old_archive_cmds=$lt_old_archive_cmds_CXX ++ ++# A language specific compiler. ++CC=$lt_compiler_CXX ++ ++# Is the compiler the GNU compiler? ++with_gcc=$GCC_CXX ++ ++# Compiler flag to turn off builtin functions. ++no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX ++ ++# How to pass a linker flag through the compiler. ++wl=$lt_lt_prog_compiler_wl_CXX ++ ++# Additional compiler flags for building library objects. ++pic_flag=$lt_lt_prog_compiler_pic_CXX ++ ++# Compiler flag to prevent dynamic linking. ++link_static_flag=$lt_lt_prog_compiler_static_CXX ++ ++# Does compiler simultaneously support -c and -o options? ++compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX ++ ++# Whether or not to add -lc for building shared libraries. ++build_libtool_need_lc=$archive_cmds_need_lc_CXX ++ ++# Whether or not to disallow shared libs when runtime libs are static. ++allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX ++ ++# Compiler flag to allow reflexive dlopens. ++export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX ++ ++# Compiler flag to generate shared objects directly from archives. ++whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX ++ ++# Whether the compiler copes with passing no objects directly. ++compiler_needs_object=$lt_compiler_needs_object_CXX ++ ++# Create an old-style archive from a shared archive. ++old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX ++ ++# Create a temporary old-style archive to link instead of a shared archive. ++old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX ++ ++# Commands used to build a shared archive. ++archive_cmds=$lt_archive_cmds_CXX ++archive_expsym_cmds=$lt_archive_expsym_cmds_CXX ++ ++# Commands used to build a loadable module if different from building ++# a shared archive. ++module_cmds=$lt_module_cmds_CXX ++module_expsym_cmds=$lt_module_expsym_cmds_CXX ++ ++# Whether we are building with GNU ld or not. ++with_gnu_ld=$lt_with_gnu_ld_CXX ++ ++# Flag that allows shared libraries with undefined symbols to be built. ++allow_undefined_flag=$lt_allow_undefined_flag_CXX ++ ++# Flag that enforces no undefined symbols. ++no_undefined_flag=$lt_no_undefined_flag_CXX ++ ++# Flag to hardcode \$libdir into a binary during linking. ++# This must work even if \$libdir does not exist ++hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX ++ ++# If ld is used when linking, flag to hardcode \$libdir into a binary ++# during linking. This must work even if \$libdir does not exist. ++hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX ++ ++# Whether we need a single "-rpath" flag with a separated argument. ++hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX ++ ++# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes ++# DIR into the resulting binary. ++hardcode_direct=$hardcode_direct_CXX ++ ++# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes ++# DIR into the resulting binary and the resulting library dependency is ++# "absolute",i.e impossible to change by setting \${shlibpath_var} if the ++# library is relocated. ++hardcode_direct_absolute=$hardcode_direct_absolute_CXX ++ ++# Set to "yes" if using the -LDIR flag during linking hardcodes DIR ++# into the resulting binary. ++hardcode_minus_L=$hardcode_minus_L_CXX ++ ++# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR ++# into the resulting binary. ++hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX ++ ++# Set to "yes" if building a shared library automatically hardcodes DIR ++# into the library and all subsequent libraries and executables linked ++# against it. ++hardcode_automatic=$hardcode_automatic_CXX ++ ++# Set to yes if linker adds runtime paths of dependent libraries ++# to runtime path list. ++inherit_rpath=$inherit_rpath_CXX ++ ++# Whether libtool must link a program against all its dependency libraries. ++link_all_deplibs=$link_all_deplibs_CXX ++ ++# Fix the shell variable \$srcfile for the compiler. ++fix_srcfile_path=$lt_fix_srcfile_path_CXX ++ ++# Set to "yes" if exported symbols are required. ++always_export_symbols=$always_export_symbols_CXX ++ ++# The commands to list exported symbols. ++export_symbols_cmds=$lt_export_symbols_cmds_CXX ++ ++# Symbols that should not be listed in the preloaded symbols. ++exclude_expsyms=$lt_exclude_expsyms_CXX ++ ++# Symbols that must always be exported. ++include_expsyms=$lt_include_expsyms_CXX ++ ++# Commands necessary for linking programs (against libraries) with templates. ++prelink_cmds=$lt_prelink_cmds_CXX ++ ++# Specify filename containing input files. ++file_list_spec=$lt_file_list_spec_CXX ++ ++# How to hardcode a shared library path into an executable. ++hardcode_action=$hardcode_action_CXX ++ ++# The directories searched by this compiler when creating a shared library. ++compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX ++ ++# Dependencies to place before and after the objects being linked to ++# create a shared library. ++predep_objects=$lt_predep_objects_CXX ++postdep_objects=$lt_postdep_objects_CXX ++predeps=$lt_predeps_CXX ++postdeps=$lt_postdeps_CXX ++ ++# The library search path used internally by the compiler when linking ++# a shared library. ++compiler_lib_search_path=$lt_compiler_lib_search_path_CXX ++ ++# ### END LIBTOOL TAG CONFIG: CXX ++_LT_EOF ++ ++ ;; ++ ++ esac ++done # for ac_tag ++ ++ ++as_fn_exit 0 ++_ACEOF ++ac_clean_files=$ac_clean_files_save ++ ++test $ac_write_fail = 0 || ++ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 ++ ++ ++# configure is writing to config.log, and then calls config.status. ++# config.status does its own redirection, appending to config.log. ++# Unfortunately, on DOS this fails, as config.log is still kept open ++# by configure, so config.status won't be able to write to it; its ++# output is simply discarded. So we exec the FD to /dev/null, ++# effectively closing config.log, so it can be properly (re)opened and ++# appended to by config.status. When coming back to configure, we ++# need to make the FD available again. ++if test "$no_create" != yes; then ++ ac_cs_success=: ++ ac_config_status_args= ++ test "$silent" = yes && ++ ac_config_status_args="$ac_config_status_args --quiet" ++ exec 5>/dev/null ++ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false ++ exec 5>>config.log ++ # Use ||, not &&, to avoid exiting from the if with $? = 1, which ++ # would make configure fail if this is the last instruction. ++ $ac_cs_success || as_fn_exit 1 ++fi ++if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 ++$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} ++fi ++ +diff --git a/bolt-plugin/configure.ac b/bolt-plugin/configure.ac +new file mode 100644 +index 000000000..f7d4343e9 +--- /dev/null ++++ b/bolt-plugin/configure.ac +@@ -0,0 +1,59 @@ ++AC_INIT([bolt plugin for ld], 0.1,,[bolt-plugin]) ++AC_CANONICAL_SYSTEM ++GCC_TOPLEV_SUBDIRS ++AM_INIT_AUTOMAKE([foreign no-dist]) ++AM_MAINTAINER_MODE ++AC_ARG_WITH(libiberty, ++ [AS_HELP_STRING([--with-libiberty=PATH], ++ [specify the directory where to find libiberty [../libiberty]])], ++ [], with_libiberty=../libiberty) ++AC_SUBST(with_libiberty) ++AC_USE_SYSTEM_EXTENSIONS ++AC_PROG_CC ++AC_PROG_CXX ++AC_SYS_LARGEFILE ++ACX_PROG_CC_WARNING_OPTS([-Wall], [ac_bolt_plugin_warn_cflags]) ++ ++# Check whether -static-libgcc is supported. ++saved_LDFLAGS="$LDFLAGS" ++LDFLAGS="$LDFLAGS -static-libgcc" ++AC_MSG_CHECKING([for -static-libgcc]) ++AC_LINK_IFELSE([AC_LANG_SOURCE([ ++ int main() {}])], [have_static_libgcc=yes], [have_static_libgcc=no]) ++AC_MSG_RESULT($have_static_libgcc); ++LDFLAGS="$saved_LDFLAGS" ++# Need -Wc to get it through libtool. ++if test "x$have_static_libgcc" = xyes; then ++ ac_bolt_plugin_ldflags="-Wc,-static-libgcc" ++fi ++AC_SUBST(ac_bolt_plugin_ldflags) ++ ++if test x"$host_subdir" = x.; then ++ gcc_build_dir=../gcc ++else ++ gcc_build_dir=../../$host_subdir/gcc ++fi ++AC_SUBST(gcc_build_dir) ++ ++# Used for constructing correct paths for offload compilers. ++accel_dir_suffix= ++real_target_noncanonical=${target_noncanonical} ++if test x"$enable_as_accelerator_for" != x; then ++ accel_dir_suffix=/accel/${target_noncanonical} ++ real_target_noncanonical=${enable_as_accelerator_for} ++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) ++AC_TYPE_INT64_T ++AC_TYPE_UINT64_T ++AC_HEADER_SYS_WAIT ++AC_CONFIG_FILES(Makefile) ++AC_CONFIG_HEADERS(config.h) ++AC_OUTPUT +diff --git a/gcc/common.opt b/gcc/common.opt +index 5eaa667b3..24834cf60 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -2411,6 +2411,22 @@ fauto-bolt= + Common Joined RejectNegative + Specify the feedback data directory required by BOLT-plugin. The default is the current directory. + ++fbolt-use ++Common Report Var(flag_bolt_use) ++Do BOLT optimization after linkage with BOLT profile read from this option. The default is data.fdata. ++ ++fbolt-use= ++Common Joined RejectNegative Var ++Do BOLT optimization after linkage with BOLT profile read from this option. ++ ++fbolt-target= ++Common Joined RejectNegative Var ++Specify the BOLT optimization target binary. ++ ++fbolt-option= ++Common Joined RejectNegative Var ++Specify BOLT optimization options separated by commas. ++ + frerun-cse-after-loop + Common Report Var(flag_rerun_cse_after_loop) Optimization + Add a common subexpression elimination pass after loop optimizations. +diff --git a/gcc/opts.c b/gcc/opts.c +index 0b389ae1d..479d726df 100644 +--- a/gcc/opts.c ++++ b/gcc/opts.c +@@ -1170,6 +1170,10 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, + if (opts->x_flag_auto_bolt && opts->x_flag_lto) + sorry ("%<-fauto-bolt%> is not supported with LTO"); + ++ /* Currently -fbolt-use is not supported for LTO. */ ++ if (opts->x_flag_bolt_use && opts->x_flag_lto) ++ sorry ("-fbolt-use is not supported with LTO"); ++ + /* Control IPA optimizations based on different -flive-patching level. */ + if (opts->x_flag_live_patching) + control_options_for_live_patching (opts, opts_set, +@@ -2938,7 +2942,26 @@ common_handle_option (struct gcc_options *opts, + break; + + case OPT_fauto_bolt_: ++ opts->x_flag_auto_bolt = true; ++ /* FALLTHRU */ + case OPT_fauto_bolt: ++ if (opts->x_flag_bolt_use) ++ error_at (loc, ++ "-fauto-bolt conflicts with -fbolt-use."); ++ break; ++ ++ case OPT_fbolt_use_: ++ case OPT_fbolt_use: ++ if (opts->x_flag_auto_bolt) ++ error_at (loc, ++ "-fauto-bolt conflicts with -fbolt-use."); ++ break; ++ ++ case OPT_fbolt_target_: ++ /* Deferred. */ ++ break; ++ ++ case OPT_fbolt_option_: + /* Deferred. */ + break; + +-- +2.27.0 + diff --git a/0031-AutoBOLT-Enable-BOLT-linker-plugin-on-aarch64-3-3.patch b/0031-AutoBOLT-Enable-BOLT-linker-plugin-on-aarch64-3-3.patch new file mode 100644 index 0000000..d276591 --- /dev/null +++ b/0031-AutoBOLT-Enable-BOLT-linker-plugin-on-aarch64-3-3.patch @@ -0,0 +1,1945 @@ +From dd17ea263e762209dada859c12d13ed9fb468459 Mon Sep 17 00:00:00 2001 +From: liyancheng <412998149@qq.com> +Date: Mon, 14 Feb 2022 15:32:25 +0800 +Subject: [PATCH 31/32] [AutoBOLT] Enable BOLT linker plugin on aarch64 3/3 + +Enable the BOLT linker plugin on aarch64 when configured +with --enable-bolt. +--- + Makefile.def | 10 + + Makefile.in | 1292 ++++++++++++++++++++++++++++++++++++++++++++++ + configure | 27 +- + configure.ac | 22 +- + gcc/config.host | 7 +- + gcc/config.in | 7 + + gcc/configure | 10 +- + gcc/configure.ac | 4 + + gcc/gcc.c | 22 + + 9 files changed, 1396 insertions(+), 5 deletions(-) + mode change 100644 => 100755 configure + mode change 100644 => 100755 gcc/configure + +diff --git a/Makefile.def b/Makefile.def +index 36fd26b03..5dda3c228 100644 +--- a/Makefile.def ++++ b/Makefile.def +@@ -129,6 +129,9 @@ host_modules= { module= gnattools; }; + host_modules= { module= lto-plugin; bootstrap=true; + extra_configure_flags='--enable-shared @extra_linker_plugin_flags@ @extra_linker_plugin_configure_flags@'; + extra_make_flags='@extra_linker_plugin_flags@'; }; ++host_modules= { module= bolt-plugin; bootstrap=true; ++ extra_configure_flags='--enable-shared @extra_linker_plugin_flags@ @extra_linker_plugin_configure_flags@'; ++ extra_make_flags='@extra_linker_plugin_flags@'; }; + host_modules= { module= libcc1; extra_configure_flags=--enable-shared; }; + host_modules= { module= gotools; }; + host_modules= { module= libctf; no_install=true; no_check=true; +@@ -327,6 +330,7 @@ dependencies = { module=configure-gcc; on=all-mpfr; }; + dependencies = { module=configure-gcc; on=all-mpc; }; + dependencies = { module=configure-gcc; on=all-isl; }; + dependencies = { module=configure-gcc; on=all-lto-plugin; }; ++dependencies = { module=configure-gcc; on=all-bolt-plugin; }; + dependencies = { module=configure-gcc; on=all-binutils; }; + dependencies = { module=configure-gcc; on=all-gas; }; + dependencies = { module=configure-gcc; on=all-ld; }; +@@ -351,6 +355,7 @@ dependencies = { module=all-gcc; on=all-libdecnumber; hard=true; }; + dependencies = { module=all-gcc; on=all-libiberty; }; + dependencies = { module=all-gcc; on=all-fixincludes; }; + dependencies = { module=all-gcc; on=all-lto-plugin; }; ++dependencies = { module=all-gcc; on=all-bolt-plugin; }; + dependencies = { module=all-gcc; on=all-libiconv; }; + dependencies = { module=info-gcc; on=all-build-libiberty; }; + dependencies = { module=dvi-gcc; on=all-build-libiberty; }; +@@ -358,8 +363,10 @@ dependencies = { module=pdf-gcc; on=all-build-libiberty; }; + dependencies = { module=html-gcc; on=all-build-libiberty; }; + dependencies = { module=install-gcc ; on=install-fixincludes; }; + dependencies = { module=install-gcc ; on=install-lto-plugin; }; ++dependencies = { module=install-gcc ; on=install-bolt-plugin; }; + dependencies = { module=install-strip-gcc ; on=install-strip-fixincludes; }; + dependencies = { module=install-strip-gcc ; on=install-strip-lto-plugin; }; ++dependencies = { module=install-strip-gcc ; on=install-strip-bolt-plugin; }; + + dependencies = { module=configure-libcpp; on=configure-libiberty; hard=true; }; + dependencies = { module=configure-libcpp; on=configure-intl; }; +@@ -378,6 +385,9 @@ dependencies = { module=all-gnattools; on=all-target-libstdc++-v3; }; + dependencies = { module=all-lto-plugin; on=all-libiberty; }; + dependencies = { module=all-lto-plugin; on=all-libiberty-linker-plugin; }; + ++dependencies = { module=all-bolt-plugin; on=all-libiberty; }; ++dependencies = { module=all-bolt-plugin; on=all-libiberty-linker-plugin; }; ++ + dependencies = { module=configure-libcc1; on=configure-gcc; }; + dependencies = { module=all-libcc1; on=all-gcc; }; + +diff --git a/Makefile.in b/Makefile.in +index 36e369df6..cfdca3d18 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -1039,6 +1039,7 @@ configure-host: \ + maybe-configure-utils \ + maybe-configure-gnattools \ + maybe-configure-lto-plugin \ ++ maybe-configure-bolt-plugin \ + maybe-configure-libcc1 \ + maybe-configure-gotools \ + maybe-configure-libctf +@@ -1197,6 +1198,9 @@ all-host: maybe-all-gnattools + @if lto-plugin-no-bootstrap + all-host: maybe-all-lto-plugin + @endif lto-plugin-no-bootstrap ++@if bolt-plugin-no-bootstrap ++all-host: maybe-all-bolt-plugin ++@endif bolt-plugin-no-bootstrap + all-host: maybe-all-libcc1 + all-host: maybe-all-gotools + @if libctf-no-bootstrap +@@ -1303,6 +1307,7 @@ info-host: maybe-info-libtermcap + info-host: maybe-info-utils + info-host: maybe-info-gnattools + info-host: maybe-info-lto-plugin ++info-host: maybe-info-bolt-plugin + info-host: maybe-info-libcc1 + info-host: maybe-info-gotools + info-host: maybe-info-libctf +@@ -1392,6 +1397,7 @@ dvi-host: maybe-dvi-libtermcap + dvi-host: maybe-dvi-utils + dvi-host: maybe-dvi-gnattools + dvi-host: maybe-dvi-lto-plugin ++dvi-host: maybe-dvi-bolt-plugin + dvi-host: maybe-dvi-libcc1 + dvi-host: maybe-dvi-gotools + dvi-host: maybe-dvi-libctf +@@ -1481,6 +1487,7 @@ pdf-host: maybe-pdf-libtermcap + pdf-host: maybe-pdf-utils + pdf-host: maybe-pdf-gnattools + pdf-host: maybe-pdf-lto-plugin ++pdf-host: maybe-pdf-bolt-plugin + pdf-host: maybe-pdf-libcc1 + pdf-host: maybe-pdf-gotools + pdf-host: maybe-pdf-libctf +@@ -1570,6 +1577,7 @@ html-host: maybe-html-libtermcap + html-host: maybe-html-utils + html-host: maybe-html-gnattools + html-host: maybe-html-lto-plugin ++html-host: maybe-html-bolt-plugin + html-host: maybe-html-libcc1 + html-host: maybe-html-gotools + html-host: maybe-html-libctf +@@ -1659,6 +1667,7 @@ TAGS-host: maybe-TAGS-libtermcap + TAGS-host: maybe-TAGS-utils + TAGS-host: maybe-TAGS-gnattools + TAGS-host: maybe-TAGS-lto-plugin ++TAGS-host: maybe-TAGS-bolt-plugin + TAGS-host: maybe-TAGS-libcc1 + TAGS-host: maybe-TAGS-gotools + TAGS-host: maybe-TAGS-libctf +@@ -1748,6 +1757,7 @@ install-info-host: maybe-install-info-libtermcap + install-info-host: maybe-install-info-utils + install-info-host: maybe-install-info-gnattools + install-info-host: maybe-install-info-lto-plugin ++install-info-host: maybe-install-info-bolt-plugin + install-info-host: maybe-install-info-libcc1 + install-info-host: maybe-install-info-gotools + install-info-host: maybe-install-info-libctf +@@ -1837,6 +1847,7 @@ install-pdf-host: maybe-install-pdf-libtermcap + install-pdf-host: maybe-install-pdf-utils + install-pdf-host: maybe-install-pdf-gnattools + install-pdf-host: maybe-install-pdf-lto-plugin ++install-pdf-host: maybe-install-pdf-bolt-plugin + install-pdf-host: maybe-install-pdf-libcc1 + install-pdf-host: maybe-install-pdf-gotools + install-pdf-host: maybe-install-pdf-libctf +@@ -1926,6 +1937,7 @@ install-html-host: maybe-install-html-libtermcap + install-html-host: maybe-install-html-utils + install-html-host: maybe-install-html-gnattools + install-html-host: maybe-install-html-lto-plugin ++install-html-host: maybe-install-html-bolt-plugin + install-html-host: maybe-install-html-libcc1 + install-html-host: maybe-install-html-gotools + install-html-host: maybe-install-html-libctf +@@ -2015,6 +2027,7 @@ installcheck-host: maybe-installcheck-libtermcap + installcheck-host: maybe-installcheck-utils + installcheck-host: maybe-installcheck-gnattools + installcheck-host: maybe-installcheck-lto-plugin ++installcheck-host: maybe-installcheck-bolt-plugin + installcheck-host: maybe-installcheck-libcc1 + installcheck-host: maybe-installcheck-gotools + installcheck-host: maybe-installcheck-libctf +@@ -2104,6 +2117,7 @@ mostlyclean-host: maybe-mostlyclean-libtermcap + mostlyclean-host: maybe-mostlyclean-utils + mostlyclean-host: maybe-mostlyclean-gnattools + mostlyclean-host: maybe-mostlyclean-lto-plugin ++mostlyclean-host: maybe-mostlyclean-bolt-plugin + mostlyclean-host: maybe-mostlyclean-libcc1 + mostlyclean-host: maybe-mostlyclean-gotools + mostlyclean-host: maybe-mostlyclean-libctf +@@ -2193,6 +2207,7 @@ clean-host: maybe-clean-libtermcap + clean-host: maybe-clean-utils + clean-host: maybe-clean-gnattools + clean-host: maybe-clean-lto-plugin ++clean-host: maybe-clean-bolt-plugin + clean-host: maybe-clean-libcc1 + clean-host: maybe-clean-gotools + clean-host: maybe-clean-libctf +@@ -2282,6 +2297,7 @@ distclean-host: maybe-distclean-libtermcap + distclean-host: maybe-distclean-utils + distclean-host: maybe-distclean-gnattools + distclean-host: maybe-distclean-lto-plugin ++distclean-host: maybe-distclean-bolt-plugin + distclean-host: maybe-distclean-libcc1 + distclean-host: maybe-distclean-gotools + distclean-host: maybe-distclean-libctf +@@ -2371,6 +2387,7 @@ maintainer-clean-host: maybe-maintainer-clean-libtermcap + maintainer-clean-host: maybe-maintainer-clean-utils + maintainer-clean-host: maybe-maintainer-clean-gnattools + maintainer-clean-host: maybe-maintainer-clean-lto-plugin ++maintainer-clean-host: maybe-maintainer-clean-bolt-plugin + maintainer-clean-host: maybe-maintainer-clean-libcc1 + maintainer-clean-host: maybe-maintainer-clean-gotools + maintainer-clean-host: maybe-maintainer-clean-libctf +@@ -2516,6 +2533,7 @@ check-host: \ + maybe-check-utils \ + maybe-check-gnattools \ + maybe-check-lto-plugin \ ++ maybe-check-bolt-plugin \ + maybe-check-libcc1 \ + maybe-check-gotools \ + maybe-check-libctf +@@ -2652,6 +2670,7 @@ install-host-nogcc: \ + maybe-install-utils \ + maybe-install-gnattools \ + maybe-install-lto-plugin \ ++ maybe-install-bolt-plugin \ + maybe-install-libcc1 \ + maybe-install-gotools \ + maybe-install-libctf +@@ -2705,6 +2724,7 @@ install-host: \ + maybe-install-utils \ + maybe-install-gnattools \ + maybe-install-lto-plugin \ ++ maybe-install-bolt-plugin \ + maybe-install-libcc1 \ + maybe-install-gotools \ + maybe-install-libctf +@@ -2814,6 +2834,7 @@ install-strip-host: \ + maybe-install-strip-utils \ + maybe-install-strip-gnattools \ + maybe-install-strip-lto-plugin \ ++ maybe-install-strip-bolt-plugin \ + maybe-install-strip-libcc1 \ + maybe-install-strip-gotools \ + maybe-install-strip-libctf +@@ -38628,6 +38649,1129 @@ maintainer-clean-lto-plugin: + + + ++.PHONY: configure-bolt-plugin maybe-configure-bolt-plugin ++maybe-configure-bolt-plugin: ++@if gcc-bootstrap ++configure-bolt-plugin: stage_current ++@endif gcc-bootstrap ++@if bolt-plugin ++maybe-configure-bolt-plugin: configure-bolt-plugin ++configure-bolt-plugin: ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ test ! -f $(HOST_SUBDIR)/bolt-plugin/Makefile || exit 0; \ ++ $(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/bolt-plugin; \ ++ $(HOST_EXPORTS) \ ++ echo Configuring in $(HOST_SUBDIR)/bolt-plugin; \ ++ cd "$(HOST_SUBDIR)/bolt-plugin" || exit 1; \ ++ case $(srcdir) in \ ++ /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ ++ *) topdir=`echo $(HOST_SUBDIR)/bolt-plugin/ | \ ++ sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ ++ esac; \ ++ module_srcdir=bolt-plugin; \ ++ $(SHELL) \ ++ $$s/$$module_srcdir/configure \ ++ --srcdir=$${topdir}/$$module_srcdir \ ++ $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ ++ --target=${target_alias} --enable-shared @extra_linker_plugin_flags@ @extra_linker_plugin_configure_flags@ \ ++ || exit 1 ++@endif bolt-plugin ++ ++ ++ ++.PHONY: configure-stage1-bolt-plugin maybe-configure-stage1-bolt-plugin ++maybe-configure-stage1-bolt-plugin: ++@if bolt-plugin-bootstrap ++maybe-configure-stage1-bolt-plugin: configure-stage1-bolt-plugin ++configure-stage1-bolt-plugin: ++ @[ $(current_stage) = stage1 ] || $(MAKE) stage1-start ++ @$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/bolt-plugin ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ TFLAGS="$(STAGE1_TFLAGS)"; \ ++ test ! -f $(HOST_SUBDIR)/bolt-plugin/Makefile || exit 0; \ ++ $(HOST_EXPORTS) \ ++ CFLAGS="$(STAGE1_CFLAGS)"; export CFLAGS; \ ++ CXXFLAGS="$(STAGE1_CXXFLAGS)"; export CXXFLAGS; \ ++ LIBCFLAGS="$(LIBCFLAGS)"; export LIBCFLAGS; \ ++ echo Configuring stage 1 in $(HOST_SUBDIR)/bolt-plugin; \ ++ $(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/bolt-plugin; \ ++ cd $(HOST_SUBDIR)/bolt-plugin || exit 1; \ ++ case $(srcdir) in \ ++ /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ ++ *) topdir=`echo $(HOST_SUBDIR)/bolt-plugin/ | \ ++ sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ ++ esac; \ ++ module_srcdir=bolt-plugin; \ ++ $(SHELL) $$s/$$module_srcdir/configure \ ++ --srcdir=$${topdir}/$$module_srcdir \ ++ $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ ++ --target=${target_alias} \ ++ \ ++ $(STAGE1_CONFIGURE_FLAGS) \ ++ --enable-shared @extra_linker_plugin_flags@ @extra_linker_plugin_configure_flags@ ++@endif bolt-plugin-bootstrap ++ ++.PHONY: configure-stage2-bolt-plugin maybe-configure-stage2-bolt-plugin ++maybe-configure-stage2-bolt-plugin: ++@if bolt-plugin-bootstrap ++maybe-configure-stage2-bolt-plugin: configure-stage2-bolt-plugin ++configure-stage2-bolt-plugin: ++ @[ $(current_stage) = stage2 ] || $(MAKE) stage2-start ++ @$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/bolt-plugin ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ TFLAGS="$(STAGE2_TFLAGS)"; \ ++ test ! -f $(HOST_SUBDIR)/bolt-plugin/Makefile || exit 0; \ ++ $(HOST_EXPORTS) \ ++ $(POSTSTAGE1_HOST_EXPORTS) \ ++ CFLAGS="$(STAGE2_CFLAGS)"; export CFLAGS; \ ++ CXXFLAGS="$(STAGE2_CXXFLAGS)"; export CXXFLAGS; \ ++ LIBCFLAGS="$(STAGE2_CFLAGS)"; export LIBCFLAGS; \ ++ echo Configuring stage 2 in $(HOST_SUBDIR)/bolt-plugin; \ ++ $(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/bolt-plugin; \ ++ cd $(HOST_SUBDIR)/bolt-plugin || exit 1; \ ++ case $(srcdir) in \ ++ /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ ++ *) topdir=`echo $(HOST_SUBDIR)/bolt-plugin/ | \ ++ sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ ++ esac; \ ++ module_srcdir=bolt-plugin; \ ++ $(SHELL) $$s/$$module_srcdir/configure \ ++ --srcdir=$${topdir}/$$module_srcdir \ ++ $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ ++ --target=${target_alias} \ ++ --with-build-libsubdir=$(HOST_SUBDIR) \ ++ $(STAGE2_CONFIGURE_FLAGS) \ ++ --enable-shared @extra_linker_plugin_flags@ @extra_linker_plugin_configure_flags@ ++@endif bolt-plugin-bootstrap ++ ++.PHONY: configure-stage3-bolt-plugin maybe-configure-stage3-bolt-plugin ++maybe-configure-stage3-bolt-plugin: ++@if bolt-plugin-bootstrap ++maybe-configure-stage3-bolt-plugin: configure-stage3-bolt-plugin ++configure-stage3-bolt-plugin: ++ @[ $(current_stage) = stage3 ] || $(MAKE) stage3-start ++ @$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/bolt-plugin ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ TFLAGS="$(STAGE3_TFLAGS)"; \ ++ test ! -f $(HOST_SUBDIR)/bolt-plugin/Makefile || exit 0; \ ++ $(HOST_EXPORTS) \ ++ $(POSTSTAGE1_HOST_EXPORTS) \ ++ CFLAGS="$(STAGE3_CFLAGS)"; export CFLAGS; \ ++ CXXFLAGS="$(STAGE3_CXXFLAGS)"; export CXXFLAGS; \ ++ LIBCFLAGS="$(STAGE3_CFLAGS)"; export LIBCFLAGS; \ ++ echo Configuring stage 3 in $(HOST_SUBDIR)/bolt-plugin; \ ++ $(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/bolt-plugin; \ ++ cd $(HOST_SUBDIR)/bolt-plugin || exit 1; \ ++ case $(srcdir) in \ ++ /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ ++ *) topdir=`echo $(HOST_SUBDIR)/bolt-plugin/ | \ ++ sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ ++ esac; \ ++ module_srcdir=bolt-plugin; \ ++ $(SHELL) $$s/$$module_srcdir/configure \ ++ --srcdir=$${topdir}/$$module_srcdir \ ++ $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ ++ --target=${target_alias} \ ++ --with-build-libsubdir=$(HOST_SUBDIR) \ ++ $(STAGE3_CONFIGURE_FLAGS) \ ++ --enable-shared @extra_linker_plugin_flags@ @extra_linker_plugin_configure_flags@ ++@endif bolt-plugin-bootstrap ++ ++.PHONY: configure-stage4-bolt-plugin maybe-configure-stage4-bolt-plugin ++maybe-configure-stage4-bolt-plugin: ++@if bolt-plugin-bootstrap ++maybe-configure-stage4-bolt-plugin: configure-stage4-bolt-plugin ++configure-stage4-bolt-plugin: ++ @[ $(current_stage) = stage4 ] || $(MAKE) stage4-start ++ @$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/bolt-plugin ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ TFLAGS="$(STAGE4_TFLAGS)"; \ ++ test ! -f $(HOST_SUBDIR)/bolt-plugin/Makefile || exit 0; \ ++ $(HOST_EXPORTS) \ ++ $(POSTSTAGE1_HOST_EXPORTS) \ ++ CFLAGS="$(STAGE4_CFLAGS)"; export CFLAGS; \ ++ CXXFLAGS="$(STAGE4_CXXFLAGS)"; export CXXFLAGS; \ ++ LIBCFLAGS="$(STAGE4_CFLAGS)"; export LIBCFLAGS; \ ++ echo Configuring stage 4 in $(HOST_SUBDIR)/bolt-plugin; \ ++ $(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/bolt-plugin; \ ++ cd $(HOST_SUBDIR)/bolt-plugin || exit 1; \ ++ case $(srcdir) in \ ++ /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ ++ *) topdir=`echo $(HOST_SUBDIR)/bolt-plugin/ | \ ++ sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ ++ esac; \ ++ module_srcdir=bolt-plugin; \ ++ $(SHELL) $$s/$$module_srcdir/configure \ ++ --srcdir=$${topdir}/$$module_srcdir \ ++ $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ ++ --target=${target_alias} \ ++ --with-build-libsubdir=$(HOST_SUBDIR) \ ++ $(STAGE4_CONFIGURE_FLAGS) \ ++ --enable-shared @extra_linker_plugin_flags@ @extra_linker_plugin_configure_flags@ ++@endif bolt-plugin-bootstrap ++ ++.PHONY: configure-stageprofile-bolt-plugin maybe-configure-stageprofile-bolt-plugin ++maybe-configure-stageprofile-bolt-plugin: ++@if bolt-plugin-bootstrap ++maybe-configure-stageprofile-bolt-plugin: configure-stageprofile-bolt-plugin ++configure-stageprofile-bolt-plugin: ++ @[ $(current_stage) = stageprofile ] || $(MAKE) stageprofile-start ++ @$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/bolt-plugin ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ TFLAGS="$(STAGEprofile_TFLAGS)"; \ ++ test ! -f $(HOST_SUBDIR)/bolt-plugin/Makefile || exit 0; \ ++ $(HOST_EXPORTS) \ ++ $(POSTSTAGE1_HOST_EXPORTS) \ ++ CFLAGS="$(STAGEprofile_CFLAGS)"; export CFLAGS; \ ++ CXXFLAGS="$(STAGEprofile_CXXFLAGS)"; export CXXFLAGS; \ ++ LIBCFLAGS="$(STAGEprofile_CFLAGS)"; export LIBCFLAGS; \ ++ echo Configuring stage profile in $(HOST_SUBDIR)/bolt-plugin; \ ++ $(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/bolt-plugin; \ ++ cd $(HOST_SUBDIR)/bolt-plugin || exit 1; \ ++ case $(srcdir) in \ ++ /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ ++ *) topdir=`echo $(HOST_SUBDIR)/bolt-plugin/ | \ ++ sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ ++ esac; \ ++ module_srcdir=bolt-plugin; \ ++ $(SHELL) $$s/$$module_srcdir/configure \ ++ --srcdir=$${topdir}/$$module_srcdir \ ++ $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ ++ --target=${target_alias} \ ++ --with-build-libsubdir=$(HOST_SUBDIR) \ ++ $(STAGEprofile_CONFIGURE_FLAGS) \ ++ --enable-shared @extra_linker_plugin_flags@ @extra_linker_plugin_configure_flags@ ++@endif bolt-plugin-bootstrap ++ ++.PHONY: configure-stagetrain-bolt-plugin maybe-configure-stagetrain-bolt-plugin ++maybe-configure-stagetrain-bolt-plugin: ++@if bolt-plugin-bootstrap ++maybe-configure-stagetrain-bolt-plugin: configure-stagetrain-bolt-plugin ++configure-stagetrain-bolt-plugin: ++ @[ $(current_stage) = stagetrain ] || $(MAKE) stagetrain-start ++ @$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/bolt-plugin ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ TFLAGS="$(STAGEtrain_TFLAGS)"; \ ++ test ! -f $(HOST_SUBDIR)/bolt-plugin/Makefile || exit 0; \ ++ $(HOST_EXPORTS) \ ++ $(POSTSTAGE1_HOST_EXPORTS) \ ++ CFLAGS="$(STAGEtrain_CFLAGS)"; export CFLAGS; \ ++ CXXFLAGS="$(STAGEtrain_CXXFLAGS)"; export CXXFLAGS; \ ++ LIBCFLAGS="$(STAGEtrain_CFLAGS)"; export LIBCFLAGS; \ ++ echo Configuring stage train in $(HOST_SUBDIR)/bolt-plugin; \ ++ $(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/bolt-plugin; \ ++ cd $(HOST_SUBDIR)/bolt-plugin || exit 1; \ ++ case $(srcdir) in \ ++ /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ ++ *) topdir=`echo $(HOST_SUBDIR)/bolt-plugin/ | \ ++ sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ ++ esac; \ ++ module_srcdir=bolt-plugin; \ ++ $(SHELL) $$s/$$module_srcdir/configure \ ++ --srcdir=$${topdir}/$$module_srcdir \ ++ $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ ++ --target=${target_alias} \ ++ --with-build-libsubdir=$(HOST_SUBDIR) \ ++ $(STAGEtrain_CONFIGURE_FLAGS) \ ++ --enable-shared @extra_linker_plugin_flags@ @extra_linker_plugin_configure_flags@ ++@endif bolt-plugin-bootstrap ++ ++.PHONY: configure-stagefeedback-bolt-plugin maybe-configure-stagefeedback-bolt-plugin ++maybe-configure-stagefeedback-bolt-plugin: ++@if bolt-plugin-bootstrap ++maybe-configure-stagefeedback-bolt-plugin: configure-stagefeedback-bolt-plugin ++configure-stagefeedback-bolt-plugin: ++ @[ $(current_stage) = stagefeedback ] || $(MAKE) stagefeedback-start ++ @$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/bolt-plugin ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ TFLAGS="$(STAGEfeedback_TFLAGS)"; \ ++ test ! -f $(HOST_SUBDIR)/bolt-plugin/Makefile || exit 0; \ ++ $(HOST_EXPORTS) \ ++ $(POSTSTAGE1_HOST_EXPORTS) \ ++ CFLAGS="$(STAGEfeedback_CFLAGS)"; export CFLAGS; \ ++ CXXFLAGS="$(STAGEfeedback_CXXFLAGS)"; export CXXFLAGS; \ ++ LIBCFLAGS="$(STAGEfeedback_CFLAGS)"; export LIBCFLAGS; \ ++ echo Configuring stage feedback in $(HOST_SUBDIR)/bolt-plugin; \ ++ $(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/bolt-plugin; \ ++ cd $(HOST_SUBDIR)/bolt-plugin || exit 1; \ ++ case $(srcdir) in \ ++ /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ ++ *) topdir=`echo $(HOST_SUBDIR)/bolt-plugin/ | \ ++ sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ ++ esac; \ ++ module_srcdir=bolt-plugin; \ ++ $(SHELL) $$s/$$module_srcdir/configure \ ++ --srcdir=$${topdir}/$$module_srcdir \ ++ $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ ++ --target=${target_alias} \ ++ --with-build-libsubdir=$(HOST_SUBDIR) \ ++ $(STAGEfeedback_CONFIGURE_FLAGS) \ ++ --enable-shared @extra_linker_plugin_flags@ @extra_linker_plugin_configure_flags@ ++@endif bolt-plugin-bootstrap ++ ++.PHONY: configure-stageautoprofile-bolt-plugin maybe-configure-stageautoprofile-bolt-plugin ++maybe-configure-stageautoprofile-bolt-plugin: ++@if bolt-plugin-bootstrap ++maybe-configure-stageautoprofile-bolt-plugin: configure-stageautoprofile-bolt-plugin ++configure-stageautoprofile-bolt-plugin: ++ @[ $(current_stage) = stageautoprofile ] || $(MAKE) stageautoprofile-start ++ @$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/bolt-plugin ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ TFLAGS="$(STAGEautoprofile_TFLAGS)"; \ ++ test ! -f $(HOST_SUBDIR)/bolt-plugin/Makefile || exit 0; \ ++ $(HOST_EXPORTS) \ ++ $(POSTSTAGE1_HOST_EXPORTS) \ ++ CFLAGS="$(STAGEautoprofile_CFLAGS)"; export CFLAGS; \ ++ CXXFLAGS="$(STAGEautoprofile_CXXFLAGS)"; export CXXFLAGS; \ ++ LIBCFLAGS="$(STAGEautoprofile_CFLAGS)"; export LIBCFLAGS; \ ++ echo Configuring stage autoprofile in $(HOST_SUBDIR)/bolt-plugin; \ ++ $(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/bolt-plugin; \ ++ cd $(HOST_SUBDIR)/bolt-plugin || exit 1; \ ++ case $(srcdir) in \ ++ /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ ++ *) topdir=`echo $(HOST_SUBDIR)/bolt-plugin/ | \ ++ sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ ++ esac; \ ++ module_srcdir=bolt-plugin; \ ++ $(SHELL) $$s/$$module_srcdir/configure \ ++ --srcdir=$${topdir}/$$module_srcdir \ ++ $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ ++ --target=${target_alias} \ ++ --with-build-libsubdir=$(HOST_SUBDIR) \ ++ $(STAGEautoprofile_CONFIGURE_FLAGS) \ ++ --enable-shared @extra_linker_plugin_flags@ @extra_linker_plugin_configure_flags@ ++@endif bolt-plugin-bootstrap ++ ++.PHONY: configure-stageautofeedback-bolt-plugin maybe-configure-stageautofeedback-bolt-plugin ++maybe-configure-stageautofeedback-bolt-plugin: ++@if bolt-plugin-bootstrap ++maybe-configure-stageautofeedback-bolt-plugin: configure-stageautofeedback-bolt-plugin ++configure-stageautofeedback-bolt-plugin: ++ @[ $(current_stage) = stageautofeedback ] || $(MAKE) stageautofeedback-start ++ @$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/bolt-plugin ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ TFLAGS="$(STAGEautofeedback_TFLAGS)"; \ ++ test ! -f $(HOST_SUBDIR)/bolt-plugin/Makefile || exit 0; \ ++ $(HOST_EXPORTS) \ ++ $(POSTSTAGE1_HOST_EXPORTS) \ ++ CFLAGS="$(STAGEautofeedback_CFLAGS)"; export CFLAGS; \ ++ CXXFLAGS="$(STAGEautofeedback_CXXFLAGS)"; export CXXFLAGS; \ ++ LIBCFLAGS="$(STAGEautofeedback_CFLAGS)"; export LIBCFLAGS; \ ++ echo Configuring stage autofeedback in $(HOST_SUBDIR)/bolt-plugin; \ ++ $(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/bolt-plugin; \ ++ cd $(HOST_SUBDIR)/bolt-plugin || exit 1; \ ++ case $(srcdir) in \ ++ /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ ++ *) topdir=`echo $(HOST_SUBDIR)/bolt-plugin/ | \ ++ sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ ++ esac; \ ++ module_srcdir=bolt-plugin; \ ++ $(SHELL) $$s/$$module_srcdir/configure \ ++ --srcdir=$${topdir}/$$module_srcdir \ ++ $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ ++ --target=${target_alias} \ ++ --with-build-libsubdir=$(HOST_SUBDIR) \ ++ $(STAGEautofeedback_CONFIGURE_FLAGS) \ ++ --enable-shared @extra_linker_plugin_flags@ @extra_linker_plugin_configure_flags@ ++@endif bolt-plugin-bootstrap ++ ++ ++ ++ ++ ++.PHONY: all-bolt-plugin maybe-all-bolt-plugin ++maybe-all-bolt-plugin: ++@if gcc-bootstrap ++all-bolt-plugin: stage_current ++@endif gcc-bootstrap ++@if bolt-plugin ++TARGET-bolt-plugin=all ++maybe-all-bolt-plugin: all-bolt-plugin ++all-bolt-plugin: configure-bolt-plugin ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ $(HOST_EXPORTS) \ ++ (cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) $(EXTRA_HOST_FLAGS) $(STAGE1_FLAGS_TO_PASS) @extra_linker_plugin_flags@ \ ++ $(TARGET-bolt-plugin)) ++@endif bolt-plugin ++ ++ ++ ++.PHONY: all-stage1-bolt-plugin maybe-all-stage1-bolt-plugin ++.PHONY: clean-stage1-bolt-plugin maybe-clean-stage1-bolt-plugin ++maybe-all-stage1-bolt-plugin: ++maybe-clean-stage1-bolt-plugin: ++@if bolt-plugin-bootstrap ++maybe-all-stage1-bolt-plugin: all-stage1-bolt-plugin ++all-stage1: all-stage1-bolt-plugin ++TARGET-stage1-bolt-plugin = $(TARGET-bolt-plugin) ++all-stage1-bolt-plugin: configure-stage1-bolt-plugin ++ @[ $(current_stage) = stage1 ] || $(MAKE) stage1-start ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ TFLAGS="$(STAGE1_TFLAGS)"; \ ++ $(HOST_EXPORTS) \ ++ cd $(HOST_SUBDIR)/bolt-plugin && \ ++ \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) \ ++ CFLAGS="$(STAGE1_CFLAGS)" \ ++ GENERATOR_CFLAGS="$(STAGE1_GENERATOR_CFLAGS)" \ ++ CXXFLAGS="$(STAGE1_CXXFLAGS)" \ ++ LIBCFLAGS="$(LIBCFLAGS)" \ ++ CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ ++ CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ ++ LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ ++ $(EXTRA_HOST_FLAGS) \ ++ $(STAGE1_FLAGS_TO_PASS) @extra_linker_plugin_flags@ \ ++ TFLAGS="$(STAGE1_TFLAGS)" \ ++ $(TARGET-stage1-bolt-plugin) ++ ++maybe-clean-stage1-bolt-plugin: clean-stage1-bolt-plugin ++clean-stage1: clean-stage1-bolt-plugin ++clean-stage1-bolt-plugin: ++ @if [ $(current_stage) = stage1 ]; then \ ++ [ -f $(HOST_SUBDIR)/bolt-plugin/Makefile ] || exit 0; \ ++ else \ ++ [ -f $(HOST_SUBDIR)/stage1-bolt-plugin/Makefile ] || exit 0; \ ++ $(MAKE) stage1-start; \ ++ fi; \ ++ cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(EXTRA_HOST_FLAGS) \ ++ $(STAGE1_FLAGS_TO_PASS) @extra_linker_plugin_flags@ clean ++@endif bolt-plugin-bootstrap ++ ++ ++.PHONY: all-stage2-bolt-plugin maybe-all-stage2-bolt-plugin ++.PHONY: clean-stage2-bolt-plugin maybe-clean-stage2-bolt-plugin ++maybe-all-stage2-bolt-plugin: ++maybe-clean-stage2-bolt-plugin: ++@if bolt-plugin-bootstrap ++maybe-all-stage2-bolt-plugin: all-stage2-bolt-plugin ++all-stage2: all-stage2-bolt-plugin ++TARGET-stage2-bolt-plugin = $(TARGET-bolt-plugin) ++all-stage2-bolt-plugin: configure-stage2-bolt-plugin ++ @[ $(current_stage) = stage2 ] || $(MAKE) stage2-start ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ TFLAGS="$(STAGE2_TFLAGS)"; \ ++ $(HOST_EXPORTS) \ ++ $(POSTSTAGE1_HOST_EXPORTS) \ ++ cd $(HOST_SUBDIR)/bolt-plugin && \ ++ \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) \ ++ CFLAGS="$(STAGE2_CFLAGS)" \ ++ GENERATOR_CFLAGS="$(STAGE2_GENERATOR_CFLAGS)" \ ++ CXXFLAGS="$(STAGE2_CXXFLAGS)" \ ++ LIBCFLAGS="$(STAGE2_CFLAGS)" \ ++ CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ ++ CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ ++ LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ ++ $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS) @extra_linker_plugin_flags@ \ ++ TFLAGS="$(STAGE2_TFLAGS)" \ ++ $(TARGET-stage2-bolt-plugin) ++ ++maybe-clean-stage2-bolt-plugin: clean-stage2-bolt-plugin ++clean-stage2: clean-stage2-bolt-plugin ++clean-stage2-bolt-plugin: ++ @if [ $(current_stage) = stage2 ]; then \ ++ [ -f $(HOST_SUBDIR)/bolt-plugin/Makefile ] || exit 0; \ ++ else \ ++ [ -f $(HOST_SUBDIR)/stage2-bolt-plugin/Makefile ] || exit 0; \ ++ $(MAKE) stage2-start; \ ++ fi; \ ++ cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS) @extra_linker_plugin_flags@ clean ++@endif bolt-plugin-bootstrap ++ ++ ++.PHONY: all-stage3-bolt-plugin maybe-all-stage3-bolt-plugin ++.PHONY: clean-stage3-bolt-plugin maybe-clean-stage3-bolt-plugin ++maybe-all-stage3-bolt-plugin: ++maybe-clean-stage3-bolt-plugin: ++@if bolt-plugin-bootstrap ++maybe-all-stage3-bolt-plugin: all-stage3-bolt-plugin ++all-stage3: all-stage3-bolt-plugin ++TARGET-stage3-bolt-plugin = $(TARGET-bolt-plugin) ++all-stage3-bolt-plugin: configure-stage3-bolt-plugin ++ @[ $(current_stage) = stage3 ] || $(MAKE) stage3-start ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ TFLAGS="$(STAGE3_TFLAGS)"; \ ++ $(HOST_EXPORTS) \ ++ $(POSTSTAGE1_HOST_EXPORTS) \ ++ cd $(HOST_SUBDIR)/bolt-plugin && \ ++ \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) \ ++ CFLAGS="$(STAGE3_CFLAGS)" \ ++ GENERATOR_CFLAGS="$(STAGE3_GENERATOR_CFLAGS)" \ ++ CXXFLAGS="$(STAGE3_CXXFLAGS)" \ ++ LIBCFLAGS="$(STAGE3_CFLAGS)" \ ++ CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ ++ CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ ++ LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ ++ $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS) @extra_linker_plugin_flags@ \ ++ TFLAGS="$(STAGE3_TFLAGS)" \ ++ $(TARGET-stage3-bolt-plugin) ++ ++maybe-clean-stage3-bolt-plugin: clean-stage3-bolt-plugin ++clean-stage3: clean-stage3-bolt-plugin ++clean-stage3-bolt-plugin: ++ @if [ $(current_stage) = stage3 ]; then \ ++ [ -f $(HOST_SUBDIR)/bolt-plugin/Makefile ] || exit 0; \ ++ else \ ++ [ -f $(HOST_SUBDIR)/stage3-bolt-plugin/Makefile ] || exit 0; \ ++ $(MAKE) stage3-start; \ ++ fi; \ ++ cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS) @extra_linker_plugin_flags@ clean ++@endif bolt-plugin-bootstrap ++ ++ ++.PHONY: all-stage4-bolt-plugin maybe-all-stage4-bolt-plugin ++.PHONY: clean-stage4-bolt-plugin maybe-clean-stage4-bolt-plugin ++maybe-all-stage4-bolt-plugin: ++maybe-clean-stage4-bolt-plugin: ++@if bolt-plugin-bootstrap ++maybe-all-stage4-bolt-plugin: all-stage4-bolt-plugin ++all-stage4: all-stage4-bolt-plugin ++TARGET-stage4-bolt-plugin = $(TARGET-bolt-plugin) ++all-stage4-bolt-plugin: configure-stage4-bolt-plugin ++ @[ $(current_stage) = stage4 ] || $(MAKE) stage4-start ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ TFLAGS="$(STAGE4_TFLAGS)"; \ ++ $(HOST_EXPORTS) \ ++ $(POSTSTAGE1_HOST_EXPORTS) \ ++ cd $(HOST_SUBDIR)/bolt-plugin && \ ++ \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) \ ++ CFLAGS="$(STAGE4_CFLAGS)" \ ++ GENERATOR_CFLAGS="$(STAGE4_GENERATOR_CFLAGS)" \ ++ CXXFLAGS="$(STAGE4_CXXFLAGS)" \ ++ LIBCFLAGS="$(STAGE4_CFLAGS)" \ ++ CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ ++ CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ ++ LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ ++ $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS) @extra_linker_plugin_flags@ \ ++ TFLAGS="$(STAGE4_TFLAGS)" \ ++ $(TARGET-stage4-bolt-plugin) ++ ++maybe-clean-stage4-bolt-plugin: clean-stage4-bolt-plugin ++clean-stage4: clean-stage4-bolt-plugin ++clean-stage4-bolt-plugin: ++ @if [ $(current_stage) = stage4 ]; then \ ++ [ -f $(HOST_SUBDIR)/bolt-plugin/Makefile ] || exit 0; \ ++ else \ ++ [ -f $(HOST_SUBDIR)/stage4-bolt-plugin/Makefile ] || exit 0; \ ++ $(MAKE) stage4-start; \ ++ fi; \ ++ cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS) @extra_linker_plugin_flags@ clean ++@endif bolt-plugin-bootstrap ++ ++ ++.PHONY: all-stageprofile-bolt-plugin maybe-all-stageprofile-bolt-plugin ++.PHONY: clean-stageprofile-bolt-plugin maybe-clean-stageprofile-bolt-plugin ++maybe-all-stageprofile-bolt-plugin: ++maybe-clean-stageprofile-bolt-plugin: ++@if bolt-plugin-bootstrap ++maybe-all-stageprofile-bolt-plugin: all-stageprofile-bolt-plugin ++all-stageprofile: all-stageprofile-bolt-plugin ++TARGET-stageprofile-bolt-plugin = $(TARGET-bolt-plugin) ++all-stageprofile-bolt-plugin: configure-stageprofile-bolt-plugin ++ @[ $(current_stage) = stageprofile ] || $(MAKE) stageprofile-start ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ TFLAGS="$(STAGEprofile_TFLAGS)"; \ ++ $(HOST_EXPORTS) \ ++ $(POSTSTAGE1_HOST_EXPORTS) \ ++ cd $(HOST_SUBDIR)/bolt-plugin && \ ++ \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) \ ++ CFLAGS="$(STAGEprofile_CFLAGS)" \ ++ GENERATOR_CFLAGS="$(STAGEprofile_GENERATOR_CFLAGS)" \ ++ CXXFLAGS="$(STAGEprofile_CXXFLAGS)" \ ++ LIBCFLAGS="$(STAGEprofile_CFLAGS)" \ ++ CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ ++ CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ ++ LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ ++ $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS) @extra_linker_plugin_flags@ \ ++ TFLAGS="$(STAGEprofile_TFLAGS)" \ ++ $(TARGET-stageprofile-bolt-plugin) ++ ++maybe-clean-stageprofile-bolt-plugin: clean-stageprofile-bolt-plugin ++clean-stageprofile: clean-stageprofile-bolt-plugin ++clean-stageprofile-bolt-plugin: ++ @if [ $(current_stage) = stageprofile ]; then \ ++ [ -f $(HOST_SUBDIR)/bolt-plugin/Makefile ] || exit 0; \ ++ else \ ++ [ -f $(HOST_SUBDIR)/stageprofile-bolt-plugin/Makefile ] || exit 0; \ ++ $(MAKE) stageprofile-start; \ ++ fi; \ ++ cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS) @extra_linker_plugin_flags@ clean ++@endif bolt-plugin-bootstrap ++ ++ ++.PHONY: all-stagetrain-bolt-plugin maybe-all-stagetrain-bolt-plugin ++.PHONY: clean-stagetrain-bolt-plugin maybe-clean-stagetrain-bolt-plugin ++maybe-all-stagetrain-bolt-plugin: ++maybe-clean-stagetrain-bolt-plugin: ++@if bolt-plugin-bootstrap ++maybe-all-stagetrain-bolt-plugin: all-stagetrain-bolt-plugin ++all-stagetrain: all-stagetrain-bolt-plugin ++TARGET-stagetrain-bolt-plugin = $(TARGET-bolt-plugin) ++all-stagetrain-bolt-plugin: configure-stagetrain-bolt-plugin ++ @[ $(current_stage) = stagetrain ] || $(MAKE) stagetrain-start ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ TFLAGS="$(STAGEtrain_TFLAGS)"; \ ++ $(HOST_EXPORTS) \ ++ $(POSTSTAGE1_HOST_EXPORTS) \ ++ cd $(HOST_SUBDIR)/bolt-plugin && \ ++ \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) \ ++ CFLAGS="$(STAGEtrain_CFLAGS)" \ ++ GENERATOR_CFLAGS="$(STAGEtrain_GENERATOR_CFLAGS)" \ ++ CXXFLAGS="$(STAGEtrain_CXXFLAGS)" \ ++ LIBCFLAGS="$(STAGEtrain_CFLAGS)" \ ++ CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ ++ CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ ++ LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ ++ $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS) @extra_linker_plugin_flags@ \ ++ TFLAGS="$(STAGEtrain_TFLAGS)" \ ++ $(TARGET-stagetrain-bolt-plugin) ++ ++maybe-clean-stagetrain-bolt-plugin: clean-stagetrain-bolt-plugin ++clean-stagetrain: clean-stagetrain-bolt-plugin ++clean-stagetrain-bolt-plugin: ++ @if [ $(current_stage) = stagetrain ]; then \ ++ [ -f $(HOST_SUBDIR)/bolt-plugin/Makefile ] || exit 0; \ ++ else \ ++ [ -f $(HOST_SUBDIR)/stagetrain-bolt-plugin/Makefile ] || exit 0; \ ++ $(MAKE) stagetrain-start; \ ++ fi; \ ++ cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS) @extra_linker_plugin_flags@ clean ++@endif bolt-plugin-bootstrap ++ ++ ++.PHONY: all-stagefeedback-bolt-plugin maybe-all-stagefeedback-bolt-plugin ++.PHONY: clean-stagefeedback-bolt-plugin maybe-clean-stagefeedback-bolt-plugin ++maybe-all-stagefeedback-bolt-plugin: ++maybe-clean-stagefeedback-bolt-plugin: ++@if bolt-plugin-bootstrap ++maybe-all-stagefeedback-bolt-plugin: all-stagefeedback-bolt-plugin ++all-stagefeedback: all-stagefeedback-bolt-plugin ++TARGET-stagefeedback-bolt-plugin = $(TARGET-bolt-plugin) ++all-stagefeedback-bolt-plugin: configure-stagefeedback-bolt-plugin ++ @[ $(current_stage) = stagefeedback ] || $(MAKE) stagefeedback-start ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ TFLAGS="$(STAGEfeedback_TFLAGS)"; \ ++ $(HOST_EXPORTS) \ ++ $(POSTSTAGE1_HOST_EXPORTS) \ ++ cd $(HOST_SUBDIR)/bolt-plugin && \ ++ \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) \ ++ CFLAGS="$(STAGEfeedback_CFLAGS)" \ ++ GENERATOR_CFLAGS="$(STAGEfeedback_GENERATOR_CFLAGS)" \ ++ CXXFLAGS="$(STAGEfeedback_CXXFLAGS)" \ ++ LIBCFLAGS="$(STAGEfeedback_CFLAGS)" \ ++ CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ ++ CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ ++ LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ ++ $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS) @extra_linker_plugin_flags@ \ ++ TFLAGS="$(STAGEfeedback_TFLAGS)" \ ++ $(TARGET-stagefeedback-bolt-plugin) ++ ++maybe-clean-stagefeedback-bolt-plugin: clean-stagefeedback-bolt-plugin ++clean-stagefeedback: clean-stagefeedback-bolt-plugin ++clean-stagefeedback-bolt-plugin: ++ @if [ $(current_stage) = stagefeedback ]; then \ ++ [ -f $(HOST_SUBDIR)/bolt-plugin/Makefile ] || exit 0; \ ++ else \ ++ [ -f $(HOST_SUBDIR)/stagefeedback-bolt-plugin/Makefile ] || exit 0; \ ++ $(MAKE) stagefeedback-start; \ ++ fi; \ ++ cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS) @extra_linker_plugin_flags@ clean ++@endif bolt-plugin-bootstrap ++ ++ ++.PHONY: all-stageautoprofile-bolt-plugin maybe-all-stageautoprofile-bolt-plugin ++.PHONY: clean-stageautoprofile-bolt-plugin maybe-clean-stageautoprofile-bolt-plugin ++maybe-all-stageautoprofile-bolt-plugin: ++maybe-clean-stageautoprofile-bolt-plugin: ++@if bolt-plugin-bootstrap ++maybe-all-stageautoprofile-bolt-plugin: all-stageautoprofile-bolt-plugin ++all-stageautoprofile: all-stageautoprofile-bolt-plugin ++TARGET-stageautoprofile-bolt-plugin = $(TARGET-bolt-plugin) ++all-stageautoprofile-bolt-plugin: configure-stageautoprofile-bolt-plugin ++ @[ $(current_stage) = stageautoprofile ] || $(MAKE) stageautoprofile-start ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ TFLAGS="$(STAGEautoprofile_TFLAGS)"; \ ++ $(HOST_EXPORTS) \ ++ $(POSTSTAGE1_HOST_EXPORTS) \ ++ cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $$s/gcc/config/i386/$(AUTO_PROFILE) \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) \ ++ CFLAGS="$(STAGEautoprofile_CFLAGS)" \ ++ GENERATOR_CFLAGS="$(STAGEautoprofile_GENERATOR_CFLAGS)" \ ++ CXXFLAGS="$(STAGEautoprofile_CXXFLAGS)" \ ++ LIBCFLAGS="$(STAGEautoprofile_CFLAGS)" \ ++ CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ ++ CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ ++ LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ ++ $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS) @extra_linker_plugin_flags@ \ ++ TFLAGS="$(STAGEautoprofile_TFLAGS)" \ ++ $(TARGET-stageautoprofile-bolt-plugin) ++ ++maybe-clean-stageautoprofile-bolt-plugin: clean-stageautoprofile-bolt-plugin ++clean-stageautoprofile: clean-stageautoprofile-bolt-plugin ++clean-stageautoprofile-bolt-plugin: ++ @if [ $(current_stage) = stageautoprofile ]; then \ ++ [ -f $(HOST_SUBDIR)/bolt-plugin/Makefile ] || exit 0; \ ++ else \ ++ [ -f $(HOST_SUBDIR)/stageautoprofile-bolt-plugin/Makefile ] || exit 0; \ ++ $(MAKE) stageautoprofile-start; \ ++ fi; \ ++ cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS) @extra_linker_plugin_flags@ clean ++@endif bolt-plugin-bootstrap ++ ++ ++.PHONY: all-stageautofeedback-bolt-plugin maybe-all-stageautofeedback-bolt-plugin ++.PHONY: clean-stageautofeedback-bolt-plugin maybe-clean-stageautofeedback-bolt-plugin ++maybe-all-stageautofeedback-bolt-plugin: ++maybe-clean-stageautofeedback-bolt-plugin: ++@if bolt-plugin-bootstrap ++maybe-all-stageautofeedback-bolt-plugin: all-stageautofeedback-bolt-plugin ++all-stageautofeedback: all-stageautofeedback-bolt-plugin ++TARGET-stageautofeedback-bolt-plugin = $(TARGET-bolt-plugin) ++all-stageautofeedback-bolt-plugin: configure-stageautofeedback-bolt-plugin ++ @[ $(current_stage) = stageautofeedback ] || $(MAKE) stageautofeedback-start ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ TFLAGS="$(STAGEautofeedback_TFLAGS)"; \ ++ $(HOST_EXPORTS) \ ++ $(POSTSTAGE1_HOST_EXPORTS) \ ++ cd $(HOST_SUBDIR)/bolt-plugin && \ ++ \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) \ ++ CFLAGS="$(STAGEautofeedback_CFLAGS)" \ ++ GENERATOR_CFLAGS="$(STAGEautofeedback_GENERATOR_CFLAGS)" \ ++ CXXFLAGS="$(STAGEautofeedback_CXXFLAGS)" \ ++ LIBCFLAGS="$(STAGEautofeedback_CFLAGS)" \ ++ CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ ++ CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ ++ LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ ++ $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS) @extra_linker_plugin_flags@ \ ++ TFLAGS="$(STAGEautofeedback_TFLAGS)" PERF_DATA=perf.data \ ++ $(TARGET-stageautofeedback-bolt-plugin) ++ ++maybe-clean-stageautofeedback-bolt-plugin: clean-stageautofeedback-bolt-plugin ++clean-stageautofeedback: clean-stageautofeedback-bolt-plugin ++clean-stageautofeedback-bolt-plugin: ++ @if [ $(current_stage) = stageautofeedback ]; then \ ++ [ -f $(HOST_SUBDIR)/bolt-plugin/Makefile ] || exit 0; \ ++ else \ ++ [ -f $(HOST_SUBDIR)/stageautofeedback-bolt-plugin/Makefile ] || exit 0; \ ++ $(MAKE) stageautofeedback-start; \ ++ fi; \ ++ cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(EXTRA_HOST_FLAGS) $(POSTSTAGE1_FLAGS_TO_PASS) @extra_linker_plugin_flags@ clean ++@endif bolt-plugin-bootstrap ++ ++ ++ ++ ++ ++.PHONY: check-bolt-plugin maybe-check-bolt-plugin ++maybe-check-bolt-plugin: ++@if bolt-plugin ++maybe-check-bolt-plugin: check-bolt-plugin ++ ++check-bolt-plugin: ++ @: $(MAKE); $(unstage) ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ $(HOST_EXPORTS) $(EXTRA_HOST_EXPORTS) \ ++ (cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(FLAGS_TO_PASS) @extra_linker_plugin_flags@ $(EXTRA_BOOTSTRAP_FLAGS) check) ++ ++@endif bolt-plugin ++ ++.PHONY: install-bolt-plugin maybe-install-bolt-plugin ++maybe-install-bolt-plugin: ++@if bolt-plugin ++maybe-install-bolt-plugin: install-bolt-plugin ++ ++install-bolt-plugin: installdirs ++ @: $(MAKE); $(unstage) ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ $(HOST_EXPORTS) \ ++ (cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(FLAGS_TO_PASS) @extra_linker_plugin_flags@ install) ++ ++@endif bolt-plugin ++ ++.PHONY: install-strip-bolt-plugin maybe-install-strip-bolt-plugin ++maybe-install-strip-bolt-plugin: ++@if bolt-plugin ++maybe-install-strip-bolt-plugin: install-strip-bolt-plugin ++ ++install-strip-bolt-plugin: installdirs ++ @: $(MAKE); $(unstage) ++ @r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ $(HOST_EXPORTS) \ ++ (cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(FLAGS_TO_PASS) @extra_linker_plugin_flags@ install-strip) ++ ++@endif bolt-plugin ++ ++# Other targets (info, dvi, pdf, etc.) ++ ++.PHONY: maybe-info-bolt-plugin info-bolt-plugin ++maybe-info-bolt-plugin: ++@if bolt-plugin ++maybe-info-bolt-plugin: info-bolt-plugin ++ ++info-bolt-plugin: \ ++ configure-bolt-plugin ++ @[ -f ./bolt-plugin/Makefile ] || exit 0; \ ++ r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ $(HOST_EXPORTS) \ ++ for flag in $(EXTRA_HOST_FLAGS) @extra_linker_plugin_flags@; do \ ++ eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ ++ done; \ ++ echo "Doing info in bolt-plugin"; \ ++ (cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ ++ "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ ++ "RANLIB=$${RANLIB}" \ ++ "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ ++ info) \ ++ || exit 1 ++ ++@endif bolt-plugin ++ ++.PHONY: maybe-dvi-bolt-plugin dvi-bolt-plugin ++maybe-dvi-bolt-plugin: ++@if bolt-plugin ++maybe-dvi-bolt-plugin: dvi-bolt-plugin ++ ++dvi-bolt-plugin: \ ++ configure-bolt-plugin ++ @[ -f ./bolt-plugin/Makefile ] || exit 0; \ ++ r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ $(HOST_EXPORTS) \ ++ for flag in $(EXTRA_HOST_FLAGS) @extra_linker_plugin_flags@; do \ ++ eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ ++ done; \ ++ echo "Doing dvi in bolt-plugin"; \ ++ (cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ ++ "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ ++ "RANLIB=$${RANLIB}" \ ++ "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ ++ dvi) \ ++ || exit 1 ++ ++@endif bolt-plugin ++ ++.PHONY: maybe-pdf-bolt-plugin pdf-bolt-plugin ++maybe-pdf-bolt-plugin: ++@if bolt-plugin ++maybe-pdf-bolt-plugin: pdf-bolt-plugin ++ ++pdf-bolt-plugin: \ ++ configure-bolt-plugin ++ @[ -f ./bolt-plugin/Makefile ] || exit 0; \ ++ r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ $(HOST_EXPORTS) \ ++ for flag in $(EXTRA_HOST_FLAGS) @extra_linker_plugin_flags@; do \ ++ eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ ++ done; \ ++ echo "Doing pdf in bolt-plugin"; \ ++ (cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ ++ "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ ++ "RANLIB=$${RANLIB}" \ ++ "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ ++ pdf) \ ++ || exit 1 ++ ++@endif bolt-plugin ++ ++.PHONY: maybe-html-bolt-plugin html-bolt-plugin ++maybe-html-bolt-plugin: ++@if bolt-plugin ++maybe-html-bolt-plugin: html-bolt-plugin ++ ++html-bolt-plugin: \ ++ configure-bolt-plugin ++ @[ -f ./bolt-plugin/Makefile ] || exit 0; \ ++ r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ $(HOST_EXPORTS) \ ++ for flag in $(EXTRA_HOST_FLAGS) @extra_linker_plugin_flags@; do \ ++ eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ ++ done; \ ++ echo "Doing html in bolt-plugin"; \ ++ (cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ ++ "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ ++ "RANLIB=$${RANLIB}" \ ++ "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ ++ html) \ ++ || exit 1 ++ ++@endif bolt-plugin ++ ++.PHONY: maybe-TAGS-bolt-plugin TAGS-bolt-plugin ++maybe-TAGS-bolt-plugin: ++@if bolt-plugin ++maybe-TAGS-bolt-plugin: TAGS-bolt-plugin ++ ++TAGS-bolt-plugin: \ ++ configure-bolt-plugin ++ @[ -f ./bolt-plugin/Makefile ] || exit 0; \ ++ r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ $(HOST_EXPORTS) \ ++ for flag in $(EXTRA_HOST_FLAGS) @extra_linker_plugin_flags@; do \ ++ eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ ++ done; \ ++ echo "Doing TAGS in bolt-plugin"; \ ++ (cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ ++ "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ ++ "RANLIB=$${RANLIB}" \ ++ "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ ++ TAGS) \ ++ || exit 1 ++ ++@endif bolt-plugin ++ ++.PHONY: maybe-install-info-bolt-plugin install-info-bolt-plugin ++maybe-install-info-bolt-plugin: ++@if bolt-plugin ++maybe-install-info-bolt-plugin: install-info-bolt-plugin ++ ++install-info-bolt-plugin: \ ++ configure-bolt-plugin \ ++ info-bolt-plugin ++ @[ -f ./bolt-plugin/Makefile ] || exit 0; \ ++ r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ $(HOST_EXPORTS) \ ++ for flag in $(EXTRA_HOST_FLAGS) @extra_linker_plugin_flags@; do \ ++ eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ ++ done; \ ++ echo "Doing install-info in bolt-plugin"; \ ++ (cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ ++ "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ ++ "RANLIB=$${RANLIB}" \ ++ "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ ++ install-info) \ ++ || exit 1 ++ ++@endif bolt-plugin ++ ++.PHONY: maybe-install-pdf-bolt-plugin install-pdf-bolt-plugin ++maybe-install-pdf-bolt-plugin: ++@if bolt-plugin ++maybe-install-pdf-bolt-plugin: install-pdf-bolt-plugin ++ ++install-pdf-bolt-plugin: \ ++ configure-bolt-plugin \ ++ pdf-bolt-plugin ++ @[ -f ./bolt-plugin/Makefile ] || exit 0; \ ++ r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ $(HOST_EXPORTS) \ ++ for flag in $(EXTRA_HOST_FLAGS) @extra_linker_plugin_flags@; do \ ++ eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ ++ done; \ ++ echo "Doing install-pdf in bolt-plugin"; \ ++ (cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ ++ "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ ++ "RANLIB=$${RANLIB}" \ ++ "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ ++ install-pdf) \ ++ || exit 1 ++ ++@endif bolt-plugin ++ ++.PHONY: maybe-install-html-bolt-plugin install-html-bolt-plugin ++maybe-install-html-bolt-plugin: ++@if bolt-plugin ++maybe-install-html-bolt-plugin: install-html-bolt-plugin ++ ++install-html-bolt-plugin: \ ++ configure-bolt-plugin \ ++ html-bolt-plugin ++ @[ -f ./bolt-plugin/Makefile ] || exit 0; \ ++ r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ $(HOST_EXPORTS) \ ++ for flag in $(EXTRA_HOST_FLAGS) @extra_linker_plugin_flags@; do \ ++ eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ ++ done; \ ++ echo "Doing install-html in bolt-plugin"; \ ++ (cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ ++ "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ ++ "RANLIB=$${RANLIB}" \ ++ "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ ++ install-html) \ ++ || exit 1 ++ ++@endif bolt-plugin ++ ++.PHONY: maybe-installcheck-bolt-plugin installcheck-bolt-plugin ++maybe-installcheck-bolt-plugin: ++@if bolt-plugin ++maybe-installcheck-bolt-plugin: installcheck-bolt-plugin ++ ++installcheck-bolt-plugin: \ ++ configure-bolt-plugin ++ @[ -f ./bolt-plugin/Makefile ] || exit 0; \ ++ r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ $(HOST_EXPORTS) \ ++ for flag in $(EXTRA_HOST_FLAGS) @extra_linker_plugin_flags@; do \ ++ eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ ++ done; \ ++ echo "Doing installcheck in bolt-plugin"; \ ++ (cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ ++ "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ ++ "RANLIB=$${RANLIB}" \ ++ "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ ++ installcheck) \ ++ || exit 1 ++ ++@endif bolt-plugin ++ ++.PHONY: maybe-mostlyclean-bolt-plugin mostlyclean-bolt-plugin ++maybe-mostlyclean-bolt-plugin: ++@if bolt-plugin ++maybe-mostlyclean-bolt-plugin: mostlyclean-bolt-plugin ++ ++mostlyclean-bolt-plugin: ++ @[ -f ./bolt-plugin/Makefile ] || exit 0; \ ++ r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ $(HOST_EXPORTS) \ ++ for flag in $(EXTRA_HOST_FLAGS) @extra_linker_plugin_flags@; do \ ++ eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ ++ done; \ ++ echo "Doing mostlyclean in bolt-plugin"; \ ++ (cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ ++ "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ ++ "RANLIB=$${RANLIB}" \ ++ "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ ++ mostlyclean) \ ++ || exit 1 ++ ++@endif bolt-plugin ++ ++.PHONY: maybe-clean-bolt-plugin clean-bolt-plugin ++maybe-clean-bolt-plugin: ++@if bolt-plugin ++maybe-clean-bolt-plugin: clean-bolt-plugin ++ ++clean-bolt-plugin: ++ @[ -f ./bolt-plugin/Makefile ] || exit 0; \ ++ r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ $(HOST_EXPORTS) \ ++ for flag in $(EXTRA_HOST_FLAGS) @extra_linker_plugin_flags@; do \ ++ eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ ++ done; \ ++ echo "Doing clean in bolt-plugin"; \ ++ (cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ ++ "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ ++ "RANLIB=$${RANLIB}" \ ++ "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ ++ clean) \ ++ || exit 1 ++ ++@endif bolt-plugin ++ ++.PHONY: maybe-distclean-bolt-plugin distclean-bolt-plugin ++maybe-distclean-bolt-plugin: ++@if bolt-plugin ++maybe-distclean-bolt-plugin: distclean-bolt-plugin ++ ++distclean-bolt-plugin: ++ @[ -f ./bolt-plugin/Makefile ] || exit 0; \ ++ r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ $(HOST_EXPORTS) \ ++ for flag in $(EXTRA_HOST_FLAGS) @extra_linker_plugin_flags@; do \ ++ eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ ++ done; \ ++ echo "Doing distclean in bolt-plugin"; \ ++ (cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ ++ "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ ++ "RANLIB=$${RANLIB}" \ ++ "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ ++ distclean) \ ++ || exit 1 ++ ++@endif bolt-plugin ++ ++.PHONY: maybe-maintainer-clean-bolt-plugin maintainer-clean-bolt-plugin ++maybe-maintainer-clean-bolt-plugin: ++@if bolt-plugin ++maybe-maintainer-clean-bolt-plugin: maintainer-clean-bolt-plugin ++ ++maintainer-clean-bolt-plugin: ++ @[ -f ./bolt-plugin/Makefile ] || exit 0; \ ++ r=`${PWD_COMMAND}`; export r; \ ++ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ ++ $(HOST_EXPORTS) \ ++ for flag in $(EXTRA_HOST_FLAGS) @extra_linker_plugin_flags@; do \ ++ eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ ++ done; \ ++ echo "Doing maintainer-clean in bolt-plugin"; \ ++ (cd $(HOST_SUBDIR)/bolt-plugin && \ ++ $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ ++ "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ ++ "RANLIB=$${RANLIB}" \ ++ "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ ++ maintainer-clean) \ ++ || exit 1 ++ ++@endif bolt-plugin ++ ++ ++ + .PHONY: configure-libcc1 maybe-configure-libcc1 + maybe-configure-libcc1: + @if gcc-bootstrap +@@ -55735,6 +56879,11 @@ stage1-start:: + mkdir stage1-lto-plugin; \ + mv stage1-lto-plugin lto-plugin + @endif lto-plugin ++@if bolt-plugin ++ @cd $(HOST_SUBDIR); [ -d stage1-bolt-plugin ] || \ ++ mkdir stage1-bolt-plugin; \ ++ mv stage1-bolt-plugin bolt-plugin ++@endif bolt-plugin + @if libctf + @cd $(HOST_SUBDIR); [ -d stage1-libctf ] || \ + mkdir stage1-libctf; \ +@@ -55855,6 +57004,11 @@ stage1-end:: + cd $(HOST_SUBDIR); mv lto-plugin stage1-lto-plugin; \ + fi + @endif lto-plugin ++@if bolt-plugin ++ @if test -d $(HOST_SUBDIR)/bolt-plugin; then \ ++ cd $(HOST_SUBDIR); mv bolt-plugin stage1-bolt-plugin; \ ++ fi ++@endif bolt-plugin + @if libctf + @if test -d $(HOST_SUBDIR)/libctf; then \ + cd $(HOST_SUBDIR); mv libctf stage1-libctf; \ +@@ -56040,6 +57194,12 @@ stage2-start:: + mv stage2-lto-plugin lto-plugin; \ + mv stage1-lto-plugin prev-lto-plugin || test -f stage1-lean + @endif lto-plugin ++@if bolt-plugin ++ @cd $(HOST_SUBDIR); [ -d stage2-bolt-plugin ] || \ ++ mkdir stage2-bolt-plugin; \ ++ mv stage2-bolt-plugin bolt-plugin; \ ++ mv stage1-bolt-plugin prev-bolt-plugin || test -f stage1-lean ++@endif bolt-plugin + @if libctf + @cd $(HOST_SUBDIR); [ -d stage2-libctf ] || \ + mkdir stage2-libctf; \ +@@ -56184,6 +57344,12 @@ stage2-end:: + mv prev-lto-plugin stage1-lto-plugin; : ; \ + fi + @endif lto-plugin ++@if bolt-plugin ++ @if test -d $(HOST_SUBDIR)/bolt-plugin; then \ ++ cd $(HOST_SUBDIR); mv bolt-plugin stage2-bolt-plugin; \ ++ mv prev-bolt-plugin stage1-bolt-plugin; : ; \ ++ fi ++@endif bolt-plugin + @if libctf + @if test -d $(HOST_SUBDIR)/libctf; then \ + cd $(HOST_SUBDIR); mv libctf stage2-libctf; \ +@@ -56394,6 +57560,12 @@ stage3-start:: + mv stage3-lto-plugin lto-plugin; \ + mv stage2-lto-plugin prev-lto-plugin || test -f stage2-lean + @endif lto-plugin ++@if bolt-plugin ++ @cd $(HOST_SUBDIR); [ -d stage3-bolt-plugin ] || \ ++ mkdir stage3-bolt-plugin; \ ++ mv stage3-bolt-plugin bolt-plugin; \ ++ mv stage2-bolt-plugin prev-bolt-plugin || test -f stage2-lean ++@endif bolt-plugin + @if libctf + @cd $(HOST_SUBDIR); [ -d stage3-libctf ] || \ + mkdir stage3-libctf; \ +@@ -56538,6 +57710,12 @@ stage3-end:: + mv prev-lto-plugin stage2-lto-plugin; : ; \ + fi + @endif lto-plugin ++@if bolt-plugin ++ @if test -d $(HOST_SUBDIR)/bolt-plugin; then \ ++ cd $(HOST_SUBDIR); mv bolt-plugin stage3-bolt-plugin; \ ++ mv prev-bolt-plugin stage2-bolt-plugin; : ; \ ++ fi ++@endif bolt-plugin + @if libctf + @if test -d $(HOST_SUBDIR)/libctf; then \ + cd $(HOST_SUBDIR); mv libctf stage3-libctf; \ +@@ -56804,6 +57982,12 @@ stage4-start:: + mv stage4-lto-plugin lto-plugin; \ + mv stage3-lto-plugin prev-lto-plugin || test -f stage3-lean + @endif lto-plugin ++@if bolt-plugin ++ @cd $(HOST_SUBDIR); [ -d stage4-bolt-plugin ] || \ ++ mkdir stage4-bolt-plugin; \ ++ mv stage4-bolt-plugin bolt-plugin; \ ++ mv stage3-bolt-plugin prev-bolt-plugin || test -f stage3-lean ++@endif bolt-plugin + @if libctf + @cd $(HOST_SUBDIR); [ -d stage4-libctf ] || \ + mkdir stage4-libctf; \ +@@ -56948,6 +58132,12 @@ stage4-end:: + mv prev-lto-plugin stage3-lto-plugin; : ; \ + fi + @endif lto-plugin ++@if bolt-plugin ++ @if test -d $(HOST_SUBDIR)/bolt-plugin; then \ ++ cd $(HOST_SUBDIR); mv bolt-plugin stage4-bolt-plugin; \ ++ mv prev-bolt-plugin stage3-bolt-plugin; : ; \ ++ fi ++@endif bolt-plugin + @if libctf + @if test -d $(HOST_SUBDIR)/libctf; then \ + cd $(HOST_SUBDIR); mv libctf stage4-libctf; \ +@@ -57202,6 +58392,12 @@ stageprofile-start:: + mv stageprofile-lto-plugin lto-plugin; \ + mv stage1-lto-plugin prev-lto-plugin || test -f stage1-lean + @endif lto-plugin ++@if bolt-plugin ++ @cd $(HOST_SUBDIR); [ -d stageprofile-bolt-plugin ] || \ ++ mkdir stageprofile-bolt-plugin; \ ++ mv stageprofile-bolt-plugin bolt-plugin; \ ++ mv stage1-bolt-plugin prev-bolt-plugin || test -f stage1-lean ++@endif bolt-plugin + @if libctf + @cd $(HOST_SUBDIR); [ -d stageprofile-libctf ] || \ + mkdir stageprofile-libctf; \ +@@ -57346,6 +58542,12 @@ stageprofile-end:: + mv prev-lto-plugin stage1-lto-plugin; : ; \ + fi + @endif lto-plugin ++@if bolt-plugin ++ @if test -d $(HOST_SUBDIR)/bolt-plugin; then \ ++ cd $(HOST_SUBDIR); mv bolt-plugin stageprofile-bolt-plugin; \ ++ mv prev-bolt-plugin stage1-bolt-plugin; : ; \ ++ fi ++@endif bolt-plugin + @if libctf + @if test -d $(HOST_SUBDIR)/libctf; then \ + cd $(HOST_SUBDIR); mv libctf stageprofile-libctf; \ +@@ -57533,6 +58735,12 @@ stagetrain-start:: + mv stagetrain-lto-plugin lto-plugin; \ + mv stageprofile-lto-plugin prev-lto-plugin || test -f stageprofile-lean + @endif lto-plugin ++@if bolt-plugin ++ @cd $(HOST_SUBDIR); [ -d stagetrain-bolt-plugin ] || \ ++ mkdir stagetrain-bolt-plugin; \ ++ mv stagetrain-bolt-plugin bolt-plugin; \ ++ mv stageprofile-bolt-plugin prev-bolt-plugin || test -f stageprofile-lean ++@endif bolt-plugin + @if libctf + @cd $(HOST_SUBDIR); [ -d stagetrain-libctf ] || \ + mkdir stagetrain-libctf; \ +@@ -57677,6 +58885,12 @@ stagetrain-end:: + mv prev-lto-plugin stageprofile-lto-plugin; : ; \ + fi + @endif lto-plugin ++@if bolt-plugin ++ @if test -d $(HOST_SUBDIR)/bolt-plugin; then \ ++ cd $(HOST_SUBDIR); mv bolt-plugin stagetrain-bolt-plugin; \ ++ mv prev-bolt-plugin stageprofile-bolt-plugin; : ; \ ++ fi ++@endif bolt-plugin + @if libctf + @if test -d $(HOST_SUBDIR)/libctf; then \ + cd $(HOST_SUBDIR); mv libctf stagetrain-libctf; \ +@@ -57864,6 +59078,12 @@ stagefeedback-start:: + mv stagefeedback-lto-plugin lto-plugin; \ + mv stagetrain-lto-plugin prev-lto-plugin || test -f stagetrain-lean + @endif lto-plugin ++@if bolt-plugin ++ @cd $(HOST_SUBDIR); [ -d stagefeedback-bolt-plugin ] || \ ++ mkdir stagefeedback-bolt-plugin; \ ++ mv stagefeedback-bolt-plugin bolt-plugin; \ ++ mv stagetrain-bolt-plugin prev-bolt-plugin || test -f stagetrain-lean ++@endif bolt-plugin + @if libctf + @cd $(HOST_SUBDIR); [ -d stagefeedback-libctf ] || \ + mkdir stagefeedback-libctf; \ +@@ -58008,6 +59228,12 @@ stagefeedback-end:: + mv prev-lto-plugin stagetrain-lto-plugin; : ; \ + fi + @endif lto-plugin ++@if bolt-plugin ++ @if test -d $(HOST_SUBDIR)/bolt-plugin; then \ ++ cd $(HOST_SUBDIR); mv bolt-plugin stagefeedback-bolt-plugin; \ ++ mv prev-bolt-plugin stagetrain-bolt-plugin; : ; \ ++ fi ++@endif bolt-plugin + @if libctf + @if test -d $(HOST_SUBDIR)/libctf; then \ + cd $(HOST_SUBDIR); mv libctf stagefeedback-libctf; \ +@@ -58218,6 +59444,12 @@ stageautoprofile-start:: + mv stageautoprofile-lto-plugin lto-plugin; \ + mv stage1-lto-plugin prev-lto-plugin || test -f stage1-lean + @endif lto-plugin ++@if bolt-plugin ++ @cd $(HOST_SUBDIR); [ -d stageautoprofile-bolt-plugin ] || \ ++ mkdir stageautoprofile-bolt-plugin; \ ++ mv stageautoprofile-bolt-plugin bolt-plugin; \ ++ mv stage1-bolt-plugin prev-bolt-plugin || test -f stage1-lean ++@endif bolt-plugin + @if libctf + @cd $(HOST_SUBDIR); [ -d stageautoprofile-libctf ] || \ + mkdir stageautoprofile-libctf; \ +@@ -58362,6 +59594,12 @@ stageautoprofile-end:: + mv prev-lto-plugin stage1-lto-plugin; : ; \ + fi + @endif lto-plugin ++@if bolt-plugin ++ @if test -d $(HOST_SUBDIR)/bolt-plugin; then \ ++ cd $(HOST_SUBDIR); mv bolt-plugin stageautoprofile-bolt-plugin; \ ++ mv prev-bolt-plugin stage1-bolt-plugin; : ; \ ++ fi ++@endif bolt-plugin + @if libctf + @if test -d $(HOST_SUBDIR)/libctf; then \ + cd $(HOST_SUBDIR); mv libctf stageautoprofile-libctf; \ +@@ -58549,6 +59787,12 @@ stageautofeedback-start:: + mv stageautofeedback-lto-plugin lto-plugin; \ + mv stageautoprofile-lto-plugin prev-lto-plugin || test -f stageautoprofile-lean + @endif lto-plugin ++@if bolt-plugin ++ @cd $(HOST_SUBDIR); [ -d stageautofeedback-bolt-plugin ] || \ ++ mkdir stageautofeedback-bolt-plugin; \ ++ mv stageautofeedback-bolt-plugin bolt-plugin; \ ++ mv stageautoprofile-bolt-plugin prev-bolt-plugin || test -f stageautoprofile-lean ++@endif bolt-plugin + @if libctf + @cd $(HOST_SUBDIR); [ -d stageautofeedback-libctf ] || \ + mkdir stageautofeedback-libctf; \ +@@ -58693,6 +59937,12 @@ stageautofeedback-end:: + mv prev-lto-plugin stageautoprofile-lto-plugin; : ; \ + fi + @endif lto-plugin ++@if bolt-plugin ++ @if test -d $(HOST_SUBDIR)/bolt-plugin; then \ ++ cd $(HOST_SUBDIR); mv bolt-plugin stageautofeedback-bolt-plugin; \ ++ mv prev-bolt-plugin stageautoprofile-bolt-plugin; : ; \ ++ fi ++@endif bolt-plugin + @if libctf + @if test -d $(HOST_SUBDIR)/libctf; then \ + cd $(HOST_SUBDIR); mv libctf stageautofeedback-libctf; \ +@@ -58985,6 +60235,16 @@ configure-stagetrain-gcc: maybe-all-stagetrain-lto-plugin + configure-stagefeedback-gcc: maybe-all-stagefeedback-lto-plugin + configure-stageautoprofile-gcc: maybe-all-stageautoprofile-lto-plugin + configure-stageautofeedback-gcc: maybe-all-stageautofeedback-lto-plugin ++configure-gcc: maybe-all-bolt-plugin ++configure-stage1-gcc: maybe-all-stage1-bolt-plugin ++configure-stage2-gcc: maybe-all-stage2-bolt-plugin ++configure-stage3-gcc: maybe-all-stage3-bolt-plugin ++configure-stage4-gcc: maybe-all-stage4-bolt-plugin ++configure-stageprofile-gcc: maybe-all-stageprofile-bolt-plugin ++configure-stagetrain-gcc: maybe-all-stagetrain-bolt-plugin ++configure-stagefeedback-gcc: maybe-all-stagefeedback-bolt-plugin ++configure-stageautoprofile-gcc: maybe-all-stageautoprofile-bolt-plugin ++configure-stageautofeedback-gcc: maybe-all-stageautofeedback-bolt-plugin + configure-gcc: maybe-all-binutils + configure-stage1-gcc: maybe-all-stage1-binutils + configure-stage2-gcc: maybe-all-stage2-binutils +@@ -59225,6 +60485,16 @@ all-stagetrain-gcc: maybe-all-stagetrain-lto-plugin + all-stagefeedback-gcc: maybe-all-stagefeedback-lto-plugin + all-stageautoprofile-gcc: maybe-all-stageautoprofile-lto-plugin + all-stageautofeedback-gcc: maybe-all-stageautofeedback-lto-plugin ++all-gcc: maybe-all-bolt-plugin ++all-stage1-gcc: maybe-all-stage1-bolt-plugin ++all-stage2-gcc: maybe-all-stage2-bolt-plugin ++all-stage3-gcc: maybe-all-stage3-bolt-plugin ++all-stage4-gcc: maybe-all-stage4-bolt-plugin ++all-stageprofile-gcc: maybe-all-stageprofile-bolt-plugin ++all-stagetrain-gcc: maybe-all-stagetrain-bolt-plugin ++all-stagefeedback-gcc: maybe-all-stagefeedback-bolt-plugin ++all-stageautoprofile-gcc: maybe-all-stageautoprofile-bolt-plugin ++all-stageautofeedback-gcc: maybe-all-stageautofeedback-bolt-plugin + all-gcc: maybe-all-libiconv + all-stage1-gcc: maybe-all-stage1-libiconv + all-stage2-gcc: maybe-all-stage2-libiconv +@@ -59277,8 +60547,10 @@ html-stageautoprofile-gcc: maybe-all-build-libiberty + html-stageautofeedback-gcc: maybe-all-build-libiberty + install-gcc: maybe-install-fixincludes + install-gcc: maybe-install-lto-plugin ++install-gcc: maybe-install-bolt-plugin + install-strip-gcc: maybe-install-strip-fixincludes + install-strip-gcc: maybe-install-strip-lto-plugin ++install-strip-gcc: maybe-install-strip-bolt-plugin + configure-libcpp: configure-libiberty + configure-stage1-libcpp: configure-stage1-libiberty + configure-stage2-libcpp: configure-stage2-libiberty +@@ -59370,6 +60642,26 @@ all-stagetrain-lto-plugin: maybe-all-stagetrain-libiberty-linker-plugin + all-stagefeedback-lto-plugin: maybe-all-stagefeedback-libiberty-linker-plugin + all-stageautoprofile-lto-plugin: maybe-all-stageautoprofile-libiberty-linker-plugin + all-stageautofeedback-lto-plugin: maybe-all-stageautofeedback-libiberty-linker-plugin ++all-bolt-plugin: maybe-all-libiberty ++all-stage1-bolt-plugin: maybe-all-stage1-libiberty ++all-stage2-bolt-plugin: maybe-all-stage2-libiberty ++all-stage3-bolt-plugin: maybe-all-stage3-libiberty ++all-stage4-bolt-plugin: maybe-all-stage4-libiberty ++all-stageprofile-bolt-plugin: maybe-all-stageprofile-libiberty ++all-stagetrain-bolt-plugin: maybe-all-stagetrain-libiberty ++all-stagefeedback-bolt-plugin: maybe-all-stagefeedback-libiberty ++all-stageautoprofile-bolt-plugin: maybe-all-stageautoprofile-libiberty ++all-stageautofeedback-bolt-plugin: maybe-all-stageautofeedback-libiberty ++all-bolt-plugin: maybe-all-libiberty-linker-plugin ++all-stage1-bolt-plugin: maybe-all-stage1-libiberty-linker-plugin ++all-stage2-bolt-plugin: maybe-all-stage2-libiberty-linker-plugin ++all-stage3-bolt-plugin: maybe-all-stage3-libiberty-linker-plugin ++all-stage4-bolt-plugin: maybe-all-stage4-libiberty-linker-plugin ++all-stageprofile-bolt-plugin: maybe-all-stageprofile-libiberty-linker-plugin ++all-stagetrain-bolt-plugin: maybe-all-stagetrain-libiberty-linker-plugin ++all-stagefeedback-bolt-plugin: maybe-all-stagefeedback-libiberty-linker-plugin ++all-stageautoprofile-bolt-plugin: maybe-all-stageautoprofile-libiberty-linker-plugin ++all-stageautofeedback-bolt-plugin: maybe-all-stageautofeedback-libiberty-linker-plugin + all-gotools: maybe-all-target-libgo + configure-intl: maybe-all-libiconv + configure-stage1-intl: maybe-all-stage1-libiconv +diff --git a/configure b/configure +old mode 100644 +new mode 100755 +index f2ec106a8..97d5ca4fc +--- a/configure ++++ b/configure +@@ -814,6 +814,7 @@ with_isl + with_isl_include + with_isl_lib + enable_isl_version_check ++enable_bolt + enable_lto + enable_linker_plugin_configure_flags + enable_linker_plugin_flags +@@ -1529,6 +1530,7 @@ Optional Features: + --enable-bootstrap enable bootstrapping [yes if native build] + --disable-isl-version-check + disable check for isl version ++ --enable-bolt enable bolt optimization support + --enable-lto enable link time optimization support + --enable-linker-plugin-configure-flags=FLAGS + additional flags for configuring linker plugins +@@ -6187,6 +6189,15 @@ fi + + + ++# Check for BOLT support. ++# Check whether --enable-bolt was given. ++if test "${enable_bolt+set}" = set; then : ++ enableval=$enable_bolt; enable_bolt=$enableval ++else ++ enable_bolt=no; default_enable_bolt=no ++fi ++ ++ + # Check for LTO support. + # Check whether --enable-lto was given. + if test "${enable_lto+set}" = set; then : +@@ -6216,6 +6227,16 @@ if test $target_elf = yes; then : + # ELF platforms build the lto-plugin always. + build_lto_plugin=yes + ++ # ELF platforms can build the bolt-plugin. ++ # NOT BUILD BOLT BY DEFAULT. ++ case $target in ++ aarch64*-*-linux*) ++ if test $enable_bolt = yes; then : ++ build_bolt_plugin=yes ++ fi ++ ;; ++ esac ++ + else + if test x"$default_enable_lto" = x"yes" ; then + case $target in +@@ -6391,6 +6412,10 @@ if test -d ${srcdir}/gcc; then + fi + fi + ++ if test "${build_bolt_plugin}" = "yes" ; then ++ configdirs="$configdirs bolt-plugin" ++ fi ++ + # If we're building an offloading compiler, add the LTO front end. + if test x"$enable_as_accelerator_for" != x ; then + case ,${enable_languages}, in +@@ -6779,7 +6804,7 @@ fi + extra_host_libiberty_configure_flags= + extra_host_zlib_configure_flags= + case " $configdirs " in +- *" lto-plugin "* | *" libcc1 "*) ++ *" lto-plugin "* | *" libcc1 "* | *" bolt-plugin "*) + # When these are to be built as shared libraries, the same applies to + # libiberty. + extra_host_libiberty_configure_flags=--enable-shared +diff --git a/configure.ac b/configure.ac +index 115db3f40..90ccd5ef8 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1810,6 +1810,12 @@ fi + AC_SUBST(isllibs) + AC_SUBST(islinc) + ++# Check for BOLT support. ++AC_ARG_ENABLE(bolt, ++[AS_HELP_STRING([--enable-bolt], [enable bolt optimization support])], ++enable_bolt=$enableval, ++enable_bolt=no; default_enable_bolt=no) ++ + # Check for LTO support. + AC_ARG_ENABLE(lto, + [AS_HELP_STRING([--enable-lto], [enable link time optimization support])], +@@ -1818,6 +1824,16 @@ enable_lto=yes; default_enable_lto=yes) + + ACX_ELF_TARGET_IFELSE([# ELF platforms build the lto-plugin always. + build_lto_plugin=yes ++ ++ # ELF platforms can build the bolt-plugin. ++ # NOT BUILD BOLT BY DEFAULT. ++ case $target in ++ aarch64*-*-linux*) ++ if test $enable_bolt = yes; then : ++ build_bolt_plugin=yes ++ fi ++ ;; ++ esac + ],[if test x"$default_enable_lto" = x"yes" ; then + case $target in + *-apple-darwin[[912]]* | *-cygwin* | *-mingw* | *djgpp*) ;; +@@ -1983,6 +1999,10 @@ if test -d ${srcdir}/gcc; then + fi + fi + ++ if test "${build_bolt_plugin}" = "yes" ; then ++ configdirs="$configdirs bolt-plugin" ++ fi ++ + # If we're building an offloading compiler, add the LTO front end. + if test x"$enable_as_accelerator_for" != x ; then + case ,${enable_languages}, in +@@ -2358,7 +2378,7 @@ fi + extra_host_libiberty_configure_flags= + extra_host_zlib_configure_flags= + case " $configdirs " in +- *" lto-plugin "* | *" libcc1 "*) ++ *" lto-plugin "* | *" libcc1 "* | *" bolt-plugin "*) + # When these are to be built as shared libraries, the same applies to + # libiberty. + extra_host_libiberty_configure_flags=--enable-shared +diff --git a/gcc/config.host b/gcc/config.host +index 84f0433e2..230ab61ac 100644 +--- a/gcc/config.host ++++ b/gcc/config.host +@@ -59,7 +59,11 @@ + # host_lto_plugin_soname Set this to the name to which the LTO linker + # plugin gets compiled on this host, if it is + # different from the default "liblto_plugin.so". +- ++# ++# host_bolt_plugin_soname Set this to the name to which the BOLT ++# plugin gets compiled on this host, if it is ++# different from the default "libbolt_plugin.so". ++# + # When setting any of these variables, check to see if a corresponding + # variable is present in config.build; if so, you will likely want to + # set it in both places. +@@ -75,6 +79,7 @@ out_host_hook_obj=host-default.o + host_can_use_collect2=yes + use_long_long_for_widest_fast_int=no + host_lto_plugin_soname=liblto_plugin.so ++host_bolt_plugin_soname=libbolt_plugin.so + + # Unsupported hosts list. Generally, only include hosts known to fail here, + # since we allow hosts not listed to be supported generically. +diff --git a/gcc/config.in b/gcc/config.in +index 364eba477..80b421d99 100644 +--- a/gcc/config.in ++++ b/gcc/config.in +@@ -24,6 +24,13 @@ + #endif + + ++/* Define to the name of the BOLT plugin DSO that must be passed to the ++ linker's -plugin=LIB option. */ ++#ifndef USED_FOR_TARGET ++#undef BOLTPLUGINSONAME ++#endif ++ ++ + /* Define to the root for URLs about GCC changes. */ + #ifndef USED_FOR_TARGET + #undef CHANGES_ROOT_URL +diff --git a/gcc/configure b/gcc/configure +old mode 100644 +new mode 100755 +index 27beb6b1e..d4f97834f +--- a/gcc/configure ++++ b/gcc/configure +@@ -12922,6 +12922,12 @@ case $use_collect2 in + esac + + ++cat >>confdefs.h <<_ACEOF ++#define BOLTPLUGINSONAME "${host_bolt_plugin_soname}" ++_ACEOF ++ ++ ++ + cat >>confdefs.h <<_ACEOF + #define LTOPLUGINSONAME "${host_lto_plugin_soname}" + _ACEOF +@@ -19022,7 +19028,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 19025 "configure" ++#line 19031 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -19128,7 +19134,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 19131 "configure" ++#line 19137 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +diff --git a/gcc/configure.ac b/gcc/configure.ac +index 82a0ce995..44154f69f 100644 +--- a/gcc/configure.ac ++++ b/gcc/configure.ac +@@ -2357,6 +2357,10 @@ case $use_collect2 in + ;; + esac + ++AC_DEFINE_UNQUOTED(BOLTPLUGINSONAME,"${host_bolt_plugin_soname}", ++[Define to the name of the BOLT plugin DSO that must be ++ passed to the linker's -plugin=LIB option.]) ++ + AC_DEFINE_UNQUOTED(LTOPLUGINSONAME,"${host_lto_plugin_soname}", + [Define to the name of the LTO plugin DSO that must be + passed to the linker's -plugin=LIB option.]) +diff --git a/gcc/gcc.c b/gcc/gcc.c +index 9f790db0d..b55075b14 100644 +--- a/gcc/gcc.c ++++ b/gcc/gcc.c +@@ -1036,6 +1036,8 @@ proper position among the other output files. */ + %{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S:\ + %(linker) " \ + LINK_PLUGIN_SPEC \ ++ "%{fauto-bolt|fauto-bolt=*|fbolt-use|fbolt-use=*: \ ++ -plugin %(linker_auto_bolt_plugin_file) }"\ + "%{flto|flto=*:%<fcompare-debug*} \ + %{flto} %{fno-lto} %{flto=*} %l " LINK_PIE_SPEC \ + "%{fuse-ld=*:-fuse-ld=%*} " LINK_COMPRESS_DEBUG_SPEC \ +@@ -1089,6 +1091,7 @@ static const char *endfile_spec = ENDFILE_SPEC; + static const char *startfile_spec = STARTFILE_SPEC; + static const char *linker_name_spec = LINKER_NAME; + static const char *linker_plugin_file_spec = ""; ++static const char *linker_auto_bolt_plugin_file_spec = ""; + static const char *lto_wrapper_spec = ""; + static const char *lto_gcc_spec = ""; + static const char *post_link_spec = POST_LINK_SPEC; +@@ -1594,6 +1597,8 @@ static struct spec_list static_specs[] = + INIT_STATIC_SPEC ("multilib_reuse", &multilib_reuse), + INIT_STATIC_SPEC ("linker", &linker_name_spec), + INIT_STATIC_SPEC ("linker_plugin_file", &linker_plugin_file_spec), ++ INIT_STATIC_SPEC ("linker_auto_bolt_plugin_file", ++ &linker_auto_bolt_plugin_file_spec), + INIT_STATIC_SPEC ("lto_wrapper", <o_wrapper_spec), + INIT_STATIC_SPEC ("lto_gcc", <o_gcc_spec), + INIT_STATIC_SPEC ("post_link", &post_link_spec), +@@ -8339,6 +8344,23 @@ driver::maybe_run_linker (const char *argv0) const + } + #endif + lto_gcc_spec = argv0; ++ ++ /* Set bolt-plugin. */ ++ const char *fauto_bolt = "fauto-bolt"; ++ const char *fbolt_use = "fbolt-use"; ++ if (switch_matches (fauto_bolt, fauto_bolt + strlen (fauto_bolt), 1) ++ || switch_matches (fbolt_use, fbolt_use + strlen (fbolt_use), 1)) ++ { ++ linker_auto_bolt_plugin_file_spec = find_a_file (&exec_prefixes, ++ BOLTPLUGINSONAME, X_OK, false); ++ if (!linker_auto_bolt_plugin_file_spec) ++ { ++ fatal_error (input_location, ++ "-fauto-bolt or -fbolt-use is used,", ++ " but %s file is not found", ++ BOLTPLUGINSONAME); ++ } ++ } + } + + /* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables +-- +2.27.0 + diff --git a/0032-Autoprefetch-Prune-invaild-loops-containing-edges-wh.patch b/0032-Autoprefetch-Prune-invaild-loops-containing-edges-wh.patch new file mode 100644 index 0000000..aa15df4 --- /dev/null +++ b/0032-Autoprefetch-Prune-invaild-loops-containing-edges-wh.patch @@ -0,0 +1,82 @@ +From 071d19832d788422034a3b052ff7ce91e1010344 Mon Sep 17 00:00:00 2001 +From: dingguangya <dingguangya1@huawei.com> +Date: Mon, 28 Feb 2022 16:52:58 +0800 +Subject: [PATCH 32/32] [Autoprefetch] Prune invaild loops containing edges whose + probability exceeds 1 + +Skip auto prefetch analysis if the loop contains the bb in which the sum +of its outgoing edge probabilities is greater than 1. +--- + gcc/testsuite/gcc.dg/autoprefetch/autoprefetch.exp | 2 +- + .../gcc.dg/autoprefetch/branch-weighted-prefetch.c | 8 ++++---- + gcc/tree-ssa-loop-prefetch.c | 12 ++++++++++++ + 3 files changed, 17 insertions(+), 5 deletions(-) + +diff --git a/gcc/testsuite/gcc.dg/autoprefetch/autoprefetch.exp b/gcc/testsuite/gcc.dg/autoprefetch/autoprefetch.exp +index a7408e338..7cae630a2 100644 +--- a/gcc/testsuite/gcc.dg/autoprefetch/autoprefetch.exp ++++ b/gcc/testsuite/gcc.dg/autoprefetch/autoprefetch.exp +@@ -20,7 +20,7 @@ load_lib target-supports.exp + # Initialize `dg'. + dg-init + +-gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] \ ++dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] \ + "" "-fprefetch-loop-arrays" + + # All done. +diff --git a/gcc/testsuite/gcc.dg/autoprefetch/branch-weighted-prefetch.c b/gcc/testsuite/gcc.dg/autoprefetch/branch-weighted-prefetch.c +index c63c5e5cb..ab537cb29 100644 +--- a/gcc/testsuite/gcc.dg/autoprefetch/branch-weighted-prefetch.c ++++ b/gcc/testsuite/gcc.dg/autoprefetch/branch-weighted-prefetch.c +@@ -1,5 +1,5 @@ +-/* { dg-do compile } */ +-/* { dg-options "-O2 -fprefetch-loop-arrays=2 --param min-insn-to-prefetch-ratio=5 --param simultaneous-prefetches=100 -fdump-tree-aprefetch-details -fdump-tree-optimized" } */ ++/* { dg-do compile { target { aarch64*-*-linux* } } } */ ++/* { dg-options "-O2 -fprefetch-loop-arrays=2 --param min-insn-to-prefetch-ratio=5 --param simultaneous-prefetches=100 --param l1-cache-size=64 --param l1-cache-line-size=32 -fdump-tree-aprefetch-details -fdump-tree-optimized" } */ + #define N 10000000 + + long long a[N]; +@@ -18,5 +18,5 @@ long long func () + + return sum; + } +-/* { dg-final { scan-tree-dump-times "Ahead 40" 1 "aprefetch" } } */ +-/* { dg-final { scan-tree-dump-times "builtin_prefetch" 1 "optimized" } } */ +\ No newline at end of file ++/* { dg-final { scan-tree-dump "Calculating prefetch distance using bb branch weighting method" "aprefetch" } } */ ++/* { dg-final { scan-tree-dump "builtin_prefetch" "optimized" } } */ +\ No newline at end of file +diff --git a/gcc/tree-ssa-loop-prefetch.c b/gcc/tree-ssa-loop-prefetch.c +index 673f453a4..0d992d8f6 100644 +--- a/gcc/tree-ssa-loop-prefetch.c ++++ b/gcc/tree-ssa-loop-prefetch.c +@@ -2267,6 +2267,15 @@ traverse_prune_bb_branch (hash_map <basic_block, bb_bp> &bb_branch_prob, + && bb_bp_node->false_edge_bb == NULL)) + return false; + ++ /* Do not process the loop with a bb branch probability of an abnormal ++ value. */ ++ if (bb_bp_node->true_edge_prob + bb_bp_node->false_edge_prob > 1) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "bb branch probability is abnormal\n"); ++ return false; ++ } ++ + if (current_bb == latch_bb) + { + max_path--; +@@ -2409,6 +2418,9 @@ estimate_num_loop_insns (struct loop *loop, eni_weights *weights) + dump_loop_bb (loop); + return 0; + } ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "Calculating prefetch distance using bb branch " ++ "weighting method\n"); + } + + for (unsigned i = 0; i < loop->num_nodes; i++) +-- +2.27.0 + diff --git a/0033-AutoFdo-Fix-memory-leaks-in-autofdo-and-autoprefetch.patch b/0033-AutoFdo-Fix-memory-leaks-in-autofdo-and-autoprefetch.patch new file mode 100644 index 0000000..3286140 --- /dev/null +++ b/0033-AutoFdo-Fix-memory-leaks-in-autofdo-and-autoprefetch.patch @@ -0,0 +1,130 @@ +From adfcca263996bf174f7108b477e81e7ec58f19c4 Mon Sep 17 00:00:00 2001 +From: dingguangya <dingguangya1@huawei.com> +Date: Mon, 14 Mar 2022 10:42:07 +0800 +Subject: [PATCH] [AutoFdo] Fix memory leaks in autofdo and autoprefetch + +Fix memory leaks in autofdo and autoprefetch. +--- + gcc/final.c | 23 +++++++++++++++-------- + gcc/tree-ssa-loop-prefetch.c | 4 ++++ + 2 files changed, 19 insertions(+), 8 deletions(-) + +diff --git a/gcc/final.c b/gcc/final.c +index b9affd3a7..da8d20958 100644 +--- a/gcc/final.c ++++ b/gcc/final.c +@@ -4770,12 +4770,16 @@ get_fdo_count_quality (profile_count count) + return profile_quality[count.quality ()]; + } + +-static const char * ++/* If the function is not public, return the function_name/file_name for ++ disambiguation of local symbols since there could be identical function ++ names coming from identical file names. The caller needs to free memory. */ ++ ++static char * + alias_local_functions (const char *fnname) + { + if (TREE_PUBLIC (cfun->decl)) + { +- return fnname; ++ return concat (fnname, NULL); + } + + return concat (fnname, "/", lbasename (dump_base_name), NULL); +@@ -4826,12 +4830,14 @@ dump_direct_callee_info_to_asm (basic_block bb, gcov_type call_count) + + if (callee) + { ++ char *func_name = ++ alias_local_functions (get_fnname_from_decl (callee)); + fprintf (asm_out_file, "\t.string \"%x\"\n", + INSN_ADDRESSES (INSN_UID (insn))); + + fprintf (asm_out_file, "\t.string \"%s%s\"\n", + ASM_FDO_CALLEE_FLAG, +- alias_local_functions (get_fnname_from_decl (callee))); ++ func_name); + + fprintf (asm_out_file, + "\t.string \"" HOST_WIDE_INT_PRINT_DEC "\"\n", +@@ -4841,9 +4847,9 @@ dump_direct_callee_info_to_asm (basic_block bb, gcov_type call_count) + { + fprintf (dump_file, "call: %x --> %s\n", + INSN_ADDRESSES (INSN_UID (insn)), +- alias_local_functions +- (get_fnname_from_decl (callee))); ++ func_name); + } ++ free (func_name); + } + } + } +@@ -4917,8 +4923,9 @@ dump_bb_info_to_asm (basic_block bb, gcov_type bb_count) + static void + dump_function_info_to_asm (const char *fnname) + { ++ char *func_name = alias_local_functions (fnname); + fprintf (asm_out_file, "\t.string \"%s%s\"\n", +- ASM_FDO_CALLER_FLAG, alias_local_functions (fnname)); ++ ASM_FDO_CALLER_FLAG, func_name); + fprintf (asm_out_file, "\t.string \"%s%d\"\n", + ASM_FDO_CALLER_SIZE_FLAG, get_function_end_addr ()); + fprintf (asm_out_file, "\t.string \"%s%s\"\n", +@@ -4926,8 +4933,7 @@ dump_function_info_to_asm (const char *fnname) + + if (dump_file) + { +- fprintf (dump_file, "\n FUNC_NAME: %s\n", +- alias_local_functions (fnname)); ++ fprintf (dump_file, "\n FUNC_NAME: %s\n", func_name); + fprintf (dump_file, " file: %s\n", + dump_base_name); + fprintf (dump_file, " profile_status: %s\n", +@@ -4937,6 +4943,7 @@ dump_function_info_to_asm (const char *fnname) + fprintf (dump_file, " function_bind: %s\n", + simple_get_function_bind ()); + } ++ free (func_name); + } + + /* Dump function profile info form AutoFDO or PGO to asm. */ +diff --git a/gcc/tree-ssa-loop-prefetch.c b/gcc/tree-ssa-loop-prefetch.c +index 0d992d8f6..781831c39 100644 +--- a/gcc/tree-ssa-loop-prefetch.c ++++ b/gcc/tree-ssa-loop-prefetch.c +@@ -2248,6 +2248,7 @@ get_bb_branch_prob (hash_map <basic_block, bb_bp> &bb_branch_prob, + branch_prob.true_edge_prob = get_edge_prob (e); + } + } ++ free (body); + } + + /* Traverse each bb in the loop and prune fake loops. */ +@@ -2416,6 +2417,7 @@ estimate_num_loop_insns (struct loop *loop, eni_weights *weights) + if (get_bb_prob (bb_branch_prob, loop) == false) + { + dump_loop_bb (loop); ++ free (body); + return 0; + } + if (dump_file && (dump_flags & TDF_DETAILS)) +@@ -2596,6 +2598,7 @@ is_high_exec_rate_loop (struct loop *loop) + + if (loop_exec_rate < (float) LOOP_EXECUTION_RATE / 100.0) + { ++ exit_edges.release (); + return false; + } + } +@@ -2606,6 +2609,7 @@ is_high_exec_rate_loop (struct loop *loop) + loop_exec_rate, (float) LOOP_EXECUTION_RATE / 100.0); + dump_loop_bb (loop); + } ++ exit_edges.release (); + return true; + } + +-- +2.27.0.windows.1 + diff --git a/0034-Backport-sanitizer-Fix-asan-against-glibc-2.34-PR100.patch b/0034-Backport-sanitizer-Fix-asan-against-glibc-2.34-PR100.patch new file mode 100644 index 0000000..10c4485 --- /dev/null +++ b/0034-Backport-sanitizer-Fix-asan-against-glibc-2.34-PR100.patch @@ -0,0 +1,72 @@ +From 2969f5190561e26a8ce42d5dcda43ef59e0b6d32 Mon Sep 17 00:00:00 2001 +From: liyancheng <412998149@qq.com> +Date: Tue, 26 Apr 2022 19:59:09 +0800 +Subject: [PATCH] [Backport] sanitizer: Fix asan against glibc 2.34 [PR100114] + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=d9f462fb372fb02da032cefd6b091d7582c425ae + +sanitizer: Fix asan against glibc 2.34 [PR100114] + +As mentioned in the PR, SIGSTKSZ is no longer a compile time constant in +glibc 2.34 and later, so +static const uptr kAltStackSize = SIGSTKSZ * 4; +needs dynamic initialization, but is used by a function called indirectly +from .preinit_array and therefore before the variable is constructed. +This results in using 0 size instead and all asan instrumented programs +die with: +==91==ERROR: AddressSanitizer failed to allocate 0x0 (0) bytes of SetAlternateSignalStack (error code: 22) + +Here is a cherry-pick from upstream to fix this. + +2021-04-17 Jakub Jelinek <jakub@redhat.com> + +PR sanitizer/100114 +* sanitizer_common/sanitizer_posix_libcdep.cpp: Cherry-pick +llvm-project revisions 82150606fb11d28813ae6da1101f5bda638165fe +and b93629dd335ffee2fc4b9b619bf86c3f9e6b0023. +--- + .../sanitizer_common/sanitizer_posix_libcdep.cpp | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp +index 304b3a01a..ac88fbe07 100644 +--- a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp ++++ b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp +@@ -169,7 +169,11 @@ bool SupportsColoredOutput(fd_t fd) { + + #if !SANITIZER_GO + // TODO(glider): different tools may require different altstack size. +-static const uptr kAltStackSize = SIGSTKSZ * 4; // SIGSTKSZ is not enough. ++static uptr GetAltStackSize() { ++ // SIGSTKSZ is not enough. ++ static const uptr kAltStackSize = SIGSTKSZ * 4; ++ return kAltStackSize; ++} + + void SetAlternateSignalStack() { + stack_t altstack, oldstack; +@@ -180,10 +184,9 @@ void SetAlternateSignalStack() { + // TODO(glider): the mapped stack should have the MAP_STACK flag in the + // future. It is not required by man 2 sigaltstack now (they're using + // malloc()). +- void* base = MmapOrDie(kAltStackSize, __func__); +- altstack.ss_sp = (char*) base; ++ altstack.ss_size = GetAltStackSize(); ++ altstack.ss_sp = (char *)MmapOrDie(altstack.ss_size, __func__); + altstack.ss_flags = 0; +- altstack.ss_size = kAltStackSize; + CHECK_EQ(0, sigaltstack(&altstack, nullptr)); + } + +@@ -191,7 +194,7 @@ void UnsetAlternateSignalStack() { + stack_t altstack, oldstack; + altstack.ss_sp = nullptr; + altstack.ss_flags = SS_DISABLE; +- altstack.ss_size = kAltStackSize; // Some sane value required on Darwin. ++ altstack.ss_size = GetAltStackSize(); // Some sane value required on Darwin. + CHECK_EQ(0, sigaltstack(&altstack, &oldstack)); + UnmapOrDie(oldstack.ss_sp, oldstack.ss_size); + } +-- +2.25.1 + diff --git a/0035-ccmp-Add-another-optimization-opportunity-for-ccmp-i.patch b/0035-ccmp-Add-another-optimization-opportunity-for-ccmp-i.patch new file mode 100644 index 0000000..fe0b533 --- /dev/null +++ b/0035-ccmp-Add-another-optimization-opportunity-for-ccmp-i.patch @@ -0,0 +1,342 @@ +From cf0f086ec274d794a2a180047123920bf8a5224b Mon Sep 17 00:00:00 2001 +From: dingguangya <dingguangya1@huawei.com> +Date: Mon, 17 Jan 2022 21:03:47 +0800 +Subject: [PATCH 01/12] [ccmp] Add another optimization opportunity for ccmp + instruction + +Add flag -fccmp2. +Enables the use of the ccmp instruction by creating a new conflict +relationship for instances where temporary expressions replacement +cannot be effectively created. +--- + gcc/ccmp.c | 33 ++++ + gcc/ccmp.h | 1 + + gcc/common.opt | 4 + + gcc/testsuite/gcc.target/aarch64/ccmp_3.c | 15 ++ + gcc/tree-ssa-coalesce.c | 197 ++++++++++++++++++++++ + 5 files changed, 250 insertions(+) + create mode 100644 gcc/testsuite/gcc.target/aarch64/ccmp_3.c + +diff --git a/gcc/ccmp.c b/gcc/ccmp.c +index ca77375a9..8d2d73e52 100644 +--- a/gcc/ccmp.c ++++ b/gcc/ccmp.c +@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see + #include "cfgexpand.h" + #include "ccmp.h" + #include "predict.h" ++#include "gimple-iterator.h" + + /* Check whether T is a simple boolean variable or a SSA name + set by a comparison operator in the same basic block. */ +@@ -129,6 +130,38 @@ ccmp_candidate_p (gimple *g) + return false; + } + ++/* Check whether bb is a potential conditional compare candidate. */ ++bool ++check_ccmp_candidate (basic_block bb) ++{ ++ gimple_stmt_iterator gsi; ++ gimple *bb_last_stmt, *stmt; ++ tree op0, op1; ++ ++ gsi = gsi_last_bb (bb); ++ bb_last_stmt = gsi_stmt (gsi); ++ ++ if (bb_last_stmt && gimple_code (bb_last_stmt) == GIMPLE_COND) ++ { ++ op0 = gimple_cond_lhs (bb_last_stmt); ++ op1 = gimple_cond_rhs (bb_last_stmt); ++ ++ if (TREE_CODE (op0) == SSA_NAME ++ && TREE_CODE (TREE_TYPE (op0)) == BOOLEAN_TYPE ++ && TREE_CODE (op1) == INTEGER_CST ++ && ((gimple_cond_code (bb_last_stmt) == NE_EXPR) ++ || (gimple_cond_code (bb_last_stmt) == EQ_EXPR))) ++ { ++ stmt = SSA_NAME_DEF_STMT (op0); ++ if (stmt && gimple_code (stmt) == GIMPLE_ASSIGN) ++ { ++ return ccmp_candidate_p (stmt); ++ } ++ } ++ } ++ return false; ++} ++ + /* Extract the comparison we want to do from the tree. */ + void + get_compare_parts (tree t, int *up, rtx_code *rcode, +diff --git a/gcc/ccmp.h b/gcc/ccmp.h +index 199dd581d..ac862f0f6 100644 +--- a/gcc/ccmp.h ++++ b/gcc/ccmp.h +@@ -21,5 +21,6 @@ along with GCC; see the file COPYING3. If not see + #define GCC_CCMP_H + + extern rtx expand_ccmp_expr (gimple *, machine_mode); ++extern bool check_ccmp_candidate (basic_block bb); + + #endif /* GCC_CCMP_H */ +diff --git a/gcc/common.opt b/gcc/common.opt +index 24834cf60..4dd566def 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -1942,6 +1942,10 @@ fira-verbose= + Common RejectNegative Joined UInteger Var(flag_ira_verbose) Init(5) + -fira-verbose=<number> Control IRA's level of diagnostic messages. + ++fccmp2 ++Common Report Var(flag_ccmp2) Init(0) Optimization ++Optimize potential ccmp instruction in complex scenarios. ++ + fivopts + Common Report Var(flag_ivopts) Init(1) Optimization + Optimize induction variables on trees. +diff --git a/gcc/testsuite/gcc.target/aarch64/ccmp_3.c b/gcc/testsuite/gcc.target/aarch64/ccmp_3.c +new file mode 100644 +index 000000000..b509ba810 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/ccmp_3.c +@@ -0,0 +1,15 @@ ++/* { dg-do compile { target { aarch64*-*-linux* } } } */ ++/* { dg-options "-O -fdump-rtl-expand-details -fccmp2" } */ ++ ++int func (int a, int b, int c) ++{ ++ while(1) ++ { ++ if(a-- == 0 || b >= c) ++ { ++ return 1; ++ } ++ } ++} ++ ++/* { dg-final { scan-assembler-times "\tccmp\t" 1} } */ +diff --git a/gcc/tree-ssa-coalesce.c b/gcc/tree-ssa-coalesce.c +index 0b0b1b18d..e0120a4a4 100644 +--- a/gcc/tree-ssa-coalesce.c ++++ b/gcc/tree-ssa-coalesce.c +@@ -38,6 +38,9 @@ along with GCC; see the file COPYING3. If not see + #include "explow.h" + #include "tree-dfa.h" + #include "stor-layout.h" ++#include "ccmp.h" ++#include "target.h" ++#include "tree-outof-ssa.h" + + /* This set of routines implements a coalesce_list. This is an object which + is used to track pairs of ssa_names which are desirable to coalesce +@@ -854,6 +857,198 @@ live_track_clear_base_vars (live_track *ptr) + bitmap_clear (&ptr->live_base_var); + } + ++/* Return true if gimple is a copy assignment. */ ++ ++static inline bool ++gimple_is_assign_copy_p (gimple *gs) ++{ ++ return (is_gimple_assign (gs) && gimple_assign_copy_p (gs) ++ && TREE_CODE (gimple_assign_lhs (gs)) == SSA_NAME ++ && TREE_CODE (gimple_assign_rhs1 (gs)) == SSA_NAME); ++} ++ ++#define MAX_CCMP_CONFLICT_NUM 5 ++ ++/* Clear high-cost conflict graphs. */ ++ ++static void ++remove_high_cost_graph_for_ccmp (ssa_conflicts *conflict_graph) ++{ ++ unsigned x = 0; ++ int add_conflict_num = 0; ++ bitmap b; ++ FOR_EACH_VEC_ELT (conflict_graph->conflicts, x, b) ++ { ++ if (b) ++ { ++ add_conflict_num++; ++ } ++ } ++ if (add_conflict_num >= MAX_CCMP_CONFLICT_NUM) ++ { ++ conflict_graph->conflicts.release (); ++ } ++} ++ ++/* Adding a new conflict graph to the original graph. */ ++ ++static void ++process_add_graph (live_track *live, basic_block bb, ++ ssa_conflicts *conflict_graph) ++{ ++ tree use, def; ++ ssa_op_iter iter; ++ gimple *first_visit_stmt = NULL; ++ for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); ++ gsi_next (&gsi)) ++ { ++ if (gimple_visited_p (gsi_stmt (gsi))) ++ { ++ first_visit_stmt = gsi_stmt (gsi); ++ break; ++ } ++ } ++ if (!first_visit_stmt) ++ return; ++ ++ for (gimple_stmt_iterator gsi = gsi_last_bb (bb); ++ gsi_stmt (gsi) != first_visit_stmt; gsi_prev (&gsi)) ++ { ++ gimple *stmt = gsi_stmt (gsi); ++ if (gimple_visited_p (gsi_stmt (gsi)) && is_gimple_debug (stmt)) ++ { ++ continue; ++ } ++ if (gimple_is_assign_copy_p (stmt)) ++ { ++ live_track_clear_var (live, gimple_assign_rhs1 (stmt)); ++ } ++ FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF) ++ { ++ live_track_process_def (live, def, conflict_graph); ++ } ++ FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE) ++ { ++ live_track_process_use (live, use); ++ } ++ } ++} ++ ++/* Build a conflict graph based on ccmp candidate. */ ++ ++static void ++add_ccmp_conflict_graph (ssa_conflicts *conflict_graph, ++ tree_live_info_p liveinfo, var_map map, basic_block bb) ++{ ++ live_track *live; ++ tree use, def; ++ ssa_op_iter iter; ++ live = new_live_track (map); ++ live_track_init (live, live_on_exit (liveinfo, bb)); ++ ++ gimple *last_stmt = gsi_stmt (gsi_last_bb (bb)); ++ gcc_assert (gimple_cond_lhs (last_stmt)); ++ ++ auto_vec<tree> stack; ++ stack.safe_push (gimple_cond_lhs (last_stmt)); ++ while (!stack.is_empty ()) ++ { ++ tree op = stack.pop (); ++ gimple *op_stmt = SSA_NAME_DEF_STMT (op); ++ if (!op_stmt || gimple_bb (op_stmt) != bb ++ || !is_gimple_assign (op_stmt) ++ || !ssa_is_replaceable_p (op_stmt)) ++ { ++ continue; ++ } ++ if (gimple_is_assign_copy_p (op_stmt)) ++ { ++ live_track_clear_var (live, gimple_assign_rhs1 (op_stmt)); ++ } ++ gimple_set_visited (op_stmt, true); ++ FOR_EACH_SSA_TREE_OPERAND (def, op_stmt, iter, SSA_OP_DEF) ++ { ++ live_track_process_def (live, def, conflict_graph); ++ } ++ FOR_EACH_SSA_TREE_OPERAND (use, op_stmt, iter, SSA_OP_USE) ++ { ++ stack.safe_push (use); ++ live_track_process_use (live, use); ++ } ++ } ++ ++ process_add_graph (live, bb, conflict_graph); ++ delete_live_track (live); ++ remove_high_cost_graph_for_ccmp (conflict_graph); ++} ++ ++/* Determine whether the ccmp conflict graph can be added. ++ i.e, ++ ++ ;; basic block 3, loop depth 1 ++ ;; pred: 2 ++ ;; 3 ++ # ivtmp.5_10 = PHI <ivtmp.5_12 (2), ivtmp.5_11 (3)> ++ _7 = b_4 (D) >= c_5 (D); ++ _8 = ivtmp.5_10 == 0; ++ _9 = _7 | _8; ++ ivtmp.5_11 = ivtmp.5_10 - 1; ++ if (_9 != 0) ++ goto <bb 4>; [10.70%] ++ else ++ goto <bb 3>; [89.30%] ++ ++ In the above loop, the expression will be replaced: ++ ++ _7 replaced by b_4 (D) >= c_5 (D) ++ _8 replaced by ivtmp.5_10 == 0 ++ ++ If the current case want use the ccmp instruction, then ++ ++ _9 can replaced by _7 | _8 ++ ++ So this requires that ivtmp.5_11 and ivtmp.5_10 be divided into different ++ partitions. ++ ++ Now this function can achieve this ability. */ ++ ++static void ++determine_add_ccmp_conflict_graph (basic_block bb, tree_live_info_p liveinfo, ++ var_map map, ssa_conflicts *graph) ++{ ++ if (!flag_ccmp2 || !targetm.gen_ccmp_first || !check_ccmp_candidate (bb)) ++ return; ++ for (gimple_stmt_iterator bsi = gsi_start_bb (bb); !gsi_end_p (bsi); ++ gsi_next (&bsi)) ++ { ++ gimple_set_visited (gsi_stmt (bsi), false); ++ } ++ ssa_conflicts *ccmp_conflict_graph; ++ ccmp_conflict_graph = ssa_conflicts_new (num_var_partitions (map)); ++ add_ccmp_conflict_graph (ccmp_conflict_graph, liveinfo, map, bb); ++ unsigned x; ++ bitmap b; ++ if (ccmp_conflict_graph) ++ { ++ FOR_EACH_VEC_ELT (ccmp_conflict_graph->conflicts, x, b) ++ { ++ if (!b) ++ continue; ++ unsigned y = bitmap_first_set_bit (b); ++ if (!graph->conflicts[x] || !bitmap_bit_p (graph->conflicts[x], y)) ++ { ++ ssa_conflicts_add (graph, x, y); ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "potential ccmp: add additional " ++ "conflict-ssa : bb[%d] %d:%d\n", ++ bb->index, x, y); ++ } ++ } ++ } ++ } ++ ssa_conflicts_delete (ccmp_conflict_graph); ++} + + /* Build a conflict graph based on LIVEINFO. Any partitions which are in the + partition view of the var_map liveinfo is based on get entries in the +@@ -938,6 +1133,8 @@ build_ssa_conflict_graph (tree_live_info_p liveinfo) + live_track_process_use (live, var); + } + ++ determine_add_ccmp_conflict_graph (bb, liveinfo, map, graph); ++ + /* If result of a PHI is unused, looping over the statements will not + record any conflicts since the def was never live. Since the PHI node + is going to be translated out of SSA form, it will insert a copy. +-- +2.27.0.windows.1 + diff --git a/0036-StructReorg-Refactoring-reorder-fields-to-struct-lay.patch b/0036-StructReorg-Refactoring-reorder-fields-to-struct-lay.patch new file mode 100644 index 0000000..41d01f7 --- /dev/null +++ b/0036-StructReorg-Refactoring-reorder-fields-to-struct-lay.patch @@ -0,0 +1,1115 @@ +From 3c06a2cda7220a48866ae2dbe3f365e300cbaeca Mon Sep 17 00:00:00 2001 +From: liyancheng <412998149@qq.com> +Date: Wed, 1 Jun 2022 17:22:12 +0800 +Subject: [PATCH 02/12] [StructReorg] Refactoring reorder fields to struct + layout optimization + +Refactor the reorder_fields optimization into struct layout optimization. Add +flag -fipa-struct-reorg=[0,1,2] to enable none, strcut reorg, reorder fields +optimizations. +--- + gcc/common.opt | 6 +- + gcc/ipa-struct-reorg/ipa-struct-reorg.c | 167 +++++++++--------- + gcc/ipa-struct-reorg/ipa-struct-reorg.h | 2 +- + gcc/opts.c | 12 ++ + gcc/passes.def | 2 +- + gcc/symbol-summary.h | 4 +- + .../struct/rf_DTE_struct_instance_field.c | 2 +- + gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c | 2 +- + .../gcc.dg/struct/rf_check_ptr_layers_bug.c | 2 +- + .../gcc.dg/struct/rf_create_fields_bug.c | 2 +- + .../gcc.dg/struct/rf_create_new_func_bug.c | 2 +- + .../gcc.dg/struct/rf_ele_minus_verify.c | 2 +- + .../gcc.dg/struct/rf_escape_by_base.c | 2 +- + gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c | 2 +- + .../gcc.dg/struct/rf_mem_ref_offset.c | 2 +- + .../struct/rf_mul_layer_ptr_record_bug.c | 2 +- + .../gcc.dg/struct/rf_pass_conflict.c | 2 +- + gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c | 2 +- + gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c | 2 +- + .../gcc.dg/struct/rf_ptr_negate_expr.c | 2 +- + gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c | 2 +- + gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c | 2 +- + gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c | 2 +- + .../gcc.dg/struct/rf_rescusive_type.c | 2 +- + .../struct/rf_rewrite_assign_more_cmp.c | 2 +- + .../gcc.dg/struct/rf_rewrite_cond_bug.c | 2 +- + .../gcc.dg/struct/rf_rewrite_cond_more_cmp.c | 2 +- + .../gcc.dg/struct/rf_rewrite_phi_bug.c | 2 +- + gcc/testsuite/gcc.dg/struct/rf_visible_func.c | 2 +- + .../gcc.dg/struct/rf_void_ptr_param_func.c | 2 +- + .../gcc.dg/struct/sr_pointer_minus.c | 2 +- + gcc/testsuite/gcc.dg/struct/struct-reorg.exp | 19 ++ + gcc/timevar.def | 2 +- + gcc/tree-pass.h | 2 +- + gcc/tree.c | 4 +- + 35 files changed, 153 insertions(+), 117 deletions(-) + +diff --git a/gcc/common.opt b/gcc/common.opt +index 4dd566def..7fc075d35 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -1876,13 +1876,17 @@ Common Ignore + Does nothing. Preserved for backward compatibility. + + fipa-reorder-fields +-Common Report Var(flag_ipa_reorder_fields) Init(0) Optimization ++Common Report Var(flag_ipa_struct_layout) Init(0) Optimization + Perform structure fields reorder optimizations. + + fipa-struct-reorg + Common Report Var(flag_ipa_struct_reorg) Init(0) Optimization + Perform structure layout optimizations. + ++fipa-struct-reorg= ++Common RejectNegative Joined UInteger Var(struct_layout_optimize_level) Init(0) IntegerRange(0, 2) ++-fipa-struct-reorg=[0,1,2] adding none, struct-reorg, reorder-fields optimizations. ++ + fipa-extend-auto-profile + Common Report Var(flag_ipa_extend_auto_profile) + Use sample profile information for source code. +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +index 2bf41e0d8..9214ee74a 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -235,7 +235,7 @@ enum srmode + { + NORMAL = 0, + COMPLETE_STRUCT_RELAYOUT, +- STRUCT_REORDER_FIELDS ++ STRUCT_LAYOUT_OPTIMIZE + }; + + static bool is_result_of_mult (tree arg, tree *num, tree struct_size); +@@ -552,7 +552,7 @@ void + srtype::simple_dump (FILE *f) + { + print_generic_expr (f, type); +- if (current_mode == STRUCT_REORDER_FIELDS) ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE) + { + fprintf (f, "(%d)", TYPE_UID (type)); + } +@@ -593,9 +593,9 @@ srfield::create_new_fields (tree newtype[max_split], + tree newfields[max_split], + tree newlast[max_split]) + { +- if (current_mode == STRUCT_REORDER_FIELDS) ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE) + { +- create_new_reorder_fields (newtype, newfields, newlast); ++ create_new_optimized_fields (newtype, newfields, newlast); + return; + } + +@@ -689,15 +689,15 @@ srfield::reorder_fields (tree newfields[max_split], tree newlast[max_split], + } + } + +-/* Create the new reorder fields for this field. ++/* Create the new optimized fields for this field. + newtype[max_split]: srtype's member variable, + newfields[max_split]: created by create_new_type func, + newlast[max_split]: created by create_new_type func. */ + + void +-srfield::create_new_reorder_fields (tree newtype[max_split], +- tree newfields[max_split], +- tree newlast[max_split]) ++srfield::create_new_optimized_fields (tree newtype[max_split], ++ tree newfields[max_split], ++ tree newlast[max_split]) + { + /* newtype, corresponding to newtype[max_split] in srtype. */ + tree nt = NULL_TREE; +@@ -794,7 +794,7 @@ srtype::create_new_type (void) + we are not splitting the struct into two clusters, + then just return false and don't change the type. */ + if (!createnewtype && maxclusters == 0 +- && current_mode != STRUCT_REORDER_FIELDS) ++ && current_mode != STRUCT_LAYOUT_OPTIMIZE) + { + newtype[0] = type; + return false; +@@ -822,8 +822,8 @@ srtype::create_new_type (void) + sprintf(id, "%d", i); + if (tname) + { +- name = concat (tname, current_mode == STRUCT_REORDER_FIELDS +- ? ".reorder." : ".reorg.", id, NULL); ++ name = concat (tname, current_mode == STRUCT_LAYOUT_OPTIMIZE ++ ? ".slo." : ".reorg.", id, NULL); + TYPE_NAME (newtype[i]) = build_decl (UNKNOWN_LOCATION, TYPE_DECL, + get_identifier (name), newtype[i]); + free (name); +@@ -969,8 +969,8 @@ srfunction::create_new_decls (void) + sprintf(id, "%d", j); + if (tname) + { +- name = concat (tname, current_mode == STRUCT_REORDER_FIELDS +- ? ".reorder." : ".reorg.", id, NULL); ++ name = concat (tname, current_mode == STRUCT_LAYOUT_OPTIMIZE ++ ? ".slo." : ".reorg.", id, NULL); + new_name = get_identifier (name); + free (name); + } +@@ -2718,7 +2718,7 @@ escape_type escape_type_volatile_array_or_ptrptr (tree type) + return escape_volatile; + if (isarraytype (type)) + return escape_array; +- if (isptrptr (type) && (current_mode != STRUCT_REORDER_FIELDS)) ++ if (isptrptr (type) && (current_mode != STRUCT_LAYOUT_OPTIMIZE)) + return escape_ptr_ptr; + return does_not_escape; + } +@@ -2740,13 +2740,13 @@ ipa_struct_reorg::record_field_type (tree field, srtype *base_srtype) + field_srtype->add_field_site (field_srfield); + } + if (field_srtype == base_srtype && current_mode != COMPLETE_STRUCT_RELAYOUT +- && current_mode != STRUCT_REORDER_FIELDS) ++ && current_mode != STRUCT_LAYOUT_OPTIMIZE) + { + base_srtype->mark_escape (escape_rescusive_type, NULL); + } + /* Types of non-pointer field are difficult to track the correctness + of the rewrite when it used by the escaped type. */ +- if (current_mode == STRUCT_REORDER_FIELDS ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE + && TREE_CODE (field_type) == RECORD_TYPE) + { + field_srtype->mark_escape (escape_instance_field, NULL); +@@ -2781,7 +2781,7 @@ ipa_struct_reorg::record_struct_field_types (tree base_type, + } + /* Types of non-pointer field are difficult to track the correctness + of the rewrite when it used by the escaped type. */ +- if (current_mode == STRUCT_REORDER_FIELDS ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE + && TREE_CODE (field_type) == RECORD_TYPE) + { + base_srtype->mark_escape (escape_instance_field, NULL); +@@ -2966,7 +2966,7 @@ ipa_struct_reorg::record_var (tree decl, escape_type escapes, int arg) + /* Separate instance is hard to trace in complete struct + relayout optimization. */ + if ((current_mode == COMPLETE_STRUCT_RELAYOUT +- || current_mode == STRUCT_REORDER_FIELDS) ++ || current_mode == STRUCT_LAYOUT_OPTIMIZE) + && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE) + { + e = escape_separate_instance; +@@ -3071,7 +3071,7 @@ ipa_struct_reorg::find_vars (gimple *stmt) + /* Add a safe func mechanism. */ + bool l_find = true; + bool r_find = true; +- if (current_mode == STRUCT_REORDER_FIELDS) ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE) + { + l_find = !(current_function->is_safe_func + && TREE_CODE (lhs) == SSA_NAME +@@ -3117,7 +3117,7 @@ ipa_struct_reorg::find_vars (gimple *stmt) + } + } + } +- else if ((current_mode == STRUCT_REORDER_FIELDS) ++ else if ((current_mode == STRUCT_LAYOUT_OPTIMIZE) + && (gimple_assign_rhs_code (stmt) == LE_EXPR + || gimple_assign_rhs_code (stmt) == LT_EXPR + || gimple_assign_rhs_code (stmt) == GE_EXPR +@@ -3128,7 +3128,7 @@ ipa_struct_reorg::find_vars (gimple *stmt) + find_var (gimple_assign_rhs2 (stmt), stmt); + } + /* find void ssa_name from stmt such as: _2 = _1 - old_arcs_1. */ +- else if ((current_mode == STRUCT_REORDER_FIELDS) ++ else if ((current_mode == STRUCT_LAYOUT_OPTIMIZE) + && gimple_assign_rhs_code (stmt) == POINTER_DIFF_EXPR + && types_compatible_p ( + TYPE_MAIN_VARIANT (TREE_TYPE (gimple_assign_rhs1 (stmt))), +@@ -3391,11 +3391,12 @@ is_result_of_mult (tree arg, tree *num, tree struct_size) + arg = gimple_assign_rhs1 (size_def_stmt); + size_def_stmt = SSA_NAME_DEF_STMT (arg); + } +- else if (rhs_code == NEGATE_EXPR && current_mode == STRUCT_REORDER_FIELDS) ++ else if (rhs_code == NEGATE_EXPR ++ && current_mode == STRUCT_LAYOUT_OPTIMIZE) + { + return trace_calculate_negate (size_def_stmt, num, struct_size); + } +- else if (rhs_code == NOP_EXPR && current_mode == STRUCT_REORDER_FIELDS) ++ else if (rhs_code == NOP_EXPR && current_mode == STRUCT_LAYOUT_OPTIMIZE) + { + return trace_calculate_diff (size_def_stmt, num); + } +@@ -3415,7 +3416,7 @@ is_result_of_mult (tree arg, tree *num, tree struct_size) + bool + ipa_struct_reorg::handled_allocation_stmt (gimple *stmt) + { +- if ((current_mode == STRUCT_REORDER_FIELDS) ++ if ((current_mode == STRUCT_LAYOUT_OPTIMIZE) + && (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC) + || gimple_call_builtin_p (stmt, BUILT_IN_MALLOC) + || gimple_call_builtin_p (stmt, BUILT_IN_CALLOC))) +@@ -3548,7 +3549,7 @@ ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other, gimple + /* x_1 = y.x_nodes; void *x; + Directly mark the structure pointer type assigned + to the void* variable as escape. */ +- else if (current_mode == STRUCT_REORDER_FIELDS ++ else if (current_mode == STRUCT_LAYOUT_OPTIMIZE + && TREE_CODE (side) == SSA_NAME + && VOID_POINTER_P (TREE_TYPE (side)) + && SSA_NAME_VAR (side) +@@ -3815,7 +3816,7 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, + and doesn't mark escape follow.). */ + /* _1 = MEM[(struct arc_t * *)a_1]. + then base a_1: ssa_name - pointer_type - integer_type. */ +- if (current_mode == STRUCT_REORDER_FIELDS) ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE) + { + bool is_int_ptr = POINTER_TYPE_P (TREE_TYPE (base)) + && (TREE_CODE (inner_type (TREE_TYPE (base))) +@@ -4031,7 +4032,7 @@ ipa_struct_reorg::maybe_record_call (cgraph_node *node, gcall *stmt) + /* callee_func (_1, _2); + Check the callee func, instead of current func. */ + if (!(free_or_realloc +- || (current_mode == STRUCT_REORDER_FIELDS ++ || (current_mode == STRUCT_LAYOUT_OPTIMIZE + && safe_functions.contains ( + node->get_edge (stmt)->callee))) + && VOID_POINTER_P (argtypet)) +@@ -4063,9 +4064,9 @@ ipa_struct_reorg::record_stmt_expr (tree expr, cgraph_node *node, gimple *stmt) + realpart, imagpart, address, escape_from_base)) + return; + +- if (current_mode == STRUCT_REORDER_FIELDS) ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE) + { +- if (!opt_for_fn (current_function_decl, flag_ipa_reorder_fields)) ++ if (!opt_for_fn (current_function_decl, flag_ipa_struct_layout)) + { + type->mark_escape (escape_non_optimize, stmt); + } +@@ -4287,7 +4288,7 @@ ipa_struct_reorg::check_definition_call (srdecl *decl, vec<srdecl*> &worklist) + check_type_and_push (gimple_call_arg (stmt, 0), decl, worklist, stmt); + } + +- if (current_mode == STRUCT_REORDER_FIELDS) ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE) + { + if (!handled_allocation_stmt (stmt)) + { +@@ -4341,7 +4342,7 @@ ipa_struct_reorg::check_definition (srdecl *decl, vec<srdecl*> &worklist) + } + return; + } +- if (current_mode == STRUCT_REORDER_FIELDS && SSA_NAME_VAR (ssa_name) ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE && SSA_NAME_VAR (ssa_name) + && VOID_POINTER_P (TREE_TYPE (SSA_NAME_VAR (ssa_name)))) + { + type->mark_escape (escape_cast_void, SSA_NAME_DEF_STMT (ssa_name)); +@@ -4442,7 +4443,7 @@ ipa_struct_reorg::check_other_side (srdecl *decl, tree other, gimple *stmt, vec< + if (!get_type_field (other, base, indirect, type1, field, + realpart, imagpart, address, escape_from_base)) + { +- if (current_mode == STRUCT_REORDER_FIELDS) ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE) + { + /* release INTEGER_TYPE cast to struct pointer. */ + bool cast_from_int_ptr = current_function->is_safe_func && base +@@ -4498,7 +4499,7 @@ get_base (tree &base, tree expr) + void + ipa_struct_reorg::check_ptr_layers (tree a_expr, tree b_expr, gimple* stmt) + { +- if (current_mode != STRUCT_REORDER_FIELDS || current_function->is_safe_func ++ if (current_mode != STRUCT_LAYOUT_OPTIMIZE || current_function->is_safe_func + || !(POINTER_TYPE_P (TREE_TYPE (a_expr))) + || !(POINTER_TYPE_P (TREE_TYPE (b_expr))) + || !handled_type (TREE_TYPE (a_expr)) +@@ -4579,7 +4580,7 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist) + && (code != EQ_EXPR && code != NE_EXPR + && code != LT_EXPR && code != LE_EXPR + && code != GT_EXPR && code != GE_EXPR)) +- || (current_mode == STRUCT_REORDER_FIELDS ++ || (current_mode == STRUCT_LAYOUT_OPTIMIZE + && (code != EQ_EXPR && code != NE_EXPR + && code != LT_EXPR && code != LE_EXPR + && code != GT_EXPR && code != GE_EXPR))) +@@ -4618,7 +4619,7 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist) + && (code != EQ_EXPR && code != NE_EXPR + && code != LT_EXPR && code != LE_EXPR + && code != GT_EXPR && code != GE_EXPR)) +- || (current_mode == STRUCT_REORDER_FIELDS ++ || (current_mode == STRUCT_LAYOUT_OPTIMIZE + && (code != EQ_EXPR && code != NE_EXPR + && code != LT_EXPR && code != LE_EXPR + && code != GT_EXPR && code != GE_EXPR))) +@@ -4740,11 +4741,11 @@ ipa_struct_reorg::record_function (cgraph_node *node) + escapes = escape_marked_as_used; + else if (!node->local) + { +- if (current_mode != STRUCT_REORDER_FIELDS) ++ if (current_mode != STRUCT_LAYOUT_OPTIMIZE) + { + escapes = escape_visible_function; + } +- if (current_mode == STRUCT_REORDER_FIELDS && node->externally_visible) ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE && node->externally_visible) + { + escapes = escape_visible_function; + } +@@ -4754,9 +4755,9 @@ ipa_struct_reorg::record_function (cgraph_node *node) + else if (!tree_versionable_function_p (node->decl)) + escapes = escape_noclonable_function; + +- if (current_mode == STRUCT_REORDER_FIELDS) ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE) + { +- if (!opt_for_fn (node->decl, flag_ipa_reorder_fields)) ++ if (!opt_for_fn (node->decl, flag_ipa_struct_layout)) + { + escapes = escape_non_optimize; + } +@@ -4773,7 +4774,7 @@ ipa_struct_reorg::record_function (cgraph_node *node) + gimple_stmt_iterator si; + + /* Add a safe func mechanism. */ +- if (current_mode == STRUCT_REORDER_FIELDS) ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE) + { + current_function->is_safe_func = safe_functions.contains (node); + if (dump_file) +@@ -4989,7 +4990,7 @@ ipa_struct_reorg::record_accesses (void) + } + + /* Add a safe func mechanism. */ +- if (current_mode == STRUCT_REORDER_FIELDS) ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE) + { + record_safe_func_with_void_ptr_parm (); + } +@@ -5188,7 +5189,7 @@ void + ipa_struct_reorg::prune_escaped_types (void) + { + if (current_mode != COMPLETE_STRUCT_RELAYOUT +- && current_mode != STRUCT_REORDER_FIELDS) ++ && current_mode != STRUCT_LAYOUT_OPTIMIZE) + { + /* Detect recusive types and mark them as escaping. */ + detect_cycles (); +@@ -5196,7 +5197,7 @@ ipa_struct_reorg::prune_escaped_types (void) + mark them as escaping. */ + propagate_escape (); + } +- if (current_mode == STRUCT_REORDER_FIELDS) ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE) + { + propagate_escape_via_original (); + propagate_escape_via_empty_with_no_original (); +@@ -5256,7 +5257,7 @@ ipa_struct_reorg::prune_escaped_types (void) + if (function->args.is_empty () + && function->decls.is_empty () + && function->globals.is_empty () +- && current_mode != STRUCT_REORDER_FIELDS) ++ && current_mode != STRUCT_LAYOUT_OPTIMIZE) + { + delete function; + functions.ordered_remove (i); +@@ -5281,10 +5282,10 @@ ipa_struct_reorg::prune_escaped_types (void) + + /* Prune types that escape, all references to those types + will have been removed in the above loops. */ +- /* The escape type is not deleted in STRUCT_REORDER_FIELDS, ++ /* The escape type is not deleted in STRUCT_LAYOUT_OPTIMIZE, + Then the type that contains the escaped type fields + can find complete information. */ +- if (current_mode != STRUCT_REORDER_FIELDS) ++ if (current_mode != STRUCT_LAYOUT_OPTIMIZE) + { + for (unsigned i = 0; i < types.length ();) + { +@@ -5334,7 +5335,7 @@ ipa_struct_reorg::create_new_types (void) + for (unsigned i = 0; i < types.length (); i++) + newtypes += types[i]->create_new_type (); + +- if (current_mode == STRUCT_REORDER_FIELDS) ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE) + { + for (unsigned i = 0; i < types.length (); i++) + { +@@ -5458,8 +5459,8 @@ ipa_struct_reorg::create_new_args (cgraph_node *new_node) + char *name = NULL; + if (tname) + { +- name = concat (tname, current_mode == STRUCT_REORDER_FIELDS +- ? ".reorder.0" : ".reorg.0", NULL); ++ name = concat (tname, current_mode == STRUCT_LAYOUT_OPTIMIZE ++ ? ".slo.0" : ".reorg.0", NULL); + new_name = get_identifier (name); + free (name); + } +@@ -5547,8 +5548,8 @@ ipa_struct_reorg::create_new_functions (void) + statistics_counter_event (NULL, "Create new function", 1); + new_node = node->create_version_clone_with_body ( + vNULL, NULL, NULL, NULL, NULL, +- current_mode == STRUCT_REORDER_FIELDS +- ? "struct_reorder" : "struct_reorg"); ++ current_mode == STRUCT_LAYOUT_OPTIMIZE ++ ? "slo" : "struct_reorg"); + new_node->can_change_signature = node->can_change_signature; + new_node->make_local (); + f->newnode = new_node; +@@ -5666,13 +5667,13 @@ ipa_struct_reorg::rewrite_expr (tree expr, tree newexpr[max_split], bool ignore_ + newbase1 = build_fold_addr_expr (newbase1); + if (indirect) + { +- if (current_mode == STRUCT_REORDER_FIELDS) ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE) + { + /* Supports the MEM_REF offset. + _1 = MEM[(struct arc *)ap_1 + 72B].flow; +- Old rewrite: _1 = ap.reorder.0_8->flow; ++ Old rewrite: _1 = ap.slo.0_8->flow; + New rewrite: _1 +- = MEM[(struct arc.reorder.0 *)ap.reorder.0_8 + 64B].flow; ++ = MEM[(struct arc.slo.0 *)ap.slo.0_8 + 64B].flow; + */ + HOST_WIDE_INT offset_tmp = 0; + HOST_WIDE_INT mem_offset = 0; +@@ -5738,10 +5739,10 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + return remove; + } + +- if ((current_mode != STRUCT_REORDER_FIELDS ++ if ((current_mode != STRUCT_LAYOUT_OPTIMIZE + && (gimple_assign_rhs_code (stmt) == EQ_EXPR + || gimple_assign_rhs_code (stmt) == NE_EXPR)) +- || (current_mode == STRUCT_REORDER_FIELDS ++ || (current_mode == STRUCT_LAYOUT_OPTIMIZE + && (TREE_CODE_CLASS (gimple_assign_rhs_code (stmt)) + == tcc_comparison))) + { +@@ -5751,7 +5752,7 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + tree newrhs2[max_split]; + tree_code rhs_code = gimple_assign_rhs_code (stmt); + tree_code code = rhs_code == EQ_EXPR ? BIT_AND_EXPR : BIT_IOR_EXPR; +- if (current_mode == STRUCT_REORDER_FIELDS ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE + && rhs_code != EQ_EXPR && rhs_code != NE_EXPR) + { + code = rhs_code; +@@ -5798,8 +5799,8 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + _6 = _4 + _5; + _5 = (long unsigned int) _3; + _3 = _1 - old_2. */ +- if (current_mode != STRUCT_REORDER_FIELDS +- || (current_mode == STRUCT_REORDER_FIELDS && (num != NULL))) ++ if (current_mode != STRUCT_LAYOUT_OPTIMIZE ++ || (current_mode == STRUCT_LAYOUT_OPTIMIZE && (num != NULL))) + { + num = gimplify_build1 (gsi, NOP_EXPR, sizetype, num); + } +@@ -5827,7 +5828,7 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + } + + /* Support POINTER_DIFF_EXPR rewriting. */ +- if (current_mode == STRUCT_REORDER_FIELDS ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE + && gimple_assign_rhs_code (stmt) == POINTER_DIFF_EXPR) + { + tree rhs1 = gimple_assign_rhs1 (stmt); +@@ -6014,7 +6015,7 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi) + srfunction *f = find_function (node); + + /* Add a safe func mechanism. */ +- if (current_mode == STRUCT_REORDER_FIELDS && f && f->is_safe_func) ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE && f && f->is_safe_func) + { + tree expr = gimple_call_arg (stmt, 0); + tree newexpr[max_split]; +@@ -6141,9 +6142,9 @@ ipa_struct_reorg::rewrite_cond (gcond *stmt, gimple_stmt_iterator *gsi) + tree_code rhs_code = gimple_cond_code (stmt); + + /* Handle only equals or not equals conditionals. */ +- if ((current_mode != STRUCT_REORDER_FIELDS ++ if ((current_mode != STRUCT_LAYOUT_OPTIMIZE + && (rhs_code != EQ_EXPR && rhs_code != NE_EXPR)) +- || (current_mode == STRUCT_REORDER_FIELDS ++ || (current_mode == STRUCT_LAYOUT_OPTIMIZE + && TREE_CODE_CLASS (rhs_code) != tcc_comparison)) + return false; + tree lhs = gimple_cond_lhs (stmt); +@@ -6171,10 +6172,10 @@ ipa_struct_reorg::rewrite_cond (gcond *stmt, gimple_stmt_iterator *gsi) + } + + /* Old rewrite: if (x_1 != 0B) +- -> _1 = x.reorder.0_1 != 0B; if (_1 != 1) ++ -> _1 = x.slo.0_1 != 0B; if (_1 != 1) + The logic is incorrect. + New rewrite: if (x_1 != 0B) +- -> if (x.reorder.0_1 != 0B);*/ ++ -> if (x.slo.0_1 != 0B);*/ + for (unsigned i = 0; i < max_split && (newlhs[i] || newrhs[i]); i++) + { + if (newlhs[i]) +@@ -6203,7 +6204,7 @@ ipa_struct_reorg::rewrite_cond (gcond *stmt, gimple_stmt_iterator *gsi) + bool + ipa_struct_reorg::rewrite_debug (gimple *stmt, gimple_stmt_iterator *) + { +- if (current_mode == STRUCT_REORDER_FIELDS) ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE) + { + /* Delete debug gimple now. */ + return true; +@@ -6367,7 +6368,7 @@ ipa_struct_reorg::rewrite_functions (void) + then don't rewrite any accesses. */ + if (!create_new_types ()) + { +- if (current_mode == STRUCT_REORDER_FIELDS) ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE) + { + for (unsigned i = 0; i < functions.length (); i++) + { +@@ -6386,7 +6387,7 @@ ipa_struct_reorg::rewrite_functions (void) + return 0; + } + +- if (current_mode == STRUCT_REORDER_FIELDS && dump_file) ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE && dump_file) + { + fprintf (dump_file, "=========== all created newtypes: ===========\n\n"); + dump_newtypes (dump_file); +@@ -6396,13 +6397,13 @@ ipa_struct_reorg::rewrite_functions (void) + { + retval = TODO_remove_functions; + create_new_functions (); +- if (current_mode == STRUCT_REORDER_FIELDS) ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE) + { + prune_escaped_types (); + } + } + +- if (current_mode == STRUCT_REORDER_FIELDS) ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE) + { + for (unsigned i = 0; i < functions.length (); i++) + { +@@ -6572,7 +6573,7 @@ ipa_struct_reorg::execute (enum srmode mode) + { + unsigned int ret = 0; + +- if (mode == NORMAL || mode == STRUCT_REORDER_FIELDS) ++ if (mode == NORMAL || mode == STRUCT_LAYOUT_OPTIMIZE) + { + current_mode = mode; + /* If there is a top-level inline-asm, +@@ -6660,12 +6661,12 @@ pass_ipa_struct_reorg::gate (function *) + && (in_lto_p || flag_whole_program)); + } + +-const pass_data pass_data_ipa_reorder_fields = ++const pass_data pass_data_ipa_struct_layout = + { + SIMPLE_IPA_PASS, // type +- "reorder_fields", // name ++ "struct_layout", // name + OPTGROUP_NONE, // optinfo_flags +- TV_IPA_REORDER_FIELDS, // tv_id ++ TV_IPA_STRUCT_LAYOUT, // tv_id + 0, // properties_required + 0, // properties_provided + 0, // properties_destroyed +@@ -6673,11 +6674,11 @@ const pass_data pass_data_ipa_reorder_fields = + 0, // todo_flags_finish + }; + +-class pass_ipa_reorder_fields : public simple_ipa_opt_pass ++class pass_ipa_struct_layout : public simple_ipa_opt_pass + { + public: +- pass_ipa_reorder_fields (gcc::context *ctxt) +- : simple_ipa_opt_pass (pass_data_ipa_reorder_fields, ctxt) ++ pass_ipa_struct_layout (gcc::context *ctxt) ++ : simple_ipa_opt_pass (pass_data_ipa_struct_layout, ctxt) + {} + + /* opt_pass methods: */ +@@ -6685,17 +6686,17 @@ public: + virtual unsigned int execute (function *) + { + unsigned int ret = 0; +- ret = ipa_struct_reorg ().execute (STRUCT_REORDER_FIELDS); ++ ret = ipa_struct_reorg ().execute (STRUCT_LAYOUT_OPTIMIZE); + return ret; + } + +-}; // class pass_ipa_reorder_fields ++}; // class pass_ipa_struct_layout + + bool +-pass_ipa_reorder_fields::gate (function *) ++pass_ipa_struct_layout::gate (function *) + { + return (optimize >= 3 +- && flag_ipa_reorder_fields ++ && flag_ipa_struct_layout + /* Don't bother doing anything if the program has errors. */ + && !seen_error () + && flag_lto_partition == LTO_PARTITION_ONE +@@ -6715,7 +6716,7 @@ make_pass_ipa_struct_reorg (gcc::context *ctxt) + } + + simple_ipa_opt_pass * +-make_pass_ipa_reorder_fields (gcc::context *ctxt) ++make_pass_ipa_struct_layout (gcc::context *ctxt) + { +- return new pass_ipa_reorder_fields (ctxt); ++ return new pass_ipa_struct_layout (ctxt); + } +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.h b/gcc/ipa-struct-reorg/ipa-struct-reorg.h +index 8fb6ce9c4..54b0dc655 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.h ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.h +@@ -187,7 +187,7 @@ struct srfield + tree newlast[max_split]); + void reorder_fields (tree newfields[max_split], tree newlast[max_split], + tree &field); +- void create_new_reorder_fields (tree newtype[max_split], ++ void create_new_optimized_fields (tree newtype[max_split], + tree newfields[max_split], + tree newlast[max_split]); + }; +diff --git a/gcc/opts.c b/gcc/opts.c +index 479d726df..c3877c24e 100644 +--- a/gcc/opts.c ++++ b/gcc/opts.c +@@ -2695,6 +2695,18 @@ common_handle_option (struct gcc_options *opts, + } + break; + ++ case OPT_fipa_struct_reorg_: ++ opts->x_struct_layout_optimize_level = value; ++ if (value > 1) ++ { ++ SET_OPTION_IF_UNSET (opts, opts_set, flag_ipa_struct_layout, value); ++ } ++ /* No break here - do -fipa-struct-reorg processing. */ ++ /* FALLTHRU. */ ++ case OPT_fipa_struct_reorg: ++ opts->x_flag_ipa_struct_reorg = value; ++ break; ++ + case OPT_fprofile_generate_: + opts->x_profile_data_prefix = xstrdup (arg); + value = true; +diff --git a/gcc/passes.def b/gcc/passes.def +index e9c91d26e..eea4d7808 100644 +--- a/gcc/passes.def ++++ b/gcc/passes.def +@@ -174,7 +174,7 @@ along with GCC; see the file COPYING3. If not see + INSERT_PASSES_AFTER (all_late_ipa_passes) + NEXT_PASS (pass_materialize_all_clones); + NEXT_PASS (pass_ipa_pta); +- NEXT_PASS (pass_ipa_reorder_fields); ++ NEXT_PASS (pass_ipa_struct_layout); + /* FIXME: this should a normal IP pass */ + NEXT_PASS (pass_ipa_struct_reorg); + NEXT_PASS (pass_omp_simd_clone); +diff --git a/gcc/symbol-summary.h b/gcc/symbol-summary.h +index ddf5e3577..f62222a96 100644 +--- a/gcc/symbol-summary.h ++++ b/gcc/symbol-summary.h +@@ -61,7 +61,7 @@ protected: + { + /* In structure optimizatons, we call new to ensure that + the allocated memory is initialized to 0. */ +- if (flag_ipa_reorder_fields || flag_ipa_struct_reorg) ++ if (flag_ipa_struct_layout || flag_ipa_struct_reorg) + return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T () + : new T (); + /* Call gcc_internal_because we do not want to call finalizer for +@@ -77,7 +77,7 @@ protected: + ggc_delete (item); + else + { +- if (flag_ipa_reorder_fields || flag_ipa_struct_reorg) ++ if (flag_ipa_struct_layout || flag_ipa_struct_reorg) + delete item; + else + m_allocator.remove (item); +diff --git a/gcc/testsuite/gcc.dg/struct/rf_DTE_struct_instance_field.c b/gcc/testsuite/gcc.dg/struct/rf_DTE_struct_instance_field.c +index b95be2dab..882a695b0 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_DTE_struct_instance_field.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_DTE_struct_instance_field.c +@@ -72,4 +72,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "No structures to transform." "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "No structures to transform." "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c b/gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c +index 3d243313b..20ecee545 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c +@@ -91,4 +91,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_check_ptr_layers_bug.c b/gcc/testsuite/gcc.dg/struct/rf_check_ptr_layers_bug.c +index a5477dcc9..ad879fc11 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_check_ptr_layers_bug.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_check_ptr_layers_bug.c +@@ -21,4 +21,4 @@ main() + { + g(); + } +-/* { dg-final { scan-ipa-dump "No structures to transform." "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "No structures to transform." "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_create_fields_bug.c b/gcc/testsuite/gcc.dg/struct/rf_create_fields_bug.c +index 886706ae9..f0c9d8f39 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_create_fields_bug.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_create_fields_bug.c +@@ -79,4 +79,4 @@ main() + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_create_new_func_bug.c b/gcc/testsuite/gcc.dg/struct/rf_create_new_func_bug.c +index f3785f392..fa5e6c2d0 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_create_new_func_bug.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_create_new_func_bug.c +@@ -53,4 +53,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_ele_minus_verify.c b/gcc/testsuite/gcc.dg/struct/rf_ele_minus_verify.c +index 1415d759a..2966869e7 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_ele_minus_verify.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_ele_minus_verify.c +@@ -57,4 +57,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_escape_by_base.c b/gcc/testsuite/gcc.dg/struct/rf_escape_by_base.c +index 003da0b57..b74b9e5e9 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_escape_by_base.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_escape_by_base.c +@@ -80,4 +80,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c b/gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c +index 10dcf098c..cf85c6109 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c +@@ -69,4 +69,4 @@ main() + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_mem_ref_offset.c b/gcc/testsuite/gcc.dg/struct/rf_mem_ref_offset.c +index 8d1a9a114..61fd9f755 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_mem_ref_offset.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_mem_ref_offset.c +@@ -55,4 +55,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_mul_layer_ptr_record_bug.c b/gcc/testsuite/gcc.dg/struct/rf_mul_layer_ptr_record_bug.c +index 23765fc56..2c115da02 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_mul_layer_ptr_record_bug.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_mul_layer_ptr_record_bug.c +@@ -27,4 +27,4 @@ main() { + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c b/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c +index 54e737ee8..c7646d8b7 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c +@@ -106,4 +106,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c b/gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c +index 2ae46fb31..01c000375 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c +@@ -84,4 +84,4 @@ main () + return cnt; + } + +-/* { dg-final { scan-ipa-dump "No structures to transform." "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "No structures to transform." "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c +index 3a3c10b70..f962163fe 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c +@@ -68,4 +68,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 3" "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 3" "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_negate_expr.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_negate_expr.c +index 7b7d110df..6558b1797 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_ptr_negate_expr.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_negate_expr.c +@@ -52,4 +52,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c +index 317aafa5f..6d528ed5b 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c +@@ -31,4 +31,4 @@ main () + printf (" Tree.\n"); + } + +-/* { dg-final { scan-ipa-dump "No structures to transform." "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "No structures to transform." "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c +index 01a33f669..e95cf2e5d 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c +@@ -52,4 +52,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c +index a38556533..cb4054522 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c +@@ -55,4 +55,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_rescusive_type.c b/gcc/testsuite/gcc.dg/struct/rf_rescusive_type.c +index 5c17ee528..38bddbae5 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_rescusive_type.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_rescusive_type.c +@@ -54,4 +54,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_rewrite_assign_more_cmp.c b/gcc/testsuite/gcc.dg/struct/rf_rewrite_assign_more_cmp.c +index 710517ee9..86034f042 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_rewrite_assign_more_cmp.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_rewrite_assign_more_cmp.c +@@ -62,4 +62,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_bug.c b/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_bug.c +index 6ed0a5d2d..aae7c4bc9 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_bug.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_bug.c +@@ -69,4 +69,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 3" "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 3" "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_more_cmp.c b/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_more_cmp.c +index 5a2dd964f..8672e7552 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_more_cmp.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_more_cmp.c +@@ -55,4 +55,4 @@ main() + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_rewrite_phi_bug.c b/gcc/testsuite/gcc.dg/struct/rf_rewrite_phi_bug.c +index faa90b42d..2d67434a0 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_rewrite_phi_bug.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_rewrite_phi_bug.c +@@ -78,4 +78,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 3" "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 3" "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_visible_func.c b/gcc/testsuite/gcc.dg/struct/rf_visible_func.c +index 8f2da99cc..a8cf2b63c 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_visible_func.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_visible_func.c +@@ -89,4 +89,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_void_ptr_param_func.c b/gcc/testsuite/gcc.dg/struct/rf_void_ptr_param_func.c +index 723142c59..b6cba3c34 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_void_ptr_param_func.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_void_ptr_param_func.c +@@ -51,4 +51,4 @@ main() + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "reorder_fields" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_layout" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/sr_pointer_minus.c b/gcc/testsuite/gcc.dg/struct/sr_pointer_minus.c +index 9a82da0d6..a0614a1ba 100644 +--- a/gcc/testsuite/gcc.dg/struct/sr_pointer_minus.c ++++ b/gcc/testsuite/gcc.dg/struct/sr_pointer_minus.c +@@ -30,4 +30,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "struct node has escaped: \"Type escapes via a unhandled rewrite stmt\"" "struct_reorg" } } */ ++/* { dg-final { scan-ipa-dump "has escaped: \"Type escapes via a unhandled rewrite stmt\"" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp +index c8db4675f..67b3ac2d5 100644 +--- a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp ++++ b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp +@@ -47,6 +47,25 @@ gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/complete_struct_relayout + gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/rf*.c]] \ + "" "-fipa-reorder-fields -fdump-ipa-all -flto-partition=one -fwhole-program" + ++# -fipa-struct-reorg=1 ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/wo_prof_*.c]] \ ++ "" "-fipa-struct-reorg=1 -fdump-ipa-all -flto-partition=one -fwhole-program" ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/w_ratio_*.c]] \ ++ "" "-fipa-struct-reorg=1 -fdump-ipa-all -flto-partition=one -fwhole-program" ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/w_prof_*.c]] \ ++ "" "-fipa-struct-reorg=1 -fdump-ipa-all -flto-partition=one -fwhole-program" ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/struct_reorg*.c]] \ ++ "" "-fipa-struct-reorg=1 -fdump-ipa-all -flto-partition=one -fwhole-program" ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/sr_*.c]] \ ++ "" "-fipa-struct-reorg=1 -fdump-ipa-all -flto-partition=one -fwhole-program" ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/csr_*.c]] \ ++ "" "-fipa-struct-reorg=1 -fdump-ipa-all -flto-partition=one -fwhole-program" ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/complete_struct_relayout.c]] \ ++ "" "-fipa-struct-reorg=1 -fdump-ipa-all -flto-partition=one -fwhole-program" ++ ++# -fipa-struct-reorg=2 ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] \ ++ "" "-fipa-struct-reorg=2 -fdump-ipa-all -flto-partition=one -fwhole-program" + # All done. + torture-finish + dg-finish +diff --git a/gcc/timevar.def b/gcc/timevar.def +index e873747a8..b179f62bb 100644 +--- a/gcc/timevar.def ++++ b/gcc/timevar.def +@@ -80,7 +80,7 @@ DEFTIMEVAR (TV_IPA_CONSTANT_PROP , "ipa cp") + DEFTIMEVAR (TV_IPA_INLINING , "ipa inlining heuristics") + DEFTIMEVAR (TV_IPA_FNSPLIT , "ipa function splitting") + DEFTIMEVAR (TV_IPA_COMDATS , "ipa comdats") +-DEFTIMEVAR (TV_IPA_REORDER_FIELDS , "ipa struct reorder fields optimization") ++DEFTIMEVAR (TV_IPA_STRUCT_LAYOUT , "ipa struct layout optimization") + DEFTIMEVAR (TV_IPA_STRUCT_REORG , "ipa struct reorg optimization") + DEFTIMEVAR (TV_IPA_EXTEND_AUTO_PROFILE, "ipa extend auto profile") + DEFTIMEVAR (TV_IPA_OPT , "ipa various optimizations") +diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h +index be6387768..187f1a85c 100644 +--- a/gcc/tree-pass.h ++++ b/gcc/tree-pass.h +@@ -509,7 +509,7 @@ extern ipa_opt_pass_d *make_pass_ipa_odr (gcc::context *ctxt); + extern ipa_opt_pass_d *make_pass_ipa_reference (gcc::context *ctxt); + extern ipa_opt_pass_d *make_pass_ipa_hsa (gcc::context *ctxt); + extern ipa_opt_pass_d *make_pass_ipa_pure_const (gcc::context *ctxt); +-extern simple_ipa_opt_pass *make_pass_ipa_reorder_fields (gcc::context *ctxt); ++extern simple_ipa_opt_pass *make_pass_ipa_struct_layout (gcc::context *ctxt); + extern simple_ipa_opt_pass *make_pass_ipa_struct_reorg (gcc::context *ctxt); + extern simple_ipa_opt_pass *make_pass_ipa_extend_auto_profile (gcc::context + *ctxt); +diff --git a/gcc/tree.c b/gcc/tree.c +index 89fa469c3..c2075d735 100644 +--- a/gcc/tree.c ++++ b/gcc/tree.c +@@ -5219,7 +5219,7 @@ fld_simplified_type_name (tree type) + /* Simplify type will cause that struct A and struct A within + struct B are different type pointers, so skip it in structure + optimizations. */ +- if (flag_ipa_reorder_fields || flag_ipa_struct_reorg) ++ if (flag_ipa_struct_layout || flag_ipa_struct_reorg) + return TYPE_NAME (type); + + if (!TYPE_NAME (type) || TREE_CODE (TYPE_NAME (type)) != TYPE_DECL) +@@ -5463,7 +5463,7 @@ fld_simplified_type (tree t, class free_lang_data_d *fld) + /* Simplify type will cause that struct A and struct A within + struct B are different type pointers, so skip it in structure + optimizations. */ +- if (flag_ipa_reorder_fields || flag_ipa_struct_reorg) ++ if (flag_ipa_struct_layout || flag_ipa_struct_reorg) + return t; + if (POINTER_TYPE_P (t)) + return fld_incomplete_type_of (t, fld); +-- +2.27.0.windows.1 + diff --git a/0038-DFE-Add-Dead-Field-Elimination-in-Struct-Reorg.patch b/0038-DFE-Add-Dead-Field-Elimination-in-Struct-Reorg.patch new file mode 100644 index 0000000..6b913ae --- /dev/null +++ b/0038-DFE-Add-Dead-Field-Elimination-in-Struct-Reorg.patch @@ -0,0 +1,902 @@ +From edd4200e2b3e94d5c124900657b91c22dfe9c557 Mon Sep 17 00:00:00 2001 +From: Mingchuan Wu <wumingchuan1992@foxmail.com> +Date: Wed, 15 Jun 2022 16:00:25 +0800 +Subject: [PATCH 04/12] [DFE] Add Dead Field Elimination in Struct-Reorg. + +We can transform gimple to eliminate fields that are never read +and remove their redundant stmts. +Also we adapted the partial escape_cast_another_ptr for struct relayout. +Add flag -fipa-struct-reorg=3 to enable dead field elimination. +--- + gcc/common.opt | 4 +- + gcc/ipa-struct-reorg/ipa-struct-reorg.c | 209 ++++++++++++++++-- + gcc/ipa-struct-reorg/ipa-struct-reorg.h | 9 +- + gcc/testsuite/gcc.dg/struct/dfe_DTE_verify.c | 86 +++++++ + .../gcc.dg/struct/dfe_ele_minus_verify.c | 60 +++++ + .../gcc.dg/struct/dfe_mem_ref_offset.c | 58 +++++ + .../struct/dfe_mul_layer_ptr_record_bug.c | 30 +++ + gcc/testsuite/gcc.dg/struct/dfe_ptr_diff.c | 71 ++++++ + .../gcc.dg/struct/dfe_ptr_negate_expr.c | 55 +++++ + gcc/testsuite/gcc.dg/struct/dfe_ptr_ptr.c | 55 +++++ + gcc/testsuite/gcc.dg/struct/struct-reorg.exp | 21 +- + 11 files changed, 639 insertions(+), 19 deletions(-) + create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_DTE_verify.c + create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_ele_minus_verify.c + create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_mem_ref_offset.c + create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_mul_layer_ptr_record_bug.c + create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_ptr_diff.c + create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_ptr_negate_expr.c + create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_ptr_ptr.c + +diff --git a/gcc/common.opt b/gcc/common.opt +index 7fc075d35..b5ea3c7a1 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -1884,8 +1884,8 @@ Common Report Var(flag_ipa_struct_reorg) Init(0) Optimization + Perform structure layout optimizations. + + fipa-struct-reorg= +-Common RejectNegative Joined UInteger Var(struct_layout_optimize_level) Init(0) IntegerRange(0, 2) +--fipa-struct-reorg=[0,1,2] adding none, struct-reorg, reorder-fields optimizations. ++Common RejectNegative Joined UInteger Var(struct_layout_optimize_level) Init(0) IntegerRange(0, 3) ++-fipa-struct-reorg=[0,1,2,3] adding none, struct-reorg, reorder-fields, dfe optimizations. + + fipa-extend-auto-profile + Common Report Var(flag_ipa_extend_auto_profile) +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +index 9214ee74a..2fa560239 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -81,6 +81,7 @@ along with GCC; see the file COPYING3. If not see + #include "tree-pretty-print.h" + #include "gimple-pretty-print.h" + #include "gimple-iterator.h" ++#include "gimple-walk.h" + #include "cfg.h" + #include "ssa.h" + #include "tree-dfa.h" +@@ -238,11 +239,44 @@ enum srmode + STRUCT_LAYOUT_OPTIMIZE + }; + ++/* Enum the struct layout optimize level, ++ which should be the same as the option -fstruct-reorg=. */ ++ ++enum struct_layout_opt_level ++{ ++ NONE = 0, ++ STRUCT_REORG, ++ STRUCT_REORDER_FIELDS, ++ DEAD_FIELD_ELIMINATION ++}; ++ + static bool is_result_of_mult (tree arg, tree *num, tree struct_size); + bool isptrptr (tree type); + + srmode current_mode; + ++hash_map<tree, tree> replace_type_map; ++ ++/* Return true if one of these types is created by struct-reorg. */ ++ ++static bool ++is_replace_type (tree type1, tree type2) ++{ ++ if (replace_type_map.is_empty ()) ++ return false; ++ if (type1 == NULL_TREE || type2 == NULL_TREE) ++ return false; ++ tree *type_value = replace_type_map.get (type1); ++ if (type_value) ++ if (types_compatible_p (*type_value, type2)) ++ return true; ++ type_value = replace_type_map.get (type2); ++ if (type_value) ++ if (types_compatible_p (*type_value, type1)) ++ return true; ++ return false; ++} ++ + } // anon namespace + + namespace struct_reorg { +@@ -318,12 +352,13 @@ srfunction::simple_dump (FILE *file) + /* Constructor of FIELD. */ + + srfield::srfield (tree field, srtype *base) +- : offset(int_byte_position (field)), ++ : offset (int_byte_position (field)), + fieldtype (TREE_TYPE (field)), + fielddecl (field), +- base(base), +- type(NULL), +- clusternum(0) ++ base (base), ++ type (NULL), ++ clusternum (0), ++ field_access (EMPTY_FIELD) + { + for(int i = 0;i < max_split; i++) + newfield[i] = NULL_TREE; +@@ -362,6 +397,25 @@ srtype::srtype (tree type) + } + } + ++/* Check it if all fields in the RECORD_TYPE are referenced. */ ++ ++bool ++srtype::has_dead_field (void) ++{ ++ bool may_dfe = false; ++ srfield *this_field; ++ unsigned i; ++ FOR_EACH_VEC_ELT (fields, i, this_field) ++ { ++ if (!(this_field->field_access & READ_FIELD)) ++ { ++ may_dfe = true; ++ break; ++ } ++ } ++ return may_dfe; ++} ++ + /* Mark the type as escaping type E at statement STMT. */ + + void +@@ -833,6 +887,10 @@ srtype::create_new_type (void) + for (unsigned i = 0; i < fields.length (); i++) + { + srfield *f = fields[i]; ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE ++ && struct_layout_optimize_level >= DEAD_FIELD_ELIMINATION ++ && !(f->field_access & READ_FIELD)) ++ continue; + f->create_new_fields (newtype, newfields, newlast); + } + +@@ -854,6 +912,16 @@ srtype::create_new_type (void) + + warn_padded = save_warn_padded; + ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE ++ && replace_type_map.get (this->newtype[0]) == NULL) ++ replace_type_map.put (this->newtype[0], this->type); ++ if (dump_file) ++ { ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE ++ && struct_layout_optimize_level >= DEAD_FIELD_ELIMINATION ++ && has_dead_field ()) ++ fprintf (dump_file, "Dead field elimination.\n"); ++ } + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Created %d types:\n", maxclusters); +@@ -1128,12 +1196,12 @@ csrtype::init_type_info (void) + + /* Close enough to pad to improve performance. + 33~63 should pad to 64 but 33~48 (first half) are too far away, and +- 65~127 should pad to 128 but 65~96 (first half) are too far away. */ ++ 65~127 should pad to 128 but 65~80 (first half) are too far away. */ + if (old_size > 48 && old_size < 64) + { + new_size = 64; + } +- if (old_size > 96 && old_size < 128) ++ if (old_size > 80 && old_size < 128) + { + new_size = 128; + } +@@ -1272,6 +1340,7 @@ public: + bool has_rewritten_type (srfunction*); + void maybe_mark_or_record_other_side (tree side, tree other, gimple *stmt); + unsigned execute_struct_relayout (void); ++ bool remove_dead_field_stmt (tree lhs); + }; + + struct ipa_struct_relayout +@@ -3206,6 +3275,90 @@ ipa_struct_reorg::find_vars (gimple *stmt) + } + } + ++/* Update field_access in srfield. */ ++ ++static void ++update_field_access (tree record, tree field, unsigned access, void *data) ++{ ++ srtype *this_srtype = ((ipa_struct_reorg *)data)->find_type (record); ++ if (this_srtype == NULL) ++ return; ++ srfield *this_srfield = this_srtype->find_field (int_byte_position (field)); ++ if (this_srfield == NULL) ++ return; ++ ++ this_srfield->field_access |= access; ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "record field access %d:", access); ++ print_generic_expr (dump_file, record); ++ fprintf (dump_file, " field:"); ++ print_generic_expr (dump_file, field); ++ fprintf (dump_file, "\n"); ++ } ++ return; ++} ++ ++/* A callback for walk_stmt_load_store_ops to visit store. */ ++ ++static bool ++find_field_p_store (gimple *, tree node, tree op, void *data) ++{ ++ if (TREE_CODE (op) != COMPONENT_REF) ++ return false; ++ tree node_type = TREE_TYPE (node); ++ if (!handled_type (node_type)) ++ return false; ++ ++ update_field_access (node_type, TREE_OPERAND (op, 1), WRITE_FIELD, data); ++ ++ return false; ++} ++ ++/* A callback for walk_stmt_load_store_ops to visit load. */ ++ ++static bool ++find_field_p_load (gimple *, tree node, tree op, void *data) ++{ ++ if (TREE_CODE (op) != COMPONENT_REF) ++ return false; ++ tree node_type = TREE_TYPE (node); ++ if (!handled_type (node_type)) ++ return false; ++ ++ update_field_access (node_type, TREE_OPERAND (op, 1), READ_FIELD, data); ++ ++ return false; ++} ++ ++/* Determine whether the stmt should be deleted. */ ++ ++bool ++ipa_struct_reorg::remove_dead_field_stmt (tree lhs) ++{ ++ tree base = NULL_TREE; ++ bool indirect = false; ++ srtype *t = NULL; ++ srfield *f = NULL; ++ bool realpart = false; ++ bool imagpart = false; ++ bool address = false; ++ bool escape_from_base = false; ++ if (!get_type_field (lhs, base, indirect, t, f, realpart, imagpart, ++ address, escape_from_base)) ++ return false; ++ if (t ==NULL) ++ return false; ++ if (t->newtype[0] == t->type) ++ return false; ++ if (f == NULL) ++ return false; ++ if (f->newfield[0] == NULL ++ && (f->field_access & WRITE_FIELD)) ++ return true; ++ return false; ++} ++ + /* Maybe record access of statement for further analaysis. */ + + void +@@ -3227,6 +3380,13 @@ ipa_struct_reorg::maybe_record_stmt (cgraph_node *node, gimple *stmt) + default: + break; + } ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE ++ && struct_layout_optimize_level >= DEAD_FIELD_ELIMINATION) ++ { ++ /* Look for loads and stores. */ ++ walk_stmt_load_store_ops (stmt, this, find_field_p_load, ++ find_field_p_store); ++ } + } + + /* Calculate the multiplier. */ +@@ -3543,8 +3703,11 @@ ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other, gimple + } + else if (type != d->type) + { +- type->mark_escape (escape_cast_another_ptr, stmt); +- d->type->mark_escape (escape_cast_another_ptr, stmt); ++ if (!is_replace_type (d->type->type, type->type)) ++ { ++ type->mark_escape (escape_cast_another_ptr, stmt); ++ d->type->mark_escape (escape_cast_another_ptr, stmt); ++ } + } + /* x_1 = y.x_nodes; void *x; + Directly mark the structure pointer type assigned +@@ -4131,8 +4294,9 @@ ipa_struct_reorg::check_type_and_push (tree newdecl, srdecl *decl, + } + /* If we have a non void* or a decl (which is hard to track), + then mark the type as escaping. */ +- if (!VOID_POINTER_P (TREE_TYPE (newdecl)) +- || DECL_P (newdecl)) ++ if (replace_type_map.get (type->type) == NULL ++ && (!VOID_POINTER_P (TREE_TYPE (newdecl)) ++ || DECL_P (newdecl))) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { +@@ -4142,7 +4306,7 @@ ipa_struct_reorg::check_type_and_push (tree newdecl, srdecl *decl, + print_generic_expr (dump_file, TREE_TYPE (newdecl)); + fprintf (dump_file, "\n"); + } +- type->mark_escape (escape_cast_another_ptr, stmt); ++ type->mark_escape (escape_cast_another_ptr, stmt); + return; + } + /* At this point there should only be unkown void* ssa names. */ +@@ -4465,11 +4629,13 @@ ipa_struct_reorg::check_other_side (srdecl *decl, tree other, gimple *stmt, vec< + + return; + } ++ if (!is_replace_type (t1->type, type->type)) ++ { ++ if (t1) ++ t1->mark_escape (escape_cast_another_ptr, stmt); + +- if (t1) +- t1->mark_escape (escape_cast_another_ptr, stmt); +- +- type->mark_escape (escape_cast_another_ptr, stmt); ++ type->mark_escape (escape_cast_another_ptr, stmt); ++ } + } + + +@@ -5722,6 +5888,19 @@ bool + ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + { + bool remove = false; ++ ++ if (current_mode == STRUCT_LAYOUT_OPTIMIZE ++ && struct_layout_optimize_level >= DEAD_FIELD_ELIMINATION ++ && remove_dead_field_stmt (gimple_assign_lhs (stmt))) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\n rewriting statement (remove): \n"); ++ print_gimple_stmt (dump_file, stmt, 0); ++ } ++ return true; ++ } ++ + if (gimple_clobber_p (stmt)) + { + tree lhs = gimple_assign_lhs (stmt); +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.h b/gcc/ipa-struct-reorg/ipa-struct-reorg.h +index 54b0dc655..936c0fa6f 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.h ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.h +@@ -142,6 +142,7 @@ public: + + bool create_new_type (void); + void analyze (void); ++ bool has_dead_field (void); + void mark_escape (escape_type, gimple *stmt); + bool has_escaped (void) + { +@@ -163,6 +164,12 @@ public: + } + }; + ++/* Bitflags used for determining if a field ++ is never accessed, read or written. */ ++const unsigned EMPTY_FIELD = 0x0u; ++const unsigned READ_FIELD = 0x01u; ++const unsigned WRITE_FIELD = 0x02u; ++ + struct srfield + { + unsigned HOST_WIDE_INT offset; +@@ -174,7 +181,7 @@ struct srfield + unsigned clusternum; + + tree newfield[max_split]; +- ++ unsigned field_access; /* FIELD_DECL -> bitflag (use for dfe). */ + // Constructors + srfield (tree field, srtype *base); + +diff --git a/gcc/testsuite/gcc.dg/struct/dfe_DTE_verify.c b/gcc/testsuite/gcc.dg/struct/dfe_DTE_verify.c +new file mode 100644 +index 000000000..4261d2352 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/dfe_DTE_verify.c +@@ -0,0 +1,86 @@ ++/* { dg-do compile } */
++
++#include <stdio.h>
++#include <stdlib.h>
++
++typedef struct node node_t;
++typedef struct node *node_p;
++
++typedef struct arc arc_t;
++typedef struct arc *arc_p;
++
++typedef struct network
++{
++ arc_p arcs;
++ arc_p sorted_arcs;
++ int x;
++ node_p nodes;
++ node_p stop_nodes;
++} network_t;
++
++struct node
++{
++ int64_t potential;
++ int orientation;
++ node_p child;
++ node_p pred;
++ node_p sibling;
++ node_p sibling_prev;
++ arc_p basic_arc;
++ arc_p firstout;
++ arc_p firstin;
++ arc_p arc_tmp;
++ int64_t flow;
++ int64_t depth;
++ int number;
++ int time;
++};
++
++struct arc
++{
++ int id;
++ int64_t cost;
++ node_p tail;
++ node_p head;
++ short ident;
++ arc_p nextout;
++ arc_p nextin;
++ int64_t flow;
++ int64_t org_cost;
++ network_t* net_add;
++};
++
++
++const int MAX = 100;
++
++/* let it escape_array, "Type is used in an array [not handled yet]". */
++network_t* net[2];
++arc_p stop_arcs = NULL;
++
++int
++main ()
++{
++ net[0] = (network_t*) calloc (1, sizeof(network_t));
++ net[0]->arcs = (arc_p) calloc (MAX, sizeof (arc_t));
++ stop_arcs = (arc_p) calloc (MAX, sizeof (arc_t));
++
++ net[0]->arcs->id = 100;
++
++ for (unsigned i = 0; i < 3; i++)
++ {
++ net[0]->arcs->id = net[0]->arcs->id + 2;
++ stop_arcs->cost = net[0]->arcs->id / 2;
++ stop_arcs->net_add = net[0];
++ printf("stop_arcs->cost = %ld\n", stop_arcs->cost);
++ net[0]->arcs++;
++ stop_arcs++;
++ }
++
++ if( net[1] != 0 && stop_arcs != 0)
++ {
++ return -1;
++ }
++ return 0;
++}
++
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_layout" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_ele_minus_verify.c b/gcc/testsuite/gcc.dg/struct/dfe_ele_minus_verify.c +new file mode 100644 +index 000000000..42d38c63a +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/dfe_ele_minus_verify.c +@@ -0,0 +1,60 @@ ++// verify newarc[cmp-1].flow
++/* { dg-do compile } */
++
++#include <stdio.h>
++#include <stdlib.h>
++
++typedef struct node node_t;
++typedef struct node *node_p;
++
++typedef struct arc arc_t;
++typedef struct arc *arc_p;
++
++struct node
++{
++ int64_t potential;
++ int orientation;
++ node_p child;
++ node_p pred;
++ node_p sibling;
++ node_p sibling_prev;
++ arc_p basic_arc;
++ arc_p firstout;
++ arc_p firstin;
++ arc_p arc_tmp;
++ int64_t flow;
++ int64_t depth;
++ int number;
++ int time;
++};
++
++struct arc
++{
++ int id;
++ int64_t cost;
++ node_p tail;
++ node_p head;
++ short ident;
++ arc_p nextout;
++ arc_p nextin;
++ int64_t flow;
++ int64_t org_cost;
++};
++
++const int MAX = 100;
++arc_p ap = NULL;
++
++int
++main ()
++{
++ ap = (arc_p) calloc(MAX, sizeof(arc_t));
++ printf("%d\n", ap[0].id);
++ for (int i = 1; i < MAX; i++)
++ {
++ ap[i-1].id = 500;
++ }
++ printf("%d\n", ap[0].id);
++ return 0;
++}
++
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_layout" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_mem_ref_offset.c b/gcc/testsuite/gcc.dg/struct/dfe_mem_ref_offset.c +new file mode 100644 +index 000000000..53583fe82 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/dfe_mem_ref_offset.c +@@ -0,0 +1,58 @@ ++/* Supports the MEM_REF offset.
++ _1 = MEM[(struct arc *)ap_4 + 72B].flow;
++ Old rewrite:_1 = ap.reorder.0_8->flow;
++ New rewrite:_1 = MEM[(struct arc.reorder.0 *)ap.reorder.0_8 + 64B].flow. */
++/* { dg-do compile } */
++
++#include <stdio.h>
++#include <stdlib.h>
++
++typedef struct node node_t;
++typedef struct node *node_p;
++
++typedef struct arc arc_t;
++typedef struct arc *arc_p;
++
++struct node
++{
++ int64_t potential;
++ int orientation;
++ node_p child;
++ node_p pred;
++ node_p sibling;
++ node_p sibling_prev;
++ arc_p basic_arc;
++ arc_p firstout;
++ arc_p firstin;
++ arc_p arc_tmp;
++ int64_t flow;
++ int64_t depth;
++ int number;
++ int time;
++};
++
++struct arc
++{
++ int id;
++ int64_t cost;
++ node_p tail;
++ node_p head;
++ short ident;
++ arc_p nextout;
++ arc_p nextin;
++ int64_t flow;
++ int64_t org_cost;
++};
++
++int
++main ()
++{
++ const int MAX = 100;
++ /* A similar scenario can be reproduced only by using local variables. */
++ arc_p ap = NULL;
++ ap = (arc_p) calloc(MAX, sizeof(arc_t));
++ printf("%d\n", ap[1].flow);
++ return 0;
++}
++
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_layout" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_mul_layer_ptr_record_bug.c b/gcc/testsuite/gcc.dg/struct/dfe_mul_layer_ptr_record_bug.c +new file mode 100644 +index 000000000..fd675ec2e +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/dfe_mul_layer_ptr_record_bug.c +@@ -0,0 +1,30 @@ ++/* { dg-do compile } */
++
++#include <stdio.h>
++#include <stdlib.h>
++
++typedef struct T_HASH_ENTRY
++{
++ unsigned int hash;
++ unsigned int klen;
++ char *key;
++} iHashEntry;
++
++typedef struct T_HASH
++{
++ unsigned int size;
++ unsigned int fill;
++ unsigned int keys;
++
++ iHashEntry **array;
++} uHash;
++
++uHash *retval;
++
++int
++main() {
++ retval->array = (iHashEntry **)calloc(sizeof(iHashEntry *), retval->size);
++ return 0;
++}
++
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_layout" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_ptr_diff.c b/gcc/testsuite/gcc.dg/struct/dfe_ptr_diff.c +new file mode 100644 +index 000000000..600e7908b +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/dfe_ptr_diff.c +@@ -0,0 +1,71 @@ ++// support POINTER_DIFF_EXPR & NOP_EXPR to avoid
++// escape_unhandled_rewrite, "Type escapes via a unhandled rewrite stmt"
++/* { dg-do compile } */
++
++#include <stdio.h>
++#include <stdlib.h>
++
++typedef struct node node_t;
++typedef struct node *node_p;
++
++typedef struct arc arc_t;
++typedef struct arc *arc_p;
++
++typedef struct network
++{
++ arc_p arcs;
++ arc_p sorted_arcs;
++ int x;
++ node_p nodes;
++ node_p stop_nodes;
++} network_t;
++
++struct node
++{
++ int64_t potential;
++ int orientation;
++ node_p child;
++ node_p pred;
++ node_p sibling;
++ node_p sibling_prev;
++ arc_p basic_arc;
++ arc_p firstout;
++ arc_p firstin;
++ arc_p arc_tmp;
++ int64_t flow;
++ int64_t depth;
++ int number;
++ int time;
++};
++
++struct arc
++{
++ int id;
++ int64_t cost;
++ node_p tail;
++ node_p head;
++ short ident;
++ arc_p nextout;
++ arc_p nextin;
++ int64_t flow;
++ int64_t org_cost;
++};
++
++int
++main ()
++{
++ arc_t *old_arcs;
++ node_t *node;
++ node_t *stop;
++ size_t off;
++ network_t* net;
++
++ for( ; node->number < stop->number; node++ )
++ {
++ off = node->basic_arc - old_arcs;
++ node->basic_arc = (arc_t *)(net->arcs + off);
++ }
++ return 0;
++}
++
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 3 "struct_layout" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_ptr_negate_expr.c b/gcc/testsuite/gcc.dg/struct/dfe_ptr_negate_expr.c +new file mode 100644 +index 000000000..f411364a7 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/dfe_ptr_negate_expr.c +@@ -0,0 +1,55 @@ ++// support NEGATE_EXPR rewriting
++/* { dg-do compile } */
++
++#include <stdio.h>
++#include <stdlib.h>
++
++typedef struct node node_t;
++typedef struct node *node_p;
++
++typedef struct arc arc_t;
++typedef struct arc *arc_p;
++
++struct node
++{
++ int64_t potential;
++ int orientation;
++ node_p child;
++ node_p pred;
++ node_p sibling;
++ node_p sibling_prev;
++ arc_p basic_arc;
++ arc_p firstout;
++ arc_p firstin;
++ arc_p arc_tmp;
++ int64_t flow;
++ int64_t depth;
++ int number;
++ int time;
++};
++
++struct arc
++{
++ int id;
++ int64_t cost;
++ node_p tail;
++ node_p head;
++ short ident;
++ arc_p nextout;
++ arc_p nextin;
++ int64_t flow;
++ int64_t org_cost;
++};
++
++int
++main ()
++{
++ int64_t susp = 0;
++ const int MAX = 100;
++ arc_p ap = (arc_p) calloc(MAX, sizeof(arc_t));
++ ap -= susp;
++ printf("%d\n", ap[1].flow);
++ return 0;
++}
++
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_layout" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_ptr_ptr.c b/gcc/testsuite/gcc.dg/struct/dfe_ptr_ptr.c +new file mode 100644 +index 000000000..a4e723763 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/dfe_ptr_ptr.c +@@ -0,0 +1,55 @@ ++// release escape_ptr_ptr, "Type is used in a pointer to a pointer [not handled yet]";
++/* { dg-do compile } */
++
++#include <stdio.h>
++#include <stdlib.h>
++
++typedef struct node node_t;
++typedef struct node *node_p;
++
++typedef struct arc arc_t;
++typedef struct arc *arc_p;
++
++struct node
++{
++ int64_t potential;
++ int orientation;
++ node_p child;
++ node_p pred;
++ node_p sibling;
++ node_p sibling_prev;
++ arc_p basic_arc;
++ arc_p firstout;
++ arc_p firstin;
++ arc_p arc_tmp;
++ int64_t flow;
++ int64_t depth;
++ int number;
++ int time;
++};
++
++struct arc
++{
++ int id;
++ int64_t cost;
++ node_p tail;
++ node_p head;
++ short ident;
++ arc_p nextout;
++ arc_p nextin;
++ int64_t flow;
++ int64_t org_cost;
++};
++
++const int MAX = 100;
++arc_t **ap = NULL;
++
++int
++main ()
++{
++ ap = (arc_t**) malloc(MAX * sizeof(arc_t*));
++ (*ap)[0].id = 300;
++ return 0;
++}
++
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_layout" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp +index 67b3ac2d5..ac5585813 100644 +--- a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp ++++ b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp +@@ -64,8 +64,27 @@ gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/complete_struct_relayout + "" "-fipa-struct-reorg=1 -fdump-ipa-all -flto-partition=one -fwhole-program" + + # -fipa-struct-reorg=2 +-gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] \ ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/rf*.c]] \ ++ "" "-fipa-struct-reorg=2 -fdump-ipa-all -flto-partition=one -fwhole-program" ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/wo_prof_*.c]] \ + "" "-fipa-struct-reorg=2 -fdump-ipa-all -flto-partition=one -fwhole-program" ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/w_ratio_*.c]] \ ++ "" "-fipa-struct-reorg=2 -fdump-ipa-all -flto-partition=one -fwhole-program" ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/w_prof_*.c]] \ ++ "" "-fipa-struct-reorg=2 -fdump-ipa-all -flto-partition=one -fwhole-program" ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/struct_reorg*.c]] \ ++ "" "-fipa-struct-reorg=2 -fdump-ipa-all -flto-partition=one -fwhole-program" ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/sr_*.c]] \ ++ "" "-fipa-struct-reorg=2 -fdump-ipa-all -flto-partition=one -fwhole-program" ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/csr_*.c]] \ ++ "" "-fipa-struct-reorg=2 -fdump-ipa-all -flto-partition=one -fwhole-program" ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/complete_struct_relayout.c]] \ ++ "" "-fipa-struct-reorg=2 -fdump-ipa-all -flto-partition=one -fwhole-program" ++ ++# -fipa-struct-reorg=3 ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/dfe*.c]] \ ++ "" "-fipa-struct-reorg=3 -fdump-ipa-all -flto-partition=one -fwhole-program" ++ + # All done. + torture-finish + dg-finish +-- +2.27.0.windows.1 + diff --git a/0039-Backport-ipa-sra-Fix-thinko-when-overriding-safe_to_.patch b/0039-Backport-ipa-sra-Fix-thinko-when-overriding-safe_to_.patch new file mode 100644 index 0000000..d63a8ef --- /dev/null +++ b/0039-Backport-ipa-sra-Fix-thinko-when-overriding-safe_to_.patch @@ -0,0 +1,143 @@ +From d8753de2129d230afc9a887d5804747c69824a68 Mon Sep 17 00:00:00 2001 +From: zhaowenyu <804544223@qq.com> +Date: Mon, 20 Jun 2022 11:24:45 +0800 +Subject: [PATCH 05/12] [Backport] ipa-sra: Fix thinko when overriding + safe_to_import_accesses (PR 101066) + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=5aa28c8cf15cd254cc5a3a12278133b93b8b017f + +ipa-sra: Fix thinko when overriding safe_to_import_accesses (PR 101066) + +The "new" IPA-SRA has a more difficult job than the previous +not-truly-IPA version when identifying situations in which a parameter +passed by reference can be passed into a third function and only thee +converted to one passed by value (and possibly "split" at the same +time). + +In order to allow this, two conditions must be fulfilled. First the +call to the third function must happen before any modifications of +memory, because it could change the value passed by reference. +Second, in order to make sure we do not introduce new (invalid) +dereferences, the call must postdominate the entry BB. + +The second condition is actually not necessary if the caller function +is also certain to dereference the pointer but the first one must +still hold. Unfortunately, the code making this overriding decision +also happen to trigger when the first condition is not fulfilled. +This is fixed in the following patch. + +gcc/ChangeLog: + +2021-06-16 Martin Jambor <mjambor@suse.cz> + +(cherry picked from commit 763121ccd908f52bc666f277ea2cf42110b3aad9) +--- + gcc/ipa-sra.c | 15 +++++++++++++-- + gcc/testsuite/gcc.dg/ipa/pr101066.c | 20 ++++++++++++++++++++ + 2 files changed, 33 insertions(+), 2 deletions(-) + create mode 100644 gcc/testsuite/gcc.dg/ipa/pr101066.c + +diff --git a/gcc/ipa-sra.c b/gcc/ipa-sra.c +index b706fceff..1cb30afc3 100644 +--- a/gcc/ipa-sra.c ++++ b/gcc/ipa-sra.c +@@ -340,7 +340,7 @@ class isra_call_summary + public: + isra_call_summary () + : m_arg_flow (), m_return_ignored (false), m_return_returned (false), +- m_bit_aligned_arg (false) ++ m_bit_aligned_arg (false), m_before_any_store (false) + {} + + void init_inputs (unsigned arg_count); +@@ -359,6 +359,10 @@ public: + + /* Set when any of the call arguments are not byte-aligned. */ + unsigned m_bit_aligned_arg : 1; ++ ++ /* Set to true if the call happend before any (other) store to memory in the ++ caller. */ ++ unsigned m_before_any_store : 1; + }; + + /* Class to manage function summaries. */ +@@ -472,6 +476,8 @@ isra_call_summary::dump (FILE *f) + fprintf (f, " return value ignored\n"); + if (m_return_returned) + fprintf (f, " return value used only to compute caller return value\n"); ++ if (m_before_any_store) ++ fprintf (f, " happens before any store to memory\n"); + for (unsigned i = 0; i < m_arg_flow.length (); i++) + { + fprintf (f, " Parameter %u:\n", i); +@@ -516,6 +522,7 @@ ipa_sra_call_summaries::duplicate (cgraph_edge *, cgraph_edge *, + new_sum->m_return_ignored = old_sum->m_return_ignored; + new_sum->m_return_returned = old_sum->m_return_returned; + new_sum->m_bit_aligned_arg = old_sum->m_bit_aligned_arg; ++ new_sum->m_before_any_store = old_sum->m_before_any_store; + } + + +@@ -2355,6 +2362,7 @@ process_scan_results (cgraph_node *node, struct function *fun, + unsigned count = gimple_call_num_args (call_stmt); + isra_call_summary *csum = call_sums->get_create (cs); + csum->init_inputs (count); ++ csum->m_before_any_store = uses_memory_as_obtained; + for (unsigned argidx = 0; argidx < count; argidx++) + { + if (!csum->m_arg_flow[argidx].pointer_pass_through) +@@ -2601,6 +2609,7 @@ isra_write_edge_summary (output_block *ob, cgraph_edge *e) + bp_pack_value (&bp, csum->m_return_ignored, 1); + bp_pack_value (&bp, csum->m_return_returned, 1); + bp_pack_value (&bp, csum->m_bit_aligned_arg, 1); ++ bp_pack_value (&bp, csum->m_before_any_store, 1); + streamer_write_bitpack (&bp); + } + +@@ -2719,6 +2728,7 @@ isra_read_edge_summary (struct lto_input_block *ib, cgraph_edge *cs) + csum->m_return_ignored = bp_unpack_value (&bp, 1); + csum->m_return_returned = bp_unpack_value (&bp, 1); + csum->m_bit_aligned_arg = bp_unpack_value (&bp, 1); ++ csum->m_before_any_store = bp_unpack_value (&bp, 1); + } + + /* Read intraprocedural analysis information about NODE and all of its outgoing +@@ -3475,7 +3485,8 @@ param_splitting_across_edge (cgraph_edge *cs) + } + else if (!ipf->safe_to_import_accesses) + { +- if (!all_callee_accesses_present_p (param_desc, arg_desc)) ++ if (!csum->m_before_any_store ++ || !all_callee_accesses_present_p (param_desc, arg_desc)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " %u->%u: cannot import accesses.\n", +diff --git a/gcc/testsuite/gcc.dg/ipa/pr101066.c b/gcc/testsuite/gcc.dg/ipa/pr101066.c +new file mode 100644 +index 000000000..1ceb6e431 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/ipa/pr101066.c +@@ -0,0 +1,20 @@ ++/* { dg-do run } */ ++/* { dg-options "-Os -fno-ipa-cp -fno-inline" } */ ++ ++int a = 1, c, d, e; ++int *b = &a; ++static int g(int *h) { ++ c = *h; ++ return d; ++} ++static void f(int *h) { ++ e = *h; ++ *b = 0; ++ g(h); ++} ++int main() { ++ f(b); ++ if (c) ++ __builtin_abort(); ++ return 0; ++} +-- +2.27.0.windows.1 + diff --git a/0040-Backport-ifcvt-Allow-constants-for-noce_convert_mult.patch b/0040-Backport-ifcvt-Allow-constants-for-noce_convert_mult.patch new file mode 100644 index 0000000..23e3b89 --- /dev/null +++ b/0040-Backport-ifcvt-Allow-constants-for-noce_convert_mult.patch @@ -0,0 +1,59 @@ +From ea059ab02ac79eba1c05d6e05cbb2590c47d7c1f Mon Sep 17 00:00:00 2001 +From: zhaowenyu <804544223@qq.com> +Date: Thu, 23 Jun 2022 10:16:08 +0800 +Subject: [PATCH 06/12] [Backport] ifcvt: Allow constants for + noce_convert_multiple. + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=9b8eaa282250ad260e01d164093b597579db00d9 + +This lifts the restriction of not allowing constants for noce_convert_multiple. +The code later checks if a valid sequence is produced anyway. +gcc/ChangeLog: + + * ifcvt.cc (noce_convert_multiple_sets): Allow constants. + (bb_ok_for_noce_convert_multiple_sets): Likewise. +--- + gcc/ifcvt.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c +index 977dd1bd4..2452f231c 100644 +--- a/gcc/ifcvt.c ++++ b/gcc/ifcvt.c +@@ -3252,7 +3252,9 @@ noce_convert_multiple_sets (struct noce_if_info *if_info) + we'll end up trying to emit r4:HI = cond ? (r1:SI) : (r3:HI). + Wrap the two cmove operands into subregs if appropriate to prevent + that. */ +- if (GET_MODE (new_val) != GET_MODE (temp)) ++ ++ if (!CONSTANT_P (new_val) ++ && GET_MODE (new_val) != GET_MODE (temp)) + { + machine_mode src_mode = GET_MODE (new_val); + machine_mode dst_mode = GET_MODE (temp); +@@ -3263,7 +3265,8 @@ noce_convert_multiple_sets (struct noce_if_info *if_info) + } + new_val = lowpart_subreg (dst_mode, new_val, src_mode); + } +- if (GET_MODE (old_val) != GET_MODE (temp)) ++ if (!CONSTANT_P (old_val) ++ && GET_MODE (old_val) != GET_MODE (temp)) + { + machine_mode src_mode = GET_MODE (old_val); + machine_mode dst_mode = GET_MODE (temp); +@@ -3392,9 +3395,9 @@ bb_ok_for_noce_convert_multiple_sets (basic_block test_bb) + if (!REG_P (dest)) + return false; + +- if (!(REG_P (src) +- || (GET_CODE (src) == SUBREG && REG_P (SUBREG_REG (src)) +- && subreg_lowpart_p (src)))) ++ if (!((REG_P (src) || CONSTANT_P (src)) ++ || (GET_CODE (src) == SUBREG && REG_P (SUBREG_REG (src)) ++ && subreg_lowpart_p (src)))) + return false; + + /* Destination must be appropriate for a conditional write. */ +-- +2.27.0.windows.1 + diff --git a/0041-Backport-Register-sysroot-in-the-driver-switches-tab.patch b/0041-Backport-Register-sysroot-in-the-driver-switches-tab.patch new file mode 100644 index 0000000..441b5c5 --- /dev/null +++ b/0041-Backport-Register-sysroot-in-the-driver-switches-tab.patch @@ -0,0 +1,40 @@ +From beeb0fb50c7e40ee3d79044abc6408f760d6584a Mon Sep 17 00:00:00 2001 +From: zhaowenyu <804544223@qq.com> +Date: Thu, 23 Jun 2022 10:40:46 +0800 +Subject: [PATCH 07/12] [Backport] Register --sysroot in the driver switches + table + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=48e2d9b7b88dabed336cd098cd212d0e53c5125f + +This change adjusts the processing of --sysroot to save the option in the internal "switches" +array, which lets self-specs test for it and provide a default value possibly dependent on +environment variables, as in + + --with-specs=%{!-sysroot*:--sysroot=%:getenv("WIND_BASE" /target)} + +2021-12-20 Olivier Hainque <hainque@adacore.com> + + gcc/ + * gcc.c (driver_handle_option): do_save --sysroot. +--- + gcc/gcc.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/gcc/gcc.c b/gcc/gcc.c +index b55075b14..655beffcc 100644 +--- a/gcc/gcc.c ++++ b/gcc/gcc.c +@@ -4190,7 +4190,9 @@ driver_handle_option (struct gcc_options *opts, + case OPT__sysroot_: + target_system_root = arg; + target_system_root_changed = 1; +- do_save = false; ++ /* Saving this option is useful to let self-specs decide to ++ provide a default one. */ ++ do_save = true; + break; + + case OPT_time_: +-- +2.27.0.windows.1 + diff --git a/0042-DFE-Fix-bugs.patch b/0042-DFE-Fix-bugs.patch new file mode 100644 index 0000000..5801558 --- /dev/null +++ b/0042-DFE-Fix-bugs.patch @@ -0,0 +1,665 @@ +From f8308a2b440efe124cd6ff59924f135e85e53888 Mon Sep 17 00:00:00 2001 +From: Mingchuan Wu <wumingchuan1992@foxmail.com> +Date: Sat, 18 Jun 2022 17:51:04 +0800 +Subject: [PATCH 08/12] [DFE] Fix bugs + +Fix bugs: +1. Fixed a bug in check replace type. +2. Use new to update field access for ref. +3. We now replace the dead fields in stmt by creating a new ssa. +4. The replaced type is no longer optimized in NORMAL mode. + +Also we added 5 dejaGNU test cases. +--- + gcc/ipa-struct-reorg/ipa-struct-reorg.c | 77 ++++++--- + gcc/testsuite/gcc.dg/struct/dfe_extr_dtrace.c | 56 ++++++ + gcc/testsuite/gcc.dg/struct/dfe_extr_gc.c | 162 ++++++++++++++++++ + gcc/testsuite/gcc.dg/struct/dfe_extr_hpsa.c | 126 ++++++++++++++ + .../gcc.dg/struct/dfe_extr_tcp_usrreq.c | 58 +++++++ + .../gcc.dg/struct/dfe_extr_ui_main.c | 61 +++++++ + 6 files changed, 516 insertions(+), 24 deletions(-) + create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_extr_dtrace.c + create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_extr_gc.c + create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_extr_hpsa.c + create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_extr_tcp_usrreq.c + create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_extr_ui_main.c + +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +index 2fa560239..00dc4bf1d 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -252,6 +252,7 @@ enum struct_layout_opt_level + + static bool is_result_of_mult (tree arg, tree *num, tree struct_size); + bool isptrptr (tree type); ++void get_base (tree &base, tree expr); + + srmode current_mode; + +@@ -631,7 +632,15 @@ srtype::analyze (void) + into 2 different structures. In future we intend to add profile + info and/or static heuristics to differentiate splitting process. */ + if (fields.length () == 2) +- fields[1]->clusternum = 1; ++ { ++ for (hash_map<tree, tree>::iterator it = replace_type_map.begin (); ++ it != replace_type_map.end (); ++it) ++ { ++ if (types_compatible_p ((*it).second, this->type)) ++ return; ++ } ++ fields[1]->clusternum = 1; ++ } + + /* Otherwise we do nothing. */ + if (fields.length () >= 3) +@@ -3278,12 +3287,33 @@ ipa_struct_reorg::find_vars (gimple *stmt) + /* Update field_access in srfield. */ + + static void +-update_field_access (tree record, tree field, unsigned access, void *data) ++update_field_access (tree node, tree op, unsigned access, void *data) + { +- srtype *this_srtype = ((ipa_struct_reorg *)data)->find_type (record); ++ HOST_WIDE_INT offset = 0; ++ switch (TREE_CODE (op)) ++ { ++ case COMPONENT_REF: ++ { ++ offset = int_byte_position (TREE_OPERAND (op, 1)); ++ break; ++ } ++ case MEM_REF: ++ { ++ offset = tree_to_uhwi (TREE_OPERAND (op, 1)); ++ break; ++ } ++ default: ++ return; ++ } ++ tree base = node; ++ get_base (base, node); ++ srdecl *this_srdecl = ((ipa_struct_reorg *)data)->find_decl (base); ++ if (this_srdecl == NULL) ++ return; ++ srtype *this_srtype = this_srdecl->type; + if (this_srtype == NULL) + return; +- srfield *this_srfield = this_srtype->find_field (int_byte_position (field)); ++ srfield *this_srfield = this_srtype->find_field (offset); + if (this_srfield == NULL) + return; + +@@ -3291,9 +3321,9 @@ update_field_access (tree record, tree field, unsigned access, void *data) + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "record field access %d:", access); +- print_generic_expr (dump_file, record); ++ print_generic_expr (dump_file, this_srtype->type); + fprintf (dump_file, " field:"); +- print_generic_expr (dump_file, field); ++ print_generic_expr (dump_file, this_srfield->fielddecl); + fprintf (dump_file, "\n"); + } + return; +@@ -3302,15 +3332,10 @@ update_field_access (tree record, tree field, unsigned access, void *data) + /* A callback for walk_stmt_load_store_ops to visit store. */ + + static bool +-find_field_p_store (gimple *, tree node, tree op, void *data) ++find_field_p_store (gimple *stmt ATTRIBUTE_UNUSED, ++ tree node, tree op, void *data) + { +- if (TREE_CODE (op) != COMPONENT_REF) +- return false; +- tree node_type = TREE_TYPE (node); +- if (!handled_type (node_type)) +- return false; +- +- update_field_access (node_type, TREE_OPERAND (op, 1), WRITE_FIELD, data); ++ update_field_access (node, op, WRITE_FIELD, data); + + return false; + } +@@ -3318,15 +3343,10 @@ find_field_p_store (gimple *, tree node, tree op, void *data) + /* A callback for walk_stmt_load_store_ops to visit load. */ + + static bool +-find_field_p_load (gimple *, tree node, tree op, void *data) ++find_field_p_load (gimple *stmt ATTRIBUTE_UNUSED, ++ tree node, tree op, void *data) + { +- if (TREE_CODE (op) != COMPONENT_REF) +- return false; +- tree node_type = TREE_TYPE (node); +- if (!handled_type (node_type)) +- return false; +- +- update_field_access (node_type, TREE_OPERAND (op, 1), READ_FIELD, data); ++ update_field_access (node, op, READ_FIELD, data); + + return false; + } +@@ -4629,7 +4649,7 @@ ipa_struct_reorg::check_other_side (srdecl *decl, tree other, gimple *stmt, vec< + + return; + } +- if (!is_replace_type (t1->type, type->type)) ++ if (!is_replace_type (inner_type (t), type->type)) + { + if (t1) + t1->mark_escape (escape_cast_another_ptr, stmt); +@@ -5898,7 +5918,16 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + fprintf (dump_file, "\n rewriting statement (remove): \n"); + print_gimple_stmt (dump_file, stmt, 0); + } +- return true; ++ /* Replace the dead field in stmt by creating a dummy ssa. */ ++ tree dummy_ssa = make_ssa_name (TREE_TYPE (gimple_assign_lhs (stmt))); ++ gimple_assign_set_lhs (stmt, dummy_ssa); ++ update_stmt (stmt); ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "To: \n"); ++ print_gimple_stmt (dump_file, stmt, 0); ++ } ++ return false; + } + + if (gimple_clobber_p (stmt)) +diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_dtrace.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_dtrace.c +new file mode 100644 +index 000000000..13a226ee8 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_dtrace.c +@@ -0,0 +1,56 @@ ++/* { dg-do compile} */ ++ ++#define NULL ((void*)0) ++typedef unsigned long size_t; ++typedef long intptr_t; ++typedef unsigned long uintptr_t; ++typedef long scalar_t__; ++typedef int bool; ++#define false 0 ++#define true 1 ++ ++typedef struct TYPE_4__ TYPE_2__; ++typedef struct TYPE_3__ TYPE_1__; ++ ++typedef int uint8_t; ++typedef int uint16_t; ++ ++struct TYPE_4__ ++{ ++ size_t cpu_id; ++}; ++ ++struct TYPE_3__ ++{ ++ int cpuc_dtrace_flags; ++}; ++ ++TYPE_2__ *CPU; ++volatile int CPU_DTRACE_FAULT; ++TYPE_1__ *cpu_core; ++scalar_t__ dtrace_load8 (uintptr_t); ++ ++__attribute__((used)) static int ++dtrace_bcmp (const void *s1, const void *s2, size_t len) ++{ ++ volatile uint16_t *flags; ++ flags = (volatile uint16_t *)&cpu_core[CPU->cpu_id].cpuc_dtrace_flags; ++ if (s1 == s2) ++ return (0); ++ if (s1 == NULL || s2 == NULL) ++ return (1); ++ if (s1 != s2 && len != 0) ++ { ++ const uint8_t *ps1 = s1; ++ const uint8_t *ps2 = s2; ++ do ++ { ++ if (dtrace_load8 ((uintptr_t)ps1++) != *ps2++) ++ return (1); ++ } ++ while (--len != 0 && !(*flags & CPU_DTRACE_FAULT)); ++ } ++ return (0); ++} ++ ++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 0 "struct_layout" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_gc.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_gc.c +new file mode 100644 +index 000000000..1fff2cb9d +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_gc.c +@@ -0,0 +1,162 @@ ++/* { dg-do compile} */ ++ ++#define NULL ((void*)0) ++typedef unsigned long size_t; ++typedef long intptr_t; ++typedef unsigned long uintptr_t; ++typedef long scalar_t__; ++typedef int bool; ++#define false 0 ++#define true 1 ++ ++struct mrb_context ++{ ++ size_t stack; ++ size_t stbase; ++ size_t stend; ++ size_t eidx; ++ int *ci; ++ int *cibase; ++ int status; ++}; ++ ++struct RObject ++{ ++ int dummy; ++}; ++ ++struct RHash ++{ ++ int dummy; ++}; ++ ++struct RFiber ++{ ++ struct mrb_context *cxt; ++}; ++ ++struct RClass ++{ ++ int dummy; ++}; ++ ++struct RBasic ++{ ++ int tt; ++}; ++ ++struct RArray ++{ ++ int dummy; ++}; ++ ++typedef int mrb_state; ++typedef int mrb_gc; ++typedef int mrb_callinfo; ++size_t ARY_LEN (struct RArray *); ++size_t MRB_ENV_STACK_LEN (struct RBasic *); ++int MRB_FIBER_TERMINATED; ++ ++#define MRB_TT_ARRAY 140 ++#define MRB_TT_CLASS 139 ++#define MRB_TT_DATA 138 ++#define MRB_TT_ENV 137 ++#define MRB_TT_EXCEPTION 136 ++#define MRB_TT_FIBER 135 ++#define MRB_TT_HASH 134 ++#define MRB_TT_ICLASS 133 ++#define MRB_TT_MODULE 132 ++#define MRB_TT_OBJECT 131 ++#define MRB_TT_PROC 130 ++#define MRB_TT_RANGE 129 ++#define MRB_TT_SCLASS 128 ++ ++size_t ci_nregs (int *); ++int gc_mark_children (int *, int *, struct RBasic *); ++size_t mrb_gc_mark_hash_size (int *, struct RHash *); ++size_t mrb_gc_mark_iv_size (int *, struct RObject *); ++size_t mrb_gc_mark_mt_size (int *, struct RClass *); ++ ++__attribute__((used)) static size_t ++gc_gray_mark (mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) ++{ ++ size_t children = 0; ++ gc_mark_children (mrb, gc, obj); ++ switch (obj->tt) ++ { ++ case MRB_TT_ICLASS: ++ children++; ++ break; ++ ++ case MRB_TT_CLASS: ++ case MRB_TT_SCLASS: ++ case MRB_TT_MODULE: ++ { ++ struct RClass *c = (struct RClass *)obj; ++ children += mrb_gc_mark_iv_size (mrb, (struct RObject *)obj); ++ children += mrb_gc_mark_mt_size (mrb, c); ++ children ++; ++ } ++ break; ++ ++ case MRB_TT_OBJECT: ++ case MRB_TT_DATA: ++ case MRB_TT_EXCEPTION: ++ children += mrb_gc_mark_iv_size (mrb, (struct RObject *)obj); ++ break; ++ ++ case MRB_TT_ENV: ++ children += MRB_ENV_STACK_LEN (obj); ++ break; ++ ++ case MRB_TT_FIBER: ++ { ++ struct mrb_context *c = ((struct RFiber *)obj)->cxt; ++ size_t i; ++ mrb_callinfo *ci; ++ if (!c || c->status == MRB_FIBER_TERMINATED) ++ break; ++ ++ i = c->stack - c->stbase; ++ if (c->ci) ++ { ++ i += ci_nregs (c->ci); ++ } ++ if (c->stbase + i > c->stend) ++ i = c->stend - c->stbase; ++ ++ children += i; ++ children += c->eidx; ++ if (c->cibase) ++ { ++ for (i = 0, ci = c->cibase; ci <= c->ci; i++, ci++) ++ ; ++ } ++ children += i; ++ } ++ break; ++ ++ case MRB_TT_ARRAY: ++ { ++ struct RArray *a = (struct RArray *)obj; ++ children += ARY_LEN (a); ++ } ++ break; ++ ++ case MRB_TT_HASH: ++ children += mrb_gc_mark_iv_size (mrb, (struct RObject *)obj); ++ children += mrb_gc_mark_hash_size (mrb, (struct RHash *)obj); ++ break; ++ ++ case MRB_TT_PROC: ++ case MRB_TT_RANGE: ++ children += 2; ++ break; ++ default: ++ break; ++ } ++ ++ return children; ++} ++ ++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 0 "struct_layout" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_hpsa.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_hpsa.c +new file mode 100644 +index 000000000..0f577667c +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_hpsa.c +@@ -0,0 +1,126 @@ ++/* { dg-do compile} */ ++ ++#define NULL ((void*)0) ++typedef unsigned long size_t; ++typedef long intptr_t; ++typedef unsigned long uintptr_t; ++typedef long scalar_t__; ++typedef int bool; ++#define false 0 ++#define true 1 ++ ++typedef struct TYPE_6__ TYPE_3__; ++typedef struct TYPE_5__ TYPE_2__; ++typedef struct TYPE_4__ TYPE_1__; ++ ++struct io_accel2_cmd ++{ ++ int dummy; ++}; ++ ++struct hpsa_tmf_struct ++{ ++ int it_nexus; ++}; ++ ++struct hpsa_scsi_dev_t ++{ ++ int nphysical_disks; ++ int ioaccel_handle; ++ struct hpsa_scsi_dev_t **phys_disk; ++}; ++ ++struct ctlr_info ++{ ++ TYPE_3__ *pdev; ++ struct io_accel2_cmd *ioaccel2_cmd_pool; ++}; ++struct TYPE_4__ ++{ ++ int LunAddrBytes; ++}; ++ ++struct TYPE_5__ ++{ ++ TYPE_1__ LUN; ++}; ++ ++struct CommandList ++{ ++ size_t cmdindex; ++ int cmd_type; ++ struct hpsa_scsi_dev_t *phys_disk; ++ TYPE_2__ Header; ++}; ++ ++struct TYPE_6__ ++{ ++ int dev; ++}; ++ ++int BUG (); ++#define CMD_IOACCEL1 132 ++#define CMD_IOACCEL2 131 ++#define CMD_IOCTL_PEND 130 ++#define CMD_SCSI 129 ++#define IOACCEL2_TMF 128 ++int dev_err (int *, char *, int); ++scalar_t__ hpsa_is_cmd_idle (struct CommandList *); ++int le32_to_cpu (int); ++int test_memcmp (unsigned char *, int *, int); ++ ++__attribute__((used)) static bool ++hpsa_cmd_dev_match (struct ctlr_info *h, struct CommandList *c, ++ struct hpsa_scsi_dev_t *dev, unsigned char *scsi3addr) ++{ ++ int i; ++ bool match = false; ++ struct io_accel2_cmd * c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; ++ struct hpsa_tmf_struct *ac = (struct hpsa_tmf_struct *)c2; ++ ++ if (hpsa_is_cmd_idle (c)) ++ return false; ++ ++ switch (c->cmd_type) ++ { ++ case CMD_SCSI: ++ case CMD_IOCTL_PEND: ++ match = !test_memcmp (scsi3addr, &c->Header.LUN.LunAddrBytes, ++ sizeof (c->Header.LUN.LunAddrBytes)); ++ break; ++ ++ case CMD_IOACCEL1: ++ case CMD_IOACCEL2: ++ if (c->phys_disk == dev) ++ { ++ match = true; ++ } ++ else ++ { ++ for (i = 0; i < dev->nphysical_disks && !match; i++) ++ { ++ match = dev->phys_disk[i] == c->phys_disk; ++ } ++ } ++ break; ++ ++ case IOACCEL2_TMF: ++ for (i = 0; i < dev->nphysical_disks && !match; i++) ++ { ++ match = dev->phys_disk[i]->ioaccel_handle == ++ le32_to_cpu (ac->it_nexus); ++ } ++ break; ++ ++ case 0: ++ match = false; ++ break; ++ default: ++ dev_err (&h->pdev->dev, "unexpected cmd_type: %d\n", c->cmd_type); ++ BUG (); ++ } ++ ++ return match; ++} ++ ++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 0 "struct_layout" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_tcp_usrreq.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_tcp_usrreq.c +new file mode 100644 +index 000000000..5570c762e +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_tcp_usrreq.c +@@ -0,0 +1,58 @@ ++/* { dg-do compile} */ ++ ++#define NULL ((void*)0) ++typedef unsigned long size_t; ++typedef long intptr_t; ++typedef unsigned long uintptr_t; ++typedef long scalar_t__; ++typedef int bool; ++#define false 0 ++#define true 1 ++ ++struct tcpcb ++{ ++ int t_state; ++}; ++ ++struct socket ++{ ++ int dummy; ++}; ++ ++struct proc ++{ ++ int dummy; ++}; ++ ++struct inpcb ++{ ++ scalar_t__ inp_lport; ++}; ++ ++int COMMON_END (int); ++int COMMON_START (); ++int PRU_LISTEN; ++int TCPS_LISTEN; ++int in_pcbbind (struct inpcb *, int *, struct proc *); ++struct inpcb* sotoinpcb (struct socket *); ++ ++__attribute__((used)) static void ++tcp_usr_listen (struct socket *so, struct proc *p) ++{ ++ int error = 0; ++ struct inpcb *inp = sotoinpcb (so); ++ struct tcpcb *tp; ++ ++ COMMON_START (); ++ if (inp->inp_lport == 0) ++ { ++ error = in_pcbbind (inp, NULL, p); ++ } ++ if (error == 0) ++ { ++ tp->t_state = TCPS_LISTEN; ++ } ++ COMMON_END (PRU_LISTEN); ++} ++ ++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 1 "struct_layout" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_ui_main.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_ui_main.c +new file mode 100644 +index 000000000..50ab9cc24 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_ui_main.c +@@ -0,0 +1,61 @@ ++/* { dg-do compile} */ ++ ++#define NULL ((void*)0) ++typedef unsigned long size_t; ++typedef long intptr_t; ++typedef unsigned long uintptr_t; ++typedef long scalar_t__; ++typedef int bool; ++#define false 0 ++#define true 1 ++ ++typedef struct TYPE_4__ TYPE_2__; ++typedef struct TYPE_3__ TYPE_1__; ++ ++struct TYPE_4__ ++{ ++ size_t modCount; ++ TYPE_1__ *modList; ++}; ++ ++struct TYPE_3__ ++{ ++ void *modDescr; ++ void *modName; ++}; ++ ++size_t MAX_MODS; ++void *String_Alloc (char *); ++int test_strlen (char *); ++int trap_FD_GetFileList (char *, char *, char *, int); ++TYPE_2__ uiInfo; ++ ++__attribute__((used)) static void ++UI_LoadMods () ++{ ++ int numdirs; ++ char dirlist[2048]; ++ char *dirptr; ++ char *descptr; ++ int i; ++ int dirlen; ++ ++ uiInfo.modCount = 0; ++ numdirs = trap_FD_GetFileList ("$modelist", "", dirlist, sizeof (dirlist)); ++ dirptr = dirlist; ++ for (i = 0; i < numdirs; i++) ++ { ++ dirlen = test_strlen (dirptr) + 1; ++ descptr = dirptr + dirlen; ++ uiInfo.modList[uiInfo.modCount].modName = String_Alloc (dirptr); ++ uiInfo.modList[uiInfo.modCount].modDescr = String_Alloc (descptr); ++ dirptr += dirlen + test_strlen (descptr) + 1; ++ uiInfo.modCount++; ++ if (uiInfo.modCount >= MAX_MODS) ++ { ++ break; ++ } ++ } ++} ++ ++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 1 "struct_layout" } } */ +-- +2.27.0.windows.1 + diff --git a/0045-Transposed-SLP-Enable-Transposed-SLP.patch b/0045-Transposed-SLP-Enable-Transposed-SLP.patch new file mode 100644 index 0000000..6323e8d --- /dev/null +++ b/0045-Transposed-SLP-Enable-Transposed-SLP.patch @@ -0,0 +1,3009 @@ +From 639b5248cbab1806618545fc30215ed9d1a019e7 Mon Sep 17 00:00:00 2001 +From: luohailing <luo_hailing@qq.com> +Date: Fri, 17 Jun 2022 22:38:55 +0800 +Subject: [PATCH 11/12] [Transposed SLP] Enable Transposed SLP Enable + Transposed SLP when memory is uncontinual with + -ftree-slp-transpose-vectorize. + +--- + gcc/common.opt | 4 + + gcc/testsuite/gcc.dg/vect/transpose-1.c | 53 ++ + gcc/testsuite/gcc.dg/vect/transpose-2.c | 50 ++ + gcc/testsuite/gcc.dg/vect/transpose-3.c | 54 ++ + gcc/testsuite/gcc.dg/vect/transpose-4.c | 53 ++ + gcc/testsuite/gcc.dg/vect/transpose-5.c | 73 ++ + gcc/testsuite/gcc.dg/vect/transpose-6.c | 67 ++ + gcc/testsuite/gcc.dg/vect/transpose-7.c | 53 ++ + gcc/testsuite/gcc.dg/vect/transpose-8.c | 53 ++ + gcc/testsuite/gcc.dg/vect/vect.exp | 7 + + gcc/tree-vect-data-refs.c | 236 +++++ + gcc/tree-vect-slp.c | 1090 ++++++++++++++++++++++- + gcc/tree-vect-stmts.c | 763 +++++++++++++++- + gcc/tree-vectorizer.h | 89 ++ + 14 files changed, 2641 insertions(+), 4 deletions(-) + create mode 100644 gcc/testsuite/gcc.dg/vect/transpose-1.c + create mode 100644 gcc/testsuite/gcc.dg/vect/transpose-2.c + create mode 100644 gcc/testsuite/gcc.dg/vect/transpose-3.c + create mode 100644 gcc/testsuite/gcc.dg/vect/transpose-4.c + create mode 100644 gcc/testsuite/gcc.dg/vect/transpose-5.c + create mode 100644 gcc/testsuite/gcc.dg/vect/transpose-6.c + create mode 100644 gcc/testsuite/gcc.dg/vect/transpose-7.c + create mode 100644 gcc/testsuite/gcc.dg/vect/transpose-8.c + +diff --git a/gcc/common.opt b/gcc/common.opt +index 24834cf60..d38401b71 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -3049,6 +3049,10 @@ ftree-vect-analyze-slp-group + Common Report Var(flag_tree_slp_group) Init(0) + Disable SLP vectorization for reduction chain on tree. + ++ftree-slp-transpose-vectorize ++Common Report Var(flag_tree_slp_transpose_vectorize) Optimization Init(0) ++Enable basic block vectorization (SLP) for transposed stores and loads on trees. ++ + fvect-cost-model= + Common Joined RejectNegative Enum(vect_cost_model) Var(flag_vect_cost_model) Init(VECT_COST_MODEL_DEFAULT) Optimization + -fvect-cost-model=[unlimited|dynamic|cheap] Specifies the cost model for vectorization. +diff --git a/gcc/testsuite/gcc.dg/vect/transpose-1.c b/gcc/testsuite/gcc.dg/vect/transpose-1.c +new file mode 100644 +index 000000000..8237a8b9e +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/vect/transpose-1.c +@@ -0,0 +1,53 @@ ++/* { dg-do compile { target { aarch64*-*-linux* } } } */ ++/* { dg-require-effective-target vect_int } */ ++#include <stdio.h> ++#include <stdlib.h> ++#include "tree-vect.h" ++ ++#define N 4 ++#define M 256 ++ ++int foo (unsigned char *pix1, int i_pix1, unsigned char *pix2, int i_pix2) ++{ ++ int i = 0; ++ int sum = 0; ++ unsigned c0[N], c1[N], c2[N], c3[N], c4[N], c5[N], c6[N], c7[N]; ++ for (i = 0; i < N; i++, pix1 += i_pix1, pix2 += i_pix2) ++ { ++ c0[i] = pix1[0] - pix2[0]; ++ c1[i] = pix1[1] - pix2[1]; ++ c2[i] = pix1[2] - pix2[2]; ++ c3[i] = pix1[3] - pix2[3]; ++ c4[i] = pix1[4] - pix2[4]; ++ c5[i] = pix1[5] - pix2[5]; ++ c6[i] = pix1[6] - pix2[6]; ++ c7[i] = pix1[7] - pix2[7]; ++ } ++ for (int i = 0; i < N; i++) ++ { ++ sum += c0[i] + c1[i] + c2[i] + c3[i] + c4[i] + c5[i] + c6[i] + c7[i]; ++ } ++ return sum; ++} ++ ++int main (int argc, const char* argv[]) ++{ ++ unsigned char input1[M]; ++ unsigned char input2[M]; ++ int i1 = 16; ++ int i2 = 8; ++ check_vect (); ++ for (int i = 0; i < M; i++) ++ { ++ input1[i] = i * 2; ++ input2[i] = i; ++ } ++ int sum = foo (input1, i1, input2, i2); ++ if (sum != 1264) ++ { ++ abort (); ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-tree-dump "vectorized using transposed version" "slp1" } } */ +diff --git a/gcc/testsuite/gcc.dg/vect/transpose-2.c b/gcc/testsuite/gcc.dg/vect/transpose-2.c +new file mode 100644 +index 000000000..b01a0410e +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/vect/transpose-2.c +@@ -0,0 +1,50 @@ ++/* { dg-do compile { target { aarch64*-*-linux* } } } */ ++/* { dg-additional-options "-fno-tree-loop-vectorize" } */ ++/* { dg-require-effective-target vect_int } */ ++#include <stdio.h> ++#include <stdlib.h> ++#include "tree-vect.h" ++ ++#define N 8 ++#define M 256 ++ ++int foo (unsigned char *pix1, int i_pix1, unsigned char *pix2, int i_pix2) ++{ ++ int i = 0; ++ int sum = 0; ++ unsigned short c0[N], c1[N], c2[N], c3[N], c4[N], c5[N], c6[N], c7[N]; ++ for (i = 0; i < N; i++, pix1 += i_pix1, pix2 += i_pix2) ++ { ++ c0[i] = pix1[0] - pix2[0]; ++ c1[i] = pix1[1] - pix2[1]; ++ c2[i] = pix1[2] - pix2[2]; ++ c3[i] = pix1[3] - pix2[3]; ++ } ++ for (int i = 0; i < N; i++) ++ { ++ sum += c0[i] + c1[i] + c2[i] + c3[i]; ++ } ++ return sum; ++} ++ ++int main (int argc, const char* argv[]) ++{ ++ unsigned char input1[M]; ++ unsigned char input2[M]; ++ int i1 = 5; ++ int i2 = 4; ++ check_vect (); ++ for (int i = 0; i < M; i++) ++ { ++ input1[i] = i * 4; ++ input2[i] = i * 2; ++ } ++ int sum = foo (input1, i1, input2, i2); ++ if (sum != 1440) ++ { ++ abort (); ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-tree-dump "vectorized using transposed version" "slp1" } } */ +diff --git a/gcc/testsuite/gcc.dg/vect/transpose-3.c b/gcc/testsuite/gcc.dg/vect/transpose-3.c +new file mode 100644 +index 000000000..529581c59 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/vect/transpose-3.c +@@ -0,0 +1,54 @@ ++/* { dg-do compile { target { aarch64*-*-linux* } } } */ ++/* { dg-additional-options "-fno-tree-loop-vectorize" } */ ++/* { dg-require-effective-target vect_int } */ ++#include <stdio.h> ++#include <stdlib.h> ++#include "tree-vect.h" ++ ++#define N 4 ++#define M 256 ++ ++int foo (unsigned short *pix1, int i_pix1, unsigned short *pix2, int i_pix2) ++{ ++ int i = 0; ++ int sum = 0; ++ unsigned c0[N], c1[N], c2[N], c3[N], c4[N], c5[N], c6[N], c7[N]; ++ for (i = 0; i < N; i++, pix1 += i_pix1, pix2 += i_pix2) ++ { ++ c0[i] = pix1[0] - pix2[0]; ++ c1[i] = pix1[1] - pix2[1]; ++ c2[i] = pix1[2] - pix2[2]; ++ c3[i] = pix1[3] - pix2[3]; ++ c4[i] = pix1[4] - pix2[4]; ++ c5[i] = pix1[5] - pix2[5]; ++ c6[i] = pix1[6] - pix2[6]; ++ c7[i] = pix1[7] - pix2[7]; ++ } ++ for (int i = 0; i < N; i++) ++ { ++ sum += c0[i] + c1[i] + c2[i] + c3[i] + c4[i] + c5[i] + c6[i] + c7[i]; ++ } ++ return sum; ++} ++ ++int main (int argc, const char* argv[]) ++{ ++ unsigned short input1[M]; ++ unsigned short input2[M]; ++ int i1 = 8; ++ int i2 = 4; ++ check_vect (); ++ for (int i = 0; i < M; i++) ++ { ++ input1[i] = i * 4; ++ input2[i] = i; ++ } ++ int sum = foo (input1, i1, input2, i2); ++ if (sum != 1680) ++ { ++ abort (); ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-tree-dump "vectorized using transposed version" "slp1" } } */ +diff --git a/gcc/testsuite/gcc.dg/vect/transpose-4.c b/gcc/testsuite/gcc.dg/vect/transpose-4.c +new file mode 100644 +index 000000000..0b4adea9b +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/vect/transpose-4.c +@@ -0,0 +1,53 @@ ++/* { dg-do compile { target { aarch64*-*-linux* } } } */ ++/* { dg-require-effective-target vect_int } */ ++#include <stdio.h> ++#include <stdlib.h> ++#include "tree-vect.h" ++ ++#define N 4 ++#define M 256 ++ ++int foo (unsigned *pix1, int i_pix1, unsigned *pix2, int i_pix2) ++{ ++ int i = 0; ++ int sum = 0; ++ unsigned c0[N], c1[N], c2[N], c3[N], c4[N], c5[N], c6[N], c7[N]; ++ for (i = 0; i < N; i++, pix1 += i_pix1, pix2 += i_pix2) ++ { ++ c0[i] = pix1[0] - pix2[0]; ++ c1[i] = pix1[1] - pix2[1]; ++ c2[i] = pix1[2] - pix2[2]; ++ c3[i] = pix1[3] - pix2[3]; ++ c4[i] = pix1[4] - pix2[4]; ++ c5[i] = pix1[5] - pix2[5]; ++ c6[i] = pix1[6] - pix2[6]; ++ c7[i] = pix1[7] - pix2[7]; ++ } ++ for (int i = 0; i < N; i++) ++ { ++ sum += c0[i] + c1[i] + c2[i] + c3[i] + c4[i] + c5[i] + c6[i] + c7[i]; ++ } ++ return sum; ++} ++ ++int main (int argc, const char* argv[]) ++{ ++ unsigned input1[M]; ++ unsigned input2[M]; ++ int i1 = 12; ++ int i2 = 6; ++ check_vect (); ++ for (int i = 0; i < M; i++) ++ { ++ input1[i] = i * 7; ++ input2[i] = i * 3; ++ } ++ int sum = foo (input1, i1, input2, i2); ++ if (sum != 3616) ++ { ++ abort (); ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-tree-dump "vectorized using transposed version" "slp1" } } */ +diff --git a/gcc/testsuite/gcc.dg/vect/transpose-5.c b/gcc/testsuite/gcc.dg/vect/transpose-5.c +new file mode 100644 +index 000000000..81a248840 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/vect/transpose-5.c +@@ -0,0 +1,73 @@ ++/* { dg-do compile { target { aarch64*-*-linux* } } } */ ++/* { dg-require-effective-target vect_int } */ ++#include <stdio.h> ++#include <stdlib.h> ++#include <math.h> ++#include "tree-vect.h" ++ ++#define N 4 ++#define M 256 ++#define eps 1e-8 ++ ++double foo (unsigned char *pix1, int i_pix1, unsigned char *pix2, int i_pix2) ++{ ++ unsigned a0[N]; ++ unsigned a1[N]; ++ unsigned a2[N]; ++ unsigned a3[N]; ++ ++ int b0[N]; ++ int b1[N]; ++ int b2[N]; ++ int b3[N]; ++ ++ for (int i = 0; i < N; i++, pix1 += i_pix1, pix2 += i_pix2) ++ { ++ a0[i] = (pix1[0] - pix2[0]) + ((pix1[4] + pix2[4]) << 16); ++ a1[i] = (pix1[1] - pix2[1]) + ((pix1[5] + pix2[5]) << 16); ++ a2[i] = (pix1[2] - pix2[2]) + ((pix1[6] + pix2[6]) << 16); ++ a3[i] = (pix1[3] - pix2[3]) + ((pix1[7] + pix2[7]) << 16); ++ } ++ ++ for (int i = 0; i < N; i++, pix1 += i_pix1, pix2 += i_pix2) ++ { ++ b0[i] = (pix1[0] - pix2[0]) + (pix1[4] + pix2[4]); ++ b1[i] = (pix1[1] - pix2[1]) + (pix1[5] + pix2[5]); ++ b2[i] = (pix1[2] - pix2[2]) + (pix1[6] + pix2[6]); ++ b3[i] = (pix1[3] - pix2[3]) + (pix1[7] + pix2[7]); ++ } ++ ++ double sum = 0; ++ for (int i = 0; i < N; i++) ++ { ++ sum += a0[i] + a1[i] + a2[i] + a3[i] + b0[i] + b1[i] + b2[i] + b3[i]; ++ } ++ return sum; ++} ++ ++int main (int argc, const char* argv[]) ++{ ++ unsigned char input1[M]; ++ unsigned char input2[M]; ++ int i1 = 8; ++ int i2 = 3; ++ unsigned char m = 2; ++ unsigned short n = 12; ++ float t = 3.0; ++ double k = 4.2; ++ check_vect (); ++ for (int i = 0; i < M; i++) ++ { ++ input1[i] = i * 6; ++ input2[i] = i * 3; ++ } ++ double sum = foo (input1, i1, input2, i2); ++ if (fabs (sum - 78648144) > eps) ++ { ++ abort (); ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-tree-dump "vectorized using transposed version" "slp1" } } */ ++/* { dg-final { scan-tree-dump-times "vectorizable_store for slp transpose" 2 "slp1" } } */ +diff --git a/gcc/testsuite/gcc.dg/vect/transpose-6.c b/gcc/testsuite/gcc.dg/vect/transpose-6.c +new file mode 100644 +index 000000000..3e134ac02 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/vect/transpose-6.c +@@ -0,0 +1,67 @@ ++/* { dg-do compile { target { aarch64*-*-linux* } } } */ ++/* { dg-require-effective-target vect_int } */ ++/* { dg-require-effective-target vect_float } */ ++#include <stdio.h> ++#include <stdlib.h> ++#include <math.h> ++#include "tree-vect.h" ++ ++#define N 4 ++#define M 256 ++#define eps 1e-8 ++ ++float foo (unsigned char *pix1, int i_pix1, unsigned char *pix2, int i_pix2) ++{ ++ unsigned a0[N]; ++ unsigned a1[N]; ++ unsigned a2[N]; ++ unsigned a3[N]; ++ ++ float c0[N]; ++ float c1[N]; ++ float c2[N]; ++ float c3[N]; ++ ++ for (int i = 0; i < N; i++, pix1 += i_pix1, pix2 += i_pix2) ++ { ++ a0[i] = (pix1[0] - pix2[0]) + ((pix1[4] - pix2[4]) << 16); ++ a1[i] = (pix1[1] - pix2[1]) + ((pix1[5] - pix2[5]) << 16); ++ a2[i] = (pix1[2] - pix2[2]) + ((pix1[6] - pix2[6]) << 16); ++ a3[i] = (pix1[3] - pix2[3]) + ((pix1[7] - pix2[7]) << 16); ++ ++ c0[i] = (pix1[0] * pix2[0]) + (pix1[4] * pix2[4]); ++ c1[i] = (pix1[1] * pix2[1]) + (pix1[5] * pix2[5]); ++ c2[i] = (pix1[2] * pix2[2]) + (pix1[6] * pix2[6]); ++ c3[i] = (pix1[3] * pix2[3]) + (pix1[7] * pix2[7]); ++ } ++ ++ float sum = 0; ++ for (int i = 0; i < N; i++) ++ { ++ sum += a0[i] + a1[i] + a2[i] + a3[i] + c0[i] + c1[i] + c2[i] + c3[i]; ++ } ++ return sum; ++} ++ ++int main (int argc, const char* argv[]) ++{ ++ unsigned char input1[M]; ++ unsigned char input2[M]; ++ int i1 = 18; ++ int i2 = 6; ++ check_vect (); ++ for (int i = 0; i < M; i++) ++ { ++ input1[i] = i * 4; ++ input2[i] = i * 2; ++ } ++ float sum = foo (input1, i1, input2, i2); ++ if (fabs (sum - 106041168) > eps) ++ { ++ abort (); ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-tree-dump "vectorized using transposed version" "slp1" } } */ ++/* { dg-final { scan-tree-dump-times "vectorizable_store for slp transpose" 2 "slp1" } } */ +diff --git a/gcc/testsuite/gcc.dg/vect/transpose-7.c b/gcc/testsuite/gcc.dg/vect/transpose-7.c +new file mode 100644 +index 000000000..2074d9aa8 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/vect/transpose-7.c +@@ -0,0 +1,53 @@ ++/* { dg-do compile { target { aarch64*-*-linux* } } } */ ++/* { dg-additional-options "-fno-tree-loop-vectorize" } */ ++/* { dg-require-effective-target vect_int } */ ++#include <stdio.h> ++#include <stdlib.h> ++#include "tree-vect.h" ++ ++#define N 16 ++#define M 256 ++ ++int foo (unsigned char *pix1, int i_pix1, unsigned char *pix2, int i_pix2) ++{ ++ int i = 0; ++ int sum = 0; ++ unsigned char c0[N], c1[N]; ++ for (int i = 0; i < N/2; i++, pix1 += i_pix1, pix2 += i_pix2) ++ { ++ c0[i] = pix1[0] - pix2[0]; ++ c1[i] = pix1[1] - pix2[1]; ++ } ++ for (int i = N/2; i < N; i++, pix1 += i_pix1, pix2 += i_pix2) ++ { ++ c0[i] = pix1[0] - pix2[0]; ++ c1[i] = pix1[1] - pix2[1]; ++ } ++ for (int i = 0; i < N; i++) ++ { ++ sum += c0[i] + c1[i]; ++ } ++ return sum; ++} ++ ++int main (int argc, const char* argv[]) ++{ ++ unsigned char input1[M]; ++ unsigned char input2[M]; ++ int i1 = 6; ++ int i2 = 4; ++ check_vect (); ++ for (int i = 0; i < M; i++) ++ { ++ input1[i] = i * 5; ++ input2[i] = i * 2; ++ } ++ int sum = foo (input1, i1, input2, i2); ++ if (sum != 3280) ++ { ++ abort (); ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-tree-dump "vectorized using transposed version" "slp1" } } */ +diff --git a/gcc/testsuite/gcc.dg/vect/transpose-8.c b/gcc/testsuite/gcc.dg/vect/transpose-8.c +new file mode 100644 +index 000000000..a154f012a +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/vect/transpose-8.c +@@ -0,0 +1,53 @@ ++/* { dg-do compile { target { aarch64*-*-linux* } } } */ ++/* { dg-additional-options "-fno-tree-loop-vectorize" } */ ++/* { dg-require-effective-target vect_int } */ ++#include <stdio.h> ++#include <stdlib.h> ++#include "tree-vect.h" ++ ++#define N 32 ++#define M 256 ++ ++int foo (unsigned char *pix1, int i_pix1, unsigned char *pix2, int i_pix2) ++{ ++ int i = 0; ++ int sum = 0; ++ unsigned char c0[N], c1[N]; ++ for (int i = 0; i < N/2; i++, pix1 += i_pix1, pix2 += i_pix2) ++ { ++ c0[i] = pix1[0] - pix2[0]; ++ c1[i] = pix1[1] - pix2[1]; ++ } ++ for (int i = N/2; i < N; i++, pix1 += i_pix1, pix2 += i_pix2) ++ { ++ c0[i] = pix1[0] - pix2[0]; ++ c1[i] = pix1[1] - pix2[1]; ++ } ++ for (int i = 0; i < N; i++) ++ { ++ sum += c0[i] + c1[i]; ++ } ++ return sum; ++} ++ ++int main (int argc, const char* argv[]) ++{ ++ unsigned char input1[M]; ++ unsigned char input2[M]; ++ int i1 = 6; ++ int i2 = 4; ++ check_vect (); ++ for (int i = 0; i < M; i++) ++ { ++ input1[i] = i * 5; ++ input2[i] = i * 2; ++ } ++ int sum = foo (input1, i1, input2, i2); ++ if (sum != 7584) ++ { ++ abort (); ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-tree-dump "vectorized using transposed version" "slp1" } } */ +diff --git a/gcc/testsuite/gcc.dg/vect/vect.exp b/gcc/testsuite/gcc.dg/vect/vect.exp +index efe17ac6f..d92e1ba5b 100644 +--- a/gcc/testsuite/gcc.dg/vect/vect.exp ++++ b/gcc/testsuite/gcc.dg/vect/vect.exp +@@ -114,6 +114,13 @@ et-dg-runtest dg-runtest [lsort \ + [glob -nocomplain $srcdir/$subdir/no-vfa-*.\[cS\]]] \ + "" $DEFAULT_VECTCFLAGS + ++# -ftree-slp-transpose-vectorize SLP tests ++set VECT_SLP_CFLAGS $SAVED_VECT_SLP_CFLAGS ++lappend VECT_SLP_CFLAGS "-ftree-slp-transpose-vectorize" ++et-dg-runtest dg-runtest [lsort \ ++ [glob -nocomplain $srcdir/$subdir/transpose-*.\[cS\]]] \ ++ "" "-ftree-slp-transpose-vectorize -fdump-tree-slp-details -O3" ++ + # -ffast-math tests + set DEFAULT_VECTCFLAGS $SAVED_DEFAULT_VECTCFLAGS + lappend DEFAULT_VECTCFLAGS "-ffast-math" +diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c +index fcc0726bd..d78b06455 100644 +--- a/gcc/tree-vect-data-refs.c ++++ b/gcc/tree-vect-data-refs.c +@@ -2647,6 +2647,9 @@ vect_analyze_group_access_1 (dr_vec_info *dr_info) + DR_GROUP_GAP (stmt_info) = groupsize - last_accessed_element; + + DR_GROUP_SIZE (stmt_info) = groupsize; ++ ++ DR_GROUP_SLP_TRANSPOSE (stmt_info) = false; ++ + if (dump_enabled_p ()) + { + dump_printf_loc (MSG_NOTE, vect_location, +@@ -2676,6 +2679,20 @@ vect_analyze_group_access_1 (dr_vec_info *dr_info) + DR_GROUP_GAP (stmt_info)); + } + ++ /* SLP: create an SLP data structure for every interleaving group of ++ loads for further analysis in vect_analyse_slp. */ ++ if (DR_IS_READ (dr) && !slp_impossible) ++ { ++ if (loop_vinfo) ++ { ++ LOOP_VINFO_GROUPED_LOADS (loop_vinfo).safe_push (stmt_info); ++ } ++ if (bb_vinfo) ++ { ++ BB_VINFO_GROUPED_LOADS (bb_vinfo).safe_push (stmt_info); ++ } ++ } ++ + /* SLP: create an SLP data structure for every interleaving group of + stores for further analysis in vect_analyse_slp. */ + if (DR_IS_WRITE (dr) && !slp_impossible) +@@ -5413,6 +5430,225 @@ vect_permute_store_chain (vec<tree> dr_chain, + } + } + ++/* Encoding the PERM_MASK_FIRST. */ ++ ++static void ++vect_indices_encoding_first (tree vectype, unsigned int array_num, ++ tree &perm_mask_high_first, ++ tree &perm_mask_low_first) ++{ ++ unsigned int nelt = TYPE_VECTOR_SUBPARTS (vectype).to_constant (); ++ vec_perm_builder sel (nelt, nelt, 1); ++ sel.quick_grow (nelt); ++ unsigned int group_num = nelt / array_num; ++ unsigned int index = 0; ++ unsigned int array = 0; ++ unsigned int group = 0; ++ ++ /* The encoding has 1 pattern in the fisrt stage. */ ++ for (array = 0; array < array_num / 2; array++) ++ { ++ for (group = 0; group < group_num * 2; group++) ++ { ++ sel[index++] = array + array_num * group; ++ } ++ } ++ vec_perm_indices indices (sel, 2, nelt); ++ perm_mask_high_first = vect_gen_perm_mask_checked (vectype, indices); ++ ++ index = 0; ++ for (array = array_num / 2; array < array_num; array++) ++ { ++ for (group = 0; group < group_num * 2; group++) ++ { ++ sel[index++] = array + array_num * group; ++ } ++ } ++ indices.new_vector (sel, 2, nelt); ++ perm_mask_low_first = vect_gen_perm_mask_checked (vectype, indices); ++} ++ ++/* Encoding the PERM_MASK. */ ++ ++static void ++vect_indices_encoding (tree vectype, unsigned int array_num, ++ tree &perm_mask_high, tree &perm_mask_low) ++{ ++ unsigned int nelt = TYPE_VECTOR_SUBPARTS (vectype).to_constant (); ++ vec_perm_builder sel (nelt, nelt, 1); ++ sel.quick_grow (nelt); ++ unsigned int group_num = nelt / array_num; ++ unsigned int index = 0; ++ unsigned int array = 0; ++ unsigned int group = 0; ++ ++ /* The encoding has 2 patterns in the folllowing stages. */ ++ for (array = 0; array < array_num / 2; array++) ++ { ++ for (group = 0; group < group_num; group++) ++ { ++ sel[index++] = group + group_num * array; ++ } ++ for (group = 0; group < group_num; group++) ++ { ++ sel[index++] = nelt + group + group_num * array; ++ } ++ } ++ vec_perm_indices indices (sel, 2, nelt); ++ perm_mask_high = vect_gen_perm_mask_checked (vectype, indices); ++ ++ index = 0; ++ for (array = array_num / 2; array < array_num; array++) ++ { ++ for (group = 0; group < group_num; group++) ++ { ++ sel[index++] = group + group_num * array; ++ } ++ for (group = 0; group < group_num; group++) ++ { ++ sel[index++] = nelt + group + group_num * array; ++ } ++ } ++ indices.new_vector (sel, 2, nelt); ++ perm_mask_low = vect_gen_perm_mask_checked (vectype, indices); ++} ++ ++/* Function vect_transpose_store_chain. ++ ++ Given a chain of interleaved stores in DR_CHAIN of LENGTH and ARRAY_NUM that ++ must be a power of 2. Generate interleave_high/low stmts to reorder ++ the data correctly for the stores. Return the final references for stores ++ in RESULT_CHAIN. This function is similar to vect_permute_store_chain (), ++ we interleave the contents of the vectors in their order. ++ ++ E.g., LENGTH is 4, the scalar type is short (i.e., VF is 8) and ARRAY_NUM ++ is 4. That is, the input is 4 vectors each containing 8 elements. ++ And 2 (VF / ARRAY_NUM) of 8 elements come from the same array. we interleave ++ the contents of the four vectors in their order. We assign a number to each ++ element, the input sequence is: ++ ++ 1st vec: 0 1 2 3 4 5 6 7 ++ 2nd vec: 8 9 10 11 12 13 14 15 ++ 3rd vec: 16 17 18 19 20 21 22 23 ++ 4th vec: 24 25 26 27 28 29 30 31 ++ ++ The output sequence should be: ++ ++ 1st vec: 0 4 8 12 16 20 24 28 ++ 2nd vec: 1 5 9 13 17 21 25 29 ++ 3rd vec: 2 6 10 14 18 22 26 30 ++ 4th vec: 3 7 11 15 19 23 27 31 ++ ++ In our example, ++ We get 2 (VF / ARRAY_NUM) elements together in every vector. ++ ++ I1: 0 4 1 5 2 6 3 7 ++ I2: 8 12 9 13 10 14 11 15 ++ I3: 16 20 17 21 18 22 19 23 ++ I4: 24 28 25 29 26 30 27 31 ++ ++ Then, we use interleave_high/low instructions to create such output. ++ Every 2 (VF / ARRAY_NUM) elements are regarded as a whole. The permutation ++ is done in log LENGTH stages. ++ ++ I1: interleave_high (1st vec, 3rd vec) ++ I2: interleave_low (1st vec, 3rd vec) ++ I3: interleave_high (2nd vec, 4th vec) ++ I4: interleave_low (2nd vec, 4th vec) ++ ++ The first stage of the sequence should be: ++ ++ I1: 0 4 16 20 1 5 17 21 ++ I2: 2 6 18 22 3 7 19 23 ++ I3: 8 12 24 28 9 13 25 29 ++ I4: 10 14 26 30 11 15 27 31 ++ ++ The following stage sequence should be, i.e. the final result is: ++ ++ I1: 0 4 8 12 16 20 24 28 ++ I2: 1 5 9 13 17 21 25 29 ++ I3: 2 6 10 14 18 22 26 30 ++ I4: 3 7 11 15 19 23 27 31. */ ++ ++void ++vect_transpose_store_chain (vec<tree> dr_chain, unsigned int length, ++ unsigned int array_num, stmt_vec_info stmt_info, ++ gimple_stmt_iterator *gsi, vec<tree> *result_chain) ++{ ++ gimple *perm_stmt = NULL; ++ tree vectype = STMT_VINFO_VECTYPE (stmt_info); ++ tree perm_mask_low_first = NULL; ++ tree perm_mask_high_first = NULL; ++ tree perm_mask_low = NULL; ++ tree perm_mask_high = NULL; ++ unsigned int log_length = exact_log2 (length); ++ ++ /* Only power of 2 is supported. */ ++ gcc_assert (pow2p_hwi (length)); ++ ++ /* The encoding has 2 types, one for the grouped pattern in the fisrt stage, ++ another for the interleaved patterns in the following stages. */ ++ gcc_assert (array_num != 0); ++ ++ /* Create grouped stmt (in the first stage): ++ group = nelt / array_num; ++ high_first = VEC_PERM_EXPR <vect1, vect2, ++ {0, array_num, 2*array_num, ..., (2*group-1)*array_num, ++ 1, 1+array_num, 1+2*array_num, ..., 1+(2*group-1)*array_num, ++ ..., ++ array_num/2-1, (array_num/2-1)+array_num, ..., ++ (array_num/2-1)+(2*group-1)*array_num}> ++ low_first = VEC_PERM_EXPR <vect1, vect2, ++ {array_num/2, array_num/2+array_num, array_num/2+2*array_num, ++ ..., array_num/2+(2*group-1)*array_num, ++ array_num/2+1, array_num/2+1+array_num, ++ ..., array_num/2+1+(2*group-1)*array_num, ++ ..., ++ array_num-1, array_num-1+array_num, ++ ..., array_num-1+(2*group-1)*array_num}> */ ++ vect_indices_encoding_first (vectype, array_num, perm_mask_high_first, ++ perm_mask_low_first); ++ ++ /* Create interleaving stmt (in the following stages): ++ high = VEC_PERM_EXPR <vect1, vect2, {0, 1, ..., group-1, ++ nelt, nelt+1, ..., nelt+group-1, ++ group, group+1, ..., 2*group-1, ++ nelt+group, nelt+group+1, ..., nelt+2*group-1, ++ ...}> ++ low = VEC_PERM_EXPR <vect1, vect2, ++ {nelt/2, nelt/2+1, ..., nelt/2+group-1, ++ nelt*3/2, nelt*3/2+1, ..., nelt*3/2+group-1, ++ nelt/2+group, nelt/2+group+1, ..., nelt/2+2*group-1, ++ nelt*3/2+group, nelt*3/2+group+1, ..., nelt*3/2+2*group-1, ++ ...}> */ ++ vect_indices_encoding (vectype, array_num, perm_mask_high, perm_mask_low); ++ ++ for (unsigned int perm_time = 0; perm_time < log_length; perm_time++) ++ { ++ for (unsigned int index = 0; index < length / 2; index++) ++ { ++ tree vect1 = dr_chain[index]; ++ tree vect2 = dr_chain[index + length / 2]; ++ ++ tree high = make_temp_ssa_name (vectype, NULL, "vect_inter_high"); ++ perm_stmt = gimple_build_assign (high, VEC_PERM_EXPR, vect1, vect2, ++ perm_time == 0 ? perm_mask_high_first ++ : perm_mask_high); ++ vect_finish_stmt_generation (stmt_info, perm_stmt, gsi); ++ (*result_chain)[2 * index] = high; ++ ++ tree low = make_temp_ssa_name (vectype, NULL, "vect_inter_low"); ++ perm_stmt = gimple_build_assign (low, VEC_PERM_EXPR, vect1, vect2, ++ perm_time == 0 ? perm_mask_low_first ++ : perm_mask_low); ++ vect_finish_stmt_generation (stmt_info, perm_stmt, gsi); ++ (*result_chain)[2 * index+1] = low; ++ } ++ memcpy (dr_chain.address (), result_chain->address (), ++ length * sizeof (tree)); ++ } ++} ++ + /* Function vect_setup_realignment + + This function is called when vectorizing an unaligned load using +diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c +index 476b32370..d30463b96 100644 +--- a/gcc/tree-vect-slp.c ++++ b/gcc/tree-vect-slp.c +@@ -2414,11 +2414,13 @@ vect_analyze_slp_instance (vec_info *vinfo, + + /* For basic block SLP, try to break the group up into multiples of the + vector size. */ ++ bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo); + unsigned HOST_WIDE_INT const_nunits; + if (is_a <bb_vec_info> (vinfo) + && STMT_VINFO_GROUPED_ACCESS (stmt_info) + && DR_GROUP_FIRST_ELEMENT (stmt_info) +- && nunits.is_constant (&const_nunits)) ++ && nunits.is_constant (&const_nunits) ++ && !bb_vinfo->transposed) + { + /* We consider breaking the group only on VF boundaries from the existing + start. */ +@@ -2455,6 +2457,898 @@ vect_analyze_slp_instance (vec_info *vinfo, + return false; + } + ++static inline bool ++is_const_assign (stmt_vec_info store_elem) ++{ ++ if (store_elem == NULL) ++ { ++ gcc_unreachable (); ++ } ++ gimple *stmt = store_elem->stmt; ++ gimple_rhs_class rhs_class = gimple_assign_rhs_class (stmt); ++ return rhs_class == GIMPLE_SINGLE_RHS ++ && TREE_CONSTANT (gimple_assign_rhs1 (store_elem->stmt)); ++} ++ ++/* Push inits to INNERMOST_INITS and check const assign. */ ++ ++static bool ++record_innermost (vec<tree> &innermost_inits, ++ vec<tree> &innermost_offsets, ++ stmt_vec_info stmt_vinfo) ++{ ++ if (!stmt_vinfo) ++ { ++ return false; ++ } ++ stmt_vec_info next_info = stmt_vinfo; ++ while (next_info) ++ { ++ /* No need to vectorize constant assign in a transposed version. */ ++ if (is_const_assign (next_info)) ++ { ++ if (dump_enabled_p ()) ++ { ++ dump_printf_loc (MSG_NOTE, vect_location, ++ "no need to vectorize, store is const assign: %G", ++ next_info->stmt); ++ } ++ return false; ++ } ++ innermost_inits.safe_push (STMT_VINFO_DR_INIT (next_info)); ++ innermost_offsets.safe_push (STMT_VINFO_DR_OFFSET (next_info)); ++ next_info = DR_GROUP_NEXT_ELEMENT (next_info); ++ } ++ return true; ++} ++ ++/* Compare inits to INNERMOST_INITS, return FALSE if inits do not match ++ the first grouped_store. And check const assign meanwhile. */ ++ ++static bool ++compare_innermost (const vec<tree> &innermost_inits, ++ const vec<tree> &innermost_offsets, ++ stmt_vec_info stmt_vinfo) ++{ ++ if (!stmt_vinfo || innermost_inits.length () != stmt_vinfo->size) ++ { ++ return false; ++ } ++ stmt_vec_info next_info = stmt_vinfo; ++ unsigned int i = 0; ++ while (next_info) ++ { ++ if (is_const_assign (next_info)) ++ { ++ if (dump_enabled_p ()) ++ { ++ dump_printf_loc (MSG_NOTE, vect_location, ++ "no need to vectorize, store is const " ++ "assign: %G", next_info->stmt); ++ } ++ return false; ++ } ++ if (innermost_inits[i] != STMT_VINFO_DR_INIT (next_info) ++ || innermost_offsets[i] != STMT_VINFO_DR_OFFSET (next_info)) ++ { ++ return false; ++ } ++ next_info = DR_GROUP_NEXT_ELEMENT (next_info); ++ i++; ++ } ++ return true; ++} ++ ++/* Check if grouped stores are of same type. ++ input: t1/t2 = TREE_TYPE (gimple_assign_lhs (first_element->stmt)) ++ output: 0 if same, 1 or -1 else. */ ++ ++static int ++tree_type_cmp (const tree t1, const tree t2) ++{ ++ gcc_checking_assert (t1 != NULL && t2 != NULL); ++ if (t1 != t2) ++ { ++ if (TREE_CODE (t1) != TREE_CODE (t2)) ++ { ++ return TREE_CODE (t1) > TREE_CODE (t2) ? 1 : -1; ++ } ++ if (TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2)) ++ { ++ return TYPE_UNSIGNED (t1) > TYPE_UNSIGNED (t2) ? 1 : -1; ++ } ++ if (TYPE_PRECISION (t1) != TYPE_PRECISION (t2)) ++ { ++ return TYPE_PRECISION (t1) > TYPE_PRECISION (t2) ? 1 : -1; ++ } ++ } ++ return 0; ++} ++ ++/* Check it if 2 grouped stores are of same type that ++ we can analyze them in a transpose group. */ ++static int ++check_same_store_type (stmt_vec_info grp1, stmt_vec_info grp2) ++{ ++ if (grp1 == grp2) ++ { ++ return 0; ++ } ++ if (grp1->size != grp2->size) ++ { ++ return grp1->size > grp2->size ? 1 : -1; ++ } ++ tree lhs1 = gimple_assign_lhs (grp1->stmt); ++ tree lhs2 = gimple_assign_lhs (grp2->stmt); ++ if (TREE_CODE (lhs1) != TREE_CODE (lhs2)) ++ { ++ return TREE_CODE (lhs1) > TREE_CODE (lhs2) ? 1 : -1; ++ } ++ tree grp_type1 = TREE_TYPE (gimple_assign_lhs (grp1->stmt)); ++ tree grp_type2 = TREE_TYPE (gimple_assign_lhs (grp2->stmt)); ++ int cmp = tree_type_cmp (grp_type1, grp_type2); ++ return cmp; ++} ++ ++/* Sort grouped stores according to group_size and store_type. ++ output: 0 if same, 1 if grp1 > grp2, -1 otherwise. */ ++ ++static int ++grouped_store_cmp (const void *grp1_, const void *grp2_) ++{ ++ stmt_vec_info grp1 = *(stmt_vec_info *)const_cast<void *>(grp1_); ++ stmt_vec_info grp2 = *(stmt_vec_info *)const_cast<void *>(grp2_); ++ return check_same_store_type (grp1, grp2); ++} ++ ++/* Transposing is based on permutation in registers. Permutation requires ++ vector length being power of 2 and satisfying the vector mode. */ ++ ++static inline bool ++check_filling_reg (stmt_vec_info current_element) ++{ ++ if (current_element->size == 0) ++ { ++ return false; ++ } ++ /* If the gimple STMT was already vectorized in vect pass, it's unable to ++ conduct transpose analysis, skip it. */ ++ bool lhs_vectorized ++ = TREE_CODE (TREE_TYPE (gimple_get_lhs (current_element->stmt))) ++ == VECTOR_TYPE; ++ bool rhs_vectorized ++ = TREE_CODE (TREE_TYPE (gimple_assign_rhs1 (current_element->stmt))) ++ == VECTOR_TYPE; ++ if (lhs_vectorized || rhs_vectorized) ++ { ++ return false; ++ } ++ unsigned int store_precision ++ = TYPE_PRECISION (TREE_TYPE (gimple_get_lhs (current_element->stmt))); ++ auto_vector_modes vector_modes; ++ targetm.vectorize.autovectorize_vector_modes (&vector_modes, false); ++ unsigned min_mode_size = -1u; ++ for (unsigned i = 0; i < vector_modes.length (); i++) ++ { ++ unsigned mode_bit_size = (GET_MODE_BITSIZE (vector_modes[i])).coeffs[0]; ++ min_mode_size = mode_bit_size < min_mode_size ++ ? mode_bit_size : min_mode_size; ++ } ++ return store_precision != 0 ++ && pow2p_hwi (current_element->size) ++ && (current_element->size * store_precision % min_mode_size == 0); ++} ++ ++/* Check if previous groups are suitable to transpose, if not, set their ++ group number to -1, reduce grp_num and clear current_groups. ++ Otherwise, just clear current_groups. */ ++ ++static void ++check_and_clear_groups (vec<stmt_vec_info> current_groups, ++ unsigned int &grp_num) ++{ ++ stmt_vec_info first_element; ++ if (current_groups.length () == 1 ++ || (current_groups.length () != 0 ++ && !pow2p_hwi (current_groups.length ()))) ++ { ++ while (current_groups.length () != 0) ++ { ++ first_element = current_groups.pop (); ++ first_element->group_number = -1; ++ } ++ grp_num--; ++ } ++ else ++ { ++ while (current_groups.length ()) ++ { ++ current_groups.pop (); ++ } ++ } ++} ++ ++ ++/* Make sure that transpose slp vectorization is conducted only if grouped ++ stores are one dimension array ref. */ ++ ++static bool ++is_store_one_dim_array (gimple *stmt) ++{ ++ tree op = gimple_get_lhs (stmt); ++ if (TREE_CODE (op) != ARRAY_REF) ++ return false; ++ return TREE_OPERAND_LENGTH (op) > 0 ++ && TREE_OPERAND_LENGTH (TREE_OPERAND (op, 0)) == 0; ++} ++ ++/* Set grouped_stores with similar MEM_REF to the same group and mark their ++ grp_num. Groups with same grp_num consist the minimum unit to analyze ++ transpose. Return num of such units. */ ++ ++static unsigned ++vect_prepare_transpose (bb_vec_info bb_vinfo) ++{ ++ stmt_vec_info current_element = NULL; ++ stmt_vec_info first_element = NULL; ++ unsigned int i = 0; ++ unsigned int grp_num = 0; ++ /* Use arrays to record MEM_REF data in different GROUPED_STORES. */ ++ auto_vec<tree> innermost_inits; ++ auto_vec<tree> innermost_offsets; ++ ++ /* A set of stmt_vec_info with same store type. Analyze them if their size ++ is suitable to transpose. */ ++ auto_vec<stmt_vec_info> current_groups; ++ ++ FOR_EACH_VEC_ELT (bb_vinfo->grouped_stores, i, current_element) ++ { ++ /* Compare current grouped_store to the first one if first_element exists, ++ push current_element to current_groups if they are similar on innermost ++ behavior of MEM_REF. */ ++ if (first_element != NULL ++ && !check_same_store_type (first_element, current_element) ++ && compare_innermost (innermost_inits, innermost_offsets, ++ current_element)) ++ { ++ current_groups.safe_push (current_element); ++ current_element->group_number = grp_num; ++ /* If current_element is the last element in grouped_stores, continue ++ will exit the loop and leave the last group unanalyzed. */ ++ if (i == bb_vinfo->grouped_stores.length () - 1) ++ { ++ check_and_clear_groups (current_groups, grp_num); ++ } ++ continue; ++ } ++ check_and_clear_groups (current_groups, grp_num); ++ innermost_inits.release (); ++ innermost_offsets.release (); ++ /* Beginning of a new group to analyze whether they are able to consist ++ a unit to conduct transpose analysis. */ ++ first_element = NULL; ++ if (is_store_one_dim_array (current_element->stmt) ++ && check_filling_reg (current_element) ++ && record_innermost (innermost_inits, innermost_offsets, ++ current_element)) ++ { ++ first_element = current_element; ++ current_groups.safe_push (current_element); ++ current_element->group_number = ++grp_num; ++ if (i == bb_vinfo->grouped_stores.length () - 1) ++ { ++ check_and_clear_groups (current_groups, grp_num); ++ } ++ continue; ++ } ++ current_element->group_number = -1; ++ } ++ return grp_num; ++} ++ ++/* Return a flag to transpose grouped stores before building slp tree. ++ Add bool may_transpose in class vec_info. */ ++ ++static bool ++vect_may_transpose (bb_vec_info bb_vinfo) ++{ ++ if (targetm.vectorize.vec_perm_const == NULL) ++ { ++ return false; ++ } ++ if (bb_vinfo->grouped_stores.length () < 2) ++ { ++ return false; ++ } ++ DUMP_VECT_SCOPE ("analyze if grouped stores may transpose to slp"); ++ /* Sort grouped_stores according to size and type for function ++ vect_prepare_transpose (). */ ++ bb_vinfo->grouped_stores.qsort (grouped_store_cmp); ++ ++ int groups = vect_prepare_transpose (bb_vinfo); ++ BB_VINFO_TRANS_GROUPS (bb_vinfo) = groups; ++ if (dump_enabled_p ()) ++ dump_printf_loc (MSG_NOTE, vect_location, ++ "%d groups to analyze transposed slp.\n", groups); ++ return groups != 0; ++} ++ ++/* Get the base address of STMT_INFO. */ ++ ++static tree ++get_op_base_address (stmt_vec_info stmt_info) ++{ ++ struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info); ++ tree op = DR_BASE_ADDRESS (dr); ++ while (TREE_OPERAND_LENGTH (op) > 0) ++ { ++ op = TREE_OPERAND (op, 0); ++ } ++ return op; ++} ++ ++/* Compare the UID of the two stmt_info STMTINFO_A and STMTINFO_B. ++ Sorting them in ascending order. */ ++ ++static int ++dr_group_cmp (const void *stmtinfo_a_, const void *stmtinfo_b_) ++{ ++ stmt_vec_info stmtinfo_a ++ = *(stmt_vec_info *) const_cast<void *> (stmtinfo_a_); ++ stmt_vec_info stmtinfo_b ++ = *(stmt_vec_info *) const_cast<void *> (stmtinfo_b_); ++ ++ /* Stabilize sort. */ ++ if (stmtinfo_a == stmtinfo_b) ++ { ++ return 0; ++ } ++ return gimple_uid (stmtinfo_a->stmt) < gimple_uid (stmtinfo_b->stmt) ? -1 : 1; ++} ++ ++/* Find the first elements of the grouped loads which are required to merge. */ ++ ++static void ++vect_slp_grouped_load_find (bb_vec_info bb_vinfo, vec<bool> &visited, ++ vec<stmt_vec_info> &res) ++{ ++ unsigned int i = 0; ++ stmt_vec_info merge_first_element = NULL; ++ stmt_vec_info first_element = NULL; ++ tree opa = NULL; ++ unsigned int grp_size_a = 0; ++ FOR_EACH_VEC_ELT (bb_vinfo->grouped_loads, i, first_element) ++ { ++ if (visited[i]) ++ { ++ continue; ++ } ++ if (!STMT_VINFO_GROUPED_ACCESS (first_element) ++ || !pow2p_hwi (DR_GROUP_SIZE (first_element))) ++ { ++ /* Non-conforming grouped load should be grouped separately. */ ++ if (merge_first_element == NULL) ++ { ++ visited[i] = true; ++ res.safe_push (first_element); ++ return; ++ } ++ } ++ if (merge_first_element == NULL) ++ { ++ merge_first_element = first_element; ++ opa = get_op_base_address (first_element); ++ grp_size_a = DR_GROUP_SIZE (first_element); ++ res.safe_push (first_element); ++ visited[i] = true; ++ continue; ++ } ++ ++ /* If the two first elements are of the same base address and group size, ++ these two grouped loads need to be merged. */ ++ tree opb = get_op_base_address (first_element); ++ unsigned int grp_size_b = DR_GROUP_SIZE (first_element); ++ if (opa == opb && grp_size_a == grp_size_b) ++ { ++ res.safe_push (first_element); ++ visited[i] = true; ++ } ++ } ++} ++ ++/* Merge the grouped loads that are found from ++ vect_slp_grouped_load_find (). */ ++ ++static stmt_vec_info ++vect_slp_grouped_load_merge (vec<stmt_vec_info> res) ++{ ++ stmt_vec_info stmt_info = res[0]; ++ if (res.length () == 1) ++ { ++ return stmt_info; ++ } ++ unsigned int i = 0; ++ unsigned int size = DR_GROUP_SIZE (res[0]); ++ unsigned int new_group_size = size * res.length (); ++ stmt_vec_info first_element = NULL; ++ stmt_vec_info merge_first_element = NULL; ++ stmt_vec_info last_element = NULL; ++ FOR_EACH_VEC_ELT (res, i, first_element) ++ { ++ if (merge_first_element == NULL) ++ { ++ merge_first_element = first_element; ++ last_element = merge_first_element; ++ size = DR_GROUP_SIZE (merge_first_element); ++ } ++ ++ if (last_element != first_element ++ && !DR_GROUP_NEXT_ELEMENT (last_element)) ++ { ++ DR_GROUP_NEXT_ELEMENT (last_element) = first_element; ++ /* Store the gap from the previous member of the group. If there is ++ no gap in the access, DR_GROUP_GAP is always 1. */ ++ DR_GROUP_GAP_TRANS (first_element) = DR_GROUP_GAP (first_element); ++ DR_GROUP_GAP (first_element) = 1; ++ } ++ for (stmt_info = first_element; stmt_info; ++ stmt_info = DR_GROUP_NEXT_ELEMENT (stmt_info)) ++ { ++ DR_GROUP_FIRST_ELEMENT (stmt_info) = merge_first_element; ++ DR_GROUP_SIZE_TRANS (stmt_info) = DR_GROUP_SIZE (stmt_info); ++ DR_GROUP_SIZE (stmt_info) = new_group_size; ++ last_element = stmt_info; ++ } ++ } ++ DR_GROUP_SIZE (merge_first_element) = new_group_size; ++ DR_GROUP_SLP_TRANSPOSE (merge_first_element) = true; ++ DR_GROUP_NEXT_ELEMENT (last_element) = NULL; ++ return merge_first_element; ++} ++ ++/* Merge the grouped loads which have the same base address and group size. ++ For example, for grouped loads (opa_1, opa_2, opb_1, opb_2): ++ opa_1: a0->a1->a2->a3 ++ opa_2: a8->a9->a10->a11 ++ opb_1: b0->b1 ++ opb_2: b16->b17 ++ we can probably get two merged grouped loads: ++ opa: a0->a1->a2->a3->a8->a9->a10->a11 ++ opb: b0->b1->b16->b17. */ ++ ++static bool ++vect_merge_slp_grouped_loads (bb_vec_info bb_vinfo) ++{ ++ if (bb_vinfo->grouped_loads.length () <= 0) ++ { ++ if (dump_enabled_p ()) ++ { ++ dump_printf_loc (MSG_NOTE, vect_location, ++ "The number of grouped loads is 0.\n"); ++ } ++ return false; ++ } ++ bb_vinfo->grouped_loads.qsort (dr_group_cmp); ++ auto_vec<bool> visited (bb_vinfo->grouped_loads.length ()); ++ auto_vec<stmt_vec_info> grouped_loads_merge; ++ for (unsigned int i = 0; i < bb_vinfo->grouped_loads.length (); i++) ++ { ++ visited.safe_push (false); ++ } ++ while (1) ++ { ++ /* Find grouped loads which are required to merge. */ ++ auto_vec<stmt_vec_info> res; ++ vect_slp_grouped_load_find (bb_vinfo, visited, res); ++ if (res.is_empty ()) ++ { ++ break; ++ } ++ /* Merge the required grouped loads into one group. */ ++ grouped_loads_merge.safe_push (vect_slp_grouped_load_merge (res)); ++ } ++ if (grouped_loads_merge.length () == bb_vinfo->grouped_loads.length ()) ++ { ++ if (dump_enabled_p ()) ++ { ++ dump_printf_loc (MSG_NOTE, vect_location, ++ "No grouped loads need to be merged.\n"); ++ } ++ return false; ++ } ++ if (dump_enabled_p ()) ++ { ++ dump_printf_loc (MSG_NOTE, vect_location, ++ "Merging grouped loads successfully.\n"); ++ } ++ BB_VINFO_GROUPED_LOADS (bb_vinfo).release (); ++ for (unsigned int i = 0; i < grouped_loads_merge.length (); i++) ++ { ++ BB_VINFO_GROUPED_LOADS (bb_vinfo).safe_push (grouped_loads_merge[i]); ++ } ++ return true; ++} ++ ++/* Find the first elements of the grouped stores ++ which are required to transpose and merge. */ ++ ++static void ++vect_slp_grouped_store_find (bb_vec_info bb_vinfo, vec<bool> &visited, ++ vec<stmt_vec_info> &res) ++{ ++ stmt_vec_info first_element = NULL; ++ stmt_vec_info merge_first_element = NULL; ++ unsigned int k = 0; ++ FOR_EACH_VEC_ELT (bb_vinfo->grouped_stores, k, first_element) ++ { ++ if (visited[k]) ++ { ++ continue; ++ } ++ /* Non-conforming grouped store should be grouped separately. */ ++ if (!STMT_VINFO_GROUPED_ACCESS (first_element) ++ || first_element->group_number == -1) ++ { ++ if (merge_first_element == NULL) ++ { ++ visited[k] = true; ++ res.safe_push (first_element); ++ return; ++ } ++ } ++ if (first_element->group_number != -1 ++ && merge_first_element == NULL) ++ { ++ merge_first_element = first_element; ++ } ++ if (merge_first_element->group_number == first_element->group_number) ++ { ++ visited[k] = true; ++ res.safe_push (first_element); ++ } ++ } ++} ++ ++/* Transpose and merge the grouped stores that are found from ++ vect_slp_grouped_store_find (). */ ++ ++static stmt_vec_info ++vect_slp_grouped_store_transform (vec<stmt_vec_info> res) ++{ ++ stmt_vec_info stmt_info = res[0]; ++ if (res.length () == 1) ++ { ++ return stmt_info; ++ } ++ stmt_vec_info rearrange_first_element = stmt_info; ++ stmt_vec_info last_element = rearrange_first_element; ++ ++ unsigned int size = DR_GROUP_SIZE (rearrange_first_element); ++ unsigned int new_group_size = size * res.length (); ++ for (unsigned int i = 1; i < res.length (); i++) ++ { ++ /* Store the gap from the previous member of the group. If there is no ++ gap in the access, DR_GROUP_GAP is always 1. */ ++ DR_GROUP_GAP_TRANS (res[i]) = DR_GROUP_GAP (res[i]); ++ DR_GROUP_GAP (res[i]) = 1; ++ } ++ while (!res.is_empty ()) ++ { ++ stmt_info = res[0]; ++ res.ordered_remove (0); ++ if (DR_GROUP_NEXT_ELEMENT (stmt_info)) ++ { ++ res.safe_push (DR_GROUP_NEXT_ELEMENT (stmt_info)); ++ } ++ DR_GROUP_FIRST_ELEMENT (stmt_info) = rearrange_first_element; ++ DR_GROUP_NEXT_ELEMENT (last_element) = stmt_info; ++ DR_GROUP_SIZE_TRANS (stmt_info) = DR_GROUP_SIZE (stmt_info); ++ DR_GROUP_SIZE (stmt_info) = new_group_size; ++ last_element = stmt_info; ++ } ++ ++ DR_GROUP_SIZE (rearrange_first_element) = new_group_size; ++ DR_GROUP_SLP_TRANSPOSE (rearrange_first_element) = true; ++ DR_GROUP_NEXT_ELEMENT (last_element) = NULL; ++ return rearrange_first_element; ++} ++ ++/* Save the STMT_INFO in the grouped stores to BB_VINFO_SCALAR_STORES for ++ transposing back grouped stores. */ ++ ++static void ++get_scalar_stores (bb_vec_info bb_vinfo) ++{ ++ unsigned int k = 0; ++ stmt_vec_info first_element = NULL; ++ FOR_EACH_VEC_ELT (bb_vinfo->grouped_stores, k, first_element) ++ { ++ /* Filter the grouped store which is unnecessary for transposing. */ ++ if (!STMT_VINFO_GROUPED_ACCESS (first_element) ++ || first_element->group_number == -1) ++ { ++ continue; ++ } ++ vec<stmt_vec_info> tmp_scalar_store; ++ tmp_scalar_store.create (DR_GROUP_SIZE (first_element)); ++ for (stmt_vec_info stmt_info = first_element; stmt_info; ++ stmt_info = DR_GROUP_NEXT_ELEMENT (stmt_info)) ++ { ++ tmp_scalar_store.safe_push (stmt_info); ++ } ++ BB_VINFO_SCALAR_STORES (bb_vinfo).safe_push (tmp_scalar_store); ++ } ++} ++ ++/* Transpose and merge the grouped stores which have the same group number. ++ For example, for grouped stores (opa_0, opa_1, opa_2, opa_3): ++ opa_0: a00->a01->a02->a03 ++ opa_1: a10->a11->a12->a13 ++ opa_2: a20->a21->a22->a23 ++ opa_2: a30->a31->a32->a33 ++ we can probably get the merged grouped store: ++ opa: a00->a10->a20->a30 ++ ->a01->a11->a21->a31 ++ ->a02->a12->a22->a32 ++ ->a03->a13->a23->a33. */ ++ ++static bool ++vect_transform_slp_grouped_stores (bb_vec_info bb_vinfo) ++{ ++ if (bb_vinfo->grouped_stores.length () <= 0) ++ { ++ if (dump_enabled_p ()) ++ { ++ dump_printf_loc (MSG_NOTE, vect_location, ++ "The number of grouped stores is 0.\n"); ++ } ++ return false; ++ } ++ ++ bb_vinfo->grouped_stores.qsort (dr_group_cmp); ++ auto_vec<stmt_vec_info> grouped_stores_merge; ++ auto_vec<bool> visited (bb_vinfo->grouped_stores.length ()); ++ unsigned int i = 0; ++ for (i = 0; i < bb_vinfo->grouped_stores.length (); i++) ++ { ++ visited.safe_push (false); ++ } ++ ++ /* Get scalar stores for the following transposition recovery. */ ++ get_scalar_stores (bb_vinfo); ++ ++ while (1) ++ { ++ /* Find grouped stores which are required to transpose and merge. */ ++ auto_vec<stmt_vec_info> res; ++ vect_slp_grouped_store_find (bb_vinfo, visited, res); ++ if (res.is_empty ()) ++ { ++ break; ++ } ++ /* Transpose and merge the required grouped stores into one group. */ ++ grouped_stores_merge.safe_push (vect_slp_grouped_store_transform (res)); ++ } ++ ++ BB_VINFO_GROUPED_STORES (bb_vinfo).release (); ++ for (i = 0; i < grouped_stores_merge.length (); i++) ++ { ++ BB_VINFO_GROUPED_STORES (bb_vinfo).safe_push (grouped_stores_merge[i]); ++ } ++ ++ if (dump_enabled_p ()) ++ { ++ dump_printf_loc (MSG_NOTE, vect_location, ++ "Transposing grouped stores successfully.\n"); ++ } ++ return true; ++} ++ ++/* A helpful function of vect_transform_back_slp_grouped_stores (). */ ++ ++static auto_vec<stmt_vec_info> ++vect_transform_back_slp_grouped_store (bb_vec_info bb_vinfo, ++ stmt_vec_info first_stmt_info) ++{ ++ auto_vec<stmt_vec_info> grouped_stores_split; ++ for (unsigned int i = 0; i < bb_vinfo->scalar_stores.length (); i++) ++ { ++ vec<stmt_vec_info> scalar_tmp = bb_vinfo->scalar_stores[i]; ++ if (scalar_tmp.length () > 1 ++ && scalar_tmp[0]->group_number != first_stmt_info->group_number) ++ { ++ continue; ++ } ++ stmt_vec_info cur_stmt_info = NULL; ++ stmt_vec_info cur_first_stmt_info = NULL; ++ stmt_vec_info last_stmt_info = NULL; ++ unsigned int k = 0; ++ FOR_EACH_VEC_ELT (scalar_tmp, k, cur_stmt_info) ++ { ++ if (k == 0) ++ { ++ cur_first_stmt_info = cur_stmt_info; ++ last_stmt_info = cur_stmt_info; ++ } ++ DR_GROUP_FIRST_ELEMENT (cur_stmt_info) = cur_first_stmt_info; ++ DR_GROUP_NEXT_ELEMENT (last_stmt_info) = cur_stmt_info; ++ last_stmt_info = cur_stmt_info; ++ } ++ DR_GROUP_SIZE (cur_first_stmt_info) = k; ++ DR_GROUP_NEXT_ELEMENT (last_stmt_info) = NULL; ++ if (first_stmt_info != cur_first_stmt_info) ++ { ++ DR_GROUP_GAP (cur_first_stmt_info) ++ = DR_GROUP_GAP_TRANS (cur_first_stmt_info); ++ DR_GROUP_SLP_TRANSPOSE (cur_first_stmt_info) = false; ++ DR_GROUP_NUMBER (cur_first_stmt_info) = -1; ++ } ++ grouped_stores_split.safe_push (cur_first_stmt_info); ++ } ++ return grouped_stores_split; ++} ++ ++/* Transform the grouped store back. */ ++ ++void ++vect_transform_back_slp_grouped_stores (bb_vec_info bb_vinfo, ++ stmt_vec_info first_stmt_info) ++{ ++ if (first_stmt_info->group_number == -1) ++ { ++ return; ++ } ++ /* Transform back. */ ++ auto_vec<stmt_vec_info> grouped_stores_split ++ = vect_transform_back_slp_grouped_store (bb_vinfo, first_stmt_info); ++ ++ /* Add the remaining grouped stores to grouped_stores_split. */ ++ stmt_vec_info first_element = NULL; ++ unsigned int i = 0; ++ FOR_EACH_VEC_ELT (bb_vinfo->grouped_stores, i, first_element) ++ { ++ if (first_element->group_number != first_stmt_info->group_number) ++ { ++ grouped_stores_split.safe_push (first_element); ++ } ++ } ++ DR_GROUP_SLP_TRANSPOSE (first_stmt_info) = false; ++ DR_GROUP_NUMBER (first_stmt_info) = -1; ++ BB_VINFO_GROUPED_STORES (bb_vinfo).release (); ++ for (i = 0; i < grouped_stores_split.length (); i++) ++ { ++ BB_VINFO_GROUPED_STORES (bb_vinfo).safe_push (grouped_stores_split[i]); ++ } ++} ++ ++/* Function check_for_slp_vectype ++ ++ Restriction for grouped stores by checking their vectype. ++ If the vectype of the grouped store is changed, it need transform back. ++ If all grouped stores need to be transformed back, return FALSE. */ ++ ++static bool ++check_for_slp_vectype (bb_vec_info bb_vinfo) ++{ ++ stmt_vec_info first_element = NULL; ++ unsigned int i = 0; ++ int count = 0; ++ auto_vec<stmt_vec_info> grouped_stores_check; ++ FOR_EACH_VEC_ELT (bb_vinfo->grouped_stores, i, first_element) ++ { ++ grouped_stores_check.safe_push (first_element); ++ } ++ FOR_EACH_VEC_ELT (grouped_stores_check, i, first_element) ++ { ++ if (STMT_VINFO_GROUPED_ACCESS (first_element) ++ && first_element->group_number != -1) ++ { ++ unsigned int group_size_b ++ = DR_GROUP_SIZE_TRANS (first_element); ++ tree vectype = STMT_VINFO_VECTYPE (first_element); ++ poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype); ++ if (nunits.to_constant () > group_size_b) ++ { ++ count++; ++ /* If the vectype is changed, this grouped store need ++ to be transformed back. */ ++ vect_transform_back_slp_grouped_stores (bb_vinfo, first_element); ++ if (dump_enabled_p ()) ++ { ++ dump_printf_loc (MSG_NOTE, vect_location, ++ "No supported: only supported for" ++ " group_size geq than nunits.\n"); ++ } ++ } ++ } ++ } ++ if (count == BB_VINFO_TRANS_GROUPS (bb_vinfo)) ++ { ++ return false; ++ } ++ return true; ++} ++ ++/* Function check_for_dr_alignment ++ ++ Check the alignment of the slp instance loads. ++ Return FALSE if a load cannot be vectorized. */ ++ ++static bool ++check_for_dr_alignment (slp_instance instance) ++{ ++ slp_tree node = NULL; ++ unsigned int i = 0; ++ FOR_EACH_VEC_ELT (SLP_INSTANCE_LOADS (instance), i, node) ++ { ++ stmt_vec_info first_stmt_info = SLP_TREE_SCALAR_STMTS (node)[0]; ++ dr_vec_info *first_dr_info = STMT_VINFO_DR_INFO (first_stmt_info); ++ enum dr_alignment_support supportable_dr_alignment ++ = vect_supportable_dr_alignment (first_dr_info, false); ++ if (supportable_dr_alignment == dr_explicit_realign_optimized ++ || supportable_dr_alignment == dr_explicit_realign) ++ { ++ return false; ++ } ++ } ++ return true; ++} ++ ++/* Initialize slp_transpose flag before transposing. */ ++ ++static void ++init_stmt_info_slp_transpose (bb_vec_info bb_vinfo) ++{ ++ stmt_vec_info first_element = NULL; ++ unsigned int k = 0; ++ FOR_EACH_VEC_ELT (bb_vinfo->grouped_stores, k, first_element) ++ { ++ if (STMT_VINFO_GROUPED_ACCESS (first_element)) ++ { ++ DR_GROUP_SLP_TRANSPOSE (first_element) = false; ++ } ++ } ++ FOR_EACH_VEC_ELT (bb_vinfo->grouped_loads, k, first_element) ++ { ++ if (STMT_VINFO_GROUPED_ACCESS (first_element)) ++ { ++ DR_GROUP_SLP_TRANSPOSE (first_element) = false; ++ } ++ } ++} ++ ++/* Analyze and transpose the stmts before building the SLP tree. */ ++ ++static bool ++vect_analyze_transpose (bb_vec_info bb_vinfo) ++{ ++ DUMP_VECT_SCOPE ("vect_analyze_transpose"); ++ ++ if (!vect_may_transpose (bb_vinfo)) ++ { ++ return false; ++ } ++ ++ /* For basic block SLP, try to merge the grouped stores and loads ++ into one group. */ ++ init_stmt_info_slp_transpose (bb_vinfo); ++ if (vect_transform_slp_grouped_stores (bb_vinfo) ++ && vect_merge_slp_grouped_loads (bb_vinfo)) ++ { ++ if (dump_enabled_p ()) ++ { ++ dump_printf_loc (MSG_NOTE, vect_location, ++ "Analysis succeeded with SLP transposed.\n"); ++ } ++ return true; ++ } ++ if (dump_enabled_p ()) ++ { ++ dump_printf_loc (MSG_NOTE, vect_location, ++ "Analysis failed with SLP transposed.\n"); ++ } ++ return false; ++} + + /* Check if there are stmts in the loop can be vectorized using SLP. Build SLP + trees of packed scalar stmts if SLP is possible. */ +@@ -3124,7 +4018,11 @@ vect_bb_vectorization_profitable_p (bb_vec_info bb_vinfo) + + vec_outside_cost = vec_prologue_cost + vec_epilogue_cost; + +- if (dump_enabled_p ()) ++ BB_VINFO_VEC_INSIDE_COST (bb_vinfo) = vec_inside_cost; ++ BB_VINFO_VEC_OUTSIDE_COST (bb_vinfo) = vec_outside_cost; ++ BB_VINFO_SCALAR_COST (bb_vinfo) = scalar_cost; ++ ++ if (!unlimited_cost_model (NULL) && dump_enabled_p ()) + { + dump_printf_loc (MSG_NOTE, vect_location, "Cost model analysis: \n"); + dump_printf (MSG_NOTE, " Vector inside of basic block cost: %d\n", +@@ -3239,6 +4137,22 @@ vect_slp_analyze_bb_1 (bb_vec_info bb_vinfo, int n_stmts, bool &fatal) + + vect_pattern_recog (bb_vinfo); + ++ /* Transpose grouped stores and loads for better vectorizable version. */ ++ if (bb_vinfo->transposed) ++ { ++ if (!vect_analyze_transpose (bb_vinfo)) ++ { ++ if (dump_enabled_p ()) ++ { ++ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, ++ "not vectorized: unhandled slp transposed in " ++ "basic block.\n"); ++ } ++ return false; ++ } ++ } ++ bb_vinfo->before_slp = true; ++ + /* Check the SLP opportunities in the basic block, analyze and build SLP + trees. */ + if (!vect_analyze_slp (bb_vinfo, n_stmts)) +@@ -3254,6 +4168,20 @@ vect_slp_analyze_bb_1 (bb_vec_info bb_vinfo, int n_stmts, bool &fatal) + return false; + } + ++ /* Check if the vectype is suitable for SLP transposed. */ ++ if (bb_vinfo->transposed && !check_for_slp_vectype (bb_vinfo)) ++ { ++ if (dump_enabled_p ()) ++ { ++ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, ++ "Failed to SLP transposed in the basic block.\n"); ++ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, ++ "not vectorized: vectype is not suitable for " ++ "SLP transposed in basic block.\n"); ++ } ++ return false; ++ } ++ + vect_record_base_alignments (bb_vinfo); + + /* Analyze and verify the alignment of data references and the +@@ -3286,6 +4214,27 @@ vect_slp_analyze_bb_1 (bb_vec_info bb_vinfo, int n_stmts, bool &fatal) + if (! BB_VINFO_SLP_INSTANCES (bb_vinfo).length ()) + return false; + ++ /* Check if the alignment is suitable for SLP transposed. */ ++ if (bb_vinfo->transposed) ++ { ++ for (i = 0; BB_VINFO_SLP_INSTANCES (bb_vinfo).iterate (i, &instance); i++) ++ { ++ if (!check_for_dr_alignment (instance)) ++ { ++ if (dump_enabled_p ()) ++ { ++ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, ++ "Failed to SLP transposed in the basic " ++ "block.\n"); ++ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, ++ "not vectorized: alignment is not suitable " ++ "for SLP transposed in basic block.\n"); ++ } ++ return false; ++ } ++ } ++ } ++ + if (!vect_slp_analyze_operations (bb_vinfo)) + { + if (dump_enabled_p ()) +@@ -3311,6 +4260,83 @@ vect_slp_analyze_bb_1 (bb_vec_info bb_vinfo, int n_stmts, bool &fatal) + return true; + } + ++static bool ++may_new_transpose_bbvinfo (bb_vec_info bb_vinfo_ori, bool res_ori) ++{ ++ /* If the flag is false or the slp analysis is broken before ++ vect_analyze_slp, we don't try to analyze the transposed SLP version. */ ++ if (!flag_tree_slp_transpose_vectorize ++ || !BB_VINFO_BEFORE_SLP (bb_vinfo_ori)) ++ { ++ return false; ++ } ++ ++ /* If the original bb_vinfo can't be vectorized, try to new a bb_vinfo ++ of the transposed version. */ ++ if (!res_ori) ++ { ++ return true; ++ } ++ ++ /* Caculate the cost of the original bb_vinfo. */ ++ if (unlimited_cost_model (NULL)) ++ { ++ vect_bb_vectorization_profitable_p (bb_vinfo_ori); ++ } ++ /* If the vec cost and scalar cost are not much difference (here we set the ++ threshold to 4), we try to new a bb_vinfo of the transposed version. */ ++ if (BB_VINFO_SCALAR_COST (bb_vinfo_ori) ++ < 4 * (BB_VINFO_VEC_INSIDE_COST (bb_vinfo_ori) ++ + BB_VINFO_VEC_OUTSIDE_COST (bb_vinfo_ori))) ++ { ++ return true; ++ } ++ return false; ++} ++ ++static bool ++may_choose_transpose_bbvinfo (bb_vec_info bb_vinfo_trans, bool res_trans, ++ bb_vec_info bb_vinfo_ori, bool res_ori) ++{ ++ /* The original bb_vinfo is chosen if the transposed bb_vinfo ++ can't be vectorized. */ ++ if (!res_trans) ++ { ++ return false; ++ } ++ /* Caculate the cost of the transposed bb_vinfo. */ ++ if (unlimited_cost_model (NULL)) ++ { ++ vect_bb_vectorization_profitable_p (bb_vinfo_trans); ++ } ++ int diff_bb_cost = -1; ++ int diff_bb_cost_trans = -1; ++ if (res_ori) ++ { ++ diff_bb_cost = BB_VINFO_SCALAR_COST (bb_vinfo_ori) ++ - BB_VINFO_VEC_INSIDE_COST (bb_vinfo_ori) ++ - BB_VINFO_VEC_OUTSIDE_COST (bb_vinfo_ori); ++ } ++ if (res_trans) ++ { ++ diff_bb_cost_trans = BB_VINFO_SCALAR_COST (bb_vinfo_trans) ++ - BB_VINFO_VEC_INSIDE_COST (bb_vinfo_trans) ++ - BB_VINFO_VEC_OUTSIDE_COST (bb_vinfo_trans); ++ } ++ /* The original bb_vinfo is chosen when one of the following conditions ++ is satisfied as follows: ++ 1) The cost of original version is better transposed version. ++ 2) The vec cost is similar to scalar cost in the transposed version. */ ++ if ((res_ori && res_trans && diff_bb_cost >= diff_bb_cost_trans) ++ || (res_trans && BB_VINFO_SCALAR_COST (bb_vinfo_trans) ++ <= (BB_VINFO_VEC_INSIDE_COST (bb_vinfo_trans) ++ + BB_VINFO_VEC_OUTSIDE_COST (bb_vinfo_trans)))) ++ { ++ return false; ++ } ++ return true; ++} ++ + /* Subroutine of vect_slp_bb. Try to vectorize the statements between + REGION_BEGIN (inclusive) and REGION_END (exclusive), returning true + on success. The region has N_STMTS statements and has the datarefs +@@ -3323,6 +4349,7 @@ vect_slp_bb_region (gimple_stmt_iterator region_begin, + unsigned int n_stmts) + { + bb_vec_info bb_vinfo; ++ bb_vec_info bb_vinfo_trans = NULL; + auto_vector_modes vector_modes; + + /* Autodetect first vector size we try. */ +@@ -3337,6 +4364,10 @@ vect_slp_bb_region (gimple_stmt_iterator region_begin, + { + bool vectorized = false; + bool fatal = false; ++ bool res_bb_vinfo_ori = false; ++ bool res_bb_vinfo_trans = false; ++ ++ /* New a bb_vinfo of the original version. */ + bb_vinfo = new _bb_vec_info (region_begin, region_end, &shared); + + bool first_time_p = shared.datarefs.is_empty (); +@@ -3346,8 +4377,57 @@ vect_slp_bb_region (gimple_stmt_iterator region_begin, + else + bb_vinfo->shared->check_datarefs (); + bb_vinfo->vector_mode = next_vector_mode; ++ bb_vinfo->transposed = false; ++ bb_vinfo->before_slp = false; ++ ++ res_bb_vinfo_ori = vect_slp_analyze_bb_1 (bb_vinfo, n_stmts, fatal); ++ /* Analyze and new a transposed bb_vinfo. */ ++ if (may_new_transpose_bbvinfo (bb_vinfo, res_bb_vinfo_ori)) ++ { ++ bool fatal_trans = false; ++ bb_vinfo_trans ++ = new _bb_vec_info (region_begin, region_end, &shared); ++ bool first_time_p = shared.datarefs.is_empty (); ++ BB_VINFO_DATAREFS (bb_vinfo_trans) = datarefs; ++ if (first_time_p) ++ { ++ bb_vinfo_trans->shared->save_datarefs (); ++ } ++ else ++ { ++ bb_vinfo_trans->shared->check_datarefs (); ++ } ++ bb_vinfo_trans->vector_mode = next_vector_mode; ++ bb_vinfo_trans->transposed = true; ++ bb_vinfo_trans->before_slp = false; ++ ++ res_bb_vinfo_trans ++ = vect_slp_analyze_bb_1 (bb_vinfo_trans, n_stmts, fatal_trans); ++ if (may_choose_transpose_bbvinfo (bb_vinfo_trans, ++ res_bb_vinfo_trans, ++ bb_vinfo, res_bb_vinfo_ori)) ++ { ++ bb_vinfo = bb_vinfo_trans; ++ fatal = fatal_trans; ++ if (dump_enabled_p ()) ++ { ++ dump_printf_loc (MSG_NOTE, vect_location, ++ "Basic block part vectorized " ++ "using transposed version.\n"); ++ } ++ } ++ else ++ { ++ if (dump_enabled_p ()) ++ { ++ dump_printf_loc (MSG_NOTE, vect_location, ++ "Basic block part vectorized " ++ "using original version.\n"); ++ } ++ } ++ } + +- if (vect_slp_analyze_bb_1 (bb_vinfo, n_stmts, fatal) ++ if ((res_bb_vinfo_ori || res_bb_vinfo_trans) + && dbg_cnt (vect_slp)) + { + if (dump_enabled_p ()) +@@ -3400,6 +4480,10 @@ vect_slp_bb_region (gimple_stmt_iterator region_begin, + } + + delete bb_vinfo; ++ if (bb_vinfo_trans) ++ { ++ bb_vinfo_trans = NULL; ++ } + + if (mode_i < vector_modes.length () + && VECTOR_MODE_P (autodetected_vector_mode) +diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c +index 6418edb52..b872cfc8d 100644 +--- a/gcc/tree-vect-stmts.c ++++ b/gcc/tree-vect-stmts.c +@@ -7329,6 +7329,153 @@ vectorizable_scan_store (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, + return true; + } + ++/* Function vect_permute_store_chains ++ ++ Call function vect_permute_store_chain (). ++ Given a chain of interleaved stores in DR_CHAIN, generate ++ interleave_high/low stmts to reorder the data correctly. ++ Return the final references for stores in RESULT_CHAIN. */ ++ ++static void ++vect_permute_store_chains (vec<tree> dr_chain, unsigned int num_each, ++ stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, ++ vec<tree> *result_chain, unsigned int group) ++{ ++ unsigned int k = 0; ++ unsigned int t = 0; ++ ++ /* Divide vectors into GROUP parts. And permute every NUM_EACH vectors ++ together. */ ++ for (k = 0; k < group; k++) ++ { ++ auto_vec<tree> dr_chain_transposed (num_each); ++ auto_vec<tree> result_chain_transposed (num_each); ++ for (t = k; t < dr_chain.length (); t = t + group) ++ { ++ dr_chain_transposed.quick_push (dr_chain[t]); ++ } ++ vect_permute_store_chain (dr_chain_transposed, num_each, stmt_info, ++ gsi, &result_chain_transposed); ++ for (t = 0; t < num_each; t++) ++ { ++ result_chain->quick_push (result_chain_transposed[t]); ++ } ++ } ++} ++ ++/* Function transpose_oprnd_store ++ ++ Calculate the transposed results from VEC_OPRNDS (VEC_STMT) ++ for vectorizable_store. */ ++ ++static void ++transpose_oprnd_store (vec<tree>vec_oprnds, vec<tree> *result_chain, ++ unsigned int vec_num, unsigned int const_nunits, ++ unsigned int array_num, stmt_vec_info first_stmt_info, ++ gimple_stmt_iterator *gsi) ++{ ++ unsigned int group_for_transform = 0; ++ unsigned int num_each = 0; ++ ++ /* Transpose back for vec_oprnds. */ ++ /* vec = {vec1, vec2, ...} */ ++ if (array_num < const_nunits ++ && const_nunits % array_num == 0) ++ { ++ vect_transpose_store_chain (vec_oprnds, ++ vec_num, array_num, ++ first_stmt_info, ++ gsi, result_chain); ++ } ++ /* vec1 = {vec_part1}, vec2 = {vec_part2}, ... */ ++ else if (array_num >= const_nunits ++ && array_num % const_nunits == 0) ++ { ++ group_for_transform = array_num / const_nunits; ++ num_each = vec_oprnds.length () / group_for_transform; ++ vect_permute_store_chains (vec_oprnds, ++ num_each, first_stmt_info, ++ gsi, result_chain, ++ group_for_transform); ++ } ++ else ++ { ++ gcc_unreachable (); ++ } ++} ++ ++static dr_vec_info * ++get_dr_info (stmt_vec_info stmt_info) ++{ ++ dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info); ++ if (dr_info->misalignment == DR_MISALIGNMENT_UNINITIALIZED) ++ { ++ SET_DR_MISALIGNMENT (dr_info, DR_MISALIGNMENT_UNKNOWN); ++ } ++ return dr_info; ++} ++ ++static unsigned ++dr_align_vect_store (dr_vec_info *cur_first_dr_info, ++ unsigned HOST_WIDE_INT &align) ++{ ++ unsigned misalign = 0; ++ align = known_alignment (DR_TARGET_ALIGNMENT (cur_first_dr_info)); ++ if (aligned_access_p (cur_first_dr_info)) ++ { ++ return misalign; ++ } ++ else if (DR_MISALIGNMENT (cur_first_dr_info) == -1) ++ { ++ align = dr_alignment (vect_dr_behavior (cur_first_dr_info)); ++ } ++ else ++ { ++ misalign = DR_MISALIGNMENT (cur_first_dr_info); ++ } ++ return misalign; ++} ++ ++static stmt_vec_info ++add_new_stmt_vect_store (tree vectype, tree dataref_ptr, tree dataref_offset, ++ tree ref_type, dr_vec_info *cur_first_dr_info, ++ tree vec_oprnd, gimple_stmt_iterator *gsi, ++ stmt_vec_info stmt_info) ++{ ++ /* Data align. */ ++ unsigned HOST_WIDE_INT align; ++ unsigned misalign = dr_align_vect_store (cur_first_dr_info, align); ++ ++ if (dataref_offset == NULL_TREE && TREE_CODE (dataref_ptr) == SSA_NAME) ++ { ++ set_ptr_info_alignment (get_ptr_info (dataref_ptr), align, misalign); ++ } ++ ++ /* Get data_ref. */ ++ tree offset = dataref_offset ? dataref_offset : build_int_cst (ref_type, 0); ++ tree data_ref = fold_build2 (MEM_REF, vectype, dataref_ptr, offset); ++ if (aligned_access_p (cur_first_dr_info)) ++ { ++ ; ++ } ++ else if (DR_MISALIGNMENT (cur_first_dr_info) == -1) ++ { ++ TREE_TYPE (data_ref) = build_aligned_type (TREE_TYPE (data_ref), ++ align * BITS_PER_UNIT); ++ } ++ else ++ { ++ tree elem_type = TREE_TYPE (vectype); ++ TREE_TYPE (data_ref) = build_aligned_type (TREE_TYPE (data_ref), ++ TYPE_ALIGN (elem_type)); ++ } ++ /* Add new stmt. */ ++ vect_copy_ref_info (data_ref, DR_REF (cur_first_dr_info->dr)); ++ gassign *new_stmt = gimple_build_assign (data_ref, vec_oprnd); ++ stmt_vec_info new_stmt_info ++ = vect_finish_stmt_generation (stmt_info, new_stmt, gsi); ++ return new_stmt_info; ++} + + /* Function vectorizable_store. + +@@ -8208,6 +8355,16 @@ vectorizable_store (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, + else if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) + vect_get_gather_scatter_ops (loop, stmt_info, &gs_info, + &dataref_ptr, &vec_offset); ++ /* If the stmt_info need to be transposed recovery, dataref_ptr ++ will be caculated later. */ ++ else if (memory_access_type == VMAT_CONTIGUOUS ++ && is_a <bb_vec_info> (vinfo) ++ && STMT_VINFO_GROUPED_ACCESS (stmt_info) ++ && DR_GROUP_SLP_TRANSPOSE ( ++ DR_GROUP_FIRST_ELEMENT (stmt_info))) ++ { ++ dataref_ptr = NULL_TREE; ++ } + else + dataref_ptr + = vect_create_data_ref_ptr (first_stmt_info, aggr_type, +@@ -8299,6 +8456,75 @@ vectorizable_store (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, + } + else + { ++ /* group_size: the size of group after transposing and merging. ++ group_size_b: the size of group before transposing and merging, ++ and only group_size_b >= const_nunits is supported. ++ array_num: the number of arrays. ++ const_nunits: TYPE_VECTOR_SUBPARTS (vectype). ++ ncontinues: group_size_b / const_nunits, it means the number of ++ times an array is stored in memory. */ ++ if (slp && is_a <bb_vec_info> (vinfo) ++ && STMT_VINFO_GROUPED_ACCESS (stmt_info) ++ && DR_GROUP_SLP_TRANSPOSE (DR_GROUP_FIRST_ELEMENT (stmt_info))) ++ { ++ if (dump_enabled_p ()) ++ { ++ dump_printf_loc (MSG_NOTE, vect_location, ++ "vectorizable_store for slp transpose.\n"); ++ } ++ /* Transpose back for grouped stores. */ ++ vect_transform_back_slp_grouped_stores (bb_vinfo, ++ first_stmt_info); ++ ++ result_chain.create (vec_oprnds.length ()); ++ unsigned int const_nunits = nunits.to_constant (); ++ unsigned int group_size_b = DR_GROUP_SIZE_TRANS (first_stmt_info); ++ unsigned int array_num = group_size / group_size_b; ++ transpose_oprnd_store (vec_oprnds, &result_chain, vec_num, ++ const_nunits, array_num, ++ first_stmt_info, gsi); ++ ++ /* For every store group, not for every vec, because transposing ++ and merging have changed the data reference access. */ ++ gcc_assert (group_size_b >= const_nunits); ++ unsigned int ncontinues = group_size_b / const_nunits; ++ ++ unsigned int k = 0; ++ for (i = 0; i < array_num; i++) ++ { ++ stmt_vec_info first_stmt_b; ++ BB_VINFO_GROUPED_STORES (vinfo).iterate (i, &first_stmt_b); ++ bool simd_lane_access_p ++ = STMT_VINFO_SIMD_LANE_ACCESS_P (first_stmt_b) != 0; ++ tree ref_type = get_group_alias_ptr_type (first_stmt_b); ++ dataref_ptr = vect_create_data_ref_ptr ( ++ first_stmt_b, aggr_type, ++ simd_lane_access_p ? loop : NULL, ++ offset, &dummy, gsi, &ptr_incr, ++ simd_lane_access_p, NULL_TREE, bump); ++ dr_vec_info *cur_first_dr_info = get_dr_info (first_stmt_b); ++ for (unsigned int t = 0; t < ncontinues; t++) ++ { ++ vec_oprnd = result_chain[k]; ++ k++; ++ if (t > 0) ++ { ++ /* Bump the vector pointer. */ ++ dataref_ptr = bump_vector_ptr (dataref_ptr, ptr_incr, ++ gsi, first_stmt_b, ++ bump); ++ } ++ new_stmt_info = add_new_stmt_vect_store ( ++ vectype, dataref_ptr, dataref_offset, ++ ref_type, cur_first_dr_info, vec_oprnd, ++ gsi, first_stmt_b); ++ } ++ } ++ oprnds.release (); ++ result_chain.release (); ++ vec_oprnds.release (); ++ return true; ++ } + new_stmt_info = NULL; + if (grouped_store) + { +@@ -8557,6 +8783,447 @@ hoist_defs_of_uses (stmt_vec_info stmt_info, class loop *loop) + return true; + } + ++static tree ++calculate_new_type (tree vectype, unsigned int const_nunits, ++ unsigned int group_size_b, unsigned int &nloads, ++ unsigned int &ncontinues, tree &lvectype) ++{ ++ tree ltype = TREE_TYPE (vectype); ++ /* nloads is the number of ARRAYs in a vector. ++ vectemp = {a[], b[], ...} */ ++ if (group_size_b < const_nunits) ++ { ++ tree ptype; ++ tree vtype ++ = vector_vector_composition_type (vectype, ++ const_nunits / group_size_b, ++ &ptype); ++ if (vtype != NULL_TREE) ++ { ++ nloads = const_nunits / group_size_b; ++ lvectype = vtype; ++ ltype = ptype; ++ ncontinues = 1; ++ } ++ } ++ /* ncontinues is the number of vectors from an ARRAY. ++ vectemp1 = {a[0], a[1], ...} ++ ... ++ vectempm = {a[k], a[k+1], ...} */ ++ else ++ { ++ nloads = 1; ++ ltype = vectype; ++ ncontinues = group_size_b / const_nunits; ++ } ++ ltype = build_aligned_type (ltype, TYPE_ALIGN (TREE_TYPE (vectype))); ++ return ltype; ++} ++ ++static void ++generate_old_load_permutations (slp_tree slp_node, unsigned int group_size, ++ vec<unsigned> &old_load_permutation) ++{ ++ /* Generate the old load permutations from the slp_node. */ ++ unsigned i = 0; ++ unsigned k = 0; ++ ++ /* If SLP_NODE has load_permutation, we copy it to old_load_permutation. ++ Otherwise, we generate a permutation sequentially. */ ++ if (SLP_TREE_LOAD_PERMUTATION (slp_node).exists ()) ++ { ++ FOR_EACH_VEC_ELT (SLP_TREE_LOAD_PERMUTATION (slp_node), i, k) ++ { ++ old_load_permutation.safe_push (k); ++ } ++ } ++ else ++ { ++ for (unsigned i = 0; i < group_size; i++) ++ { ++ old_load_permutation.safe_push (i); ++ } ++ } ++} ++ ++static void ++generate_new_load_permutation_mapping (unsigned slp_node_length, ++ vec<unsigned> &group_idx, ++ const vec<unsigned> &load_permutation, ++ unsigned int group_size_b, ++ unsigned &new_group_size, ++ vec<unsigned> &group_from) ++{ ++ /* group_num_vec: only stores the group_loads IDs which are caculated from ++ load_permutation. */ ++ auto_vec<unsigned> group_num_vec; ++ ++ /* Caculate which group_loads are the stmts in SLP_NODE from. */ ++ unsigned i = 0; ++ unsigned k = 0; ++ FOR_EACH_VEC_ELT (load_permutation, i, k) ++ { ++ unsigned int t0 = k / group_size_b; ++ if (!group_num_vec.contains (t0)) ++ { ++ group_num_vec.safe_push (t0); ++ } ++ group_from.safe_push (t0); ++ } ++ group_num_vec.qsort (cmp_for_group_num); ++ /* n_groups: the number of group_loads. */ ++ unsigned int n_groups = group_num_vec.length (); ++ new_group_size = n_groups * group_size_b; ++ for (i = 0; i < n_groups; i++) ++ { ++ group_idx.safe_push (group_num_vec[i] * group_size_b); ++ } ++ /* A new mapping from group_ind_vec to group_from. ++ For example: ++ Origin: group_from = {1,1,3,3,5,5,7,7}; ++ After mapping: group_from = {0,0,1,1,2,2,2,2}; */ ++ auto_vec<unsigned> group_ind_vec (n_groups); ++ for (k = 0; k < n_groups; k++) ++ { ++ group_ind_vec.safe_push (k); ++ } ++ for (i = 0; i < slp_node_length; i++) ++ { ++ for (k = 0; k < n_groups; k++) ++ { ++ if (group_from[i] == group_num_vec[k]) ++ { ++ group_from[i] = group_ind_vec[k]; ++ break; ++ } ++ } ++ } ++} ++ ++static void ++generate_new_load_permutation (vec<unsigned> &new_load_permutation, ++ const vec<unsigned> &old_load_permutation, ++ slp_tree slp_node, bool &this_load_permuted, ++ const vec<unsigned> &group_from, ++ unsigned int group_size_b) ++{ ++ unsigned slp_node_length = SLP_TREE_SCALAR_STMTS (slp_node).length (); ++ /* Generate the new load permutation from the new mapping. */ ++ new_load_permutation.create (slp_node_length); ++ unsigned i = 0; ++ unsigned k = 0; ++ FOR_EACH_VEC_ELT (old_load_permutation, i, k) ++ { ++ /* t1 is the new permutation of k in the old permutation. ++ t1 = base_address + offset: ++ base_address = group_from[i] * group_size_b; ++ offset = k % group_size_b. */ ++ unsigned int t1 ++ = group_from[i] * group_size_b + k % group_size_b; ++ new_load_permutation.safe_push (t1); ++ if (t1 != k) ++ { ++ this_load_permuted = true; ++ } ++ } ++} ++ ++static bool ++is_slp_perm (bool slp_perm, bool this_load_permuted, poly_uint64 nunits, ++ unsigned int group_size, stmt_vec_info first_stmt_info) ++{ ++ /* Calculate the unrolling factor based on the smallest type. */ ++ poly_uint64 unrolling_factor ++ = exact_div (common_multiple (nunits, group_size), group_size); ++ /* The load requires permutation when unrolling exposes ++ a gap either because the group is larger than the SLP ++ group-size or because there is a gap between the groups. */ ++ if (!slp_perm && !this_load_permuted ++ && (known_eq (unrolling_factor, 1U) ++ || (group_size == DR_GROUP_SIZE (first_stmt_info) ++ && DR_GROUP_GAP (first_stmt_info) == 0))) ++ { ++ return false; ++ } ++ else ++ { ++ return true; ++ } ++} ++ ++static void ++generate_load_permutation (slp_tree slp_node, unsigned &new_group_size, ++ unsigned int group_size, unsigned int group_size_b, ++ bool &this_load_permuted, vec<unsigned> &group_idx, ++ vec<unsigned> &new_load_permutation) ++{ ++ /* Generate the old load permutations from SLP_NODE. */ ++ vec<unsigned> old_load_permutation; ++ old_load_permutation.create (group_size); ++ generate_old_load_permutations (slp_node, group_size, old_load_permutation); ++ ++ /* Caculate which group_loads are the stmts in SLP_NODE from. */ ++ unsigned slp_node_length = SLP_TREE_SCALAR_STMTS (slp_node).length (); ++ /* group_from: stores the group_loads ID for every stmt in SLP_NODE. */ ++ vec<unsigned> group_from; ++ group_from.create (slp_node_length); ++ generate_new_load_permutation_mapping (slp_node_length, group_idx, ++ old_load_permutation, ++ group_size_b, new_group_size, ++ group_from); ++ ++ /* Generate the new load permutation from the new mapping and caculate ++ this_load_permuted flag. If this_load_permuted is true, we need execute ++ slp permutation by using new load permutation. */ ++ generate_new_load_permutation (new_load_permutation, old_load_permutation, ++ slp_node, this_load_permuted, group_from, ++ group_size_b); ++ old_load_permutation.release (); ++ group_from.release (); ++} ++ ++static unsigned int ++dr_align_vect_load (dr_vec_info *cur_first_dr_info, ++ unsigned HOST_WIDE_INT &align, ++ enum dr_alignment_support alignment_support_scheme) ++{ ++ unsigned int misalign = 0; ++ ++ align = known_alignment (DR_TARGET_ALIGNMENT (cur_first_dr_info)); ++ if (alignment_support_scheme == dr_aligned) ++ { ++ gcc_assert (aligned_access_p (cur_first_dr_info)); ++ } ++ else if (DR_MISALIGNMENT (cur_first_dr_info) == -1) ++ { ++ align = dr_alignment (vect_dr_behavior (cur_first_dr_info)); ++ } ++ else ++ { ++ misalign = DR_MISALIGNMENT (cur_first_dr_info); ++ } ++ return misalign; ++} ++ ++static stmt_vec_info ++add_new_stmt_vect_load (tree vectype, tree dataref_ptr, tree dataref_offset, ++ tree ref_type, tree ltype, gassign *(&new_stmt), ++ dr_vec_info *cur_first_dr_info, ++ gimple_stmt_iterator *gsi, stmt_vec_info stmt_info) ++{ ++ /* Data align. */ ++ enum dr_alignment_support alignment_support_scheme ++ = vect_supportable_dr_alignment (cur_first_dr_info, false); ++ unsigned HOST_WIDE_INT align; ++ unsigned int misalign = dr_align_vect_load (cur_first_dr_info, align, ++ alignment_support_scheme); ++ if (dataref_offset == NULL_TREE && TREE_CODE (dataref_ptr) == SSA_NAME) ++ { ++ set_ptr_info_alignment (get_ptr_info (dataref_ptr), align, misalign); ++ } ++ ++ /* Get data_ref. */ ++ tree offset = dataref_offset ? dataref_offset : build_int_cst (ref_type, 0); ++ tree data_ref = fold_build2 (MEM_REF, ltype, dataref_ptr, offset); ++ if (alignment_support_scheme == dr_aligned) ++ { ++ ; ++ } ++ else if (DR_MISALIGNMENT (cur_first_dr_info) == -1) ++ { ++ TREE_TYPE (data_ref) ++ = build_aligned_type (TREE_TYPE (data_ref), align * BITS_PER_UNIT); ++ } ++ else ++ { ++ tree elem_type = TREE_TYPE (vectype); ++ TREE_TYPE (data_ref) ++ = build_aligned_type (TREE_TYPE (data_ref), TYPE_ALIGN (elem_type)); ++ } ++ ++ /* Add new stmt. */ ++ vect_copy_ref_info (data_ref, DR_REF (cur_first_dr_info->dr)); ++ new_stmt = gimple_build_assign (make_ssa_name (ltype), data_ref); ++ stmt_vec_info new_stmt_info ++ = vect_finish_stmt_generation (stmt_info, new_stmt, gsi); ++ return new_stmt_info; ++} ++ ++static void ++push_new_stmt_to_dr_chain (bool slp_perm, stmt_vec_info new_stmt_info, ++ vec<tree> &dr_chain, slp_tree slp_node) ++{ ++ if (slp_perm) ++ { ++ dr_chain.quick_push (gimple_assign_lhs (new_stmt_info->stmt)); ++ } ++ else ++ { ++ SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt_info); ++ } ++} ++ ++static stmt_vec_info ++get_first_stmt_info_before_transpose (stmt_vec_info first_stmt_info, ++ unsigned int group_el, ++ unsigned int group_size) ++{ ++ stmt_vec_info last_stmt_info = first_stmt_info; ++ unsigned int count = 0; ++ gcc_assert (group_el < group_size); ++ while (count < group_el) ++ { ++ last_stmt_info = DR_GROUP_NEXT_ELEMENT (last_stmt_info); ++ count++; ++ } ++ return last_stmt_info; ++} ++ ++static stmt_vec_info ++add_new_stmt_for_nloads_greater_than_one (tree lvectype, tree vectype, ++ vec<constructor_elt, va_gc> *v, ++ stmt_vec_info stmt_info, ++ gimple_stmt_iterator *gsi) ++{ ++ tree vec_inv = build_constructor (lvectype, v); ++ tree new_temp = vect_init_vector (stmt_info, vec_inv, lvectype, gsi); ++ vec_info *vinfo = stmt_info->vinfo; ++ stmt_vec_info new_stmt_info = vinfo->lookup_def (new_temp); ++ if (lvectype != vectype) ++ { ++ gassign *new_stmt = gimple_build_assign (make_ssa_name (vectype), ++ VIEW_CONVERT_EXPR, ++ build1 (VIEW_CONVERT_EXPR, ++ vectype, new_temp)); ++ new_stmt_info = vect_finish_stmt_generation (stmt_info, new_stmt, gsi); ++ } ++ return new_stmt_info; ++} ++ ++/* Function new_vect_stmt_for_nloads. ++ ++ New a VEC_STMT when nloads Arrays are merged into a vector. ++ ++ ncopies is the number of vectors that need to be loaded from memmory. ++ nloads is the number of ARRAYs in a vector. ++ vectemp = {a[], b[], ...} */ ++ ++static void ++new_vect_stmt_for_nloads (unsigned int ncopies, unsigned int nloads, ++ vec<unsigned> group_idx, stmt_vec_info stmt_info, ++ offset_info *offset_info, vectype_info *vectype_info, ++ vect_memory_access_type memory_access_type, ++ bool slp_perm, vec<tree>& dr_chain, slp_tree slp_node, ++ gimple_stmt_iterator *gsi) ++{ ++ vec<constructor_elt, va_gc> *v = NULL; ++ stmt_vec_info first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info); ++ unsigned int group_size = DR_GROUP_SIZE (first_stmt_info); ++ stmt_vec_info first_stmt_info_b = NULL; ++ stmt_vec_info new_stmt_info = NULL; ++ tree dataref_ptr = NULL_TREE; ++ tree dummy; ++ gimple *ptr_incr = NULL; ++ unsigned int n = 0; ++ for (unsigned int i = 0; i < ncopies; i++) ++ { ++ vec_alloc (v, nloads); ++ for (unsigned int t = 0; t < nloads; t++) ++ { ++ first_stmt_info_b = get_first_stmt_info_before_transpose ( ++ first_stmt_info, group_idx[n++], group_size); ++ dr_vec_info* cur_first_dr_info = get_dr_info (first_stmt_info_b); ++ tree bump = vect_get_data_ptr_increment (cur_first_dr_info, ++ vectype_info->ltype, ++ memory_access_type); ++ bool simd_lane_access_p ++ = STMT_VINFO_SIMD_LANE_ACCESS_P (first_stmt_info_b) != 0; ++ ++ /* Create dataref_ptr which is point to init_address. */ ++ dataref_ptr = vect_create_data_ref_ptr ( ++ first_stmt_info_b, vectype_info->ltype, NULL, ++ offset_info->offset, &dummy, gsi, &ptr_incr, ++ simd_lane_access_p, offset_info->byte_offset, bump); ++ ++ gassign *new_stmt = NULL; ++ new_stmt_info = add_new_stmt_vect_load ( ++ vectype_info->vectype, dataref_ptr, ++ offset_info->dataref_offset, vectype_info->ref_type, ++ vectype_info->ltype, new_stmt, cur_first_dr_info, ++ gsi, first_stmt_info_b); ++ ++ CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, gimple_assign_lhs (new_stmt)); ++ } ++ new_stmt_info = add_new_stmt_for_nloads_greater_than_one ( ++ vectype_info->lvectype, vectype_info->vectype, ++ v, first_stmt_info_b, gsi); ++ push_new_stmt_to_dr_chain (slp_perm, new_stmt_info, ++ dr_chain, slp_node); ++ } ++} ++ ++/* Function new_vect_stmt_for_ncontinues. ++ ++ New a VEC_STMTs when an Array is divided into several vectors. ++ ++ n_groups is the number of ARRAYs. ++ ncontinues is the number of vectors from an ARRAY. ++ vectemp1 = {a[0], a[1], ...} ++ ... ++ vectempm = {a[k], a[k+1], ...} */ ++ ++static void ++new_vect_stmt_for_ncontinues (unsigned int ncontinues, vec<unsigned> group_idx, ++ stmt_vec_info stmt_info, offset_info* offset_info, ++ vectype_info* vectype_info, ++ vect_memory_access_type memory_access_type, ++ bool slp_perm, vec<tree>& dr_chain, ++ slp_tree slp_node, ++ gimple_stmt_iterator *gsi) ++{ ++ stmt_vec_info first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info); ++ unsigned int group_size = DR_GROUP_SIZE (first_stmt_info); ++ stmt_vec_info new_stmt_info = NULL; ++ tree dataref_ptr = NULL_TREE; ++ tree dummy; ++ gimple *ptr_incr = NULL; ++ unsigned int n_groups = group_idx.length (); ++ for (unsigned int i = 0; i < n_groups; i++) ++ { ++ stmt_vec_info first_stmt_info_b = get_first_stmt_info_before_transpose ( ++ first_stmt_info, group_idx[i], group_size); ++ dr_vec_info* cur_first_dr_info = get_dr_info (first_stmt_info_b); ++ tree bump = vect_get_data_ptr_increment (cur_first_dr_info, ++ vectype_info->ltype, memory_access_type); ++ bool simd_lane_access_p ++ = STMT_VINFO_SIMD_LANE_ACCESS_P (first_stmt_info_b) != 0; ++ for (unsigned int k = 0; k < ncontinues; k++) ++ { ++ /* Create dataref_ptr which is point to init_address. */ ++ if (k == 0) ++ { ++ dataref_ptr = vect_create_data_ref_ptr ( ++ first_stmt_info_b, vectype_info->ltype, NULL, ++ offset_info->offset, &dummy, gsi, &ptr_incr, ++ simd_lane_access_p, offset_info->byte_offset, bump); ++ } ++ else ++ { ++ dataref_ptr = bump_vector_ptr (dataref_ptr, ptr_incr, ++ gsi, first_stmt_info_b, bump); ++ } ++ gassign *new_stmt = NULL; ++ new_stmt_info = add_new_stmt_vect_load ( ++ vectype_info->vectype, dataref_ptr, ++ offset_info->dataref_offset, vectype_info->ref_type, ++ vectype_info->ltype, new_stmt, cur_first_dr_info, ++ gsi, first_stmt_info_b); ++ push_new_stmt_to_dr_chain (slp_perm, new_stmt_info, ++ dr_chain, slp_node); ++ } ++ } ++} ++ + /* vectorizable_load. + + Check if STMT_INFO reads a non scalar data-ref (array/pointer/structure) +@@ -9364,6 +10031,9 @@ vectorizable_load (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, + tree vec_mask = NULL_TREE; + prev_stmt_info = NULL; + poly_uint64 group_elt = 0; ++ unsigned new_group_size = 0; ++ vec<unsigned> new_load_permutation; ++ + for (j = 0; j < ncopies; j++) + { + stmt_vec_info new_stmt_info = NULL; +@@ -9385,6 +10055,15 @@ vectorizable_load (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, + dataref_ptr = unshare_expr (DR_BASE_ADDRESS (first_dr_info->dr)); + dataref_offset = build_int_cst (ref_type, 0); + } ++ /* If the stmt_info need to be transposed recovery, dataref_ptr ++ will be caculated later. */ ++ else if (slp && is_a <bb_vec_info> (vinfo) ++ && STMT_VINFO_GROUPED_ACCESS (stmt_info) ++ && DR_GROUP_SLP_TRANSPOSE ( ++ DR_GROUP_FIRST_ELEMENT (stmt_info))) ++ { ++ dataref_ptr = NULL_TREE; ++ } + else if (diff_first_stmt_info) + { + dataref_ptr +@@ -9501,6 +10180,63 @@ vectorizable_load (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, + /* Record that VEC_ARRAY is now dead. */ + vect_clobber_variable (stmt_info, gsi, vec_array); + } ++ else if (slp && is_a <bb_vec_info> (vinfo) ++ && STMT_VINFO_GROUPED_ACCESS (stmt_info) ++ && DR_GROUP_SLP_TRANSPOSE (DR_GROUP_FIRST_ELEMENT (stmt_info))) ++ { ++ if (dump_enabled_p ()) ++ { ++ dump_printf_loc (MSG_NOTE, vect_location, ++ "vectorizable_load for slp transpose.\n"); ++ } ++ /* group_size: the size of group after merging. ++ group_size_b: the size of group before merging. ++ const_nunits: TYPE_VECTOR_SUBPARTS (vectype), it is the number of ++ elements in a vector. ++ nloads: const_nunits / group_size_b or 1, it means the number ++ of ARRAYs in a vector. ++ ncontinues: group_size_b / const_nunits or 1, it means the number ++ of vectors from an ARRAY. */ ++ unsigned int group_size_b = DR_GROUP_SIZE_TRANS (first_stmt_info); ++ unsigned int const_nunits = nunits.to_constant (); ++ unsigned int nloads = const_nunits; ++ unsigned int ncontinues = group_size_b; ++ tree lvectype = vectype; ++ tree ltype = calculate_new_type (vectype, const_nunits, ++ group_size_b, nloads, ++ ncontinues, lvectype); ++ bool this_load_permuted = false; ++ auto_vec<unsigned> group_idx; ++ generate_load_permutation (slp_node, new_group_size, group_size, ++ group_size_b, this_load_permuted, ++ group_idx, new_load_permutation); ++ slp_perm = is_slp_perm (slp_perm, this_load_permuted, nunits, ++ group_size, first_stmt_info); ++ ++ /* ncopies: the number of vectors that need to be loaded from ++ memmory. */ ++ unsigned int ncopies = new_group_size / const_nunits; ++ offset_info offset_info = {offset, byte_offset, dataref_offset}; ++ vectype_info vectype_info = {vectype, ltype, lvectype, ref_type}; ++ if (slp_perm) ++ { ++ dr_chain.create (ncopies); ++ } ++ if (nloads > 1 && ncontinues == 1) ++ { ++ new_vect_stmt_for_nloads (ncopies, nloads, group_idx, stmt_info, ++ &offset_info, &vectype_info, ++ memory_access_type, slp_perm, dr_chain, ++ slp_node, gsi); ++ } ++ else ++ { ++ new_vect_stmt_for_ncontinues (ncontinues, group_idx, stmt_info, ++ &offset_info, &vectype_info, ++ memory_access_type, slp_perm, ++ dr_chain, slp_node, gsi); ++ } ++ } + else + { + for (i = 0; i < vec_num; i++) +@@ -9840,7 +10576,32 @@ vectorizable_load (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, + if (slp && !slp_perm) + continue; + +- if (slp_perm) ++ /* Using the new load permutation to generate vector permute statements ++ from a list of loads in DR_CHAIN. */ ++ if (slp && slp_perm && is_a <bb_vec_info> (vinfo) ++ && STMT_VINFO_GROUPED_ACCESS (stmt_info) ++ && DR_GROUP_SLP_TRANSPOSE (DR_GROUP_FIRST_ELEMENT (stmt_info))) ++ { ++ unsigned n_perms; ++ stmt_vec_info stmt_info_ = SLP_TREE_SCALAR_STMTS (slp_node)[0]; ++ unsigned int old_size = DR_GROUP_SIZE (stmt_info); ++ DR_GROUP_SIZE (stmt_info_) = new_group_size; ++ vec<unsigned> old_load_permutation ++ = SLP_TREE_LOAD_PERMUTATION (slp_node); ++ SLP_TREE_LOAD_PERMUTATION (slp_node) = new_load_permutation; ++ bool perm_load_success = vect_transform_slp_perm_load ( ++ slp_node, dr_chain, gsi, vf, ++ slp_node_instance, false, &n_perms); ++ DR_GROUP_SIZE (stmt_info_) = old_size; ++ SLP_TREE_LOAD_PERMUTATION (slp_node) = old_load_permutation; ++ new_load_permutation.release (); ++ if (!perm_load_success) ++ { ++ dr_chain.release (); ++ return false; ++ } ++ } ++ else if (slp_perm) + { + unsigned n_perms; + if (!vect_transform_slp_perm_load (slp_node, dr_chain, gsi, vf, +diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h +index f7becb34a..1c4a6c421 100644 +--- a/gcc/tree-vectorizer.h ++++ b/gcc/tree-vectorizer.h +@@ -297,6 +297,21 @@ public: + vec<ddr_p> ddrs; + }; + ++/* Information about offset in vectorizable_load. */ ++struct offset_info { ++ tree offset; ++ tree byte_offset; ++ tree dataref_offset; ++}; ++ ++/* Information about vectype in vectorizable_load. */ ++struct vectype_info { ++ tree vectype; ++ tree ltype; ++ tree lvectype; ++ tree ref_type; ++}; ++ + /* Vectorizer state common between loop and basic-block vectorization. */ + class vec_info { + public: +@@ -335,6 +350,14 @@ public: + stmt in the chain. */ + auto_vec<stmt_vec_info> grouped_stores; + ++ /* All interleaving chains of loads, represented by the first ++ stmt in the chain. */ ++ auto_vec<stmt_vec_info> grouped_loads; ++ ++ /* All interleaving chains of stores (before transposed), represented by all ++ stmt in the chain. */ ++ auto_vec<vec<stmt_vec_info> > scalar_stores; ++ + /* Cost data used by the target cost model. */ + void *target_cost_data; + +@@ -702,6 +725,8 @@ public: + #define LOOP_VINFO_CHECK_NONZERO(L) (L)->check_nonzero + #define LOOP_VINFO_LOWER_BOUNDS(L) (L)->lower_bounds + #define LOOP_VINFO_GROUPED_STORES(L) (L)->grouped_stores ++#define LOOP_VINFO_GROUPED_LOADS(L) (L)->grouped_loads ++#define LOOP_VINFO_SCALAR_STORES(L) (L)->scalar_stores + #define LOOP_VINFO_SLP_INSTANCES(L) (L)->slp_instances + #define LOOP_VINFO_SLP_UNROLLING_FACTOR(L) (L)->slp_unrolling_factor + #define LOOP_VINFO_REDUCTIONS(L) (L)->reductions +@@ -764,6 +789,25 @@ public: + basic_block bb; + gimple_stmt_iterator region_begin; + gimple_stmt_iterator region_end; ++ ++ /* True, if bb_vinfo can goto vect_analyze_slp. */ ++ bool before_slp; ++ ++ /* True, if bb_vinfo is a transposed version. */ ++ bool transposed; ++ ++ /* The number of transposed groups. */ ++ int transposed_group; ++ ++ /* The cost of the scalar iterations. */ ++ int scalar_cost; ++ ++ /* The cost of the vector prologue and epilogue, including peeled ++ iterations and set-up code. */ ++ int vec_outside_cost; ++ ++ /* The cost of the vector loop body. */ ++ int vec_inside_cost; + } *bb_vec_info; + + #define BB_VINFO_BB(B) (B)->bb +@@ -772,6 +816,14 @@ public: + #define BB_VINFO_DATAREFS(B) (B)->shared->datarefs + #define BB_VINFO_DDRS(B) (B)->shared->ddrs + #define BB_VINFO_TARGET_COST_DATA(B) (B)->target_cost_data ++#define BB_VINFO_GROUPED_LOADS(B) (B)->grouped_loads ++#define BB_VINFO_SCALAR_STORES(B) (B)->scalar_stores ++#define BB_VINFO_VEC_OUTSIDE_COST(B) (B)->vec_outside_cost ++#define BB_VINFO_VEC_INSIDE_COST(B) (B)->vec_inside_cost ++#define BB_VINFO_SCALAR_COST(B) (B)->scalar_cost ++#define BB_VINFO_SLP_TRANSPOSED(B) (B)->transposed ++#define BB_VINFO_BEFORE_SLP(B) (B)->before_slp ++#define BB_VINFO_TRANS_GROUPS(B) (B)->transposed_group + + static inline bb_vec_info + vec_info_for_bb (basic_block bb) +@@ -1012,6 +1064,17 @@ public: + stmt_vec_info next_element; + /* The size of the group. */ + unsigned int size; ++ ++ /* The size of the group before transposed. */ ++ unsigned int size_before_transpose; ++ ++ /* If true, the stmt_info is slp transposed. */ ++ bool slp_transpose; ++ ++ /* Mark the group store number for rebuild interleaving chain ++ during transpose phase. Value -1 represents unable to transpose. */ ++ int group_number; ++ + /* For stores, number of stores from this group seen. We vectorize the last + one. */ + unsigned int store_count; +@@ -1019,6 +1082,9 @@ public: + is 1. */ + unsigned int gap; + ++ /* The gap before transposed. */ ++ unsigned int gap_before_transpose; ++ + /* The minimum negative dependence distance this stmt participates in + or zero if none. */ + unsigned int min_neg_dist; +@@ -1217,6 +1283,12 @@ STMT_VINFO_BB_VINFO (stmt_vec_info stmt_vinfo) + #define STMT_VINFO_REDUC_VECTYPE_IN(S) (S)->reduc_vectype_in + #define STMT_VINFO_SLP_VECT_ONLY(S) (S)->slp_vect_only_p + ++#define DR_GROUP_SLP_TRANSPOSE(S) \ ++ (gcc_checking_assert ((S)->dr_aux.dr), (S)->slp_transpose) ++#define DR_GROUP_SIZE_TRANS(S) \ ++ (gcc_checking_assert ((S)->dr_aux.dr), (S)->size_before_transpose) ++#define DR_GROUP_NUMBER(S) \ ++ (gcc_checking_assert ((S)->dr_aux.dr), (S)->group_number) + #define DR_GROUP_FIRST_ELEMENT(S) \ + (gcc_checking_assert ((S)->dr_aux.dr), (S)->first_element) + #define DR_GROUP_NEXT_ELEMENT(S) \ +@@ -1227,6 +1299,8 @@ STMT_VINFO_BB_VINFO (stmt_vec_info stmt_vinfo) + (gcc_checking_assert ((S)->dr_aux.dr), (S)->store_count) + #define DR_GROUP_GAP(S) \ + (gcc_checking_assert ((S)->dr_aux.dr), (S)->gap) ++#define DR_GROUP_GAP_TRANS(S) \ ++ (gcc_checking_assert ((S)->dr_aux.dr), (S)->gap_before_transpose) + + #define REDUC_GROUP_FIRST_ELEMENT(S) \ + (gcc_checking_assert (!(S)->dr_aux.dr), (S)->first_element) +@@ -1624,6 +1698,17 @@ vect_get_scalar_dr_size (dr_vec_info *dr_info) + return tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (dr_info->dr)))); + } + ++/* Compare two unsigned int A and B. ++ Sorting them in ascending order. */ ++ ++static inline int ++cmp_for_group_num (const void *a_, const void *b_) ++{ ++ unsigned int a = *(unsigned int *)const_cast<void *>(a_); ++ unsigned int b = *(unsigned int *)const_cast<void *>(b_); ++ return a < b ? -1 : 1; ++} ++ + /* Return true if LOOP_VINFO requires a runtime check for whether the + vector loop is profitable. */ + +@@ -1787,6 +1872,9 @@ extern bool vect_grouped_load_supported (tree, bool, unsigned HOST_WIDE_INT); + extern bool vect_load_lanes_supported (tree, unsigned HOST_WIDE_INT, bool); + extern void vect_permute_store_chain (vec<tree> ,unsigned int, stmt_vec_info, + gimple_stmt_iterator *, vec<tree> *); ++extern void vect_transpose_store_chain (vec<tree>, unsigned int, unsigned int, ++ stmt_vec_info, gimple_stmt_iterator *, ++ vec<tree> *); + extern tree vect_setup_realignment (stmt_vec_info, gimple_stmt_iterator *, + tree *, enum dr_alignment_support, tree, + class loop **); +@@ -1849,6 +1937,7 @@ extern void vect_free_slp_instance (slp_instance, bool); + extern bool vect_transform_slp_perm_load (slp_tree, vec<tree> , + gimple_stmt_iterator *, poly_uint64, + slp_instance, bool, unsigned *); ++extern void vect_transform_back_slp_grouped_stores (bb_vec_info, stmt_vec_info); + extern bool vect_slp_analyze_operations (vec_info *); + extern void vect_schedule_slp (vec_info *); + extern opt_result vect_analyze_slp (vec_info *, unsigned); +-- +2.27.0.windows.1 + diff --git a/0046-ArrayWidenCompare-Add-a-new-optimization-for-array-c.patch b/0046-ArrayWidenCompare-Add-a-new-optimization-for-array-c.patch new file mode 100644 index 0000000..4a3da78 --- /dev/null +++ b/0046-ArrayWidenCompare-Add-a-new-optimization-for-array-c.patch @@ -0,0 +1,1982 @@ +From 8072fe107c04778de78db90bf6fdb7baf474e24a Mon Sep 17 00:00:00 2001 +From: dingguangya <dingguangya1@huawei.com> +Date: Thu, 2 Jun 2022 12:48:17 +0800 +Subject: [PATCH 12/12] [ArrayWidenCompare] Add a new optimization for array + comparison scenarios + +Add option farray-widen-compare. +For an array pointer whose element is a single-byte type, +by changing the pointer type to a long-byte type, the elements +can be combined and compared after loading. +--- + gcc/Makefile.in | 1 + + gcc/common.opt | 5 + + gcc/doc/invoke.texi | 13 +- + gcc/passes.def | 1 + + .../gcc.dg/tree-ssa/awiden-compare-1.c | 19 + + .../gcc.dg/tree-ssa/awiden-compare-2.c | 90 + + .../gcc.dg/tree-ssa/awiden-compare-3.c | 22 + + .../gcc.dg/tree-ssa/awiden-compare-4.c | 22 + + .../gcc.dg/tree-ssa/awiden-compare-5.c | 19 + + .../gcc.dg/tree-ssa/awiden-compare-6.c | 19 + + .../gcc.dg/tree-ssa/awiden-compare-7.c | 22 + + .../gcc.dg/tree-ssa/awiden-compare-8.c | 24 + + gcc/timevar.def | 1 + + gcc/tree-pass.h | 1 + + gcc/tree-ssa-loop-array-widen-compare.c | 1555 +++++++++++++++++ + 15 files changed, 1813 insertions(+), 1 deletion(-) + create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-1.c + create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-2.c + create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-3.c + create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-4.c + create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-5.c + create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-6.c + create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-7.c + create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-8.c + create mode 100644 gcc/tree-ssa-loop-array-widen-compare.c + +diff --git a/gcc/Makefile.in b/gcc/Makefile.in +index 23394c64b..2b2bf474a 100644 +--- a/gcc/Makefile.in ++++ b/gcc/Makefile.in +@@ -1591,6 +1591,7 @@ OBJS = \ + tree-ssa-loop-ivopts.o \ + tree-ssa-loop-manip.o \ + tree-ssa-loop-niter.o \ ++ tree-ssa-loop-array-widen-compare.o \ + tree-ssa-loop-prefetch.o \ + tree-ssa-loop-split.o \ + tree-ssa-loop-unswitch.o \ +diff --git a/gcc/common.opt b/gcc/common.opt +index 24834cf60..2985a5791 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -1060,6 +1060,11 @@ fasynchronous-unwind-tables + Common Report Var(flag_asynchronous_unwind_tables) Optimization + Generate unwind tables that are exact at each instruction boundary. + ++farray-widen-compare ++Common Report Var(flag_array_widen_compare) Optimization ++Extends types for pointers to arrays to improve array comparsion performance. ++In some extreme situations this may result in unsafe behavior. ++ + fauto-inc-dec + Common Report Var(flag_auto_inc_dec) Init(1) Optimization + Generate auto-inc/dec instructions. +diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi +index 4b0fd2ffb..44f1f8a2e 100644 +--- a/gcc/doc/invoke.texi ++++ b/gcc/doc/invoke.texi +@@ -459,7 +459,7 @@ Objective-C and Objective-C++ Dialects}. + -falign-loops[=@var{n}[:@var{m}:[@var{n2}[:@var{m2}]]]] @gol + -fno-allocation-dce -fallow-store-data-races @gol + -fassociative-math -fauto-profile -fauto-profile[=@var{path}] @gol +--fauto-inc-dec -fbranch-probabilities @gol ++-farray-widen-compare -fauto-inc-dec -fbranch-probabilities @gol + -fcaller-saves @gol + -fcombine-stack-adjustments -fconserve-stack @gol + -fcompare-elim -fcprop-registers -fcrossjumping @gol +@@ -9710,6 +9710,17 @@ This pass is always skipped on architectures that do not have + instructions to support this. Enabled by default at @option{-O} and + higher on architectures that support this. + ++@item -farray-widen-compare ++@opindex farray-widen-compare ++In the narrow-byte array comparison scenario, the types of pointers ++pointing to array are extended so that elements of multiple bytes can ++be loaded at a time when a wide type is used to dereference an array, ++thereby improving the performance of this comparison scenario. In some ++extreme situations this may result in unsafe behavior. ++ ++This option may generate better or worse code; results are highly dependent ++on the structure of loops within the source code. ++ + @item -fdce + @opindex fdce + Perform dead code elimination (DCE) on RTL@. +diff --git a/gcc/passes.def b/gcc/passes.def +index e9c91d26e..797b803ca 100644 +--- a/gcc/passes.def ++++ b/gcc/passes.def +@@ -91,6 +91,7 @@ along with GCC; see the file COPYING3. If not see + NEXT_PASS (pass_dse); + NEXT_PASS (pass_cd_dce); + NEXT_PASS (pass_phiopt, true /* early_p */); ++ NEXT_PASS (pass_array_widen_compare); + NEXT_PASS (pass_tail_recursion); + NEXT_PASS (pass_convert_switch); + NEXT_PASS (pass_cleanup_eh); +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-1.c b/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-1.c +new file mode 100644 +index 000000000..27b69b0e9 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-1.c +@@ -0,0 +1,19 @@ ++/* { dg-do compile { target {{ aarch64*-*-linux* } && lp64 } } } */ ++/* { dg-options "-O3 -mabi=lp64 -farray-widen-compare -fdump-tree-awiden_compare-details" } */ ++ ++#include <stdint.h> ++#include <stdio.h> ++ ++#define my_min(x, y) ((x) < (y) ? (x) : (y)) ++ ++uint32_t ++func (uint32_t len0, uint32_t len1, const uint32_t len_limit, const uint8_t *const pb, const uint8_t *const cur) ++{ ++ uint32_t len = my_min(len0, len1); ++ while (++len != len_limit) ++ if (pb[len] != cur[len]) ++ break; ++ return len; ++} ++ ++/* { dg-final { scan-tree-dump-times "loop form is success" 1 "awiden_compare"} } */ +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-2.c b/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-2.c +new file mode 100644 +index 000000000..d102364f2 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-2.c +@@ -0,0 +1,90 @@ ++/* { dg-do compile { target {{ aarch64*-*-linux* } && lp64 } } } */ ++/* { dg-options "-O3 -mabi=lp64 -farray-widen-compare -fdump-tree-awiden_compare-details" } */ ++ ++#include <stdint.h> ++#include <stdio.h> ++ ++#define EMPTY_HASH_VALUE 0 ++#define my_min(x, y) ((x) < (y) ? (x) : (y)) ++#define true 1 ++ ++typedef struct { ++ uint32_t len; ++ uint32_t dist; ++} lzma_match; ++ ++ ++lzma_match * ++func ( ++ const uint32_t len_limit, ++ const uint32_t pos, ++ const uint8_t *const cur, ++ uint32_t cur_match, ++ uint32_t depth, ++ uint32_t *const son, ++ const uint32_t cyclic_pos, ++ const uint32_t cyclic_size, ++ lzma_match *matches, ++ uint32_t len_best) ++{ ++ uint32_t *ptr0 = son + (cyclic_pos << 1) + 1; ++ uint32_t *ptr1 = son + (cyclic_pos << 1); ++ ++ uint32_t len0 = 0; ++ uint32_t len1 = 0; ++ ++ while (true) ++ { ++ const uint32_t delta = pos - cur_match; ++ if (depth-- == 0 || delta >= cyclic_size) ++ { ++ *ptr0 = EMPTY_HASH_VALUE; ++ *ptr1 = EMPTY_HASH_VALUE; ++ return matches; ++ } ++ ++ uint32_t *const pair = son + ((cyclic_pos - delta + (delta > cyclic_pos ? cyclic_size : 0)) << 1); ++ ++ const uint8_t *const pb = cur -delta; ++ uint32_t len = my_min(len0, len1); ++ ++ if (pb[len] == cur[len]) ++ { ++ while (++len != len_limit) ++ if (pb[len] != cur[len]) ++ break; ++ ++ if (len_best < len) ++ { ++ len_best = len; ++ matches->len = len; ++ matches->dist = delta - 1; ++ ++matches; ++ ++ if (len == len_limit) ++ { ++ *ptr1 = pair[0]; ++ *ptr0 = pair[1]; ++ return matches; ++ } ++ } ++ } ++ ++ if (pb[len] < cur[len]) ++ { ++ *ptr1 = cur_match; ++ ptr1 = pair + 1; ++ cur_match = *ptr1; ++ len1 = len; ++ } ++ else ++ { ++ *ptr0 = cur_match; ++ ptr0 = pair; ++ cur_match = *ptr0; ++ len0 = len; ++ } ++ } ++} ++ ++/* { dg-final { scan-tree-dump-times "loop form is success" 1 "awiden_compare"} } */ +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-3.c b/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-3.c +new file mode 100644 +index 000000000..52dd6b02b +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-3.c +@@ -0,0 +1,22 @@ ++/* { dg-do compile { target {{ aarch64*-*-linux* } && lp64 } } } */ ++/* { dg-options "-O3 -mabi=lp64 -farray-widen-compare -fdump-tree-awiden_compare-details" } */ ++ ++#include <stdint.h> ++#include <stdio.h> ++ ++#define my_min(x, y) ((x) < (y) ? (x) : (y)) ++ ++uint32_t ++func (uint32_t len0, uint32_t len1, const uint32_t len_limit, const uint8_t *const pb, const uint8_t *const cur) ++{ ++ uint32_t len = my_min(len0, len1); ++ while (len != len_limit) ++ { ++ if (pb[len] != cur[len]) ++ break; ++ len = len + 1; ++ } ++ return len; ++} ++ ++/* { dg-final { scan-tree-dump-times "loop form is success" 1 "awiden_compare"} } */ +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-4.c b/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-4.c +new file mode 100644 +index 000000000..d3185d326 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-4.c +@@ -0,0 +1,22 @@ ++/* { dg-do compile { target {{ aarch64*-*-linux* } && lp64 } } } */ ++/* { dg-options "-O3 -mabi=lp64 -farray-widen-compare -fdump-tree-awiden_compare-details" } */ ++ ++#include <stdint.h> ++#include <stdio.h> ++ ++#define my_min(x, y) ((x) < (y) ? (x) : (y)) ++ ++uint32_t ++func (uint32_t len0, uint32_t len1, const uint32_t len_limit, const uint8_t *const pb, const uint8_t *const cur) ++{ ++ uint32_t len = my_min(len0, len1); ++ while (len != len_limit) ++ { ++ if (pb[len] != cur[len]) ++ break; ++ len = len + 2; ++ } ++ return len; ++} ++ ++/* { dg-final { scan-tree-dump-times "loop form is success" 0 "awiden_compare"} } */ +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-5.c b/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-5.c +new file mode 100644 +index 000000000..9743dc623 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-5.c +@@ -0,0 +1,19 @@ ++/* { dg-do compile { target {{ aarch64*-*-linux* } && lp64 } } } */ ++/* { dg-options "-O3 -mabi=lp64 -farray-widen-compare -fdump-tree-awiden_compare-details" } */ ++ ++#include <stdint.h> ++#include <stdio.h> ++ ++#define my_min(x, y) ((x) < (y) ? (x) : (y)) ++ ++uint32_t ++func (uint32_t len0, uint32_t len1, const uint32_t len_limit, const uint8_t *const pb, const uint8_t *const cur) ++{ ++ uint32_t len = my_min(len0, len1); ++ while (++len != len_limit) ++ if (pb[len] != cur[len-1]) ++ break; ++ return len; ++} ++ ++/* { dg-final { scan-tree-dump-times "loop form is success" 0 "awiden_compare"} } */ +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-6.c b/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-6.c +new file mode 100644 +index 000000000..2323d5bf7 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-6.c +@@ -0,0 +1,19 @@ ++/* { dg-do compile { target {{ aarch64*-*-linux* } && lp64 } } } */ ++/* { dg-options "-O3 -mabi=lp64 -farray-widen-compare -fdump-tree-awiden_compare-details" } */ ++ ++#include <stdint.h> ++#include <stdio.h> ++ ++#define my_min(x, y) ((x) < (y) ? (x) : (y)) ++ ++uint32_t ++func (uint32_t len0, uint32_t len1, const uint32_t len_limit, const uint8_t *const pb, const uint8_t *const cur) ++{ ++ uint32_t len = my_min(len0, len1); ++ while (len++ != len_limit) ++ if (pb[len] != cur[len]) ++ break; ++ return len; ++} ++ ++/* { dg-final { scan-tree-dump-times "loop form is success" 0 "awiden_compare"} } */ +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-7.c b/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-7.c +new file mode 100644 +index 000000000..33db62fa4 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-7.c +@@ -0,0 +1,22 @@ ++/* { dg-do compile { target {{ aarch64*-*-linux* } && lp64 } } } */ ++/* { dg-options "-O3 -mabi=lp64 -farray-widen-compare -fdump-tree-awiden_compare-details" } */ ++ ++#include <stdint.h> ++#include <stdio.h> ++ ++#define my_min(x, y) ((x) < (y) ? (x) : (y)) ++ ++uint32_t ++func (uint32_t len0, uint32_t len1, const uint32_t len_limit, const uint8_t *const pb, const uint8_t *const cur) ++{ ++ uint32_t len = my_min(len0, len1); ++ while (len != len_limit) ++ { ++ len = len + 1; ++ if (pb[len] != cur[len]) ++ break; ++ } ++ return len; ++} ++ ++/* { dg-final { scan-tree-dump-times "loop form is success" 0 "awiden_compare"} } */ +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-8.c b/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-8.c +new file mode 100644 +index 000000000..8c96d24a1 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/awiden-compare-8.c +@@ -0,0 +1,24 @@ ++/* { dg-do compile { target {{ aarch64*-*-linux* } && lp64 } } } */ ++/* { dg-options "-O3 -mabi=lp64 -farray-widen-compare -fdump-tree-awiden_compare-details" } */ ++ ++#include <stdint.h> ++#include <stdio.h> ++ ++#define my_min(x, y) ((x) < (y) ? (x) : (y)) ++ ++uint32_t ++func (uint32_t len0, uint32_t len1, const uint32_t len_limit, const uint8_t *const pb, const uint8_t *const cur) ++{ ++ uint32_t len = my_min(len0, len1); ++ while (++len != len_limit) ++ { ++ if (pb[len] != cur[len]) ++ { ++ len = len - 1; ++ break; ++ } ++ } ++ return len; ++} ++ ++/* { dg-final { scan-tree-dump-times "loop form is success" 0 "awiden_compare"} } */ +diff --git a/gcc/timevar.def b/gcc/timevar.def +index e873747a8..6d90bb6e1 100644 +--- a/gcc/timevar.def ++++ b/gcc/timevar.def +@@ -215,6 +215,7 @@ DEFTIMEVAR (TV_TREE_NRV , "tree NRV optimization") + DEFTIMEVAR (TV_TREE_COPY_RENAME , "tree rename SSA copies") + DEFTIMEVAR (TV_TREE_SSA_VERIFY , "tree SSA verifier") + DEFTIMEVAR (TV_TREE_STMT_VERIFY , "tree STMT verifier") ++DEFTIMEVAR (TV_TREE_ARRAY_WIDEN_COMPARE, "tree array widen compare") + DEFTIMEVAR (TV_TREE_SWITCH_CONVERSION, "tree switch conversion") + DEFTIMEVAR (TV_TREE_SWITCH_LOWERING, "tree switch lowering") + DEFTIMEVAR (TV_TREE_RECIP , "gimple CSE reciprocals") +diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h +index be6387768..aca0b83f2 100644 +--- a/gcc/tree-pass.h ++++ b/gcc/tree-pass.h +@@ -436,6 +436,7 @@ extern gimple_opt_pass *make_pass_cselim (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_phiopt (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_forwprop (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_phiprop (gcc::context *ctxt); ++extern gimple_opt_pass *make_pass_array_widen_compare (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_tree_ifcombine (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_dse (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_nrv (gcc::context *ctxt); +diff --git a/gcc/tree-ssa-loop-array-widen-compare.c b/gcc/tree-ssa-loop-array-widen-compare.c +new file mode 100644 +index 000000000..ba51d785d +--- /dev/null ++++ b/gcc/tree-ssa-loop-array-widen-compare.c +@@ -0,0 +1,1555 @@ ++/* Array widen compare. ++ Copyright (C) 2022-2022 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/>. */ ++ ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "backend.h" ++#include "target.h" ++#include "tree.h" ++#include "gimple.h" ++#include "tree-pass.h" ++#include "gimple-ssa.h" ++#include "tree-pretty-print.h" ++#include "fold-const.h" ++#include "gimplify.h" ++#include "gimple-iterator.h" ++#include "tree-ssa-loop-manip.h" ++#include "tree-ssa-loop.h" ++#include "ssa.h" ++#include "tree-into-ssa.h" ++#include "cfganal.h" ++#include "cfgloop.h" ++#include "gimple-pretty-print.h" ++#include "tree-cfg.h" ++#include "cgraph.h" ++#include "print-tree.h" ++#include "cfghooks.h" ++#include "gimple-fold.h" ++ ++/* This pass handles scenarios similar to the following: ++ ++ uint32_t ++ func (uint32_t len0, uint32_t len1, const uint32_t len_limit, ++ const uint8_t *const pb, const uint8_t *const cur) ++ { ++ uint32_t len = my_min (len0, len1); ++ while (++len != len_limit) ++ if (pb[len] != cur[len]) ++ break; ++ return len; ++ } ++ ++ Features of this type of loop: ++ 1) the loop has two exits; ++ 2) One of the exits comes from the comparison result of the array; ++ ++ From the source code point of view, the pass completes the conversion of the ++ above scenario into: ++ ++ uint32_t ++ func (uint32_t len0, uint32_t len1, const uint32_t len_limit, ++ const uint8_t *const pb, const uint8_t *const cur) ++ { ++ uint32_t len = my_min (len0, len1); ++ // align_loop ++ for(++len; len + sizeof(uint64_t) <= len_limit; len += sizeof (uint64_t)) ++ { ++ uint64_t a = *((uint64_t*)(cur+len)); ++ uint64_t b = *((uint64_t*)(pb+len)); ++ if (a != b) ++ { ++ int lz = __builtin_ctzll (a ^ b); ++ len += lz / 8; ++ return len; ++ } ++ } ++ // epilogue_loop ++ for (;len != len_limit; ++len) ++ if (pb[len] != cur[len]) ++ break; ++ return len; ++ } ++ ++ This pass is to complete the conversion of such scenarios from the internal ++ perspective of the compiler: ++ 1) determine_loop_form: The function completes the screening of such ++ scenarios; ++ 2) convert_to_new_loop: The function completes the conversion of ++ origin_loop to new loops, and removes origin_loop; ++ 3) origin_loop_info: The structure is used to record important information ++ of origin_loop: such as loop exit, growth step size ++ of loop induction variable, initial value ++ of induction variable, etc; ++ 4) create_new_loops: The function is used as the key content of the pass ++ to complete the creation of new loops. */ ++ ++/* The useful information of origin loop. */ ++ ++struct origin_loop_info ++{ ++ tree base; /* The initial index of the array in the old loop. */ ++ tree limit; /* The limit index of the array in the old loop. */ ++ tree arr1; /* Array 1 in the old loop. */ ++ tree arr2; /* Array 2 in the old loop. */ ++ edge entry_edge; /* The edge into the old loop. */ ++ basic_block exit_bb1; ++ basic_block exit_bb2; ++ edge exit_e1; ++ edge exit_e2; ++ gimple *cond_stmt1; ++ gimple *cond_stmt2; ++ gimple *update_stmt; ++ bool exist_prolog_assgin; ++ /* Whether the marker has an initial value assigned ++ to the array index. */ ++ unsigned HOST_WIDE_INT step; ++ /* The growth step of the loop induction variable. */ ++}; ++ ++typedef struct origin_loop_info origin_loop_info; ++ ++static origin_loop_info origin_loop; ++hash_map <basic_block, tree> defs_map; ++ ++/* Dump the bb information in a loop. */ ++ ++static void ++dump_loop_bb (struct loop *loop) ++{ ++ basic_block *body = get_loop_body_in_dom_order (loop); ++ basic_block bb = NULL; ++ ++ for (unsigned i = 0; i < loop->num_nodes; i++) ++ { ++ bb = body[i]; ++ if (bb->loop_father != loop) ++ { ++ continue; ++ } ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "===== the %dth bb of loop ==========:\n", i); ++ gimple_dump_bb (dump_file, bb, 0, dump_flags); ++ fprintf (dump_file, "\n"); ++ } ++ } ++ free (body); ++} ++ ++/* Return true if the loop has precisely one backedge. */ ++ ++static bool ++loop_single_backedge_p (class loop *loop) ++{ ++ basic_block latch = loop->latch; ++ if (!single_succ_p (latch)) ++ return false; ++ ++ edge e = single_succ_edge (latch); ++ edge backedge = find_edge (latch, loop->header); ++ ++ if (e != backedge) ++ return false; ++ ++ return true; ++} ++ ++/* Return true if the loop has precisely one preheader BB. */ ++ ++static bool ++loop_single_preheader_bb (class loop *loop) ++{ ++ basic_block header = loop->header; ++ if (EDGE_COUNT (header->preds) != 2) ++ return false; ++ ++ edge e1 = EDGE_PRED (header, 0); ++ edge e2 = EDGE_PRED (header, 1); ++ ++ if ((e1->src == loop->latch && e2->src->loop_father != loop) ++ || (e2->src == loop->latch && e1->src->loop_father != loop)) ++ return true; ++ ++ return false; ++} ++ ++/* Initialize the origin_loop structure. */ ++static void ++init_origin_loop_structure () ++{ ++ origin_loop.base = NULL; ++ origin_loop.limit = NULL; ++ origin_loop.arr1 = NULL; ++ origin_loop.arr2 = NULL; ++ origin_loop.exit_e1 = NULL; ++ origin_loop.exit_e2 = NULL; ++ origin_loop.exit_bb1 = NULL; ++ origin_loop.exit_bb2 =NULL; ++ origin_loop.entry_edge = NULL; ++ origin_loop.cond_stmt1 = NULL; ++ origin_loop.cond_stmt2 = NULL; ++ origin_loop.update_stmt = NULL; ++ origin_loop.exist_prolog_assgin = false; ++ origin_loop.step = 0; ++} ++ ++/* Get the edge that first entered the loop. */ ++ ++static edge ++get_loop_preheader_edge (class loop *loop) ++{ ++ edge e; ++ edge_iterator ei; ++ ++ FOR_EACH_EDGE (e, ei, loop->header->preds) ++ if (e->src != loop->latch) ++ break; ++ ++ if (!e) ++ { ++ gcc_assert (!loop_outer (loop)); ++ return single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)); ++ } ++ ++ return e; ++} ++ ++/* Make sure the exit condition stmt satisfies a specific form. */ ++ ++static bool ++check_cond_stmt (gimple *stmt) ++{ ++ if (!stmt) ++ return false; ++ if (gimple_code (stmt) != GIMPLE_COND) ++ return false; ++ ++ if (gimple_cond_code (stmt) != NE_EXPR && gimple_cond_code (stmt) != EQ_EXPR) ++ return false; ++ ++ tree lhs = gimple_cond_lhs (stmt); ++ tree rhs = gimple_cond_rhs (stmt); ++ ++ /* The parameter that does not support the cond statement is not SSA_NAME. ++ eg: if (len_1 != 100). */ ++ if (TREE_CODE (lhs) != SSA_NAME || TREE_CODE (rhs) != SSA_NAME) ++ return false; ++ ++ return true; ++} ++ ++/* Record the exit information in the original loop including exit edge, ++ exit bb block, exit condition stmt, ++ eg: exit_eX origin_exit_bbX cond_stmtX. */ ++ ++static bool ++record_origin_loop_exit_info (class loop *loop) ++{ ++ bool found = false; ++ edge e = NULL; ++ unsigned i = 0; ++ gimple *stmt; ++ ++ if (origin_loop.exit_e1 != NULL || origin_loop.exit_bb1 != NULL ++ || origin_loop.exit_e2 != NULL || origin_loop.exit_bb2 != NULL ++ || origin_loop.cond_stmt1 != NULL || origin_loop.cond_stmt2 != NULL) ++ return false; ++ ++ vec<edge> exit_edges = get_loop_exit_edges (loop); ++ if (exit_edges == vNULL) ++ return false; ++ ++ if (exit_edges.length () != 2) ++ goto fail; ++ ++ FOR_EACH_VEC_ELT (exit_edges, i, e) ++ { ++ if (e->src == loop->header) ++ { ++ origin_loop.exit_e1 = e; ++ origin_loop.exit_bb1 = e->dest; ++ stmt = gsi_stmt (gsi_last_bb (e->src)); ++ if (check_cond_stmt (stmt)) ++ origin_loop.cond_stmt1 = stmt; ++ } ++ else ++ { ++ origin_loop.exit_e2 = e; ++ origin_loop.exit_bb2 = e->dest; ++ stmt = gsi_stmt (gsi_last_bb (e->src)); ++ if (check_cond_stmt (stmt)) ++ origin_loop.cond_stmt2 = stmt; ++ } ++ } ++ ++ if (origin_loop.exit_e1 != NULL && origin_loop.exit_bb1 != NULL ++ && origin_loop.exit_e2 != NULL && origin_loop.exit_bb2 != NULL ++ && origin_loop.cond_stmt1 != NULL && origin_loop.cond_stmt2 != NULL) ++ found = true; ++ ++fail: ++ exit_edges.release (); ++ return found; ++} ++ ++/* Returns true if t is SSA_NAME and user variable exists. */ ++ ++static bool ++ssa_name_var_p (tree t) ++{ ++ if (!t || TREE_CODE (t) != SSA_NAME) ++ return false; ++ if (SSA_NAME_VAR (t)) ++ return true; ++ return false; ++} ++ ++/* Returns true if t1 and t2 are SSA_NAME and belong to the same variable. */ ++ ++static bool ++same_ssa_name_var_p (tree t1, tree t2) ++{ ++ if (!ssa_name_var_p (t1) || !ssa_name_var_p (t2)) ++ return false; ++ if (SSA_NAME_VAR (t1) == SSA_NAME_VAR (t2)) ++ return true; ++ return false; ++} ++ ++/* Get origin loop induction variable upper bound. */ ++ ++static bool ++get_iv_upper_bound (gimple *stmt) ++{ ++ if (origin_loop.limit != NULL) ++ return false; ++ ++ tree lhs = gimple_cond_lhs (stmt); ++ tree rhs = gimple_cond_rhs (stmt); ++ ++ if (TREE_CODE (TREE_TYPE (lhs)) != INTEGER_TYPE ++ || TREE_CODE (TREE_TYPE (rhs)) != INTEGER_TYPE) ++ return false; ++ ++ gimple *g = SSA_NAME_DEF_STMT (rhs); ++ ++ /* TODO: Currently, the input restrictions on lhs and rhs are implemented ++ through PARM_DECL. We may consider releasing the restrictions later, and ++ we need to consider the overall adaptation scenario and adding test ++ cases. */ ++ if (ssa_name_var_p (rhs) && TREE_CODE (SSA_NAME_VAR (rhs)) == PARM_DECL ++ && g && gimple_code (g) == GIMPLE_NOP ++ && (ssa_name_var_p (lhs) && TREE_CODE (SSA_NAME_VAR (lhs)) != PARM_DECL)) ++ { ++ origin_loop.limit = rhs; ++ } ++ else ++ return false; ++ ++ if (origin_loop.limit != NULL) ++ return true; ++ ++ return false; ++} ++ ++/* Returns true only when the expression on the rhs code of stmt is PLUS_EXPR, ++ rhs1 is SSA_NAME with the same var as origin_loop base, and rhs2 is ++ INTEGER_CST. */ ++ ++static bool ++check_update_stmt (gimple *stmt) ++{ ++ if (!stmt) ++ return false; ++ ++ if (gimple_assign_rhs_code (stmt) == PLUS_EXPR) ++ { ++ tree rhs1 = gimple_assign_rhs1 (stmt); ++ tree rhs2 = gimple_assign_rhs2 (stmt); ++ if (TREE_CODE (rhs1) == SSA_NAME && TREE_CODE (rhs2) == INTEGER_CST ++ && same_ssa_name_var_p (rhs1, origin_loop.base)) ++ { ++ origin_loop.step = tree_to_uhwi (rhs2); ++ if (origin_loop.step == 1) ++ return true; ++ } ++ } ++ return false; ++} ++ ++/* Get origin loop induction variable initial value. */ ++ ++static bool ++get_iv_base (gimple *stmt) ++{ ++ tree lhs = gimple_cond_lhs (stmt); ++ if (origin_loop.base != NULL || origin_loop.update_stmt != NULL) ++ return false; ++ ++ basic_block header = gimple_bb (stmt); ++ ++ gphi_iterator gsi; ++ edge e; ++ edge_iterator ei; ++ tree iv_after; ++ ++ for (gsi = gsi_start_phis (header); !gsi_end_p (gsi); gsi_next (&gsi)) ++ { ++ gphi *phi = gsi.phi (); ++ tree res = gimple_phi_result (phi); ++ if (!same_ssa_name_var_p (res, lhs)) ++ continue; ++ tree base = PHI_ARG_DEF_FROM_EDGE (phi, origin_loop.entry_edge); ++ if (!same_ssa_name_var_p (base, lhs)) ++ return false; ++ origin_loop.base = base; ++ FOR_EACH_EDGE (e, ei, header->preds) ++ { ++ if (e != origin_loop.entry_edge) ++ { ++ iv_after = PHI_ARG_DEF_FROM_EDGE (phi, e); ++ gimple *update = SSA_NAME_DEF_STMT (iv_after); ++ if (!check_update_stmt (update)) ++ return false; ++ origin_loop.update_stmt = update; ++ if (gimple_bb (update) == header && iv_after == lhs) ++ origin_loop.exist_prolog_assgin = true; ++ } ++ } ++ } ++ ++ if (origin_loop.base != NULL && origin_loop.update_stmt != NULL) ++ return true; ++ ++ return false; ++} ++ ++/* Record the upper bound and initial value of the induction variable in the ++ original loop; When prolog_assign is present, make sure loop header is in ++ simple form; And the interpretation of prolog_assign is as follows: ++ eg: while (++len != limit) ++ ...... ++ For such a loop, ++len will be processed before entering header_bb, and the ++ assign is regarded as the prolog_assign of the loop. */ ++ ++static bool ++record_origin_loop_header (class loop *loop) ++{ ++ basic_block header = loop->header; ++ ++ if (origin_loop.entry_edge != NULL || origin_loop.base != NULL ++ || origin_loop.update_stmt != NULL || origin_loop.limit != NULL) ++ return false; ++ origin_loop.entry_edge = get_loop_preheader_edge (loop); ++ ++ gimple_stmt_iterator gsi; ++ gimple *stmt; ++ ++ for (gsi = gsi_last_bb (header); !gsi_end_p (gsi); gsi_prev (&gsi)) ++ { ++ stmt = gsi_stmt (gsi); ++ if (stmt && is_gimple_debug (stmt)) ++ continue; ++ if (stmt && gimple_code (stmt) == GIMPLE_COND) ++ { ++ if (!get_iv_upper_bound (stmt)) ++ return false; ++ if (!get_iv_base (stmt)) ++ return false; ++ } ++ else if (stmt && gimple_code (stmt) == GIMPLE_ASSIGN) ++ { ++ if (stmt != origin_loop.update_stmt || !origin_loop.exist_prolog_assgin) ++ return false; ++ } ++ else ++ return false; ++ } ++ ++ if (origin_loop.entry_edge != NULL && origin_loop.base != NULL ++ && origin_loop.update_stmt != NULL && origin_loop.limit != NULL) ++ return true; ++ ++ return false; ++} ++ ++/* When prolog_assign does not exist, make sure that update_stmt exists in the ++ loop latch, and its form is a specific form, eg: ++ len_2 = len_1 + 1. */ ++ ++static bool ++record_origin_loop_latch (class loop *loop) ++{ ++ basic_block latch = loop->latch; ++ gimple_stmt_iterator gsi; ++ gimple *stmt; ++ ++ gsi = gsi_start_bb (latch); ++ ++ if (origin_loop.exist_prolog_assgin) ++ { ++ if (gsi_end_p (gsi)) ++ return true; ++ } ++ else ++ { ++ if (gsi_one_before_end_p (gsi)) ++ { ++ stmt = gsi_stmt (gsi); ++ if (stmt == origin_loop.update_stmt) ++ return true; ++ } ++ } ++ return false; ++} ++ ++/* Returns true when the DEF_STMT corresponding to arg0 of the mem_ref tree ++ satisfies the POINTER_PLUS_EXPR type. */ ++ ++static bool ++check_body_mem_ref (tree mem_ref) ++{ ++ tree arg0 = TREE_OPERAND (mem_ref , 0); ++ tree arg1 = TREE_OPERAND (mem_ref , 1); ++ ++ if (TREE_CODE (TREE_TYPE (arg0)) == POINTER_TYPE ++ && TREE_CODE (arg1) == INTEGER_CST ++ && tree_to_uhwi (arg1) == 0) ++ { ++ gimple *tmp_g = SSA_NAME_DEF_STMT (arg0); ++ if (tmp_g && gimple_assign_rhs_code (tmp_g) == POINTER_PLUS_EXPR) ++ return true; ++ } ++ return false; ++} ++ ++/* Returns true if the rh2 of the current stmt comes from the base in the ++ original loop. */ ++ ++static bool ++check_body_pointer_plus (gimple *stmt, tree &tmp_index) ++{ ++ tree rhs1 = gimple_assign_rhs1 (stmt); ++ tree rhs2 = gimple_assign_rhs2 (stmt); ++ if (TREE_CODE (TREE_TYPE (rhs1)) == POINTER_TYPE) ++ { ++ gimple *g = SSA_NAME_DEF_STMT (rhs2); ++ if (g && gimple_assign_rhs_code (g) == NOP_EXPR) ++ { ++ tree nop_rhs = gimple_assign_rhs1 (g); ++ if (same_ssa_name_var_p (nop_rhs, origin_loop.base)) ++ { ++ if (!origin_loop.arr1) ++ { ++ origin_loop.arr1 = rhs1; ++ tmp_index = rhs2; ++ } ++ else if (!origin_loop.arr2) ++ { ++ origin_loop.arr2 = rhs1; ++ if (tmp_index != rhs2) ++ return false; ++ } ++ else ++ return false; ++ return true; ++ } ++ } ++ } ++ return false; ++} ++ ++/* Record the array comparison information in the original loop, while ensuring ++ that there are only statements related to cont_stmt in the loop body. */ ++ ++static bool ++record_origin_loop_body (class loop *loop) ++{ ++ basic_block body = gimple_bb (origin_loop.cond_stmt2); ++ ++ if (origin_loop.arr1 != NULL || origin_loop.arr2 != NULL) ++ return false; ++ ++ gimple_stmt_iterator gsi; ++ for (gsi = gsi_start_bb (body); !gsi_end_p (gsi); gsi_next (&gsi)) ++ { ++ gimple_set_visited (gsi_stmt (gsi), false); ++ } ++ ++ tree cond_lhs = gimple_cond_lhs (origin_loop.cond_stmt2); ++ tree cond_rhs = gimple_cond_rhs (origin_loop.cond_stmt2); ++ if (TREE_CODE (TREE_TYPE (cond_lhs)) != INTEGER_TYPE ++ || TREE_CODE (TREE_TYPE (cond_rhs)) != INTEGER_TYPE) ++ return false; ++ ++ auto_vec<tree> stack; ++ tree tmp_index = NULL; ++ stack.safe_push (cond_lhs); ++ stack.safe_push (cond_rhs); ++ gimple_set_visited (origin_loop.cond_stmt2, true); ++ ++ while (!stack.is_empty ()) ++ { ++ tree op = stack.pop (); ++ gimple *g = SSA_NAME_DEF_STMT (op); ++ if (!g || gimple_bb (g) != body || !is_gimple_assign (g)) ++ continue; ++ gimple_set_visited (g, true); ++ if (gimple_assign_rhs_code (g) == MEM_REF) ++ { ++ tree mem_ref = gimple_assign_rhs1 (g); ++ if (!check_body_mem_ref (mem_ref)) ++ return false; ++ stack.safe_push (TREE_OPERAND (mem_ref , 0)); ++ } ++ else if (gimple_assign_rhs_code (g) == POINTER_PLUS_EXPR) ++ { ++ tree rhs2 = gimple_assign_rhs2 (g); ++ if (!check_body_pointer_plus (g, tmp_index)) ++ return false; ++ stack.safe_push (rhs2); ++ } ++ else if (gimple_assign_rhs_code (g) == NOP_EXPR) ++ { ++ tree rhs = gimple_assign_rhs1 (g); ++ if (!same_ssa_name_var_p (rhs, origin_loop.base)) ++ return false; ++ stack.safe_push (rhs); ++ } ++ else ++ return false; ++ } ++ bool allvisited = true; ++ for (gsi = gsi_start_bb (body); !gsi_end_p (gsi); gsi_next (&gsi)) ++ { ++ if (!gimple_visited_p (gsi_stmt (gsi)) ++ && !is_gimple_debug (gsi_stmt (gsi))) ++ allvisited = false; ++ } ++ if (allvisited) ++ { ++ if (origin_loop.arr1 != NULL && origin_loop.arr2 != NULL) ++ return true; ++ } ++ return false; ++} ++ ++/* Dump the original loop information to see if the origin loop ++ form matches. */ ++ ++static void ++dump_origin_loop_info () ++{ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nThe origin loop info:\n"); ++ fprintf (dump_file, "\n the origin_loop.limit is:\n"); ++ print_node (dump_file, "", origin_loop.limit, 0); ++ fprintf (dump_file, "\n"); ++ fprintf (dump_file, "\n the origin_loop.base is:\n"); ++ print_node (dump_file, "", origin_loop.base, 0); ++ fprintf (dump_file, "\n"); ++ fprintf (dump_file, "\n the origin_loop.arr1 is:\n"); ++ print_node (dump_file, "", origin_loop.arr1, 0); ++ fprintf (dump_file, "\n"); ++ fprintf (dump_file, "\n the origin_loop.arr2 is:\n"); ++ print_node (dump_file, "", origin_loop.arr2, 0); ++ fprintf (dump_file, "\n"); ++ fprintf (dump_file, "\n the origin_loop.cond_stmt1 is:\n"); ++ print_gimple_stmt (dump_file, origin_loop.cond_stmt1, 0); ++ fprintf (dump_file, "\n"); ++ fprintf (dump_file, "\n the origin_loop.cond_stmt2 is:\n"); ++ print_gimple_stmt (dump_file, origin_loop.cond_stmt2, 0); ++ fprintf (dump_file, "\n"); ++ fprintf (dump_file, "\n the origin_loop.update_stmt is:\n"); ++ print_gimple_stmt (dump_file, origin_loop.update_stmt, 0); ++ fprintf (dump_file, "\n"); ++ } ++} ++ ++/* Returns true only if the exit bb of the original loop is unique and its phi ++ node parameter comes from the same variable. */ ++ ++static bool ++check_exit_bb (class loop *loop) ++{ ++ if (origin_loop.exit_bb1 != origin_loop.exit_bb2 ++ || flow_bb_inside_loop_p (loop, origin_loop.exit_bb1)) ++ return false; ++ ++ gphi_iterator gsi; ++ for (gsi = gsi_start_phis (origin_loop.exit_bb1); !gsi_end_p (gsi); ++ gsi_next (&gsi)) ++ { ++ gphi *phi = gsi.phi (); ++ tree res = gimple_phi_result (phi); ++ if (!same_ssa_name_var_p (res, origin_loop.base)) ++ continue; ++ if (gimple_phi_num_args (phi) == 2) ++ { ++ tree arg0 = gimple_phi_arg_def (phi, 0); ++ tree arg1 = gimple_phi_arg_def (phi, 1); ++ if (arg0 == arg1) ++ return true; ++ } ++ } ++ return false; ++} ++ ++/* Make sure that the recorded origin_loop information meets the ++ relative requirements. */ ++ ++static bool ++check_origin_loop_info (class loop *loop) ++{ ++ dump_origin_loop_info (); ++ tree arr1_elem_size, arr2_elem_size; ++ ++ if (!check_exit_bb (loop)) ++ return false; ++ ++ if (TREE_CODE (origin_loop.base) != SSA_NAME) ++ return false; ++ ++ if (!TYPE_READONLY (TREE_TYPE (origin_loop.limit))) ++ return false; ++ ++ if (!TYPE_READONLY (TREE_TYPE (TREE_TYPE (origin_loop.arr1)))) ++ return false; ++ ++ if (!TYPE_READONLY (TREE_TYPE (TREE_TYPE (origin_loop.arr2)))) ++ return false; ++ ++ if (TREE_CODE (TREE_TYPE (origin_loop.arr1)) != POINTER_TYPE ++ || TREE_CODE (TREE_TYPE (origin_loop.arr2)) != POINTER_TYPE ++ || TREE_CODE (TREE_TYPE (TREE_TYPE (origin_loop.arr1))) != INTEGER_TYPE ++ || TREE_CODE (TREE_TYPE (TREE_TYPE (origin_loop.arr2))) != INTEGER_TYPE) ++ return false; ++ ++ arr1_elem_size = TYPE_SIZE (TREE_TYPE (TREE_TYPE (origin_loop.arr1))); ++ arr2_elem_size = TYPE_SIZE (TREE_TYPE (TREE_TYPE (origin_loop.arr2))); ++ ++ if (tree_to_uhwi (arr1_elem_size) != 8 || tree_to_uhwi (arr2_elem_size) != 8) ++ return false; ++ ++ return true; ++} ++ ++/* Record the useful information of the original loop and judge whether the ++ information meets the specified conditions. */ ++ ++static bool ++check_record_loop_form (class loop *loop) ++{ ++ if (!record_origin_loop_exit_info (loop)) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nFailed to record loop exit information.\n"); ++ } ++ return false; ++ } ++ ++ if (!record_origin_loop_header (loop)) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nFailed to record loop header information.\n"); ++ } ++ return false; ++ } ++ ++ if (!record_origin_loop_latch (loop)) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nFailed to record loop latch information.\n"); ++ } ++ return false; ++ } ++ ++ if (!record_origin_loop_body (loop)) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nFailed to record loop body information.\n"); ++ } ++ return false; ++ } ++ ++ if (!check_origin_loop_info (loop)) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nFailed to check origin loop information.\n"); ++ } ++ return false; ++ } ++ ++ return true; ++} ++ ++/* The main entry for judging whether the loop meets some conditions. */ ++ ++static bool ++determine_loop_form (class loop *loop) ++{ ++ /* Currently only standard loops are processed, that is, only loop_header, ++ loop_latch, loop_body 3 bb blocks are included. */ ++ if (loop->inner || loop->num_nodes != 3) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nWrong loop form, there is inner loop or" ++ "redundant bb.\n"); ++ } ++ return false; ++ } ++ ++ if (single_exit (loop) || !loop->latch) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nWrong loop form, only one exit or loop_latch" ++ "does not exist.\n"); ++ } ++ return false; ++ } ++ ++ /* Support loop with only one backedge. */ ++ if (!loop_single_backedge_p (loop)) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nWrong loop form, loop back edges are not" ++ "unique.\n"); ++ } ++ return false; ++ } ++ ++ /* Support loop with only one preheader BB. */ ++ if (!loop_single_preheader_bb (loop)) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nWrong loop form, loop preheader bb are not" ++ "unique.\n"); ++ } ++ return false; ++ } ++ ++ init_origin_loop_structure (); ++ if (!check_record_loop_form (loop)) ++ return false; ++ ++ return true; ++} ++ ++/* Create prolog bb for newly constructed loop; When prolog_assign exists in ++ the original loop, the corresponding assign needs to be added to prolog_bb; ++ eg: <bb 7> ++ len_16 = len_10 + 1 ++ Create simple copy statement when prolog_assign does not exist; ++ eg: <bb 7> ++ len_16 = len_10 ++ ++ The IR of bb is as above. */ ++ ++static void ++create_prolog_bb (basic_block &prolog_bb, basic_block after_bb, ++ basic_block dominator_bb, class loop *outer, edge entry_edge) ++{ ++ gimple_seq stmts = NULL; ++ gimple_stmt_iterator gsi; ++ gimple *g; ++ tree lhs1; ++ ++ prolog_bb = create_empty_bb (after_bb); ++ add_bb_to_loop (prolog_bb, outer); ++ redirect_edge_and_branch (entry_edge, prolog_bb); ++ set_immediate_dominator (CDI_DOMINATORS, prolog_bb, dominator_bb); ++ gsi = gsi_last_bb (prolog_bb); ++ lhs1 = copy_ssa_name (origin_loop.base); ++ ++ if (origin_loop.exist_prolog_assgin) ++ g = gimple_build_assign (lhs1, PLUS_EXPR, origin_loop.base, ++ build_int_cst (TREE_TYPE (origin_loop.base), origin_loop.step)); ++ else ++ g = gimple_build_assign (lhs1, NOP_EXPR, origin_loop.base); ++ gimple_seq_add_stmt (&stmts, g); ++ gsi_insert_seq_after (&gsi, stmts, GSI_NEW_STMT); ++ set_current_def (origin_loop.base, lhs1); ++ defs_map.put (prolog_bb, lhs1); ++} ++ ++/* Create preheader bb for new loop; In order to ensure the standard form of ++ the loop, add a preheader_bb before loop_header. */ ++ ++static void ++create_loop_pred_bb (basic_block &loop_pred_bb, basic_block after_bb, ++ basic_block dominator_bb, class loop *outer) ++{ ++ loop_pred_bb = create_empty_bb (after_bb); ++ add_bb_to_loop (loop_pred_bb, outer); ++ set_immediate_dominator (CDI_DOMINATORS, loop_pred_bb, dominator_bb); ++ defs_map.put (loop_pred_bb, get_current_def (origin_loop.base)); ++} ++ ++/* Add phi_arg for bb with phi node. */ ++ ++static void ++rewrite_add_phi_arg (basic_block bb) ++{ ++ edge e; ++ edge_iterator ei; ++ gphi *phi; ++ gphi_iterator gsi; ++ tree res; ++ location_t loc; ++ ++ for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) ++ { ++ phi = gsi.phi (); ++ res = gimple_phi_result (phi); ++ ++ FOR_EACH_EDGE (e, ei, bb->preds) ++ { ++ if (PHI_ARG_DEF_FROM_EDGE (phi, e)) ++ continue; ++ tree var = *(defs_map.get (e->src)); ++ if (!same_ssa_name_var_p (var, res)) ++ continue; ++ if (virtual_operand_p (var)) ++ loc = UNKNOWN_LOCATION; ++ else ++ loc = gimple_location (SSA_NAME_DEF_STMT (var)); ++ add_phi_arg (phi, var, e, loc); ++ } ++ } ++} ++ ++/* Create loop_header BB for align_loop. ++ eg: <bb 9> ++ _18 = (long unsigned int) len_17; ++ _19 = _18 + 8; ++ _20 = (long unsigned int) len_limit_12 (D); ++ if (_19 <= _20) ++ ++ The IR of bb is as above. */ ++ ++static void ++create_align_loop_header (basic_block &align_loop_header, basic_block after_bb, ++ basic_block dominator_bb, class loop *outer) ++{ ++ gimple_seq stmts = NULL; ++ gimple_stmt_iterator gsi; ++ gcond *cond_stmt; ++ gphi *phi; ++ tree res; ++ ++ tree entry_node = get_current_def (origin_loop.base); ++ align_loop_header = create_empty_bb (after_bb); ++ add_bb_to_loop (align_loop_header, outer); ++ make_single_succ_edge (after_bb, align_loop_header, EDGE_FALLTHRU); ++ set_immediate_dominator (CDI_DOMINATORS, align_loop_header, dominator_bb); ++ gsi = gsi_last_bb (align_loop_header); ++ phi = create_phi_node (NULL_TREE, align_loop_header); ++ create_new_def_for (entry_node, phi, gimple_phi_result_ptr (phi)); ++ res = gimple_phi_result (phi); ++ ++ tree lhs1 = gimple_build (&stmts, NOP_EXPR, long_unsigned_type_node, res); ++ tree lhs2 = gimple_build (&stmts, PLUS_EXPR, TREE_TYPE (lhs1), lhs1, ++ build_int_cst (TREE_TYPE (lhs1), 8)); ++ tree lhs3 = gimple_build (&stmts, NOP_EXPR, long_unsigned_type_node, ++ origin_loop.limit); ++ cond_stmt = gimple_build_cond (LE_EXPR, lhs2, lhs3, NULL_TREE, NULL_TREE); ++ gimple_seq_add_stmt (&stmts, cond_stmt); ++ gsi_insert_seq_after (&gsi, stmts, GSI_NEW_STMT); ++ ++ set_current_def (origin_loop.base, res); ++ defs_map.put (align_loop_header, res); ++} ++ ++/* Create loop body BB for align_loop. ++ eg: <bb 10> ++ _21 = (sizetype) len_17; ++ _22 = cur_15 (D) + _21; ++ _23 = MEM[(long unsigned int *)_22]; ++ _24 = pb_13 (D) + _21; ++ _25 = MEM[(long unsigned int *)_24]; ++ if (_23 != _25) ++ ++ The IR of bb is as above. */ ++ ++static void ++create_align_loop_body_bb (basic_block &align_loop_body_bb, ++ basic_block after_bb, basic_block dominator_bb, ++ class loop *outer) ++{ ++ gimple_seq stmts = NULL; ++ gimple_stmt_iterator gsi; ++ gimple *g; ++ gcond *cond_stmt; ++ tree lhs1, lhs2; ++ ++ align_loop_body_bb = create_empty_bb (after_bb); ++ add_bb_to_loop (align_loop_body_bb, outer); ++ make_edge (after_bb, align_loop_body_bb, EDGE_TRUE_VALUE); ++ set_immediate_dominator (CDI_DOMINATORS, align_loop_body_bb, dominator_bb); ++ gsi = gsi_last_bb (align_loop_body_bb); ++ ++ tree var = gimple_build (&stmts, NOP_EXPR, sizetype, ++ get_current_def (origin_loop.base)); ++ lhs1 = gimple_build (&stmts, POINTER_PLUS_EXPR, TREE_TYPE (origin_loop.arr2), ++ origin_loop.arr2, var); ++ g = gimple_build_assign (make_ssa_name (long_unsigned_type_node), ++ fold_build2 (MEM_REF, long_unsigned_type_node, lhs1, ++ build_int_cst (build_pointer_type (long_unsigned_type_node), 0))); ++ gimple_seq_add_stmt (&stmts, g); ++ lhs1 = gimple_assign_lhs (g); ++ lhs2 = gimple_build (&stmts, POINTER_PLUS_EXPR, TREE_TYPE (origin_loop.arr1), ++ origin_loop.arr1, var); ++ g = gimple_build_assign (make_ssa_name (long_unsigned_type_node), ++ fold_build2 (MEM_REF, long_unsigned_type_node, lhs2, ++ build_int_cst (build_pointer_type (long_unsigned_type_node), 0))); ++ gimple_seq_add_stmt (&stmts, g); ++ lhs2 = gimple_assign_lhs (g); ++ cond_stmt = gimple_build_cond (gimple_cond_code (origin_loop.cond_stmt2), ++ lhs1, lhs2, NULL_TREE, NULL_TREE); ++ gimple_seq_add_stmt (&stmts, cond_stmt); ++ gsi_insert_seq_after (&gsi, stmts, GSI_NEW_STMT); ++} ++ ++/* Create loop_latch BB for align_loop. ++ eg: <bb 11> ++ len_26 = len_17 + 8; ++ ++ The IR of bb is as above. */ ++ ++static void ++create_align_loop_latch (basic_block &align_loop_latch, basic_block after_bb, ++ basic_block dominator_bb, class loop *outer) ++{ ++ gimple_seq stmts = NULL; ++ gimple_stmt_iterator gsi; ++ gimple *g; ++ tree res; ++ ++ tree entry_node = get_current_def (origin_loop.base); ++ align_loop_latch = create_empty_bb (after_bb); ++ add_bb_to_loop (align_loop_latch, outer); ++ make_edge (after_bb, align_loop_latch, EDGE_FALSE_VALUE); ++ set_immediate_dominator (CDI_DOMINATORS, align_loop_latch, dominator_bb); ++ gsi = gsi_last_bb (align_loop_latch); ++ res = copy_ssa_name (entry_node); ++ g = gimple_build_assign (res, PLUS_EXPR, entry_node, ++ build_int_cst (TREE_TYPE (entry_node), 8)); ++ gimple_seq_add_stmt (&stmts, g); ++ gsi_insert_seq_after (&gsi, stmts, GSI_NEW_STMT); ++ defs_map.put (align_loop_latch, res); ++} ++ ++/* Create a new loop and add it to outer_loop and return. */ ++ ++static class loop * ++init_new_loop (class loop *outer_loop, basic_block header, basic_block latch) ++{ ++ class loop *new_loop; ++ new_loop = alloc_loop (); ++ new_loop->header = header; ++ new_loop->latch = latch; ++ add_loop (new_loop, outer_loop); ++ ++ return new_loop; ++} ++ ++/* Create necessary exit BB for align_loop. ++ eg: <bb 12> ++ _27 = _23 ^ _25; ++ _28 = __builtin_ctzll (_27); ++ _29 = _28 >> 3; ++ len_30 = _29 + len_17; ++ ++ The IR of bb is as above. */ ++ ++static void ++create_align_loop_exit_bb (basic_block &align_loop_exit_bb, ++ basic_block after_bb, basic_block dominator_bb, ++ class loop *outer) ++{ ++ gimple_seq stmts = NULL; ++ gimple_stmt_iterator gsi; ++ gimple *g; ++ gimple *cond_stmt; ++ tree lhs1, lhs2; ++ tree cond_lhs, cond_rhs; ++ gcall *build_ctzll; ++ ++ tree entry_node = get_current_def (origin_loop.base); ++ align_loop_exit_bb = create_empty_bb (after_bb); ++ add_bb_to_loop (align_loop_exit_bb, outer); ++ make_edge (after_bb, align_loop_exit_bb, EDGE_TRUE_VALUE); ++ set_immediate_dominator (CDI_DOMINATORS, align_loop_exit_bb, dominator_bb); ++ gsi = gsi_last_bb (align_loop_exit_bb); ++ ++ cond_stmt = gsi_stmt (gsi_last_bb (after_bb)); ++ cond_lhs = gimple_cond_lhs (cond_stmt); ++ cond_rhs = gimple_cond_rhs (cond_stmt); ++ ++ lhs1 = gimple_build (&stmts, BIT_XOR_EXPR, TREE_TYPE (cond_lhs), cond_lhs, ++ cond_rhs); ++ build_ctzll = gimple_build_call (builtin_decl_explicit (BUILT_IN_CTZLL), 1, ++ lhs1); ++ lhs1 = make_ssa_name (integer_type_node); ++ gimple_call_set_lhs (build_ctzll, lhs1); ++ gimple_seq_add_stmt (&stmts, build_ctzll); ++ lhs2 = copy_ssa_name (lhs1); ++ g = gimple_build_assign (lhs2, RSHIFT_EXPR, lhs1, ++ build_int_cst (TREE_TYPE (lhs1), 3)); ++ gimple_seq_add_stmt (&stmts, g); ++ lhs1 = gimple_build (&stmts, NOP_EXPR, TREE_TYPE (entry_node), lhs2); ++ lhs2 = copy_ssa_name (entry_node); ++ g = gimple_build_assign (lhs2, PLUS_EXPR, lhs1, entry_node); ++ gimple_seq_add_stmt (&stmts, g); ++ gsi_insert_seq_after (&gsi, stmts, GSI_NEW_STMT); ++ defs_map.put (align_loop_exit_bb, lhs2); ++} ++ ++/* Create loop_header BB for epilogue_loop. ++ eg: <bb 14> ++ # len_31 = PHI <len_17 (13), len_37 (16)> ++ if (len_31 != len_limit_12 (D)) ++ ++ The IR of bb is as above. */ ++ ++static void ++create_epilogue_loop_header (basic_block &epilogue_loop_header, ++ basic_block after_bb, basic_block dominator_bb, ++ class loop *outer) ++{ ++ gimple_seq stmts = NULL; ++ gimple_stmt_iterator gsi; ++ gcond *cond_stmt; ++ tree res; ++ gphi *phi; ++ ++ tree entry_node = get_current_def (origin_loop.base); ++ epilogue_loop_header = create_empty_bb (after_bb); ++ add_bb_to_loop (epilogue_loop_header, outer); ++ make_single_succ_edge (after_bb, epilogue_loop_header, EDGE_FALLTHRU); ++ set_immediate_dominator (CDI_DOMINATORS, epilogue_loop_header, dominator_bb); ++ gsi = gsi_last_bb (epilogue_loop_header); ++ phi = create_phi_node (NULL_TREE, epilogue_loop_header); ++ create_new_def_for (entry_node, phi, gimple_phi_result_ptr (phi)); ++ res = gimple_phi_result (phi); ++ cond_stmt = gimple_build_cond (gimple_cond_code (origin_loop.cond_stmt1), res, ++ origin_loop.limit, NULL_TREE, NULL_TREE); ++ gimple_seq_add_stmt (&stmts, cond_stmt); ++ gsi_insert_seq_after (&gsi, stmts, GSI_NEW_STMT); ++ ++ set_current_def (origin_loop.base, res); ++ defs_map.put (epilogue_loop_header, res); ++} ++ ++/* Create loop body BB for epilogue_loop. ++ eg: <bb 15> ++ _32 = (sizetype) len_31; ++ _33 = pb_13 (D) + _32; ++ _34 = *_33; ++ _35 = cur_15 (D) + _32; ++ _36 = *_35; ++ if (_34 != _36) ++ ++ The IR of bb is as above. */ ++ ++static void ++create_epilogue_loop_body_bb (basic_block &epilogue_loop_body_bb, ++ basic_block after_bb, basic_block dominator_bb, ++ class loop *outer) ++{ ++ gimple_seq stmts = NULL; ++ gimple_stmt_iterator gsi; ++ gimple *g; ++ gcond *cond_stmt; ++ tree lhs1, lhs2, lhs3; ++ ++ tree entry_node = get_current_def (origin_loop.base); ++ epilogue_loop_body_bb = create_empty_bb (after_bb); ++ add_bb_to_loop (epilogue_loop_body_bb, outer); ++ make_edge (after_bb, epilogue_loop_body_bb, EDGE_TRUE_VALUE); ++ set_immediate_dominator (CDI_DOMINATORS, epilogue_loop_body_bb, dominator_bb); ++ gsi = gsi_last_bb (epilogue_loop_body_bb); ++ lhs1 = gimple_build (&stmts, NOP_EXPR, sizetype, entry_node); ++ lhs2 = gimple_build (&stmts, POINTER_PLUS_EXPR, TREE_TYPE (origin_loop.arr1), ++ origin_loop.arr1, lhs1); ++ g = gimple_build_assign (make_ssa_name (unsigned_char_type_node), ++ fold_build2 (MEM_REF, unsigned_char_type_node, lhs2, ++ build_int_cst (TREE_TYPE (lhs2), 0))); ++ gimple_seq_add_stmt (&stmts, g); ++ lhs2 = gimple_assign_lhs (g); ++ lhs3 = gimple_build (&stmts, POINTER_PLUS_EXPR, TREE_TYPE (origin_loop.arr2), ++ origin_loop.arr2, lhs1); ++ g = gimple_build_assign (make_ssa_name (unsigned_char_type_node), ++ fold_build2 (MEM_REF, unsigned_char_type_node, lhs3, ++ build_int_cst (TREE_TYPE (lhs3), 0))); ++ gimple_seq_add_stmt (&stmts, g); ++ lhs3 = gimple_assign_lhs (g); ++ cond_stmt = gimple_build_cond (gimple_cond_code (origin_loop.cond_stmt2), lhs2, ++ lhs3, NULL_TREE, NULL_TREE); ++ gimple_seq_add_stmt (&stmts, cond_stmt); ++ gsi_insert_seq_after (&gsi, stmts, GSI_NEW_STMT); ++ defs_map.put (epilogue_loop_body_bb, get_current_def (origin_loop.base)); ++} ++ ++/* Create loop_latch BB for epilogue_loop. ++ eg: <bb 16> ++ len_37 = len_31 + 1; ++ ++ The IR of bb is as above. */ ++ ++static void ++create_epilogue_loop_latch (basic_block &epilogue_loop_latch, ++ basic_block after_bb, basic_block dominator_bb, ++ class loop *outer) ++{ ++ gimple_seq stmts = NULL; ++ gimple_stmt_iterator gsi; ++ gimple *g; ++ tree res; ++ ++ tree entry_node = get_current_def (origin_loop.base); ++ epilogue_loop_latch = create_empty_bb (after_bb); ++ add_bb_to_loop (epilogue_loop_latch, outer); ++ make_edge (after_bb, epilogue_loop_latch, EDGE_FALSE_VALUE); ++ set_immediate_dominator (CDI_DOMINATORS, epilogue_loop_latch, dominator_bb); ++ gsi = gsi_last_bb (epilogue_loop_latch); ++ res = copy_ssa_name (entry_node); ++ g = gimple_build_assign (res, PLUS_EXPR, entry_node, ++ build_int_cst (TREE_TYPE (entry_node), origin_loop.step)); ++ gimple_seq_add_stmt (&stmts, g); ++ gsi_insert_seq_after (&gsi, stmts, GSI_NEW_STMT); ++ defs_map.put (epilogue_loop_latch, res); ++} ++ ++/* convert_to_new_loop ++ | | ++ | | ++ | | entry_edge ++ | ______ | ++ | / V V ++ | | -----origin_loop_header--- ++ | | | | ++ | | -------------------------\ ++ | | | \ ++ | | V \___ ___ ___ ___ ___ ___ ___ ++ | | -----origin_loop_body----- | ++ | | | | | ++ | | -------------------------\ | ++ | | | \___ ___ ___ ___ | ++ | | V V V ++ | | -----origin_loop_latch---- -----exit_bb------ ++ | | | | | | ++ | | /-------------------------- ------------------ ++ | \ __ / ++ | ++ | | ++ | ====> |entry_edge ++ | V ++ | -------prolog_bb----- ++ | | | ++ | --------------------- ++ | | ++ | V ++ | -----align_loop_header---- ++ | /-----------------> | | ++ |/ -------------------------- ++ || / \ ++ || V V ++ || ---align_loop_body--- ---epilogue_loop_header-- ++ || | | -------| |<---| ++ || --------------------\ / ------------------------- | ++ || | \____ | | | ++ || V | | V | ++ || ---align_loop_latch--- | | ---epilogue_loop_body---- | ++ || | | | | ----| | | ++ || ---------------------- | | / ------------------------- | ++ || / __________/ | | | | ++ || / | | | V | ++ | \ __________/ | | | ---epilogue_loop_latch--- | ++ | | | | | | | ++ | | | | ------------------------- / ++ | V | | | / ++ | -align_loop_exit_bb- | | \______________/ ++ | | | | | ++ | -------------------- | | ++ | | | | ++ | | V V ++ | | -----exit_bb------ ++ | |---->| | ++ | ------------------ ++ ++ The origin_loop conversion process starts from entry_edge and ends at ++ exit_bb; The execution logic of origin_loop is completely replaced by ++ align_loop + epilogue_loop: ++ 1) align_loop mainly implements the idea of using wide-type dereference ++ and comparison on array elements, so as to achieve the effect of ++ acceleration; For the corresponding source code understanding, please ++ refer to the description of the pass at the beginning; ++ 2) epilogue_loop processes the previous loop remaining array element ++ comparison. */ ++ ++static void ++create_new_loops (edge entry_edge) ++{ ++ basic_block prolog_bb; ++ basic_block align_loop_header, align_loop_latch, align_loop_body_bb; ++ basic_block align_pred_bb, align_loop_exit_bb; ++ basic_block epilogue_loop_header, epilogue_loop_latch, epilogue_loop_body_bb; ++ basic_block epilogue_loop_pred_bb; ++ class loop *align_loop; ++ class loop *epilogue_loop; ++ ++ class loop *outer = entry_edge->src->loop_father; ++ ++ create_prolog_bb (prolog_bb, entry_edge->src, entry_edge->src, outer, ++ entry_edge); ++ ++ create_loop_pred_bb (align_pred_bb, prolog_bb, prolog_bb, outer); ++ make_single_succ_edge (prolog_bb, align_pred_bb, EDGE_FALLTHRU); ++ ++ create_align_loop_header (align_loop_header, align_pred_bb, ++ align_pred_bb, outer); ++ ++ create_align_loop_body_bb (align_loop_body_bb, align_loop_header, ++ align_loop_header, outer); ++ ++ create_align_loop_latch (align_loop_latch, align_loop_body_bb, ++ align_loop_body_bb, outer); ++ make_edge (align_loop_latch, align_loop_header, EDGE_FALLTHRU); ++ rewrite_add_phi_arg (align_loop_header); ++ ++ align_loop = init_new_loop (outer, align_loop_header, align_loop_latch); ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nPrint byte align loop %d:\n", align_loop->num); ++ flow_loop_dump (align_loop, dump_file, NULL, 1); ++ fprintf (dump_file, "\n\n"); ++ } ++ ++ create_align_loop_exit_bb (align_loop_exit_bb, align_loop_body_bb, ++ align_loop_body_bb, outer); ++ ++ create_loop_pred_bb (epilogue_loop_pred_bb, align_loop_header, ++ align_loop_header, outer); ++ make_edge (align_loop_header, epilogue_loop_pred_bb, EDGE_FALSE_VALUE); ++ ++ create_epilogue_loop_header (epilogue_loop_header, epilogue_loop_pred_bb, ++ epilogue_loop_pred_bb, outer); ++ ++ create_epilogue_loop_body_bb (epilogue_loop_body_bb, epilogue_loop_header, ++ epilogue_loop_header, outer); ++ ++ create_epilogue_loop_latch (epilogue_loop_latch, epilogue_loop_body_bb, ++ epilogue_loop_body_bb, outer); ++ make_single_succ_edge (epilogue_loop_latch, epilogue_loop_header, ++ EDGE_FALLTHRU); ++ rewrite_add_phi_arg (epilogue_loop_header); ++ ++ epilogue_loop = init_new_loop (outer, epilogue_loop_header, ++ epilogue_loop_latch); ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nPrint epilogue loop %d:\n", epilogue_loop->num); ++ flow_loop_dump (epilogue_loop, dump_file, NULL, 1); ++ fprintf (dump_file, "\n\n"); ++ } ++ make_single_succ_edge (align_loop_exit_bb, origin_loop.exit_bb1, ++ EDGE_FALLTHRU); ++ set_immediate_dominator (CDI_DOMINATORS, origin_loop.exit_bb1, ++ entry_edge->src); ++ make_edge (epilogue_loop_body_bb, origin_loop.exit_bb1, EDGE_TRUE_VALUE); ++ ++ make_edge (epilogue_loop_header, origin_loop.exit_bb2, EDGE_FALSE_VALUE); ++ set_immediate_dominator (CDI_DOMINATORS, origin_loop.exit_bb2, ++ entry_edge->src); ++ ++ rewrite_add_phi_arg (origin_loop.exit_bb1); ++ rewrite_add_phi_arg (origin_loop.exit_bb2); ++ ++ remove_edge (origin_loop.exit_e1); ++ remove_edge (origin_loop.exit_e2); ++} ++ ++/* Make sure that the dominance relationship of the newly inserted cfg ++ is not missing. */ ++ ++static void ++update_loop_dominator (cdi_direction dir) ++{ ++ gcc_assert (dom_info_available_p (dir)); ++ ++ basic_block bb; ++ FOR_EACH_BB_FN (bb, cfun) ++ { ++ basic_block imm_bb = get_immediate_dominator (dir, bb); ++ if (!imm_bb || bb == origin_loop.exit_bb1) ++ { ++ set_immediate_dominator (CDI_DOMINATORS, bb, ++ recompute_dominator (CDI_DOMINATORS, bb)); ++ continue; ++ } ++ } ++} ++ ++/* Clear information about the original loop. */ ++ ++static void ++remove_origin_loop (class loop *loop) ++{ ++ basic_block *body; ++ ++ body = get_loop_body_in_dom_order (loop); ++ unsigned n = loop->num_nodes; ++ for (unsigned i = 0; i < n; i++) ++ { ++ delete_basic_block (body[i]); ++ } ++ free (body); ++ delete_loop (loop); ++} ++ ++/* Perform the conversion of origin_loop to new_loop. */ ++ ++static void ++convert_to_new_loop (class loop *loop) ++{ ++ create_new_loops (origin_loop.entry_edge); ++ remove_origin_loop (loop); ++ update_loop_dominator (CDI_DOMINATORS); ++ update_ssa (TODO_update_ssa); ++} ++ ++/* The main entry of array-widen-compare optimizes. */ ++ ++static unsigned int ++tree_ssa_array_widen_compare () ++{ ++ unsigned int todo = 0; ++ class loop *loop; ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ flow_loops_dump (dump_file, NULL, 1); ++ fprintf (dump_file, "\nConfirm which loop can be optimized using" ++ " array-widen-compare\n"); ++ } ++ ++ enum li_flags LI = LI_FROM_INNERMOST; ++ FOR_EACH_LOOP (loop, LI) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "======================================\n"); ++ fprintf (dump_file, "Processing loop %d:\n", loop->num); ++ fprintf (dump_file, "======================================\n"); ++ flow_loop_dump (loop, dump_file, NULL, 1); ++ fprintf (dump_file, "\n\n"); ++ } ++ ++ if (determine_loop_form (loop)) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "The %dth loop form is success matched," ++ "and the loop can be optimized.\n", ++ loop->num); ++ dump_loop_bb (loop); ++ } ++ ++ convert_to_new_loop (loop); ++ } ++ } ++ ++ todo |= (TODO_update_ssa); ++ return todo; ++} ++ ++/* Array widen compare. */ ++ ++namespace { ++ ++const pass_data pass_data_tree_array_widen_compare = ++{ ++ GIMPLE_PASS, ++ "awiden_compare", ++ OPTGROUP_LOOP, ++ TV_TREE_ARRAY_WIDEN_COMPARE, ++ (PROP_cfg | PROP_ssa), ++ 0, ++ 0, ++ 0, ++ (TODO_update_ssa | TODO_verify_all) ++}; ++ ++class pass_array_widen_compare : public gimple_opt_pass ++{ ++public: ++ pass_array_widen_compare (gcc::context *ctxt) ++ : gimple_opt_pass (pass_data_tree_array_widen_compare, ctxt) ++ {} ++ ++ /* opt_pass methods: */ ++ virtual bool gate (function *); ++ virtual unsigned int execute (function *); ++ ++}; // class pass_array_widen_compare ++ ++bool ++pass_array_widen_compare::gate (function *) ++{ ++ return (flag_array_widen_compare > 0 && optimize >= 3); ++} ++ ++unsigned int ++pass_array_widen_compare::execute (function *fun) ++{ ++ if (number_of_loops (fun) <= 1) ++ return 0; ++ ++ /* Only supports LP64 data mode. */ ++ if (TYPE_PRECISION (long_integer_type_node) != 64 ++ || POINTER_SIZE != 64 || TYPE_PRECISION (integer_type_node) != 32) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "The current data mode is not supported," ++ "only the LP64 date mode is supported.\n"); ++ return 0; ++ } ++ ++ return tree_ssa_array_widen_compare (); ++} ++ ++} // anon namespace ++ ++gimple_opt_pass * ++make_pass_array_widen_compare (gcc::context *ctxt) ++{ ++ return new pass_array_widen_compare (ctxt); ++} +\ No newline at end of file +-- +2.27.0.windows.1 + diff --git a/0047-DFE-Fix-the-bug-caused-by-inconsistent-types.patch b/0047-DFE-Fix-the-bug-caused-by-inconsistent-types.patch new file mode 100644 index 0000000..4e6cc86 --- /dev/null +++ b/0047-DFE-Fix-the-bug-caused-by-inconsistent-types.patch @@ -0,0 +1,379 @@ +From 8f51c8c83355cb1b69553e582fb512c6e37b71f5 Mon Sep 17 00:00:00 2001 +From: Mingchuan Wu <wumingchuan1992@foxmail.com> +Date: Thu, 18 Aug 2022 17:15:08 +0800 +Subject: [PATCH] [DFE] Fix the bug caused by inconsistent types: 1. Update + some functions to fix the bug caused by inconsistent base and node types. + +Also we added 3 dejaGNU test cases. +--- + gcc/ipa-struct-reorg/ipa-struct-reorg.c | 57 ++++++++----- + .../gcc.dg/struct/dfe_extr_board_init.c | 77 +++++++++++++++++ + gcc/testsuite/gcc.dg/struct/dfe_extr_claw.c | 77 +++++++++++++++++ + .../gcc.dg/struct/dfe_extr_mv_udc_core.c | 82 +++++++++++++++++++ + 4 files changed, 273 insertions(+), 20 deletions(-) + create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_extr_board_init.c + create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_extr_claw.c + create mode 100644 gcc/testsuite/gcc.dg/struct/dfe_extr_mv_udc_core.c + +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +index 00dc4bf1d..8d3da3540 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -3284,33 +3284,31 @@ ipa_struct_reorg::find_vars (gimple *stmt) + } + } + +-/* Update field_access in srfield. */ +- +-static void +-update_field_access (tree node, tree op, unsigned access, void *data) ++static HOST_WIDE_INT ++get_offset (tree op, HOST_WIDE_INT offset) + { +- HOST_WIDE_INT offset = 0; + switch (TREE_CODE (op)) + { + case COMPONENT_REF: + { +- offset = int_byte_position (TREE_OPERAND (op, 1)); +- break; ++ return int_byte_position (TREE_OPERAND (op, 1)); + } + case MEM_REF: + { +- offset = tree_to_uhwi (TREE_OPERAND (op, 1)); +- break; ++ return tree_to_uhwi (TREE_OPERAND (op, 1)); + } + default: +- return; ++ return offset; + } +- tree base = node; +- get_base (base, node); +- srdecl *this_srdecl = ((ipa_struct_reorg *)data)->find_decl (base); +- if (this_srdecl == NULL) +- return; +- srtype *this_srtype = this_srdecl->type; ++ return offset; ++} ++ ++/* Record field access. */ ++static void ++record_field_access (tree type, HOST_WIDE_INT offset, ++ unsigned access, void *data) ++{ ++ srtype *this_srtype = ((ipa_struct_reorg *)data)->find_type (type); + if (this_srtype == NULL) + return; + srfield *this_srfield = this_srtype->find_field (offset); +@@ -3321,12 +3319,33 @@ update_field_access (tree node, tree op, unsigned access, void *data) + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "record field access %d:", access); +- print_generic_expr (dump_file, this_srtype->type); ++ print_generic_expr (dump_file, type); + fprintf (dump_file, " field:"); + print_generic_expr (dump_file, this_srfield->fielddecl); + fprintf (dump_file, "\n"); + } + return; ++ ++} ++ ++/* Update field_access in srfield. */ ++ ++static void ++update_field_access (tree node, tree op, unsigned access, void *data) ++{ ++ HOST_WIDE_INT offset = 0; ++ offset = get_offset (op, offset); ++ tree node_type = inner_type (TREE_TYPE (node)); ++ record_field_access (node_type, offset, access, data); ++ tree base = node; ++ get_base (base, node); ++ tree base_type = inner_type (TREE_TYPE (base)); ++ if (!types_compatible_p (base_type, node_type)) ++ { ++ record_field_access (base_type, get_offset (node, offset), ++ access, data); ++ } ++ return; + } + + /* A callback for walk_stmt_load_store_ops to visit store. */ +@@ -3373,8 +3392,7 @@ ipa_struct_reorg::remove_dead_field_stmt (tree lhs) + return false; + if (f == NULL) + return false; +- if (f->newfield[0] == NULL +- && (f->field_access & WRITE_FIELD)) ++ if (f->newfield[0] == NULL) + return true; + return false; + } +@@ -5927,7 +5945,6 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + fprintf (dump_file, "To: \n"); + print_gimple_stmt (dump_file, stmt, 0); + } +- return false; + } + + if (gimple_clobber_p (stmt)) +diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_board_init.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_board_init.c +new file mode 100644 +index 000000000..4e52564b6 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_board_init.c +@@ -0,0 +1,77 @@ ++/* { dg-do compile} */ ++ ++#define NULL ((void*)0) ++typedef unsigned long size_t; ++typedef long intptr_t; ++typedef unsigned long uintptr_t; ++typedef long scalar_t__; ++typedef int bool; ++#define false 0 ++#define true 1 ++ ++typedef struct TYPE_5__ TYPE_2__; ++typedef struct TYPE_4__ TYPE_1__; ++ ++struct TYPE_4__ ++{ ++ int Pin; ++ int Pull; ++ int Mode; ++ int Speed; ++}; ++ ++struct TYPE_5__ ++{ ++ int MEMRMP; ++}; ++typedef TYPE_1__ GPIO_InitTypeDef; ++ ++int BT_RST_PIN; ++int BT_RST_PORT; ++int CONN_POS10_PIN; ++int CONN_POS10_PORT; ++int GPIO_HIGH (int, int); ++int GPIO_MODE_INPUT; ++int GPIO_MODE_OUTPUT_PP; ++int GPIO_NOPULL; ++int GPIO_PULLUP; ++int GPIO_SPEED_FREQ_LOW; ++int HAL_GPIO_Init (int, TYPE_1__ *); ++scalar_t__ IS_GPIO_RESET (int, int); ++TYPE_2__ *SYSCFG; ++int __HAL_RCC_GPIOB_CLK_ENABLE (); ++int __HAL_RCC_GPIOC_CLK_ENABLE (); ++ ++__attribute__((used)) static void ++LBF_DFU_If_Needed (void) ++{ ++ GPIO_InitTypeDef GPIO_InitStruct; ++ __HAL_RCC_GPIOC_CLK_ENABLE (); ++ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; ++ GPIO_InitStruct.Pull = GPIO_NOPULL; ++ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; ++ GPIO_InitStruct.Pin = BT_RST_PIN; ++ HAL_GPIO_Init (BT_RST_PORT, &GPIO_InitStruct); ++ ++ GPIO_HIGH (BT_RST_PORT, BT_RST_PIN); ++ __HAL_RCC_GPIOB_CLK_ENABLE (); ++ GPIO_InitStruct.Mode = GPIO_MODE_INPUT; ++ GPIO_InitStruct.Pull = GPIO_PULLUP; ++ GPIO_InitStruct.Pin = CONN_POS10_PIN; ++ HAL_GPIO_Init (CONN_POS10_PORT, &GPIO_InitStruct); ++ ++ if (IS_GPIO_RESET (CONN_POS10_PORT, CONN_POS10_PIN)) ++ { ++ SYSCFG->MEMRMP = 0x00000001; ++ asm ( ++ "LDR R0, =0x000000\n\t" ++ "LDR SP, [R0, #0]\n\t" ++ ); ++ asm ( ++ "LDR R0, [R0, #0]\n\t" ++ "BX R0\n\t" ++ ); ++ } ++} ++ ++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 0 "struct_layout" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_claw.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_claw.c +new file mode 100644 +index 000000000..894e9f460 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_claw.c +@@ -0,0 +1,77 @@ ++/* { dg-do compile} */ ++ ++#define NULL ((void*)0) ++typedef unsigned long size_t; ++typedef long intptr_t; ++typedef unsigned long uintptr_t; ++typedef long scalar_t__; ++typedef int bool; ++#define false 0 ++#define true 1 ++ ++typedef struct TYPE_2__ TYPE_1__; ++ ++struct net_device ++{ ++ struct claw_privbk* ml_priv; ++}; ++struct clawctl ++{ ++ int linkid; ++}; ++struct claw_privbk ++{ ++ int system_validate_comp; ++ TYPE_1__* p_env; ++ int ctl_bk; ++}; ++typedef int __u8; ++struct TYPE_2__ ++{ ++ scalar_t__ packing; ++ int api_type; ++}; ++ ++int CLAW_DBF_TEXT (int, int, char*); ++int CONNECTION_REQUEST; ++int HOST_APPL_NAME; ++scalar_t__ PACKING_ASK; ++scalar_t__ PACK_SEND; ++int WS_APPL_NAME_IP_NAME; ++int WS_APPL_NAME_PACKED; ++int claw_send_control (struct net_device*, int, int, int, int, int, int); ++int setup; ++ ++__attribute__((used)) static int ++claw_snd_conn_req (struct net_device *dev, __u8 link) ++{ ++ int rc; ++ struct claw_privbk *privptr = dev->ml_priv; ++ struct clawctl *p_ctl; ++ CLAW_DBF_TEXT (2, setup, "snd_conn"); ++ rc = 1; ++ p_ctl = (struct clawctl *)&privptr->ctl_bk; ++ p_ctl->linkid = link; ++ if (privptr->system_validate_comp == 0x00) ++ { ++ return rc; ++ } ++ if (privptr->p_env->packing == PACKING_ASK) ++ { ++ rc = claw_send_control (dev, CONNECTION_REQUEST, 0, 0, 0, ++ WS_APPL_NAME_PACKED, WS_APPL_NAME_PACKED); ++ } ++ if (privptr->p_env->packing == PACK_SEND) ++ { ++ rc = claw_send_control (dev, CONNECTION_REQUEST, 0, 0, 0, ++ WS_APPL_NAME_IP_NAME, WS_APPL_NAME_IP_NAME); ++ } ++ if (privptr->p_env->packing == 0) ++ { ++ rc = claw_send_control (dev, CONNECTION_REQUEST, 0, 0, 0, ++ HOST_APPL_NAME, privptr->p_env->api_type); ++ } ++ return rc; ++} ++ ++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 1 "struct_layout" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_mv_udc_core.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_mv_udc_core.c +new file mode 100644 +index 000000000..9801f87f1 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_mv_udc_core.c +@@ -0,0 +1,82 @@ ++/* { dg-do compile} */ ++ ++#define NULL ((void*)0) ++typedef unsigned long size_t; ++typedef long intptr_t; ++typedef unsigned long uintptr_t; ++typedef long scalar_t__; ++typedef int bool; ++#define false 0 ++#define true 1 ++ ++typedef struct TYPE_4__ TYPE_2__; ++typedef struct TYPE_3__ TYPE_1__; ++typedef int u32; ++ ++struct mv_udc ++{ ++ TYPE_2__ *op_regs; ++ TYPE_1__ *ep_dqh; ++ struct mv_ep *eps; ++}; ++ ++struct mv_ep ++{ ++ TYPE_1__ *dqh; ++ struct mv_udc *udc; ++}; ++ ++struct TYPE_4__ ++{ ++ int *epctrlx; ++}; ++ ++struct TYPE_3__ ++{ ++ int max_packet_length; ++ int next_dtd_ptr; ++}; ++ ++int EP0_MAX_PKT_SIZE; ++int EPCTRL_RX_ENABLE; ++int EPCTRL_RX_EP_TYPE_SHIFT; ++int EPCTRL_TX_ENABLE; ++int EPCTRL_TX_EP_TYPE_SHIFT; ++int EP_QUEUE_HEAD_IOS; ++int EP_QUEUE_HEAD_MAX_PKT_LEN_POS; ++int EP_QUEUE_HEAD_NEXT_TERMINATE; ++int USB_ENDPOINT_XFER_CONTROL; ++int readl (int *); ++int writel (int, int *); ++ ++__attribute__((used)) static void ++ep0_reset (struct mv_udc *udc) ++{ ++ struct mv_ep *ep; ++ u32 epctrlx; ++ int i = 0; ++ for (i = 0; i < 2; i++) ++ { ++ ep = &udc->eps[i]; ++ ep->udc = udc; ++ ep->dqh = &udc->ep_dqh[i]; ++ ep->dqh->max_packet_length = ++ (EP0_MAX_PKT_SIZE << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) ++ | EP_QUEUE_HEAD_IOS; ++ ep->dqh->next_dtd_ptr = EP_QUEUE_HEAD_NEXT_TERMINATE; ++ epctrlx = readl (&udc->op_regs->epctrlx[0]); ++ if (i) ++ { ++ epctrlx |= EPCTRL_TX_ENABLE ++ | (USB_ENDPOINT_XFER_CONTROL << EPCTRL_TX_EP_TYPE_SHIFT); ++ } ++ else ++ { ++ epctrlx |= EPCTRL_RX_ENABLE ++ | (USB_ENDPOINT_XFER_CONTROL << EPCTRL_RX_EP_TYPE_SHIFT); ++ } ++ writel (epctrlx, &udc->op_regs->epctrlx[0]); ++ } ++} ++ ++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_layout" } } */ +-- +2.33.0 + diff --git a/0048-Struct-Reorg-Type-simplify-limitation-when-in-struct.patch b/0048-Struct-Reorg-Type-simplify-limitation-when-in-struct.patch new file mode 100644 index 0000000..e44de6e --- /dev/null +++ b/0048-Struct-Reorg-Type-simplify-limitation-when-in-struct.patch @@ -0,0 +1,146 @@ +From b66a843505f32685f428c502f1a88e0f681b4acd Mon Sep 17 00:00:00 2001 +From: eastb233 <xiezhiheng@huawei.com> +Date: Thu, 15 Sep 2022 17:57:00 +0800 +Subject: [PATCH] [Struct Reorg] Type simplify limitation when in structure + optimizaiton + +When enable structure optimization, we should not simplify +TYPE NODE. But now we unconditionally skip the simplification +under structure optimization regardless of whether it takes +effect. So add the same limitation as the optimization has. +--- + gcc/ipa-struct-reorg/ipa-struct-reorg.c | 72 ++++++++++++------------- + gcc/tree.c | 13 ++++- + 2 files changed, 47 insertions(+), 38 deletions(-) + +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +index 8d3da35400d..54c20ca3f33 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -104,6 +104,42 @@ along with GCC; see the file COPYING3. If not see + + #define VOID_POINTER_P(type) (POINTER_TYPE_P (type) && VOID_TYPE_P (TREE_TYPE (type))) + ++/* Check whether in C language or LTO with only C language. */ ++bool ++lang_c_p (void) ++{ ++ const char *language_string = lang_hooks.name; ++ ++ if (!language_string) ++ { ++ return false; ++ } ++ ++ if (lang_GNU_C ()) ++ { ++ return true; ++ } ++ else if (strcmp (language_string, "GNU GIMPLE") == 0) // for LTO check ++ { ++ unsigned i = 0; ++ tree t = NULL_TREE; ++ ++ FOR_EACH_VEC_SAFE_ELT (all_translation_units, i, t) ++ { ++ language_string = TRANSLATION_UNIT_LANGUAGE (t); ++ if (language_string == NULL ++ || strncmp (language_string, "GNU C", 5) ++ || (language_string[5] != '\0' ++ && !(ISDIGIT (language_string[5])))) ++ { ++ return false; ++ } ++ } ++ return true; ++ } ++ return false; ++} ++ + namespace { + + using namespace struct_reorg; +@@ -163,42 +199,6 @@ handled_type (tree type) + return false; + } + +-/* Check whether in C language or LTO with only C language. */ +-bool +-lang_c_p (void) +-{ +- const char *language_string = lang_hooks.name; +- +- if (!language_string) +- { +- return false; +- } +- +- if (lang_GNU_C ()) +- { +- return true; +- } +- else if (strcmp (language_string, "GNU GIMPLE") == 0) // for LTO check +- { +- unsigned i = 0; +- tree t = NULL_TREE; +- +- FOR_EACH_VEC_SAFE_ELT (all_translation_units, i, t) +- { +- language_string = TRANSLATION_UNIT_LANGUAGE (t); +- if (language_string == NULL +- || strncmp (language_string, "GNU C", 5) +- || (language_string[5] != '\0' +- && !(ISDIGIT (language_string[5])))) +- { +- return false; +- } +- } +- return true; +- } +- return false; +-} +- + /* Get the number of pointer layers. */ + + int +diff --git a/gcc/tree.c b/gcc/tree.c +index c2075d73586..84a440b3576 100644 +--- a/gcc/tree.c ++++ b/gcc/tree.c +@@ -128,6 +128,9 @@ const char *const tree_code_class_strings[] = + /* obstack.[ch] explicitly declined to prototype this. */ + extern int _obstack_allocated_p (struct obstack *h, void *obj); + ++/* Check whether in C language or LTO with only C language. */ ++extern bool lang_c_p (void); ++ + /* Statistics-gathering stuff. */ + + static uint64_t tree_code_counts[MAX_TREE_CODES]; +@@ -5219,7 +5222,10 @@ fld_simplified_type_name (tree type) + /* Simplify type will cause that struct A and struct A within + struct B are different type pointers, so skip it in structure + optimizations. */ +- if (flag_ipa_struct_layout || flag_ipa_struct_reorg) ++ if ((flag_ipa_struct_layout || flag_ipa_struct_reorg) ++ && lang_c_p () ++ && flag_lto_partition == LTO_PARTITION_ONE ++ && (in_lto_p || flag_whole_program)) + return TYPE_NAME (type); + + if (!TYPE_NAME (type) || TREE_CODE (TYPE_NAME (type)) != TYPE_DECL) +@@ -5463,7 +5469,10 @@ fld_simplified_type (tree t, class free_lang_data_d *fld) + /* Simplify type will cause that struct A and struct A within + struct B are different type pointers, so skip it in structure + optimizations. */ +- if (flag_ipa_struct_layout || flag_ipa_struct_reorg) ++ if ((flag_ipa_struct_layout || flag_ipa_struct_reorg) ++ && lang_c_p () ++ && flag_lto_partition == LTO_PARTITION_ONE ++ && (in_lto_p || flag_whole_program)) + return t; + if (POINTER_TYPE_P (t)) + return fld_incomplete_type_of (t, fld); +-- +2.21.0.windows.1 + diff --git a/0049-build-Add-some-file-right-to-executable.patch b/0049-build-Add-some-file-right-to-executable.patch new file mode 100644 index 0000000..b9aa9b9 --- /dev/null +++ b/0049-build-Add-some-file-right-to-executable.patch @@ -0,0 +1,21 @@ +From 7dffda64fcbbd522616d7dc9c70530d146f4fed6 Mon Sep 17 00:00:00 2001 +From: zhongyunde <zhongyunde@huawei.com> +Date: Tue, 1 Nov 2022 16:38:38 +0800 +Subject: [PATCH 01/35] [build] Add some file right to executable + +--- + libgcc/mkheader.sh | 0 + move-if-change | 0 + 2 files changed, 0 insertions(+), 0 deletions(-) + mode change 100644 => 100755 libgcc/mkheader.sh + mode change 100644 => 100755 move-if-change + +diff --git a/libgcc/mkheader.sh b/libgcc/mkheader.sh +old mode 100644 +new mode 100755 +diff --git a/move-if-change b/move-if-change +old mode 100644 +new mode 100755 +-- +2.27.0.windows.1 + diff --git a/0050-Backport-phiopt-Optimize-x-1024-0-to-int-x-10-PR9769.patch b/0050-Backport-phiopt-Optimize-x-1024-0-to-int-x-10-PR9769.patch new file mode 100644 index 0000000..d3acf4c --- /dev/null +++ b/0050-Backport-phiopt-Optimize-x-1024-0-to-int-x-10-PR9769.patch @@ -0,0 +1,186 @@ +From c690da762e873d0f5c66ea084e420ba4842354a6 Mon Sep 17 00:00:00 2001 +From: Jakub Jelinek <jakub@redhat.com> +Date: Wed, 4 Nov 2020 11:55:29 +0100 +Subject: [PATCH 02/35] [Backport] phiopt: Optimize x ? 1024 : 0 to (int) x << + 10 [PR97690] + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=3e190757fa332d327bee27495f37beb01155cfab + +The following patch generalizes the x ? 1 : 0 -> (int) x optimization +to handle also left shifts by constant. + +During x86_64-linux and i686-linux bootstraps + regtests it triggered +in 1514 unique non-LTO -m64 cases (sort -u on log mentioning +filename, function name and shift count) and 1866 -m32 cases. + +Unfortunately, the patch regresses (before the tests have been adjusted): ++FAIL: gcc.dg/tree-ssa/ssa-ccp-11.c scan-tree-dump-times optimized "if " 0 ++FAIL: gcc.dg/vect/bb-slp-pattern-2.c -flto -ffat-lto-objects scan-tree-dump-times slp1 "optimized: basic block" 1 ++FAIL: gcc.dg/vect/bb-slp-pattern-2.c scan-tree-dump-times slp1 "optimized: basic block" 1 +and in both cases it actually results in worse code. + +> > We'd need some optimization that would go through all PHI edges and +> > compute if some use of the phi results don't actually compute a constant +> > across all the PHI edges - 1 & 0 and 0 & 1 is always 0. + +> PRE should do this, IMHO only optimizing it at -O2 is fine. + +> > Similarly, in the slp vectorization test there is: +> > a[0] = b[0] ? 1 : 7; + +> note this, carefully avoiding the already "optimized" b[0] ? 1 : 0 ... + +> So the option is to put : 7 in the 2, 4 an 8 case as well. The testcase +> wasn't added for any real-world case but is artificial I guess for +> COND_EXPR handling of invariants. + +> But yeah, for things like SLP it means we eventually have to +> implement reverse transforms for all of this to make the lanes +> matching. But that's true anyway for things like x + 1 vs. x + 0 +> or x / 3 vs. x / 2 or other simplifications we do. + +2020-11-04 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/97690 + * tree-ssa-phiopt.c (conditional_replacement): Also optimize + cond ? pow2p_cst : 0 as ((type) cond) << cst. + + * gcc.dg/tree-ssa/phi-opt-22.c: New test. + * gcc.dg/tree-ssa/ssa-ccp-11.c: Use -O2 instead of -O1. + * gcc.dg/vect/bb-slp-pattern-2.c (foo): Use ? 2 : 7, ? 4 : 7 and + ? 8 : 7 instead of ? 2 : 0, ? 4 : 0, ? 8 : 0. +--- + gcc/testsuite/gcc.dg/tree-ssa/phi-opt-22.c | 11 ++++++ + gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-11.c | 2 +- + gcc/testsuite/gcc.dg/vect/bb-slp-pattern-2.c | 6 ++-- + gcc/tree-ssa-phiopt.c | 38 ++++++++++++++------ + 4 files changed, 43 insertions(+), 14 deletions(-) + create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/phi-opt-22.c + +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-22.c b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-22.c +new file mode 100644 +index 000000000..fd3706666 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-22.c +@@ -0,0 +1,11 @@ ++/* PR tree-optimization/97690 */ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -fdump-tree-phiopt2" } */ ++ ++int foo (_Bool d) { return d ? 2 : 0; } ++int bar (_Bool d) { return d ? 1 : 0; } ++int baz (_Bool d) { return d ? -__INT_MAX__ - 1 : 0; } ++int qux (_Bool d) { return d ? 1024 : 0; } ++ ++/* { dg-final { scan-tree-dump-not "if" "phiopt2" } } */ ++/* { dg-final { scan-tree-dump-times " << " 3 "phiopt2" } } */ +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-11.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-11.c +index 36b8e7fc8..d70ea5a01 100644 +--- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-11.c ++++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-11.c +@@ -1,5 +1,5 @@ + /* { dg-do compile } */ +-/* { dg-options "-O1 -fdump-tree-optimized" } */ ++/* { dg-options "-O2 -fdump-tree-optimized" } */ + + /* Test for CPROP across a DAG. */ + +diff --git a/gcc/testsuite/gcc.dg/vect/bb-slp-pattern-2.c b/gcc/testsuite/gcc.dg/vect/bb-slp-pattern-2.c +index d32cb7585..e64f0115a 100644 +--- a/gcc/testsuite/gcc.dg/vect/bb-slp-pattern-2.c ++++ b/gcc/testsuite/gcc.dg/vect/bb-slp-pattern-2.c +@@ -13,13 +13,13 @@ foo (short * __restrict__ a, int * __restrict__ b, int stride) + for (i = 0; i < N/stride; i++, a += stride, b += stride) + { + a[0] = b[0] ? 1 : 7; +- a[1] = b[1] ? 2 : 0; ++ a[1] = b[1] ? 2 : 7; + a[2] = b[2] ? 3 : 0; +- a[3] = b[3] ? 4 : 0; ++ a[3] = b[3] ? 4 : 7; + a[4] = b[4] ? 5 : 0; + a[5] = b[5] ? 6 : 0; + a[6] = b[6] ? 7 : 0; +- a[7] = b[7] ? 8 : 0; ++ a[7] = b[7] ? 8 : 7; + } + } + +diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c +index 591b6435f..85587e8d1 100644 +--- a/gcc/tree-ssa-phiopt.c ++++ b/gcc/tree-ssa-phiopt.c +@@ -753,7 +753,9 @@ conditional_replacement (basic_block cond_bb, basic_block middle_bb, + gimple_stmt_iterator gsi; + edge true_edge, false_edge; + tree new_var, new_var2; +- bool neg; ++ bool neg = false; ++ int shift = 0; ++ tree nonzero_arg; + + /* FIXME: Gimplification of complex type is too hard for now. */ + /* We aren't prepared to handle vectors either (and it is a question +@@ -764,14 +766,22 @@ conditional_replacement (basic_block cond_bb, basic_block middle_bb, + || POINTER_TYPE_P (TREE_TYPE (arg1)))) + return false; + +- /* The PHI arguments have the constants 0 and 1, or 0 and -1, then +- convert it to the conditional. */ +- if ((integer_zerop (arg0) && integer_onep (arg1)) +- || (integer_zerop (arg1) && integer_onep (arg0))) +- neg = false; +- else if ((integer_zerop (arg0) && integer_all_onesp (arg1)) +- || (integer_zerop (arg1) && integer_all_onesp (arg0))) ++ /* The PHI arguments have the constants 0 and 1, or 0 and -1 or ++ 0 and (1 << cst), then convert it to the conditional. */ ++ if (integer_zerop (arg0)) ++ nonzero_arg = arg1; ++ else if (integer_zerop (arg1)) ++ nonzero_arg = arg0; ++ else ++ return false; ++ if (integer_all_onesp (nonzero_arg)) + neg = true; ++ else if (integer_pow2p (nonzero_arg)) ++ { ++ shift = tree_log2 (nonzero_arg); ++ if (shift && POINTER_TYPE_P (TREE_TYPE (nonzero_arg))) ++ return false; ++ } + else + return false; + +@@ -783,12 +793,12 @@ conditional_replacement (basic_block cond_bb, basic_block middle_bb, + falls through into BB. + + There is a single PHI node at the join point (BB) and its arguments +- are constants (0, 1) or (0, -1). ++ are constants (0, 1) or (0, -1) or (0, (1 << shift)). + + So, given the condition COND, and the two PHI arguments, we can + rewrite this PHI into non-branching code: + +- dest = (COND) or dest = COND' ++ dest = (COND) or dest = COND' or dest = (COND) << shift + + We use the condition as-is if the argument associated with the + true edge has the value one or the argument associated with the +@@ -823,6 +833,14 @@ conditional_replacement (basic_block cond_bb, basic_block middle_bb, + cond = fold_build1_loc (gimple_location (stmt), + NEGATE_EXPR, TREE_TYPE (cond), cond); + } ++ else if (shift) ++ { ++ cond = fold_convert_loc (gimple_location (stmt), ++ TREE_TYPE (result), cond); ++ cond = fold_build2_loc (gimple_location (stmt), ++ LSHIFT_EXPR, TREE_TYPE (cond), cond, ++ build_int_cst (integer_type_node, shift)); ++ } + + /* Insert our new statements at the end of conditional block before the + COND_STMT. */ +-- +2.27.0.windows.1 + diff --git a/0051-Backport-phiopt-Fix-up-conditional_replacement-PR993.patch b/0051-Backport-phiopt-Fix-up-conditional_replacement-PR993.patch new file mode 100644 index 0000000..3d47670 --- /dev/null +++ b/0051-Backport-phiopt-Fix-up-conditional_replacement-PR993.patch @@ -0,0 +1,92 @@ +From 79a974bc7bb67cf425a7839f3c1f5689e41c7ee8 Mon Sep 17 00:00:00 2001 +From: Jakub Jelinek <jakub@redhat.com> +Date: Tue, 9 Mar 2021 19:13:11 +0100 +Subject: [PATCH 03/35] [Backport] phiopt: Fix up conditional_replacement + [PR99305] + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=b610c30453d8e4cc88693d85a5a100d089640be5 + +Before my PR97690 changes, conditional_replacement would not set neg +when the nonzero arg was boolean true. +I've simplified the testing, so that it first finds the zero argument +and then checks the other argument for all the handled cases +(1, -1 and 1 << X, where the last case is what the patch added support for). +But, unfortunately I've placed the integer_all_onesp test first. +For unsigned precision 1 types such as bool integer_all_onesp, integer_onep +and integer_pow2p can all be true and the code set neg to true in that case, +which is undesirable. + +The following patch tests integer_pow2p first (which is trivially true +for integer_onep too and tree_log2 in that case gives shift == 0) +and only if that isn't the case, integer_all_onesp. + +2021-03-09 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/99305 + * tree-ssa-phiopt.c (conditional_replacement): Test integer_pow2p + before integer_all_onesp instead of vice versa. + + * g++.dg/opt/pr99305.C: New test. +--- + gcc/testsuite/g++.dg/opt/pr99305.C | 26 ++++++++++++++++++++++++++ + gcc/tree-ssa-phiopt.c | 6 +++--- + 2 files changed, 29 insertions(+), 3 deletions(-) + create mode 100644 gcc/testsuite/g++.dg/opt/pr99305.C + +diff --git a/gcc/testsuite/g++.dg/opt/pr99305.C b/gcc/testsuite/g++.dg/opt/pr99305.C +new file mode 100644 +index 000000000..8a91277e7 +--- /dev/null ++++ b/gcc/testsuite/g++.dg/opt/pr99305.C +@@ -0,0 +1,26 @@ ++// PR tree-optimization/99305 ++// { dg-do compile } ++// { dg-options "-O3 -fno-ipa-icf -fdump-tree-optimized" } ++// { dg-final { scan-tree-dump-times " = \\\(unsigned char\\\) c_\[0-9]*\\\(D\\\);" 3 "optimized" } } ++// { dg-final { scan-tree-dump-times " = \[^\n\r]* \\+ \[0-9]*;" 3 "optimized" } } ++// { dg-final { scan-tree-dump-times " = \[^\n\r]* <= 9;" 3 "optimized" } } ++// { dg-final { scan-tree-dump-not "if \\\(c_\[0-9]*\\\(D\\\) \[!=]= 0\\\)" "optimized" } } ++// { dg-final { scan-tree-dump-not " = PHI <" "optimized" } } ++ ++bool ++foo (char c) ++{ ++ return c >= 48 && c <= 57; ++} ++ ++bool ++bar (char c) ++{ ++ return c != 0 && foo (c); ++} ++ ++bool ++baz (char c) ++{ ++ return c != 0 && c >= 48 && c <= 57; ++} +diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c +index 85587e8d1..b9be28474 100644 +--- a/gcc/tree-ssa-phiopt.c ++++ b/gcc/tree-ssa-phiopt.c +@@ -774,14 +774,14 @@ conditional_replacement (basic_block cond_bb, basic_block middle_bb, + nonzero_arg = arg0; + else + return false; +- if (integer_all_onesp (nonzero_arg)) +- neg = true; +- else if (integer_pow2p (nonzero_arg)) ++ if (integer_pow2p (nonzero_arg)) + { + shift = tree_log2 (nonzero_arg); + if (shift && POINTER_TYPE_P (TREE_TYPE (nonzero_arg))) + return false; + } ++ else if (integer_all_onesp (nonzero_arg)) ++ neg = true; + else + return false; + +-- +2.27.0.windows.1 + diff --git a/0052-Backport-phiopt-Handle-bool-in-two_value_replacement.patch b/0052-Backport-phiopt-Handle-bool-in-two_value_replacement.patch new file mode 100644 index 0000000..9ea9a42 --- /dev/null +++ b/0052-Backport-phiopt-Handle-bool-in-two_value_replacement.patch @@ -0,0 +1,122 @@ +From 09263d5ed4d81a008ca8ffcc2883dc766e7874d5 Mon Sep 17 00:00:00 2001 +From: Jakub Jelinek <jakub@redhat.com> +Date: Sun, 6 Dec 2020 10:58:10 +0100 +Subject: [PATCH 04/35] [Backport] phiopt: Handle bool in two_value_replacement + [PR796232] + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=8c23434fdadcf4caa1f0e966294c5f67ccf4bcf9 + +The following patch improves code generation on the included testcase by +enabling two_value_replacement on booleans. It does that only for arg0/arg1 +values that conditional_replacement doesn't handle. Additionally +it limits two_value_replacement optimization to the late phiopt like +conditional_replacement. + +2020-12-06 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/96232 + * tree-ssa-phiopt.c (two_value_replacement): Optimize even boolean lhs + cases as long as arg0 has wider precision and conditional_replacement + doesn't handle that case. + (tree_ssa_phiopt_worker): Don't call two_value_replacement during + early phiopt. + + * gcc.dg/tree-ssa/pr96232-2.c: New test. + * gcc.dg/tree-ssa/pr88676-2.c: Check phiopt2 dump rather than phiopt1. +--- + gcc/testsuite/gcc.dg/tree-ssa/pr88676-2.c | 4 ++-- + gcc/testsuite/gcc.dg/tree-ssa/pr96232-2.c | 18 ++++++++++++++++++ + gcc/tree-ssa-phiopt.c | 23 +++++++++++++++++++---- + 3 files changed, 39 insertions(+), 6 deletions(-) + create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr96232-2.c + +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr88676-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr88676-2.c +index 0e616365b..ea88407b6 100644 +--- a/gcc/testsuite/gcc.dg/tree-ssa/pr88676-2.c ++++ b/gcc/testsuite/gcc.dg/tree-ssa/pr88676-2.c +@@ -1,7 +1,7 @@ + /* PR tree-optimization/88676 */ + /* { dg-do compile } */ +-/* { dg-options "-O2 -fdump-tree-phiopt1" } */ +-/* { dg-final { scan-tree-dump-not " = PHI <" "phiopt1" { target le } } } */ ++/* { dg-options "-O2 -fdump-tree-phiopt2" } */ ++/* { dg-final { scan-tree-dump-not " = PHI <" "phiopt2" { target le } } } */ + + struct foo1 { + int i:1; +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr96232-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr96232-2.c +new file mode 100644 +index 000000000..9f51820ed +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/pr96232-2.c +@@ -0,0 +1,18 @@ ++/* PR tree-optimization/96232 */ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -fdump-tree-optimized" } */ ++/* { dg-final { scan-tree-dump " 38 - " "optimized" } } */ ++/* { dg-final { scan-tree-dump " \\+ 97;" "optimized" } } */ ++/* { dg-final { scan-tree-dump-not "PHI <" "optimized" } } */ ++ ++int ++foo (_Bool x) ++{ ++ return x ? 37 : 38; ++} ++ ++int ++bar (_Bool x) ++{ ++ return x ? 98 : 97; ++} +diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c +index b9be28474..0623d740d 100644 +--- a/gcc/tree-ssa-phiopt.c ++++ b/gcc/tree-ssa-phiopt.c +@@ -339,7 +339,7 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) + } + + /* Do the replacement of conditional if it can be done. */ +- if (two_value_replacement (bb, bb1, e2, phi, arg0, arg1)) ++ if (!early_p && two_value_replacement (bb, bb1, e2, phi, arg0, arg1)) + cfgchanged = true; + else if (!early_p + && conditional_replacement (bb, bb1, e1, e2, phi, +@@ -636,7 +636,6 @@ two_value_replacement (basic_block cond_bb, basic_block middle_bb, + + if (TREE_CODE (lhs) != SSA_NAME + || !INTEGRAL_TYPE_P (TREE_TYPE (lhs)) +- || TREE_CODE (TREE_TYPE (lhs)) == BOOLEAN_TYPE + || TREE_CODE (rhs) != INTEGER_CST) + return false; + +@@ -649,9 +648,25 @@ two_value_replacement (basic_block cond_bb, basic_block middle_bb, + return false; + } + ++ /* Defer boolean x ? 0 : {1,-1} or x ? {1,-1} : 0 to ++ conditional_replacement. */ ++ if (TREE_CODE (TREE_TYPE (lhs)) == BOOLEAN_TYPE ++ && (integer_zerop (arg0) ++ || integer_zerop (arg1) ++ || TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE ++ || (TYPE_PRECISION (TREE_TYPE (arg0)) ++ <= TYPE_PRECISION (TREE_TYPE (lhs))))) ++ return false; ++ + wide_int min, max; +- if (get_range_info (lhs, &min, &max) != VR_RANGE +- || min + 1 != max ++ if (TREE_CODE (TREE_TYPE (lhs)) == BOOLEAN_TYPE) ++ { ++ min = wi::to_wide (boolean_false_node); ++ max = wi::to_wide (boolean_true_node); ++ } ++ else if (get_range_info (lhs, &min, &max) != VR_RANGE) ++ return false; ++ if (min + 1 != max + || (wi::to_wide (rhs) != min + && wi::to_wide (rhs) != max)) + return false; +-- +2.27.0.windows.1 + diff --git a/0053-Backport-phiopt-Optimize-x-__builtin_clz-x-32-in-GIM.patch b/0053-Backport-phiopt-Optimize-x-__builtin_clz-x-32-in-GIM.patch new file mode 100644 index 0000000..15c260e --- /dev/null +++ b/0053-Backport-phiopt-Optimize-x-__builtin_clz-x-32-in-GIM.patch @@ -0,0 +1,256 @@ +From a92cf465f10585350f7cd5739457c3f2852cfc86 Mon Sep 17 00:00:00 2001 +From: Jakub Jelinek <jakub@redhat.com> +Date: Wed, 21 Oct 2020 10:51:33 +0200 +Subject: [PATCH 05/35] [Backport] phiopt: Optimize x ? __builtin_clz (x) : 32 + in GIMPLE [PR97503] + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=5244b4af5e47bc98a2a9cf36f048981583a1b163 + +While we have at the RTL level noce_try_ifelse_collapse combined with +simplify_cond_clz_ctz, that optimization doesn't always trigger because +e.g. on powerpc there is an define_insn to compare a reg against zero and +copy that register to another one and so we end up with a different pseudo +in the simplify_cond_clz_ctz test and punt. + +For targets that define C?Z_DEFINED_VALUE_AT_ZERO to 2 for certain modes, +we can optimize it already in phiopt though, just need to ensure that +we transform the __builtin_c?z* calls into .C?Z ifns because my recent +VRP changes codified that the builtin calls are always undefined at zero, +while ifns honor C?Z_DEFINED_VALUE_AT_ZERO equal to 2. +And, in phiopt we already have popcount handling that does pretty much the +same thing, except for always using a zero value rather than the one set +by C?Z_DEFINED_VALUE_AT_ZERO. + +So, this patch extends that function to handle not just popcount, but also +clz and ctz. + +2020-10-21 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/97503 + * tree-ssa-phiopt.c: Include internal-fn.h. + (cond_removal_in_popcount_pattern): Rename to ... + (cond_removal_in_popcount_clz_ctz_pattern): ... this. Handle not just + popcount, but also clz and ctz if it has C?Z_DEFINED_VALUE_AT_ZERO 2. + + * gcc.dg/tree-ssa/pr97503.c: New test. +--- + gcc/testsuite/gcc.dg/tree-ssa/pr97503.c | 19 +++++ + gcc/tree-ssa-phiopt.c | 100 ++++++++++++++++++------ + 2 files changed, 95 insertions(+), 24 deletions(-) + create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr97503.c + +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr97503.c b/gcc/testsuite/gcc.dg/tree-ssa/pr97503.c +new file mode 100644 +index 000000000..3a3dae6c7 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/pr97503.c +@@ -0,0 +1,19 @@ ++/* PR tree-optimization/97503 */ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -fdump-tree-optimized" } */ ++/* { dg-additional-options "-mbmi -mlzcnt" { target i?86-*-* x86_64-*-* } } */ ++/* { dg-final { scan-tree-dump-times "\.CLZ" 2 "optimized" { target { { i?86-*-* x86_64-*-* aarch64-*-* powerpc*-*-* } && lp64 } } } } */ ++/* { dg-final { scan-tree-dump-not "__builtin_clz" "optimized" { target { { i?86-*-* x86_64-*-* aarch64-*-* powerpc*-*-*} && lp64 } } } } */ ++/* { dg-final { scan-tree-dump-not "PHI <" "optimized" { target { { i?86-*-* x86_64-*-* aarch64-*-* powerpc*-*-*} && lp64 } } } } */ ++ ++int ++foo (int x) ++{ ++ return x ? __builtin_clz (x) : 32; ++} ++ ++int ++bar (unsigned long long x) ++{ ++ return x ? __builtin_clzll (x) : 64; ++} +diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c +index 0623d740d..c1e11916e 100644 +--- a/gcc/tree-ssa-phiopt.c ++++ b/gcc/tree-ssa-phiopt.c +@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see + #include "tree-inline.h" + #include "case-cfn-macros.h" + #include "tree-eh.h" ++#include "internal-fn.h" + + static unsigned int tree_ssa_phiopt_worker (bool, bool, bool); + static bool two_value_replacement (basic_block, basic_block, edge, gphi *, +@@ -60,8 +61,9 @@ static bool minmax_replacement (basic_block, basic_block, + edge, edge, gimple *, tree, tree); + static bool abs_replacement (basic_block, basic_block, + edge, edge, gimple *, tree, tree); +-static bool cond_removal_in_popcount_pattern (basic_block, basic_block, +- edge, edge, gimple *, tree, tree); ++static bool cond_removal_in_popcount_clz_ctz_pattern (basic_block, basic_block, ++ edge, edge, gimple *, ++ tree, tree); + static bool cond_store_replacement (basic_block, basic_block, edge, edge, + hash_set<tree> *); + static bool cond_if_else_store_replacement (basic_block, basic_block, basic_block); +@@ -348,8 +350,9 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) + else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) + cfgchanged = true; + else if (!early_p +- && cond_removal_in_popcount_pattern (bb, bb1, e1, e2, +- phi, arg0, arg1)) ++ && cond_removal_in_popcount_clz_ctz_pattern (bb, bb1, e1, ++ e2, phi, arg0, ++ arg1)) + cfgchanged = true; + else if (minmax_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) + cfgchanged = true; +@@ -1771,16 +1774,20 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb, + + <bb 4> + c_12 = PHI <_9(2)> +-*/ ++ ++ Similarly for __builtin_clz or __builtin_ctz if ++ C?Z_DEFINED_VALUE_AT_ZERO is 2, optab is present and ++ instead of 0 above it uses the value from that macro. */ + + static bool +-cond_removal_in_popcount_pattern (basic_block cond_bb, basic_block middle_bb, +- edge e1, edge e2, +- gimple *phi, tree arg0, tree arg1) ++cond_removal_in_popcount_clz_ctz_pattern (basic_block cond_bb, ++ basic_block middle_bb, ++ edge e1, edge e2, gimple *phi, ++ tree arg0, tree arg1) + { + gimple *cond; + gimple_stmt_iterator gsi, gsi_from; +- gimple *popcount; ++ gimple *call; + gimple *cast = NULL; + tree lhs, arg; + +@@ -1798,35 +1805,67 @@ cond_removal_in_popcount_pattern (basic_block cond_bb, basic_block middle_bb, + gsi_next_nondebug (&gsi); + if (!gsi_end_p (gsi)) + { +- popcount = gsi_stmt (gsi); ++ call = gsi_stmt (gsi); + gsi_next_nondebug (&gsi); + if (!gsi_end_p (gsi)) + return false; + } + else + { +- popcount = cast; ++ call = cast; + cast = NULL; + } + +- /* Check that we have a popcount builtin. */ +- if (!is_gimple_call (popcount)) ++ /* Check that we have a popcount/clz/ctz builtin. */ ++ if (!is_gimple_call (call) || gimple_call_num_args (call) != 1) ++ return false; ++ ++ arg = gimple_call_arg (call, 0); ++ lhs = gimple_get_lhs (call); ++ ++ if (lhs == NULL_TREE) + return false; +- combined_fn cfn = gimple_call_combined_fn (popcount); ++ ++ combined_fn cfn = gimple_call_combined_fn (call); ++ internal_fn ifn = IFN_LAST; ++ int val = 0; + switch (cfn) + { + CASE_CFN_POPCOUNT: + break; ++ CASE_CFN_CLZ: ++ if (INTEGRAL_TYPE_P (TREE_TYPE (arg))) ++ { ++ scalar_int_mode mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg)); ++ if (direct_internal_fn_supported_p (IFN_CLZ, TREE_TYPE (arg), ++ OPTIMIZE_FOR_BOTH) ++ && CLZ_DEFINED_VALUE_AT_ZERO (mode, val) == 2) ++ { ++ ifn = IFN_CLZ; ++ break; ++ } ++ } ++ return false; ++ CASE_CFN_CTZ: ++ if (INTEGRAL_TYPE_P (TREE_TYPE (arg))) ++ { ++ scalar_int_mode mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg)); ++ if (direct_internal_fn_supported_p (IFN_CTZ, TREE_TYPE (arg), ++ OPTIMIZE_FOR_BOTH) ++ && CTZ_DEFINED_VALUE_AT_ZERO (mode, val) == 2) ++ { ++ ifn = IFN_CTZ; ++ break; ++ } ++ } ++ return false; + default: + return false; + } + +- arg = gimple_call_arg (popcount, 0); +- lhs = gimple_get_lhs (popcount); +- + if (cast) + { +- /* We have a cast stmt feeding popcount builtin. */ ++ /* We have a cast stmt feeding popcount/clz/ctz builtin. */ + /* Check that we have a cast prior to that. */ + if (gimple_code (cast) != GIMPLE_ASSIGN + || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (cast))) +@@ -1839,7 +1878,7 @@ cond_removal_in_popcount_pattern (basic_block cond_bb, basic_block middle_bb, + + cond = last_stmt (cond_bb); + +- /* Cond_bb has a check for b_4 [!=|==] 0 before calling the popcount ++ /* Cond_bb has a check for b_4 [!=|==] 0 before calling the popcount/clz/ctz + builtin. */ + if (gimple_code (cond) != GIMPLE_COND + || (gimple_cond_code (cond) != NE_EXPR +@@ -1859,10 +1898,13 @@ cond_removal_in_popcount_pattern (basic_block cond_bb, basic_block middle_bb, + } + + /* Check PHI arguments. */ +- if (lhs != arg0 || !integer_zerop (arg1)) ++ if (lhs != arg0 ++ || TREE_CODE (arg1) != INTEGER_CST ++ || wi::to_wide (arg1) != val) + return false; + +- /* And insert the popcount builtin and cast stmt before the cond_bb. */ ++ /* And insert the popcount/clz/ctz builtin and cast stmt before the ++ cond_bb. */ + gsi = gsi_last_bb (cond_bb); + if (cast) + { +@@ -1870,9 +1912,19 @@ cond_removal_in_popcount_pattern (basic_block cond_bb, basic_block middle_bb, + gsi_move_before (&gsi_from, &gsi); + reset_flow_sensitive_info (gimple_get_lhs (cast)); + } +- gsi_from = gsi_for_stmt (popcount); +- gsi_move_before (&gsi_from, &gsi); +- reset_flow_sensitive_info (gimple_get_lhs (popcount)); ++ gsi_from = gsi_for_stmt (call); ++ if (ifn == IFN_LAST || gimple_call_internal_p (call)) ++ gsi_move_before (&gsi_from, &gsi); ++ else ++ { ++ /* For __builtin_c[lt]z* force .C[LT]Z ifn, because only ++ the latter is well defined at zero. */ ++ call = gimple_build_call_internal (ifn, 1, gimple_call_arg (call, 0)); ++ gimple_call_set_lhs (call, lhs); ++ gsi_insert_before (&gsi, call, GSI_SAME_STMT); ++ gsi_remove (&gsi_from, true); ++ } ++ reset_flow_sensitive_info (lhs); + + /* Now update the PHI and remove unneeded bbs. */ + replace_phi_edge_with_variable (cond_bb, e2, phi, lhs); +-- +2.27.0.windows.1 + diff --git a/0054-Backport-phiopt-Optimize-x-__builtin_clz-x-32-in-GIM.patch b/0054-Backport-phiopt-Optimize-x-__builtin_clz-x-32-in-GIM.patch new file mode 100644 index 0000000..160afc0 --- /dev/null +++ b/0054-Backport-phiopt-Optimize-x-__builtin_clz-x-32-in-GIM.patch @@ -0,0 +1,69 @@ +From 7d5d2ab082ce9986db4f3313013b44faa46bc412 Mon Sep 17 00:00:00 2001 +From: Jakub Jelinek <jakub@redhat.com> +Date: Thu, 22 Oct 2020 09:34:28 +0200 +Subject: [PATCH 06/35] [Backport] phiopt: Optimize x ? __builtin_clz (x) : 32 + in GIMPLE fallout [PR97503] + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=ef2d3ec325b1b720df5da20784eba46249af2294 + +> this broke sparc-sun-solaris2.11 bootstrap +> +> /vol/gcc/src/hg/master/local/gcc/tree-ssa-phiopt.c: In function 'bool cond_removal_in_popcount_clz_ctz_pattern(basic_block, basic_block, edge, edge, gimple*, tree, tree)': +> /vol/gcc/src/hg/master/local/gcc/tree-ssa-phiopt.c:1858:27: error: variable 'mode' set but not used [-Werror=unused-but-set-variable] +> 1858 | scalar_int_mode mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg)); +> | ^~~~ +> +> +> and doubtlessly several other targets that use the defaults.h definition of +> +> #define CTZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) 0 + +Ugh, seems many of those macros do not evaluate the first argument. +This got broken by the change to direct_internal_fn_supported_p, previously +it used mode also in the optab test. + +2020-10-22 Jakub Jelinek <jakub@redhat.com> + + * tree-ssa-phiopt.c (cond_removal_in_popcount_clz_ctz_pattern): + For CLZ and CTZ tests, use type temporary instead of mode. +--- + gcc/tree-ssa-phiopt.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c +index c1e11916e..707a5882e 100644 +--- a/gcc/tree-ssa-phiopt.c ++++ b/gcc/tree-ssa-phiopt.c +@@ -1836,10 +1836,10 @@ cond_removal_in_popcount_clz_ctz_pattern (basic_block cond_bb, + CASE_CFN_CLZ: + if (INTEGRAL_TYPE_P (TREE_TYPE (arg))) + { +- scalar_int_mode mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg)); +- if (direct_internal_fn_supported_p (IFN_CLZ, TREE_TYPE (arg), +- OPTIMIZE_FOR_BOTH) +- && CLZ_DEFINED_VALUE_AT_ZERO (mode, val) == 2) ++ tree type = TREE_TYPE (arg); ++ if (direct_internal_fn_supported_p (IFN_CLZ, type, OPTIMIZE_FOR_BOTH) ++ && CLZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (type), ++ val) == 2) + { + ifn = IFN_CLZ; + break; +@@ -1849,10 +1849,10 @@ cond_removal_in_popcount_clz_ctz_pattern (basic_block cond_bb, + CASE_CFN_CTZ: + if (INTEGRAL_TYPE_P (TREE_TYPE (arg))) + { +- scalar_int_mode mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg)); +- if (direct_internal_fn_supported_p (IFN_CTZ, TREE_TYPE (arg), +- OPTIMIZE_FOR_BOTH) +- && CTZ_DEFINED_VALUE_AT_ZERO (mode, val) == 2) ++ tree type = TREE_TYPE (arg); ++ if (direct_internal_fn_supported_p (IFN_CTZ, type, OPTIMIZE_FOR_BOTH) ++ && CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (type), ++ val) == 2) + { + ifn = IFN_CTZ; + break; +-- +2.27.0.windows.1 + diff --git a/0055-Backport-phiopt-Optimize-x-0-y-y-to-x-31-y-PR96928.patch b/0055-Backport-phiopt-Optimize-x-0-y-y-to-x-31-y-PR96928.patch new file mode 100644 index 0000000..35b773e --- /dev/null +++ b/0055-Backport-phiopt-Optimize-x-0-y-y-to-x-31-y-PR96928.patch @@ -0,0 +1,218 @@ +From 018523df11698dd0e2d42326c57bdf724a7a1aa5 Mon Sep 17 00:00:00 2001 +From: Jakub Jelinek <jakub@redhat.com> +Date: Tue, 5 Jan 2021 16:35:22 +0100 +Subject: [PATCH 07/35] [Backport] phiopt: Optimize x < 0 ? ~y : y to (x >> 31) + ^ y [PR96928] + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=576714b309b330df0e80e34114bcdf0bba35e146 + +As requested in the PR, the one's complement abs can be done more +efficiently without cmov or branching. + +Had to change the ifcvt-onecmpl-abs-1.c testcase, we no longer optimize +it in ifcvt, on x86_64 with -m32 we generate in the end the exact same +code, but with -m64: + movl %edi, %eax +- notl %eax +- cmpl %edi, %eax +- cmovl %edi, %eax ++ sarl $31, %eax ++ xorl %edi, %eax + ret + +2021-01-05 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/96928 + * tree-ssa-phiopt.c (xor_replacement): New function. + (tree_ssa_phiopt_worker): Call it. + + * gcc.dg/tree-ssa/pr96928.c: New test. + * gcc.target/i386/ifcvt-onecmpl-abs-1.c: Remove -fdump-rtl-ce1, + instead of scanning rtl dump for ifcvt message check assembly + for xor instruction. +--- + gcc/testsuite/gcc.dg/tree-ssa/pr96928.c | 38 +++++++++ + gcc/tree-ssa-phiopt.c | 108 ++++++++++++++++++++++++ + 2 files changed, 146 insertions(+) + create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr96928.c + +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr96928.c b/gcc/testsuite/gcc.dg/tree-ssa/pr96928.c +new file mode 100644 +index 000000000..209135726 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/pr96928.c +@@ -0,0 +1,38 @@ ++/* PR tree-optimization/96928 */ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -fdump-tree-phiopt2" } */ ++/* { dg-final { scan-tree-dump-times " = a_\[0-9]*\\\(D\\\) >> " 5 "phiopt2" } } */ ++/* { dg-final { scan-tree-dump-times " = ~c_\[0-9]*\\\(D\\\);" 1 "phiopt2" } } */ ++/* { dg-final { scan-tree-dump-times " = ~" 1 "phiopt2" } } */ ++/* { dg-final { scan-tree-dump-times " = \[abc_0-9\\\(\\\)D]* \\\^ " 5 "phiopt2" } } */ ++/* { dg-final { scan-tree-dump-not "a < 0" "phiopt2" } } */ ++ ++int ++foo (int a) ++{ ++ return a < 0 ? ~a : a; ++} ++ ++int ++bar (int a, int b) ++{ ++ return a < 0 ? ~b : b; ++} ++ ++unsigned ++baz (int a, unsigned int b) ++{ ++ return a < 0 ? ~b : b; ++} ++ ++unsigned ++qux (int a, unsigned int c) ++{ ++ return a >= 0 ? ~c : c; ++} ++ ++int ++corge (int a, int b) ++{ ++ return a >= 0 ? b : ~b; ++} +diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c +index 707a5882e..b9cd07a60 100644 +--- a/gcc/tree-ssa-phiopt.c ++++ b/gcc/tree-ssa-phiopt.c +@@ -61,6 +61,8 @@ static bool minmax_replacement (basic_block, basic_block, + edge, edge, gimple *, tree, tree); + static bool abs_replacement (basic_block, basic_block, + edge, edge, gimple *, tree, tree); ++static bool xor_replacement (basic_block, basic_block, ++ edge, edge, gimple *, tree, tree); + static bool cond_removal_in_popcount_clz_ctz_pattern (basic_block, basic_block, + edge, edge, gimple *, + tree, tree); +@@ -349,6 +351,9 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) + cfgchanged = true; + else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) + cfgchanged = true; ++ else if (!early_p ++ && xor_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) ++ cfgchanged = true; + else if (!early_p + && cond_removal_in_popcount_clz_ctz_pattern (bb, bb1, e1, + e2, phi, arg0, +@@ -2059,6 +2064,109 @@ abs_replacement (basic_block cond_bb, basic_block middle_bb, + return true; + } + ++/* Optimize x < 0 ? ~y : y into (x >> (prec-1)) ^ y. */ ++ ++static bool ++xor_replacement (basic_block cond_bb, basic_block middle_bb, ++ edge e0 ATTRIBUTE_UNUSED, edge e1, ++ gimple *phi, tree arg0, tree arg1) ++{ ++ if (!INTEGRAL_TYPE_P (TREE_TYPE (arg1))) ++ return false; ++ ++ /* OTHER_BLOCK must have only one executable statement which must have the ++ form arg0 = ~arg1 or arg1 = ~arg0. */ ++ ++ gimple *assign = last_and_only_stmt (middle_bb); ++ /* If we did not find the proper one's complement assignment, then we cannot ++ optimize. */ ++ if (assign == NULL) ++ return false; ++ ++ /* If we got here, then we have found the only executable statement ++ in OTHER_BLOCK. If it is anything other than arg = ~arg1 or ++ arg1 = ~arg0, then we cannot optimize. */ ++ if (!is_gimple_assign (assign)) ++ return false; ++ ++ if (gimple_assign_rhs_code (assign) != BIT_NOT_EXPR) ++ return false; ++ ++ tree lhs = gimple_assign_lhs (assign); ++ tree rhs = gimple_assign_rhs1 (assign); ++ ++ /* The assignment has to be arg0 = -arg1 or arg1 = -arg0. */ ++ if (!(lhs == arg0 && rhs == arg1) && !(lhs == arg1 && rhs == arg0)) ++ return false; ++ ++ gimple *cond = last_stmt (cond_bb); ++ tree result = PHI_RESULT (phi); ++ ++ /* Only relationals comparing arg[01] against zero are interesting. */ ++ enum tree_code cond_code = gimple_cond_code (cond); ++ if (cond_code != LT_EXPR && cond_code != GE_EXPR) ++ return false; ++ ++ /* Make sure the conditional is x OP 0. */ ++ tree clhs = gimple_cond_lhs (cond); ++ if (TREE_CODE (clhs) != SSA_NAME ++ || !INTEGRAL_TYPE_P (TREE_TYPE (clhs)) ++ || TYPE_UNSIGNED (TREE_TYPE (clhs)) ++ || TYPE_PRECISION (TREE_TYPE (clhs)) != TYPE_PRECISION (TREE_TYPE (arg1)) ++ || !integer_zerop (gimple_cond_rhs (cond))) ++ return false; ++ ++ /* We need to know which is the true edge and which is the false ++ edge so that we know if have xor or inverted xor. */ ++ edge true_edge, false_edge; ++ extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge); ++ ++ /* For GE_EXPR, if the true edge goes to OTHER_BLOCK, then we ++ will need to invert the result. Similarly for LT_EXPR if ++ the false edge goes to OTHER_BLOCK. */ ++ edge e; ++ if (cond_code == GE_EXPR) ++ e = true_edge; ++ else ++ e = false_edge; ++ ++ bool invert = e->dest == middle_bb; ++ ++ result = duplicate_ssa_name (result, NULL); ++ ++ gimple_stmt_iterator gsi = gsi_last_bb (cond_bb); ++ ++ int prec = TYPE_PRECISION (TREE_TYPE (clhs)); ++ gimple *new_stmt ++ = gimple_build_assign (make_ssa_name (TREE_TYPE (clhs)), RSHIFT_EXPR, clhs, ++ build_int_cst (integer_type_node, prec - 1)); ++ gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT); ++ ++ if (!useless_type_conversion_p (TREE_TYPE (result), TREE_TYPE (clhs))) ++ { ++ new_stmt = gimple_build_assign (make_ssa_name (TREE_TYPE (result)), ++ NOP_EXPR, gimple_assign_lhs (new_stmt)); ++ gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT); ++ } ++ lhs = gimple_assign_lhs (new_stmt); ++ ++ if (invert) ++ { ++ new_stmt = gimple_build_assign (make_ssa_name (TREE_TYPE (result)), ++ BIT_NOT_EXPR, rhs); ++ gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT); ++ rhs = gimple_assign_lhs (new_stmt); ++ } ++ ++ new_stmt = gimple_build_assign (result, BIT_XOR_EXPR, lhs, rhs); ++ gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT); ++ ++ replace_phi_edge_with_variable (cond_bb, e1, phi, result); ++ ++ /* Note that we optimized this PHI. */ ++ return true; ++} ++ + /* Auxiliary functions to determine the set of memory accesses which + can't trap because they are preceded by accesses to the same memory + portion. We do that for MEM_REFs, so we only need to track +-- +2.27.0.windows.1 + diff --git a/0056-Backport-phiopt-Optimize-x-y-cmp-z-PR94589.patch b/0056-Backport-phiopt-Optimize-x-y-cmp-z-PR94589.patch new file mode 100644 index 0000000..473dee8 --- /dev/null +++ b/0056-Backport-phiopt-Optimize-x-y-cmp-z-PR94589.patch @@ -0,0 +1,1067 @@ +From 02313ab8cf7eb4defc1482ece48c07c2d8c77be9 Mon Sep 17 00:00:00 2001 +From: Jakub Jelinek <jakub@redhat.com> +Date: Thu, 6 May 2021 10:15:40 +0200 +Subject: [PATCH 08/35] [Backport] phiopt: Optimize (x <=> y) cmp z [PR94589] + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=ad96c867e173c1ebcfc201b201adac5095683a08 + +genericize_spaceship genericizes i <=> j to approximately +({ int c; if (i == j) c = 0; else if (i < j) c = -1; else c = 1; c; }) +for strong ordering and +({ int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; c; }) +for partial ordering. +The C++ standard supports then == or != comparisons of that against +strong/partial ordering enums, or </<=/==/!=/>/>= comparisons of <=> result +against literal 0. + +In some cases we already optimize that but in many cases we keep performing +all the 2 or 3 comparisons, compute the spaceship value and then compare +that. + +The following patch recognizes those patterns if the <=> operands are +integral types or floating point (the latter only for -ffast-math) and +optimizes it to the single comparison that is needed (plus adds debug stmts +if needed for the spaceship result). + +There is one thing I'd like to address in a follow-up: the pr94589-2.C +testcase should be matching just 12 times each, but runs +into operator>=(partial_ordering, unspecified) being defined as +(_M_value&1)==_M_value +rather than _M_value>=0. When not honoring NaNs, the 2 case should be +unreachable and so (_M_value&1)==_M_value is then equivalent to _M_value>=0, +but is not a single use but two uses. I'll need to pattern match that case +specially. + +2021-05-06 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/94589 + * tree-ssa-phiopt.c (tree_ssa_phiopt_worker): Call + spaceship_replacement. + (cond_only_block_p, spaceship_replacement): New functions. + + * gcc.dg/pr94589-1.c: New test. + * gcc.dg/pr94589-2.c: New test. + * gcc.dg/pr94589-3.c: New test. + * gcc.dg/pr94589-4.c: New test. + * g++.dg/opt/pr94589-1.C: New test. + * g++.dg/opt/pr94589-2.C: New test. + * g++.dg/opt/pr94589-3.C: New test. + * g++.dg/opt/pr94589-4.C: New test. +--- + gcc/testsuite/g++.dg/opt/pr94589-1.C | 33 +++ + gcc/testsuite/g++.dg/opt/pr94589-2.C | 33 +++ + gcc/testsuite/g++.dg/opt/pr94589-3.C | 84 ++++++ + gcc/testsuite/g++.dg/opt/pr94589-4.C | 84 ++++++ + gcc/testsuite/gcc.dg/pr94589-1.c | 35 +++ + gcc/testsuite/gcc.dg/pr94589-2.c | 35 +++ + gcc/testsuite/gcc.dg/pr94589-3.c | 97 ++++++ + gcc/testsuite/gcc.dg/pr94589-4.c | 97 ++++++ + gcc/tree-ssa-phiopt.c | 424 +++++++++++++++++++++++++++ + 9 files changed, 922 insertions(+) + create mode 100644 gcc/testsuite/g++.dg/opt/pr94589-1.C + create mode 100644 gcc/testsuite/g++.dg/opt/pr94589-2.C + create mode 100644 gcc/testsuite/g++.dg/opt/pr94589-3.C + create mode 100644 gcc/testsuite/g++.dg/opt/pr94589-4.C + create mode 100644 gcc/testsuite/gcc.dg/pr94589-1.c + create mode 100644 gcc/testsuite/gcc.dg/pr94589-2.c + create mode 100644 gcc/testsuite/gcc.dg/pr94589-3.c + create mode 100644 gcc/testsuite/gcc.dg/pr94589-4.c + +diff --git a/gcc/testsuite/g++.dg/opt/pr94589-1.C b/gcc/testsuite/g++.dg/opt/pr94589-1.C +new file mode 100644 +index 000000000..d1cc5050c +--- /dev/null ++++ b/gcc/testsuite/g++.dg/opt/pr94589-1.C +@@ -0,0 +1,33 @@ ++// PR tree-optimization/94589 ++// { dg-do compile { target c++20 } } ++// { dg-options "-O2 -g0 -fdump-tree-optimized" } ++// { dg-final { scan-tree-dump-times "\[ij]_\[0-9]+\\(D\\) (?:<|<=|==|!=|>|>=) \[ij]_\[0-9]+\\(D\\)" 12 "optimized" } } ++// { dg-final { scan-tree-dump-times "i_\[0-9]+\\(D\\) (?:<|<=|==|!=|>|>=) \[45]" 12 "optimized" } } ++ ++#include <compare> ++ ++#define A __attribute__((noipa)) ++A bool f1 (int i, int j) { auto c = i <=> j; return c == 0; } ++A bool f2 (int i, int j) { auto c = i <=> j; return c != 0; } ++A bool f3 (int i, int j) { auto c = i <=> j; return c > 0; } ++A bool f4 (int i, int j) { auto c = i <=> j; return c < 0; } ++A bool f5 (int i, int j) { auto c = i <=> j; return c >= 0; } ++A bool f6 (int i, int j) { auto c = i <=> j; return c <= 0; } ++A bool f7 (int i, int j) { auto c = i <=> j; return c == std::strong_ordering::less; } ++A bool f8 (int i, int j) { auto c = i <=> j; return c != std::strong_ordering::less; } ++A bool f9 (int i, int j) { auto c = i <=> j; return c == std::strong_ordering::equal; } ++A bool f10 (int i, int j) { auto c = i <=> j; return c != std::strong_ordering::equal; } ++A bool f11 (int i, int j) { auto c = i <=> j; return c == std::strong_ordering::greater; } ++A bool f12 (int i, int j) { auto c = i <=> j; return c != std::strong_ordering::greater; } ++A bool f13 (int i) { auto c = i <=> 5; return c == 0; } ++A bool f14 (int i) { auto c = i <=> 5; return c != 0; } ++A bool f15 (int i) { auto c = i <=> 5; return c > 0; } ++A bool f16 (int i) { auto c = i <=> 5; return c < 0; } ++A bool f17 (int i) { auto c = i <=> 5; return c >= 0; } ++A bool f18 (int i) { auto c = i <=> 5; return c <= 0; } ++A bool f19 (int i) { auto c = i <=> 5; return c == std::strong_ordering::less; } ++A bool f20 (int i) { auto c = i <=> 5; return c != std::strong_ordering::less; } ++A bool f21 (int i) { auto c = i <=> 5; return c == std::strong_ordering::equal; } ++A bool f22 (int i) { auto c = i <=> 5; return c != std::strong_ordering::equal; } ++A bool f23 (int i) { auto c = i <=> 5; return c == std::strong_ordering::greater; } ++A bool f24 (int i) { auto c = i <=> 5; return c != std::strong_ordering::greater; } +diff --git a/gcc/testsuite/g++.dg/opt/pr94589-2.C b/gcc/testsuite/g++.dg/opt/pr94589-2.C +new file mode 100644 +index 000000000..dda947e22 +--- /dev/null ++++ b/gcc/testsuite/g++.dg/opt/pr94589-2.C +@@ -0,0 +1,33 @@ ++// PR tree-optimization/94589 ++// { dg-do compile { target c++20 } } ++// { dg-options "-O2 -g0 -ffast-math -fdump-tree-optimized" } ++// { dg-final { scan-tree-dump-times "\[ij]_\[0-9]+\\(D\\) (?:<|<=|==|!=|>|>=) \[ij]_\[0-9]+\\(D\\)" 14 "optimized" } } ++// { dg-final { scan-tree-dump-times "i_\[0-9]+\\(D\\) (?:<|<=|==|!=|>|>=) 5\\.0" 14 "optimized" } } ++ ++#include <compare> ++ ++#define A __attribute__((noipa)) ++A bool f1 (double i, double j) { auto c = i <=> j; return c == 0; } ++A bool f2 (double i, double j) { auto c = i <=> j; return c != 0; } ++A bool f3 (double i, double j) { auto c = i <=> j; return c > 0; } ++A bool f4 (double i, double j) { auto c = i <=> j; return c < 0; } ++A bool f5 (double i, double j) { auto c = i <=> j; return c >= 0; } ++A bool f6 (double i, double j) { auto c = i <=> j; return c <= 0; } ++A bool f7 (double i, double j) { auto c = i <=> j; return c == std::partial_ordering::less; } ++A bool f8 (double i, double j) { auto c = i <=> j; return c != std::partial_ordering::less; } ++A bool f9 (double i, double j) { auto c = i <=> j; return c == std::partial_ordering::equivalent; } ++A bool f10 (double i, double j) { auto c = i <=> j; return c != std::partial_ordering::equivalent; } ++A bool f11 (double i, double j) { auto c = i <=> j; return c == std::partial_ordering::greater; } ++A bool f12 (double i, double j) { auto c = i <=> j; return c != std::partial_ordering::greater; } ++A bool f13 (double i) { auto c = i <=> 5.0; return c == 0; } ++A bool f14 (double i) { auto c = i <=> 5.0; return c != 0; } ++A bool f15 (double i) { auto c = i <=> 5.0; return c > 0; } ++A bool f16 (double i) { auto c = i <=> 5.0; return c < 0; } ++A bool f17 (double i) { auto c = i <=> 5.0; return c >= 0; } ++A bool f18 (double i) { auto c = i <=> 5.0; return c <= 0; } ++A bool f19 (double i) { auto c = i <=> 5.0; return c == std::partial_ordering::less; } ++A bool f20 (double i) { auto c = i <=> 5.0; return c != std::partial_ordering::less; } ++A bool f21 (double i) { auto c = i <=> 5.0; return c == std::partial_ordering::equivalent; } ++A bool f22 (double i) { auto c = i <=> 5.0; return c != std::partial_ordering::equivalent; } ++A bool f23 (double i) { auto c = i <=> 5.0; return c == std::partial_ordering::greater; } ++A bool f24 (double i) { auto c = i <=> 5.0; return c != std::partial_ordering::greater; } +diff --git a/gcc/testsuite/g++.dg/opt/pr94589-3.C b/gcc/testsuite/g++.dg/opt/pr94589-3.C +new file mode 100644 +index 000000000..725b81f56 +--- /dev/null ++++ b/gcc/testsuite/g++.dg/opt/pr94589-3.C +@@ -0,0 +1,84 @@ ++// { dg-do run { target c++20 } } ++// { dg-options "-O2 -g" } ++ ++#include "pr94589-1.C" ++ ++#define C(fn, i, j, r) if (fn (i, j) != r) __builtin_abort () ++#define D(fn, i, r) if (fn (i) != r) __builtin_abort () ++ ++int ++main () ++{ ++ C (f1, 7, 8, false); ++ C (f1, 8, 8, true); ++ C (f1, 9, 8, false); ++ C (f2, 7, 8, true); ++ C (f2, 8, 8, false); ++ C (f2, 9, 8, true); ++ C (f3, 7, 8, false); ++ C (f3, 8, 8, false); ++ C (f3, 9, 8, true); ++ C (f4, 7, 8, true); ++ C (f4, 8, 8, false); ++ C (f4, 9, 8, false); ++ C (f5, 7, 8, false); ++ C (f5, 8, 8, true); ++ C (f5, 9, 8, true); ++ C (f6, 7, 8, true); ++ C (f6, 8, 8, true); ++ C (f6, 9, 8, false); ++ C (f7, 7, 8, true); ++ C (f7, 8, 8, false); ++ C (f7, 9, 8, false); ++ C (f8, 7, 8, false); ++ C (f8, 8, 8, true); ++ C (f8, 9, 8, true); ++ C (f9, 7, 8, false); ++ C (f9, 8, 8, true); ++ C (f9, 9, 8, false); ++ C (f10, 7, 8, true); ++ C (f10, 8, 8, false); ++ C (f10, 9, 8, true); ++ C (f11, 7, 8, false); ++ C (f11, 8, 8, false); ++ C (f11, 9, 8, true); ++ C (f12, 7, 8, true); ++ C (f12, 8, 8, true); ++ C (f12, 9, 8, false); ++ D (f13, 4, false); ++ D (f13, 5, true); ++ D (f13, 6, false); ++ D (f14, 4, true); ++ D (f14, 5, false); ++ D (f14, 6, true); ++ D (f15, 4, false); ++ D (f15, 5, false); ++ D (f15, 6, true); ++ D (f16, 4, true); ++ D (f16, 5, false); ++ D (f16, 6, false); ++ D (f17, 4, false); ++ D (f17, 5, true); ++ D (f17, 6, true); ++ D (f18, 4, true); ++ D (f18, 5, true); ++ D (f18, 6, false); ++ D (f19, 4, true); ++ D (f19, 5, false); ++ D (f19, 6, false); ++ D (f20, 4, false); ++ D (f20, 5, true); ++ D (f20, 6, true); ++ D (f21, 4, false); ++ D (f21, 5, true); ++ D (f21, 6, false); ++ D (f22, 4, true); ++ D (f22, 5, false); ++ D (f22, 6, true); ++ D (f23, 4, false); ++ D (f23, 5, false); ++ D (f23, 6, true); ++ D (f24, 4, true); ++ D (f24, 5, true); ++ D (f24, 6, false); ++} +diff --git a/gcc/testsuite/g++.dg/opt/pr94589-4.C b/gcc/testsuite/g++.dg/opt/pr94589-4.C +new file mode 100644 +index 000000000..256a45580 +--- /dev/null ++++ b/gcc/testsuite/g++.dg/opt/pr94589-4.C +@@ -0,0 +1,84 @@ ++// { dg-do run { target c++20 } } ++// { dg-options "-O2 -g -ffast-math" } ++ ++#include "pr94589-2.C" ++ ++#define C(fn, i, j, r) if (fn (i, j) != r) __builtin_abort () ++#define D(fn, i, r) if (fn (i) != r) __builtin_abort () ++ ++int ++main () ++{ ++ C (f1, 7.0, 8.0, false); ++ C (f1, 8.0, 8.0, true); ++ C (f1, 9.0, 8.0, false); ++ C (f2, 7.0, 8.0, true); ++ C (f2, 8.0, 8.0, false); ++ C (f2, 9.0, 8.0, true); ++ C (f3, 7.0, 8.0, false); ++ C (f3, 8.0, 8.0, false); ++ C (f3, 9.0, 8.0, true); ++ C (f4, 7.0, 8.0, true); ++ C (f4, 8.0, 8.0, false); ++ C (f4, 9.0, 8.0, false); ++ C (f5, 7.0, 8.0, false); ++ C (f5, 8.0, 8.0, true); ++ C (f5, 9.0, 8.0, true); ++ C (f6, 7.0, 8.0, true); ++ C (f6, 8.0, 8.0, true); ++ C (f6, 9.0, 8.0, false); ++ C (f7, 7.0, 8.0, true); ++ C (f7, 8.0, 8.0, false); ++ C (f7, 9.0, 8.0, false); ++ C (f8, 7.0, 8.0, false); ++ C (f8, 8.0, 8.0, true); ++ C (f8, 9.0, 8.0, true); ++ C (f9, 7.0, 8.0, false); ++ C (f9, 8.0, 8.0, true); ++ C (f9, 9.0, 8.0, false); ++ C (f10, 7.0, 8.0, true); ++ C (f10, 8.0, 8.0, false); ++ C (f10, 9.0, 8.0, true); ++ C (f11, 7.0, 8.0, false); ++ C (f11, 8.0, 8.0, false); ++ C (f11, 9.0, 8.0, true); ++ C (f12, 7.0, 8.0, true); ++ C (f12, 8.0, 8.0, true); ++ C (f12, 9.0, 8.0, false); ++ D (f13, 4.0, false); ++ D (f13, 5.0, true); ++ D (f13, 6.0, false); ++ D (f14, 4.0, true); ++ D (f14, 5.0, false); ++ D (f14, 6.0, true); ++ D (f15, 4.0, false); ++ D (f15, 5.0, false); ++ D (f15, 6.0, true); ++ D (f16, 4.0, true); ++ D (f16, 5.0, false); ++ D (f16, 6.0, false); ++ D (f17, 4.0, false); ++ D (f17, 5.0, true); ++ D (f17, 6.0, true); ++ D (f18, 4.0, true); ++ D (f18, 5.0, true); ++ D (f18, 6.0, false); ++ D (f19, 4.0, true); ++ D (f19, 5.0, false); ++ D (f19, 6.0, false); ++ D (f20, 4.0, false); ++ D (f20, 5.0, true); ++ D (f20, 6.0, true); ++ D (f21, 4.0, false); ++ D (f21, 5.0, true); ++ D (f21, 6.0, false); ++ D (f22, 4.0, true); ++ D (f22, 5.0, false); ++ D (f22, 6.0, true); ++ D (f23, 4.0, false); ++ D (f23, 5.0, false); ++ D (f23, 6.0, true); ++ D (f24, 4.0, true); ++ D (f24, 5.0, true); ++ D (f24, 6.0, false); ++} +diff --git a/gcc/testsuite/gcc.dg/pr94589-1.c b/gcc/testsuite/gcc.dg/pr94589-1.c +new file mode 100644 +index 000000000..de404ea82 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/pr94589-1.c +@@ -0,0 +1,35 @@ ++/* PR tree-optimization/94589 */ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -g0 -fdump-tree-optimized" } */ ++/* { dg-final { scan-tree-dump-times "\[ij]_\[0-9]+\\(D\\) (?:<|<=|==|!=|>|>=) \[ij]_\[0-9]+\\(D\\)" 14 "optimized" } } */ ++/* { dg-final { scan-tree-dump-times "i_\[0-9]+\\(D\\) (?:<|<=|==|!=|>|>=) \[45]" 14 "optimized" } } */ ++ ++#define A __attribute__((noipa)) ++A int f1 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c == 0; } ++A int f2 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c != 0; } ++A int f3 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c > 0; } ++A int f4 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c < 0; } ++A int f5 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c >= 0; } ++A int f6 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c <= 0; } ++A int f7 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c == -1; } ++A int f8 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c != -1; } ++A int f9 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c > -1; } ++A int f10 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c <= -1; } ++A int f11 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c == 1; } ++A int f12 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c != 1; } ++A int f13 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c < 1; } ++A int f14 (int i, int j) { int c = i == j ? 0 : i < j ? -1 : 1; return c >= 1; } ++A int f15 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c == 0; } ++A int f16 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c != 0; } ++A int f17 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c > 0; } ++A int f18 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c < 0; } ++A int f19 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c >= 0; } ++A int f20 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c <= 0; } ++A int f21 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c == -1; } ++A int f22 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c != -1; } ++A int f23 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c > -1; } ++A int f24 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c <= -1; } ++A int f25 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c == 1; } ++A int f26 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c != 1; } ++A int f27 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c < 1; } ++A int f28 (int i) { int c = i == 5 ? 0 : i < 5 ? -1 : 1; return c >= 1; } +diff --git a/gcc/testsuite/gcc.dg/pr94589-2.c b/gcc/testsuite/gcc.dg/pr94589-2.c +new file mode 100644 +index 000000000..9481b764d +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/pr94589-2.c +@@ -0,0 +1,35 @@ ++/* PR tree-optimization/94589 */ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -g0 -ffast-math -fdump-tree-optimized" } */ ++/* { dg-final { scan-tree-dump-times "\[ij]_\[0-9]+\\(D\\) (?:<|<=|==|!=|>|>=) \[ij]_\[0-9]+\\(D\\)" 14 "optimized" } } */ ++/* { dg-final { scan-tree-dump-times "i_\[0-9]+\\(D\\) (?:<|<=|==|!=|>|>=) 5\\.0" 14 "optimized" } } */ ++ ++#define A __attribute__((noipa)) ++A int f1 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c == 0; } ++A int f2 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c != 0; } ++A int f3 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c > 0; } ++A int f4 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c < 0; } ++A int f5 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c >= 0; } ++A int f6 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c <= 0; } ++A int f7 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c == -1; } ++A int f8 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c != -1; } ++A int f9 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c > -1; } ++A int f10 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c <= -1; } ++A int f11 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c == 1; } ++A int f12 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c != 1; } ++A int f13 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c < 1; } ++A int f14 (double i, double j) { int c; if (i == j) c = 0; else if (i < j) c = -1; else if (i > j) c = 1; else c = 2; return c >= 1; } ++A int f15 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c == 0; } ++A int f16 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c != 0; } ++A int f17 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c > 0; } ++A int f18 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c < 0; } ++A int f19 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c >= 0; } ++A int f20 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c <= 0; } ++A int f21 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c == -1; } ++A int f22 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c != -1; } ++A int f23 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c > -1; } ++A int f24 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c <= -1; } ++A int f25 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c == 1; } ++A int f26 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c != 1; } ++A int f27 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c < 1; } ++A int f28 (double i) { int c; if (i == 5.0) c = 0; else if (i < 5.0) c = -1; else if (i > 5.0) c = 1; else c = 2; return c >= 1; } +diff --git a/gcc/testsuite/gcc.dg/pr94589-3.c b/gcc/testsuite/gcc.dg/pr94589-3.c +new file mode 100644 +index 000000000..df82fab73 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/pr94589-3.c +@@ -0,0 +1,97 @@ ++/* { dg-do run } */ ++/* { dg-options "-O2 -g" } */ ++ ++#include "pr94589-1.c" ++ ++#define C(fn, i, j, r) if (fn (i, j) != r) __builtin_abort () ++#define D(fn, i, r) if (fn (i) != r) __builtin_abort () ++ ++int ++main () ++{ ++ C (f1, 7, 8, 0); ++ C (f1, 8, 8, 1); ++ C (f1, 9, 8, 0); ++ C (f2, 7, 8, 1); ++ C (f2, 8, 8, 0); ++ C (f2, 9, 8, 1); ++ C (f3, 7, 8, 0); ++ C (f3, 8, 8, 0); ++ C (f3, 9, 8, 1); ++ C (f4, 7, 8, 1); ++ C (f4, 8, 8, 0); ++ C (f4, 9, 8, 0); ++ C (f5, 7, 8, 0); ++ C (f5, 8, 8, 1); ++ C (f5, 9, 8, 1); ++ C (f6, 7, 8, 1); ++ C (f6, 8, 8, 1); ++ C (f6, 9, 8, 0); ++ C (f7, 7, 8, 1); ++ C (f7, 8, 8, 0); ++ C (f7, 9, 8, 0); ++ C (f8, 7, 8, 0); ++ C (f8, 8, 8, 1); ++ C (f8, 9, 8, 1); ++ C (f9, 7, 8, 0); ++ C (f9, 8, 8, 1); ++ C (f9, 9, 8, 1); ++ C (f10, 7, 8, 1); ++ C (f10, 8, 8, 0); ++ C (f10, 9, 8, 0); ++ C (f11, 7, 8, 0); ++ C (f11, 8, 8, 0); ++ C (f11, 9, 8, 1); ++ C (f12, 7, 8, 1); ++ C (f12, 8, 8, 1); ++ C (f12, 9, 8, 0); ++ C (f13, 7, 8, 1); ++ C (f13, 8, 8, 1); ++ C (f13, 9, 8, 0); ++ C (f14, 7, 8, 0); ++ C (f14, 8, 8, 0); ++ C (f14, 9, 8, 1); ++ D (f15, 4, 0); ++ D (f15, 5, 1); ++ D (f15, 6, 0); ++ D (f16, 4, 1); ++ D (f16, 5, 0); ++ D (f16, 6, 1); ++ D (f17, 4, 0); ++ D (f17, 5, 0); ++ D (f17, 6, 1); ++ D (f18, 4, 1); ++ D (f18, 5, 0); ++ D (f18, 6, 0); ++ D (f19, 4, 0); ++ D (f19, 5, 1); ++ D (f19, 6, 1); ++ D (f20, 4, 1); ++ D (f20, 5, 1); ++ D (f20, 6, 0); ++ D (f21, 4, 1); ++ D (f21, 5, 0); ++ D (f21, 6, 0); ++ D (f22, 4, 0); ++ D (f22, 5, 1); ++ D (f22, 6, 1); ++ D (f23, 4, 0); ++ D (f23, 5, 1); ++ D (f23, 6, 1); ++ D (f24, 4, 1); ++ D (f24, 5, 0); ++ D (f24, 6, 0); ++ D (f25, 4, 0); ++ D (f25, 5, 0); ++ D (f25, 6, 1); ++ D (f26, 4, 1); ++ D (f26, 5, 1); ++ D (f26, 6, 0); ++ D (f27, 4, 1); ++ D (f27, 5, 1); ++ D (f27, 6, 0); ++ D (f28, 4, 0); ++ D (f28, 5, 0); ++ D (f28, 6, 1); ++ return 0; ++} +diff --git a/gcc/testsuite/gcc.dg/pr94589-4.c b/gcc/testsuite/gcc.dg/pr94589-4.c +new file mode 100644 +index 000000000..b2557fb07 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/pr94589-4.c +@@ -0,0 +1,97 @@ ++/* { dg-do run } */ ++/* { dg-options "-O2 -g -ffast-math" } */ ++ ++#include "pr94589-2.c" ++ ++#define C(fn, i, j, r) if (fn (i, j) != r) __builtin_abort () ++#define D(fn, i, r) if (fn (i) != r) __builtin_abort () ++ ++int ++main () ++{ ++ C (f1, 7.0, 8.0, 0); ++ C (f1, 8.0, 8.0, 1); ++ C (f1, 9.0, 8.0, 0); ++ C (f2, 7.0, 8.0, 1); ++ C (f2, 8.0, 8.0, 0); ++ C (f2, 9.0, 8.0, 1); ++ C (f3, 7.0, 8.0, 0); ++ C (f3, 8.0, 8.0, 0); ++ C (f3, 9.0, 8.0, 1); ++ C (f4, 7.0, 8.0, 1); ++ C (f4, 8.0, 8.0, 0); ++ C (f4, 9.0, 8.0, 0); ++ C (f5, 7.0, 8.0, 0); ++ C (f5, 8.0, 8.0, 1); ++ C (f5, 9.0, 8.0, 1); ++ C (f6, 7.0, 8.0, 1); ++ C (f6, 8.0, 8.0, 1); ++ C (f6, 9.0, 8.0, 0); ++ C (f7, 7.0, 8.0, 1); ++ C (f7, 8.0, 8.0, 0); ++ C (f7, 9.0, 8.0, 0); ++ C (f8, 7.0, 8.0, 0); ++ C (f8, 8.0, 8.0, 1); ++ C (f8, 9.0, 8.0, 1); ++ C (f9, 7.0, 8.0, 0); ++ C (f9, 8.0, 8.0, 1); ++ C (f9, 9.0, 8.0, 1); ++ C (f10, 7.0, 8.0, 1); ++ C (f10, 8.0, 8.0, 0); ++ C (f10, 9.0, 8.0, 0); ++ C (f11, 7.0, 8.0, 0); ++ C (f11, 8.0, 8.0, 0); ++ C (f11, 9.0, 8.0, 1); ++ C (f12, 7.0, 8.0, 1); ++ C (f12, 8.0, 8.0, 1); ++ C (f12, 9.0, 8.0, 0); ++ C (f13, 7.0, 8.0, 1); ++ C (f13, 8.0, 8.0, 1); ++ C (f13, 9.0, 8.0, 0); ++ C (f14, 7.0, 8.0, 0); ++ C (f14, 8.0, 8.0, 0); ++ C (f14, 9.0, 8.0, 1); ++ D (f15, 4.0, 0); ++ D (f15, 5.0, 1); ++ D (f15, 6.0, 0); ++ D (f16, 4.0, 1); ++ D (f16, 5.0, 0); ++ D (f16, 6.0, 1); ++ D (f17, 4.0, 0); ++ D (f17, 5.0, 0); ++ D (f17, 6.0, 1); ++ D (f18, 4.0, 1); ++ D (f18, 5.0, 0); ++ D (f18, 6.0, 0); ++ D (f19, 4.0, 0); ++ D (f19, 5.0, 1); ++ D (f19, 6.0, 1); ++ D (f20, 4.0, 1); ++ D (f20, 5.0, 1); ++ D (f20, 6.0, 0); ++ D (f21, 4.0, 1); ++ D (f21, 5.0, 0); ++ D (f21, 6.0, 0); ++ D (f22, 4.0, 0); ++ D (f22, 5.0, 1); ++ D (f22, 6.0, 1); ++ D (f23, 4.0, 0); ++ D (f23, 5.0, 1); ++ D (f23, 6.0, 1); ++ D (f24, 4.0, 1); ++ D (f24, 5.0, 0); ++ D (f24, 6.0, 0); ++ D (f25, 4.0, 0); ++ D (f25, 5.0, 0); ++ D (f25, 6.0, 1); ++ D (f26, 4.0, 1); ++ D (f26, 5.0, 1); ++ D (f26, 6.0, 0); ++ D (f27, 4.0, 1); ++ D (f27, 5.0, 1); ++ D (f27, 6.0, 0); ++ D (f28, 4.0, 0); ++ D (f28, 5.0, 0); ++ D (f28, 6.0, 1); ++ return 0; ++} +diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c +index b9cd07a60..fca32222f 100644 +--- a/gcc/tree-ssa-phiopt.c ++++ b/gcc/tree-ssa-phiopt.c +@@ -63,6 +63,8 @@ static bool abs_replacement (basic_block, basic_block, + edge, edge, gimple *, tree, tree); + static bool xor_replacement (basic_block, basic_block, + edge, edge, gimple *, tree, tree); ++static bool spaceship_replacement (basic_block, basic_block, ++ edge, edge, gphi *, tree, tree); + static bool cond_removal_in_popcount_clz_ctz_pattern (basic_block, basic_block, + edge, edge, gimple *, + tree, tree); +@@ -361,6 +363,8 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) + cfgchanged = true; + else if (minmax_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) + cfgchanged = true; ++ else if (spaceship_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) ++ cfgchanged = true; + } + } + +@@ -1753,6 +1757,426 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb, + return true; + } + ++/* Return true if the only executable statement in BB is a GIMPLE_COND. */ ++ ++static bool ++cond_only_block_p (basic_block bb) ++{ ++ /* BB must have no executable statements. */ ++ gimple_stmt_iterator gsi = gsi_after_labels (bb); ++ if (phi_nodes (bb)) ++ return false; ++ while (!gsi_end_p (gsi)) ++ { ++ gimple *stmt = gsi_stmt (gsi); ++ if (is_gimple_debug (stmt)) ++ ; ++ else if (gimple_code (stmt) == GIMPLE_NOP ++ || gimple_code (stmt) == GIMPLE_PREDICT ++ || gimple_code (stmt) == GIMPLE_COND) ++ ; ++ else ++ return false; ++ gsi_next (&gsi); ++ } ++ return true; ++} ++ ++/* Attempt to optimize (x <=> y) cmp 0 and similar comparisons. ++ For strong ordering <=> try to match something like: ++ <bb 2> : // cond3_bb (== cond2_bb) ++ if (x_4(D) != y_5(D)) ++ goto <bb 3>; [INV] ++ else ++ goto <bb 6>; [INV] ++ ++ <bb 3> : // cond_bb ++ if (x_4(D) < y_5(D)) ++ goto <bb 6>; [INV] ++ else ++ goto <bb 4>; [INV] ++ ++ <bb 4> : // middle_bb ++ ++ <bb 6> : // phi_bb ++ # iftmp.0_2 = PHI <1(4), 0(2), -1(3)> ++ _1 = iftmp.0_2 == 0; ++ ++ and for partial ordering <=> something like: ++ ++ <bb 2> : // cond3_bb ++ if (a_3(D) == b_5(D)) ++ goto <bb 6>; [50.00%] ++ else ++ goto <bb 3>; [50.00%] ++ ++ <bb 3> [local count: 536870913]: // cond2_bb ++ if (a_3(D) < b_5(D)) ++ goto <bb 6>; [50.00%] ++ else ++ goto <bb 4>; [50.00%] ++ ++ <bb 4> [local count: 268435456]: // cond_bb ++ if (a_3(D) > b_5(D)) ++ goto <bb 6>; [50.00%] ++ else ++ goto <bb 5>; [50.00%] ++ ++ <bb 5> [local count: 134217728]: // middle_bb ++ ++ <bb 6> [local count: 1073741824]: // phi_bb ++ # SR.27_4 = PHI <0(2), -1(3), 1(4), 2(5)> ++ _2 = SR.27_4 > 0; */ ++ ++static bool ++spaceship_replacement (basic_block cond_bb, basic_block middle_bb, ++ edge e0, edge e1, gphi *phi, ++ tree arg0, tree arg1) ++{ ++ if (!INTEGRAL_TYPE_P (TREE_TYPE (PHI_RESULT (phi))) ++ || TYPE_UNSIGNED (TREE_TYPE (PHI_RESULT (phi))) ++ || !tree_fits_shwi_p (arg0) ++ || !tree_fits_shwi_p (arg1) ++ || !IN_RANGE (tree_to_shwi (arg0), -1, 2) ++ || !IN_RANGE (tree_to_shwi (arg1), -1, 2)) ++ return false; ++ ++ basic_block phi_bb = gimple_bb (phi); ++ gcc_assert (phi_bb == e0->dest && phi_bb == e1->dest); ++ if (!IN_RANGE (EDGE_COUNT (phi_bb->preds), 3, 4)) ++ return false; ++ ++ use_operand_p use_p; ++ gimple *use_stmt; ++ if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi))) ++ return false; ++ if (!single_imm_use (PHI_RESULT (phi), &use_p, &use_stmt)) ++ return false; ++ enum tree_code cmp; ++ tree lhs, rhs; ++ if (gimple_code (use_stmt) == GIMPLE_COND) ++ { ++ cmp = gimple_cond_code (use_stmt); ++ lhs = gimple_cond_lhs (use_stmt); ++ rhs = gimple_cond_rhs (use_stmt); ++ } ++ else if (is_gimple_assign (use_stmt)) ++ { ++ if (gimple_assign_rhs_class (use_stmt) == GIMPLE_BINARY_RHS) ++ { ++ cmp = gimple_assign_rhs_code (use_stmt); ++ lhs = gimple_assign_rhs1 (use_stmt); ++ rhs = gimple_assign_rhs2 (use_stmt); ++ } ++ else if (gimple_assign_rhs_code (use_stmt) == COND_EXPR) ++ { ++ tree cond = gimple_assign_rhs1 (use_stmt); ++ if (!COMPARISON_CLASS_P (cond)) ++ return false; ++ cmp = TREE_CODE (cond); ++ lhs = TREE_OPERAND (cond, 0); ++ rhs = TREE_OPERAND (cond, 1); ++ } ++ else ++ return false; ++ } ++ else ++ return false; ++ switch (cmp) ++ { ++ case EQ_EXPR: ++ case NE_EXPR: ++ case LT_EXPR: ++ case GT_EXPR: ++ case LE_EXPR: ++ case GE_EXPR: ++ break; ++ default: ++ return false; ++ } ++ if (lhs != PHI_RESULT (phi) ++ || !tree_fits_shwi_p (rhs) ++ || !IN_RANGE (tree_to_shwi (rhs), -1, 1)) ++ return false; ++ ++ if (!empty_block_p (middle_bb)) ++ return false; ++ ++ gcond *cond1 = as_a <gcond *> (last_stmt (cond_bb)); ++ enum tree_code cmp1 = gimple_cond_code (cond1); ++ if (cmp1 != LT_EXPR && cmp1 != GT_EXPR) ++ return false; ++ tree lhs1 = gimple_cond_lhs (cond1); ++ tree rhs1 = gimple_cond_rhs (cond1); ++ /* The optimization may be unsafe due to NaNs. */ ++ if (HONOR_NANS (TREE_TYPE (lhs1))) ++ return false; ++ if (TREE_CODE (lhs1) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs1)) ++ return false; ++ if (TREE_CODE (rhs1) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs1)) ++ return false; ++ ++ if (!single_pred_p (cond_bb) || !cond_only_block_p (cond_bb)) ++ return false; ++ ++ basic_block cond2_bb = single_pred (cond_bb); ++ if (EDGE_COUNT (cond2_bb->succs) != 2) ++ return false; ++ edge cond2_phi_edge; ++ if (EDGE_SUCC (cond2_bb, 0)->dest == cond_bb) ++ { ++ if (EDGE_SUCC (cond2_bb, 1)->dest != phi_bb) ++ return false; ++ cond2_phi_edge = EDGE_SUCC (cond2_bb, 1); ++ } ++ else if (EDGE_SUCC (cond2_bb, 0)->dest != phi_bb) ++ return false; ++ else ++ cond2_phi_edge = EDGE_SUCC (cond2_bb, 0); ++ tree arg2 = gimple_phi_arg_def (phi, cond2_phi_edge->dest_idx); ++ if (!tree_fits_shwi_p (arg2)) ++ return false; ++ gimple *cond2 = last_stmt (cond2_bb); ++ if (cond2 == NULL || gimple_code (cond2) != GIMPLE_COND) ++ return false; ++ enum tree_code cmp2 = gimple_cond_code (cond2); ++ tree lhs2 = gimple_cond_lhs (cond2); ++ tree rhs2 = gimple_cond_rhs (cond2); ++ if (lhs2 == lhs1) ++ { ++ if (!operand_equal_p (rhs2, rhs1, 0)) ++ return false; ++ } ++ else if (lhs2 == rhs1) ++ { ++ if (rhs2 != lhs1) ++ return false; ++ } ++ else ++ return false; ++ ++ tree arg3 = arg2; ++ basic_block cond3_bb = cond2_bb; ++ edge cond3_phi_edge = cond2_phi_edge; ++ gimple *cond3 = cond2; ++ enum tree_code cmp3 = cmp2; ++ tree lhs3 = lhs2; ++ tree rhs3 = rhs2; ++ if (EDGE_COUNT (phi_bb->preds) == 4) ++ { ++ if (absu_hwi (tree_to_shwi (arg2)) != 1) ++ return false; ++ if (e1->flags & EDGE_TRUE_VALUE) ++ { ++ if (tree_to_shwi (arg0) != 2 ++ || absu_hwi (tree_to_shwi (arg1)) != 1 ++ || wi::to_widest (arg1) == wi::to_widest (arg2)) ++ return false; ++ } ++ else if (tree_to_shwi (arg1) != 2 ++ || absu_hwi (tree_to_shwi (arg0)) != 1 ++ || wi::to_widest (arg0) == wi::to_widest (arg1)) ++ return false; ++ if (cmp2 != LT_EXPR && cmp2 != GT_EXPR) ++ return false; ++ /* if (x < y) goto phi_bb; else fallthru; ++ if (x > y) goto phi_bb; else fallthru; ++ bbx:; ++ phi_bb:; ++ is ok, but if x and y are swapped in one of the comparisons, ++ or the comparisons are the same and operands not swapped, ++ or second goto phi_bb is not the true edge, it is not. */ ++ if ((lhs2 == lhs1) ++ ^ (cmp2 == cmp1) ++ ^ ((e1->flags & EDGE_TRUE_VALUE) != 0)) ++ return false; ++ if ((cond2_phi_edge->flags & EDGE_TRUE_VALUE) == 0) ++ return false; ++ if (!single_pred_p (cond2_bb) || !cond_only_block_p (cond2_bb)) ++ return false; ++ cond3_bb = single_pred (cond2_bb); ++ if (EDGE_COUNT (cond2_bb->succs) != 2) ++ return false; ++ if (EDGE_SUCC (cond3_bb, 0)->dest == cond2_bb) ++ { ++ if (EDGE_SUCC (cond3_bb, 1)->dest != phi_bb) ++ return false; ++ cond3_phi_edge = EDGE_SUCC (cond3_bb, 1); ++ } ++ else if (EDGE_SUCC (cond3_bb, 0)->dest != phi_bb) ++ return false; ++ else ++ cond3_phi_edge = EDGE_SUCC (cond3_bb, 0); ++ arg3 = gimple_phi_arg_def (phi, cond3_phi_edge->dest_idx); ++ cond3 = last_stmt (cond3_bb); ++ if (cond3 == NULL || gimple_code (cond3) != GIMPLE_COND) ++ return false; ++ cmp3 = gimple_cond_code (cond3); ++ lhs3 = gimple_cond_lhs (cond3); ++ rhs3 = gimple_cond_rhs (cond3); ++ if (lhs3 == lhs1) ++ { ++ if (!operand_equal_p (rhs3, rhs1, 0)) ++ return false; ++ } ++ else if (lhs3 == rhs1) ++ { ++ if (rhs3 != lhs1) ++ return false; ++ } ++ else ++ return false; ++ } ++ else if (absu_hwi (tree_to_shwi (arg0)) != 1 ++ || absu_hwi (tree_to_shwi (arg1)) != 1 ++ || wi::to_widest (arg0) == wi::to_widest (arg1)) ++ return false; ++ ++ if (!integer_zerop (arg3) || (cmp3 != EQ_EXPR && cmp3 != NE_EXPR)) ++ return false; ++ if ((cond3_phi_edge->flags & (cmp3 == EQ_EXPR ++ ? EDGE_TRUE_VALUE : EDGE_FALSE_VALUE)) == 0) ++ return false; ++ ++ /* lhs1 one_cmp rhs1 results in PHI_RESULT (phi) of 1. */ ++ enum tree_code one_cmp; ++ if ((cmp1 == LT_EXPR) ++ ^ (!integer_onep ((e1->flags & EDGE_TRUE_VALUE) ? arg1 : arg0))) ++ one_cmp = LT_EXPR; ++ else ++ one_cmp = GT_EXPR; ++ ++ enum tree_code res_cmp; ++ switch (cmp) ++ { ++ case EQ_EXPR: ++ if (integer_zerop (rhs)) ++ res_cmp = EQ_EXPR; ++ else if (integer_minus_onep (rhs)) ++ res_cmp = one_cmp == LT_EXPR ? GT_EXPR : LT_EXPR; ++ else if (integer_onep (rhs)) ++ res_cmp = one_cmp; ++ else ++ return false; ++ break; ++ case NE_EXPR: ++ if (integer_zerop (rhs)) ++ res_cmp = NE_EXPR; ++ else if (integer_minus_onep (rhs)) ++ res_cmp = one_cmp == LT_EXPR ? LE_EXPR : GE_EXPR; ++ else if (integer_onep (rhs)) ++ res_cmp = one_cmp == LT_EXPR ? GE_EXPR : LE_EXPR; ++ else ++ return false; ++ break; ++ case LT_EXPR: ++ if (integer_onep (rhs)) ++ res_cmp = one_cmp == LT_EXPR ? GE_EXPR : LE_EXPR; ++ else if (integer_zerop (rhs)) ++ res_cmp = one_cmp == LT_EXPR ? GT_EXPR : LT_EXPR; ++ else ++ return false; ++ break; ++ case LE_EXPR: ++ if (integer_zerop (rhs)) ++ res_cmp = one_cmp == LT_EXPR ? GE_EXPR : LE_EXPR; ++ else if (integer_minus_onep (rhs)) ++ res_cmp = one_cmp == LT_EXPR ? GT_EXPR : LT_EXPR; ++ else ++ return false; ++ break; ++ case GT_EXPR: ++ if (integer_minus_onep (rhs)) ++ res_cmp = one_cmp == LT_EXPR ? LE_EXPR : GE_EXPR; ++ else if (integer_zerop (rhs)) ++ res_cmp = one_cmp; ++ else ++ return false; ++ break; ++ case GE_EXPR: ++ if (integer_zerop (rhs)) ++ res_cmp = one_cmp == LT_EXPR ? LE_EXPR : GE_EXPR; ++ else if (integer_onep (rhs)) ++ res_cmp = one_cmp; ++ else ++ return false; ++ break; ++ default: ++ gcc_unreachable (); ++ } ++ ++ if (gimple_code (use_stmt) == GIMPLE_COND) ++ { ++ gcond *use_cond = as_a <gcond *> (use_stmt); ++ gimple_cond_set_code (use_cond, res_cmp); ++ gimple_cond_set_lhs (use_cond, lhs1); ++ gimple_cond_set_rhs (use_cond, rhs1); ++ } ++ else if (gimple_assign_rhs_class (use_stmt) == GIMPLE_BINARY_RHS) ++ { ++ gimple_assign_set_rhs_code (use_stmt, res_cmp); ++ gimple_assign_set_rhs1 (use_stmt, lhs1); ++ gimple_assign_set_rhs2 (use_stmt, rhs1); ++ } ++ else ++ { ++ tree cond = build2 (res_cmp, TREE_TYPE (gimple_assign_rhs1 (use_stmt)), ++ lhs1, rhs1); ++ gimple_assign_set_rhs1 (use_stmt, cond); ++ } ++ update_stmt (use_stmt); ++ ++ if (MAY_HAVE_DEBUG_BIND_STMTS) ++ { ++ use_operand_p use_p; ++ imm_use_iterator iter; ++ bool has_debug_uses = false; ++ FOR_EACH_IMM_USE_FAST (use_p, iter, PHI_RESULT (phi)) ++ { ++ gimple *use_stmt = USE_STMT (use_p); ++ gcc_assert (is_gimple_debug (use_stmt)); ++ has_debug_uses = true; ++ break; ++ } ++ ++ if (has_debug_uses) ++ { ++ /* If there are debug uses, emit something like: ++ # DEBUG D#1 => i_2(D) > j_3(D) ? 1 : -1 ++ # DEBUG D#2 => i_2(D) == j_3(D) ? 0 : D#1 ++ where > stands for the comparison that yielded 1 ++ and replace debug uses of phi result with that D#2. ++ Ignore the value of 2, because if NaNs aren't expected, ++ all floating point numbers should be comparable. */ ++ gimple_stmt_iterator gsi = gsi_after_labels (gimple_bb (phi)); ++ tree type = TREE_TYPE (PHI_RESULT (phi)); ++ tree temp1 = make_node (DEBUG_EXPR_DECL); ++ DECL_ARTIFICIAL (temp1) = 1; ++ TREE_TYPE (temp1) = type; ++ SET_DECL_MODE (temp1, TYPE_MODE (type)); ++ tree t = build2 (one_cmp, boolean_type_node, lhs1, rhs2); ++ t = build3 (COND_EXPR, type, t, build_one_cst (type), ++ build_int_cst (type, -1)); ++ gimple *g = gimple_build_debug_bind (temp1, t, phi); ++ gsi_insert_before (&gsi, g, GSI_SAME_STMT); ++ tree temp2 = make_node (DEBUG_EXPR_DECL); ++ DECL_ARTIFICIAL (temp2) = 1; ++ TREE_TYPE (temp2) = type; ++ SET_DECL_MODE (temp2, TYPE_MODE (type)); ++ t = build2 (EQ_EXPR, boolean_type_node, lhs1, rhs2); ++ t = build3 (COND_EXPR, type, t, build_zero_cst (type), temp1); ++ g = gimple_build_debug_bind (temp2, t, phi); ++ gsi_insert_before (&gsi, g, GSI_SAME_STMT); ++ replace_uses_by (PHI_RESULT (phi), temp2); ++ } ++ } ++ ++ gimple_stmt_iterator psi = gsi_for_stmt (phi); ++ remove_phi_node (&psi, true); ++ ++ return true; ++} ++ + /* Convert + + <bb 2> +-- +2.27.0.windows.1 + diff --git a/0057-Backport-Add-support-for-__builtin_bswap128.patch b/0057-Backport-Add-support-for-__builtin_bswap128.patch new file mode 100644 index 0000000..5f00306 --- /dev/null +++ b/0057-Backport-Add-support-for-__builtin_bswap128.patch @@ -0,0 +1,253 @@ +From 96afd5b761a74e9eef40a2e843810c503c669de8 Mon Sep 17 00:00:00 2001 +From: Eric Botcazou <ebotcazou@gcc.gnu.org> +Date: Thu, 28 May 2020 00:31:15 +0200 +Subject: [PATCH 09/35] [Backport] Add support for __builtin_bswap128 + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=fe7ebef7fe4f9acb79658ed9db0749b07efc3105 + +This patch introduces a new builtin named __builtin_bswap128 on targets +where TImode is supported, i.e. 64-bit targets only in practice. The +implementation simply reuses the existing double word path in optab, so +no routine is added to libgcc (which means that you get two calls to +_bswapdi2 in the worst case). + +gcc/ChangeLog: + + * builtin-types.def (BT_UINT128): New primitive type. + (BT_FN_UINT128_UINT128): New function type. + * builtins.def (BUILT_IN_BSWAP128): New GCC builtin. + * doc/extend.texi (__builtin_bswap128): Document it. + * builtins.c (expand_builtin): Deal with BUILT_IN_BSWAP128. + (is_inexpensive_builtin): Likewise. + * fold-const-call.c (fold_const_call_ss): Likewise. + * fold-const.c (tree_call_nonnegative_warnv_p): Likewise. + * tree-ssa-ccp.c (evaluate_stmt): Likewise. + * tree-vect-stmts.c (vect_get_data_ptr_increment): Likewise. + (vectorizable_call): Likewise. + * optabs.c (expand_unop): Always use the double word path for it. + * tree-core.h (enum tree_index): Add TI_UINT128_TYPE. + * tree.h (uint128_type_node): New global type. + * tree.c (build_common_tree_nodes): Build it if TImode is supported. + +gcc/testsuite/ChangeLog: + + * gcc.dg/builtin-bswap-10.c: New test. + * gcc.dg/builtin-bswap-11.c: Likewise. + * gcc.dg/builtin-bswap-12.c: Likewise. + * gcc.target/i386/builtin-bswap-5.c: Likewise. +--- + gcc/builtin-types.def | 4 ++++ + gcc/builtins.c | 2 ++ + gcc/builtins.def | 2 ++ + gcc/doc/extend.texi | 10 ++++++++-- + gcc/fold-const-call.c | 1 + + gcc/fold-const.c | 2 ++ + gcc/optabs.c | 5 ++++- + gcc/tree-core.h | 1 + + gcc/tree-ssa-ccp.c | 1 + + gcc/tree-vect-stmts.c | 5 +++-- + gcc/tree.c | 2 ++ + gcc/tree.h | 1 + + 12 files changed, 31 insertions(+), 5 deletions(-) + +diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def +index c7aa691b2..c46b1bc5c 100644 +--- a/gcc/builtin-types.def ++++ b/gcc/builtin-types.def +@@ -73,6 +73,9 @@ DEF_PRIMITIVE_TYPE (BT_UINT8, unsigned_char_type_node) + DEF_PRIMITIVE_TYPE (BT_UINT16, uint16_type_node) + DEF_PRIMITIVE_TYPE (BT_UINT32, uint32_type_node) + DEF_PRIMITIVE_TYPE (BT_UINT64, uint64_type_node) ++DEF_PRIMITIVE_TYPE (BT_UINT128, uint128_type_node ++ ? uint128_type_node ++ : error_mark_node) + DEF_PRIMITIVE_TYPE (BT_WORD, (*lang_hooks.types.type_for_mode) (word_mode, 1)) + DEF_PRIMITIVE_TYPE (BT_UNWINDWORD, (*lang_hooks.types.type_for_mode) + (targetm.unwind_word_mode (), 1)) +@@ -300,6 +303,7 @@ DEF_FUNCTION_TYPE_1 (BT_FN_UINT8_FLOAT, BT_UINT8, BT_FLOAT) + DEF_FUNCTION_TYPE_1 (BT_FN_UINT16_UINT16, BT_UINT16, BT_UINT16) + DEF_FUNCTION_TYPE_1 (BT_FN_UINT32_UINT32, BT_UINT32, BT_UINT32) + DEF_FUNCTION_TYPE_1 (BT_FN_UINT64_UINT64, BT_UINT64, BT_UINT64) ++DEF_FUNCTION_TYPE_1 (BT_FN_UINT128_UINT128, BT_UINT128, BT_UINT128) + DEF_FUNCTION_TYPE_1 (BT_FN_UINT64_FLOAT, BT_UINT64, BT_FLOAT) + DEF_FUNCTION_TYPE_1 (BT_FN_BOOL_INT, BT_BOOL, BT_INT) + DEF_FUNCTION_TYPE_1 (BT_FN_BOOL_PTR, BT_BOOL, BT_PTR) +diff --git a/gcc/builtins.c b/gcc/builtins.c +index 10b6fd3bb..1b1c75cc1 100644 +--- a/gcc/builtins.c ++++ b/gcc/builtins.c +@@ -8015,6 +8015,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, + case BUILT_IN_BSWAP16: + case BUILT_IN_BSWAP32: + case BUILT_IN_BSWAP64: ++ case BUILT_IN_BSWAP128: + target = expand_builtin_bswap (target_mode, exp, target, subtarget); + if (target) + return target; +@@ -11732,6 +11733,7 @@ is_inexpensive_builtin (tree decl) + case BUILT_IN_BSWAP16: + case BUILT_IN_BSWAP32: + case BUILT_IN_BSWAP64: ++ case BUILT_IN_BSWAP128: + case BUILT_IN_CLZ: + case BUILT_IN_CLZIMAX: + case BUILT_IN_CLZL: +diff --git a/gcc/builtins.def b/gcc/builtins.def +index fa8b0641a..ee67ac15d 100644 +--- a/gcc/builtins.def ++++ b/gcc/builtins.def +@@ -834,6 +834,8 @@ DEF_GCC_BUILTIN (BUILT_IN_APPLY_ARGS, "apply_args", BT_FN_PTR_VAR, ATTR_L + DEF_GCC_BUILTIN (BUILT_IN_BSWAP16, "bswap16", BT_FN_UINT16_UINT16, ATTR_CONST_NOTHROW_LEAF_LIST) + DEF_GCC_BUILTIN (BUILT_IN_BSWAP32, "bswap32", BT_FN_UINT32_UINT32, ATTR_CONST_NOTHROW_LEAF_LIST) + DEF_GCC_BUILTIN (BUILT_IN_BSWAP64, "bswap64", BT_FN_UINT64_UINT64, ATTR_CONST_NOTHROW_LEAF_LIST) ++DEF_GCC_BUILTIN (BUILT_IN_BSWAP128, "bswap128", BT_FN_UINT128_UINT128, ATTR_CONST_NOTHROW_LEAF_LIST) ++ + DEF_EXT_LIB_BUILTIN (BUILT_IN_CLEAR_CACHE, "__clear_cache", BT_FN_VOID_PTR_PTR, ATTR_NOTHROW_LEAF_LIST) + /* [trans-mem]: Adjust BUILT_IN_TM_CALLOC if BUILT_IN_CALLOC is changed. */ + DEF_LIB_BUILTIN (BUILT_IN_CALLOC, "calloc", BT_FN_PTR_SIZE_SIZE, ATTR_MALLOC_WARN_UNUSED_RESULT_SIZE_1_2_NOTHROW_LEAF_LIST) +diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi +index 9c7345959..a7bd772de 100644 +--- a/gcc/doc/extend.texi ++++ b/gcc/doc/extend.texi +@@ -13727,14 +13727,20 @@ exactly 8 bits. + + @deftypefn {Built-in Function} uint32_t __builtin_bswap32 (uint32_t x) + Similar to @code{__builtin_bswap16}, except the argument and return types +-are 32 bit. ++are 32-bit. + @end deftypefn + + @deftypefn {Built-in Function} uint64_t __builtin_bswap64 (uint64_t x) + Similar to @code{__builtin_bswap32}, except the argument and return types +-are 64 bit. ++are 64-bit. + @end deftypefn + ++@deftypefn {Built-in Function} uint128_t __builtin_bswap128 (uint128_t x) ++Similar to @code{__builtin_bswap64}, except the argument and return types ++are 128-bit. Only supported on targets when 128-bit types are supported. ++@end deftypefn ++ ++ + @deftypefn {Built-in Function} Pmode __builtin_extend_pointer (void * x) + On targets where the user visible pointer size is smaller than the size + of an actual hardware address this function returns the extended user +diff --git a/gcc/fold-const-call.c b/gcc/fold-const-call.c +index 6150d7ada..da01759d9 100644 +--- a/gcc/fold-const-call.c ++++ b/gcc/fold-const-call.c +@@ -1032,6 +1032,7 @@ fold_const_call_ss (wide_int *result, combined_fn fn, const wide_int_ref &arg, + case CFN_BUILT_IN_BSWAP16: + case CFN_BUILT_IN_BSWAP32: + case CFN_BUILT_IN_BSWAP64: ++ case CFN_BUILT_IN_BSWAP128: + *result = wide_int::from (arg, precision, TYPE_SIGN (arg_type)).bswap (); + return true; + +diff --git a/gcc/fold-const.c b/gcc/fold-const.c +index 6e635382f..78227a83d 100644 +--- a/gcc/fold-const.c ++++ b/gcc/fold-const.c +@@ -13889,8 +13889,10 @@ tree_call_nonnegative_warnv_p (tree type, combined_fn fn, tree arg0, tree arg1, + CASE_CFN_POPCOUNT: + CASE_CFN_CLZ: + CASE_CFN_CLRSB: ++ case CFN_BUILT_IN_BSWAP16: + case CFN_BUILT_IN_BSWAP32: + case CFN_BUILT_IN_BSWAP64: ++ case CFN_BUILT_IN_BSWAP128: + /* Always true. */ + return true; + +diff --git a/gcc/optabs.c b/gcc/optabs.c +index 049a18ceb..c3751fdf7 100644 +--- a/gcc/optabs.c ++++ b/gcc/optabs.c +@@ -2896,8 +2896,11 @@ expand_unop (machine_mode mode, optab unoptab, rtx op0, rtx target, + if (temp) + return temp; + ++ /* We do not provide a 128-bit bswap in libgcc so force the use of ++ a double bswap for 64-bit targets. */ + if (GET_MODE_SIZE (int_mode) == 2 * UNITS_PER_WORD +- && optab_handler (unoptab, word_mode) != CODE_FOR_nothing) ++ && (UNITS_PER_WORD == 64 ++ || optab_handler (unoptab, word_mode) != CODE_FOR_nothing)) + { + temp = expand_doubleword_bswap (mode, op0, target); + if (temp) +diff --git a/gcc/tree-core.h b/gcc/tree-core.h +index eb01c2434..058e046aa 100644 +--- a/gcc/tree-core.h ++++ b/gcc/tree-core.h +@@ -600,6 +600,7 @@ enum tree_index { + TI_UINT16_TYPE, + TI_UINT32_TYPE, + TI_UINT64_TYPE, ++ TI_UINT128_TYPE, + + TI_VOID, + +diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c +index 952fd9cd4..dcdf10369 100644 +--- a/gcc/tree-ssa-ccp.c ++++ b/gcc/tree-ssa-ccp.c +@@ -2005,6 +2005,7 @@ evaluate_stmt (gimple *stmt) + case BUILT_IN_BSWAP16: + case BUILT_IN_BSWAP32: + case BUILT_IN_BSWAP64: ++ case BUILT_IN_BSWAP128: + val = get_value_for_expr (gimple_call_arg (stmt, 0), true); + if (val.lattice_val == UNDEFINED) + break; +diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c +index b872cfc8d..4636b7ba2 100644 +--- a/gcc/tree-vect-stmts.c ++++ b/gcc/tree-vect-stmts.c +@@ -3085,7 +3085,7 @@ vect_get_data_ptr_increment (dr_vec_info *dr_info, tree aggr_type, + return iv_step; + } + +-/* Check and perform vectorization of BUILT_IN_BSWAP{16,32,64}. */ ++/* Check and perform vectorization of BUILT_IN_BSWAP{16,32,64,128}. */ + + static bool + vectorizable_bswap (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, +@@ -3454,7 +3454,8 @@ vectorizable_call (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, + else if (modifier == NONE + && (gimple_call_builtin_p (stmt, BUILT_IN_BSWAP16) + || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP32) +- || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP64))) ++ || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP64) ++ || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP128))) + return vectorizable_bswap (stmt_info, gsi, vec_stmt, slp_node, + vectype_in, cost_vec); + else +diff --git a/gcc/tree.c b/gcc/tree.c +index 84a440b35..3e6647ae0 100644 +--- a/gcc/tree.c ++++ b/gcc/tree.c +@@ -10394,6 +10394,8 @@ build_common_tree_nodes (bool signed_char) + uint16_type_node = make_or_reuse_type (16, 1); + uint32_type_node = make_or_reuse_type (32, 1); + uint64_type_node = make_or_reuse_type (64, 1); ++ if (targetm.scalar_mode_supported_p (TImode)) ++ uint128_type_node = make_or_reuse_type (128, 1); + + /* Decimal float types. */ + if (targetm.decimal_float_supported_p ()) +diff --git a/gcc/tree.h b/gcc/tree.h +index 328a2d5d2..bddc6e528 100644 +--- a/gcc/tree.h ++++ b/gcc/tree.h +@@ -4035,6 +4035,7 @@ tree_strip_any_location_wrapper (tree exp) + #define uint16_type_node global_trees[TI_UINT16_TYPE] + #define uint32_type_node global_trees[TI_UINT32_TYPE] + #define uint64_type_node global_trees[TI_UINT64_TYPE] ++#define uint128_type_node global_trees[TI_UINT128_TYPE] + + #define void_node global_trees[TI_VOID] + +-- +2.27.0.windows.1 + diff --git a/0058-Backport-tree-optimization-95393-fold-MIN-MAX_EXPR-g.patch b/0058-Backport-tree-optimization-95393-fold-MIN-MAX_EXPR-g.patch new file mode 100644 index 0000000..0edbcb0 --- /dev/null +++ b/0058-Backport-tree-optimization-95393-fold-MIN-MAX_EXPR-g.patch @@ -0,0 +1,113 @@ +From b9ac0cc69aab3c8d662d5b0a9ed43d971c13ac70 Mon Sep 17 00:00:00 2001 +From: Richard Biener <rguenther@suse.de> +Date: Fri, 29 May 2020 09:25:53 +0200 +Subject: [PATCH 10/35] [Backport] tree-optimization/95393 - fold MIN/MAX_EXPR + generated by phiopt + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=07852a81f58532c63a57631d7c3757fc6bcea17d + +This makes sure to fold generated stmts so they do not survive +until RTL expansion and cause awkward code generation. + +2020-05-29 Richard Biener <rguenther@suse.de> + + PR tree-optimization/95393 + * tree-ssa-phiopt.c (minmax_replacement): Use gimple_build + to build the min/max expression so we simplify cases like + MAX(0, s) immediately. + + * gcc.dg/tree-ssa/phi-opt-21.c: New testcase. + * g++.dg/vect/slp-pr87105.cc: Adjust. +--- + gcc/testsuite/g++.dg/vect/slp-pr87105.cc | 2 +- + gcc/testsuite/gcc.dg/tree-ssa/phi-opt-21.c | 15 +++++++++++++ + gcc/tree-ssa-phiopt.c | 25 +++++++++++----------- + 3 files changed, 29 insertions(+), 13 deletions(-) + create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/phi-opt-21.c + +diff --git a/gcc/testsuite/g++.dg/vect/slp-pr87105.cc b/gcc/testsuite/g++.dg/vect/slp-pr87105.cc +index 5518f319b..d07b1cd46 100644 +--- a/gcc/testsuite/g++.dg/vect/slp-pr87105.cc ++++ b/gcc/testsuite/g++.dg/vect/slp-pr87105.cc +@@ -102,4 +102,4 @@ void quadBoundingBoxA(const Point bez[3], Box& bBox) noexcept { + // { dg-final { scan-tree-dump-times "basic block part vectorized" 1 "slp2" { xfail { { ! vect_element_align } && { ! vect_hw_misalign } } } } } + // It's a bit awkward to detect that all stores were vectorized but the + // following more or less does the trick +-// { dg-final { scan-tree-dump "vect_iftmp\[^\r\m\]* = MIN" "slp2" { xfail { { ! vect_element_align } && { ! vect_hw_misalign } } } } } ++// { dg-final { scan-tree-dump "vect_\[^\r\m\]* = MIN" "slp2" { xfail { { ! vect_element_align } && { ! vect_hw_misalign } } } } } +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-21.c b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-21.c +new file mode 100644 +index 000000000..9f3d56957 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-21.c +@@ -0,0 +1,15 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -fdump-tree-phiopt4-details" } */ ++ ++int f(unsigned s) ++{ ++ int i; ++ for (i = 0; i < s; ++i) ++ ; ++ ++ return i; ++} ++ ++/* { dg-final { scan-tree-dump "converted to straightline code" "phiopt4" } } */ ++/* Make sure we fold the detected MAX<s, 0>. */ ++/* { dg-final { scan-tree-dump-not "MAX" "phiopt4" } } */ +diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c +index fca32222f..269eda21c 100644 +--- a/gcc/tree-ssa-phiopt.c ++++ b/gcc/tree-ssa-phiopt.c +@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see + #include "tree-inline.h" + #include "case-cfn-macros.h" + #include "tree-eh.h" ++#include "gimple-fold.h" + #include "internal-fn.h" + + static unsigned int tree_ssa_phiopt_worker (bool, bool, bool); +@@ -1414,7 +1415,6 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb, + { + tree result, type, rhs; + gcond *cond; +- gassign *new_stmt; + edge true_edge, false_edge; + enum tree_code cmp, minmax, ass_code; + tree smaller, alt_smaller, larger, alt_larger, arg_true, arg_false; +@@ -1738,19 +1738,20 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb, + gsi_move_before (&gsi_from, &gsi); + } + +- /* Create an SSA var to hold the min/max result. If we're the only +- things setting the target PHI, then we can clone the PHI +- variable. Otherwise we must create a new one. */ +- result = PHI_RESULT (phi); +- if (EDGE_COUNT (gimple_bb (phi)->preds) == 2) +- result = duplicate_ssa_name (result, NULL); +- else +- result = make_ssa_name (TREE_TYPE (result)); +- + /* Emit the statement to compute min/max. */ +- new_stmt = gimple_build_assign (result, minmax, arg0, arg1); ++ gimple_seq stmts = NULL; ++ tree phi_result = PHI_RESULT (phi); ++ result = gimple_build (&stmts, minmax, TREE_TYPE (phi_result), arg0, arg1); ++ /* Duplicate range info if we're the only things setting the target PHI. */ ++ if (!gimple_seq_empty_p (stmts) ++ && EDGE_COUNT (gimple_bb (phi)->preds) == 2 ++ && !POINTER_TYPE_P (TREE_TYPE (phi_result)) ++ && SSA_NAME_RANGE_INFO (phi_result)) ++ duplicate_ssa_name_range_info (result, SSA_NAME_RANGE_TYPE (phi_result), ++ SSA_NAME_RANGE_INFO (phi_result)); ++ + gsi = gsi_last_bb (cond_bb); +- gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT); ++ gsi_insert_seq_before (&gsi, stmts, GSI_NEW_STMT); + + replace_phi_edge_with_variable (cond_bb, e1, phi, result); + +-- +2.27.0.windows.1 + diff --git a/0059-Backport-Add-a-couple-of-A-CST1-CST2-match-and-simpl.patch b/0059-Backport-Add-a-couple-of-A-CST1-CST2-match-and-simpl.patch new file mode 100644 index 0000000..a16b336 --- /dev/null +++ b/0059-Backport-Add-a-couple-of-A-CST1-CST2-match-and-simpl.patch @@ -0,0 +1,91 @@ +From 9f3a8c600abe16f172b36d8113862e8f7aea940c Mon Sep 17 00:00:00 2001 +From: Andrew Pinski <apinski@marvell.com> +Date: Sun, 16 May 2021 13:07:06 -0700 +Subject: [PATCH 11/35] [Backport] Add a couple of A?CST1:CST2 match and + simplify optimizations + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=b6bdd7a4cb41ee057f2d064fffcb00f23ce6b497 + +Instead of some of the more manual optimizations inside phi-opt, +it would be good idea to do a lot of the heavy lifting inside match +and simplify instead. In the process, this moves the three simple +A?CST1:CST2 (where CST1 or CST2 is zero) simplifications. + +OK? Boostrapped and tested on x86_64-linux-gnu with no regressions. + +Differences from V1: +* Use bit_xor 1 instead of bit_not to fix the problem with boolean types +which are not 1 bit precision. + +Thanks, +Andrew Pinski + +gcc: + * match.pd (A?CST1:CST2): Add simplifcations for A?0:+-1, A?+-1:0, + A?POW2:0 and A?0:POW2. +--- + gcc/match.pd | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 48 insertions(+) + +diff --git a/gcc/match.pd b/gcc/match.pd +index 660d5c268..032830b0d 100644 +--- a/gcc/match.pd ++++ b/gcc/match.pd +@@ -3334,6 +3334,54 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) + (if (cst1 && cst2) + (vec_cond @0 { cst1; } { cst2; }))))) + ++/* A few simplifications of "a ? CST1 : CST2". */ ++/* NOTE: Only do this on gimple as the if-chain-to-switch ++ optimization depends on the gimple to have if statements in it. */ ++#if GIMPLE ++(simplify ++ (cond @0 INTEGER_CST@1 INTEGER_CST@2) ++ (switch ++ (if (integer_zerop (@2)) ++ (switch ++ /* a ? 1 : 0 -> a if 0 and 1 are integral types. */ ++ (if (integer_onep (@1)) ++ (convert (convert:boolean_type_node @0))) ++ /* a ? powerof2cst : 0 -> a << (log2(powerof2cst)) */ ++ (if (INTEGRAL_TYPE_P (type) && integer_pow2p (@1)) ++ (with { ++ tree shift = build_int_cst (integer_type_node, tree_log2 (@1)); ++ } ++ (lshift (convert (convert:boolean_type_node @0)) { shift; }))) ++ /* a ? -1 : 0 -> -a. No need to check the TYPE_PRECISION not being 1 ++ here as the powerof2cst case above will handle that case correctly. */ ++ (if (INTEGRAL_TYPE_P (type) && integer_all_onesp (@1)) ++ (negate (convert (convert:boolean_type_node @0)))))) ++ (if (integer_zerop (@1)) ++ (with { ++ tree booltrue = constant_boolean_node (true, boolean_type_node); ++ } ++ (switch ++ /* a ? 0 : 1 -> !a. */ ++ (if (integer_onep (@2)) ++ (convert (bit_xor (convert:boolean_type_node @0) { booltrue; } ))) ++ /* a ? powerof2cst : 0 -> (!a) << (log2(powerof2cst)) */ ++ (if (INTEGRAL_TYPE_P (type) && integer_pow2p (@2)) ++ (with { ++ tree shift = build_int_cst (integer_type_node, tree_log2 (@2)); ++ } ++ (lshift (convert (bit_xor (convert:boolean_type_node @0) { booltrue; } )) ++ { shift; }))) ++ /* a ? -1 : 0 -> -(!a). No need to check the TYPE_PRECISION not being 1 ++ here as the powerof2cst case above will handle that case correctly. */ ++ (if (INTEGRAL_TYPE_P (type) && integer_all_onesp (@2)) ++ (negate (convert (bit_xor (convert:boolean_type_node @0) { booltrue; } )))) ++ ) ++ ) ++ ) ++ ) ++) ++#endif ++ + /* Simplification moved from fold_cond_expr_with_comparison. It may also + be extended. */ + /* This pattern implements two kinds simplification: +-- +2.27.0.windows.1 + diff --git a/0060-Backport-Optimize-x-0-y-y-to-x-31-y-in-match.pd.patch b/0060-Backport-Optimize-x-0-y-y-to-x-31-y-in-match.pd.patch new file mode 100644 index 0000000..80d602a --- /dev/null +++ b/0060-Backport-Optimize-x-0-y-y-to-x-31-y-in-match.pd.patch @@ -0,0 +1,155 @@ +From 4352b952ba24c413697fcfc191d06165a8a31ced Mon Sep 17 00:00:00 2001 +From: Andrew Pinski <apinski@marvell.com> +Date: Sat, 22 May 2021 19:49:50 +0000 +Subject: [PATCH 12/35] [Backport] Optimize x < 0 ? ~y : y to (x >> 31) ^ y in + match.pd + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=1fd76b24306ed4df4cf9e797d900699ed59ce7f7 + +This copies the optimization that is done in phiopt for +"x < 0 ? ~y : y to (x >> 31) ^ y" into match.pd. The code +for phiopt is kept around until phiopt uses match.pd (which +I am working towards). + +Note the original testcase is now optimized early on and I added a +new testcase to optimize during phiopt. + +OK? Bootstrapped and tested on x86_64-linux-gnu with no regressions. + +Thanks, +Andrew Pinski + +Differences from v1: +V2: Add check for integeral type to make sure vector types are not done. + +gcc: + * match.pd (x < 0 ? ~y : y): New patterns. + +gcc/testsuite: + * gcc.dg/tree-ssa/pr96928.c: Update test for slightly different IR. + * gcc.dg/tree-ssa/pr96928-1.c: New testcase. +--- + gcc/match.pd | 32 +++++++++++++++ + gcc/testsuite/gcc.dg/tree-ssa/pr96928-1.c | 48 +++++++++++++++++++++++ + gcc/testsuite/gcc.dg/tree-ssa/pr96928.c | 7 +++- + 3 files changed, 85 insertions(+), 2 deletions(-) + create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr96928-1.c + +diff --git a/gcc/match.pd b/gcc/match.pd +index 032830b0d..5899eea95 100644 +--- a/gcc/match.pd ++++ b/gcc/match.pd +@@ -4390,6 +4390,38 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) + (cmp (bit_and@2 @0 integer_pow2p@1) @1) + (icmp @2 { build_zero_cst (TREE_TYPE (@0)); }))) + ++(for cmp (ge lt) ++/* x < 0 ? ~y : y into (x >> (prec-1)) ^ y. */ ++/* x >= 0 ? ~y : y into ~((x >> (prec-1)) ^ y). */ ++ (simplify ++ (cond (cmp @0 integer_zerop) (bit_not @1) @1) ++ (if (INTEGRAL_TYPE_P (type) ++ && INTEGRAL_TYPE_P (TREE_TYPE (@0)) ++ && !TYPE_UNSIGNED (TREE_TYPE (@0)) ++ && TYPE_PRECISION (TREE_TYPE (@0)) == TYPE_PRECISION (type)) ++ (with ++ { ++ tree shifter = build_int_cst (integer_type_node, TYPE_PRECISION (type) - 1); ++ } ++ (if (cmp == LT_EXPR) ++ (bit_xor (convert (rshift @0 {shifter;})) @1) ++ (bit_not (bit_xor (convert (rshift @0 {shifter;})) @1)))))) ++/* x < 0 ? y : ~y into ~((x >> (prec-1)) ^ y). */ ++/* x >= 0 ? y : ~y into (x >> (prec-1)) ^ y. */ ++ (simplify ++ (cond (cmp @0 integer_zerop) @1 (bit_not @1)) ++ (if (INTEGRAL_TYPE_P (type) ++ && INTEGRAL_TYPE_P (TREE_TYPE (@0)) ++ && !TYPE_UNSIGNED (TREE_TYPE (@0)) ++ && TYPE_PRECISION (TREE_TYPE (@0)) == TYPE_PRECISION (type)) ++ (with ++ { ++ tree shifter = build_int_cst (integer_type_node, TYPE_PRECISION (type) - 1); ++ } ++ (if (cmp == GE_EXPR) ++ (bit_xor (convert (rshift @0 {shifter;})) @1) ++ (bit_not (bit_xor (convert (rshift @0 {shifter;})) @1))))))) ++ + /* If we have (A & C) != 0 ? D : 0 where C and D are powers of 2, + convert this into a shift followed by ANDing with D. */ + (simplify +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr96928-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr96928-1.c +new file mode 100644 +index 000000000..a2770e5e8 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/pr96928-1.c +@@ -0,0 +1,48 @@ ++/* PR tree-optimization/96928 */ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -fdump-tree-phiopt2" } */ ++/* { dg-final { scan-tree-dump-times " = a_\[0-9]*\\\(D\\\) >> " 5 "phiopt2" } } */ ++/* { dg-final { scan-tree-dump-times " = ~c_\[0-9]*\\\(D\\\);" 1 "phiopt2" } } */ ++/* { dg-final { scan-tree-dump-times " = ~" 1 "phiopt2" } } */ ++/* { dg-final { scan-tree-dump-times " = \[abc_0-9\\\(\\\)D]* \\\^ " 5 "phiopt2" } } */ ++/* { dg-final { scan-tree-dump-not "a < 0" "phiopt2" } } */ ++ ++int ++foo (int a) ++{ ++ if (a < 0) ++ return ~a; ++ return a; ++} ++ ++int ++bar (int a, int b) ++{ ++ if (a < 0) ++ return ~b; ++ return b; ++} ++ ++unsigned ++baz (int a, unsigned int b) ++{ ++ if (a < 0) ++ return ~b; ++ return b; ++} ++ ++unsigned ++qux (int a, unsigned int c) ++{ ++ if (a >= 0) ++ return ~c; ++ return c; ++} ++ ++int ++corge (int a, int b) ++{ ++ if (a >= 0) ++ return b; ++ return ~b; ++} +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr96928.c b/gcc/testsuite/gcc.dg/tree-ssa/pr96928.c +index 209135726..e8fd82fc2 100644 +--- a/gcc/testsuite/gcc.dg/tree-ssa/pr96928.c ++++ b/gcc/testsuite/gcc.dg/tree-ssa/pr96928.c +@@ -1,8 +1,11 @@ + /* PR tree-optimization/96928 */ + /* { dg-do compile } */ +-/* { dg-options "-O2 -fdump-tree-phiopt2" } */ ++/* { dg-options "-O2 -fdump-tree-phiopt2 -fdump-tree-optimized" } */ + /* { dg-final { scan-tree-dump-times " = a_\[0-9]*\\\(D\\\) >> " 5 "phiopt2" } } */ +-/* { dg-final { scan-tree-dump-times " = ~c_\[0-9]*\\\(D\\\);" 1 "phiopt2" } } */ ++/* The following check is done at optimized because a ^ (~b) is rewritten as ~(a^b) ++ and in the case of match.pd optimizing these ?:, the ~ is moved out already ++ by the time we get to phiopt2. */ ++/* { dg-final { scan-tree-dump-times "\\\^ c_\[0-9]*\\\(D\\\);" 1 "optimized" } } */ + /* { dg-final { scan-tree-dump-times " = ~" 1 "phiopt2" } } */ + /* { dg-final { scan-tree-dump-times " = \[abc_0-9\\\(\\\)D]* \\\^ " 5 "phiopt2" } } */ + /* { dg-final { scan-tree-dump-not "a < 0" "phiopt2" } } */ +-- +2.27.0.windows.1 + diff --git a/0061-Backport-Replace-conditional_replacement-with-match-.patch b/0061-Backport-Replace-conditional_replacement-with-match-.patch new file mode 100644 index 0000000..12808be --- /dev/null +++ b/0061-Backport-Replace-conditional_replacement-with-match-.patch @@ -0,0 +1,249 @@ +From 406071e8c1838c824f06c35ef3cf9419aa543e6e Mon Sep 17 00:00:00 2001 +From: Andrew Pinski <apinski@marvell.com> +Date: Tue, 1 Jun 2021 01:05:09 +0000 +Subject: [PATCH 13/35] [Backport] Replace conditional_replacement with match + and simplify + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=9f55df63154a39d67ef5b24def7044bf87300831 + +This is the first of series of patches to simplify phi-opt +to use match and simplify in many cases. This simplification +will more things to optimize. + +This is what Richard requested in +https://gcc.gnu.org/pipermail/gcc-patches/2021-May/571197.html +and I think it is the right thing to do too. + +OK? Bootstrapped and tested on x86_64-linux-gnu with no regressions. + +gcc/ChangeLog: + + PR tree-optimization/25290 + * tree-ssa-phiopt.c (match_simplify_replacement): + New function. + (tree_ssa_phiopt_worker): Use match_simplify_replacement. + (two_value_replacement): Change the comment about + conditional_replacement. + (conditional_replacement): Delete. +--- + gcc/tree-ssa-phiopt.c | 144 ++++++++++++------------------------------ + 1 file changed, 39 insertions(+), 105 deletions(-) + +diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c +index 269eda21c..9fa6363b6 100644 +--- a/gcc/tree-ssa-phiopt.c ++++ b/gcc/tree-ssa-phiopt.c +@@ -52,8 +52,8 @@ along with GCC; see the file COPYING3. If not see + static unsigned int tree_ssa_phiopt_worker (bool, bool, bool); + static bool two_value_replacement (basic_block, basic_block, edge, gphi *, + tree, tree); +-static bool conditional_replacement (basic_block, basic_block, +- edge, edge, gphi *, tree, tree); ++static bool match_simplify_replacement (basic_block, basic_block, ++ edge, edge, gphi *, tree, tree); + static gphi *factor_out_conditional_conversion (edge, edge, gphi *, tree, tree, + gimple *); + static int value_replacement (basic_block, basic_block, +@@ -349,8 +349,8 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) + if (!early_p && two_value_replacement (bb, bb1, e2, phi, arg0, arg1)) + cfgchanged = true; + else if (!early_p +- && conditional_replacement (bb, bb1, e1, e2, phi, +- arg0, arg1)) ++ && match_simplify_replacement (bb, bb1, e1, e2, phi, ++ arg0, arg1)) + cfgchanged = true; + else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) + cfgchanged = true; +@@ -662,7 +662,7 @@ two_value_replacement (basic_block cond_bb, basic_block middle_bb, + } + + /* Defer boolean x ? 0 : {1,-1} or x ? {1,-1} : 0 to +- conditional_replacement. */ ++ match_simplify_replacement. */ + if (TREE_CODE (TREE_TYPE (lhs)) == BOOLEAN_TYPE + && (integer_zerop (arg0) + || integer_zerop (arg1) +@@ -763,137 +763,71 @@ two_value_replacement (basic_block cond_bb, basic_block middle_bb, + return true; + } + +-/* The function conditional_replacement does the main work of doing the +- conditional replacement. Return true if the replacement is done. ++/* The function match_simplify_replacement does the main work of doing the ++ replacement using match and simplify. Return true if the replacement is done. + Otherwise return false. + BB is the basic block where the replacement is going to be done on. ARG0 + is argument 0 from PHI. Likewise for ARG1. */ + + static bool +-conditional_replacement (basic_block cond_bb, basic_block middle_bb, +- edge e0, edge e1, gphi *phi, +- tree arg0, tree arg1) ++match_simplify_replacement (basic_block cond_bb, basic_block middle_bb, ++ edge e0, edge e1, gphi *phi, ++ tree arg0, tree arg1) + { +- tree result; + gimple *stmt; +- gassign *new_stmt; + tree cond; + gimple_stmt_iterator gsi; + edge true_edge, false_edge; +- tree new_var, new_var2; +- bool neg = false; +- int shift = 0; +- tree nonzero_arg; +- +- /* FIXME: Gimplification of complex type is too hard for now. */ +- /* We aren't prepared to handle vectors either (and it is a question +- if it would be worthwhile anyway). */ +- if (!(INTEGRAL_TYPE_P (TREE_TYPE (arg0)) +- || POINTER_TYPE_P (TREE_TYPE (arg0))) +- || !(INTEGRAL_TYPE_P (TREE_TYPE (arg1)) +- || POINTER_TYPE_P (TREE_TYPE (arg1)))) +- return false; ++ gimple_seq seq = NULL; ++ tree result; + +- /* The PHI arguments have the constants 0 and 1, or 0 and -1 or +- 0 and (1 << cst), then convert it to the conditional. */ +- if (integer_zerop (arg0)) +- nonzero_arg = arg1; +- else if (integer_zerop (arg1)) +- nonzero_arg = arg0; +- else +- return false; +- if (integer_pow2p (nonzero_arg)) +- { +- shift = tree_log2 (nonzero_arg); +- if (shift && POINTER_TYPE_P (TREE_TYPE (nonzero_arg))) +- return false; +- } +- else if (integer_all_onesp (nonzero_arg)) +- neg = true; +- else ++ if (!empty_block_p (middle_bb)) + return false; + +- if (!empty_block_p (middle_bb)) ++ /* Special case A ? B : B as this will always simplify to B. */ ++ if (operand_equal_for_phi_arg_p (arg0, arg1)) + return false; + +- /* At this point we know we have a GIMPLE_COND with two successors. ++ /* At this point we know we have a GIMPLE_COND with two successors. + One successor is BB, the other successor is an empty block which + falls through into BB. + +- There is a single PHI node at the join point (BB) and its arguments +- are constants (0, 1) or (0, -1) or (0, (1 << shift)). +- +- So, given the condition COND, and the two PHI arguments, we can +- rewrite this PHI into non-branching code: ++ There is a single PHI node at the join point (BB). + +- dest = (COND) or dest = COND' or dest = (COND) << shift +- +- We use the condition as-is if the argument associated with the +- true edge has the value one or the argument associated with the +- false edge as the value zero. Note that those conditions are not +- the same since only one of the outgoing edges from the GIMPLE_COND +- will directly reach BB and thus be associated with an argument. */ ++ So, given the condition COND, and the two PHI arguments, match and simplify ++ can happen on (COND) ? arg0 : arg1. */ + + stmt = last_stmt (cond_bb); +- result = PHI_RESULT (phi); + + /* To handle special cases like floating point comparison, it is easier and + less error-prone to build a tree and gimplify it on the fly though it is +- less efficient. */ +- cond = fold_build2_loc (gimple_location (stmt), +- gimple_cond_code (stmt), boolean_type_node, +- gimple_cond_lhs (stmt), gimple_cond_rhs (stmt)); ++ less efficient. ++ Don't use fold_build2 here as that might create (bool)a instead of just ++ "a != 0". */ ++ cond = build2_loc (gimple_location (stmt), ++ gimple_cond_code (stmt), boolean_type_node, ++ gimple_cond_lhs (stmt), gimple_cond_rhs (stmt)); + + /* We need to know which is the true edge and which is the false + edge so that we know when to invert the condition below. */ + extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge); +- if ((e0 == true_edge && integer_zerop (arg0)) +- || (e0 == false_edge && !integer_zerop (arg0)) +- || (e1 == true_edge && integer_zerop (arg1)) +- || (e1 == false_edge && !integer_zerop (arg1))) +- cond = fold_build1_loc (gimple_location (stmt), +- TRUTH_NOT_EXPR, TREE_TYPE (cond), cond); +- +- if (neg) +- { +- cond = fold_convert_loc (gimple_location (stmt), +- TREE_TYPE (result), cond); +- cond = fold_build1_loc (gimple_location (stmt), +- NEGATE_EXPR, TREE_TYPE (cond), cond); +- } +- else if (shift) +- { +- cond = fold_convert_loc (gimple_location (stmt), +- TREE_TYPE (result), cond); +- cond = fold_build2_loc (gimple_location (stmt), +- LSHIFT_EXPR, TREE_TYPE (cond), cond, +- build_int_cst (integer_type_node, shift)); +- } ++ if (e1 == true_edge || e0 == false_edge) ++ std::swap (arg0, arg1); + +- /* Insert our new statements at the end of conditional block before the +- COND_STMT. */ +- gsi = gsi_for_stmt (stmt); +- new_var = force_gimple_operand_gsi (&gsi, cond, true, NULL, true, +- GSI_SAME_STMT); ++ tree type = TREE_TYPE (gimple_phi_result (phi)); ++ result = gimple_simplify (COND_EXPR, type, ++ cond, ++ arg0, arg1, ++ &seq, NULL); ++ if (!result) ++ return false; + +- if (!useless_type_conversion_p (TREE_TYPE (result), TREE_TYPE (new_var))) +- { +- location_t locus_0, locus_1; ++ gsi = gsi_last_bb (cond_bb); + +- new_var2 = make_ssa_name (TREE_TYPE (result)); +- new_stmt = gimple_build_assign (new_var2, CONVERT_EXPR, new_var); +- gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT); +- new_var = new_var2; +- +- /* Set the locus to the first argument, unless is doesn't have one. */ +- locus_0 = gimple_phi_arg_location (phi, 0); +- locus_1 = gimple_phi_arg_location (phi, 1); +- if (locus_0 == UNKNOWN_LOCATION) +- locus_0 = locus_1; +- gimple_set_location (new_stmt, locus_0); +- } ++ if (seq) ++ gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT); + +- replace_phi_edge_with_variable (cond_bb, e1, phi, new_var); ++ replace_phi_edge_with_variable (cond_bb, e1, phi, result); + + /* Note that we optimized this PHI. */ + return true; +@@ -3905,7 +3839,7 @@ gate_hoist_loads (void) + Conditional Replacement + ----------------------- + +- This transformation, implemented in conditional_replacement, ++ This transformation, implemented in match_simplify_replacement, + replaces + + bb0: +-- +2.27.0.windows.1 + diff --git a/0062-Backport-Allow-match-and-simplified-phiopt-to-run-in.patch b/0062-Backport-Allow-match-and-simplified-phiopt-to-run-in.patch new file mode 100644 index 0000000..bf1b0cd --- /dev/null +++ b/0062-Backport-Allow-match-and-simplified-phiopt-to-run-in.patch @@ -0,0 +1,174 @@ +From fabbe6ccc798d3cb097c6371b4d53cd6dfde6c7c Mon Sep 17 00:00:00 2001 +From: Andrew Pinski <apinski@marvell.com> +Date: Fri, 11 Jun 2021 13:21:34 -0700 +Subject: [PATCH 14/35] [Backport] Allow match-and-simplified phiopt to run in + early phiopt + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=cd48e550d1dc58307ab1c0ab490745673f748ccc + +To move a few things more to match-and-simplify from phiopt, +we need to allow match_simplify_replacement to run in early +phiopt. To do this we add a replacement for gimple_simplify +that is explictly for phiopt. + +OK? Bootstrapped and tested on x86_64-linux-gnu with no +regressions. + +gcc/ChangeLog: + + * tree-ssa-phiopt.c (match_simplify_replacement): + Add early_p argument. Call gimple_simplify_phiopt + instead of gimple_simplify. + (tree_ssa_phiopt_worker): Update call to + match_simplify_replacement and allow unconditionally. + (phiopt_early_allow): New function. + (gimple_simplify_phiopt): New function. +--- + gcc/tree-ssa-phiopt.c | 89 ++++++++++++++++++++++++++++++++++--------- + 1 file changed, 70 insertions(+), 19 deletions(-) + +diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c +index 9fa6363b6..92aeb8415 100644 +--- a/gcc/tree-ssa-phiopt.c ++++ b/gcc/tree-ssa-phiopt.c +@@ -48,12 +48,13 @@ along with GCC; see the file COPYING3. If not see + #include "tree-eh.h" + #include "gimple-fold.h" + #include "internal-fn.h" ++#include "gimple-match.h" + + static unsigned int tree_ssa_phiopt_worker (bool, bool, bool); + static bool two_value_replacement (basic_block, basic_block, edge, gphi *, + tree, tree); + static bool match_simplify_replacement (basic_block, basic_block, +- edge, edge, gphi *, tree, tree); ++ edge, edge, gphi *, tree, tree, bool); + static gphi *factor_out_conditional_conversion (edge, edge, gphi *, tree, tree, + gimple *); + static int value_replacement (basic_block, basic_block, +@@ -348,9 +349,9 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) + /* Do the replacement of conditional if it can be done. */ + if (!early_p && two_value_replacement (bb, bb1, e2, phi, arg0, arg1)) + cfgchanged = true; +- else if (!early_p +- && match_simplify_replacement (bb, bb1, e1, e2, phi, +- arg0, arg1)) ++ else if (match_simplify_replacement (bb, bb1, e1, e2, phi, ++ arg0, arg1, ++ early_p)) + cfgchanged = true; + else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) + cfgchanged = true; +@@ -763,6 +764,67 @@ two_value_replacement (basic_block cond_bb, basic_block middle_bb, + return true; + } + ++/* Return TRUE if CODE should be allowed during early phiopt. ++ Currently this is to allow MIN/MAX and ABS/NEGATE. */ ++static bool ++phiopt_early_allow (enum tree_code code) ++{ ++ switch (code) ++ { ++ case MIN_EXPR: ++ case MAX_EXPR: ++ case ABS_EXPR: ++ case ABSU_EXPR: ++ case NEGATE_EXPR: ++ case SSA_NAME: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++/* gimple_simplify_phiopt is like gimple_simplify but designed for PHIOPT. ++ Return NULL if nothing can be simplified or the resulting simplified value ++ with parts pushed if EARLY_P was true. Also rejects non allowed tree code ++ if EARLY_P is set. ++ Takes the comparison from COMP_STMT and two args, ARG0 and ARG1 and tries ++ to simplify CMP ? ARG0 : ARG1. */ ++static tree ++gimple_simplify_phiopt (bool early_p, tree type, gimple *comp_stmt, ++ tree arg0, tree arg1, ++ gimple_seq *seq) ++{ ++ tree result; ++ enum tree_code comp_code = gimple_cond_code (comp_stmt); ++ location_t loc = gimple_location (comp_stmt); ++ tree cmp0 = gimple_cond_lhs (comp_stmt); ++ tree cmp1 = gimple_cond_rhs (comp_stmt); ++ /* To handle special cases like floating point comparison, it is easier and ++ less error-prone to build a tree and gimplify it on the fly though it is ++ less efficient. ++ Don't use fold_build2 here as that might create (bool)a instead of just ++ "a != 0". */ ++ tree cond = build2_loc (loc, comp_code, boolean_type_node, ++ cmp0, cmp1); ++ gimple_match_op op (gimple_match_cond::UNCOND, ++ COND_EXPR, type, cond, arg0, arg1); ++ ++ if (op.resimplify (early_p ? NULL : seq, follow_all_ssa_edges)) ++ { ++ /* Early we want only to allow some generated tree codes. */ ++ if (!early_p ++ || op.code.is_tree_code () ++ || phiopt_early_allow ((tree_code)op.code)) ++ { ++ result = maybe_push_res_to_seq (&op, seq); ++ if (result) ++ return result; ++ } ++ } ++ ++ return NULL; ++} ++ + /* The function match_simplify_replacement does the main work of doing the + replacement using match and simplify. Return true if the replacement is done. + Otherwise return false. +@@ -772,10 +834,9 @@ two_value_replacement (basic_block cond_bb, basic_block middle_bb, + static bool + match_simplify_replacement (basic_block cond_bb, basic_block middle_bb, + edge e0, edge e1, gphi *phi, +- tree arg0, tree arg1) ++ tree arg0, tree arg1, bool early_p) + { + gimple *stmt; +- tree cond; + gimple_stmt_iterator gsi; + edge true_edge, false_edge; + gimple_seq seq = NULL; +@@ -799,15 +860,6 @@ match_simplify_replacement (basic_block cond_bb, basic_block middle_bb, + + stmt = last_stmt (cond_bb); + +- /* To handle special cases like floating point comparison, it is easier and +- less error-prone to build a tree and gimplify it on the fly though it is +- less efficient. +- Don't use fold_build2 here as that might create (bool)a instead of just +- "a != 0". */ +- cond = build2_loc (gimple_location (stmt), +- gimple_cond_code (stmt), boolean_type_node, +- gimple_cond_lhs (stmt), gimple_cond_rhs (stmt)); +- + /* We need to know which is the true edge and which is the false + edge so that we know when to invert the condition below. */ + extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge); +@@ -815,10 +867,9 @@ match_simplify_replacement (basic_block cond_bb, basic_block middle_bb, + std::swap (arg0, arg1); + + tree type = TREE_TYPE (gimple_phi_result (phi)); +- result = gimple_simplify (COND_EXPR, type, +- cond, +- arg0, arg1, +- &seq, NULL); ++ result = gimple_simplify_phiopt (early_p, type, stmt, ++ arg0, arg1, ++ &seq); + if (!result) + return false; + +-- +2.27.0.windows.1 + diff --git a/0063-Backport-Improve-match_simplify_replacement-in-phi-o.patch b/0063-Backport-Improve-match_simplify_replacement-in-phi-o.patch new file mode 100644 index 0000000..8440622 --- /dev/null +++ b/0063-Backport-Improve-match_simplify_replacement-in-phi-o.patch @@ -0,0 +1,259 @@ +From d212d216be0752370dbe7bc63bd75b3a9249e0b5 Mon Sep 17 00:00:00 2001 +From: Andrew Pinski <apinski@marvell.com> +Date: Tue, 1 Jun 2021 06:48:05 +0000 +Subject: [PATCH 15/35] [Backport] Improve match_simplify_replacement in + phi-opt + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=c4574d23cb07340918793a5a98ae7bb2988b3791 + +This improves match_simplify_replace in phi-opt to handle the +case where there is one cheap (non-call) preparation statement in the +middle basic block similar to xor_replacement and others. +This allows to remove xor_replacement which it does too. + +OK? Bootstrapped and tested on x86_64-linux-gnu with no regressions. + +Thanks, +Andrew Pinski + +Changes since v1: +v3 - Just minor changes to using gimple_assign_lhs +instead of gimple_lhs and fixing a comment. +v2 - change the check on the preparation statement to +allow only assignments and no calls and only assignments +that feed into the phi. + +gcc/ChangeLog: + + PR tree-optimization/25290 + * tree-ssa-phiopt.c (xor_replacement): Delete. + (tree_ssa_phiopt_worker): Delete use of xor_replacement. + (match_simplify_replacement): Allow one cheap preparation + statement that can be moved to before the if. + +gcc/testsuite/ChangeLog: + + * gcc.dg/tree-ssa/pr96928-1.c: Fix testcase for now that ~ + happens on the outside of the bit_xor. +--- + gcc/tree-ssa-phiopt.c | 164 ++++++++++++++---------------------------- + 1 file changed, 52 insertions(+), 112 deletions(-) + +diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c +index 92aeb8415..51a2d3684 100644 +--- a/gcc/tree-ssa-phiopt.c ++++ b/gcc/tree-ssa-phiopt.c +@@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see + #include "cfghooks.h" + #include "tree-pass.h" + #include "ssa.h" ++#include "tree-ssa.h" + #include "optabs-tree.h" + #include "insn-config.h" + #include "gimple-pretty-print.h" +@@ -63,8 +64,6 @@ static bool minmax_replacement (basic_block, basic_block, + edge, edge, gimple *, tree, tree); + static bool abs_replacement (basic_block, basic_block, + edge, edge, gimple *, tree, tree); +-static bool xor_replacement (basic_block, basic_block, +- edge, edge, gimple *, tree, tree); + static bool spaceship_replacement (basic_block, basic_block, + edge, edge, gphi *, tree, tree); + static bool cond_removal_in_popcount_clz_ctz_pattern (basic_block, basic_block, +@@ -355,9 +354,6 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) + cfgchanged = true; + else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) + cfgchanged = true; +- else if (!early_p +- && xor_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) +- cfgchanged = true; + else if (!early_p + && cond_removal_in_popcount_clz_ctz_pattern (bb, bb1, e1, + e2, phi, arg0, +@@ -841,14 +837,51 @@ match_simplify_replacement (basic_block cond_bb, basic_block middle_bb, + edge true_edge, false_edge; + gimple_seq seq = NULL; + tree result; +- +- if (!empty_block_p (middle_bb)) +- return false; ++ gimple *stmt_to_move = NULL; + + /* Special case A ? B : B as this will always simplify to B. */ + if (operand_equal_for_phi_arg_p (arg0, arg1)) + return false; + ++ /* If the basic block only has a cheap preparation statement, ++ allow it and move it once the transformation is done. */ ++ if (!empty_block_p (middle_bb)) ++ { ++ stmt_to_move = last_and_only_stmt (middle_bb); ++ if (!stmt_to_move) ++ return false; ++ ++ if (gimple_vuse (stmt_to_move)) ++ return false; ++ ++ if (gimple_could_trap_p (stmt_to_move) ++ || gimple_has_side_effects (stmt_to_move)) ++ return false; ++ ++ if (gimple_uses_undefined_value_p (stmt_to_move)) ++ return false; ++ ++ /* Allow assignments and not no calls. ++ As const calls don't match any of the above, yet they could ++ still have some side-effects - they could contain ++ gimple_could_trap_p statements, like floating point ++ exceptions or integer division by zero. See PR70586. ++ FIXME: perhaps gimple_has_side_effects or gimple_could_trap_p ++ should handle this. */ ++ if (!is_gimple_assign (stmt_to_move)) ++ return false; ++ ++ tree lhs = gimple_assign_lhs (stmt_to_move); ++ gimple *use_stmt; ++ use_operand_p use_p; ++ ++ /* Allow only a statement which feeds into the phi. */ ++ if (!lhs || TREE_CODE (lhs) != SSA_NAME ++ || !single_imm_use (lhs, &use_p, &use_stmt) ++ || use_stmt != phi) ++ return false; ++ } ++ + /* At this point we know we have a GIMPLE_COND with two successors. + One successor is BB, the other successor is an empty block which + falls through into BB. +@@ -874,7 +907,17 @@ match_simplify_replacement (basic_block cond_bb, basic_block middle_bb, + return false; + + gsi = gsi_last_bb (cond_bb); +- ++ if (stmt_to_move) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "statement un-sinked:\n"); ++ print_gimple_stmt (dump_file, stmt_to_move, 0, ++ TDF_VOPS|TDF_MEMSYMS); ++ } ++ gimple_stmt_iterator gsi1 = gsi_for_stmt (stmt_to_move); ++ gsi_move_before (&gsi1, &gsi); ++ } + if (seq) + gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT); + +@@ -2474,109 +2517,6 @@ abs_replacement (basic_block cond_bb, basic_block middle_bb, + return true; + } + +-/* Optimize x < 0 ? ~y : y into (x >> (prec-1)) ^ y. */ +- +-static bool +-xor_replacement (basic_block cond_bb, basic_block middle_bb, +- edge e0 ATTRIBUTE_UNUSED, edge e1, +- gimple *phi, tree arg0, tree arg1) +-{ +- if (!INTEGRAL_TYPE_P (TREE_TYPE (arg1))) +- return false; +- +- /* OTHER_BLOCK must have only one executable statement which must have the +- form arg0 = ~arg1 or arg1 = ~arg0. */ +- +- gimple *assign = last_and_only_stmt (middle_bb); +- /* If we did not find the proper one's complement assignment, then we cannot +- optimize. */ +- if (assign == NULL) +- return false; +- +- /* If we got here, then we have found the only executable statement +- in OTHER_BLOCK. If it is anything other than arg = ~arg1 or +- arg1 = ~arg0, then we cannot optimize. */ +- if (!is_gimple_assign (assign)) +- return false; +- +- if (gimple_assign_rhs_code (assign) != BIT_NOT_EXPR) +- return false; +- +- tree lhs = gimple_assign_lhs (assign); +- tree rhs = gimple_assign_rhs1 (assign); +- +- /* The assignment has to be arg0 = -arg1 or arg1 = -arg0. */ +- if (!(lhs == arg0 && rhs == arg1) && !(lhs == arg1 && rhs == arg0)) +- return false; +- +- gimple *cond = last_stmt (cond_bb); +- tree result = PHI_RESULT (phi); +- +- /* Only relationals comparing arg[01] against zero are interesting. */ +- enum tree_code cond_code = gimple_cond_code (cond); +- if (cond_code != LT_EXPR && cond_code != GE_EXPR) +- return false; +- +- /* Make sure the conditional is x OP 0. */ +- tree clhs = gimple_cond_lhs (cond); +- if (TREE_CODE (clhs) != SSA_NAME +- || !INTEGRAL_TYPE_P (TREE_TYPE (clhs)) +- || TYPE_UNSIGNED (TREE_TYPE (clhs)) +- || TYPE_PRECISION (TREE_TYPE (clhs)) != TYPE_PRECISION (TREE_TYPE (arg1)) +- || !integer_zerop (gimple_cond_rhs (cond))) +- return false; +- +- /* We need to know which is the true edge and which is the false +- edge so that we know if have xor or inverted xor. */ +- edge true_edge, false_edge; +- extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge); +- +- /* For GE_EXPR, if the true edge goes to OTHER_BLOCK, then we +- will need to invert the result. Similarly for LT_EXPR if +- the false edge goes to OTHER_BLOCK. */ +- edge e; +- if (cond_code == GE_EXPR) +- e = true_edge; +- else +- e = false_edge; +- +- bool invert = e->dest == middle_bb; +- +- result = duplicate_ssa_name (result, NULL); +- +- gimple_stmt_iterator gsi = gsi_last_bb (cond_bb); +- +- int prec = TYPE_PRECISION (TREE_TYPE (clhs)); +- gimple *new_stmt +- = gimple_build_assign (make_ssa_name (TREE_TYPE (clhs)), RSHIFT_EXPR, clhs, +- build_int_cst (integer_type_node, prec - 1)); +- gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT); +- +- if (!useless_type_conversion_p (TREE_TYPE (result), TREE_TYPE (clhs))) +- { +- new_stmt = gimple_build_assign (make_ssa_name (TREE_TYPE (result)), +- NOP_EXPR, gimple_assign_lhs (new_stmt)); +- gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT); +- } +- lhs = gimple_assign_lhs (new_stmt); +- +- if (invert) +- { +- new_stmt = gimple_build_assign (make_ssa_name (TREE_TYPE (result)), +- BIT_NOT_EXPR, rhs); +- gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT); +- rhs = gimple_assign_lhs (new_stmt); +- } +- +- new_stmt = gimple_build_assign (result, BIT_XOR_EXPR, lhs, rhs); +- gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT); +- +- replace_phi_edge_with_variable (cond_bb, e1, phi, result); +- +- /* Note that we optimized this PHI. */ +- return true; +-} +- + /* Auxiliary functions to determine the set of memory accesses which + can't trap because they are preceded by accesses to the same memory + portion. We do that for MEM_REFs, so we only need to track +-- +2.27.0.windows.1 + diff --git a/0064-Backport-phiopt-Use-gphi-phi-instead-of-gimple-phi-s.patch b/0064-Backport-phiopt-Use-gphi-phi-instead-of-gimple-phi-s.patch new file mode 100644 index 0000000..de21109 --- /dev/null +++ b/0064-Backport-phiopt-Use-gphi-phi-instead-of-gimple-phi-s.patch @@ -0,0 +1,103 @@ +From 0d55d24aa4e47c40f74e0281d023089cfaafcf74 Mon Sep 17 00:00:00 2001 +From: Jakub Jelinek <jakub@redhat.com> +Date: Thu, 6 May 2021 14:05:06 +0200 +Subject: [PATCH 16/35] [Backport] phiopt: Use gphi *phi instead of gimple *phi + some more + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=cfd65e8d5299a7cf7d2ecd92b0e24ea4cfb697d9 + +Various functions in phiopt are also called with a gphi * but use +gimple * argument for it. + +2021-05-06 Jakub Jelinek <jakub@redhat.com> + + * tree-ssa-phiopt.c (value_replacement, minmax_replacement, + abs_replacement, xor_replacement, + cond_removal_in_popcount_clz_ctz_pattern, + replace_phi_edge_with_variable): Change type of phi argument from + gimple * to gphi *. +--- + gcc/tree-ssa-phiopt.c | 22 ++++++++++------------ + 1 file changed, 10 insertions(+), 12 deletions(-) + +diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c +index 51a2d3684..045a7b1b8 100644 +--- a/gcc/tree-ssa-phiopt.c ++++ b/gcc/tree-ssa-phiopt.c +@@ -59,21 +59,21 @@ static bool match_simplify_replacement (basic_block, basic_block, + static gphi *factor_out_conditional_conversion (edge, edge, gphi *, tree, tree, + gimple *); + static int value_replacement (basic_block, basic_block, +- edge, edge, gimple *, tree, tree); ++ edge, edge, gphi *, tree, tree); + static bool minmax_replacement (basic_block, basic_block, +- edge, edge, gimple *, tree, tree); ++ edge, edge, gphi *, tree, tree); + static bool abs_replacement (basic_block, basic_block, +- edge, edge, gimple *, tree, tree); ++ edge, edge, gphi *, tree, tree); + static bool spaceship_replacement (basic_block, basic_block, + edge, edge, gphi *, tree, tree); + static bool cond_removal_in_popcount_clz_ctz_pattern (basic_block, basic_block, +- edge, edge, gimple *, ++ edge, edge, gphi *, + tree, tree); + static bool cond_store_replacement (basic_block, basic_block, edge, edge, + hash_set<tree> *); + static bool cond_if_else_store_replacement (basic_block, basic_block, basic_block); + static hash_set<tree> * get_non_trapping (); +-static void replace_phi_edge_with_variable (basic_block, edge, gimple *, tree); ++static void replace_phi_edge_with_variable (basic_block, edge, gphi *, tree); + static void hoist_adjacent_loads (basic_block, basic_block, + basic_block, basic_block); + static bool do_phiopt_pattern (basic_block, basic_block, basic_block); +@@ -389,7 +389,7 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) + + static void + replace_phi_edge_with_variable (basic_block cond_block, +- edge e, gimple *phi, tree new_tree) ++ edge e, gphi *phi, tree new_tree) + { + basic_block bb = gimple_bb (phi); + basic_block block_to_remove; +@@ -1129,8 +1129,7 @@ absorbing_element_p (tree_code code, tree arg, bool right, tree rval) + + static int + value_replacement (basic_block cond_bb, basic_block middle_bb, +- edge e0, edge e1, gimple *phi, +- tree arg0, tree arg1) ++ edge e0, edge e1, gphi *phi, tree arg0, tree arg1) + { + gimple_stmt_iterator gsi; + gimple *cond; +@@ -1438,8 +1437,7 @@ value_replacement (basic_block cond_bb, basic_block middle_bb, + + static bool + minmax_replacement (basic_block cond_bb, basic_block middle_bb, +- edge e0, edge e1, gimple *phi, +- tree arg0, tree arg1) ++ edge e0, edge e1, gphi *phi, tree arg0, tree arg1) + { + tree result, type, rhs; + gcond *cond; +@@ -2240,7 +2238,7 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb, + static bool + cond_removal_in_popcount_clz_ctz_pattern (basic_block cond_bb, + basic_block middle_bb, +- edge e1, edge e2, gimple *phi, ++ edge e1, edge e2, gphi *phi, + tree arg0, tree arg1) + { + gimple *cond; +@@ -2398,7 +2396,7 @@ cond_removal_in_popcount_clz_ctz_pattern (basic_block cond_bb, + static bool + abs_replacement (basic_block cond_bb, basic_block middle_bb, + edge e0 ATTRIBUTE_UNUSED, edge e1, +- gimple *phi, tree arg0, tree arg1) ++ gphi *phi, tree arg0, tree arg1) + { + tree result; + gassign *new_stmt; +-- +2.27.0.windows.1 + diff --git a/0065-Backport-Optimize-x-bswap-x-0-in-tree-ssa-phiopt.patch b/0065-Backport-Optimize-x-bswap-x-0-in-tree-ssa-phiopt.patch new file mode 100644 index 0000000..db7b4b2 --- /dev/null +++ b/0065-Backport-Optimize-x-bswap-x-0-in-tree-ssa-phiopt.patch @@ -0,0 +1,212 @@ +From 33dc778a34d7b93978efe922bb1b4583d8e6c4bb Mon Sep 17 00:00:00 2001 +From: Roger Sayle <roger@nextmovesoftware.com> +Date: Mon, 2 Aug 2021 13:27:53 +0100 +Subject: [PATCH 17/35] [Backport] Optimize x ? bswap(x) : 0 in tree-ssa-phiopt + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=f9fcf754825a1e01033336f84c18690aaa971a6f + +Many thanks again to Jakub Jelinek for a speedy fix for PR 101642. +Interestingly, that test case "bswap16(x) ? : x" also reveals a +missed optimization opportunity. The resulting "x ? bswap(x) : 0" +can be further simplified to just bswap(x). + +Conveniently, tree-ssa-phiopt.c already recognizes/optimizes the +related "x ? popcount(x) : 0", so this patch simply makes that +transformation make general, additionally handling bswap, parity, +ffs and clrsb. All of the required infrastructure is already +present thanks to Jakub previously adding support for clz/ctz. +To reflect this generalization, the name of the function is changed +from cond_removal_in_popcount_clz_ctz_pattern to the hopefully +equally descriptive cond_removal_in_builtin_zero_pattern. + +2021-08-02 Roger Sayle <roger@nextmovesoftware.com> + +gcc/ChangeLog + * tree-ssa-phiopt.c (cond_removal_in_builtin_zero_pattern): + Renamed from cond_removal_in_popcount_clz_ctz_pattern. + Add support for BSWAP, FFS, PARITY and CLRSB builtins. + (tree_ssa_phiop_worker): Update call to function above. + +gcc/testsuite/ChangeLog + * gcc.dg/tree-ssa/phi-opt-25.c: New test case. +--- + gcc/testsuite/gcc.dg/tree-ssa/phi-opt-25.c | 83 ++++++++++++++++++++++ + gcc/tree-ssa-phiopt.c | 37 +++++++--- + 2 files changed, 109 insertions(+), 11 deletions(-) + create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/phi-opt-25.c + +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-25.c b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-25.c +new file mode 100644 +index 000000000..c52c92e1d +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-25.c +@@ -0,0 +1,83 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -fdump-tree-optimized" } */ ++ ++unsigned short test_bswap16(unsigned short x) ++{ ++ return x ? __builtin_bswap16(x) : 0; ++} ++ ++unsigned int test_bswap32(unsigned int x) ++{ ++ return x ? __builtin_bswap32(x) : 0; ++} ++ ++unsigned long long test_bswap64(unsigned long long x) ++{ ++ return x ? __builtin_bswap64(x) : 0; ++} ++ ++int test_clrsb(int x) ++{ ++ return x ? __builtin_clrsb(x) : (__SIZEOF_INT__*8-1); ++} ++ ++int test_clrsbl(long x) ++{ ++ return x ? __builtin_clrsbl(x) : (__SIZEOF_LONG__*8-1); ++} ++ ++int test_clrsbll(long long x) ++{ ++ return x ? __builtin_clrsbll(x) : (__SIZEOF_LONG_LONG__*8-1); ++} ++ ++#if 0 ++/* BUILT_IN_FFS is transformed by match.pd */ ++int test_ffs(unsigned int x) ++{ ++ return x ? __builtin_ffs(x) : 0; ++} ++ ++int test_ffsl(unsigned long x) ++{ ++ return x ? __builtin_ffsl(x) : 0; ++} ++ ++int test_ffsll(unsigned long long x) ++{ ++ return x ? __builtin_ffsll(x) : 0; ++} ++#endif ++ ++int test_parity(int x) ++{ ++ return x ? __builtin_parity(x) : 0; ++} ++ ++int test_parityl(long x) ++{ ++ return x ? __builtin_parityl(x) : 0; ++} ++ ++int test_parityll(long long x) ++{ ++ return x ? __builtin_parityll(x) : 0; ++} ++ ++int test_popcount(int x) ++{ ++ return x ? __builtin_popcount(x) : 0; ++} ++ ++int test_popcountl(long x) ++{ ++ return x ? __builtin_popcountl(x) : 0; ++} ++ ++int test_popcountll(long long x) ++{ ++ return x ? __builtin_popcountll(x) : 0; ++} ++ ++/* { dg-final { scan-tree-dump-not "goto" "optimized" } } */ ++ +diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c +index 045a7b1b8..21ac08145 100644 +--- a/gcc/tree-ssa-phiopt.c ++++ b/gcc/tree-ssa-phiopt.c +@@ -66,9 +66,9 @@ static bool abs_replacement (basic_block, basic_block, + edge, edge, gphi *, tree, tree); + static bool spaceship_replacement (basic_block, basic_block, + edge, edge, gphi *, tree, tree); +-static bool cond_removal_in_popcount_clz_ctz_pattern (basic_block, basic_block, +- edge, edge, gphi *, +- tree, tree); ++static bool cond_removal_in_builtin_zero_pattern (basic_block, basic_block, ++ edge, edge, gphi *, ++ tree, tree); + static bool cond_store_replacement (basic_block, basic_block, edge, edge, + hash_set<tree> *); + static bool cond_if_else_store_replacement (basic_block, basic_block, basic_block); +@@ -355,9 +355,8 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) + else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) + cfgchanged = true; + else if (!early_p +- && cond_removal_in_popcount_clz_ctz_pattern (bb, bb1, e1, +- e2, phi, arg0, +- arg1)) ++ && cond_removal_in_builtin_zero_pattern (bb, bb1, e1, e2, ++ phi, arg0, arg1)) + cfgchanged = true; + else if (minmax_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) + cfgchanged = true; +@@ -2204,7 +2203,8 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb, + return true; + } + +-/* Convert ++/* Optimize x ? __builtin_fun (x) : C, where C is __builtin_fun (0). ++ Convert + + <bb 2> + if (b_4(D) != 0) +@@ -2236,10 +2236,10 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb, + instead of 0 above it uses the value from that macro. */ + + static bool +-cond_removal_in_popcount_clz_ctz_pattern (basic_block cond_bb, +- basic_block middle_bb, +- edge e1, edge e2, gphi *phi, +- tree arg0, tree arg1) ++cond_removal_in_builtin_zero_pattern (basic_block cond_bb, ++ basic_block middle_bb, ++ edge e1, edge e2, gphi *phi, ++ tree arg0, tree arg1) + { + gimple *cond; + gimple_stmt_iterator gsi, gsi_from; +@@ -2287,6 +2287,12 @@ cond_removal_in_popcount_clz_ctz_pattern (basic_block cond_bb, + int val = 0; + switch (cfn) + { ++ case CFN_BUILT_IN_BSWAP16: ++ case CFN_BUILT_IN_BSWAP32: ++ case CFN_BUILT_IN_BSWAP64: ++ case CFN_BUILT_IN_BSWAP128: ++ CASE_CFN_FFS: ++ CASE_CFN_PARITY: + CASE_CFN_POPCOUNT: + break; + CASE_CFN_CLZ: +@@ -2315,6 +2321,15 @@ cond_removal_in_popcount_clz_ctz_pattern (basic_block cond_bb, + } + } + return false; ++ case BUILT_IN_CLRSB: ++ val = TYPE_PRECISION (integer_type_node) - 1; ++ break; ++ case BUILT_IN_CLRSBL: ++ val = TYPE_PRECISION (long_integer_type_node) - 1; ++ break; ++ case BUILT_IN_CLRSBLL: ++ val = TYPE_PRECISION (long_long_integer_type_node) - 1; ++ break; + default: + return false; + } +-- +2.27.0.windows.1 + diff --git a/0066-Backport-tree-optimization-102880-make-PHI-OPT-recog.patch b/0066-Backport-tree-optimization-102880-make-PHI-OPT-recog.patch new file mode 100644 index 0000000..df34234 --- /dev/null +++ b/0066-Backport-tree-optimization-102880-make-PHI-OPT-recog.patch @@ -0,0 +1,251 @@ +From 77398954ce517aa011b7a254c7aa2858521b2093 Mon Sep 17 00:00:00 2001 +From: Richard Biener <rguenther@suse.de> +Date: Mon, 15 Nov 2021 15:19:36 +0100 +Subject: [PATCH 18/35] [Backport] tree-optimization/102880 - make PHI-OPT + recognize more CFGs + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=f98f373dd822b35c52356b753d528924e9f89678 + +This allows extra edges into the middle BB for the PHI-OPT +transforms using replace_phi_edge_with_variable that do not +end up moving stmts from that middle BB. This avoids regressing +gcc.dg/tree-ssa/ssa-hoist-4.c with the actual fix for PR102880 +where CFG cleanup has the choice to remove two forwarders and +picks "the wrong" leading to + + if (a > b) / + /\ / + / <BB> + / | + # PHI <a, b> + +rather than + + if (a > b) | + /\ | + <BB> \ | + / \ | + # PHI <a, b, b> + +but it's relatively straight-forward to support extra edges +into the middle-BB in paths ending in replace_phi_edge_with_variable +and that do not require moving stmts. That's because we really +only want to remove the edge from the condition to the middle BB. +Of course actually doing that means updating dominators in non-trival +ways which is why I kept the original code for the single edge +case and simply defer to CFG cleanup by adjusting the condition for +the complicated case. + +The testcase needs to be a GIMPLE one since it's quite unreliable +to produce the desired CFG. + +2021-11-15 Richard Biener <rguenther@suse.de> + + PR tree-optimization/102880 + * tree-ssa-phiopt.c (tree_ssa_phiopt_worker): Push + single_pred (bb1) condition to places that really need it. + (match_simplify_replacement): Likewise. + (value_replacement): Likewise. + (replace_phi_edge_with_variable): Deal with extra edges + into the middle BB. + + * gcc.dg/tree-ssa/phi-opt-26.c: New testcase. +--- + gcc/testsuite/gcc.dg/tree-ssa/phi-opt-26.c | 31 +++++++++ + gcc/tree-ssa-phiopt.c | 73 +++++++++++++--------- + 2 files changed, 75 insertions(+), 29 deletions(-) + create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/phi-opt-26.c + +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-26.c b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-26.c +new file mode 100644 +index 000000000..21aa66e38 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-26.c +@@ -0,0 +1,31 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O -fgimple -fdump-tree-phiopt1" } */ ++ ++int __GIMPLE (ssa,startwith("phiopt")) ++foo (int a, int b, int flag) ++{ ++ int res; ++ ++ __BB(2): ++ if (flag_2(D) != 0) ++ goto __BB6; ++ else ++ goto __BB4; ++ ++ __BB(4): ++ if (a_3(D) > b_4(D)) ++ goto __BB7; ++ else ++ goto __BB6; ++ ++ __BB(6): ++ goto __BB7; ++ ++ __BB(7): ++ res_1 = __PHI (__BB4: a_3(D), __BB6: b_4(D)); ++ return res_1; ++} ++ ++/* We should be able to detect MAX despite the extra edge into ++ the middle BB. */ ++/* { dg-final { scan-tree-dump "MAX" "phiopt1" } } */ +diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c +index 21ac08145..079d29e74 100644 +--- a/gcc/tree-ssa-phiopt.c ++++ b/gcc/tree-ssa-phiopt.c +@@ -219,7 +219,6 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) + + /* If either bb1's succ or bb2 or bb2's succ is non NULL. */ + if (EDGE_COUNT (bb1->succs) == 0 +- || bb2 == NULL + || EDGE_COUNT (bb2->succs) == 0) + continue; + +@@ -279,14 +278,14 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) + || (e1->flags & EDGE_FALLTHRU) == 0) + continue; + +- /* Also make sure that bb1 only have one predecessor and that it +- is bb. */ +- if (!single_pred_p (bb1) +- || single_pred (bb1) != bb) +- continue; +- + if (do_store_elim) + { ++ /* Also make sure that bb1 only have one predecessor and that it ++ is bb. */ ++ if (!single_pred_p (bb1) ++ || single_pred (bb1) != bb) ++ continue; ++ + /* bb1 is the middle block, bb2 the join block, bb the split block, + e1 the fallthrough edge from bb1 to bb2. We can't do the + optimization if the join block has more than two predecessors. */ +@@ -331,10 +330,11 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) + node. */ + gcc_assert (arg0 != NULL_TREE && arg1 != NULL_TREE); + +- gphi *newphi = factor_out_conditional_conversion (e1, e2, phi, +- arg0, arg1, +- cond_stmt); +- if (newphi != NULL) ++ gphi *newphi; ++ if (single_pred_p (bb1) ++ && (newphi = factor_out_conditional_conversion (e1, e2, phi, ++ arg0, arg1, ++ cond_stmt))) + { + phi = newphi; + /* factor_out_conditional_conversion may create a new PHI in +@@ -355,12 +355,14 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) + else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) + cfgchanged = true; + else if (!early_p ++ && single_pred_p (bb1) + && cond_removal_in_builtin_zero_pattern (bb, bb1, e1, e2, + phi, arg0, arg1)) + cfgchanged = true; + else if (minmax_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) + cfgchanged = true; +- else if (spaceship_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) ++ else if (single_pred_p (bb1) ++ && spaceship_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) + cfgchanged = true; + } + } +@@ -391,35 +393,41 @@ replace_phi_edge_with_variable (basic_block cond_block, + edge e, gphi *phi, tree new_tree) + { + basic_block bb = gimple_bb (phi); +- basic_block block_to_remove; + gimple_stmt_iterator gsi; + + /* Change the PHI argument to new. */ + SET_USE (PHI_ARG_DEF_PTR (phi, e->dest_idx), new_tree); + + /* Remove the empty basic block. */ ++ edge edge_to_remove; + if (EDGE_SUCC (cond_block, 0)->dest == bb) ++ edge_to_remove = EDGE_SUCC (cond_block, 1); ++ else ++ edge_to_remove = EDGE_SUCC (cond_block, 0); ++ if (EDGE_COUNT (edge_to_remove->dest->preds) == 1) + { +- EDGE_SUCC (cond_block, 0)->flags |= EDGE_FALLTHRU; +- EDGE_SUCC (cond_block, 0)->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE); +- EDGE_SUCC (cond_block, 0)->probability = profile_probability::always (); +- +- block_to_remove = EDGE_SUCC (cond_block, 1)->dest; ++ e->flags |= EDGE_FALLTHRU; ++ e->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE); ++ e->probability = profile_probability::always (); ++ delete_basic_block (edge_to_remove->dest); ++ ++ /* Eliminate the COND_EXPR at the end of COND_BLOCK. */ ++ gsi = gsi_last_bb (cond_block); ++ gsi_remove (&gsi, true); + } + else + { +- EDGE_SUCC (cond_block, 1)->flags |= EDGE_FALLTHRU; +- EDGE_SUCC (cond_block, 1)->flags +- &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE); +- EDGE_SUCC (cond_block, 1)->probability = profile_probability::always (); +- +- block_to_remove = EDGE_SUCC (cond_block, 0)->dest; ++ /* If there are other edges into the middle block make ++ CFG cleanup deal with the edge removal to avoid ++ updating dominators here in a non-trivial way. */ ++ gcond *cond = as_a <gcond *> (last_stmt (cond_block)); ++ if (edge_to_remove->flags & EDGE_TRUE_VALUE) ++ gimple_cond_make_false (cond); ++ else ++ gimple_cond_make_true (cond); + } +- delete_basic_block (block_to_remove); + +- /* Eliminate the COND_EXPR at the end of COND_BLOCK. */ +- gsi = gsi_last_bb (cond_block); +- gsi_remove (&gsi, true); ++ statistics_counter_event (cfun, "Replace PHI with variable", 1); + + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, +@@ -846,6 +854,9 @@ match_simplify_replacement (basic_block cond_bb, basic_block middle_bb, + allow it and move it once the transformation is done. */ + if (!empty_block_p (middle_bb)) + { ++ if (!single_pred_p (middle_bb)) ++ return false; ++ + stmt_to_move = last_and_only_stmt (middle_bb); + if (!stmt_to_move) + return false; +@@ -1225,6 +1236,11 @@ value_replacement (basic_block cond_bb, basic_block middle_bb, + } + else + { ++ if (!single_pred_p (middle_bb)) ++ return 0; ++ statistics_counter_event (cfun, "Replace PHI with " ++ "variable/value_replacement", 1); ++ + /* Replace the PHI arguments with arg. */ + SET_PHI_ARG_DEF (phi, e0->dest_idx, arg); + SET_PHI_ARG_DEF (phi, e1->dest_idx, arg); +@@ -1239,7 +1255,6 @@ value_replacement (basic_block cond_bb, basic_block middle_bb, + } + return 1; + } +- + } + + /* Now optimize (x != 0) ? x + y : y to just x + y. */ +-- +2.27.0.windows.1 + diff --git a/0067-Backport-tree-Add-vector_element_bits-_tree-PR94980-.patch b/0067-Backport-tree-Add-vector_element_bits-_tree-PR94980-.patch new file mode 100644 index 0000000..06217a8 --- /dev/null +++ b/0067-Backport-tree-Add-vector_element_bits-_tree-PR94980-.patch @@ -0,0 +1,250 @@ +From a2f5e6f38fe7b5b32a252643b00dd2d7ab0e3fac Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Tue, 12 May 2020 09:01:10 +0100 +Subject: [PATCH 19/35] [Backport] tree: Add vector_element_bits(_tree) + [PR94980 1/3] + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=d17a896da1e898928d337596d029f0ece0039d55 + +A lot of code that wants to know the number of bits in a vector +element gets that information from the element's TYPE_SIZE, +which is always equal to TYPE_SIZE_UNIT * BITS_PER_UNIT. +This doesn't work for SVE and AVX512-style packed boolean vectors, +where several elements can occupy a single byte. + +This patch introduces a new pair of helpers for getting the true +(possibly sub-byte) size. I made a token attempt to convert obvious +element size calculations, but I'm sure I missed some. + +2020-05-12 Richard Sandiford <richard.sandiford@arm.com> + +gcc/ + PR tree-optimization/94980 + * tree.h (vector_element_bits, vector_element_bits_tree): Declare. + * tree.c (vector_element_bits, vector_element_bits_tree): New. + * match.pd: Use the new functions instead of determining the + vector element size directly from TYPE_SIZE(_UNIT). + * tree-vect-data-refs.c (vect_gather_scatter_fn_p): Likewise. + * tree-vect-patterns.c (vect_recog_mask_conversion_pattern): Likewise. + * tree-vect-stmts.c (vect_is_simple_cond): Likewise. + * tree-vect-generic.c (expand_vector_piecewise): Likewise. + (expand_vector_conversion): Likewise. + (expand_vector_addition): Likewise for a TYPE_SIZE_UNIT used as + a divisor. Convert the dividend to bits to compensate. + * tree-vect-loop.c (vectorizable_live_operation): Call + vector_element_bits instead of open-coding it. +--- + gcc/ChangeLog | 17 +++++++++++++++++ + gcc/match.pd | 2 +- + gcc/tree-vect-data-refs.c | 2 +- + gcc/tree-vect-generic.c | 19 +++++++------------ + gcc/tree-vect-loop.c | 4 +--- + gcc/tree-vect-patterns.c | 3 +-- + gcc/tree-vect-stmts.c | 3 +-- + gcc/tree.c | 24 ++++++++++++++++++++++++ + gcc/tree.h | 2 ++ + 9 files changed, 55 insertions(+), 21 deletions(-) + +diff --git a/gcc/ChangeLog b/gcc/ChangeLog +index 3b1384e70..07aea9b86 100644 +--- a/gcc/ChangeLog ++++ b/gcc/ChangeLog +@@ -1,3 +1,20 @@ ++2020-05-12 Richard Sandiford <richard.sandiford@arm.com> ++ ++ PR tree-optimization/94980 ++ * tree.h (vector_element_bits, vector_element_bits_tree): Declare. ++ * tree.c (vector_element_bits, vector_element_bits_tree): New. ++ * match.pd: Use the new functions instead of determining the ++ vector element size directly from TYPE_SIZE(_UNIT). ++ * tree-vect-data-refs.c (vect_gather_scatter_fn_p): Likewise. ++ * tree-vect-patterns.c (vect_recog_mask_conversion_pattern): Likewise. ++ * tree-vect-stmts.c (vect_is_simple_cond): Likewise. ++ * tree-vect-generic.c (expand_vector_piecewise): Likewise. ++ (expand_vector_conversion): Likewise. ++ (expand_vector_addition): Likewise for a TYPE_SIZE_UNIT used as ++ a divisor. Convert the dividend to bits to compensate. ++ * tree-vect-loop.c (vectorizable_live_operation): Call ++ vector_element_bits instead of open-coding it. ++ + 2021-04-08 Release Manager + + * GCC 10.3.0 released. +diff --git a/gcc/match.pd b/gcc/match.pd +index 5899eea95..79a0228d2 100644 +--- a/gcc/match.pd ++++ b/gcc/match.pd +@@ -6236,7 +6236,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) + } + (if (ins) + (bit_insert { op0; } { ins; } +- { bitsize_int (at * tree_to_uhwi (TYPE_SIZE (TREE_TYPE (type)))); }) ++ { bitsize_int (at * vector_element_bits (type)); }) + (if (changed) + (vec_perm { op0; } { op1; } { op2; })))))))))) + +diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c +index d78b06455..e4466a4f3 100644 +--- a/gcc/tree-vect-data-refs.c ++++ b/gcc/tree-vect-data-refs.c +@@ -3709,7 +3709,7 @@ vect_gather_scatter_fn_p (vec_info *vinfo, bool read_p, bool masked_p, + tree *offset_vectype_out) + { + unsigned int memory_bits = tree_to_uhwi (TYPE_SIZE (memory_type)); +- unsigned int element_bits = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (vectype))); ++ unsigned int element_bits = vector_element_bits (vectype); + if (element_bits != memory_bits) + /* For now the vector elements must be the same width as the + memory elements. */ +diff --git a/gcc/tree-vect-generic.c b/gcc/tree-vect-generic.c +index c10492034..37c3956a4 100644 +--- a/gcc/tree-vect-generic.c ++++ b/gcc/tree-vect-generic.c +@@ -276,8 +276,7 @@ expand_vector_piecewise (gimple_stmt_iterator *gsi, elem_op_func f, + tree part_width = TYPE_SIZE (inner_type); + tree index = bitsize_int (0); + int nunits = nunits_for_known_piecewise_op (type); +- int delta = tree_to_uhwi (part_width) +- / tree_to_uhwi (TYPE_SIZE (TREE_TYPE (type))); ++ int delta = tree_to_uhwi (part_width) / vector_element_bits (type); + int i; + location_t loc = gimple_location (gsi_stmt (*gsi)); + +@@ -357,8 +356,7 @@ expand_vector_addition (gimple_stmt_iterator *gsi, + elem_op_func f, elem_op_func f_parallel, + tree type, tree a, tree b, enum tree_code code) + { +- int parts_per_word = UNITS_PER_WORD +- / tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (type))); ++ int parts_per_word = BITS_PER_WORD / vector_element_bits (type); + + if (INTEGRAL_TYPE_P (TREE_TYPE (type)) + && parts_per_word >= 4 +@@ -1733,19 +1731,17 @@ expand_vector_conversion (gimple_stmt_iterator *gsi) + optab optab1 = unknown_optab; + + gcc_checking_assert (VECTOR_TYPE_P (ret_type) && VECTOR_TYPE_P (arg_type)); +- gcc_checking_assert (tree_fits_uhwi_p (TYPE_SIZE (TREE_TYPE (ret_type)))); +- gcc_checking_assert (tree_fits_uhwi_p (TYPE_SIZE (TREE_TYPE (arg_type)))); + if (INTEGRAL_TYPE_P (TREE_TYPE (ret_type)) + && SCALAR_FLOAT_TYPE_P (TREE_TYPE (arg_type))) + code = FIX_TRUNC_EXPR; + else if (INTEGRAL_TYPE_P (TREE_TYPE (arg_type)) + && SCALAR_FLOAT_TYPE_P (TREE_TYPE (ret_type))) + code = FLOAT_EXPR; +- if (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (ret_type))) +- < tree_to_uhwi (TYPE_SIZE (TREE_TYPE (arg_type)))) ++ unsigned int ret_elt_bits = vector_element_bits (ret_type); ++ unsigned int arg_elt_bits = vector_element_bits (arg_type); ++ if (ret_elt_bits < arg_elt_bits) + modifier = NARROW; +- else if (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (ret_type))) +- > tree_to_uhwi (TYPE_SIZE (TREE_TYPE (arg_type)))) ++ else if (ret_elt_bits > arg_elt_bits) + modifier = WIDEN; + + if (modifier == NONE && (code == FIX_TRUNC_EXPR || code == FLOAT_EXPR)) +@@ -1908,8 +1904,7 @@ expand_vector_conversion (gimple_stmt_iterator *gsi) + tree part_width = TYPE_SIZE (compute_type); + tree index = bitsize_int (0); + int nunits = nunits_for_known_piecewise_op (arg_type); +- int delta = tree_to_uhwi (part_width) +- / tree_to_uhwi (TYPE_SIZE (TREE_TYPE (arg_type))); ++ int delta = tree_to_uhwi (part_width) / arg_elt_bits; + int i; + location_t loc = gimple_location (gsi_stmt (*gsi)); + +diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c +index 899b56087..7990e31de 100644 +--- a/gcc/tree-vect-loop.c ++++ b/gcc/tree-vect-loop.c +@@ -8059,9 +8059,7 @@ vectorizable_live_operation (stmt_vec_info stmt_info, + : gimple_get_lhs (stmt); + lhs_type = TREE_TYPE (lhs); + +- bitsize = (VECTOR_BOOLEAN_TYPE_P (vectype) +- ? bitsize_int (TYPE_PRECISION (TREE_TYPE (vectype))) +- : TYPE_SIZE (TREE_TYPE (vectype))); ++ bitsize = vector_element_bits_tree (vectype); + vec_bitsize = TYPE_SIZE (vectype); + + /* Get the vectorized lhs of STMT and the lane to use (counted in bits). */ +diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c +index 84d7ddb17..b076740ef 100644 +--- a/gcc/tree-vect-patterns.c ++++ b/gcc/tree-vect-patterns.c +@@ -4406,8 +4406,7 @@ vect_recog_mask_conversion_pattern (stmt_vec_info stmt_vinfo, tree *type_out) + || dt == vect_constant_def)) + { + tree wide_scalar_type = build_nonstandard_integer_type +- (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (vectype1))), +- TYPE_UNSIGNED (rhs1_type)); ++ (vector_element_bits (vectype1), TYPE_UNSIGNED (rhs1_type)); + tree vectype3 = get_vectype_for_scalar_type (vinfo, + wide_scalar_type); + if (expand_vec_cond_expr_p (vectype1, vectype3, TREE_CODE (rhs1))) +diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c +index 4636b7ba2..0bdf9a547 100644 +--- a/gcc/tree-vect-stmts.c ++++ b/gcc/tree-vect-stmts.c +@@ -10717,8 +10717,7 @@ vect_is_simple_cond (tree cond, vec_info *vinfo, slp_tree slp_node, + && tree_int_cst_lt (TYPE_SIZE (scalar_type), + TYPE_SIZE (TREE_TYPE (vectype)))) + scalar_type = build_nonstandard_integer_type +- (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (vectype))), +- TYPE_UNSIGNED (scalar_type)); ++ (vector_element_bits (vectype), TYPE_UNSIGNED (scalar_type)); + *comp_vectype = get_vectype_for_scalar_type (vinfo, scalar_type, + slp_node); + } +diff --git a/gcc/tree.c b/gcc/tree.c +index 3e6647ae0..9a0cedf10 100644 +--- a/gcc/tree.c ++++ b/gcc/tree.c +@@ -13892,6 +13892,30 @@ vector_type_mode (const_tree t) + return mode; + } + ++/* Return the size in bits of each element of vector type TYPE. */ ++ ++unsigned int ++vector_element_bits (const_tree type) ++{ ++ gcc_checking_assert (VECTOR_TYPE_P (type)); ++ if (VECTOR_BOOLEAN_TYPE_P (type)) ++ return vector_element_size (tree_to_poly_uint64 (TYPE_SIZE (type)), ++ TYPE_VECTOR_SUBPARTS (type)); ++ return tree_to_uhwi (TYPE_SIZE (TREE_TYPE (type))); ++} ++ ++/* Calculate the size in bits of each element of vector type TYPE ++ and return the result as a tree of type bitsizetype. */ ++ ++tree ++vector_element_bits_tree (const_tree type) ++{ ++ gcc_checking_assert (VECTOR_TYPE_P (type)); ++ if (VECTOR_BOOLEAN_TYPE_P (type)) ++ return bitsize_int (vector_element_bits (type)); ++ return TYPE_SIZE (TREE_TYPE (type)); ++} ++ + /* Verify that basic properties of T match TV and thus T can be a variant of + TV. TV should be the more specified variant (i.e. the main variant). */ + +diff --git a/gcc/tree.h b/gcc/tree.h +index bddc6e528..c66207fa0 100644 +--- a/gcc/tree.h ++++ b/gcc/tree.h +@@ -1996,6 +1996,8 @@ class auto_suppress_location_wrappers + + extern machine_mode element_mode (const_tree); + extern machine_mode vector_type_mode (const_tree); ++extern unsigned int vector_element_bits (const_tree); ++extern tree vector_element_bits_tree (const_tree); + + /* The "canonical" type for this type node, which is used by frontends to + compare the type for equality with another type. If two types are +-- +2.27.0.windows.1 + diff --git a/0068-Backport-Lower-VEC_COND_EXPR-into-internal-functions.patch b/0068-Backport-Lower-VEC_COND_EXPR-into-internal-functions.patch new file mode 100644 index 0000000..6bbb8ad --- /dev/null +++ b/0068-Backport-Lower-VEC_COND_EXPR-into-internal-functions.patch @@ -0,0 +1,1063 @@ +From 3a45b2fc131e4639b05f62d6064bd964d129c19b Mon Sep 17 00:00:00 2001 +From: Martin Liska <mliska@suse.cz> +Date: Mon, 9 Mar 2020 13:23:03 +0100 +Subject: [PATCH 20/35] [Backport] Lower VEC_COND_EXPR into internal functions. + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=502d63b6d6141597bb18fd23c87736a1b384cf8f + +gcc/ChangeLog: + + * Makefile.in: Add new file. + * expr.c (expand_expr_real_2): Add gcc_unreachable as we should + not meet this condition. + (do_store_flag): Likewise. + * gimplify.c (gimplify_expr): Gimplify first argument of + VEC_COND_EXPR to be a SSA name. + * internal-fn.c (vec_cond_mask_direct): New. + (vec_cond_direct): Likewise. + (vec_condu_direct): Likewise. + (vec_condeq_direct): Likewise. + (expand_vect_cond_optab_fn): New. + (expand_vec_cond_optab_fn): Likewise. + (expand_vec_condu_optab_fn): Likewise. + (expand_vec_condeq_optab_fn): Likewise. + (expand_vect_cond_mask_optab_fn): Likewise. + (expand_vec_cond_mask_optab_fn): Likewise. + (direct_vec_cond_mask_optab_supported_p): Likewise. + (direct_vec_cond_optab_supported_p): Likewise. + (direct_vec_condu_optab_supported_p): Likewise. + (direct_vec_condeq_optab_supported_p): Likewise. + * internal-fn.def (VCOND): New OPTAB. + (VCONDU): Likewise. + (VCONDEQ): Likewise. + (VCOND_MASK): Likewise. + * optabs.c (get_rtx_code): Make it global. + (expand_vec_cond_mask_expr): Removed. + (expand_vec_cond_expr): Removed. + * optabs.h (expand_vec_cond_expr): Likewise. + (vector_compare_rtx): Make it global. + * passes.def: Add new pass_gimple_isel pass. + * tree-cfg.c (verify_gimple_assign_ternary): Add check + for VEC_COND_EXPR about first argument. + * tree-pass.h (make_pass_gimple_isel): New. + * tree-ssa-forwprop.c (pass_forwprop::execute): Prevent + propagation of the first argument of a VEC_COND_EXPR. + * tree-ssa-reassoc.c (ovce_extract_ops): Support SSA_NAME as + first argument of a VEC_COND_EXPR. + (optimize_vec_cond_expr): Likewise. + * tree-vect-generic.c (expand_vector_divmod): Make SSA_NAME + for a first argument of created VEC_COND_EXPR. + (expand_vector_condition): Fix coding style. + * tree-vect-stmts.c (vectorizable_condition): Gimplify + first argument. + * gimple-isel.cc: New file. + +gcc/testsuite/ChangeLog: + + * g++.dg/vect/vec-cond-expr-eh.C: New test. +--- + gcc/Makefile.in | 2 + + gcc/expr.c | 25 +- + gcc/gimple-isel.cc | 244 +++++++++++++++++++ + gcc/gimplify.c | 15 +- + gcc/internal-fn.c | 89 +++++++ + gcc/internal-fn.def | 5 + + gcc/optabs.c | 124 +--------- + gcc/optabs.h | 7 +- + gcc/passes.def | 1 + + gcc/testsuite/g++.dg/vect/vec-cond-expr-eh.C | 17 ++ + gcc/tree-cfg.c | 2 +- + gcc/tree-pass.h | 1 + + gcc/tree-ssa-forwprop.c | 3 +- + gcc/tree-ssa-reassoc.c | 64 +++-- + gcc/tree-vect-generic.c | 45 ++-- + gcc/tree-vect-stmts.c | 8 +- + 16 files changed, 441 insertions(+), 211 deletions(-) + create mode 100644 gcc/gimple-isel.cc + create mode 100644 gcc/testsuite/g++.dg/vect/vec-cond-expr-eh.C + +diff --git a/gcc/Makefile.in b/gcc/Makefile.in +index 2b2bf474a..3f06b8907 100644 +--- a/gcc/Makefile.in ++++ b/gcc/Makefile.in +@@ -1623,6 +1623,7 @@ OBJS = \ + tree-streamer-out.o \ + tree-tailcall.o \ + tree-vect-generic.o \ ++ gimple-isel.o \ + tree-vect-patterns.o \ + tree-vect-data-refs.o \ + tree-vect-stmts.o \ +@@ -2591,6 +2592,7 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \ + $(srcdir)/dwarf2cfi.c \ + $(srcdir)/dwarf2out.c \ + $(srcdir)/tree-vect-generic.c \ ++ $(srcdir)/gimple-isel.cc \ + $(srcdir)/dojump.c $(srcdir)/emit-rtl.h \ + $(srcdir)/emit-rtl.c $(srcdir)/except.h $(srcdir)/explow.c $(srcdir)/expr.c \ + $(srcdir)/expr.h \ +diff --git a/gcc/expr.c b/gcc/expr.c +index d66fdd4e9..c468b5eb9 100644 +--- a/gcc/expr.c ++++ b/gcc/expr.c +@@ -9286,17 +9286,8 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode, + if (temp != 0) + return temp; + +- /* For vector MIN <x, y>, expand it a VEC_COND_EXPR <x <= y, x, y> +- and similarly for MAX <x, y>. */ + if (VECTOR_TYPE_P (type)) +- { +- tree t0 = make_tree (type, op0); +- tree t1 = make_tree (type, op1); +- tree comparison = build2 (code == MIN_EXPR ? LE_EXPR : GE_EXPR, +- type, t0, t1); +- return expand_vec_cond_expr (type, comparison, t0, t1, +- original_target); +- } ++ gcc_unreachable (); + + /* At this point, a MEM target is no longer useful; we will get better + code without it. */ +@@ -9885,10 +9876,6 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode, + return temp; + } + +- case VEC_COND_EXPR: +- target = expand_vec_cond_expr (type, treeop0, treeop1, treeop2, target); +- return target; +- + case VEC_DUPLICATE_EXPR: + op0 = expand_expr (treeop0, NULL_RTX, VOIDmode, modifier); + target = expand_vector_broadcast (mode, op0); +@@ -12222,8 +12209,7 @@ do_store_flag (sepops ops, rtx target, machine_mode mode) + STRIP_NOPS (arg1); + + /* For vector typed comparisons emit code to generate the desired +- all-ones or all-zeros mask. Conveniently use the VEC_COND_EXPR +- expander for this. */ ++ all-ones or all-zeros mask. */ + if (TREE_CODE (ops->type) == VECTOR_TYPE) + { + tree ifexp = build2 (ops->code, ops->type, arg0, arg1); +@@ -12231,12 +12217,7 @@ do_store_flag (sepops ops, rtx target, machine_mode mode) + && expand_vec_cmp_expr_p (TREE_TYPE (arg0), ops->type, ops->code)) + return expand_vec_cmp_expr (ops->type, ifexp, target); + else +- { +- tree if_true = constant_boolean_node (true, ops->type); +- tree if_false = constant_boolean_node (false, ops->type); +- return expand_vec_cond_expr (ops->type, ifexp, if_true, +- if_false, target); +- } ++ gcc_unreachable (); + } + + /* Optimize (x % C1) == C2 or (x % C1) != C2 if it is beneficial +diff --git a/gcc/gimple-isel.cc b/gcc/gimple-isel.cc +new file mode 100644 +index 000000000..97f920805 +--- /dev/null ++++ b/gcc/gimple-isel.cc +@@ -0,0 +1,244 @@ ++/* Schedule GIMPLE vector statements. ++ Copyright (C) 2020 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/>. */ ++ ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "backend.h" ++#include "rtl.h" ++#include "tree.h" ++#include "gimple.h" ++#include "tree-pass.h" ++#include "ssa.h" ++#include "expmed.h" ++#include "optabs-tree.h" ++#include "tree-eh.h" ++#include "gimple-iterator.h" ++#include "gimplify-me.h" ++#include "gimplify.h" ++#include "tree-cfg.h" ++ ++/* Expand all VEC_COND_EXPR gimple assignments into calls to internal ++ function based on type of selected expansion. */ ++ ++static gimple * ++gimple_expand_vec_cond_expr (gimple_stmt_iterator *gsi, ++ hash_map<tree, unsigned int> *vec_cond_ssa_name_uses) ++{ ++ tree lhs, op0a = NULL_TREE, op0b = NULL_TREE; ++ enum tree_code code; ++ enum tree_code tcode; ++ machine_mode cmp_op_mode; ++ bool unsignedp; ++ enum insn_code icode; ++ imm_use_iterator imm_iter; ++ ++ /* Only consider code == GIMPLE_ASSIGN. */ ++ gassign *stmt = dyn_cast<gassign *> (gsi_stmt (*gsi)); ++ if (!stmt) ++ return NULL; ++ ++ code = gimple_assign_rhs_code (stmt); ++ if (code != VEC_COND_EXPR) ++ return NULL; ++ ++ tree op0 = gimple_assign_rhs1 (stmt); ++ tree op1 = gimple_assign_rhs2 (stmt); ++ tree op2 = gimple_assign_rhs3 (stmt); ++ lhs = gimple_assign_lhs (stmt); ++ machine_mode mode = TYPE_MODE (TREE_TYPE (lhs)); ++ ++ gcc_assert (!COMPARISON_CLASS_P (op0)); ++ if (TREE_CODE (op0) == SSA_NAME) ++ { ++ unsigned int used_vec_cond_exprs = 0; ++ unsigned int *slot = vec_cond_ssa_name_uses->get (op0); ++ if (slot) ++ used_vec_cond_exprs = *slot; ++ else ++ { ++ gimple *use_stmt; ++ FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, op0) ++ { ++ gassign *assign = dyn_cast<gassign *> (use_stmt); ++ if (assign != NULL ++ && gimple_assign_rhs_code (assign) == VEC_COND_EXPR ++ && gimple_assign_rhs1 (assign) == op0) ++ used_vec_cond_exprs++; ++ } ++ vec_cond_ssa_name_uses->put (op0, used_vec_cond_exprs); ++ } ++ ++ gassign *def_stmt = dyn_cast<gassign *> (SSA_NAME_DEF_STMT (op0)); ++ if (def_stmt) ++ { ++ tcode = gimple_assign_rhs_code (def_stmt); ++ op0a = gimple_assign_rhs1 (def_stmt); ++ op0b = gimple_assign_rhs2 (def_stmt); ++ ++ tree op0a_type = TREE_TYPE (op0a); ++ if (used_vec_cond_exprs >= 2 ++ && (get_vcond_mask_icode (mode, TYPE_MODE (op0a_type)) ++ != CODE_FOR_nothing) ++ && expand_vec_cmp_expr_p (op0a_type, TREE_TYPE (lhs), tcode)) ++ { ++ /* Keep the SSA name and use vcond_mask. */ ++ tcode = TREE_CODE (op0); ++ } ++ } ++ else ++ tcode = TREE_CODE (op0); ++ } ++ else ++ tcode = TREE_CODE (op0); ++ ++ if (TREE_CODE_CLASS (tcode) != tcc_comparison) ++ { ++ gcc_assert (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (op0))); ++ if (get_vcond_mask_icode (mode, TYPE_MODE (TREE_TYPE (op0))) ++ != CODE_FOR_nothing) ++ return gimple_build_call_internal (IFN_VCOND_MASK, 3, op0, op1, op2); ++ /* Fake op0 < 0. */ ++ else ++ { ++ gcc_assert (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (op0))) ++ == MODE_VECTOR_INT); ++ op0a = op0; ++ op0b = build_zero_cst (TREE_TYPE (op0)); ++ tcode = LT_EXPR; ++ } ++ } ++ cmp_op_mode = TYPE_MODE (TREE_TYPE (op0a)); ++ unsignedp = TYPE_UNSIGNED (TREE_TYPE (op0a)); ++ ++ ++ gcc_assert (known_eq (GET_MODE_SIZE (mode), GET_MODE_SIZE (cmp_op_mode)) ++ && known_eq (GET_MODE_NUNITS (mode), ++ GET_MODE_NUNITS (cmp_op_mode))); ++ ++ icode = get_vcond_icode (mode, cmp_op_mode, unsignedp); ++ if (icode == CODE_FOR_nothing) ++ { ++ if (tcode == LT_EXPR ++ && op0a == op0 ++ && TREE_CODE (op0) == VECTOR_CST) ++ { ++ /* A VEC_COND_EXPR condition could be folded from EQ_EXPR/NE_EXPR ++ into a constant when only get_vcond_eq_icode is supported. ++ Verify < 0 and != 0 behave the same and change it to NE_EXPR. */ ++ unsigned HOST_WIDE_INT nelts; ++ if (!VECTOR_CST_NELTS (op0).is_constant (&nelts)) ++ { ++ if (VECTOR_CST_STEPPED_P (op0)) ++ gcc_unreachable (); ++ nelts = vector_cst_encoded_nelts (op0); ++ } ++ for (unsigned int i = 0; i < nelts; ++i) ++ if (tree_int_cst_sgn (vector_cst_elt (op0, i)) == 1) ++ gcc_unreachable (); ++ tcode = NE_EXPR; ++ } ++ if (tcode == EQ_EXPR || tcode == NE_EXPR) ++ { ++ tree tcode_tree = build_int_cst (integer_type_node, tcode); ++ return gimple_build_call_internal (IFN_VCONDEQ, 5, op0a, op0b, op1, ++ op2, tcode_tree); ++ } ++ } ++ ++ gcc_assert (icode != CODE_FOR_nothing); ++ tree tcode_tree = build_int_cst (integer_type_node, tcode); ++ return gimple_build_call_internal (unsignedp ? IFN_VCONDU : IFN_VCOND, ++ 5, op0a, op0b, op1, op2, tcode_tree); ++} ++ ++ ++ ++/* Iterate all gimple statements and try to expand ++ VEC_COND_EXPR assignments. */ ++ ++static unsigned int ++gimple_expand_vec_cond_exprs (void) ++{ ++ gimple_stmt_iterator gsi; ++ basic_block bb; ++ bool cfg_changed = false; ++ hash_map<tree, unsigned int> vec_cond_ssa_name_uses; ++ ++ FOR_EACH_BB_FN (bb, cfun) ++ { ++ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) ++ { ++ gimple *g = gimple_expand_vec_cond_expr (&gsi, ++ &vec_cond_ssa_name_uses); ++ if (g != NULL) ++ { ++ tree lhs = gimple_assign_lhs (gsi_stmt (gsi)); ++ gimple_set_lhs (g, lhs); ++ gsi_replace (&gsi, g, false); ++ } ++ } ++ } ++ ++ return cfg_changed ? TODO_cleanup_cfg : 0; ++} ++ ++namespace { ++ ++const pass_data pass_data_gimple_isel = ++{ ++ GIMPLE_PASS, /* type */ ++ "isel", /* name */ ++ OPTGROUP_VEC, /* optinfo_flags */ ++ TV_NONE, /* tv_id */ ++ PROP_cfg, /* properties_required */ ++ 0, /* properties_provided */ ++ 0, /* properties_destroyed */ ++ 0, /* todo_flags_start */ ++ TODO_update_ssa, /* todo_flags_finish */ ++}; ++ ++class pass_gimple_isel : public gimple_opt_pass ++{ ++public: ++ pass_gimple_isel (gcc::context *ctxt) ++ : gimple_opt_pass (pass_data_gimple_isel, ctxt) ++ {} ++ ++ /* opt_pass methods: */ ++ virtual bool gate (function *) ++ { ++ return true; ++ } ++ ++ virtual unsigned int execute (function *) ++ { ++ return gimple_expand_vec_cond_exprs (); ++ } ++ ++}; // class pass_gimple_isel ++ ++} // anon namespace ++ ++gimple_opt_pass * ++make_pass_gimple_isel (gcc::context *ctxt) ++{ ++ return new pass_gimple_isel (ctxt); ++} ++ +diff --git a/gcc/gimplify.c b/gcc/gimplify.c +index 89a4ae087..16b2f4328 100644 +--- a/gcc/gimplify.c ++++ b/gcc/gimplify.c +@@ -14272,20 +14272,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, + } + + case VEC_COND_EXPR: +- { +- enum gimplify_status r0, r1, r2; +- +- r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, +- post_p, is_gimple_condexpr, fb_rvalue); +- r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, +- post_p, is_gimple_val, fb_rvalue); +- r2 = gimplify_expr (&TREE_OPERAND (*expr_p, 2), pre_p, +- post_p, is_gimple_val, fb_rvalue); +- +- ret = MIN (MIN (r0, r1), r2); +- recalculate_side_effects (*expr_p); +- } +- break; ++ goto expr_3; + + case VEC_PERM_EXPR: + /* Classified as tcc_expression. */ +diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c +index 5e9aa6072..644f234e0 100644 +--- a/gcc/internal-fn.c ++++ b/gcc/internal-fn.c +@@ -49,6 +49,7 @@ along with GCC; see the file COPYING3. If not see + #include "gimple-ssa.h" + #include "tree-phinodes.h" + #include "ssa-iterators.h" ++#include "explow.h" + + /* The names of each internal function, indexed by function number. */ + const char *const internal_fn_name_array[] = { +@@ -107,6 +108,10 @@ init_internal_fns () + #define mask_store_direct { 3, 2, false } + #define store_lanes_direct { 0, 0, false } + #define mask_store_lanes_direct { 0, 0, false } ++#define vec_cond_mask_direct { 0, 0, false } ++#define vec_cond_direct { 0, 0, false } ++#define vec_condu_direct { 0, 0, false } ++#define vec_condeq_direct { 0, 0, false } + #define scatter_store_direct { 3, 1, false } + #define unary_direct { 0, 0, true } + #define binary_direct { 0, 0, true } +@@ -2548,6 +2553,86 @@ expand_mask_store_optab_fn (internal_fn, gcall *stmt, convert_optab optab) + + #define expand_mask_store_lanes_optab_fn expand_mask_store_optab_fn + ++/* Expand VCOND, VCONDU and VCONDEQ optab internal functions. ++ The expansion of STMT happens based on OPTAB table associated. */ ++ ++static void ++expand_vect_cond_optab_fn (internal_fn, gcall *stmt, convert_optab optab) ++{ ++ class expand_operand ops[6]; ++ insn_code icode; ++ tree lhs = gimple_call_lhs (stmt); ++ tree op0a = gimple_call_arg (stmt, 0); ++ tree op0b = gimple_call_arg (stmt, 1); ++ tree op1 = gimple_call_arg (stmt, 2); ++ tree op2 = gimple_call_arg (stmt, 3); ++ enum tree_code tcode = (tree_code) int_cst_value (gimple_call_arg (stmt, 4)); ++ ++ tree vec_cond_type = TREE_TYPE (lhs); ++ tree op_mode = TREE_TYPE (op0a); ++ bool unsignedp = TYPE_UNSIGNED (op_mode); ++ ++ machine_mode mode = TYPE_MODE (vec_cond_type); ++ machine_mode cmp_op_mode = TYPE_MODE (op_mode); ++ ++ icode = convert_optab_handler (optab, mode, cmp_op_mode); ++ rtx comparison ++ = vector_compare_rtx (VOIDmode, tcode, op0a, op0b, unsignedp, icode, 4); ++ rtx rtx_op1 = expand_normal (op1); ++ rtx rtx_op2 = expand_normal (op2); ++ ++ rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE); ++ create_output_operand (&ops[0], target, mode); ++ create_input_operand (&ops[1], rtx_op1, mode); ++ create_input_operand (&ops[2], rtx_op2, mode); ++ create_fixed_operand (&ops[3], comparison); ++ create_fixed_operand (&ops[4], XEXP (comparison, 0)); ++ create_fixed_operand (&ops[5], XEXP (comparison, 1)); ++ expand_insn (icode, 6, ops); ++} ++ ++#define expand_vec_cond_optab_fn expand_vect_cond_optab_fn ++#define expand_vec_condu_optab_fn expand_vect_cond_optab_fn ++#define expand_vec_condeq_optab_fn expand_vect_cond_optab_fn ++ ++/* Expand VCOND_MASK optab internal function. ++ The expansion of STMT happens based on OPTAB table associated. */ ++ ++static void ++expand_vect_cond_mask_optab_fn (internal_fn, gcall *stmt, convert_optab optab) ++{ ++ class expand_operand ops[4]; ++ ++ tree lhs = gimple_call_lhs (stmt); ++ tree op0 = gimple_call_arg (stmt, 0); ++ tree op1 = gimple_call_arg (stmt, 1); ++ tree op2 = gimple_call_arg (stmt, 2); ++ tree vec_cond_type = TREE_TYPE (lhs); ++ ++ machine_mode mode = TYPE_MODE (vec_cond_type); ++ machine_mode mask_mode = TYPE_MODE (TREE_TYPE (op0)); ++ enum insn_code icode = convert_optab_handler (optab, mode, mask_mode); ++ rtx mask, rtx_op1, rtx_op2; ++ ++ gcc_assert (icode != CODE_FOR_nothing); ++ ++ mask = expand_normal (op0); ++ rtx_op1 = expand_normal (op1); ++ rtx_op2 = expand_normal (op2); ++ ++ mask = force_reg (mask_mode, mask); ++ rtx_op1 = force_reg (GET_MODE (rtx_op1), rtx_op1); ++ ++ rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE); ++ create_output_operand (&ops[0], target, mode); ++ create_input_operand (&ops[1], rtx_op1, mode); ++ create_input_operand (&ops[2], rtx_op2, mode); ++ create_input_operand (&ops[3], mask, mask_mode); ++ expand_insn (icode, 4, ops); ++} ++ ++#define expand_vec_cond_mask_optab_fn expand_vect_cond_mask_optab_fn ++ + static void + expand_ABNORMAL_DISPATCHER (internal_fn, gcall *) + { +@@ -3131,6 +3216,10 @@ multi_vector_optab_supported_p (convert_optab optab, tree_pair types, + #define direct_mask_store_optab_supported_p direct_optab_supported_p + #define direct_store_lanes_optab_supported_p multi_vector_optab_supported_p + #define direct_mask_store_lanes_optab_supported_p multi_vector_optab_supported_p ++#define direct_vec_cond_mask_optab_supported_p multi_vector_optab_supported_p ++#define direct_vec_cond_optab_supported_p multi_vector_optab_supported_p ++#define direct_vec_condu_optab_supported_p multi_vector_optab_supported_p ++#define direct_vec_condeq_optab_supported_p multi_vector_optab_supported_p + #define direct_scatter_store_optab_supported_p convert_optab_supported_p + #define direct_while_optab_supported_p convert_optab_supported_p + #define direct_fold_extract_optab_supported_p direct_optab_supported_p +diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def +index 1d190d492..0c6fc3711 100644 +--- a/gcc/internal-fn.def ++++ b/gcc/internal-fn.def +@@ -136,6 +136,11 @@ DEF_INTERNAL_OPTAB_FN (STORE_LANES, ECF_CONST, vec_store_lanes, store_lanes) + DEF_INTERNAL_OPTAB_FN (MASK_STORE_LANES, 0, + vec_mask_store_lanes, mask_store_lanes) + ++DEF_INTERNAL_OPTAB_FN (VCOND, 0, vcond, vec_cond) ++DEF_INTERNAL_OPTAB_FN (VCONDU, 0, vcondu, vec_condu) ++DEF_INTERNAL_OPTAB_FN (VCONDEQ, 0, vcondeq, vec_condeq) ++DEF_INTERNAL_OPTAB_FN (VCOND_MASK, 0, vcond_mask, vec_cond_mask) ++ + DEF_INTERNAL_OPTAB_FN (WHILE_ULT, ECF_CONST | ECF_NOTHROW, while_ult, while) + DEF_INTERNAL_OPTAB_FN (CHECK_RAW_PTRS, ECF_CONST | ECF_NOTHROW, + check_raw_ptrs, check_ptrs) +diff --git a/gcc/optabs.c b/gcc/optabs.c +index c3751fdf7..64a1a1768 100644 +--- a/gcc/optabs.c ++++ b/gcc/optabs.c +@@ -5454,7 +5454,7 @@ get_rtx_code (enum tree_code tcode, bool unsignedp) + first comparison operand for insn ICODE. Do not generate the + compare instruction itself. */ + +-static rtx ++rtx + vector_compare_rtx (machine_mode cmp_mode, enum tree_code tcode, + tree t_op0, tree t_op1, bool unsignedp, + enum insn_code icode, unsigned int opno) +@@ -5821,128 +5821,6 @@ expand_vec_perm_var (machine_mode mode, rtx v0, rtx v1, rtx sel, rtx target) + return tmp; + } + +-/* Generate insns for a VEC_COND_EXPR with mask, given its TYPE and its +- three operands. */ +- +-rtx +-expand_vec_cond_mask_expr (tree vec_cond_type, tree op0, tree op1, tree op2, +- rtx target) +-{ +- class expand_operand ops[4]; +- machine_mode mode = TYPE_MODE (vec_cond_type); +- machine_mode mask_mode = TYPE_MODE (TREE_TYPE (op0)); +- enum insn_code icode = get_vcond_mask_icode (mode, mask_mode); +- rtx mask, rtx_op1, rtx_op2; +- +- if (icode == CODE_FOR_nothing) +- return 0; +- +- mask = expand_normal (op0); +- rtx_op1 = expand_normal (op1); +- rtx_op2 = expand_normal (op2); +- +- mask = force_reg (mask_mode, mask); +- rtx_op1 = force_reg (GET_MODE (rtx_op1), rtx_op1); +- +- create_output_operand (&ops[0], target, mode); +- create_input_operand (&ops[1], rtx_op1, mode); +- create_input_operand (&ops[2], rtx_op2, mode); +- create_input_operand (&ops[3], mask, mask_mode); +- expand_insn (icode, 4, ops); +- +- return ops[0].value; +-} +- +-/* Generate insns for a VEC_COND_EXPR, given its TYPE and its +- three operands. */ +- +-rtx +-expand_vec_cond_expr (tree vec_cond_type, tree op0, tree op1, tree op2, +- rtx target) +-{ +- class expand_operand ops[6]; +- enum insn_code icode; +- rtx comparison, rtx_op1, rtx_op2; +- machine_mode mode = TYPE_MODE (vec_cond_type); +- machine_mode cmp_op_mode; +- bool unsignedp; +- tree op0a, op0b; +- enum tree_code tcode; +- +- if (COMPARISON_CLASS_P (op0)) +- { +- op0a = TREE_OPERAND (op0, 0); +- op0b = TREE_OPERAND (op0, 1); +- tcode = TREE_CODE (op0); +- } +- else +- { +- gcc_assert (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (op0))); +- if (get_vcond_mask_icode (mode, TYPE_MODE (TREE_TYPE (op0))) +- != CODE_FOR_nothing) +- return expand_vec_cond_mask_expr (vec_cond_type, op0, op1, +- op2, target); +- /* Fake op0 < 0. */ +- else +- { +- gcc_assert (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (op0))) +- == MODE_VECTOR_INT); +- op0a = op0; +- op0b = build_zero_cst (TREE_TYPE (op0)); +- tcode = LT_EXPR; +- } +- } +- cmp_op_mode = TYPE_MODE (TREE_TYPE (op0a)); +- unsignedp = TYPE_UNSIGNED (TREE_TYPE (op0a)); +- +- +- gcc_assert (known_eq (GET_MODE_SIZE (mode), GET_MODE_SIZE (cmp_op_mode)) +- && known_eq (GET_MODE_NUNITS (mode), +- GET_MODE_NUNITS (cmp_op_mode))); +- +- icode = get_vcond_icode (mode, cmp_op_mode, unsignedp); +- if (icode == CODE_FOR_nothing) +- { +- if (tcode == LT_EXPR +- && op0a == op0 +- && TREE_CODE (op0) == VECTOR_CST) +- { +- /* A VEC_COND_EXPR condition could be folded from EQ_EXPR/NE_EXPR +- into a constant when only get_vcond_eq_icode is supported. +- Verify < 0 and != 0 behave the same and change it to NE_EXPR. */ +- unsigned HOST_WIDE_INT nelts; +- if (!VECTOR_CST_NELTS (op0).is_constant (&nelts)) +- { +- if (VECTOR_CST_STEPPED_P (op0)) +- return 0; +- nelts = vector_cst_encoded_nelts (op0); +- } +- for (unsigned int i = 0; i < nelts; ++i) +- if (tree_int_cst_sgn (vector_cst_elt (op0, i)) == 1) +- return 0; +- tcode = NE_EXPR; +- } +- if (tcode == EQ_EXPR || tcode == NE_EXPR) +- icode = get_vcond_eq_icode (mode, cmp_op_mode); +- if (icode == CODE_FOR_nothing) +- return 0; +- } +- +- comparison = vector_compare_rtx (VOIDmode, tcode, op0a, op0b, unsignedp, +- icode, 4); +- rtx_op1 = expand_normal (op1); +- rtx_op2 = expand_normal (op2); +- +- create_output_operand (&ops[0], target, mode); +- create_input_operand (&ops[1], rtx_op1, mode); +- create_input_operand (&ops[2], rtx_op2, mode); +- create_fixed_operand (&ops[3], comparison); +- create_fixed_operand (&ops[4], XEXP (comparison, 0)); +- create_fixed_operand (&ops[5], XEXP (comparison, 1)); +- expand_insn (icode, 6, ops); +- return ops[0].value; +-} +- + /* Generate VEC_SERIES_EXPR <OP0, OP1>, returning a value of mode VMODE. + Use TARGET for the result if nonnull and convenient. */ + +diff --git a/gcc/optabs.h b/gcc/optabs.h +index 5bd19503a..7c2ec257c 100644 +--- a/gcc/optabs.h ++++ b/gcc/optabs.h +@@ -321,9 +321,6 @@ extern rtx expand_vec_perm_const (machine_mode, rtx, rtx, + /* Generate code for vector comparison. */ + extern rtx expand_vec_cmp_expr (tree, tree, rtx); + +-/* Generate code for VEC_COND_EXPR. */ +-extern rtx expand_vec_cond_expr (tree, tree, tree, tree, rtx); +- + /* Generate code for VEC_SERIES_EXPR. */ + extern rtx expand_vec_series_expr (machine_mode, rtx, rtx, rtx); + +@@ -364,5 +361,9 @@ extern void expand_jump_insn (enum insn_code icode, unsigned int nops, + class expand_operand *ops); + + extern enum rtx_code get_rtx_code (enum tree_code tcode, bool unsignedp); ++extern rtx vector_compare_rtx (machine_mode cmp_mode, enum tree_code tcode, ++ tree t_op0, tree t_op1, bool unsignedp, ++ enum insn_code icode, unsigned int opno); ++ + + #endif /* GCC_OPTABS_H */ +diff --git a/gcc/passes.def b/gcc/passes.def +index 94554cc1d..5a62819cc 100644 +--- a/gcc/passes.def ++++ b/gcc/passes.def +@@ -403,6 +403,7 @@ along with GCC; see the file COPYING3. If not see + NEXT_PASS (pass_cleanup_eh); + NEXT_PASS (pass_lower_resx); + NEXT_PASS (pass_nrv); ++ NEXT_PASS (pass_gimple_isel); + NEXT_PASS (pass_cleanup_cfg_post_optimizing); + NEXT_PASS (pass_warn_function_noreturn); + NEXT_PASS (pass_gen_hsail); +diff --git a/gcc/testsuite/g++.dg/vect/vec-cond-expr-eh.C b/gcc/testsuite/g++.dg/vect/vec-cond-expr-eh.C +new file mode 100644 +index 000000000..00fe24224 +--- /dev/null ++++ b/gcc/testsuite/g++.dg/vect/vec-cond-expr-eh.C +@@ -0,0 +1,17 @@ ++/* { dg-do compile } */ ++/* { dg-additional-options "-fnon-call-exceptions" } */ ++ ++typedef double v2df __attribute__((vector_size(16))); ++ ++v2df foo (v2df a, v2df b, v2df c, v2df d) ++{ ++ try ++ { ++ v2df res = a < b ? c : d; ++ return res; ++ } ++ catch (...) ++ { ++ return (v2df){}; ++ } ++} +diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c +index 1af59fc6f..d82fe23d8 100644 +--- a/gcc/tree-cfg.c ++++ b/gcc/tree-cfg.c +@@ -4196,7 +4196,7 @@ verify_gimple_assign_ternary (gassign *stmt) + return true; + } + +- if (((rhs_code == VEC_COND_EXPR || rhs_code == COND_EXPR) ++ if ((rhs_code == COND_EXPR + ? !is_gimple_condexpr (rhs1) : !is_gimple_val (rhs1)) + || !is_gimple_val (rhs2) + || !is_gimple_val (rhs3)) +diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h +index 09dd9b289..1c620b28e 100644 +--- a/gcc/tree-pass.h ++++ b/gcc/tree-pass.h +@@ -631,6 +631,7 @@ extern gimple_opt_pass *make_pass_local_fn_summary (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_update_address_taken (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_convert_switch (gcc::context *ctxt); + extern gimple_opt_pass *make_pass_lower_vaarg (gcc::context *ctxt); ++extern gimple_opt_pass *make_pass_gimple_isel (gcc::context *ctxt); + + /* Current optimization pass. */ + extern opt_pass *current_pass; +diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c +index 3161d2e39..ba0b55f4a 100644 +--- a/gcc/tree-ssa-forwprop.c ++++ b/gcc/tree-ssa-forwprop.c +@@ -3131,8 +3131,7 @@ pass_forwprop::execute (function *fun) + tree rhs1 = gimple_assign_rhs1 (stmt); + enum tree_code code = gimple_assign_rhs_code (stmt); + +- if (code == COND_EXPR +- || code == VEC_COND_EXPR) ++ if (code == COND_EXPR) + { + /* In this case the entire COND_EXPR is in rhs1. */ + if (forward_propagate_into_cond (&gsi)) +diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c +index af8df8563..5f978ac78 100644 +--- a/gcc/tree-ssa-reassoc.c ++++ b/gcc/tree-ssa-reassoc.c +@@ -3830,7 +3830,8 @@ optimize_range_tests (enum tree_code opcode, + to type of comparison. */ + + static tree_code +-ovce_extract_ops (tree var, gassign **rets, bool *reti, tree *type) ++ovce_extract_ops (tree var, gassign **rets, bool *reti, tree *type, ++ tree *lhs, tree *rhs, gassign **vcond) + { + if (TREE_CODE (var) != SSA_NAME) + return ERROR_MARK; +@@ -3838,6 +3839,8 @@ ovce_extract_ops (tree var, gassign **rets, bool *reti, tree *type) + gassign *stmt = dyn_cast <gassign *> (SSA_NAME_DEF_STMT (var)); + if (stmt == NULL) + return ERROR_MARK; ++ if (*vcond) ++ *vcond = stmt; + + /* ??? If we start creating more COND_EXPR, we could perform + this same optimization with them. For now, simplify. */ +@@ -3846,9 +3849,20 @@ ovce_extract_ops (tree var, gassign **rets, bool *reti, tree *type) + + tree cond = gimple_assign_rhs1 (stmt); + tree_code cmp = TREE_CODE (cond); +- if (TREE_CODE_CLASS (cmp) != tcc_comparison) ++ if (cmp != SSA_NAME) + return ERROR_MARK; + ++ gassign *assign = dyn_cast<gassign *> (SSA_NAME_DEF_STMT (cond)); ++ if (stmt == NULL ++ || TREE_CODE_CLASS (gimple_assign_rhs_code (assign)) != tcc_comparison) ++ return ERROR_MARK; ++ ++ cmp = gimple_assign_rhs_code (assign); ++ if (lhs) ++ *lhs = gimple_assign_rhs1 (assign); ++ if (rhs) ++ *rhs = gimple_assign_rhs2 (assign); ++ + /* ??? For now, allow only canonical true and false result vectors. + We could expand this to other constants should the need arise, + but at the moment we don't create them. */ +@@ -3869,7 +3883,7 @@ ovce_extract_ops (tree var, gassign **rets, bool *reti, tree *type) + + /* Success! */ + if (rets) +- *rets = stmt; ++ *rets = assign; + if (reti) + *reti = inv; + if (type) +@@ -3893,10 +3907,11 @@ optimize_vec_cond_expr (tree_code opcode, vec<operand_entry *> *ops) + { + tree elt0 = (*ops)[i]->op; + +- gassign *stmt0; ++ gassign *stmt0, *vcond0; + bool invert; +- tree type; +- tree_code cmp0 = ovce_extract_ops (elt0, &stmt0, &invert, &type); ++ tree type, lhs0, rhs0; ++ tree_code cmp0 = ovce_extract_ops (elt0, &stmt0, &invert, &type, &lhs0, ++ &rhs0, &vcond0); + if (cmp0 == ERROR_MARK) + continue; + +@@ -3904,26 +3919,20 @@ optimize_vec_cond_expr (tree_code opcode, vec<operand_entry *> *ops) + { + tree &elt1 = (*ops)[j]->op; + +- gassign *stmt1; +- tree_code cmp1 = ovce_extract_ops (elt1, &stmt1, NULL, NULL); ++ gassign *stmt1, *vcond1; ++ tree lhs1, rhs1; ++ tree_code cmp1 = ovce_extract_ops (elt1, &stmt1, NULL, NULL, &lhs1, ++ &rhs1, &vcond1); + if (cmp1 == ERROR_MARK) + continue; + +- tree cond0 = gimple_assign_rhs1 (stmt0); +- tree x0 = TREE_OPERAND (cond0, 0); +- tree y0 = TREE_OPERAND (cond0, 1); +- +- tree cond1 = gimple_assign_rhs1 (stmt1); +- tree x1 = TREE_OPERAND (cond1, 0); +- tree y1 = TREE_OPERAND (cond1, 1); +- + tree comb; + if (opcode == BIT_AND_EXPR) +- comb = maybe_fold_and_comparisons (type, cmp0, x0, y0, cmp1, x1, +- y1); ++ comb = maybe_fold_and_comparisons (type, cmp0, lhs0, rhs0, ++ cmp1, lhs1, rhs1); + else if (opcode == BIT_IOR_EXPR) +- comb = maybe_fold_or_comparisons (type, cmp0, x0, y0, cmp1, x1, +- y1); ++ comb = maybe_fold_or_comparisons (type, cmp0, lhs0, rhs0, ++ cmp1, lhs1, rhs1); + else + gcc_unreachable (); + if (comb == NULL) +@@ -3933,19 +3942,22 @@ optimize_vec_cond_expr (tree_code opcode, vec<operand_entry *> *ops) + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Transforming "); +- print_generic_expr (dump_file, cond0); ++ print_generic_expr (dump_file, gimple_assign_lhs (stmt0)); + fprintf (dump_file, " %c ", opcode == BIT_AND_EXPR ? '&' : '|'); +- print_generic_expr (dump_file, cond1); ++ print_generic_expr (dump_file, gimple_assign_lhs (stmt1)); + fprintf (dump_file, " into "); + print_generic_expr (dump_file, comb); + fputc ('\n', dump_file); + } + +- gimple_assign_set_rhs1 (stmt0, comb); ++ gimple_stmt_iterator gsi = gsi_for_stmt (vcond0); ++ tree exp = force_gimple_operand_gsi (&gsi, comb, true, NULL_TREE, ++ true, GSI_SAME_STMT); + if (invert) +- std::swap (*gimple_assign_rhs2_ptr (stmt0), +- *gimple_assign_rhs3_ptr (stmt0)); +- update_stmt (stmt0); ++ swap_ssa_operands (vcond0, gimple_assign_rhs2_ptr (vcond0), ++ gimple_assign_rhs3_ptr (vcond0)); ++ gimple_assign_set_rhs1 (vcond0, exp); ++ update_stmt (vcond0); + + elt1 = error_mark_node; + any_changes = true; +diff --git a/gcc/tree-vect-generic.c b/gcc/tree-vect-generic.c +index 37c3956a4..0ec4412bc 100644 +--- a/gcc/tree-vect-generic.c ++++ b/gcc/tree-vect-generic.c +@@ -693,12 +693,14 @@ expand_vector_divmod (gimple_stmt_iterator *gsi, tree type, tree op0, + if (addend == NULL_TREE + && expand_vec_cond_expr_p (type, type, LT_EXPR)) + { +- tree zero, cst, cond, mask_type; +- gimple *stmt; ++ tree zero, cst, mask_type, mask; ++ gimple *stmt, *cond; + + mask_type = truth_type_for (type); + zero = build_zero_cst (type); +- cond = build2 (LT_EXPR, mask_type, op0, zero); ++ mask = make_ssa_name (mask_type); ++ cond = gimple_build_assign (mask, LT_EXPR, op0, zero); ++ gsi_insert_before (gsi, cond, GSI_SAME_STMT); + tree_vector_builder vec (type, nunits, 1); + for (i = 0; i < nunits; i++) + vec.quick_push (build_int_cst (TREE_TYPE (type), +@@ -706,8 +708,8 @@ expand_vector_divmod (gimple_stmt_iterator *gsi, tree type, tree op0, + << shifts[i]) - 1)); + cst = vec.build (); + addend = make_ssa_name (type); +- stmt = gimple_build_assign (addend, VEC_COND_EXPR, cond, +- cst, zero); ++ stmt ++ = gimple_build_assign (addend, VEC_COND_EXPR, mask, cst, zero); + gsi_insert_before (gsi, stmt, GSI_SAME_STMT); + } + } +@@ -949,21 +951,28 @@ expand_vector_condition (gimple_stmt_iterator *gsi) + tree index = bitsize_int (0); + tree comp_width = width; + tree comp_index = index; +- int i; + location_t loc = gimple_location (gsi_stmt (*gsi)); ++ tree_code code = TREE_CODE (a); + +- if (!is_gimple_val (a)) ++ if (code == SSA_NAME) + { +- gcc_assert (COMPARISON_CLASS_P (a)); +- a_is_comparison = true; +- a1 = TREE_OPERAND (a, 0); +- a2 = TREE_OPERAND (a, 1); +- comp_inner_type = TREE_TYPE (TREE_TYPE (a1)); +- comp_width = TYPE_SIZE (comp_inner_type); ++ gimple *assign = SSA_NAME_DEF_STMT (a); ++ if (TREE_CODE_CLASS (gimple_assign_rhs_code (assign)) == tcc_comparison) ++ { ++ a_is_comparison = true; ++ a1 = gimple_assign_rhs1 (assign); ++ a2 = gimple_assign_rhs2 (assign); ++ code = gimple_assign_rhs_code (assign); ++ comp_inner_type = TREE_TYPE (TREE_TYPE (a1)); ++ comp_width = vector_element_bits_tree (TREE_TYPE (a1)); ++ } + } + +- if (expand_vec_cond_expr_p (type, TREE_TYPE (a1), TREE_CODE (a))) +- return; ++ if (expand_vec_cond_expr_p (type, TREE_TYPE (a1), code)) ++ { ++ gcc_assert (TREE_CODE (a) == SSA_NAME || TREE_CODE (a) == VECTOR_CST); ++ return; ++ } + + /* Handle vector boolean types with bitmasks. If there is a comparison + and we can expand the comparison into the vector boolean bitmask, +@@ -986,7 +995,7 @@ expand_vector_condition (gimple_stmt_iterator *gsi) + : expand_vec_cmp_expr_p (TREE_TYPE (a1), type, TREE_CODE (a)))) + { + if (a_is_comparison) +- a = gimplify_build2 (gsi, TREE_CODE (a), type, a1, a2); ++ a = gimplify_build2 (gsi, code, type, a1, a2); + a1 = gimplify_build2 (gsi, BIT_AND_EXPR, type, a, b); + a2 = gimplify_build1 (gsi, BIT_NOT_EXPR, type, a); + a2 = gimplify_build2 (gsi, BIT_AND_EXPR, type, a2, c); +@@ -1017,7 +1026,7 @@ expand_vector_condition (gimple_stmt_iterator *gsi) + + int nunits = nunits_for_known_piecewise_op (type); + vec_alloc (v, nunits); +- for (i = 0; i < nunits; i++) ++ for (int i = 0; i < nunits; i++) + { + tree aa, result; + tree bb = tree_vec_extract (gsi, inner_type, b, width, index); +@@ -1028,7 +1037,7 @@ expand_vector_condition (gimple_stmt_iterator *gsi) + comp_width, comp_index); + tree aa2 = tree_vec_extract (gsi, comp_inner_type, a2, + comp_width, comp_index); +- aa = fold_build2 (TREE_CODE (a), cond_type, aa1, aa2); ++ aa = fold_build2 (code, cond_type, aa1, aa2); + } + else if (a_is_scalar_bitmask) + { +diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c +index 0bdf9a547..2c2197022 100644 +--- a/gcc/tree-vect-stmts.c ++++ b/gcc/tree-vect-stmts.c +@@ -11100,8 +11100,12 @@ vectorizable_condition (stmt_vec_info stmt_info, gimple_stmt_iterator *gsi, + { + vec_cond_rhs = vec_oprnds1[i]; + if (bitop1 == NOP_EXPR) +- vec_compare = build2 (cond_code, vec_cmp_type, +- vec_cond_lhs, vec_cond_rhs); ++ { ++ gimple_seq stmts = NULL; ++ vec_compare = gimple_build (&stmts, cond_code, vec_cmp_type, ++ vec_cond_lhs, vec_cond_rhs); ++ gsi_insert_before (gsi, stmts, GSI_SAME_STMT); ++ } + else + { + new_temp = make_ssa_name (vec_cmp_type); +-- +2.27.0.windows.1 + diff --git a/0069-Backport-gimple-match-Add-a-gimple_extract_op-functi.patch b/0069-Backport-gimple-match-Add-a-gimple_extract_op-functi.patch new file mode 100644 index 0000000..7ef1e00 --- /dev/null +++ b/0069-Backport-gimple-match-Add-a-gimple_extract_op-functi.patch @@ -0,0 +1,379 @@ +From 21d265af074726b166e08301a2f847c474fcb680 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Tue, 30 Nov 2021 09:52:24 +0000 +Subject: [PATCH 21/35] [Backport] gimple-match: Add a gimple_extract_op + function + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=33973fa754de1f95d459bfca66c0d80deec36537 + +code_helper and gimple_match_op seem like generally useful ways +of summing up a gimple_assign or gimple_call (or gimple_cond). +This patch adds a gimple_extract_op function that can be used +for that. + +gcc/ + * gimple-match.h (code_helper): Add functions for querying whether + the code represents an internal_fn or a built_in_function. + Provide explicit conversion operators for both cases. + (gimple_extract_op): Declare. + * gimple-match-head.c (gimple_extract): New function, extracted from... + (gimple_simplify): ...here. + (gimple_extract_op): New function. +--- + gcc/gimple-match-head.c | 219 ++++++++++++++++++++-------------------- + gcc/gimple-match.h | 27 +++++ + 2 files changed, 135 insertions(+), 111 deletions(-) + +diff --git a/gcc/gimple-match-head.c b/gcc/gimple-match-head.c +index 9b3e7298d..c1dea1734 100644 +--- a/gcc/gimple-match-head.c ++++ b/gcc/gimple-match-head.c +@@ -884,12 +884,20 @@ try_conditional_simplification (internal_fn ifn, gimple_match_op *res_op, + return true; + } + +-/* The main STMT based simplification entry. It is used by the fold_stmt +- and the fold_stmt_to_constant APIs. */ ++/* Common subroutine of gimple_extract_op and gimple_simplify. Try to ++ describe STMT in RES_OP, returning true on success. Before recording ++ an operand, call: + +-bool +-gimple_simplify (gimple *stmt, gimple_match_op *res_op, gimple_seq *seq, +- tree (*valueize)(tree), tree (*top_valueize)(tree)) ++ - VALUEIZE_CONDITION for a COND_EXPR condition ++ - VALUEIZE_OP for every other top-level operand ++ ++ Both routines take a tree argument and returns a tree. */ ++ ++template<typename ValueizeOp, typename ValueizeCondition> ++inline bool ++gimple_extract (gimple *stmt, gimple_match_op *res_op, ++ ValueizeOp valueize_op, ++ ValueizeCondition valueize_condition) + { + switch (gimple_code (stmt)) + { +@@ -905,101 +913,50 @@ gimple_simplify (gimple *stmt, gimple_match_op *res_op, gimple_seq *seq, + || code == VIEW_CONVERT_EXPR) + { + tree op0 = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0); +- bool valueized = false; +- op0 = do_valueize (op0, top_valueize, valueized); +- res_op->set_op (code, type, op0); +- return (gimple_resimplify1 (seq, res_op, valueize) +- || valueized); ++ res_op->set_op (code, type, valueize_op (op0)); ++ return true; + } + else if (code == BIT_FIELD_REF) + { + tree rhs1 = gimple_assign_rhs1 (stmt); +- tree op0 = TREE_OPERAND (rhs1, 0); +- bool valueized = false; +- op0 = do_valueize (op0, top_valueize, valueized); ++ tree op0 = valueize_op (TREE_OPERAND (rhs1, 0)); + res_op->set_op (code, type, op0, + TREE_OPERAND (rhs1, 1), + TREE_OPERAND (rhs1, 2), + REF_REVERSE_STORAGE_ORDER (rhs1)); +- if (res_op->reverse) +- return valueized; +- return (gimple_resimplify3 (seq, res_op, valueize) +- || valueized); ++ return true; + } +- else if (code == SSA_NAME +- && top_valueize) ++ else if (code == SSA_NAME) + { + tree op0 = gimple_assign_rhs1 (stmt); +- tree valueized = top_valueize (op0); +- if (!valueized || op0 == valueized) +- return false; +- res_op->set_op (TREE_CODE (op0), type, valueized); ++ res_op->set_op (TREE_CODE (op0), type, valueize_op (op0)); + return true; + } + break; + case GIMPLE_UNARY_RHS: + { + tree rhs1 = gimple_assign_rhs1 (stmt); +- bool valueized = false; +- rhs1 = do_valueize (rhs1, top_valueize, valueized); +- res_op->set_op (code, type, rhs1); +- return (gimple_resimplify1 (seq, res_op, valueize) +- || valueized); ++ res_op->set_op (code, type, valueize_op (rhs1)); ++ return true; + } + case GIMPLE_BINARY_RHS: + { +- tree rhs1 = gimple_assign_rhs1 (stmt); +- tree rhs2 = gimple_assign_rhs2 (stmt); +- bool valueized = false; +- rhs1 = do_valueize (rhs1, top_valueize, valueized); +- rhs2 = do_valueize (rhs2, top_valueize, valueized); ++ tree rhs1 = valueize_op (gimple_assign_rhs1 (stmt)); ++ tree rhs2 = valueize_op (gimple_assign_rhs2 (stmt)); + res_op->set_op (code, type, rhs1, rhs2); +- return (gimple_resimplify2 (seq, res_op, valueize) +- || valueized); ++ return true; + } + case GIMPLE_TERNARY_RHS: + { +- bool valueized = false; + tree rhs1 = gimple_assign_rhs1 (stmt); +- /* If this is a [VEC_]COND_EXPR first try to simplify an +- embedded GENERIC condition. */ +- if (code == COND_EXPR +- || code == VEC_COND_EXPR) +- { +- if (COMPARISON_CLASS_P (rhs1)) +- { +- tree lhs = TREE_OPERAND (rhs1, 0); +- tree rhs = TREE_OPERAND (rhs1, 1); +- lhs = do_valueize (lhs, top_valueize, valueized); +- rhs = do_valueize (rhs, top_valueize, valueized); +- gimple_match_op res_op2 (res_op->cond, TREE_CODE (rhs1), +- TREE_TYPE (rhs1), lhs, rhs); +- if ((gimple_resimplify2 (seq, &res_op2, valueize) +- || valueized) +- && res_op2.code.is_tree_code ()) +- { +- valueized = true; +- if (TREE_CODE_CLASS ((enum tree_code) res_op2.code) +- == tcc_comparison) +- rhs1 = build2 (res_op2.code, TREE_TYPE (rhs1), +- res_op2.ops[0], res_op2.ops[1]); +- else if (res_op2.code == SSA_NAME +- || res_op2.code == INTEGER_CST +- || res_op2.code == VECTOR_CST) +- rhs1 = res_op2.ops[0]; +- else +- valueized = false; +- } +- } +- } +- tree rhs2 = gimple_assign_rhs2 (stmt); +- tree rhs3 = gimple_assign_rhs3 (stmt); +- rhs1 = do_valueize (rhs1, top_valueize, valueized); +- rhs2 = do_valueize (rhs2, top_valueize, valueized); +- rhs3 = do_valueize (rhs3, top_valueize, valueized); ++ if (code == COND_EXPR && COMPARISON_CLASS_P (rhs1)) ++ rhs1 = valueize_condition (rhs1); ++ else ++ rhs1 = valueize_op (rhs1); ++ tree rhs2 = valueize_op (gimple_assign_rhs2 (stmt)); ++ tree rhs3 = valueize_op (gimple_assign_rhs3 (stmt)); + res_op->set_op (code, type, rhs1, rhs2, rhs3); +- return (gimple_resimplify3 (seq, res_op, valueize) +- || valueized); ++ return true; + } + default: + gcc_unreachable (); +@@ -1013,7 +970,6 @@ gimple_simplify (gimple *stmt, gimple_match_op *res_op, gimple_seq *seq, + && gimple_call_num_args (stmt) >= 1 + && gimple_call_num_args (stmt) <= 5) + { +- bool valueized = false; + combined_fn cfn; + if (gimple_call_internal_p (stmt)) + cfn = as_combined_fn (gimple_call_internal_fn (stmt)); +@@ -1023,7 +979,7 @@ gimple_simplify (gimple *stmt, gimple_match_op *res_op, gimple_seq *seq, + if (!fn) + return false; + +- fn = do_valueize (fn, top_valueize, valueized); ++ fn = valueize_op (fn); + if (TREE_CODE (fn) != ADDR_EXPR + || TREE_CODE (TREE_OPERAND (fn, 0)) != FUNCTION_DECL) + return false; +@@ -1039,47 +995,17 @@ gimple_simplify (gimple *stmt, gimple_match_op *res_op, gimple_seq *seq, + unsigned int num_args = gimple_call_num_args (stmt); + res_op->set_op (cfn, TREE_TYPE (gimple_call_lhs (stmt)), num_args); + for (unsigned i = 0; i < num_args; ++i) +- { +- tree arg = gimple_call_arg (stmt, i); +- res_op->ops[i] = do_valueize (arg, top_valueize, valueized); +- } +- if (internal_fn_p (cfn) +- && try_conditional_simplification (as_internal_fn (cfn), +- res_op, seq, valueize)) +- return true; +- switch (num_args) +- { +- case 1: +- return (gimple_resimplify1 (seq, res_op, valueize) +- || valueized); +- case 2: +- return (gimple_resimplify2 (seq, res_op, valueize) +- || valueized); +- case 3: +- return (gimple_resimplify3 (seq, res_op, valueize) +- || valueized); +- case 4: +- return (gimple_resimplify4 (seq, res_op, valueize) +- || valueized); +- case 5: +- return (gimple_resimplify5 (seq, res_op, valueize) +- || valueized); +- default: +- gcc_unreachable (); +- } ++ res_op->ops[i] = valueize_op (gimple_call_arg (stmt, i)); ++ return true; + } + break; + + case GIMPLE_COND: + { +- tree lhs = gimple_cond_lhs (stmt); +- tree rhs = gimple_cond_rhs (stmt); +- bool valueized = false; +- lhs = do_valueize (lhs, top_valueize, valueized); +- rhs = do_valueize (rhs, top_valueize, valueized); ++ tree lhs = valueize_op (gimple_cond_lhs (stmt)); ++ tree rhs = valueize_op (gimple_cond_rhs (stmt)); + res_op->set_op (gimple_cond_code (stmt), boolean_type_node, lhs, rhs); +- return (gimple_resimplify2 (seq, res_op, valueize) +- || valueized); ++ return true; + } + + default: +@@ -1089,6 +1015,77 @@ gimple_simplify (gimple *stmt, gimple_match_op *res_op, gimple_seq *seq, + return false; + } + ++/* Try to describe STMT in RES_OP, returning true on success. ++ For GIMPLE_CONDs, describe the condition that is being tested. ++ For GIMPLE_ASSIGNs, describe the rhs of the assignment. ++ For GIMPLE_CALLs, describe the call. */ ++ ++bool ++gimple_extract_op (gimple *stmt, gimple_match_op *res_op) ++{ ++ auto nop = [](tree op) { return op; }; ++ return gimple_extract (stmt, res_op, nop, nop); ++} ++ ++/* The main STMT based simplification entry. It is used by the fold_stmt ++ and the fold_stmt_to_constant APIs. */ ++ ++bool ++gimple_simplify (gimple *stmt, gimple_match_op *res_op, gimple_seq *seq, ++ tree (*valueize)(tree), tree (*top_valueize)(tree)) ++{ ++ bool valueized = false; ++ auto valueize_op = [&](tree op) ++ { ++ return do_valueize (op, top_valueize, valueized); ++ }; ++ auto valueize_condition = [&](tree op) -> tree ++ { ++ bool cond_valueized = false; ++ tree lhs = do_valueize (TREE_OPERAND (op, 0), top_valueize, ++ cond_valueized); ++ tree rhs = do_valueize (TREE_OPERAND (op, 1), top_valueize, ++ cond_valueized); ++ gimple_match_op res_op2 (res_op->cond, TREE_CODE (op), ++ TREE_TYPE (op), lhs, rhs); ++ if ((gimple_resimplify2 (seq, &res_op2, valueize) ++ || cond_valueized) ++ && res_op2.code.is_tree_code ()) ++ { ++ if (TREE_CODE_CLASS ((tree_code) res_op2.code) == tcc_comparison) ++ { ++ valueized = true; ++ return build2 (res_op2.code, TREE_TYPE (op), ++ res_op2.ops[0], res_op2.ops[1]); ++ } ++ else if (res_op2.code == SSA_NAME ++ || res_op2.code == INTEGER_CST ++ || res_op2.code == VECTOR_CST) ++ { ++ valueized = true; ++ return res_op2.ops[0]; ++ } ++ } ++ return valueize_op (op); ++ }; ++ ++ if (!gimple_extract (stmt, res_op, valueize_op, valueize_condition)) ++ return false; ++ ++ if (res_op->code.is_internal_fn ()) ++ { ++ internal_fn ifn = internal_fn (res_op->code); ++ if (try_conditional_simplification (ifn, res_op, seq, valueize)) ++ return true; ++ } ++ ++ if (!res_op->reverse ++ && res_op->num_ops ++ && res_op->resimplify (seq, valueize)) ++ return true; ++ ++ return valueized; ++} + + /* Helper for the autogenerated code, valueize OP. */ + +diff --git a/gcc/gimple-match.h b/gcc/gimple-match.h +index 097898aed..39858c45f 100644 +--- a/gcc/gimple-match.h ++++ b/gcc/gimple-match.h +@@ -33,13 +33,39 @@ public: + code_helper (combined_fn fn) : rep (-(int) fn) {} + operator tree_code () const { return (tree_code) rep; } + operator combined_fn () const { return (combined_fn) -rep; } ++ explicit operator internal_fn () const; ++ explicit operator built_in_function () const; + bool is_tree_code () const { return rep > 0; } + bool is_fn_code () const { return rep < 0; } ++ bool is_internal_fn () const; ++ bool is_builtin_fn () const; + int get_rep () const { return rep; } + private: + int rep; + }; + ++inline code_helper::operator internal_fn () const ++{ ++ return as_internal_fn (combined_fn (*this)); ++} ++ ++inline code_helper::operator built_in_function () const ++{ ++ return as_builtin_fn (combined_fn (*this)); ++} ++ ++inline bool ++code_helper::is_internal_fn () const ++{ ++ return is_fn_code () && internal_fn_p (combined_fn (*this)); ++} ++ ++inline bool ++code_helper::is_builtin_fn () const ++{ ++ return is_fn_code () && builtin_fn_p (combined_fn (*this)); ++} ++ + /* Represents the condition under which an operation should happen, + and the value to use otherwise. The condition applies elementwise + (as for VEC_COND_EXPR) if the values are vectors. */ +@@ -333,6 +359,7 @@ gimple_simplified_result_is_gimple_val (const gimple_match_op *op) + + extern tree (*mprts_hook) (gimple_match_op *); + ++bool gimple_extract_op (gimple *, gimple_match_op *); + bool gimple_simplify (gimple *, gimple_match_op *, gimple_seq *, + tree (*)(tree), tree (*)(tree)); + tree maybe_push_res_to_seq (gimple_match_op *, gimple_seq *, +-- +2.27.0.windows.1 + diff --git a/0070-Backport-aarch64-Fix-subs_compare_2.c-regression-PR1.patch b/0070-Backport-aarch64-Fix-subs_compare_2.c-regression-PR1.patch new file mode 100644 index 0000000..ab9ac6e --- /dev/null +++ b/0070-Backport-aarch64-Fix-subs_compare_2.c-regression-PR1.patch @@ -0,0 +1,1004 @@ +From f6b6948de1d836b594ad388388b7121dd7a702cb Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Tue, 15 Feb 2022 18:09:35 +0000 +Subject: [PATCH 22/35] [Backport] aarch64: Fix subs_compare_2.c regression + [PR100874] +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=8e84b2b37a541b27feea69769fc314d534464ebd + +subs_compare_2.c tests that we can use a SUBS+CSEL sequence for: + +unsigned int +foo (unsigned int a, unsigned int b) +{ + unsigned int x = a - 4; + if (a < 4) + return x; + else + return 0; +} + +As Andrew notes in the PR, this is effectively MIN (x, 4) - 4, +and it is now recognised as such by phiopt. Previously it was +if-converted in RTL instead. + +I tried to look for ways to generalise this to other situations +and to other ?:-style operations, not just max and min. However, +for general ?: we tend to push an outer “- CST” into the arms of +the ?: -- at least if one of them simplifies -- so I didn't find +any useful abstraction. + +This patch therefore adds a pattern specifically for +max/min(a,cst)-cst. I'm not thrilled at having to do this, +but it seems like the least worst fix in the circumstances. +Also, max(a,cst)-cst for unsigned a is a useful saturating +subtraction idiom and so is arguably worth its own code +for that reason. + +gcc/ + PR target/100874 + * config/aarch64/aarch64-protos.h (aarch64_maxmin_plus_const): + Declare. + * config/aarch64/aarch64.cc (aarch64_maxmin_plus_const): New function. + * config/aarch64/aarch64.md (*aarch64_minmax_plus): New pattern. + +gcc/testsuite/ + * gcc.target/aarch64/max_plus_1.c: New test. + * gcc.target/aarch64/max_plus_2.c: Likewise. + * gcc.target/aarch64/max_plus_3.c: Likewise. + * gcc.target/aarch64/max_plus_4.c: Likewise. + * gcc.target/aarch64/max_plus_5.c: Likewise. + * gcc.target/aarch64/max_plus_6.c: Likewise. + * gcc.target/aarch64/max_plus_7.c: Likewise. + * gcc.target/aarch64/min_plus_1.c: Likewise. + * gcc.target/aarch64/min_plus_2.c: Likewise. + * gcc.target/aarch64/min_plus_3.c: Likewise. + * gcc.target/aarch64/min_plus_4.c: Likewise. + * gcc.target/aarch64/min_plus_5.c: Likewise. + * gcc.target/aarch64/min_plus_6.c: Likewise. + * gcc.target/aarch64/min_plus_7.c: Likewise. +--- + gcc/config/aarch64/aarch64-protos.h | 1 + + gcc/config/aarch64/aarch64.c | 104 ++++++++++++ + gcc/config/aarch64/aarch64.md | 27 ++++ + gcc/testsuite/gcc.target/aarch64/max_plus_1.c | 149 ++++++++++++++++++ + gcc/testsuite/gcc.target/aarch64/max_plus_2.c | 35 ++++ + gcc/testsuite/gcc.target/aarch64/max_plus_3.c | 35 ++++ + gcc/testsuite/gcc.target/aarch64/max_plus_4.c | 30 ++++ + gcc/testsuite/gcc.target/aarch64/max_plus_5.c | 35 ++++ + gcc/testsuite/gcc.target/aarch64/max_plus_6.c | 9 ++ + gcc/testsuite/gcc.target/aarch64/max_plus_7.c | 35 ++++ + gcc/testsuite/gcc.target/aarch64/min_plus_1.c | 149 ++++++++++++++++++ + gcc/testsuite/gcc.target/aarch64/min_plus_2.c | 35 ++++ + gcc/testsuite/gcc.target/aarch64/min_plus_3.c | 35 ++++ + gcc/testsuite/gcc.target/aarch64/min_plus_4.c | 30 ++++ + gcc/testsuite/gcc.target/aarch64/min_plus_5.c | 35 ++++ + gcc/testsuite/gcc.target/aarch64/min_plus_6.c | 9 ++ + gcc/testsuite/gcc.target/aarch64/min_plus_7.c | 35 ++++ + 17 files changed, 788 insertions(+) + create mode 100644 gcc/testsuite/gcc.target/aarch64/max_plus_1.c + create mode 100644 gcc/testsuite/gcc.target/aarch64/max_plus_2.c + create mode 100644 gcc/testsuite/gcc.target/aarch64/max_plus_3.c + create mode 100644 gcc/testsuite/gcc.target/aarch64/max_plus_4.c + create mode 100644 gcc/testsuite/gcc.target/aarch64/max_plus_5.c + create mode 100644 gcc/testsuite/gcc.target/aarch64/max_plus_6.c + create mode 100644 gcc/testsuite/gcc.target/aarch64/max_plus_7.c + create mode 100644 gcc/testsuite/gcc.target/aarch64/min_plus_1.c + create mode 100644 gcc/testsuite/gcc.target/aarch64/min_plus_2.c + create mode 100644 gcc/testsuite/gcc.target/aarch64/min_plus_3.c + create mode 100644 gcc/testsuite/gcc.target/aarch64/min_plus_4.c + create mode 100644 gcc/testsuite/gcc.target/aarch64/min_plus_5.c + create mode 100644 gcc/testsuite/gcc.target/aarch64/min_plus_6.c + create mode 100644 gcc/testsuite/gcc.target/aarch64/min_plus_7.c + +diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h +index 226f3a8ff..9b6d309a7 100644 +--- a/gcc/config/aarch64/aarch64-protos.h ++++ b/gcc/config/aarch64/aarch64-protos.h +@@ -696,6 +696,7 @@ bool aarch64_legitimate_address_p (machine_mode, rtx, bool, + aarch64_addr_query_type = ADDR_QUERY_M); + machine_mode aarch64_select_cc_mode (RTX_CODE, rtx, rtx); + rtx aarch64_gen_compare_reg (RTX_CODE, rtx, rtx); ++bool aarch64_maxmin_plus_const (rtx_code, rtx *, bool); + rtx aarch64_load_tp (rtx); + + void aarch64_expand_compare_and_swap (rtx op[]); +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index f78942b04..85dbd3898 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -3038,6 +3038,110 @@ aarch64_gen_compare_reg_maybe_ze (RTX_CODE code, rtx x, rtx y, + return aarch64_gen_compare_reg (code, x, y); + } + ++/* Consider the operation: ++ ++ OPERANDS[0] = CODE (OPERANDS[1], OPERANDS[2]) + OPERANDS[3] ++ ++ where: ++ ++ - CODE is [SU]MAX or [SU]MIN ++ - OPERANDS[2] and OPERANDS[3] are constant integers ++ - OPERANDS[3] is a positive or negative shifted 12-bit immediate ++ - all operands have mode MODE ++ ++ Decide whether it is possible to implement the operation using: ++ ++ SUBS <tmp>, OPERANDS[1], -OPERANDS[3] ++ or ++ ADDS <tmp>, OPERANDS[1], OPERANDS[3] ++ ++ followed by: ++ ++ <insn> OPERANDS[0], <tmp>, [wx]zr, <cond> ++ ++ where <insn> is one of CSEL, CSINV or CSINC. Return true if so. ++ If GENERATE_P is true, also update OPERANDS as follows: ++ ++ OPERANDS[4] = -OPERANDS[3] ++ OPERANDS[5] = the rtl condition representing <cond> ++ OPERANDS[6] = <tmp> ++ OPERANDS[7] = 0 for CSEL, -1 for CSINV or 1 for CSINC. */ ++bool ++aarch64_maxmin_plus_const (rtx_code code, rtx *operands, bool generate_p) ++{ ++ signop sgn = (code == UMAX || code == UMIN ? UNSIGNED : SIGNED); ++ rtx dst = operands[0]; ++ rtx maxmin_op = operands[2]; ++ rtx add_op = operands[3]; ++ machine_mode mode = GET_MODE (dst); ++ ++ /* max (x, y) - z == (x >= y + 1 ? x : y) - z ++ == (x >= y ? x : y) - z ++ == (x > y ? x : y) - z ++ == (x > y - 1 ? x : y) - z ++ ++ min (x, y) - z == (x <= y - 1 ? x : y) - z ++ == (x <= y ? x : y) - z ++ == (x < y ? x : y) - z ++ == (x < y + 1 ? x : y) - z ++ ++ Check whether z is in { y - 1, y, y + 1 } and pick the form(s) for ++ which x is compared with z. Set DIFF to y - z. Thus the supported ++ combinations are as follows, with DIFF being the value after the ":": ++ ++ max (x, y) - z == x >= y + 1 ? x - (y + 1) : -1 [z == y + 1] ++ == x >= y ? x - y : 0 [z == y] ++ == x > y ? x - y : 0 [z == y] ++ == x > y - 1 ? x - (y - 1) : 1 [z == y - 1] ++ ++ min (x, y) - z == x <= y - 1 ? x - (y - 1) : 1 [z == y - 1] ++ == x <= y ? x - y : 0 [z == y] ++ == x < y ? x - y : 0 [z == y] ++ == x < y + 1 ? x - (y + 1) : -1 [z == y + 1]. */ ++ auto maxmin_val = rtx_mode_t (maxmin_op, mode); ++ auto add_val = rtx_mode_t (add_op, mode); ++ auto sub_val = wi::neg (add_val); ++ auto diff = wi::sub (maxmin_val, sub_val); ++ if (!(diff == 0 ++ || (diff == 1 && wi::gt_p (maxmin_val, sub_val, sgn)) ++ || (diff == -1 && wi::lt_p (maxmin_val, sub_val, sgn)))) ++ return false; ++ ++ if (!generate_p) ++ return true; ++ ++ rtx_code cmp; ++ switch (code) ++ { ++ case SMAX: ++ cmp = diff == 1 ? GT : GE; ++ break; ++ case UMAX: ++ cmp = diff == 1 ? GTU : GEU; ++ break; ++ case SMIN: ++ cmp = diff == -1 ? LT : LE; ++ break; ++ case UMIN: ++ cmp = diff == -1 ? LTU : LEU; ++ break; ++ default: ++ gcc_unreachable (); ++ } ++ rtx cc = gen_rtx_REG (CCmode, CC_REGNUM); ++ ++ operands[4] = immed_wide_int_const (sub_val, mode); ++ operands[5] = gen_rtx_fmt_ee (cmp, VOIDmode, cc, const0_rtx); ++ if (can_create_pseudo_p ()) ++ operands[6] = gen_reg_rtx (mode); ++ else ++ operands[6] = dst; ++ operands[7] = immed_wide_int_const (diff, mode); ++ ++ return true; ++} ++ ++ + /* Build the SYMBOL_REF for __tls_get_addr. */ + + static GTY(()) rtx tls_get_addr_libfunc; +diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md +index ee80261f1..7c2562f49 100644 +--- a/gcc/config/aarch64/aarch64.md ++++ b/gcc/config/aarch64/aarch64.md +@@ -4499,6 +4499,33 @@ + } + ) + ++;; Implement MAX/MIN (A, B) - C using SUBS/ADDS followed by CSEL/CSINV/CSINC. ++;; See aarch64_maxmin_plus_const for details about the supported cases. ++(define_insn_and_split "*aarch64_minmax_plus" ++ [(set (match_operand:GPI 0 "register_operand" "=r") ++ (plus:GPI ++ (MAXMIN:GPI ++ (match_operand:GPI 1 "register_operand" "r") ++ (match_operand:GPI 2 "const_int_operand")) ++ (match_operand:GPI 3 "aarch64_plus_immediate"))) ++ (clobber (reg:CC CC_REGNUM))] ++ "aarch64_maxmin_plus_const (<CODE>, operands, false)" ++ "#" ++ "&& 1" ++ [(parallel ++ [(set (reg:CC CC_REGNUM) ++ (compare:CC (match_dup 1) (match_dup 4))) ++ (set (match_dup 6) ++ (plus:GPI (match_dup 1) (match_dup 3)))]) ++ (set (match_dup 0) ++ (if_then_else:GPI (match_dup 5) (match_dup 6) (match_dup 7)))] ++ { ++ if (!aarch64_maxmin_plus_const (<CODE>, operands, true)) ++ gcc_unreachable (); ++ } ++ [(set_attr "length" "8")] ++) ++ + ;; ------------------------------------------------------------------- + ;; Logical operations + ;; ------------------------------------------------------------------- +diff --git a/gcc/testsuite/gcc.target/aarch64/max_plus_1.c b/gcc/testsuite/gcc.target/aarch64/max_plus_1.c +new file mode 100644 +index 000000000..ef336aeec +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/max_plus_1.c +@@ -0,0 +1,149 @@ ++/* { dg-do run } */ ++/* { dg-options "-O2 --save-temps" } */ ++/* { dg-final { check-function-bodies "**" "" "" } } */ ++ ++/* ++** f1: ++** adds (w[0-9]+), w0, #4 ++** csel w0, \1, wzr, g[te] ++** ret ++*/ ++/* ++** f2: ++** adds (w[0-9]+), w0, #4 ++** csel w0, \1, wzr, g[te] ++** ret ++*/ ++/* ++** f3: ++** adds (w[0-9]+), w0, #5 ++** csinc w0, \1, wzr, gt ++** ret ++*/ ++/* ++** f4: ++** adds (w[0-9]+), w0, #3 ++** csinv w0, \1, wzr, ge ++** ret ++*/ ++ ++#ifndef TYPE ++#define TYPE int32_t ++#define TYPE_MIN INT32_MIN ++#define TYPE_MAX INT32_MAX ++#define VALUE -4 ++#endif ++ ++#include <stdint.h> ++ ++TYPE __attribute__((noipa)) ++f1 (TYPE x) ++{ ++ return (x > VALUE ? x - VALUE : 0); ++} ++ ++TYPE __attribute__((noipa)) ++f2 (TYPE x) ++{ ++ return (x > VALUE ? x : VALUE) - VALUE; ++} ++ ++TYPE __attribute__((noipa)) ++f3 (TYPE x) ++{ ++ return (x > VALUE ? x : VALUE) - (VALUE - 1); ++} ++ ++TYPE __attribute__((noipa)) ++f4 (TYPE x) ++{ ++ return (x > VALUE ? x : VALUE) - (VALUE + 1); ++} ++ ++TYPE __attribute__((noipa)) ++f5 (TYPE x) ++{ ++ return (x > VALUE ? x : VALUE) - (VALUE + 2); ++} ++ ++TYPE __attribute__((noipa)) ++f6 (TYPE x) ++{ ++ return (x > VALUE ? x : VALUE) - (VALUE - 2); ++} ++ ++int ++main (void) ++{ ++ TYPE max_test = TYPE_MAX; ++ if (TYPE_MIN < 0 && VALUE < 0) ++ max_test += VALUE; ++ ++ if (f1 (TYPE_MIN) != 0) ++ __builtin_abort (); ++ if (f1 (VALUE - 1) != 0) ++ __builtin_abort (); ++ if (f1 (VALUE) != 0) ++ __builtin_abort (); ++ if (f1 (VALUE + 1) != 1) ++ __builtin_abort (); ++ if (f1 (max_test) != max_test - VALUE) ++ __builtin_abort (); ++ ++ if (f2 (TYPE_MIN) != 0) ++ __builtin_abort (); ++ if (f2 (VALUE - 1) != 0) ++ __builtin_abort (); ++ if (f2 (VALUE) != 0) ++ __builtin_abort (); ++ if (f2 (VALUE + 1) != 1) ++ __builtin_abort (); ++ if (f2 (max_test) != max_test - VALUE) ++ __builtin_abort (); ++ ++ if (f3 (TYPE_MIN) != 1) ++ __builtin_abort (); ++ if (f3 (VALUE - 1) != 1) ++ __builtin_abort (); ++ if (f3 (VALUE) != 1) ++ __builtin_abort (); ++ if (f3 (VALUE + 1) != 2) ++ __builtin_abort (); ++ if (f3 (max_test - 1) != max_test - VALUE) ++ __builtin_abort (); ++ ++ if (f4 (TYPE_MIN) != -1) ++ __builtin_abort (); ++ if (f4 (VALUE - 1) != -1) ++ __builtin_abort (); ++ if (f4 (VALUE) != -1) ++ __builtin_abort (); ++ if (f4 (VALUE + 1) != 0) ++ __builtin_abort (); ++ if (f4 (max_test) != max_test - VALUE - 1) ++ __builtin_abort (); ++ ++ if (f5 (TYPE_MIN) != -2) ++ __builtin_abort (); ++ if (f5 (VALUE - 1) != -2) ++ __builtin_abort (); ++ if (f5 (VALUE) != -2) ++ __builtin_abort (); ++ if (f5 (VALUE + 1) != -1) ++ __builtin_abort (); ++ if (f5 (max_test) != max_test - VALUE - 2) ++ __builtin_abort (); ++ ++ if (f6 (TYPE_MIN) != 2) ++ __builtin_abort (); ++ if (f6 (VALUE - 1) != 2) ++ __builtin_abort (); ++ if (f6 (VALUE) != 2) ++ __builtin_abort (); ++ if (f6 (VALUE + 1) != 3) ++ __builtin_abort (); ++ if (VALUE <= max_test - 2 && f6 (max_test - 2) != max_test - VALUE) ++ __builtin_abort (); ++ ++ return 0; ++} +diff --git a/gcc/testsuite/gcc.target/aarch64/max_plus_2.c b/gcc/testsuite/gcc.target/aarch64/max_plus_2.c +new file mode 100644 +index 000000000..a2a1295d9 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/max_plus_2.c +@@ -0,0 +1,35 @@ ++/* { dg-do run } */ ++/* { dg-options "-O2 --save-temps" } */ ++/* { dg-final { check-function-bodies "**" "" "" } } */ ++ ++/* ++** f1: ++** adds (x[0-9]+), x0, #4094 ++** csel x0, \1, xzr, g[te] ++** ret ++*/ ++/* ++** f2: ++** adds (x[0-9]+), x0, #4094 ++** csel x0, \1, xzr, g[te] ++** ret ++*/ ++/* ++** f3: ++** adds (x[0-9]+), x0, #4095 ++** csinc x0, \1, xzr, gt ++** ret ++*/ ++/* ++** f4: ++** adds (x[0-9]+), x0, #4093 ++** csinv x0, \1, xzr, ge ++** ret ++*/ ++ ++#define TYPE int64_t ++#define TYPE_MIN INT64_MIN ++#define TYPE_MAX INT64_MAX ++#define VALUE -4094 ++ ++#include "max_plus_1.c" +diff --git a/gcc/testsuite/gcc.target/aarch64/max_plus_3.c b/gcc/testsuite/gcc.target/aarch64/max_plus_3.c +new file mode 100644 +index 000000000..a9792ecc9 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/max_plus_3.c +@@ -0,0 +1,35 @@ ++/* { dg-do run } */ ++/* { dg-options "-O2 --save-temps" } */ ++/* { dg-final { check-function-bodies "**" "" "" } } */ ++ ++/* ++** f1: ++** adds (w[0-9]+), w0, #4095 ++** csel w0, \1, wzr, g[te] ++** ret ++*/ ++/* ++** f2: ++** adds (w[0-9]+), w0, #4095 ++** csel w0, \1, wzr, g[te] ++** ret ++*/ ++/* ++** f3: ++** adds (w[0-9]+), w0, #4096 ++** csinc w0, \1, wzr, gt ++** ret ++*/ ++/* ++** f4: ++** adds (w[0-9]+), w0, #4094 ++** csinv w0, \1, wzr, ge ++** ret ++*/ ++ ++#define TYPE int32_t ++#define TYPE_MIN INT32_MIN ++#define TYPE_MAX INT32_MAX ++#define VALUE -4095 ++ ++#include "max_plus_1.c" +diff --git a/gcc/testsuite/gcc.target/aarch64/max_plus_4.c b/gcc/testsuite/gcc.target/aarch64/max_plus_4.c +new file mode 100644 +index 000000000..5090fa101 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/max_plus_4.c +@@ -0,0 +1,30 @@ ++/* { dg-do run } */ ++/* { dg-options "-O2 --save-temps" } */ ++/* { dg-final { check-function-bodies "**" "" "" } } */ ++ ++/* ++** f1: ++** adds (x[0-9]+), x0, #4096 ++** csel x0, \1, xzr, g[te] ++** ret ++*/ ++/* ++** f2: ++** adds (x[0-9]+), x0, #4096 ++** csel x0, \1, xzr, g[te] ++** ret ++*/ ++/* f3 out of range */ ++/* ++** f4: ++** adds (x[0-9]+), x0, #4095 ++** csinv x0, \1, xzr, ge ++** ret ++*/ ++ ++#define TYPE int64_t ++#define TYPE_MIN INT64_MIN ++#define TYPE_MAX INT64_MAX ++#define VALUE -4096 ++ ++#include "max_plus_1.c" +diff --git a/gcc/testsuite/gcc.target/aarch64/max_plus_5.c b/gcc/testsuite/gcc.target/aarch64/max_plus_5.c +new file mode 100644 +index 000000000..63f3b3442 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/max_plus_5.c +@@ -0,0 +1,35 @@ ++/* { dg-do run } */ ++/* { dg-options "-O2 --save-temps" } */ ++/* { dg-final { check-function-bodies "**" "" "" } } */ ++ ++/* ++** f1: ++** adds (w[0-9]+), w0, #4095 ++** csel w0, \1, wzr, (cs|hi) ++** ret ++*/ ++/* ++** f2: ++** adds (w[0-9]+), w0, #4095 ++** csel w0, \1, wzr, (cs|hi) ++** ret ++*/ ++/* ++** f3: ++** adds (w[0-9]+), w0, #4096 ++** csinc w0, \1, wzr, hi ++** ret ++*/ ++/* ++** f4: ++** adds (w[0-9]+), w0, #4094 ++** csinv w0, \1, wzr, cs ++** ret ++*/ ++ ++#define TYPE uint32_t ++#define TYPE_MIN 0 ++#define TYPE_MAX UINT32_MAX ++#define VALUE (uint32_t)-4095 ++ ++#include "max_plus_1.c" +diff --git a/gcc/testsuite/gcc.target/aarch64/max_plus_6.c b/gcc/testsuite/gcc.target/aarch64/max_plus_6.c +new file mode 100644 +index 000000000..ad592c690 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/max_plus_6.c +@@ -0,0 +1,9 @@ ++/* { dg-do run } */ ++/* { dg-options "-O2 --save-temps" } */ ++ ++#define TYPE uint64_t ++#define TYPE_MIN 0 ++#define TYPE_MAX UINT64_MAX ++#define VALUE (uint64_t)-2 ++ ++#include "max_plus_1.c" +diff --git a/gcc/testsuite/gcc.target/aarch64/max_plus_7.c b/gcc/testsuite/gcc.target/aarch64/max_plus_7.c +new file mode 100644 +index 000000000..ac9f27dec +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/max_plus_7.c +@@ -0,0 +1,35 @@ ++/* { dg-do run } */ ++/* { dg-options "-O2 --save-temps" } */ ++/* { dg-final { check-function-bodies "**" "" "" } } */ ++ ++/* ++** f1: ++** adds (x[0-9]+), x0, #3 ++** csel x0, \1, xzr, (cs|hi) ++** ret ++*/ ++/* ++** f2: ++** adds (x[0-9]+), x0, #3 ++** csel x0, \1, xzr, (cs|hi) ++** ret ++*/ ++/* ++** f3: ++** adds (x[0-9]+), x0, #4 ++** csinc x0, \1, xzr, hi ++** ret ++*/ ++/* ++** f4: ++** adds (x[0-9]+), x0, #2 ++** csinv x0, \1, xzr, cs ++** ret ++*/ ++ ++#define TYPE uint64_t ++#define TYPE_MIN 0 ++#define TYPE_MAX UINT64_MAX ++#define VALUE (uint64_t)-3 ++ ++#include "max_plus_1.c" +diff --git a/gcc/testsuite/gcc.target/aarch64/min_plus_1.c b/gcc/testsuite/gcc.target/aarch64/min_plus_1.c +new file mode 100644 +index 000000000..f4c9106df +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/min_plus_1.c +@@ -0,0 +1,149 @@ ++/* { dg-do run } */ ++/* { dg-options "-O2 --save-temps" } */ ++/* { dg-final { check-function-bodies "**" "" "" } } */ ++ ++/* ++** f1: ++** subs (w[0-9]+), w0, #?4 ++** csel w0, \1, wzr, l[te] ++** ret ++*/ ++/* ++** f2: ++** subs (w[0-9]+), w0, #?4 ++** csel w0, \1, wzr, l[te] ++** ret ++*/ ++/* ++** f3: ++** subs (w[0-9]+), w0, #?3 ++** csinc w0, \1, wzr, le ++** ret ++*/ ++/* ++** f4: ++** subs (w[0-9]+), w0, #?5 ++** csinv w0, \1, wzr, lt ++** ret ++*/ ++ ++#ifndef TYPE ++#define TYPE int32_t ++#define TYPE_MIN INT32_MIN ++#define TYPE_MAX INT32_MAX ++#define VALUE 4 ++#endif ++ ++#include <stdint.h> ++ ++TYPE __attribute__((noipa)) ++f1 (TYPE x) ++{ ++ return (x < VALUE ? x - VALUE : 0); ++} ++ ++TYPE __attribute__((noipa)) ++f2 (TYPE x) ++{ ++ return (x < VALUE ? x : VALUE) - VALUE; ++} ++ ++TYPE __attribute__((noipa)) ++f3 (TYPE x) ++{ ++ return (x < VALUE ? x : VALUE) - (VALUE - 1); ++} ++ ++TYPE __attribute__((noipa)) ++f4 (TYPE x) ++{ ++ return (x < VALUE ? x : VALUE) - (VALUE + 1); ++} ++ ++TYPE __attribute__((noipa)) ++f5 (TYPE x) ++{ ++ return (x < VALUE ? x : VALUE) - (VALUE + 2); ++} ++ ++TYPE __attribute__((noipa)) ++f6 (TYPE x) ++{ ++ return (x < VALUE ? x : VALUE) - (VALUE - 2); ++} ++ ++int ++main (void) ++{ ++ TYPE min_test = TYPE_MIN; ++ if (TYPE_MIN < 0 && VALUE > 0) ++ min_test += VALUE; ++ ++ if (f1 (min_test) != min_test - VALUE) ++ __builtin_abort (); ++ if (f1 (VALUE - 1) != -1) ++ __builtin_abort (); ++ if (f1 (VALUE) != 0) ++ __builtin_abort (); ++ if (f1 (VALUE + 1) != 0) ++ __builtin_abort (); ++ if (f1 (TYPE_MAX) != 0) ++ __builtin_abort (); ++ ++ if (f2 (min_test) != min_test - VALUE) ++ __builtin_abort (); ++ if (f2 (VALUE - 1) != -1) ++ __builtin_abort (); ++ if (f2 (VALUE) != 0) ++ __builtin_abort (); ++ if (f2 (VALUE + 1) != 0) ++ __builtin_abort (); ++ if (f2 (TYPE_MAX) != 0) ++ __builtin_abort (); ++ ++ if (f3 (min_test) != min_test - VALUE + 1) ++ __builtin_abort (); ++ if (f3 (VALUE - 1) != 0) ++ __builtin_abort (); ++ if (f3 (VALUE) != 1) ++ __builtin_abort (); ++ if (f3 (VALUE + 1) != 1) ++ __builtin_abort (); ++ if (f3 (TYPE_MAX) != 1) ++ __builtin_abort (); ++ ++ if (f4 (min_test + 1) != min_test - VALUE) ++ __builtin_abort (); ++ if (f4 (VALUE - 1) != -2) ++ __builtin_abort (); ++ if (f4 (VALUE) != -1) ++ __builtin_abort (); ++ if (f4 (VALUE + 1) != -1) ++ __builtin_abort (); ++ if (f4 (TYPE_MAX) != -1) ++ __builtin_abort (); ++ ++ if (VALUE >= min_test + 2 && f5 (min_test + 2) != min_test - VALUE) ++ __builtin_abort (); ++ if (f5 (VALUE - 1) != -3) ++ __builtin_abort (); ++ if (f5 (VALUE) != -2) ++ __builtin_abort (); ++ if (f5 (VALUE + 1) != -2) ++ __builtin_abort (); ++ if (f5 (TYPE_MAX) != -2) ++ __builtin_abort (); ++ ++ if (f6 (min_test) != min_test - VALUE + 2) ++ __builtin_abort (); ++ if (f6 (VALUE - 1) != 1) ++ __builtin_abort (); ++ if (f6 (VALUE) != 2) ++ __builtin_abort (); ++ if (f6 (VALUE + 1) != 2) ++ __builtin_abort (); ++ if (f6 (TYPE_MAX) != 2) ++ __builtin_abort (); ++ ++ return 0; ++} +diff --git a/gcc/testsuite/gcc.target/aarch64/min_plus_2.c b/gcc/testsuite/gcc.target/aarch64/min_plus_2.c +new file mode 100644 +index 000000000..bc0141b72 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/min_plus_2.c +@@ -0,0 +1,35 @@ ++/* { dg-do run } */ ++/* { dg-options "-O2 --save-temps" } */ ++/* { dg-final { check-function-bodies "**" "" "" } } */ ++ ++/* ++** f1: ++** subs (x[0-9]+), x0, #?4094 ++** csel x0, \1, xzr, l[te] ++** ret ++*/ ++/* ++** f2: ++** subs (x[0-9]+), x0, #?4094 ++** csel x0, \1, xzr, l[te] ++** ret ++*/ ++/* ++** f3: ++** subs (x[0-9]+), x0, #?4093 ++** csinc x0, \1, xzr, le ++** ret ++*/ ++/* ++** f4: ++** subs (x[0-9]+), x0, #?4095 ++** csinv x0, \1, xzr, lt ++** ret ++*/ ++ ++#define TYPE int64_t ++#define TYPE_MIN INT64_MIN ++#define TYPE_MAX INT64_MAX ++#define VALUE 4094 ++ ++#include "min_plus_1.c" +diff --git a/gcc/testsuite/gcc.target/aarch64/min_plus_3.c b/gcc/testsuite/gcc.target/aarch64/min_plus_3.c +new file mode 100644 +index 000000000..1808e4b0c +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/min_plus_3.c +@@ -0,0 +1,35 @@ ++/* { dg-do run } */ ++/* { dg-options "-O2 --save-temps" } */ ++/* { dg-final { check-function-bodies "**" "" "" } } */ ++ ++/* ++** f1: ++** subs (w[0-9]+), w0, #?4095 ++** csel w0, \1, wzr, l[te] ++** ret ++*/ ++/* ++** f2: ++** subs (w[0-9]+), w0, #?4095 ++** csel w0, \1, wzr, l[te] ++** ret ++*/ ++/* ++** f3: ++** subs (w[0-9]+), w0, #?4094 ++** csinc w0, \1, wzr, le ++** ret ++*/ ++/* ++** f4: ++** subs (w[0-9]+), w0, #?4096 ++** csinv w0, \1, wzr, lt ++** ret ++*/ ++ ++#define TYPE int32_t ++#define TYPE_MIN INT32_MIN ++#define TYPE_MAX INT32_MAX ++#define VALUE 4095 ++ ++#include "min_plus_1.c" +diff --git a/gcc/testsuite/gcc.target/aarch64/min_plus_4.c b/gcc/testsuite/gcc.target/aarch64/min_plus_4.c +new file mode 100644 +index 000000000..6c581fed6 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/min_plus_4.c +@@ -0,0 +1,30 @@ ++/* { dg-do run } */ ++/* { dg-options "-O2 --save-temps" } */ ++/* { dg-final { check-function-bodies "**" "" "" } } */ ++ ++/* ++** f1: ++** subs (x[0-9]+), x0, #?4096 ++** csel x0, \1, xzr, l[te] ++** ret ++*/ ++/* ++** f2: ++** subs (x[0-9]+), x0, #?4096 ++** csel x0, \1, xzr, l[te] ++** ret ++*/ ++/* ++** f3: ++** subs (x[0-9]+), x0, #?4095 ++** csinc x0, \1, xzr, le ++** ret ++*/ ++/* f4 out of range */ ++ ++#define TYPE int64_t ++#define TYPE_MIN INT64_MIN ++#define TYPE_MAX INT64_MAX ++#define VALUE 4096 ++ ++#include "min_plus_1.c" +diff --git a/gcc/testsuite/gcc.target/aarch64/min_plus_5.c b/gcc/testsuite/gcc.target/aarch64/min_plus_5.c +new file mode 100644 +index 000000000..97542d507 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/min_plus_5.c +@@ -0,0 +1,35 @@ ++/* { dg-do run } */ ++/* { dg-options "-O2 --save-temps" } */ ++/* { dg-final { check-function-bodies "**" "" "" } } */ ++ ++/* ++** f1: ++** subs (w[0-9]+), w0, #?4095 ++** csel w0, \1, wzr, (cc|ls) ++** ret ++*/ ++/* ++** f2: ++** subs (w[0-9]+), w0, #?4095 ++** csel w0, \1, wzr, (cc|ls) ++** ret ++*/ ++/* ++** f3: ++** subs (w[0-9]+), w0, #?4094 ++** csinc w0, \1, wzr, ls ++** ret ++*/ ++/* ++** f4: ++** subs (w[0-9]+), w0, #?4096 ++** csinv w0, \1, wzr, cc ++** ret ++*/ ++ ++#define TYPE uint32_t ++#define TYPE_MIN 0 ++#define TYPE_MAX UINT32_MAX ++#define VALUE 4095 ++ ++#include "min_plus_1.c" +diff --git a/gcc/testsuite/gcc.target/aarch64/min_plus_6.c b/gcc/testsuite/gcc.target/aarch64/min_plus_6.c +new file mode 100644 +index 000000000..176533cb2 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/min_plus_6.c +@@ -0,0 +1,9 @@ ++/* { dg-do run } */ ++/* { dg-options "-O2 --save-temps" } */ ++ ++#define TYPE uint64_t ++#define TYPE_MIN 0 ++#define TYPE_MAX UINT64_MAX ++#define VALUE 1 ++ ++#include "min_plus_1.c" +diff --git a/gcc/testsuite/gcc.target/aarch64/min_plus_7.c b/gcc/testsuite/gcc.target/aarch64/min_plus_7.c +new file mode 100644 +index 000000000..d6a217a51 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/min_plus_7.c +@@ -0,0 +1,35 @@ ++/* { dg-do run } */ ++/* { dg-options "-O2 --save-temps" } */ ++/* { dg-final { check-function-bodies "**" "" "" } } */ ++ ++/* ++** f1: ++** subs (x[0-9]+), x0, #?2 ++** csel x0, \1, xzr, (cc|ls) ++** ret ++*/ ++/* ++** f2: ++** subs (x[0-9]+), x0, #?2 ++** csel x0, \1, xzr, (cc|ls) ++** ret ++*/ ++/* ++** f3: ++** subs (x[0-9]+), x0, #?1 ++** csinc x0, \1, xzr, ls ++** ret ++*/ ++/* ++** f4: ++** subs (x[0-9]+), x0, #?3 ++** csinv x0, \1, xzr, cc ++** ret ++*/ ++ ++#define TYPE uint64_t ++#define TYPE_MIN 0 ++#define TYPE_MAX UINT64_MAX ++#define VALUE 2 ++ ++#include "min_plus_1.c" +-- +2.27.0.windows.1 + diff --git a/0071-PHIOPT-Disable-the-match-A-CST1-0-when-the-CST1-is-n.patch b/0071-PHIOPT-Disable-the-match-A-CST1-0-when-the-CST1-is-n.patch new file mode 100644 index 0000000..18c2e3b --- /dev/null +++ b/0071-PHIOPT-Disable-the-match-A-CST1-0-when-the-CST1-is-n.patch @@ -0,0 +1,31 @@ +From b57c55b282e7a9a7b2cc0d3843e58fd7998685e6 Mon Sep 17 00:00:00 2001 +From: zhongyunde <zhongyunde@huawei.com> +Date: Fri, 4 Nov 2022 23:19:44 +0800 +Subject: [PATCH 23/35] [PHIOPT] Disable the match A?CST1:0 when the CST1 is + negitive value + +Fix the regression of gcc.target/aarch64/sve/vcond_3.c + +gcc: + * match.pd (A?CST1:CST2): Disable the simplifcations A? (-CST1):0 +--- + gcc/match.pd | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/gcc/match.pd b/gcc/match.pd +index 79a0228d2..fc1a34dd3 100644 +--- a/gcc/match.pd ++++ b/gcc/match.pd +@@ -3347,7 +3347,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) + (if (integer_onep (@1)) + (convert (convert:boolean_type_node @0))) + /* a ? powerof2cst : 0 -> a << (log2(powerof2cst)) */ +- (if (INTEGRAL_TYPE_P (type) && integer_pow2p (@1)) ++ (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (TREE_TYPE (@1)) ++ && integer_pow2p (@1)) + (with { + tree shift = build_int_cst (integer_type_node, tree_log2 (@1)); + } +-- +2.27.0.windows.1 + diff --git a/0072-Struct-Reorg-Merge-struct_layout-pass-into-struct_re.patch b/0072-Struct-Reorg-Merge-struct_layout-pass-into-struct_re.patch new file mode 100644 index 0000000..a7c7f74 --- /dev/null +++ b/0072-Struct-Reorg-Merge-struct_layout-pass-into-struct_re.patch @@ -0,0 +1,1770 @@ +From 6a7b9e30955e0da5258d8c4ab8de611c8a5653a5 Mon Sep 17 00:00:00 2001 +From: liyancheng <412998149@qq.com> +Date: Thu, 3 Nov 2022 20:11:18 +0800 +Subject: [PATCH 24/35] [Struct Reorg] Merge struct_layout pass into + struct_reorg + +1. Merge struct_layout pass into struct_reorg +2. Merge srmode and into struct_layout_opt_level +3. Adapt to all relevant deja tests +--- + gcc/common.opt | 2 +- + gcc/ipa-struct-reorg/ipa-struct-reorg.c | 316 ++++++++---------- + gcc/opts.c | 15 +- + gcc/passes.def | 1 - + gcc/symbol-summary.h | 4 +- + gcc/testsuite/gcc.dg/struct/dfe_DTE_verify.c | 2 +- + .../gcc.dg/struct/dfe_ele_minus_verify.c | 2 +- + .../gcc.dg/struct/dfe_extr_board_init.c | 2 +- + gcc/testsuite/gcc.dg/struct/dfe_extr_claw.c | 2 +- + gcc/testsuite/gcc.dg/struct/dfe_extr_dtrace.c | 2 +- + gcc/testsuite/gcc.dg/struct/dfe_extr_gc.c | 2 +- + gcc/testsuite/gcc.dg/struct/dfe_extr_hpsa.c | 2 +- + .../gcc.dg/struct/dfe_extr_mv_udc_core.c | 2 +- + .../gcc.dg/struct/dfe_extr_tcp_usrreq.c | 2 +- + .../gcc.dg/struct/dfe_extr_ui_main.c | 2 +- + .../gcc.dg/struct/dfe_mem_ref_offset.c | 2 +- + .../struct/dfe_mul_layer_ptr_record_bug.c | 2 +- + gcc/testsuite/gcc.dg/struct/dfe_ptr_diff.c | 2 +- + .../gcc.dg/struct/dfe_ptr_negate_expr.c | 2 +- + gcc/testsuite/gcc.dg/struct/dfe_ptr_ptr.c | 2 +- + .../struct/rf_DTE_struct_instance_field.c | 2 +- + gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c | 2 +- + .../gcc.dg/struct/rf_check_ptr_layers_bug.c | 2 +- + .../gcc.dg/struct/rf_create_fields_bug.c | 2 +- + .../gcc.dg/struct/rf_create_new_func_bug.c | 2 +- + .../gcc.dg/struct/rf_ele_minus_verify.c | 2 +- + .../gcc.dg/struct/rf_escape_by_base.c | 2 +- + gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c | 2 +- + .../gcc.dg/struct/rf_mem_ref_offset.c | 2 +- + .../struct/rf_mul_layer_ptr_record_bug.c | 2 +- + .../gcc.dg/struct/rf_pass_conflict.c | 2 +- + gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c | 2 +- + gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c | 2 +- + .../gcc.dg/struct/rf_ptr_negate_expr.c | 2 +- + gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c | 2 +- + gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c | 2 +- + gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c | 2 +- + .../gcc.dg/struct/rf_rescusive_type.c | 2 +- + .../struct/rf_rewrite_assign_more_cmp.c | 2 +- + .../gcc.dg/struct/rf_rewrite_cond_bug.c | 2 +- + .../gcc.dg/struct/rf_rewrite_cond_more_cmp.c | 2 +- + .../gcc.dg/struct/rf_rewrite_phi_bug.c | 2 +- + gcc/testsuite/gcc.dg/struct/rf_visible_func.c | 2 +- + .../gcc.dg/struct/rf_void_ptr_param_func.c | 2 +- + gcc/testsuite/gcc.dg/struct/sr_maxmin_expr.c | 2 +- + gcc/testsuite/gcc.dg/struct/struct-reorg.exp | 4 +- + gcc/testsuite/gcc.dg/struct/struct_reorg-1.c | 2 +- + gcc/testsuite/gcc.dg/struct/struct_reorg-2.c | 2 +- + gcc/testsuite/gcc.dg/struct/struct_reorg-3.c | 2 +- + gcc/testsuite/gcc.dg/struct/struct_reorg-4.c | 2 +- + .../gcc.dg/struct/w_prof_global_array.c | 2 +- + .../gcc.dg/struct/w_prof_global_var.c | 2 +- + .../gcc.dg/struct/w_prof_local_array.c | 2 +- + .../gcc.dg/struct/w_prof_local_var.c | 2 +- + .../gcc.dg/struct/w_prof_single_str_global.c | 2 +- + gcc/testsuite/gcc.dg/struct/w_prof_two_strs.c | 2 +- + .../gcc.dg/struct/w_ratio_cold_str.c | 2 +- + .../gcc.dg/struct/wo_prof_array_field.c | 2 +- + .../struct/wo_prof_array_through_pointer.c | 2 +- + .../gcc.dg/struct/wo_prof_double_malloc.c | 2 +- + .../gcc.dg/struct/wo_prof_empty_str.c | 2 +- + .../struct/wo_prof_escape_arg_to_local.c | 2 +- + .../struct/wo_prof_escape_substr_array.c | 2 +- + .../gcc.dg/struct/wo_prof_global_array.c | 2 +- + .../gcc.dg/struct/wo_prof_global_var.c | 2 +- + .../gcc.dg/struct/wo_prof_local_array.c | 2 +- + .../gcc.dg/struct/wo_prof_local_var.c | 2 +- + .../gcc.dg/struct/wo_prof_malloc_size_var-1.c | 2 +- + .../gcc.dg/struct/wo_prof_malloc_size_var.c | 2 +- + .../struct/wo_prof_mult_field_peeling.c | 2 +- + .../gcc.dg/struct/wo_prof_single_str_global.c | 2 +- + .../gcc.dg/struct/wo_prof_single_str_local.c | 2 +- + .../gcc.dg/struct/wo_prof_two_strs.c | 2 +- + gcc/timevar.def | 1 - + gcc/tree-pass.h | 1 - + gcc/tree.c | 4 +- + 76 files changed, 222 insertions(+), 260 deletions(-) + +diff --git a/gcc/common.opt b/gcc/common.opt +index be7bfee60..ad147f7a9 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -1881,7 +1881,7 @@ Common Ignore + Does nothing. Preserved for backward compatibility. + + fipa-reorder-fields +-Common Report Var(flag_ipa_struct_layout) Init(0) Optimization ++Common Report Var(flag_ipa_reorder_fields) Init(0) Optimization + Perform structure fields reorder optimizations. + + fipa-struct-reorg +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +index 54c20ca3f..08cb51fee 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -232,12 +232,6 @@ is_from_void_ptr_parm (tree ssa_name) + && VOID_POINTER_P (TREE_TYPE (ssa_name))); + } + +-enum srmode +-{ +- NORMAL = 0, +- COMPLETE_STRUCT_RELAYOUT, +- STRUCT_LAYOUT_OPTIMIZE +-}; + + /* Enum the struct layout optimize level, + which should be the same as the option -fstruct-reorg=. */ +@@ -245,16 +239,17 @@ enum srmode + enum struct_layout_opt_level + { + NONE = 0, +- STRUCT_REORG, +- STRUCT_REORDER_FIELDS, +- DEAD_FIELD_ELIMINATION ++ STRUCT_SPLIT = 1 << 0, ++ COMPLETE_STRUCT_RELAYOUT = 1 << 1, ++ STRUCT_REORDER_FIELDS = 1 << 2, ++ DEAD_FIELD_ELIMINATION = 1 << 3 + }; + + static bool is_result_of_mult (tree arg, tree *num, tree struct_size); + bool isptrptr (tree type); + void get_base (tree &base, tree expr); + +-srmode current_mode; ++static unsigned int current_layout_opt_level; + + hash_map<tree, tree> replace_type_map; + +@@ -607,7 +602,7 @@ void + srtype::simple_dump (FILE *f) + { + print_generic_expr (f, type); +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE) ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS) + { + fprintf (f, "(%d)", TYPE_UID (type)); + } +@@ -656,7 +651,7 @@ srfield::create_new_fields (tree newtype[max_split], + tree newfields[max_split], + tree newlast[max_split]) + { +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE) ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS) + { + create_new_optimized_fields (newtype, newfields, newlast); + return; +@@ -857,7 +852,7 @@ srtype::create_new_type (void) + we are not splitting the struct into two clusters, + then just return false and don't change the type. */ + if (!createnewtype && maxclusters == 0 +- && current_mode != STRUCT_LAYOUT_OPTIMIZE) ++ && current_layout_opt_level < STRUCT_REORDER_FIELDS) + { + newtype[0] = type; + return false; +@@ -885,8 +880,7 @@ srtype::create_new_type (void) + sprintf(id, "%d", i); + if (tname) + { +- name = concat (tname, current_mode == STRUCT_LAYOUT_OPTIMIZE +- ? ".slo." : ".reorg.", id, NULL); ++ name = concat (tname, ".reorg.", id, NULL); + TYPE_NAME (newtype[i]) = build_decl (UNKNOWN_LOCATION, TYPE_DECL, + get_identifier (name), newtype[i]); + free (name); +@@ -896,8 +890,7 @@ srtype::create_new_type (void) + for (unsigned i = 0; i < fields.length (); i++) + { + srfield *f = fields[i]; +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE +- && struct_layout_optimize_level >= DEAD_FIELD_ELIMINATION ++ if (current_layout_opt_level & DEAD_FIELD_ELIMINATION + && !(f->field_access & READ_FIELD)) + continue; + f->create_new_fields (newtype, newfields, newlast); +@@ -921,13 +914,12 @@ srtype::create_new_type (void) + + warn_padded = save_warn_padded; + +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS + && replace_type_map.get (this->newtype[0]) == NULL) + replace_type_map.put (this->newtype[0], this->type); + if (dump_file) + { +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE +- && struct_layout_optimize_level >= DEAD_FIELD_ELIMINATION ++ if (current_layout_opt_level & DEAD_FIELD_ELIMINATION + && has_dead_field ()) + fprintf (dump_file, "Dead field elimination.\n"); + } +@@ -1046,8 +1038,7 @@ srfunction::create_new_decls (void) + sprintf(id, "%d", j); + if (tname) + { +- name = concat (tname, current_mode == STRUCT_LAYOUT_OPTIMIZE +- ? ".slo." : ".reorg.", id, NULL); ++ name = concat (tname, ".reorg.", id, NULL); + new_name = get_identifier (name); + free (name); + } +@@ -1266,7 +1257,7 @@ public: + { + } + +- unsigned execute (enum srmode mode); ++ unsigned execute (unsigned int opt); + void mark_type_as_escape (tree type, escape_type, gimple *stmt = NULL); + + // fields +@@ -2796,7 +2787,7 @@ escape_type escape_type_volatile_array_or_ptrptr (tree type) + return escape_volatile; + if (isarraytype (type)) + return escape_array; +- if (isptrptr (type) && (current_mode != STRUCT_LAYOUT_OPTIMIZE)) ++ if (isptrptr (type) && (current_layout_opt_level < STRUCT_REORDER_FIELDS)) + return escape_ptr_ptr; + return does_not_escape; + } +@@ -2817,14 +2808,13 @@ ipa_struct_reorg::record_field_type (tree field, srtype *base_srtype) + field_srfield->type = field_srtype; + field_srtype->add_field_site (field_srfield); + } +- if (field_srtype == base_srtype && current_mode != COMPLETE_STRUCT_RELAYOUT +- && current_mode != STRUCT_LAYOUT_OPTIMIZE) ++ if (field_srtype == base_srtype && current_layout_opt_level == STRUCT_SPLIT) + { + base_srtype->mark_escape (escape_rescusive_type, NULL); + } + /* Types of non-pointer field are difficult to track the correctness + of the rewrite when it used by the escaped type. */ +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS + && TREE_CODE (field_type) == RECORD_TYPE) + { + field_srtype->mark_escape (escape_instance_field, NULL); +@@ -2859,7 +2849,7 @@ ipa_struct_reorg::record_struct_field_types (tree base_type, + } + /* Types of non-pointer field are difficult to track the correctness + of the rewrite when it used by the escaped type. */ +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS + && TREE_CODE (field_type) == RECORD_TYPE) + { + base_srtype->mark_escape (escape_instance_field, NULL); +@@ -3043,8 +3033,7 @@ ipa_struct_reorg::record_var (tree decl, escape_type escapes, int arg) + + /* Separate instance is hard to trace in complete struct + relayout optimization. */ +- if ((current_mode == COMPLETE_STRUCT_RELAYOUT +- || current_mode == STRUCT_LAYOUT_OPTIMIZE) ++ if (current_layout_opt_level >= COMPLETE_STRUCT_RELAYOUT + && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE) + { + e = escape_separate_instance; +@@ -3149,7 +3138,7 @@ ipa_struct_reorg::find_vars (gimple *stmt) + /* Add a safe func mechanism. */ + bool l_find = true; + bool r_find = true; +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE) ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS) + { + l_find = !(current_function->is_safe_func + && TREE_CODE (lhs) == SSA_NAME +@@ -3195,7 +3184,7 @@ ipa_struct_reorg::find_vars (gimple *stmt) + } + } + } +- else if ((current_mode == STRUCT_LAYOUT_OPTIMIZE) ++ else if ((current_layout_opt_level >= STRUCT_REORDER_FIELDS) + && (gimple_assign_rhs_code (stmt) == LE_EXPR + || gimple_assign_rhs_code (stmt) == LT_EXPR + || gimple_assign_rhs_code (stmt) == GE_EXPR +@@ -3206,7 +3195,7 @@ ipa_struct_reorg::find_vars (gimple *stmt) + find_var (gimple_assign_rhs2 (stmt), stmt); + } + /* find void ssa_name from stmt such as: _2 = _1 - old_arcs_1. */ +- else if ((current_mode == STRUCT_LAYOUT_OPTIMIZE) ++ else if ((current_layout_opt_level >= STRUCT_REORDER_FIELDS) + && gimple_assign_rhs_code (stmt) == POINTER_DIFF_EXPR + && types_compatible_p ( + TYPE_MAIN_VARIANT (TREE_TYPE (gimple_assign_rhs1 (stmt))), +@@ -3418,8 +3407,7 @@ ipa_struct_reorg::maybe_record_stmt (cgraph_node *node, gimple *stmt) + default: + break; + } +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE +- && struct_layout_optimize_level >= DEAD_FIELD_ELIMINATION) ++ if (current_layout_opt_level & DEAD_FIELD_ELIMINATION) + { + /* Look for loads and stores. */ + walk_stmt_load_store_ops (stmt, this, find_field_p_load, +@@ -3590,11 +3578,12 @@ is_result_of_mult (tree arg, tree *num, tree struct_size) + size_def_stmt = SSA_NAME_DEF_STMT (arg); + } + else if (rhs_code == NEGATE_EXPR +- && current_mode == STRUCT_LAYOUT_OPTIMIZE) ++ && current_layout_opt_level >= STRUCT_REORDER_FIELDS) + { + return trace_calculate_negate (size_def_stmt, num, struct_size); + } +- else if (rhs_code == NOP_EXPR && current_mode == STRUCT_LAYOUT_OPTIMIZE) ++ else if (rhs_code == NOP_EXPR ++ && current_layout_opt_level >= STRUCT_REORDER_FIELDS) + { + return trace_calculate_diff (size_def_stmt, num); + } +@@ -3614,17 +3603,17 @@ is_result_of_mult (tree arg, tree *num, tree struct_size) + bool + ipa_struct_reorg::handled_allocation_stmt (gimple *stmt) + { +- if ((current_mode == STRUCT_LAYOUT_OPTIMIZE) ++ if ((current_layout_opt_level >= STRUCT_REORDER_FIELDS) + && (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC) + || gimple_call_builtin_p (stmt, BUILT_IN_MALLOC) + || gimple_call_builtin_p (stmt, BUILT_IN_CALLOC))) + { + return true; + } +- if ((current_mode == COMPLETE_STRUCT_RELAYOUT) ++ if ((current_layout_opt_level == COMPLETE_STRUCT_RELAYOUT) + && gimple_call_builtin_p (stmt, BUILT_IN_CALLOC)) + return true; +- if ((current_mode == NORMAL) ++ if ((current_layout_opt_level == STRUCT_SPLIT) + && (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC) + || gimple_call_builtin_p (stmt, BUILT_IN_MALLOC) + || gimple_call_builtin_p (stmt, BUILT_IN_CALLOC) +@@ -3750,7 +3739,7 @@ ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other, gimple + /* x_1 = y.x_nodes; void *x; + Directly mark the structure pointer type assigned + to the void* variable as escape. */ +- else if (current_mode == STRUCT_LAYOUT_OPTIMIZE ++ else if (current_layout_opt_level >= STRUCT_REORDER_FIELDS + && TREE_CODE (side) == SSA_NAME + && VOID_POINTER_P (TREE_TYPE (side)) + && SSA_NAME_VAR (side) +@@ -4017,7 +4006,7 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, + and doesn't mark escape follow.). */ + /* _1 = MEM[(struct arc_t * *)a_1]. + then base a_1: ssa_name - pointer_type - integer_type. */ +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE) ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS) + { + bool is_int_ptr = POINTER_TYPE_P (TREE_TYPE (base)) + && (TREE_CODE (inner_type (TREE_TYPE (base))) +@@ -4081,7 +4070,7 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, + /* Escape the operation of fetching field with pointer offset such as: + *(&(t->right)) = malloc (0); -> MEM[(struct node * *)_1 + 8B] = malloc (0); + */ +- if (current_mode != NORMAL ++ if (current_layout_opt_level > STRUCT_SPLIT + && (TREE_CODE (expr) == MEM_REF) && (offset != 0)) + { + gcc_assert (can_escape); +@@ -4233,7 +4222,7 @@ ipa_struct_reorg::maybe_record_call (cgraph_node *node, gcall *stmt) + /* callee_func (_1, _2); + Check the callee func, instead of current func. */ + if (!(free_or_realloc +- || (current_mode == STRUCT_LAYOUT_OPTIMIZE ++ || (current_layout_opt_level >= STRUCT_REORDER_FIELDS + && safe_functions.contains ( + node->get_edge (stmt)->callee))) + && VOID_POINTER_P (argtypet)) +@@ -4265,14 +4254,7 @@ ipa_struct_reorg::record_stmt_expr (tree expr, cgraph_node *node, gimple *stmt) + realpart, imagpart, address, escape_from_base)) + return; + +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE) +- { +- if (!opt_for_fn (current_function_decl, flag_ipa_struct_layout)) +- { +- type->mark_escape (escape_non_optimize, stmt); +- } +- } +- else ++ if (current_layout_opt_level > NONE) + { + if (!opt_for_fn (current_function_decl, flag_ipa_struct_reorg)) + { +@@ -4379,7 +4361,7 @@ ipa_struct_reorg::check_type_and_push (tree newdecl, srdecl *decl, + void + ipa_struct_reorg::check_alloc_num (gimple *stmt, srtype *type) + { +- if (current_mode == COMPLETE_STRUCT_RELAYOUT ++ if (current_layout_opt_level == COMPLETE_STRUCT_RELAYOUT + && handled_allocation_stmt (stmt)) + { + tree arg0 = gimple_call_arg (stmt, 0); +@@ -4490,7 +4472,7 @@ ipa_struct_reorg::check_definition_call (srdecl *decl, vec<srdecl*> &worklist) + check_type_and_push (gimple_call_arg (stmt, 0), decl, worklist, stmt); + } + +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE) ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS) + { + if (!handled_allocation_stmt (stmt)) + { +@@ -4544,7 +4526,8 @@ ipa_struct_reorg::check_definition (srdecl *decl, vec<srdecl*> &worklist) + } + return; + } +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE && SSA_NAME_VAR (ssa_name) ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS ++ && SSA_NAME_VAR (ssa_name) + && VOID_POINTER_P (TREE_TYPE (SSA_NAME_VAR (ssa_name)))) + { + type->mark_escape (escape_cast_void, SSA_NAME_DEF_STMT (ssa_name)); +@@ -4631,7 +4614,7 @@ ipa_struct_reorg::check_other_side (srdecl *decl, tree other, gimple *stmt, vec< + { + /* In Complete Struct Relayout opti, if lhs type is the same + as rhs type, we could return without any harm. */ +- if (current_mode == COMPLETE_STRUCT_RELAYOUT) ++ if (current_layout_opt_level == COMPLETE_STRUCT_RELAYOUT) + { + return; + } +@@ -4645,7 +4628,7 @@ ipa_struct_reorg::check_other_side (srdecl *decl, tree other, gimple *stmt, vec< + if (!get_type_field (other, base, indirect, type1, field, + realpart, imagpart, address, escape_from_base)) + { +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE) ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS) + { + /* release INTEGER_TYPE cast to struct pointer. */ + bool cast_from_int_ptr = current_function->is_safe_func && base +@@ -4703,7 +4686,8 @@ get_base (tree &base, tree expr) + void + ipa_struct_reorg::check_ptr_layers (tree a_expr, tree b_expr, gimple* stmt) + { +- if (current_mode != STRUCT_LAYOUT_OPTIMIZE || current_function->is_safe_func ++ if (current_layout_opt_level < STRUCT_REORDER_FIELDS ++ || current_function->is_safe_func + || !(POINTER_TYPE_P (TREE_TYPE (a_expr))) + || !(POINTER_TYPE_P (TREE_TYPE (b_expr))) + || !handled_type (TREE_TYPE (a_expr)) +@@ -4779,12 +4763,9 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist) + tree rhs2 = gimple_cond_rhs (stmt); + tree orhs = rhs1; + enum tree_code code = gimple_cond_code (stmt); +- if ((current_mode == NORMAL && (code != EQ_EXPR && code != NE_EXPR)) +- || (current_mode == COMPLETE_STRUCT_RELAYOUT +- && (code != EQ_EXPR && code != NE_EXPR +- && code != LT_EXPR && code != LE_EXPR +- && code != GT_EXPR && code != GE_EXPR)) +- || (current_mode == STRUCT_LAYOUT_OPTIMIZE ++ if ((current_layout_opt_level == STRUCT_SPLIT ++ && (code != EQ_EXPR && code != NE_EXPR)) ++ || (current_layout_opt_level >= COMPLETE_STRUCT_RELAYOUT + && (code != EQ_EXPR && code != NE_EXPR + && code != LT_EXPR && code != LE_EXPR + && code != GT_EXPR && code != GE_EXPR))) +@@ -4818,15 +4799,12 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist) + tree rhs2 = gimple_assign_rhs2 (stmt); + tree orhs = rhs1; + enum tree_code code = gimple_assign_rhs_code (stmt); +- if ((current_mode == NORMAL && (code != EQ_EXPR && code != NE_EXPR)) +- || (current_mode == COMPLETE_STRUCT_RELAYOUT ++ if ((current_layout_opt_level == STRUCT_SPLIT ++ && (code != EQ_EXPR && code != NE_EXPR)) ++ || (current_layout_opt_level >= COMPLETE_STRUCT_RELAYOUT + && (code != EQ_EXPR && code != NE_EXPR + && code != LT_EXPR && code != LE_EXPR +- && code != GT_EXPR && code != GE_EXPR)) +- || (current_mode == STRUCT_LAYOUT_OPTIMIZE +- && (code != EQ_EXPR && code != NE_EXPR +- && code != LT_EXPR && code != LE_EXPR +- && code != GT_EXPR && code != GE_EXPR))) ++ && code != GT_EXPR && code != GE_EXPR))) + { + mark_expr_escape (rhs1, escape_non_eq, stmt); + mark_expr_escape (rhs2, escape_non_eq, stmt); +@@ -4945,11 +4923,11 @@ ipa_struct_reorg::record_function (cgraph_node *node) + escapes = escape_marked_as_used; + else if (!node->local) + { +- if (current_mode != STRUCT_LAYOUT_OPTIMIZE) ++ if (current_layout_opt_level < STRUCT_REORDER_FIELDS) + { + escapes = escape_visible_function; + } +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE && node->externally_visible) ++ else if (node->externally_visible) + { + escapes = escape_visible_function; + } +@@ -4959,14 +4937,7 @@ ipa_struct_reorg::record_function (cgraph_node *node) + else if (!tree_versionable_function_p (node->decl)) + escapes = escape_noclonable_function; + +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE) +- { +- if (!opt_for_fn (node->decl, flag_ipa_struct_layout)) +- { +- escapes = escape_non_optimize; +- } +- } +- else if (current_mode == NORMAL || current_mode == COMPLETE_STRUCT_RELAYOUT) ++ if (current_layout_opt_level > NONE) + { + if (!opt_for_fn (node->decl, flag_ipa_struct_reorg)) + { +@@ -4978,10 +4949,10 @@ ipa_struct_reorg::record_function (cgraph_node *node) + gimple_stmt_iterator si; + + /* Add a safe func mechanism. */ +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE) ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS) + { + current_function->is_safe_func = safe_functions.contains (node); +- if (dump_file) ++ if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "\nfunction %s/%u: is_safe_func = %d\n", + node->name (), node->order, +@@ -5194,7 +5165,7 @@ ipa_struct_reorg::record_accesses (void) + } + + /* Add a safe func mechanism. */ +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE) ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS) + { + record_safe_func_with_void_ptr_parm (); + } +@@ -5392,8 +5363,7 @@ ipa_struct_reorg::propagate_escape_via_empty_with_no_original (void) + void + ipa_struct_reorg::prune_escaped_types (void) + { +- if (current_mode != COMPLETE_STRUCT_RELAYOUT +- && current_mode != STRUCT_LAYOUT_OPTIMIZE) ++ if (current_layout_opt_level == STRUCT_SPLIT) + { + /* Detect recusive types and mark them as escaping. */ + detect_cycles (); +@@ -5401,7 +5371,7 @@ ipa_struct_reorg::prune_escaped_types (void) + mark them as escaping. */ + propagate_escape (); + } +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE) ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS) + { + propagate_escape_via_original (); + propagate_escape_via_empty_with_no_original (); +@@ -5461,7 +5431,7 @@ ipa_struct_reorg::prune_escaped_types (void) + if (function->args.is_empty () + && function->decls.is_empty () + && function->globals.is_empty () +- && current_mode != STRUCT_LAYOUT_OPTIMIZE) ++ && current_layout_opt_level < STRUCT_REORDER_FIELDS) + { + delete function; + functions.ordered_remove (i); +@@ -5489,7 +5459,7 @@ ipa_struct_reorg::prune_escaped_types (void) + /* The escape type is not deleted in STRUCT_LAYOUT_OPTIMIZE, + Then the type that contains the escaped type fields + can find complete information. */ +- if (current_mode != STRUCT_LAYOUT_OPTIMIZE) ++ if (current_layout_opt_level < STRUCT_REORDER_FIELDS) + { + for (unsigned i = 0; i < types.length ();) + { +@@ -5539,7 +5509,7 @@ ipa_struct_reorg::create_new_types (void) + for (unsigned i = 0; i < types.length (); i++) + newtypes += types[i]->create_new_type (); + +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE) ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS) + { + for (unsigned i = 0; i < types.length (); i++) + { +@@ -5561,14 +5531,31 @@ ipa_struct_reorg::create_new_types (void) + } + } + +- if (dump_file) ++ if (current_layout_opt_level == STRUCT_SPLIT) + { +- if (newtypes) +- fprintf (dump_file, "\nNumber of structures to transform is %d\n", newtypes); +- else +- fprintf (dump_file, "\nNo structures to transform.\n"); ++ if (dump_file) ++ { ++ if (newtypes) ++ fprintf (dump_file, "\nNumber of structures to transform in" ++ " struct split is %d\n", newtypes); ++ else ++ fprintf (dump_file, "\nNo structures to transform in" ++ " struct split.\n"); ++ } ++ } ++ else ++ { ++ if (dump_file) ++ { ++ if (newtypes) ++ fprintf (dump_file, "\nNumber of structures to transform" ++ " is %d\n", newtypes); ++ else ++ fprintf (dump_file, "\nNo structures to transform.\n"); ++ } + } + ++ + return newtypes != 0; + } + +@@ -5663,8 +5650,7 @@ ipa_struct_reorg::create_new_args (cgraph_node *new_node) + char *name = NULL; + if (tname) + { +- name = concat (tname, current_mode == STRUCT_LAYOUT_OPTIMIZE +- ? ".slo.0" : ".reorg.0", NULL); ++ name = concat (tname, ".reorg.0", NULL); + new_name = get_identifier (name); + free (name); + } +@@ -5751,9 +5737,7 @@ ipa_struct_reorg::create_new_functions (void) + } + statistics_counter_event (NULL, "Create new function", 1); + new_node = node->create_version_clone_with_body ( +- vNULL, NULL, NULL, NULL, NULL, +- current_mode == STRUCT_LAYOUT_OPTIMIZE +- ? "slo" : "struct_reorg"); ++ vNULL, NULL, NULL, NULL, NULL, "struct_reorg"); + new_node->can_change_signature = node->can_change_signature; + new_node->make_local (); + f->newnode = new_node; +@@ -5871,7 +5855,7 @@ ipa_struct_reorg::rewrite_expr (tree expr, tree newexpr[max_split], bool ignore_ + newbase1 = build_fold_addr_expr (newbase1); + if (indirect) + { +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE) ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS) + { + /* Supports the MEM_REF offset. + _1 = MEM[(struct arc *)ap_1 + 72B].flow; +@@ -5927,8 +5911,7 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + { + bool remove = false; + +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE +- && struct_layout_optimize_level >= DEAD_FIELD_ELIMINATION ++ if (current_layout_opt_level & DEAD_FIELD_ELIMINATION + && remove_dead_field_stmt (gimple_assign_lhs (stmt))) + { + if (dump_file && (dump_flags & TDF_DETAILS)) +@@ -5964,10 +5947,10 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + return remove; + } + +- if ((current_mode != STRUCT_LAYOUT_OPTIMIZE ++ if ((current_layout_opt_level < STRUCT_REORDER_FIELDS + && (gimple_assign_rhs_code (stmt) == EQ_EXPR + || gimple_assign_rhs_code (stmt) == NE_EXPR)) +- || (current_mode == STRUCT_LAYOUT_OPTIMIZE ++ || (current_layout_opt_level >= STRUCT_REORDER_FIELDS + && (TREE_CODE_CLASS (gimple_assign_rhs_code (stmt)) + == tcc_comparison))) + { +@@ -5977,7 +5960,7 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + tree newrhs2[max_split]; + tree_code rhs_code = gimple_assign_rhs_code (stmt); + tree_code code = rhs_code == EQ_EXPR ? BIT_AND_EXPR : BIT_IOR_EXPR; +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS + && rhs_code != EQ_EXPR && rhs_code != NE_EXPR) + { + code = rhs_code; +@@ -6024,8 +6007,9 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + _6 = _4 + _5; + _5 = (long unsigned int) _3; + _3 = _1 - old_2. */ +- if (current_mode != STRUCT_LAYOUT_OPTIMIZE +- || (current_mode == STRUCT_LAYOUT_OPTIMIZE && (num != NULL))) ++ if (current_layout_opt_level < STRUCT_REORDER_FIELDS ++ || (current_layout_opt_level >= STRUCT_REORDER_FIELDS ++ && (num != NULL))) + { + num = gimplify_build1 (gsi, NOP_EXPR, sizetype, num); + } +@@ -6053,7 +6037,7 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + } + + /* Support POINTER_DIFF_EXPR rewriting. */ +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS + && gimple_assign_rhs_code (stmt) == POINTER_DIFF_EXPR) + { + tree rhs1 = gimple_assign_rhs1 (stmt); +@@ -6240,7 +6224,8 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi) + srfunction *f = find_function (node); + + /* Add a safe func mechanism. */ +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE && f && f->is_safe_func) ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS ++ && f && f->is_safe_func) + { + tree expr = gimple_call_arg (stmt, 0); + tree newexpr[max_split]; +@@ -6367,9 +6352,9 @@ ipa_struct_reorg::rewrite_cond (gcond *stmt, gimple_stmt_iterator *gsi) + tree_code rhs_code = gimple_cond_code (stmt); + + /* Handle only equals or not equals conditionals. */ +- if ((current_mode != STRUCT_LAYOUT_OPTIMIZE ++ if ((current_layout_opt_level < STRUCT_REORDER_FIELDS + && (rhs_code != EQ_EXPR && rhs_code != NE_EXPR)) +- || (current_mode == STRUCT_LAYOUT_OPTIMIZE ++ || (current_layout_opt_level >= STRUCT_REORDER_FIELDS + && TREE_CODE_CLASS (rhs_code) != tcc_comparison)) + return false; + tree lhs = gimple_cond_lhs (stmt); +@@ -6429,7 +6414,7 @@ ipa_struct_reorg::rewrite_cond (gcond *stmt, gimple_stmt_iterator *gsi) + bool + ipa_struct_reorg::rewrite_debug (gimple *stmt, gimple_stmt_iterator *) + { +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE) ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS) + { + /* Delete debug gimple now. */ + return true; +@@ -6593,7 +6578,7 @@ ipa_struct_reorg::rewrite_functions (void) + then don't rewrite any accesses. */ + if (!create_new_types ()) + { +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE) ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS) + { + for (unsigned i = 0; i < functions.length (); i++) + { +@@ -6612,7 +6597,7 @@ ipa_struct_reorg::rewrite_functions (void) + return 0; + } + +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE && dump_file) ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS && dump_file) + { + fprintf (dump_file, "=========== all created newtypes: ===========\n\n"); + dump_newtypes (dump_file); +@@ -6622,13 +6607,13 @@ ipa_struct_reorg::rewrite_functions (void) + { + retval = TODO_remove_functions; + create_new_functions (); +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE) ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS) + { + prune_escaped_types (); + } + } + +- if (current_mode == STRUCT_LAYOUT_OPTIMIZE) ++ if (current_layout_opt_level >= STRUCT_REORDER_FIELDS) + { + for (unsigned i = 0; i < functions.length (); i++) + { +@@ -6794,13 +6779,13 @@ ipa_struct_reorg::execute_struct_relayout (void) + } + + unsigned int +-ipa_struct_reorg::execute (enum srmode mode) ++ipa_struct_reorg::execute (unsigned int opt) + { + unsigned int ret = 0; + +- if (mode == NORMAL || mode == STRUCT_LAYOUT_OPTIMIZE) ++ if (opt != COMPLETE_STRUCT_RELAYOUT) + { +- current_mode = mode; ++ current_layout_opt_level = opt; + /* If there is a top-level inline-asm, + the pass immediately returns. */ + if (symtab->first_asm_symbol ()) +@@ -6809,20 +6794,20 @@ ipa_struct_reorg::execute (enum srmode mode) + } + record_accesses (); + prune_escaped_types (); +- if (current_mode == NORMAL) ++ if (opt == STRUCT_SPLIT) + { + analyze_types (); + } + + ret = rewrite_functions (); + } +- else if (mode == COMPLETE_STRUCT_RELAYOUT) ++ else // do COMPLETE_STRUCT_RELAYOUT + { + if (dump_file) + { + fprintf (dump_file, "\n\nTry Complete Struct Relayout:\n"); + } +- current_mode = COMPLETE_STRUCT_RELAYOUT; ++ current_layout_opt_level = COMPLETE_STRUCT_RELAYOUT; + if (symtab->first_asm_symbol ()) + { + return 0; +@@ -6861,67 +6846,48 @@ public: + virtual unsigned int execute (function *) + { + unsigned int ret = 0; +- ret = ipa_struct_reorg ().execute (NORMAL); +- if (!ret) ++ unsigned int ret_reorg = 0; ++ unsigned int level = 0; ++ switch (struct_layout_optimize_level) + { +- ret = ipa_struct_reorg ().execute (COMPLETE_STRUCT_RELAYOUT); ++ case 3: level |= DEAD_FIELD_ELIMINATION; ++ // FALLTHRU ++ case 2: level |= STRUCT_REORDER_FIELDS; ++ // FALLTHRU ++ case 1: ++ level |= COMPLETE_STRUCT_RELAYOUT; ++ level |= STRUCT_SPLIT; ++ break; ++ case 0: break; ++ default: gcc_unreachable (); + } +- return ret; +- } + +-}; // class pass_ipa_struct_reorg +- +-bool +-pass_ipa_struct_reorg::gate (function *) +-{ +- return (optimize >= 3 +- && flag_ipa_struct_reorg +- /* Don't bother doing anything if the program has errors. */ +- && !seen_error () +- && flag_lto_partition == LTO_PARTITION_ONE +- /* Only enable struct optimizations in C since other +- languages' grammar forbid. */ +- && lang_c_p () +- /* Only enable struct optimizations in lto or whole_program. */ +- && (in_lto_p || flag_whole_program)); +-} ++ /* Preserved for backward compatibility, reorder fields needs run before ++ struct split and complete struct relayout. */ ++ if (flag_ipa_reorder_fields && level < STRUCT_REORDER_FIELDS) ++ ret = ipa_struct_reorg ().execute (STRUCT_REORDER_FIELDS); + +-const pass_data pass_data_ipa_struct_layout = +-{ +- SIMPLE_IPA_PASS, // type +- "struct_layout", // name +- OPTGROUP_NONE, // optinfo_flags +- TV_IPA_STRUCT_LAYOUT, // tv_id +- 0, // properties_required +- 0, // properties_provided +- 0, // properties_destroyed +- 0, // todo_flags_start +- 0, // todo_flags_finish +-}; ++ if (level >= STRUCT_REORDER_FIELDS) ++ ret = ipa_struct_reorg ().execute (level); + +-class pass_ipa_struct_layout : public simple_ipa_opt_pass +-{ +-public: +- pass_ipa_struct_layout (gcc::context *ctxt) +- : simple_ipa_opt_pass (pass_data_ipa_struct_layout, ctxt) +- {} ++ if (level >= COMPLETE_STRUCT_RELAYOUT) ++ { ++ /* Preserved for backward compatibility. */ ++ ret_reorg = ipa_struct_reorg ().execute (STRUCT_SPLIT); ++ if (!ret_reorg) ++ ret_reorg = ipa_struct_reorg ().execute (COMPLETE_STRUCT_RELAYOUT); ++ } + +- /* opt_pass methods: */ +- virtual bool gate (function *); +- virtual unsigned int execute (function *) +- { +- unsigned int ret = 0; +- ret = ipa_struct_reorg ().execute (STRUCT_LAYOUT_OPTIMIZE); +- return ret; ++ return ret | ret_reorg; + } + +-}; // class pass_ipa_struct_layout ++}; // class pass_ipa_struct_reorg + + bool +-pass_ipa_struct_layout::gate (function *) ++pass_ipa_struct_reorg::gate (function *) + { + return (optimize >= 3 +- && flag_ipa_struct_layout ++ && flag_ipa_struct_reorg + /* Don't bother doing anything if the program has errors. */ + && !seen_error () + && flag_lto_partition == LTO_PARTITION_ONE +@@ -6939,9 +6905,3 @@ make_pass_ipa_struct_reorg (gcc::context *ctxt) + { + return new pass_ipa_struct_reorg (ctxt); + } +- +-simple_ipa_opt_pass * +-make_pass_ipa_struct_layout (gcc::context *ctxt) +-{ +- return new pass_ipa_struct_layout (ctxt); +-} +diff --git a/gcc/opts.c b/gcc/opts.c +index c3877c24e..f12b13599 100644 +--- a/gcc/opts.c ++++ b/gcc/opts.c +@@ -2696,15 +2696,20 @@ common_handle_option (struct gcc_options *opts, + break; + + case OPT_fipa_struct_reorg_: +- opts->x_struct_layout_optimize_level = value; +- if (value > 1) +- { +- SET_OPTION_IF_UNSET (opts, opts_set, flag_ipa_struct_layout, value); +- } + /* No break here - do -fipa-struct-reorg processing. */ + /* FALLTHRU. */ + case OPT_fipa_struct_reorg: + opts->x_flag_ipa_struct_reorg = value; ++ if (value && !opts->x_struct_layout_optimize_level) ++ { ++ /* Using the -fipa-struct-reorg option is equivalent to using ++ -fipa-struct-reorg=1. */ ++ opts->x_struct_layout_optimize_level = 1; ++ } ++ break; ++ ++ case OPT_fipa_reorder_fields: ++ SET_OPTION_IF_UNSET (opts, opts_set, flag_ipa_struct_reorg, value); + break; + + case OPT_fprofile_generate_: +diff --git a/gcc/passes.def b/gcc/passes.def +index 94554cc1d..f3b6048d8 100644 +--- a/gcc/passes.def ++++ b/gcc/passes.def +@@ -175,7 +175,6 @@ along with GCC; see the file COPYING3. If not see + INSERT_PASSES_AFTER (all_late_ipa_passes) + NEXT_PASS (pass_materialize_all_clones); + NEXT_PASS (pass_ipa_pta); +- NEXT_PASS (pass_ipa_struct_layout); + /* FIXME: this should a normal IP pass */ + NEXT_PASS (pass_ipa_struct_reorg); + NEXT_PASS (pass_omp_simd_clone); +diff --git a/gcc/symbol-summary.h b/gcc/symbol-summary.h +index f62222a96..1e7341b24 100644 +--- a/gcc/symbol-summary.h ++++ b/gcc/symbol-summary.h +@@ -61,7 +61,7 @@ protected: + { + /* In structure optimizatons, we call new to ensure that + the allocated memory is initialized to 0. */ +- if (flag_ipa_struct_layout || flag_ipa_struct_reorg) ++ if (flag_ipa_struct_reorg) + return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T () + : new T (); + /* Call gcc_internal_because we do not want to call finalizer for +@@ -77,7 +77,7 @@ protected: + ggc_delete (item); + else + { +- if (flag_ipa_struct_layout || flag_ipa_struct_reorg) ++ if (flag_ipa_struct_reorg) + delete item; + else + m_allocator.remove (item); +diff --git a/gcc/testsuite/gcc.dg/struct/dfe_DTE_verify.c b/gcc/testsuite/gcc.dg/struct/dfe_DTE_verify.c +index 4261d2352..afa181e07 100644 +--- a/gcc/testsuite/gcc.dg/struct/dfe_DTE_verify.c ++++ b/gcc/testsuite/gcc.dg/struct/dfe_DTE_verify.c +@@ -83,4 +83,4 @@ main () + return 0;
+ }
+
+-/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_layout" } } */
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_reorg" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_ele_minus_verify.c b/gcc/testsuite/gcc.dg/struct/dfe_ele_minus_verify.c +index 42d38c63a..c87db2aba 100644 +--- a/gcc/testsuite/gcc.dg/struct/dfe_ele_minus_verify.c ++++ b/gcc/testsuite/gcc.dg/struct/dfe_ele_minus_verify.c +@@ -57,4 +57,4 @@ main () + return 0;
+ }
+
+-/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_layout" } } */
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_reorg" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_board_init.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_board_init.c +index 4e52564b6..d217f7bd8 100644 +--- a/gcc/testsuite/gcc.dg/struct/dfe_extr_board_init.c ++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_board_init.c +@@ -74,4 +74,4 @@ LBF_DFU_If_Needed (void) + } + } + +-/* { dg-final { scan-ipa-dump-times "Dead field elimination" 0 "struct_layout" } } */ ++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 0 "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_claw.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_claw.c +index 894e9f460..e56bf467b 100644 +--- a/gcc/testsuite/gcc.dg/struct/dfe_extr_claw.c ++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_claw.c +@@ -74,4 +74,4 @@ claw_snd_conn_req (struct net_device *dev, __u8 link) + return rc; + } + +-/* { dg-final { scan-ipa-dump-times "Dead field elimination" 1 "struct_layout" } } */ ++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 1 "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_dtrace.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_dtrace.c +index 13a226ee8..c86c4bb3c 100644 +--- a/gcc/testsuite/gcc.dg/struct/dfe_extr_dtrace.c ++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_dtrace.c +@@ -53,4 +53,4 @@ dtrace_bcmp (const void *s1, const void *s2, size_t len) + return (0); + } + +-/* { dg-final { scan-ipa-dump-times "Dead field elimination" 0 "struct_layout" } } */ ++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 0 "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_gc.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_gc.c +index 1fff2cb9d..8484d29d2 100644 +--- a/gcc/testsuite/gcc.dg/struct/dfe_extr_gc.c ++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_gc.c +@@ -159,4 +159,4 @@ gc_gray_mark (mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) + return children; + } + +-/* { dg-final { scan-ipa-dump-times "Dead field elimination" 0 "struct_layout" } } */ ++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 0 "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_hpsa.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_hpsa.c +index 0f577667c..300b2dac4 100644 +--- a/gcc/testsuite/gcc.dg/struct/dfe_extr_hpsa.c ++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_hpsa.c +@@ -123,4 +123,4 @@ hpsa_cmd_dev_match (struct ctlr_info *h, struct CommandList *c, + return match; + } + +-/* { dg-final { scan-ipa-dump-times "Dead field elimination" 0 "struct_layout" } } */ ++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 0 "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_mv_udc_core.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_mv_udc_core.c +index 9801f87f1..9397b98ea 100644 +--- a/gcc/testsuite/gcc.dg/struct/dfe_extr_mv_udc_core.c ++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_mv_udc_core.c +@@ -79,4 +79,4 @@ ep0_reset (struct mv_udc *udc) + } + } + +-/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_layout" } } */ ++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_tcp_usrreq.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_tcp_usrreq.c +index 5570c762e..0ae75e13e 100644 +--- a/gcc/testsuite/gcc.dg/struct/dfe_extr_tcp_usrreq.c ++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_tcp_usrreq.c +@@ -55,4 +55,4 @@ tcp_usr_listen (struct socket *so, struct proc *p) + COMMON_END (PRU_LISTEN); + } + +-/* { dg-final { scan-ipa-dump-times "Dead field elimination" 1 "struct_layout" } } */ ++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 1 "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_ui_main.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_ui_main.c +index 50ab9cc24..512fb37a7 100644 +--- a/gcc/testsuite/gcc.dg/struct/dfe_extr_ui_main.c ++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_ui_main.c +@@ -58,4 +58,4 @@ UI_LoadMods () + } + } + +-/* { dg-final { scan-ipa-dump-times "Dead field elimination" 1 "struct_layout" } } */ ++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 1 "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/dfe_mem_ref_offset.c b/gcc/testsuite/gcc.dg/struct/dfe_mem_ref_offset.c +index 53583fe82..0dea5517c 100644 +--- a/gcc/testsuite/gcc.dg/struct/dfe_mem_ref_offset.c ++++ b/gcc/testsuite/gcc.dg/struct/dfe_mem_ref_offset.c +@@ -55,4 +55,4 @@ main () + return 0;
+ }
+
+-/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_layout" } } */
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_reorg" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_mul_layer_ptr_record_bug.c b/gcc/testsuite/gcc.dg/struct/dfe_mul_layer_ptr_record_bug.c +index fd675ec2e..00bd911c1 100644 +--- a/gcc/testsuite/gcc.dg/struct/dfe_mul_layer_ptr_record_bug.c ++++ b/gcc/testsuite/gcc.dg/struct/dfe_mul_layer_ptr_record_bug.c +@@ -27,4 +27,4 @@ main() { + return 0;
+ }
+
+-/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_layout" } } */
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_reorg" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_ptr_diff.c b/gcc/testsuite/gcc.dg/struct/dfe_ptr_diff.c +index 600e7908b..0cfa6554e 100644 +--- a/gcc/testsuite/gcc.dg/struct/dfe_ptr_diff.c ++++ b/gcc/testsuite/gcc.dg/struct/dfe_ptr_diff.c +@@ -68,4 +68,4 @@ main () + return 0;
+ }
+
+-/* { dg-final { scan-ipa-dump-times "Dead field elimination" 3 "struct_layout" } } */
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 3 "struct_reorg" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_ptr_negate_expr.c b/gcc/testsuite/gcc.dg/struct/dfe_ptr_negate_expr.c +index f411364a7..4a7069244 100644 +--- a/gcc/testsuite/gcc.dg/struct/dfe_ptr_negate_expr.c ++++ b/gcc/testsuite/gcc.dg/struct/dfe_ptr_negate_expr.c +@@ -52,4 +52,4 @@ main () + return 0;
+ }
+
+-/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_layout" } } */
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_reorg" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/dfe_ptr_ptr.c b/gcc/testsuite/gcc.dg/struct/dfe_ptr_ptr.c +index a4e723763..b91efe10f 100644 +--- a/gcc/testsuite/gcc.dg/struct/dfe_ptr_ptr.c ++++ b/gcc/testsuite/gcc.dg/struct/dfe_ptr_ptr.c +@@ -52,4 +52,4 @@ main () + return 0;
+ }
+
+-/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_layout" } } */
++/* { dg-final { scan-ipa-dump-times "Dead field elimination" 2 "struct_reorg" } } */
+diff --git a/gcc/testsuite/gcc.dg/struct/rf_DTE_struct_instance_field.c b/gcc/testsuite/gcc.dg/struct/rf_DTE_struct_instance_field.c +index 882a695b0..1b6a462e2 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_DTE_struct_instance_field.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_DTE_struct_instance_field.c +@@ -72,4 +72,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "No structures to transform." "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "No structures to transform." "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c b/gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c +index 20ecee545..346c71264 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c +@@ -91,4 +91,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_check_ptr_layers_bug.c b/gcc/testsuite/gcc.dg/struct/rf_check_ptr_layers_bug.c +index ad879fc11..8eb16c8d6 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_check_ptr_layers_bug.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_check_ptr_layers_bug.c +@@ -21,4 +21,4 @@ main() + { + g(); + } +-/* { dg-final { scan-ipa-dump "No structures to transform." "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "No structures to transform." "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_create_fields_bug.c b/gcc/testsuite/gcc.dg/struct/rf_create_fields_bug.c +index f0c9d8f39..7d7641f01 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_create_fields_bug.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_create_fields_bug.c +@@ -79,4 +79,4 @@ main() + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_create_new_func_bug.c b/gcc/testsuite/gcc.dg/struct/rf_create_new_func_bug.c +index fa5e6c2d0..63fb3f828 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_create_new_func_bug.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_create_new_func_bug.c +@@ -53,4 +53,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_ele_minus_verify.c b/gcc/testsuite/gcc.dg/struct/rf_ele_minus_verify.c +index 2966869e7..8c431e15f 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_ele_minus_verify.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_ele_minus_verify.c +@@ -57,4 +57,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_escape_by_base.c b/gcc/testsuite/gcc.dg/struct/rf_escape_by_base.c +index b74b9e5e9..efc95a4cd 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_escape_by_base.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_escape_by_base.c +@@ -80,4 +80,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c b/gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c +index cf85c6109..75fc10575 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c +@@ -69,4 +69,4 @@ main() + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_mem_ref_offset.c b/gcc/testsuite/gcc.dg/struct/rf_mem_ref_offset.c +index 61fd9f755..9fb06877b 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_mem_ref_offset.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_mem_ref_offset.c +@@ -55,4 +55,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_mul_layer_ptr_record_bug.c b/gcc/testsuite/gcc.dg/struct/rf_mul_layer_ptr_record_bug.c +index 2c115da02..e8eb0eaa0 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_mul_layer_ptr_record_bug.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_mul_layer_ptr_record_bug.c +@@ -27,4 +27,4 @@ main() { + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c b/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c +index c7646d8b7..bd535afd0 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c +@@ -106,4 +106,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c b/gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c +index 01c000375..11393a197 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c +@@ -84,4 +84,4 @@ main () + return cnt; + } + +-/* { dg-final { scan-ipa-dump "No structures to transform." "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "No structures to transform." "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c +index f962163fe..d601fae64 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c +@@ -68,4 +68,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 3" "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 3" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_negate_expr.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_negate_expr.c +index 6558b1797..4d5f25aa1 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_ptr_negate_expr.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_negate_expr.c +@@ -52,4 +52,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c +index 6d528ed5b..b3891fde9 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c +@@ -31,4 +31,4 @@ main () + printf (" Tree.\n"); + } + +-/* { dg-final { scan-ipa-dump "No structures to transform." "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "No structures to transform." "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c +index e95cf2e5d..4df79e4f0 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c +@@ -52,4 +52,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c +index cb4054522..49d2106d1 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c +@@ -55,4 +55,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_rescusive_type.c b/gcc/testsuite/gcc.dg/struct/rf_rescusive_type.c +index 38bddbae5..f71c7894f 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_rescusive_type.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_rescusive_type.c +@@ -54,4 +54,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_rewrite_assign_more_cmp.c b/gcc/testsuite/gcc.dg/struct/rf_rewrite_assign_more_cmp.c +index 86034f042..721cee2c6 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_rewrite_assign_more_cmp.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_rewrite_assign_more_cmp.c +@@ -62,4 +62,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_bug.c b/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_bug.c +index aae7c4bc9..3871d3d99 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_bug.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_bug.c +@@ -69,4 +69,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 3" "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 3" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_more_cmp.c b/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_more_cmp.c +index 8672e7552..5ad206433 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_more_cmp.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_more_cmp.c +@@ -55,4 +55,4 @@ main() + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_rewrite_phi_bug.c b/gcc/testsuite/gcc.dg/struct/rf_rewrite_phi_bug.c +index 2d67434a0..a002f9889 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_rewrite_phi_bug.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_rewrite_phi_bug.c +@@ -78,4 +78,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 3" "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 3" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_visible_func.c b/gcc/testsuite/gcc.dg/struct/rf_visible_func.c +index a8cf2b63c..f77a062bd 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_visible_func.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_visible_func.c +@@ -89,4 +89,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/rf_void_ptr_param_func.c b/gcc/testsuite/gcc.dg/struct/rf_void_ptr_param_func.c +index b6cba3c34..cba6225a5 100644 +--- a/gcc/testsuite/gcc.dg/struct/rf_void_ptr_param_func.c ++++ b/gcc/testsuite/gcc.dg/struct/rf_void_ptr_param_func.c +@@ -51,4 +51,4 @@ main() + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_layout" } } */ +\ No newline at end of file ++/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/sr_maxmin_expr.c b/gcc/testsuite/gcc.dg/struct/sr_maxmin_expr.c +index fb135ef0b..e3d219fe1 100644 +--- a/gcc/testsuite/gcc.dg/struct/sr_maxmin_expr.c ++++ b/gcc/testsuite/gcc.dg/struct/sr_maxmin_expr.c +@@ -22,4 +22,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "No structures to transform." "struct_reorg" } } */ ++/* { dg-final { scan-ipa-dump "No structures to transform in struct split." "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp +index ac5585813..2eebef768 100644 +--- a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp ++++ b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp +@@ -64,8 +64,6 @@ gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/complete_struct_relayout + "" "-fipa-struct-reorg=1 -fdump-ipa-all -flto-partition=one -fwhole-program" + + # -fipa-struct-reorg=2 +-gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/rf*.c]] \ +- "" "-fipa-struct-reorg=2 -fdump-ipa-all -flto-partition=one -fwhole-program" + gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/wo_prof_*.c]] \ + "" "-fipa-struct-reorg=2 -fdump-ipa-all -flto-partition=one -fwhole-program" + gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/w_ratio_*.c]] \ +@@ -80,6 +78,8 @@ gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/csr_*.c]] \ + "" "-fipa-struct-reorg=2 -fdump-ipa-all -flto-partition=one -fwhole-program" + gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/complete_struct_relayout.c]] \ + "" "-fipa-struct-reorg=2 -fdump-ipa-all -flto-partition=one -fwhole-program" ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/rf*.c]] \ ++ "" "-fipa-struct-reorg=2 -fdump-ipa-all -flto-partition=one -fwhole-program" + + # -fipa-struct-reorg=3 + gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/dfe*.c]] \ +diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-1.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-1.c +index 23444fe8b..a73ff8e7e 100644 +--- a/gcc/testsuite/gcc.dg/struct/struct_reorg-1.c ++++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-1.c +@@ -27,4 +27,4 @@ int main() + return g (); + } + +-/* { dg-final { scan-ipa-dump "No structures to transform." "struct_reorg" } } */ ++/* { dg-final { scan-ipa-dump "No structures to transform in struct split." "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-2.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-2.c +index 44babd35b..d7ab7d21c 100644 +--- a/gcc/testsuite/gcc.dg/struct/struct_reorg-2.c ++++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-2.c +@@ -26,4 +26,4 @@ int main() + assert (f(1, 2) == 3); + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in struct split is 2" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-3.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-3.c +index 2d1f95c99..9e5b192eb 100644 +--- a/gcc/testsuite/gcc.dg/struct/struct_reorg-3.c ++++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-3.c +@@ -25,4 +25,4 @@ int main() + f (NULL, NULL, 1); + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in struct split is 1" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-4.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-4.c +index e5a8a6c84..27b4b56e0 100644 +--- a/gcc/testsuite/gcc.dg/struct/struct_reorg-4.c ++++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-4.c +@@ -56,4 +56,4 @@ main (void) + return 0; + } + +-/* { dg-final { scan-ipa-dump "No structures to transform." "struct_reorg" } } */ ++/* { dg-final { scan-ipa-dump "No structures to transform in struct split." "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_global_array.c b/gcc/testsuite/gcc.dg/struct/w_prof_global_array.c +index 733413a94..9e0f84da8 100644 +--- a/gcc/testsuite/gcc.dg/struct/w_prof_global_array.c ++++ b/gcc/testsuite/gcc.dg/struct/w_prof_global_array.c +@@ -26,4 +26,4 @@ main () + } + + /*--------------------------------------------------------------------------*/ +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in struct split is 1" "struct_reorg" { xfail *-*-* } } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_global_var.c b/gcc/testsuite/gcc.dg/struct/w_prof_global_var.c +index 0ef686e74..c868347e3 100644 +--- a/gcc/testsuite/gcc.dg/struct/w_prof_global_var.c ++++ b/gcc/testsuite/gcc.dg/struct/w_prof_global_var.c +@@ -39,4 +39,4 @@ main () + } + + /*--------------------------------------------------------------------------*/ +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in struct split is 1" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_local_array.c b/gcc/testsuite/gcc.dg/struct/w_prof_local_array.c +index 23a53be53..185ff3125 100644 +--- a/gcc/testsuite/gcc.dg/struct/w_prof_local_array.c ++++ b/gcc/testsuite/gcc.dg/struct/w_prof_local_array.c +@@ -34,4 +34,4 @@ main () + } + + /*--------------------------------------------------------------------------*/ +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in struct split is 1" "struct_reorg" { xfail *-*-* } } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_local_var.c b/gcc/testsuite/gcc.dg/struct/w_prof_local_var.c +index 0cbb172f2..6294fb2a2 100644 +--- a/gcc/testsuite/gcc.dg/struct/w_prof_local_var.c ++++ b/gcc/testsuite/gcc.dg/struct/w_prof_local_var.c +@@ -37,4 +37,4 @@ main () + } + + /*--------------------------------------------------------------------------*/ +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in struct split is 1" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_single_str_global.c b/gcc/testsuite/gcc.dg/struct/w_prof_single_str_global.c +index f900b1349..3ca4e0e71 100644 +--- a/gcc/testsuite/gcc.dg/struct/w_prof_single_str_global.c ++++ b/gcc/testsuite/gcc.dg/struct/w_prof_single_str_global.c +@@ -28,4 +28,4 @@ main () + } + + /*--------------------------------------------------------------------------*/ +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in struct split is 1" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_two_strs.c b/gcc/testsuite/gcc.dg/struct/w_prof_two_strs.c +index 13b4cdc70..ac99b9e62 100644 +--- a/gcc/testsuite/gcc.dg/struct/w_prof_two_strs.c ++++ b/gcc/testsuite/gcc.dg/struct/w_prof_two_strs.c +@@ -61,4 +61,4 @@ main () + } + + /*--------------------------------------------------------------------------*/ +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in struct split is 2" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/w_ratio_cold_str.c b/gcc/testsuite/gcc.dg/struct/w_ratio_cold_str.c +index dcc545964..afa145a57 100644 +--- a/gcc/testsuite/gcc.dg/struct/w_ratio_cold_str.c ++++ b/gcc/testsuite/gcc.dg/struct/w_ratio_cold_str.c +@@ -40,4 +40,4 @@ main () + + /*--------------------------------------------------------------------------*/ + /* Arrays are not handled. */ +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in struct split is 1" "struct_reorg" { xfail *-*-* } } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_array_field.c b/gcc/testsuite/gcc.dg/struct/wo_prof_array_field.c +index 6d6375fc1..7fa6ae275 100644 +--- a/gcc/testsuite/gcc.dg/struct/wo_prof_array_field.c ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_array_field.c +@@ -23,4 +23,4 @@ int main() + } + + /*--------------------------------------------------------------------------*/ +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in struct split is 1" "struct_reorg" { xfail *-*-* } } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_array_through_pointer.c b/gcc/testsuite/gcc.dg/struct/wo_prof_array_through_pointer.c +index 9d3213408..b3bde5836 100644 +--- a/gcc/testsuite/gcc.dg/struct/wo_prof_array_through_pointer.c ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_array_through_pointer.c +@@ -35,4 +35,4 @@ main () + return 0; + } + +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in struct split is 1" "struct_reorg" { xfail *-*-* } } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_double_malloc.c b/gcc/testsuite/gcc.dg/struct/wo_prof_double_malloc.c +index d79992a53..f2bb82b94 100644 +--- a/gcc/testsuite/gcc.dg/struct/wo_prof_double_malloc.c ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_double_malloc.c +@@ -26,4 +26,4 @@ int main() + } + + /*--------------------------------------------------------------------------*/ +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in struct split is 1" "struct_reorg" { xfail *-*-* } } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_empty_str.c b/gcc/testsuite/gcc.dg/struct/wo_prof_empty_str.c +index ee9b0d765..0685cf8fe 100644 +--- a/gcc/testsuite/gcc.dg/struct/wo_prof_empty_str.c ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_empty_str.c +@@ -41,4 +41,4 @@ main () + } + + /*--------------------------------------------------------------------------*/ +-/* { dg-final { scan-ipa-dump "No structures to transform" "struct_reorg" } } */ ++/* { dg-final { scan-ipa-dump "No structures to transform in struct split" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_arg_to_local.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_arg_to_local.c +index 9ebb2b4cc..1a0a5a9c6 100644 +--- a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_arg_to_local.c ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_arg_to_local.c +@@ -40,5 +40,5 @@ main () + } + + /*--------------------------------------------------------------------------*/ +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in struct split is 1" "struct_reorg" } } */ + +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_array.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_array.c +index 60d2466e1..9533538c4 100644 +--- a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_array.c ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_array.c +@@ -30,4 +30,4 @@ main () + } + + /*--------------------------------------------------------------------------*/ +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in struct split is 1" "struct_reorg" { xfail *-*-* } } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_global_array.c b/gcc/testsuite/gcc.dg/struct/wo_prof_global_array.c +index 1c5a3aa15..100a93868 100644 +--- a/gcc/testsuite/gcc.dg/struct/wo_prof_global_array.c ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_global_array.c +@@ -29,4 +29,4 @@ main () + } + + /*--------------------------------------------------------------------------*/ +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in struct split is 1" "struct_reorg" { xfail *-*-* } } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_global_var.c b/gcc/testsuite/gcc.dg/struct/wo_prof_global_var.c +index a0d1467fe..669d0b886 100644 +--- a/gcc/testsuite/gcc.dg/struct/wo_prof_global_var.c ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_global_var.c +@@ -42,4 +42,4 @@ main () + } + + /*--------------------------------------------------------------------------*/ +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in struct split is 1" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_local_array.c b/gcc/testsuite/gcc.dg/struct/wo_prof_local_array.c +index 6c24e1c8b..ce6c1544c 100644 +--- a/gcc/testsuite/gcc.dg/struct/wo_prof_local_array.c ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_local_array.c +@@ -37,4 +37,4 @@ main () + } + + /*--------------------------------------------------------------------------*/ +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" { xfail *-*-* } } } */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in struct split is 1" "struct_reorg" { xfail *-*-* } } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_local_var.c b/gcc/testsuite/gcc.dg/struct/wo_prof_local_var.c +index 8f2f8143f..eca2ebf32 100644 +--- a/gcc/testsuite/gcc.dg/struct/wo_prof_local_var.c ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_local_var.c +@@ -40,4 +40,4 @@ main () + } + + /*--------------------------------------------------------------------------*/ +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in struct split is 1" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var-1.c b/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var-1.c +index 98bf01a6d..6f8f94d7d 100644 +--- a/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var-1.c ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var-1.c +@@ -44,4 +44,4 @@ main () + } + + /*--------------------------------------------------------------------------*/ +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in struct split is 1" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var.c b/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var.c +index 66b0f967c..2ca729d1f 100644 +--- a/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var.c ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var.c +@@ -44,4 +44,4 @@ main () + } + + /*--------------------------------------------------------------------------*/ +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in struct split is 1" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_mult_field_peeling.c b/gcc/testsuite/gcc.dg/struct/wo_prof_mult_field_peeling.c +index d28bcfb02..6000b2919 100644 +--- a/gcc/testsuite/gcc.dg/struct/wo_prof_mult_field_peeling.c ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_mult_field_peeling.c +@@ -39,4 +39,4 @@ main () + + /*--------------------------------------------------------------------------*/ + /* Two more fields structure is not splitted. */ +-/* { dg-final { scan-ipa-dump "No structures to transform." "struct_reorg" } } */ ++/* { dg-final { scan-ipa-dump "No structures to transform in struct split." "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_global.c b/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_global.c +index 37a6a43a8..f4a103409 100644 +--- a/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_global.c ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_global.c +@@ -31,4 +31,4 @@ main () + } + + /*--------------------------------------------------------------------------*/ +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in struct split is 1" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_local.c b/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_local.c +index ca9a8efcf..0c97173eb 100644 +--- a/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_local.c ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_local.c +@@ -31,4 +31,4 @@ main () + } + + /*--------------------------------------------------------------------------*/ +-/* { dg-final { scan-ipa-dump "No structures to transform" "struct_reorg" } } */ ++/* { dg-final { scan-ipa-dump "No structures to transform in struct split" "struct_reorg" } } */ +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_two_strs.c b/gcc/testsuite/gcc.dg/struct/wo_prof_two_strs.c +index cba92e995..bc8eacc77 100644 +--- a/gcc/testsuite/gcc.dg/struct/wo_prof_two_strs.c ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_two_strs.c +@@ -64,4 +64,4 @@ main () + } + + /*--------------------------------------------------------------------------*/ +-/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "struct_reorg" } } */ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in struct split is 2" "struct_reorg" } } */ +diff --git a/gcc/timevar.def b/gcc/timevar.def +index e9866ebf0..2814b14f2 100644 +--- a/gcc/timevar.def ++++ b/gcc/timevar.def +@@ -80,7 +80,6 @@ DEFTIMEVAR (TV_IPA_CONSTANT_PROP , "ipa cp") + DEFTIMEVAR (TV_IPA_INLINING , "ipa inlining heuristics") + DEFTIMEVAR (TV_IPA_FNSPLIT , "ipa function splitting") + DEFTIMEVAR (TV_IPA_COMDATS , "ipa comdats") +-DEFTIMEVAR (TV_IPA_STRUCT_LAYOUT , "ipa struct layout optimization") + DEFTIMEVAR (TV_IPA_STRUCT_REORG , "ipa struct reorg optimization") + DEFTIMEVAR (TV_IPA_EXTEND_AUTO_PROFILE, "ipa extend auto profile") + DEFTIMEVAR (TV_IPA_OPT , "ipa various optimizations") +diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h +index 09dd9b289..2b4864b89 100644 +--- a/gcc/tree-pass.h ++++ b/gcc/tree-pass.h +@@ -510,7 +510,6 @@ extern ipa_opt_pass_d *make_pass_ipa_odr (gcc::context *ctxt); + extern ipa_opt_pass_d *make_pass_ipa_reference (gcc::context *ctxt); + extern ipa_opt_pass_d *make_pass_ipa_hsa (gcc::context *ctxt); + extern ipa_opt_pass_d *make_pass_ipa_pure_const (gcc::context *ctxt); +-extern simple_ipa_opt_pass *make_pass_ipa_struct_layout (gcc::context *ctxt); + extern simple_ipa_opt_pass *make_pass_ipa_struct_reorg (gcc::context *ctxt); + extern simple_ipa_opt_pass *make_pass_ipa_extend_auto_profile (gcc::context + *ctxt); +diff --git a/gcc/tree.c b/gcc/tree.c +index 84a440b35..8bbd54e0d 100644 +--- a/gcc/tree.c ++++ b/gcc/tree.c +@@ -5222,7 +5222,7 @@ fld_simplified_type_name (tree type) + /* Simplify type will cause that struct A and struct A within + struct B are different type pointers, so skip it in structure + optimizations. */ +- if ((flag_ipa_struct_layout || flag_ipa_struct_reorg) ++ if (flag_ipa_struct_reorg + && lang_c_p () + && flag_lto_partition == LTO_PARTITION_ONE + && (in_lto_p || flag_whole_program)) +@@ -5469,7 +5469,7 @@ fld_simplified_type (tree t, class free_lang_data_d *fld) + /* Simplify type will cause that struct A and struct A within + struct B are different type pointers, so skip it in structure + optimizations. */ +- if ((flag_ipa_struct_layout || flag_ipa_struct_reorg) ++ if (flag_ipa_struct_reorg + && lang_c_p () + && flag_lto_partition == LTO_PARTITION_ONE + && (in_lto_p || flag_whole_program)) +-- +2.27.0.windows.1 + diff --git a/0073-PHIOPT-Add-A-B-op-CST-B-match-and-simplify-optimizat.patch b/0073-PHIOPT-Add-A-B-op-CST-B-match-and-simplify-optimizat.patch new file mode 100644 index 0000000..8057532 --- /dev/null +++ b/0073-PHIOPT-Add-A-B-op-CST-B-match-and-simplify-optimizat.patch @@ -0,0 +1,89 @@ +From 9af03694082c462bee86c167c78717089a93a188 Mon Sep 17 00:00:00 2001 +From: zhongyunde <zhongyunde@huawei.com> +Date: Sat, 5 Nov 2022 13:22:33 +0800 +Subject: [PATCH 25/35] [PHIOPT] Add A ? B op CST : B match and simplify + optimizations + + Refer to commit b6bdd7a4, use pattern match to simple + A ? B op CST : B (where CST is power of 2) simplifications. + Fixes the 1st issue of https://gitee.com/openeuler/gcc/issues/I5TSG0?from=project-issue. + + gcc/ + * match.pd (A ? B op CST : B): Add simplifcations for A ? B op POW2 : B + + gcc/testsuite/ + * gcc.dg/pr107190.c: New test. +--- + gcc/match.pd | 21 +++++++++++++++++++++ + gcc/testsuite/gcc.dg/pr107190.c | 27 +++++++++++++++++++++++++++ + 2 files changed, 48 insertions(+) + create mode 100644 gcc/testsuite/gcc.dg/pr107190.c + +diff --git a/gcc/match.pd b/gcc/match.pd +index fc1a34dd3..5c5b5f89e 100644 +--- a/gcc/match.pd ++++ b/gcc/match.pd +@@ -3383,6 +3383,27 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) + ) + #endif + ++#if GIMPLE ++(if (canonicalize_math_p ()) ++/* These patterns are mostly used by PHIOPT to move some operations outside of ++ the if statements. They should be done late because it gives jump threading ++ and few other passes to reduce what is going on. */ ++/* a ? x op C : x -> x op (a << log2(C)) when C is power of 2. */ ++ (for op (plus minus bit_ior bit_xor lshift rshift lrotate rrotate) ++ (simplify ++ (cond @0 (op:s @1 integer_pow2p@2) @1) ++ /* powerof2cst */ ++ (if (INTEGRAL_TYPE_P (type)) ++ (with { ++ tree shift = build_int_cst (integer_type_node, tree_log2 (@2)); ++ } ++ (op @1 (lshift (convert (convert:boolean_type_node @0)) { shift; }))) ++ ) ++ ) ++ ) ++) ++#endif ++ + /* Simplification moved from fold_cond_expr_with_comparison. It may also + be extended. */ + /* This pattern implements two kinds simplification: +diff --git a/gcc/testsuite/gcc.dg/pr107190.c b/gcc/testsuite/gcc.dg/pr107190.c +new file mode 100644 +index 000000000..235b2761a +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/pr107190.c +@@ -0,0 +1,27 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -fexpensive-optimizations -fdump-tree-phiopt2-details" } */ ++ ++# define BN_BITS4 32 ++# define BN_MASK2 (0xffffffffffffffffL) ++# define BN_MASK2l (0xffffffffL) ++# define BN_MASK2h (0xffffffff00000000L) ++# define BN_MASK2h1 (0xffffffff80000000L) ++# define LBITS(a) ((a)&BN_MASK2l) ++# define HBITS(a) (((a)>>BN_BITS4)&BN_MASK2l) ++# define L2HBITS(a) (((a)<<BN_BITS4)&BN_MASK2) ++ ++unsigned int test_m(unsigned long in0, unsigned long in1) { ++ unsigned long m, m1, lt, ht, bl, bh; ++ lt = LBITS(in0); ++ ht = HBITS(in0); ++ bl = LBITS(in1); ++ bh = HBITS(in1); ++ m = bh * lt; ++ m1 = bl * ht; ++ ht = bh * ht; ++ m = (m + m1) & BN_MASK2; ++ if (m < m1) ht += L2HBITS((unsigned long)1); ++ return ht + m; ++} ++ ++/* { dg-final { scan-tree-dump "COND_EXPR in block 2 and PHI in block 4 converted to straightline code" "phiopt2" } } */ +-- +2.27.0.windows.1 + diff --git a/0074-FORWPROP-Fold-series-of-instructions-into-mul.patch b/0074-FORWPROP-Fold-series-of-instructions-into-mul.patch new file mode 100644 index 0000000..d864621 --- /dev/null +++ b/0074-FORWPROP-Fold-series-of-instructions-into-mul.patch @@ -0,0 +1,130 @@ +From 2a2d0ba6a26d64f4c1f9352bb2c69dea8b67d6a6 Mon Sep 17 00:00:00 2001 +From: zhongyunde <zhongyunde@huawei.com> +Date: Wed, 9 Nov 2022 17:04:13 +0800 +Subject: [PATCH 26/35] [FORWPROP] Fold series of instructions into mul + + Merge the low part of series instructions into mul + + gcc/ + * match.pd: Add simplifcations for low part of mul + * common.opt: Add new option fmerge-mull enable with -O2 + * opts.c: default_options_table + + gcc/testsuite/ + * g++.dg/tree-ssa/mull64.C: New test. +--- + gcc/common.opt | 4 +++ + gcc/match.pd | 27 ++++++++++++++++++++ + gcc/opts.c | 1 + + gcc/testsuite/g++.dg/tree-ssa/mull64.C | 34 ++++++++++++++++++++++++++ + 4 files changed, 66 insertions(+) + create mode 100644 gcc/testsuite/g++.dg/tree-ssa/mull64.C + +diff --git a/gcc/common.opt b/gcc/common.opt +index ad147f7a9..6a7f66624 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -2069,6 +2069,10 @@ fmerge-debug-strings + Common Report Var(flag_merge_debug_strings) Init(1) + Attempt to merge identical debug strings across compilation units. + ++fmerge-mull ++Common Report Var(flag_merge_mull) Init(0) Optimization ++Attempt to merge series instructions into mul. ++ + fmessage-length= + Common RejectNegative Joined UInteger + -fmessage-length=<number> Limit diagnostics to <number> characters per line. 0 suppresses line-wrapping. +diff --git a/gcc/match.pd b/gcc/match.pd +index 5c5b5f89e..f6c5befd7 100644 +--- a/gcc/match.pd ++++ b/gcc/match.pd +@@ -3404,6 +3404,33 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) + ) + #endif + ++#if GIMPLE ++/* These patterns are mostly used by FORWPROP1 to fold some operations into more ++ simple IR. The following scenario should be matched: ++ In0Lo = In0(D) & 4294967295; ++ In0Hi = In0(D) >> 32; ++ In1Lo = In1(D) & 4294967295; ++ In1Hi = In1(D) >> 32; ++ Addc = In0Lo * In1Hi + In0Hi * In1Lo; ++ addc32 = Addc << 32; ++ ResLo = In0Lo * In1Lo + addc32 */ ++(simplify ++ (plus:c (mult @4 @5) ++ (lshift ++ (plus:c ++ (mult (bit_and@4 SSA_NAME@0 @2) (rshift SSA_NAME@1 @3)) ++ (mult (rshift SSA_NAME@0 @3) (bit_and@5 SSA_NAME@1 INTEGER_CST@2))) ++ INTEGER_CST@3 ++ ) ++ ) ++ (if (flag_merge_mull && INTEGRAL_TYPE_P (type) ++ && INTEGRAL_TYPE_P (TREE_TYPE (@0)) && types_match (@0, @1) ++ && TYPE_PRECISION (type) == 64) ++ (mult (convert:type @0) (convert:type @1)) ++ ) ++) ++#endif ++ + /* Simplification moved from fold_cond_expr_with_comparison. It may also + be extended. */ + /* This pattern implements two kinds simplification: +diff --git a/gcc/opts.c b/gcc/opts.c +index f12b13599..751965e46 100644 +--- a/gcc/opts.c ++++ b/gcc/opts.c +@@ -511,6 +511,7 @@ static const struct default_options default_options_table[] = + { OPT_LEVELS_2_PLUS, OPT_fvect_cost_model_, NULL, VECT_COST_MODEL_CHEAP }, + { OPT_LEVELS_2_PLUS, OPT_finline_functions, NULL, 1 }, + { OPT_LEVELS_2_PLUS, OPT_ftree_loop_distribute_patterns, NULL, 1 }, ++ { OPT_LEVELS_2_PLUS, OPT_fmerge_mull, NULL, 1 }, + + /* -O2 and above optimizations, but not -Os or -Og. */ + { OPT_LEVELS_2_PLUS_SPEED_ONLY, OPT_falign_functions, NULL, 1 }, +diff --git a/gcc/testsuite/g++.dg/tree-ssa/mull64.C b/gcc/testsuite/g++.dg/tree-ssa/mull64.C +new file mode 100644 +index 000000000..2a3b74604 +--- /dev/null ++++ b/gcc/testsuite/g++.dg/tree-ssa/mull64.C +@@ -0,0 +1,34 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -Wno-psabi -fmerge-mull -fdump-tree-forwprop1-details" } */ ++ ++# define BN_BITS4 32 ++# define BN_MASK2 (0xffffffffffffffffL) ++# define BN_MASK2l (0xffffffffL) ++# define BN_MASK2h (0xffffffff00000000L) ++# define BN_MASK2h1 (0xffffffff80000000L) ++# define LBITS(a) ((a)&BN_MASK2l) ++# define HBITS(a) (((a)>>BN_BITS4)&BN_MASK2l) ++# define L2HBITS(a) (((a)<<BN_BITS4)&BN_MASK2) ++ ++void mul64(unsigned long in0, unsigned long in1, ++ unsigned long &retLo, unsigned long &retHi) { ++ unsigned long m00, m01, m10, m11, al, ah, bl, bh; ++ unsigned long Addc, addc32, low; ++ al = LBITS(in0); ++ ah = HBITS(in0); ++ bl = LBITS(in1); ++ bh = HBITS(in1); ++ m10 = bh * al; ++ m00 = bl * al; ++ m01 = bl * ah; ++ m11 = bh * ah; ++ Addc = (m10 + m01) & BN_MASK2; ++ if (Addc < m01) m11 += L2HBITS((unsigned long)1); ++ m11 += HBITS(Addc); ++ addc32 = L2HBITS(Addc); ++ low = (m00 + addc32) & BN_MASK2; if (low < addc32) m11++; ++ retLo = low; ++ retHi = m11; ++} ++ ++/* { dg-final { scan-tree-dump "gimple_simplified to low_18 = in0_4" "forwprop1" } } */ +-- +2.27.0.windows.1 + diff --git a/0075-FORWPROP-Fold-series-of-instructions-into-umulh.patch b/0075-FORWPROP-Fold-series-of-instructions-into-umulh.patch new file mode 100644 index 0000000..e8a58aa --- /dev/null +++ b/0075-FORWPROP-Fold-series-of-instructions-into-umulh.patch @@ -0,0 +1,105 @@ +From 315911bd3ae6f42366779e262ab76d9ed79359a0 Mon Sep 17 00:00:00 2001 +From: zhongyunde <zhongyunde@huawei.com> +Date: Fri, 11 Nov 2022 11:30:37 +0800 +Subject: [PATCH 27/35] [FORWPROP] Fold series of instructions into umulh + + Merge the high part of series instructions into umulh + + gcc/ + * match.pd: Add simplifcations for high part of umulh + + gcc/testsuite/ + * g++.dg/tree-ssa/mull64.C: Add checking of tree pass forwprop4 +--- + gcc/match.pd | 56 ++++++++++++++++++++++++++ + gcc/testsuite/g++.dg/tree-ssa/mull64.C | 5 ++- + 2 files changed, 59 insertions(+), 2 deletions(-) + +diff --git a/gcc/match.pd b/gcc/match.pd +index f6c5befd7..433682afb 100644 +--- a/gcc/match.pd ++++ b/gcc/match.pd +@@ -3404,6 +3404,62 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) + ) + #endif + ++#if GIMPLE ++/* These patterns are mostly used by FORWPROP4 to move some operations outside of ++ the if statements. They should be done late because it gives jump threading ++ and few other passes to reduce what is going on. */ ++/* Mul64 is defined as a multiplication algorithm which compute two 64-bit ++ integers to one 128-bit integer. Try to match the high part of mul pattern ++ after the low part of mul pattern is simplified. The following scenario ++ should be matched: ++ (i64 ResLo, i64 ResHi) = Mul64(i64 In0, i64 In1) { ++ In0Lo = In0(D) & 4294967295; -- bit_and@4 SSA_NAME@0 @2 ++ In0Hi = In0(D) >> 32; -- rshift@5 SSA_NAME@0 @3 ++ In1Lo = In1(D) & 4294967295; -- bit_and@6 SSA_NAME@1 INTEGER_CST@2 ++ In1Hi = In1(D) >> 32; -- rshift@7 SSA_NAME@1 INTEGER_CST@3 ++ Mull_01 = In0Hi * In1Lo; -- mult@8 @5 @6 ++ Addc = In0Lo * In1Hi + Mull_01; -- plus@9 (mult (@4 @7) @8 ++ AddH = (Addc >> 32) + In0Hi * In1Hi -- (plus@11 (rshift @9 @3) (mult @5 @7)) ++ addc32 = Addc << 32; -- lshift@10 @9 @3 ++ ResLo = In0(D) * In1(D); -- mult @0 @1 ++ ResHi = ((long unsigned int) (addc32 > ResLo)) + ++ (((long unsigned int) (Mull_01 > Addc)) << 32) + AddH; ++ } */ ++(simplify ++ (plus:c ++ (plus:c ++ (convert ++ (gt (lshift@10 @9 @3) ++ (mult:c @0 @1))) ++ (lshift ++ (convert ++ (gt @8 @9)) ++ @3)) ++ (plus:c@11 ++ (rshift ++ (plus:c@9 ++ (mult:c (bit_and@4 SSA_NAME@0 @2) @7) ++ (mult:c@8 @5 (bit_and@6 SSA_NAME@1 INTEGER_CST@2))) ++ @3) ++ (mult:c (rshift@5 SSA_NAME@0 @3) ++ (rshift@7 SSA_NAME@1 INTEGER_CST@3)) ++ ) ++ ) ++ (if (flag_merge_mull && INTEGRAL_TYPE_P (type) ++ && INTEGRAL_TYPE_P (TREE_TYPE (@0)) && types_match (@0, @1) ++ && TYPE_PRECISION (type) == 64) ++ (with { ++ tree i128_type = build_nonstandard_integer_type (128, TYPE_UNSIGNED (type)); ++ tree shift = build_int_cst (integer_type_node, 64); ++ } ++ (convert:type (rshift ++ (mult (convert:i128_type @0) ++ (convert:i128_type @1)) ++ { shift; }))) ++ ) ++) ++#endif ++ + #if GIMPLE + /* These patterns are mostly used by FORWPROP1 to fold some operations into more + simple IR. The following scenario should be matched: +diff --git a/gcc/testsuite/g++.dg/tree-ssa/mull64.C b/gcc/testsuite/g++.dg/tree-ssa/mull64.C +index 2a3b74604..f61cf5e6f 100644 +--- a/gcc/testsuite/g++.dg/tree-ssa/mull64.C ++++ b/gcc/testsuite/g++.dg/tree-ssa/mull64.C +@@ -1,5 +1,5 @@ + /* { dg-do compile } */ +-/* { dg-options "-O2 -Wno-psabi -fmerge-mull -fdump-tree-forwprop1-details" } */ ++/* { dg-options "-O2 -Wno-psabi -fdump-tree-forwprop1-details -fdump-tree-forwprop4-details" } */ + + # define BN_BITS4 32 + # define BN_MASK2 (0xffffffffffffffffL) +@@ -31,4 +31,5 @@ void mul64(unsigned long in0, unsigned long in1, + retHi = m11; + } + +-/* { dg-final { scan-tree-dump "gimple_simplified to low_18 = in0_4" "forwprop1" } } */ ++/* { dg-final { scan-tree-dump "gimple_simplified to" "forwprop1" } } */ ++/* { dg-final { scan-tree-dump-times "gimple_simplified to" 1 "forwprop4" } } */ +-- +2.27.0.windows.1 + diff --git a/0076-Struct-Reorg-Fix-speccpu2006-462-double-free-I60YUV.patch b/0076-Struct-Reorg-Fix-speccpu2006-462-double-free-I60YUV.patch new file mode 100644 index 0000000..88613ba --- /dev/null +++ b/0076-Struct-Reorg-Fix-speccpu2006-462-double-free-I60YUV.patch @@ -0,0 +1,38 @@ +From b669b4512e8425f4d752ef76bf61097cf40d9b35 Mon Sep 17 00:00:00 2001 +From: zgat <1071107108@qq.com> +Date: Thu, 17 Nov 2022 02:55:48 +0000 +Subject: [PATCH 28/35] [Struct Reorg] Fix speccpu2006 462 double free #I60YUV + modify gcc/tree.c. Normal operation speccpu 462 after modifed + +Signed-off-by: zgat <1071107108@qq.com> +--- + gcc/tree.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/gcc/tree.c b/gcc/tree.c +index 2a532d15a..a61788651 100644 +--- a/gcc/tree.c ++++ b/gcc/tree.c +@@ -5224,8 +5224,7 @@ fld_simplified_type_name (tree type) + optimizations. */ + if (flag_ipa_struct_reorg + && lang_c_p () +- && flag_lto_partition == LTO_PARTITION_ONE +- && (in_lto_p || flag_whole_program)) ++ && flag_lto_partition == LTO_PARTITION_ONE) + return TYPE_NAME (type); + + if (!TYPE_NAME (type) || TREE_CODE (TYPE_NAME (type)) != TYPE_DECL) +@@ -5471,8 +5470,7 @@ fld_simplified_type (tree t, class free_lang_data_d *fld) + optimizations. */ + if (flag_ipa_struct_reorg + && lang_c_p () +- && flag_lto_partition == LTO_PARTITION_ONE +- && (in_lto_p || flag_whole_program)) ++ && flag_lto_partition == LTO_PARTITION_ONE) + return t; + if (POINTER_TYPE_P (t)) + return fld_incomplete_type_of (t, fld); +-- +2.27.0.windows.1 + diff --git a/0077-Struct-Reorg-Add-Safe-Structure-Pointer-Compression.patch b/0077-Struct-Reorg-Add-Safe-Structure-Pointer-Compression.patch new file mode 100644 index 0000000..c804ea6 --- /dev/null +++ b/0077-Struct-Reorg-Add-Safe-Structure-Pointer-Compression.patch @@ -0,0 +1,1193 @@ +From 0445301c09926a20d5e02809b2cd35bddc9fa50e Mon Sep 17 00:00:00 2001 +From: liyancheng <412998149@qq.com> +Date: Wed, 9 Nov 2022 21:00:04 +0800 +Subject: [PATCH 29/35] [Struct Reorg] Add Safe Structure Pointer Compression + +Safe structure pointer compression allows safely compressing pointers +stored in structure to reduce the size of structure. +Add flag -fipa-struct-reorg=4 to enable safe structure pointer compression. +--- + gcc/common.opt | 5 +- + gcc/ipa-struct-reorg/ipa-struct-reorg.c | 905 +++++++++++++++++++++++- + gcc/ipa-struct-reorg/ipa-struct-reorg.h | 4 + + gcc/params.opt | 4 + + 4 files changed, 877 insertions(+), 41 deletions(-) + +diff --git a/gcc/common.opt b/gcc/common.opt +index 6a7f66624..c9b099817 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -1889,8 +1889,9 @@ Common Report Var(flag_ipa_struct_reorg) Init(0) Optimization + Perform structure layout optimizations. + + fipa-struct-reorg= +-Common RejectNegative Joined UInteger Var(struct_layout_optimize_level) Init(0) IntegerRange(0, 3) +--fipa-struct-reorg=[0,1,2,3] adding none, struct-reorg, reorder-fields, dfe optimizations. ++Common RejectNegative Joined UInteger Var(struct_layout_optimize_level) Init(0) IntegerRange(0, 4) ++-fipa-struct-reorg=[0,1,2,3,4] adding none, struct-reorg, reorder-fields, ++dfe, safe-pointer-compression optimizations. + + fipa-extend-auto-profile + Common Report Var(flag_ipa_extend_auto_profile) +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +index 08cb51fee..3550411dc 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -83,6 +83,7 @@ along with GCC; see the file COPYING3. If not see + #include "gimple-iterator.h" + #include "gimple-walk.h" + #include "cfg.h" ++#include "cfghooks.h" /* For split_block. */ + #include "ssa.h" + #include "tree-dfa.h" + #include "fold-const.h" +@@ -145,7 +146,27 @@ namespace { + using namespace struct_reorg; + using namespace struct_relayout; + +-/* Return true iff TYPE is stdarg va_list type. */ ++static void ++set_var_attributes (tree var) ++{ ++ if (!var) ++ return; ++ gcc_assert (TREE_CODE (var) == VAR_DECL); ++ ++ DECL_ARTIFICIAL (var) = 1; ++ DECL_EXTERNAL (var) = 0; ++ TREE_STATIC (var) = 1; ++ TREE_PUBLIC (var) = 0; ++ TREE_USED (var) = 1; ++ DECL_CONTEXT (var) = NULL_TREE; ++ TREE_THIS_VOLATILE (var) = 0; ++ TREE_ADDRESSABLE (var) = 0; ++ TREE_READONLY (var) = 0; ++ if (is_global_var (var)) ++ set_decl_tls_model (var, TLS_MODEL_NONE); ++} ++ ++/* Return true if TYPE is stdarg va_list type. */ + + static inline bool + is_va_list_type (tree type) +@@ -242,9 +263,15 @@ enum struct_layout_opt_level + STRUCT_SPLIT = 1 << 0, + COMPLETE_STRUCT_RELAYOUT = 1 << 1, + STRUCT_REORDER_FIELDS = 1 << 2, +- DEAD_FIELD_ELIMINATION = 1 << 3 ++ DEAD_FIELD_ELIMINATION = 1 << 3, ++ POINTER_COMPRESSION_SAFE = 1 << 4 + }; + ++/* Defines the target pointer size of compressed pointer, which should be 8, ++ 16, 32. */ ++ ++static int compressed_size = 32; ++ + static bool is_result_of_mult (tree arg, tree *num, tree struct_size); + bool isptrptr (tree type); + void get_base (tree &base, tree expr); +@@ -366,7 +393,10 @@ srtype::srtype (tree type) + : type (type), + chain_type (false), + escapes (does_not_escape), ++ pc_gptr (NULL_TREE), + visited (false), ++ pc_candidate (false), ++ has_legal_alloc_num (false), + has_alloc_array (0) + { + for (int i = 0; i < max_split; i++) +@@ -447,6 +477,31 @@ srtype::mark_escape (escape_type e, gimple *stmt) + } + } + ++/* Create a global header for compressed struct. */ ++ ++void ++srtype::create_global_ptr_for_pc () ++{ ++ if (!pc_candidate || pc_gptr != NULL_TREE) ++ return; ++ ++ const char *type_name = get_type_name (type); ++ gcc_assert (type_name != NULL); ++ ++ char *gptr_name = concat (type_name, "_pc", NULL); ++ tree new_name = get_identifier (gptr_name); ++ tree new_type = build_pointer_type (newtype[0]); ++ tree new_var = build_decl (UNKNOWN_LOCATION, VAR_DECL, new_name, new_type); ++ set_var_attributes (new_var); ++ pc_gptr = new_var; ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "\nType: %s has create global header for pointer" ++ " compression: %s\n", type_name, gptr_name); ++ ++ free (gptr_name); ++} ++ + /* Add FIELD to the list of fields that use this type. */ + + void +@@ -790,20 +845,31 @@ srfield::create_new_optimized_fields (tree newtype[max_split], + fields.safe_push (field); + } + +- DECL_NAME (field) = DECL_NAME (fielddecl); + if (type == NULL) + { ++ DECL_NAME (field) = DECL_NAME (fielddecl); + /* Common members do not need to reconstruct. + Otherwise, int* -> int** or void* -> void**. */ + TREE_TYPE (field) = nt; ++ SET_DECL_ALIGN (field, DECL_ALIGN (fielddecl)); ++ } ++ else if (type->pc_candidate) ++ { ++ const char *old_name = IDENTIFIER_POINTER (DECL_NAME (fielddecl)); ++ char *new_name = concat (old_name, "_pc", NULL); ++ DECL_NAME (field) = get_identifier (new_name); ++ free (new_name); ++ TREE_TYPE (field) = make_unsigned_type (compressed_size); ++ SET_DECL_ALIGN (field, compressed_size); + } + else + { +- TREE_TYPE (field) +- = reconstruct_complex_type (TREE_TYPE (fielddecl), nt); ++ DECL_NAME (field) = DECL_NAME (fielddecl); ++ TREE_TYPE (field) = reconstruct_complex_type (TREE_TYPE (fielddecl), nt); ++ SET_DECL_ALIGN (field, DECL_ALIGN (fielddecl)); + } ++ + DECL_SOURCE_LOCATION (field) = DECL_SOURCE_LOCATION (fielddecl); +- SET_DECL_ALIGN (field, DECL_ALIGN (fielddecl)); + DECL_USER_ALIGN (field) = DECL_USER_ALIGN (fielddecl); + TREE_ADDRESSABLE (field) = TREE_ADDRESSABLE (fielddecl); + DECL_NONADDRESSABLE_P (field) = !TREE_ADDRESSABLE (fielddecl); +@@ -923,6 +989,10 @@ srtype::create_new_type (void) + && has_dead_field ()) + fprintf (dump_file, "Dead field elimination.\n"); + } ++ ++ if (pc_candidate && pc_gptr == NULL_TREE) ++ create_global_ptr_for_pc (); ++ + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Created %d types:\n", maxclusters); +@@ -1341,6 +1411,30 @@ public: + void maybe_mark_or_record_other_side (tree side, tree other, gimple *stmt); + unsigned execute_struct_relayout (void); + bool remove_dead_field_stmt (tree lhs); ++ ++ // Pointer compression methods: ++ void check_and_prune_struct_for_pointer_compression (void); ++ void try_rewrite_with_pointer_compression (gassign *, gimple_stmt_iterator *, ++ tree, tree, tree &, tree &); ++ bool safe_void_cmp_p (tree, srtype *); ++ bool pc_candidate_st_type_p (tree); ++ bool pc_candidate_tree_p (tree); ++ bool pc_type_conversion_candidate_p (tree); ++ bool pc_direct_rewrite_chance_p (tree, tree &); ++ bool compress_candidate_with_check (gimple_stmt_iterator *, tree, tree &); ++ bool compress_candidate (gassign *, gimple_stmt_iterator *, tree, tree &); ++ bool decompress_candidate_with_check (gimple_stmt_iterator *, tree, tree &); ++ bool decompress_candidate (gimple_stmt_iterator *, tree, tree, tree &, ++ tree &); ++ srtype *get_compression_candidate_type (tree); ++ tree compress_ptr_to_offset (tree, srtype *, gimple_stmt_iterator *); ++ tree decompress_offset_to_ptr (tree, srtype *, gimple_stmt_iterator *); ++ basic_block create_bb_for_compress_candidate (basic_block, tree, srtype *, ++ tree &); ++ basic_block create_bb_for_decompress_candidate (basic_block, tree, srtype *, ++ tree &); ++ basic_block create_bb_for_compress_nullptr (basic_block, tree &); ++ basic_block create_bb_for_decompress_nullptr (basic_block, tree, tree &); + }; + + struct ipa_struct_relayout +@@ -1391,29 +1485,6 @@ namespace { + + /* Methods for ipa_struct_relayout. */ + +-static void +-set_var_attributes (tree var) +-{ +- if (!var) +- { +- return; +- } +- gcc_assert (TREE_CODE (var) == VAR_DECL); +- +- DECL_ARTIFICIAL (var) = 1; +- DECL_EXTERNAL (var) = 0; +- TREE_STATIC (var) = 1; +- TREE_PUBLIC (var) = 0; +- TREE_USED (var) = 1; +- DECL_CONTEXT (var) = NULL; +- TREE_THIS_VOLATILE (var) = 0; +- TREE_ADDRESSABLE (var) = 0; +- TREE_READONLY (var) = 0; +- if (is_global_var (var)) +- { +- set_decl_tls_model (var, TLS_MODEL_NONE); +- } +-} + + tree + ipa_struct_relayout::create_new_vars (tree type, const char *name) +@@ -3135,6 +3206,19 @@ ipa_struct_reorg::find_vars (gimple *stmt) + records the right value _1 declaration. */ + find_var (gimple_assign_rhs1 (stmt), stmt); + ++ /* Pointer types from non-zero pointer need to be escaped in pointer ++ compression and complete relayout. ++ e.g _1->t = (struct *) 0x400000. */ ++ if (current_layout_opt_level >= COMPLETE_STRUCT_RELAYOUT ++ && TREE_CODE (lhs) == COMPONENT_REF ++ && TREE_CODE (TREE_TYPE (lhs)) == POINTER_TYPE ++ && TREE_CODE (rhs) == INTEGER_CST ++ && !integer_zerop (rhs)) ++ { ++ mark_type_as_escape (inner_type (TREE_TYPE (lhs)), ++ escape_cast_int, stmt); ++ } ++ + /* Add a safe func mechanism. */ + bool l_find = true; + bool r_find = true; +@@ -3603,14 +3687,15 @@ is_result_of_mult (tree arg, tree *num, tree struct_size) + bool + ipa_struct_reorg::handled_allocation_stmt (gimple *stmt) + { +- if ((current_layout_opt_level >= STRUCT_REORDER_FIELDS) ++ if ((current_layout_opt_level & STRUCT_REORDER_FIELDS) + && (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC) + || gimple_call_builtin_p (stmt, BUILT_IN_MALLOC) + || gimple_call_builtin_p (stmt, BUILT_IN_CALLOC))) + { + return true; + } +- if ((current_layout_opt_level == COMPLETE_STRUCT_RELAYOUT) ++ if ((current_layout_opt_level == COMPLETE_STRUCT_RELAYOUT ++ || current_layout_opt_level & POINTER_COMPRESSION_SAFE) + && gimple_call_builtin_p (stmt, BUILT_IN_CALLOC)) + return true; + if ((current_layout_opt_level == STRUCT_SPLIT) +@@ -3737,15 +3822,20 @@ ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other, gimple + } + } + /* x_1 = y.x_nodes; void *x; +- Directly mark the structure pointer type assigned +- to the void* variable as escape. */ ++ Mark the structure pointer type assigned ++ to the void* variable as escape. Unless the void* is only used to compare ++ with variables of the same type. */ + else if (current_layout_opt_level >= STRUCT_REORDER_FIELDS + && TREE_CODE (side) == SSA_NAME + && VOID_POINTER_P (TREE_TYPE (side)) + && SSA_NAME_VAR (side) + && VOID_POINTER_P (TREE_TYPE (SSA_NAME_VAR (side)))) + { +- mark_type_as_escape (TREE_TYPE (other), escape_cast_void, stmt); ++ if (current_layout_opt_level < POINTER_COMPRESSION_SAFE ++ || !safe_void_cmp_p (side, type)) ++ { ++ mark_type_as_escape (TREE_TYPE (other), escape_cast_void, stmt); ++ } + } + + check_ptr_layers (side, other, stmt); +@@ -4361,7 +4451,7 @@ ipa_struct_reorg::check_type_and_push (tree newdecl, srdecl *decl, + void + ipa_struct_reorg::check_alloc_num (gimple *stmt, srtype *type) + { +- if (current_layout_opt_level == COMPLETE_STRUCT_RELAYOUT ++ if (current_layout_opt_level >= COMPLETE_STRUCT_RELAYOUT + && handled_allocation_stmt (stmt)) + { + tree arg0 = gimple_call_arg (stmt, 0); +@@ -4388,6 +4478,22 @@ ipa_struct_reorg::check_alloc_num (gimple *stmt, srtype *type) + ? type->has_alloc_array + : type->has_alloc_array + 1; + } ++ if (current_layout_opt_level & POINTER_COMPRESSION_SAFE ++ && TREE_CODE (arg0) == INTEGER_CST) ++ { ++ /* Only known size during compilation can be optimized ++ at this level. */ ++ unsigned HOST_WIDE_INT max_alloc_size = 0; ++ switch (compressed_size) ++ { ++ case 8: max_alloc_size = 0xff; break; // max of uint8 ++ case 16: max_alloc_size = 0xffff; break; // max of uint16 ++ case 32: max_alloc_size = 0xffffffff; break; // max of uint32 ++ default: gcc_unreachable (); break; ++ } ++ if (tree_to_uhwi (arg0) < max_alloc_size) ++ type->has_legal_alloc_num = true; ++ } + } + } + +@@ -4530,7 +4636,11 @@ ipa_struct_reorg::check_definition (srdecl *decl, vec<srdecl*> &worklist) + && SSA_NAME_VAR (ssa_name) + && VOID_POINTER_P (TREE_TYPE (SSA_NAME_VAR (ssa_name)))) + { +- type->mark_escape (escape_cast_void, SSA_NAME_DEF_STMT (ssa_name)); ++ if (current_layout_opt_level < POINTER_COMPRESSION_SAFE ++ || !safe_void_cmp_p (ssa_name, type)) ++ { ++ type->mark_escape (escape_cast_void, SSA_NAME_DEF_STMT (ssa_name)); ++ } + } + gimple *stmt = SSA_NAME_DEF_STMT (ssa_name); + +@@ -5509,6 +5619,8 @@ ipa_struct_reorg::create_new_types (void) + for (unsigned i = 0; i < types.length (); i++) + newtypes += types[i]->create_new_type (); + ++ /* Some new types may not have been created at create_new_type (), so ++ recreate new type for all struct fields. */ + if (current_layout_opt_level >= STRUCT_REORDER_FIELDS) + { + for (unsigned i = 0; i < types.length (); i++) +@@ -5519,9 +5631,18 @@ ipa_struct_reorg::create_new_types (void) + for (unsigned j = 0; j < fields->length (); j++) + { + tree field = (*fields)[j]; +- TREE_TYPE (field) +- = reconstruct_complex_type (TREE_TYPE (field), +- types[i]->newtype[0]); ++ if (types[i]->pc_candidate) ++ { ++ TREE_TYPE (field) ++ = make_unsigned_type (compressed_size); ++ SET_DECL_ALIGN (field, compressed_size); ++ } ++ else ++ { ++ TREE_TYPE (field) ++ = reconstruct_complex_type (TREE_TYPE (field), ++ types[i]->newtype[0]); ++ } + } + } + } +@@ -5906,6 +6027,556 @@ ipa_struct_reorg::rewrite_expr (tree expr, tree newexpr[max_split], bool ignore_ + return true; + } + ++/* Emit a series of gimples to compress the pointer to the index relative to ++ the global header. The basic blocks where gsi is located must have at least ++ one stmt. */ ++ ++tree ++ipa_struct_reorg::compress_ptr_to_offset (tree xhs, srtype *type, ++ gimple_stmt_iterator *gsi) ++{ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nCompress candidate pointer:\n"); ++ print_generic_expr (dump_file, xhs); ++ fprintf (dump_file, "\nto offset:\n"); ++ } ++ ++ /* Emit gimple _X1 = ptr - gptr. */ ++ tree pointer_addr = fold_convert (long_unsigned_type_node, xhs); ++ tree gptr_addr = fold_convert (long_unsigned_type_node, type->pc_gptr); ++ tree step1 = gimplify_build2 (gsi, MINUS_EXPR, long_unsigned_type_node, ++ pointer_addr, gptr_addr); ++ ++ /* Emit gimple _X2 = _X1 / sizeof (struct). */ ++ tree step2 = gimplify_build2 (gsi, TRUNC_DIV_EXPR, long_unsigned_type_node, ++ step1, TYPE_SIZE_UNIT (type->newtype[0])); ++ ++ /* Emit gimple _X3 = _X2 + 1. */ ++ tree step3 = gimplify_build2 (gsi, PLUS_EXPR, long_unsigned_type_node, ++ step2, build_one_cst (long_unsigned_type_node)); ++ ++ /* Emit _X4 = (compressed_size) _X3. */ ++ tree step4 = gimplify_build1 (gsi, NOP_EXPR, ++ make_unsigned_type (compressed_size), step3); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ print_generic_expr (dump_file, step3); ++ fprintf (dump_file, "\n"); ++ } ++ return step4; ++} ++ ++/* Emit a series of gimples to decompress the index into the original ++ pointer. The basic blocks where gsi is located must have at least ++ one stmt. */ ++ ++tree ++ipa_struct_reorg::decompress_offset_to_ptr (tree xhs, srtype *type, ++ gimple_stmt_iterator *gsi) ++{ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nDecompress candidate offset:\n"); ++ print_generic_expr (dump_file, xhs); ++ fprintf (dump_file, "\nto pointer:\n"); ++ } ++ ++ /* Emit _X1 = xhs - 1. */ ++ tree offset = fold_convert (long_unsigned_type_node, xhs); ++ tree step1 = gimplify_build2 (gsi, MINUS_EXPR, long_unsigned_type_node, ++ offset, ++ build_one_cst (long_unsigned_type_node)); ++ ++ /* Emit _X2 = _X1 * sizeof (struct). */ ++ tree step2 = gimplify_build2 (gsi, MULT_EXPR, long_unsigned_type_node, ++ step1, TYPE_SIZE_UNIT (type->newtype[0])); ++ ++ /* Emit _X3 = phead + _X2. */ ++ tree gptr_addr = fold_convert (long_unsigned_type_node, type->pc_gptr); ++ tree step3 = gimplify_build2 (gsi, PLUS_EXPR, long_unsigned_type_node, ++ gptr_addr, step2); ++ ++ /* Emit _X4 = (struct *) _X3. */ ++ tree step4 = gimplify_build1 (gsi, NOP_EXPR, TREE_TYPE (type->pc_gptr), ++ step3); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ print_generic_expr (dump_file, step3); ++ fprintf (dump_file, "\n"); ++ } ++ return step4; ++} ++ ++/* Return the compression candidate srtype of SSA_NAME or COMPONENT_REF. */ ++ ++srtype * ++ipa_struct_reorg::get_compression_candidate_type (tree xhs) ++{ ++ if (xhs == NULL_TREE) ++ return NULL; ++ ++ if (TREE_CODE (xhs) == SSA_NAME || TREE_CODE (xhs) == COMPONENT_REF) ++ { ++ srtype *access_type = find_type (inner_type (TREE_TYPE (xhs))); ++ if (access_type != NULL && access_type->pc_candidate) ++ return access_type; ++ } ++ return NULL; ++} ++ ++/* True if the input type is the candidate type for pointer compression. */ ++ ++bool ++ipa_struct_reorg::pc_candidate_st_type_p (tree type) ++{ ++ if (type == NULL_TREE) ++ return false; ++ ++ if (TREE_CODE (type) == POINTER_TYPE) ++ { ++ if (TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE) ++ { ++ srtype *access_type = find_type (TREE_TYPE (type)); ++ if (access_type != NULL && access_type->pc_candidate) ++ return true; ++ } ++ } ++ return false; ++} ++ ++/* True if the input xhs is a candidate for pointer compression. */ ++ ++bool ++ipa_struct_reorg::pc_candidate_tree_p (tree xhs) ++{ ++ if (xhs == NULL_TREE) ++ return false; ++ ++ if (TREE_CODE (xhs) == COMPONENT_REF) ++ { ++ srtype *base_type = find_type (TREE_TYPE (TREE_OPERAND (xhs, 0))); ++ if (base_type == NULL || base_type->has_escaped ()) ++ return false; ++ ++ return pc_candidate_st_type_p (TREE_TYPE (xhs)); ++ } ++ return false; ++} ++ ++/* True if xhs is a component_ref that base has escaped but uses a compression ++ candidate type. */ ++ ++bool ++ipa_struct_reorg::pc_type_conversion_candidate_p (tree xhs) ++{ ++ if (xhs == NULL_TREE) ++ return false; ++ ++ if (TREE_CODE (xhs) == COMPONENT_REF) ++ { ++ srtype *base_type = find_type (TREE_TYPE (TREE_OPERAND (xhs, 0))); ++ if (base_type != NULL && base_type->has_escaped ()) ++ return pc_candidate_st_type_p (TREE_TYPE (xhs)); ++ ++ } ++ return false; ++} ++ ++/* Creates a new basic block with zero for compressed null pointers. */ ++ ++basic_block ++ipa_struct_reorg::create_bb_for_compress_nullptr (basic_block last_bb, ++ tree &phi) ++{ ++ basic_block new_bb = create_empty_bb (last_bb); ++ if (last_bb->loop_father != NULL) ++ { ++ add_bb_to_loop (new_bb, last_bb->loop_father); ++ loops_state_set (LOOPS_NEED_FIXUP); ++ } ++ ++ /* Emit phi = 0. */ ++ gimple_stmt_iterator gsi = gsi_last_bb (new_bb); ++ phi = make_ssa_name (make_unsigned_type (compressed_size)); ++ tree rhs = build_int_cst (make_unsigned_type (compressed_size), 0); ++ gimple *new_stmt = gimple_build_assign (phi, rhs); ++ gsi_insert_after (&gsi, new_stmt, GSI_NEW_STMT); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nCreate bb %d for compress nullptr:\n", ++ new_bb->index); ++ gimple_dump_bb (dump_file, new_bb, 0, dump_flags); ++ } ++ return new_bb; ++} ++ ++/* Create a new basic block to compress the pointer to the index relative to ++ the allocated memory pool header. */ ++ ++basic_block ++ipa_struct_reorg::create_bb_for_compress_candidate (basic_block last_bb, ++ tree new_rhs, srtype *type, ++ tree &phi) ++{ ++ basic_block new_bb = create_empty_bb (last_bb); ++ if (last_bb->loop_father != NULL) ++ { ++ add_bb_to_loop (new_bb, last_bb->loop_father); ++ loops_state_set (LOOPS_NEED_FIXUP); ++ } ++ ++ gimple_stmt_iterator gsi = gsi_last_bb (new_bb); ++ /* compress_ptr_to_offset () needs at least one stmt in target bb. */ ++ gsi_insert_after (&gsi, gimple_build_nop (), GSI_NEW_STMT); ++ phi = compress_ptr_to_offset (new_rhs, type, &gsi); ++ /* Remove the NOP created above. */ ++ gsi_remove (&gsi, true); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nCreate bb %d for compress candidate:\n", ++ new_bb->index); ++ gimple_dump_bb (dump_file, new_bb, 0, dump_flags); ++ } ++ return new_bb; ++} ++ ++/* Compression can be simplified by these following cases: ++ 1. if rhs is NULL, uses zero to represent it. ++ 2. if new_rhs has been converted into INTEGER_TYPE in the previous stmt, ++ just use it here. For example: ++ _1 = t->s ++ -> tt->s = _1. */ ++ ++bool ++ipa_struct_reorg::pc_direct_rewrite_chance_p (tree rhs, tree &new_rhs) ++{ ++ if (integer_zerop (rhs)) ++ { ++ new_rhs = build_int_cst (make_unsigned_type (compressed_size), 0); ++ return true; ++ } ++ else if (new_rhs && TREE_CODE (TREE_TYPE (new_rhs)) == INTEGER_TYPE) ++ { ++ return true; ++ } ++ return false; ++} ++ ++/* Perform pointer compression with check. The conversion will be as shown in ++ the following example: ++ Orig bb: ++ bb <1>: ++ _1->t = _2 ++ ++ will be transformed to: ++ bb <1>: ++ _3 = _2 ++ if (_2 == NULL) ++ goto bb <2> ++ else ++ goto bb <3> ++ ++ bb <2>: ++ _3 = 0 ++ goto bb <4> ++ ++ bb <3>: ++ ... ++ _4 = compress (_2) ++ goto bb <4> ++ ++ bb <4>: ++ _5 = PHI (_3, _4) ++ _1->t = _5 ++ The gsi will move to the beginning of split dst bb <4>, _1->t = _5 will be ++ emitted by rewrite_assign (). */ ++ ++bool ++ipa_struct_reorg::compress_candidate_with_check (gimple_stmt_iterator *gsi, ++ tree rhs, tree &new_rhs) ++{ ++ tree cond_lhs = make_ssa_name (TREE_TYPE (new_rhs)); ++ gimple *assign_stmt = gimple_build_assign (cond_lhs, new_rhs); ++ gsi_insert_before (gsi, assign_stmt, GSI_SAME_STMT); ++ ++ /* Insert cond stmt. */ ++ tree rhs_pointer_type = build_pointer_type (TREE_TYPE (new_rhs)); ++ gcond *cond = gimple_build_cond (EQ_EXPR, cond_lhs, ++ build_int_cst (rhs_pointer_type, 0), ++ NULL_TREE, NULL_TREE); ++ gimple_set_location (cond, UNKNOWN_LOCATION); ++ gsi_insert_before (gsi, cond, GSI_SAME_STMT); ++ ++ gimple* cur_stmt = as_a <gimple *> (cond); ++ edge e = split_block (cur_stmt->bb, cur_stmt); ++ basic_block split_src_bb = e->src; ++ basic_block split_dst_bb = e->dest; ++ ++ /* Create bb for nullptr. */ ++ tree phi1 = NULL_TREE; ++ basic_block true_bb = create_bb_for_compress_nullptr (split_src_bb, phi1); ++ ++ /* Create bb for comprssion. */ ++ srtype *type = get_compression_candidate_type (rhs); ++ gcc_assert (type != NULL); ++ tree phi2 = NULL_TREE; ++ basic_block false_bb = create_bb_for_compress_candidate (true_bb, new_rhs, ++ type, phi2); ++ ++ /* Rebuild and reset cfg. */ ++ remove_edge_raw (e); ++ ++ edge etrue = make_edge (split_src_bb, true_bb, EDGE_TRUE_VALUE); ++ etrue->probability = profile_probability::unlikely (); ++ true_bb->count = etrue->count (); ++ ++ edge efalse = make_edge (split_src_bb, false_bb, EDGE_FALSE_VALUE); ++ efalse->probability = profile_probability::likely (); ++ false_bb->count = efalse->count (); ++ ++ edge e1 = make_single_succ_edge (true_bb, split_dst_bb, EDGE_FALLTHRU); ++ edge e2 = make_single_succ_edge (false_bb, split_dst_bb, EDGE_FALLTHRU); ++ ++ tree phi = make_ssa_name (make_unsigned_type (compressed_size)); ++ gphi *phi_node = create_phi_node (phi, split_dst_bb); ++ add_phi_arg (phi_node, phi1, e1, UNKNOWN_LOCATION); ++ add_phi_arg (phi_node, phi2, e2, UNKNOWN_LOCATION); ++ ++ if (dom_info_available_p (CDI_DOMINATORS)) ++ { ++ set_immediate_dominator (CDI_DOMINATORS, split_dst_bb, split_src_bb); ++ set_immediate_dominator (CDI_DOMINATORS, true_bb, split_src_bb); ++ set_immediate_dominator (CDI_DOMINATORS, false_bb, split_src_bb); ++ } ++ *gsi = gsi_start_bb (split_dst_bb); ++ new_rhs = phi; ++ return true; ++} ++ ++/* If there is a direct rewrite chance or simplification opportunity, perform ++ the simplified compression rewrite. Otherwise, create a cond expression and ++ two basic blocks to implement pointer compression. */ ++ ++bool ++ipa_struct_reorg::compress_candidate (gassign *stmt, gimple_stmt_iterator *gsi, ++ tree rhs, tree &new_rhs) ++{ ++ if (pc_direct_rewrite_chance_p (rhs, new_rhs)) ++ return true; ++ ++ return compress_candidate_with_check (gsi, rhs, new_rhs); ++} ++ ++/* Create a new basic block to decompress the index to null pointer. */ ++ ++basic_block ++ipa_struct_reorg::create_bb_for_decompress_nullptr (basic_block last_bb, ++ tree new_rhs, ++ tree &phi_node) ++{ ++ basic_block new_bb = create_empty_bb (last_bb); ++ if (last_bb->loop_father != NULL) ++ { ++ add_bb_to_loop (new_bb, last_bb->loop_father); ++ loops_state_set (LOOPS_NEED_FIXUP); ++ } ++ gimple_stmt_iterator gsi = gsi_last_bb (new_bb); ++ tree rhs_pointer_type = build_pointer_type (TREE_TYPE (new_rhs)); ++ phi_node = make_ssa_name (rhs_pointer_type); ++ gimple *new_stmt = gimple_build_assign (phi_node, ++ build_int_cst (rhs_pointer_type, 0)); ++ gsi_insert_after (&gsi, new_stmt, GSI_NEW_STMT); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nCreate bb %d for decompress nullptr:\n", ++ new_bb->index); ++ gimple_dump_bb (dump_file, new_bb, 0, dump_flags); ++ } ++ return new_bb; ++} ++ ++/* Create a new basic block to decompress the index into original pointer. */ ++ ++basic_block ++ipa_struct_reorg::create_bb_for_decompress_candidate (basic_block last_bb, ++ tree lhs, srtype *type, ++ tree &phi_node) ++{ ++ basic_block new_bb = create_empty_bb (last_bb); ++ if (last_bb->loop_father != NULL) ++ { ++ add_bb_to_loop (new_bb, last_bb->loop_father); ++ loops_state_set (LOOPS_NEED_FIXUP); ++ } ++ gimple_stmt_iterator gsi = gsi_last_bb (new_bb); ++ /* decompress_ptr_to_offset () needs at least one stmt in target bb. */ ++ gsi_insert_after (&gsi, gimple_build_nop (), GSI_NEW_STMT); ++ phi_node = decompress_offset_to_ptr (lhs, type, &gsi); ++ /* Remove the NOP created above. */ ++ gsi_remove (&gsi, true); ++ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "\nCreate bb %d for decompress candidate:\n", ++ new_bb->index); ++ gimple_dump_bb (dump_file, new_bb, 0, dump_flags); ++ } ++ return new_bb; ++} ++ ++/* Perform pointer decompression with check. The conversion will be as shown ++ in the following example: ++ Orig bb: ++ bb <1>: ++ _1 = _2->t ++ ++ will be transformed to: ++ bb <1>: ++ _3 = _2->t ++ if (_3 == 0) ++ goto bb <2> ++ else ++ goto bb <3> ++ ++ bb <2>: ++ _4 = NULL ++ goto bb <4> ++ ++ bb <3>: ++ ... ++ _5 = decompress (_3) ++ goto bb <4> ++ ++ bb <4>: ++ _6 = PHI (_4, _5) ++ _1 = _6 ++ The gsi will move to the beginning of split dst bb <4>, _1 = _6 will be ++ emitted by rewrite_assign (). */ ++ ++bool ++ipa_struct_reorg::decompress_candidate_with_check (gimple_stmt_iterator *gsi, ++ tree rhs, tree &new_rhs) ++{ ++ /* Insert cond stmt. */ ++ tree cond_lhs = make_ssa_name (TREE_TYPE (new_rhs)); ++ gassign *cond_assign = gimple_build_assign (cond_lhs, new_rhs); ++ gsi_insert_before (gsi, cond_assign, GSI_SAME_STMT); ++ ++ tree pc_type = make_unsigned_type (compressed_size); ++ gcond *cond = gimple_build_cond (EQ_EXPR, cond_lhs, ++ build_int_cst (pc_type, 0), ++ NULL_TREE, NULL_TREE); ++ gimple_set_location (cond, UNKNOWN_LOCATION); ++ gsi_insert_before (gsi, cond, GSI_SAME_STMT); ++ ++ /* Split bb. */ ++ gimple* cur_stmt = as_a <gimple *> (cond); ++ edge e = split_block (cur_stmt->bb, cur_stmt); ++ basic_block split_src_bb = e->src; ++ basic_block split_dst_bb = e->dest; ++ ++ /* Create bb for decompress nullptr. */ ++ tree phi1 = NULL_TREE; ++ basic_block true_bb = create_bb_for_decompress_nullptr (split_src_bb, ++ new_rhs, phi1); ++ ++ /* Create bb for decomprssion candidate. */ ++ tree phi2 = NULL_TREE; ++ srtype *type = get_compression_candidate_type (rhs); ++ gcc_assert (type != NULL); ++ basic_block false_bb = create_bb_for_decompress_candidate (true_bb, cond_lhs, ++ type, phi2); ++ ++ /* Refresh and reset cfg. */ ++ remove_edge_raw (e); ++ ++ edge etrue = make_edge (split_src_bb, true_bb, EDGE_TRUE_VALUE); ++ etrue->probability = profile_probability::unlikely (); ++ true_bb->count = etrue->count (); ++ ++ edge efalse = make_edge (split_src_bb, false_bb, EDGE_FALSE_VALUE); ++ efalse->probability = profile_probability::likely (); ++ false_bb->count = efalse->count (); ++ ++ edge e1 = make_single_succ_edge (true_bb, split_dst_bb, EDGE_FALLTHRU); ++ edge e2 = make_single_succ_edge (false_bb, split_dst_bb, EDGE_FALLTHRU); ++ ++ tree phi = make_ssa_name (build_pointer_type (TREE_TYPE (cond_lhs))); ++ gphi *phi_node = create_phi_node (phi, split_dst_bb); ++ add_phi_arg (phi_node, phi1, e1, UNKNOWN_LOCATION); ++ add_phi_arg (phi_node, phi2, e2, UNKNOWN_LOCATION); ++ ++ if (dom_info_available_p (CDI_DOMINATORS)) ++ { ++ set_immediate_dominator (CDI_DOMINATORS, split_dst_bb, split_src_bb); ++ set_immediate_dominator (CDI_DOMINATORS, true_bb, split_src_bb); ++ set_immediate_dominator (CDI_DOMINATORS, false_bb, split_src_bb); ++ } ++ *gsi = gsi_start_bb (split_dst_bb); ++ new_rhs = phi; ++ return true; ++} ++ ++/* If there is a simplification opportunity, perform the simplified ++ decompression rewrite. Otherwise, create a cond expression and two basic ++ blocks to implement pointer decompression. */ ++ ++bool ++ipa_struct_reorg::decompress_candidate (gimple_stmt_iterator *gsi, ++ tree lhs, tree rhs, tree &new_lhs, ++ tree &new_rhs) ++{ ++ // TODO: simplifiy check and rewrite will be pushed in next PR. ++ return decompress_candidate_with_check (gsi, rhs, new_rhs); ++} ++ ++/* Try to perform pointer compression and decompression. */ ++ ++void ++ipa_struct_reorg::try_rewrite_with_pointer_compression (gassign *stmt, ++ gimple_stmt_iterator ++ *gsi, tree lhs, ++ tree rhs, tree &new_lhs, ++ tree &new_rhs) ++{ ++ bool l = pc_candidate_tree_p (lhs); ++ bool r = pc_candidate_tree_p (rhs); ++ if (!l && !r) ++ { ++ tree tmp_rhs = new_rhs == NULL_TREE ? rhs : new_rhs; ++ if (pc_type_conversion_candidate_p (lhs)) ++ { ++ /* Transfer MEM[(struct *)_1].files = _4; ++ to MEM[(struct *)_1].files = (struct *)_4; */ ++ new_rhs = fold_convert (TREE_TYPE (lhs), tmp_rhs); ++ } ++ else if (pc_type_conversion_candidate_p (rhs)) ++ { ++ /* Transfer _4 = MEM[(struct *)_1].nodes; ++ to _4 = (new_struct *) MEM[(struct *)_1].nodes; */ ++ new_rhs = fold_convert (TREE_TYPE (new_lhs), tmp_rhs); ++ } ++ } ++ else if (l && r) ++ gcc_unreachable (); ++ else if (l) ++ { ++ if (!compress_candidate (stmt, gsi, rhs, new_rhs)) ++ gcc_unreachable (); ++ } ++ else if (r) ++ { ++ if (!decompress_candidate (gsi, lhs, rhs, new_lhs, new_rhs)) ++ gcc_unreachable (); ++ } ++} ++ + bool + ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + { +@@ -6109,6 +6780,9 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + fprintf (dump_file, "replaced with:\n"); + for (unsigned i = 0; i < max_split && (newlhs[i] || newrhs[i]); i++) + { ++ if (current_layout_opt_level >= POINTER_COMPRESSION_SAFE) ++ try_rewrite_with_pointer_compression (stmt, gsi, lhs, rhs, ++ newlhs[i], newrhs[i]); + gimple *newstmt = gimple_build_assign (newlhs[i] ? newlhs[i] : lhs, newrhs[i] ? newrhs[i] : rhs); + if (dump_file && (dump_flags & TDF_DETAILS)) + { +@@ -6183,6 +6857,13 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi) + gcc_assert (false); + gimple_call_set_lhs (g, decl->newdecl[i]); + gsi_insert_before (gsi, g, GSI_SAME_STMT); ++ if (type->pc_candidate) ++ { ++ /* Init global header for pointer compression. */ ++ gassign *gptr ++ = gimple_build_assign (type->pc_gptr, decl->newdecl[i]); ++ gsi_insert_before (gsi, gptr, GSI_SAME_STMT); ++ } + } + return true; + } +@@ -6649,6 +7330,12 @@ ipa_struct_reorg::rewrite_functions (void) + push_cfun (DECL_STRUCT_FUNCTION (node->decl)); + current_function = f; + ++ if (current_layout_opt_level >= POINTER_COMPRESSION_SAFE) ++ { ++ calculate_dominance_info (CDI_DOMINATORS); ++ loop_optimizer_init (0); ++ } ++ + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "\nBefore rewrite: %dth_%s\n", +@@ -6724,6 +7411,9 @@ ipa_struct_reorg::rewrite_functions (void) + + free_dominance_info (CDI_DOMINATORS); + ++ if (current_layout_opt_level >= POINTER_COMPRESSION_SAFE) ++ loop_optimizer_finalize (); ++ + if (dump_file) + { + fprintf (dump_file, "\nAfter rewrite: %dth_%s\n", +@@ -6758,6 +7448,10 @@ ipa_struct_reorg::execute_struct_relayout (void) + { + continue; + } ++ if (get_type_name (types[i]->type) == NULL) ++ { ++ continue; ++ } + retval |= ipa_struct_relayout (type, this).execute (); + } + +@@ -6778,6 +7472,132 @@ ipa_struct_reorg::execute_struct_relayout (void) + return retval; + } + ++ ++/* True if the var with void type is only used to compare with the same ++ target type. */ ++ ++bool ++ipa_struct_reorg::safe_void_cmp_p (tree var, srtype *type) ++{ ++ imm_use_iterator imm_iter; ++ use_operand_p use_p; ++ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, var) ++ { ++ gimple *use_stmt = USE_STMT (use_p); ++ if (is_gimple_debug (use_stmt)) ++ continue; ++ ++ if (gimple_code (use_stmt) == GIMPLE_COND) ++ { ++ tree lhs = gimple_cond_lhs (use_stmt); ++ tree rhs = gimple_cond_rhs (use_stmt); ++ tree xhs = lhs == var ? rhs : lhs; ++ if (types_compatible_p (inner_type (TREE_TYPE (xhs)), type->type)) ++ continue; ++ ++ } ++ return false; ++ } ++ return true; ++} ++ ++/* Mark the structure that should perform pointer compression. */ ++ ++void ++ipa_struct_reorg::check_and_prune_struct_for_pointer_compression (void) ++{ ++ unsigned pc_transform_num = 0; ++ ++ if (dump_file) ++ fprintf (dump_file, "\nMark the structure that should perform pointer" ++ " compression:\n"); ++ ++ for (unsigned i = 0; i < types.length (); i++) ++ { ++ srtype *type = types[i]; ++ if (dump_file) ++ print_generic_expr (dump_file, type->type); ++ ++ if (type->has_escaped ()) ++ { ++ if (dump_file) ++ fprintf (dump_file, " has escaped by %s, skip compression.\n", ++ type->escape_reason ()); ++ continue; ++ } ++ if (TYPE_FIELDS (type->type) == NULL) ++ { ++ if (dump_file) ++ fprintf (dump_file, " has zero field, skip compression.\n"); ++ continue; ++ } ++ if (type->chain_type) ++ { ++ if (dump_file) ++ fprintf (dump_file, " is chain_type, skip compression.\n"); ++ continue; ++ } ++ if (type->has_alloc_array != 1) ++ { ++ if (dump_file) ++ fprintf (dump_file, " has alloc number: %d, skip compression.\n", ++ type->has_alloc_array); ++ continue; ++ } ++ if (get_type_name (type->type) == NULL) ++ { ++ if (dump_file) ++ fprintf (dump_file, " has empty struct name," ++ " skip compression.\n"); ++ continue; ++ } ++ if ((current_layout_opt_level & POINTER_COMPRESSION_SAFE) ++ && !type->has_legal_alloc_num) ++ { ++ if (dump_file) ++ fprintf (dump_file, " has illegal struct array size," ++ " skip compression.\n"); ++ continue; ++ } ++ pc_transform_num++; ++ type->pc_candidate = true; ++ if (dump_file) ++ fprintf (dump_file, " attemps to do pointer compression.\n"); ++ } ++ ++ if (dump_file) ++ { ++ if (pc_transform_num) ++ fprintf (dump_file, "\nNumber of structures to transform in " ++ "pointer compression is %d\n", pc_transform_num); ++ else ++ fprintf (dump_file, "\nNo structures to transform in " ++ "pointer compression.\n"); ++ } ++} ++ ++/* Init pointer size from parameter param_pointer_compression_size. */ ++ ++static void ++init_pointer_size_for_pointer_compression (void) ++{ ++ switch (param_pointer_compression_size) ++ { ++ case 8: ++ compressed_size = 8; // sizeof (uint8) ++ break; ++ case 16: ++ compressed_size = 16; // sizeof (uint16) ++ break; ++ case 32: ++ compressed_size = 32; // sizeof (uint32) ++ break; ++ default: ++ error ("Invalid pointer compression size, using the following param: " ++ "\"--param pointer-compression-size=[8,16,32]\""); ++ } ++} ++ + unsigned int + ipa_struct_reorg::execute (unsigned int opt) + { +@@ -6798,6 +7618,8 @@ ipa_struct_reorg::execute (unsigned int opt) + { + analyze_types (); + } ++ if (opt >= POINTER_COMPRESSION_SAFE) ++ check_and_prune_struct_for_pointer_compression (); + + ret = rewrite_functions (); + } +@@ -6850,6 +7672,8 @@ public: + unsigned int level = 0; + switch (struct_layout_optimize_level) + { ++ case 4: level |= POINTER_COMPRESSION_SAFE; ++ // FALLTHRU + case 3: level |= DEAD_FIELD_ELIMINATION; + // FALLTHRU + case 2: level |= STRUCT_REORDER_FIELDS; +@@ -6862,6 +7686,9 @@ public: + default: gcc_unreachable (); + } + ++ if (level & POINTER_COMPRESSION_SAFE) ++ init_pointer_size_for_pointer_compression (); ++ + /* Preserved for backward compatibility, reorder fields needs run before + struct split and complete struct relayout. */ + if (flag_ipa_reorder_fields && level < STRUCT_REORDER_FIELDS) +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.h b/gcc/ipa-struct-reorg/ipa-struct-reorg.h +index 936c0fa6f..d88799982 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.h ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.h +@@ -122,7 +122,10 @@ private: + public: + + tree newtype[max_split]; ++ tree pc_gptr; + bool visited; ++ bool pc_candidate; ++ bool has_legal_alloc_num; + int has_alloc_array; + + // Constructors +@@ -144,6 +147,7 @@ public: + void analyze (void); + bool has_dead_field (void); + void mark_escape (escape_type, gimple *stmt); ++ void create_global_ptr_for_pc (); + bool has_escaped (void) + { + return escapes != does_not_escape; +diff --git a/gcc/params.opt b/gcc/params.opt +index 9d1faa7ab..1d355819c 100644 +--- a/gcc/params.opt ++++ b/gcc/params.opt +@@ -984,4 +984,8 @@ High execution rate loops to be analyzed in prefetch (in%). + Common Joined UInteger Var(param_prefetch_func_counts_threshold) Init(100) Param Optimization + Threshold functions of cache miss counts to be analyzed in prefetching. + ++-param=compressed-pointer-size= ++Common Joined UInteger Var(param_pointer_compression_size) Init(32) IntegerRange(8, 32) Param Optimization ++Target size of compressed pointer, which should be 8, 16 or 32. ++ + ; This comment is to ensure we retain the blank line above. +-- +2.27.0.windows.1 + diff --git a/0078-Loop-distribution-Add-isomorphic-stmts-analysis.patch b/0078-Loop-distribution-Add-isomorphic-stmts-analysis.patch new file mode 100644 index 0000000..baeff90 --- /dev/null +++ b/0078-Loop-distribution-Add-isomorphic-stmts-analysis.patch @@ -0,0 +1,1007 @@ +From d334ec1579fb0668da5e23ced3b782d7f6f35d77 Mon Sep 17 00:00:00 2001 +From: benniaobufeijiushiji <linda7@huawei.com> +Date: Mon, 17 Oct 2022 17:21:57 +0800 +Subject: [PATCH 30/35] [Loop-distribution] Add isomorphic stmts analysis + +Use option -ftree-slp-transpose-vectorize + +Check if loop is vectorizable before analysis. For unvectorizable +loops, try to find isomorphic stmts from grouped load as new seed stmts +for distribution. +--- + gcc/tree-loop-distribution.c | 858 +++++++++++++++++++++++++++++++++++ + gcc/tree-vect-loop.c | 37 +- + gcc/tree-vectorizer.h | 3 +- + 3 files changed, 894 insertions(+), 4 deletions(-) + +diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c +index 888af4894..c08af6562 100644 +--- a/gcc/tree-loop-distribution.c ++++ b/gcc/tree-loop-distribution.c +@@ -90,6 +90,8 @@ along with GCC; see the file COPYING3. If not see + data reuse. */ + + #include "config.h" ++#define INCLUDE_MAP ++#define INCLUDE_ALGORITHM + #include "system.h" + #include "coretypes.h" + #include "backend.h" +@@ -115,6 +117,7 @@ along with GCC; see the file COPYING3. If not see + #include "tree-vectorizer.h" + #include "tree-eh.h" + #include "gimple-fold.h" ++#include "optabs-tree.h" + + + #define MAX_DATAREFS_NUM \ +@@ -183,6 +186,52 @@ struct rdg_vertex + #define RDG_MEM_WRITE_STMT(RDG, I) RDGV_HAS_MEM_WRITE (&(RDG->vertices[I])) + #define RDG_MEM_READS_STMT(RDG, I) RDGV_HAS_MEM_READS (&(RDG->vertices[I])) + ++/* Results of isomorphic group analysis. */ ++#define UNINITIALIZED (0) ++#define ISOMORPHIC (1) ++#define HETEROGENEOUS (1 << 1) ++#define UNCERTAIN (1 << 2) ++ ++/* Information of a stmt while analyzing isomorphic use in group. */ ++ ++typedef struct _group_info ++{ ++ gimple *stmt; ++ ++ /* True if stmt can be a cut point. */ ++ bool cut_point; ++ ++ /* For use_stmt with two rhses, one of which is the lhs of stmt. ++ If the other is unknown to be isomorphic, mark it uncertain. */ ++ bool uncertain; ++ ++ /* Searching of isomorphic stmt reaches heterogeneous groups or reaches ++ MEM stmts. */ ++ bool done; ++ ++ _group_info () ++ { ++ stmt = NULL; ++ cut_point = false; ++ uncertain = false; ++ done = false; ++ } ++} *group_info; ++ ++/* PAIR of cut points and corresponding profit. */ ++typedef std::pair<vec<gimple *> *, int> stmts_profit; ++ ++/* MAP of vector factor VF and corresponding stmts_profit PAIR. */ ++typedef std::map<unsigned, stmts_profit> vf_stmts_profit_map; ++ ++/* PAIR of group_num and iteration_num. We consider rhses from the same ++ group and interation are isomorphic. */ ++typedef std::pair<unsigned, unsigned> group_iteration; ++ ++/* An isomorphic stmt is detetmined by lhs of use_stmt, group_num and ++ the iteration_num when we insert this stmt to this map. */ ++typedef std::map<tree, group_iteration> isomer_stmt_lhs; ++ + /* Data dependence type. */ + + enum rdg_dep_type +@@ -640,6 +689,18 @@ class loop_distribution + void finalize_partitions (class loop *loop, vec<struct partition *> + *partitions, vec<ddr_p> *alias_ddrs); + ++ /* Analyze loop form and if it's vectorizable to decide if we need to ++ insert temp arrays to distribute it. */ ++ bool may_insert_temp_arrays (loop_p loop, struct graph *&rdg, ++ control_dependences *cd); ++ ++ /* Reset gimple_uid of GIMPLE_DEBUG and GIMPLE_LABEL to -1. */ ++ void reset_gimple_uid (loop_p loop); ++ ++ bool check_loop_vectorizable (loop_p loop); ++ ++ inline void rebuild_rdg (loop_p loop, struct graph *&rdg, ++ control_dependences *cd); + /* Distributes the code from LOOP in such a way that producer statements + are placed before consumer statements. Tries to separate only the + statements from STMTS into separate loops. Returns the number of +@@ -2900,6 +2961,803 @@ loop_distribution::finalize_partitions (class loop *loop, + fuse_memset_builtins (partitions); + } + ++/* Gimple uids of GIMPLE_DEBUG and GIMPLE_LABEL were changed during function ++ vect_analyze_loop, reset them to -1. */ ++ ++void ++loop_distribution::reset_gimple_uid (loop_p loop) ++{ ++ basic_block *bbs = get_loop_body_in_custom_order (loop, this, ++ bb_top_order_cmp_r); ++ for (int i = 0; i < int (loop->num_nodes); i++) ++ { ++ basic_block bb = bbs[i]; ++ for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); ++ gsi_next (&gsi)) ++ { ++ gimple *stmt = gsi_stmt (gsi); ++ if (is_gimple_debug (stmt) || gimple_code (stmt) == GIMPLE_LABEL) ++ gimple_set_uid (stmt, -1); ++ } ++ } ++ free (bbs); ++} ++ ++bool ++loop_distribution::check_loop_vectorizable (loop_p loop) ++{ ++ vec_info_shared shared; ++ vect_analyze_loop (loop, &shared, true); ++ loop_vec_info vinfo = loop_vec_info_for_loop (loop); ++ reset_gimple_uid (loop); ++ if (vinfo == NULL) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, ++ "Loop %d no temp array insertion: bad data access pattern," ++ " unable to generate loop_vinfo.\n", loop->num); ++ return false; ++ } ++ if (vinfo->vectorizable) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "Loop %d no temp array insertion: original loop" ++ " can be vectorized without distribution.\n", ++ loop->num); ++ delete vinfo; ++ loop->aux = NULL; ++ return false; ++ } ++ if (vinfo->grouped_loads.length () == 0) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "Loop %d no temp array insertion: original loop" ++ " has no grouped loads.\n" , loop->num); ++ delete vinfo; ++ loop->aux = NULL; ++ return false; ++ } ++ return true; ++} ++ ++inline void ++loop_distribution::rebuild_rdg (loop_p loop, struct graph *&rdg, ++ control_dependences *cd) ++{ ++ free_rdg (rdg); ++ rdg = build_rdg (loop, cd); ++ gcc_checking_assert (rdg != NULL); ++} ++ ++bool ++loop_distribution::may_insert_temp_arrays (loop_p loop, struct graph *&rdg, ++ control_dependences *cd) ++{ ++ if (!(flag_tree_slp_transpose_vectorize && flag_tree_loop_vectorize)) ++ return false; ++ ++ /* Only loops with two basic blocks HEADER and LATCH are supported. HEADER ++ is the main body of a LOOP and LATCH is the basic block that controls the ++ LOOP execution. Size of temp array is determined by loop execution time, ++ so it must be a const. */ ++ tree loop_extent = number_of_latch_executions (loop); ++ if (loop->inner != NULL || loop->num_nodes > 2 ++ || rdg->n_vertices > param_slp_max_insns_in_bb ++ || TREE_CODE (loop_extent) != INTEGER_CST) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "Loop %d: no temp array insertion: bad loop" ++ " form.\n", loop->num); ++ return false; ++ } ++ ++ if (loop->dont_vectorize) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "Loop %d: no temp array insertion: this loop" ++ " should never be vectorized.\n", ++ loop->num); ++ return false; ++ } ++ ++ /* Do not distribute a LOOP that is able to be vectorized without ++ distribution. */ ++ if (!check_loop_vectorizable (loop)) ++ { ++ rebuild_rdg (loop, rdg, cd); ++ return false; ++ } ++ ++ rebuild_rdg (loop, rdg, cd); ++ return true; ++} ++ ++/* Return max grouped loads' length if all groupes length satisfy len = 2 ^ n. ++ Otherwise, return 0. */ ++ ++static unsigned ++get_max_vf (loop_vec_info vinfo) ++{ ++ unsigned size = 0; ++ unsigned max = 0; ++ stmt_vec_info stmt_info; ++ unsigned i = 0; ++ FOR_EACH_VEC_ELT (vinfo->grouped_loads, i, stmt_info) ++ { ++ size = stmt_info->size; ++ if (!pow2p_hwi (size)) ++ return 0; ++ max = size > max ? size : max; ++ } ++ return max; ++} ++ ++/* Convert grouped_loads from linked list to vector with length vf. Init ++ group_info of each stmt in the same group and put then into a vector. And ++ these vectors consist WORKLISTS. We will re-analyze a group if it is ++ uncertain, so we regard WORKLISTS as a circular queue. */ ++ ++static unsigned ++build_queue (loop_vec_info vinfo, unsigned vf, ++ vec<vec<group_info> *> &worklists) ++{ ++ stmt_vec_info stmt_info; ++ unsigned i = 0; ++ group_info ginfo = NULL; ++ vec<group_info> *worklist = NULL; ++ FOR_EACH_VEC_ELT (vinfo->grouped_loads, i, stmt_info) ++ { ++ unsigned group_size = stmt_info->size; ++ stmt_vec_info c_stmt_info = stmt_info; ++ while (group_size >= vf) ++ { ++ vec_alloc (worklist, vf); ++ for (unsigned j = 0; j < vf; ++j) ++ { ++ ginfo = new _group_info (); ++ ginfo->stmt = c_stmt_info->stmt; ++ worklist->safe_push (ginfo); ++ c_stmt_info = c_stmt_info->next_element; ++ } ++ worklists.safe_push (worklist); ++ group_size -= vf; ++ } ++ } ++ return worklists.length (); ++} ++ ++static bool ++check_same_oprand_type (tree op1, tree op2) ++{ ++ tree type1 = TREE_TYPE (op1); ++ tree type2 = TREE_TYPE (op2); ++ if (TREE_CODE (type1) != INTEGER_TYPE && TREE_CODE (type1) != REAL_TYPE) ++ return false; ++ ++ return (TREE_CODE (type1) == TREE_CODE (type2) ++ && TYPE_UNSIGNED (type1) == TYPE_UNSIGNED (type2) ++ && TYPE_PRECISION (type1) == TYPE_PRECISION (type2)); ++} ++ ++static bool ++bit_field_p (gimple *stmt) ++{ ++ unsigned i = 0; ++ auto_vec<data_reference_p, 2> datarefs_vec; ++ data_reference_p dr; ++ if (!find_data_references_in_stmt (NULL, stmt, &datarefs_vec)) ++ return true; ++ ++ FOR_EACH_VEC_ELT (datarefs_vec, i, dr) ++ { ++ if (TREE_CODE (DR_REF (dr)) == COMPONENT_REF ++ && DECL_BIT_FIELD (TREE_OPERAND (DR_REF (dr), 1))) ++ return true; ++ } ++ return false; ++} ++ ++static inline bool ++shift_operation (enum tree_code op) ++{ ++ return op == LSHIFT_EXPR || op == RSHIFT_EXPR || op == LROTATE_EXPR ++ || op == RROTATE_EXPR; ++} ++ ++/* Return relationship between USE_STMT and the first use_stmt of the group. ++ RHS1 is the lhs of stmt recorded in group_info. If another rhs of use_stmt ++ is not a constant, return UNCERTAIN and re-check it later. */ ++ ++static unsigned ++check_isomorphic (gimple *use_stmt, gimple *first, ++ tree rhs1, vec<tree> &hetero_lhs) ++{ ++ /* Check same operation. */ ++ enum tree_code rhs_code_first = gimple_assign_rhs_code (first); ++ enum tree_code rhs_code_current = gimple_assign_rhs_code (use_stmt); ++ if (rhs_code_first != rhs_code_current) ++ return HETEROGENEOUS; ++ ++ /* For shift operations, oprands should be equal. */ ++ if (shift_operation (rhs_code_current)) ++ { ++ tree shift_op_first = gimple_assign_rhs2 (first); ++ tree shift_op_current = gimple_assign_rhs2 (use_stmt); ++ if (!operand_equal_p (shift_op_first, shift_op_current, 0) ++ || !TREE_CONSTANT (shift_op_first)) ++ return HETEROGENEOUS; ++ ++ return ISOMORPHIC; ++ } ++ /* Type convertion expr or assignment. */ ++ if (gimple_num_ops (first) == 2) ++ return (rhs_code_first == NOP_EXPR || rhs_code_first == CONVERT_EXPR ++ || rhs_code_first == SSA_NAME) ? ISOMORPHIC : HETEROGENEOUS; ++ ++ /* We find USE_STMT from lhs of a stmt, denote it as rhs1 of USE_STMT and ++ the other one as rhs2. Check if define-stmt of current rhs2 is isomorphic ++ with define-stmt of rhs2 in the first USE_STMT at this group. */ ++ tree rhs2_first = gimple_assign_rhs1 (use_stmt) == rhs1 ++ ? gimple_assign_rhs2 (first) : gimple_assign_rhs1 (first); ++ tree rhs2_curr = gimple_assign_rhs1 (use_stmt) == rhs1 ++ ? gimple_assign_rhs2 (use_stmt) : gimple_assign_rhs1 (use_stmt); ++ ++ if (check_same_oprand_type (rhs2_first, rhs2_curr)) ++ { ++ if (TREE_CONSTANT (rhs2_curr)) ++ return ISOMORPHIC; ++ else if (hetero_lhs.contains (rhs2_curr)) ++ return HETEROGENEOUS; ++ ++ /* Provisionally set the stmt as uncertain and analyze the whole group ++ in function CHECK_UNCERTAIN later if all use_stmts are uncertain. */ ++ return UNCERTAIN; ++ } ++ return HETEROGENEOUS; ++} ++ ++static bool ++unsupported_operations (gimple *stmt) ++{ ++ enum tree_code code = gimple_assign_rhs_code (stmt); ++ return code == COND_EXPR; ++} ++ ++/* Check if the single use_stmt of STMT is isomorphic with the first one's ++ use_stmt in current group. */ ++ ++static unsigned ++check_use_stmt (group_info elmt, gimple *&first, ++ vec<gimple *> &tmp_stmts, vec<tree> &hetero_lhs) ++{ ++ if (gimple_code (elmt->stmt) != GIMPLE_ASSIGN) ++ return HETEROGENEOUS; ++ use_operand_p dummy; ++ tree lhs = gimple_assign_lhs (elmt->stmt); ++ gimple *use_stmt = NULL; ++ single_imm_use (lhs, &dummy, &use_stmt); ++ /* STMTs with three rhs are not supported, e.g., GIMPLE_COND. */ ++ if (use_stmt == NULL || gimple_code (use_stmt) != GIMPLE_ASSIGN ++ || unsupported_operations (use_stmt) || bit_field_p (use_stmt)) ++ return HETEROGENEOUS; ++ tmp_stmts.safe_push (use_stmt); ++ if (first == NULL) ++ { ++ first = use_stmt; ++ return UNINITIALIZED; ++ } ++ /* Check if current use_stmt and the first menber's use_stmt in the group ++ are of the same type. */ ++ tree first_lhs = gimple_assign_lhs (first); ++ tree curr_lhs = gimple_assign_lhs (use_stmt); ++ if (!check_same_oprand_type (first_lhs, curr_lhs)) ++ return HETEROGENEOUS; ++ return check_isomorphic (use_stmt, first, lhs, hetero_lhs); ++} ++ ++/* Replace stmt field in group with stmts in TMP_STMTS, and insert their ++ lhs_info to ISOMER_LHS. */ ++ ++static void ++update_isomer_lhs (vec<group_info> *group, unsigned group_num, ++ unsigned iteration, isomer_stmt_lhs &isomer_lhs, ++ vec<gimple *> tmp_stmts, int &profit, ++ vec<unsigned> &merged_groups) ++{ ++ group_info elmt = NULL; ++ /* Do not insert temp array if isomorphic stmts from grouped load have ++ only casting operations. Once isomorphic calculation has 3 oprands, ++ such as plus operation, this group can be regarded as cut point. */ ++ bool operated = (gimple_num_ops (tmp_stmts[0]) == 3); ++ /* Do not insert temp arrays if search of iosomophic stmts reaches ++ MEM stmts. */ ++ bool has_vdef = gimple_vdef (tmp_stmts[0]) != NULL; ++ bool merge = false; ++ for (unsigned i = 0; i < group->length (); i++) ++ { ++ elmt = (*group)[i]; ++ elmt->stmt = has_vdef ? NULL : tmp_stmts[i]; ++ elmt->cut_point = has_vdef ? false : (elmt->cut_point || operated); ++ elmt->uncertain = false; ++ elmt->done = has_vdef; ++ tree lhs = gimple_assign_lhs (tmp_stmts[i]); ++ if (isomer_lhs.find (lhs) != isomer_lhs.end ()) ++ { ++ merge = true; ++ continue; ++ } ++ isomer_lhs[lhs] = std::make_pair (group_num, iteration); ++ } ++ if (merge) ++ { ++ merged_groups.safe_push (group_num); ++ profit = 0; ++ return; ++ } ++ enum vect_cost_for_stmt kind = scalar_stmt; ++ int scalar_cost = builtin_vectorization_cost (kind, NULL_TREE, 0); ++ profit = (tmp_stmts.length () - 1) * scalar_cost; ++} ++ ++/* Try to find rhs2 in ISOMER_LHS, if all rhs2 were found and their group_num ++ and iteration are same, GROUP is isomorphic. */ ++ ++static unsigned ++check_isomorphic_rhs (vec<group_info> *group, vec<gimple *> &tmp_stmts, ++ isomer_stmt_lhs &isomer_lhs) ++{ ++ group_info elmt = NULL; ++ gimple *stmt = NULL; ++ unsigned j = 0; ++ unsigned group_num = -1u; ++ unsigned iteration = -1u; ++ tree rhs1 = NULL; ++ tree rhs2 = NULL; ++ unsigned status = UNINITIALIZED; ++ FOR_EACH_VEC_ELT (*group, j, elmt) ++ { ++ rhs1 = gimple_assign_lhs (elmt->stmt); ++ stmt = tmp_stmts[j]; ++ rhs2 = (rhs1 == gimple_assign_rhs1 (stmt)) ++ ? gimple_assign_rhs2 (stmt) : gimple_assign_rhs1 (stmt); ++ isomer_stmt_lhs::iterator iter = isomer_lhs.find (rhs2); ++ if (iter != isomer_lhs.end ()) ++ { ++ if (group_num == -1u) ++ { ++ group_num = iter->second.first; ++ iteration = iter->second.second; ++ status |= ISOMORPHIC; ++ continue; ++ } ++ if (iter->second.first == group_num ++ && iter->second.second == iteration) ++ { ++ status |= ISOMORPHIC; ++ continue; ++ } ++ return HETEROGENEOUS; ++ } ++ else ++ status |= UNCERTAIN; ++ } ++ return status; ++} ++ ++/* Update group_info for uncertain groups. */ ++ ++static void ++update_uncertain_stmts (vec<group_info> *group, unsigned group_num, ++ unsigned iteration, vec<gimple *> &tmp_stmts) ++{ ++ unsigned j = 0; ++ group_info elmt = NULL; ++ FOR_EACH_VEC_ELT (*group, j, elmt) ++ { ++ elmt->uncertain = true; ++ elmt->done = false; ++ } ++} ++ ++/* Push stmts in TMP_STMTS into HETERO_LHS. */ ++ ++static void ++set_hetero (vec<group_info> *group, vec<tree> &hetero_lhs, ++ vec<gimple *> &tmp_stmts) ++{ ++ group_info elmt = NULL; ++ unsigned i = 0; ++ for (i = 0; i < group->length (); i++) ++ { ++ elmt = (*group)[i]; ++ elmt->uncertain = false; ++ elmt->done = true; ++ } ++ gimple *stmt = NULL; ++ FOR_EACH_VEC_ELT (tmp_stmts, i, stmt) ++ if (stmt != NULL) ++ hetero_lhs.safe_push (gimple_assign_lhs (stmt)); ++} ++ ++/* Given an uncertain group, TMP_STMTS are use_stmts of stmts in GROUP. ++ Rhs1 is the lhs of stmt in GROUP, rhs2 is the other rhs of USE_STMT. ++ ++ Try to find rhs2 in ISOMER_LHS, if all found rhs2 have same group_num ++ and iteration, this uncertain group is isomorphic. ++ ++ If no rhs matched, this GROUP remains uncertain and update group_info. ++ ++ Otherwise, this GROUP is heterogeneous and return true to end analysis ++ for this group. */ ++ ++static bool ++check_uncertain (vec<group_info> *group, unsigned group_num, ++ unsigned iteration, int &profit, ++ vec<gimple *> &tmp_stmts, isomer_stmt_lhs &isomer_lhs, ++ vec<tree> &hetero_lhs, vec<unsigned> &merged_groups) ++{ ++ unsigned status = check_isomorphic_rhs (group, tmp_stmts, isomer_lhs); ++ bool done = false; ++ switch (status) ++ { ++ case UNCERTAIN: ++ update_uncertain_stmts (group, group_num, iteration, tmp_stmts); ++ break; ++ case ISOMORPHIC: ++ update_isomer_lhs (group, group_num, iteration, isomer_lhs, ++ tmp_stmts, profit, merged_groups); ++ break; ++ default: ++ set_hetero (group, hetero_lhs, tmp_stmts); ++ done = true; ++ } ++ return done; ++} ++ ++/* Return false if analysis of this group is not finished, e.g., isomorphic or ++ uncertain. Calculate the profit if vectorized. */ ++ ++static bool ++check_group (vec<group_info> *group, unsigned group_num, unsigned iteration, ++ int &profit, vec<unsigned> &merged_groups, ++ isomer_stmt_lhs &isomer_lhs, vec<tree> &hetero_lhs) ++{ ++ unsigned j = 0; ++ group_info elmt = NULL; ++ gimple *first = NULL; ++ unsigned res = 0; ++ /* Record single use stmts in TMP_STMTS and decide whether replace stmts in ++ ginfo in succeeding processes. */ ++ auto_vec<gimple *> tmp_stmts; ++ FOR_EACH_VEC_ELT (*group, j, elmt) ++ { ++ if (merged_groups.contains (group_num)) ++ return true; ++ res |= check_use_stmt (elmt, first, tmp_stmts, hetero_lhs); ++ } ++ ++ /* Update each group member according to RES. */ ++ switch (res) ++ { ++ case ISOMORPHIC: ++ update_isomer_lhs (group, group_num, iteration, isomer_lhs, ++ tmp_stmts, profit, merged_groups); ++ return false; ++ case UNCERTAIN: ++ return check_uncertain (group, group_num, iteration, profit, ++ tmp_stmts, isomer_lhs, hetero_lhs, ++ merged_groups); ++ default: ++ set_hetero (group, hetero_lhs, tmp_stmts); ++ return true; ++ } ++} ++ ++/* Return true if all analysises are done except uncertain groups. */ ++ ++static bool ++end_of_search (vec<vec<group_info> *> &circular_queue, ++ vec<unsigned> &merged_groups) ++{ ++ unsigned i = 0; ++ vec<group_info> *group = NULL; ++ group_info elmt = NULL; ++ FOR_EACH_VEC_ELT (circular_queue, i, group) ++ { ++ if (merged_groups.contains (i)) ++ continue; ++ elmt = (*group)[0]; ++ /* If there is any isomorphic use_stmts, continue analysis of isomorphic ++ use_stmts. */ ++ if (!elmt->done && !elmt->uncertain) ++ return false; ++ } ++ return true; ++} ++ ++/* Push valid stmts to STMTS as cutpoints. */ ++ ++static bool ++check_any_cutpoints (vec<vec<group_info> *> &circular_queue, ++ vec<gimple *> *&stmts, vec<unsigned> &merged_groups) ++{ ++ unsigned front = 0; ++ vec<group_info> *group = NULL; ++ group_info elmt = NULL; ++ unsigned max = circular_queue.length () * circular_queue[0]->length (); ++ vec_alloc (stmts, max); ++ while (front < circular_queue.length ()) ++ { ++ unsigned i = 0; ++ if (merged_groups.contains (front)) ++ { ++ front++; ++ continue; ++ } ++ group = circular_queue[front++]; ++ FOR_EACH_VEC_ELT (*group, i, elmt) ++ if (elmt->stmt != NULL && elmt->done && elmt->cut_point) ++ stmts->safe_push (elmt->stmt); ++ } ++ return stmts->length () != 0; ++} ++ ++/* Grouped loads are isomorphic. Make pair for group number and iteration, ++ map load stmt to this pair. We set iteration 0 here. */ ++ ++static void ++init_isomer_lhs (vec<vec<group_info> *> &groups, isomer_stmt_lhs &isomer_lhs) ++{ ++ vec<group_info> *group = NULL; ++ group_info elmt = NULL; ++ unsigned i = 0; ++ FOR_EACH_VEC_ELT (groups, i, group) ++ { ++ unsigned j = 0; ++ FOR_EACH_VEC_ELT (*group, j, elmt) ++ isomer_lhs[gimple_assign_lhs (elmt->stmt)] = std::make_pair (i, 0); ++ } ++} ++ ++/* It's not a strict analysis of load/store profit. Assume scalar and vector ++ load/store are of the same cost. The result PROFIT equals profit form ++ vectorizing of scalar loads/stores minus cost of a vectorized load/store. */ ++ ++static int ++load_store_profit (unsigned scalar_mem_ops, unsigned vf, unsigned new_mem_ops) ++{ ++ int profit = 0; ++ enum vect_cost_for_stmt kind = scalar_load; ++ int scalar_cost = builtin_vectorization_cost (kind, NULL_TREE, 0); ++ profit += (scalar_mem_ops - (scalar_mem_ops / vf)) * scalar_cost; ++ profit -= new_mem_ops / vf * scalar_cost; ++ kind = scalar_store; ++ scalar_cost = builtin_vectorization_cost (kind, NULL_TREE, 0); ++ profit -= new_mem_ops / vf * scalar_cost; ++ return profit; ++} ++ ++/* Breadth first search the graph consisting of define-use chain starting from ++ the circular queue initialized by function BUILD_QUEUE. Find single use of ++ each stmt in group and check if they are isomorphic. Isomorphic is defined ++ as same rhs type, same operator, and isomorphic calculation of each rhs ++ starting from load. If another rhs is uncertain to be isomorphic, put it ++ at the end of circular queue and re-analyze it during the next iteration. ++ If a group shares the same use_stmt with another group, skip one of them in ++ succeedor prcoesses as merged. Iterate the circular queue until all ++ remianing groups heterogeneous or reaches MEN stmts. If all other groups ++ have finishes the analysis, and the remaining groups are uncertain, ++ return false to avoid endless loop. */ ++ ++bool ++bfs_find_isomer_stmts (vec<vec<group_info> *> &circular_queue, ++ stmts_profit &profit_pair, unsigned vf, ++ bool &reach_vdef) ++{ ++ isomer_stmt_lhs isomer_lhs; ++ auto_vec<tree> hetero_lhs; ++ auto_vec<unsigned> merged_groups; ++ vec<group_info> *group = NULL; ++ /* True if analysis finishes. */ ++ bool done = false; ++ int profit_sum = 0; ++ vec<gimple *> *stmts = NULL; ++ init_isomer_lhs (circular_queue, isomer_lhs); ++ for (unsigned i = 1; !done; ++i) ++ { ++ unsigned front = 0; ++ /* Re-initialize DONE to TRUE while a new iteration begins. */ ++ done = true; ++ while (front < circular_queue.length ()) ++ { ++ int profit = 0; ++ group = circular_queue[front]; ++ done &= check_group (group, front, i, profit, merged_groups, ++ isomer_lhs, hetero_lhs); ++ profit_sum += profit; ++ if (profit != 0 && (*group)[0]->stmt == NULL) ++ { ++ reach_vdef = true; ++ return false; ++ } ++ ++front; ++ } ++ /* Uncertain result, return. */ ++ if (!done && end_of_search (circular_queue, merged_groups)) ++ return false; ++ } ++ if (check_any_cutpoints (circular_queue, stmts, merged_groups)) ++ { ++ profit_pair.first = stmts; ++ unsigned loads = circular_queue.length () * circular_queue[0]->length (); ++ profit_pair.second = profit_sum + load_store_profit (loads, vf, ++ stmts->length ()); ++ if (profit_pair.second > 0) ++ return true; ++ } ++ return false; ++} ++ ++/* Free memory allocated by ginfo. */ ++ ++static void ++free_ginfos (vec<vec<group_info> *> &worklists) ++{ ++ vec<group_info> *worklist; ++ unsigned i = 0; ++ while (i < worklists.length ()) ++ { ++ worklist = worklists[i++]; ++ group_info ginfo; ++ unsigned j = 0; ++ FOR_EACH_VEC_ELT (*worklist, j, ginfo) ++ delete ginfo; ++ } ++} ++ ++static void ++release_tmp_stmts (vf_stmts_profit_map &candi_stmts) ++{ ++ vf_stmts_profit_map::iterator iter; ++ for (iter = candi_stmts.begin (); iter != candi_stmts.end (); ++iter) ++ iter->second.first->release (); ++} ++ ++/* Choose the group of stmt with maximun profit. */ ++ ++static bool ++decide_stmts_by_profit (vf_stmts_profit_map &candi_stmts, vec<gimple *> &stmts) ++{ ++ vf_stmts_profit_map::iterator iter; ++ int profit = 0; ++ int max = 0; ++ vec<gimple *> *tmp = NULL; ++ for (iter = candi_stmts.begin (); iter != candi_stmts.end (); ++iter) ++ { ++ profit = iter->second.second; ++ if (profit > max) ++ { ++ tmp = iter->second.first; ++ max = profit; ++ } ++ } ++ if (max == 0) ++ { ++ release_tmp_stmts (candi_stmts); ++ return false; ++ } ++ unsigned i = 0; ++ gimple *stmt = NULL; ++ FOR_EACH_VEC_ELT (*tmp, i, stmt) ++ stmts.safe_push (stmt); ++ release_tmp_stmts (candi_stmts); ++ return stmts.length () != 0; ++} ++ ++/* Find isomorphic stmts from grouped loads with vector factor VF. ++ ++ Given source code as follows and ignore casting. ++ ++ a0 = (a[0] + b[0]) + ((a[4] - b[4]) << 16); ++ a1 = (a[1] + b[1]) + ((a[5] - b[5]) << 16); ++ a2 = (a[2] + b[2]) + ((a[6] - b[6]) << 16); ++ a3 = (a[3] + b[3]) + ((a[7] - b[7]) << 16); ++ ++ We get grouped loads in VINFO as ++ ++ GROUP_1 GROUP_2 ++ _1 = *a _11 = *b ++ _2 = *(a + 1) _12 = *(b + 1) ++ _3 = *(a + 2) _13 = *(b + 2) ++ _4 = *(a + 3) _14 = *(b + 3) ++ _5 = *(a + 4) _15 = *(b + 4) ++ _6 = *(a + 5) _16 = *(b + 5) ++ _7 = *(a + 6) _17 = *(b + 6) ++ _8 = *(a + 7) _18 = *(b + 7) ++ ++ First we try VF = 8, we get two worklists ++ ++ WORKLIST_1 WORKLIST_2 ++ _1 = *a _11 = *b ++ _2 = *(a + 1) _12 = *(b + 1) ++ _3 = *(a + 2) _13 = *(b + 2) ++ _4 = *(a + 3) _14 = *(b + 3) ++ _5 = *(a + 4) _15 = *(b + 4) ++ _6 = *(a + 5) _16 = *(b + 5) ++ _7 = *(a + 6) _17 = *(b + 6) ++ _8 = *(a + 7) _18 = *(b + 7) ++ ++ We find _111 = _1 + _11 and _115 = _5 - _15 are not isomorphic, ++ so we try VF = VF / 2. ++ ++ GROUP_1 GROUP_2 ++ _1 = *a _5 = *(a + 4) ++ _2 = *(a + 1) _6 = *(a + 5) ++ _3 = *(a + 2) _7 = *(a + 6) ++ _4 = *(a + 3) _8 = *(a + 7) ++ ++ GROUP_3 GROUP_4 ++ _11 = *b _15 = *(b + 4) ++ _12 = *(b + 1) _16 = *(b + 5) ++ _13 = *(b + 2) _17 = *(b + 6) ++ _14 = *(b + 3) _18 = *(b + 7) ++ ++ We first analyze group_1, and find all operations are isomorphic, then ++ replace stmts in group_1 with their use_stmts. Group_2 as well. ++ ++ GROUP_1 GROUP_2 ++ _111 = _1 + _11 _115 = _5 - _15 ++ _112 = _2 + _12 _116 = _6 - _16 ++ _113 = _3 + _13 _117 = _7 - _17 ++ _114 = _4 + _14 _118 = _8 - _18 ++ ++ When analyzing group_3 and group_4, we find their use_stmts are the same ++ as group_1 and group_2. So group_3 is regarded as being merged to group_1 ++ and group_4 being merged to group_2. In future procedures, we will skip ++ group_3 and group_4. ++ ++ We repeat such processing until opreations are not isomorphic or searching ++ reaches MEM stmts. In our given case, searching end up at a0, a1, a2 and ++ a3. */ ++ ++static bool ++find_isomorphic_stmts (loop_vec_info vinfo, vec<gimple *> &stmts) ++{ ++ unsigned vf = get_max_vf (vinfo); ++ if (vf == 0) ++ return false; ++ auto_vec<vec<group_info> *> circular_queue; ++ /* Map of vector factor and corresponding vectorizing profit. */ ++ stmts_profit profit_map; ++ /* Map of cut_points and vector factor. */ ++ vf_stmts_profit_map candi_stmts; ++ bool reach_vdef = false; ++ while (vf > 2) ++ { ++ if (build_queue (vinfo, vf, circular_queue) == 0) ++ return false; ++ if (!bfs_find_isomer_stmts (circular_queue, profit_map, vf, reach_vdef)) ++ { ++ if (reach_vdef) ++ { ++ release_tmp_stmts (candi_stmts); ++ free_ginfos (circular_queue); ++ circular_queue.release (); ++ return false; ++ } ++ vf /= 2; ++ free_ginfos (circular_queue); ++ circular_queue.release (); ++ continue; ++ } ++ candi_stmts[vf] = profit_map; ++ free_ginfos (circular_queue); ++ vf /= 2; ++ circular_queue.release (); ++ } ++ return decide_stmts_by_profit (candi_stmts, stmts); ++} ++ + /* Distributes the code from LOOP in such a way that producer statements + are placed before consumer statements. Tries to separate only the + statements from STMTS into separate loops. Returns the number of +diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c +index 7990e31de..1e332d3c5 100644 +--- a/gcc/tree-vect-loop.c ++++ b/gcc/tree-vect-loop.c +@@ -2516,9 +2516,11 @@ vect_reanalyze_as_main_loop (loop_vec_info loop_vinfo, unsigned int *n_stmts) + + Apply a set of analyses on LOOP, and create a loop_vec_info struct + for it. The different analyses will record information in the +- loop_vec_info struct. */ ++ loop_vec_info struct. When RESULT_ONLY_P is true, quit analysis ++ if loop is vectorizable, otherwise, do not delete vinfo.*/ + opt_loop_vec_info +-vect_analyze_loop (class loop *loop, vec_info_shared *shared) ++vect_analyze_loop (class loop *loop, vec_info_shared *shared, ++ bool result_only_p) + { + auto_vector_modes vector_modes; + +@@ -2545,6 +2547,8 @@ vect_analyze_loop (class loop *loop, vec_info_shared *shared) + unsigned n_stmts = 0; + machine_mode autodetected_vector_mode = VOIDmode; + opt_loop_vec_info first_loop_vinfo = opt_loop_vec_info::success (NULL); ++ /* Loop_vinfo for loop-distribution pass. */ ++ opt_loop_vec_info fail_loop_vinfo = opt_loop_vec_info::success (NULL); + machine_mode next_vector_mode = VOIDmode; + poly_uint64 lowest_th = 0; + unsigned vectorized_loops = 0; +@@ -2633,6 +2637,13 @@ vect_analyze_loop (class loop *loop, vec_info_shared *shared) + if (res) + { + LOOP_VINFO_VECTORIZABLE_P (loop_vinfo) = 1; ++ /* In loop-distribution pass, we only need to get loop_vinfo, do not ++ conduct further operations. */ ++ if (result_only_p) ++ { ++ loop->aux = (loop_vec_info) loop_vinfo; ++ return loop_vinfo; ++ } + vectorized_loops++; + + /* Once we hit the desired simdlen for the first time, +@@ -2724,7 +2735,19 @@ vect_analyze_loop (class loop *loop, vec_info_shared *shared) + } + else + { +- delete loop_vinfo; ++ /* If current analysis shows LOOP is unable to vectorize, loop_vinfo ++ will be deleted. If LOOP is under ldist analysis, backup it before ++ it is deleted and return it if all modes are analyzed and still ++ fail to vectorize. */ ++ if (result_only_p && (mode_i == vector_modes.length () ++ || autodetected_vector_mode == VOIDmode)) ++ { ++ fail_loop_vinfo = loop_vinfo; ++ } ++ else ++ { ++ delete loop_vinfo; ++ } + if (fatal) + { + gcc_checking_assert (first_loop_vinfo == NULL); +@@ -2773,6 +2796,14 @@ vect_analyze_loop (class loop *loop, vec_info_shared *shared) + return first_loop_vinfo; + } + ++ /* Return loop_vinfo for ldist if loop is unvectorizable. */ ++ if (result_only_p && (mode_i == vector_modes.length () ++ || autodetected_vector_mode == VOIDmode)) ++ { ++ loop->aux = (loop_vec_info) fail_loop_vinfo; ++ return fail_loop_vinfo; ++ } ++ + return opt_loop_vec_info::propagate_failure (res); + } + +diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h +index 1c4a6c421..dc8175f00 100644 +--- a/gcc/tree-vectorizer.h ++++ b/gcc/tree-vectorizer.h +@@ -1896,7 +1896,8 @@ extern bool check_reduction_path (dump_user_location_t, loop_p, gphi *, tree, + enum tree_code); + extern bool needs_fold_left_reduction_p (tree, tree_code); + /* Drive for loop analysis stage. */ +-extern opt_loop_vec_info vect_analyze_loop (class loop *, vec_info_shared *); ++extern opt_loop_vec_info vect_analyze_loop (class loop *, vec_info_shared *, ++ bool result_only_p = false); + extern tree vect_build_loop_niters (loop_vec_info, bool * = NULL); + extern void vect_gen_vector_loop_niters (loop_vec_info, tree, tree *, + tree *, bool); +-- +2.27.0.windows.1 + diff --git a/0079-loop-vect-Transfer-arrays-using-registers-between-lo.patch b/0079-loop-vect-Transfer-arrays-using-registers-between-lo.patch new file mode 100644 index 0000000..c004eac --- /dev/null +++ b/0079-loop-vect-Transfer-arrays-using-registers-between-lo.patch @@ -0,0 +1,267 @@ +From 013544d0b477647c8835a8806c75e7b09155b8ed Mon Sep 17 00:00:00 2001 +From: benniaobufeijiushiji <linda7@huawei.com> +Date: Mon, 8 Aug 2022 09:13:53 +0800 +Subject: [PATCH 31/35] [loop-vect] Transfer arrays using registers between + loops For vectorized stores in loop, if all succeed loops immediately use the + data, transfer data using registers instead of load store to prevent overhead + from memory access. + +--- + gcc/testsuite/gcc.dg/vect/vect-perm-1.c | 45 ++++++ + gcc/tree-vect-stmts.c | 181 ++++++++++++++++++++++++ + 2 files changed, 226 insertions(+) + create mode 100644 gcc/testsuite/gcc.dg/vect/vect-perm-1.c + +diff --git a/gcc/testsuite/gcc.dg/vect/vect-perm-1.c b/gcc/testsuite/gcc.dg/vect/vect-perm-1.c +new file mode 100644 +index 000000000..d8b29fbd5 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/vect/vect-perm-1.c +@@ -0,0 +1,45 @@ ++/* { dg-do compile { target { aarch64*-*-linux* } } } */
++/* { dg-options "-O3 -fdump-tree-vect-all-details -save-temps" } */
++
++#include <stdio.h>
++#include <stdlib.h>
++
++static unsigned inline abs2 (unsigned a)
++{
++ unsigned s = ((a>>15)&0x10001)*0xffff;
++ return (a+s)^s;
++}
++
++int foo (unsigned *a00, unsigned *a11, unsigned *a22, unsigned *a33)
++{
++ unsigned tmp[4][4];
++ unsigned a0, a1, a2, a3;
++ int sum = 0;
++ for (int i = 0; i < 4; i++)
++ {
++ int t0 = a00[i] + a11[i];
++ int t1 = a00[i] - a11[i];
++ int t2 = a22[i] + a33[i];
++ int t3 = a22[i] - a33[i];
++ tmp[i][0] = t0 + t2;
++ tmp[i][2] = t0 - t2;
++ tmp[i][1] = t1 + t3;
++ tmp[i][3] = t1 - t3;
++ }
++ for (int i = 0; i < 4; i++)
++ {
++ int t0 = tmp[0][i] + tmp[1][i];
++ int t1 = tmp[0][i] - tmp[1][i];
++ int t2 = tmp[2][i] + tmp[3][i];
++ int t3 = tmp[2][i] - tmp[3][i];
++ a0 = t0 + t2;
++ a2 = t0 - t2;
++ a1 = t1 + t3;
++ a3 = t1 - t3;
++ sum += abs2 (a0) + abs2 (a1) + abs2 (a2) + abs2 (a3);
++ }
++ return (((unsigned short) sum) + ((unsigned) sum >>16)) >> 1;
++}
++
++/* { dg-final { scan-tree-dump-times "vectorized 2 loops" 1 "vect" } } */
++/* { dg-final { scan-tree-dump-times "VEC_PERM_EXPR" 16 "vect" } } */
+diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c +index 2c2197022..98b233718 100644 +--- a/gcc/tree-vect-stmts.c ++++ b/gcc/tree-vect-stmts.c +@@ -2276,6 +2276,173 @@ vector_vector_composition_type (tree vtype, poly_uint64 nelts, tree *ptype) + return NULL_TREE; + } + ++/* Check succeedor BB, BB without load is regarded as empty BB. Ignore empty ++ BB in DFS. */ ++ ++static unsigned ++mem_refs_in_bb (basic_block bb, vec<gimple *> &stmts) ++{ ++ unsigned num = 0; ++ for (gimple_stmt_iterator gsi = gsi_start_bb (bb); ++ !gsi_end_p (gsi); gsi_next (&gsi)) ++ { ++ gimple *stmt = gsi_stmt (gsi); ++ if (is_gimple_debug (stmt)) ++ continue; ++ if (is_gimple_assign (stmt) && gimple_has_mem_ops (stmt) ++ && !gimple_has_volatile_ops (stmt)) ++ { ++ if (gimple_assign_rhs_code (stmt) == MEM_REF ++ || gimple_assign_rhs_code (stmt) == ARRAY_REF) ++ { ++ stmts.safe_push (stmt); ++ num++; ++ } ++ else if (TREE_CODE (gimple_get_lhs (stmt)) == MEM_REF ++ || TREE_CODE (gimple_get_lhs (stmt)) == ARRAY_REF) ++ num++; ++ } ++ } ++ return num; ++} ++ ++static bool ++check_same_base (vec<data_reference_p> *datarefs, data_reference_p dr) ++{ ++ for (unsigned ui = 0; ui < datarefs->length (); ui++) ++ { ++ tree op1 = TREE_OPERAND (DR_BASE_OBJECT (dr), 0); ++ tree op2 = TREE_OPERAND (DR_BASE_OBJECT ((*datarefs)[ui]), 0); ++ if (TREE_CODE (op1) != TREE_CODE (op2)) ++ continue; ++ if (TREE_CODE (op1) == ADDR_EXPR) ++ { ++ op1 = TREE_OPERAND (op1, 0); ++ op2 = TREE_OPERAND (op2, 0); ++ } ++ enum tree_code code = TREE_CODE (op1); ++ switch (code) ++ { ++ case VAR_DECL: ++ if (DECL_NAME (op1) == DECL_NAME (op2) ++ && DR_IS_READ ((*datarefs)[ui])) ++ return true; ++ break; ++ case SSA_NAME: ++ if (SSA_NAME_VERSION (op1) == SSA_NAME_VERSION (op2) ++ && DR_IS_READ ((*datarefs)[ui])) ++ return true; ++ break; ++ default: ++ break; ++ } ++ } ++ return false; ++} ++ ++/* Iterate all load STMTS, if staisfying same base vectorized stmt, then return, ++ Otherwise, set false to SUCCESS. */ ++ ++static void ++check_vec_use (loop_vec_info loop_vinfo, vec<gimple *> &stmts, ++ stmt_vec_info stmt_info, bool &success) ++{ ++ if (stmt_info == NULL) ++ { ++ success = false; ++ return; ++ } ++ if (DR_IS_READ (stmt_info->dr_aux.dr)) ++ { ++ success = false; ++ return; ++ } ++ unsigned ui = 0; ++ gimple *candidate = NULL; ++ FOR_EACH_VEC_ELT (stmts, ui, candidate) ++ { ++ if (TREE_CODE (TREE_TYPE (gimple_get_lhs (candidate))) != VECTOR_TYPE) ++ continue; ++ ++ if (candidate->bb != candidate->bb->loop_father->header) ++ { ++ success = false; ++ return; ++ } ++ auto_vec<data_reference_p> datarefs; ++ tree res = find_data_references_in_bb (candidate->bb->loop_father, ++ candidate->bb, &datarefs); ++ if (res == chrec_dont_know) ++ { ++ success = false; ++ return; ++ } ++ if (check_same_base (&datarefs, stmt_info->dr_aux.dr)) ++ return; ++ } ++ success = false; ++} ++ ++/* Deep first search from present BB. If succeedor has load STMTS, ++ stop further searching. */ ++ ++static void ++dfs_check_bb (loop_vec_info loop_vinfo, basic_block bb, stmt_vec_info stmt_info, ++ bool &success, vec<basic_block> &visited_bbs) ++{ ++ if (bb == cfun->cfg->x_exit_block_ptr) ++ { ++ success = false; ++ return; ++ } ++ if (!success || visited_bbs.contains (bb) || bb == loop_vinfo->loop->latch) ++ return; ++ ++ visited_bbs.safe_push (bb); ++ auto_vec<gimple *> stmts; ++ unsigned num = mem_refs_in_bb (bb, stmts); ++ /* Empty BB. */ ++ if (num == 0) ++ { ++ edge e; ++ edge_iterator ei; ++ FOR_EACH_EDGE (e, ei, bb->succs) ++ { ++ dfs_check_bb (loop_vinfo, e->dest, stmt_info, success, visited_bbs); ++ if (!success) ++ return; ++ } ++ return; ++ } ++ /* Non-empty BB. */ ++ check_vec_use (loop_vinfo, stmts, stmt_info, success); ++} ++ ++/* For grouped store, if all succeedors of present BB have vectorized load ++ from same base of store. If so, set memory_access_type using ++ VMAT_CONTIGUOUS_PERMUTE instead of VMAT_LOAD_STORE_LANES. */ ++ ++static bool ++conti_perm (stmt_vec_info stmt_vinfo, loop_vec_info loop_vinfo) ++{ ++ gimple *stmt = stmt_vinfo->stmt; ++ if (gimple_code (stmt) != GIMPLE_ASSIGN) ++ return false; ++ ++ if (DR_IS_READ (stmt_vinfo->dr_aux.dr)) ++ return false; ++ ++ basic_block bb = stmt->bb; ++ bool success = true; ++ auto_vec<basic_block> visited_bbs; ++ visited_bbs.safe_push (bb); ++ edge e; ++ edge_iterator ei; ++ FOR_EACH_EDGE (e, ei, bb->succs) ++ dfs_check_bb (loop_vinfo, e->dest, stmt_vinfo, success, visited_bbs); ++ return success; ++} ++ + /* A subroutine of get_load_store_type, with a subset of the same + arguments. Handle the case where STMT_INFO is part of a grouped load + or store. +@@ -2434,6 +2601,20 @@ get_group_load_store_type (stmt_vec_info stmt_info, tree vectype, bool slp, + *memory_access_type = VMAT_CONTIGUOUS_PERMUTE; + overrun_p = would_overrun_p; + } ++ ++ if (*memory_access_type == VMAT_LOAD_STORE_LANES ++ && TREE_CODE (loop_vinfo->num_iters) == INTEGER_CST ++ && maybe_eq (tree_to_shwi (loop_vinfo->num_iters), ++ loop_vinfo->vectorization_factor) ++ && conti_perm (stmt_info, loop_vinfo) ++ && (vls_type == VLS_LOAD ++ ? vect_grouped_load_supported (vectype, single_element_p, ++ group_size) ++ : vect_grouped_store_supported (vectype, group_size))) ++ { ++ *memory_access_type = VMAT_CONTIGUOUS_PERMUTE; ++ overrun_p = would_overrun_p; ++ } + } + + /* As a last resort, trying using a gather load or scatter store. +-- +2.27.0.windows.1 + diff --git a/0080-Struct-Reorg-Add-Unsafe-Structure-Pointer-Compressio.patch b/0080-Struct-Reorg-Add-Unsafe-Structure-Pointer-Compressio.patch new file mode 100644 index 0000000..ee51cb3 --- /dev/null +++ b/0080-Struct-Reorg-Add-Unsafe-Structure-Pointer-Compressio.patch @@ -0,0 +1,1061 @@ +From 7dc6940ba0f463137ff6cf98032d1e98edecde54 Mon Sep 17 00:00:00 2001 +From: liyancheng <412998149@qq.com> +Date: Fri, 25 Nov 2022 19:36:59 +0800 +Subject: [PATCH 32/35] [Struct Reorg] Add Unsafe Structure Pointer Compression + +Unsafe structure pointer compression allows some danger conversions to +achieve faster performance. +Add flag -fipa-struct-reorg=5 to enable unsafe structure pointer compression. +--- + gcc/common.opt | 6 +- + gcc/ipa-struct-reorg/ipa-struct-reorg.c | 309 +++++++++++++++--- + .../gcc.dg/struct/csr_skip_void_struct_name.c | 53 +++ + gcc/testsuite/gcc.dg/struct/pc_cast_int.c | 91 ++++++ + .../gcc.dg/struct/pc_compress_and_decomress.c | 90 +++++ + gcc/testsuite/gcc.dg/struct/pc_ptr2void.c | 87 +++++ + .../gcc.dg/struct/pc_simple_rewrite_pc.c | 112 +++++++ + .../gcc.dg/struct/pc_skip_void_struct_name.c | 53 +++ + gcc/testsuite/gcc.dg/struct/struct-reorg.exp | 8 + + 9 files changed, 757 insertions(+), 52 deletions(-) + create mode 100644 gcc/testsuite/gcc.dg/struct/csr_skip_void_struct_name.c + create mode 100644 gcc/testsuite/gcc.dg/struct/pc_cast_int.c + create mode 100644 gcc/testsuite/gcc.dg/struct/pc_compress_and_decomress.c + create mode 100644 gcc/testsuite/gcc.dg/struct/pc_ptr2void.c + create mode 100644 gcc/testsuite/gcc.dg/struct/pc_simple_rewrite_pc.c + create mode 100644 gcc/testsuite/gcc.dg/struct/pc_skip_void_struct_name.c + +diff --git a/gcc/common.opt b/gcc/common.opt +index c9b099817..384595f16 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -1889,9 +1889,9 @@ Common Report Var(flag_ipa_struct_reorg) Init(0) Optimization + Perform structure layout optimizations. + + fipa-struct-reorg= +-Common RejectNegative Joined UInteger Var(struct_layout_optimize_level) Init(0) IntegerRange(0, 4) +--fipa-struct-reorg=[0,1,2,3,4] adding none, struct-reorg, reorder-fields, +-dfe, safe-pointer-compression optimizations. ++Common RejectNegative Joined UInteger Var(struct_layout_optimize_level) Init(0) IntegerRange(0, 5) ++-fipa-struct-reorg=[0,1,2,3,4,5] adding none, struct-reorg, reorder-fields, ++dfe, safe-pointer-compression, unsafe-pointer-compression optimizations. + + fipa-extend-auto-profile + Common Report Var(flag_ipa_extend_auto_profile) +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +index 3550411dc..ee4893dfb 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -264,7 +264,8 @@ enum struct_layout_opt_level + COMPLETE_STRUCT_RELAYOUT = 1 << 1, + STRUCT_REORDER_FIELDS = 1 << 2, + DEAD_FIELD_ELIMINATION = 1 << 3, +- POINTER_COMPRESSION_SAFE = 1 << 4 ++ POINTER_COMPRESSION_SAFE = 1 << 4, ++ POINTER_COMPRESSION_UNSAFE = 1 << 5 + }; + + /* Defines the target pointer size of compressed pointer, which should be 8, +@@ -1266,12 +1267,12 @@ csrtype::init_type_info (void) + + /* Close enough to pad to improve performance. + 33~63 should pad to 64 but 33~48 (first half) are too far away, and +- 65~127 should pad to 128 but 65~80 (first half) are too far away. */ ++ 65~127 should pad to 128 but 65~70 (first half) are too far away. */ + if (old_size > 48 && old_size < 64) + { + new_size = 64; + } +- if (old_size > 80 && old_size < 128) ++ if (old_size > 70 && old_size < 128) + { + new_size = 128; + } +@@ -1421,8 +1422,12 @@ public: + bool pc_candidate_tree_p (tree); + bool pc_type_conversion_candidate_p (tree); + bool pc_direct_rewrite_chance_p (tree, tree &); ++ bool pc_simplify_chance_for_compress_p (gassign *, tree); ++ bool compress_candidate_without_check (gimple_stmt_iterator *, tree, tree &); + bool compress_candidate_with_check (gimple_stmt_iterator *, tree, tree &); + bool compress_candidate (gassign *, gimple_stmt_iterator *, tree, tree &); ++ bool decompress_candidate_without_check (gimple_stmt_iterator *, ++ tree, tree, tree &, tree &); + bool decompress_candidate_with_check (gimple_stmt_iterator *, tree, tree &); + bool decompress_candidate (gimple_stmt_iterator *, tree, tree, tree &, + tree &); +@@ -1996,27 +2001,95 @@ ipa_struct_relayout::maybe_rewrite_cst (tree cst, gimple_stmt_iterator *gsi, + { + return false; + } +- gsi_next (gsi); +- gimple *stmt2 = gsi_stmt (*gsi); +- +- if (gimple_code (stmt2) == GIMPLE_ASSIGN +- && gimple_assign_rhs_code (stmt2) == POINTER_PLUS_EXPR) ++ // Check uses. ++ imm_use_iterator imm_iter_lhs; ++ use_operand_p use_p_lhs; ++ FOR_EACH_IMM_USE_FAST (use_p_lhs, imm_iter_lhs, gimple_assign_lhs (stmt)) + { +- tree lhs = gimple_assign_lhs (stmt2); +- tree rhs1 = gimple_assign_rhs1 (stmt2); +- if (types_compatible_p (inner_type (TREE_TYPE (rhs1)), ctype.type) +- || types_compatible_p (inner_type (TREE_TYPE (lhs)), ctype.type)) ++ gimple *stmt2 = USE_STMT (use_p_lhs); ++ if (gimple_code (stmt2) != GIMPLE_ASSIGN) ++ continue; ++ if (gimple_assign_rhs_code (stmt2) == POINTER_PLUS_EXPR) ++ { ++ tree lhs = gimple_assign_lhs (stmt2); ++ tree rhs1 = gimple_assign_rhs1 (stmt2); ++ if (types_compatible_p (inner_type (TREE_TYPE (rhs1)), ctype.type) ++ || types_compatible_p (inner_type (TREE_TYPE (lhs)), ++ ctype.type)) ++ { ++ tree num = NULL; ++ if (is_result_of_mult (cst, &num, ++ TYPE_SIZE_UNIT (ctype.type))) ++ { ++ times = TREE_INT_CST_LOW (num); ++ return true; ++ } ++ } ++ } ++ // For pointer compression. ++ else if (gimple_assign_rhs_code (stmt2) == PLUS_EXPR) + { +- tree num = NULL; +- if (is_result_of_mult (cst, &num, TYPE_SIZE_UNIT (ctype.type))) ++ // Check uses. ++ imm_use_iterator imm_iter_cast; ++ use_operand_p use_p_cast; ++ FOR_EACH_IMM_USE_FAST (use_p_cast, imm_iter_cast, ++ gimple_assign_lhs (stmt2)) + { +- times = TREE_INT_CST_LOW (num); +- ret = true; ++ gimple *stmt_cast = USE_STMT (use_p_cast); ++ if (gimple_code (stmt_cast) != GIMPLE_ASSIGN) ++ continue; ++ if (gimple_assign_cast_p (stmt_cast)) ++ { ++ tree lhs_type = inner_type (TREE_TYPE ( ++ gimple_assign_lhs (stmt_cast))); ++ if (types_compatible_p (lhs_type, ctype.type)) ++ { ++ tree num = NULL; ++ if (is_result_of_mult (cst, &num, ++ TYPE_SIZE_UNIT (ctype.type))) ++ { ++ times = TREE_INT_CST_LOW (num); ++ return true; ++ } ++ } ++ } ++ } ++ } ++ } ++ } ++ // For pointer compression. ++ if (gimple_assign_rhs_code (stmt) == TRUNC_DIV_EXPR) ++ { ++ imm_use_iterator imm_iter; ++ use_operand_p use_p; ++ tree lhs = gimple_assign_lhs (stmt); ++ if (lhs == NULL_TREE) ++ return false; ++ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs) ++ { ++ gimple *use_stmt = USE_STMT (use_p); ++ if (is_gimple_debug (use_stmt)) ++ continue; ++ if (gimple_code (use_stmt) != GIMPLE_ASSIGN) ++ continue; ++ if (gimple_assign_cast_p (use_stmt)) ++ { ++ tree lhs_type = inner_type (TREE_TYPE ( ++ gimple_assign_lhs (use_stmt))); ++ if (TYPE_UNSIGNED (lhs_type) ++ && TREE_CODE (lhs_type) == INTEGER_TYPE ++ && TYPE_PRECISION (lhs_type) == compressed_size) ++ { ++ tree num = NULL; ++ if (is_result_of_mult (cst, &num, ++ TYPE_SIZE_UNIT (ctype.type))) ++ { ++ times = TREE_INT_CST_LOW (num); ++ return true; ++ } + } + } + } +- gsi_prev (gsi); +- return ret; + } + return false; + } +@@ -3110,7 +3183,9 @@ ipa_struct_reorg::record_var (tree decl, escape_type escapes, int arg) + e = escape_separate_instance; + } + +- if (e != does_not_escape) ++ if (e != does_not_escape ++ && (current_layout_opt_level != COMPLETE_STRUCT_RELAYOUT ++ || replace_type_map.get (type->type) == NULL)) + type->mark_escape (e, NULL); + } + +@@ -3793,7 +3868,9 @@ ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other, gimple + if (TREE_CODE (side) == SSA_NAME + && VOID_POINTER_P (TREE_TYPE (side))) + return; +- d->type->mark_escape (escape_cast_another_ptr, stmt); ++ if (current_layout_opt_level != COMPLETE_STRUCT_RELAYOUT ++ || replace_type_map.get (d->type->type) == NULL) ++ d->type->mark_escape (escape_cast_another_ptr, stmt); + return; + } + +@@ -3810,7 +3887,9 @@ ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other, gimple + else + { + /* *_1 = &MEM[(void *)&x + 8B]. */ +- type->mark_escape (escape_cast_another_ptr, stmt); ++ if (current_layout_opt_level != COMPLETE_STRUCT_RELAYOUT ++ || replace_type_map.get (type->type) == NULL) ++ type->mark_escape (escape_cast_another_ptr, stmt); + } + } + else if (type != d->type) +@@ -4550,7 +4629,9 @@ ipa_struct_reorg::check_definition_assign (srdecl *decl, vec<srdecl*> &worklist) + /* Casts between pointers and integer are escaping. */ + if (gimple_assign_cast_p (stmt)) + { +- type->mark_escape (escape_cast_int, stmt); ++ if (current_layout_opt_level != COMPLETE_STRUCT_RELAYOUT ++ || replace_type_map.get (type->type) == NULL) ++ type->mark_escape (escape_cast_int, stmt); + return; + } + +@@ -4897,7 +4978,9 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist) + /* Casts between pointers and integer are escaping. */ + if (gimple_assign_cast_p (stmt)) + { +- type->mark_escape (escape_cast_int, stmt); ++ if (current_layout_opt_level != COMPLETE_STRUCT_RELAYOUT ++ || replace_type_map.get (type->type) == NULL) ++ type->mark_escape (escape_cast_int, stmt); + return; + } + +@@ -5566,9 +5649,9 @@ ipa_struct_reorg::prune_escaped_types (void) + + /* Prune types that escape, all references to those types + will have been removed in the above loops. */ +- /* The escape type is not deleted in STRUCT_LAYOUT_OPTIMIZE, +- Then the type that contains the escaped type fields +- can find complete information. */ ++ /* The escape type is not deleted in current_layout_opt_level after ++ STRUCT_REORDER_FIELDS, then the type that contains the ++ escaped type fields can find complete information. */ + if (current_layout_opt_level < STRUCT_REORDER_FIELDS) + { + for (unsigned i = 0; i < types.length ();) +@@ -6052,17 +6135,17 @@ ipa_struct_reorg::compress_ptr_to_offset (tree xhs, srtype *type, + tree step2 = gimplify_build2 (gsi, TRUNC_DIV_EXPR, long_unsigned_type_node, + step1, TYPE_SIZE_UNIT (type->newtype[0])); + +- /* Emit gimple _X3 = _X2 + 1. */ +- tree step3 = gimplify_build2 (gsi, PLUS_EXPR, long_unsigned_type_node, +- step2, build_one_cst (long_unsigned_type_node)); ++ /* Emit _X3 = (compressed_size) _X2. */ ++ tree pc_type = make_unsigned_type (compressed_size); ++ tree step3 = gimplify_build1 (gsi, NOP_EXPR, pc_type, step2); + +- /* Emit _X4 = (compressed_size) _X3. */ +- tree step4 = gimplify_build1 (gsi, NOP_EXPR, +- make_unsigned_type (compressed_size), step3); ++ /* Emit gimple _X4 = _X3 + 1. */ ++ tree step4 = gimplify_build2 (gsi, PLUS_EXPR, pc_type, step3, ++ build_one_cst (pc_type)); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { +- print_generic_expr (dump_file, step3); ++ print_generic_expr (dump_file, step4); + fprintf (dump_file, "\n"); + } + return step4; +@@ -6104,7 +6187,7 @@ ipa_struct_reorg::decompress_offset_to_ptr (tree xhs, srtype *type, + + if (dump_file && (dump_flags & TDF_DETAILS)) + { +- print_generic_expr (dump_file, step3); ++ print_generic_expr (dump_file, step4); + fprintf (dump_file, "\n"); + } + return step4; +@@ -6267,6 +6350,49 @@ ipa_struct_reorg::pc_direct_rewrite_chance_p (tree rhs, tree &new_rhs) + return false; + } + ++/* The following cases can simplify the checking of null pointer: ++ 1. rhs defined from POINTER_PLUS_EXPR. ++ 2. rhs used as COMPONENT_REF in this basic block. */ ++ ++bool ++ipa_struct_reorg::pc_simplify_chance_for_compress_p (gassign *stmt, ++ tree rhs) ++{ ++ imm_use_iterator imm_iter; ++ use_operand_p use_p; ++ gimple *def_stmt = SSA_NAME_DEF_STMT (rhs); ++ ++ if (def_stmt && is_gimple_assign (def_stmt) ++ && gimple_assign_rhs_code (def_stmt) == POINTER_PLUS_EXPR) ++ return true; ++ ++ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, rhs) ++ { ++ gimple *use_stmt = USE_STMT (use_p); ++ if (use_stmt->bb != stmt->bb || !is_gimple_assign (use_stmt)) ++ continue; ++ ++ tree use_rhs = gimple_assign_rhs1 (use_stmt); ++ if (TREE_CODE (use_rhs) == COMPONENT_REF ++ && TREE_OPERAND (TREE_OPERAND (use_rhs, 0), 0) == rhs) ++ return true; ++ } ++ return false; ++} ++ ++/* Perform compression directly without checking null pointer. */ ++ ++bool ++ipa_struct_reorg::compress_candidate_without_check (gimple_stmt_iterator *gsi, ++ tree rhs, ++ tree &new_rhs) ++{ ++ srtype *type = get_compression_candidate_type (rhs); ++ gcc_assert (type != NULL); ++ new_rhs = compress_ptr_to_offset (new_rhs, type, gsi); ++ return true; ++} ++ + /* Perform pointer compression with check. The conversion will be as shown in + the following example: + Orig bb: +@@ -6368,6 +6494,9 @@ ipa_struct_reorg::compress_candidate (gassign *stmt, gimple_stmt_iterator *gsi, + { + if (pc_direct_rewrite_chance_p (rhs, new_rhs)) + return true; ++ else if (current_layout_opt_level & POINTER_COMPRESSION_UNSAFE ++ && pc_simplify_chance_for_compress_p (stmt, rhs)) ++ return compress_candidate_without_check (gsi, rhs, new_rhs); + + return compress_candidate_with_check (gsi, rhs, new_rhs); + } +@@ -6430,6 +6559,79 @@ ipa_struct_reorg::create_bb_for_decompress_candidate (basic_block last_bb, + return new_bb; + } + ++/* Try decompress candidate without check. */ ++ ++bool ++ipa_struct_reorg::decompress_candidate_without_check (gimple_stmt_iterator *gsi, ++ tree lhs, tree rhs, ++ tree &new_lhs, ++ tree &new_rhs) ++{ ++ imm_use_iterator imm_iter; ++ use_operand_p use_p; ++ bool processed = false; ++ ++ if (!gsi_one_before_end_p (*gsi)) ++ { ++ gsi_next (gsi); ++ gimple *next_stmt = gsi_stmt (*gsi); ++ if (gimple_assign_rhs_class (next_stmt) == GIMPLE_SINGLE_RHS) ++ { ++ tree next_rhs = gimple_assign_rhs1 (next_stmt); ++ /* If current lhs is used as rhs in the next stmt: ++ -> _1 = t->s ++ tt->s = _1. */ ++ if (lhs == next_rhs) ++ { ++ /* Check whether: ++ 1. the lhs is only used in the next stmt. ++ 2. the next lhs is candidate type. */ ++ if (has_single_use (lhs) ++ && pc_candidate_tree_p (gimple_assign_lhs (next_stmt))) ++ { ++ processed = true; ++ /* Copy directly without conversion after update type. */ ++ TREE_TYPE (new_lhs) ++ = make_unsigned_type (compressed_size); ++ } ++ } ++ /* -> _1 = t->s ++ _2 = _1->s ++ In this case, _1 might not be nullptr, so decompress it without ++ check. */ ++ else if (TREE_CODE (next_rhs) == COMPONENT_REF) ++ { ++ tree use_base = TREE_OPERAND (TREE_OPERAND (next_rhs, 0), 0); ++ if (use_base == lhs) ++ { ++ srtype *type = get_compression_candidate_type (rhs); ++ gcc_assert (type != NULL); ++ gsi_prev (gsi); ++ tree new_ref = NULL_TREE; ++ if (TREE_CODE (new_rhs) == MEM_REF) ++ new_ref = new_rhs; ++ else ++ { ++ tree base = TREE_OPERAND (TREE_OPERAND (new_rhs, 0), 0); ++ tree new_mem_ref = build_simple_mem_ref (base); ++ new_ref = build3 (COMPONENT_REF, ++ TREE_TYPE (new_rhs), ++ new_mem_ref, ++ TREE_OPERAND (new_rhs, 1), ++ NULL_TREE); ++ } ++ new_rhs = decompress_offset_to_ptr (new_ref, type, gsi); ++ processed = true; ++ gsi_next (gsi); ++ } ++ } ++ } ++ gsi_prev (gsi); ++ return processed; ++ } ++ return false; ++} ++ + /* Perform pointer decompression with check. The conversion will be as shown + in the following example: + Orig bb: +@@ -6532,7 +6734,10 @@ ipa_struct_reorg::decompress_candidate (gimple_stmt_iterator *gsi, + tree lhs, tree rhs, tree &new_lhs, + tree &new_rhs) + { +- // TODO: simplifiy check and rewrite will be pushed in next PR. ++ if (current_layout_opt_level & POINTER_COMPRESSION_UNSAFE ++ && decompress_candidate_without_check (gsi, lhs, rhs, new_lhs, new_rhs)) ++ return true; ++ + return decompress_candidate_with_check (gsi, rhs, new_rhs); + } + +@@ -7551,18 +7756,26 @@ ipa_struct_reorg::check_and_prune_struct_for_pointer_compression (void) + " skip compression.\n"); + continue; + } +- if ((current_layout_opt_level & POINTER_COMPRESSION_SAFE) +- && !type->has_legal_alloc_num) ++ if (!type->has_legal_alloc_num) + { +- if (dump_file) +- fprintf (dump_file, " has illegal struct array size," +- " skip compression.\n"); +- continue; ++ if (current_layout_opt_level & POINTER_COMPRESSION_UNSAFE) ++ { ++ if (dump_file) ++ fprintf (dump_file, " has unknown alloc size, but" ++ " in unsafe mode, so"); ++ } ++ else ++ { ++ if (dump_file) ++ fprintf (dump_file, " has illegal struct array size," ++ " skip compression.\n"); ++ continue; ++ } + } + pc_transform_num++; + type->pc_candidate = true; + if (dump_file) +- fprintf (dump_file, " attemps to do pointer compression.\n"); ++ fprintf (dump_file, " attempts to do pointer compression.\n"); + } + + if (dump_file) +@@ -7584,14 +7797,10 @@ init_pointer_size_for_pointer_compression (void) + switch (param_pointer_compression_size) + { + case 8: +- compressed_size = 8; // sizeof (uint8) +- break; ++ // FALLTHRU + case 16: +- compressed_size = 16; // sizeof (uint16) +- break; +- case 32: +- compressed_size = 32; // sizeof (uint32) +- break; ++ // FALLTHRU ++ case 32: compressed_size = param_pointer_compression_size; break; + default: + error ("Invalid pointer compression size, using the following param: " + "\"--param pointer-compression-size=[8,16,32]\""); +@@ -7672,6 +7881,8 @@ public: + unsigned int level = 0; + switch (struct_layout_optimize_level) + { ++ case 5: level |= POINTER_COMPRESSION_UNSAFE; ++ // FALLTHRU + case 4: level |= POINTER_COMPRESSION_SAFE; + // FALLTHRU + case 3: level |= DEAD_FIELD_ELIMINATION; +diff --git a/gcc/testsuite/gcc.dg/struct/csr_skip_void_struct_name.c b/gcc/testsuite/gcc.dg/struct/csr_skip_void_struct_name.c +new file mode 100644 +index 000000000..c5e4968d9 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/csr_skip_void_struct_name.c +@@ -0,0 +1,53 @@ ++// Structures without names should not be optimized ++/* { dg-do compile } */ ++#include <stdlib.h> ++#include <math.h> ++ ++typedef struct ++{ ++ int a; ++ float b; ++ double s1; ++ double s2; ++ double s3; ++ double s4; ++ double s5; ++ double s6; ++ double s7; ++ double s8; ++} str_t1; ++ ++#define N 1000 ++ ++int num; ++ ++int ++main () ++{ ++ int i, r; ++ ++ r = rand (); ++ num = r > N ? N : r; ++ str_t1 *p1 = calloc (num, sizeof (str_t1)); ++ ++ if (p1 == NULL) ++ return 0; ++ ++ for (i = 0; i < num; i++) ++ p1[i].a = 1; ++ ++ for (i = 0; i < num; i++) ++ p1[i].b = 2; ++ ++ for (i = 0; i < num; i++) ++ if (p1[i].a != 1) ++ abort (); ++ ++ for (i = 0; i < num; i++) ++ if (fabsf (p1[i].b - 2) > 0.0001) ++ abort (); ++ ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "No structures to transform in Complete Structure Relayout." "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/pc_cast_int.c b/gcc/testsuite/gcc.dg/struct/pc_cast_int.c +new file mode 100644 +index 000000000..6f67fc556 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/pc_cast_int.c +@@ -0,0 +1,91 @@ ++// Escape cast int for pointer compression ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++typedef struct network ++{ ++ arc_p arcs; ++ arc_p sorted_arcs; ++ int x; ++ node_p nodes; ++ node_p stop_nodes; ++} network_t; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++ network_t* net_add; ++}; ++ ++ ++const int MAX = 100; ++network_t* net; ++node_p node; ++ ++int ++main () ++{ ++ net = (network_t*) calloc (1, sizeof(network_t)); ++ net->arcs = (arc_p) calloc (MAX, sizeof (arc_t)); ++ net->sorted_arcs = (arc_p) calloc (MAX, sizeof (arc_t)); ++ net->nodes = (node_p) calloc (MAX, sizeof (node_t)); ++ net->arcs->id = 100; ++ ++ node = net->nodes; ++ node_p n1 = (node_p) 0x123456; ++ ++ for (unsigned i = 0; i < MAX; i++) ++ { ++ node->pred = n1; ++ node = node + 1; ++ } ++ ++ node = net->nodes; ++ ++ for (unsigned i = 0; i < MAX; i++) ++ { ++ if (node->pred != n1) ++ { ++ abort (); ++ } ++ node = node + 1; ++ } ++ ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "No structures to transform in pointer compression" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/pc_compress_and_decomress.c b/gcc/testsuite/gcc.dg/struct/pc_compress_and_decomress.c +new file mode 100644 +index 000000000..d0b8d1afa +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/pc_compress_and_decomress.c +@@ -0,0 +1,90 @@ ++// Support basic pointer compression and decompression ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++typedef struct network ++{ ++ arc_p arcs; ++ arc_p sorted_arcs; ++ int x; ++ node_p nodes; ++ node_p stop_nodes; ++} network_t; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++ network_t* net_add; ++}; ++ ++ ++const int MAX = 100; ++network_t* net; ++node_p node; ++ ++int ++main () ++{ ++ net = (network_t*) calloc (1, sizeof(network_t)); ++ net->arcs = (arc_p) calloc (MAX, sizeof (arc_t)); ++ net->sorted_arcs = (arc_p) calloc (MAX, sizeof (arc_t)); ++ net->nodes = (node_p) calloc (MAX, sizeof (node_t)); ++ net->arcs->id = 100; ++ ++ node = net->nodes; ++ ++ for (unsigned i = 0; i < MAX; i++) ++ { ++ node->pred = node; ++ node = node + 1; ++ } ++ ++ node = net->nodes; ++ ++ for (unsigned i = 0; i < MAX; i++) ++ { ++ if (node->pred != node) ++ { ++ abort (); ++ } ++ node = node + 1; ++ } ++ ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in pointer compression is 1" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/pc_ptr2void.c b/gcc/testsuite/gcc.dg/struct/pc_ptr2void.c +new file mode 100644 +index 000000000..5022c1967 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/pc_ptr2void.c +@@ -0,0 +1,87 @@ ++// Partially support escape_cast_void for pointer compression. ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++typedef struct network ++{ ++ arc_p arcs, sorted_arcs; ++ int x; ++ node_p nodes, stop_nodes; ++} network_t; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++}; ++ ++const int MAX = 100; ++network_t* net = NULL; ++int cnt = 0; ++ ++__attribute__((noinline)) int ++primal_feasible (network_t *net) ++{ ++ void* stop; ++ node_t *node; ++ ++ node = net->nodes; ++ stop = (void *)net->stop_nodes; ++ for( node++; node < (node_t *)stop; node++ ) ++ { ++ net->x = 1; ++ printf( "PRIMAL NETWORK SIMPLEX: "); ++ } ++ return 0; ++} ++ ++int ++main () ++{ ++ net = (network_t*) calloc (1, 20); ++ net->nodes = calloc (MAX, sizeof (node_t)); ++ net->stop_nodes = net->nodes + MAX - 1; ++ cnt = primal_feasible( net ); ++ ++ net = (network_t*) calloc (1, 20); ++ if( !(net->arcs) ) ++ { ++ return -1; ++ } ++ return cnt; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in pointer compression is 1" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/pc_simple_rewrite_pc.c b/gcc/testsuite/gcc.dg/struct/pc_simple_rewrite_pc.c +new file mode 100644 +index 000000000..98943c9b8 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/pc_simple_rewrite_pc.c +@@ -0,0 +1,112 @@ ++// Check simplify rewrite chance for pointer compression and decompression ++/* { dg-do compile } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++typedef struct network ++{ ++ arc_p arcs; ++ arc_p sorted_arcs; ++ int x; ++ node_p nodes; ++ node_p stop_nodes; ++} network_t; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++ network_t* net_add; ++}; ++ ++ ++const int MAX = 100; ++network_t* net; ++node_p node; ++arc_p arc; ++ ++int ++main () ++{ ++ net = (network_t*) calloc (1, sizeof(network_t)); ++ net->arcs = (arc_p) calloc (MAX, sizeof (arc_t)); ++ net->sorted_arcs = (arc_p) calloc (MAX, sizeof (arc_t)); ++ net->nodes = (node_p) calloc (MAX, sizeof (node_t)); ++ net->arcs->id = 100; ++ ++ node = net->nodes; ++ arc = net->arcs; ++ ++ for (unsigned i = 0; i < MAX; i++) ++ { ++ arc->head = node; ++ arc->head->child = node; ++ node->potential = i + 1; ++ arc->cost = arc->head->potential; ++ arc->tail = node->sibling; ++ if (i % 2) ++ node->pred = net->nodes + i; ++ else ++ node->pred = NULL; ++ ++ if (node->pred && node->pred->child != NULL) ++ node->number = 0; ++ else ++ node->number = 1; ++ ++ node = node + 1; ++ arc = arc + 1; ++ } ++ ++ node = net->nodes; ++ arc = net->arcs; ++ ++ for (unsigned i = 0; i < MAX; i++) ++ { ++ node_p t = i % 2 ? node : NULL; ++ int tt = i % 2 ? 0 : 1; ++ if (arc->head->pred != t || arc->cost == 0 ++ || arc->tail != node->sibling || node->number != tt) ++ { ++ abort (); ++ } ++ arc = arc + 1; ++ node = node + 1; ++ } ++ ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "Number of structures to transform in pointer compression is 1" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/pc_skip_void_struct_name.c b/gcc/testsuite/gcc.dg/struct/pc_skip_void_struct_name.c +new file mode 100644 +index 000000000..a0e191267 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/pc_skip_void_struct_name.c +@@ -0,0 +1,53 @@ ++// Structures without names should not be optimized ++/* { dg-do compile } */ ++#include <stdlib.h> ++#include <math.h> ++ ++typedef struct ++{ ++ int a; ++ float b; ++ double s1; ++ double s2; ++ double s3; ++ double s4; ++ double s5; ++ double s6; ++ double s7; ++ double s8; ++} str_t1; ++ ++#define N 1000 ++ ++int num; ++ ++int ++main () ++{ ++ int i, r; ++ ++ r = rand (); ++ num = r > N ? N : r; ++ str_t1 *p1 = calloc (num, sizeof (str_t1)); ++ ++ if (p1 == NULL) ++ return 0; ++ ++ for (i = 0; i < num; i++) ++ p1[i].a = 1; ++ ++ for (i = 0; i < num; i++) ++ p1[i].b = 2; ++ ++ for (i = 0; i < num; i++) ++ if (p1[i].a != 1) ++ abort (); ++ ++ for (i = 0; i < num; i++) ++ if (fabsf (p1[i].b - 2) > 0.0001) ++ abort (); ++ ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "No structures to transform in pointer compression" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp +index 2eebef768..d7367ed96 100644 +--- a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp ++++ b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp +@@ -85,6 +85,14 @@ gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/rf*.c]] \ + gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/dfe*.c]] \ + "" "-fipa-struct-reorg=3 -fdump-ipa-all -flto-partition=one -fwhole-program" + ++# -fipa-struct-reorg=4 ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/pc*.c]] \ ++ "" "-fipa-struct-reorg=4 -fdump-ipa-all -flto-partition=one -fwhole-program" ++ ++# -fipa-struct-reorg=5 ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/pc*.c]] \ ++ "" "-fipa-struct-reorg=5 -fdump-ipa-all -flto-partition=one -fwhole-program" ++ + # All done. + torture-finish + dg-finish +-- +2.27.0.windows.1 + diff --git a/0081-Loop-distribution-Insert-temp-arrays-built-from-isom.patch b/0081-Loop-distribution-Insert-temp-arrays-built-from-isom.patch new file mode 100644 index 0000000..2197b2f --- /dev/null +++ b/0081-Loop-distribution-Insert-temp-arrays-built-from-isom.patch @@ -0,0 +1,826 @@ +From ca2a541ed3425bec64f97fe277c6c02bf4f20049 Mon Sep 17 00:00:00 2001 +From: benniaobufeijiushiji <linda7@huawei.com> +Date: Thu, 27 Oct 2022 10:26:34 +0800 +Subject: [PATCH 33/35] [Loop-distribution] Insert temp arrays built from + isomorphic stmts Use option -ftree-slp-transpose-vectorize Build temp arrays + for isomorphic stmt and regard them as new seed_stmts for loop distribution. + +--- + gcc/testsuite/gcc.dg/tree-ssa/ins-ldist-1.c | 67 +++ + gcc/testsuite/gcc.dg/tree-ssa/ins-ldist-2.c | 17 + + gcc/testsuite/gcc.dg/tree-ssa/ins-ldist-3.c | 19 + + gcc/tree-loop-distribution.c | 577 +++++++++++++++++++- + 4 files changed, 663 insertions(+), 17 deletions(-) + create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ins-ldist-1.c + create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ins-ldist-2.c + create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ins-ldist-3.c + +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ins-ldist-1.c b/gcc/testsuite/gcc.dg/tree-ssa/ins-ldist-1.c +new file mode 100644 +index 000000000..649463647 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/ins-ldist-1.c +@@ -0,0 +1,67 @@ ++/* { dg-do compile { target { aarch64*-*-linux* } } } */ ++/* { dg-do run { target { aarch64*-*-linux* } } } */ ++/* { dg-options "-O3 -ftree-slp-transpose-vectorize -fdump-tree-ldist-all-details -save-temps" } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++static unsigned inline abs2 (unsigned a) ++{ ++ unsigned s = ((a>>15)&0x10001)*0xffff; ++ return (a+s)^s; ++} ++ ++int foo (unsigned char *oxa, int ia, unsigned char *oxb, int ib) ++{ ++ unsigned tmp[4][4]; ++ unsigned a0, a1, a2, a3; ++ int sum = 0; ++ for (int i = 0; i < 4; i++, oxa += ia, oxb += ib) ++ { ++ a0 = (oxa[0] - oxb[0]) + ((oxa[4] - oxb[4]) << 16); ++ a1 = (oxa[1] - oxb[1]) + ((oxa[5] - oxb[5]) << 16); ++ a2 = (oxa[2] - oxb[2]) + ((oxa[6] - oxb[6]) << 16); ++ a3 = (oxa[3] - oxb[3]) + ((oxa[7] - oxb[7]) << 16); ++ int t0 = a0 + a1; ++ int t1 = a0 - a1; ++ int t2 = a2 + a3; ++ int t3 = a2 - a3; ++ tmp[i][0] = t0 + t2; ++ tmp[i][2] = t0 - t2; ++ tmp[i][1] = t1 + t3; ++ tmp[i][3] = t1 - t3; ++ } ++ for (int i = 0; i < 4; i++) ++ { ++ int t0 = tmp[0][i] + tmp[1][i]; ++ int t1 = tmp[0][i] - tmp[1][i]; ++ int t2 = tmp[2][i] + tmp[3][i]; ++ int t3 = tmp[2][i] - tmp[3][i]; ++ a0 = t0 + t2; ++ a2 = t0 - t2; ++ a1 = t1 + t3; ++ a3 = t1 - t3; ++ sum += abs2 (a0) + abs2 (a1) + abs2 (a2) + abs2 (a3); ++ } ++ return (((unsigned short) sum) + ((unsigned) sum >>16)) >> 1; ++} ++ ++int main () ++{ ++ unsigned char oxa[128] = {0}; ++ unsigned char oxb[128] = {0}; ++ for (int i = 0; i < 128; i++) ++ { ++ oxa[i] += i * 3; ++ oxb[i] = i * 2; ++ } ++ int sum = foo (oxa, 16, oxb, 32); ++ if (sum != 736) ++ { ++ abort (); ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-tree-dump-times "Insertion done: 4 temp arrays inserted" 1 "ldist" } } */ ++/* { dg-final { scan-tree-dump-times "distributed: split to 2 loops" 1 "ldist" } } */ +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ins-ldist-2.c b/gcc/testsuite/gcc.dg/tree-ssa/ins-ldist-2.c +new file mode 100644 +index 000000000..1b50fd27d +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/ins-ldist-2.c +@@ -0,0 +1,17 @@ ++/* { dg-do compile { target { aarch64*-*-linux* } } } */ ++/* { dg-options "-O3 -ftree-slp-transpose-vectorize -fdump-tree-ldist-all-details" } */ ++ ++unsigned a0[4], a1[4], a2[4], a3[4]; ++ ++void foo (unsigned char *oxa, int ia, unsigned char *oxb, int ib) ++{ ++ for (int i = 0; i < 4; i++, oxa += ia, oxb += ib) ++ { ++ a0[i] = (oxa[0] - oxb[0]) + ((oxa[4] - oxb[4]) << 16); ++ a1[i] = (oxa[1] - oxb[1]) + ((oxa[5] - oxb[5]) << 16); ++ a2[i] = (oxa[2] - oxb[2]) + ((oxa[6] - oxb[6]) << 16); ++ a3[i] = (oxa[3] - oxb[3]) + ((oxa[7] - oxb[7]) << 16); ++ } ++} ++ ++/* { dg-final { scan-tree-dump-times "Loop 1 not distributed." 1 "ldist" } } */ +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ins-ldist-3.c b/gcc/testsuite/gcc.dg/tree-ssa/ins-ldist-3.c +new file mode 100644 +index 000000000..94b992b05 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/tree-ssa/ins-ldist-3.c +@@ -0,0 +1,19 @@ ++/* { dg-do compile { target { aarch64*-*-linux* } } } */ ++/* { dg-options "-O3 -ftree-slp-transpose-vectorize -fdump-tree-ldist-all-details" } */ ++ ++unsigned a0[4], a1[4], a2[4], a3[4]; ++ ++void foo (unsigned char *oxa, int ia, unsigned char *oxb, int ib) ++{ ++ for (int i = 0; i < 4; i++, oxa += ia, oxb += ib) ++ { ++ a0[i] = ((oxa[0] - oxb[0]) + ((oxa[4] - oxb[4]) << 16)) + 1; ++ a1[i] = ((oxa[1] - oxb[1]) + ((oxa[5] - oxb[5]) << 16)) - 2; ++ a2[i] = ((oxa[2] - oxb[2]) + ((oxa[6] - oxb[6]) << 16)) * 3; ++ a3[i] = ((oxa[3] - oxb[3]) + ((oxa[7] - oxb[7]) << 16)) / 4; ++ } ++} ++ ++/* { dg-final { scan-tree-dump-times "Insertion done: 4 temp arrays inserted" 1 "ldist" } } */ ++/* { dg-final { scan-tree-dump-times "Insertion removed" 1 "ldist" } } */ ++/* { dg-final { scan-tree-dump-times "Loop 1 not distributed." 1 "ldist" } } */ +\ No newline at end of file +diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c +index c08af6562..88b56379c 100644 +--- a/gcc/tree-loop-distribution.c ++++ b/gcc/tree-loop-distribution.c +@@ -36,6 +36,47 @@ along with GCC; see the file COPYING3. If not see + | D(I) = A(I-1)*E + |ENDDO + ++ If an unvectorizable loop has grouped loads, and calculations from grouped ++ loads are isomorphic, build temp arrays using stmts where isomorphic ++ calculations end. Afer distribution, the partition built from temp ++ arrays can be vectorized in pass SLP after loop unrolling. For example, ++ ++ |DO I = 1, N ++ | A = FOO (ARG_1); ++ | B = FOO (ARG_2); ++ | C = BAR_0 (A); ++ | D = BAR_1 (B); ++ |ENDDO ++ ++ is transformed to ++ ++ |DO I = 1, N ++ | J = FOO (ARG_1); ++ | K = FOO (ARG_2); ++ | X[I] = J; ++ | Y[I] = K; ++ | A = X[I]; ++ | B = Y[I]; ++ | C = BAR_0 (A); ++ | D = BAR_1 (B); ++ |ENDDO ++ ++ and is then distributed to ++ ++ |DO I = 1, N ++ | J = FOO (ARG_1); ++ | K = FOO (ARG_2); ++ | X[I] = J; ++ | Y[I] = K; ++ |ENDDO ++ ++ |DO I = 1, N ++ | A = X[I]; ++ | B = Y[I]; ++ | C = BAR_0 (A); ++ | D = BAR_1 (B); ++ |ENDDO ++ + Loop distribution is the dual of loop fusion. It separates statements + of a loop (or loop nest) into multiple loops (or loop nests) with the + same loop header. The major goal is to separate statements which may +@@ -44,7 +85,9 @@ along with GCC; see the file COPYING3. If not see + + 1) Seed partitions with specific type statements. For now we support + two types seed statements: statement defining variable used outside +- of loop; statement storing to memory. ++ of loop; statement storing to memory. Moreover, for unvectorizable ++ loops, we try to find isomorphic stmts from grouped load and build ++ temp arrays as new seed statements. + 2) Build reduced dependence graph (RDG) for loop to be distributed. + The vertices (RDG:V) model all statements in the loop and the edges + (RDG:E) model flow and control dependencies between statements. +@@ -643,7 +686,8 @@ class loop_distribution + /* Returns true when PARTITION1 and PARTITION2 access the same memory + object in RDG. */ + bool share_memory_accesses (struct graph *rdg, +- partition *partition1, partition *partition2); ++ partition *partition1, partition *partition2, ++ hash_set<tree> *excluded_arrays); + + /* For each seed statement in STARTING_STMTS, this function builds + partition for it by adding depended statements according to RDG. +@@ -686,8 +730,9 @@ class loop_distribution + + /* Fuse PARTITIONS of LOOP if necessary before finalizing distribution. + ALIAS_DDRS contains ddrs which need runtime alias check. */ +- void finalize_partitions (class loop *loop, vec<struct partition *> +- *partitions, vec<ddr_p> *alias_ddrs); ++ void finalize_partitions (class loop *loop, ++ vec<struct partition *> *partitions, ++ vec<ddr_p> *alias_ddrs, bitmap producers); + + /* Analyze loop form and if it's vectorizable to decide if we need to + insert temp arrays to distribute it. */ +@@ -701,6 +746,28 @@ class loop_distribution + + inline void rebuild_rdg (loop_p loop, struct graph *&rdg, + control_dependences *cd); ++ ++ /* If loop is not distributed, remove inserted temp arrays. */ ++ void remove_insertion (loop_p loop, struct graph *flow_only_rdg, ++ bitmap producers, struct partition *partition); ++ ++ /* Insert temp arrays if isomorphic computation exists. Temp arrays will be ++ regarded as SEED_STMTS for building partitions in succeeding processes. */ ++ bool insert_temp_arrays (loop_p loop, vec<gimple *> seed_stmts, ++ hash_set<tree> *tmp_array_vars, bitmap producers); ++ ++ void build_producers (loop_p loop, bitmap producers, ++ vec<gimple *> &transformed); ++ ++ void do_insertion (loop_p loop, struct graph *flow_only_rdg, tree iv, ++ bitmap cut_points, hash_set <tree> *tmp_array_vars, ++ bitmap producers); ++ ++ /* Fuse PARTITIONS built from inserted temp arrays into one partition, ++ fuse the rest into another. */ ++ void merge_remaining_partitions (vec<struct partition *> *partitions, ++ bitmap producers); ++ + /* Distributes the code from LOOP in such a way that producer statements + are placed before consumer statements. Tries to separate only the + statements from STMTS into separate loops. Returns the number of +@@ -1913,7 +1980,8 @@ loop_distribution::classify_partition (loop_p loop, + + bool + loop_distribution::share_memory_accesses (struct graph *rdg, +- partition *partition1, partition *partition2) ++ partition *partition1, partition *partition2, ++ hash_set <tree> *excluded_arrays) + { + unsigned i, j; + bitmap_iterator bi, bj; +@@ -1947,7 +2015,10 @@ loop_distribution::share_memory_accesses (struct graph *rdg, + if (operand_equal_p (DR_BASE_ADDRESS (dr1), DR_BASE_ADDRESS (dr2), 0) + && operand_equal_p (DR_OFFSET (dr1), DR_OFFSET (dr2), 0) + && operand_equal_p (DR_INIT (dr1), DR_INIT (dr2), 0) +- && operand_equal_p (DR_STEP (dr1), DR_STEP (dr2), 0)) ++ && operand_equal_p (DR_STEP (dr1), DR_STEP (dr2), 0) ++ /* An exception, if PARTITION1 and PARTITION2 contain the ++ temp array we inserted, do not merge them. */ ++ && !excluded_arrays->contains (DR_REF (dr1))) + return true; + } + } +@@ -2909,13 +2980,47 @@ fuse_memset_builtins (vec<struct partition *> *partitions) + } + } + ++void ++loop_distribution::merge_remaining_partitions ++ (vec<struct partition *> *partitions, ++ bitmap producers) ++{ ++ struct partition *partition = NULL; ++ struct partition *p1 = NULL, *p2 = NULL; ++ for (unsigned i = 0; partitions->iterate (i, &partition); i++) ++ { ++ if (bitmap_intersect_p (producers, partition->stmts)) ++ { ++ if (p1 == NULL) ++ { ++ p1 = partition; ++ continue; ++ } ++ partition_merge_into (NULL, p1, partition, FUSE_FINALIZE); ++ } ++ else ++ { ++ if (p2 == NULL) ++ { ++ p2 = partition; ++ continue; ++ } ++ partition_merge_into (NULL, p2, partition, FUSE_FINALIZE); ++ } ++ partitions->unordered_remove (i); ++ partition_free (partition); ++ i--; ++ } ++} ++ + void + loop_distribution::finalize_partitions (class loop *loop, + vec<struct partition *> *partitions, +- vec<ddr_p> *alias_ddrs) ++ vec<ddr_p> *alias_ddrs, ++ bitmap producers) + { + unsigned i; +- struct partition *partition, *a; ++ struct partition *partition; + + if (partitions->length () == 1 + || alias_ddrs->length () > 0) +@@ -2947,13 +3052,7 @@ loop_distribution::finalize_partitions (class loop *loop, + || (loop->inner == NULL + && i >= NUM_PARTITION_THRESHOLD && num_normal > num_builtin)) + { +- a = (*partitions)[0]; +- for (i = 1; partitions->iterate (i, &partition); ++i) +- { +- partition_merge_into (NULL, a, partition, FUSE_FINALIZE); +- partition_free (partition); +- } +- partitions->truncate (1); ++ merge_remaining_partitions (partitions, producers); + } + + /* Fuse memset builtins if possible. */ +@@ -3758,6 +3857,404 @@ find_isomorphic_stmts (loop_vec_info vinfo, vec<gimple *> &stmts) + return decide_stmts_by_profit (candi_stmts, stmts); + } + ++/* Get iv from SEED_STMTS and make sure each seed_stmt has only one iv as index ++ and all indices are the same. */ ++ ++static tree ++find_index (vec<gimple *> seed_stmts) ++{ ++ if (seed_stmts.length () == 0) ++ return NULL; ++ bool found_index = false; ++ tree index = NULL; ++ unsigned ui = 0; ++ for (ui = 0; ui < seed_stmts.length (); ui++) ++ { ++ if (!gimple_vdef (seed_stmts[ui])) ++ return NULL; ++ tree lhs = gimple_assign_lhs (seed_stmts[ui]); ++ unsigned num_index = 0; ++ while (TREE_CODE (lhs) == ARRAY_REF) ++ { ++ if (TREE_CODE (TREE_OPERAND (lhs, 1)) == SSA_NAME) ++ { ++ num_index++; ++ if (num_index > 1) ++ return NULL; ++ if (index == NULL) ++ { ++ index = TREE_OPERAND (lhs, 1); ++ found_index = true; ++ } ++ else if (index != TREE_OPERAND (lhs, 1)) ++ return NULL; ++ } ++ lhs = TREE_OPERAND (lhs, 0); ++ } ++ if (!found_index) ++ return NULL; ++ } ++ return index; ++} ++ ++/* Check if expression of phi is an increament of a const. */ ++ ++static void ++check_phi_inc (struct vertex *v_phi, struct graph *rdg, bool &found_inc) ++{ ++ struct graph_edge *e_phi; ++ for (e_phi = v_phi->succ; e_phi; e_phi = e_phi->succ_next) ++ { ++ struct vertex *v_inc = &(rdg->vertices[e_phi->dest]); ++ if (!is_gimple_assign (RDGV_STMT (v_inc)) ++ || gimple_expr_code (RDGV_STMT (v_inc)) != PLUS_EXPR) ++ continue; ++ tree rhs1 = gimple_assign_rhs1 (RDGV_STMT (v_inc)); ++ tree rhs2 = gimple_assign_rhs2 (RDGV_STMT (v_inc)); ++ if (!(integer_onep (rhs1) || integer_onep (rhs2))) ++ continue; ++ struct graph_edge *e_inc; ++ /* find cycle with only two vertices inc and phi: inc <--> phi. */ ++ bool found_cycle = false; ++ for (e_inc = v_inc->succ; e_inc; e_inc = e_inc->succ_next) ++ { ++ if (e_inc->dest == e_phi->src) ++ { ++ found_cycle = true; ++ break; ++ } ++ } ++ if (!found_cycle) ++ continue; ++ found_inc = true; ++ } ++} ++ ++/* Check if phi satisfies form like PHI <0, i>. */ ++ ++static inline bool ++iv_check_phi_stmt (gimple *phi_stmt) ++{ ++ return gimple_phi_num_args (phi_stmt) == 2 ++ && (integer_zerop (gimple_phi_arg_def (phi_stmt, 0)) ++ || integer_zerop (gimple_phi_arg_def (phi_stmt, 1))); ++} ++ ++/* Make sure the iteration varible is a phi. */ ++ ++static tree ++get_iv_from_seed (struct graph *flow_only_rdg, vec<gimple *> seed_stmts) ++{ ++ tree index = find_index (seed_stmts); ++ if (index == NULL) ++ return NULL; ++ for (int i = 0; i < flow_only_rdg->n_vertices; i++) ++ { ++ struct vertex *v = &(flow_only_rdg->vertices[i]); ++ if (RDGV_STMT (v) != seed_stmts[0]) ++ continue; ++ struct graph_edge *e; ++ bool found_phi = false; ++ for (e = v->pred; e; e = e->pred_next) ++ { ++ struct vertex *v_phi = &(flow_only_rdg->vertices[e->src]); ++ gimple *phi_stmt = RDGV_STMT (v_phi); ++ if (gimple_code (phi_stmt) != GIMPLE_PHI ++ || gimple_phi_result (phi_stmt) != index) ++ continue; ++ if (!iv_check_phi_stmt (phi_stmt)) ++ return NULL; ++ /* find inc expr in succ of phi. */ ++ bool found_inc = false; ++ check_phi_inc (v_phi, flow_only_rdg, found_inc); ++ if (!found_inc) ++ return NULL; ++ found_phi = true; ++ break; ++ } ++ if (!found_phi) ++ return NULL; ++ break; ++ } ++ return index; ++} ++ ++/* Do not distribute loop if vertexes in ROOT_MAP have antidependence with in ++ FLOW_ONLY_RDG. */ ++ ++static bool ++check_no_dependency (struct graph *flow_only_rdg, bitmap root_map) ++{ ++ bitmap_iterator bi; ++ unsigned ui; ++ auto_vec<unsigned, 16> visited_nodes; ++ auto_bitmap visited_map; ++ EXECUTE_IF_SET_IN_BITMAP (root_map, 0, ui, bi) ++ visited_nodes.safe_push (ui); ++ for (ui = 0; ui < visited_nodes.length (); ui++) ++ { ++ struct vertex *v = &(flow_only_rdg->vertices[visited_nodes[ui]]); ++ struct graph_edge *e; ++ for (e = v->succ; e; e = e->succ_next) ++ { ++ if (bitmap_bit_p (root_map, e->dest)) ++ return false; ++ if (bitmap_bit_p (visited_map, e->dest)) ++ continue; ++ visited_nodes.safe_push (e->dest); ++ bitmap_set_bit (visited_map, e->dest); ++ } ++ } ++ return true; ++} ++ ++/* Find isomorphic stmts from GROUPED_LOADS in VINFO and make sure ++ there is no dependency among those STMT we found. */ ++ ++static unsigned ++get_cut_points (struct graph *flow_only_rdg, bitmap cut_points, ++ loop_vec_info vinfo) ++{ ++ unsigned n_stmts = 0; ++ ++ /* STMTS that may be CUT_POINTS. */ ++ auto_vec<gimple *> stmts; ++ if (!find_isomorphic_stmts (vinfo, stmts)) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "No temp array insertion: no isomorphic stmts" ++ " were found.\n"); ++ return 0; ++ } ++ ++ for (int i = 0; i < flow_only_rdg->n_vertices; i++) ++ { ++ if (stmts.contains (RDG_STMT (flow_only_rdg, i))) ++ bitmap_set_bit (cut_points, i); ++ } ++ n_stmts = bitmap_count_bits (cut_points); ++ ++ bool succ = check_no_dependency (flow_only_rdg, cut_points); ++ if (!succ) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "No temp array inserted: data dependency" ++ " among isomorphic stmts.\n"); ++ return 0; ++ } ++ return n_stmts; ++} ++ ++static void ++build_temp_array (struct vertex *v, gimple_stmt_iterator &gsi, ++ poly_uint64 array_extent, tree iv, ++ hash_set<tree> *tmp_array_vars, vec<gimple *> *transformed) ++{ ++ gimple *stmt = RDGV_STMT (v); ++ tree lhs = gimple_assign_lhs (stmt); ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "original stmt:\t"); ++ print_gimple_stmt (dump_file, stmt, 0, TDF_VOPS|TDF_MEMSYMS); ++ } ++ tree var_ssa = duplicate_ssa_name (lhs, stmt); ++ gimple_assign_set_lhs (stmt, var_ssa); ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "changed to:\t"); ++ print_gimple_stmt (dump_file, stmt, 0, TDF_VOPS | TDF_MEMSYMS); ++ } ++ gimple_set_uid (gsi_stmt (gsi), -1); ++ tree vect_elt_type = TREE_TYPE (lhs); ++ tree array_type = build_array_type_nelts (vect_elt_type, array_extent); ++ tree array = create_tmp_var (array_type); ++ tree array_ssa = build4 (ARRAY_REF, vect_elt_type, array, iv, NULL, NULL); ++ tmp_array_vars->add (array_ssa); ++ gimple *store = gimple_build_assign (array_ssa, var_ssa); ++ tree new_vdef = make_ssa_name (gimple_vop (cfun), store); ++ gsi_insert_after (&gsi, store, GSI_NEW_STMT); ++ gimple_set_vdef (store, new_vdef); ++ transformed->safe_push (store); ++ gimple_set_uid (gsi_stmt (gsi), -1); ++ tree array_ssa2 = build4 (ARRAY_REF, vect_elt_type, array, iv, NULL, NULL); ++ tmp_array_vars->add (array_ssa2); ++ gimple *load = gimple_build_assign (lhs, array_ssa2); ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "insert stmt:\t"); ++ print_gimple_stmt (dump_file, store, 0, TDF_VOPS|TDF_MEMSYMS); ++ fprintf (dump_file, " and stmt:\t"); ++ print_gimple_stmt (dump_file, load, 0, TDF_VOPS|TDF_MEMSYMS); ++ } ++ gimple_set_vuse (load, new_vdef); ++ gsi_insert_after (&gsi, load, GSI_NEW_STMT); ++ gimple_set_uid (gsi_stmt (gsi), -1); ++} ++ ++/* Set bitmap PRODUCERS based on vec TRANSFORMED. */ ++ ++void ++loop_distribution::build_producers (loop_p loop, bitmap producers, ++ vec<gimple *> &transformed) ++{ ++ auto_vec<gimple *, 10> stmts; ++ stmts_from_loop (loop, &stmts); ++ int i = 0; ++ gimple *stmt = NULL; ++ ++ FOR_EACH_VEC_ELT (stmts, i, stmt) ++ gimple_set_uid (stmt, i); ++ i = 0; ++ FOR_EACH_VEC_ELT (transformed, i, stmt) ++ bitmap_set_bit (producers, stmt->uid); ++} ++ ++/* Transform stmt ++ ++ A = FOO (ARG_1); ++ ++ to ++ ++ STMT_1: A1 = FOO (ARG_1); ++ STMT_2: X[I] = A1; ++ STMT_3: A = X[I]; ++ ++ Producer is STMT_2 who defines the temp array and consumer is ++ STMT_3 who uses the temp array. */ ++ ++void ++loop_distribution::do_insertion (loop_p loop, struct graph *flow_only_rdg, ++ tree iv, bitmap cut_points, ++ hash_set<tree> *tmp_array_vars, ++ bitmap producers) ++{ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "=== do insertion ===\n"); ++ ++ auto_vec<gimple *> transformed; ++ ++ /* Execution times of loop. */ ++ poly_uint64 array_extent ++ = tree_to_poly_uint64 (number_of_latch_executions (loop)) + 1; ++ ++ basic_block *bbs = get_loop_body_in_custom_order (loop, this, ++ bb_top_order_cmp_r); ++ ++ for (int i = 0; i < int (loop->num_nodes); i++) ++ { ++ basic_block bb = bbs[i]; ++ ++ /* Find all cut points in bb and transform them. */ ++ for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); ++ gsi_next (&gsi)) ++ { ++ unsigned j = gimple_uid (gsi_stmt (gsi)); ++ if (bitmap_bit_p (cut_points, j)) ++ { ++ struct vertex *v = &(flow_only_rdg->vertices[j]); ++ build_temp_array (v, gsi, array_extent, iv, tmp_array_vars, ++ &transformed); ++ } ++ } ++ } ++ build_producers (loop, producers, transformed); ++ update_ssa (TODO_update_ssa); ++ free (bbs); ++} ++ ++/* After temp array insertion, given stmts ++ STMT_1: M = FOO (ARG_1); ++ STMT_2: X[I] = M; ++ STMT_3: A = X[I]; ++ STMT_2 is the producer, STMT_1 is its prev and STMT_3 is its next. ++ Replace M with A, and remove STMT_2 and STMT_3. */ ++ ++static void ++reset_gimple_assign (struct graph *flow_only_rdg, struct partition *partition, ++ gimple_stmt_iterator &gsi, int j) ++{ ++ struct vertex *v = &(flow_only_rdg->vertices[j]); ++ gimple *stmt = RDGV_STMT (v); ++ gimple *prev = stmt->prev; ++ gimple *next = stmt->next; ++ tree n_lhs = gimple_assign_lhs (next); ++ gimple_assign_set_lhs (prev, n_lhs); ++ unlink_stmt_vdef (stmt); ++ if (partition) ++ bitmap_clear_bit (partition->stmts, gimple_uid (gsi_stmt (gsi))); ++ gsi_remove (&gsi, true); ++ release_defs (stmt); ++ if (partition) ++ bitmap_clear_bit (partition->stmts, gimple_uid (gsi_stmt (gsi))); ++ gsi_remove (&gsi, true); ++} ++ ++void ++loop_distribution::remove_insertion (loop_p loop, struct graph *flow_only_rdg, ++ bitmap producers, struct partition *partition) ++{ ++ basic_block *bbs = get_loop_body_in_custom_order (loop, this, ++ bb_top_order_cmp_r); ++ for (int i = 0; i < int (loop->num_nodes); i++) ++ { ++ basic_block bb = bbs[i]; ++ for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); ++ gsi_next (&gsi)) ++ { ++ unsigned j = gimple_uid (gsi_stmt (gsi)); ++ if (bitmap_bit_p (producers, j)) ++ reset_gimple_assign (flow_only_rdg, partition, gsi, j); ++ } ++ } ++ update_ssa (TODO_update_ssa); ++ free (bbs); ++} ++ ++/* Insert temp arrays if isomorphic computation exists. Temp arrays will be ++ regarded as SEED_STMTS for building partitions in succeeding processes. */ ++ ++bool ++loop_distribution::insert_temp_arrays (loop_p loop, vec<gimple *> seed_stmts, ++ hash_set<tree> *tmp_array_vars, bitmap producers) ++{ ++ struct graph *flow_only_rdg = build_rdg (loop, NULL); ++ gcc_checking_assert (flow_only_rdg != NULL); ++ tree iv = get_iv_from_seed (flow_only_rdg, seed_stmts); ++ if (iv == NULL) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "Loop %d no temp array insertion: failed to get" ++ " iteration variable.\n", loop->num); ++ free_rdg (flow_only_rdg); ++ return false; ++ } ++ auto_bitmap cut_points; ++ loop_vec_info vinfo = loop_vec_info_for_loop (loop); ++ unsigned n_cut_points = get_cut_points (flow_only_rdg, cut_points, vinfo); ++ delete vinfo; ++ loop->aux = NULL; ++ if (n_cut_points == 0) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "Loop %d no temp array insertion: no cut points" ++ " found.\n", loop->num); ++ free_rdg (flow_only_rdg); ++ return false; ++ } ++ do_insertion (loop, flow_only_rdg, iv, cut_points, tmp_array_vars, producers); ++ if (dump_enabled_p ()) ++ { ++ dump_user_location_t loc = find_loop_location (loop); ++ dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, "Insertion done:" ++ " %d temp arrays inserted in Loop %d.\n", ++ n_cut_points, loop->num); ++ } ++ free_rdg (flow_only_rdg); ++ return true; ++} ++ ++static bool find_seed_stmts_for_distribution (class loop *, vec<gimple *> *); ++ + /* Distributes the code from LOOP in such a way that producer statements + are placed before consumer statements. Tries to separate only the + statements from STMTS into separate loops. Returns the number of +@@ -3814,6 +4311,34 @@ loop_distribution::distribute_loop (class loop *loop, vec<gimple *> stmts, + return 0; + } + ++ /* Try to distribute LOOP if LOOP is simple enough and unable to vectorize. ++ If LOOP has grouped loads, recursively find isomorphic stmts and insert ++ temp arrays, rebuild RDG and call find_seed_stmts_for_distribution ++ to replace STMTS. */ ++ ++ hash_set<tree> tmp_array_vars; ++ ++ /* STMTs that define those inserted TMP_ARRAYs. */ ++ auto_bitmap producers; ++ ++ /* New SEED_STMTS after insertion. */ ++ auto_vec<gimple *> work_list; ++ bool insert_success = false; ++ if (may_insert_temp_arrays (loop, rdg, cd)) ++ { ++ if (insert_temp_arrays (loop, stmts, &tmp_array_vars, producers)) ++ { ++ if (find_seed_stmts_for_distribution (loop, &work_list)) ++ { ++ insert_success = true; ++ stmts = work_list; ++ } ++ else ++ remove_insertion (loop, rdg, producers, NULL); ++ rebuild_rdg (loop, rdg, cd); ++ } ++ } ++ + data_reference_p dref; + for (i = 0; datarefs_vec.iterate (i, &dref); ++i) + dref->aux = (void *) (uintptr_t) i; +@@ -3894,7 +4419,7 @@ loop_distribution::distribute_loop (class loop *loop, vec<gimple *> stmts, + for (int j = i + 1; + partitions.iterate (j, &partition); ++j) + { +- if (share_memory_accesses (rdg, into, partition)) ++ if (share_memory_accesses (rdg, into, partition, &tmp_array_vars)) + { + partition_merge_into (rdg, into, partition, FUSE_SHARE_REF); + partitions.unordered_remove (j); +@@ -3944,7 +4469,7 @@ loop_distribution::distribute_loop (class loop *loop, vec<gimple *> stmts, + } + } + +- finalize_partitions (loop, &partitions, &alias_ddrs); ++ finalize_partitions (loop, &partitions, &alias_ddrs, producers); + + /* If there is a reduction in all partitions make sure the last one + is not classified for builtin code generation. */ +@@ -3962,6 +4487,24 @@ loop_distribution::distribute_loop (class loop *loop, vec<gimple *> stmts, + } + + nbp = partitions.length (); ++ ++ /* If we have inserted TMP_ARRAYs but there is only one partition left in ++ the succeeding processes, remove those inserted TMP_ARRAYs back to the ++ original version. */ ++ ++ if (nbp == 1 && insert_success) ++ { ++ struct partition *partition = NULL; ++ partitions.iterate (0, &partition); ++ remove_insertion (loop, rdg, producers, partition); ++ if (dump_enabled_p ()) ++ { ++ dump_user_location_t loc = find_loop_location (loop); ++ dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, "Insertion removed:" ++ " unable to distribute loop %d.\n", loop->num); ++ } ++ } ++ + if (nbp == 0 + || (nbp == 1 && !partition_builtin_p (partitions[0])) + || (nbp > 1 && partition_contains_all_rw (rdg, partitions))) +-- +2.27.0.windows.1 + diff --git a/0082-Revert-Backport-tree-optimization-102880-make-PHI-OP.patch b/0082-Revert-Backport-tree-optimization-102880-make-PHI-OP.patch new file mode 100644 index 0000000..3642252 --- /dev/null +++ b/0082-Revert-Backport-tree-optimization-102880-make-PHI-OP.patch @@ -0,0 +1,206 @@ +From 717782ec36469eb81650b07e8b5536281a59993d Mon Sep 17 00:00:00 2001 +From: zhongyunde <zhongyunde@huawei.com> +Date: Tue, 29 Nov 2022 22:12:29 +0800 +Subject: [PATCH 34/35] Revert "[Backport] tree-optimization/102880 - make + PHI-OPT recognize more CFGs" + +This reverts commit 77398954ce517aa011b7a254c7aa2858521b2093. +--- + gcc/testsuite/gcc.dg/tree-ssa/phi-opt-26.c | 31 --------- + gcc/tree-ssa-phiopt.c | 73 +++++++++------------- + 2 files changed, 29 insertions(+), 75 deletions(-) + delete mode 100644 gcc/testsuite/gcc.dg/tree-ssa/phi-opt-26.c + +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-26.c b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-26.c +deleted file mode 100644 +index 21aa66e38..000000000 +--- a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-26.c ++++ /dev/null +@@ -1,31 +0,0 @@ +-/* { dg-do compile } */ +-/* { dg-options "-O -fgimple -fdump-tree-phiopt1" } */ +- +-int __GIMPLE (ssa,startwith("phiopt")) +-foo (int a, int b, int flag) +-{ +- int res; +- +- __BB(2): +- if (flag_2(D) != 0) +- goto __BB6; +- else +- goto __BB4; +- +- __BB(4): +- if (a_3(D) > b_4(D)) +- goto __BB7; +- else +- goto __BB6; +- +- __BB(6): +- goto __BB7; +- +- __BB(7): +- res_1 = __PHI (__BB4: a_3(D), __BB6: b_4(D)); +- return res_1; +-} +- +-/* We should be able to detect MAX despite the extra edge into +- the middle BB. */ +-/* { dg-final { scan-tree-dump "MAX" "phiopt1" } } */ +diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c +index 079d29e74..21ac08145 100644 +--- a/gcc/tree-ssa-phiopt.c ++++ b/gcc/tree-ssa-phiopt.c +@@ -219,6 +219,7 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) + + /* If either bb1's succ or bb2 or bb2's succ is non NULL. */ + if (EDGE_COUNT (bb1->succs) == 0 ++ || bb2 == NULL + || EDGE_COUNT (bb2->succs) == 0) + continue; + +@@ -278,14 +279,14 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) + || (e1->flags & EDGE_FALLTHRU) == 0) + continue; + ++ /* Also make sure that bb1 only have one predecessor and that it ++ is bb. */ ++ if (!single_pred_p (bb1) ++ || single_pred (bb1) != bb) ++ continue; ++ + if (do_store_elim) + { +- /* Also make sure that bb1 only have one predecessor and that it +- is bb. */ +- if (!single_pred_p (bb1) +- || single_pred (bb1) != bb) +- continue; +- + /* bb1 is the middle block, bb2 the join block, bb the split block, + e1 the fallthrough edge from bb1 to bb2. We can't do the + optimization if the join block has more than two predecessors. */ +@@ -330,11 +331,10 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) + node. */ + gcc_assert (arg0 != NULL_TREE && arg1 != NULL_TREE); + +- gphi *newphi; +- if (single_pred_p (bb1) +- && (newphi = factor_out_conditional_conversion (e1, e2, phi, +- arg0, arg1, +- cond_stmt))) ++ gphi *newphi = factor_out_conditional_conversion (e1, e2, phi, ++ arg0, arg1, ++ cond_stmt); ++ if (newphi != NULL) + { + phi = newphi; + /* factor_out_conditional_conversion may create a new PHI in +@@ -355,14 +355,12 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) + else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) + cfgchanged = true; + else if (!early_p +- && single_pred_p (bb1) + && cond_removal_in_builtin_zero_pattern (bb, bb1, e1, e2, + phi, arg0, arg1)) + cfgchanged = true; + else if (minmax_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) + cfgchanged = true; +- else if (single_pred_p (bb1) +- && spaceship_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) ++ else if (spaceship_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) + cfgchanged = true; + } + } +@@ -393,41 +391,35 @@ replace_phi_edge_with_variable (basic_block cond_block, + edge e, gphi *phi, tree new_tree) + { + basic_block bb = gimple_bb (phi); ++ basic_block block_to_remove; + gimple_stmt_iterator gsi; + + /* Change the PHI argument to new. */ + SET_USE (PHI_ARG_DEF_PTR (phi, e->dest_idx), new_tree); + + /* Remove the empty basic block. */ +- edge edge_to_remove; + if (EDGE_SUCC (cond_block, 0)->dest == bb) +- edge_to_remove = EDGE_SUCC (cond_block, 1); +- else +- edge_to_remove = EDGE_SUCC (cond_block, 0); +- if (EDGE_COUNT (edge_to_remove->dest->preds) == 1) + { +- e->flags |= EDGE_FALLTHRU; +- e->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE); +- e->probability = profile_probability::always (); +- delete_basic_block (edge_to_remove->dest); +- +- /* Eliminate the COND_EXPR at the end of COND_BLOCK. */ +- gsi = gsi_last_bb (cond_block); +- gsi_remove (&gsi, true); ++ EDGE_SUCC (cond_block, 0)->flags |= EDGE_FALLTHRU; ++ EDGE_SUCC (cond_block, 0)->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE); ++ EDGE_SUCC (cond_block, 0)->probability = profile_probability::always (); ++ ++ block_to_remove = EDGE_SUCC (cond_block, 1)->dest; + } + else + { +- /* If there are other edges into the middle block make +- CFG cleanup deal with the edge removal to avoid +- updating dominators here in a non-trivial way. */ +- gcond *cond = as_a <gcond *> (last_stmt (cond_block)); +- if (edge_to_remove->flags & EDGE_TRUE_VALUE) +- gimple_cond_make_false (cond); +- else +- gimple_cond_make_true (cond); ++ EDGE_SUCC (cond_block, 1)->flags |= EDGE_FALLTHRU; ++ EDGE_SUCC (cond_block, 1)->flags ++ &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE); ++ EDGE_SUCC (cond_block, 1)->probability = profile_probability::always (); ++ ++ block_to_remove = EDGE_SUCC (cond_block, 0)->dest; + } ++ delete_basic_block (block_to_remove); + +- statistics_counter_event (cfun, "Replace PHI with variable", 1); ++ /* Eliminate the COND_EXPR at the end of COND_BLOCK. */ ++ gsi = gsi_last_bb (cond_block); ++ gsi_remove (&gsi, true); + + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, +@@ -854,9 +846,6 @@ match_simplify_replacement (basic_block cond_bb, basic_block middle_bb, + allow it and move it once the transformation is done. */ + if (!empty_block_p (middle_bb)) + { +- if (!single_pred_p (middle_bb)) +- return false; +- + stmt_to_move = last_and_only_stmt (middle_bb); + if (!stmt_to_move) + return false; +@@ -1236,11 +1225,6 @@ value_replacement (basic_block cond_bb, basic_block middle_bb, + } + else + { +- if (!single_pred_p (middle_bb)) +- return 0; +- statistics_counter_event (cfun, "Replace PHI with " +- "variable/value_replacement", 1); +- + /* Replace the PHI arguments with arg. */ + SET_PHI_ARG_DEF (phi, e0->dest_idx, arg); + SET_PHI_ARG_DEF (phi, e1->dest_idx, arg); +@@ -1255,6 +1239,7 @@ value_replacement (basic_block cond_bb, basic_block middle_bb, + } + return 1; + } ++ + } + + /* Now optimize (x != 0) ? x + y : y to just x + y. */ +-- +2.27.0.windows.1 + diff --git a/0083-Struct-reorg-Add-struct-semi-relayout-optimize.patch b/0083-Struct-reorg-Add-struct-semi-relayout-optimize.patch new file mode 100644 index 0000000..05581a4 --- /dev/null +++ b/0083-Struct-reorg-Add-struct-semi-relayout-optimize.patch @@ -0,0 +1,1297 @@ +From cebf7903906d0b530fce240b601591d6254ee53f Mon Sep 17 00:00:00 2001 +From: benniaobufeijiushiji <linda7@huawei.com> +Date: Wed, 30 Nov 2022 22:42:35 +0800 +Subject: [PATCH 35/35] [Struct reorg] Add struct-semi-relayout optimize + +Add support for structs with multi-allocation which is escaped in +complete-relayout. +Add flag -fipa-struct-reorg=6 and parameter semi-relayout-level. +--- + gcc/common.opt | 7 +- + gcc/ipa-struct-reorg/ipa-struct-reorg.c | 916 +++++++++++++++++- + gcc/ipa-struct-reorg/ipa-struct-reorg.h | 8 + + gcc/params.opt | 4 + + .../gcc.dg/struct/semi_relayout_rewrite.c | 86 ++ + gcc/testsuite/gcc.dg/struct/struct-reorg.exp | 4 + + 6 files changed, 992 insertions(+), 33 deletions(-) + create mode 100644 gcc/testsuite/gcc.dg/struct/semi_relayout_rewrite.c + +diff --git a/gcc/common.opt b/gcc/common.opt +index 384595f16..588e19400 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -1889,9 +1889,10 @@ Common Report Var(flag_ipa_struct_reorg) Init(0) Optimization + Perform structure layout optimizations. + + fipa-struct-reorg= +-Common RejectNegative Joined UInteger Var(struct_layout_optimize_level) Init(0) IntegerRange(0, 5) +--fipa-struct-reorg=[0,1,2,3,4,5] adding none, struct-reorg, reorder-fields, +-dfe, safe-pointer-compression, unsafe-pointer-compression optimizations. ++Common RejectNegative Joined UInteger Var(struct_layout_optimize_level) Init(0) IntegerRange(0, 6) ++-fipa-struct-reorg=[0,1,2,3,4,5,6] adding none, struct-reorg, reorder-fields, ++dfe, safe-pointer-compression, unsafe-pointer-compression, semi-relayout ++optimizations. + + fipa-extend-auto-profile + Common Report Var(flag_ipa_extend_auto_profile) +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +index ee4893dfb..4751711fe 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -265,7 +265,8 @@ enum struct_layout_opt_level + STRUCT_REORDER_FIELDS = 1 << 2, + DEAD_FIELD_ELIMINATION = 1 << 3, + POINTER_COMPRESSION_SAFE = 1 << 4, +- POINTER_COMPRESSION_UNSAFE = 1 << 5 ++ POINTER_COMPRESSION_UNSAFE = 1 << 5, ++ SEMI_RELAYOUT = 1 << 6 + }; + + /* Defines the target pointer size of compressed pointer, which should be 8, +@@ -280,6 +281,7 @@ void get_base (tree &base, tree expr); + static unsigned int current_layout_opt_level; + + hash_map<tree, tree> replace_type_map; ++hash_map<tree, tree> semi_relayout_map; + + /* Return true if one of these types is created by struct-reorg. */ + +@@ -398,7 +400,9 @@ srtype::srtype (tree type) + visited (false), + pc_candidate (false), + has_legal_alloc_num (false), +- has_alloc_array (0) ++ has_alloc_array (0), ++ semi_relayout (false), ++ bucket_parts (0) + { + for (int i = 0; i < max_split; i++) + newtype[i] = NULL_TREE; +@@ -883,6 +887,66 @@ srfield::create_new_optimized_fields (tree newtype[max_split], + newfield[0] = field; + } + ++/* Given a struct s whose fields has already reordered by size, we try to ++ combine fields less than 8 bytes together to 8 bytes. Example: ++ struct s { ++ uint64_t a, ++ uint32_t b, ++ uint32_t c, ++ uint32_t d, ++ uint16_t e, ++ uint8_t f ++ } ++ ++ We allocate memory for arrays of struct S, before semi-relayout, their ++ layout in memory is shown as below: ++ [a,b,c,d,e,f,padding;a,b,c,d,e,f,padding;...] ++ ++ During semi-relayout, we put a number of structs into a same region called ++ bucket. The number is determined by param realyout-bucket-capacity-level. ++ Using 1024 here as example. After semi-relayout, the layout in a bucket is ++ shown as below: ++ part1 [a;a;a...] ++ part2 [b,c;b,c;b,c;...] ++ part3 [d,e,f,pad;d,e,f,pad;d,e,f,pad;...] ++ ++ In the last bucket, if the amount of rest structs is less than the capacity ++ of a bucket, the rest of allcated memory will be wasted as padding. */ ++ ++unsigned ++srtype::calculate_bucket_size () ++{ ++ unsigned parts = 0; ++ unsigned bit_sum = 0; ++ unsigned relayout_offset = 0; ++ /* Currently, limit each 8 bytes with less than 2 fields. */ ++ unsigned curr_part_num = 0; ++ unsigned field_num = 0; ++ for (tree f = TYPE_FIELDS (newtype[0]); f; f = DECL_CHAIN (f)) ++ { ++ unsigned size = TYPE_PRECISION (TREE_TYPE (f)); ++ bit_sum += size; ++ field_num++; ++ if (++curr_part_num > 2 || bit_sum > 64) ++ { ++ bit_sum = size; ++ parts++; ++ relayout_offset = relayout_part_size * parts; ++ curr_part_num = 1; ++ } ++ else ++ { ++ relayout_offset = relayout_part_size * parts + (bit_sum - size) / 8; ++ } ++ new_field_offsets.put (f, relayout_offset); ++ } ++ /* Donnot relayout a struct with only one field after DFE. */ ++ if (field_num == 1) ++ return 0; ++ bucket_parts = ++parts; ++ return parts * relayout_part_size; ++} ++ + /* Create the new TYPE corresponding to THIS type. */ + + bool +@@ -994,6 +1058,15 @@ srtype::create_new_type (void) + if (pc_candidate && pc_gptr == NULL_TREE) + create_global_ptr_for_pc (); + ++ if (semi_relayout) ++ { ++ bucket_size = calculate_bucket_size (); ++ if (bucket_size == 0) ++ return false; ++ if (semi_relayout_map.get (this->newtype[0]) == NULL) ++ semi_relayout_map.put (this->newtype[0], this->type); ++ } ++ + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Created %d types:\n", maxclusters); +@@ -1393,7 +1466,7 @@ public: + bool should_create = false, bool can_escape = false); + bool wholeaccess (tree expr, tree base, tree accesstype, srtype *t); + +- void check_alloc_num (gimple *stmt, srtype *type); ++ void check_alloc_num (gimple *stmt, srtype *type, bool ptrptr); + void check_definition_assign (srdecl *decl, vec<srdecl*> &worklist); + void check_definition_call (srdecl *decl, vec<srdecl*> &worklist); + void check_definition (srdecl *decl, vec<srdecl*>&); +@@ -1440,6 +1513,33 @@ public: + tree &); + basic_block create_bb_for_compress_nullptr (basic_block, tree &); + basic_block create_bb_for_decompress_nullptr (basic_block, tree, tree &); ++ ++ // Semi-relayout methods: ++ bool is_semi_relayout_candidate (tree); ++ srtype *get_semi_relayout_candidate_type (tree); ++ void check_and_prune_struct_for_semi_relayout (void); ++ tree rewrite_pointer_diff (gimple_stmt_iterator *, tree, tree, srtype *); ++ tree rewrite_pointer_plus_integer (gimple *, gimple_stmt_iterator *, tree, ++ tree, srtype *); ++ tree build_div_expr (gimple_stmt_iterator *, tree, tree); ++ tree get_true_pointer_base (gimple_stmt_iterator *, tree, srtype *); ++ tree get_real_allocated_ptr (tree, gimple_stmt_iterator *); ++ tree set_ptr_for_use (tree, gimple_stmt_iterator *); ++ void record_allocated_size (tree, gimple_stmt_iterator *, tree); ++ tree read_allocated_size (tree, gimple_stmt_iterator *); ++ gimple *create_aligned_alloc (gimple_stmt_iterator *, srtype *, tree, ++ tree &); ++ void create_memset_zero (tree, gimple_stmt_iterator *, tree); ++ void create_memcpy (tree, tree, tree, gimple_stmt_iterator *); ++ void create_free (tree, gimple_stmt_iterator *); ++ void copy_to_lhs (tree, tree, gimple_stmt_iterator *); ++ srtype *get_relayout_candidate_type (tree); ++ long unsigned int get_true_field_offset (srfield *, srtype *); ++ tree rewrite_address (tree, srfield *, srtype *, gimple_stmt_iterator *); ++ bool check_sr_copy (gimple *); ++ void relayout_field_copy (gimple_stmt_iterator *, gimple *, tree, tree, ++ tree&, tree &); ++ void do_semi_relayout (gimple_stmt_iterator *, gimple *, tree &, tree &); + }; + + struct ipa_struct_relayout +@@ -4528,7 +4628,7 @@ ipa_struct_reorg::check_type_and_push (tree newdecl, srdecl *decl, + } + + void +-ipa_struct_reorg::check_alloc_num (gimple *stmt, srtype *type) ++ipa_struct_reorg::check_alloc_num (gimple *stmt, srtype *type, bool ptrptr) + { + if (current_layout_opt_level >= COMPLETE_STRUCT_RELAYOUT + && handled_allocation_stmt (stmt)) +@@ -4536,6 +4636,14 @@ ipa_struct_reorg::check_alloc_num (gimple *stmt, srtype *type) + tree arg0 = gimple_call_arg (stmt, 0); + basic_block bb = gimple_bb (stmt); + cgraph_node *node = current_function->node; ++ if (!ptrptr && current_layout_opt_level >= SEMI_RELAYOUT ++ && gimple_call_builtin_p (stmt, BUILT_IN_MALLOC)) ++ { ++ /* Malloc is commonly used for allocations of a single struct ++ and semi-relayout will waste a mess of memory, so we skip it. */ ++ type->has_alloc_array = -4; ++ return; ++ } + if (integer_onep (arg0)) + { + /* Actually NOT an array, but may ruin other array. */ +@@ -4544,6 +4652,10 @@ ipa_struct_reorg::check_alloc_num (gimple *stmt, srtype *type) + else if (bb->loop_father != NULL + && loop_outer (bb->loop_father) != NULL) + { ++ /* For semi-relayout, do not escape realloc. */ ++ if (current_layout_opt_level & SEMI_RELAYOUT ++ && gimple_call_builtin_p (stmt, BUILT_IN_REALLOC)) ++ return; + /* The allocation is in a loop. */ + type->has_alloc_array = -2; + } +@@ -4635,6 +4747,13 @@ ipa_struct_reorg::check_definition_assign (srdecl *decl, vec<srdecl*> &worklist) + return; + } + ++ if (semi_relayout_map.get (type->type) != NULL) ++ { ++ if (current_layout_opt_level != COMPLETE_STRUCT_RELAYOUT) ++ type->mark_escape (escape_unhandled_rewrite, stmt); ++ return; ++ } ++ + /* d) if the name is from a cast/assignment, make sure it is used as + that type or void* + i) If void* then push the ssa_name into worklist. */ +@@ -4679,7 +4798,8 @@ ipa_struct_reorg::check_definition_call (srdecl *decl, vec<srdecl*> &worklist) + } + } + +- check_alloc_num (stmt, type); ++ bool ptrptr = isptrptr (decl->orig_type); ++ check_alloc_num (stmt, type, ptrptr); + return; + } + +@@ -6249,6 +6369,53 @@ ipa_struct_reorg::pc_candidate_tree_p (tree xhs) + return false; + } + ++srtype * ++ipa_struct_reorg::get_semi_relayout_candidate_type (tree xhs) ++{ ++ if (xhs == NULL) ++ return NULL; ++ if (TREE_CODE (xhs) == SSA_NAME || TREE_CODE (xhs) == COMPONENT_REF) ++ { ++ srtype *access_type = find_type (inner_type (TREE_TYPE (xhs))); ++ if (access_type != NULL && access_type->semi_relayout) ++ return access_type; ++ } ++ return NULL; ++} ++ ++bool ++ipa_struct_reorg::is_semi_relayout_candidate (tree xhs) ++{ ++ if (xhs == NULL) ++ return false; ++ ++ if (TREE_CODE (xhs) == SSA_NAME) ++ xhs = TREE_TYPE (xhs); ++ ++ if (TREE_CODE (xhs) == POINTER_TYPE) ++ { ++ srtype *var_type = find_type (TREE_TYPE (xhs)); ++ if (!var_type || var_type->has_escaped ()) ++ return false; ++ if (var_type->semi_relayout) ++ return true; ++ } ++ ++ if (TREE_CODE (xhs) == COMPONENT_REF) ++ { ++ tree mem = TREE_OPERAND (xhs, 0); ++ if (TREE_CODE (mem) == MEM_REF) ++ { ++ tree type = TREE_TYPE (mem); ++ srtype *old_type = get_relayout_candidate_type (type); ++ if (types_compatible_p (type, old_type->type) ++ && old_type->semi_relayout) ++ return true; ++ } ++ } ++ return false; ++} ++ + /* True if xhs is a component_ref that base has escaped but uses a compression + candidate type. */ + +@@ -6782,6 +6949,404 @@ ipa_struct_reorg::try_rewrite_with_pointer_compression (gassign *stmt, + } + } + ++tree ++ipa_struct_reorg::rewrite_pointer_diff (gimple_stmt_iterator *gsi, tree ptr1, ++ tree ptr2, srtype *type) ++{ ++ tree shifts = build_int_cst (long_integer_type_node, semi_relayout_align); ++ tree pointer_type = build_pointer_type (unsigned_char_type_node); ++ /* addr_high_1 = (intptr_t)ptr1 >> shifts */ ++ tree ptr1_cvt = fold_convert (pointer_type, ptr1); ++ tree addr_high_1 = gimplify_build2 (gsi, RSHIFT_EXPR, pointer_type, ++ ptr1_cvt, shifts); ++ /* addr_high_2 = (intptr_t)ptr2 >> shifts */ ++ tree ptr2_cvt = fold_convert (pointer_type, ptr2); ++ tree addr_high_2 = gimplify_build2 (gsi, RSHIFT_EXPR, pointer_type, ++ ptr2_cvt, shifts); ++ /* off1 = (intptr_t)ptr1 - (addr_high_1 << shifts) */ ++ tree bucket_start_1 = gimplify_build2 (gsi, LSHIFT_EXPR, pointer_type, ++ addr_high_1, shifts); ++ tree off1 = gimplify_build2 (gsi, MINUS_EXPR, long_integer_type_node, ++ ptr1_cvt, bucket_start_1); ++ /* off2 = (intptr_t)ptr2 - (addr_high_2 << shifts) */ ++ tree bucket_start_2 = gimplify_build2 (gsi, LSHIFT_EXPR, pointer_type, ++ addr_high_2, shifts); ++ tree off2 = gimplify_build2 (gsi, MINUS_EXPR, long_integer_type_node, ++ ptr2_cvt, bucket_start_2); ++ /* group_diff = (addr_high_1 - addr_high_2) / bucket_parts */ ++ tree bucket_sub = gimplify_build2 (gsi, MINUS_EXPR, long_integer_type_node, ++ addr_high_1, addr_high_2); ++ tree bucket_parts = build_int_cst (long_integer_type_node, ++ type->bucket_parts); ++ tree group_diff = gimplify_build2 (gsi, TRUNC_DIV_EXPR, ++ long_integer_type_node, ++ bucket_sub, bucket_parts); ++ /* off_addr_diff = off1 - off2 */ ++ tree off_addr_diff = gimplify_build2 (gsi, MINUS_EXPR, long_integer_type_node, ++ off1, off2); ++ /* res = group_diff * bucket_capacity + off_diff / 8 */ ++ tree capacity = build_int_cst (long_integer_type_node, ++ relayout_part_size / 8); ++ tree unit_size = build_int_cst (long_integer_type_node, 8); ++ tree bucket_index_diff = gimplify_build2 (gsi, MULT_EXPR, ++ long_integer_type_node, ++ group_diff, capacity); ++ tree off_index = gimplify_build2 (gsi, TRUNC_DIV_EXPR, ++ long_integer_type_node, ++ off_addr_diff, unit_size); ++ tree res = gimplify_build2 (gsi, PLUS_EXPR, long_unsigned_type_node, ++ bucket_index_diff, off_index); ++ return res; ++} ++ ++basic_block ++create_bb_for_group_diff_eq_0 (basic_block last_bb, tree phi, tree new_granule) ++{ ++ basic_block new_bb = create_empty_bb (last_bb); ++ if (last_bb->loop_father != NULL) ++ { ++ add_bb_to_loop (new_bb, last_bb->loop_father); ++ loops_state_set (LOOPS_NEED_FIXUP); ++ } ++ /* Emit res = new_granule; */ ++ gimple_stmt_iterator gsi = gsi_last_bb (new_bb); ++ gimple *new_stmt = gimple_build_assign (phi, new_granule); ++ gsi_insert_after (&gsi, new_stmt, GSI_NEW_STMT); ++ return new_bb; ++} ++ ++basic_block ++create_bb_for_group_diff_ne_0 (basic_block new_bb, tree &phi, tree ptr, ++ tree group_diff, tree off_times_8, srtype *type) ++{ ++ tree shifts = build_int_cst (long_unsigned_type_node, semi_relayout_align); ++ gimple_stmt_iterator gsi = gsi_last_bb (new_bb); ++ gsi_insert_after (&gsi, gimple_build_nop (), GSI_NEW_STMT); ++ /* curr_group_start = (ptr >> shifts) << shifts; */ ++ tree ptr_r_1 = gimplify_build2 (&gsi, RSHIFT_EXPR, long_integer_type_node, ++ ptr, shifts); ++ tree curr_group_start = gimplify_build2 (&gsi, LSHIFT_EXPR, long_integer_type_node, ++ ptr_r_1, shifts); ++ /* curr_off_from_group = ptr - curr_group_start; */ ++ tree curr_off_from_group = gimplify_build2 (&gsi, MINUS_EXPR, ++ long_integer_type_node, ++ ptr, curr_group_start); ++ /* res = curr_group_start + ((group_diff * parts) << shifts) ++ + ((curr_off_from_group + off_times_8) % shifts); */ ++ tree step1 = gimplify_build2 (&gsi, MULT_EXPR, long_integer_type_node, ++ group_diff, build_int_cst ( ++ long_integer_type_node, type->bucket_parts)); ++ tree step2 = gimplify_build2 (&gsi, LSHIFT_EXPR, long_integer_type_node, ++ step1, shifts); ++ tree step3 = gimplify_build2 (&gsi, PLUS_EXPR, long_integer_type_node, ++ curr_off_from_group, off_times_8); ++ tree step4 = gimplify_build2 (&gsi, TRUNC_MOD_EXPR, long_integer_type_node, ++ step3, build_int_cst ( ++ long_integer_type_node, relayout_part_size)); ++ tree step5 = gimplify_build2 (&gsi, PLUS_EXPR, long_integer_type_node, ++ step2, step4); ++ tree res_phi1 = gimplify_build2 (&gsi, PLUS_EXPR, long_integer_type_node, ++ curr_group_start, step5); ++ /* if (group_diff < 0) */ ++ gcond *cond = gimple_build_cond (LT_EXPR, group_diff, ++ build_int_cst (long_integer_type_node, 0), ++ NULL_TREE, NULL_TREE); ++ gsi_insert_before (&gsi, cond, GSI_SAME_STMT); ++ /* remove nop */ ++ gsi_remove (&gsi, true); ++ /* res += shifts */ ++ basic_block true_bb = create_empty_bb (new_bb); ++ if (new_bb->loop_father != NULL) ++ { ++ add_bb_to_loop (true_bb, new_bb->loop_father); ++ loops_state_set (LOOPS_NEED_FIXUP); ++ } ++ gimple_stmt_iterator true_gsi = gsi_last_bb (true_bb); ++ tree res_phi2 = make_ssa_name (long_integer_type_node); ++ gimple *new_stmt ++ = gimple_build_assign (res_phi2, PLUS_EXPR, res_phi1, ++ build_int_cst (long_integer_type_node, relayout_part_size)); ++ gsi_insert_after (&true_gsi, new_stmt, GSI_NEW_STMT); ++ /* create phi bb */ ++ basic_block res_bb = create_empty_bb (true_bb); ++ if (new_bb->loop_father != NULL) ++ { ++ add_bb_to_loop (res_bb, new_bb->loop_father); ++ loops_state_set (LOOPS_NEED_FIXUP); ++ } ++ /* rebuild cfg */ ++ edge etrue = make_edge (new_bb, true_bb, EDGE_TRUE_VALUE); ++ etrue->probability = profile_probability::unlikely (); ++ true_bb->count = etrue->count (); ++ ++ edge efalse = make_edge (new_bb, res_bb, EDGE_FALSE_VALUE); ++ efalse->probability = profile_probability::likely (); ++ res_bb->count = efalse->count (); ++ ++ edge efall = make_single_succ_edge (true_bb, res_bb, EDGE_FALLTHRU); ++ ++ phi = make_ssa_name (long_integer_type_node); ++ gphi *phi_node = create_phi_node (phi, res_bb); ++ add_phi_arg (phi_node, res_phi2, efall, UNKNOWN_LOCATION); ++ add_phi_arg (phi_node, res_phi1, efalse, UNKNOWN_LOCATION); ++ ++ if (dom_info_available_p (CDI_DOMINATORS)) ++ { ++ set_immediate_dominator (CDI_DOMINATORS, true_bb, new_bb); ++ set_immediate_dominator (CDI_DOMINATORS, res_bb, new_bb); ++ } ++ return res_bb; ++} ++ ++tree ++ipa_struct_reorg::rewrite_pointer_plus_integer (gimple *stmt, ++ gimple_stmt_iterator *gsi, ++ tree ptr, tree offset, ++ srtype *type) ++{ ++ gcc_assert (type->semi_relayout); ++ tree off = fold_convert (long_integer_type_node, offset); ++ tree num_8 = build_int_cst (integer_type_node, 8); ++ tree shifts = build_int_cst (integer_type_node, semi_relayout_align); ++ /* off_times_8 = off * 8; */ ++ tree off_times_8 = gimplify_build2 (gsi, MULT_EXPR, long_integer_type_node, ++ off, num_8); ++ /* new_granule = ptr + off * 8; */ ++ tree ptr_int = fold_convert (long_integer_type_node, ptr); ++ tree new_granule = gimplify_build2 (gsi, PLUS_EXPR, long_integer_type_node, ++ ptr_int, off_times_8); ++ /* group_diff = (new_granule >> shifts) - (ptr >> shifts); */ ++ tree group_diff_rhs_1 = gimplify_build2 (gsi, RSHIFT_EXPR, ++ long_integer_type_node, ++ new_granule, shifts); ++ tree group_diff_rhs_2 = gimplify_build2 (gsi, RSHIFT_EXPR, ++ long_integer_type_node, ++ ptr, shifts); ++ tree group_diff = gimplify_build2 (gsi, MINUS_EXPR, long_integer_type_node, ++ group_diff_rhs_1, group_diff_rhs_2); ++ /* if (group_diff == 0) */ ++ gcond *cond = gimple_build_cond (EQ_EXPR, group_diff, ++ build_int_cst (long_integer_type_node, 0), ++ NULL_TREE, NULL_TREE); ++ gimple_set_location (cond, UNKNOWN_LOCATION); ++ gsi_insert_before (gsi, cond, GSI_SAME_STMT); ++ ++ gimple *curr_stmt = as_a <gimple *> (cond); ++ edge e = split_block (curr_stmt->bb, curr_stmt); ++ basic_block split_src_bb = e->src; ++ basic_block split_dst_bb = e->dest; ++ remove_edge_raw (e); ++ /* if (group_diff == 0) ++ res = new_granule; */ ++ tree res_phi_1 = make_ssa_name (long_integer_type_node); ++ basic_block true_bb = create_bb_for_group_diff_eq_0 (split_src_bb, res_phi_1, ++ new_granule); ++ /* else */ ++ tree res_phi_2 = NULL_TREE; ++ basic_block false_bb = create_empty_bb (split_src_bb); ++ if (split_src_bb->loop_father != NULL) ++ { ++ add_bb_to_loop (false_bb, split_src_bb->loop_father); ++ loops_state_set (LOOPS_NEED_FIXUP); ++ } ++ ++ edge etrue = make_edge (split_src_bb, true_bb, EDGE_TRUE_VALUE); ++ etrue->probability = profile_probability::very_likely (); ++ true_bb->count = etrue->count (); ++ ++ edge efalse = make_edge (split_src_bb, false_bb, EDGE_FALSE_VALUE); ++ efalse->probability = profile_probability::unlikely (); ++ false_bb->count = efalse->count (); ++ basic_block res_bb = create_bb_for_group_diff_ne_0 (false_bb, res_phi_2, ++ ptr_int, group_diff, ++ off_times_8, type); ++ /* rebuild cfg */ ++ edge e_true_fall = make_single_succ_edge (true_bb, split_dst_bb, ++ EDGE_FALLTHRU); ++ edge e_false_fall = make_single_succ_edge (res_bb, split_dst_bb, ++ EDGE_FALLTHRU); ++ tree res_int = make_ssa_name (long_integer_type_node); ++ gphi *phi_node = create_phi_node (res_int, split_dst_bb); ++ add_phi_arg (phi_node, res_phi_1, e_true_fall, UNKNOWN_LOCATION); ++ add_phi_arg (phi_node, res_phi_2, e_false_fall, UNKNOWN_LOCATION); ++ if (dom_info_available_p (CDI_DOMINATORS)) ++ { ++ set_immediate_dominator (CDI_DOMINATORS, split_dst_bb, split_src_bb); ++ set_immediate_dominator (CDI_DOMINATORS, true_bb, split_src_bb); ++ set_immediate_dominator (CDI_DOMINATORS, false_bb, split_src_bb); ++ } ++ *gsi = gsi_start_bb (split_dst_bb); ++ tree pointer_type = build_pointer_type (unsigned_char_type_node); ++ tree res = gimplify_build1 (gsi, NOP_EXPR, pointer_type, res_int); ++ return res; ++} ++ ++tree ++ipa_struct_reorg::build_div_expr (gimple_stmt_iterator *gsi, ++ tree expr, tree orig_size) ++{ ++ tree div_expr = build2 (TRUNC_DIV_EXPR, long_unsigned_type_node, ++ expr, orig_size); ++ tree num = make_ssa_name (long_unsigned_type_node); ++ gimple *g = gimple_build_assign (num, div_expr); ++ gsi_insert_before (gsi, g, GSI_SAME_STMT); ++ return num; ++} ++ ++srtype * ++ipa_struct_reorg::get_relayout_candidate_type (tree type) ++{ ++ if (type == NULL) ++ return NULL; ++ if (TREE_CODE (type) != RECORD_TYPE) ++ return NULL; ++ return find_type (inner_type (type)); ++} ++ ++long unsigned int ++ipa_struct_reorg::get_true_field_offset (srfield *field, srtype *type) ++{ ++ unsigned HOST_WIDE_INT new_offset; ++ new_offset = *(type->new_field_offsets.get (field->newfield[0])); ++ return new_offset; ++} ++ ++tree ++ipa_struct_reorg::get_true_pointer_base (gimple_stmt_iterator *gsi, ++ tree mem_ref, srtype *type) ++{ ++ tree ptr = TREE_OPERAND (mem_ref, 0); ++ tree off_bytes = TREE_OPERAND (mem_ref, 1); ++ unsigned num = tree_to_shwi (off_bytes); ++ if (num == 0) ++ return ptr; ++ tree orig_size = TYPE_SIZE_UNIT (TREE_TYPE (mem_ref)); ++ tree off = build_int_cst (long_integer_type_node, ++ num / tree_to_uhwi (orig_size)); ++ gimple *stmt = gsi_stmt (*gsi); ++ tree new_pointer_base = rewrite_pointer_plus_integer (stmt, gsi, ptr, ++ off, type); ++ return new_pointer_base; ++} ++ ++tree ++ipa_struct_reorg::rewrite_address (tree pointer_base, srfield *field, ++ srtype *type, gimple_stmt_iterator *gsi) ++{ ++ unsigned HOST_WIDE_INT field_offset = get_true_field_offset (field, type); ++ ++ tree pointer_ssa = fold_convert (long_unsigned_type_node, pointer_base); ++ tree step1 = gimplify_build1 (gsi, NOP_EXPR, long_unsigned_type_node, ++ pointer_ssa); ++ tree new_offset_ssa = build_int_cst (long_unsigned_type_node, field_offset); ++ tree step2 = gimplify_build2 (gsi, PLUS_EXPR, long_unsigned_type_node, step1, ++ new_offset_ssa); ++ tree field_ssa = fold_convert ( ++ build_pointer_type (TREE_TYPE (field->newfield[0])), step2); ++ tree step3 = gimplify_build1 (gsi, NOP_EXPR, ++ TREE_TYPE (field_ssa), field_ssa); ++ ++ tree new_mem_ref = fold_build2 (MEM_REF, TREE_TYPE (field->newfield[0]), ++ step3, build_int_cst (TREE_TYPE (field_ssa), 0)); ++ return new_mem_ref; ++} ++ ++bool ++ipa_struct_reorg::check_sr_copy (gimple *stmt) ++{ ++ tree lhs = gimple_assign_lhs (stmt); ++ tree rhs = gimple_assign_rhs1 (stmt); ++ ++ if (TREE_CODE (lhs) != MEM_REF || TREE_CODE (rhs) != MEM_REF) ++ return false; ++ srtype *t1 = get_relayout_candidate_type (TREE_TYPE (lhs)); ++ srtype *t2 = get_relayout_candidate_type (TREE_TYPE (rhs)); ++ if (!t1 || !t2 || !t1->semi_relayout || !t2->semi_relayout || t1 != t2) ++ return false; ++ tree pointer1 = TREE_OPERAND (lhs, 0); ++ tree pointer2 = TREE_OPERAND (rhs, 0); ++ if (TREE_CODE (TREE_TYPE (pointer1)) != POINTER_TYPE ++ || TREE_CODE (TREE_TYPE (pointer2)) != POINTER_TYPE) ++ return false; ++ ++ tree type1 = TREE_TYPE (TREE_TYPE (pointer1)); ++ tree type2 = TREE_TYPE (TREE_TYPE (pointer2)); ++ ++ srtype *t3 = get_relayout_candidate_type (type1); ++ srtype *t4 = get_relayout_candidate_type (type2); ++ ++ if (t3 != t4 || t3 != t1) ++ return false; ++ ++ return true; ++} ++ ++void ++ipa_struct_reorg::relayout_field_copy (gimple_stmt_iterator *gsi, gimple *stmt, ++ tree lhs, tree rhs, ++ tree &newlhs, tree &newrhs) ++{ ++ srtype *type = get_relayout_candidate_type (TREE_TYPE (lhs)); ++ tree lhs_base_pointer = get_true_pointer_base (gsi, newlhs, type); ++ tree rhs_base_pointer = get_true_pointer_base (gsi, newrhs, type); ++ tree new_l_mem_ref = NULL_TREE; ++ tree new_r_mem_ref = NULL_TREE; ++ srfield *field = NULL; ++ unsigned i = 0; ++ FOR_EACH_VEC_ELT (type->fields, i, field) ++ { ++ if (!field->newfield[0]) ++ continue; ++ new_l_mem_ref = rewrite_address (lhs_base_pointer, field, type, gsi); ++ new_r_mem_ref = rewrite_address (rhs_base_pointer, field, type, gsi); ++ gimple *new_stmt = gimple_build_assign (new_l_mem_ref, new_r_mem_ref); ++ gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT); ++ } ++ newlhs = new_l_mem_ref; ++ newrhs = new_r_mem_ref; ++} ++ ++void ++ipa_struct_reorg::do_semi_relayout (gimple_stmt_iterator *gsi, gimple *stmt, ++ tree &newlhs, tree &newrhs) ++{ ++ tree lhs = gimple_assign_lhs (stmt); ++ tree rhs = gimple_assign_rhs1 (stmt); ++ ++ bool l = TREE_CODE (lhs) == COMPONENT_REF ? is_semi_relayout_candidate (lhs) ++ : false; ++ bool r = TREE_CODE (rhs) == COMPONENT_REF ? is_semi_relayout_candidate (rhs) ++ : false; ++ ++ gcc_assert (!(l && r)); ++ ++ if (!l && !r) ++ { ++ if (check_sr_copy (stmt)) ++ relayout_field_copy (gsi, stmt, lhs, rhs, newlhs, newrhs); ++ } ++ else if (l) ++ { ++ srtype *type = get_relayout_candidate_type ( ++ TREE_TYPE (TREE_OPERAND (lhs, 0))); ++ srfield *new_field = type->find_field ( ++ int_byte_position (TREE_OPERAND (lhs, 1))); ++ tree pointer_base = get_true_pointer_base ( ++ gsi, TREE_OPERAND (newlhs, 0), type); ++ newlhs = rewrite_address (pointer_base, new_field, type, gsi); ++ } ++ else if (r) ++ { ++ srtype *type = get_relayout_candidate_type ( ++ TREE_TYPE (TREE_OPERAND (rhs, 0))); ++ srfield *new_field = type->find_field ( ++ int_byte_position (TREE_OPERAND (rhs, 1))); ++ tree pointer_base = get_true_pointer_base ( ++ gsi, TREE_OPERAND (newrhs, 0), type); ++ newrhs = rewrite_address (pointer_base, new_field, type, gsi); ++ } ++} ++ + bool + ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + { +@@ -6876,7 +7441,8 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + tree size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (lhs))); + tree num; + /* Check if rhs2 is a multiplication of the size of the type. */ +- if (!is_result_of_mult (rhs2, &num, size)) ++ if (!is_result_of_mult (rhs2, &num, size) ++ && !(current_layout_opt_level & SEMI_RELAYOUT)) + internal_error ("the rhs of pointer was not a multiplicate and it slipped through."); + + /* Add the judgment of num, support for POINTER_DIFF_EXPR. +@@ -6898,11 +7464,34 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + tree newsize = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (newlhs[i]))); + newsize = gimplify_build2 (gsi, MULT_EXPR, sizetype, num, + newsize); ++ if (current_layout_opt_level >= SEMI_RELAYOUT) ++ { ++ if (is_semi_relayout_candidate (lhs)) ++ { ++ srtype *type = get_semi_relayout_candidate_type (lhs); ++ newrhs[i] = rewrite_pointer_plus_integer (stmt, gsi, ++ newrhs[i], num, type); ++ newsize = build_int_cst (long_unsigned_type_node, 0); ++ } ++ } + new_stmt = gimple_build_assign (newlhs[i], POINTER_PLUS_EXPR, + newrhs[i], newsize); + } + else + { ++ /* rhs2 is not a const integer */ ++ if (current_layout_opt_level >= SEMI_RELAYOUT) ++ { ++ if (is_semi_relayout_candidate (lhs)) ++ { ++ num = build_div_expr (gsi, rhs2, ++ build_int_cst (long_unsigned_type_node, 1)); ++ srtype *type = get_semi_relayout_candidate_type (lhs); ++ newrhs[i] = rewrite_pointer_plus_integer (stmt, ++ gsi, newrhs[i], num, type); ++ rhs2 = build_int_cst (long_unsigned_type_node, 0); ++ } ++ } + new_stmt = gimple_build_assign (newlhs[i], POINTER_PLUS_EXPR, + newrhs[i], rhs2); + } +@@ -6952,13 +7541,32 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + return false; + + /* The two operands always have pointer/reference type. */ +- for (unsigned i = 0; i < max_split && newrhs1[i] && newrhs2[i]; i++) ++ if (current_layout_opt_level >= SEMI_RELAYOUT ++ && (is_semi_relayout_candidate (rhs1) ++ || is_semi_relayout_candidate (rhs2))) + { +- gimple_assign_set_rhs1 (stmt, newrhs1[i]); +- gimple_assign_set_rhs2 (stmt, newrhs2[i]); +- update_stmt (stmt); ++ for (unsigned i = 0; i < max_split && newrhs1[i] &&newrhs2[i]; i++) ++ { ++ srtype *type = get_semi_relayout_candidate_type (rhs1); ++ if (!type) ++ type = get_semi_relayout_candidate_type (rhs2); ++ gcc_assert (type != NULL); ++ tree res = rewrite_pointer_diff (gsi, newrhs1[i], ++ newrhs2[i], type); ++ gimple *g = gimple_build_assign (gimple_assign_lhs (stmt), res); ++ gsi_insert_before (gsi, g, GSI_SAME_STMT); ++ } ++ remove = true; ++ } ++ else ++ { ++ for (unsigned i = 0; i < max_split && newrhs1[i] && newrhs2[i]; i++) ++ { ++ gimple_assign_set_rhs1 (stmt, newrhs1[i]); ++ gimple_assign_set_rhs2 (stmt, newrhs2[i]); ++ update_stmt (stmt); ++ } + } +- remove = false; + return remove; + } + +@@ -6985,6 +7593,8 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + fprintf (dump_file, "replaced with:\n"); + for (unsigned i = 0; i < max_split && (newlhs[i] || newrhs[i]); i++) + { ++ if (current_layout_opt_level & SEMI_RELAYOUT) ++ do_semi_relayout (gsi, stmt, newlhs[i], newrhs[i]); + if (current_layout_opt_level >= POINTER_COMPRESSION_SAFE) + try_rewrite_with_pointer_compression (stmt, gsi, lhs, rhs, + newlhs[i], newrhs[i]); +@@ -7003,6 +7613,108 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) + return remove; + } + ++tree ++ipa_struct_reorg::get_real_allocated_ptr (tree ptr, gimple_stmt_iterator *gsi) ++{ ++ tree ptr_to_int = fold_convert (long_unsigned_type_node, ptr); ++ tree align = build_int_cst (long_unsigned_type_node, relayout_part_size); ++ tree real_addr = gimplify_build2 (gsi, MINUS_EXPR, long_unsigned_type_node, ++ ptr_to_int, align); ++ tree res = gimplify_build1 (gsi, NOP_EXPR, ++ build_pointer_type (long_unsigned_type_node), real_addr); ++ return res; ++} ++ ++tree ++ipa_struct_reorg::set_ptr_for_use (tree ptr, gimple_stmt_iterator *gsi) ++{ ++ tree ptr_to_int = fold_convert (long_unsigned_type_node, ptr); ++ tree align = build_int_cst (long_unsigned_type_node, relayout_part_size); ++ tree ptr_int = gimplify_build2 (gsi, PLUS_EXPR, long_unsigned_type_node, ++ ptr_to_int, align); ++ tree res = gimplify_build1 (gsi, NOP_EXPR, ++ build_pointer_type (long_unsigned_type_node), ptr_int); ++ return res; ++} ++ ++void ++ipa_struct_reorg::record_allocated_size (tree ptr, gimple_stmt_iterator *gsi, ++ tree size) ++{ ++ tree to_type = build_pointer_type (long_unsigned_type_node); ++ tree type_cast = fold_convert (to_type, ptr); ++ tree lhs = fold_build2 (MEM_REF, long_unsigned_type_node, ptr, ++ build_int_cst (build_pointer_type (long_unsigned_type_node), 0)); ++ gimple *stmt = gimple_build_assign (lhs, size); ++ gsi_insert_before (gsi, stmt, GSI_SAME_STMT); ++} ++ ++tree ++ipa_struct_reorg::read_allocated_size (tree ptr, gimple_stmt_iterator *gsi) ++{ ++ tree to_type = build_pointer_type (long_unsigned_type_node); ++ tree off = build_int_cst (to_type, 0); ++ tree size = gimplify_build2 (gsi, MEM_REF, long_unsigned_type_node, ++ ptr, off); ++ return size; ++} ++ ++gimple * ++ipa_struct_reorg::create_aligned_alloc (gimple_stmt_iterator *gsi, ++ srtype *type, tree num, tree &size) ++{ ++ tree fn = builtin_decl_implicit (BUILT_IN_ALIGNED_ALLOC); ++ ++ tree align = build_int_cst (long_unsigned_type_node, relayout_part_size); ++ unsigned bucket_size = type->bucket_size; ++ ++ tree nbuckets = gimplify_build2 (gsi, CEIL_DIV_EXPR, long_unsigned_type_node, ++ num, build_int_cst (long_unsigned_type_node, ++ relayout_part_size / 8)); ++ tree use_size = gimplify_build2 (gsi, MULT_EXPR, long_unsigned_type_node, ++ nbuckets, build_int_cst ( ++ long_unsigned_type_node, bucket_size)); ++ size = gimplify_build2 (gsi, PLUS_EXPR, long_unsigned_type_node, ++ use_size, align); ++ gimple *g = gimple_build_call (fn, 2, align, size); ++ gsi_insert_before (gsi, g, GSI_SAME_STMT); ++ return g; ++} ++ ++void ++ipa_struct_reorg::create_memset_zero (tree ptr, gimple_stmt_iterator *gsi, ++ tree size) ++{ ++ tree fn = builtin_decl_implicit (BUILT_IN_MEMSET); ++ tree val = build_int_cst (long_unsigned_type_node, 0); ++ gimple *g = gimple_build_call (fn, 3, ptr, val, size); ++ gsi_insert_before (gsi, g, GSI_SAME_STMT); ++} ++ ++void ++ipa_struct_reorg::create_memcpy (tree src, tree dst, tree size, ++ gimple_stmt_iterator *gsi) ++{ ++ tree fn = builtin_decl_implicit (BUILT_IN_MEMCPY); ++ gimple *g = gimple_build_call (fn, 3, dst, src, size); ++ gsi_insert_before (gsi, g, GSI_SAME_STMT); ++} ++ ++void ++ipa_struct_reorg::create_free (tree ptr, gimple_stmt_iterator *gsi) ++{ ++ tree fn = builtin_decl_implicit (BUILT_IN_FREE); ++ gimple *g = gimple_build_call (fn, 1, ptr); ++ gsi_insert_before (gsi, g, GSI_SAME_STMT); ++} ++ ++void ++ipa_struct_reorg::copy_to_lhs (tree lhs, tree new_lhs, gimple_stmt_iterator *gsi) ++{ ++ gimple *g = gimple_build_assign (lhs, new_lhs); ++ gsi_insert_before (gsi, g, GSI_SAME_STMT); ++} ++ + /* Rewrite function call statement STMT. Return TRUE if the statement + is to be removed. */ + +@@ -7044,24 +7756,77 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi) + ? TYPE_SIZE_UNIT (decl->orig_type) + : TYPE_SIZE_UNIT (type->newtype[i]); + gimple *g; +- /* Every allocation except for calloc needs the size multiplied out. */ +- if (!gimple_call_builtin_p (stmt, BUILT_IN_CALLOC)) +- newsize = gimplify_build2 (gsi, MULT_EXPR, sizetype, num, newsize); +- +- if (gimple_call_builtin_p (stmt, BUILT_IN_MALLOC) +- || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA)) +- g = gimple_build_call (gimple_call_fndecl (stmt), +- 1, newsize); +- else if (gimple_call_builtin_p (stmt, BUILT_IN_CALLOC)) +- g = gimple_build_call (gimple_call_fndecl (stmt), +- 2, num, newsize); +- else if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC)) +- g = gimple_build_call (gimple_call_fndecl (stmt), +- 2, newrhs1[i], newsize); +- else +- gcc_assert (false); +- gimple_call_set_lhs (g, decl->newdecl[i]); +- gsi_insert_before (gsi, g, GSI_SAME_STMT); ++ bool rewrite = false; ++ if (current_layout_opt_level >= SEMI_RELAYOUT ++ && type->semi_relayout) ++ { ++ if (gimple_call_builtin_p (stmt, BUILT_IN_MALLOC)) ++ ; ++ else if (gimple_call_builtin_p (stmt, BUILT_IN_CALLOC)) ++ { ++ tree rhs2 = gimple_call_arg (stmt, 1); ++ if (tree_to_uhwi (rhs2) == tree_to_uhwi ( ++ TYPE_SIZE_UNIT (type->type))) ++ { ++ rewrite = true; ++ tree size = NULL_TREE; ++ g = create_aligned_alloc (gsi, type, num, size); ++ tree real_ptr = make_ssa_name ( ++ build_pointer_type (unsigned_char_type_node)); ++ gimple_set_lhs (g, real_ptr); ++ create_memset_zero (real_ptr, gsi, size); ++ record_allocated_size (real_ptr, gsi, size); ++ tree lhs_use = set_ptr_for_use (real_ptr, gsi); ++ copy_to_lhs (decl->newdecl[i], lhs_use, gsi); ++ } ++ } ++ else if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC)) ++ { ++ rewrite = true; ++ tree size = NULL_TREE; ++ g = create_aligned_alloc (gsi, type, num, size); ++ tree real_ptr = make_ssa_name ( ++ build_pointer_type (unsigned_char_type_node)); ++ gimple_set_lhs (g, real_ptr); ++ create_memset_zero (real_ptr, gsi, size); ++ tree src = get_real_allocated_ptr (newrhs1[i], gsi); ++ tree old_size = read_allocated_size (src, gsi); ++ create_memcpy (src, real_ptr, old_size, gsi); ++ record_allocated_size (real_ptr, gsi, size); ++ tree lhs_use = set_ptr_for_use (real_ptr, gsi); ++ create_free (src, gsi); ++ copy_to_lhs (decl->newdecl[i], lhs_use, gsi); ++ } ++ else ++ { ++ gcc_assert (false); ++ internal_error ("supported type for semi-relayout."); ++ } ++ } ++ if (!rewrite ++ && (current_layout_opt_level >= STRUCT_REORDER_FIELDS ++ || current_layout_opt_level == STRUCT_SPLIT)) ++ { ++ /* Every allocation except for calloc needs the size ++ multiplied out. */ ++ if (!gimple_call_builtin_p (stmt, BUILT_IN_CALLOC)) ++ newsize = gimplify_build2 (gsi, MULT_EXPR, sizetype, ++ num, newsize); ++ if (gimple_call_builtin_p (stmt, BUILT_IN_MALLOC) ++ || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA)) ++ g = gimple_build_call (gimple_call_fndecl (stmt), ++ 1, newsize); ++ else if (gimple_call_builtin_p (stmt, BUILT_IN_CALLOC)) ++ g = gimple_build_call (gimple_call_fndecl (stmt), ++ 2, num, newsize); ++ else if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC)) ++ g = gimple_build_call (gimple_call_fndecl (stmt), ++ 2, newrhs1[i], newsize); ++ else ++ gcc_assert (false); ++ gimple_call_set_lhs (g, decl->newdecl[i]); ++ gsi_insert_before (gsi, g, GSI_SAME_STMT); ++ } + if (type->pc_candidate) + { + /* Init global header for pointer compression. */ +@@ -7081,8 +7846,11 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi) + if (!rewrite_expr (expr, newexpr)) + return false; + ++ srtype *t = find_type (TREE_TYPE (TREE_TYPE (expr))); + if (newexpr[1] == NULL) + { ++ if (t && t->semi_relayout) ++ newexpr[0] = get_real_allocated_ptr (newexpr[0], gsi); + gimple_call_set_arg (stmt, 0, newexpr[0]); + update_stmt (stmt); + return false; +@@ -7789,6 +8557,85 @@ ipa_struct_reorg::check_and_prune_struct_for_pointer_compression (void) + } + } + ++void ++ipa_struct_reorg::check_and_prune_struct_for_semi_relayout (void) ++{ ++ unsigned relayout_transform = 0; ++ for (unsigned i = 0; i < types.length (); i++) ++ { ++ srtype *type = types[i]; ++ if (dump_file) ++ { ++ print_generic_expr (dump_file, type->type); ++ } ++ if (type->has_escaped ()) ++ { ++ if (dump_file) ++ { ++ fprintf (dump_file, " has escaped by %s, skip relayout.\n", ++ type->escape_reason ()); ++ } ++ continue; ++ } ++ if (TYPE_FIELDS (type->type) == NULL) ++ { ++ if (dump_file) ++ { ++ fprintf (dump_file, " has zero field, skip relayout.\n"); ++ } ++ continue; ++ } ++ if (type->chain_type) ++ { ++ if (dump_file) ++ { ++ fprintf (dump_file, " is chain_type, skip relayout.\n"); ++ } ++ continue; ++ } ++ if (type->has_alloc_array == 0 || type->has_alloc_array == 1 ++ || type->has_alloc_array == -1 || type->has_alloc_array == -3 ++ || type->has_alloc_array == -4) ++ { ++ if (dump_file) ++ { ++ fprintf (dump_file, " has alloc number: %d, skip relayout.\n", ++ type->has_alloc_array); ++ } ++ continue; ++ } ++ if (get_type_name (type->type) == NULL) ++ { ++ if (dump_file) ++ { ++ fprintf (dump_file, " has empty struct name," ++ " skip relayout.\n"); ++ } ++ continue; ++ } ++ relayout_transform++; ++ type->semi_relayout = true; ++ if (dump_file) ++ { ++ fprintf (dump_file, " attempts to do semi-relayout.\n"); ++ } ++ } ++ ++ if (dump_file) ++ { ++ if (relayout_transform) ++ { ++ fprintf (dump_file, "\nNumber of structures to transform in " ++ "semi-relayout is %d\n", relayout_transform); ++ } ++ else ++ { ++ fprintf (dump_file, "\nNo structures to transform in " ++ "semi-relayout.\n"); ++ } ++ } ++} ++ + /* Init pointer size from parameter param_pointer_compression_size. */ + + static void +@@ -7829,7 +8676,8 @@ ipa_struct_reorg::execute (unsigned int opt) + } + if (opt >= POINTER_COMPRESSION_SAFE) + check_and_prune_struct_for_pointer_compression (); +- ++ if (opt >= SEMI_RELAYOUT) ++ check_and_prune_struct_for_semi_relayout (); + ret = rewrite_functions (); + } + else // do COMPLETE_STRUCT_RELAYOUT +@@ -7881,6 +8729,8 @@ public: + unsigned int level = 0; + switch (struct_layout_optimize_level) + { ++ case 6: level |= SEMI_RELAYOUT; ++ // FALLTHRU + case 5: level |= POINTER_COMPRESSION_UNSAFE; + // FALLTHRU + case 4: level |= POINTER_COMPRESSION_SAFE; +@@ -7900,6 +8750,12 @@ public: + if (level & POINTER_COMPRESSION_SAFE) + init_pointer_size_for_pointer_compression (); + ++ if (level & SEMI_RELAYOUT) ++ { ++ semi_relayout_align = semi_relayout_level; ++ relayout_part_size = 1 << semi_relayout_level; ++ } ++ + /* Preserved for backward compatibility, reorder fields needs run before + struct split and complete struct relayout. */ + if (flag_ipa_reorder_fields && level < STRUCT_REORDER_FIELDS) +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.h b/gcc/ipa-struct-reorg/ipa-struct-reorg.h +index d88799982..982f43e58 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.h ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.h +@@ -25,6 +25,9 @@ namespace struct_reorg { + + const int max_split = 2; + ++unsigned semi_relayout_align = semi_relayout_level; ++unsigned relayout_part_size = 1 << semi_relayout_level; ++ + template <typename type> + struct auto_vec_del : auto_vec<type*> + { +@@ -127,6 +130,10 @@ public: + bool pc_candidate; + bool has_legal_alloc_num; + int has_alloc_array; ++ bool semi_relayout; ++ hash_map<tree, unsigned long> new_field_offsets; ++ unsigned bucket_parts; ++ unsigned bucket_size; + + // Constructors + srtype(tree type); +@@ -148,6 +155,7 @@ public: + bool has_dead_field (void); + void mark_escape (escape_type, gimple *stmt); + void create_global_ptr_for_pc (); ++ unsigned calculate_bucket_size (); + bool has_escaped (void) + { + return escapes != does_not_escape; +diff --git a/gcc/params.opt b/gcc/params.opt +index 1d355819c..83fd705ee 100644 +--- a/gcc/params.opt ++++ b/gcc/params.opt +@@ -988,4 +988,8 @@ Threshold functions of cache miss counts to be analyzed in prefetching. + Common Joined UInteger Var(param_pointer_compression_size) Init(32) IntegerRange(8, 32) Param Optimization + Target size of compressed pointer, which should be 8, 16 or 32. + ++-param=semi-relayout-level= ++Common Joined UInteger Var(semi_relayout_level) Init(13) IntegerRange(11, 15) Param Optimization ++Set capacity of each bucket to semi-relayout to (1 << semi-relayout-level) / 8 . ++ + ; This comment is to ensure we retain the blank line above. +diff --git a/gcc/testsuite/gcc.dg/struct/semi_relayout_rewrite.c b/gcc/testsuite/gcc.dg/struct/semi_relayout_rewrite.c +new file mode 100644 +index 000000000..87c756c79 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/semi_relayout_rewrite.c +@@ -0,0 +1,86 @@ ++// Check simplify rewrite chance for semi-relayout
++/* { dg-do compile } */
++
++#include <stdio.h>
++#include <stdlib.h>
++
++typedef struct node node_t;
++typedef struct node *node_p;
++
++typedef struct arc arc_t;
++typedef struct arc *arc_p;
++
++typedef struct network
++{
++ arc_p arcs;
++ arc_p sorted_arcs;
++ int x;
++ node_p nodes;
++ node_p stop_nodes;
++} network_t;
++
++struct node
++{
++ int64_t potential;
++ int orientation;
++ node_p child;
++ node_p pred;
++ node_p sibling;
++ node_p sibling_prev;
++ arc_p basic_arc;
++ arc_p firstout;
++ arc_p firstin;
++ arc_p arc_tmp;
++ int64_t flow;
++ int64_t depth;
++ int number;
++ int time;
++};
++
++struct arc
++{
++ int id;
++ int64_t cost;
++ node_p tail;
++ node_p head;
++ short ident;
++ arc_p nextout;
++ arc_p nextin;
++ int64_t flow;
++ int64_t org_cost;
++ network_t* net_add;
++};
++
++
++const int MAX = 100;
++network_t* net;
++node_p node;
++arc_p arc;
++
++int
++main ()
++{
++ net = (network_t*) calloc (1, sizeof(network_t));
++ net->arcs = (arc_p) calloc (MAX, sizeof (arc_t));
++ net->sorted_arcs = (arc_p) calloc (MAX, sizeof (arc_t));
++ net->nodes = (node_p) calloc (MAX, sizeof (node_t));
++ net->arcs->id = 100;
++
++ node = net->nodes;
++ arc = net->arcs;
++
++ for (unsigned i = 0; i < MAX; i++)
++ {
++ arc->head = node;
++ arc->head->child = node;
++ node->potential = i + 1;
++ arc->cost = arc->head->potential;
++ arc->tail = node->sibling;
++ node = node + 1;
++ arc = arc + 1;
++ }
++
++ return 0;
++}
++
++/* { dg-final { scan-ipa-dump "Number of structures to transform in semi-relayout is 1" "struct_reorg" } } */ +\ No newline at end of file +diff --git a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp +index d7367ed96..281046b48 100644 +--- a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp ++++ b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp +@@ -93,6 +93,10 @@ gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/pc*.c]] \ + gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/pc*.c]] \ + "" "-fipa-struct-reorg=5 -fdump-ipa-all -flto-partition=one -fwhole-program" + ++# -fipa-struct-reorg=6 ++gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/semi_relayout*.c]] \ ++ "" "-fipa-struct-reorg=6 -fdump-ipa-all -flto-partition=one -fwhole-program" ++ + # All done. + torture-finish + dg-finish +-- +2.27.0.windows.1 + diff --git a/0084-MULL64-Disable-mull64-transformation-by-default.patch b/0084-MULL64-Disable-mull64-transformation-by-default.patch new file mode 100644 index 0000000..66668b1 --- /dev/null +++ b/0084-MULL64-Disable-mull64-transformation-by-default.patch @@ -0,0 +1,64 @@ +From fb86109ebb10cdb82e1e3ffa37bb7e770fb7c066 Mon Sep 17 00:00:00 2001 +From: eastb233 <xiezhiheng@huawei.com> +Date: Wed, 7 Dec 2022 09:43:15 +0800 +Subject: [PATCH] [MULL64] Disable mull64 transformation by default + +This commit disables mull64 transformation by default since +it shows some runtime failure in workloads. +--- + gcc/match.pd | 2 +- + gcc/opts.c | 1 - + gcc/testsuite/g++.dg/tree-ssa/mull64.C | 2 +- + gcc/testsuite/gcc.dg/pr107190.c | 2 +- + 4 files changed, 3 insertions(+), 4 deletions(-) + +diff --git a/gcc/match.pd b/gcc/match.pd +index 433682afb..01f81b063 100644 +--- a/gcc/match.pd ++++ b/gcc/match.pd +@@ -3393,7 +3393,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) + (simplify + (cond @0 (op:s @1 integer_pow2p@2) @1) + /* powerof2cst */ +- (if (INTEGRAL_TYPE_P (type)) ++ (if (flag_merge_mull && INTEGRAL_TYPE_P (type)) + (with { + tree shift = build_int_cst (integer_type_node, tree_log2 (@2)); + } +diff --git a/gcc/opts.c b/gcc/opts.c +index 751965e46..f12b13599 100644 +--- a/gcc/opts.c ++++ b/gcc/opts.c +@@ -511,7 +511,6 @@ static const struct default_options default_options_table[] = + { OPT_LEVELS_2_PLUS, OPT_fvect_cost_model_, NULL, VECT_COST_MODEL_CHEAP }, + { OPT_LEVELS_2_PLUS, OPT_finline_functions, NULL, 1 }, + { OPT_LEVELS_2_PLUS, OPT_ftree_loop_distribute_patterns, NULL, 1 }, +- { OPT_LEVELS_2_PLUS, OPT_fmerge_mull, NULL, 1 }, + + /* -O2 and above optimizations, but not -Os or -Og. */ + { OPT_LEVELS_2_PLUS_SPEED_ONLY, OPT_falign_functions, NULL, 1 }, +diff --git a/gcc/testsuite/g++.dg/tree-ssa/mull64.C b/gcc/testsuite/g++.dg/tree-ssa/mull64.C +index f61cf5e6f..cad891e62 100644 +--- a/gcc/testsuite/g++.dg/tree-ssa/mull64.C ++++ b/gcc/testsuite/g++.dg/tree-ssa/mull64.C +@@ -1,5 +1,5 @@ + /* { dg-do compile } */ +-/* { dg-options "-O2 -Wno-psabi -fdump-tree-forwprop1-details -fdump-tree-forwprop4-details" } */ ++/* { dg-options "-O2 -fmerge-mull -Wno-psabi -fdump-tree-forwprop1-details -fdump-tree-forwprop4-details" } */ + + # define BN_BITS4 32 + # define BN_MASK2 (0xffffffffffffffffL) +diff --git a/gcc/testsuite/gcc.dg/pr107190.c b/gcc/testsuite/gcc.dg/pr107190.c +index 235b2761a..d1e72e5df 100644 +--- a/gcc/testsuite/gcc.dg/pr107190.c ++++ b/gcc/testsuite/gcc.dg/pr107190.c +@@ -1,5 +1,5 @@ + /* { dg-do compile } */ +-/* { dg-options "-O2 -fexpensive-optimizations -fdump-tree-phiopt2-details" } */ ++/* { dg-options "-O2 -fmerge-mull -fexpensive-optimizations -fdump-tree-phiopt2-details" } */ + + # define BN_BITS4 32 + # define BN_MASK2 (0xffffffffffffffffL) +-- +2.25.1 + diff --git a/0085-loop-distribution-Bugfix-for-loop-distribution.patch b/0085-loop-distribution-Bugfix-for-loop-distribution.patch new file mode 100644 index 0000000..37c2a1b --- /dev/null +++ b/0085-loop-distribution-Bugfix-for-loop-distribution.patch @@ -0,0 +1,58 @@ +From d73cd8783ca930724def3e9909fc484ec15404f5 Mon Sep 17 00:00:00 2001 +From: benniaobufeijiushiji <linda7@huawei.com> +Date: Mon, 19 Dec 2022 11:48:12 +0800 +Subject: [PATCH 1/3] [loop-distribution] Bugfix for loop-distribution Add + exception in function BUILD_QUEUE when there is a null pointer in + grouped_loads. + +--- + gcc/tree-loop-distribution.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c +index 88b56379c..b68b9c7eb 100644 +--- a/gcc/tree-loop-distribution.c ++++ b/gcc/tree-loop-distribution.c +@@ -3208,16 +3208,31 @@ build_queue (loop_vec_info vinfo, unsigned vf, + { + unsigned group_size = stmt_info->size; + stmt_vec_info c_stmt_info = stmt_info; ++ bool succ = true; + while (group_size >= vf) + { + vec_alloc (worklist, vf); + for (unsigned j = 0; j < vf; ++j) + { ++ if (c_stmt_info == NULL) ++ { ++ succ = false; ++ break; ++ } + ginfo = new _group_info (); + ginfo->stmt = c_stmt_info->stmt; + worklist->safe_push (ginfo); + c_stmt_info = c_stmt_info->next_element; + } ++ if (!succ) ++ { ++ unsigned k = 0; ++ ginfo = NULL; ++ FOR_EACH_VEC_ELT (*worklist, k, ginfo) ++ delete ginfo; ++ vec_free (worklist); ++ break; ++ } + worklists.safe_push (worklist); + group_size -= vf; + } +@@ -3711,6 +3726,7 @@ free_ginfos (vec<vec<group_info> *> &worklists) + unsigned j = 0; + FOR_EACH_VEC_ELT (*worklist, j, ginfo) + delete ginfo; ++ vec_free (worklist); + } + } + +-- +2.27.0.windows.1 + diff --git a/0086-semi-relayout-Bugfix-for-struct-semi-relayout.patch b/0086-semi-relayout-Bugfix-for-struct-semi-relayout.patch new file mode 100644 index 0000000..81d967c --- /dev/null +++ b/0086-semi-relayout-Bugfix-for-struct-semi-relayout.patch @@ -0,0 +1,26 @@ +From b2b710238e13eb2fced77d89cd8dcc86f77b6c6c Mon Sep 17 00:00:00 2001 +From: benniaobufeijiushiji <linda7@huawei.com> +Date: Mon, 19 Dec 2022 15:12:24 +0800 +Subject: [PATCH 2/3] [semi-relayout] Bugfix for struct semi-relayout Bugfix + when relayout candidate type is null. + +--- + gcc/ipa-struct-reorg/ipa-struct-reorg.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +index 4751711fe..2cac340c7 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -6408,6 +6408,8 @@ ipa_struct_reorg::is_semi_relayout_candidate (tree xhs) + { + tree type = TREE_TYPE (mem); + srtype *old_type = get_relayout_candidate_type (type); ++ if (!old_type) ++ return false; + if (types_compatible_p (type, old_type->type) + && old_type->semi_relayout) + return true; +-- +2.27.0.windows.1 + diff --git a/0087-Backport-tree-optimization-97238-fix-typo-causing-IC.patch b/0087-Backport-tree-optimization-97238-fix-typo-causing-IC.patch new file mode 100644 index 0000000..b47cff9 --- /dev/null +++ b/0087-Backport-tree-optimization-97238-fix-typo-causing-IC.patch @@ -0,0 +1,55 @@ +From ae15300352b0fa47a533af852f88e7244c2820cc Mon Sep 17 00:00:00 2001 +From: Richard Biener <rguenther@suse.de> +Date: Tue, 29 Sep 2020 14:38:06 +0200 +Subject: [PATCH 3/3] [Backport] tree-optimization/97238 - fix typo causing ICE + +Reference: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=29aef377d814bd342dd5a306f99e0d614623ce0e + +This fixes a typo causing a NULL dereference. + +2020-09-29 Richard Biener <rguenther@suse.de> + + PR tree-optimization/97238 + * tree-ssa-reassoc.c (ovce_extract_ops): Fix typo. + + * gcc.dg/pr97238.c: New testcase. +--- + gcc/testsuite/gcc.dg/pr97238.c | 12 ++++++++++++ + gcc/tree-ssa-reassoc.c | 2 +- + 2 files changed, 13 insertions(+), 1 deletion(-) + create mode 100644 gcc/testsuite/gcc.dg/pr97238.c + +diff --git a/gcc/testsuite/gcc.dg/pr97238.c b/gcc/testsuite/gcc.dg/pr97238.c +new file mode 100644 +index 000000000..746e93a97 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/pr97238.c +@@ -0,0 +1,12 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O -Wno-psabi -w" } */ ++ ++typedef int __attribute__ ((__vector_size__ (8))) V; ++int b, c, e; ++V d; ++ ++V ++foo (void) ++{ ++ return (b || e) | c > d | ((b || e) | c > d); ++} +diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c +index 5f978ac78..62e7c8dca 100644 +--- a/gcc/tree-ssa-reassoc.c ++++ b/gcc/tree-ssa-reassoc.c +@@ -3853,7 +3853,7 @@ ovce_extract_ops (tree var, gassign **rets, bool *reti, tree *type, + return ERROR_MARK; + + gassign *assign = dyn_cast<gassign *> (SSA_NAME_DEF_STMT (cond)); +- if (stmt == NULL ++ if (assign == NULL + || TREE_CODE_CLASS (gimple_assign_rhs_code (assign)) != tcc_comparison) + return ERROR_MARK; + +-- +2.27.0.windows.1 + diff --git a/0088-Backport-fix-typo-causing-ICE.patch b/0088-Backport-fix-typo-causing-ICE.patch new file mode 100644 index 0000000..fea8ac7 --- /dev/null +++ b/0088-Backport-fix-typo-causing-ICE.patch @@ -0,0 +1,25 @@ +From d631be52d401d834261f86113b3a738014540b6c Mon Sep 17 00:00:00 2001 +From: xiongzhou4 <xiongzhou4@huawei.com> +Date: Fri, 30 Dec 2022 20:15:11 +0800 +Subject: [PATCH] Replace *vcond with vcond as we check for NULL pointer. + +--- + gcc/tree-ssa-reassoc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c +index 62e7c8dca..1ad43dba1 100644 +--- a/gcc/tree-ssa-reassoc.c ++++ b/gcc/tree-ssa-reassoc.c +@@ -3839,7 +3839,7 @@ ovce_extract_ops (tree var, gassign **rets, bool *reti, tree *type, + gassign *stmt = dyn_cast <gassign *> (SSA_NAME_DEF_STMT (var)); + if (stmt == NULL) + return ERROR_MARK; +- if (*vcond) ++ if (vcond) + *vcond = stmt; + + /* ??? If we start creating more COND_EXPR, we could perform +-- +2.33.0 + diff --git a/0089-State-sysroot-option-as-validated-once-processed.patch b/0089-State-sysroot-option-as-validated-once-processed.patch new file mode 100644 index 0000000..a3da278 --- /dev/null +++ b/0089-State-sysroot-option-as-validated-once-processed.patch @@ -0,0 +1,30 @@ +From a7c23eb36641d605df37f5942d188a764a2480f9 Mon Sep 17 00:00:00 2001 +From: huitailangzju <804544223@qq.com> +Date: Tue, 14 Feb 2023 10:54:10 +0800 +Subject: [PATCH] State --sysroot option as validated once processed + +[Reference] https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=8e86086bd33134467cc9c2a75327d1238dc71df9 + +Since we now save the option in the "switches" table +to let specs use it more generally, we need to explicitly +state that the option was validated else the driver +will consider it "unrecognized". +--- + gcc/gcc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/gcc/gcc.c b/gcc/gcc.c +index 655beffcc..efa0b53ce 100644 +--- a/gcc/gcc.c ++++ b/gcc/gcc.c +@@ -4193,6 +4193,7 @@ driver_handle_option (struct gcc_options *opts, + /* Saving this option is useful to let self-specs decide to + provide a default one. */ + do_save = true; ++ validated = true; + break; + + case OPT_time_: +-- +2.28.0.windows.1 + diff --git a/0090-bogus-Wstringop-overflow-with-VLA-of-elements-larger.patch b/0090-bogus-Wstringop-overflow-with-VLA-of-elements-larger.patch new file mode 100644 index 0000000..fb51808 --- /dev/null +++ b/0090-bogus-Wstringop-overflow-with-VLA-of-elements-larger.patch @@ -0,0 +1,129 @@ +From bf537e82d452ee9b79f438df721c2e0dfaae12a0 Mon Sep 17 00:00:00 2001 +From: Xiong Zhou <xiongzhou4@huawei.com> +Date: Fri, 5 May 2023 11:57:40 +0800 +Subject: [PATCH 1/2] - bogus -Wstringop-overflow with VLA of elements larger + than byte + +--- + gcc/calls.c | 5 ++ + gcc/testsuite/gcc.dg/Wstringop-overflow-67.c | 92 ++++++++++++++++++++ + 2 files changed, 97 insertions(+) + create mode 100644 gcc/testsuite/gcc.dg/Wstringop-overflow-67.c + +diff --git a/gcc/calls.c b/gcc/calls.c +index 26894342c..45c137cee 100644 +--- a/gcc/calls.c ++++ b/gcc/calls.c +@@ -2112,6 +2112,11 @@ maybe_warn_rdwr_sizes (rdwr_map *rwm, tree fndecl, tree fntype, tree exp) + } + else + { ++ /* If the size cannot be determined clear it to keep it from ++ being taken as real (and excessive). */ ++ if (objsize && integer_all_onesp (objsize)) ++ objsize = NULL_TREE; ++ + /* For read-only and read-write attributes also set the source + size. */ + srcsize = objsize; +diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-67.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-67.c +new file mode 100644 +index 000000000..7b8f3f014 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-67.c +@@ -0,0 +1,92 @@ ++/* PR middle-end/100571 - bogus -Wstringop-overflow with VLA of elements ++ larger than byte ++ { dg-do compile } ++ { dg-options "-O2 -Wall" } */ ++ ++__attribute__ ((access (read_only, 1, 2))) void fro (int *, int); ++__attribute__ ((access (write_only, 1, 2))) void fwo (int *, int); ++__attribute__ ((access (read_write, 1, 2))) void frw (int *, int); ++ ++extern __SIZE_TYPE__ n; ++ ++void alloca_ro (void) ++{ ++ int *a = __builtin_alloca (n * sizeof *a); ++ a[0] = 0; ++ fro (a, n); ++} ++ ++void alloca_wo (void) ++{ ++ int *a = __builtin_alloca (n * sizeof *a); ++ fwo (a, n); ++} ++ ++void alloca_rw (void) ++{ ++ int *a = __builtin_alloca (n * sizeof *a); ++ a[0] = 0; ++ frw (a, n); ++} ++ ++ ++void calloc_ro (void) ++{ ++ int *a = __builtin_calloc (n, sizeof *a); ++ fro (a, n); ++} ++ ++void calloc_wo (void) ++{ ++ int *a = __builtin_calloc (n, sizeof *a); ++ fwo (a, n); ++} ++ ++void calloc_rw (void) ++{ ++ int *a = __builtin_calloc (n, sizeof *a); ++ a[0] = 0; ++ frw (a, n); ++} ++ ++ ++void malloc_ro (void) ++{ ++ int *a = __builtin_malloc (n * sizeof *a); ++ a[0] = 0; ++ fro (a, n); ++} ++ ++void malloc_wo (void) ++{ ++ int *a = __builtin_malloc (n * sizeof *a); ++ fwo (a, n); ++} ++ ++void malloc_rw (void) ++{ ++ int *a = __builtin_malloc (n * sizeof *a); ++ a[0] = 0; ++ frw (a, n); ++} ++ ++ ++void vla_ro (void) ++{ ++ int a[n]; ++ a[0] = 0; ++ fro (a, n); ++} ++ ++void vla_wo (void) ++{ ++ int a[n]; ++ fwo (a, n); ++} ++ ++void vla_rw (void) ++{ ++ int a[n]; ++ a[0] = 0; ++ frw (a, n); ++} +-- +2.33.0 + diff --git a/0091-phiopt2-Add-option-to-control-the-simplify.patch b/0091-phiopt2-Add-option-to-control-the-simplify.patch new file mode 100644 index 0000000..b37c1e8 --- /dev/null +++ b/0091-phiopt2-Add-option-to-control-the-simplify.patch @@ -0,0 +1,183 @@ +From bc6537191e91c854cc6bee3319290d7a86768957 Mon Sep 17 00:00:00 2001 +From: zhongyunde <zhongyunde@huawei.com> +Date: Wed, 10 May 2023 18:39:47 +0800 +Subject: [PATCH 2/2] [phiopt2] Add option to control the simplify + +The phiopt is brought in https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=c4574d23cb07340918793a5a98ae7bb2988b3791 +But may be also has some bug fixed by later commit, so disable it default temporary. +This optimization is expected to enable after we update the gcc'base to gcc12's release version. +--- + gcc/common.opt | 4 ++++ + gcc/testsuite/gcc.dg/tree-ssa/20040514-1.c | 2 +- + gcc/testsuite/gcc.dg/tree-ssa/bool-1.c | 2 +- + gcc/testsuite/gcc.dg/tree-ssa/bool-2.c | 2 +- + gcc/testsuite/gcc.dg/tree-ssa/phi-opt-10.c | 2 +- + gcc/testsuite/gcc.dg/tree-ssa/phi-opt-22.c | 2 +- + gcc/testsuite/gcc.dg/tree-ssa/phi-opt-4.c | 2 +- + gcc/testsuite/gcc.dg/tree-ssa/phi-opt-7.c | 2 +- + gcc/testsuite/gcc.dg/tree-ssa/phi-opt-8.c | 2 +- + gcc/testsuite/gcc.dg/tree-ssa/pr18134.c | 2 +- + gcc/testsuite/gcc.dg/tree-ssa/pr21829.c | 2 +- + gcc/testsuite/gcc.dg/tree-ssa/pr96928-1.c | 4 ++-- + gcc/tree-ssa-phiopt.c | 3 +++ + 13 files changed, 19 insertions(+), 12 deletions(-) + +diff --git a/gcc/common.opt b/gcc/common.opt +index be7bfee60..5ad2def18 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -2781,6 +2781,10 @@ ftree-store-ccp + Common Ignore + Does nothing. Preserved for backward compatibility. + ++ftree-fold-phiopt ++Common Report Var(flag_fold_phiopt) Init(0) Optimization ++Attempt to simply the phi node with ssa form. ++ + ftree-ch + Common Report Var(flag_tree_ch) Optimization + Enable loop header copying on trees. +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040514-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20040514-1.c +index 364ce6a69..b04316d55 100644 +--- a/gcc/testsuite/gcc.dg/tree-ssa/20040514-1.c ++++ b/gcc/testsuite/gcc.dg/tree-ssa/20040514-1.c +@@ -1,5 +1,5 @@ + /* { dg-do compile } */ +-/* { dg-options "-O1 -fdump-tree-phiopt2-details" } */ ++/* { dg-options "-O1 -ftree-fold-phiopt -fdump-tree-phiopt2-details" } */ + + int t( int i) + { +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/bool-1.c b/gcc/testsuite/gcc.dg/tree-ssa/bool-1.c +index 401357f2f..892654108 100644 +--- a/gcc/testsuite/gcc.dg/tree-ssa/bool-1.c ++++ b/gcc/testsuite/gcc.dg/tree-ssa/bool-1.c +@@ -1,5 +1,5 @@ + /* { dg-do compile } */ +-/* { dg-options "-O1 -fdump-tree-optimized" } */ ++/* { dg-options "-O1 -ftree-fold-phiopt -fdump-tree-optimized" } */ + + int f(_Bool x) + { +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/bool-2.c b/gcc/testsuite/gcc.dg/tree-ssa/bool-2.c +index add9cca1e..5ead90f06 100644 +--- a/gcc/testsuite/gcc.dg/tree-ssa/bool-2.c ++++ b/gcc/testsuite/gcc.dg/tree-ssa/bool-2.c +@@ -1,5 +1,5 @@ + /* { dg-do compile } */ +-/* { dg-options "-O1 -fdump-tree-optimized" } */ ++/* { dg-options "-O1 -ftree-fold-phiopt -fdump-tree-optimized" } */ + + int f(_Bool x) + { +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-10.c b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-10.c +index 4c190e6af..7b678fafc 100644 +--- a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-10.c ++++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-10.c +@@ -1,5 +1,5 @@ + /* { dg-do compile } */ +-/* { dg-options "-O1 -fdump-tree-optimized" } */ ++/* { dg-options "-O1 -ftree-fold-phiopt -fdump-tree-optimized" } */ + + int nem1_phi (unsigned long a) { return a ? -1 : 0; } + int eqm1_phi (unsigned long a) { return a ? 0 : -1; } +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-22.c b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-22.c +index fd3706666..23b679644 100644 +--- a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-22.c ++++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-22.c +@@ -1,6 +1,6 @@ + /* PR tree-optimization/97690 */ + /* { dg-do compile } */ +-/* { dg-options "-O2 -fdump-tree-phiopt2" } */ ++/* { dg-options "-O2 -ftree-fold-phiopt -fdump-tree-phiopt2" } */ + + int foo (_Bool d) { return d ? 2 : 0; } + int bar (_Bool d) { return d ? 1 : 0; } +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-4.c b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-4.c +index 3bdb85609..4efd9afc4 100644 +--- a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-4.c ++++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-4.c +@@ -1,5 +1,5 @@ + /* { dg-do compile } */ +-/* { dg-options "-O1 -fdump-tree-optimized" } */ ++/* { dg-options "-O1 -ftree-fold-phiopt -fdump-tree-optimized" } */ + + _Bool t(); + _Bool t1(); +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-7.c b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-7.c +index 18ecbd52a..60dcc6733 100644 +--- a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-7.c ++++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-7.c +@@ -1,5 +1,5 @@ + /* { dg-do compile } */ +-/* { dg-options "-O1 -fdump-tree-optimized" } */ ++/* { dg-options "-O1 -ftree-fold-phiopt -fdump-tree-optimized" } */ + + int g(int,int); + int f(int t, int c) +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-8.c b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-8.c +index 98c596b6a..aaa71a317 100644 +--- a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-8.c ++++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-8.c +@@ -1,5 +1,5 @@ + /* { dg-do compile } */ +-/* { dg-options "-O -fdump-tree-optimized -fdump-tree-phiopt2" } */ ++/* { dg-options "-O -ftree-fold-phiopt -fdump-tree-optimized -fdump-tree-phiopt2" } */ + + int g(int,int); + int f(int t, int c) +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr18134.c b/gcc/testsuite/gcc.dg/tree-ssa/pr18134.c +index cd40ab2c1..efb1907cf 100644 +--- a/gcc/testsuite/gcc.dg/tree-ssa/pr18134.c ++++ b/gcc/testsuite/gcc.dg/tree-ssa/pr18134.c +@@ -1,5 +1,5 @@ + /* { dg-do compile } */ +-/* { dg-options "-O1 -fdump-tree-optimized" } */ ++/* { dg-options "-O1 -ftree-fold-phiopt -fdump-tree-optimized" } */ + + int foo (int a) + { +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr21829.c b/gcc/testsuite/gcc.dg/tree-ssa/pr21829.c +index 8f5ae5127..8c8ada905 100644 +--- a/gcc/testsuite/gcc.dg/tree-ssa/pr21829.c ++++ b/gcc/testsuite/gcc.dg/tree-ssa/pr21829.c +@@ -1,5 +1,5 @@ + /* { dg-do compile } */ +-/* { dg-options "-O2 -fdump-tree-optimized" } */ ++/* { dg-options "-O2 -ftree-fold-phiopt -fdump-tree-optimized" } */ + + int test(int v) + { +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr96928-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr96928-1.c +index a2770e5e8..88c13806a 100644 +--- a/gcc/testsuite/gcc.dg/tree-ssa/pr96928-1.c ++++ b/gcc/testsuite/gcc.dg/tree-ssa/pr96928-1.c +@@ -1,9 +1,9 @@ + /* PR tree-optimization/96928 */ + /* { dg-do compile } */ +-/* { dg-options "-O2 -fdump-tree-phiopt2" } */ ++/* { dg-options "-O2 -ftree-fold-phiopt -fdump-tree-phiopt2 -fdump-tree-optimized" } */ + /* { dg-final { scan-tree-dump-times " = a_\[0-9]*\\\(D\\\) >> " 5 "phiopt2" } } */ + /* { dg-final { scan-tree-dump-times " = ~c_\[0-9]*\\\(D\\\);" 1 "phiopt2" } } */ +-/* { dg-final { scan-tree-dump-times " = ~" 1 "phiopt2" } } */ ++/* { dg-final { scan-tree-dump-times " = ~" 1 "optimized" } } */ + /* { dg-final { scan-tree-dump-times " = \[abc_0-9\\\(\\\)D]* \\\^ " 5 "phiopt2" } } */ + /* { dg-final { scan-tree-dump-not "a < 0" "phiopt2" } } */ + +diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c +index 51a2d3684..b7012932f 100644 +--- a/gcc/tree-ssa-phiopt.c ++++ b/gcc/tree-ssa-phiopt.c +@@ -839,6 +839,9 @@ match_simplify_replacement (basic_block cond_bb, basic_block middle_bb, + tree result; + gimple *stmt_to_move = NULL; + ++ if (!flag_fold_phiopt) ++ return false; ++ + /* Special case A ? B : B as this will always simplify to B. */ + if (operand_equal_for_phi_arg_p (arg0, arg1)) + return false; +-- +2.33.0 + diff --git a/0092-gimple-Factor-the-code-to-avoid-depending-auto-featu.patch b/0092-gimple-Factor-the-code-to-avoid-depending-auto-featu.patch new file mode 100644 index 0000000..c73e472 --- /dev/null +++ b/0092-gimple-Factor-the-code-to-avoid-depending-auto-featu.patch @@ -0,0 +1,170 @@ +From 3cddb0b4960e5983404bbebb11e31ffb62e98350 Mon Sep 17 00:00:00 2001 +From: zhongyunde <zhongyunde@huawei.com> +Date: Sat, 13 May 2023 10:04:02 +0800 +Subject: [PATCH 1/5] [gimple] Factor the code to avoid depending auto feature + +The lambda function with captrue can't use a function pointer +to express, so use a class to model. +--- + gcc/config/aarch64/aarch64.c | 8 +-- + gcc/gimple-match-head.c | 115 ++++++++++++++++++++++++----------- + 2 files changed, 85 insertions(+), 38 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 85dbd3898..10e037325 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -3098,10 +3098,10 @@ aarch64_maxmin_plus_const (rtx_code code, rtx *operands, bool generate_p) + == x <= y ? x - y : 0 [z == y] + == x < y ? x - y : 0 [z == y] + == x < y + 1 ? x - (y + 1) : -1 [z == y + 1]. */ +- auto maxmin_val = rtx_mode_t (maxmin_op, mode); +- auto add_val = rtx_mode_t (add_op, mode); +- auto sub_val = wi::neg (add_val); +- auto diff = wi::sub (maxmin_val, sub_val); ++ rtx_mode_t maxmin_val = rtx_mode_t (maxmin_op, mode); ++ rtx_mode_t add_val = rtx_mode_t (add_op, mode); ++ wide_int sub_val = wi::neg (add_val); ++ wide_int diff = wi::sub (maxmin_val, sub_val); + if (!(diff == 0 + || (diff == 1 && wi::gt_p (maxmin_val, sub_val, sgn)) + || (diff == -1 && wi::lt_p (maxmin_val, sub_val, sgn)))) +diff --git a/gcc/gimple-match-head.c b/gcc/gimple-match-head.c +index c1dea1734..061aef39c 100644 +--- a/gcc/gimple-match-head.c ++++ b/gcc/gimple-match-head.c +@@ -1023,10 +1023,87 @@ gimple_extract (gimple *stmt, gimple_match_op *res_op, + bool + gimple_extract_op (gimple *stmt, gimple_match_op *res_op) + { +- auto nop = [](tree op) { return op; }; ++ /* This function is not called by other function now, so leave the ++ lambda to minimize modifiers. */ ++ tree (*nop)(tree) = [](tree op) ++ { ++ return op; ++ }; + return gimple_extract (stmt, res_op, nop, nop); + } + ++/* The std=gnu++98 doesn't support c++ auto feature, and the origin ++ lambda capture some variables, so they can't be replaced with a ++ simple function pointer. */ ++class __lambda_valueize ++{ ++ typedef tree (*tree_op_func)(tree); ++ ++ public: ++ inline tree operator () (tree op) const ++ { ++ return do_valueize (op, top_valueize, valueized); ++ } ++ ++ private: ++ tree_op_func &top_valueize; ++ bool &valueized; ++ ++ public: ++ __lambda_valueize (tree_op_func &_top_valueize, bool &_valueized) ++ : top_valueize{_top_valueize}, valueized {_valueized} ++ {} ++}; ++ ++class __lambda_condition ++{ ++ typedef tree (*tree_op_func)(tree); ++ ++ public: ++ inline tree operator () (tree op) const ++ { ++ bool cond_valueized = false; ++ tree lhs = do_valueize (TREE_OPERAND (op, 0), top_valueize, ++ cond_valueized); ++ tree rhs = do_valueize (TREE_OPERAND (op, 1), top_valueize, ++ cond_valueized); ++ gimple_match_op res_op2 (res_op->cond, TREE_CODE (op), ++ TREE_TYPE (op), lhs, rhs); ++ if ((gimple_resimplify2 (seq, &res_op2, valueize) || cond_valueized) ++ && res_op2.code.is_tree_code ()) ++ { ++ if (TREE_CODE_CLASS ((tree_code) res_op2.code) == tcc_comparison) ++ { ++ valueized = true; ++ return build2 (res_op2.code, TREE_TYPE (op), res_op2.ops[0], ++ res_op2.ops[1]); ++ } ++ else if (res_op2.code == SSA_NAME ++ || res_op2.code == INTEGER_CST ++ || res_op2.code == VECTOR_CST) ++ { ++ valueized = true; ++ return res_op2.ops[0]; ++ } ++ } ++ return do_valueize (op, top_valueize, valueized); ++ } ++ ++ private: ++ tree_op_func &top_valueize; ++ tree_op_func &valueize; ++ bool &valueized; ++ gimple_match_op *&res_op; ++ gimple_seq *&seq; ++ ++ public: ++ __lambda_condition (tree_op_func &_top_valueize, tree_op_func &_valueize, ++ bool &_valueized, gimple_match_op *&_res_op, gimple_seq *&_seq) ++ : top_valueize{_top_valueize}, valueize{_valueize}, valueized {_valueized}, ++ res_op {_res_op}, seq {_seq} ++ {} ++}; ++ + /* The main STMT based simplification entry. It is used by the fold_stmt + and the fold_stmt_to_constant APIs. */ + +@@ -1035,39 +1112,9 @@ gimple_simplify (gimple *stmt, gimple_match_op *res_op, gimple_seq *seq, + tree (*valueize)(tree), tree (*top_valueize)(tree)) + { + bool valueized = false; +- auto valueize_op = [&](tree op) +- { +- return do_valueize (op, top_valueize, valueized); +- }; +- auto valueize_condition = [&](tree op) -> tree +- { +- bool cond_valueized = false; +- tree lhs = do_valueize (TREE_OPERAND (op, 0), top_valueize, +- cond_valueized); +- tree rhs = do_valueize (TREE_OPERAND (op, 1), top_valueize, +- cond_valueized); +- gimple_match_op res_op2 (res_op->cond, TREE_CODE (op), +- TREE_TYPE (op), lhs, rhs); +- if ((gimple_resimplify2 (seq, &res_op2, valueize) +- || cond_valueized) +- && res_op2.code.is_tree_code ()) +- { +- if (TREE_CODE_CLASS ((tree_code) res_op2.code) == tcc_comparison) +- { +- valueized = true; +- return build2 (res_op2.code, TREE_TYPE (op), +- res_op2.ops[0], res_op2.ops[1]); +- } +- else if (res_op2.code == SSA_NAME +- || res_op2.code == INTEGER_CST +- || res_op2.code == VECTOR_CST) +- { +- valueized = true; +- return res_op2.ops[0]; +- } +- } +- return valueize_op (op); +- }; ++ __lambda_valueize valueize_op = __lambda_valueize{top_valueize, valueized}; ++ __lambda_condition valueize_condition = __lambda_condition{top_valueize, ++ valueize, valueized, res_op, seq}; + + if (!gimple_extract (stmt, res_op, valueize_op, valueize_condition)) + return false; +-- +2.33.0 + diff --git a/0093-StructReorg-Fix-escape_cast_another_ptr-check-bug.patch b/0093-StructReorg-Fix-escape_cast_another_ptr-check-bug.patch new file mode 100644 index 0000000..a007943 --- /dev/null +++ b/0093-StructReorg-Fix-escape_cast_another_ptr-check-bug.patch @@ -0,0 +1,112 @@ +From 9527d026dceb1e4f9d9f5c117dacfdfa65ce2735 Mon Sep 17 00:00:00 2001 +From: Mingchuan Wu <wumingchuan1992@foxmail.com> +Date: Tue, 23 May 2023 21:03:58 +0800 +Subject: [PATCH 2/5] [StructReorg] Fix escape_cast_another_ptr check bug + +In the other side check, escape mark is added +when the replacement struct type exists. +--- + gcc/ipa-struct-reorg/ipa-struct-reorg.c | 15 +++--- + .../struct/wo_prof_escape_replace_type.c | 49 +++++++++++++++++++ + 2 files changed, 57 insertions(+), 7 deletions(-) + create mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_escape_replace_type.c + +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +index 2cac340c7..218140f58 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -688,6 +688,8 @@ srtype::analyze (void) + info and/or static heuristics to differentiate splitting process. */ + if (fields.length () == 2) + { ++ /* Currently, when the replacement structure type exists, ++ we only split the replacement structure. */ + for (hash_map<tree, tree>::iterator it = replace_type_map.begin (); + it != replace_type_map.end (); ++it) + { +@@ -4921,7 +4923,9 @@ ipa_struct_reorg::check_other_side (srdecl *decl, tree other, gimple *stmt, vec< + } + + srtype *t1 = find_type (inner_type (t)); +- if (t1 == type) ++ /* In the other side check, escape mark is added ++ when the replacement struct type exists. */ ++ if (t1 == type || is_replace_type (inner_type (t), type->type)) + { + /* In Complete Struct Relayout opti, if lhs type is the same + as rhs type, we could return without any harm. */ +@@ -4961,13 +4965,10 @@ ipa_struct_reorg::check_other_side (srdecl *decl, tree other, gimple *stmt, vec< + + return; + } +- if (!is_replace_type (inner_type (t), type->type)) +- { +- if (t1) +- t1->mark_escape (escape_cast_another_ptr, stmt); ++ if (t1) ++ t1->mark_escape (escape_cast_another_ptr, stmt); + +- type->mark_escape (escape_cast_another_ptr, stmt); +- } ++ type->mark_escape (escape_cast_another_ptr, stmt); + } + + +diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_replace_type.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_replace_type.c +new file mode 100644 +index 000000000..d0a7b505e +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_replace_type.c +@@ -0,0 +1,49 @@ ++/* { dg-do compile } */ ++ ++#include <stdlib.h> ++ ++struct AngleDef ++{ ++ double K; ++ double th0; ++}; ++typedef struct AngleDef angldef; ++ ++struct bndangdihe ++{ ++ int nbond; ++ int nangl; ++ int ndihe; ++}; ++typedef struct bndangdihe bah; ++ ++struct ambprmtop ++{ ++ double *AnglK; ++ double *AnglEq; ++ bah nBAH; ++ angldef *AParam; ++ char source[512]; ++ char eprulesource[512]; ++}; ++typedef struct ambprmtop prmtop; ++ ++static void OrderBondParameters (prmtop *tp) ++{ ++ int i; ++ tp->AParam = (angldef *)malloc (tp->nBAH.nangl * sizeof (angldef)); ++ for (i = 0; i < tp->nBAH.nangl; i++) ++ { ++ tp->AParam[i].K = tp->AnglK[i]; ++ tp->AParam[i].th0 = tp->AnglEq[i]; ++ } ++} ++ ++void main () ++{ ++ prmtop *tp = (prmtop *)malloc (100 * sizeof (prmtop)); ++ OrderBondParameters (tp); ++} ++ ++/*---------------------------------------------------------------------------------------------*/ ++/* { dg-final { scan-ipa-dump "No structures to transform in struct split." "struct_reorg" } } */ +-- +2.33.0 + diff --git a/0094-Backport-Fix-zero-masking-for-vcvtps2ph-when-dest-op.patch b/0094-Backport-Fix-zero-masking-for-vcvtps2ph-when-dest-op.patch new file mode 100644 index 0000000..10dc835 --- /dev/null +++ b/0094-Backport-Fix-zero-masking-for-vcvtps2ph-when-dest-op.patch @@ -0,0 +1,172 @@ +From 5b473317f6b1890238f1778d0fdebf8ed09292d9 Mon Sep 17 00:00:00 2001 +From: liuhongt <hongtao.liu@intel.com> +Date: Fri, 29 May 2020 13:38:49 +0800 +Subject: [PATCH 3/5] [Backport] Fix zero-masking for vcvtps2ph when dest + operand is memory. + +Reference: https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=43088bb4dadd3d14b6b594c5f9363fe879f3d7f7 + +When dest is memory, zero-masking is not valid, only merging-masking is available, + +2020-06-24 Hongtao Liu <hongtao.liu@inte.com> + +gcc/ChangeLog: + PR target/95254 + * config/i386/sse.md (*vcvtps2ph_store<merge_mask_name>): + Refine from *vcvtps2ph_store<mask_name>. + (vcvtps2ph256<mask_name>): Refine constraint from vm to v. + (<mask_codefor>avx512f_vcvtps2ph512<mask_name>): Ditto. + (*vcvtps2ph256<merge_mask_name>): New define_insn. + (*avx512f_vcvtps2ph512<merge_mask_name>): Ditto. + * config/i386/subst.md (merge_mask): New define_subst. + (merge_mask_name): New define_subst_attr. + (merge_mask_operand3): Ditto. + +gcc/testsuite/ChangeLog: + * gcc.target/i386/avx512f-vcvtps2ph-pr95254.c: New test. + * gcc.target/i386/avx512vl-vcvtps2ph-pr95254.c: Ditto. +--- + gcc/config/i386/sse.md | 32 ++++++++++++++++--- + gcc/config/i386/subst.md | 12 +++++++ + .../i386/avx512f-vcvtps2ph-pr95254.c | 12 +++++++ + .../i386/avx512vl-vcvtps2ph-pr95254.c | 18 +++++++++++ + 4 files changed, 70 insertions(+), 4 deletions(-) + create mode 100644 gcc/testsuite/gcc.target/i386/avx512f-vcvtps2ph-pr95254.c + create mode 100644 gcc/testsuite/gcc.target/i386/avx512vl-vcvtps2ph-pr95254.c + +diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md +index bf01e1d74..915b8e3d2 100644 +--- a/gcc/config/i386/sse.md ++++ b/gcc/config/i386/sse.md +@@ -21354,19 +21354,19 @@ + (set_attr "prefix" "maybe_evex") + (set_attr "mode" "V4SF")]) + +-(define_insn "*vcvtps2ph_store<mask_name>" ++(define_insn "*vcvtps2ph_store<merge_mask_name>" + [(set (match_operand:V4HI 0 "memory_operand" "=m") + (unspec:V4HI [(match_operand:V4SF 1 "register_operand" "v") + (match_operand:SI 2 "const_0_to_255_operand" "N")] + UNSPEC_VCVTPS2PH))] + "TARGET_F16C || TARGET_AVX512VL" +- "vcvtps2ph\t{%2, %1, %0<mask_operand3>|%0<mask_operand3>, %1, %2}" ++ "vcvtps2ph\t{%2, %1, %0<merge_mask_operand3>|%0<merge_mask_operand3>, %1, %2}" + [(set_attr "type" "ssecvt") + (set_attr "prefix" "maybe_evex") + (set_attr "mode" "V4SF")]) + + (define_insn "vcvtps2ph256<mask_name>" +- [(set (match_operand:V8HI 0 "nonimmediate_operand" "=vm") ++ [(set (match_operand:V8HI 0 "register_operand" "=v") + (unspec:V8HI [(match_operand:V8SF 1 "register_operand" "v") + (match_operand:SI 2 "const_0_to_255_operand" "N")] + UNSPEC_VCVTPS2PH))] +@@ -21377,8 +21377,20 @@ + (set_attr "btver2_decode" "vector") + (set_attr "mode" "V8SF")]) + ++(define_insn "*vcvtps2ph256<merge_mask_name>" ++ [(set (match_operand:V8HI 0 "memory_operand" "=m") ++ (unspec:V8HI [(match_operand:V8SF 1 "register_operand" "v") ++ (match_operand:SI 2 "const_0_to_255_operand" "N")] ++ UNSPEC_VCVTPS2PH))] ++ "TARGET_F16C || TARGET_AVX512VL" ++ "vcvtps2ph\t{%2, %1, %0<merge_mask_operand3>|%0<merge_mask_operand3>, %1, %2}" ++ [(set_attr "type" "ssecvt") ++ (set_attr "prefix" "maybe_evex") ++ (set_attr "btver2_decode" "vector") ++ (set_attr "mode" "V8SF")]) ++ + (define_insn "<mask_codefor>avx512f_vcvtps2ph512<mask_name>" +- [(set (match_operand:V16HI 0 "nonimmediate_operand" "=vm") ++ [(set (match_operand:V16HI 0 "register_operand" "=v") + (unspec:V16HI + [(match_operand:V16SF 1 "register_operand" "v") + (match_operand:SI 2 "const_0_to_255_operand" "N")] +@@ -21389,6 +21401,18 @@ + (set_attr "prefix" "evex") + (set_attr "mode" "V16SF")]) + ++(define_insn "*avx512f_vcvtps2ph512<merge_mask_name>" ++ [(set (match_operand:V16HI 0 "memory_operand" "=m") ++ (unspec:V16HI ++ [(match_operand:V16SF 1 "register_operand" "v") ++ (match_operand:SI 2 "const_0_to_255_operand" "N")] ++ UNSPEC_VCVTPS2PH))] ++ "TARGET_AVX512F" ++ "vcvtps2ph\t{%2, %1, %0<merge_mask_operand3>|%0<merge_mask_operand3>, %1, %2}" ++ [(set_attr "type" "ssecvt") ++ (set_attr "prefix" "evex") ++ (set_attr "mode" "V16SF")]) ++ + ;; For gather* insn patterns + (define_mode_iterator VEC_GATHER_MODE + [V2DI V2DF V4DI V4DF V4SI V4SF V8SI V8SF]) +diff --git a/gcc/config/i386/subst.md b/gcc/config/i386/subst.md +index 4a1c9b080..27eb3430d 100644 +--- a/gcc/config/i386/subst.md ++++ b/gcc/config/i386/subst.md +@@ -75,6 +75,18 @@ + (match_operand:SUBST_V 2 "nonimm_or_0_operand" "0C") + (match_operand:<avx512fmaskmode> 3 "register_operand" "Yk")))]) + ++(define_subst_attr "merge_mask_name" "merge_mask" "" "_merge_mask") ++(define_subst_attr "merge_mask_operand3" "merge_mask" "" "%{%3%}") ++(define_subst "merge_mask" ++ [(set (match_operand:SUBST_V 0) ++ (match_operand:SUBST_V 1))] ++ "TARGET_AVX512F" ++ [(set (match_dup 0) ++ (vec_merge:SUBST_V ++ (match_dup 1) ++ (match_dup 0) ++ (match_operand:<avx512fmaskmode> 2 "register_operand" "Yk")))]) ++ + (define_subst_attr "mask_scalar_merge_name" "mask_scalar_merge" "" "_mask") + (define_subst_attr "mask_scalar_merge_operand3" "mask_scalar_merge" "" "%{%3%}") + (define_subst_attr "mask_scalar_merge_operand4" "mask_scalar_merge" "" "%{%4%}") +diff --git a/gcc/testsuite/gcc.target/i386/avx512f-vcvtps2ph-pr95254.c b/gcc/testsuite/gcc.target/i386/avx512f-vcvtps2ph-pr95254.c +new file mode 100644 +index 000000000..9e0da9473 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/i386/avx512f-vcvtps2ph-pr95254.c +@@ -0,0 +1,12 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -mavx512f" } */ ++ ++#include<immintrin.h> ++extern __m256i res; ++void ++foo (__m512 a, __mmask16 m) ++{ ++ res = _mm512_maskz_cvtps_ph (m, a, 10); ++} ++ ++/* { dg-final { scan-assembler-not "vcvtps2ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]\[^\n\]*res\[^\n\]*\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)"} } */ +diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vcvtps2ph-pr95254.c b/gcc/testsuite/gcc.target/i386/avx512vl-vcvtps2ph-pr95254.c +new file mode 100644 +index 000000000..0c685ea66 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/i386/avx512vl-vcvtps2ph-pr95254.c +@@ -0,0 +1,18 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O2 -mavx512vl -mavx512f" } */ ++ ++#include<immintrin.h> ++extern __m128i res; ++void ++foo (__m256 a, __mmask8 m) ++{ ++ res = _mm256_maskz_cvtps_ph (m, a, 10); ++} ++ ++void ++foo1 (__m128 a, __mmask8 m) ++{ ++ res = _mm_maskz_cvtps_ph (m, a, 10); ++} ++ ++/* { dg-final { scan-assembler-not "vcvtps2ph\[ \\t\]+\[^\{\n\]*%\[xy\]mm\[0-9\]\[^\n\]*res\[^\n\]*\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)"} } */ +-- +2.33.0 + diff --git a/0095-Struct-reorg-Fix-the-use-of-as_a.patch b/0095-Struct-reorg-Fix-the-use-of-as_a.patch new file mode 100644 index 0000000..77a8880 --- /dev/null +++ b/0095-Struct-reorg-Fix-the-use-of-as_a.patch @@ -0,0 +1,49 @@ +From 1ab2b199a30db4ec605581a5a23b5c258a127db6 Mon Sep 17 00:00:00 2001 +From: dingguangya <dingguangya1@huawei.com> +Date: Fri, 26 May 2023 09:27:38 +0800 +Subject: [PATCH 4/5] [Struct reorg] Fix the use of as_a + +The as_a function is an internal type conversion +function in gcc, which should be: gimple * ->gcond * when used, +so fix the problem with function usage at this. +--- + gcc/ipa-struct-reorg/ipa-struct-reorg.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +index 2cac340c7..b0e4624b2 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -6607,8 +6607,7 @@ ipa_struct_reorg::compress_candidate_with_check (gimple_stmt_iterator *gsi, + gimple_set_location (cond, UNKNOWN_LOCATION); + gsi_insert_before (gsi, cond, GSI_SAME_STMT); + +- gimple* cur_stmt = as_a <gimple *> (cond); +- edge e = split_block (cur_stmt->bb, cur_stmt); ++ edge e = split_block (cond->bb, cond); + basic_block split_src_bb = e->src; + basic_block split_dst_bb = e->dest; + +@@ -6847,8 +6846,7 @@ ipa_struct_reorg::decompress_candidate_with_check (gimple_stmt_iterator *gsi, + gsi_insert_before (gsi, cond, GSI_SAME_STMT); + + /* Split bb. */ +- gimple* cur_stmt = as_a <gimple *> (cond); +- edge e = split_block (cur_stmt->bb, cur_stmt); ++ edge e = split_block (cond->bb, cond); + basic_block split_src_bb = e->src; + basic_block split_dst_bb = e->dest; + +@@ -7133,8 +7131,7 @@ ipa_struct_reorg::rewrite_pointer_plus_integer (gimple *stmt, + gimple_set_location (cond, UNKNOWN_LOCATION); + gsi_insert_before (gsi, cond, GSI_SAME_STMT); + +- gimple *curr_stmt = as_a <gimple *> (cond); +- edge e = split_block (curr_stmt->bb, curr_stmt); ++ edge e = split_block (cond->bb, cond); + basic_block split_src_bb = e->src; + basic_block split_dst_bb = e->dest; + remove_edge_raw (e); +-- +2.33.0 + diff --git a/0096-libquadmath-Revert-Enable-libquadmath-on-kunpeng.patch b/0096-libquadmath-Revert-Enable-libquadmath-on-kunpeng.patch new file mode 100644 index 0000000..4811c21 --- /dev/null +++ b/0096-libquadmath-Revert-Enable-libquadmath-on-kunpeng.patch @@ -0,0 +1,474 @@ +From 95dc65ad458a6c781536e30e65fdeec42349a0c9 Mon Sep 17 00:00:00 2001 +From: eastb233 <xiezhiheng@huawei.com> +Date: Wed, 31 May 2023 10:39:56 +0800 +Subject: [PATCH 1/3] [libquadmath] Revert "Enable libquadmath on kunpeng" + +This reverts commit 85740d3cc56fda699beae689b5d73233d16097af. + +Revert original libquadmath feature to refactor it. +--- + libquadmath/Makefile.in | 353 ++++++++++++++++++++-------------------- + libquadmath/quadmath.h | 6 +- + 2 files changed, 178 insertions(+), 181 deletions(-) + +diff --git a/libquadmath/Makefile.in b/libquadmath/Makefile.in +index 66df9c922..8c0112122 100644 +--- a/libquadmath/Makefile.in ++++ b/libquadmath/Makefile.in +@@ -90,7 +90,7 @@ POST_UNINSTALL = : + build_triplet = @build@ + host_triplet = @host@ + target_triplet = @target@ +-#libquadmath_la_DEPENDENCIES = ++@BUILD_LIBQUADMATH_FALSE@libquadmath_la_DEPENDENCIES = + subdir = . + ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 + am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \ +@@ -147,68 +147,68 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(infodir)" \ + "$(DESTDIR)$(libsubincludedir)" + LTLIBRARIES = $(toolexeclib_LTLIBRARIES) + am__dirstamp = $(am__leading_dot)dirstamp +-am_libquadmath_la_OBJECTS = math/x2y2m1q.lo \ +- math/acoshq.lo math/fmodq.lo \ +- math/acosq.lo math/frexpq.lo \ +- math/rem_pio2q.lo math/asinhq.lo \ +- math/hypotq.lo math/remainderq.lo \ +- math/asinq.lo math/rintq.lo \ +- math/atan2q.lo math/isinfq.lo \ +- math/roundq.lo math/atanhq.lo \ +- math/isnanq.lo math/scalblnq.lo \ +- math/atanq.lo math/j0q.lo \ +- math/scalbnq.lo math/cbrtq.lo \ +- math/j1q.lo math/signbitq.lo \ +- math/ceilq.lo math/jnq.lo \ +- math/sincos_table.lo math/complex.lo \ +- math/ldexpq.lo math/sincosq.lo \ +- math/copysignq.lo math/lgammaq.lo \ +- math/sincosq_kernel.lo math/coshq.lo \ +- math/llroundq.lo math/sinhq.lo \ +- math/cosq.lo math/log10q.lo \ +- math/sinq.lo math/cosq_kernel.lo \ +- math/log1pq.lo math/sinq_kernel.lo \ +- math/erfq.lo math/logq.lo \ +- math/sqrtq.lo math/expm1q.lo \ +- math/lroundq.lo math/tanhq.lo \ +- math/expq.lo math/modfq.lo \ +- math/tanq.lo math/fabsq.lo \ +- math/nanq.lo math/tgammaq.lo \ +- math/finiteq.lo math/nextafterq.lo \ +- math/truncq.lo math/floorq.lo \ +- math/powq.lo math/fmaq.lo \ +- math/logbq.lo math/exp2q.lo \ +- math/issignalingq.lo \ +- math/lgammaq_neg.lo \ +- math/lgammaq_product.lo \ +- math/tanq_kernel.lo \ +- math/tgammaq_product.lo \ +- math/casinhq_kernel.lo math/cacoshq.lo \ +- math/cacosq.lo math/casinhq.lo \ +- math/casinq.lo math/catanhq.lo \ +- math/catanq.lo math/cimagq.lo \ +- math/conjq.lo math/cprojq.lo \ +- math/crealq.lo math/fdimq.lo \ +- math/fmaxq.lo math/fminq.lo \ +- math/ilogbq.lo math/llrintq.lo \ +- math/log2q.lo math/lrintq.lo \ +- math/nearbyintq.lo math/remquoq.lo \ +- math/ccoshq.lo math/cexpq.lo \ +- math/clog10q.lo math/clogq.lo \ +- math/csinq.lo math/csinhq.lo \ +- math/csqrtq.lo math/ctanq.lo \ +- math/ctanhq.lo printf/addmul_1.lo \ +- printf/add_n.lo printf/cmp.lo \ +- printf/divrem.lo printf/flt1282mpn.lo \ +- printf/fpioconst.lo printf/lshift.lo \ +- printf/mul_1.lo printf/mul_n.lo \ +- printf/mul.lo printf/printf_fphex.lo \ +- printf/printf_fp.lo \ +- printf/quadmath-printf.lo \ +- printf/rshift.lo printf/submul_1.lo \ +- printf/sub_n.lo strtod/strtoflt128.lo \ +- strtod/mpn2flt128.lo \ +- strtod/tens_in_limb.lo ++@BUILD_LIBQUADMATH_TRUE@am_libquadmath_la_OBJECTS = math/x2y2m1q.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/acoshq.lo math/fmodq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/acosq.lo math/frexpq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/rem_pio2q.lo math/asinhq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/hypotq.lo math/remainderq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/asinq.lo math/rintq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/atan2q.lo math/isinfq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/roundq.lo math/atanhq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/isnanq.lo math/scalblnq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/atanq.lo math/j0q.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/scalbnq.lo math/cbrtq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/j1q.lo math/signbitq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/ceilq.lo math/jnq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/sincos_table.lo math/complex.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/ldexpq.lo math/sincosq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/copysignq.lo math/lgammaq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/sincosq_kernel.lo math/coshq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/llroundq.lo math/sinhq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/cosq.lo math/log10q.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/sinq.lo math/cosq_kernel.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/log1pq.lo math/sinq_kernel.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/erfq.lo math/logq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/sqrtq.lo math/expm1q.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/lroundq.lo math/tanhq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/expq.lo math/modfq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/tanq.lo math/fabsq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/nanq.lo math/tgammaq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/finiteq.lo math/nextafterq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/truncq.lo math/floorq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/powq.lo math/fmaq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/logbq.lo math/exp2q.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/issignalingq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/lgammaq_neg.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/lgammaq_product.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/tanq_kernel.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/tgammaq_product.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/casinhq_kernel.lo math/cacoshq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/cacosq.lo math/casinhq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/casinq.lo math/catanhq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/catanq.lo math/cimagq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/conjq.lo math/cprojq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/crealq.lo math/fdimq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/fmaxq.lo math/fminq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/ilogbq.lo math/llrintq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/log2q.lo math/lrintq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/nearbyintq.lo math/remquoq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/ccoshq.lo math/cexpq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/clog10q.lo math/clogq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/csinq.lo math/csinhq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/csqrtq.lo math/ctanq.lo \ ++@BUILD_LIBQUADMATH_TRUE@ math/ctanhq.lo printf/addmul_1.lo \ ++@BUILD_LIBQUADMATH_TRUE@ printf/add_n.lo printf/cmp.lo \ ++@BUILD_LIBQUADMATH_TRUE@ printf/divrem.lo printf/flt1282mpn.lo \ ++@BUILD_LIBQUADMATH_TRUE@ printf/fpioconst.lo printf/lshift.lo \ ++@BUILD_LIBQUADMATH_TRUE@ printf/mul_1.lo printf/mul_n.lo \ ++@BUILD_LIBQUADMATH_TRUE@ printf/mul.lo printf/printf_fphex.lo \ ++@BUILD_LIBQUADMATH_TRUE@ printf/printf_fp.lo \ ++@BUILD_LIBQUADMATH_TRUE@ printf/quadmath-printf.lo \ ++@BUILD_LIBQUADMATH_TRUE@ printf/rshift.lo printf/submul_1.lo \ ++@BUILD_LIBQUADMATH_TRUE@ printf/sub_n.lo strtod/strtoflt128.lo \ ++@BUILD_LIBQUADMATH_TRUE@ strtod/mpn2flt128.lo \ ++@BUILD_LIBQUADMATH_TRUE@ strtod/tens_in_limb.lo + libquadmath_la_OBJECTS = $(am_libquadmath_la_OBJECTS) + AM_V_lt = $(am__v_lt_@AM_V@) + am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +@@ -218,8 +218,8 @@ libquadmath_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libquadmath_la_LDFLAGS) $(LDFLAGS) -o \ + $@ +-am_libquadmath_la_rpath = -rpath \ +- $(toolexeclibdir) ++@BUILD_LIBQUADMATH_TRUE@am_libquadmath_la_rpath = -rpath \ ++@BUILD_LIBQUADMATH_TRUE@ $(toolexeclibdir) + AM_V_P = $(am__v_P_@AM_V@) + am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) + am__v_P_0 = false +@@ -337,7 +337,7 @@ CFLAGS = @CFLAGS@ + CPP = @CPP@ + CPPFLAGS = @CPPFLAGS@ + CYGPATH_W = @CYGPATH_W@ +-DEFS = @DEFS@ -D__float128="long double" ++DEFS = @DEFS@ + DEPDIR = @DEPDIR@ + DSYMUTIL = @DSYMUTIL@ + DUMPBIN = @DUMPBIN@ +@@ -409,7 +409,7 @@ datadir = @datadir@ + datarootdir = @datarootdir@ + docdir = @docdir@ + dvidir = @dvidir@ +-enable_shared = yes ++enable_shared = @enable_shared@ + enable_static = @enable_static@ + exec_prefix = @exec_prefix@ + get_gcc_base_ver = @get_gcc_base_ver@ +@@ -451,109 +451,109 @@ top_build_prefix = @top_build_prefix@ + top_builddir = @top_builddir@ + top_srcdir = @top_srcdir@ + AUTOMAKE_OPTIONS = foreign info-in-builddir +-ACLOCAL_AMFLAGS = -I .. -I ../config +-AM_CPPFLAGS = -I $(top_srcdir)/../include +-AM_CFLAGS = $(XCFLAGS) +-gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER) +-@LIBQUAD_USE_SYMVER_FALSE@version_arg = +-@LIBQUAD_USE_SYMVER_GNU_TRUE@@LIBQUAD_USE_SYMVER_TRUE@version_arg = -Wl,--version-script=$(srcdir)/quadmath.map +-@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@version_arg = -Wl,-M,quadmath.map-sun +-@LIBQUAD_USE_SYMVER_FALSE@version_dep = +-@LIBQUAD_USE_SYMVER_GNU_TRUE@@LIBQUAD_USE_SYMVER_TRUE@version_dep = $(srcdir)/quadmath.map +-@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@version_dep = quadmath.map-sun +-toolexeclib_LTLIBRARIES = libquadmath.la +-libquadmath_la_LIBADD = +-libquadmath_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \ +- $(version_arg) $(lt_host_flags) -lm +- +-libquadmath_la_DEPENDENCIES = $(version_dep) $(libquadmath_la_LIBADD) +-nodist_libsubinclude_HEADERS = quadmath.h quadmath_weak.h +-libsubincludedir = $(libdir)/gcc/$(target_alias)/$(gcc_version)/include +-libquadmath_la_SOURCES = \ +- math/x2y2m1q.c math/acoshq.c math/fmodq.c \ +- math/acosq.c math/frexpq.c \ +- math/rem_pio2q.c math/asinhq.c math/hypotq.c math/remainderq.c \ +- math/asinq.c math/rintq.c math/atan2q.c math/isinfq.c \ +- math/roundq.c math/atanhq.c math/isnanq.c math/scalblnq.c math/atanq.c \ +- math/j0q.c math/scalbnq.c math/cbrtq.c math/j1q.c math/signbitq.c \ +- math/ceilq.c math/jnq.c math/sincos_table.c math/complex.c math/ldexpq.c \ +- math/sincosq.c math/copysignq.c math/lgammaq.c math/sincosq_kernel.c \ +- math/coshq.c math/llroundq.c math/sinhq.c math/cosq.c math/log10q.c \ +- math/sinq.c math/cosq_kernel.c math/log1pq.c math/sinq_kernel.c \ +- math/erfq.c math/logq.c math/sqrtq.c math/expm1q.c math/lroundq.c \ +- math/tanhq.c math/expq.c math/modfq.c math/tanq.c math/fabsq.c \ +- math/nanq.c math/tgammaq.c math/finiteq.c math/nextafterq.c \ +- math/truncq.c math/floorq.c math/powq.c math/fmaq.c math/logbq.c \ +- math/exp2q.c math/issignalingq.c math/lgammaq_neg.c math/lgammaq_product.c \ +- math/tanq_kernel.c math/tgammaq_product.c math/casinhq_kernel.c \ +- math/cacoshq.c math/cacosq.c math/casinhq.c math/casinq.c \ +- math/catanhq.c math/catanq.c math/cimagq.c math/conjq.c math/cprojq.c \ +- math/crealq.c math/fdimq.c math/fmaxq.c math/fminq.c math/ilogbq.c \ +- math/llrintq.c math/log2q.c math/lrintq.c math/nearbyintq.c math/remquoq.c \ +- math/ccoshq.c math/cexpq.c math/clog10q.c math/clogq.c math/csinq.c \ +- math/csinhq.c math/csqrtq.c math/ctanq.c math/ctanhq.c \ +- printf/addmul_1.c printf/add_n.c printf/cmp.c printf/divrem.c \ +- printf/flt1282mpn.c printf/fpioconst.c printf/lshift.c printf/mul_1.c \ +- printf/mul_n.c printf/mul.c printf/printf_fphex.c printf/printf_fp.c \ +- printf/quadmath-printf.c printf/rshift.c printf/submul_1.c printf/sub_n.c \ +- strtod/strtoflt128.c strtod/mpn2flt128.c strtod/tens_in_limb.c ++@BUILD_LIBQUADMATH_TRUE@ACLOCAL_AMFLAGS = -I .. -I ../config ++@BUILD_LIBQUADMATH_TRUE@AM_CPPFLAGS = -I $(top_srcdir)/../include ++@BUILD_LIBQUADMATH_TRUE@AM_CFLAGS = $(XCFLAGS) ++@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 ++@BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_FALSE@version_dep = ++@BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_GNU_TRUE@@LIBQUAD_USE_SYMVER_TRUE@version_dep = $(srcdir)/quadmath.map ++@BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@version_dep = quadmath.map-sun ++@BUILD_LIBQUADMATH_TRUE@toolexeclib_LTLIBRARIES = libquadmath.la ++@BUILD_LIBQUADMATH_TRUE@libquadmath_la_LIBADD = ++@BUILD_LIBQUADMATH_TRUE@libquadmath_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \ ++@BUILD_LIBQUADMATH_TRUE@ $(version_arg) $(lt_host_flags) -lm ++ ++@BUILD_LIBQUADMATH_TRUE@libquadmath_la_DEPENDENCIES = $(version_dep) $(libquadmath_la_LIBADD) ++@BUILD_LIBQUADMATH_TRUE@nodist_libsubinclude_HEADERS = quadmath.h quadmath_weak.h ++@BUILD_LIBQUADMATH_TRUE@libsubincludedir = $(libdir)/gcc/$(target_alias)/$(gcc_version)/include ++@BUILD_LIBQUADMATH_TRUE@libquadmath_la_SOURCES = \ ++@BUILD_LIBQUADMATH_TRUE@ math/x2y2m1q.c math/acoshq.c math/fmodq.c \ ++@BUILD_LIBQUADMATH_TRUE@ math/acosq.c math/frexpq.c \ ++@BUILD_LIBQUADMATH_TRUE@ math/rem_pio2q.c math/asinhq.c math/hypotq.c math/remainderq.c \ ++@BUILD_LIBQUADMATH_TRUE@ math/asinq.c math/rintq.c math/atan2q.c math/isinfq.c \ ++@BUILD_LIBQUADMATH_TRUE@ math/roundq.c math/atanhq.c math/isnanq.c math/scalblnq.c math/atanq.c \ ++@BUILD_LIBQUADMATH_TRUE@ math/j0q.c math/scalbnq.c math/cbrtq.c math/j1q.c math/signbitq.c \ ++@BUILD_LIBQUADMATH_TRUE@ math/ceilq.c math/jnq.c math/sincos_table.c math/complex.c math/ldexpq.c \ ++@BUILD_LIBQUADMATH_TRUE@ math/sincosq.c math/copysignq.c math/lgammaq.c math/sincosq_kernel.c \ ++@BUILD_LIBQUADMATH_TRUE@ math/coshq.c math/llroundq.c math/sinhq.c math/cosq.c math/log10q.c \ ++@BUILD_LIBQUADMATH_TRUE@ math/sinq.c math/cosq_kernel.c math/log1pq.c math/sinq_kernel.c \ ++@BUILD_LIBQUADMATH_TRUE@ math/erfq.c math/logq.c math/sqrtq.c math/expm1q.c math/lroundq.c \ ++@BUILD_LIBQUADMATH_TRUE@ math/tanhq.c math/expq.c math/modfq.c math/tanq.c math/fabsq.c \ ++@BUILD_LIBQUADMATH_TRUE@ math/nanq.c math/tgammaq.c math/finiteq.c math/nextafterq.c \ ++@BUILD_LIBQUADMATH_TRUE@ math/truncq.c math/floorq.c math/powq.c math/fmaq.c math/logbq.c \ ++@BUILD_LIBQUADMATH_TRUE@ math/exp2q.c math/issignalingq.c math/lgammaq_neg.c math/lgammaq_product.c \ ++@BUILD_LIBQUADMATH_TRUE@ math/tanq_kernel.c math/tgammaq_product.c math/casinhq_kernel.c \ ++@BUILD_LIBQUADMATH_TRUE@ math/cacoshq.c math/cacosq.c math/casinhq.c math/casinq.c \ ++@BUILD_LIBQUADMATH_TRUE@ math/catanhq.c math/catanq.c math/cimagq.c math/conjq.c math/cprojq.c \ ++@BUILD_LIBQUADMATH_TRUE@ math/crealq.c math/fdimq.c math/fmaxq.c math/fminq.c math/ilogbq.c \ ++@BUILD_LIBQUADMATH_TRUE@ math/llrintq.c math/log2q.c math/lrintq.c math/nearbyintq.c math/remquoq.c \ ++@BUILD_LIBQUADMATH_TRUE@ math/ccoshq.c math/cexpq.c math/clog10q.c math/clogq.c math/csinq.c \ ++@BUILD_LIBQUADMATH_TRUE@ math/csinhq.c math/csqrtq.c math/ctanq.c math/ctanhq.c \ ++@BUILD_LIBQUADMATH_TRUE@ printf/addmul_1.c printf/add_n.c printf/cmp.c printf/divrem.c \ ++@BUILD_LIBQUADMATH_TRUE@ printf/flt1282mpn.c printf/fpioconst.c printf/lshift.c printf/mul_1.c \ ++@BUILD_LIBQUADMATH_TRUE@ printf/mul_n.c printf/mul.c printf/printf_fphex.c printf/printf_fp.c \ ++@BUILD_LIBQUADMATH_TRUE@ printf/quadmath-printf.c printf/rshift.c printf/submul_1.c printf/sub_n.c \ ++@BUILD_LIBQUADMATH_TRUE@ strtod/strtoflt128.c strtod/mpn2flt128.c strtod/tens_in_limb.c + + + # 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 + # friends when we are called from the top level Makefile. +-AM_MAKEFLAGS = \ +- "AR_FLAGS=$(AR_FLAGS)" \ +- "CC_FOR_BUILD=$(CC_FOR_BUILD)" \ +- "CFLAGS=$(CFLAGS)" \ +- "CXXFLAGS=$(CXXFLAGS)" \ +- "CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \ +- "CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \ +- "INSTALL=$(INSTALL)" \ +- "INSTALL_DATA=$(INSTALL_DATA)" \ +- "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \ +- "INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \ +- "JC1FLAGS=$(JC1FLAGS)" \ +- "LDFLAGS=$(LDFLAGS)" \ +- "LIBCFLAGS=$(LIBCFLAGS)" \ +- "LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \ +- "MAKE=$(MAKE)" \ +- "MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \ +- "PICFLAG=$(PICFLAG)" \ +- "PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \ +- "SHELL=$(SHELL)" \ +- "RUNTESTFLAGS=$(RUNTESTFLAGS)" \ +- "exec_prefix=$(exec_prefix)" \ +- "infodir=$(infodir)" \ +- "libdir=$(libdir)" \ +- "prefix=$(prefix)" \ +- "includedir=$(includedir)" \ +- "AR=$(AR)" \ +- "AS=$(AS)" \ +- "CC=$(CC)" \ +- "CXX=$(CXX)" \ +- "LD=$(LD)" \ +- "LIBCFLAGS=$(LIBCFLAGS)" \ +- "NM=$(NM)" \ +- "PICFLAG=$(PICFLAG)" \ +- "RANLIB=$(RANLIB)" \ +- "DESTDIR=$(DESTDIR)" ++@BUILD_LIBQUADMATH_TRUE@AM_MAKEFLAGS = \ ++@BUILD_LIBQUADMATH_TRUE@ "AR_FLAGS=$(AR_FLAGS)" \ ++@BUILD_LIBQUADMATH_TRUE@ "CC_FOR_BUILD=$(CC_FOR_BUILD)" \ ++@BUILD_LIBQUADMATH_TRUE@ "CFLAGS=$(CFLAGS)" \ ++@BUILD_LIBQUADMATH_TRUE@ "CXXFLAGS=$(CXXFLAGS)" \ ++@BUILD_LIBQUADMATH_TRUE@ "CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \ ++@BUILD_LIBQUADMATH_TRUE@ "CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \ ++@BUILD_LIBQUADMATH_TRUE@ "INSTALL=$(INSTALL)" \ ++@BUILD_LIBQUADMATH_TRUE@ "INSTALL_DATA=$(INSTALL_DATA)" \ ++@BUILD_LIBQUADMATH_TRUE@ "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \ ++@BUILD_LIBQUADMATH_TRUE@ "INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \ ++@BUILD_LIBQUADMATH_TRUE@ "JC1FLAGS=$(JC1FLAGS)" \ ++@BUILD_LIBQUADMATH_TRUE@ "LDFLAGS=$(LDFLAGS)" \ ++@BUILD_LIBQUADMATH_TRUE@ "LIBCFLAGS=$(LIBCFLAGS)" \ ++@BUILD_LIBQUADMATH_TRUE@ "LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \ ++@BUILD_LIBQUADMATH_TRUE@ "MAKE=$(MAKE)" \ ++@BUILD_LIBQUADMATH_TRUE@ "MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \ ++@BUILD_LIBQUADMATH_TRUE@ "PICFLAG=$(PICFLAG)" \ ++@BUILD_LIBQUADMATH_TRUE@ "PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \ ++@BUILD_LIBQUADMATH_TRUE@ "SHELL=$(SHELL)" \ ++@BUILD_LIBQUADMATH_TRUE@ "RUNTESTFLAGS=$(RUNTESTFLAGS)" \ ++@BUILD_LIBQUADMATH_TRUE@ "exec_prefix=$(exec_prefix)" \ ++@BUILD_LIBQUADMATH_TRUE@ "infodir=$(infodir)" \ ++@BUILD_LIBQUADMATH_TRUE@ "libdir=$(libdir)" \ ++@BUILD_LIBQUADMATH_TRUE@ "prefix=$(prefix)" \ ++@BUILD_LIBQUADMATH_TRUE@ "includedir=$(includedir)" \ ++@BUILD_LIBQUADMATH_TRUE@ "AR=$(AR)" \ ++@BUILD_LIBQUADMATH_TRUE@ "AS=$(AS)" \ ++@BUILD_LIBQUADMATH_TRUE@ "CC=$(CC)" \ ++@BUILD_LIBQUADMATH_TRUE@ "CXX=$(CXX)" \ ++@BUILD_LIBQUADMATH_TRUE@ "LD=$(LD)" \ ++@BUILD_LIBQUADMATH_TRUE@ "LIBCFLAGS=$(LIBCFLAGS)" \ ++@BUILD_LIBQUADMATH_TRUE@ "NM=$(NM)" \ ++@BUILD_LIBQUADMATH_TRUE@ "PICFLAG=$(PICFLAG)" \ ++@BUILD_LIBQUADMATH_TRUE@ "RANLIB=$(RANLIB)" \ ++@BUILD_LIBQUADMATH_TRUE@ "DESTDIR=$(DESTDIR)" + + + # Subdir rules rely on $(FLAGS_TO_PASS) +-FLAGS_TO_PASS = $(AM_MAKEFLAGS) +-MAKEOVERRIDES = +-@GENINSRC_FALSE@STAMP_GENINSRC = ++@BUILD_LIBQUADMATH_TRUE@FLAGS_TO_PASS = $(AM_MAKEFLAGS) ++@BUILD_LIBQUADMATH_TRUE@MAKEOVERRIDES = ++@BUILD_LIBQUADMATH_TRUE@@GENINSRC_FALSE@STAMP_GENINSRC = + + # AM_CONDITIONAL on configure option --generated-files-in-srcdir +-@GENINSRC_TRUE@STAMP_GENINSRC = stamp-geninsrc +-ALL_LOCAL_DEPS = $(STAMP_GENINSRC) +-@BUILD_INFO_FALSE@STAMP_BUILD_INFO = ++@BUILD_LIBQUADMATH_TRUE@@GENINSRC_TRUE@STAMP_GENINSRC = stamp-geninsrc ++@BUILD_LIBQUADMATH_TRUE@ALL_LOCAL_DEPS = $(STAMP_GENINSRC) ++@BUILD_INFO_FALSE@@BUILD_LIBQUADMATH_TRUE@STAMP_BUILD_INFO = + + # AM_CONDITIONAL on configure check ACX_CHECK_PROG_VER([MAKEINFO]) +-@BUILD_INFO_TRUE@STAMP_BUILD_INFO = stamp-build-info +-CLEANFILES = $(STAMP_GENINSRC) $(STAMP_BUILD_INFO) +-MAINTAINERCLEANFILES = $(srcdir)/libquadmath.info ++@BUILD_INFO_TRUE@@BUILD_LIBQUADMATH_TRUE@STAMP_BUILD_INFO = stamp-build-info ++@BUILD_LIBQUADMATH_TRUE@CLEANFILES = $(STAMP_GENINSRC) $(STAMP_BUILD_INFO) ++@BUILD_LIBQUADMATH_TRUE@MAINTAINERCLEANFILES = $(srcdir)/libquadmath.info + + # Automake Documentation: + # If your package has Texinfo files in many directories, you can use the +@@ -564,8 +564,8 @@ TEXINFO_TEX = ../gcc/doc/include/texinfo.tex + + # Defines info, dvi, pdf and html targets + MAKEINFOFLAGS = -I $(srcdir)/../gcc/doc/include +-info_TEXINFOS = +-info_TEXINFOS = libquadmath.texi ++@BUILD_LIBQUADMATH_FALSE@info_TEXINFOS = ++@BUILD_LIBQUADMATH_TRUE@info_TEXINFOS = libquadmath.texi + libquadmath_TEXINFOS = libquadmath-vers.texi + MULTISRCTOP = + MULTIBUILDTOP = +@@ -1187,7 +1187,6 @@ distclean-tags: + -rm -f cscope.out cscope.in.out cscope.po.out cscope.files + check-am: all-am + check: check-am +-#all-local + all-am: Makefile $(INFO_DEPS) $(LTLIBRARIES) $(HEADERS) config.h \ + all-local + installdirs: +@@ -1426,22 +1425,22 @@ uninstall-am: uninstall-dvi-am uninstall-html-am uninstall-info-am \ + + .PRECIOUS: Makefile + +-@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@quadmath.map-sun : $(srcdir)/quadmath.map \ +-@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ $(top_srcdir)/../contrib/make_sunver.pl \ +-@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ $(libquadmath_la_OBJECTS) $(libquadmath_la_LIBADD) +-@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ perl $(top_srcdir)/../contrib/make_sunver.pl \ +-@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ $(srcdir)/quadmath.map \ +-@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ `echo $(libquadmath_la_OBJECTS) $(libquadmath_la_LIBADD) | \ +-@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ sed 's,\([^/ ]*\)\.l\([ao]\),.libs/\1.\2,g'` \ +-@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ > $@ || (rm -f $@ ; exit 1) +- +-stamp-geninsrc: libquadmath.info +- cp -p $(top_builddir)/libquadmath.info $(srcdir)/libquadmath.info +- @touch $@ +- +-stamp-build-info: libquadmath.texi $(libquadmath_TEXINFOS) +- $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) -o libquadmath.info $(srcdir)/libquadmath.texi +- @touch $@ ++@BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@quadmath.map-sun : $(srcdir)/quadmath.map \ ++@BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ $(top_srcdir)/../contrib/make_sunver.pl \ ++@BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ $(libquadmath_la_OBJECTS) $(libquadmath_la_LIBADD) ++@BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ perl $(top_srcdir)/../contrib/make_sunver.pl \ ++@BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ $(srcdir)/quadmath.map \ ++@BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ `echo $(libquadmath_la_OBJECTS) $(libquadmath_la_LIBADD) | \ ++@BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ sed 's,\([^/ ]*\)\.l\([ao]\),.libs/\1.\2,g'` \ ++@BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@ > $@ || (rm -f $@ ; exit 1) ++ ++@BUILD_LIBQUADMATH_TRUE@stamp-geninsrc: libquadmath.info ++@BUILD_LIBQUADMATH_TRUE@ cp -p $(top_builddir)/libquadmath.info $(srcdir)/libquadmath.info ++@BUILD_LIBQUADMATH_TRUE@ @touch $@ ++ ++@BUILD_LIBQUADMATH_TRUE@stamp-build-info: libquadmath.texi $(libquadmath_TEXINFOS) ++@BUILD_LIBQUADMATH_TRUE@ $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) -o libquadmath.info $(srcdir)/libquadmath.texi ++@BUILD_LIBQUADMATH_TRUE@ @touch $@ + + all-local: $(ALL_LOCAL_DEPS) + +diff --git a/libquadmath/quadmath.h b/libquadmath/quadmath.h +index faa5977cb..81eb957d2 100644 +--- a/libquadmath/quadmath.h ++++ b/libquadmath/quadmath.h +@@ -27,9 +27,6 @@ Boston, MA 02110-1301, USA. */ + extern "C" { + #endif + +-#ifdef AARCH64_QUADMATH +-typedef long double __float128; +-#endif + /* Define the complex type corresponding to __float128 + ("_Complex __float128" is not allowed) */ + #if (!defined(_ARCH_PPC)) || defined(__LONG_DOUBLE_IEEE128__) +@@ -163,9 +160,10 @@ extern int quadmath_snprintf (char *str, size_t size, + #define FLT128_MAX_10_EXP 4932 + + ++#define HUGE_VALQ __builtin_huge_valq() + /* The following alternative is valid, but brings the warning: + (floating constant exceeds range of ‘__float128’) */ +- #define HUGE_VALQ (__extension__ 0x1.0p32767Q) ++/* #define HUGE_VALQ (__extension__ 0x1.0p32767Q) */ + + #define M_Eq 2.718281828459045235360287471352662498Q /* e */ + #define M_LOG2Eq 1.442695040888963407359924681001892137Q /* log_2 e */ +-- +2.33.0 + diff --git a/0097-libquadmath-refactor-Enable-libquadmath-on-kunpeng.patch b/0097-libquadmath-refactor-Enable-libquadmath-on-kunpeng.patch new file mode 100644 index 0000000..1ddcef5 --- /dev/null +++ b/0097-libquadmath-refactor-Enable-libquadmath-on-kunpeng.patch @@ -0,0 +1,197 @@ +From 60e80a17a7019026dc7e2da9dc597c9fdf426e33 Mon Sep 17 00:00:00 2001 +From: eastb233 <xiezhiheng@huawei.com> +Date: Wed, 31 May 2023 10:48:47 +0800 +Subject: [PATCH 2/3] [libquadmath][refactor] Enable libquadmath on kunpeng + +This enable libquadmath on kunpeng platform to convenient +users that migrating from x86 platform. libquadmath uses "__float128" +as quad precision floating point type and with math functions with "q" +suffix like "cosq". For those who do not need to adapt to x86 platform, +you can use "long double" as quad precision floating point type and math +functions with "l" suffix like "cosl" in libm for quad precision math. +--- + libquadmath/Makefile.am | 4 ++++ + libquadmath/Makefile.in | 3 ++- + libquadmath/configure | 28 ++++++++++++++++++++++++++-- + libquadmath/configure.ac | 7 +++++++ + libquadmath/quadmath.h | 13 +++++++++++-- + 5 files changed, 50 insertions(+), 5 deletions(-) + +diff --git a/libquadmath/Makefile.am b/libquadmath/Makefile.am +index 35dffb46f..bf0398d9c 100644 +--- a/libquadmath/Makefile.am ++++ b/libquadmath/Makefile.am +@@ -2,6 +2,10 @@ + + AUTOMAKE_OPTIONS = foreign info-in-builddir + ++if ARCH_AARCH64 ++DEFS += -D__float128="long double" ++endif ++ + ## Skip over everything if the quadlib is not available: + if BUILD_LIBQUADMATH + ACLOCAL_AMFLAGS = -I .. -I ../config +diff --git a/libquadmath/Makefile.in b/libquadmath/Makefile.in +index 8c0112122..449cc8a06 100644 +--- a/libquadmath/Makefile.in ++++ b/libquadmath/Makefile.in +@@ -90,6 +90,7 @@ POST_UNINSTALL = : + build_triplet = @build@ + host_triplet = @host@ + target_triplet = @target@ ++@ARCH_AARCH64_TRUE@am__append_1 = -D__float128="long double" + @BUILD_LIBQUADMATH_FALSE@libquadmath_la_DEPENDENCIES = + subdir = . + ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +@@ -337,7 +338,7 @@ CFLAGS = @CFLAGS@ + CPP = @CPP@ + CPPFLAGS = @CPPFLAGS@ + CYGPATH_W = @CYGPATH_W@ +-DEFS = @DEFS@ ++DEFS = @DEFS@ $(am__append_1) + DEPDIR = @DEPDIR@ + DSYMUTIL = @DSYMUTIL@ + DUMPBIN = @DUMPBIN@ +diff --git a/libquadmath/configure b/libquadmath/configure +index b5b212c06..da41959ee 100644 +--- a/libquadmath/configure ++++ b/libquadmath/configure +@@ -633,6 +633,8 @@ am__EXEEXT_TRUE + LTLIBOBJS + LIBOBJS + get_gcc_base_ver ++ARCH_AARCH64_FALSE ++ARCH_AARCH64_TRUE + GENINSRC_FALSE + GENINSRC_TRUE + XCFLAGS +@@ -10816,7 +10818,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 10819 "configure" ++#line 10821 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -10922,7 +10924,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 10925 "configure" ++#line 10927 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -12715,6 +12717,11 @@ else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + ++ #if defined(__aarch64__) ++ typedef long double __float128; ++ #define __builtin_huge_valq() (__extension__ 0x1.0p32767Q) ++ #endif ++ + #if (!defined(_ARCH_PPC)) || defined(__LONG_DOUBLE_IEEE128__) + typedef _Complex float __attribute__((mode(TC))) __complex128; + #else +@@ -12766,6 +12773,11 @@ fi + cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ + ++ #if defined(__aarch64__) ++ typedef long double __float128; ++ #define __builtin_huge_valq() (__extension__ 0x1.0p32767Q) ++ #endif ++ + #if (!defined(_ARCH_PPC)) || defined(__LONG_DOUBLE_IEEE128__) + typedef _Complex float __attribute__((mode(TC))) __complex128; + #else +@@ -13224,6 +13236,14 @@ else + GENINSRC_FALSE= + fi + ++ if expr "$target_cpu" : "aarch64.*" > /dev/null; then ++ ARCH_AARCH64_TRUE= ++ ARCH_AARCH64_FALSE='#' ++else ++ ARCH_AARCH64_TRUE='#' ++ ARCH_AARCH64_FALSE= ++fi ++ + + # Determine what GCC version number to use in filesystem paths. + +@@ -13407,6 +13427,10 @@ if test -z "${GENINSRC_TRUE}" && test -z "${GENINSRC_FALSE}"; then + as_fn_error $? "conditional \"GENINSRC\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 + fi ++if test -z "${ARCH_AARCH64_TRUE}" && test -z "${ARCH_AARCH64_FALSE}"; then ++ as_fn_error $? "conditional \"ARCH_AARCH64\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi + + : "${CONFIG_STATUS=./config.status}" + ac_write_fail=0 +diff --git a/libquadmath/configure.ac b/libquadmath/configure.ac +index f9d745e60..0b8511f04 100644 +--- a/libquadmath/configure.ac ++++ b/libquadmath/configure.ac +@@ -218,6 +218,11 @@ AM_CONDITIONAL(LIBQUAD_USE_SYMVER_SUN, [test "x$quadmath_use_symver" = xsun]) + + AC_CACHE_CHECK([whether __float128 is supported], [libquad_cv_have_float128], + [GCC_TRY_COMPILE_OR_LINK([ ++ #if defined(__aarch64__) ++ typedef long double __float128; ++ #define __builtin_huge_valq() (__extension__ 0x1.0p32767Q) ++ #endif ++ + #if (!defined(_ARCH_PPC)) || defined(__LONG_DOUBLE_IEEE128__) + typedef _Complex float __attribute__((mode(TC))) __complex128; + #else +@@ -380,6 +385,8 @@ AS_HELP_STRING([--enable-generated-files-in-srcdir], + [enable_generated_files_in_srcdir=no]) + AC_MSG_RESULT($enable_generated_files_in_srcdir) + AM_CONDITIONAL(GENINSRC, test "$enable_generated_files_in_srcdir" = yes) ++AM_CONDITIONAL(ARCH_AARCH64, ++ [expr "$target_cpu" : "aarch64.*" > /dev/null]) + + # Determine what GCC version number to use in filesystem paths. + GCC_BASE_VER +diff --git a/libquadmath/quadmath.h b/libquadmath/quadmath.h +index 81eb957d2..bb1b49df6 100644 +--- a/libquadmath/quadmath.h ++++ b/libquadmath/quadmath.h +@@ -27,6 +27,12 @@ Boston, MA 02110-1301, USA. */ + extern "C" { + #endif + ++#if defined(__aarch64__) ++#ifndef __float128 ++typedef long double __float128; ++#endif ++#endif ++ + /* Define the complex type corresponding to __float128 + ("_Complex __float128" is not allowed) */ + #if (!defined(_ARCH_PPC)) || defined(__LONG_DOUBLE_IEEE128__) +@@ -160,10 +166,13 @@ extern int quadmath_snprintf (char *str, size_t size, + #define FLT128_MAX_10_EXP 4932 + + +-#define HUGE_VALQ __builtin_huge_valq() ++#if defined(__aarch64__) + /* The following alternative is valid, but brings the warning: + (floating constant exceeds range of ‘__float128’) */ +-/* #define HUGE_VALQ (__extension__ 0x1.0p32767Q) */ ++# define HUGE_VALQ (__extension__ 0x1.0p32767Q) ++#else ++# define HUGE_VALQ __builtin_huge_valq() ++#endif + + #define M_Eq 2.718281828459045235360287471352662498Q /* e */ + #define M_LOG2Eq 1.442695040888963407359924681001892137Q /* log_2 e */ +-- +2.33.0 + diff --git a/0098-AArch64-Rewrite-the-tsv110-option.patch b/0098-AArch64-Rewrite-the-tsv110-option.patch new file mode 100644 index 0000000..d441343 --- /dev/null +++ b/0098-AArch64-Rewrite-the-tsv110-option.patch @@ -0,0 +1,114 @@ +From 4a0b942c8f6643509e6e9a605c99a258a6523308 Mon Sep 17 00:00:00 2001 +From: d00573793 <dingguangya1@huawei.com> +Date: Wed, 31 May 2023 17:00:24 +0800 +Subject: [PATCH 3/3] [AArch64] Rewrite the tsv110 option + +Reset the more appropriate options for tsv110. +--- + gcc/common/config/aarch64/aarch64-common.c | 76 ++++++++++++++++++++++ + 1 file changed, 76 insertions(+) + +diff --git a/gcc/common/config/aarch64/aarch64-common.c b/gcc/common/config/aarch64/aarch64-common.c +index 51bd319d6..2a23a605d 100644 +--- a/gcc/common/config/aarch64/aarch64-common.c ++++ b/gcc/common/config/aarch64/aarch64-common.c +@@ -44,6 +44,8 @@ + #undef TARGET_OPTION_INIT_STRUCT + #define TARGET_OPTION_INIT_STRUCT aarch64_option_init_struct + ++#define INVALID_IMP ((unsigned) -1) ++ + /* Set default optimization options. */ + static const struct default_options aarch_option_optimization_table[] = + { +@@ -65,6 +67,77 @@ static const struct default_options aarch_option_optimization_table[] = + { OPT_LEVELS_NONE, 0, NULL, 0 } + }; + ++/* CPU vendor id. */ ++static unsigned vendor_id = INVALID_IMP; ++ ++/* The part number of the CPU. */ ++static unsigned part_id = INVALID_IMP; ++ ++/* Return the hex integer that is after ':' for the FIELD. ++ Return -1 if there was problem parsing the integer. */ ++static unsigned ++parse_cpuinfo (char *field) ++{ ++ if (field == NULL) ++ return INVALID_IMP; ++ const char *rest = strchr (field, ':'); ++ ++ if (rest == NULL) ++ return INVALID_IMP; ++ ++ char *after; ++ unsigned fint = strtol (rest + 1, &after, 16); ++ if (after == rest + 1) ++ return INVALID_IMP; ++ return fint; ++} ++ ++/* Read CPU vendor_id and part_id. */ ++ ++static void ++read_cpuinfo () ++{ ++ FILE *fp = fopen ("/proc/cpuinfo", "r"); ++ if (fp == NULL) ++ return; ++ ++ /* Read 1024-byte data from /proc/cpuinfo. */ ++ char cpuinfo[1024]; ++ fread(cpuinfo, sizeof(char), sizeof(cpuinfo) - 1, fp); ++ ++ char *vendor = strstr(cpuinfo, "CPU implementer"); ++ vendor_id = parse_cpuinfo(vendor); ++ ++ char *part = strstr(cpuinfo, "CPU part"); ++ part_id = parse_cpuinfo(part); ++ ++ fclose(fp); ++} ++ ++/* Reset the tsv110 option. After checking the platform information, ++ this function can reset the more appropriate options. ++ TODO: Currently, this function is not applicable to the cross ++ compilation scenario. */ ++ ++static void ++reset_tsv110_option () ++{ ++ /* Read CPU Information. */ ++ if (vendor_id == INVALID_IMP) ++ read_cpuinfo (); ++ ++ if (vendor_id == 0x48 && part_id == 0xd01) ++ { ++ /* Outline-atomics is enabled by default and ++ aarch64_flag_outline_atomics defaults to 2. Therefore, the current ++ modification affects only the default scenario. When the option ++ moutline-atomics is added, the value of aarch64_flag_outline_atomics is 1, ++ that is, aarch64_flag_outline_atomics is not reset to 0. */ ++ if (aarch64_flag_outline_atomics == 2) ++ aarch64_flag_outline_atomics = 0; ++ } ++} ++ + /* Implement TARGET_HANDLE_OPTION. + This function handles the target specific options for CPU/target selection. + +@@ -83,6 +156,9 @@ aarch64_handle_option (struct gcc_options *opts, + const char *arg = decoded->arg; + int val = decoded->value; + ++ /* Reset the tsv110 options. */ ++ reset_tsv110_option (); ++ + switch (code) + { + case OPT_march_: +-- +2.33.0 + diff --git a/0099-Struct-Reorg-Add-escape-propagate-on-external-functi.patch b/0099-Struct-Reorg-Add-escape-propagate-on-external-functi.patch new file mode 100644 index 0000000..db9038e --- /dev/null +++ b/0099-Struct-Reorg-Add-escape-propagate-on-external-functi.patch @@ -0,0 +1,258 @@ +From c6370dc949c39319ef1c31d0b42efc041d27379a Mon Sep 17 00:00:00 2001 +From: huang-xiaoquan <huangxiaoquan1@huawei.com> +Date: Thu, 8 Jun 2023 11:37:09 +0800 +Subject: [PATCH] [Struct Reorg] Add escape propagate on external functions + using type + +External functions may use members of members through structure pointers. +Therefore, escape propagation of member types of types used by external +functions is added. +--- + gcc/ipa-struct-reorg/ipa-struct-reorg.c | 71 +++++++++++++++++-- + gcc/testsuite/gcc.dg/struct/dfe_extr_claw.c | 7 ++ + .../gcc.dg/struct/rf_external_func_types.c | 69 ++++++++++++++++++ + 3 files changed, 140 insertions(+), 7 deletions(-) + create mode 100644 gcc/testsuite/gcc.dg/struct/rf_external_func_types.c + +diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +index 7de4fee0e..367bcf210 100644 +--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c ++++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c +@@ -1412,6 +1412,7 @@ public: + srglobal globals; + srfunction *current_function; + hash_set <cgraph_node *> safe_functions; ++ auto_vec<srtype *> ext_func_types; + + bool done_recording; + +@@ -1426,6 +1427,7 @@ public: + void propagate_escape (void); + void propagate_escape_via_original (void); + void propagate_escape_via_empty_with_no_original (void); ++ void propagate_escape_via_ext_func_types (void); + void analyze_types (void); + void clear_visited (void); + bool create_new_types (void); +@@ -3131,7 +3133,14 @@ ipa_struct_reorg::record_type (tree type) + return NULL; + + if (dump_file && (dump_flags & TDF_DETAILS)) +- fprintf (dump_file, "Recording new type: %u.\n", typeuid); ++ { ++ fprintf (dump_file, "Recording new type: %u.\n", typeuid); ++ const char *type_name = get_type_name (type); ++ if (type_name == NULL) ++ fprintf (dump_file, "Recording new type NULL name\n"); ++ else ++ fprintf (dump_file, "Recording new type name: %s.\n", type_name); ++ } + + type1 = new srtype (type); + types.safe_push (type1); +@@ -4478,6 +4487,18 @@ ipa_struct_reorg::maybe_record_call (cgraph_node *node, gcall *stmt) + gimple_call_arg (stmt, i)); + if (d) + d->type->mark_escape (escapes, stmt); ++ ++ if (escapes == escape_external_function ++ && !gimple_call_builtin_p (stmt, BUILT_IN_MEMSET)) ++ { ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ { ++ fprintf (dump_file, "escape_external_function: "); ++ print_gimple_stmt (dump_file, stmt, 0); ++ } ++ if (d) ++ ext_func_types.safe_push (d->type); ++ } + } + return; + } +@@ -5672,6 +5693,35 @@ ipa_struct_reorg::propagate_escape_via_empty_with_no_original (void) + } + } + ++/* Escape propagation is performed on types that escape through external ++ functions. */ ++ ++void ++ipa_struct_reorg::propagate_escape_via_ext_func_types (void) ++{ ++ if (dump_file && (dump_flags & TDF_DETAILS)) ++ fprintf (dump_file, "\n propagate_escape_via_ext_func_types: \n\n"); ++ unsigned i = 0; ++ hash_set<srtype *> visited_types; ++ while (i < ext_func_types.length ()) ++ { ++ visited_types.add (ext_func_types[i]); ++ unsigned j = 0; ++ srfield * field; ++ FOR_EACH_VEC_ELT (ext_func_types[i]->fields, j, field) ++ { ++ if (field->type) ++ { ++ if (!field->type->has_escaped ()) ++ field->type->mark_escape (escape_dependent_type_escapes, NULL); ++ if (!visited_types.contains (field->type)) ++ ext_func_types.safe_push (field->type); ++ } ++ } ++ i++; ++ } ++} ++ + /* Prune the escaped types and their decls from what was recorded. */ + + void +@@ -5689,6 +5739,7 @@ ipa_struct_reorg::prune_escaped_types (void) + { + propagate_escape_via_original (); + propagate_escape_via_empty_with_no_original (); ++ propagate_escape_via_ext_func_types (); + } + + if (dump_file && (dump_flags & TDF_DETAILS)) +@@ -8242,8 +8293,9 @@ ipa_struct_reorg::rewrite_functions (void) + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "\nNo rewrite:\n"); +- dump_function_to_file (current_function_decl, dump_file, +- dump_flags | TDF_VOPS); ++ if (current_function_decl) ++ dump_function_to_file (current_function_decl, dump_file, ++ dump_flags | TDF_VOPS); + } + pop_cfun (); + } +@@ -8278,8 +8330,9 @@ ipa_struct_reorg::rewrite_functions (void) + { + fprintf (dump_file, "==== Before create decls: %dth_%s ====\n\n", + i, f->node->name ()); +- dump_function_to_file (current_function_decl, dump_file, +- dump_flags | TDF_VOPS); ++ if (current_function_decl) ++ dump_function_to_file (current_function_decl, dump_file, ++ dump_flags | TDF_VOPS); + } + pop_cfun (); + } +@@ -8313,8 +8366,9 @@ ipa_struct_reorg::rewrite_functions (void) + { + fprintf (dump_file, "\nBefore rewrite: %dth_%s\n", + i, f->node->name ()); +- dump_function_to_file (current_function_decl, dump_file, +- dump_flags | TDF_VOPS); ++ if (current_function_decl) ++ dump_function_to_file (current_function_decl, dump_file, ++ dump_flags | TDF_VOPS); + fprintf (dump_file, "\n======== Start to rewrite: %dth_%s ========\n", + i, f->node->name ()); + } +@@ -8659,6 +8713,9 @@ ipa_struct_reorg::execute (unsigned int opt) + { + unsigned int ret = 0; + ++ if (dump_file) ++ fprintf (dump_file, "\n\n====== ipa_struct_reorg level %d ======\n\n", opt); ++ + if (opt != COMPLETE_STRUCT_RELAYOUT) + { + current_layout_opt_level = opt; +diff --git a/gcc/testsuite/gcc.dg/struct/dfe_extr_claw.c b/gcc/testsuite/gcc.dg/struct/dfe_extr_claw.c +index e56bf467b..f9e2cf471 100644 +--- a/gcc/testsuite/gcc.dg/struct/dfe_extr_claw.c ++++ b/gcc/testsuite/gcc.dg/struct/dfe_extr_claw.c +@@ -42,6 +42,13 @@ int WS_APPL_NAME_PACKED; + int claw_send_control (struct net_device*, int, int, int, int, int, int); + int setup; + ++__attribute__((noinline)) int ++claw_send_control (struct net_device* net, int a, int b, int c, int d, int e, ++ int f) ++{ ++ return net->ml_priv->system_validate_comp + a + b + c + d + f; ++} ++ + __attribute__((used)) static int + claw_snd_conn_req (struct net_device *dev, __u8 link) + { +diff --git a/gcc/testsuite/gcc.dg/struct/rf_external_func_types.c b/gcc/testsuite/gcc.dg/struct/rf_external_func_types.c +new file mode 100644 +index 000000000..2a9bea783 +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/struct/rf_external_func_types.c +@@ -0,0 +1,69 @@ ++/* { dg-do compile } */ ++/* { dg-additional-options "-shared" } */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++typedef struct node node_t; ++typedef struct node *node_p; ++ ++typedef struct arc arc_t; ++typedef struct arc *arc_p; ++ ++typedef struct network ++{ ++ int x; ++ arc_p arcs, sorted_arcs; ++ node_p nodes, stop_nodes; ++} network_t; ++ ++struct node ++{ ++ int64_t potential; ++ int orientation; ++ node_p child; ++ node_p pred; ++ node_p sibling; ++ node_p sibling_prev; ++ arc_p basic_arc; ++ arc_p firstout; ++ arc_p firstin; ++ arc_p arc_tmp; ++ int64_t flow; ++ int64_t depth; ++ int number; ++ int time; ++}; ++ ++struct arc ++{ ++ int id; ++ int64_t cost; ++ node_p tail; ++ node_p head; ++ short ident; ++ arc_p nextout; ++ arc_p nextin; ++ int64_t flow; ++ int64_t org_cost; ++}; ++ ++extern int bcf_sr_add_reader (network_t *); ++extern int bcf_hdr_dup (arc_p); ++ ++int ++test () ++{ ++ network_t *net = (network_t *) calloc (1, 20); ++ ++ if (!bcf_sr_add_reader(net)) ++ printf("error"); ++ arc_p arc = net->nodes->basic_arc; ++ if(!bcf_hdr_dup(arc)) ++ { ++ return -1; ++ } ++ return 0; ++} ++ ++/* { dg-final { scan-ipa-dump "No structures to transform." "struct_reorg" } } */ +\ No newline at end of file +-- +2.33.0 + diff --git a/0100-PGO-kernel-Add-fkernel-pgo-option-to-support-PGO-ker.patch b/0100-PGO-kernel-Add-fkernel-pgo-option-to-support-PGO-ker.patch new file mode 100644 index 0000000..a77c072 --- /dev/null +++ b/0100-PGO-kernel-Add-fkernel-pgo-option-to-support-PGO-ker.patch @@ -0,0 +1,46 @@ +From 90d3ef0637c66045eeab78ccf04e9ff51b9b451a Mon Sep 17 00:00:00 2001 +From: xiongzhou4 <xiongzhou4@huawei.com> +Date: Thu, 1 Jun 2023 09:28:27 +0800 +Subject: [PATCH 5/5] [PGO kernel] Add fkernel-pgo option to support PGO kernel + compilation. + +If specified, disable TLS setting of instrumentation variables in +gcc/tree-profile.c, as kernel does not support TLS. +--- + gcc/common.opt | 4 ++++ + gcc/tree-profile.c | 4 +++- + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/gcc/common.opt b/gcc/common.opt +index 238c97db8..6f0ed7cea 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -2302,6 +2302,10 @@ fprofile-generate= + Common Joined RejectNegative + Enable common options for generating profile info for profile feedback directed optimizations, and set -fprofile-dir=. + ++fkernel-pgo ++Common Report Var(flag_kernel_pgo) Optimization Init(0) ++Disable TLS setting of instrumentation variables to support PGO kernel compilation in -fprofile-generate, as kernel does not support TLS. ++ + fprofile-partial-training + Common Report Var(flag_profile_partial_training) Optimization + Do not assume that functions never executed during the train run are cold. +diff --git a/gcc/tree-profile.c b/gcc/tree-profile.c +index 6c0838261..924817472 100644 +--- a/gcc/tree-profile.c ++++ b/gcc/tree-profile.c +@@ -105,7 +105,9 @@ init_ic_make_global_vars (void) + DECL_ARTIFICIAL (ic_tuple_var) = 1; + DECL_INITIAL (ic_tuple_var) = NULL; + DECL_EXTERNAL (ic_tuple_var) = 1; +- if (targetm.have_tls) ++ /* Disable TLS setting when compiling kernel in -fprofile-generate, ++ as kernel does not support TLS. */ ++ if (targetm.have_tls && !flag_kernel_pgo) + set_decl_tls_model (ic_tuple_var, decl_default_tls_model (ic_tuple_var)); + } + +-- +2.33.0 + diff --git a/0101-To-resolve-the-SPEC-.548-fluctuation-problem-revert-.patch b/0101-To-resolve-the-SPEC-.548-fluctuation-problem-revert-.patch new file mode 100644 index 0000000..836197a --- /dev/null +++ b/0101-To-resolve-the-SPEC-.548-fluctuation-problem-revert-.patch @@ -0,0 +1,26 @@ +From 962eda7f0336c883c52c33a9b61a19f7e80ea9e2 Mon Sep 17 00:00:00 2001 +From: root <root@localhost.localdomain> +Date: Tue, 6 Jun 2023 22:29:03 +0800 +Subject: [PATCH] To resolve the SPEC .548 fluctuation problem, revert GCC + commit 835d50c66aa5bde2f354a6e63a2afa7d2f76a05a + +--- + gcc/config/aarch64/aarch64.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 85dbd3898..116b4b8ca 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -12726,7 +12726,7 @@ cost_plus: + } + + if (GET_MODE_CLASS (mode) == MODE_INT +- && (aarch64_plus_immediate (op1, mode) ++ && ((CONST_INT_P (op1) && aarch64_uimm12_shift (INTVAL (op1))) + || aarch64_sve_addvl_addpl_immediate (op1, mode))) + { + *cost += rtx_cost (op0, mode, PLUS, 0, speed); +-- +2.33.0 + diff --git a/0102-GOMP-Enabling-moutline-atomics-improves-libgomp-perf.patch b/0102-GOMP-Enabling-moutline-atomics-improves-libgomp-perf.patch new file mode 100644 index 0000000..019af78 --- /dev/null +++ b/0102-GOMP-Enabling-moutline-atomics-improves-libgomp-perf.patch @@ -0,0 +1,34 @@ +From 8aeb2d4d05f6c0ba949fa3fa85ea5ac75a7255c9 Mon Sep 17 00:00:00 2001 +From: d00573793 <dingguangya1@huawei.com> +Date: Mon, 19 Jun 2023 23:56:49 +0800 +Subject: [PATCH] [GOMP] Enabling moutline-atomics improves libgomp performance + in multi-thread scenarios + +Libgomp is used in multi-thread scenarios, +Enabling moutline-atomics improves performance. + +diff --git a/libgomp/configure.tgt b/libgomp/configure.tgt +index 4790a31e3..e5b558be0 100644 +--- a/libgomp/configure.tgt ++++ b/libgomp/configure.tgt +@@ -30,6 +30,17 @@ if test $gcc_cv_have_tls = yes ; then + esac + fi + ++# Enabling moutline-atomics improves libgomp performance in multi-thread scenarios. ++case "${target_cpu}" in ++ aarch64*) ++ case "${target}" in ++ aarch64*-*-linux*) ++ XCFLAGS="${XCFLAGS} -moutline-atomics" ++ ;; ++ esac ++ ;; ++esac ++ + # Since we require POSIX threads, assume a POSIX system by default. + config_path="posix" + +-- +2.27.0.windows.1 + diff --git a/0103-test-Add-option-ftree-fold-phiopt-to-avoid-fail-NFC.patch b/0103-test-Add-option-ftree-fold-phiopt-to-avoid-fail-NFC.patch new file mode 100644 index 0000000..6bc7758 --- /dev/null +++ b/0103-test-Add-option-ftree-fold-phiopt-to-avoid-fail-NFC.patch @@ -0,0 +1,143 @@ +From 1d0bbeb4171f21baf18db6a802bd0b9685e2d25b Mon Sep 17 00:00:00 2001 +From: zhongyunde <zhongyunde@huawei.com> +Date: Tue, 20 Jun 2023 08:59:57 +0800 +Subject: [PATCH] [test] Add option -ftree-fold-phiopt to avoid fail, NFC + +Fix https://gitee.com/openeuler/gcc/issues/I7EQCC?from=project-issue +--- + gcc/testsuite/c-c++-common/ubsan/pr85213.c | 2 +- + gcc/testsuite/gcc.dg/uninit-8.c | 2 +- + gcc/testsuite/gcc.target/aarch64/bics_3.c | 2 +- + gcc/testsuite/gcc.target/aarch64/scalar-vca.c | 2 +- + gcc/testsuite/gcc.target/aarch64/scalar_intrinsics.c | 2 +- + gcc/testsuite/gcc.target/aarch64/simd/int_comparisons_1.c | 2 +- + gcc/testsuite/gcc.target/aarch64/simd/vcaled_f64.c | 2 +- + gcc/testsuite/gcc.target/aarch64/simd/vcales_f32.c | 2 +- + gcc/testsuite/gcc.target/aarch64/simd/vcaltd_f64.c | 2 +- + gcc/testsuite/gcc.target/aarch64/simd/vcalts_f32.c | 2 +- + 10 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/gcc/testsuite/c-c++-common/ubsan/pr85213.c b/gcc/testsuite/c-c++-common/ubsan/pr85213.c +index 8a6be81d2..804c29da7 100644 +--- a/gcc/testsuite/c-c++-common/ubsan/pr85213.c ++++ b/gcc/testsuite/c-c++-common/ubsan/pr85213.c +@@ -1,6 +1,6 @@ + /* PR sanitizer/85213 */ + /* { dg-do compile } */ +-/* { dg-options "-O1 -fsanitize=undefined -fcompare-debug" } */ ++/* { dg-options "-O1 -ftree-fold-phiopt -fsanitize=undefined -fcompare-debug" } */ + + int + foo (int x) +diff --git a/gcc/testsuite/gcc.dg/uninit-8.c b/gcc/testsuite/gcc.dg/uninit-8.c +index 98700f4aa..e8fd942cf 100644 +--- a/gcc/testsuite/gcc.dg/uninit-8.c ++++ b/gcc/testsuite/gcc.dg/uninit-8.c +@@ -3,7 +3,7 @@ + May be the same as uninit-1.c. */ + + /* { dg-do compile } */ +-/* { dg-options "-O -Wuninitialized" } */ ++/* { dg-options "-O -ftree-fold-phiopt -Wuninitialized" } */ + + #include <limits.h> + +diff --git a/gcc/testsuite/gcc.target/aarch64/bics_3.c b/gcc/testsuite/gcc.target/aarch64/bics_3.c +index 3257df622..ab6f0210e 100644 +--- a/gcc/testsuite/gcc.target/aarch64/bics_3.c ++++ b/gcc/testsuite/gcc.target/aarch64/bics_3.c +@@ -1,5 +1,5 @@ + /* { dg-do run } */ +-/* { dg-options "-O2 --save-temps" } */ ++/* { dg-options "-O2 -ftree-fold-phiopt --save-temps" } */ + + extern void abort (void); + +diff --git a/gcc/testsuite/gcc.target/aarch64/scalar-vca.c b/gcc/testsuite/gcc.target/aarch64/scalar-vca.c +index 40a359725..58ce99328 100644 +--- a/gcc/testsuite/gcc.target/aarch64/scalar-vca.c ++++ b/gcc/testsuite/gcc.target/aarch64/scalar-vca.c +@@ -1,5 +1,5 @@ + /* { dg-do run } */ +-/* { dg-options "-O3 --save-temps" } */ ++/* { dg-options "-O3 -ftree-fold-phiopt --save-temps" } */ + + #include <arm_neon.h> + +diff --git a/gcc/testsuite/gcc.target/aarch64/scalar_intrinsics.c b/gcc/testsuite/gcc.target/aarch64/scalar_intrinsics.c +index c2e13b651..bcd7e4c83 100644 +--- a/gcc/testsuite/gcc.target/aarch64/scalar_intrinsics.c ++++ b/gcc/testsuite/gcc.target/aarch64/scalar_intrinsics.c +@@ -1,5 +1,5 @@ + /* { dg-do compile } */ +-/* { dg-options "-O2 -dp" } */ ++/* { dg-options "-O2 -ftree-fold-phiopt -dp" } */ + + #include <arm_neon.h> + +diff --git a/gcc/testsuite/gcc.target/aarch64/simd/int_comparisons_1.c b/gcc/testsuite/gcc.target/aarch64/simd/int_comparisons_1.c +index f2c55922f..3f989257b 100644 +--- a/gcc/testsuite/gcc.target/aarch64/simd/int_comparisons_1.c ++++ b/gcc/testsuite/gcc.target/aarch64/simd/int_comparisons_1.c +@@ -1,5 +1,5 @@ + /* { dg-do compile } */ +-/* { dg-options "-O3 -fno-inline" } */ ++/* { dg-options "-O3 -ftree-fold-phiopt -fno-inline" } */ + + /* Scan-assembler test, so, incorporate as little other code as possible. */ + +diff --git a/gcc/testsuite/gcc.target/aarch64/simd/vcaled_f64.c b/gcc/testsuite/gcc.target/aarch64/simd/vcaled_f64.c +index 198b18b4e..357d0f61a 100644 +--- a/gcc/testsuite/gcc.target/aarch64/simd/vcaled_f64.c ++++ b/gcc/testsuite/gcc.target/aarch64/simd/vcaled_f64.c +@@ -1,7 +1,7 @@ + /* Test the vcaled_f64 AArch64 SIMD intrinsic. */ + + /* { dg-do run } */ +-/* { dg-options "-save-temps -O3" } */ ++/* { dg-options "-save-temps -O3 -ftree-fold-phiopt" } */ + + #include "arm_neon.h" + +diff --git a/gcc/testsuite/gcc.target/aarch64/simd/vcales_f32.c b/gcc/testsuite/gcc.target/aarch64/simd/vcales_f32.c +index 6b58501f3..a2b5a5f50 100644 +--- a/gcc/testsuite/gcc.target/aarch64/simd/vcales_f32.c ++++ b/gcc/testsuite/gcc.target/aarch64/simd/vcales_f32.c +@@ -1,7 +1,7 @@ + /* Test the vcales_f32 AArch64 SIMD intrinsic. */ + + /* { dg-do run } */ +-/* { dg-options "-save-temps -O3" } */ ++/* { dg-options "-save-temps -O3 -ftree-fold-phiopt" } */ + + #include "arm_neon.h" + +diff --git a/gcc/testsuite/gcc.target/aarch64/simd/vcaltd_f64.c b/gcc/testsuite/gcc.target/aarch64/simd/vcaltd_f64.c +index 50a3b2718..d77f68378 100644 +--- a/gcc/testsuite/gcc.target/aarch64/simd/vcaltd_f64.c ++++ b/gcc/testsuite/gcc.target/aarch64/simd/vcaltd_f64.c +@@ -1,7 +1,7 @@ + /* Test the vcaltd_f64 AArch64 SIMD intrinsic. */ + + /* { dg-do run } */ +-/* { dg-options "-save-temps -O3" } */ ++/* { dg-options "-save-temps -O3 -ftree-fold-phiopt" } */ + + #include "arm_neon.h" + +diff --git a/gcc/testsuite/gcc.target/aarch64/simd/vcalts_f32.c b/gcc/testsuite/gcc.target/aarch64/simd/vcalts_f32.c +index 1807e0b95..d723b9ac5 100644 +--- a/gcc/testsuite/gcc.target/aarch64/simd/vcalts_f32.c ++++ b/gcc/testsuite/gcc.target/aarch64/simd/vcalts_f32.c +@@ -1,7 +1,7 @@ + /* Test the vcalts_f32 AArch64 SIMD intrinsic. */ + + /* { dg-do run } */ +-/* { dg-options "-save-temps -O3" } */ ++/* { dg-options "-save-temps -O3 -ftree-fold-phiopt" } */ + + #include "arm_neon.h" + +-- +2.33.0 + diff --git a/0104-aarch64-Use-local-frame-vars-in-shrink-wrapping-code.patch b/0104-aarch64-Use-local-frame-vars-in-shrink-wrapping-code.patch new file mode 100644 index 0000000..1cc0839 --- /dev/null +++ b/0104-aarch64-Use-local-frame-vars-in-shrink-wrapping-code.patch @@ -0,0 +1,348 @@ +From 153060b97c667bbd06caad9c3fc1f9f6fe7266df Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Fri, 16 Jun 2023 16:43:41 +0100 +Subject: [PATCH] aarch64: Use local frame vars in shrink-wrapping code + +aarch64_layout_frame uses a shorthand for referring to +cfun->machine->frame: + + aarch64_frame &frame = cfun->machine->frame; + +This patch does the same for some other heavy users of the structure. +No functional change intended. + +gcc/ + * config/aarch64/aarch64.c (aarch64_save_callee_saves): Use + a local shorthand for cfun->machine->frame. + (aarch64_restore_callee_saves, aarch64_get_separate_components): + (aarch64_process_components): Likewise. + (aarch64_allocate_and_probe_stack_space): Likewise. + (aarch64_expand_prologue, aarch64_expand_epilogue): Likewise. + (aarch64_layout_frame): Use existing shorthand for one more case. +--- + gcc/config/aarch64/aarch64.c | 115 ++++++++++++++++++----------------- + 1 file changed, 60 insertions(+), 55 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index e6bf5ae3808..368bb394105 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -7403,6 +7403,7 @@ aarch64_save_callee_saves (poly_int64 start_offset, + unsigned start, unsigned limit, bool skip_wb, + bool hard_fp_valid_p) + { ++ aarch64_frame &frame = cfun->machine->frame; + rtx_insn *insn; + unsigned regno; + unsigned regno2; +@@ -7417,8 +7418,8 @@ aarch64_save_callee_saves (poly_int64 start_offset, + bool frame_related_p = aarch64_emit_cfi_for_reg_p (regno); + + if (skip_wb +- && (regno == cfun->machine->frame.wb_candidate1 +- || regno == cfun->machine->frame.wb_candidate2)) ++ && (regno == frame.wb_candidate1 ++ || regno == frame.wb_candidate2)) + continue; + + if (cfun->machine->reg_is_wrapped_separately[regno]) +@@ -7426,7 +7427,7 @@ aarch64_save_callee_saves (poly_int64 start_offset, + + machine_mode mode = aarch64_reg_save_mode (regno); + reg = gen_rtx_REG (mode, regno); +- offset = start_offset + cfun->machine->frame.reg_offset[regno]; ++ offset = start_offset + frame.reg_offset[regno]; + rtx base_rtx = stack_pointer_rtx; + poly_int64 sp_offset = offset; + +@@ -7439,7 +7440,7 @@ aarch64_save_callee_saves (poly_int64 start_offset, + { + gcc_assert (known_eq (start_offset, 0)); + poly_int64 fp_offset +- = cfun->machine->frame.below_hard_fp_saved_regs_size; ++ = frame.below_hard_fp_saved_regs_size; + if (hard_fp_valid_p) + base_rtx = hard_frame_pointer_rtx; + else +@@ -7461,8 +7462,7 @@ aarch64_save_callee_saves (poly_int64 start_offset, + && (regno2 = aarch64_next_callee_save (regno + 1, limit)) <= limit + && !cfun->machine->reg_is_wrapped_separately[regno2] + && known_eq (GET_MODE_SIZE (mode), +- cfun->machine->frame.reg_offset[regno2] +- - cfun->machine->frame.reg_offset[regno])) ++ frame.reg_offset[regno2] - frame.reg_offset[regno])) + { + rtx reg2 = gen_rtx_REG (mode, regno2); + rtx mem2; +@@ -7512,6 +7512,7 @@ static void + aarch64_restore_callee_saves (poly_int64 start_offset, unsigned start, + unsigned limit, bool skip_wb, rtx *cfi_ops) + { ++ aarch64_frame &frame = cfun->machine->frame; + unsigned regno; + unsigned regno2; + poly_int64 offset; +@@ -7528,13 +7529,13 @@ aarch64_restore_callee_saves (poly_int64 start_offset, unsigned start, + rtx reg, mem; + + if (skip_wb +- && (regno == cfun->machine->frame.wb_candidate1 +- || regno == cfun->machine->frame.wb_candidate2)) ++ && (regno == frame.wb_candidate1 ++ || regno == frame.wb_candidate2)) + continue; + + machine_mode mode = aarch64_reg_save_mode (regno); + reg = gen_rtx_REG (mode, regno); +- offset = start_offset + cfun->machine->frame.reg_offset[regno]; ++ offset = start_offset + frame.reg_offset[regno]; + rtx base_rtx = stack_pointer_rtx; + if (mode == VNx2DImode && BYTES_BIG_ENDIAN) + aarch64_adjust_sve_callee_save_base (mode, base_rtx, anchor_reg, +@@ -7545,8 +7546,7 @@ aarch64_restore_callee_saves (poly_int64 start_offset, unsigned start, + && (regno2 = aarch64_next_callee_save (regno + 1, limit)) <= limit + && !cfun->machine->reg_is_wrapped_separately[regno2] + && known_eq (GET_MODE_SIZE (mode), +- cfun->machine->frame.reg_offset[regno2] +- - cfun->machine->frame.reg_offset[regno])) ++ frame.reg_offset[regno2] - frame.reg_offset[regno])) + { + rtx reg2 = gen_rtx_REG (mode, regno2); + rtx mem2; +@@ -7640,6 +7640,7 @@ offset_12bit_unsigned_scaled_p (machine_mode mode, poly_int64 offset) + static sbitmap + aarch64_get_separate_components (void) + { ++ aarch64_frame &frame = cfun->machine->frame; + sbitmap components = sbitmap_alloc (LAST_SAVED_REGNUM + 1); + bitmap_clear (components); + +@@ -7656,18 +7657,18 @@ aarch64_get_separate_components (void) + if (mode == VNx2DImode && BYTES_BIG_ENDIAN) + continue; + +- poly_int64 offset = cfun->machine->frame.reg_offset[regno]; ++ poly_int64 offset = frame.reg_offset[regno]; + + /* If the register is saved in the first SVE save slot, we use + it as a stack probe for -fstack-clash-protection. */ + if (flag_stack_clash_protection +- && maybe_ne (cfun->machine->frame.below_hard_fp_saved_regs_size, 0) ++ && maybe_ne (frame.below_hard_fp_saved_regs_size, 0) + && known_eq (offset, 0)) + continue; + + /* Get the offset relative to the register we'll use. */ + if (frame_pointer_needed) +- offset -= cfun->machine->frame.below_hard_fp_saved_regs_size; ++ offset -= frame.below_hard_fp_saved_regs_size; + else + offset += crtl->outgoing_args_size; + +@@ -7686,11 +7687,11 @@ aarch64_get_separate_components (void) + /* If the spare predicate register used by big-endian SVE code + is call-preserved, it must be saved in the main prologue + before any saves that use it. */ +- if (cfun->machine->frame.spare_pred_reg != INVALID_REGNUM) +- bitmap_clear_bit (components, cfun->machine->frame.spare_pred_reg); ++ if (frame.spare_pred_reg != INVALID_REGNUM) ++ bitmap_clear_bit (components, frame.spare_pred_reg); + +- unsigned reg1 = cfun->machine->frame.wb_candidate1; +- unsigned reg2 = cfun->machine->frame.wb_candidate2; ++ unsigned reg1 = frame.wb_candidate1; ++ unsigned reg2 = frame.wb_candidate2; + /* If registers have been chosen to be stored/restored with + writeback don't interfere with them to avoid having to output explicit + stack adjustment instructions. */ +@@ -7799,6 +7800,7 @@ aarch64_get_next_set_bit (sbitmap bmp, unsigned int start) + static void + aarch64_process_components (sbitmap components, bool prologue_p) + { ++ aarch64_frame &frame = cfun->machine->frame; + rtx ptr_reg = gen_rtx_REG (Pmode, frame_pointer_needed + ? HARD_FRAME_POINTER_REGNUM + : STACK_POINTER_REGNUM); +@@ -7813,9 +7815,9 @@ aarch64_process_components (sbitmap components, bool prologue_p) + machine_mode mode = aarch64_reg_save_mode (regno); + + rtx reg = gen_rtx_REG (mode, regno); +- poly_int64 offset = cfun->machine->frame.reg_offset[regno]; ++ poly_int64 offset = frame.reg_offset[regno]; + if (frame_pointer_needed) +- offset -= cfun->machine->frame.below_hard_fp_saved_regs_size; ++ offset -= frame.below_hard_fp_saved_regs_size; + else + offset += crtl->outgoing_args_size; + +@@ -7840,14 +7842,14 @@ aarch64_process_components (sbitmap components, bool prologue_p) + break; + } + +- poly_int64 offset2 = cfun->machine->frame.reg_offset[regno2]; ++ poly_int64 offset2 = frame.reg_offset[regno2]; + /* The next register is not of the same class or its offset is not + mergeable with the current one into a pair. */ + if (aarch64_sve_mode_p (mode) + || !satisfies_constraint_Ump (mem) + || GP_REGNUM_P (regno) != GP_REGNUM_P (regno2) + || (crtl->abi->id () == ARM_PCS_SIMD && FP_REGNUM_P (regno)) +- || maybe_ne ((offset2 - cfun->machine->frame.reg_offset[regno]), ++ || maybe_ne ((offset2 - frame.reg_offset[regno]), + GET_MODE_SIZE (mode))) + { + insn = emit_insn (set); +@@ -7869,7 +7871,7 @@ aarch64_process_components (sbitmap components, bool prologue_p) + /* REGNO2 can be saved/restored in a pair with REGNO. */ + rtx reg2 = gen_rtx_REG (mode, regno2); + if (frame_pointer_needed) +- offset2 -= cfun->machine->frame.below_hard_fp_saved_regs_size; ++ offset2 -= frame.below_hard_fp_saved_regs_size; + else + offset2 += crtl->outgoing_args_size; + rtx addr2 = plus_constant (Pmode, ptr_reg, offset2); +@@ -7964,6 +7966,7 @@ aarch64_allocate_and_probe_stack_space (rtx temp1, rtx temp2, + bool frame_related_p, + bool final_adjustment_p) + { ++ aarch64_frame &frame = cfun->machine->frame; + HOST_WIDE_INT guard_size + = 1 << param_stack_clash_protection_guard_size; + HOST_WIDE_INT guard_used_by_caller = STACK_CLASH_CALLER_GUARD; +@@ -7984,25 +7987,25 @@ aarch64_allocate_and_probe_stack_space (rtx temp1, rtx temp2, + register as a probe. We can't assume that LR was saved at position 0 + though, so treat any space below it as unprobed. */ + if (final_adjustment_p +- && known_eq (cfun->machine->frame.below_hard_fp_saved_regs_size, 0)) ++ && known_eq (frame.below_hard_fp_saved_regs_size, 0)) + { +- poly_int64 lr_offset = cfun->machine->frame.reg_offset[LR_REGNUM]; ++ poly_int64 lr_offset = frame.reg_offset[LR_REGNUM]; + if (known_ge (lr_offset, 0)) + min_probe_threshold -= lr_offset.to_constant (); + else + gcc_assert (!flag_stack_clash_protection || known_eq (poly_size, 0)); + } + +- poly_int64 frame_size = cfun->machine->frame.frame_size; ++ poly_int64 frame_size = frame.frame_size; + + /* We should always have a positive probe threshold. */ + gcc_assert (min_probe_threshold > 0); + + if (flag_stack_clash_protection && !final_adjustment_p) + { +- poly_int64 initial_adjust = cfun->machine->frame.initial_adjust; +- poly_int64 sve_callee_adjust = cfun->machine->frame.sve_callee_adjust; +- poly_int64 final_adjust = cfun->machine->frame.final_adjust; ++ poly_int64 initial_adjust = frame.initial_adjust; ++ poly_int64 sve_callee_adjust = frame.sve_callee_adjust; ++ poly_int64 final_adjust = frame.final_adjust; + + if (known_eq (frame_size, 0)) + { +@@ -8291,17 +8294,18 @@ aarch64_epilogue_uses (int regno) + void + aarch64_expand_prologue (void) + { +- poly_int64 frame_size = cfun->machine->frame.frame_size; +- poly_int64 initial_adjust = cfun->machine->frame.initial_adjust; +- HOST_WIDE_INT callee_adjust = cfun->machine->frame.callee_adjust; +- poly_int64 final_adjust = cfun->machine->frame.final_adjust; +- poly_int64 callee_offset = cfun->machine->frame.callee_offset; +- poly_int64 sve_callee_adjust = cfun->machine->frame.sve_callee_adjust; ++ aarch64_frame &frame = cfun->machine->frame; ++ poly_int64 frame_size = frame.frame_size; ++ poly_int64 initial_adjust = frame.initial_adjust; ++ HOST_WIDE_INT callee_adjust = frame.callee_adjust; ++ poly_int64 final_adjust = frame.final_adjust; ++ poly_int64 callee_offset = frame.callee_offset; ++ poly_int64 sve_callee_adjust = frame.sve_callee_adjust; + poly_int64 below_hard_fp_saved_regs_size +- = cfun->machine->frame.below_hard_fp_saved_regs_size; +- unsigned reg1 = cfun->machine->frame.wb_candidate1; +- unsigned reg2 = cfun->machine->frame.wb_candidate2; +- bool emit_frame_chain = cfun->machine->frame.emit_frame_chain; ++ = frame.below_hard_fp_saved_regs_size; ++ unsigned reg1 = frame.wb_candidate1; ++ unsigned reg2 = frame.wb_candidate2; ++ bool emit_frame_chain = frame.emit_frame_chain; + rtx_insn *insn; + + if (flag_stack_clash_protection && known_eq (callee_adjust, 0)) +@@ -8367,7 +8371,7 @@ aarch64_expand_prologue (void) + + /* The offset of the frame chain record (if any) from the current SP. */ + poly_int64 chain_offset = (initial_adjust + callee_adjust +- - cfun->machine->frame.hard_fp_offset); ++ - frame.hard_fp_offset); + gcc_assert (known_ge (chain_offset, 0)); + + /* The offset of the bottom of the save area from the current SP. */ +@@ -8470,15 +8474,16 @@ aarch64_use_return_insn_p (void) + void + aarch64_expand_epilogue (bool for_sibcall) + { +- poly_int64 initial_adjust = cfun->machine->frame.initial_adjust; +- HOST_WIDE_INT callee_adjust = cfun->machine->frame.callee_adjust; +- poly_int64 final_adjust = cfun->machine->frame.final_adjust; +- poly_int64 callee_offset = cfun->machine->frame.callee_offset; +- poly_int64 sve_callee_adjust = cfun->machine->frame.sve_callee_adjust; ++ aarch64_frame &frame = cfun->machine->frame; ++ poly_int64 initial_adjust = frame.initial_adjust; ++ HOST_WIDE_INT callee_adjust = frame.callee_adjust; ++ poly_int64 final_adjust = frame.final_adjust; ++ poly_int64 callee_offset = frame.callee_offset; ++ poly_int64 sve_callee_adjust = frame.sve_callee_adjust; + poly_int64 below_hard_fp_saved_regs_size +- = cfun->machine->frame.below_hard_fp_saved_regs_size; +- unsigned reg1 = cfun->machine->frame.wb_candidate1; +- unsigned reg2 = cfun->machine->frame.wb_candidate2; ++ = frame.below_hard_fp_saved_regs_size; ++ unsigned reg1 = frame.wb_candidate1; ++ unsigned reg2 = frame.wb_candidate2; + rtx cfi_ops = NULL; + rtx_insn *insn; + /* A stack clash protection prologue may not have left EP0_REGNUM or +@@ -8511,7 +8516,7 @@ aarch64_expand_epilogue (bool for_sibcall) + /* We need to add memory barrier to prevent read from deallocated stack. */ + bool need_barrier_p + = maybe_ne (get_frame_size () +- + cfun->machine->frame.saved_varargs_size, 0); ++ + frame.saved_varargs_size, 0); + + /* Emit a barrier to prevent loads from a deallocated stack. */ + if (maybe_gt (final_adjust, crtl->outgoing_args_size) +@@ -11170,24 +11175,24 @@ aarch64_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to) + poly_int64 + aarch64_initial_elimination_offset (unsigned from, unsigned to) + { ++ aarch64_frame &frame = cfun->machine->frame; ++ + if (to == HARD_FRAME_POINTER_REGNUM) + { + if (from == ARG_POINTER_REGNUM) +- return cfun->machine->frame.hard_fp_offset; ++ return frame.hard_fp_offset; + + if (from == FRAME_POINTER_REGNUM) +- return cfun->machine->frame.hard_fp_offset +- - cfun->machine->frame.locals_offset; ++ return frame.hard_fp_offset - frame.locals_offset; + } + + if (to == STACK_POINTER_REGNUM) + { + if (from == FRAME_POINTER_REGNUM) +- return cfun->machine->frame.frame_size +- - cfun->machine->frame.locals_offset; ++ return frame.frame_size - frame.locals_offset; + } + +- return cfun->machine->frame.frame_size; ++ return frame.frame_size; + } + + +-- +2.39.3 diff --git a/0105-aarch64-Avoid-a-use-of-callee_offset.patch b/0105-aarch64-Avoid-a-use-of-callee_offset.patch new file mode 100644 index 0000000..9b6d88c --- /dev/null +++ b/0105-aarch64-Avoid-a-use-of-callee_offset.patch @@ -0,0 +1,72 @@ +From 901269e14884a86c532b99fb41d5f46b519344f0 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Tue, 27 Jun 2023 11:12:21 +0100 +Subject: [PATCH] aarch64: Avoid a use of callee_offset + +When we emit the frame chain, i.e. when we reach Here in this statement +of aarch64_expand_prologue: + + if (emit_frame_chain) + { + // Here + ... + } + +the stack is in one of two states: + +- We've allocated up to the frame chain, but no more. + +- We've allocated the whole frame, and the frame chain is within easy + reach of the new SP. + +The offset of the frame chain from the current SP is available +in aarch64_frame as callee_offset. It is also available as the +chain_offset local variable, where the latter is calculated from other +data. (However, chain_offset is not always equal to callee_offset when +!emit_frame_chain, so chain_offset isn't redundant.) + +In c600df9a4060da3c6121ff4d0b93f179eafd69d1 I switched to using +chain_offset for the initialisation of the hard frame pointer: + + aarch64_add_offset (Pmode, hard_frame_pointer_rtx, +- stack_pointer_rtx, callee_offset, ++ stack_pointer_rtx, chain_offset, + tmp1_rtx, tmp0_rtx, frame_pointer_needed); + +But the later REG_CFA_ADJUST_CFA handling still used callee_offset. + +I think the difference is harmless, but it's more logical for the +CFA note to be in sync, and it's more convenient for later patches +if it uses chain_offset. + +gcc/ + * config/aarch64/aarch64.c (aarch64_expand_prologue): Use + chain_offset rather than callee_offset. +--- + gcc/config/aarch64/aarch64.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 368bb394105..2aaf187bcc3 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -8299,7 +8299,6 @@ aarch64_expand_prologue (void) + poly_int64 initial_adjust = frame.initial_adjust; + HOST_WIDE_INT callee_adjust = frame.callee_adjust; + poly_int64 final_adjust = frame.final_adjust; +- poly_int64 callee_offset = frame.callee_offset; + poly_int64 sve_callee_adjust = frame.sve_callee_adjust; + poly_int64 below_hard_fp_saved_regs_size + = frame.below_hard_fp_saved_regs_size; +@@ -8408,8 +8407,7 @@ aarch64_expand_prologue (void) + implicit. */ + if (!find_reg_note (insn, REG_CFA_ADJUST_CFA, NULL_RTX)) + { +- rtx src = plus_constant (Pmode, stack_pointer_rtx, +- callee_offset); ++ rtx src = plus_constant (Pmode, stack_pointer_rtx, chain_offset); + add_reg_note (insn, REG_CFA_ADJUST_CFA, + gen_rtx_SET (hard_frame_pointer_rtx, src)); + } +-- +2.39.3 diff --git a/0106-aarch64-Explicitly-handle-frames-with-no-saved-registers.patch b/0106-aarch64-Explicitly-handle-frames-with-no-saved-registers.patch new file mode 100644 index 0000000..b1ba615 --- /dev/null +++ b/0106-aarch64-Explicitly-handle-frames-with-no-saved-registers.patch @@ -0,0 +1,47 @@ +From c8ffe35ca907e0042524a5369158fcb5631d5108 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Fri, 16 Jun 2023 17:00:51 +0100 +Subject: [PATCH] aarch64: Explicitly handle frames with no saved registers + +If a frame has no saved registers, it can be allocated in one go. +There is no need to treat the areas below and above the saved +registers as separate. + +And if we allocate the frame in one go, it should be allocated +as the initial_adjust rather than the final_adjust. This allows the +frame size to grow to guard_size - guard_used_by_caller before a stack +probe is needed. (A frame with no register saves is necessarily a +leaf frame.) + +This is a no-op as thing stand, since a leaf function will have +no outgoing arguments, and so all the frame will be above where +the saved registers normally go. + +gcc/ + * config/aarch64/aarch64.c (aarch64_layout_frame): Explicitly + allocate the frame in one go if there are no saved registers. +--- + gcc/config/aarch64/aarch64.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 2aaf187bcc3..81537c01951 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -7035,9 +7035,11 @@ aarch64_layout_frame (void) + + HOST_WIDE_INT const_size, const_outgoing_args_size, const_fp_offset; + HOST_WIDE_INT const_saved_regs_size; +- if (frame.frame_size.is_constant (&const_size) +- && const_size < max_push_offset +- && known_eq (frame.hard_fp_offset, const_size)) ++ if (known_eq (frame.saved_regs_size, 0)) ++ frame.initial_adjust = frame.frame_size; ++ else if (frame.frame_size.is_constant (&const_size) ++ && const_size < max_push_offset ++ && known_eq (frame.hard_fp_offset, const_size)) + { + /* Simple, small frame with no outgoing arguments: + +-- +2.39.3 diff --git a/0107-aarch64-Add-bytes_below_saved_regs-to-frame-info.patch b/0107-aarch64-Add-bytes_below_saved_regs-to-frame-info.patch new file mode 100644 index 0000000..a8f6d44 --- /dev/null +++ b/0107-aarch64-Add-bytes_below_saved_regs-to-frame-info.patch @@ -0,0 +1,232 @@ +From 781490f3e1bd3789048485981e5039300abf41cb Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Fri, 16 Jun 2023 16:55:12 +0100 +Subject: [PATCH] aarch64: Add bytes_below_saved_regs to frame info + +The frame layout code currently hard-codes the assumption that +the number of bytes below the saved registers is equal to the +size of the outgoing arguments. This patch abstracts that +value into a new field of aarch64_frame. + +gcc/ + * config/aarch64/aarch64.h (aarch64_frame::bytes_below_saved_regs): New + field. + * config/aarch64/aarch64.c (aarch64_layout_frame): Initialize it, + and use it instead of crtl->outgoing_args_size. + (aarch64_get_separate_components): Use bytes_below_saved_regs instead + of outgoing_args_size. + (aarch64_process_components): Likewise. +--- + gcc/config/aarch64/aarch64.c | 71 ++++++++++++++++++------------------ + gcc/config/aarch64/aarch64.h | 5 +++ + 2 files changed, 41 insertions(+), 35 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 81537c01951..6109518189f 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -6902,6 +6902,8 @@ aarch64_layout_frame (void) + gcc_assert (crtl->is_leaf + || maybe_ne (frame.reg_offset[R30_REGNUM], SLOT_NOT_REQUIRED)); + ++ frame.bytes_below_saved_regs = crtl->outgoing_args_size; ++ + /* Now assign stack slots for the registers. Start with the predicate + registers, since predicate LDR and STR have a relatively small + offset range. These saves happen below the hard frame pointer. */ +@@ -7006,18 +7008,18 @@ aarch64_layout_frame (void) + + poly_int64 varargs_and_saved_regs_size = offset + frame.saved_varargs_size; + +- poly_int64 above_outgoing_args ++ poly_int64 saved_regs_and_above + = aligned_upper_bound (varargs_and_saved_regs_size + + get_frame_size (), + STACK_BOUNDARY / BITS_PER_UNIT); + + frame.hard_fp_offset +- = above_outgoing_args - frame.below_hard_fp_saved_regs_size; ++ = saved_regs_and_above - frame.below_hard_fp_saved_regs_size; + + /* Both these values are already aligned. */ +- gcc_assert (multiple_p (crtl->outgoing_args_size, ++ gcc_assert (multiple_p (frame.bytes_below_saved_regs, + STACK_BOUNDARY / BITS_PER_UNIT)); +- frame.frame_size = above_outgoing_args + crtl->outgoing_args_size; ++ frame.frame_size = saved_regs_and_above + frame.bytes_below_saved_regs; + + frame.locals_offset = frame.saved_varargs_size; + +@@ -7033,7 +7035,7 @@ aarch64_layout_frame (void) + else if (frame.wb_candidate1 != INVALID_REGNUM) + max_push_offset = 256; + +- HOST_WIDE_INT const_size, const_outgoing_args_size, const_fp_offset; ++ HOST_WIDE_INT const_size, const_below_saved_regs, const_fp_offset; + HOST_WIDE_INT const_saved_regs_size; + if (known_eq (frame.saved_regs_size, 0)) + frame.initial_adjust = frame.frame_size; +@@ -7041,31 +7043,31 @@ aarch64_layout_frame (void) + && const_size < max_push_offset + && known_eq (frame.hard_fp_offset, const_size)) + { +- /* Simple, small frame with no outgoing arguments: ++ /* Simple, small frame with no data below the saved registers. + + stp reg1, reg2, [sp, -frame_size]! + stp reg3, reg4, [sp, 16] */ + frame.callee_adjust = const_size; + } +- else if (crtl->outgoing_args_size.is_constant (&const_outgoing_args_size) ++ else if (frame.bytes_below_saved_regs.is_constant (&const_below_saved_regs) + && frame.saved_regs_size.is_constant (&const_saved_regs_size) +- && const_outgoing_args_size + const_saved_regs_size < 512 +- /* We could handle this case even with outgoing args, provided +- that the number of args left us with valid offsets for all +- predicate and vector save slots. It's such a rare case that +- it hardly seems worth the effort though. */ +- && (!saves_below_hard_fp_p || const_outgoing_args_size == 0) ++ && const_below_saved_regs + const_saved_regs_size < 512 ++ /* We could handle this case even with data below the saved ++ registers, provided that that data left us with valid offsets ++ for all predicate and vector save slots. It's such a rare ++ case that it hardly seems worth the effort though. */ ++ && (!saves_below_hard_fp_p || const_below_saved_regs == 0) + && !(cfun->calls_alloca + && frame.hard_fp_offset.is_constant (&const_fp_offset) + && const_fp_offset < max_push_offset)) + { +- /* Frame with small outgoing arguments: ++ /* Frame with small area below the saved registers: + + sub sp, sp, frame_size +- stp reg1, reg2, [sp, outgoing_args_size] +- stp reg3, reg4, [sp, outgoing_args_size + 16] */ ++ stp reg1, reg2, [sp, bytes_below_saved_regs] ++ stp reg3, reg4, [sp, bytes_below_saved_regs + 16] */ + frame.initial_adjust = frame.frame_size; +- frame.callee_offset = const_outgoing_args_size; ++ frame.callee_offset = const_below_saved_regs; + } + else if (saves_below_hard_fp_p + && known_eq (frame.saved_regs_size, +@@ -7075,30 +7077,29 @@ aarch64_layout_frame (void) + + sub sp, sp, hard_fp_offset + below_hard_fp_saved_regs_size + save SVE registers relative to SP +- sub sp, sp, outgoing_args_size */ ++ sub sp, sp, bytes_below_saved_regs */ + frame.initial_adjust = (frame.hard_fp_offset + + frame.below_hard_fp_saved_regs_size); +- frame.final_adjust = crtl->outgoing_args_size; ++ frame.final_adjust = frame.bytes_below_saved_regs; + } + else if (frame.hard_fp_offset.is_constant (&const_fp_offset) + && const_fp_offset < max_push_offset) + { +- /* Frame with large outgoing arguments or SVE saves, but with +- a small local area: ++ /* Frame with large area below the saved registers, or with SVE saves, ++ but with a small area above: + + stp reg1, reg2, [sp, -hard_fp_offset]! + stp reg3, reg4, [sp, 16] + [sub sp, sp, below_hard_fp_saved_regs_size] + [save SVE registers relative to SP] +- sub sp, sp, outgoing_args_size */ ++ sub sp, sp, bytes_below_saved_regs */ + frame.callee_adjust = const_fp_offset; + frame.sve_callee_adjust = frame.below_hard_fp_saved_regs_size; +- frame.final_adjust = crtl->outgoing_args_size; ++ frame.final_adjust = frame.bytes_below_saved_regs; + } + else + { +- /* Frame with large local area and outgoing arguments or SVE saves, +- using frame pointer: ++ /* General case: + + sub sp, sp, hard_fp_offset + stp x29, x30, [sp, 0] +@@ -7106,10 +7107,10 @@ aarch64_layout_frame (void) + stp reg3, reg4, [sp, 16] + [sub sp, sp, below_hard_fp_saved_regs_size] + [save SVE registers relative to SP] +- sub sp, sp, outgoing_args_size */ ++ sub sp, sp, bytes_below_saved_regs */ + frame.initial_adjust = frame.hard_fp_offset; + frame.sve_callee_adjust = frame.below_hard_fp_saved_regs_size; +- frame.final_adjust = crtl->outgoing_args_size; ++ frame.final_adjust = frame.bytes_below_saved_regs; + } + + /* Make sure the individual adjustments add up to the full frame size. */ +@@ -7672,7 +7673,7 @@ aarch64_get_separate_components (void) + if (frame_pointer_needed) + offset -= frame.below_hard_fp_saved_regs_size; + else +- offset += crtl->outgoing_args_size; ++ offset += frame.bytes_below_saved_regs; + + /* Check that we can access the stack slot of the register with one + direct load with no adjustments needed. */ +@@ -7821,7 +7822,7 @@ aarch64_process_components (sbitmap components, bool prologue_p) + if (frame_pointer_needed) + offset -= frame.below_hard_fp_saved_regs_size; + else +- offset += crtl->outgoing_args_size; ++ offset += frame.bytes_below_saved_regs; + + rtx addr = plus_constant (Pmode, ptr_reg, offset); + rtx mem = gen_frame_mem (mode, addr); +@@ -7875,7 +7876,7 @@ aarch64_process_components (sbitmap components, bool prologue_p) + if (frame_pointer_needed) + offset2 -= frame.below_hard_fp_saved_regs_size; + else +- offset2 += crtl->outgoing_args_size; ++ offset2 += frame.bytes_below_saved_regs; + rtx addr2 = plus_constant (Pmode, ptr_reg, offset2); + rtx mem2 = gen_frame_mem (mode, addr2); + rtx set2 = prologue_p ? gen_rtx_SET (mem2, reg2) +@@ -7949,10 +7950,10 @@ aarch64_stack_clash_protection_alloca_probe_range (void) + registers. If POLY_SIZE is not large enough to require a probe this function + will only adjust the stack. When allocating the stack space + FRAME_RELATED_P is then used to indicate if the allocation is frame related. +- FINAL_ADJUSTMENT_P indicates whether we are allocating the outgoing +- arguments. If we are then we ensure that any allocation larger than the ABI +- defined buffer needs a probe so that the invariant of having a 1KB buffer is +- maintained. ++ FINAL_ADJUSTMENT_P indicates whether we are allocating the area below ++ the saved registers. If we are then we ensure that any allocation ++ larger than the ABI defined buffer needs a probe so that the ++ invariant of having a 1KB buffer is maintained. + + We emit barriers after each stack adjustment to prevent optimizations from + breaking the invariant that we never drop the stack more than a page. This +@@ -8161,7 +8162,7 @@ aarch64_allocate_and_probe_stack_space (rtx temp1, rtx temp2, + /* Handle any residuals. Residuals of at least MIN_PROBE_THRESHOLD have to + be probed. This maintains the requirement that each page is probed at + least once. For initial probing we probe only if the allocation is +- more than GUARD_SIZE - buffer, and for the outgoing arguments we probe ++ more than GUARD_SIZE - buffer, and below the saved registers we probe + if the amount is larger than buffer. GUARD_SIZE - buffer + buffer == + GUARD_SIZE. This works that for any allocation that is large enough to + trigger a probe here, we'll have at least one, and if they're not large +diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h +index 9be4ec3d280..083ffbfbc53 100644 +--- a/gcc/config/aarch64/aarch64.h ++++ b/gcc/config/aarch64/aarch64.h +@@ -820,6 +820,11 @@ struct GTY (()) aarch64_frame + /* The size of the callee-save registers with a slot in REG_OFFSET. */ + poly_int64 saved_regs_size; + ++ /* The number of bytes between the bottom of the static frame (the bottom ++ of the outgoing arguments) and the bottom of the register save area. ++ This value is always a multiple of STACK_BOUNDARY. */ ++ poly_int64 bytes_below_saved_regs; ++ + /* The size of the callee-save registers with a slot in REG_OFFSET that + are saved below the hard frame pointer. */ + poly_int64 below_hard_fp_saved_regs_size; +-- +2.39.3 diff --git a/0108-aarch64-Add-bytes_below_hard_fp-to-frame-info.patch b/0108-aarch64-Add-bytes_below_hard_fp-to-frame-info.patch new file mode 100644 index 0000000..a95a651 --- /dev/null +++ b/0108-aarch64-Add-bytes_below_hard_fp-to-frame-info.patch @@ -0,0 +1,83 @@ +From a519149de34facf645064c1ea5748aeb7d72aca4 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Tue, 27 Jun 2023 11:17:33 +0100 +Subject: [PATCH] aarch64: Add bytes_below_hard_fp to frame info + +Following on from the previous bytes_below_saved_regs patch, this one +records the number of bytes that are below the hard frame pointer. +This eventually replaces below_hard_fp_saved_regs_size. + +If a frame pointer is not needed, the epilogue adds final_adjust +to the stack pointer before restoring registers: + + aarch64_add_sp (tmp1_rtx, tmp0_rtx, final_adjust, true); + +Therefore, if the epilogue needs to restore the stack pointer from +the hard frame pointer, the directly corresponding offset is: + + -bytes_below_hard_fp + final_adjust + +i.e. go from the hard frame pointer to the bottom of the frame, +then add the same amount as if we were using the stack pointer +from the outset. + +gcc/ + * config/aarch64/aarch64.h (aarch64_frame::bytes_below_hard_fp): New + field. + * config/aarch64/aarch64.c (aarch64_layout_frame): Initialize it. + (aarch64_expand_epilogue): Use it instead of + below_hard_fp_saved_regs_size. +--- + gcc/config/aarch64/aarch64.c | 6 +++--- + gcc/config/aarch64/aarch64.h | 5 +++++ + 2 files changed, 8 insertions(+), 3 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 6109518189f..2652515b361 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -6954,6 +6954,7 @@ aarch64_layout_frame (void) + of the callee save area. */ + bool saves_below_hard_fp_p = maybe_ne (offset, 0); + frame.below_hard_fp_saved_regs_size = offset; ++ frame.bytes_below_hard_fp = offset + frame.bytes_below_saved_regs; + if (frame.emit_frame_chain) + { + /* FP and LR are placed in the linkage record. */ +@@ -8481,8 +8482,7 @@ aarch64_expand_epilogue (bool for_sibcall) + poly_int64 final_adjust = frame.final_adjust; + poly_int64 callee_offset = frame.callee_offset; + poly_int64 sve_callee_adjust = frame.sve_callee_adjust; +- poly_int64 below_hard_fp_saved_regs_size +- = frame.below_hard_fp_saved_regs_size; ++ poly_int64 bytes_below_hard_fp = frame.bytes_below_hard_fp; + unsigned reg1 = frame.wb_candidate1; + unsigned reg2 = frame.wb_candidate2; + rtx cfi_ops = NULL; +@@ -8538,7 +8538,7 @@ aarch64_expand_epilogue (bool for_sibcall) + is restored on the instruction doing the writeback. */ + aarch64_add_offset (Pmode, stack_pointer_rtx, + hard_frame_pointer_rtx, +- -callee_offset - below_hard_fp_saved_regs_size, ++ -bytes_below_hard_fp + final_adjust, + tmp1_rtx, tmp0_rtx, callee_adjust == 0); + else + /* The case where we need to re-use the register here is very rare, so +diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h +index 083ffbfbc53..a4cbc678cef 100644 +--- a/gcc/config/aarch64/aarch64.h ++++ b/gcc/config/aarch64/aarch64.h +@@ -829,6 +829,11 @@ struct GTY (()) aarch64_frame + are saved below the hard frame pointer. */ + poly_int64 below_hard_fp_saved_regs_size; + ++ /* The number of bytes between the bottom of the static frame (the bottom ++ of the outgoing arguments) and the hard frame pointer. This value is ++ always a multiple of STACK_BOUNDARY. */ ++ poly_int64 bytes_below_hard_fp; ++ + /* Offset from the base of the frame (incomming SP) to the + top of the locals area. This value is always a multiple of + STACK_BOUNDARY. */ +-- +2.39.3 diff --git a/0109-aarch64-Tweak-aarch64_save-restore_callee_saves.patch b/0109-aarch64-Tweak-aarch64_save-restore_callee_saves.patch new file mode 100644 index 0000000..8e01e1a --- /dev/null +++ b/0109-aarch64-Tweak-aarch64_save-restore_callee_saves.patch @@ -0,0 +1,220 @@ +From 6ef2e97b16bea4d4ce2cd52de444a3a2595504d6 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Tue, 27 Jun 2023 11:21:41 +0100 +Subject: [PATCH] aarch64: Tweak aarch64_save/restore_callee_saves + +aarch64_save_callee_saves and aarch64_restore_callee_saves took +a parameter called start_offset that gives the offset of the +bottom of the saved register area from the current stack pointer. +However, it's more convenient for later patches if we use the +bottom of the entire frame as the reference point, rather than +the bottom of the saved registers. + +Doing that removes the need for the callee_offset field. +Other than that, this is not a win on its own. It only really +makes sense in combination with the follow-on patches. + +gcc/ + * config/aarch64/aarch64.h (aarch64_frame::callee_offset): Delete. + * config/aarch64/aarch64.c (aarch64_layout_frame): Remove + callee_offset handling. + (aarch64_save_callee_saves): Replace the start_offset parameter + with a bytes_below_sp parameter. + (aarch64_restore_callee_saves): Likewise. + (aarch64_expand_prologue): Update accordingly. + (aarch64_expand_epilogue): Likewise. +--- + gcc/config/aarch64/aarch64.c | 56 ++++++++++++++++++------------------ + gcc/config/aarch64/aarch64.h | 4 --- + 2 files changed, 28 insertions(+), 32 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 2652515b361..884002e3b7b 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -7028,7 +7028,6 @@ aarch64_layout_frame (void) + frame.final_adjust = 0; + frame.callee_adjust = 0; + frame.sve_callee_adjust = 0; +- frame.callee_offset = 0; + + HOST_WIDE_INT max_push_offset = 0; + if (frame.wb_candidate2 != INVALID_REGNUM) +@@ -7068,7 +7067,6 @@ aarch64_layout_frame (void) + stp reg1, reg2, [sp, bytes_below_saved_regs] + stp reg3, reg4, [sp, bytes_below_saved_regs + 16] */ + frame.initial_adjust = frame.frame_size; +- frame.callee_offset = const_below_saved_regs; + } + else if (saves_below_hard_fp_p + && known_eq (frame.saved_regs_size, +@@ -7398,12 +7396,13 @@ aarch64_add_cfa_expression (rtx_insn *insn, rtx reg, + } + + /* Emit code to save the callee-saved registers from register number START +- to LIMIT to the stack at the location starting at offset START_OFFSET, +- skipping any write-back candidates if SKIP_WB is true. HARD_FP_VALID_P +- is true if the hard frame pointer has been set up. */ ++ to LIMIT to the stack. The stack pointer is currently BYTES_BELOW_SP ++ bytes above the bottom of the static frame. Skip any write-back ++ candidates if SKIP_WB is true. HARD_FP_VALID_P is true if the hard ++ frame pointer has been set up. */ + + static void +-aarch64_save_callee_saves (poly_int64 start_offset, ++aarch64_save_callee_saves (poly_int64 bytes_below_sp, + unsigned start, unsigned limit, bool skip_wb, + bool hard_fp_valid_p) + { +@@ -7431,7 +7430,9 @@ aarch64_save_callee_saves (poly_int64 start_offset, + + machine_mode mode = aarch64_reg_save_mode (regno); + reg = gen_rtx_REG (mode, regno); +- offset = start_offset + frame.reg_offset[regno]; ++ offset = (frame.reg_offset[regno] ++ + frame.bytes_below_saved_regs ++ - bytes_below_sp); + rtx base_rtx = stack_pointer_rtx; + poly_int64 sp_offset = offset; + +@@ -7442,9 +7443,7 @@ aarch64_save_callee_saves (poly_int64 start_offset, + else if (GP_REGNUM_P (regno) + && (!offset.is_constant (&const_offset) || const_offset >= 512)) + { +- gcc_assert (known_eq (start_offset, 0)); +- poly_int64 fp_offset +- = frame.below_hard_fp_saved_regs_size; ++ poly_int64 fp_offset = frame.bytes_below_hard_fp - bytes_below_sp; + if (hard_fp_valid_p) + base_rtx = hard_frame_pointer_rtx; + else +@@ -7508,12 +7507,13 @@ aarch64_save_callee_saves (poly_int64 start_offset, + } + + /* Emit code to restore the callee registers from register number START +- up to and including LIMIT. Restore from the stack offset START_OFFSET, +- skipping any write-back candidates if SKIP_WB is true. Write the +- appropriate REG_CFA_RESTORE notes into CFI_OPS. */ ++ up to and including LIMIT. The stack pointer is currently BYTES_BELOW_SP ++ bytes above the bottom of the static frame. Skip any write-back ++ candidates if SKIP_WB is true. Write the appropriate REG_CFA_RESTORE ++ notes into CFI_OPS. */ + + static void +-aarch64_restore_callee_saves (poly_int64 start_offset, unsigned start, ++aarch64_restore_callee_saves (poly_int64 bytes_below_sp, unsigned start, + unsigned limit, bool skip_wb, rtx *cfi_ops) + { + aarch64_frame &frame = cfun->machine->frame; +@@ -7539,7 +7539,9 @@ aarch64_restore_callee_saves (poly_int64 start_offset, unsigned start, + + machine_mode mode = aarch64_reg_save_mode (regno); + reg = gen_rtx_REG (mode, regno); +- offset = start_offset + frame.reg_offset[regno]; ++ offset = (frame.reg_offset[regno] ++ + frame.bytes_below_saved_regs ++ - bytes_below_sp); + rtx base_rtx = stack_pointer_rtx; + if (mode == VNx2DImode && BYTES_BIG_ENDIAN) + aarch64_adjust_sve_callee_save_base (mode, base_rtx, anchor_reg, +@@ -8304,8 +8306,6 @@ aarch64_expand_prologue (void) + HOST_WIDE_INT callee_adjust = frame.callee_adjust; + poly_int64 final_adjust = frame.final_adjust; + poly_int64 sve_callee_adjust = frame.sve_callee_adjust; +- poly_int64 below_hard_fp_saved_regs_size +- = frame.below_hard_fp_saved_regs_size; + unsigned reg1 = frame.wb_candidate1; + unsigned reg2 = frame.wb_candidate2; + bool emit_frame_chain = frame.emit_frame_chain; +@@ -8377,8 +8377,8 @@ aarch64_expand_prologue (void) + - frame.hard_fp_offset); + gcc_assert (known_ge (chain_offset, 0)); + +- /* The offset of the bottom of the save area from the current SP. */ +- poly_int64 saved_regs_offset = chain_offset - below_hard_fp_saved_regs_size; ++ /* The offset of the current SP from the bottom of the static frame. */ ++ poly_int64 bytes_below_sp = frame_size - initial_adjust - callee_adjust; + + if (emit_frame_chain) + { +@@ -8386,7 +8386,7 @@ aarch64_expand_prologue (void) + { + reg1 = R29_REGNUM; + reg2 = R30_REGNUM; +- aarch64_save_callee_saves (saved_regs_offset, reg1, reg2, ++ aarch64_save_callee_saves (bytes_below_sp, reg1, reg2, + false, false); + } + else +@@ -8426,7 +8426,7 @@ aarch64_expand_prologue (void) + emit_insn (gen_stack_tie (stack_pointer_rtx, hard_frame_pointer_rtx)); + } + +- aarch64_save_callee_saves (saved_regs_offset, R0_REGNUM, R30_REGNUM, ++ aarch64_save_callee_saves (bytes_below_sp, R0_REGNUM, R30_REGNUM, + callee_adjust != 0 || emit_frame_chain, + emit_frame_chain); + if (maybe_ne (sve_callee_adjust, 0)) +@@ -8436,16 +8436,17 @@ aarch64_expand_prologue (void) + aarch64_allocate_and_probe_stack_space (tmp1_rtx, tmp0_rtx, + sve_callee_adjust, + !frame_pointer_needed, false); +- saved_regs_offset += sve_callee_adjust; ++ bytes_below_sp -= sve_callee_adjust; + } +- aarch64_save_callee_saves (saved_regs_offset, P0_REGNUM, P15_REGNUM, ++ aarch64_save_callee_saves (bytes_below_sp, P0_REGNUM, P15_REGNUM, + false, emit_frame_chain); +- aarch64_save_callee_saves (saved_regs_offset, V0_REGNUM, V31_REGNUM, ++ aarch64_save_callee_saves (bytes_below_sp, V0_REGNUM, V31_REGNUM, + callee_adjust != 0 || emit_frame_chain, + emit_frame_chain); + + /* We may need to probe the final adjustment if it is larger than the guard + that is assumed by the called. */ ++ gcc_assert (known_eq (bytes_below_sp, final_adjust)); + aarch64_allocate_and_probe_stack_space (tmp1_rtx, tmp0_rtx, final_adjust, + !frame_pointer_needed, true); + } +@@ -8480,7 +8481,6 @@ aarch64_expand_epilogue (bool for_sibcall) + poly_int64 initial_adjust = frame.initial_adjust; + HOST_WIDE_INT callee_adjust = frame.callee_adjust; + poly_int64 final_adjust = frame.final_adjust; +- poly_int64 callee_offset = frame.callee_offset; + poly_int64 sve_callee_adjust = frame.sve_callee_adjust; + poly_int64 bytes_below_hard_fp = frame.bytes_below_hard_fp; + unsigned reg1 = frame.wb_candidate1; +@@ -8548,13 +8548,13 @@ aarch64_expand_epilogue (bool for_sibcall) + + /* Restore the vector registers before the predicate registers, + so that we can use P4 as a temporary for big-endian SVE frames. */ +- aarch64_restore_callee_saves (callee_offset, V0_REGNUM, V31_REGNUM, ++ aarch64_restore_callee_saves (final_adjust, V0_REGNUM, V31_REGNUM, + callee_adjust != 0, &cfi_ops); +- aarch64_restore_callee_saves (callee_offset, P0_REGNUM, P15_REGNUM, ++ aarch64_restore_callee_saves (final_adjust, P0_REGNUM, P15_REGNUM, + false, &cfi_ops); + if (maybe_ne (sve_callee_adjust, 0)) + aarch64_add_sp (NULL_RTX, NULL_RTX, sve_callee_adjust, true); +- aarch64_restore_callee_saves (callee_offset - sve_callee_adjust, ++ aarch64_restore_callee_saves (final_adjust + sve_callee_adjust, + R0_REGNUM, R30_REGNUM, + callee_adjust != 0, &cfi_ops); + +diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h +index a4cbc678cef..405b7545913 100644 +--- a/gcc/config/aarch64/aarch64.h ++++ b/gcc/config/aarch64/aarch64.h +@@ -856,10 +856,6 @@ struct GTY (()) aarch64_frame + It is zero when no push is used. */ + HOST_WIDE_INT callee_adjust; + +- /* The offset from SP to the callee-save registers after initial_adjust. +- It may be non-zero if no push is used (ie. callee_adjust == 0). */ +- poly_int64 callee_offset; +- + /* The size of the stack adjustment before saving or after restoring + SVE registers. */ + poly_int64 sve_callee_adjust; +-- +2.39.3 diff --git a/0110-aarch64-Only-calculate-chain_offset-if-there-is-a-chain.patch b/0110-aarch64-Only-calculate-chain_offset-if-there-is-a-chain.patch new file mode 100644 index 0000000..407924e --- /dev/null +++ b/0110-aarch64-Only-calculate-chain_offset-if-there-is-a-chain.patch @@ -0,0 +1,43 @@ +From 176001612860c2b04133c1de26eb673860800865 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Tue, 27 Jun 2023 11:24:27 +0100 +Subject: [PATCH] aarch64: Only calculate chain_offset if there is a chain + +After previous patches, it is no longer necessary to calculate +a chain_offset in cases where there is no chain record. + +gcc/ + * config/aarch64/aarch64.c (aarch64_expand_prologue): Move the + calculation of chain_offset into the emit_frame_chain block. +--- + gcc/config/aarch64/aarch64.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 884002e3b7b..69cfa4b86a6 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -8372,16 +8372,16 @@ aarch64_expand_prologue (void) + if (callee_adjust != 0) + aarch64_push_regs (reg1, reg2, callee_adjust); + +- /* The offset of the frame chain record (if any) from the current SP. */ +- poly_int64 chain_offset = (initial_adjust + callee_adjust +- - frame.hard_fp_offset); +- gcc_assert (known_ge (chain_offset, 0)); +- + /* The offset of the current SP from the bottom of the static frame. */ + poly_int64 bytes_below_sp = frame_size - initial_adjust - callee_adjust; + + if (emit_frame_chain) + { ++ /* The offset of the frame chain record (if any) from the current SP. */ ++ poly_int64 chain_offset = (initial_adjust + callee_adjust ++ - frame.hard_fp_offset); ++ gcc_assert (known_ge (chain_offset, 0)); ++ + if (callee_adjust == 0) + { + reg1 = R29_REGNUM; +-- +2.39.3 diff --git a/0111-aarch64-Rename-locals_offset-to-bytes_above_locals.patch b/0111-aarch64-Rename-locals_offset-to-bytes_above_locals.patch new file mode 100644 index 0000000..0d9b4ee --- /dev/null +++ b/0111-aarch64-Rename-locals_offset-to-bytes_above_locals.patch @@ -0,0 +1,90 @@ +From 45365e7aeb03a56ac4ec0781764017952645348f Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Tue, 27 Jun 2023 11:25:40 +0100 +Subject: [PATCH] aarch64: Rename locals_offset to bytes_above_locals +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +locals_offset was described as: + + /* Offset from the base of the frame (incomming SP) to the + top of the locals area. This value is always a multiple of + STACK_BOUNDARY. */ + +This is implicitly an âupside downâ view of the frame: the incoming +SP is at offset 0, and anything N bytes below the incoming SP is at +offset N (rather than -N). + +However, reg_offset instead uses a âright way upâ view; that is, +it views offsets in address terms. Something above X is at a +positive offset from X and something below X is at a negative +offset from X. + +Also, even on FRAME_GROWS_DOWNWARD targets like AArch64, +target-independent code views offsets in address terms too: +locals are allocated at negative offsets to virtual_stack_vars. + +It seems confusing to have *_offset fields of the same structure +using different polarities like this. This patch tries to avoid +that by renaming locals_offset to bytes_above_locals. + +gcc/ + * config/aarch64/aarch64.h (aarch64_frame::locals_offset): Rename to... + (aarch64_frame::bytes_above_locals): ...this. + * config/aarch64/aarch64.c (aarch64_layout_frame) + (aarch64_initial_elimination_offset): Update accordingly. +--- + gcc/config/aarch64/aarch64.c | 6 +++--- + gcc/config/aarch64/aarch64.h | 6 +++--- + 2 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 69cfa4b86a6..456b8b3308c 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -7022,7 +7022,7 @@ aarch64_layout_frame (void) + STACK_BOUNDARY / BITS_PER_UNIT)); + frame.frame_size = saved_regs_and_above + frame.bytes_below_saved_regs; + +- frame.locals_offset = frame.saved_varargs_size; ++ frame.bytes_above_locals = frame.saved_varargs_size; + + frame.initial_adjust = 0; + frame.final_adjust = 0; +@@ -11184,13 +11184,13 @@ aarch64_initial_elimination_offset (unsigned from, unsigned to) + return frame.hard_fp_offset; + + if (from == FRAME_POINTER_REGNUM) +- return frame.hard_fp_offset - frame.locals_offset; ++ return frame.hard_fp_offset - frame.bytes_above_locals; + } + + if (to == STACK_POINTER_REGNUM) + { + if (from == FRAME_POINTER_REGNUM) +- return frame.frame_size - frame.locals_offset; ++ return frame.frame_size - frame.bytes_above_locals; + } + + return frame.frame_size; +diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h +index 405b7545913..41a84799175 100644 +--- a/gcc/config/aarch64/aarch64.h ++++ b/gcc/config/aarch64/aarch64.h +@@ -834,10 +834,10 @@ struct GTY (()) aarch64_frame + always a multiple of STACK_BOUNDARY. */ + poly_int64 bytes_below_hard_fp; + +- /* Offset from the base of the frame (incomming SP) to the +- top of the locals area. This value is always a multiple of ++ /* The number of bytes between the top of the locals area and the top ++ of the frame (the incomming SP). This value is always a multiple of + STACK_BOUNDARY. */ +- poly_int64 locals_offset; ++ poly_int64 bytes_above_locals; + + /* Offset from the base of the frame (incomming SP) to the + hard_frame_pointer. This value is always a multiple of +-- +2.39.3 diff --git a/0112-aarch64-Rename-hard_fp_offset-to-bytes_above_hard_fp.patch b/0112-aarch64-Rename-hard_fp_offset-to-bytes_above_hard_fp.patch new file mode 100644 index 0000000..dae0e44 --- /dev/null +++ b/0112-aarch64-Rename-hard_fp_offset-to-bytes_above_hard_fp.patch @@ -0,0 +1,147 @@ +From ba6a8c0b2cb27af94913f6dea26e10106e38ec3e Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Tue, 27 Jun 2023 11:28:11 +0100 +Subject: [PATCH] aarch64: Rename hard_fp_offset to bytes_above_hard_fp +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +Similarly to the previous locals_offset patch, hard_fp_offset +was described as: + + /* Offset from the base of the frame (incomming SP) to the + hard_frame_pointer. This value is always a multiple of + STACK_BOUNDARY. */ + poly_int64 hard_fp_offset; + +which again took an âupside-downâ view: higher offsets meant lower +addresses. This patch renames the field to bytes_above_hard_fp instead. + +gcc/ + * config/aarch64/aarch64.h (aarch64_frame::hard_fp_offset): Rename + to... + (aarch64_frame::bytes_above_hard_fp): ...this. + * config/aarch64/aarch64.c (aarch64_layout_frame) + (aarch64_expand_prologue): Update accordingly. + (aarch64_initial_elimination_offset): Likewise. +--- + gcc/config/aarch64/aarch64.c | 26 +++++++++++++------------- + gcc/config/aarch64/aarch64.h | 6 +++--- + 2 files changed, 16 insertions(+), 16 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 456b8b3308c..81ddb99c165 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -7014,7 +7014,7 @@ aarch64_layout_frame (void) + + get_frame_size (), + STACK_BOUNDARY / BITS_PER_UNIT); + +- frame.hard_fp_offset ++ frame.bytes_above_hard_fp + = saved_regs_and_above - frame.below_hard_fp_saved_regs_size; + + /* Both these values are already aligned. */ +@@ -7035,13 +7035,13 @@ aarch64_layout_frame (void) + else if (frame.wb_candidate1 != INVALID_REGNUM) + max_push_offset = 256; + +- HOST_WIDE_INT const_size, const_below_saved_regs, const_fp_offset; ++ HOST_WIDE_INT const_size, const_below_saved_regs, const_above_fp; + HOST_WIDE_INT const_saved_regs_size; + if (known_eq (frame.saved_regs_size, 0)) + frame.initial_adjust = frame.frame_size; + else if (frame.frame_size.is_constant (&const_size) + && const_size < max_push_offset +- && known_eq (frame.hard_fp_offset, const_size)) ++ && known_eq (frame.bytes_above_hard_fp, const_size)) + { + /* Simple, small frame with no data below the saved registers. + +@@ -7058,8 +7058,8 @@ aarch64_layout_frame (void) + case that it hardly seems worth the effort though. */ + && (!saves_below_hard_fp_p || const_below_saved_regs == 0) + && !(cfun->calls_alloca +- && frame.hard_fp_offset.is_constant (&const_fp_offset) +- && const_fp_offset < max_push_offset)) ++ && frame.bytes_above_hard_fp.is_constant (&const_above_fp) ++ && const_above_fp < max_push_offset)) + { + /* Frame with small area below the saved registers: + +@@ -7077,12 +7077,12 @@ aarch64_layout_frame (void) + sub sp, sp, hard_fp_offset + below_hard_fp_saved_regs_size + save SVE registers relative to SP + sub sp, sp, bytes_below_saved_regs */ +- frame.initial_adjust = (frame.hard_fp_offset ++ frame.initial_adjust = (frame.bytes_above_hard_fp + + frame.below_hard_fp_saved_regs_size); + frame.final_adjust = frame.bytes_below_saved_regs; + } +- else if (frame.hard_fp_offset.is_constant (&const_fp_offset) +- && const_fp_offset < max_push_offset) ++ else if (frame.bytes_above_hard_fp.is_constant (&const_above_fp) ++ && const_above_fp < max_push_offset) + { + /* Frame with large area below the saved registers, or with SVE saves, + but with a small area above: +@@ -7092,7 +7092,7 @@ aarch64_layout_frame (void) + [sub sp, sp, below_hard_fp_saved_regs_size] + [save SVE registers relative to SP] + sub sp, sp, bytes_below_saved_regs */ +- frame.callee_adjust = const_fp_offset; ++ frame.callee_adjust = const_above_fp; + frame.sve_callee_adjust = frame.below_hard_fp_saved_regs_size; + frame.final_adjust = frame.bytes_below_saved_regs; + } +@@ -7107,7 +7107,7 @@ aarch64_layout_frame (void) + [sub sp, sp, below_hard_fp_saved_regs_size] + [save SVE registers relative to SP] + sub sp, sp, bytes_below_saved_regs */ +- frame.initial_adjust = frame.hard_fp_offset; ++ frame.initial_adjust = frame.bytes_above_hard_fp; + frame.sve_callee_adjust = frame.below_hard_fp_saved_regs_size; + frame.final_adjust = frame.bytes_below_saved_regs; + } +@@ -8379,7 +8379,7 @@ aarch64_expand_prologue (void) + { + /* The offset of the frame chain record (if any) from the current SP. */ + poly_int64 chain_offset = (initial_adjust + callee_adjust +- - frame.hard_fp_offset); ++ - frame.bytes_above_hard_fp); + gcc_assert (known_ge (chain_offset, 0)); + + if (callee_adjust == 0) +@@ -11181,10 +11181,10 @@ aarch64_initial_elimination_offset (unsigned from, unsigned to) + if (to == HARD_FRAME_POINTER_REGNUM) + { + if (from == ARG_POINTER_REGNUM) +- return frame.hard_fp_offset; ++ return frame.bytes_above_hard_fp; + + if (from == FRAME_POINTER_REGNUM) +- return frame.hard_fp_offset - frame.bytes_above_locals; ++ return frame.bytes_above_hard_fp - frame.bytes_above_locals; + } + + if (to == STACK_POINTER_REGNUM) +diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h +index 41a84799175..9839e18a27e 100644 +--- a/gcc/config/aarch64/aarch64.h ++++ b/gcc/config/aarch64/aarch64.h +@@ -839,10 +839,10 @@ struct GTY (()) aarch64_frame + STACK_BOUNDARY. */ + poly_int64 bytes_above_locals; + +- /* Offset from the base of the frame (incomming SP) to the +- hard_frame_pointer. This value is always a multiple of ++ /* The number of bytes between the hard_frame_pointer and the top of ++ the frame (the incomming SP). This value is always a multiple of + STACK_BOUNDARY. */ +- poly_int64 hard_fp_offset; ++ poly_int64 bytes_above_hard_fp; + + /* The size of the frame. This value is the offset from base of the + frame (incomming SP) to the stack_pointer. This value is always +-- +2.39.3 diff --git a/0113-aarch64-Tweak-frame_size-comment.patch b/0113-aarch64-Tweak-frame_size-comment.patch new file mode 100644 index 0000000..0094a9f --- /dev/null +++ b/0113-aarch64-Tweak-frame_size-comment.patch @@ -0,0 +1,34 @@ +From b5e2fcfa7a1c722fe426132562af4a96fff9fb5c Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Thu, 22 Jun 2023 22:26:30 +0100 +Subject: [PATCH] aarch64: Tweak frame_size comment +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +This patch fixes another case in which a value was described with +an âupside-downâ view. + +gcc/ + * config/aarch64/aarch64.h (aarch64_frame::frame_size): Tweak comment. +--- + gcc/config/aarch64/aarch64.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h +index 9839e18a27e..8d8916c7227 100644 +--- a/gcc/config/aarch64/aarch64.h ++++ b/gcc/config/aarch64/aarch64.h +@@ -844,8 +844,8 @@ struct GTY (()) aarch64_frame + STACK_BOUNDARY. */ + poly_int64 bytes_above_hard_fp; + +- /* The size of the frame. This value is the offset from base of the +- frame (incomming SP) to the stack_pointer. This value is always ++ /* The size of the frame, i.e. the number of bytes between the bottom ++ of the outgoing arguments and the incoming SP. This value is always + a multiple of STACK_BOUNDARY. */ + poly_int64 frame_size; + +-- +2.39.3 diff --git a/0114-aarch64-Measure-reg_offset-from-the-bottom-of-the-frame.patch b/0114-aarch64-Measure-reg_offset-from-the-bottom-of-the-frame.patch new file mode 100644 index 0000000..da5ad6a --- /dev/null +++ b/0114-aarch64-Measure-reg_offset-from-the-bottom-of-the-frame.patch @@ -0,0 +1,194 @@ +From ae7192e24b8fd6b3f14b44de03bebc6af92c13ed Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Tue, 27 Jun 2023 11:36:08 +0100 +Subject: [PATCH] aarch64: Measure reg_offset from the bottom of the frame + +reg_offset was measured from the bottom of the saved register area. +This made perfect sense with the original layout, since the bottom +of the saved register area was also the hard frame pointer address. +It became slightly less obvious with SVE, since we save SVE +registers below the hard frame pointer, but it still made sense. + +However, if we want to allow different frame layouts, it's more +convenient and obvious to measure reg_offset from the bottom of +the frame. After previous patches, it's also a slight simplification +in its own right. + +gcc/ + * config/aarch64/aarch64.h (aarch64_frame): Add comment above + reg_offset. + * config/aarch64/aarch64.c (aarch64_layout_frame): Walk offsets + from the bottom of the frame, rather than the bottom of the saved + register area. Measure reg_offset from the bottom of the frame + rather than the bottom of the saved register area. + (aarch64_save_callee_saves): Update accordingly. + (aarch64_restore_callee_saves): Likewise. + (aarch64_get_separate_components): Likewise. + (aarch64_process_components): Likewise. +--- + gcc/config/aarch64/aarch64.c | 53 ++++++++++++++++-------------------- + gcc/config/aarch64/aarch64.h | 3 ++ + 2 files changed, 27 insertions(+), 29 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 81ddb99c165..1ed335f5487 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -6826,7 +6826,6 @@ aarch64_needs_frame_chain (void) + static void + aarch64_layout_frame (void) + { +- poly_int64 offset = 0; + int regno, last_fp_reg = INVALID_REGNUM; + machine_mode vector_save_mode = aarch64_reg_save_mode (V8_REGNUM); + poly_int64 vector_save_size = GET_MODE_SIZE (vector_save_mode); +@@ -6902,7 +6901,9 @@ aarch64_layout_frame (void) + gcc_assert (crtl->is_leaf + || maybe_ne (frame.reg_offset[R30_REGNUM], SLOT_NOT_REQUIRED)); + +- frame.bytes_below_saved_regs = crtl->outgoing_args_size; ++ poly_int64 offset = crtl->outgoing_args_size; ++ gcc_assert (multiple_p (offset, STACK_BOUNDARY / BITS_PER_UNIT)); ++ frame.bytes_below_saved_regs = offset; + + /* Now assign stack slots for the registers. Start with the predicate + registers, since predicate LDR and STR have a relatively small +@@ -6914,7 +6915,8 @@ aarch64_layout_frame (void) + offset += BYTES_PER_SVE_PRED; + } + +- if (maybe_ne (offset, 0)) ++ poly_int64 saved_prs_size = offset - frame.bytes_below_saved_regs; ++ if (maybe_ne (saved_prs_size, 0)) + { + /* If we have any vector registers to save above the predicate registers, + the offset of the vector register save slots need to be a multiple +@@ -6932,10 +6934,10 @@ aarch64_layout_frame (void) + offset = aligned_upper_bound (offset, STACK_BOUNDARY / BITS_PER_UNIT); + else + { +- if (known_le (offset, vector_save_size)) +- offset = vector_save_size; +- else if (known_le (offset, vector_save_size * 2)) +- offset = vector_save_size * 2; ++ if (known_le (saved_prs_size, vector_save_size)) ++ offset = frame.bytes_below_saved_regs + vector_save_size; ++ else if (known_le (saved_prs_size, vector_save_size * 2)) ++ offset = frame.bytes_below_saved_regs + vector_save_size * 2; + else + gcc_unreachable (); + } +@@ -6952,9 +6954,10 @@ aarch64_layout_frame (void) + + /* OFFSET is now the offset of the hard frame pointer from the bottom + of the callee save area. */ +- bool saves_below_hard_fp_p = maybe_ne (offset, 0); +- frame.below_hard_fp_saved_regs_size = offset; +- frame.bytes_below_hard_fp = offset + frame.bytes_below_saved_regs; ++ frame.below_hard_fp_saved_regs_size = offset - frame.bytes_below_saved_regs; ++ bool saves_below_hard_fp_p ++ = maybe_ne (frame.below_hard_fp_saved_regs_size, 0); ++ frame.bytes_below_hard_fp = offset; + if (frame.emit_frame_chain) + { + /* FP and LR are placed in the linkage record. */ +@@ -7005,9 +7008,10 @@ aarch64_layout_frame (void) + + offset = aligned_upper_bound (offset, STACK_BOUNDARY / BITS_PER_UNIT); + +- frame.saved_regs_size = offset; ++ frame.saved_regs_size = offset - frame.bytes_below_saved_regs; + +- poly_int64 varargs_and_saved_regs_size = offset + frame.saved_varargs_size; ++ poly_int64 varargs_and_saved_regs_size ++ = frame.saved_regs_size + frame.saved_varargs_size; + + poly_int64 saved_regs_and_above + = aligned_upper_bound (varargs_and_saved_regs_size +@@ -7430,9 +7434,7 @@ aarch64_save_callee_saves (poly_int64 bytes_below_sp, + + machine_mode mode = aarch64_reg_save_mode (regno); + reg = gen_rtx_REG (mode, regno); +- offset = (frame.reg_offset[regno] +- + frame.bytes_below_saved_regs +- - bytes_below_sp); ++ offset = frame.reg_offset[regno] - bytes_below_sp; + rtx base_rtx = stack_pointer_rtx; + poly_int64 sp_offset = offset; + +@@ -7539,9 +7541,7 @@ aarch64_restore_callee_saves (poly_int64 bytes_below_sp, unsigned start, + + machine_mode mode = aarch64_reg_save_mode (regno); + reg = gen_rtx_REG (mode, regno); +- offset = (frame.reg_offset[regno] +- + frame.bytes_below_saved_regs +- - bytes_below_sp); ++ offset = frame.reg_offset[regno] - bytes_below_sp; + rtx base_rtx = stack_pointer_rtx; + if (mode == VNx2DImode && BYTES_BIG_ENDIAN) + aarch64_adjust_sve_callee_save_base (mode, base_rtx, anchor_reg, +@@ -7669,14 +7669,12 @@ aarch64_get_separate_components (void) + it as a stack probe for -fstack-clash-protection. */ + if (flag_stack_clash_protection + && maybe_ne (frame.below_hard_fp_saved_regs_size, 0) +- && known_eq (offset, 0)) ++ && known_eq (offset, frame.bytes_below_saved_regs)) + continue; + + /* Get the offset relative to the register we'll use. */ + if (frame_pointer_needed) +- offset -= frame.below_hard_fp_saved_regs_size; +- else +- offset += frame.bytes_below_saved_regs; ++ offset -= frame.bytes_below_hard_fp; + + /* Check that we can access the stack slot of the register with one + direct load with no adjustments needed. */ +@@ -7823,9 +7821,7 @@ aarch64_process_components (sbitmap components, bool prologue_p) + rtx reg = gen_rtx_REG (mode, regno); + poly_int64 offset = frame.reg_offset[regno]; + if (frame_pointer_needed) +- offset -= frame.below_hard_fp_saved_regs_size; +- else +- offset += frame.bytes_below_saved_regs; ++ offset -= frame.bytes_below_hard_fp; + + rtx addr = plus_constant (Pmode, ptr_reg, offset); + rtx mem = gen_frame_mem (mode, addr); +@@ -7877,9 +7873,7 @@ aarch64_process_components (sbitmap components, bool prologue_p) + /* REGNO2 can be saved/restored in a pair with REGNO. */ + rtx reg2 = gen_rtx_REG (mode, regno2); + if (frame_pointer_needed) +- offset2 -= frame.below_hard_fp_saved_regs_size; +- else +- offset2 += frame.bytes_below_saved_regs; ++ offset2 -= frame.bytes_below_hard_fp; + rtx addr2 = plus_constant (Pmode, ptr_reg, offset2); + rtx mem2 = gen_frame_mem (mode, addr2); + rtx set2 = prologue_p ? gen_rtx_SET (mem2, reg2) +@@ -7995,7 +7989,8 @@ aarch64_allocate_and_probe_stack_space (rtx temp1, rtx temp2, + if (final_adjustment_p + && known_eq (frame.below_hard_fp_saved_regs_size, 0)) + { +- poly_int64 lr_offset = frame.reg_offset[LR_REGNUM]; ++ poly_int64 lr_offset = (frame.reg_offset[LR_REGNUM] ++ - frame.bytes_below_saved_regs); + if (known_ge (lr_offset, 0)) + min_probe_threshold -= lr_offset.to_constant (); + else +diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h +index 8d8916c7227..1c3c62639cb 100644 +--- a/gcc/config/aarch64/aarch64.h ++++ b/gcc/config/aarch64/aarch64.h +@@ -809,6 +809,9 @@ extern enum aarch64_processor aarch64_tune; + #ifdef HAVE_POLY_INT_H + struct GTY (()) aarch64_frame + { ++ /* The offset from the bottom of the static frame (the bottom of the ++ outgoing arguments) of each register save slot, or -2 if no save is ++ needed. */ + poly_int64 reg_offset[LAST_SAVED_REGNUM + 1]; + + /* The number of extra stack bytes taken up by register varargs. +-- +2.39.3 diff --git a/0115-aarch64-Simplify-top-of-frame-allocation.patch b/0115-aarch64-Simplify-top-of-frame-allocation.patch new file mode 100644 index 0000000..77ba598 --- /dev/null +++ b/0115-aarch64-Simplify-top-of-frame-allocation.patch @@ -0,0 +1,54 @@ +From ff7193c5313d736e20aa66c33abeaf102cc6c152 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Fri, 16 Jun 2023 17:44:39 +0100 +Subject: [PATCH] aarch64: Simplify top of frame allocation + +After previous patches, it no longer really makes sense to allocate +the top of the frame in terms of varargs_and_saved_regs_size and +saved_regs_and_above. + +gcc/ + * config/aarch64/aarch64.c (aarch64_layout_frame): Simplify + the allocation of the top of the frame. +--- + gcc/config/aarch64/aarch64.c | 23 ++++++++--------------- + 1 file changed, 8 insertions(+), 15 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 1ed335f5487..70542c6e13f 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -7010,23 +7010,16 @@ aarch64_layout_frame (void) + + frame.saved_regs_size = offset - frame.bytes_below_saved_regs; + +- poly_int64 varargs_and_saved_regs_size +- = frame.saved_regs_size + frame.saved_varargs_size; +- +- poly_int64 saved_regs_and_above +- = aligned_upper_bound (varargs_and_saved_regs_size +- + get_frame_size (), +- STACK_BOUNDARY / BITS_PER_UNIT); +- +- frame.bytes_above_hard_fp +- = saved_regs_and_above - frame.below_hard_fp_saved_regs_size; ++ offset += get_frame_size (); ++ offset = aligned_upper_bound (offset, STACK_BOUNDARY / BITS_PER_UNIT); ++ poly_int64 top_of_locals = offset; + +- /* Both these values are already aligned. */ +- gcc_assert (multiple_p (frame.bytes_below_saved_regs, +- STACK_BOUNDARY / BITS_PER_UNIT)); +- frame.frame_size = saved_regs_and_above + frame.bytes_below_saved_regs; ++ offset += frame.saved_varargs_size; ++ gcc_assert (multiple_p (offset, STACK_BOUNDARY / BITS_PER_UNIT)); ++ frame.frame_size = offset; + +- frame.bytes_above_locals = frame.saved_varargs_size; ++ frame.bytes_above_hard_fp = frame.frame_size - frame.bytes_below_hard_fp; ++ frame.bytes_above_locals = frame.frame_size - top_of_locals; + + frame.initial_adjust = 0; + frame.final_adjust = 0; +-- +2.39.3 diff --git a/0116-aarch64-Minor-initial-adjustment-tweak.patch b/0116-aarch64-Minor-initial-adjustment-tweak.patch new file mode 100644 index 0000000..e9066b2 --- /dev/null +++ b/0116-aarch64-Minor-initial-adjustment-tweak.patch @@ -0,0 +1,37 @@ +From 5854b895a92e9fe8b26a051442d44a6fd685512a Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Thu, 22 Jun 2023 22:18:45 +0100 +Subject: [PATCH] aarch64: Minor initial adjustment tweak + +This patch just changes a calculation of initial_adjust +to one that makes it slightly more obvious that the total +adjustment is frame.frame_size. + +gcc/ + * config/aarch64/aarch64.c (aarch64_layout_frame): Tweak + calculation of initial_adjust for frames in which all saves + are SVE saves. +--- + gcc/config/aarch64/aarch64.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 70542c6e13f..08a8667bbc1 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -7071,11 +7071,10 @@ aarch64_layout_frame (void) + { + /* Frame in which all saves are SVE saves: + +- sub sp, sp, hard_fp_offset + below_hard_fp_saved_regs_size ++ sub sp, sp, frame_size - bytes_below_saved_regs + save SVE registers relative to SP + sub sp, sp, bytes_below_saved_regs */ +- frame.initial_adjust = (frame.bytes_above_hard_fp +- + frame.below_hard_fp_saved_regs_size); ++ frame.initial_adjust = frame.frame_size - frame.bytes_below_saved_regs; + frame.final_adjust = frame.bytes_below_saved_regs; + } + else if (frame.bytes_above_hard_fp.is_constant (&const_above_fp) +-- +2.39.3 diff --git a/0117-aarch64-Tweak-stack-clash-boundary-condition.patch b/0117-aarch64-Tweak-stack-clash-boundary-condition.patch new file mode 100644 index 0000000..826f53e --- /dev/null +++ b/0117-aarch64-Tweak-stack-clash-boundary-condition.patch @@ -0,0 +1,124 @@ +From af6bac9775e7d2bc94e4e3600740c3c475e117b5 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Tue, 27 Jun 2023 15:11:44 +0100 +Subject: [PATCH] aarch64: Tweak stack clash boundary condition + +The AArch64 ABI says that, when stack clash protection is used, +there can be a maximum of 1KiB of unprobed space at sp on entry +to a function. Therefore, we need to probe when allocating +>= guard_size - 1KiB of data (>= rather than >). This is what +GCC does. + +If an allocation is exactly guard_size bytes, it is enough to allocate +those bytes and probe once at offset 1024. It isn't possible to use a +single probe at any other offset: higher would conmplicate later code, +by leaving more unprobed space than usual, while lower would risk +leaving an entire page unprobed. For simplicity, the code probes all +allocations at offset 1024. + +Some register saves also act as probes. If we need to allocate +more space below the last such register save probe, we need to +probe the allocation if it is > 1KiB. Again, this allocation is +then sometimes (but not always) probed at offset 1024. This sort of +allocation is currently only used for outgoing arguments, which are +rarely this big. + +However, the code also probed if this final outgoing-arguments +allocation was == 1KiB, rather than just > 1KiB. This isn't +necessary, since the register save then probes at offset 1024 +as required. Continuing to probe allocations of exactly 1KiB +would complicate later patches. + +gcc/ + * config/aarch64/aarch64.c (aarch64_allocate_and_probe_stack_space): + Don't probe final allocations that are exactly 1KiB in size (after + unprobed space above the final allocation has been deducted). + +gcc/testsuite/ + * gcc.target/aarch64/stack-check-prologue-17.c: New test. +--- + gcc/config/aarch64/aarch64.c | 4 +- + .../aarch64/stack-check-prologue-17.c | 55 +++++++++++++++++++ + 2 files changed, 58 insertions(+), 1 deletion(-) + create mode 100644 gcc/testsuite/gcc.target/aarch64/stack-check-prologue-17.c + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 08a8667bbc1..43240af8ae4 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -7962,9 +7962,11 @@ aarch64_allocate_and_probe_stack_space (rtx temp1, rtx temp2, + HOST_WIDE_INT guard_size + = 1 << param_stack_clash_protection_guard_size; + HOST_WIDE_INT guard_used_by_caller = STACK_CLASH_CALLER_GUARD; ++ HOST_WIDE_INT byte_sp_alignment = STACK_BOUNDARY / BITS_PER_UNIT; ++ gcc_assert (multiple_p (poly_size, byte_sp_alignment)); + HOST_WIDE_INT min_probe_threshold + = (final_adjustment_p +- ? guard_used_by_caller ++ ? guard_used_by_caller + byte_sp_alignment + : guard_size - guard_used_by_caller); + /* When doing the final adjustment for the outgoing arguments, take into + account any unprobed space there is above the current SP. There are +diff --git a/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-17.c b/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-17.c +new file mode 100644 +index 00000000000..0d8a25d73a2 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-17.c +@@ -0,0 +1,55 @@ ++/* { dg-options "-O2 -fstack-clash-protection -fomit-frame-pointer --param stack-clash-protection-guard-size=12" } */ ++/* { dg-final { check-function-bodies "**" "" } } */ ++ ++void f(int, ...); ++void g(); ++ ++/* ++** test1: ++** ... ++** str x30, \[sp\] ++** sub sp, sp, #1024 ++** cbnz w0, .* ++** bl g ++** ... ++*/ ++int test1(int z) { ++ __uint128_t x = 0; ++ int y[0x400]; ++ if (z) ++ { ++ f(0, 0, 0, 0, 0, 0, 0, &y, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x); ++ } ++ g(); ++ return 1; ++} ++ ++/* ++** test2: ++** ... ++** str x30, \[sp\] ++** sub sp, sp, #1040 ++** str xzr, \[sp\] ++** cbnz w0, .* ++** bl g ++** ... ++*/ ++int test2(int z) { ++ __uint128_t x = 0; ++ int y[0x400]; ++ if (z) ++ { ++ f(0, 0, 0, 0, 0, 0, 0, &y, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x); ++ } ++ g(); ++ return 1; ++} +-- +2.39.3 diff --git a/0118-aarch64-Put-LR-save-probe-in-first-16-bytes.patch b/0118-aarch64-Put-LR-save-probe-in-first-16-bytes.patch new file mode 100644 index 0000000..75a9fec --- /dev/null +++ b/0118-aarch64-Put-LR-save-probe-in-first-16-bytes.patch @@ -0,0 +1,269 @@ +From 128abc59aedc06b4418ac57d08a484e1fd92dee2 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Tue, 27 Jun 2023 15:12:55 +0100 +Subject: [PATCH] aarch64: Put LR save probe in first 16 bytes + +-fstack-clash-protection uses the save of LR as a probe for the next +allocation. The next allocation could be: + +* another part of the static frame, e.g. when allocating SVE save slots + or outgoing arguments + +* an alloca in the same function + +* an allocation made by a callee function + +However, when -fomit-frame-pointer is used, the LR save slot is placed +above the other GPR save slots. It could therefore be up to 80 bytes +above the base of the GPR save area (which is also the hard fp address). + +aarch64_allocate_and_probe_stack_space took this into account when +deciding how much subsequent space could be allocated without needing +a probe. However, it interacted badly with: + + /* If doing a small final adjustment, we always probe at offset 0. + This is done to avoid issues when LR is not at position 0 or when + the final adjustment is smaller than the probing offset. */ + else if (final_adjustment_p && rounded_size == 0) + residual_probe_offset = 0; + +which forces any allocation that is smaller than the guard page size +to be probed at offset 0 rather than the usual offset 1024. It was +therefore possible to construct cases in which we had: + +* a probe using LR at SP + 80 bytes (or some other value >= 16) +* an allocation of the guard page size - 16 bytes +* a probe at SP + 0 + +which allocates guard page size + 64 consecutive unprobed bytes. + +This patch requires the LR probe to be in the first 16 bytes of the +save area when stack clash protection is active. Doing it +unconditionally would cause code-quality regressions, but a later +patch deals with that. + +The new comment doesn't say that the probe register is required +to be LR, since a later patch removes that restriction. + +gcc/ + * config/aarch64/aarch64.c (aarch64_layout_frame): Ensure that + the LR save slot is in the first 16 bytes of the register save area. + (aarch64_allocate_and_probe_stack_space): Remove workaround for + when LR was not in the first 16 bytes. + +gcc/testsuite/ + * gcc.target/aarch64/stack-check-prologue-18.c: New test. +--- + gcc/config/aarch64/aarch64.c | 65 +++++------ + .../aarch64/stack-check-prologue-18.c | 103 ++++++++++++++++++ + 2 files changed, 130 insertions(+), 38 deletions(-) + create mode 100644 gcc/testsuite/gcc.target/aarch64/stack-check-prologue-18.c + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 43240af8ae4..3d73c5f352f 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -6958,26 +6958,38 @@ aarch64_layout_frame (void) + bool saves_below_hard_fp_p + = maybe_ne (frame.below_hard_fp_saved_regs_size, 0); + frame.bytes_below_hard_fp = offset; ++ ++#define ALLOCATE_GPR_SLOT(REGNO) \ ++ do \ ++ { \ ++ frame.reg_offset[REGNO] = offset; \ ++ if (frame.wb_candidate1 == INVALID_REGNUM) \ ++ frame.wb_candidate1 = (REGNO); \ ++ else if (frame.wb_candidate2 == INVALID_REGNUM) \ ++ frame.wb_candidate2 = (REGNO); \ ++ offset += UNITS_PER_WORD; \ ++ } \ ++ while (0) ++ + if (frame.emit_frame_chain) + { + /* FP and LR are placed in the linkage record. */ +- frame.reg_offset[R29_REGNUM] = offset; +- frame.wb_candidate1 = R29_REGNUM; +- frame.reg_offset[R30_REGNUM] = offset + UNITS_PER_WORD; +- frame.wb_candidate2 = R30_REGNUM; +- offset += 2 * UNITS_PER_WORD; ++ ALLOCATE_GPR_SLOT (R29_REGNUM); ++ ALLOCATE_GPR_SLOT (R30_REGNUM); + } ++ else if (flag_stack_clash_protection ++ && known_eq (frame.reg_offset[R30_REGNUM], SLOT_REQUIRED)) ++ /* Put the LR save slot first, since it makes a good choice of probe ++ for stack clash purposes. The idea is that the link register usually ++ has to be saved before a call anyway, and so we lose little by ++ stopping it from being individually shrink-wrapped. */ ++ ALLOCATE_GPR_SLOT (R30_REGNUM); + + for (regno = R0_REGNUM; regno <= R30_REGNUM; regno++) + if (known_eq (frame.reg_offset[regno], SLOT_REQUIRED)) +- { +- frame.reg_offset[regno] = offset; +- if (frame.wb_candidate1 == INVALID_REGNUM) +- frame.wb_candidate1 = regno; +- else if (frame.wb_candidate2 == INVALID_REGNUM) +- frame.wb_candidate2 = regno; +- offset += UNITS_PER_WORD; +- } ++ ALLOCATE_GPR_SLOT (regno); ++ ++#undef ALLOCATE_GPR_SLOT + + poly_int64 max_int_offset = offset; + offset = aligned_upper_bound (offset, STACK_BOUNDARY / BITS_PER_UNIT); +@@ -7968,29 +7980,6 @@ aarch64_allocate_and_probe_stack_space (rtx temp1, rtx temp2, + = (final_adjustment_p + ? guard_used_by_caller + byte_sp_alignment + : guard_size - guard_used_by_caller); +- /* When doing the final adjustment for the outgoing arguments, take into +- account any unprobed space there is above the current SP. There are +- two cases: +- +- - When saving SVE registers below the hard frame pointer, we force +- the lowest save to take place in the prologue before doing the final +- adjustment (i.e. we don't allow the save to be shrink-wrapped). +- This acts as a probe at SP, so there is no unprobed space. +- +- - When there are no SVE register saves, we use the store of the link +- register as a probe. We can't assume that LR was saved at position 0 +- though, so treat any space below it as unprobed. */ +- if (final_adjustment_p +- && known_eq (frame.below_hard_fp_saved_regs_size, 0)) +- { +- poly_int64 lr_offset = (frame.reg_offset[LR_REGNUM] +- - frame.bytes_below_saved_regs); +- if (known_ge (lr_offset, 0)) +- min_probe_threshold -= lr_offset.to_constant (); +- else +- gcc_assert (!flag_stack_clash_protection || known_eq (poly_size, 0)); +- } +- + poly_int64 frame_size = frame.frame_size; + + /* We should always have a positive probe threshold. */ +@@ -8170,8 +8159,8 @@ aarch64_allocate_and_probe_stack_space (rtx temp1, rtx temp2, + if (final_adjustment_p && rounded_size != 0) + min_probe_threshold = 0; + /* If doing a small final adjustment, we always probe at offset 0. +- This is done to avoid issues when LR is not at position 0 or when +- the final adjustment is smaller than the probing offset. */ ++ This is done to avoid issues when the final adjustment is smaller ++ than the probing offset. */ + else if (final_adjustment_p && rounded_size == 0) + residual_probe_offset = 0; + +diff --git a/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-18.c b/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-18.c +new file mode 100644 +index 00000000000..b646f040b54 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-18.c +@@ -0,0 +1,103 @@ ++/* { dg-options "-O2 -fstack-clash-protection -fomit-frame-pointer --param stack-clash-protection-guard-size=12" } */ ++/* { dg-final { check-function-bodies "**" "" } } */ ++ ++void f(int, ...); ++void g(); ++ ++/* ++** test1: ++** ... ++** str x30, \[sp\] ++** ... ++** sub sp, sp, #4064 ++** str xzr, \[sp\] ++** cbnz w0, .* ++** bl g ++** ... ++** str x26, \[sp, #?4128\] ++** ... ++*/ ++int test1(int z) { ++ __uint128_t x = 0; ++ int y[0x400]; ++ if (z) ++ { ++ asm volatile ("" ::: ++ "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26"); ++ f(0, 0, 0, 0, 0, 0, 0, &y, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x); ++ } ++ g(); ++ return 1; ++} ++ ++/* ++** test2: ++** ... ++** str x30, \[sp\] ++** ... ++** sub sp, sp, #1040 ++** str xzr, \[sp\] ++** cbnz w0, .* ++** bl g ++** ... ++*/ ++int test2(int z) { ++ __uint128_t x = 0; ++ int y[0x400]; ++ if (z) ++ { ++ asm volatile ("" ::: ++ "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26"); ++ f(0, 0, 0, 0, 0, 0, 0, &y, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x); ++ } ++ g(); ++ return 1; ++} ++ ++/* ++** test3: ++** ... ++** str x30, \[sp\] ++** ... ++** sub sp, sp, #1024 ++** cbnz w0, .* ++** bl g ++** ... ++*/ ++int test3(int z) { ++ __uint128_t x = 0; ++ int y[0x400]; ++ if (z) ++ { ++ asm volatile ("" ::: ++ "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26"); ++ f(0, 0, 0, 0, 0, 0, 0, &y, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ++ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x); ++ } ++ g(); ++ return 1; ++} +-- +2.39.3 diff --git a/0119-aarch64-Simplif-yprobe-of-final-frame-allocation.patch b/0119-aarch64-Simplif-yprobe-of-final-frame-allocation.patch new file mode 100644 index 0000000..e59baf2 --- /dev/null +++ b/0119-aarch64-Simplif-yprobe-of-final-frame-allocation.patch @@ -0,0 +1,98 @@ +From c940aadecb4f623a39abe16b6c62b307e2b10638 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Tue, 8 Aug 2023 01:57:26 +0100 +Subject: [PATCH] aarch64: Simplify probe of final frame allocation + +Previous patches ensured that the final frame allocation only needs +a probe when the size is strictly greater than 1KiB. It's therefore +safe to use the normal 1024 probe offset in all cases. + +The main motivation for doing this is to simplify the code and +remove the number of special cases. + +gcc/ + * config/aarch64/aarch64.c (aarch64_allocate_and_probe_stack_space): + Always probe the residual allocation at offset 1024, asserting + that that is in range. + +gcc/testsuite/ + * gcc.target/aarch64/stack-check-prologue-17.c: Expect the probe + to be at offset 1024 rather than offset 0. + * gcc.target/aarch64/stack-check-prologue-18.c: Likewise. +--- + gcc/config/aarch64/aarch64.c | 12 ++++-------- + .../gcc.target/aarch64/stack-check-prologue-17.c | 2 +- + .../gcc.target/aarch64/stack-check-prologue-18.c | 4 ++-- + 3 files changed, 7 insertions(+), 11 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 3d73c5f352f..37c6219b07a 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -8153,16 +8153,12 @@ aarch64_allocate_and_probe_stack_space (rtx temp1, rtx temp2, + are still safe. */ + if (residual) + { +- HOST_WIDE_INT residual_probe_offset = guard_used_by_caller; ++ gcc_assert (guard_used_by_caller + byte_sp_alignment <= size); ++ + /* If we're doing final adjustments, and we've done any full page + allocations then any residual needs to be probed. */ + if (final_adjustment_p && rounded_size != 0) + min_probe_threshold = 0; +- /* If doing a small final adjustment, we always probe at offset 0. +- This is done to avoid issues when the final adjustment is smaller +- than the probing offset. */ +- else if (final_adjustment_p && rounded_size == 0) +- residual_probe_offset = 0; + + aarch64_sub_sp (temp1, temp2, residual, frame_related_p); + if (residual >= min_probe_threshold) +@@ -8173,8 +8169,8 @@ aarch64_allocate_and_probe_stack_space (rtx temp1, rtx temp2, + HOST_WIDE_INT_PRINT_DEC " bytes, probing will be required." + "\n", residual); + +- emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx, +- residual_probe_offset)); ++ emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx, ++ guard_used_by_caller)); + emit_insn (gen_blockage ()); + } + } +diff --git a/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-17.c b/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-17.c +index 0d8a25d73a2..f0ec1389771 100644 +--- a/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-17.c ++++ b/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-17.c +@@ -33,7 +33,7 @@ int test1(int z) { + ** ... + ** str x30, \[sp\] + ** sub sp, sp, #1040 +-** str xzr, \[sp\] ++** str xzr, \[sp, #?1024\] + ** cbnz w0, .* + ** bl g + ** ... +diff --git a/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-18.c b/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-18.c +index b646f040b54..71d33ba34e9 100644 +--- a/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-18.c ++++ b/gcc/testsuite/gcc.target/aarch64/stack-check-prologue-18.c +@@ -10,7 +10,7 @@ void g(); + ** str x30, \[sp\] + ** ... + ** sub sp, sp, #4064 +-** str xzr, \[sp\] ++** str xzr, \[sp, #?1024\] + ** cbnz w0, .* + ** bl g + ** ... +@@ -52,7 +52,7 @@ int test1(int z) { + ** str x30, \[sp\] + ** ... + ** sub sp, sp, #1040 +-** str xzr, \[sp\] ++** str xzr, \[sp, #?1024\] + ** cbnz w0, .* + ** bl g + ** ... +-- +2.39.3 diff --git a/0120-aarch64-Explicitly-record-probe-registers-in-frame-info.patch b/0120-aarch64-Explicitly-record-probe-registers-in-frame-info.patch new file mode 100644 index 0000000..e10da56 --- /dev/null +++ b/0120-aarch64-Explicitly-record-probe-registers-in-frame-info.patch @@ -0,0 +1,275 @@ +From 3c73e7bc86a918c2c24b3ad96b2d44716a5e2614 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Tue, 27 Jun 2023 11:50:34 +0100 +Subject: [PATCH] aarch64: Explicitly record probe registers in frame info + +The stack frame is currently divided into three areas: + +A: the area above the hard frame pointer +B: the SVE saves below the hard frame pointer +C: the outgoing arguments + +If the stack frame is allocated in one chunk, the allocation needs a +probe if the frame size is >= guard_size - 1KiB. In addition, if the +function is not a leaf function, it must probe an address no more than +1KiB above the outgoing SP. We ensured the second condition by + +(1) using single-chunk allocations for non-leaf functions only if + the link register save slot is within 512 bytes of the bottom + of the frame; and + +(2) using the link register save as a probe (meaning, for instance, + that it can't be individually shrink wrapped) + +If instead the stack is allocated in multiple chunks, then: + +* an allocation involving only the outgoing arguments (C above) requires + a probe if the allocation size is > 1KiB + +* any other allocation requires a probe if the allocation size + is >= guard_size - 1KiB + +* second and subsequent allocations require the previous allocation + to probe at the bottom of the allocated area, regardless of the size + of that previous allocation + +The final point means that, unlike for single allocations, +it can be necessary to have both a non-SVE register probe and +an SVE register probe. For example: + +* allocate A, probe using a non-SVE register save +* allocate B, probe using an SVE register save +* allocate C + +The non-SVE register used in this case was again the link register. +It was previously used even if the link register save slot was some +bytes above the bottom of the non-SVE register saves, but an earlier +patch avoided that by putting the link register save slot first. + +As a belt-and-braces fix, this patch explicitly records which +probe registers we're using and allows the non-SVE probe to be +whichever register comes first (as for SVE). + +The patch also avoids unnecessary probes in sve/pcs/stack_clash_3.c. + +gcc/ + * config/aarch64/aarch64.h (aarch64_frame::sve_save_and_probe) + (aarch64_frame::hard_fp_save_and_probe): New fields. + * config/aarch64/aarch64.c (aarch64_layout_frame): Initialize them. + Rather than asserting that a leaf function saves LR, instead assert + that a leaf function saves something. + (aarch64_get_separate_components): Prevent the chosen probe + registers from being individually shrink-wrapped. + (aarch64_allocate_and_probe_stack_space): Remove workaround for + probe registers that aren't at the bottom of the previous allocation. + +gcc/testsuite/ + * gcc.target/aarch64/sve/pcs/stack_clash_3.c: Avoid redundant probes. +--- + gcc/config/aarch64/aarch64.c | 67 +++++++++++++++---- + gcc/config/aarch64/aarch64.h | 8 +++ + .../aarch64/sve/pcs/stack_clash_3.c | 6 +- + 3 files changed, 64 insertions(+), 17 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 37c6219b07a..2dea9b5617d 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -6897,13 +6897,10 @@ aarch64_layout_frame (void) + && !crtl->abi->clobbers_full_reg_p (regno)) + frame.reg_offset[regno] = SLOT_REQUIRED; + +- /* With stack-clash, LR must be saved in non-leaf functions. */ +- gcc_assert (crtl->is_leaf +- || maybe_ne (frame.reg_offset[R30_REGNUM], SLOT_NOT_REQUIRED)); +- + poly_int64 offset = crtl->outgoing_args_size; + gcc_assert (multiple_p (offset, STACK_BOUNDARY / BITS_PER_UNIT)); + frame.bytes_below_saved_regs = offset; ++ frame.sve_save_and_probe = INVALID_REGNUM; + + /* Now assign stack slots for the registers. Start with the predicate + registers, since predicate LDR and STR have a relatively small +@@ -6911,6 +6908,8 @@ aarch64_layout_frame (void) + for (regno = P0_REGNUM; regno <= P15_REGNUM; regno++) + if (known_eq (frame.reg_offset[regno], SLOT_REQUIRED)) + { ++ if (frame.sve_save_and_probe == INVALID_REGNUM) ++ frame.sve_save_and_probe = regno; + frame.reg_offset[regno] = offset; + offset += BYTES_PER_SVE_PRED; + } +@@ -6948,6 +6947,8 @@ aarch64_layout_frame (void) + for (regno = V0_REGNUM; regno <= V31_REGNUM; regno++) + if (known_eq (frame.reg_offset[regno], SLOT_REQUIRED)) + { ++ if (frame.sve_save_and_probe == INVALID_REGNUM) ++ frame.sve_save_and_probe = regno; + frame.reg_offset[regno] = offset; + offset += vector_save_size; + } +@@ -6957,11 +6958,19 @@ aarch64_layout_frame (void) + frame.below_hard_fp_saved_regs_size = offset - frame.bytes_below_saved_regs; + bool saves_below_hard_fp_p + = maybe_ne (frame.below_hard_fp_saved_regs_size, 0); ++ gcc_assert (!saves_below_hard_fp_p ++ || (frame.sve_save_and_probe != INVALID_REGNUM ++ && known_eq (frame.reg_offset[frame.sve_save_and_probe], ++ frame.bytes_below_saved_regs))); ++ + frame.bytes_below_hard_fp = offset; ++ frame.hard_fp_save_and_probe = INVALID_REGNUM; + + #define ALLOCATE_GPR_SLOT(REGNO) \ + do \ + { \ ++ if (frame.hard_fp_save_and_probe == INVALID_REGNUM) \ ++ frame.hard_fp_save_and_probe = (REGNO); \ + frame.reg_offset[REGNO] = offset; \ + if (frame.wb_candidate1 == INVALID_REGNUM) \ + frame.wb_candidate1 = (REGNO); \ +@@ -6998,6 +7007,8 @@ aarch64_layout_frame (void) + for (regno = V0_REGNUM; regno <= V31_REGNUM; regno++) + if (known_eq (frame.reg_offset[regno], SLOT_REQUIRED)) + { ++ if (frame.hard_fp_save_and_probe == INVALID_REGNUM) ++ frame.hard_fp_save_and_probe = regno; + /* If there is an alignment gap between integer and fp callee-saves, + allocate the last fp register to it if possible. */ + if (regno == last_fp_reg +@@ -7021,6 +7032,17 @@ aarch64_layout_frame (void) + offset = aligned_upper_bound (offset, STACK_BOUNDARY / BITS_PER_UNIT); + + frame.saved_regs_size = offset - frame.bytes_below_saved_regs; ++ gcc_assert (known_eq (frame.saved_regs_size, ++ frame.below_hard_fp_saved_regs_size) ++ || (frame.hard_fp_save_and_probe != INVALID_REGNUM ++ && known_eq (frame.reg_offset[frame.hard_fp_save_and_probe], ++ frame.bytes_below_hard_fp))); ++ ++ /* With stack-clash, a register must be saved in non-leaf functions. ++ The saving of the bottommost register counts as an implicit probe, ++ which allows us to maintain the invariant described in the comment ++ at expand_prologue. */ ++ gcc_assert (crtl->is_leaf || maybe_ne (frame.saved_regs_size, 0)); + + offset += get_frame_size (); + offset = aligned_upper_bound (offset, STACK_BOUNDARY / BITS_PER_UNIT); +@@ -7120,6 +7142,25 @@ aarch64_layout_frame (void) + frame.final_adjust = frame.bytes_below_saved_regs; + } + ++ /* The frame is allocated in pieces, with each non-final piece ++ including a register save at offset 0 that acts as a probe for ++ the following piece. In addition, the save of the bottommost register ++ acts as a probe for callees and allocas. Roll back any probes that ++ aren't needed. ++ ++ A probe isn't needed if it is associated with the final allocation ++ (including callees and allocas) that happens before the epilogue is ++ executed. */ ++ if (crtl->is_leaf ++ && !cfun->calls_alloca ++ && known_eq (frame.final_adjust, 0)) ++ { ++ if (maybe_ne (frame.sve_callee_adjust, 0)) ++ frame.sve_save_and_probe = INVALID_REGNUM; ++ else ++ frame.hard_fp_save_and_probe = INVALID_REGNUM; ++ } ++ + /* Make sure the individual adjustments add up to the full frame size. */ + gcc_assert (known_eq (frame.initial_adjust + + frame.callee_adjust +@@ -7669,13 +7710,6 @@ aarch64_get_separate_components (void) + + poly_int64 offset = frame.reg_offset[regno]; + +- /* If the register is saved in the first SVE save slot, we use +- it as a stack probe for -fstack-clash-protection. */ +- if (flag_stack_clash_protection +- && maybe_ne (frame.below_hard_fp_saved_regs_size, 0) +- && known_eq (offset, frame.bytes_below_saved_regs)) +- continue; +- + /* Get the offset relative to the register we'll use. */ + if (frame_pointer_needed) + offset -= frame.bytes_below_hard_fp; +@@ -7710,6 +7744,13 @@ aarch64_get_separate_components (void) + + bitmap_clear_bit (components, LR_REGNUM); + bitmap_clear_bit (components, SP_REGNUM); ++ if (flag_stack_clash_protection) ++ { ++ if (frame.sve_save_and_probe != INVALID_REGNUM) ++ bitmap_clear_bit (components, frame.sve_save_and_probe); ++ if (frame.hard_fp_save_and_probe != INVALID_REGNUM) ++ bitmap_clear_bit (components, frame.hard_fp_save_and_probe); ++ } + + return components; + } +@@ -8246,8 +8287,8 @@ aarch64_epilogue_uses (int regno) + When probing is needed, we emit a probe at the start of the prologue + and every PARAM_STACK_CLASH_PROTECTION_GUARD_SIZE bytes thereafter. + +- We have to track how much space has been allocated and the only stores +- to the stack we track as implicit probes are the FP/LR stores. ++ We can also use register saves as probes. These are stored in ++ sve_save_and_probe and hard_fp_save_and_probe. + + For outgoing arguments we probe if the size is larger than 1KB, such that + the ABI specified buffer is maintained for the next callee. +diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h +index 1c3c62639cb..5279503fd09 100644 +--- a/gcc/config/aarch64/aarch64.h ++++ b/gcc/config/aarch64/aarch64.h +@@ -877,6 +877,14 @@ struct GTY (()) aarch64_frame + This is the register they should use. */ + unsigned spare_pred_reg; + ++ /* An SVE register that is saved below the hard frame pointer and that acts ++ as a probe for later allocations, or INVALID_REGNUM if none. */ ++ unsigned sve_save_and_probe; ++ ++ /* A register that is saved at the hard frame pointer and that acts ++ as a probe for later allocations, or INVALID_REGNUM if none. */ ++ unsigned hard_fp_save_and_probe; ++ + bool laid_out; + }; + +diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pcs/stack_clash_3.c b/gcc/testsuite/gcc.target/aarch64/sve/pcs/stack_clash_3.c +index 3e01ec36c3a..3530a0d504b 100644 +--- a/gcc/testsuite/gcc.target/aarch64/sve/pcs/stack_clash_3.c ++++ b/gcc/testsuite/gcc.target/aarch64/sve/pcs/stack_clash_3.c +@@ -11,11 +11,10 @@ + ** mov x11, sp + ** ... + ** sub sp, sp, x13 +-** str p4, \[sp\] + ** cbz w0, [^\n]* ++** str p4, \[sp\] + ** ... + ** ptrue p0\.b, all +-** ldr p4, \[sp\] + ** addvl sp, sp, #1 + ** ldr x24, \[sp\], 32 + ** ret +@@ -39,13 +38,12 @@ test_1 (int n) + ** mov x11, sp + ** ... + ** sub sp, sp, x13 +-** str p4, \[sp\] + ** cbz w0, [^\n]* ++** str p4, \[sp\] + ** str p5, \[sp, #1, mul vl\] + ** str p6, \[sp, #2, mul vl\] + ** ... + ** ptrue p0\.b, all +-** ldr p4, \[sp\] + ** addvl sp, sp, #1 + ** ldr x24, \[sp\], 32 + ** ret +-- +2.39.3 diff --git a/0121-aarch64-Remove-below_hard_fp_saved_regs_size.patch b/0121-aarch64-Remove-below_hard_fp_saved_regs_size.patch new file mode 100644 index 0000000..c86e6db --- /dev/null +++ b/0121-aarch64-Remove-below_hard_fp_saved_regs_size.patch @@ -0,0 +1,158 @@ +From 1c659316abe90c98b98494c9f13bd040e25063d8 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Thu, 22 Jun 2023 22:15:39 +0100 +Subject: [PATCH] aarch64: Remove below_hard_fp_saved_regs_size + +After previous patches, it's no longer necessary to store +saved_regs_size and below_hard_fp_saved_regs_size in the frame info. +All measurements instead use the top or bottom of the frame as +reference points. + +gcc/ + * config/aarch64/aarch64.h (aarch64_frame::saved_regs_size) + (aarch64_frame::below_hard_fp_saved_regs_size): Delete. + * config/aarch64/aarch64.c (aarch64_layout_frame): Update accordingly. +--- + gcc/config/aarch64/aarch64.c | 46 +++++++++++++++++------------------- + gcc/config/aarch64/aarch64.h | 7 ------ + 2 files changed, 22 insertions(+), 31 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 2dea9b5617d..91833473c75 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -6955,9 +6955,9 @@ aarch64_layout_frame (void) + + /* OFFSET is now the offset of the hard frame pointer from the bottom + of the callee save area. */ +- frame.below_hard_fp_saved_regs_size = offset - frame.bytes_below_saved_regs; +- bool saves_below_hard_fp_p +- = maybe_ne (frame.below_hard_fp_saved_regs_size, 0); ++ poly_int64 below_hard_fp_saved_regs_size ++ = offset - frame.bytes_below_saved_regs; ++ bool saves_below_hard_fp_p = maybe_ne (below_hard_fp_saved_regs_size, 0); + gcc_assert (!saves_below_hard_fp_p + || (frame.sve_save_and_probe != INVALID_REGNUM + && known_eq (frame.reg_offset[frame.sve_save_and_probe], +@@ -7031,9 +7031,8 @@ aarch64_layout_frame (void) + + offset = aligned_upper_bound (offset, STACK_BOUNDARY / BITS_PER_UNIT); + +- frame.saved_regs_size = offset - frame.bytes_below_saved_regs; +- gcc_assert (known_eq (frame.saved_regs_size, +- frame.below_hard_fp_saved_regs_size) ++ poly_int64 saved_regs_size = offset - frame.bytes_below_saved_regs; ++ gcc_assert (known_eq (saved_regs_size, below_hard_fp_saved_regs_size) + || (frame.hard_fp_save_and_probe != INVALID_REGNUM + && known_eq (frame.reg_offset[frame.hard_fp_save_and_probe], + frame.bytes_below_hard_fp))); +@@ -7042,7 +7041,7 @@ aarch64_layout_frame (void) + The saving of the bottommost register counts as an implicit probe, + which allows us to maintain the invariant described in the comment + at expand_prologue. */ +- gcc_assert (crtl->is_leaf || maybe_ne (frame.saved_regs_size, 0)); ++ gcc_assert (crtl->is_leaf || maybe_ne (saved_regs_size, 0)); + + offset += get_frame_size (); + offset = aligned_upper_bound (offset, STACK_BOUNDARY / BITS_PER_UNIT); +@@ -7068,7 +7067,7 @@ aarch64_layout_frame (void) + + HOST_WIDE_INT const_size, const_below_saved_regs, const_above_fp; + HOST_WIDE_INT const_saved_regs_size; +- if (known_eq (frame.saved_regs_size, 0)) ++ if (known_eq (saved_regs_size, 0)) + frame.initial_adjust = frame.frame_size; + else if (frame.frame_size.is_constant (&const_size) + && const_size < max_push_offset +@@ -7081,7 +7080,7 @@ aarch64_layout_frame (void) + frame.callee_adjust = const_size; + } + else if (frame.bytes_below_saved_regs.is_constant (&const_below_saved_regs) +- && frame.saved_regs_size.is_constant (&const_saved_regs_size) ++ && saved_regs_size.is_constant (&const_saved_regs_size) + && const_below_saved_regs + const_saved_regs_size < 512 + /* We could handle this case even with data below the saved + registers, provided that that data left us with valid offsets +@@ -7100,8 +7099,7 @@ aarch64_layout_frame (void) + frame.initial_adjust = frame.frame_size; + } + else if (saves_below_hard_fp_p +- && known_eq (frame.saved_regs_size, +- frame.below_hard_fp_saved_regs_size)) ++ && known_eq (saved_regs_size, below_hard_fp_saved_regs_size)) + { + /* Frame in which all saves are SVE saves: + +@@ -7123,7 +7121,7 @@ aarch64_layout_frame (void) + [save SVE registers relative to SP] + sub sp, sp, bytes_below_saved_regs */ + frame.callee_adjust = const_above_fp; +- frame.sve_callee_adjust = frame.below_hard_fp_saved_regs_size; ++ frame.sve_callee_adjust = below_hard_fp_saved_regs_size; + frame.final_adjust = frame.bytes_below_saved_regs; + } + else +@@ -7138,7 +7136,7 @@ aarch64_layout_frame (void) + [save SVE registers relative to SP] + sub sp, sp, bytes_below_saved_regs */ + frame.initial_adjust = frame.bytes_above_hard_fp; +- frame.sve_callee_adjust = frame.below_hard_fp_saved_regs_size; ++ frame.sve_callee_adjust = below_hard_fp_saved_regs_size; + frame.final_adjust = frame.bytes_below_saved_regs; + } + +@@ -8252,17 +8250,17 @@ aarch64_epilogue_uses (int regno) + | local variables | <-- frame_pointer_rtx + | | + +-------------------------------+ +- | padding | \ +- +-------------------------------+ | +- | callee-saved registers | | frame.saved_regs_size +- +-------------------------------+ | +- | LR' | | +- +-------------------------------+ | +- | FP' | | +- +-------------------------------+ |<- hard_frame_pointer_rtx (aligned) +- | SVE vector registers | | \ +- +-------------------------------+ | | below_hard_fp_saved_regs_size +- | SVE predicate registers | / / ++ | padding | ++ +-------------------------------+ ++ | callee-saved registers | ++ +-------------------------------+ ++ | LR' | ++ +-------------------------------+ ++ | FP' | ++ +-------------------------------+ <-- hard_frame_pointer_rtx (aligned) ++ | SVE vector registers | ++ +-------------------------------+ ++ | SVE predicate registers | + +-------------------------------+ + | dynamic allocation | + +-------------------------------+ +diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h +index 5279503fd09..b0d13cf08ec 100644 +--- a/gcc/config/aarch64/aarch64.h ++++ b/gcc/config/aarch64/aarch64.h +@@ -820,18 +820,11 @@ struct GTY (()) aarch64_frame + STACK_BOUNDARY. */ + HOST_WIDE_INT saved_varargs_size; + +- /* The size of the callee-save registers with a slot in REG_OFFSET. */ +- poly_int64 saved_regs_size; +- + /* The number of bytes between the bottom of the static frame (the bottom + of the outgoing arguments) and the bottom of the register save area. + This value is always a multiple of STACK_BOUNDARY. */ + poly_int64 bytes_below_saved_regs; + +- /* The size of the callee-save registers with a slot in REG_OFFSET that +- are saved below the hard frame pointer. */ +- poly_int64 below_hard_fp_saved_regs_size; +- + /* The number of bytes between the bottom of the static frame (the bottom + of the outgoing arguments) and the hard frame pointer. This value is + always a multiple of STACK_BOUNDARY. */ +-- +2.39.3 + diff --git a/0122-aarch64-Make-stack-smash-canary-protect-saved-registers.patch b/0122-aarch64-Make-stack-smash-canary-protect-saved-registers.patch new file mode 100644 index 0000000..513a464 --- /dev/null +++ b/0122-aarch64-Make-stack-smash-canary-protect-saved-registers.patch @@ -0,0 +1,297 @@ +From dad1c82acf67a8a1cc68e2acf3ec89a503e361fc Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Thu, 15 Jun 2023 19:16:52 +0100 +Subject: [PATCH] aarch64: Make stack smash canary protect saved registers + +AArch64 normally puts the saved registers near the bottom of the frame, +immediately above any dynamic allocations. But this means that a +stack-smash attack on those dynamic allocations could overwrite the +saved registers without needing to reach as far as the stack smash +canary. + +The same thing could also happen for variable-sized arguments that are +passed by value, since those are allocated before a call and popped on +return. + +This patch avoids that by putting the locals (and thus the canary) below +the saved registers when stack smash protection is active. + +The patch fixes CVE-2023-4039. + +gcc/ + * config/aarch64/aarch64.c (aarch64_save_regs_above_locals_p): + New function. + (aarch64_layout_frame): Use it to decide whether locals should + go above or below the saved registers. + (aarch64_expand_prologue): Update stack layout comment. + Emit a stack tie after the final adjustment. + +gcc/testsuite/ + * gcc.target/aarch64/stack-protector-8.c: New test. + * gcc.target/aarch64/stack-protector-9.c: Likewise. +--- + gcc/config/aarch64/aarch64.c | 47 +++++++-- + .../gcc.target/aarch64/stack-protector-8.c | 95 +++++++++++++++++++ + .../gcc.target/aarch64/stack-protector-9.c | 33 +++++++ + 3 files changed, 169 insertions(+), 6 deletions(-) + create mode 100644 gcc/testsuite/gcc.target/aarch64/stack-protector-8.c + create mode 100644 gcc/testsuite/gcc.target/aarch64/stack-protector-9.c + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 91833473c75..ce701b91a3f 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -6820,6 +6820,20 @@ aarch64_needs_frame_chain (void) + return aarch64_use_frame_pointer; + } + ++/* Return true if the current function should save registers above ++ the locals area, rather than below it. */ ++ ++static bool ++aarch64_save_regs_above_locals_p () ++{ ++ /* When using stack smash protection, make sure that the canary slot ++ comes between the locals and the saved registers. Otherwise, ++ it would be possible for a carefully sized smash attack to change ++ the saved registers (particularly LR and FP) without reaching the ++ canary. */ ++ return crtl->stack_protect_guard; ++} ++ + /* Mark the registers that need to be saved by the callee and calculate + the size of the callee-saved registers area and frame record (both FP + and LR may be omitted). */ +@@ -6831,6 +6845,7 @@ aarch64_layout_frame (void) + poly_int64 vector_save_size = GET_MODE_SIZE (vector_save_mode); + bool frame_related_fp_reg_p = false; + aarch64_frame &frame = cfun->machine->frame; ++ poly_int64 top_of_locals = -1; + + frame.emit_frame_chain = aarch64_needs_frame_chain (); + +@@ -6897,8 +6912,16 @@ aarch64_layout_frame (void) + && !crtl->abi->clobbers_full_reg_p (regno)) + frame.reg_offset[regno] = SLOT_REQUIRED; + ++ bool regs_at_top_p = aarch64_save_regs_above_locals_p (); ++ + poly_int64 offset = crtl->outgoing_args_size; + gcc_assert (multiple_p (offset, STACK_BOUNDARY / BITS_PER_UNIT)); ++ if (regs_at_top_p) ++ { ++ offset += get_frame_size (); ++ offset = aligned_upper_bound (offset, STACK_BOUNDARY / BITS_PER_UNIT); ++ top_of_locals = offset; ++ } + frame.bytes_below_saved_regs = offset; + frame.sve_save_and_probe = INVALID_REGNUM; + +@@ -7043,15 +7066,18 @@ aarch64_layout_frame (void) + at expand_prologue. */ + gcc_assert (crtl->is_leaf || maybe_ne (saved_regs_size, 0)); + +- offset += get_frame_size (); +- offset = aligned_upper_bound (offset, STACK_BOUNDARY / BITS_PER_UNIT); +- poly_int64 top_of_locals = offset; +- ++ if (!regs_at_top_p) ++ { ++ offset += get_frame_size (); ++ offset = aligned_upper_bound (offset, STACK_BOUNDARY / BITS_PER_UNIT); ++ top_of_locals = offset; ++ } + offset += frame.saved_varargs_size; + gcc_assert (multiple_p (offset, STACK_BOUNDARY / BITS_PER_UNIT)); + frame.frame_size = offset; + + frame.bytes_above_hard_fp = frame.frame_size - frame.bytes_below_hard_fp; ++ gcc_assert (known_ge (top_of_locals, 0)); + frame.bytes_above_locals = frame.frame_size - top_of_locals; + + frame.initial_adjust = 0; +@@ -8247,10 +8273,10 @@ aarch64_epilogue_uses (int regno) + | for register varargs | + | | + +-------------------------------+ +- | local variables | <-- frame_pointer_rtx ++ | local variables (1) | <-- frame_pointer_rtx + | | + +-------------------------------+ +- | padding | ++ | padding (1) | + +-------------------------------+ + | callee-saved registers | + +-------------------------------+ +@@ -8262,6 +8288,10 @@ aarch64_epilogue_uses (int regno) + +-------------------------------+ + | SVE predicate registers | + +-------------------------------+ ++ | local variables (2) | ++ +-------------------------------+ ++ | padding (2) | ++ +-------------------------------+ + | dynamic allocation | + +-------------------------------+ + | padding | +@@ -8271,6 +8301,9 @@ aarch64_epilogue_uses (int regno) + +-------------------------------+ + | | <-- stack_pointer_rtx (aligned) + ++ The regions marked (1) and (2) are mutually exclusive. (2) is used ++ when aarch64_save_regs_above_locals_p is true. ++ + Dynamic stack allocations via alloca() decrease stack_pointer_rtx + but leave frame_pointer_rtx and hard_frame_pointer_rtx + unchanged. +@@ -8462,6 +8495,8 @@ aarch64_expand_prologue (void) + gcc_assert (known_eq (bytes_below_sp, final_adjust)); + aarch64_allocate_and_probe_stack_space (tmp1_rtx, tmp0_rtx, final_adjust, + !frame_pointer_needed, true); ++ if (emit_frame_chain && maybe_ne (final_adjust, 0)) ++ emit_insn (gen_stack_tie (stack_pointer_rtx, hard_frame_pointer_rtx)); + } + + /* Return TRUE if we can use a simple_return insn. +diff --git a/gcc/testsuite/gcc.target/aarch64/stack-protector-8.c b/gcc/testsuite/gcc.target/aarch64/stack-protector-8.c +new file mode 100644 +index 00000000000..e71d820e365 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/stack-protector-8.c +@@ -0,0 +1,95 @@ ++/* { dg-options " -O -fstack-protector-strong -mstack-protector-guard=sysreg -mstack-protector-guard-reg=tpidr2_el0 -mstack-protector-guard-offset=16" } */ ++/* { dg-final { check-function-bodies "**" "" } } */ ++ ++void g(void *); ++__SVBool_t *h(void *); ++ ++/* ++** test1: ++** sub sp, sp, #288 ++** stp x29, x30, \[sp, #?272\] ++** add x29, sp, #?272 ++** mrs (x[0-9]+), tpidr2_el0 ++** ldr (x[0-9]+), \[\1, #?16\] ++** str \2, \[sp, #?264\] ++** mov \2, #?0 ++** add x0, sp, #?8 ++** bl g ++** ... ++** mrs .* ++** ... ++** bne .* ++** ... ++** ldp x29, x30, \[sp, #?272\] ++** add sp, sp, #?288 ++** ret ++** bl __stack_chk_fail ++*/ ++int test1() { ++ int y[0x40]; ++ g(y); ++ return 1; ++} ++ ++/* ++** test2: ++** stp x29, x30, \[sp, #?-16\]! ++** mov x29, sp ++** sub sp, sp, #1040 ++** mrs (x[0-9]+), tpidr2_el0 ++** ldr (x[0-9]+), \[\1, #?16\] ++** str \2, \[sp, #?1032\] ++** mov \2, #?0 ++** add x0, sp, #?8 ++** bl g ++** ... ++** mrs .* ++** ... ++** bne .* ++** ... ++** add sp, sp, #?1040 ++** ldp x29, x30, \[sp\], #?16 ++** ret ++** bl __stack_chk_fail ++*/ ++int test2() { ++ int y[0x100]; ++ g(y); ++ return 1; ++} ++ ++#pragma GCC target "+sve" ++ ++/* ++** test3: ++** stp x29, x30, \[sp, #?-16\]! ++** mov x29, sp ++** addvl sp, sp, #-18 ++** ... ++** str p4, \[sp\] ++** ... ++** sub sp, sp, #272 ++** mrs (x[0-9]+), tpidr2_el0 ++** ldr (x[0-9]+), \[\1, #?16\] ++** str \2, \[sp, #?264\] ++** mov \2, #?0 ++** add x0, sp, #?8 ++** bl h ++** ... ++** mrs .* ++** ... ++** bne .* ++** ... ++** add sp, sp, #?272 ++** ... ++** ldr p4, \[sp\] ++** ... ++** addvl sp, sp, #18 ++** ldp x29, x30, \[sp\], #?16 ++** ret ++** bl __stack_chk_fail ++*/ ++__SVBool_t test3() { ++ int y[0x40]; ++ return *h(y); ++} +diff --git a/gcc/testsuite/gcc.target/aarch64/stack-protector-9.c b/gcc/testsuite/gcc.target/aarch64/stack-protector-9.c +new file mode 100644 +index 00000000000..58f322aa480 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/stack-protector-9.c +@@ -0,0 +1,33 @@ ++/* { dg-options "-O2 -mcpu=neoverse-v1 -fstack-protector-all" } */ ++/* { dg-final { check-function-bodies "**" "" } } */ ++ ++/* ++** main: ++** ... ++** stp x29, x30, \[sp, #?-[0-9]+\]! ++** ... ++** sub sp, sp, #[0-9]+ ++** ... ++** str x[0-9]+, \[x29, #?-8\] ++** ... ++*/ ++int f(const char *); ++void g(void *); ++int main(int argc, char* argv[]) ++{ ++ int a; ++ int b; ++ char c[2+f(argv[1])]; ++ int d[0x100]; ++ char y; ++ ++ y=42; a=4; b=10; ++ c[0] = 'h'; c[1] = '\0'; ++ ++ c[f(argv[2])] = '\0'; ++ ++ __builtin_printf("%d %d\n%s\n", a, b, c); ++ g(d); ++ ++ return 0; ++} +-- +2.39.3 @@ -1,3 +0,0 @@ -#!/bin/sh -# Traditionally, /lib/cpp only knew about C. -exec /usr/bin/cpp -xc "$@" @@ -1,767 +1,3063 @@ -# -# spec file for package gcc -# -# Copyright (c) 2021 SUSE LLC -# -# All modifications and additions to the file contributed by third parties -# remain the property of their copyright owners, unless otherwise agreed -# upon. The license for this file, and modifications and additions to the -# file, is the same license as for the pristine package itself (unless the -# license for the pristine package is not an Open Source License, in which -# case the license is the MIT License). An "Open Source License" is a -# license that conforms to the Open Source Definition (Version 1.9) -# published by the Open Source Initiative. - -# Please submit bugfixes or comments via https://bugs.opensuse.org/ -# - - -Name: gcc -%define separate_bi32 0 -%define separate_bi64 0 -%ifarch ppc -%define separate_bi64 1 +%global gcc_version 10.3.1 +%global gcc_major 10.3.1 +%global _unpackaged_files_terminate_build 0 +%global _performance_build 1 + +%undefine _hardened_build +%undefine _annotated_build + +%global build_ada 0 +%global build_objc 1 +%global build_go 0 +%global build_d 0 +%global build_check 0 +%ifarch %{ix86} x86_64 ia64 ppc64le aarch64 +%global build_libquadmath 1 +%else +%global build_libquadmath 0 +%endif +%ifarch %{ix86} x86_64 ppc ppc64 ppc64le ppc64p7 s390 s390x %{arm} aarch64 +%global build_libasan 1 +%else +%global build_libasan 0 +%endif +%ifarch x86_64 ppc64 ppc64le aarch64 +%global build_libtsan 1 +%else +%global build_libtsan 0 %endif -%ifarch x86_64 s390x ppc64 -%define separate_bi32 1 +%ifarch x86_64 ppc64 ppc64le aarch64 +%global build_liblsan 1 +%else +%global build_liblsan 0 +%endif +%ifarch %{ix86} x86_64 ppc ppc64 ppc64le ppc64p7 s390 s390x %{arm} aarch64 +%global build_libubsan 1 +%else +%global build_libubsan 0 %endif -# Ada currently fails to build on a few platforms, enable it only -# on those that work -# Note that AdaCore only supports %ix86, x86_64 and ia64 -%ifarch %ix86 x86_64 ppc ppc64 ppc64le s390 s390x ia64 aarch64 -%define build_ada 1 +%ifarch %{ix86} x86_64 ppc ppc64 ppc64le ppc64p7 s390 s390x %{arm} aarch64 %{mips} riscv64 +%global build_libatomic 1 %else -# alpha hppa arm -%define build_ada 0 -%endif -Url: http://gcc.gnu.org/ -%define gcc_version 7 -%define gcc_suffix 7 -Version: 7 -Release: 3.9.1 -Summary: The system GNU C Compiler -License: GPL-3.0+ -Group: Development/Languages/C and C++ -Provides: c_compiler - -Requires: cpp -Requires: gcc%{gcc_version} -BuildRoot: %{_tmppath}/%{name}-%{version}-build -BuildRequires: gcc%{gcc_version} -Source: cpp +%global build_libatomic 0 +%endif +%ifarch %{ix86} x86_64 %{arm} alpha ppc ppc64 ppc64le ppc64p7 s390 s390x aarch64 +%global build_libitm 1 +%else +%global build_libitm 0 +%endif +%global build_isl 1 +%global build_libstdcxx_docs 0 +%ifarch %{ix86} x86_64 ppc ppc64 ppc64le ppc64p7 s390 s390x %{arm} aarch64 %{mips} +%global attr_ifunc 1 +%else +%global attr_ifunc 0 +%endif +%ifarch riscv64 +%global _lib lib +%global _smp_mflags -j8 +%endif -%description -The system GNU C Compiler. +Summary: Various compilers (C, C++, Objective-C, ...) +Name: gcc +Version: %{gcc_version} +Release: 38 +License: GPLv3+ and GPLv3+ with exceptions and GPLv2+ with exceptions and LGPLv2+ and BSD +URL: https://gcc.gnu.org + +Source0: https://ftp.gnu.org/gnu/gcc/gcc-10.3.0/gcc-10.3.0.tar.xz +%global isl_version 0.15 + +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +BuildRequires: binutils >= 2.31 +BuildRequires: glibc-headers +BuildRequires: libtool, zlib-devel, texinfo, flex, bison +BuildRequires: gmp-devel >= 4.1.2-8, mpfr-devel >= 3.1.0, libmpc-devel >= 0.8.1 +BuildRequires: gcc, gcc-c++, make, chrpath +%if %{build_go} +BuildRequires: hostname, procps +%endif +BuildRequires: gdb +BuildRequires: glibc-devel >= 2.17 +%ifarch %{multilib_64_archs} sparcv9 ppc +BuildRequires: /lib/libc.so.6 /usr/lib/libc.so /lib64/libc.so.6 /usr/lib64/libc.so +%endif +%if %{build_ada} +BuildRequires: gcc-gnat >= 3.1, libgnat >= 3.1 +%endif +%ifarch ia64 +BuildRequires: libunwind >= 0.98 +%endif +%if %{build_isl} +BuildRequires: isl >= %{isl_version}, isl-devel >= %{isl_version} +Requires: isl >= %{isl_version}, isl-devel >= %{isl_version} +%endif +%if %{build_libstdcxx_docs} +BuildRequires: doxygen >= 1.7.1 +BuildRequires: graphviz, dblatex, texlive-collection-latex, docbook5-style-xsl +%endif +Requires: cpp = %{version}-%{release} +Requires: binutils >= 2.31 +Conflicts: gdb < 5.1-2 +Requires: glibc-devel >= 2.17 +Requires: libgcc >= %{version}-%{release} +Requires: libgomp = %{version}-%{release} +%if !%{build_ada} +Obsoletes: gcc-gnat < %{version}-%{release} +%endif +Obsoletes: gcc-java < %{version}-%{release} +AutoReq: true +Provides: bundled(libiberty) +Provides: gcc(major) = %{gcc_major} + + +Patch1: 0001-libquadmath-Enable-libquadmath-on-kunpeng.patch +Patch2: 0002-Backport-cselim-Extend-to-check-non-trapping-for-mor.patch +Patch3: 0003-version-Set-version-to-10.3.1.patch +Patch4: 0004-Backport-tree-optimization-Avoid-issueing-loads-in-S.patch +Patch5: 0005-Backport-tree-optimization-Fix-load-eliding-in-SM.patch +Patch6: 0006-simdmath-Enable-simdmath-on-kunpeng.patch +Patch7: 0007-Vect-Enable-skipping-vectorization-on-reduction-chai.patch +Patch8: 0008-Backport-tree-optimization-Add-checks-to-avoid-spoil.patch +Patch9: 0009-Backport-expand-Simplify-removing-subregs-when-expan.patch +Patch10: 0010-Backport-tree-optimization-94963-avoid-bogus-uninit-.patch +Patch11: 0011-simdmath-Enable-64-bits-simd-when-test-simd_pcs_attr.patch +Patch12: 0012-fp-model-Enable-fp-model-on-kunpeng.patch +Patch13: 0013-LoopElim-Redundant-loop-elimination-optimization.patch +Patch14: 0014-Backport-StructReorg-Structure-reorganization-optimi.patch +Patch15: 0015-CompleteStructReorg-Complete-Structure-Reorganizatio.patch +Patch16: 0016-StructReorg-Bugfix-in-certain-scenarios.patch +Patch17: 0017-mcmodel-Enable-mcmodel-medium-on-kunpeng.patch +Patch18: 0018-StructReorderFields-Structure-reorder-fields.patch +Patch19: 0019-StructReorderFields-Fix-bugs-and-improve-mechanism.patch +Patch20: 0020-Backport-vect-Fix-an-ICE-in-vect_recog_mask_conversi.patch +Patch21: 0021-mcmodel-Bugfix-for-mcmodel-medium-on-x86.patch +Patch22: 0022-StructReorderFields-Fix-pointer-layer-check-bug.patch +Patch23: 0023-StructReorderFields-Add-pointer-offset-check.patch +Patch24: 0024-StructReorderFields-Add-lto-and-whole-program-gate.patch +Patch25: 0025-AutoPrefetch-Support-cache-misses-profile.patch +Patch26: 0026-AutoFDO-Enable-discriminator-and-MCF-algorithm-on-Au.patch +Patch27: 0027-Autoprefetch-Support-auto-feedback-prefetch.patch +Patch28: 0028-AutoPrefetch-Handle-the-case-that-the-basic-block-br.patch +Patch29: 0029-AutoBOLT-Support-saving-feedback-count-info-to-ELF-s.patch +Patch30: 0030-AutoBOLT-Add-bolt-linker-plugin-2-3.patch +Patch31: 0031-AutoBOLT-Enable-BOLT-linker-plugin-on-aarch64-3-3.patch +Patch32: 0032-Autoprefetch-Prune-invaild-loops-containing-edges-wh.patch +Patch33: 0033-AutoFdo-Fix-memory-leaks-in-autofdo-and-autoprefetch.patch +Patch34: 0034-Backport-sanitizer-Fix-asan-against-glibc-2.34-PR100.patch +Patch35: 0035-ccmp-Add-another-optimization-opportunity-for-ccmp-i.patch +Patch36: 0036-StructReorg-Refactoring-reorder-fields-to-struct-lay.patch +Patch38: 0038-DFE-Add-Dead-Field-Elimination-in-Struct-Reorg.patch +Patch39: 0039-Backport-ipa-sra-Fix-thinko-when-overriding-safe_to_.patch +Patch40: 0040-Backport-ifcvt-Allow-constants-for-noce_convert_mult.patch +Patch41: 0041-Backport-Register-sysroot-in-the-driver-switches-tab.patch +Patch42: 0042-DFE-Fix-bugs.patch +Patch45: 0045-Transposed-SLP-Enable-Transposed-SLP.patch +Patch46: 0046-ArrayWidenCompare-Add-a-new-optimization-for-array-c.patch +Patch47: 0047-DFE-Fix-the-bug-caused-by-inconsistent-types.patch +Patch48: 0048-Struct-Reorg-Type-simplify-limitation-when-in-struct.patch +Patch49: 0049-build-Add-some-file-right-to-executable.patch +Patch50: 0050-Backport-phiopt-Optimize-x-1024-0-to-int-x-10-PR9769.patch +Patch51: 0051-Backport-phiopt-Fix-up-conditional_replacement-PR993.patch +Patch52: 0052-Backport-phiopt-Handle-bool-in-two_value_replacement.patch +Patch53: 0053-Backport-phiopt-Optimize-x-__builtin_clz-x-32-in-GIM.patch +Patch54: 0054-Backport-phiopt-Optimize-x-__builtin_clz-x-32-in-GIM.patch +Patch55: 0055-Backport-phiopt-Optimize-x-0-y-y-to-x-31-y-PR96928.patch +Patch56: 0056-Backport-phiopt-Optimize-x-y-cmp-z-PR94589.patch +Patch57: 0057-Backport-Add-support-for-__builtin_bswap128.patch +Patch58: 0058-Backport-tree-optimization-95393-fold-MIN-MAX_EXPR-g.patch +Patch59: 0059-Backport-Add-a-couple-of-A-CST1-CST2-match-and-simpl.patch +Patch60: 0060-Backport-Optimize-x-0-y-y-to-x-31-y-in-match.pd.patch +Patch61: 0061-Backport-Replace-conditional_replacement-with-match-.patch +Patch62: 0062-Backport-Allow-match-and-simplified-phiopt-to-run-in.patch +Patch63: 0063-Backport-Improve-match_simplify_replacement-in-phi-o.patch +Patch64: 0064-Backport-phiopt-Use-gphi-phi-instead-of-gimple-phi-s.patch +Patch65: 0065-Backport-Optimize-x-bswap-x-0-in-tree-ssa-phiopt.patch +Patch66: 0066-Backport-tree-optimization-102880-make-PHI-OPT-recog.patch +Patch67: 0067-Backport-tree-Add-vector_element_bits-_tree-PR94980-.patch +Patch68: 0068-Backport-Lower-VEC_COND_EXPR-into-internal-functions.patch +Patch69: 0069-Backport-gimple-match-Add-a-gimple_extract_op-functi.patch +Patch70: 0070-Backport-aarch64-Fix-subs_compare_2.c-regression-PR1.patch +Patch71: 0071-PHIOPT-Disable-the-match-A-CST1-0-when-the-CST1-is-n.patch +Patch72: 0072-Struct-Reorg-Merge-struct_layout-pass-into-struct_re.patch +Patch73: 0073-PHIOPT-Add-A-B-op-CST-B-match-and-simplify-optimizat.patch +Patch74: 0074-FORWPROP-Fold-series-of-instructions-into-mul.patch +Patch75: 0075-FORWPROP-Fold-series-of-instructions-into-umulh.patch +Patch76: 0076-Struct-Reorg-Fix-speccpu2006-462-double-free-I60YUV.patch +Patch77: 0077-Struct-Reorg-Add-Safe-Structure-Pointer-Compression.patch +Patch78: 0078-Loop-distribution-Add-isomorphic-stmts-analysis.patch +Patch79: 0079-loop-vect-Transfer-arrays-using-registers-between-lo.patch +Patch80: 0080-Struct-Reorg-Add-Unsafe-Structure-Pointer-Compressio.patch +Patch81: 0081-Loop-distribution-Insert-temp-arrays-built-from-isom.patch +Patch82: 0082-Revert-Backport-tree-optimization-102880-make-PHI-OP.patch +Patch83: 0083-Struct-reorg-Add-struct-semi-relayout-optimize.patch +Patch84: 0084-MULL64-Disable-mull64-transformation-by-default.patch +Patch85: 0085-loop-distribution-Bugfix-for-loop-distribution.patch +Patch86: 0086-semi-relayout-Bugfix-for-struct-semi-relayout.patch +Patch87: 0087-Backport-tree-optimization-97238-fix-typo-causing-IC.patch +Patch88: 0088-Backport-fix-typo-causing-ICE.patch +Patch89: 0089-State-sysroot-option-as-validated-once-processed.patch +Patch90: 0090-bogus-Wstringop-overflow-with-VLA-of-elements-larger.patch +Patch91: 0091-phiopt2-Add-option-to-control-the-simplify.patch +Patch92: 0092-gimple-Factor-the-code-to-avoid-depending-auto-featu.patch +Patch93: 0093-StructReorg-Fix-escape_cast_another_ptr-check-bug.patch +Patch94: 0094-Backport-Fix-zero-masking-for-vcvtps2ph-when-dest-op.patch +Patch95: 0095-Struct-reorg-Fix-the-use-of-as_a.patch +Patch96: 0096-libquadmath-Revert-Enable-libquadmath-on-kunpeng.patch +Patch97: 0097-libquadmath-refactor-Enable-libquadmath-on-kunpeng.patch +Patch98: 0098-AArch64-Rewrite-the-tsv110-option.patch +Patch99: 0099-Struct-Reorg-Add-escape-propagate-on-external-functi.patch +Patch100: 0100-PGO-kernel-Add-fkernel-pgo-option-to-support-PGO-ker.patch +Patch101: 0101-To-resolve-the-SPEC-.548-fluctuation-problem-revert-.patch +Patch102: 0102-GOMP-Enabling-moutline-atomics-improves-libgomp-perf.patch +Patch103: 0103-test-Add-option-ftree-fold-phiopt-to-avoid-fail-NFC.patch +Patch104: 0104-aarch64-Use-local-frame-vars-in-shrink-wrapping-code.patch +Patch105: 0105-aarch64-Avoid-a-use-of-callee_offset.patch +Patch106: 0106-aarch64-Explicitly-handle-frames-with-no-saved-registers.patch +Patch107: 0107-aarch64-Add-bytes_below_saved_regs-to-frame-info.patch +Patch108: 0108-aarch64-Add-bytes_below_hard_fp-to-frame-info.patch +Patch109: 0109-aarch64-Tweak-aarch64_save-restore_callee_saves.patch +Patch110: 0110-aarch64-Only-calculate-chain_offset-if-there-is-a-chain.patch +Patch111: 0111-aarch64-Rename-locals_offset-to-bytes_above_locals.patch +Patch112: 0112-aarch64-Rename-hard_fp_offset-to-bytes_above_hard_fp.patch +Patch113: 0113-aarch64-Tweak-frame_size-comment.patch +Patch114: 0114-aarch64-Measure-reg_offset-from-the-bottom-of-the-frame.patch +Patch115: 0115-aarch64-Simplify-top-of-frame-allocation.patch +Patch116: 0116-aarch64-Minor-initial-adjustment-tweak.patch +Patch117: 0117-aarch64-Tweak-stack-clash-boundary-condition.patch +Patch118: 0118-aarch64-Put-LR-save-probe-in-first-16-bytes.patch +Patch119: 0119-aarch64-Simplif-yprobe-of-final-frame-allocation.patch +Patch120: 0120-aarch64-Explicitly-record-probe-registers-in-frame-info.patch +Patch121: 0121-aarch64-Remove-below_hard_fp_saved_regs_size.patch +Patch122: 0122-aarch64-Make-stack-smash-canary-protect-saved-registers.patch + +%global gcc_target_platform %{_arch}-linux-gnu + +%if %{build_go} +# Avoid stripping these libraries and binaries. +%global __os_install_post \ +chmod 644 %{buildroot}%{_prefix}/%{_lib}/libgo.so.16.* \ +chmod 644 %{buildroot}%{_prefix}/bin/go.gcc \ +chmod 644 %{buildroot}%{_prefix}/bin/gofmt.gcc \ +chmod 644 %{buildroot}%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/cgo \ +chmod 644 %{buildroot}%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/buildid \ +chmod 644 %{buildroot}%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/test2json \ +chmod 644 %{buildroot}%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/vet \ +%__os_install_post \ +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libgo.so.16.* \ +chmod 755 %{buildroot}%{_prefix}/bin/go.gcc \ +chmod 755 %{buildroot}%{_prefix}/bin/gofmt.gcc \ +chmod 755 %{buildroot}%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/cgo \ +chmod 755 %{buildroot}%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/buildid \ +chmod 755 %{buildroot}%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/test2json \ +chmod 755 %{buildroot}%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/vet \ +%{nil} +%endif +%description +The gcc package contains the GNU Compiler Collection version 10. +You'll need this package in order to compile C code. + +%package -n libgcc +Summary: GCC version 10 shared support library +Autoreq: false +%if !%{build_ada} +Obsoletes: libgnat < %{version}-%{release} +%endif +Obsoletes: libmudflap +Obsoletes: libmudflap-devel +Obsoletes: libmudflap-static +Obsoletes: libgcj < %{version}-%{release} +Obsoletes: libgcj-devel < %{version}-%{release} +Obsoletes: libgcj-src < %{version}-%{release} +%ifarch %{ix86} x86_64 +Obsoletes: libcilkrts +Obsoletes: libcilkrts-static +Obsoletes: libmpx +Obsoletes: libmpx-static +%endif +%description -n libgcc +This package contains GCC shared support library which is needed +e.g. for exception handling support. + +%package c++ +Summary: C++ support for GCC +Requires: gcc = %{version}-%{release} +Requires: libstdc++ = %{version}-%{release} +Requires: libstdc++-devel = %{version}-%{release} +Provides: gcc-g++ = %{version}-%{release} +Provides: g++ = %{version}-%{release} +Autoreq: true + +%description c++ +This package adds C++ support to the GNU Compiler Collection. +It includes support for most of the current C++ specification, +including templates and exception handling. + +%package -n libstdc++ +Summary: GNU Standard C++ Library +Autoreq: true +Requires: glibc >= 2.10.90-7 + +%description -n libstdc++ +The libstdc++ package contains a rewritten standard compliant GCC Standard +C++ Library. -%package -n gcc-32bit -Summary: The system GNU C Compiler -License: GPL-3.0+ -Group: Development/Languages/C and C++ -Requires: gcc = %{version} -Requires: gcc%{gcc_version}-32bit +%package -n libstdc++-devel +Summary: Header files and libraries for C++ development +Requires: libstdc++%{?_isa} = %{version}-%{release} +Autoreq: true -%description -n gcc-32bit -The system GNU C Compiler. +%description -n libstdc++-devel +This is the GNU implementation of the standard C++ libraries. This +package includes the header files and libraries needed for C++ +development. This includes rewritten implementation of STL. + +%package -n libstdc++-static +Summary: Static libraries for the GNU standard C++ library +Requires: libstdc++-devel = %{version}-%{release} +Autoreq: true + +%description -n libstdc++-static +Static libraries for the GNU standard C++ library. + +%package -n libstdc++-docs +Summary: Documentation for the GNU standard C++ library +Autoreq: true + +%description -n libstdc++-docs +Manual, doxygen generated API information and Frequently Asked Questions +for the GNU standard C++ library. + +%package objc +Summary: Objective-C support for GCC +Requires: gcc = %{version}-%{release} +Requires: libobjc = %{version}-%{release} +Autoreq: true + +%description objc +gcc-objc provides Objective-C support for the GCC. +Mainly used on systems running NeXTSTEP, Objective-C is an +object-oriented derivative of the C language. + +%package objc++ +Summary: Objective-C++ support for GCC +Requires: gcc-c++ = %{version}-%{release}, gcc-objc = %{version}-%{release} +Autoreq: true + +%description objc++ +gcc-objc++ package provides Objective-C++ support for the GCC. + +%package -n libobjc +Summary: Objective-C runtime +Autoreq: true + +%description -n libobjc +This package contains Objective-C shared library which is needed to run +Objective-C dynamically linked programs. + +%package gfortran +Summary: Fortran support +Requires: gcc = %{version}-%{release} +Requires: libgfortran = %{version}-%{release} +%if %{build_libquadmath} +Requires: libquadmath = %{version}-%{release} +Requires: libquadmath-devel = %{version}-%{release} +%endif +Provides: gcc-fortran = %{version}-%{release} +Provides: gfortran = %{version}-%{release} +Autoreq: true + +%description gfortran +The gcc-gfortran package provides support for compiling Fortran +programs with the GNU Compiler Collection. + +%package -n libgfortran +Summary: Fortran runtime +Autoreq: true +%if %{build_libquadmath} +Requires: libquadmath = %{version}-%{release} +%endif +%description -n libgfortran +This package contains Fortran shared library which is needed to run +Fortran dynamically linked programs. +%package -n libgfortran-static +Summary: Static Fortran libraries +Requires: libgfortran = %{version}-%{release} +Requires: gcc = %{version}-%{release} +%if %{build_libquadmath} +Requires: libquadmath-static = %{version}-%{release} +%endif -%package -n gcc-64bit -Summary: The system GNU C Compiler -License: GPL-3.0+ -Group: Development/Languages/C and C++ -Requires: gcc = %{version} -Requires: gcc%{gcc_version}-64bit +%description -n libgfortran-static +This package contains static Fortran libraries. -%description -n gcc-64bit -The system GNU C Compiler. +%package gdc +Summary: D support +Requires: gcc = %{version}-%{release} +Requires: libgphobos = %{version}-%{release} +Provides: gcc-d = %{version}-%{release} +Provides: gdc = %{version}-%{release} +Autoreq: true +%description gdc +The gcc-gdc package provides support for compiling D +programs with the GNU Compiler Collection. +%package -n libgphobos +Summary: D runtime +Autoreq: true -%package -n cpp -Summary: The system GNU Preprocessor -License: GPL-3.0+ -Group: Development/Languages/C and C++ -Requires: cpp%{gcc_version} +%description -n libgphobos +This package contains D shared library which is needed to run +D dynamically linked programs. -%description -n cpp -The system GNU Preprocessor. +%package -n libgphobos-static +Summary: Static D libraries +Requires: libgphobos = %{version}-%{release} +Requires: gcc-gdc = %{version}-%{release} +%description -n libgphobos-static +This package contains static D libraries. -%package -n gcc-devel -Summary: The system GNU C Compiler Plugin development files -License: GPL-3.0+ -Group: Development/Languages/C and C++ -Requires: gcc = %{version} -Requires: gcc%{gcc_version}-devel +%package -n libgomp +Summary: GCC OpenMP v4.5 shared support library -%description -n gcc-devel -The system GNU C Compiler Plugin development files. +%description -n libgomp +This package contains GCC shared support library which is needed +for OpenMP v4.5 support. +%package gdb-plugin +Summary: GCC plugin for GDB +Requires: gcc = %{version}-%{release} -%package -n gcc-locale -Summary: The system GNU Compiler locale files -License: GPL-3.0+ -Group: Development/Languages/C and C++ -Requires: gcc%{gcc_version}-locale +%description gdb-plugin +This package contains GCC plugin for GDB C expression evaluation. -%description -n gcc-locale -The system GNU Compiler locale files. +%package -n libgccjit +Summary: Library for embedding GCC inside programs and libraries +Requires: gcc = %{version}-%{release} +%description -n libgccjit +This package contains shared library with GCC JIT front-end. +%package -n libgccjit-devel +Summary: Support for embedding GCC inside programs and libraries +BuildRequires: python3-sphinx +Requires: libgccjit = %{version}-%{release} -%package -n gcc-info -Summary: The system GNU Compiler documentation -License: GFDL-1.2 -Group: Development/Languages/C and C++ -PreReq: gcc%{gcc_version}-info +%description -n libgccjit-devel +This package contains header files and documentation for GCC JIT front-end. -%description -n gcc-info -The system GNU Compiler documentation. +%package -n libquadmath +Summary: GCC __float128 shared support library +%description -n libquadmath +This package contains GCC shared support library which is needed +for __float128 math support and for Fortran REAL*16 support. +%package -n libquadmath-devel +Summary: GCC __float128 support +Requires: libquadmath = %{version}-%{release} +Requires: gcc = %{version}-%{release} -%package -n gcc-c++ -Summary: The system GNU C++ Compiler -License: GPL-3.0+ -Group: Development/Languages/C and C++ -Provides: c++_compiler -Requires: gcc = %{version} -Requires: gcc%{gcc_version}-c++ +%description -n libquadmath-devel +This package contains headers for building Fortran programs using +REAL*16 and programs using __float128 math. -%description -n gcc-c++ -The system GNU C++ Compiler. +%package -n libquadmath-static +Summary: Static libraries for __float128 support +Requires: libquadmath-devel = %{version}-%{release} +%description -n libquadmath-static +This package contains static libraries for building Fortran programs +using REAL*16 and programs using __float128 math. -%package -n gcc-c++-32bit -Summary: The system GNU C++ Compiler -License: GPL-3.0+ -Group: Development/Languages/C and C++ -Requires: gcc%{gcc_version}-c++-32bit -Requires: gcc-32bit = %{version} -Requires: gcc-c++ = %{version} +%package -n libitm +Summary: The GNU Transactional Memory library -%description -n gcc-c++-32bit -The system GNU C++ Compiler 32 bit support. +%description -n libitm +This package contains the GNU Transactional Memory library +which is a GCC transactional memory support runtime library. +%package -n libitm-devel +Summary: The GNU Transactional Memory support +Requires: libitm = %{version}-%{release} +Requires: gcc = %{version}-%{release} -%package -n gcc-c++-64bit -Summary: The system GNU C++ Compiler -License: GPL-3.0+ -Group: Development/Languages/C and C++ -Requires: gcc%{gcc_version}-c++-64bit -Requires: gcc-64bit = %{version} -Requires: gcc-c++ = %{version} +%description -n libitm-devel +This package contains headers and support files for the +GNU Transactional Memory library. -%description -n gcc-c++-64bit -The system GNU C++ Compiler 64 bit support. +%package -n libitm-static +Summary: The GNU Transactional Memory static library +Requires: libitm-devel = %{version}-%{release} +%description -n libitm-static +This package contains GNU Transactional Memory static libraries. +%package -n libatomic +Summary: The GNU Atomic library -%package -n libstdc++-devel -Summary: The system GNU C++ development files -License: GPL-3.0-with-GCC-exception -Group: System/Libraries -Requires: libstdc++6-devel-gcc%{gcc_version} +%description -n libatomic +This package contains the GNU Atomic library +which is a GCC support runtime library for atomic operations not supported +by hardware. -%description -n libstdc++-devel -The system GNU C++ development files. +%package -n libatomic-static +Summary: The GNU Atomic static library +Requires: libatomic = %{version}-%{release} +%description -n libatomic-static +This package contains GNU Atomic static libraries. -%package -n libstdc++-devel-32bit -Summary: The system GNU C++ 32bit development files -License: GPL-3.0-with-GCC-exception -Group: System/Libraries -Requires: libstdc++-devel -Requires: libstdc++6-devel-gcc%{gcc_version}-32bit +%package -n libasan +Summary: The Address Sanitizer runtime library -%description -n libstdc++-devel-32bit -The system GNU C++ 32bit development files. +%description -n libasan +This package contains the Address Sanitizer library +which is used for -fsanitize=address instrumented programs. +%package -n libasan-static +Summary: The Address Sanitizer static library +Requires: libasan = %{version}-%{release} -%package -n libstdc++-devel-64bit -Summary: The system GNU C++ 64bit development files -License: GPL-3.0-with-GCC-exception -Group: System/Libraries -Requires: libstdc++-devel -Requires: libstdc++6-devel-gcc%{gcc_version}-64bit +%description -n libasan-static +This package contains Address Sanitizer static runtime library. -%description -n libstdc++-devel-64bit -The system GNU C++ 64bit development files. +%package -n libtsan +Summary: The Thread Sanitizer runtime library +%description -n libtsan +This package contains the Thread Sanitizer library +which is used for -fsanitize=thread instrumented programs. +%package -n libtsan-static +Summary: The Thread Sanitizer static library +Requires: libtsan = %{version}-%{release} -%package -n gcc-fortran -Summary: The system GNU Fortran Compiler -License: GPL-3.0+ -Group: Development/Languages/Fortran -Requires: gcc = %{version} -Requires: gcc%{gcc_version}-fortran +%description -n libtsan-static +This package contains Thread Sanitizer static runtime library. -%description -n gcc-fortran -The system GNU Fortran Compiler. +%package -n libubsan +Summary: The Undefined Behavior Sanitizer runtime library +%description -n libubsan +This package contains the Undefined Behavior Sanitizer library +which is used for -fsanitize=undefined instrumented programs. -%package -n gcc-fortran-32bit -Summary: The system GNU Fortran Compiler -License: GPL-3.0+ -Group: Development/Languages/Fortran -Requires: gcc%{gcc_version}-fortran-32bit -Requires: gcc-fortran = %{version} +%package -n libubsan-static +Summary: The Undefined Behavior Sanitizer static library +Requires: libubsan = %{version}-%{release} -%description -n gcc-fortran-32bit -The system GNU Fortran Compiler 32 bit support. +%description -n libubsan-static +This package contains Undefined Behavior Sanitizer static runtime library. +%package -n liblsan +Summary: The Leak Sanitizer runtime library -%package -n gcc-fortran-64bit -Summary: The system GNU Fortran Compiler -License: GPL-3.0+ -Group: Development/Languages/Fortran -Requires: gcc%{gcc_version}-fortran-64bit -Requires: gcc-fortran = %{version} +%description -n liblsan +This package contains the Leak Sanitizer library +which is used for -fsanitize=leak instrumented programs. -%description -n gcc-fortran-64bit -The system GNU Fortran Compiler 64 bit support. +%package -n liblsan-static +Summary: The Leak Sanitizer static library +Requires: liblsan = %{version}-%{release} +%description -n liblsan-static +This package contains Leak Sanitizer static runtime library. +%package -n cpp +Summary: The C Preprocessor +Requires: filesystem >= 3 +Provides: /lib/cpp +Autoreq: true -%package -n gcc-objc -Summary: The system GNU Objective C Compiler -License: GPL-3.0+ -Group: Development/Languages/Other -Requires: gcc = %{version} -Requires: gcc%{gcc_version}-objc -%ifarch ppc64 -Obsoletes: gcc-objc-64bit +%description -n cpp +Cpp is the GNU C-Compatible Compiler Preprocessor. +Cpp is a macro processor which is used automatically +by the C compiler to transform your program before actual +compilation. It is called a macro processor because it allows +you to define macros, abbreviations for longer +constructs. + +The C preprocessor provides four separate functionalities: the +inclusion of header files (files of declarations that can be +substituted into your program); macro expansion (you can define macros, +and the C preprocessor will replace the macros with their definitions +throughout the program); conditional compilation (using special +preprocessing directives, you can include or exclude parts of the +program according to various conditions); and line control (if you use +a program to combine or rearrange source files into an intermediate +file which is then compiled, you can use line control to inform the +compiler about where each source line originated). + +You should install this package if you are a C programmer and you use +macros. + +%package gnat +Summary: Ada 83, 95, 2005 and 2012 support for GCC +Requires: gcc = %{version}-%{release} +Requires: libgnat = %{version}-%{release}, libgnat-devel = %{version}-%{release} +Autoreq: true + +%description gnat +GNAT is a GNU Ada 83, 95, 2005 and 2012 front-end to GCC. This package includes +development tools, the documents and Ada compiler. + +%package -n libgnat +Summary: GNU Ada 83, 95, 2005 and 2012 runtime shared libraries +Autoreq: true + +%description -n libgnat +GNAT is a GNU Ada 83, 95, 2005 and 2012 front-end to GCC. This package includes +shared libraries, which are required to run programs compiled with the GNAT. + +%package -n libgnat-devel +Summary: GNU Ada 83, 95, 2005 and 2012 libraries +Autoreq: true + +%description -n libgnat-devel +GNAT is a GNU Ada 83, 95, 2005 and 2012 front-end to GCC. This package includes +libraries, which are required to compile with the GNAT. + +%package -n libgnat-static +Summary: GNU Ada 83, 95, 2005 and 2012 static libraries +Requires: libgnat-devel = %{version}-%{release} +Autoreq: true + +%description -n libgnat-static +GNAT is a GNU Ada 83, 95, 2005 and 2012 front-end to GCC. This package includes +static libraries. + +%package go +Summary: Go support +Requires: gcc = %{version}-%{release} +Requires: libgo = %{version}-%{release} +Requires: libgo-devel = %{version}-%{release} +Requires(post): %{_sbindir}/update-alternatives +Requires(postun): %{_sbindir}/update-alternatives +Provides: gccgo = %{version}-%{release} +Autoreq: true + +%description go +The gcc-go package provides support for compiling Go programs +with the GNU Compiler Collection. + +%package -n libgo +Summary: Go runtime +Autoreq: true + +%description -n libgo +This package contains Go shared library which is needed to run +Go dynamically linked programs. + +%package -n libgo-devel +Summary: Go development libraries +Requires: libgo = %{version}-%{release} +Autoreq: true + +%description -n libgo-devel +This package includes libraries and support files for compiling +Go programs. + +%package -n libgo-static +Summary: Static Go libraries +Requires: libgo = %{version}-%{release} +Requires: gcc = %{version}-%{release} + +%description -n libgo-static +This package contains static Go libraries. + +%package plugin-devel +Summary: Support for compiling GCC plugins +Requires: gcc = %{version}-%{release} +Requires: gmp-devel >= 4.1.2-8, mpfr-devel >= 3.1.0, libmpc-devel >= 0.8.1 + +%description plugin-devel +This package contains header files and other support files +for compiling GCC plugins. The GCC plugin ABI is currently +not stable, so plugins must be rebuilt any time GCC is updated. + +%prep +%setup -q -n gcc-10.3.0 +/bin/pwd + +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch14 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 +%patch20 -p1 +%patch21 -p1 +%patch22 -p1 +%patch23 -p1 +%patch24 -p1 +%patch25 -p1 +%patch26 -p1 +%patch27 -p1 +%patch28 -p1 +%patch29 -p1 +%patch30 -p1 +%patch31 -p1 +%patch32 -p1 +%patch33 -p1 +%patch34 -p1 +%patch35 -p1 +%patch36 -p1 +%patch38 -p1 +%patch39 -p1 +%patch40 -p1 +%patch41 -p1 +%patch42 -p1 +%patch45 -p1 +%patch46 -p1 +%patch47 -p1 +%patch48 -p1 +%patch49 -p1 +%patch50 -p1 +%patch51 -p1 +%patch52 -p1 +%patch53 -p1 +%patch54 -p1 +%patch55 -p1 +%patch56 -p1 +%patch57 -p1 +%patch58 -p1 +%patch59 -p1 +%patch60 -p1 +%patch61 -p1 +%patch62 -p1 +%patch63 -p1 +%patch64 -p1 +%patch65 -p1 +%patch66 -p1 +%patch67 -p1 +%patch68 -p1 +%patch69 -p1 +%patch70 -p1 +%patch71 -p1 +%patch72 -p1 +%patch73 -p1 +%patch74 -p1 +%patch75 -p1 +%patch76 -p1 +%patch77 -p1 +%patch78 -p1 +%patch79 -p1 +%patch80 -p1 +%patch81 -p1 +%patch82 -p1 +%patch83 -p1 +%patch84 -p1 +%patch85 -p1 +%patch86 -p1 +%patch87 -p1 +%patch88 -p1 +%patch89 -p1 +%patch90 -p1 +%patch91 -p1 +%patch92 -p1 +%patch93 -p1 +%patch94 -p1 +%patch95 -p1 +%patch96 -p1 +%patch97 -p1 +%patch98 -p1 +%patch99 -p1 +%patch100 -p1 +%patch101 -p1 +%patch102 -p1 +%patch103 -p1 +%patch104 -p1 +%patch105 -p1 +%patch106 -p1 +%patch107 -p1 +%patch108 -p1 +%patch109 -p1 +%patch110 -p1 +%patch111 -p1 +%patch112 -p1 +%patch113 -p1 +%patch114 -p1 +%patch115 -p1 +%patch116 -p1 +%patch117 -p1 +%patch118 -p1 +%patch119 -p1 +%patch120 -p1 +%patch121 -p1 +%patch122 -p1 + +%build + +export CONFIG_SITE=NONE + +CC=gcc +CXX=g++ +OPT_FLAGS=`echo %{optflags}|sed -e 's/-flto=auto//g;s/-flto//g;s/-ffat-lto-objects//g'` +OPT_FLAGS=`echo $OPT_FLAGS|sed -e 's/-m64//g;s/-m32//g;s/-m31//g'` +OPT_FLAGS=`echo $OPT_FLAGS|sed -e 's/-mfpmath=sse/-mfpmath=sse -msse2/g'` +OPT_FLAGS=`echo $OPT_FLAGS|sed -e 's/ -pipe / /g'` +OPT_FLAGS=`echo $OPT_FLAGS|sed -e 's/-Werror=format-security/ /g'` +%ifarch x86_64 +OPT_FLAGS=`echo $OPT_FLAGS|sed -e 's/-fcf-protection/ /g'` +%endif +%ifarch sparc +OPT_FLAGS=`echo $OPT_FLAGS|sed -e 's/-mcpu=ultrasparc/-mtune=ultrasparc/g;s/-mcpu=v[78]//g'` +%endif +%ifarch %{ix86} +OPT_FLAGS=`echo $OPT_FLAGS|sed -e 's/-march=i.86//g'` +%endif +OPT_FLAGS=`echo "$OPT_FLAGS" | sed -e 's/[[:blank:]]\+/ /g'` +case "$OPT_FLAGS" in + *-fasynchronous-unwind-tables*) + sed -i -e 's/-fno-exceptions /-fno-exceptions -fno-asynchronous-unwind-tables /' \ + libgcc/Makefile.in + ;; +esac + +rm -rf obj-%{gcc_target_platform} +mkdir obj-%{gcc_target_platform} +cd obj-%{gcc_target_platform} + +enablelgo= +enablelada= +enablelobjc= +enableld= +%if %{build_objc} +enablelobjc=,objc,obj-c++ +%endif +%if %{build_ada} +enablelada=,ada +%endif +%if %{build_go} +enablelgo=,go +%endif +%if %{build_d} +enableld=,d +%endif +OPT_FLAGS="$OPT_FLAGS -O2 -Wp,-D_FORTIFY_SOURCE=2 -fstack-protector-strong -fPIE -Wl,-z,relro,-z,now" +OPT_LDFLAGS="$OPT_LDFLAGS -Wl,-z,relro,-z,now" +export extra_ldflags_libobjc="-Wl,-z,relro,-z,now" +export FCFLAGS="$OPT_FLAGS" +CC="$CC" CFLAGS="$OPT_FLAGS" \ + CXXFLAGS="`echo " $OPT_FLAGS " | sed 's/ -Wall / /g;s/ -fexceptions / /g' \ + | sed 's/ -Werror=format-security / /'`" \ + LDFLAGS="$OPT_LDFLAGS" \ + CFLAGS_FOR_TARGET="$OPT_FLAGS" \ + CXXFLAGS_FOR_TARGET="$OPT_FLAGS" \ + XCFLAGS="$OPT_FLAGS" TCFLAGS="$OPT_FLAGS" GCJFLAGS="$OPT_FLAGS" \ + ../configure --prefix=%{_prefix} --mandir=%{_mandir} --infodir=%{_infodir} \ + --enable-shared --enable-threads=posix --enable-checking=release \ + --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions \ + --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu \ + --enable-languages=c,c++,fortran${enablelobjc}${enablelada}${enablelgo}${enableld},lto --enable-plugin \ + --enable-initfini-array --disable-libgcj --with-isl --without-cloog \ + --enable-gnu-indirect-function --build=%{gcc_target_platform} \ + --with-stage1-ldflags="$OPT_LDFLAGS" \ + --with-boot-ldflags="$OPT_LDFLAGS" --disable-bootstrap \ +%ifarch x86_64 + --with-tune=generic \ + --with-arch_32=x86-64 \ + --disable-multilib +%endif +%ifarch aarch64 + --with-multilib-list=lp64 \ + --enable-bolt +%endif +%ifarch riscv64 + --with-arch=rv64g --with-abi=lp64d \ + --disable-libquadmath --disable-multilib %endif -%description -n gcc-objc -The system GNU Objective C Compiler. - - - -%package -n gcc-objc-32bit -Summary: The system GNU Objective C Compiler -License: GPL-3.0+ -Group: Development/Languages/Other -Requires: gcc%{gcc_version}-objc-32bit -Requires: gcc-objc = %{version} - -%description -n gcc-objc-32bit -The system GNU Objective C Compiler 32 bit support. +%ifarch sparc sparcv9 sparc64 +make %{?_smp_mflags} BOOT_CFLAGS="$OPT_FLAGS" bootstrap +%else +make %{?_smp_mflags} BOOT_CFLAGS="$OPT_FLAGS" BOOT_LDFLAGS="-pie -Wl,-z,relro,-z,now" +%endif +# Build libgccjit separately, so that normal compiler binaries aren't -fpic +# unnecessarily. +mkdir objlibgccjit +cd objlibgccjit +CC="$CC" CXX="$CXX" CFLAGS="$OPT_FLAGS" \ + CXXFLAGS="`echo " $OPT_FLAGS " | sed 's/ -Wall / /g;s/ -fexceptions / /g' \ + | sed 's/ -Wformat-security / -Wformat -Wformat-security /'`" \ + XCFLAGS="$OPT_FLAGS" TCFLAGS="$OPT_FLAGS" \ + ../../configure --disable-bootstrap --enable-host-shared \ + --enable-languages=jit \ +%ifarch x86_64 + --with-tune=generic \ + --with-arch_32=x86-64 \ + --disable-multilib +%endif +%ifarch aarch64 + --with-multilib-list=lp64 \ + --enable-bolt +%endif +%ifarch riscv64 + --with-arch=rv64g --with-abi=lp64d \ + --disable-libquadmath --disable-multilib +%endif +make %{?_smp_mflags} BOOT_CFLAGS="$OPT_FLAGS" all-gcc +cp -a gcc/libgccjit.so* ../gcc/ +cd ../gcc/ +ln -sf xgcc %{gcc_target_platform}-gcc-%{gcc_major} +cp -a Makefile{,.orig} +sed -i -e '/^CHECK_TARGETS/s/$/ check-jit/' Makefile +touch -r Makefile.orig Makefile +rm Makefile.orig +make jit.sphinx.html +make jit.sphinx.install-html jit_htmldir=`pwd`/../../rpm.doc/libgccjit-devel/html +cd .. + +# Make generated man pages even if Pod::Man is not new enough +perl -pi -e 's/head3/head2/' ../contrib/texi2pod.pl +for i in ../gcc/doc/*.texi; do + cp -a $i $i.orig; sed 's/ftable/table/' $i.orig > $i +done +make %{?_smp_mflags} -C gcc generated-manpages +for i in ../gcc/doc/*.texi; do mv -f $i.orig $i; done + +# Make generated doxygen pages. +%if %{build_libstdcxx_docs} +cd %{gcc_target_platform}/libstdc++-v3 +make %{?_smp_mflags} doc-html-doxygen +make %{?_smp_mflags} doc-man-doxygen +cd ../.. +%endif +# Copy various doc files here and there +cd .. +mkdir -p rpm.doc/gfortran rpm.doc/objc rpm.doc/gdc rpm.doc/libphobos +mkdir -p rpm.doc/go rpm.doc/libgo rpm.doc/libquadmath rpm.doc/libitm +mkdir -p rpm.doc/changelogs/{gcc/cp,gcc/ada,gcc/jit,libstdc++-v3,libobjc,libgomp,libcc1,libatomic,libsanitizer} -%package -n gcc-objc-64bit -Summary: The system GNU Objective C Compiler -License: GPL-3.0+ -Group: Development/Languages/Other -Requires: gcc%{gcc_version}-objc-64bit -Requires: gcc-objc = %{version} +for i in {gcc,gcc/cp,gcc/ada,gcc/jit,libstdc++-v3,libobjc,libgomp,libcc1,libatomic,libsanitizer}/ChangeLog*; do + cp -p $i rpm.doc/changelogs/$i +done -%description -n gcc-objc-64bit -The system GNU Objective C Compiler 64 bit support. +(cd gcc/fortran; for i in ChangeLog*; do + cp -p $i ../../rpm.doc/gfortran/$i +done) +(cd libgfortran; for i in ChangeLog*; do + cp -p $i ../rpm.doc/gfortran/$i.libgfortran +done) +%if %{build_objc} +(cd libobjc; for i in README*; do + cp -p $i ../rpm.doc/objc/$i.libobjc +done) +%endif +%if %{build_d} +(cd gcc/d; for i in ChangeLog*; do + cp -p $i ../../rpm.doc/gdc/$i.gdc +done) +(cd libphobos; for i in ChangeLog*; do + cp -p $i ../rpm.doc/libphobos/$i.libphobos +done +cp -a src/LICENSE*.txt libdruntime/LICENSE ../rpm.doc/libphobos/) +%endif +%if %{build_libquadmath} +(cd libquadmath; for i in ChangeLog* COPYING.LIB; do + cp -p $i ../rpm.doc/libquadmath/$i.libquadmath +done) +%endif +%if %{build_libitm} +(cd libitm; for i in ChangeLog*; do + cp -p $i ../rpm.doc/libitm/$i.libitm +done) +%endif +%if %{build_go} +(cd gcc/go; for i in README* ChangeLog*; do + cp -p $i ../../rpm.doc/go/$i +done) +(cd libgo; for i in LICENSE* PATENTS* README; do + cp -p $i ../rpm.doc/libgo/$i.libgo +done) +%endif +rm -f rpm.doc/changelogs/gcc/ChangeLog.[1-9] +find rpm.doc -name \*ChangeLog\* | xargs bzip2 -9 +%install +rm -rf %{buildroot} +mkdir -p %{buildroot} + +# RISC-V ABI wants to install everything in /lib64/lp64d or /usr/lib64/lp64d. +# Make these be symlinks to /lib64 or /usr/lib64 respectively. See: +# https://lists.fedoraproject.org/archives/list/devel@lists.fedoraproject.org/thread/DRHT5YTPK4WWVGL3GIN5BF2IKX2ODHZ3/ +%ifarch riscv64 +for d in %{buildroot}%{_libdir} %{buildroot}/%{_lib} \ + %{buildroot}%{_datadir}/gdb/auto-load/%{_prefix}/%{_lib} \ + %{buildroot}%{_prefix}/include/c++/%{gcc_major}/%{gcc_target_platform}/%{_lib}; do + mkdir -p $d + (cd $d && ln -sf . lp64d) +done +%endif -%package -n gcc-obj-c++ -Summary: The system GNU Objective C++ Compiler -License: GPL-3.0+ -Group: Development/Languages/Other -Requires: gcc%{gcc_version}-obj-c++ -Requires: gcc-objc = %{version} -%description -n gcc-obj-c++ -The system GNU Objective C++ Compiler. +cd obj-%{gcc_target_platform} +TARGET_PLATFORM=%{gcc_target_platform} +# There are some MP bugs in libstdc++ Makefiles +make %{?_smp_mflags} -C %{gcc_target_platform}/libstdc++-v3 -%package -n gcc-PIE -Summary: A default configuration to build all binaries in PIE mode -License: GPL-3.0+ -Group: Development/Languages/Other -Requires: gcc +make prefix=%{buildroot}%{_prefix} mandir=%{buildroot}%{_mandir} \ + infodir=%{buildroot}%{_infodir} install +%if %{build_ada} +chmod 644 %{buildroot}%{_infodir}/gnat* +%endif -%description -n gcc-PIE -This package contains a configuration file (spec) that changes the -compilers default setting to build all ELF binaries in the Position -Independend Executable (PIE) variant. This enables better address -space randomization (ASLR). +FULLPATH=%{buildroot}%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +FULLEPATH=%{buildroot}%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major} + +# fix some things +ln -sf gcc %{buildroot}%{_prefix}/bin/cc +rm -f %{buildroot}%{_prefix}/lib/cpp +ln -sf ../bin/cpp %{buildroot}/%{_prefix}/lib/cpp +ln -sf gfortran %{buildroot}%{_prefix}/bin/f95 +rm -f %{buildroot}%{_infodir}/dir +gzip -9 %{buildroot}%{_infodir}/*.info* +ln -sf gcc %{buildroot}%{_prefix}/bin/gnatgcc +mkdir -p %{buildroot}%{_fmoddir} + +%if %{build_go} +mv %{buildroot}%{_prefix}/bin/go{,.gcc} +mv %{buildroot}%{_prefix}/bin/gofmt{,.gcc} +ln -sf /etc/alternatives/go %{buildroot}%{_prefix}/bin/go +ln -sf /etc/alternatives/gofmt %{buildroot}%{_prefix}/bin/gofmt +%endif +cxxconfig="`find %{gcc_target_platform}/libstdc++-v3/include -name c++config.h`" +for i in `find %{gcc_target_platform}/[36]*/libstdc++-v3/include -name c++config.h 2>/dev/null`; do + if ! diff -up $cxxconfig $i; then + cat > %{buildroot}%{_prefix}/include/c++/%{gcc_major}/%{gcc_target_platform}/bits/c++config.h <<EOF +#ifndef _CPP_CPPCONFIG_WRAPPER +#define _CPP_CPPCONFIG_WRAPPER 1 +#include <bits/wordsize.h> +#if __WORDSIZE == 32 +%ifarch %{multilib_64_archs} +`cat $(find %{gcc_target_platform}/32/libstdc++-v3/include -name c++config.h)` +%else +`cat $(find %{gcc_target_platform}/libstdc++-v3/include -name c++config.h)` +%endif +#else +%ifarch %{multilib_64_archs} +`cat $(find %{gcc_target_platform}/libstdc++-v3/include -name c++config.h)` +%else +`cat $(find %{gcc_target_platform}/64/libstdc++-v3/include -name c++config.h)` +%endif +#endif +#endif +EOF + break + fi +done -%package -n gcc-ada -Summary: The system GNU Ada Compiler -License: GPL-3.0+ -Group: Development/Languages/C and C++ -Requires: gcc = %{version} -Requires: gcc%{gcc_version}-ada +for f in `find %{buildroot}%{_prefix}/include/c++/%{gcc_major}/%{gcc_target_platform}/ -name c++config.h`; do + for i in 1 2 4 8; do + sed -i -e 's/#define _GLIBCXX_ATOMIC_BUILTINS_'$i' 1/#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_'$i'\ +&\ +#endif/' $f + done +done -%description -n gcc-ada -The system GNU Ada Compiler. +# Nuke bits/*.h.gch dirs +# 1) there is no bits/*.h header installed, so when gch file can't be +# used, compilation fails +# 2) sometimes it is hard to match the exact options used for building +# libstdc++-v3 or they aren't desirable +# 3) there are multilib issues, conflicts etc. with this +# 4) it is huge +# People can always precompile on their own whatever they want, but +# shipping this for everybody is unnecessary. +rm -rf %{buildroot}%{_prefix}/include/c++/%{gcc_major}/%{gcc_target_platform}/bits/*.h.gch + +%if %{build_libstdcxx_docs} +libstdcxx_doc_builddir=%{gcc_target_platform}/libstdc++-v3/doc/doxygen +mkdir -p ../rpm.doc/libstdc++-v3 +cp -r -p ../libstdc++-v3/doc/html ../rpm.doc/libstdc++-v3/html +cp -r -p $libstdcxx_doc_builddir/html ../rpm.doc/libstdc++-v3/html/api +mkdir -p %{buildroot}%{_mandir}/man3 +cp -r -p $libstdcxx_doc_builddir/man/man3/* %{buildroot}%{_mandir}/man3/ +find ../rpm.doc/libstdc++-v3 -name \*~ | xargs rm +%endif -%package -n gcc-ada-32bit -Summary: The system GNU Ada Compiler -License: GPL-3.0+ -Group: Development/Languages/C and C++ -Requires: gcc%{gcc_version}-ada-32bit -Requires: gcc-ada = %{version} +%ifarch sparcv9 sparc64 +ln -f %{buildroot}%{_prefix}/bin/%{gcc_target_platform}-gcc \ + %{buildroot}%{_prefix}/bin/sparc-%{_vendor}-%{_target_os}-gcc +%endif +%ifarch ppc ppc64 ppc64p7 +ln -f %{buildroot}%{_prefix}/bin/%{gcc_target_platform}-gcc \ + %{buildroot}%{_prefix}/bin/ppc-%{_vendor}-%{_target_os}-gcc +%endif -%description -n gcc-ada-32bit -The system GNU Ada Compiler 32 bit support. +FULLLSUBDIR= +%ifarch sparcv9 ppc +FULLLSUBDIR=lib32 +%endif +%ifarch sparc64 ppc64 ppc64p7 +FULLLSUBDIR=lib64 +%endif +if [ -n "$FULLLSUBDIR" ]; then + FULLLPATH=$FULLPATH/$FULLLSUBDIR + mkdir -p $FULLLPATH +else + FULLLPATH=$FULLPATH +fi -%package -n gcc-ada-64bit -Summary: The system GNU Ada Compiler -License: GPL-3.0+ -Group: Development/Languages/C and C++ -Requires: gcc%{gcc_version}-ada-64bit -Requires: gcc-ada = %{version} +find %{buildroot} -name \*.la | xargs rm -f -%description -n gcc-ada-64bit -The system GNU Ada Compiler 64 bit support. +mv %{buildroot}%{_prefix}/%{_lib}/libgfortran.spec $FULLPATH/ +%if %{build_d} +mv %{buildroot}%{_prefix}/%{_lib}/libgphobos.spec $FULLPATH/ +%endif +%if %{build_libitm} +mv %{buildroot}%{_prefix}/%{_lib}/libitm.spec $FULLPATH/ +%endif +%if %{build_libasan} +mv %{buildroot}%{_prefix}/%{_lib}/libsanitizer.spec $FULLPATH/ +%endif +mkdir -p %{buildroot}/%{_lib} +mv -f %{buildroot}%{_prefix}/%{_lib}/libgcc_s.so.1 %{buildroot}/%{_lib}/libgcc_s-%{gcc_major}.so.1 +chmod 755 %{buildroot}/%{_lib}/libgcc_s-%{gcc_major}.so.1 +ln -sf libgcc_s-%{gcc_major}.so.1 %{buildroot}/%{_lib}/libgcc_s.so.1 +%ifarch %{ix86} x86_64 ppc ppc64 ppc64p7 ppc64le %{arm} aarch64 riscv64 +rm -f $FULLPATH/libgcc_s.so +echo '/* GNU ld script + Use the shared library, but some functions are only in + the static library, so try that secondarily. */ +OUTPUT_FORMAT('`gcc -Wl,--print-output-format -nostdlib -r -o /dev/null`') +GROUP ( /%{_lib}/libgcc_s.so.1 libgcc.a )' > $FULLPATH/libgcc_s.so +%else +ln -sf /%{_lib}/libgcc_s.so.1 $FULLPATH/libgcc_s.so +%endif +%ifarch sparcv9 ppc +%ifarch ppc +rm -f $FULLPATH/64/libgcc_s.so +echo '/* GNU ld script + Use the shared library, but some functions are only in + the static library, so try that secondarily. */ +OUTPUT_FORMAT('`gcc -m64 -Wl,--print-output-format -nostdlib -r -o /dev/null`') +GROUP ( /lib64/libgcc_s.so.1 libgcc.a )' > $FULLPATH/64/libgcc_s.so +%else +ln -sf /lib64/libgcc_s.so.1 $FULLPATH/64/libgcc_s.so +%endif +%endif +%ifarch %{multilib_64_archs} +%ifarch x86_64 ppc64 ppc64p7 +rm -f $FULLPATH/64/libgcc_s.so +echo '/* GNU ld script + Use the shared library, but some functions are only in + the static library, so try that secondarily. */ +OUTPUT_FORMAT('`gcc -m32 -Wl,--print-output-format -nostdlib -r -o /dev/null`') +GROUP ( /lib/libgcc_s.so.1 libgcc.a )' > $FULLPATH/32/libgcc_s.so +%else +ln -sf /lib/libgcc_s.so.1 $FULLPATH/32/libgcc_s.so +%endif +%endif -%package -n gcc-go -Summary: The system GNU Go Compiler -License: GPL-3.0+ -Group: Development/Languages/C and C++ -Requires: gcc = %{version} -Requires: gcc%{gcc_version}-go -Requires(post): update-alternatives -Requires(postun): update-alternatives +mv -f %{buildroot}%{_prefix}/%{_lib}/libgomp.spec $FULLPATH/ -%description -n gcc-go -The system GNU Go Compiler. +%if %{build_ada} +mv -f $FULLPATH/adalib/libgnarl-*.so %{buildroot}%{_prefix}/%{_lib}/ +mv -f $FULLPATH/adalib/libgnat-*.so %{buildroot}%{_prefix}/%{_lib}/ +rm -f $FULLPATH/adalib/libgnarl.so* $FULLPATH/adalib/libgnat.so* +%endif -%package -n gcc-go-32bit -Summary: The system GNU Go Compiler -License: GPL-3.0+ -Group: Development/Languages/C and C++ -Requires: gcc%{gcc_version}-go-32bit -Requires: gcc-go = %{version} +mkdir -p %{buildroot}%{_prefix}/libexec/getconf +if gcc/xgcc -B gcc/ -E -P -dD -xc /dev/null | grep '__LONG_MAX__.*\(2147483647\|0x7fffffff\($\|[LU]\)\)'; then + ln -sf POSIX_V6_ILP32_OFF32 %{buildroot}%{_prefix}/libexec/getconf/default +else + ln -sf POSIX_V6_LP64_OFF64 %{buildroot}%{_prefix}/libexec/getconf/default +fi -%description -n gcc-go-32bit -The system GNU Go Compiler 32bit support. +mkdir -p %{buildroot}%{_datadir}/gdb/auto-load/%{_prefix}/%{_lib} +mv -f %{buildroot}%{_prefix}/%{_lib}/libstdc++*gdb.py* \ + %{buildroot}%{_datadir}/gdb/auto-load/%{_prefix}/%{_lib}/ +pushd ../libstdc++-v3/python +for i in `find . -name \*.py`; do + touch -r $i %{buildroot}%{_prefix}/share/gcc-%{gcc_major}/python/$i +done +touch -r hook.in %{buildroot}%{_datadir}/gdb/auto-load/%{_prefix}/%{_lib}/libstdc++*gdb.py +popd + +rm -f $FULLEPATH/libgccjit.so +cp -a objlibgccjit/gcc/libgccjit.so* %{buildroot}%{_prefix}/%{_lib}/ +cp -a ../gcc/jit/libgccjit*.h %{buildroot}%{_prefix}/include/ +/usr/bin/install -c -m 644 objlibgccjit/gcc/doc/libgccjit.info %{buildroot}/%{_infodir}/ +gzip -9 %{buildroot}/%{_infodir}/libgccjit.info + +pushd $FULLPATH +if [ "%{_lib}" = "lib" ]; then +%if %{build_objc} +ln -sf ../../../libobjc.so.4 libobjc.so +%endif +ln -sf ../../../libstdc++.so.6.*[0-9] libstdc++.so +ln -sf ../../../libgfortran.so.5.* libgfortran.so +ln -sf ../../../libgomp.so.1.* libgomp.so +%if %{build_go} +ln -sf ../../../libgo.so.16.* libgo.so +%endif +%if %{build_libquadmath} +ln -sf ../../../libquadmath.so.0.* libquadmath.so +%endif +%if %{build_d} +ln -sf ../../../libgdruntime.so.1.* libgdruntime.so +ln -sf ../../../libgphobos.so.1.* libgphobos.so +%endif +%if %{build_libitm} +ln -sf ../../../libitm.so.1.* libitm.so +%endif +%if %{build_libatomic} +ln -sf ../../../libatomic.so.1.* libatomic.so +%endif +%if %{build_libasan} +ln -sf ../../../libasan.so.6.* libasan.so +mv ../../../libasan_preinit.o libasan_preinit.o +%endif +%if %{build_libubsan} +ln -sf ../../../libubsan.so.1.* libubsan.so +%endif +else +%if %{build_objc} +ln -sf ../../../../%{_lib}/libobjc.so.4 libobjc.so +%endif +ln -sf ../../../../%{_lib}/libstdc++.so.6.*[0-9] libstdc++.so +ln -sf ../../../../%{_lib}/libgfortran.so.5.* libgfortran.so +ln -sf ../../../../%{_lib}/libgomp.so.1.* libgomp.so +%if %{build_go} +ln -sf ../../../../%{_lib}/libgo.so.16.* libgo.so +%endif +%if %{build_libquadmath} +ln -sf ../../../../%{_lib}/libquadmath.so.0.* libquadmath.so +%endif +%if %{build_d} +ln -sf ../../../../%{_lib}/libgdruntime.so.1.* libgdruntime.so +ln -sf ../../../../%{_lib}/libgphobos.so.1.* libgphobos.so +%endif +%if %{build_libitm} +ln -sf ../../../../%{_lib}/libitm.so.1.* libitm.so +%endif +%if %{build_libatomic} +ln -sf ../../../../%{_lib}/libatomic.so.1.* libatomic.so +%endif +%if %{build_libasan} +ln -sf ../../../../%{_lib}/libasan.so.6.* libasan.so +mv ../../../../%{_lib}/libasan_preinit.o libasan_preinit.o +%endif +%if %{build_libubsan} +ln -sf ../../../../%{_lib}/libubsan.so.1.* libubsan.so +%endif +%if %{build_libtsan} +rm -f libtsan.so +echo 'INPUT ( %{_prefix}/%{_lib}/'`echo ../../../../%{_lib}/libtsan.so.0.* | sed 's,^.*libt,libt,'`' )' > libtsan.so +mv ../../../../%{_lib}/libtsan_preinit.o libtsan_preinit.o +%endif +%if %{build_liblsan} +rm -f liblsan.so +echo 'INPUT ( %{_prefix}/%{_lib}/'`echo ../../../../%{_lib}/liblsan.so.0.* | sed 's,^.*libl,libl,'`' )' > liblsan.so +mv ../../../../%{_lib}/liblsan_preinit.o liblsan_preinit.o +%endif +fi +mv -f %{buildroot}%{_prefix}/%{_lib}/libstdc++.*a $FULLLPATH/ +mv -f %{buildroot}%{_prefix}/%{_lib}/libstdc++fs.*a $FULLLPATH/ +mv -f %{buildroot}%{_prefix}/%{_lib}/libsupc++.*a $FULLLPATH/ +mv -f %{buildroot}%{_prefix}/%{_lib}/libgfortran.*a $FULLLPATH/ +%if %{build_objc} +mv -f %{buildroot}%{_prefix}/%{_lib}/libobjc.*a . +%endif +mv -f %{buildroot}%{_prefix}/%{_lib}/libgomp.*a . +%if %{build_libquadmath} +mv -f %{buildroot}%{_prefix}/%{_lib}/libquadmath.*a $FULLLPATH/ +%endif +%if %{build_d} +mv -f %{buildroot}%{_prefix}/%{_lib}/libgdruntime.*a $FULLLPATH/ +mv -f %{buildroot}%{_prefix}/%{_lib}/libgphobos.*a $FULLLPATH/ +%endif +%if %{build_libitm} +mv -f %{buildroot}%{_prefix}/%{_lib}/libitm.*a $FULLLPATH/ +%endif +%if %{build_libatomic} +mv -f %{buildroot}%{_prefix}/%{_lib}/libatomic.*a $FULLLPATH/ +%endif +%if %{build_libasan} +mv -f %{buildroot}%{_prefix}/%{_lib}/libasan.*a $FULLLPATH/ +%endif +%if %{build_libubsan} +mv -f %{buildroot}%{_prefix}/%{_lib}/libubsan.*a $FULLLPATH/ +%endif +%if %{build_libtsan} +mv -f %{buildroot}%{_prefix}/%{_lib}/libtsan.*a $FULLPATH/ +%endif +%if %{build_liblsan} +mv -f %{buildroot}%{_prefix}/%{_lib}/liblsan.*a $FULLPATH/ +%endif +%if %{build_go} +mv -f %{buildroot}%{_prefix}/%{_lib}/libgo.*a $FULLLPATH/ +mv -f %{buildroot}%{_prefix}/%{_lib}/libgobegin.*a $FULLLPATH/ +mv -f %{buildroot}%{_prefix}/%{_lib}/libgolibbegin.*a $FULLLPATH/ +%endif -%package -n gcc-go-64bit -Summary: The system GNU Go Compiler -License: GPL-3.0+ -Group: Development/Languages/C and C++ -Requires: gcc%{gcc_version}-go-64bit -Requires: gcc-go = %{version} +%if %{build_ada} +%ifarch sparcv9 ppc +rm -rf $FULLPATH/64/ada{include,lib} +%endif +%ifarch %{multilib_64_archs} +rm -rf $FULLPATH/32/ada{include,lib} +%endif +if [ "$FULLPATH" != "$FULLLPATH" ]; then +mv -f $FULLPATH/ada{include,lib} $FULLLPATH/ +pushd $FULLLPATH/adalib +if [ "%{_lib}" = "lib" ]; then +ln -sf ../../../../../libgnarl-*.so libgnarl.so +ln -sf ../../../../../libgnarl-*.so libgnarl-9.so +ln -sf ../../../../../libgnat-*.so libgnat.so +ln -sf ../../../../../libgnat-*.so libgnat-9.so +else +ln -sf ../../../../../../%{_lib}/libgnarl-*.so libgnarl.so +ln -sf ../../../../../../%{_lib}/libgnarl-*.so libgnarl-9.so +ln -sf ../../../../../../%{_lib}/libgnat-*.so libgnat.so +ln -sf ../../../../../../%{_lib}/libgnat-*.so libgnat-9.so +fi +popd +else +pushd $FULLPATH/adalib +if [ "%{_lib}" = "lib" ]; then +ln -sf ../../../../libgnarl-*.so libgnarl.so +ln -sf ../../../../libgnarl-*.so libgnarl-9.so +ln -sf ../../../../libgnat-*.so libgnat.so +ln -sf ../../../../libgnat-*.so libgnat-9.so +else +ln -sf ../../../../../%{_lib}/libgnarl-*.so libgnarl.so +ln -sf ../../../../../%{_lib}/libgnarl-*.so libgnarl-9.so +ln -sf ../../../../../%{_lib}/libgnat-*.so libgnat.so +ln -sf ../../../../../%{_lib}/libgnat-*.so libgnat-9.so +fi +popd +fi +%endif -%description -n gcc-go-64bit -The system GNU Go Compiler 64bit support. +%ifarch sparcv9 ppc +%if %{build_objc} +ln -sf ../../../../../lib64/libobjc.so.4 64/libobjc.so +%endif +ln -sf ../`echo ../../../../lib/libstdc++.so.6.*[0-9] | sed s~/lib/~/lib64/~` 64/libstdc++.so +ln -sf ../`echo ../../../../lib/libgfortran.so.5.* | sed s~/lib/~/lib64/~` 64/libgfortran.so +ln -sf ../`echo ../../../../lib/libgomp.so.1.* | sed s~/lib/~/lib64/~` 64/libgomp.so +%if %{build_go} +rm -f libgo.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib/libgo.so.16.* | sed 's,^.*libg,libg,'`' )' > libgo.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib/libgo.so.16.* | sed 's,^.*libg,libg,'`' )' > 64/libgo.so +%endif +%if %{build_libquadmath} +rm -f libquadmath.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib/libquadmath.so.0.* | sed 's,^.*libq,libq,'`' )' > libquadmath.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib/libquadmath.so.0.* | sed 's,^.*libq,libq,'`' )' > 64/libquadmath.so +%endif +%if %{build_d} +rm -f libgdruntime.so libgphobos.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib/libgdruntime.so.1.* | sed 's,^.*libg,libg,'`' )' > libgdruntime.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib/libgdruntime.so.1.* | sed 's,^.*libg,libg,'`' )' > 64/libgdruntime.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib/libgphobos.so.1.* | sed 's,^.*libg,libg,'`' )' > libgphobos.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib/libgphobos.so.1.* | sed 's,^.*libg,libg,'`' )' > 64/libgphobos.so +%endif +%if %{build_libitm} +rm -f libitm.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib/libitm.so.1.* | sed 's,^.*libi,libi,'`' )' > libitm.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib/libitm.so.1.* | sed 's,^.*libi,libi,'`' )' > 64/libitm.so +%endif +%if %{build_libatomic} +rm -f libatomic.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib/libatomic.so.1.* | sed 's,^.*liba,liba,'`' )' > libatomic.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib/libatomic.so.1.* | sed 's,^.*liba,liba,'`' )' > 64/libatomic.so +%endif +%if %{build_libasan} +rm -f libasan.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib/libasan.so.6.* | sed 's,^.*liba,liba,'`' )' > libasan.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib/libasan.so.6.* | sed 's,^.*liba,liba,'`' )' > 64/libasan.so +mv ../../../../lib64/libasan_preinit.o 64/libasan_preinit.o +%endif +%if %{build_libubsan} +rm -f libubsan.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib/libubsan.so.1.* | sed 's,^.*libu,libu,'`' )' > libubsan.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib/libubsan.so.1.* | sed 's,^.*libu,libu,'`' )' > 64/libubsan.so +%endif +ln -sf lib32/libgfortran.a libgfortran.a +ln -sf ../lib64/libgfortran.a 64/libgfortran.a +%if %{build_objc} +mv -f %{buildroot}%{_prefix}/lib64/libobjc.*a 64/ +%endif +mv -f %{buildroot}%{_prefix}/lib64/libgomp.*a 64/ +ln -sf lib32/libstdc++.a libstdc++.a +ln -sf ../lib64/libstdc++.a 64/libstdc++.a +ln -sf lib32/libstdc++fs.a libstdc++fs.a +ln -sf ../lib64/libstdc++fs.a 64/libstdc++fs.a +ln -sf lib32/libsupc++.a libsupc++.a +ln -sf ../lib64/libsupc++.a 64/libsupc++.a +%if %{build_libquadmath} +ln -sf lib32/libquadmath.a libquadmath.a +ln -sf ../lib64/libquadmath.a 64/libquadmath.a +%endif +%if %{build_d} +ln -sf lib32/libgdruntime.a libgdruntime.a +ln -sf ../lib64/libgdruntime.a 64/libgdruntime.a +ln -sf lib32/libgphobos.a libgphobos.a +ln -sf ../lib64/libgphobos.a 64/libgphobos.a +%endif +%if %{build_libitm} +ln -sf lib32/libitm.a libitm.a +ln -sf ../lib64/libitm.a 64/libitm.a +%endif +%if %{build_libatomic} +ln -sf lib32/libatomic.a libatomic.a +ln -sf ../lib64/libatomic.a 64/libatomic.a +%endif +%if %{build_libasan} +ln -sf lib32/libasan.a libasan.a +ln -sf ../lib64/libasan.a 64/libasan.a +%endif +%if %{build_libubsan} +ln -sf lib32/libubsan.a libubsan.a +ln -sf ../lib64/libubsan.a 64/libubsan.a +%endif +%if %{build_go} +ln -sf lib32/libgo.a libgo.a +ln -sf ../lib64/libgo.a 64/libgo.a +ln -sf lib32/libgobegin.a libgobegin.a +ln -sf ../lib64/libgobegin.a 64/libgobegin.a +ln -sf lib32/libgolibbegin.a libgolibbegin.a +ln -sf ../lib64/libgolibbegin.a 64/libgolibbegin.a +%endif +%if %{build_ada} +ln -sf lib32/adainclude adainclude +ln -sf ../lib64/adainclude 64/adainclude +ln -sf lib32/adalib adalib +ln -sf ../lib64/adalib 64/adalib +%endif +%endif +%ifarch %{multilib_64_archs} +mkdir -p 32 +%if %{build_objc} +ln -sf ../../../../libobjc.so.4 32/libobjc.so +%endif +ln -sf ../`echo ../../../../lib64/libstdc++.so.6.*[0-9] | sed s~/../lib64/~/~` 32/libstdc++.so +ln -sf ../`echo ../../../../lib64/libgfortran.so.5.* | sed s~/../lib64/~/~` 32/libgfortran.so +ln -sf ../`echo ../../../../lib64/libgomp.so.1.* | sed s~/../lib64/~/~` 32/libgomp.so +%if %{build_go} +rm -f libgo.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib64/libgo.so.16.* | sed 's,^.*libg,libg,'`' )' > libgo.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib64/libgo.so.16.* | sed 's,^.*libg,libg,'`' )' > 32/libgo.so +%endif +%if %{build_libquadmath} +rm -f libquadmath.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib64/libquadmath.so.0.* | sed 's,^.*libq,libq,'`' )' > libquadmath.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib64/libquadmath.so.0.* | sed 's,^.*libq,libq,'`' )' > 32/libquadmath.so +%endif +%if %{build_d} +rm -f libgdruntime.so libgphobos.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib64/libgdruntime.so.1.* | sed 's,^.*libg,libg,'`' )' > libgdruntime.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib64/libgdruntime.so.1.* | sed 's,^.*libg,libg,'`' )' > 32/libgdruntime.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib64/libgphobos.so.1.* | sed 's,^.*libg,libg,'`' )' > libgphobos.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib64/libgphobos.so.1.* | sed 's,^.*libg,libg,'`' )' > 32/libgphobos.so +%endif +%if %{build_libitm} +rm -f libitm.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib64/libitm.so.1.* | sed 's,^.*libi,libi,'`' )' > libitm.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib64/libitm.so.1.* | sed 's,^.*libi,libi,'`' )' > 32/libitm.so +%endif +%if %{build_libatomic} +rm -f libatomic.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib64/libatomic.so.1.* | sed 's,^.*liba,liba,'`' )' > libatomic.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib64/libatomic.so.1.* | sed 's,^.*liba,liba,'`' )' > 32/libatomic.so +%endif +%if %{build_libasan} +rm -f libasan.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib64/libasan.so.6.* | sed 's,^.*liba,liba,'`' )' > libasan.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib64/libasan.so.6.* | sed 's,^.*liba,liba,'`' )' > 32/libasan.so +mv ../../../../lib/libasan_preinit.o 32/libasan_preinit.o +%endif +%if %{build_libubsan} +rm -f libubsan.so +echo 'INPUT ( %{_prefix}/lib64/'`echo ../../../../lib64/libubsan.so.1.* | sed 's,^.*libu,libu,'`' )' > libubsan.so +echo 'INPUT ( %{_prefix}/lib/'`echo ../../../../lib64/libubsan.so.1.* | sed 's,^.*libu,libu,'`' )' > 32/libubsan.so +%endif +%if %{build_objc} +mv -f %{buildroot}%{_prefix}/lib/libobjc.*a 32/ +%endif +mv -f %{buildroot}%{_prefix}/lib/libgomp.*a 32/ +%endif +%ifarch sparc64 ppc64 ppc64p7 +ln -sf ../lib32/libgfortran.a 32/libgfortran.a +ln -sf lib64/libgfortran.a libgfortran.a +ln -sf ../lib32/libstdc++.a 32/libstdc++.a +ln -sf lib64/libstdc++.a libstdc++.a +ln -sf ../lib32/libstdc++fs.a 32/libstdc++fs.a +ln -sf lib64/libstdc++fs.a libstdc++fs.a +ln -sf ../lib32/libsupc++.a 32/libsupc++.a +ln -sf lib64/libsupc++.a libsupc++.a +%if %{build_libquadmath} +ln -sf ../lib32/libquadmath.a 32/libquadmath.a +ln -sf lib64/libquadmath.a libquadmath.a +%endif +%if %{build_d} +ln -sf ../lib32/libgdruntime.a 32/libgdruntime.a +ln -sf lib64/libgdruntime.a libgdruntime.a +ln -sf ../lib32/libgphobos.a 32/libgphobos.a +ln -sf lib64/libgphobos.a libgphobos.a +%endif +%if %{build_libitm} +ln -sf ../lib32/libitm.a 32/libitm.a +ln -sf lib64/libitm.a libitm.a +%endif +%if %{build_libatomic} +ln -sf ../lib32/libatomic.a 32/libatomic.a +ln -sf lib64/libatomic.a libatomic.a +%endif +%if %{build_libasan} +ln -sf ../lib32/libasan.a 32/libasan.a +ln -sf lib64/libasan.a libasan.a +%endif +%if %{build_libubsan} +ln -sf ../lib32/libubsan.a 32/libubsan.a +ln -sf lib64/libubsan.a libubsan.a +%endif +%if %{build_go} +ln -sf ../lib32/libgo.a 32/libgo.a +ln -sf lib64/libgo.a libgo.a +ln -sf ../lib32/libgobegin.a 32/libgobegin.a +ln -sf lib64/libgobegin.a libgobegin.a +ln -sf ../lib32/libgolibbegin.a 32/libgolibbegin.a +ln -sf lib64/libgolibbegin.a libgolibbegin.a +%endif +%if %{build_ada} +ln -sf ../lib32/adainclude 32/adainclude +ln -sf lib64/adainclude adainclude +ln -sf ../lib32/adalib 32/adalib +ln -sf lib64/adalib adalib +%endif +%else +%ifarch %{multilib_64_archs} +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{gcc_major}/libgfortran.a 32/libgfortran.a +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{gcc_major}/libstdc++.a 32/libstdc++.a +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{gcc_major}/libstdc++fs.a 32/libstdc++fs.a +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{gcc_major}/libsupc++.a 32/libsupc++.a +%if %{build_libquadmath} +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{gcc_major}/libquadmath.a 32/libquadmath.a +%endif +%if %{build_d} +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{gcc_major}/libgdruntime.a 32/libgdruntime.a +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{gcc_major}/libgphobos.a 32/libgphobos.a +%endif +%if %{build_libitm} +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{gcc_major}/libitm.a 32/libitm.a +%endif +%if %{build_libatomic} +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{gcc_major}/libatomic.a 32/libatomic.a +%endif +%if %{build_libasan} +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{gcc_major}/libasan.a 32/libasan.a +%endif +%if %{build_libubsan} +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{gcc_major}/libubsan.a 32/libubsan.a +%endif +%if %{build_go} +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{gcc_major}/libgo.a 32/libgo.a +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{gcc_major}/libgobegin.a 32/libgobegin.a +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{gcc_major}/libgolibbegin.a 32/libgolibbegin.a +%endif +%if %{build_ada} +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{gcc_major}/adainclude 32/adainclude +ln -sf ../../../%{multilib_32_arch}-%{_vendor}-%{_target_os}/%{gcc_major}/adalib 32/adalib +%endif +%endif +%endif +# If we are building a debug package then copy all of the static archives +# into the debug directory to keep them as unstripped copies. +%if 0%{?_enable_debug_packages} +for d in . $FULLLSUBDIR; do + mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/debug%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/$d + for f in `find $d -maxdepth 1 -a \ + \( -name libasan.a -o -name libatomic.a \ + -o -name libcaf_single.a \ + -o -name libgcc.a -o -name libgcc_eh.a \ + -o -name libgcov.a -o -name libgfortran.a \ + -o -name libgo.a -o -name libgobegin.a \ + -o -name libgolibbegin.a -o -name libgomp.a \ + -o -name libitm.a -o -name liblsan.a \ + -o -name libobjc.a -o -name libgdruntime.a -o -name libgphobos.a \ + -o -name libquadmath.a -o -name libstdc++.a \ + -o -name libstdc++fs.a -o -name libsupc++.a \ + -o -name libtsan.a -o -name libubsan.a \) -a -type f`; do + cp -a $f $RPM_BUILD_ROOT%{_prefix}/lib/debug%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/$d/ + done +done +%endif -%prep +# Strip debug info from Fortran/ObjC/Java static libraries +strip -g `find . \( -name libgfortran.a -o -name libobjc.a -o -name libgomp.a \ + -o -name libgcc.a -o -name libgcov.a -o -name libquadmath.a \ + -o -name libgdruntime.a -o -name libgphobos.a \ + -o -name libitm.a -o -name libgo.a -o -name libcaf\*.a \ + -o -name libatomic.a -o -name libasan.a -o -name libtsan.a \ + -o -name libubsan.a -o -name liblsan.a -o -name libcc1.a \) \ + -a -type f` +popd +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libgfortran.so.5.* +chrpath -d %{buildroot}%{_prefix}/%{_lib}/libgfortran.so.5.* +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libgomp.so.1.* +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libcc1.so.0.* +%if %{build_libquadmath} +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libquadmath.so.0.* +%endif +%if %{build_d} +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libgdruntime.so.1.* +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libgphobos.so.1.* +%endif +%if %{build_libitm} +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libitm.so.1.* +%endif +%if %{build_libatomic} +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libatomic.so.1.* +%endif +%if %{build_libasan} +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libasan.so.6.* +chrpath -d %{buildroot}%{_prefix}/%{_lib}/libasan.so.6.* +%endif +%if %{build_libubsan} +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libubsan.so.1.* +chrpath -d %{buildroot}%{_prefix}/%{_lib}/libubsan.so.1.* +%endif +%if %{build_libtsan} +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libtsan.so.0.* +chrpath -d %{buildroot}%{_prefix}/%{_lib}/libtsan.so.0.* +%endif +%if %{build_liblsan} +chmod 755 %{buildroot}%{_prefix}/%{_lib}/liblsan.so.0.* +chrpath -d %{buildroot}%{_prefix}/%{_lib}/liblsan.so.0.* +%endif +%if %{build_go} +# Avoid stripping these libraries and binaries. +chmod 644 %{buildroot}%{_prefix}/%{_lib}/libgo.so.16.* +chmod 644 %{buildroot}%{_prefix}/bin/go.gcc +chmod 644 %{buildroot}%{_prefix}/bin/gofmt.gcc +chmod 644 %{buildroot}%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/cgo +chmod 644 %{buildroot}%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/buildid +chmod 644 %{buildroot}%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/test2json +chmod 644 %{buildroot}%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/vet +%endif +%if %{build_objc} +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libobjc.so.4.* +%endif -%install -mkdir -p $RPM_BUILD_ROOT/lib -mkdir -p $RPM_BUILD_ROOT%{_prefix}/bin -mkdir -p $RPM_BUILD_ROOT%{_mandir}/man1 -mkdir -p $RPM_BUILD_ROOT%{_infodir} -mkdir -p $RPM_BUILD_ROOT%{_prefix}/share/doc/packages/gcc-objc/ -mkdir -p $RPM_BUILD_ROOT%{_prefix}/share/doc/packages/gcc-obj-c++/ -# Link all the binaries -for program in \ - gcc gcov gcov-dump gcov-tool \ - g++ \ - cpp \ - gfortran \ - gccgo \ %if %{build_ada} - gnat gnatbind gnatbl gnatchop gnatclean gnatfind gnatkr \ - gnatlink gnatls gnatmake gnatname gnatprep gnatxref gprmake \ +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libgnarl*so* +chmod 755 %{buildroot}%{_prefix}/%{_lib}/libgnat*so* %endif - gcc-ar gcc-nm gcc-ranlib \ - ; do - ln -sf $program-%{gcc_suffix} $RPM_BUILD_ROOT%{_prefix}/bin/$program + +mv $FULLPATH/include-fixed/syslimits.h $FULLPATH/include/syslimits.h +mv $FULLPATH/include-fixed/limits.h $FULLPATH/include/limits.h +for h in `find $FULLPATH/include -name \*.h`; do + if grep -q 'It has been auto-edited by fixincludes from' $h; then + rh=`grep -A2 'It has been auto-edited by fixincludes from' $h | tail -1 | sed 's|^.*"\(.*\)".*$|\1|'` + diff -up $rh $h || : + rm -f $h + fi done -# For go and gofmt use alternatives since they are shared with golang -mkdir -p %{buildroot}%{_sysconfdir}/alternatives -ln -sf %{_sysconfdir}/alternatives/go %{buildroot}%{_bindir}/go -ln -sf %{_sysconfdir}/alternatives/gofmt %{buildroot}%{_bindir}/gofmt -# Link section 1 manpages -for man1 in \ - gcc gcov gcov-dump gcov-tool \ - g++ \ - cpp \ - gfortran \ - gccgo \ - ; do - ln -sf $man1-%{gcc_suffix}.1.gz $RPM_BUILD_ROOT%{_mandir}/man1/$man1.1.gz + +cat > %{buildroot}%{_prefix}/bin/c89 <<"EOF" +#!/bin/sh +fl="-std=c89" +for opt; do + case "$opt" in + -ansi|-std=c89|-std=iso9899:1990) fl="";; + -std=*) echo "`basename $0` called with non ANSI/ISO C option $opt" >&2 + exit 1;; + esac done -# Link info pages -for info in cpp gcc gfortran ; do - ln -sf $info-%{gcc_suffix}.info.gz $RPM_BUILD_ROOT%{_infodir}/$info.info.gz +exec gcc $fl ${1+"$@"} +EOF +cat > %{buildroot}%{_prefix}/bin/c99 <<"EOF" +#!/bin/sh +fl="-std=c99" +for opt; do + case "$opt" in + -std=c99|-std=iso9899:1999) fl="";; + -std=*) echo "`basename $0` called with non ISO C99 option $opt" >&2 + exit 1;; + esac done -# Provide the traditional /lib/cpp that only handles C -cp $RPM_SOURCE_DIR/cpp $RPM_BUILD_ROOT/lib/ -chmod 755 $RPM_BUILD_ROOT/lib/cpp -# Provide extra symlinks -ln -sf g++-%{gcc_suffix} $RPM_BUILD_ROOT%{_prefix}/bin/c++ -ln -sf gcc-%{gcc_suffix} $RPM_BUILD_ROOT%{_prefix}/bin/cc -ln -sf g++-%{gcc_suffix}.1.gz $RPM_BUILD_ROOT%{_mandir}/man1/c++.1.gz -ln -sf gcc-%{gcc_suffix}.1.gz $RPM_BUILD_ROOT%{_mandir}/man1/cc.1.gz -# Install the LTO linker plugin so it is auto-loaded by BFD -mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/bfd-plugins -ln -s `gcc-%{gcc_suffix} -print-file-name=liblto_plugin.so.0.0.0` $RPM_BUILD_ROOT%{_prefix}/lib/bfd-plugins/liblto_plugin.so.0.0.0 - -dir=`gcc-%{gcc_suffix} -print-prog-name=cc1` -dir=${dir%/cc1} -mkdir -p $RPM_BUILD_ROOT/$dir -cat > $RPM_BUILD_ROOT/$dir/defaults.spec <<EOF -*default_spec: -%%{pie|fpic|fPIC|fpie|fPIE|no-pie|fno-pic|fno-PIC|fno-pie|fno-PIE|shared|static|nostdlib|nodefaultlibs|nostartfiles:;:-fPIE}%%{fno-pic|fno-PIC|fno-pie|fno-PIE|pie|no-pie|shared|static|nostdlib|nodefaultlibs|nostartfiles:;: -pie} +exec gcc $fl ${1+"$@"} EOF +chmod 755 %{buildroot}%{_prefix}/bin/c?9 + +cd .. +%find_lang %{name} +%find_lang cpplib + +# Remove binaries we will not be including, so that they don't end up in +# gcc-debuginfo +rm -f %{buildroot}%{_prefix}/%{_lib}/{libffi*,libiberty.a} || : +rm -f $FULLEPATH/install-tools/{mkheaders,fixincl} +rm -f %{buildroot}%{_prefix}/lib/{32,64}/libiberty.a +rm -f %{buildroot}%{_prefix}/%{_lib}/libssp* +rm -f %{buildroot}%{_prefix}/%{_lib}/libvtv* || : +rm -f %{buildroot}%{_prefix}/bin/%{_target_platform}-gfortran || : +rm -f %{buildroot}%{_prefix}/bin/%{_target_platform}-gccgo || : +rm -f %{buildroot}%{_prefix}/bin/%{_target_platform}-gcj || : +rm -f %{buildroot}%{_prefix}/bin/%{_target_platform}-gcc-ar || : +rm -f %{buildroot}%{_prefix}/bin/%{_target_platform}-gcc-nm || : +rm -f %{buildroot}%{_prefix}/bin/%{_target_platform}-gcc-ranlib || : +rm -f %{buildroot}%{_prefix}/bin/%{_target_platform}-gdc || : + +%ifarch %{multilib_64_archs} +# Remove libraries for the other arch on multilib arches +rm -f %{buildroot}%{_prefix}/lib/lib*.so* +rm -f %{buildroot}%{_prefix}/lib/lib*.a +rm -f %{buildroot}/lib/libgcc_s*.so* +%if %{build_go} +rm -rf %{buildroot}%{_prefix}/lib/go/%{gcc_major}/%{gcc_target_platform} +%ifnarch sparc64 ppc64 ppc64p7 +ln -sf %{multilib_32_arch}-%{_vendor}-%{_target_os} %{buildroot}%{_prefix}/lib/go/%{gcc_major}/%{gcc_target_platform} +%endif +%endif +%else +%ifarch sparcv9 ppc +rm -f %{buildroot}%{_prefix}/lib64/lib*.so* +rm -f %{buildroot}%{_prefix}/lib64/lib*.a +rm -f %{buildroot}/lib64/libgcc_s*.so* +%if %{build_go} +rm -rf %{buildroot}%{_prefix}/lib64/go/%{gcc_major}/%{gcc_target_platform} +%endif +%endif +%endif -%post -n gcc-go -# we don't want a BuildRequires on gccN-go but otherwise the install -# step of the build fails, so simply skip the script when gccN-go isn't there -if [ -f %{_bindir}/go-%{gcc_suffix} ] ; then -update-alternatives \ - --install %{_bindir}/go go %{_bindir}/go-%{gcc_suffix} 100 \ - --slave %{_bindir}/gofmt gofmt %{_bindir}/gofmt-%{gcc_suffix} -fi +rm -f %{buildroot}%{mandir}/man3/ffi* + +# Help plugins find out nvra. +echo gcc-%{version}-%{release}.%{_arch} > $FULLPATH/rpmver -%postun -n gcc-go -if [ $1 -eq 0 ] ; then - update-alternatives --remove go %{_bindir}/go-%{gcc_suffix} +%check +cd obj-%{gcc_target_platform} + +%if %{build_check} +# run the tests. +LC_ALL=C make %{?_smp_mflags} -k check ALT_CC_UNDER_TEST=gcc ALT_CXX_UNDER_TEST=g++ \ + RUNTESTFLAGS="--target_board=unix/'{,-fstack-protector-strong}'" || : +echo ====================TESTING========================= +( LC_ALL=C ../contrib/test_summary || : ) 2>&1 | sed -n '/^cat.*EOF/,/^EOF/{/^cat.*EOF/d;/^EOF/d;/^LAST_UPDATED:/d;p;}' +echo ====================TESTING END===================== +mkdir testlogs-%{_target_platform}-%{version}-%{release} +for i in `find . -name \*.log | grep -F testsuite/ | grep -v 'config.log\|acats.*/tests/'`; do + ln $i testlogs-%{_target_platform}-%{version}-%{release}/ || : +done +tar cf - testlogs-%{_target_platform}-%{version}-%{release} | xz -9e \ + | uuencode testlogs-%{_target_platform}.tar.xz || : +rm -rf testlogs-%{_target_platform}-%{version}-%{release} +%endif + +%post go +%{_sbindir}/update-alternatives --install \ + %{_prefix}/bin/go go %{_prefix}/bin/go.gcc 92 \ + --slave %{_prefix}/bin/gofmt gofmt %{_prefix}/bin/gofmt.gcc + +%preun go +if [ $1 = 0 ]; then + %{_sbindir}/update-alternatives --remove go %{_prefix}/bin/go.gcc fi -%files -%defattr(-,root,root) -%{_prefix}/bin/gcc +# Because glibc Prereq's libgcc and /sbin/ldconfig +# comes from glibc, it might not exist yet when +# libgcc is installed +%post -n libgcc -p <lua> +if posix.access ("/sbin/ldconfig", "x") then + local pid = posix.fork () + if pid == 0 then + posix.exec ("/sbin/ldconfig") + elseif pid ~= -1 then + posix.wait (pid) + end +end + +%postun -n libgcc -p <lua> +if posix.access ("/sbin/ldconfig", "x") then + local pid = posix.fork () + if pid == 0 then + posix.exec ("/sbin/ldconfig") + elseif pid ~= -1 then + posix.wait (pid) + end +end + +%ldconfig_scriptlets -n libstdc++ + +%ldconfig_scriptlets -n libobjc + +%ldconfig_scriptlets -n libgfortran + +%ldconfig_scriptlets -n libgphobos + +%ldconfig_scriptlets -n libgnat + +%ldconfig_scriptlets -n libgomp + +%ldconfig_scriptlets gdb-plugin + +%ldconfig_scriptlets -n libgccjit + +%ldconfig_scriptlets -n libgquadmath + +%ldconfig_scriptlets -n libitm + +%ldconfig_scriptlets -n libatomic + +%ldconfig_scriptlets -n libasan + +%ldconfig_scriptlets -n libubsan + +%ldconfig_scriptlets -n libtsan + +%ldconfig_scriptlets -n liblsan + +%ldconfig_scriptlets -n libgo + +%files -f %{name}.lang %{_prefix}/bin/cc +%{_prefix}/bin/c89 +%{_prefix}/bin/c99 +%{_prefix}/bin/gcc %{_prefix}/bin/gcov -%{_prefix}/bin/gcov-dump %{_prefix}/bin/gcov-tool +%{_prefix}/bin/gcov-dump %{_prefix}/bin/gcc-ar %{_prefix}/bin/gcc-nm %{_prefix}/bin/gcc-ranlib -%dir %{_prefix}/lib/bfd-plugins -%{_prefix}/lib/bfd-plugins/liblto_plugin.so.0.0.0 -%doc %{_mandir}/man1/gcc.1.gz -%doc %{_mandir}/man1/cc.1.gz -%doc %{_mandir}/man1/gcov.1.gz -%doc %{_mandir}/man1/gcov-dump.1.gz -%doc %{_mandir}/man1/gcov-tool.1.gz - -%files -n cpp -%defattr(-,root,root) -/lib/cpp -%{_prefix}/bin/cpp -%doc %{_mandir}/man1/cpp.1.gz - -# Plugins are only enabled for Tumbleweed -%if 0%{!?sle_version:1} -%files -n gcc-devel -%defattr(-,root,root) -# empty - only for the dependency +%{_prefix}/bin/lto-dump +%ifarch ppc +%{_prefix}/bin/%{_target_platform}-gcc +%endif +%ifarch sparc64 sparcv9 +%{_prefix}/bin/sparc-%{_vendor}-%{_target_os}-gcc +%endif +%ifarch ppc64 ppc64p7 +%{_prefix}/bin/ppc-%{_vendor}-%{_target_os}-gcc +%endif +%{_prefix}/bin/%{gcc_target_platform}-gcc +%{_prefix}/bin/%{gcc_target_platform}-gcc-%{gcc_major} +%{_mandir}/man1/gcc.1* +%{_mandir}/man1/gcov.1* +%{_mandir}/man1/gcov-tool.1* +%{_mandir}/man1/gcov-dump.1* +%{_mandir}/man1/lto-dump.1* +%{_infodir}/gcc* +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%dir %{_prefix}/libexec/gcc +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform} +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/lto1 +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/lto-wrapper +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/liblto_plugin.so* +%ifarch aarch64 +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/libbolt_plugin.so* +%endif +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/rpmver +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/stddef.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/stdarg.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/stdfix.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/varargs.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/float.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/limits.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/stdbool.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/iso646.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/syslimits.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/unwind.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/omp.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/openacc.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/acc_prof.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/stdint.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/stdint-gcc.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/stdalign.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/stdnoreturn.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/stdatomic.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/gcov.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/simdmath.h +%ifarch %{ix86} x86_64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/mmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/xmmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/emmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/pmmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/tmmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/ammintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/smmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/nmmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/bmmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/wmmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/immintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avxintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/x86intrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/fma4intrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/xopintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/lwpintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/popcntintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/bmiintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/tbmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/ia32intrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx2intrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/bmi2intrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/f16cintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/fmaintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/lzcntintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/rtmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/xtestintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/adxintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/prfchwintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/rdseedintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/fxsrintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/xsaveintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/xsaveoptintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512cdintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512erintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512fintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512pfintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/shaintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/mm_malloc.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/mm3dnow.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/cpuid.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/cross-stdarg.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512bwintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512dqintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512ifmaintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512ifmavlintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512vbmiintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512vbmivlintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512vlbwintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512vldqintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512vlintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/clflushoptintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/clwbintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/mwaitxintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/xsavecintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/xsavesintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/clzerointrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/pkuintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx5124fmapsintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx5124vnniwintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512vpopcntdqintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/sgxintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/gfniintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/cetintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/cet.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512vbmi2intrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512vbmi2vlintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512vnniintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512vnnivlintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/vaesintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/vpclmulqdqintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512vpopcntdqvlintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512bitalgintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/pconfigintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/wbnoinvdintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/movdirintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/waitpkgintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/cldemoteintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512bf16vlintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512bf16intrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/enqcmdintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512vp2intersectintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/avx512vp2intersectvlintrin.h +%endif +%ifarch ia64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/ia64intrin.h +%endif +%ifarch ppc ppc64 ppc64le ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/ppc-asm.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/altivec.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/ppu_intrinsics.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/si2vmx.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/spu2vmx.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/vec_types.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/htmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/htmxlintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/bmi2intrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/bmiintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/xmmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/mm_malloc.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/emmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/mmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/x86intrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/pmmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/tmmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/smmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/amo.h +%endif +%ifarch %{arm} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/unwind-arm-common.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/mmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/arm_neon.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/arm_acle.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/arm_cmse.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/arm_fp16.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/arm_bf16.h +%endif +%ifarch aarch64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/arm_neon.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/arm_acle.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/arm_fp16.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/arm_bf16.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/arm_sve.h +%endif +%ifarch sparc sparcv9 sparc64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/visintrin.h +%endif +%ifarch s390 s390x +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/s390intrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/htmintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/htmxlintrin.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/vecintrin.h +%endif +%if %{build_libasan} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/sanitizer +%endif +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/collect2 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/crt*.o +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgcc.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgcov.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgcc_eh.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgcc_s.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgomp.spec +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgomp.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgomp.so +%if %{build_libitm} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libitm.spec +%endif +%if %{build_libasan} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libsanitizer.spec +%endif +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/crt*.o +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libgcc.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libgcov.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libgcc_eh.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libgcc_s.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libgomp.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libgomp.so +%if %{build_libquadmath} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libquadmath.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libquadmath.so +%endif +%if %{build_libitm} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libitm.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libitm.so +%endif +%if %{build_libatomic} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libatomic.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libatomic.so +%endif +%if %{build_libasan} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libasan.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libasan.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libasan_preinit.o +%endif +%if %{build_libubsan} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libubsan.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libubsan.so +%endif +%endif +%ifarch %{multilib_64_archs} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/crt*.o +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libgcc.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libgcov.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libgcc_eh.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libgcc_s.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libgomp.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libgomp.so +%if %{build_libquadmath} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libquadmath.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libquadmath.so +%endif +%if %{build_libitm} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libitm.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libitm.so +%endif +%if %{build_libatomic} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libatomic.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libatomic.so +%endif +%if %{build_libasan} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libasan.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libasan.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libasan_preinit.o +%endif +%if %{build_libubsan} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libubsan.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libubsan.so +%endif +%endif +%ifarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%if %{build_libquadmath} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libquadmath.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libquadmath.so +%endif +%if %{build_libitm} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libitm.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libitm.so +%endif +%if %{build_libatomic} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libatomic.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libatomic.so +%endif +%if %{build_libasan} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libasan.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libasan.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libasan_preinit.o +%endif +%if %{build_libubsan} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libubsan.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libubsan.so +%endif +%else +%if %{build_libatomic} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libatomic.so %endif +%if %{build_libasan} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libasan.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libasan_preinit.o +%endif +%if %{build_libubsan} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libubsan.so +%endif +%endif +%if %{build_libtsan} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libtsan.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libtsan_preinit.o +%endif +%if %{build_liblsan} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/liblsan.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/liblsan_preinit.o +%endif +%{_prefix}/libexec/getconf/default +%doc gcc/README* rpm.doc/changelogs/gcc/ChangeLog* +%{!?_licensedir:%global license %%doc} +%license gcc/COPYING* COPYING.RUNTIME -%files -n gcc-c++ -%defattr(-,root,root) +%files -n cpp -f cpplib.lang +%{_prefix}/lib/cpp +%{_prefix}/bin/cpp +%{_mandir}/man1/cpp.1* +%{_infodir}/cpp* +%dir %{_prefix}/libexec/gcc +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform} +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major} +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/cc1 + +%files -n libgcc +/%{_lib}/libgcc_s-%{gcc_major}.so.1 +/%{_lib}/libgcc_s.so.1 +%{!?_licensedir:%global license %%doc} +%license gcc/COPYING* COPYING.RUNTIME + +%files c++ +%{_prefix}/bin/%{gcc_target_platform}-*++ %{_prefix}/bin/g++ %{_prefix}/bin/c++ -%doc %{_mandir}/man1/g++.1.gz -%doc %{_mandir}/man1/c++.1.gz - -%files -n gcc-fortran -%defattr(-,root,root) -%{_prefix}/bin/gfortran -%doc %{_mandir}/man1/gfortran.1.gz - -%files -n gcc-objc -%defattr(-,root,root) -# empty - only for the dependency - -%files -n gcc-obj-c++ -%defattr(-,root,root) -# empty - only for the dependency - -%files -n gcc-PIE -%defattr(-,root,root) -/usr/lib*/gcc/*-suse-linux*/*/defaults.spec - -%files -n gcc-locale -%defattr(-,root,root) -# empty - only for the dependency - -%files -n gcc-info -%defattr(-,root,root) -%{_infodir}/cpp.info.gz -%{_infodir}/gcc.info.gz -%{_infodir}/gfortran.info.gz +%{_mandir}/man1/g++.1* +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%dir %{_prefix}/libexec/gcc +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform} +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major} +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/cc1plus +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libstdc++.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libstdc++.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libstdc++fs.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libsupc++.a +%endif +%ifarch %{multilib_64_archs} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libstdc++.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libstdc++.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libstdc++fs.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libsupc++.a +%endif +%ifarch sparcv9 ppc %{multilib_64_archs} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libstdc++.so +%endif +%ifarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libstdc++.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libstdc++fs.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libsupc++.a +%endif +%doc rpm.doc/changelogs/gcc/cp/ChangeLog* -%if %{build_ada} -%files -n gcc-ada -%defattr(-,root,root) -%{_prefix}/bin/gnat -%{_prefix}/bin/gnatbind -%{_prefix}/bin/gnatbl -%{_prefix}/bin/gnatchop -%{_prefix}/bin/gnatclean -%{_prefix}/bin/gnatfind -%{_prefix}/bin/gnatkr -%{_prefix}/bin/gnatlink -%{_prefix}/bin/gnatls -%{_prefix}/bin/gnatmake -%{_prefix}/bin/gnatname -%{_prefix}/bin/gnatprep -%{_prefix}/bin/gnatxref -%{_prefix}/bin/gprmake +%files -n libstdc++ +%{_prefix}/%{_lib}/libstdc++.so.6* +# Package symlink to keep compatibility +%ifarch riscv64 +%{_datadir}/gdb/auto-load/%{_prefix}/%{_lib}/lp64d %endif +%{_datadir}/gdb/auto-load/%{_prefix}/%{_lib}/libstdc*gdb.py* +%dir %{_prefix}/share/gcc-%{gcc_major} +%dir %{_prefix}/share/gcc-%{gcc_major}/python +%{_prefix}/share/gcc-%{gcc_major}/python/libstdcxx %files -n libstdc++-devel -%defattr(-,root,root) -# empty - only for the dependency - -%files -n gcc-go -%defattr(-,root,root) -%{_bindir}/gccgo -%{_bindir}/go -%{_bindir}/gofmt -%ghost %{_sysconfdir}/alternatives/go -%ghost %{_sysconfdir}/alternatives/gofmt -%doc %{_mandir}/man1/gccgo.1.gz +%dir %{_prefix}/include/c++ +%{_prefix}/include/c++/%{gcc_major} +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%ifnarch sparcv9 ppc %{multilib_64_archs} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libstdc++.so +%endif +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32/libstdc++fs.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64/libstdc++fs.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libstdc++fs.a +%endif +%doc rpm.doc/changelogs/libstdc++-v3/ChangeLog* libstdc++-v3/README* + +%files -n libstdc++-static +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32/libstdc++.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32/libsupc++.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64/libstdc++.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64/libsupc++.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libstdc++.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libsupc++.a +%endif -%if %{separate_bi32} +%if %{build_libstdcxx_docs} +%files -n libstdc++-docs +%{_mandir}/man3/* +%doc rpm.doc/libstdc++-v3/html +%endif -%files -n gcc-32bit -%defattr(-,root,root) -# empty - only for the dependency +%if %{build_objc} +%files objc +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%dir %{_prefix}/libexec/gcc +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform} +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/objc +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/cc1obj +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libobjc.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libobjc.so +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libobjc.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libobjc.so +%endif +%ifarch %{multilib_64_archs} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libobjc.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libobjc.so +%endif +%doc rpm.doc/objc/* +%doc libobjc/THREADS* rpm.doc/changelogs/libobjc/ChangeLog* -%files -n gcc-c++-32bit -%defattr(-,root,root) -# empty - only for the dependency +%files objc++ +%dir %{_prefix}/libexec/gcc +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform} +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major} +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/cc1objplus -%files -n libstdc++-devel-32bit -%defattr(-,root,root) -# empty - only for the dependency +%files -n libobjc +%{_prefix}/%{_lib}/libobjc.so.4* +%endif -%files -n gcc-fortran-32bit -%defattr(-,root,root) -# empty - only for the dependency +%files gfortran +%{_prefix}/bin/gfortran +%{_prefix}/bin/f95 +%{_mandir}/man1/gfortran.1* +%{_infodir}/gfortran* +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%dir %{_prefix}/libexec/gcc +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform} +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/finclude +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/ISO_Fortran_binding.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/finclude/omp_lib.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/finclude/omp_lib.f90 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/finclude/omp_lib.mod +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/finclude/omp_lib_kinds.mod +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/finclude/openacc.f90 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/finclude/openacc.mod +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/finclude/openacc_kinds.mod +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/finclude/openacc_lib.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/finclude/ieee_arithmetic.mod +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/finclude/ieee_exceptions.mod +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/finclude/ieee_features.mod +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/finclude/simdmath_f.h +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/f951 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgfortran.spec +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libcaf_single.a +%ifarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgfortran.a +%endif +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgfortran.so +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libcaf_single.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libgfortran.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libgfortran.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/finclude +%endif +%ifarch %{multilib_64_archs} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libcaf_single.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libgfortran.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libgfortran.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/finclude +%endif +%dir %{_fmoddir} +%doc rpm.doc/gfortran/* + +%files -n libgfortran +%{_prefix}/%{_lib}/libgfortran.so.5* + +%files -n libgfortran-static +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32/libgfortran.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64/libgfortran.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgfortran.a +%endif -%files -n gcc-objc-32bit -%defattr(-,root,root) -# empty - only for the dependency +%if %{build_d} +%files gdc +%{_prefix}/bin/gdc +%{_mandir}/man1/gdc.1* +%{_infodir}/gdc* +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%dir %{_prefix}/libexec/gcc +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform} +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/d +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/d21 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgphobos.spec +%ifarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgdruntime.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgphobos.a +%endif +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgdruntime.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgphobos.so +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libgdruntime.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libgphobos.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libgdruntime.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libgphobos.so +%endif +%ifarch %{multilib_64_archs} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libgdruntime.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libgphobos.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libgdruntime.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libgphobos.so +%endif +%doc rpm.doc/gdc/* + +%files -n libgphobos +%{_prefix}/%{_lib}/libgdruntime.so.1* +%{_prefix}/%{_lib}/libgphobos.so.1* +%doc rpm.doc/libphobos/* + +%files -n libgphobos-static +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32/libgdruntime.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32/libgphobos.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64/libgdruntime.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64/libgphobos.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgdruntime.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgphobos.a +%endif +%endif %if %{build_ada} -%files -n gcc-ada-32bit -%defattr(-,root,root) -# empty - only for the dependency +%files gnat +%{_prefix}/bin/gnat +%{_prefix}/bin/gnat[^i]* +%{_infodir}/gnat* +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%dir %{_prefix}/libexec/gcc +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform} +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major} +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/adainclude +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/adalib +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/ada_target_properties +%endif +%ifarch %{multilib_64_archs} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/adainclude +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/adalib +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/ada_target_properties +%endif +%ifarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/adainclude +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/adalib +%endif +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/ada_target_properties +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/gnat1 +%doc rpm.doc/changelogs/gcc/ada/ChangeLog* + +%files -n libgnat +%{_prefix}/%{_lib}/libgnat-*.so +%{_prefix}/%{_lib}/libgnarl-*.so + +%files -n libgnat-devel +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32/adainclude +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32/adalib +%exclude %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32/adalib/libgnat.a +%exclude %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32/adalib/libgnarl.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64/adainclude +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64/adalib +%exclude %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64/adalib/libgnat.a +%exclude %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64/adalib/libgnarl.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/adainclude +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/adalib +%exclude %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/adalib/libgnat.a +%exclude %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/adalib/libgnarl.a %endif -%files -n gcc-go-32bit -%defattr(-,root,root) -# empty - only for the dependency +%files -n libgnat-static +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32/adalib +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32/adalib/libgnat.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32/adalib/libgnarl.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64/adalib +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64/adalib/libgnat.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64/adalib/libgnarl.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/adalib +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/adalib/libgnat.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/adalib/libgnarl.a +%endif +%endif +%files -n libgomp +%{_prefix}/%{_lib}/libgomp.so.1* +%{_infodir}/libgomp.info* +%doc rpm.doc/changelogs/libgomp/ChangeLog* + +%if %{build_libquadmath} +%files -n libquadmath +%{_prefix}/%{_lib}/libquadmath.so.0* +%{_infodir}/libquadmath.info* +%{!?_licensedir:%global license %%doc} +%license rpm.doc/libquadmath/COPYING* + +%files -n libquadmath-devel +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/quadmath.h +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include/quadmath_weak.h +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libquadmath.so +%endif +%doc rpm.doc/libquadmath/ChangeLog* + +%files -n libquadmath-static +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32/libquadmath.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64/libquadmath.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libquadmath.a +%endif %endif -%if %{separate_bi64} -%files -n gcc-64bit -%defattr(-,root,root) -# empty - only for the dependency +%if %{build_libitm} +%files -n libitm +%{_prefix}/%{_lib}/libitm.so.1* +%{_infodir}/libitm.info* + +%files -n libitm-devel +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/include +#%%{_prefix}/lib/gcc/%%{gcc_target_platform}/%%{gcc_major}/include/itm.h +#%%{_prefix}/lib/gcc/%%{gcc_target_platform}/%%{gcc_major}/include/itm_weak.h +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libitm.so +%endif +%doc rpm.doc/libitm/ChangeLog* + +%files -n libitm-static +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32/libitm.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64/libitm.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libitm.a +%endif +%endif -%files -n gcc-c++-64bit -%defattr(-,root,root) -# empty - only for the dependency +%if %{build_libatomic} +%files -n libatomic +%{_prefix}/%{_lib}/libatomic.so.1* + +%files -n libatomic-static +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32/libatomic.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64/libatomic.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libatomic.a +%endif +%doc rpm.doc/changelogs/libatomic/ChangeLog* +%endif -%files -n libstdc++-devel-64bit -%defattr(-,root,root) -# empty - only for the dependency +%if %{build_libasan} +%files -n libasan +%{_prefix}/%{_lib}/libasan.so.6* + +%files -n libasan-static +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32/libasan.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64/libasan.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libasan.a +%endif +%doc rpm.doc/changelogs/libsanitizer/ChangeLog* +%{!?_licensedir:%global license %%doc} +%license libsanitizer/LICENSE.TXT +%endif -%files -n gcc-fortran-64bit -%defattr(-,root,root) -# empty - only for the dependency +%if %{build_libubsan} +%files -n libubsan +%{_prefix}/%{_lib}/libubsan.so.1* + +%files -n libubsan-static +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32/libubsan.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64/libubsan.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libubsan.a +%endif +%doc rpm.doc/changelogs/libsanitizer/ChangeLog* +%{!?_licensedir:%global license %%doc} +%license libsanitizer/LICENSE.TXT +%endif -%files -n gcc-objc-64bit -%defattr(-,root,root) -# empty - only for the dependency +%if %{build_libtsan} +%files -n libtsan +%{_prefix}/%{_lib}/libtsan.so.0* + +%files -n libtsan-static +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libtsan.a +%doc rpm.doc/changelogs/libsanitizer/ChangeLog* +%{!?_licensedir:%global license %%doc} +%license libsanitizer/LICENSE.TXT +%endif -%if %{build_ada} -%files -n gcc-ada-64bit -%defattr(-,root,root) -# empty - only for the dependency +%if %{build_liblsan} +%files -n liblsan +%{_prefix}/%{_lib}/liblsan.so.0* + +%files -n liblsan-static +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/liblsan.a +%doc rpm.doc/changelogs/libsanitizer/ChangeLog* +%{!?_licensedir:%global license %%doc} +%license libsanitizer/LICENSE.TXT %endif -%files -n gcc-go-64bit -%defattr(-,root,root) -# empty - only for the dependency +%if %{build_go} +%files go +%ghost %{_prefix}/bin/go +%attr(755,root,root) %{_prefix}/bin/go.gcc +%{_prefix}/bin/gccgo +%ghost %{_prefix}/bin/gofmt +%attr(755,root,root) %{_prefix}/bin/gofmt.gcc +%{_mandir}/man1/gccgo.1* +%{_mandir}/man1/go.1* +%{_mandir}/man1/gofmt.1* +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%dir %{_prefix}/libexec/gcc +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform} +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major} +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/go1 +%attr(755,root,root) %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/cgo +%attr(755,root,root) %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/buildid +%attr(755,root,root) %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/test2json +%attr(755,root,root) %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/vet +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libgo.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libgo.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libgobegin.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/64/libgolibbegin.a +%endif +%ifarch %{multilib_64_archs} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libgo.so +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libgo.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libgobegin.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/32/libgolibbegin.a +%endif +%ifarch sparcv9 ppc %{multilib_64_archs} +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgo.so +%endif +%ifarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgo.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgobegin.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgolibbegin.a +%endif +%doc rpm.doc/go/* + +%files -n libgo +%attr(755,root,root) %{_prefix}/%{_lib}/libgo.so.16* +%doc rpm.doc/libgo/* + +%files -n libgo-devel +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%dir %{_prefix}/%{_lib}/go +%dir %{_prefix}/%{_lib}/go/%{gcc_major} +%{_prefix}/%{_lib}/go/%{gcc_major}/%{gcc_target_platform} +%ifarch %{multilib_64_archs} +%ifnarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/go +%dir %{_prefix}/lib/go/%{gcc_major} +%{_prefix}/lib/go/%{gcc_major}/%{gcc_target_platform} +%endif +%endif +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32/libgobegin.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32/libgolibbegin.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64/libgobegin.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64/libgolibbegin.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgobegin.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgolibbegin.a +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgo.so +%endif +%files -n libgo-static +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%ifarch sparcv9 ppc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib32/libgo.a +%endif +%ifarch sparc64 ppc64 ppc64p7 +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/lib64/libgo.a +%endif +%ifnarch sparcv9 sparc64 ppc ppc64 ppc64p7 +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/libgo.a %endif +%endif + +%files -n libgccjit +%{_prefix}/%{_lib}/libgccjit.so.* +%doc rpm.doc/changelogs/gcc/jit/ChangeLog* + +%files -n libgccjit-devel +%{_prefix}/%{_lib}/libgccjit.so +%{_prefix}/include/libgccjit*.h +%{_infodir}/libgccjit.info* +%doc rpm.doc/libgccjit-devel/* +%doc gcc/jit/docs/examples + +%files plugin-devel +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/plugin +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/plugin/gtype.state +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/plugin/include +%dir %{_prefix}/libexec/gcc +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform} +%dir %{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major} +%{_prefix}/libexec/gcc/%{gcc_target_platform}/%{gcc_major}/plugin + +%files gdb-plugin +%{_prefix}/%{_lib}/libcc1.so* +%dir %{_prefix}/lib/gcc +%dir %{_prefix}/lib/gcc/%{gcc_target_platform} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major} +%dir %{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/plugin +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/plugin/libcc1plugin.so* +%{_prefix}/lib/gcc/%{gcc_target_platform}/%{gcc_major}/plugin/libcp1plugin.so* +%doc rpm.doc/changelogs/libcc1/ChangeLog* %changelog -* Fri Jul 9 2021 rguenther@suse.com -- With gcc-PIE add -pie even when -fPIC is specified but we are - not linking a shared library. [boo#1185348] -- Fix postun of gcc-go alternative. -* Wed Jun 13 2018 rguenther@suse.com -- Add gccgo symlink, add go and gofmt as alternatives to support - parallel install of golang. [bnc#1096677] -* Tue Jun 5 2018 rguenther@suse.com -- Fix gcc-PIE spec to properly honor -no-pie at link time. - [bnc#1096008] -* Fri Jun 9 2017 rguenther@suse.com -- Fix gcc-devel guard to use %%sle_version. [bnc#1043590] -* Wed Jun 7 2017 rguenther@suse.com -- Guard gcc-devel so it is only built on Tumbleweed. -- Remove bogus link to versioned g++.info file which doesn't exist. - Instead refer to gcc.info from the g++ info directory entry. - [bnc#922419] -* Tue Jun 6 2017 mliska@suse.cz -- Include gcov-tool and gcov-dump binaries. -* Thu Apr 13 2017 rguenther@suse.com -- Remove README in empty packages only required for SLE11 and older. -- Remove now empty %%build section. -* Tue Apr 4 2017 rguenther@suse.com -- Fix dependencies of libstdc++-devel-{32,64}-bit. -* Thu Mar 23 2017 rguenther@suse.com -- Switch gcc to default 7. -- Remove unrelated README.packaging. -* Fri Feb 10 2017 rguenther@suse.com -- Enable Ada for s390x. -* Mon Jan 23 2017 rguenther@suse.com -- Remove java related packages, those are in a separate gcc-java now. -* Thu Aug 18 2016 rguenther@suse.com -- Add gcc-devel package. -* Wed Apr 27 2016 rguenther@suse.com -- Switch gcc to default 6. -* Thu Apr 14 2016 rguenther@suse.com -- Enable Ada for ppc64le and aarch64. -* Thu May 21 2015 rguenther@suse.com -- Properly query gcc-%%gcc_suffix for paths. -* Tue May 19 2015 rguenther@suse.com -- Fix bogus requires to gcc5-c++-{32,64}bit. -* Fri May 8 2015 rguenther@suse.com -- Adjust for GCC 5 package renames. -* Mon Apr 20 2015 rguenther@suse.com -- Switch gcc to default 5. -- Add gcc-go{,-32bit,-64bit} packages. -* Mon Mar 2 2015 schwab@suse.de -- Add gcc-ada-32bit and gcc-ada-64bit packages only if building Ada -* Wed Feb 25 2015 rguenther@suse.com -- Add gcc-ada-32bit and gcc-ada-64bit packages. -* Wed Feb 4 2015 meissner@suse.com -- add a gcc-PIE subpackage, which enables building PIE binaries - by default using the defaults.spec file. bsc#912298 -* Mon Aug 4 2014 rguenther@suse.com -- Add libstdc++-devel-32bit and libstdc++-devel-64bit packages. - [bnc#890226] -* Fri Mar 21 2014 rguenther@suse.com -- Link to the system compiler LTO plugin from /usr/lib/bfd-plugins. -* Tue Feb 4 2014 rguenther@suse.com -- Remove gcc-z9 wrapper which is obsolete. -* Mon Dec 2 2013 rguenther@suse.com -- Move gcc-ar, gcc-nm and gcc-ranlib to the gcc package instead - of packaging them separately. -* Wed Jun 19 2013 rguenther@suse.com -- Package gcc-ar, gcc-nm and gcc-ranlib wrapping ar, nm and ranlib - in a plugin-aware fashion. -* Mon May 27 2013 rguenther@suse.com -- Switch gcc to default 4.8. -* Mon Jan 7 2013 rguenther@suse.com -- Re-enable Ada for ppc64. -* Thu Dec 13 2012 rguenther@suse.com -- Add BuildRequires to gcc$version, required for cc1 path detection. -* Wed Nov 28 2012 rguenther@suse.com -- Rework gcc-info. - * Install symlinks to the versioned info files and adjust - install_info calls. [bnc#756182] - * Provide uninstall hook that removes the alias entries. -* Thu Oct 4 2012 dmueller@suse.com -- remove gcc-ada subpackage for those architectures that - don't have a gccXX-ada package -* Wed Apr 18 2012 rguenther@suse.com -- Switch gcc to default 4.7. -* Fri Jan 27 2012 rguenther@suse.com -- Change licenses to follow SPDX convention. -* Mon Sep 26 2011 dmueller@suse.de -- use the target gcc binary for finding the right cc1 path -* Wed May 11 2011 rguenther@novell.com -- Switch gcc to default 4.6. -* Thu Feb 10 2011 rguenther@novell.com -- Fix licenses to match those of the system compiler. [bnc#670658] -* Tue Jan 25 2011 rguenther@novell.com -- Fix string quoting. [bnc#666416] -* Wed Jan 12 2011 rguenther@novell.com -- Uglify spec file formatting. -* Fri Dec 10 2010 rguenther@novell.com -- Add info directory aliases for unversioned variants of the - GCC user manuals. [bnc#635355] -* Mon Nov 29 2010 rguenther@novell.com -- Drop libffi packages. -* Fri Feb 26 2010 rguenther@novell.com -- Fix gcc-c++-32bit and gcc-c++-64bit again. -* Thu Feb 25 2010 rguenther@suse.de -- Drop c++_compiler provides from gcc-c++-32bit and gcc-c++-64bit. -* Thu Feb 25 2010 rguenther@suse.de -- Re-add gcc-c++-32bit and gcc-c++-64bit packages. -* Tue Feb 16 2010 coolo@novell.com -- Switch gcc to default 4.5. -* Mon Apr 27 2009 rguenther@suse.de -- Switch gcc default to 4.4. -* Mon Feb 16 2009 rguenther@suse.de -- Enable links for classpath binaries and manpages again. -* Fri Jan 9 2009 rguenther@suse.de -- On ppc64 obsolete gcc-objc-64bit by gcc-objc. -* Thu Dec 4 2008 matz@suse.de -- Add new gcc-z9 package on s390 and s390x to change the - default -march and -mtune settings. -* Wed May 7 2008 rguenther@suse.de -- Make dependencies between the gcc subpackages versioned. [bnc#385305] -* Fri Nov 23 2007 rguenther@suse.de -- Make gcc-gij dependency of gcc-java a recommendation, all java - tools are back to the gcc-java package. Require libgcj-devel - from gcc-java. -- Revert /lib/cpp changes. -* Fri Nov 16 2007 rguenther@suse.de -- For now disable symlinking of binaries and manpages that - conflict with the classpath package. -* Tue Nov 13 2007 rguenther@suse.de -- Make /lib/cpp traditional and avoid GCC and target specific - defines. -* Tue Oct 30 2007 rguenther@suse.de -- Add gcc-gij dependency to gcc-java as it contains many of the - tools formerly packaged in the gcc-java package. -* Mon Sep 24 2007 rguenther@suse.de -- Switch gcc default to 4.3. -* Fri Jul 27 2007 rguenther@suse.de -- Fix typo. -* Tue Jul 24 2007 rguenther@suse.de -- Add 32bit and 64bit variants of gcc-gij. [#293423] -* Fri Jul 6 2007 rguenther@suse.de -- Mark ppc64 as separate bi-32. -* Thu Jun 14 2007 ro@suse.de -- Do not mark README.packaging as NoSource. (again) -* Fri Jun 8 2007 rguenther@suse.de -- Switch gcc default to 4.2. [#275939] -* Tue Apr 24 2007 rguenther@suse.de -- Do not link to grmic and grmiregistry, they conflict with - the classpath package versions. -* Tue Jan 16 2007 rguenther@suse.de -- Do not mark README.packaging as NoSource. -* Thu Nov 9 2006 rguenther@suse.de -- Remove gcc-c++-32bit and gcc-c++-64bit packages. -* Tue Oct 31 2006 dmueller@suse.de -- don't build as root -* Mon Oct 30 2006 rguenther@suse.de -- Make gcc architecture dependent again. [#215971] -* Thu Oct 26 2006 rguenther@suse.de -- Add dependencies to the gcc and non-32/64bit packages. [#215217] -* Tue Sep 19 2006 rguenther@suse.de -- New gcc-gij package. -* Fri Aug 25 2006 rguenther@suse.de -- Add 32bit and 64bit support packages to gcc, gcc-c++, gcc-fortran, - gcc-objc and libffi-devel. -* Thu Aug 24 2006 rguenther@suse.de -- Make gcc require cpp to pull in /lib/cpp. -* Fri Aug 18 2006 rguenther@suse.de -- gcc obsoletes gcc-mudflap which is no longer. -* Mon Aug 7 2006 rguenther@suse.de -- Provide gcc-mudflap, gcc-info and gcc-locale packages [#197515]. -* Fri Jul 14 2006 rguenther@suse.de -- New package. +* Tue Oct 10 2023 Xiong Zhou <xiongzhou4@huawei.com> - 10.3.1-38 +- Type:Backport +- ID:NA +- SUG:NA +- DESC: Fix CVE-2023-4039. + +* Wed Jun 28 2023 dingguangya <dingguangya1@huawei.com> - 10.3.1-37 +- Type:Spec +- ID:NA +- SUG:NA +- DESC: Sync patch from openeuler/gcc + +* Mon Jun 19 2023 dingguangya <dingguangya1@huawei.com> - 10.3.1-36 +- Type:Spec +- ID:NA +- SUG:NA +- DESC: Sync patch from openeuler/gcc + +* Wed Jun 14 2023 Wang Ding <wangding16@huawei.com> - 10.3.1-35 +- Type:Spec +- ID:NA +- SUG:NA +- DESC: To resolve the spec 548 fluctuation problem, revert GCC commit. + +* Fri Jun 9 2023 Wang Ding <wangding16@huawei.com> - 10.3.1-34 +- Type:Sync +- ID:NA +- SUG:NA +- DESC:Add PGO kernel option to support PGO kernel + +* Fri Jun 9 2023 huangxiaoquan <huangxiaoquan1@huawei.com> - 10.3.1-33 +- Type:Sync +- ID:NA +- SUG:NA +- DESC:Sync patch from openeuler/gcc + +* Thu Jun 8 2023 huangxiaoquan <huangxiaoquan1@huawei.com> - 10.3.1-32 +- Type:Sync +- ID:NA +- SUG:NA +- DESC:Sync patch from openeuler/gcc + +* Sat Jun 3 2023 Wang Ding <wangding16@huawei.com> - 10.3.1-31 +- Type:Sync +- ID:NA +- SUG:NA +- DESC:Revert patch97 and correct the incorrect patch number + +* Fri Jun 2 2023 Wang Ding <wangding16@huawei.com> - 10.3.1-30 +- Type:Sync +- ID:NA +- SUG:NA +- DESC:Sync patch from openeuler/gcc + +* Wed May 24 2023 liyancheng <412998149@qq.com> - 10.3.1-29 +- Type:Revert +- ID:NA +- SUG:NA +- DESC:Revert patch89 + The glibc version of oe-22.03 is 2.34, so revert it + +* Mon May 22 2023 huangxiaoquan <huangxiaoquan1@huawei.com> - 10.3.1-28 +- Type:Sync +- ID:NA +- SUG:NA +- DESC:Sync patch from openeuler/gcc + +* Wed Apr 12 2023 huangxiaoquan <huangxiaoquan1@huawei.com> - 10.3.1-27 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:enable isl and add --with-isl + +* Fri Mar 24 2023 huangxiaoquan <huangxiaoquan1@huawei.com> - 10.3.1-26 +- Type:SPEC +- ID:NA +- SUG:NA +- DESC:Enable-languages uses variables + +* Mon Mar 20 2023 huangxiaoquan <huangxiaoquan1@huawei.com> - 10.3.1-25 +- Type:Revert +- ID:NA +- SUG:NA +- DESC:Revert without pie option + +* Thu Mar 9 2023 huangxiaoquan <huangxiaoquan1@huawei.com> - 10.3.1-24 +- Type:Fix +- ID:NA +- SUG:NA +- DESC:Add pie and delete rpath in libgfortran + +* Sun Feb 26 2023 huitailang <804544223@qq.com> - 10.3.1-23 +- Type:Sync +- ID:NA +- SUG:NA +- DESC:Sync patch from openeuler/gcc + Fix sysroot option once processed. + +* Tue Jan 10 2023 liyancheng <412998149@qq.com> - 10.3.1-22 +- Type:Sync +- ID:NA +- SUG:NA +- DESC:Sync patch from openeuler/gcc + Fix conflict with glibc 2.36. + +* Fri Dec 30 2022 Xiong Zhou <xiongzhou4@huawei.com> - 10.3.1-21 +- Type:Sync +- ID:NA +- SUG:NA +- DESC:Sync patch from openeuler/gcc + Fix typo in tree-ssa-reassoc.c. + +* Fri Dec 23 2022 benniaobufeijiushiji <linda7@huawei.com> - 10.3.1-20 +- Type:Sync +- ID:NA +- SUG:NA +- DESC:Sync patch from openeuler/gcc + Bugfix for loop-distribution, semi-relayout and mull64. + +* Mon Dec 19 2022 liyancheng <412998149@qq.com> - 10.3.1-19 +- Type:Fix +- ID:NA +- SUG:NA +- DESC:Delete rpath in liblsan,libasan,libubsan,libtsan + +* Thu Dec 8 2022 liyancheng <412998149@qq.com> - 10.3.1-18 +- Type:Sync +- ID:NA +- SUG:NA +- DESC:Sync patch from openeuler/gcc, fix wrong date + +* Thu Dec 1 2022 benniaobufeijiushiji <linda7@huawei.com> - 10.3.1-17 +- Type:Sync +- ID:NA +- SUG:NA +- DESC:Sync patch from openeuler/gcc + +* Fri Sep 16 2022 eastb233 <xiezhiheng@huawei.com> - 10.3.1-16 +- Type:Sync +- ID:NA +- SUG:NA +- DESC:Sync patch from openeuler/gcc + +* Thu Sep 8 2022 benniaobufeijiushiji <linda7@huawei.com> - 10.3.1-15 +- Type:Sync +- ID:NA +- SUG:NA +- DESC:Sync patch from openeuler/gcc + +* Tue Aug 16 2022 benniaobufeijiushiji <linda7@huawei.com> - 10.3.1-14 +- Type:Revert +- ID:NA +- SUG:NA +- DESC:Remove 2 unnecessary patches + +* Mon Aug 8 2022 benniaobufeijiushiji <linda7@huawei.com> - 10.3.1-13 +- Type:Sync +- ID:NA +- SUG:NA +- DESC:Sync patch from openeuler/gcc + +* Fri Jul 08 2022 zhaomengmeng <zhaomengmeng@kylinos.cn> - 10.3.1-12 +- Type:SPEC +- ID:NA +- SUG:NA +- DESC:Enable libgccjit + +* Fri May 6 2022 liyancheng <412998149@qq.com> - 10.3.1-11 +- Type:Sync +- ID:NA +- SUG:NA +- DESC:Sync patch from openeuler/gcc + +* Tue Mar 22 2022 benniaobufeijiushiji <linda7@huawei.com> - 10.3.1-10 +- Type:Sync +- ID:NA +- SUG:NA +- DESC:Sync patch from openeuler/gcc + +* Wed Mar 2 2022 benniaobufeijiushiji <linda7@huawei.com> - 10.3.1-9 +- Type:Sync +- ID:NA +- SUG:NA +- DESC:Sync patch from openeuler/gcc + +* Tue Mar 1 2022 benniaobufeijiushiji <linda7@huawei.com> - 10.3.1-8 +- Type:SPEC +- ID:NA +- SUG:NA +- DESC:Remove date in release + +* Wed Feb 23 2022 benniaobufeijiushiji <linda7@huawei.com> - 10.3.1-20220223.7 +- Type:Sync +- ID:NA +- SUG:NA +- DESC:Sync patch from openeuler/gcc + +* Wed Jan 05 2022 eastb233 <xiezhiheng@huawei.com> - 10.3.1-20220105.6 +- Type:SPEC +- ID:NA +- SUG:NA +- DESC:Return the ownership of gdb/auto-load folder to gdb-headless + +* Tue Sep 14 2021 eastb233 <xiezhiheng@huawei.com> - 10.3.1-20210914.5 +- Type:Sync +- ID:NA +- SUG:NA +- DESC:Sync patch from openeuler/gcc + +* Fri Aug 27 2021 eastb233 <xiezhiheng@huawei.com> - 10.3.1-20210827.4 +- Type:RISC-V +- ID:NA +- SUG:NA +- DESC:Adapts to the RISC-V backend construction + +* Thu Aug 19 2021 eastb233 <xiezhiheng@huawei.com> - 10.3.1-20210819.3 +- Type:Sync +- ID:NA +- SUG:NA +- DESC:Sync patch from openeuler/gcc + +* Wed Jul 28 2021 eastb233 <xiezhiheng@huawei.com> - 10.3.0-20210728.2 +- Type:Sync +- ID:NA +- SUG:NA +- DESC:Sync patch from openeuler/gcc + +* Tue Jul 27 2021 eastb233 <xiezhiheng@huawei.com> - 10.3.0-20210727.1 +- Type:Init +- ID:NA +- SUG:NA +- DESC:Init GCC 10.3.0 repository @@ -0,0 +1 @@ +443c15b92614a3ce8f22e3b24ca2226a gcc-10.3.0.tar.xz |