diff --git Makefile.def Makefile.def index 7c33a3b..b9c1e0d 100644 --- Makefile.def +++ Makefile.def @@ -46,7 +46,8 @@ host_modules= { module= fixincludes; bootstrap=true; host_modules= { module= flex; no_check_cross= true; }; host_modules= { module= gas; bootstrap=true; }; host_modules= { module= gcc; bootstrap=true; - extra_make_flags="$(EXTRA_GCC_FLAGS)"; }; + extra_make_flags="$(EXTRA_GCC_FLAGS)"; + extra_configure_flags='--enable-pie-tools=@enable_pie_tools@'; }; host_modules= { module= gmp; lib_path=.libs; bootstrap=true; // Work around in-tree gmp configure bug with missing flex. extra_configure_flags='--disable-shared LEX="touch lex.yy.c"'; @@ -656,6 +657,7 @@ languages = { language=brig; gcc-check-target=check-brig; lib-check-target=check-target-libhsail-rt; }; languages = { language=d; gcc-check-target=check-d; lib-check-target=check-target-libphobos; }; +languages = { language=jit; gcc-check-target=check-jit; }; // Toplevel bootstrap bootstrap_stage = { id=1 ; }; diff --git Makefile.in Makefile.in index 20cbbe2..ecf48c8 100644 --- Makefile.in +++ Makefile.in @@ -112,6 +112,9 @@ GCC_SHLIB_SUBDIR = @GCC_SHLIB_SUBDIR@ # If the build should make suitable code for shared host resources. host_shared = @host_shared@ +# If we should build compilers and supporting tools as PIE. +enable_pie_tools = @enable_pie_tools@ + # Build programs are put under this directory. BUILD_SUBDIR = @build_subdir@ # This is set by the configure script to the arguments to use when configuring @@ -11581,7 +11584,7 @@ configure-gcc: $$s/$$module_srcdir/configure \ --srcdir=$${topdir}/$$module_srcdir \ $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ - --target=${target_alias} \ + --target=${target_alias} --enable-pie-tools=@enable_pie_tools@ \ || exit 1 @endif gcc @@ -11616,7 +11619,8 @@ configure-stage1-gcc: $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ --target=${target_alias} \ \ - $(STAGE1_CONFIGURE_FLAGS) + $(STAGE1_CONFIGURE_FLAGS) \ + --enable-pie-tools=@enable_pie_tools@ @endif gcc-bootstrap .PHONY: configure-stage2-gcc maybe-configure-stage2-gcc @@ -11649,7 +11653,8 @@ configure-stage2-gcc: $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ --target=${target_alias} \ --with-build-libsubdir=$(HOST_SUBDIR) \ - $(STAGE2_CONFIGURE_FLAGS) + $(STAGE2_CONFIGURE_FLAGS) \ + --enable-pie-tools=@enable_pie_tools@ @endif gcc-bootstrap .PHONY: configure-stage3-gcc maybe-configure-stage3-gcc @@ -11682,7 +11687,8 @@ configure-stage3-gcc: $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ --target=${target_alias} \ --with-build-libsubdir=$(HOST_SUBDIR) \ - $(STAGE3_CONFIGURE_FLAGS) + $(STAGE3_CONFIGURE_FLAGS) \ + --enable-pie-tools=@enable_pie_tools@ @endif gcc-bootstrap .PHONY: configure-stage4-gcc maybe-configure-stage4-gcc @@ -11715,7 +11721,8 @@ configure-stage4-gcc: $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ --target=${target_alias} \ --with-build-libsubdir=$(HOST_SUBDIR) \ - $(STAGE4_CONFIGURE_FLAGS) + $(STAGE4_CONFIGURE_FLAGS) \ + --enable-pie-tools=@enable_pie_tools@ @endif gcc-bootstrap .PHONY: configure-stageprofile-gcc maybe-configure-stageprofile-gcc @@ -11748,7 +11755,8 @@ configure-stageprofile-gcc: $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ --target=${target_alias} \ --with-build-libsubdir=$(HOST_SUBDIR) \ - $(STAGEprofile_CONFIGURE_FLAGS) + $(STAGEprofile_CONFIGURE_FLAGS) \ + --enable-pie-tools=@enable_pie_tools@ @endif gcc-bootstrap .PHONY: configure-stagetrain-gcc maybe-configure-stagetrain-gcc @@ -11781,7 +11789,8 @@ configure-stagetrain-gcc: $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ --target=${target_alias} \ --with-build-libsubdir=$(HOST_SUBDIR) \ - $(STAGEtrain_CONFIGURE_FLAGS) + $(STAGEtrain_CONFIGURE_FLAGS) \ + --enable-pie-tools=@enable_pie_tools@ @endif gcc-bootstrap .PHONY: configure-stagefeedback-gcc maybe-configure-stagefeedback-gcc @@ -11814,7 +11823,8 @@ configure-stagefeedback-gcc: $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ --target=${target_alias} \ --with-build-libsubdir=$(HOST_SUBDIR) \ - $(STAGEfeedback_CONFIGURE_FLAGS) + $(STAGEfeedback_CONFIGURE_FLAGS) \ + --enable-pie-tools=@enable_pie_tools@ @endif gcc-bootstrap .PHONY: configure-stageautoprofile-gcc maybe-configure-stageautoprofile-gcc @@ -11847,7 +11857,8 @@ configure-stageautoprofile-gcc: $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ --target=${target_alias} \ --with-build-libsubdir=$(HOST_SUBDIR) \ - $(STAGEautoprofile_CONFIGURE_FLAGS) + $(STAGEautoprofile_CONFIGURE_FLAGS) \ + --enable-pie-tools=@enable_pie_tools@ @endif gcc-bootstrap .PHONY: configure-stageautofeedback-gcc maybe-configure-stageautofeedback-gcc @@ -11880,7 +11891,8 @@ configure-stageautofeedback-gcc: $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ --target=${target_alias} \ --with-build-libsubdir=$(HOST_SUBDIR) \ - $(STAGEautofeedback_CONFIGURE_FLAGS) + $(STAGEautofeedback_CONFIGURE_FLAGS) \ + --enable-pie-tools=@enable_pie_tools@ @endif gcc-bootstrap @@ -57074,6 +57086,14 @@ check-gcc-d: (cd gcc && $(MAKE) $(GCC_FLAGS_TO_PASS) check-d); check-d: check-gcc-d check-target-libphobos +.PHONY: check-gcc-jit check-jit +check-gcc-jit: + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(HOST_EXPORTS) \ + (cd gcc && $(MAKE) $(GCC_FLAGS_TO_PASS) check-jit); +check-jit: check-gcc-jit + # The gcc part of install-no-fixedincludes, which relies on an intimate # knowledge of how a number of gcc internal targets (inter)operate. Delegate. diff --git Makefile.tpl Makefile.tpl index 9adf4f9..329d927 100644 --- Makefile.tpl +++ Makefile.tpl @@ -115,6 +115,9 @@ GCC_SHLIB_SUBDIR = @GCC_SHLIB_SUBDIR@ # If the build should make suitable code for shared host resources. host_shared = @host_shared@ +# If we should build compilers and supporting tools as PIE. +enable_pie_tools = @enable_pie_tools@ + # Build programs are put under this directory. BUILD_SUBDIR = @build_subdir@ # This is set by the configure script to the arguments to use when configuring diff --git README.md README.md new file mode 100644 index 0000000..03bb0ba --- /dev/null +++ README.md @@ -0,0 +1,28 @@ +# This is a branch of GCC 11.4 with experimental support for AArch64 (Arm64) on Darwin. + +The branch is recommended for (and has been tested on) powerpc, i686, x86_64 and aarch64 Darwin from Darwin9 (Mac OSX 10.5) through Darwin21 (macOS 12) (for architectures relevant to each version). The branch has also been tested to build cross-compilers between x86_64 and aarch64 and on aarch64-linux-gnu without regressions. + +The branch contains a number of back-ports from GCC master that are required for Arm64 support and recommended for other Darwin architectures. _Some of these are not suitable for application to the upstream branch and therefore will only be available on the Darwin-specific branch_. + +The support for Aarch64 (Arm64) remains experimental but is adequate now for many programs (and self-bootstrap). + +Please see README for general information on the GCC sources. + +Please see the GCC 11.4 release documentation for the implementation status of core language features. + +Please see gcc/config/aarch64/darwinpcs.md for a description of the macOS AArch64 (Arm64) ABI support. + +Please report issues for this branch to: https://github.com/iains/gcc-11-branch/issues + +**_The current release is GCC-11.4-darwin-r0. (May 2023)_** + +This release: + * Includes all upstream fixes. + * All fixes in previous releases and on the GCC-12 branch. + * An adjustment to the handling of the configuration for -stdlib and the paths used. + - `--with-gxx-libcxx-include-dir=no` will disable the stdlib option on Darwin platforms that otherwise default to providing the option (10.8+). + - If the option is unset on those platforms, the libc++ include path will be configured to internal to the compiler (in the same manner as libstdc++) allowing distributions to package a self-contained solution. + +Thanks to contributors and testers. + +Iain Sandoe, May 2023 diff --git c++tools/resolver.cc c++tools/resolver.cc index ef08de5..298a700 100644 --- c++tools/resolver.cc +++ c++tools/resolver.cc @@ -307,3 +307,14 @@ module_resolver::IncludeTranslateRequest (Cody::Server *s, Cody::Flags, return 0; } +/* This handles a client notification to the server that a CMI has been + produced for a module. For this simplified server, we just accept + the transaction and respond with "OK". */ + +int +module_resolver::ModuleCompiledRequest (Cody::Server *s, Cody::Flags, + std::string &) +{ + s->OKResponse(); + return 0; +} diff --git c++tools/resolver.h c++tools/resolver.h index a9547bf..ac4caf0 100644 --- c++tools/resolver.h +++ c++tools/resolver.h @@ -96,6 +96,10 @@ public: std::string &include) override; + using parent::ModuleCompiledRequest; + virtual int ModuleCompiledRequest (Cody::Server *s, Cody::Flags Flags, + std::string &Module) override; + private: using parent::GetCMISuffix; virtual char const *GetCMISuffix () override; diff --git c++tools/server.cc c++tools/server.cc index ebc1efb..3a52fec 100644 --- c++tools/server.cc +++ c++tools/server.cc @@ -360,7 +360,11 @@ accept_from (char *arg ATTRIBUTE_UNUSED) hints.ai_next = NULL; struct addrinfo *addrs = NULL; - if (int e = getaddrinfo (slash == arg ? NULL : arg, "0", &hints, &addrs)) + /* getaddrinfo requires either hostname or servname to be non-null, so that we must + set a port number (to cover the case that the string passed contains just /NN). + Use an arbitrary in-range port number, but avoiding "0" which triggers a bug on + some BSD variants. */ + if (int e = getaddrinfo (slash == arg ? NULL : arg, "1", &hints, &addrs)) { noisy ("cannot resolve '%s': %s", arg, gai_strerror (e)); ok = false; diff --git config/gcc-plugin.m4 config/gcc-plugin.m4 index 8f27871..7ee342f 100644 --- config/gcc-plugin.m4 +++ config/gcc-plugin.m4 @@ -91,14 +91,18 @@ AC_DEFUN([GCC_ENABLE_PLUGINS], # Check that we can build shared objects with -fPIC -shared saved_LDFLAGS="$LDFLAGS" saved_CFLAGS="$CFLAGS" + saved_CXXFLAGS="$CXXFLAGS" case "${host}" in *-*-darwin*) CFLAGS=`echo $CFLAGS | sed s/-mdynamic-no-pic//g` CFLAGS="$CFLAGS -fPIC" + CXXFLAGS=`echo $CXXFLAGS | sed s/-mdynamic-no-pic//g` + CXXFLAGS="$CXXFLAGS -fPIC" LDFLAGS="$LDFLAGS -shared -undefined dynamic_lookup" ;; *) CFLAGS="$CFLAGS -fPIC" + CXXFLAGS="$CXXFLAGS -fPIC" LDFLAGS="$LDFLAGS -fPIC -shared" ;; esac @@ -113,6 +117,7 @@ AC_DEFUN([GCC_ENABLE_PLUGINS], fi LDFLAGS="$saved_LDFLAGS" CFLAGS="$saved_CFLAGS" + CXXFLAGS="$saved_CXXFLAGS" # If plugin support had been requested but not available, fail. if test x"$enable_plugin" = x"no" ; then diff --git config/mh-darwin config/mh-darwin index b72835a..bb41127 100644 --- config/mh-darwin +++ config/mh-darwin @@ -11,7 +11,8 @@ # non-bootstrapped compiler), later stages will be built by GCC which supports # the required flags. -# We cannot use mdynamic-no-pic when building shared host resources. +# We cannot use mdynamic-no-pic when building shared host resources, or for PIE +# tool executables, which also enables host-shared. ifeq (${host_shared},no) BOOTSTRAP_TOOL_CAN_USE_MDYNAMIC_NO_PIC := $(shell \ diff --git configure configure index 74775c3..a1a861b 100755 --- configure +++ configure @@ -682,6 +682,7 @@ get_gcc_base_ver extra_host_zlib_configure_flags extra_host_libiberty_configure_flags stage1_languages +enable_pie_tools host_shared extra_linker_plugin_flags extra_linker_plugin_configure_flags @@ -823,6 +824,7 @@ enable_lto enable_linker_plugin_configure_flags enable_linker_plugin_flags enable_host_shared +enable_pie_tools enable_stage1_languages enable_objc_gc with_target_bdw_gc @@ -1544,6 +1546,8 @@ Optional Features: additional flags for configuring and building linker plugins [none] --enable-host-shared build host code as shared libraries + --enable-pie-tools build Position Independent Executables for the + compilers and other tools --enable-stage1-languages[=all] choose additional languages to build during stage1. Mostly useful for compiler development @@ -8041,6 +8045,20 @@ else fi fi +case $target in + *-darwin2* | *-darwin1[56789]*) + # For these versions, we default to using embedded rpaths. + if test "x$enable_darwin_at_rpath" != "xno"; then + poststage1_ldflags="$poststage1_ldflags -nodefaultrpaths" + fi + ;; + *-darwin*) + # For these versions, we only use embedded rpaths on demand. + if test "x$enable_darwin_at_rpath" = "xyes"; then + poststage1_ldflags="$poststage1_ldflags -nodefaultrpaths" + fi + ;; +esac # GCC GRAPHITE dependency isl. @@ -8294,6 +8312,42 @@ else fi +# Check whether --enable-pie-tools was given. +# Checked early because it can affect host make fragments. +# Check whether --enable-pie-tools was given. +if test "${enable_pie_tools+set}" = set; then : + enableval=$enable_pie_tools; enable_pie_tools=$enableval + case $target in + aarch64-*-darwin1[1-9]*) + if test x$enable_pie_tools != xyes ; then + echo configure.ac: warning: aarch64-darwin must use PIE, pie-tools setting ignored. 1>&2 + enable_pie_tools=yes + host_shared=yes + fi ;; + *) ;; + esac +else + case $target in + # PIE is the default for macOS 10.7+ so reflect that in the configure. + # However, we build 32b toolchains mdynamic-no-pic by default which is + # not compatible with PIE. + x86_64-*-darwin1[1-9]* | *-*-darwin2*) enable_pie_tools=yes ;; + *) enable_pie_tools=no ;; + esac +fi + + +case $target in + *-*-darwin*) + if test x$enable_pie_tools = xyes && test x$host_shared != xyes ; then + echo configure.ac: warning: for Darwin PIE requires PIC code, switching host-shared on 1>&2 + host_shared=yes + fi ;; + *) ;; +esac + + + # By default, C and C++ are the only stage 1 languages. stage1_languages=,c, @@ -9911,8 +9965,6 @@ done - - # Generate default definitions for YACC, M4, LEX and other programs that run # on the build machine. These are used if the Makefile can't locate these # programs in objdir. diff --git configure.ac configure.ac index 3613860..1e613e3 100644 --- configure.ac +++ configure.ac @@ -1781,6 +1781,20 @@ AC_ARG_WITH(boot-ldflags, if test "$poststage1_libs" = ""; then poststage1_ldflags="-static-libstdc++ -static-libgcc" fi]) +case $target in + *-darwin2* | *-darwin1[[56789]]*) + # For these versions, we default to using embedded rpaths. + if test "x$enable_darwin_at_rpath" != "xno"; then + poststage1_ldflags="$poststage1_ldflags -nodefaultrpaths" + fi + ;; + *-darwin*) + # For these versions, we only use embedded rpaths on demand. + if test "x$enable_darwin_at_rpath" = "xyes"; then + poststage1_ldflags="$poststage1_ldflags -nodefaultrpaths" + fi + ;; +esac AC_SUBST(poststage1_ldflags) # GCC GRAPHITE dependency isl. @@ -1885,7 +1899,41 @@ AC_ARG_ENABLE(host-shared, x86_64-*-darwin* | aarch64-*-darwin*) host_shared=yes ;; *) host_shared=no ;; esac]) + +# Check whether --enable-pie-tools was given. +# Checked early because it can affect host make fragments. +AC_ARG_ENABLE(pie-tools, +[AS_HELP_STRING([--enable-pie-tools], + [build Position Independent Executables for the compilers and other tools])], +[enable_pie_tools=$enableval + case $target in + aarch64-*-darwin1[[1-9]]*) + if test x$enable_pie_tools != xyes ; then + echo configure.ac: warning: aarch64-darwin must use PIE, pie-tools setting ignored. 1>&2 + enable_pie_tools=yes + host_shared=yes + fi ;; + *) ;; + esac], +[case $target in + # PIE is the default for macOS 10.7+ so reflect that in the configure. + # However, we build 32b toolchains mdynamic-no-pic by default which is + # not compatible with PIE. + x86_64-*-darwin1[[1-9]]* | *-*-darwin2*) enable_pie_tools=yes ;; + *) enable_pie_tools=no ;; + esac]) + +case $target in + *-*-darwin*) + if test x$enable_pie_tools = xyes && test x$host_shared != xyes ; then + echo configure.ac: warning: for Darwin PIE requires PIC code, switching host-shared on 1>&2 + host_shared=yes + fi ;; + *) ;; +esac + AC_SUBST(host_shared) +AC_SUBST([enable_pie_tools]) # By default, C and C++ are the only stage 1 languages. stage1_languages=,c, diff --git fixincludes/configure fixincludes/configure index 6e2d67b..b3bca66 100755 --- fixincludes/configure +++ fixincludes/configure @@ -2644,7 +2644,7 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # _LT_DARWIN_LINKER_FEATURES # -------------------------- -# Checks for linker and compiler features on darwin +# Checks for linker and compiler features on Darwin / macOS / iOS # _LT_SYS_MODULE_PATH_AIX diff --git gcc/Makefile.in gcc/Makefile.in index 7bfd6ce..012465f 100644 --- gcc/Makefile.in +++ gcc/Makefile.in @@ -270,11 +270,15 @@ COMPILER += $(CET_HOST_FLAGS) NO_PIE_CFLAGS = @NO_PIE_CFLAGS@ NO_PIE_FLAG = @NO_PIE_FLAG@ -# We don't want to compile the compilers with -fPIE, it make PCH fail. +ifneq (@enable_pie_tools@,yes) +# Build and link the compilers and tools without PIE. COMPILER += $(NO_PIE_CFLAGS) - -# Link with -no-pie since we compile the compiler with -fno-PIE. LINKER += $(NO_PIE_FLAG) +else +# FIXME these need to be configured. +COMPILER += -fPIE +LINKER += -pie +endif # Like LINKER, but use a mutex for serializing front end links. ifeq (@DO_LINK_MUTEX@,true) @@ -407,6 +411,7 @@ ifeq ($(enable_plugin),yes) endif enable_host_shared = @enable_host_shared@ +enable_default_pie = @enable_default_pie@ enable_as_accelerator = @enable_as_accelerator@ @@ -1145,6 +1150,8 @@ LANG_MAKEFRAGS = @all_lang_makefrags@ # Used by gcc/jit/Make-lang.in LD_VERSION_SCRIPT_OPTION = @ld_version_script_option@ LD_SONAME_OPTION = @ld_soname_option@ +@ENABLE_DARWIN_AT_RPATH_TRUE@DARWIN_RPATH = @rpath +@ENABLE_DARWIN_AT_RPATH_FALSE@DARWIN_RPATH = ${libdir} # Flags to pass to recursive makes. # CC is set by configure. @@ -1916,9 +1923,12 @@ cs-tconfig.h: Makefile $(SHELL) $(srcdir)/mkconfig.sh tconfig.h cs-tm.h: Makefile - TARGET_CPU_DEFAULT="$(target_cpu_default)" \ - HEADERS="$(tm_include_list)" DEFINES="$(tm_defines)" \ - $(SHELL) $(srcdir)/mkconfig.sh tm.h +@ENABLE_DARWIN_AT_RPATH_FALSE@ TARGET_CPU_DEFAULT="$(target_cpu_default)" \ +@ENABLE_DARWIN_AT_RPATH_FALSE@ HEADERS="$(tm_include_list)" DEFINES="$(tm_defines)" \ +@ENABLE_DARWIN_AT_RPATH_FALSE@ $(SHELL) $(srcdir)/mkconfig.sh tm.h +@ENABLE_DARWIN_AT_RPATH_TRUE@ TARGET_CPU_DEFAULT="$(target_cpu_default)" \ +@ENABLE_DARWIN_AT_RPATH_TRUE@ HEADERS="$(tm_include_list)" DEFINES="$(tm_defines) DARWIN_AT_RPATH=1" \ +@ENABLE_DARWIN_AT_RPATH_TRUE@ $(SHELL) $(srcdir)/mkconfig.sh tm.h cs-tm_p.h: Makefile TARGET_CPU_DEFAULT="" \ @@ -4084,6 +4094,9 @@ site.exp: ./config.status Makefile echo "set COMPAT_OPTIONS \"$(COMPAT_OPTIONS)\"" >> ./site.tmp; \ else true; \ fi + @if test "x@enable_darwin_at_rpath@" = "xyes" ; then \ + echo "set ENABLE_DARWIN_AT_RPATH 1" >> ./site.tmp; \ + fi @echo "## All variables above are generated by configure. Do Not Edit ##" >> ./site.tmp @cat ./site.tmp > site.exp @cat site.bak | sed \ diff --git gcc/aclocal.m4 gcc/aclocal.m4 index 6be36df..126e09b 100644 --- gcc/aclocal.m4 +++ gcc/aclocal.m4 @@ -12,6 +12,56 @@ # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997-2017 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) 2006-2017 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($@)]) + m4_include([../libtool.m4]) m4_include([../ltoptions.m4]) m4_include([../ltsugar.m4]) diff --git gcc/ada/gcc-interface/Make-lang.in gcc/ada/gcc-interface/Make-lang.in index d88c354..b98b7fe 100644 --- gcc/ada/gcc-interface/Make-lang.in +++ gcc/ada/gcc-interface/Make-lang.in @@ -655,6 +655,14 @@ endif # For unwind-pe.h CFLAGS-ada/raise-gcc.o += -I$(srcdir)/../libgcc -DEH_MECHANISM_$(EH_MECHANISM) +# Under aarch64 darwin, we need to include the iOS signal trampoline. + +ifeq ($(strip $(filter-out aarch64 arm64 darwin%,$(host_cpu) $(host_os))),) + EXTRA_HOST_OBJS=ada/sigtramp-ios.o +else + EXTRA_HOST_OBJS = +endif + ada/libgnat/s-excmac.o: ada/libgnat/s-excmac.ads ada/libgnat/s-excmac.adb ada/libgnat/s-excmac.ads: $(srcdir)/ada/libgnat/s-excmac__$(EH_MECHANISM).ads @@ -668,16 +676,16 @@ ada/libgnat/s-excmac.adb: $(srcdir)/ada/libgnat/s-excmac__$(EH_MECHANISM).adb # Needs to be built with CC=gcc # Since the RTL should be built with the latest compiler, remove the # stamp target in the parent directory whenever gnat1 is rebuilt -gnat1$(exeext): $(TARGET_ADA_SRCS) $(GNAT1_OBJS) $(ADA_BACKEND) libcommon-target.a \ - $(LIBDEPS) $(ada.prev) +gnat1$(exeext): $(TARGET_ADA_SRCS) $(GNAT1_OBJS) $(ADA_BACKEND) $(EXTRA_HOST_OBJS) libcommon-target.a \ + $(EXTRA_HOST_OBJS) $(LIBDEPS) $(ada.prev) @$(call LINK_PROGRESS,$(INDEX.ada),start) - +$(GCC_LLINK) -o $@ $(GNAT1_OBJS) $(ADA_BACKEND) \ + +$(GCC_LLINK) -o $@ $(GNAT1_OBJS) $(ADA_BACKEND) $(EXTRA_HOST_OBJS) \ libcommon-target.a $(LIBS) $(SYSLIBS) $(BACKENDLIBS) $(CFLAGS) $(RM) stamp-gnatlib2-rts stamp-tools @$(call LINK_PROGRESS,$(INDEX.ada),end) -gnatbind$(exeext): ada/b_gnatb.o $(CONFIG_H) $(GNATBIND_OBJS) ggc-none.o libcommon-target.a $(LIBDEPS) - +$(GCC_LINK) -o $@ ada/b_gnatb.o $(GNATBIND_OBJS) ggc-none.o libcommon-target.a $(LIBS) $(SYSLIBS) $(CFLAGS) +gnatbind$(exeext): ada/b_gnatb.o $(CONFIG_H) $(GNATBIND_OBJS) $(EXTRA_HOST_OBJS) ggc-none.o libcommon-target.a $(LIBDEPS) + +$(GCC_LINK) -o $@ ada/b_gnatb.o $(GNATBIND_OBJS) $(EXTRA_HOST_OBJS) ggc-none.o libcommon-target.a $(LIBS) $(SYSLIBS) $(CFLAGS) # use target-gcc target-gnatmake target-gnatbind target-gnatlink gnattools: $(GCC_PARTS) $(CONFIG_H) prefix.o force diff --git gcc/ada/gcc-interface/Makefile.in gcc/ada/gcc-interface/Makefile.in index 6cc9503..3ac49ef 100644 --- gcc/ada/gcc-interface/Makefile.in +++ gcc/ada/gcc-interface/Makefile.in @@ -793,20 +793,23 @@ gnatlib-shared-darwin: $(GNATRTL_NONTASKING_OBJS) $(LIBGNAT_OBJS) \ $(SO_OPTS) \ -Wl,-install_name,@rpath/libgnat$(hyphen)$(LIBRARY_VERSION)$(soext) \ - $(MISCLIB) + -nodefaultrpaths -Wl,-rpath,@loader_path/,-rpath,@loader_path/.. \ + -Wl,-rpath,@loader_path/../../../../ $(MISCLIB) cd $(RTSDIR); `echo "$(GCC_FOR_TARGET)" \ | sed -e 's,\./xgcc,../../xgcc,' -e 's,-B\./,-B../../,'` -dynamiclib $(PICFLAG_FOR_TARGET) \ -o libgnarl$(hyphen)$(LIBRARY_VERSION)$(soext) \ $(GNATRTL_TASKING_OBJS) \ $(SO_OPTS) \ -Wl,-install_name,@rpath/libgnarl$(hyphen)$(LIBRARY_VERSION)$(soext) \ + -nodefaultrpaths -Wl,-rpath,@loader_path/,-rpath,@loader_path/.. \ + -Wl,-rpath,@loader_path/../../../../ \ $(THREADSLIB) -Wl,libgnat$(hyphen)$(LIBRARY_VERSION)$(soext) cd $(RTSDIR); $(LN_S) libgnat$(hyphen)$(LIBRARY_VERSION)$(soext) \ libgnat$(soext) cd $(RTSDIR); $(LN_S) libgnarl$(hyphen)$(LIBRARY_VERSION)$(soext) \ libgnarl$(soext) - cd $(RTSDIR); dsymutil libgnat$(hyphen)$(LIBRARY_VERSION)$(soext) - cd $(RTSDIR); dsymutil libgnarl$(hyphen)$(LIBRARY_VERSION)$(soext) + cd $(RTSDIR); $(DSYMUTIL_FOR_TARGET) libgnat$(hyphen)$(LIBRARY_VERSION)$(soext) + cd $(RTSDIR); $(DSYMUTIL_FOR_TARGET) libgnarl$(hyphen)$(LIBRARY_VERSION)$(soext) gnatlib-shared: $(MAKE) $(FLAGS_TO_PASS) \ diff --git gcc/ada/gcc-interface/decl.c gcc/ada/gcc-interface/decl.c index c27a4eb..bc3757c 100644 --- gcc/ada/gcc-interface/decl.c +++ gcc/ada/gcc-interface/decl.c @@ -170,7 +170,7 @@ gt_pch_nx (Entity_Id &) void gt_pch_nx (Entity_Id *x, gt_pointer_operator op, void *cookie) { - op (x, cookie); + op (x, NULL, cookie); } struct dummy_type_hasher : ggc_cache_ptr_hash diff --git gcc/ada/sigtramp-ios.c gcc/ada/sigtramp-ios.c index 7715ddb..f95e6ef 100644 --- gcc/ada/sigtramp-ios.c +++ gcc/ada/sigtramp-ios.c @@ -71,6 +71,10 @@ /* sigtramp stub providing unwind info for common registers. */ +#if defined(__cplusplus) +extern "C" { +#endif + extern void __gnat_sigtramp_common (int signo, void *siginfo, void *sigcontext, __sigtramphandler_t * handler); @@ -87,6 +91,10 @@ void __gnat_sigtramp (int signo, void *si, void *ucontext, __gnat_sigtramp_common (signo, si, mcontext, handler); } +#if defined(__cplusplus) +} +#endif + /* asm string construction helpers. */ #define STR(TEXT) #TEXT diff --git gcc/builtins.def gcc/builtins.def index b67649a..0df16ab 100644 --- gcc/builtins.def +++ gcc/builtins.def @@ -954,6 +954,8 @@ DEF_BUILTIN_STUB (BUILT_IN_ADJUST_TRAMPOLINE, "__builtin_adjust_trampoline") DEF_BUILTIN_STUB (BUILT_IN_INIT_DESCRIPTOR, "__builtin_init_descriptor") DEF_BUILTIN_STUB (BUILT_IN_ADJUST_DESCRIPTOR, "__builtin_adjust_descriptor") DEF_BUILTIN_STUB (BUILT_IN_NONLOCAL_GOTO, "__builtin_nonlocal_goto") +DEF_BUILTIN_STUB (BUILT_IN_NESTED_PTR_CREATED, "__builtin_nested_func_ptr_created") +DEF_BUILTIN_STUB (BUILT_IN_NESTED_PTR_DELETED, "__builtin_nested_func_ptr_deleted") /* Implementing __builtin_setjmp. */ DEF_BUILTIN_STUB (BUILT_IN_SETJMP_SETUP, "__builtin_setjmp_setup") diff --git gcc/c-family/c-attribs.c gcc/c-family/c-attribs.c index cdf89d6..c3d3f46 100644 --- gcc/c-family/c-attribs.c +++ gcc/c-family/c-attribs.c @@ -121,6 +121,8 @@ static tree handle_pure_attribute (tree *, tree, tree, int, bool *); static tree handle_tm_attribute (tree *, tree, tree, int, bool *); static tree handle_tm_wrap_attribute (tree *, tree, tree, int, bool *); static tree handle_novops_attribute (tree *, tree, tree, int, bool *); +static tree handle_unavailable_attribute (tree *, tree, tree, int, + bool *); static tree handle_vector_size_attribute (tree *, tree, tree, int, bool *) ATTRIBUTE_NONNULL(3); static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *); @@ -404,6 +406,8 @@ const struct attribute_spec c_common_attribute_table[] = handle_novops_attribute, NULL }, { "deprecated", 0, 1, false, false, false, false, handle_deprecated_attribute, NULL }, + { "unavailable", 0, 1, false, false, false, false, + handle_unavailable_attribute, NULL }, { "vector_size", 1, 1, false, true, false, true, handle_vector_size_attribute, NULL }, { "visibility", 1, 1, false, false, false, false, @@ -4117,6 +4121,71 @@ handle_deprecated_attribute (tree *node, tree name, return NULL_TREE; } +/* Handle a "unavailable" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_unavailable_attribute (tree *node, tree name, + tree args, int flags, + bool *no_add_attrs) +{ + tree type = NULL_TREE; + int warn = 0; + tree what = NULL_TREE; + + if (!args) + *no_add_attrs = true; + else if (TREE_CODE (TREE_VALUE (args)) != STRING_CST) + { + error ("the message attached to % is not a string"); + *no_add_attrs = true; + } + + if (DECL_P (*node)) + { + tree decl = *node; + type = TREE_TYPE (decl); + + if (TREE_CODE (decl) == TYPE_DECL + || TREE_CODE (decl) == PARM_DECL + || VAR_OR_FUNCTION_DECL_P (decl) + || TREE_CODE (decl) == FIELD_DECL + || TREE_CODE (decl) == CONST_DECL + || objc_method_decl (TREE_CODE (decl))) + TREE_UNAVAILABLE (decl) = 1; + else + warn = 1; + } + else if (TYPE_P (*node)) + { + if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) + *node = build_variant_type_copy (*node); + TREE_UNAVAILABLE (*node) = 1; + type = *node; + } + else + warn = 1; + + if (warn) + { + *no_add_attrs = true; + if (type && TYPE_NAME (type)) + { + if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) + what = TYPE_NAME (*node); + else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && DECL_NAME (TYPE_NAME (type))) + what = DECL_NAME (TYPE_NAME (type)); + } + if (what) + warning (OPT_Wattributes, "%qE attribute ignored for %qE", name, what); + else + warning (OPT_Wattributes, "%qE attribute ignored", name); + } + + return NULL_TREE; +} + /* Return the "base" type from TYPE that is suitable to apply attribute vector_size to by stripping arrays, function types, etc. */ static tree diff --git gcc/c-family/c-opts.c gcc/c-family/c-opts.c index 6f001e0..193c584 100644 --- gcc/c-family/c-opts.c +++ gcc/c-family/c-opts.c @@ -852,9 +852,9 @@ c_common_post_options (const char **pfilename) else if (!flag_gnu89_inline && !flag_isoc99) error ("%<-fno-gnu89-inline%> is only supported in GNU99 or C99 mode"); - /* Default to ObjC sjlj exception handling if NeXT runtime. */ + /* Default to ObjC sjlj exception handling if NeXT runtime < v2. */ if (flag_objc_sjlj_exceptions < 0) - flag_objc_sjlj_exceptions = flag_next_runtime; + flag_objc_sjlj_exceptions = (flag_next_runtime && flag_objc_abi < 2); if (flag_objc_exceptions && !flag_objc_sjlj_exceptions) flag_exceptions = 1; @@ -1051,7 +1051,7 @@ c_common_post_options (const char **pfilename) if (flag_extern_tls_init) { - if (!TARGET_SUPPORTS_ALIASES || !SUPPORTS_WEAK) + if (!SUPPORTS_WEAK) { /* Lazy TLS initialization for a variable in another TU requires alias and weak reference support. */ diff --git gcc/c-family/c-pch.c gcc/c-family/c-pch.c index fd94c37..c851f1f 100644 --- gcc/c-family/c-pch.c +++ gcc/c-family/c-pch.c @@ -54,7 +54,6 @@ struct c_pch_validity { unsigned char debug_info_type; signed char match[MATCH_SIZE]; - void (*pch_init) (void); size_t target_data_length; }; @@ -117,7 +116,6 @@ pch_init (void) gcc_assert (v.match[i] == *pch_matching[i].flag_var); } } - v.pch_init = &pch_init; target_validity = targetm.get_pch_validity (&v.target_data_length); if (fwrite (partial_pch, IDENT_LENGTH, 1, f) != 1 @@ -275,19 +273,6 @@ c_common_valid_pch (cpp_reader *pfile, const char *name, int fd) } } - /* If the text segment was not loaded at the same address as it was - when the PCH file was created, function pointers loaded from the - PCH will not be valid. We could in theory remap all the function - pointers, but no support for that exists at present. - Since we have the same executable, it should only be necessary to - check one function. */ - if (v.pch_init != &pch_init) - { - cpp_warning (pfile, CPP_W_INVALID_PCH, - "%s: had text segment at different address", name); - return 2; - } - /* Check the target-specific validity data. */ { void *this_file_data = xmalloc (v.target_data_length); @@ -387,7 +372,8 @@ c_common_no_more_pch (void) if (cpp_get_callbacks (parse_in)->valid_pch) { cpp_get_callbacks (parse_in)->valid_pch = NULL; - host_hooks.gt_pch_use_address (NULL, 0, -1, 0); + void *addr = NULL; + host_hooks.gt_pch_use_address (addr, 0, -1, 0); } } diff --git gcc/c/c-decl.c gcc/c/c-decl.c index ddef9c6..1bc6bfb 100644 --- gcc/c/c-decl.c +++ gcc/c/c-decl.c @@ -73,13 +73,16 @@ enum decl_context TYPENAME}; /* Typename (inside cast or sizeof) */ /* States indicating how grokdeclarator() should handle declspecs marked - with __attribute__((deprecated)). An object declared as - __attribute__((deprecated)) suppresses warnings of uses of other - deprecated items. */ + with __attribute__((deprecated)) or __attribute__((unavailable)). + An object declared as __attribute__((unavailable)) should suppress + any reports of being declared with unavailable or deprecated items. + An object declared as __attribute__((deprecated)) should suppress + warnings of uses of other deprecated items. */ enum deprecated_states { DEPRECATED_NORMAL, - DEPRECATED_SUPPRESS + DEPRECATED_SUPPRESS, + UNAVAILABLE_DEPRECATED_SUPPRESS }; @@ -2641,6 +2644,10 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) if (TREE_DEPRECATED (newdecl)) TREE_DEPRECATED (olddecl) = 1; + /* Merge unavailability. */ + if (TREE_UNAVAILABLE (newdecl)) + TREE_UNAVAILABLE (olddecl) = 1; + /* If a decl is in a system header and the other isn't, keep the one on the system header. Otherwise, keep source location of definition rather than declaration and of prototype rather than non-prototype unless that @@ -4878,6 +4885,7 @@ quals_from_declspecs (const struct c_declspecs *specs) && !specs->typedef_p && !specs->explicit_signed_p && !specs->deprecated_p + && !specs->unavailable_p && !specs->long_p && !specs->long_long_p && !specs->short_p @@ -5080,9 +5088,14 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, tree expr = NULL_TREE; enum deprecated_states deprecated_state = DEPRECATED_NORMAL; - /* An object declared as __attribute__((deprecated)) suppresses + /* An object declared as __attribute__((unavailable)) suppresses + warnings and errors from __attribute__((deprecated/unavailable)) + components. + An object declared as __attribute__((deprecated)) suppresses warnings of uses of other deprecated items. */ - if (lookup_attribute ("deprecated", attributes)) + if (lookup_attribute ("unavailable", attributes)) + deprecated_state = UNAVAILABLE_DEPRECATED_SUPPRESS; + else if (lookup_attribute ("deprecated", attributes)) deprecated_state = DEPRECATED_SUPPRESS; decl = grokdeclarator (declarator, declspecs, @@ -6219,7 +6232,7 @@ smallest_type_quals_location (const location_t *locations, set to indicate whether operands in *EXPR can be used in constant expressions. DEPRECATED_STATE is a deprecated_states value indicating whether - deprecation warnings should be suppressed. + deprecation/unavailability warnings should be suppressed. In the TYPENAME case, DECLARATOR is really an absolute declarator. It may also be so in the PARM case, for a prototype where the @@ -6349,8 +6362,14 @@ grokdeclarator (const struct c_declarator *declarator, if (decl_context == NORMAL && !funcdef_flag && current_scope->parm_flag) decl_context = PARM; - if (declspecs->deprecated_p && deprecated_state != DEPRECATED_SUPPRESS) - warn_deprecated_use (declspecs->type, declspecs->decl_attr); + if (deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS) + { + if (declspecs->unavailable_p) + error_unavailable_use (declspecs->type, declspecs->decl_attr); + else if (declspecs->deprecated_p + && deprecated_state != DEPRECATED_SUPPRESS) + warn_deprecated_use (declspecs->type, declspecs->decl_attr); + } if ((decl_context == NORMAL || decl_context == FIELD) && current_scope == file_scope @@ -8992,8 +9011,8 @@ resort_field_decl_cmp (const void *x_p, const void *y_p) { tree d1 = DECL_NAME (*x); tree d2 = DECL_NAME (*y); - resort_data.new_value (&d1, resort_data.cookie); - resort_data.new_value (&d2, resort_data.cookie); + resort_data.new_value (&d1, &d1, resort_data.cookie); + resort_data.new_value (&d2, &d2, resort_data.cookie); if (d1 < d2) return -1; } @@ -10785,6 +10804,8 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, specs->typespec_kind = spec.kind; if (TREE_DEPRECATED (type)) specs->deprecated_p = true; + if (TREE_UNAVAILABLE (type)) + specs->unavailable_p = true; /* Handle type specifier keywords. */ if (TREE_CODE (type) == IDENTIFIER_NODE diff --git gcc/c/c-tree.h gcc/c/c-tree.h index a671a3e..4c1022d 100644 --- gcc/c/c-tree.h +++ gcc/c/c-tree.h @@ -370,6 +370,8 @@ struct c_declspecs { BOOL_BITFIELD explicit_signed_p : 1; /* Whether the specifiers include a deprecated typedef. */ BOOL_BITFIELD deprecated_p : 1; + /* Whether the specifiers include an unavailable typedef. */ + BOOL_BITFIELD unavailable_p : 1; /* Whether the type defaulted to "int" because there were no type specifiers. */ BOOL_BITFIELD default_int_p : 1; diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c index 84b4408..c5786cf 100644 --- gcc/c/c-typeck.c +++ gcc/c/c-typeck.c @@ -2561,7 +2561,9 @@ build_component_ref (location_t loc, tree datum, tree component, || (use_datum_quals && TREE_THIS_VOLATILE (datum))) TREE_THIS_VOLATILE (ref) = 1; - if (TREE_DEPRECATED (subdatum)) + if (TREE_UNAVAILABLE (subdatum)) + error_unavailable_use (subdatum, NULL_TREE); + else if (TREE_DEPRECATED (subdatum)) warn_deprecated_use (subdatum, NULL_TREE); datum = ref; @@ -2846,7 +2848,9 @@ build_external_ref (location_t loc, tree id, bool fun, tree *type) if (TREE_TYPE (ref) == error_mark_node) return error_mark_node; - if (TREE_DEPRECATED (ref)) + if (TREE_UNAVAILABLE (ref)) + error_unavailable_use (ref, NULL_TREE); + else if (TREE_DEPRECATED (ref)) warn_deprecated_use (ref, NULL_TREE); /* Recursive call does not count as usage. */ diff --git gcc/calls.c gcc/calls.c index 7d908c6..263cfe6 100644 --- gcc/calls.c +++ gcc/calls.c @@ -2390,7 +2390,8 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, with those made by function.c. */ /* See if this argument should be passed by invisible reference. */ - function_arg_info arg (type, argpos < n_named_args); + function_arg_info arg (type, argpos < n_named_args, + argpos == n_named_args - 1); if (pass_by_reference (args_so_far_pnt, arg)) { const bool callee_copies @@ -2565,6 +2566,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, #endif reg_parm_stack_space, args[i].pass_on_stack ? 0 : args[i].partial, + args_so_far, fndecl, args_size, &args[i].locate); #ifdef BLOCK_REG_PADDING else @@ -5283,6 +5285,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, argvec[count].reg != 0, #endif reg_parm_stack_space, 0, + args_so_far, NULL_TREE, &args_size, &argvec[count].locate); if (argvec[count].reg == 0 || argvec[count].partial != 0 @@ -5374,6 +5377,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, argvec[count].reg != 0, #endif reg_parm_stack_space, argvec[count].partial, + args_so_far, NULL_TREE, &args_size, &argvec[count].locate); args_size.constant += argvec[count].locate.size.constant; gcc_assert (!argvec[count].locate.size.var); diff --git gcc/calls.h gcc/calls.h index 4a018f6..fd920c6 100644 --- gcc/calls.h +++ gcc/calls.h @@ -35,24 +35,43 @@ class function_arg_info { public: function_arg_info () - : type (NULL_TREE), mode (VOIDmode), named (false), + : type (NULL_TREE), mode (VOIDmode), named (false), last_named (false), pass_by_reference (false) {} /* Initialize an argument of mode MODE, either before or after promotion. */ function_arg_info (machine_mode mode, bool named) - : type (NULL_TREE), mode (mode), named (named), pass_by_reference (false) + : type (NULL_TREE), mode (mode), named (named), last_named (false), + pass_by_reference (false) + {} + + function_arg_info (machine_mode mode, bool named, bool last_named) + : type (NULL_TREE), mode (mode), named (named), last_named (last_named), + pass_by_reference (false) {} /* Initialize an unpromoted argument of type TYPE. */ function_arg_info (tree type, bool named) - : type (type), mode (TYPE_MODE (type)), named (named), + : type (type), mode (TYPE_MODE (type)), named (named), last_named (false), pass_by_reference (false) {} + /* Initialize an unpromoted argument of type TYPE. */ + function_arg_info (tree type, bool named, bool last_named) + : type (type), mode (TYPE_MODE (type)), named (named), + last_named (last_named), pass_by_reference (false) + {} + /* Initialize an argument with explicit properties. */ function_arg_info (tree type, machine_mode mode, bool named) - : type (type), mode (mode), named (named), pass_by_reference (false) + : type (type), mode (mode), named (named), last_named (false), + pass_by_reference (false) + {} + + /* Initialize an argument with explicit properties. */ + function_arg_info (tree type, machine_mode mode, bool named, bool last_named) + : type (type), mode (mode), named (named), last_named (last_named), + pass_by_reference (false) {} /* Return true if the gimple-level type is an aggregate. */ @@ -105,6 +124,9 @@ public: "..."). See also TARGET_STRICT_ARGUMENT_NAMING. */ unsigned int named : 1; + /* True if this is the last named argument. */ + unsigned int last_named : 1; + /* True if we have decided to pass the argument by reference, in which case the function_arg_info describes a pointer to the original argument. */ unsigned int pass_by_reference : 1; diff --git gcc/common.opt gcc/common.opt index 4a3f09d..09a4a11 100644 --- gcc/common.opt +++ gcc/common.opt @@ -2090,6 +2090,10 @@ foffload-abi= Common Joined RejectNegative Enum(offload_abi) Var(flag_offload_abi) Init(OFFLOAD_ABI_UNSET) -foffload-abi=[lp64|ilp32] Set the ABI to use in an offload compiler. +foff-stack-trampolines +Common RejectNegative Var(flag_off_stack_trampolines) Init(OFF_STACK_TRAMPOLINES_INIT) +Generate trampolines in executable memory rather than executable stack. + Enum Name(offload_abi) Type(enum offload_abi) UnknownError(unknown offload ABI %qs) @@ -2646,6 +2650,10 @@ fstack-usage Common RejectNegative Var(flag_stack_usage) Output stack usage information on a per-function basis. +fstack-use-cumulative-args +Common RejectNegative Var(flag_stack_use_cumulative_args) Init(STACK_USE_CUMULATIVE_ARGS_INIT) +Use cumulative args-based stack layout hooks. + fstrength-reduce Common Ignore Does nothing. Preserved for backward compatibility. @@ -2714,7 +2722,7 @@ Common Var(flag_tracer) Optimization Perform superblock formation via tail duplication. ftrampolines -Common Var(flag_trampolines) Init(0) +Common Var(flag_trampolines) Init(OFF_STACK_TRAMPOLINES_INIT) For targets that normally need trampolines for nested functions, always generate them instead of using descriptors. diff --git gcc/config.gcc gcc/config.gcc index bf809ef..2acb7c2 100644 --- gcc/config.gcc +++ gcc/config.gcc @@ -749,7 +749,7 @@ case ${target} in tm_file="${tm_file} ${cpu_type}/darwin.h" tm_p_file="${tm_p_file} darwin-protos.h" target_gtfiles="$target_gtfiles \$(srcdir)/config/darwin.c" - extra_options="${extra_options} darwin.opt" + extra_options="${extra_options} rpath.opt darwin.opt" c_target_objs="${c_target_objs} darwin-c.o" cxx_target_objs="${cxx_target_objs} darwin-c.o" d_target_objs="${d_target_objs} darwin-d.o" @@ -1099,6 +1099,23 @@ case ${target} in ;; esac +# Defaults that need fixing. +case ${target} in +aarch64*-*-darwin2*) + tm_defines="$tm_defines STACK_USE_CUMULATIVE_ARGS_INIT=1" + tm_defines="$tm_defines OFF_STACK_TRAMPOLINES_INIT=1" + ;; +*-*-darwin2*) + tm_defines="$tm_defines STACK_USE_CUMULATIVE_ARGS_INIT=0" + # Currently, we do this for macOS 11 and above. + tm_defines="$tm_defines OFF_STACK_TRAMPOLINES_INIT=1" + ;; +*) + tm_defines="$tm_defines STACK_USE_CUMULATIVE_ARGS_INIT=0" + tm_defines="$tm_defines OFF_STACK_TRAMPOLINES_INIT=0" + ;; +esac + case ${target} in aarch64*-*-elf | aarch64*-*-fuchsia* | aarch64*-*-rtems*) tm_file="${tm_file} dbxelf.h elfos.h newlib-stdint.h" @@ -1137,6 +1154,11 @@ aarch64*-*-elf | aarch64*-*-fuchsia* | aarch64*-*-rtems*) done TM_MULTILIB_CONFIG=`echo $TM_MULTILIB_CONFIG | sed 's/^,//'` ;; +aarch64-*-darwin* ) + tm_file="${tm_file} aarch64/aarch64-errata.h" + tmake_file="${tmake_file} aarch64/t-aarch64 aarch64/t-aarch64-darwin" + tm_defines="${tm_defines} TARGET_DEFAULT_ASYNC_UNWIND_TABLES=1" + ;; aarch64*-*-freebsd*) tm_file="${tm_file} dbxelf.h elfos.h ${fbsd_tm_file}" tm_file="${tm_file} aarch64/aarch64-elf.h aarch64/aarch64-errata.h aarch64/aarch64-freebsd.h" diff --git gcc/config.host gcc/config.host index 0a02c33..81ff7ed 100644 --- gcc/config.host +++ gcc/config.host @@ -99,7 +99,8 @@ case ${host} in esac case ${host} in - aarch64*-*-freebsd* | aarch64*-*-linux* | aarch64*-*-fuchsia*) + aarch64*-*-freebsd* | aarch64*-*-linux* | aarch64*-*-fuchsia* |\ + aarch64*-*-darwin*) case ${target} in aarch64*-*-*) host_extra_gcc_objs="driver-aarch64.o" @@ -251,6 +252,10 @@ case ${host} in host_extra_gcc_objs="${host_extra_gcc_objs} driver-mingw32.o" host_lto_plugin_soname=liblto_plugin.dll ;; + aarch64*-*-darwin*) + out_host_hook_obj="${out_host_hook_obj} host-aarch64-darwin.o" + host_xmake_file="${host_xmake_file} aarch64/x-darwin" + ;; i[34567]86-*-darwin* | x86_64-*-darwin*) out_host_hook_obj="${out_host_hook_obj} host-i386-darwin.o" host_xmake_file="${host_xmake_file} i386/x-darwin" diff --git gcc/config.in gcc/config.in index 048bf52..547f0f4 100644 --- gcc/config.in +++ gcc/config.in @@ -49,6 +49,19 @@ #endif +/* Specify a runpath directory, additional to those provided by the compiler + */ +#ifndef USED_FOR_TARGET +#undef DARWIN_ADD_RPATH +#endif + + +/* Should add an extra runpath directory */ +#ifndef USED_FOR_TARGET +#undef DARWIN_DO_EXTRA_RPATH +#endif + + /* Define to enable the use of a default assembler. */ #ifndef USED_FOR_TARGET #undef DEFAULT_ASSEMBLER @@ -224,6 +237,13 @@ #endif +/* Define if you build Position Independent Executables for the compilers and + other tools. */ +#ifndef USED_FOR_TARGET +#undef ENABLE_PIE_TOOLS +#endif + + /* Define to enable plugin support. */ #ifndef USED_FOR_TARGET #undef ENABLE_PLUGIN @@ -2207,6 +2227,12 @@ #endif +/* Define to 1 if ld64 supports '-platform_version'. */ +#ifndef USED_FOR_TARGET +#undef LD64_HAS_PLATFORM_VERSION +#endif + + /* Define to ld64 version. */ #ifndef USED_FOR_TARGET #undef LD64_VERSION diff --git gcc/config/aarch64/aarch64-builtins.c gcc/config/aarch64/aarch64-builtins.c index f9a8c0a..4a63a66 100644 --- gcc/config/aarch64/aarch64-builtins.c +++ gcc/config/aarch64/aarch64-builtins.c @@ -529,6 +529,10 @@ enum aarch64_builtins AARCH64_RBIT, AARCH64_RBITL, AARCH64_RBITLL, + /* OS-specific */ + AARCH64_BUILTIN_CFSTRING, + AARCH64_BUILTIN_HUGE_VALQ, + AARCH64_BUILTIN_INFQ, AARCH64_BUILTIN_MAX }; @@ -645,6 +649,9 @@ tree aarch64_fp16_ptr_type_node = NULL_TREE; tree aarch64_bf16_type_node = NULL_TREE; tree aarch64_bf16_ptr_type_node = NULL_TREE; +/* Pointer to __float128 on Mach-O, where the 128b float is not long double. */ +tree aarch64_float128_ptr_type_node = NULL_TREE; + /* Wrapper around add_builtin_function. NAME is the name of the built-in function, TYPE is the function type, CODE is the function subcode (relative to AARCH64_BUILTIN_GENERAL), and ATTRS is the function @@ -1250,6 +1257,40 @@ aarch64_init_bf16_types (void) aarch64_bf16_ptr_type_node = build_pointer_type (aarch64_bf16_type_node); } +/* Initialize the backend REAL_TYPE type supporting __float128 on Mach-O, + as well as the related built-ins. */ +static void +aarch64_init_float128_types (void) +{ + tree ftype, fndecl; + + /* Populate the float128 node if it is not already done so that the FEs + know it is available. */ + if (float128_type_node == NULL_TREE) + { + float128_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (float128_type_node) = 128; + SET_TYPE_MODE (float128_type_node, TFmode); + layout_type (float128_type_node); + } + + lang_hooks.types.register_builtin_type (float128_type_node, "__float128"); + aarch64_float128_ptr_type_node = build_pointer_type (float128_type_node); + + ftype = build_function_type_list (float128_type_node, NULL_TREE); + + fndecl = aarch64_general_add_builtin ("__builtin_huge_valq", ftype, + AARCH64_BUILTIN_HUGE_VALQ); + TREE_READONLY (fndecl) = 1; + aarch64_builtin_decls[AARCH64_BUILTIN_HUGE_VALQ] = fndecl; + + fndecl = aarch64_general_add_builtin ("__builtin_infq", ftype, + AARCH64_BUILTIN_INFQ); + TREE_READONLY (fndecl) = 1; + aarch64_builtin_decls[AARCH64_BUILTIN_INFQ] = fndecl; +} + + /* Pointer authentication builtins that will become NOP on legacy platform. Currently, these builtins are for internal use only (libgcc EH unwinder). */ @@ -1466,8 +1507,9 @@ aarch64_general_init_builtins (void) aarch64_init_fpsr_fpcr_builtins (); aarch64_init_fp16_types (); - aarch64_init_bf16_types (); + if (TARGET_MACHO) + aarch64_init_float128_types (); if (TARGET_SIMD) aarch64_init_simd_builtins (); @@ -1499,6 +1541,14 @@ aarch64_general_init_builtins (void) aarch64_init_memtag_builtins (); } +void +aarch64_init_subtarget_builtins (void) +{ +#ifdef SUBTARGET_INIT_BUILTINS + SUBTARGET_INIT_BUILTINS; +#endif +} + /* Implement TARGET_BUILTIN_DECL for the AARCH64_BUILTIN_GENERAL group. */ tree aarch64_general_builtin_decl (unsigned code, bool) @@ -2410,6 +2460,15 @@ aarch64_general_fold_builtin (unsigned int fcode, tree type, VAR1 (UNOP, floatv4si, 2, ALL, v4sf) VAR1 (UNOP, floatv2di, 2, ALL, v2df) return fold_build1 (FLOAT_EXPR, type, args[0]); + case AARCH64_BUILTIN_HUGE_VALQ: + case AARCH64_BUILTIN_INFQ: + { + gcc_assert (n_args == 0); + REAL_VALUE_TYPE inf; + real_inf (&inf); + return build_real (type, inf); + } + break; default: break; } diff --git gcc/config/aarch64/aarch64-c.c gcc/config/aarch64/aarch64-c.c index 0586946..e73fe98 100644 --- gcc/config/aarch64/aarch64-c.c +++ gcc/config/aarch64/aarch64-c.c @@ -364,4 +364,8 @@ aarch64_register_pragmas (void) targetm.check_builtin_call = aarch64_check_builtin_call; c_register_pragma ("GCC", "aarch64", aarch64_pragma_aarch64); + +#ifdef REGISTER_SUBTARGET_PRAGMAS + REGISTER_SUBTARGET_PRAGMAS (); +#endif } diff --git gcc/config/aarch64/aarch64-protos.h gcc/config/aarch64/aarch64-protos.h index fdc79b1..a6f56df 100644 --- gcc/config/aarch64/aarch64-protos.h +++ gcc/config/aarch64/aarch64-protos.h @@ -108,6 +108,14 @@ enum aarch64_symbol_type SYMBOL_TLSLE24, SYMBOL_TLSLE32, SYMBOL_TLSLE48, + SYMBOL_MO_SMALL_ABS, + SYMBOL_MO_SMALL_PCR, + SYMBOL_MO_SMALL_GOT, + SYMBOL_MO_SMALL_TLS, + SYMBOL_MO_LARGE_ABS, + SYMBOL_MO_LARGE_PCR, + SYMBOL_MO_LARGE_GOT, + SYMBOL_MO_LARGE_TLS, SYMBOL_FORCE_TO_MEM }; @@ -737,6 +745,7 @@ void aarch64_post_cfi_startproc (void); poly_int64 aarch64_initial_elimination_offset (unsigned, unsigned); int aarch64_get_condition_code (rtx); bool aarch64_address_valid_for_prefetch_p (rtx, bool); +bool aarch64_address_valid_for_unscaled_prefetch_p (rtx, bool); bool aarch64_bitmask_imm (HOST_WIDE_INT val, machine_mode); unsigned HOST_WIDE_INT aarch64_and_split_imm1 (HOST_WIDE_INT val_in); unsigned HOST_WIDE_INT aarch64_and_split_imm2 (HOST_WIDE_INT val_in); @@ -886,6 +895,7 @@ void aarch64_expand_vector_init (rtx, rtx); void aarch64_sve_expand_vector_init (rtx, rtx); void aarch64_init_cumulative_args (CUMULATIVE_ARGS *, const_tree, rtx, const_tree, unsigned, bool = false); +void aarch64_init_cumulative_incoming_args (CUMULATIVE_ARGS *, const_tree, rtx); void aarch64_init_expanders (void); void aarch64_init_simd_builtins (void); void aarch64_emit_call_insn (rtx); @@ -961,6 +971,7 @@ void aarch64_override_options_internal (struct gcc_options *); const char *aarch64_general_mangle_builtin_type (const_tree); void aarch64_general_init_builtins (void); +void aarch64_init_subtarget_builtins (void); tree aarch64_general_fold_builtin (unsigned int, tree, unsigned int, tree *); gimple *aarch64_general_gimple_fold_builtin (unsigned int, gcall *); rtx aarch64_general_expand_builtin (unsigned int, tree, rtx, int); diff --git gcc/config/aarch64/aarch64-sve-builtins.cc gcc/config/aarch64/aarch64-sve-builtins.cc index fcc458a..f773802 100644 --- gcc/config/aarch64/aarch64-sve-builtins.cc +++ gcc/config/aarch64/aarch64-sve-builtins.cc @@ -3916,7 +3916,7 @@ gt_pch_nx (function_instance *) } inline void -gt_pch_nx (function_instance *, void (*) (void *, void *), void *) +gt_pch_nx (function_instance *, gt_pointer_operator, void *) { } diff --git gcc/config/aarch64/aarch64.c gcc/config/aarch64/aarch64.c index 391a93f..1d3d49b 100644 --- gcc/config/aarch64/aarch64.c +++ gcc/config/aarch64/aarch64.c @@ -291,8 +291,10 @@ static bool aarch64_vfp_is_call_or_return_candidate (machine_mode, const_tree, machine_mode *, int *, bool *, bool); +#if !TARGET_MACHO static void aarch64_elf_asm_constructor (rtx, int) ATTRIBUTE_UNUSED; static void aarch64_elf_asm_destructor (rtx, int) ATTRIBUTE_UNUSED; +#endif static void aarch64_override_options_after_change (void); static bool aarch64_vector_mode_supported_p (machine_mode); static int aarch64_address_cost (rtx, machine_mode, addr_space_t, bool); @@ -2242,6 +2244,9 @@ static const struct attribute_spec aarch64_attribute_table[] = { "Advanced SIMD type", 1, 1, false, true, false, true, NULL, NULL }, { "SVE type", 3, 3, false, true, false, true, NULL, NULL }, { "SVE sizeless type", 0, 0, false, true, false, true, NULL, NULL }, +#ifdef SUBTARGET_ATTRIBUTE_TABLE + SUBTARGET_ATTRIBUTE_TABLE, +#endif { NULL, 0, 0, false, false, false, false, NULL, NULL } }; @@ -3341,7 +3346,7 @@ aarch64_hard_regno_mode_ok (unsigned regno, machine_mode mode) if (known_le (GET_MODE_SIZE (mode), 8)) return true; if (known_le (GET_MODE_SIZE (mode), 16)) - return (regno & 1) == 0; + return (regno & 1) == 0 || TARGET_MACHO; /* darwinpcs D.4 */ } else if (FP_REGNUM_P (regno)) { @@ -3387,8 +3392,10 @@ static bool aarch64_takes_arguments_in_sve_regs_p (const_tree fntype) { CUMULATIVE_ARGS args_so_far_v; + /* This does not apply to variadic functions, so all the (currently + uncounted) arguments must be named. */ aarch64_init_cumulative_args (&args_so_far_v, NULL_TREE, NULL_RTX, - NULL_TREE, 0, true); + NULL_TREE, -1, true); cumulative_args_t args_so_far = pack_cumulative_args (&args_so_far_v); for (tree chain = TYPE_ARG_TYPES (fntype); @@ -3769,6 +3776,7 @@ aarch64_load_symref_appropriately (rtx dest, rtx imm, switch (type) { case SYMBOL_SMALL_ABSOLUTE: + case SYMBOL_MO_SMALL_PCR: { /* In ILP32, the mode of dest can be either SImode or DImode. */ rtx tmp_reg = dest; @@ -3779,6 +3787,21 @@ aarch64_load_symref_appropriately (rtx dest, rtx imm, if (can_create_pseudo_p ()) tmp_reg = gen_reg_rtx (mode); + if (TARGET_MACHO) + { + rtx sym, off; + split_const (imm, &sym, &off); + /* Negative offsets don't work, whether by intention is TBD. */ + if (INTVAL (off) < 0 || INTVAL (off) > 8 * 1024 * 1024) + { + emit_move_insn (tmp_reg, gen_rtx_HIGH (mode, sym)); + emit_insn (gen_add_losym (dest, tmp_reg, sym)); + /* FIXME: add the SI option if/when we support ilp32. */ + emit_insn (gen_adddi3 (dest, dest, off)); + return; + } + /* else small enough positive offset is OK. */ + } emit_move_insn (tmp_reg, gen_rtx_HIGH (mode, copy_rtx (imm))); emit_insn (gen_add_losym (dest, tmp_reg, imm)); return; @@ -3862,6 +3885,7 @@ aarch64_load_symref_appropriately (rtx dest, rtx imm, return; } + case SYMBOL_MO_SMALL_GOT: case SYMBOL_SMALL_GOT_4G: { /* In ILP32, the mode of dest can be either SImode or DImode, @@ -5979,6 +6003,7 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm) case SYMBOL_SMALL_TLSIE: case SYMBOL_SMALL_GOT_28K: case SYMBOL_SMALL_GOT_4G: + case SYMBOL_MO_SMALL_GOT: case SYMBOL_TINY_GOT: case SYMBOL_TINY_TLSIE: if (const_offset != 0) @@ -5992,6 +6017,7 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm) /* FALLTHRU */ case SYMBOL_SMALL_ABSOLUTE: + case SYMBOL_MO_SMALL_PCR: case SYMBOL_TINY_ABSOLUTE: case SYMBOL_TLSLE12: case SYMBOL_TLSLE24: @@ -6565,6 +6591,7 @@ aarch64_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED) gcc_unreachable (); } +#if !TARGET_MACHO static bool aarch64_vfp_is_call_candidate (cumulative_args_t pcum_v, machine_mode mode, const_tree type, int *nregs) @@ -6574,6 +6601,7 @@ aarch64_vfp_is_call_candidate (cumulative_args_t pcum_v, machine_mode mode, &pcum->aapcs_vfp_rmode, nregs, NULL, pcum->silent_p); } +#endif /* Given MODE and TYPE of a function argument, return the alignment in bits. The idea is to suppress any stronger alignment requested by @@ -6667,6 +6695,13 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) gcc_assert (!alignment || abi_break < alignment); pcum->aapcs_arg_processed = true; + if (TARGET_MACHO) + { + /* Set suitable defaults for queries. */ + pcum->darwinpcs_arg_boundary + = aarch64_function_arg_alignment (mode, type, &abi_break); + pcum->darwinpcs_arg_padding = BITS_PER_UNIT; + } pure_scalable_type_info pst_info; if (type && pst_info.analyze_registers (type)) @@ -6726,13 +6761,29 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) /* No frontends can create types with variable-sized modes, so we shouldn't be asked to pass or return them. */ size = GET_MODE_SIZE (mode).to_constant (); + + if (TARGET_MACHO) + /* Since we can pack things on the stack, we need the unrounded size. */ + pcum->darwinpcs_stack_bytes = size; + size = ROUND_UP (size, UNITS_PER_WORD); allocate_ncrn = (type) ? !(FLOAT_TYPE_P (type)) : !FLOAT_MODE_P (mode); + bool is_ha = false; +#if !TARGET_MACHO allocate_nvrn = aarch64_vfp_is_call_candidate (pcum_v, mode, type, &nregs); +#else + /* We care if the value is a homogenous aggregate when laying out the stack, + so use this call directly. */ + allocate_nvrn + = aarch64_vfp_is_call_or_return_candidate (mode, type, + &pcum->aapcs_vfp_rmode, + &nregs, &is_ha, + pcum->silent_p); +#endif gcc_assert (!sve_p || !allocate_nvrn); /* allocate_ncrn may be false-positive, but allocate_nvrn is quite reliable. @@ -6749,7 +6800,13 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) if (!pcum->silent_p && !TARGET_FLOAT) aarch64_err_no_fpadvsimd (mode); - if (nvrn + nregs <= NUM_FP_ARG_REGS) + if (TARGET_MACHO + && !arg.named) + { + pcum->aapcs_nextnvrn = NUM_FP_ARG_REGS; + goto on_stack; + } + else if (nvrn + nregs <= NUM_FP_ARG_REGS) { pcum->aapcs_nextnvrn = nvrn + nregs; if (!aarch64_composite_type_p (type, mode)) @@ -6773,6 +6830,7 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) } pcum->aapcs_reg = par; } + pcum->darwinpcs_stack_bytes = 0; return; } else @@ -6789,10 +6847,18 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) /* C6 - C9. though the sign and zero extension semantics are handled elsewhere. This is the case where the argument fits entirely general registers. */ + if (allocate_ncrn && (ncrn + nregs <= NUM_ARG_REGS)) { gcc_assert (nregs == 0 || nregs == 1 || nregs == 2); + if (TARGET_MACHO + && !arg.named) + { + pcum->aapcs_nextncrn = NUM_ARG_REGS; + goto on_stack; + } + /* C.8 if the argument has an alignment of 16 then the NGRN is rounded up to the next even number. */ if (nregs == 2 @@ -6802,7 +6868,9 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) alignment nregs should be > 2 and therefore it should be passed by reference rather than value. */ && (aarch64_function_arg_alignment (mode, type, &abi_break) - == 16 * BITS_PER_UNIT)) + == 16 * BITS_PER_UNIT) + /* Darwin PCS deletes rule C.8. */ + && !TARGET_MACHO) { if (warn_pcs_change && abi_break) inform (input_location, "parameter passing for argument of type " @@ -6848,8 +6916,8 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) } pcum->aapcs_reg = par; } - pcum->aapcs_nextncrn = ncrn + nregs; + pcum->darwinpcs_stack_bytes = 0; return; } @@ -6859,10 +6927,87 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) /* The argument is passed on stack; record the needed number of words for this argument and align the total size if necessary. */ on_stack: - pcum->aapcs_stack_words = size / UNITS_PER_WORD; - if (aarch64_function_arg_alignment (mode, type, &abi_break) - == 16 * BITS_PER_UNIT) + unsigned int align = aarch64_function_arg_alignment (mode, type, &abi_break); + + if (TARGET_MACHO) + { + /* Darwin does not round up the allocation for smaller entities to 8 + bytes. It only requires the natural alignment for these. + + but we don't do this for: + * unnamed parms in variadic functions + * complex types + * unions + * aggregates (except for homogeneous ones which are handles as the + enclosed type). + each entry starts a new slot. + + 16 byte entities are naturally aligned on the stack. + There was no darwinpcs for GCC 9, so neither the implementation + change nor the warning should fire here (i.e. we do not need to check + if 16byte entities alter the stack size). */ + +gcc_checking_assert (arg.named == pcum->named_p); + pcum->darwinpcs_arg_padding = BITS_PER_UNIT; + if (!pcum->named_p + || TREE_CODE (type) == COMPLEX_TYPE + || (TREE_CODE (type) == RECORD_TYPE + && !is_ha && !SCALAR_FLOAT_MODE_P (pcum->aapcs_vfp_rmode)) + || TREE_CODE (type) == UNION_TYPE) + { + pcum->aapcs_stack_words = size / UNITS_PER_WORD; + pcum->darwinpcs_sub_word_offset = 0; + pcum->darwinpcs_sub_word_pos = 0; + pcum->darwinpcs_arg_boundary = MAX (align, PARM_BOUNDARY); + if (!pcum->named_p) + pcum->darwinpcs_arg_padding = PARM_BOUNDARY; + return; + } + + /* Updated sub-word offset aligned for the new object. + We are looking for the case that the new object will fit after some + existing object(s) in the same stack slot. In that case, we do not + need to add any more stack space for it. */ + int new_off + = ROUND_UP (pcum->darwinpcs_sub_word_pos, align / BITS_PER_UNIT); + + if (new_off >= UNITS_PER_WORD) + { + /* That exceeds a stack slot, start a new one. */ + pcum->darwinpcs_sub_word_offset = 0; + pcum->darwinpcs_sub_word_pos = 0; + new_off = 0; + } + /* This is the end of the new object. */ + int new_pos = new_off + pcum->darwinpcs_stack_bytes; + + if (pcum->darwinpcs_sub_word_pos == 0) + /* New stack slot, just allocate one or more words, and note where + the next arg will start. */ + pcum->aapcs_stack_words = size / UNITS_PER_WORD; + else if (new_pos <= UNITS_PER_WORD) + /* Old stack slot, object starts at new_off and goes to new_pos, we do + not add any stack space. */ + pcum->darwinpcs_sub_word_offset = new_off; + pcum->darwinpcs_sub_word_pos = new_pos; + pcum->darwinpcs_arg_boundary = align; + if (pcum->last_named_p && new_pos > 0) + { + /* Round the last named arg to the start of the next stack slot. */ + if (new_pos <= 4) + pcum->darwinpcs_arg_padding = PARM_BOUNDARY; + else if (new_pos <= 6) + pcum->darwinpcs_arg_padding = 4 * BITS_PER_UNIT; + else if (pcum->darwinpcs_sub_word_pos <= 7) + pcum->darwinpcs_arg_padding = 2 * BITS_PER_UNIT; + } + return; + } + + /* size was already rounded up to PARM_BOUNDARY. */ + pcum->aapcs_stack_words = size / UNITS_PER_WORD; + if (align == 16 * BITS_PER_UNIT) { int new_size = ROUND_UP (pcum->aapcs_stack_size, 16 / UNITS_PER_WORD); if (pcum->aapcs_stack_size != new_size) @@ -6915,7 +7060,28 @@ aarch64_init_cumulative_args (CUMULATIVE_ARGS *pcum, pcum->aapcs_arg_processed = false; pcum->aapcs_stack_words = 0; pcum->aapcs_stack_size = 0; + pcum->darwinpcs_stack_bytes = 0; + pcum->darwinpcs_sub_word_offset = 0; + pcum->darwinpcs_sub_word_pos = 0; + pcum->darwinpcs_arg_boundary = BITS_PER_UNIT; + pcum->darwinpcs_arg_padding = BITS_PER_UNIT; + /* If we have been invoked for incoming args, then n_named will have been + set to -1, but we should have a function decl - so pick up the named + count from that. If that fails, and we end up with -1, this effectively + corresponds to assuming that there is an arbitrary number of named + args. */ + pcum->darwinpcs_n_named = n_named; + if (n_named == (unsigned)-1 && fndecl) + { + tree fnt = TREE_TYPE (fndecl); + if (fnt && TYPE_ARG_TYPES (fnt)) + pcum->darwinpcs_n_named = list_length (TYPE_ARG_TYPES (fnt)); + } + pcum->darwinpcs_n_args_processed = 0; + pcum->named_p = pcum->darwinpcs_n_named != 0; + pcum->last_named_p = pcum->darwinpcs_n_named == 1; pcum->silent_p = silent_p; + pcum->aapcs_vfp_rmode = VOIDmode; if (!silent_p && !TARGET_FLOAT @@ -6954,8 +7120,10 @@ aarch64_function_arg_advance (cumulative_args_t pcum_v, || pcum->pcs_variant == ARM_PCS_SVE) { aarch64_layout_arg (pcum_v, arg); - gcc_assert ((pcum->aapcs_reg != NULL_RTX) - != (pcum->aapcs_stack_words != 0)); + pcum->darwinpcs_n_args_processed++; + gcc_assert (TARGET_MACHO + || (pcum->aapcs_reg != NULL_RTX) + != (pcum->aapcs_stack_words != 0)); pcum->aapcs_arg_processed = false; pcum->aapcs_ncrn = pcum->aapcs_nextncrn; pcum->aapcs_nvrn = pcum->aapcs_nextnvrn; @@ -6963,6 +7131,12 @@ aarch64_function_arg_advance (cumulative_args_t pcum_v, pcum->aapcs_stack_size += pcum->aapcs_stack_words; pcum->aapcs_stack_words = 0; pcum->aapcs_reg = NULL_RTX; + pcum->darwinpcs_arg_boundary = BITS_PER_UNIT; + pcum->darwinpcs_arg_padding = BITS_PER_UNIT; + pcum->named_p + = pcum->darwinpcs_n_args_processed < pcum->darwinpcs_n_named; + pcum->last_named_p + = pcum->darwinpcs_n_args_processed + 1 == pcum->darwinpcs_n_named; } } @@ -6973,12 +7147,15 @@ aarch64_function_arg_regno_p (unsigned regno) || (FP_REGNUM_P (regno) && regno < V0_REGNUM + NUM_FP_ARG_REGS)); } -/* Implement FUNCTION_ARG_BOUNDARY. Every parameter gets at least - PARM_BOUNDARY bits of alignment, but will be given anything up - to STACK_BOUNDARY bits if the type requires it. This makes sure - that both before and after the layout of each argument, the Next - Stacked Argument Address (NSAA) will have a minimum alignment of - 8 bytes. */ +/* Implement FUNCTION_ARG_BOUNDARY. + For AAPCS64, Every parameter gets at least PARM_BOUNDARY bits of + alignment, but will be given anything up to STACK_BOUNDARY bits + if the type requires it. This makes sure that both before and after + the layout of each argument, the Next Stacked Argument Address (NSAA) + will have a minimum alignment of 8 bytes. + + For darwinpcs, this is only called to lower va_arg entries which are + always aligned as for AAPCS64. */ static unsigned int aarch64_function_arg_boundary (machine_mode mode, const_tree type) @@ -6986,15 +7163,118 @@ aarch64_function_arg_boundary (machine_mode mode, const_tree type) unsigned int abi_break; unsigned int alignment = aarch64_function_arg_alignment (mode, type, &abi_break); +#if TARGET_MACHO + /* This can only work for unnamed args. */ + machine_mode comp_mode = VOIDmode; + int nregs; + bool is_ha; + aarch64_vfp_is_call_or_return_candidate (mode, type, &comp_mode, &nregs, + &is_ha, /*silent*/true); + if (TREE_CODE (type) == COMPLEX_TYPE + || (TREE_CODE (type) == RECORD_TYPE + && !is_ha && !SCALAR_FLOAT_MODE_P (comp_mode)) + || TREE_CODE (type) == UNION_TYPE) + return MIN (MAX (alignment, PARM_BOUNDARY), STACK_BOUNDARY); + return MIN (alignment, STACK_BOUNDARY); +#else alignment = MIN (MAX (alignment, PARM_BOUNDARY), STACK_BOUNDARY); if (abi_break && warn_psabi) { abi_break = MIN (MAX (abi_break, PARM_BOUNDARY), STACK_BOUNDARY); + if (alignment != abi_break && !TARGET_MACHO) + inform (input_location, "parameter passing for argument of type " + "%qT changed in GCC 9.1", type); + } + + return alignment; +#endif +} + +/* For Darwin, we want to use the arg boundary computed when laying out the + function arg, to cope with items packed on the stack and the different + rules applied to unnamed parms. */ + +static unsigned int +aarch64_function_arg_boundary_ca (machine_mode mode ATTRIBUTE_UNUSED, + const_tree type ATTRIBUTE_UNUSED, + cumulative_args_t ca ATTRIBUTE_UNUSED) +{ + unsigned int abi_break; + unsigned int alignment = aarch64_function_arg_alignment (mode, type, + &abi_break); +#if TARGET_MACHO + CUMULATIVE_ARGS *pcum = get_cumulative_args (ca); +gcc_checking_assert (pcum->aapcs_arg_processed); + + bool named_p = pcum->darwinpcs_n_args_processed < pcum->darwinpcs_n_named; +gcc_checking_assert (named_p == pcum->named_p); + machine_mode comp_mode = VOIDmode; + int nregs; + bool is_ha; + aarch64_vfp_is_call_or_return_candidate (mode, type, &comp_mode, &nregs, + &is_ha, /*silent*/true); + bool no_pack = (TREE_CODE (type) == COMPLEX_TYPE + || (TREE_CODE (type) == RECORD_TYPE + && !is_ha && !SCALAR_FLOAT_MODE_P (comp_mode)) + || TREE_CODE (type) == UNION_TYPE); + + bool in_regs = (pcum->aapcs_reg != NULL_RTX); + + if ((named_p && !no_pack) || in_regs) + ; /* Leave the alignment as natural. */ + else + alignment = MAX (alignment, PARM_BOUNDARY); +gcc_checking_assert (alignment == pcum->darwinpcs_arg_boundary); + return MIN (alignment, STACK_BOUNDARY); + +#else + alignment = MIN (MAX (alignment, PARM_BOUNDARY), STACK_BOUNDARY); + if (abi_break & warn_psabi) + { + abi_break = MIN (MAX (abi_break, PARM_BOUNDARY), STACK_BOUNDARY); if (alignment != abi_break) inform (input_location, "parameter passing for argument of type " "%qT changed in GCC 9.1", type); } return alignment; +#endif +} + +/* Implement TARGET_FUNCTION_ARG_ROUND_BOUNDARY_CA for darwinpcs which allows + non-standard passing of byte-aligned items [D.2]. This is done by pulling + the values out of the cumulative args struct. */ + +static unsigned int +aarch64_function_arg_round_boundary_ca (machine_mode mode ATTRIBUTE_UNUSED, + const_tree type ATTRIBUTE_UNUSED, + cumulative_args_t ca) +{ + CUMULATIVE_ARGS *pcum = get_cumulative_args (ca); +gcc_checking_assert (pcum->aapcs_arg_processed); + bool named_p = pcum->darwinpcs_n_args_processed < pcum->darwinpcs_n_named; +gcc_checking_assert (named_p == pcum->named_p); + bool last_named_p = pcum->darwinpcs_n_args_processed + 1 == pcum->darwinpcs_n_named; +gcc_checking_assert (last_named_p == pcum->last_named_p); + + unsigned boundary = BITS_PER_UNIT; + if (last_named_p && pcum->darwinpcs_sub_word_pos > 0) + { + /* Round the last named arg to the start of the next stack slot. */ + if (pcum->darwinpcs_sub_word_pos <= 4) + boundary = PARM_BOUNDARY; + else if (pcum->darwinpcs_sub_word_pos <= 6) + boundary = 4 * BITS_PER_UNIT; + else if (pcum->darwinpcs_sub_word_pos <= 7) + boundary = 2 * BITS_PER_UNIT; + } + else if (named_p) + /* Named args are naturally aligned, but with no rounding. */ + ; + else + /* un-named args are rounded to fill slots. */ + boundary = PARM_BOUNDARY; +gcc_checking_assert (boundary == pcum->darwinpcs_arg_padding); + return boundary; } /* Implement TARGET_GET_RAW_RESULT_MODE and TARGET_GET_RAW_ARG_MODE. */ @@ -10096,6 +10376,7 @@ aarch64_classify_address (struct aarch64_address_info *info, /* load literal: pc-relative constant pool entry. Only supported for SI mode or larger. */ info->type = ADDRESS_SYMBOLIC; + info->offset = NULL_RTX; if (!load_store_pair_p && GET_MODE_SIZE (mode).is_constant (&const_size) @@ -10103,6 +10384,7 @@ aarch64_classify_address (struct aarch64_address_info *info, { poly_int64 offset; rtx sym = strip_offset_and_salt (x, &offset); + return ((LABEL_REF_P (sym) || (SYMBOL_REF_P (sym) && CONSTANT_POOL_ADDRESS_P (sym) @@ -10120,10 +10402,13 @@ aarch64_classify_address (struct aarch64_address_info *info, poly_int64 offset; HOST_WIDE_INT const_offset; rtx sym = strip_offset_and_salt (info->offset, &offset); + if (SYMBOL_REF_P (sym) && offset.is_constant (&const_offset) && (aarch64_classify_symbol (sym, const_offset) - == SYMBOL_SMALL_ABSOLUTE)) + == SYMBOL_SMALL_ABSOLUTE + || aarch64_classify_symbol (sym, const_offset) + == SYMBOL_MO_SMALL_PCR)) { /* The symbol and offset must be aligned to the access size. */ unsigned int align; @@ -10173,6 +10458,55 @@ aarch64_address_valid_for_prefetch_p (rtx x, bool strict_p) if (!res) return false; + /* For ELF targets using GAS, we emit prfm unconditionally; GAS will alter + the instruction to pick the prfum form where possible (i.e. when the + offset is in the range -256..255) and fall back to prfm otherwise. + We can reject cases where the offset exceeds the range usable by both + insns [-256..32760], or for offsets > 255 when the value is not divisible + by 8. + For Mach-O (Darwin) where the assembler uses the LLVM back end, that does + not yet do the substitution, so we must reject all prfum cases. */ + if (addr.offset) + { + HOST_WIDE_INT offs = INTVAL (addr.offset); + if (offs < -256) /* Out of range for both prfum and prfm. */ + return false; + if (offs > 32760) /* Out of range for prfm. */ + return false; + if (offs & 0x07) /* We cannot use prfm. */ + { + if (offs > 255) /* Out of range for prfum. */ + return false; + if (TARGET_MACHO) + return false; + } + if (TARGET_MACHO && offs < 0) + return false; + } + + /* ... except writeback forms. */ + return addr.type != ADDRESS_REG_WB; +} + +/* Return true if the address X is valid for a PRFUM instruction. + STRICT_P is true if we should do strict checking with + aarch64_classify_address. */ + +bool +aarch64_address_valid_for_unscaled_prefetch_p (rtx x, bool strict_p) +{ + struct aarch64_address_info addr; + + /* PRFUM accepts the same addresses as DImode, but constrained to a range + -256..255. */ + bool res = aarch64_classify_address (&addr, x, DImode, strict_p); + if (!res) + return false; + + if (addr.offset && ((INTVAL (addr.offset) > 255) + || (INTVAL (addr.offset) < -256))) + return false; + /* ... except writeback forms. */ return addr.type != ADDRESS_REG_WB; } @@ -10857,6 +11191,144 @@ sizetochar (int size) } } +static void +output_macho_postfix_expr (FILE *file, rtx x, const char *postfix) +{ + char buf[256]; + + restart: + switch (GET_CODE (x)) + { + case PC: + putc ('.', file); + break; + + case SYMBOL_REF: + if (SYMBOL_REF_DECL (x)) + assemble_external (SYMBOL_REF_DECL (x)); + assemble_name (file, XSTR (x, 0)); + fprintf (file, "@%s", postfix); + break; + + case LABEL_REF: + x = label_ref_label (x); + /* Fall through. */ + case CODE_LABEL: + ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); + assemble_name (file, buf); + fprintf (file, "@%s", postfix); + break; + + case CONST_INT: + fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); + break; + + case CONST: + /* This used to output parentheses around the expression, + but that does not work on the 386 (either ATT or BSD assembler). */ + output_macho_postfix_expr (file, XEXP (x, 0), postfix); + break; + + case CONST_WIDE_INT: + /* We do not know the mode here so we have to use a round about + way to build a wide-int to get it printed properly. */ + { + wide_int w = wide_int::from_array (&CONST_WIDE_INT_ELT (x, 0), + CONST_WIDE_INT_NUNITS (x), + CONST_WIDE_INT_NUNITS (x) + * HOST_BITS_PER_WIDE_INT, + false); + print_decs (w, file); + } + break; + + case CONST_DOUBLE: + if (CONST_DOUBLE_AS_INT_P (x)) + { + /* We can use %d if the number is one word and positive. */ + if (CONST_DOUBLE_HIGH (x)) + fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX, + (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (x), + (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x)); + else if (CONST_DOUBLE_LOW (x) < 0) + fprintf (file, HOST_WIDE_INT_PRINT_HEX, + (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x)); + else + fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x)); + } + else + /* We can't handle floating point constants; + PRINT_OPERAND must handle them. */ + output_operand_lossage ("floating constant misused"); + break; + + case CONST_FIXED: + fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_FIXED_VALUE_LOW (x)); + break; + + case PLUS: + /* Some assemblers need integer constants to appear last (eg masm). */ + if (CONST_INT_P (XEXP (x, 0))) + { + output_macho_postfix_expr (file, XEXP (x, 1), postfix); + if (INTVAL (XEXP (x, 0)) >= 0) + fprintf (file, "+"); + output_addr_const (file, XEXP (x, 0)); + } + else + { + output_macho_postfix_expr (file, XEXP (x, 0), postfix); + if (!CONST_INT_P (XEXP (x, 1)) + || INTVAL (XEXP (x, 1)) >= 0) + fprintf (file, "+"); + output_addr_const (file, XEXP (x, 1)); + } + break; + + case MINUS: + /* Avoid outputting things like x-x or x+5-x, + since some assemblers can't handle that. */ + x = simplify_subtraction (x); + if (GET_CODE (x) != MINUS) + goto restart; + + output_macho_postfix_expr (file, XEXP (x, 0), postfix); + fprintf (file, "-"); + if ((CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) >= 0) + || GET_CODE (XEXP (x, 1)) == PC + || GET_CODE (XEXP (x, 1)) == SYMBOL_REF) + output_addr_const (file, XEXP (x, 1)); + else + { + fputs (targetm.asm_out.open_paren, file); + output_addr_const (file, XEXP (x, 1)); + fputs (targetm.asm_out.close_paren, file); + } + break; + + case ZERO_EXTEND: + case SIGN_EXTEND: + case SUBREG: + case TRUNCATE: + output_addr_const (file, XEXP (x, 0)); + break; + + case UNSPEC: + if (XINT (x, 1) == UNSPEC_SALT_ADDR) + { + output_macho_postfix_expr (file, XVECEXP (x, 0, 0), postfix); + break; + } + /* FALLTHROUGH */ + default: + if (targetm.asm_out.output_addr_const_extra (file, x)) + break; + + output_operand_lossage ("invalid expression as operand"); + } + +} + /* Print operand X to file F in a target specific manner according to CODE. The acceptable formatting commands given by CODE are: 'c': An integer or symbol address without a preceding # @@ -10925,6 +11397,12 @@ aarch64_print_operand (FILE *f, rtx x, int code) } break; + case 'K': + output_macho_postfix_expr (f, x, "PAGEOFF"); + break; + case 'O': + output_macho_postfix_expr (f, x, "GOTPAGEOFF"); + break; case 'e': { x = unwrap_const_vec_duplicate (x); @@ -11245,7 +11723,7 @@ aarch64_print_operand (FILE *f, rtx x, int code) case 'A': if (GET_CODE (x) == HIGH) x = XEXP (x, 0); - +#if !TARGET_MACHO switch (aarch64_classify_symbolic_expression (x)) { case SYMBOL_SMALL_GOT_4G: @@ -11276,9 +11754,29 @@ aarch64_print_operand (FILE *f, rtx x, int code) break; } output_addr_const (asm_out_file, x); +#endif +#if TARGET_MACHO + // FIXME update classify symbolic expression to handle macho. + switch (aarch64_classify_symbolic_expression (x)) + { + case SYMBOL_MO_SMALL_PCR: + output_macho_postfix_expr (asm_out_file, x, "PAGE"); +// asm_fprintf (asm_out_file, "@PAGE;mopcr"); + break; + case SYMBOL_MO_SMALL_GOT: + output_macho_postfix_expr (asm_out_file, x, "GOTPAGE"); +// asm_fprintf (asm_out_file, "@GOTPAGE;mosg"); + break; + default: + output_macho_postfix_expr (asm_out_file, x, "BLEAH"); +// asm_fprintf (asm_out_file, "@BLEAH"); + break; + } +#endif break; case 'L': +#if !TARGET_MACHO switch (aarch64_classify_symbolic_expression (x)) { case SYMBOL_SMALL_GOT_4G: @@ -11316,10 +11814,12 @@ aarch64_print_operand (FILE *f, rtx x, int code) default: break; } +#endif output_addr_const (asm_out_file, x); break; case 'G': +#if !TARGET_MACHO switch (aarch64_classify_symbolic_expression (x)) { case SYMBOL_TLSLE24: @@ -11328,6 +11828,7 @@ aarch64_print_operand (FILE *f, rtx x, int code) default: break; } +#endif output_addr_const (asm_out_file, x); break; @@ -11475,8 +11976,14 @@ aarch64_print_address_internal (FILE *f, machine_mode mode, rtx x, break; case ADDRESS_LO_SUM: +#if TARGET_MACHO + asm_fprintf (f, "[%s, #", reg_names [REGNO (addr.base)]); + output_macho_postfix_expr (f, addr.offset, "PAGEOFF"); +// output_addr_const (f, addr.offset); +#else asm_fprintf (f, "[%s, #:lo12:", reg_names [REGNO (addr.base)]); output_addr_const (f, addr.offset); +#endif asm_fprintf (f, "]"); return true; @@ -11946,6 +12453,8 @@ aarch64_asm_output_labelref (FILE* f, const char *name) asm_fprintf (f, "%U%s", name); } +#if !TARGET_MACHO + static void aarch64_elf_asm_constructor (rtx symbol, int priority) { @@ -11985,6 +12494,7 @@ aarch64_elf_asm_destructor (rtx symbol, int priority) assemble_aligned_integer (POINTER_BYTES, symbol); } } +#endif const char* aarch64_output_casesi (rtx *operands) @@ -12088,7 +12598,11 @@ aarch64_select_rtx_section (machine_mode mode, if (aarch64_can_use_per_function_literal_pools_p ()) return function_section (current_function_decl); +#ifdef TARGET_MACHO + return machopic_select_rtx_section (mode, x, align); +#else return default_elf_select_rtx_section (mode, x, align); +#endif } /* Implement ASM_OUTPUT_POOL_EPILOGUE. */ @@ -14177,15 +14691,17 @@ aarch64_init_builtins () { aarch64_general_init_builtins (); aarch64_sve::init_builtins (); -#ifdef SUBTARGET_INIT_BUILTINS - SUBTARGET_INIT_BUILTINS; -#endif + aarch64_init_subtarget_builtins (); } /* Implement TARGET_FOLD_BUILTIN. */ static tree aarch64_fold_builtin (tree fndecl, int nargs, tree *args, bool) { +#ifdef SUBTARGET_FOLD_BUILTIN + if (tree res = SUBTARGET_FOLD_BUILTIN (fndecl, nargs, args, false)) + return res; +#endif unsigned int code = DECL_MD_FUNCTION_CODE (fndecl); unsigned int subcode = code >> AARCH64_BUILTIN_SHIFT; tree type = TREE_TYPE (TREE_TYPE (fndecl)); @@ -17366,10 +17882,14 @@ initialize_aarch64_code_model (struct gcc_options *opts) } break; case AARCH64_CMODEL_LARGE: - if (opts->x_flag_pic) + if (TARGET_MACHO) + /* We need to implement fPIC here (arm64_32 also accepts the large + model). */ + ; + else if (opts->x_flag_pic) sorry ("code model %qs with %<-f%s%>", "large", opts->x_flag_pic > 1 ? "PIC" : "pic"); - if (opts->x_aarch64_abi == AARCH64_ABI_ILP32) + else if (opts->x_aarch64_abi == AARCH64_ABI_ILP32) sorry ("code model %qs not supported in ilp32 mode", "large"); break; case AARCH64_CMODEL_TINY_PIC: @@ -18281,7 +18801,9 @@ aarch64_classify_symbol (rtx x, HOST_WIDE_INT offset) case AARCH64_CMODEL_SMALL_SPIC: case AARCH64_CMODEL_SMALL_PIC: case AARCH64_CMODEL_SMALL: - return SYMBOL_SMALL_ABSOLUTE; + return TARGET_MACHO + ? SYMBOL_MO_SMALL_PCR + : SYMBOL_SMALL_ABSOLUTE; default: gcc_unreachable (); @@ -18318,14 +18840,28 @@ aarch64_classify_symbol (rtx x, HOST_WIDE_INT offset) case AARCH64_CMODEL_SMALL: /* Same reasoning as the tiny code model, but the offset cap here is 1MB, allowing +/-3.9GB for the offset to the symbol. */ - +#if TARGET_MACHO + if (TARGET_MACHO) + { + /* Constant pool addresses are always TU-local and PC- + relative. We indirect common, external and weak + symbols (but weak only if not hidden). */ + if (!CONSTANT_POOL_ADDRESS_P (x) + && (MACHO_SYMBOL_MUST_INDIRECT_P (x) + || !aarch64_symbol_binds_local_p (x))) + return SYMBOL_MO_SMALL_GOT; + } + else +#endif if (SYMBOL_REF_WEAK (x) && !aarch64_symbol_binds_local_p (x)) return SYMBOL_FORCE_TO_MEM; + if (!(IN_RANGE (offset, -0x100000, 0x100000) || offset_within_block_p (x, offset))) return SYMBOL_FORCE_TO_MEM; - return SYMBOL_SMALL_ABSOLUTE; + return TARGET_MACHO ? SYMBOL_MO_SMALL_PCR + : SYMBOL_SMALL_ABSOLUTE; case AARCH64_CMODEL_TINY_PIC: if (!aarch64_symbol_binds_local_p (x)) @@ -18334,10 +18870,25 @@ aarch64_classify_symbol (rtx x, HOST_WIDE_INT offset) case AARCH64_CMODEL_SMALL_SPIC: case AARCH64_CMODEL_SMALL_PIC: +#if TARGET_MACHO + if (TARGET_MACHO) + { + /* Constant pool addresses are always TU-local and PC- + relative. We indirect common, external and weak + symbols (but weak only if not hidden). */ + if (!CONSTANT_POOL_ADDRESS_P (x) + && (MACHO_SYMBOL_MUST_INDIRECT_P (x) + || !aarch64_symbol_binds_local_p (x))) + return SYMBOL_MO_SMALL_GOT; + } + else +#endif if (!aarch64_symbol_binds_local_p (x)) return (aarch64_cmodel == AARCH64_CMODEL_SMALL_SPIC - ? SYMBOL_SMALL_GOT_28K : SYMBOL_SMALL_GOT_4G); - return SYMBOL_SMALL_ABSOLUTE; + ? SYMBOL_SMALL_GOT_28K : SYMBOL_SMALL_GOT_4G); + + return TARGET_MACHO ? SYMBOL_MO_SMALL_PCR + : SYMBOL_SMALL_ABSOLUTE; case AARCH64_CMODEL_LARGE: /* This is alright even in PIC code as the constant @@ -18467,7 +19018,10 @@ static GTY(()) tree va_list_type; void *__vr_top; int __gr_offs; int __vr_offs; - }; */ + }; + + darwinpcs uses 'char *' for the va_list (in common with other platform + ports). */ static tree aarch64_build_builtin_va_list (void) @@ -18475,6 +19029,13 @@ aarch64_build_builtin_va_list (void) tree va_list_name; tree f_stack, f_grtop, f_vrtop, f_groff, f_vroff; + /* darwinpcs uses a simple char * for this. */ + if (TARGET_MACHO) + { + va_list_type = build_pointer_type (char_type_node); + return va_list_type; + } + /* Create the type. */ va_list_type = lang_hooks.types.make_type (RECORD_TYPE); /* Give it the required name. */ @@ -18546,6 +19107,13 @@ aarch64_expand_builtin_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED) int vr_save_area_size = cfun->va_list_fpr_size; int vr_offset; + /* darwinpcs uses the default, char * va_list impl. */ + if (TARGET_MACHO) + { + std_expand_builtin_va_start (valist, nextarg); + return; + } + cum = &crtl->args.info; if (cfun->va_list_gpr_size) gr_save_area_size = MIN ((NUM_ARG_REGS - cum->aapcs_ncrn) * UNITS_PER_WORD, @@ -18636,6 +19204,9 @@ aarch64_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, HOST_WIDE_INT size, rsize, adjust, align; tree t, u, cond1, cond2; + if (TARGET_MACHO) + return std_gimplify_va_arg_expr (valist, type, pre_p, post_p); + indirect_p = pass_va_arg_by_reference (type); if (indirect_p) type = build_pointer_type (type); @@ -18820,8 +19391,18 @@ aarch64_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, field_ptr_t = double_ptr_type_node; break; case E_TFmode: - field_t = long_double_type_node; - field_ptr_t = long_double_ptr_type_node; + if (TARGET_MACHO) + { + /* Darwin has __float128, and long double is the same as + double. */ + field_t = float128_type_node; + field_ptr_t = aarch64_float128_ptr_type_node; + } + else + { + field_t = long_double_type_node; + field_ptr_t = long_double_ptr_type_node; + } break; case E_HFmode: field_t = aarch64_fp16_type_node; @@ -18892,6 +19473,9 @@ aarch64_setup_incoming_varargs (cumulative_args_t cum_v, int gr_saved = cfun->va_list_gpr_size; int vr_saved = cfun->va_list_fpr_size; + if (TARGET_MACHO) + return default_setup_incoming_varargs (cum_v, arg, pretend_size, no_rtl); + /* The caller has advanced CUM up to, but not beyond, the last named argument. Advance a local copy of CUM past the last "real" named argument, to find out how many registers are left over. */ @@ -19675,6 +20259,12 @@ aarch64_autovectorize_vector_modes (vector_modes *modes, bool) static const char * aarch64_mangle_type (const_tree type) { + /* The darwinpcs ABI documents say that "__va_list" has to be + mangled as char *. */ + if (TARGET_MACHO + && lang_hooks.types_compatible_p (CONST_CAST_TREE (type), va_list_type)) + return "Pc"; + /* The AArch64 ABI documents say that "__va_list" has to be mangled as if it is in the "std" namespace. */ if (lang_hooks.types_compatible_p (CONST_CAST_TREE (type), va_list_type)) @@ -19689,6 +20279,10 @@ aarch64_mangle_type (const_tree type) return "Dh"; } + /* TFmode is __float128 for Darwin. */ + if (TARGET_MACHO && TYPE_MODE (type) == TFmode) + return "g"; + /* Mangle AArch64-specific internal types. TYPE_NAME is non-NULL_TREE for builtin types. */ if (TYPE_NAME (type) != NULL) @@ -21547,7 +22141,9 @@ aarch64_declare_function_name (FILE *stream, const char* name, aarch64_asm_output_variant_pcs (stream, fndecl, name); /* Don't forget the type directive for ELF. */ +#ifdef ASM_OUTPUT_TYPE_DIRECTIVE ASM_OUTPUT_TYPE_DIRECTIVE (stream, name, "function"); +#endif ASM_OUTPUT_LABEL (stream, name); cfun->machine->label_is_assembled = true; @@ -21608,12 +22204,17 @@ aarch64_output_patchable_area (unsigned int patch_area_size, bool record_p) /* Implement ASM_OUTPUT_DEF_FROM_DECLS. Output .variant_pcs for aliases. */ void -aarch64_asm_output_alias (FILE *stream, const tree decl, const tree target) +aarch64_asm_output_alias (FILE *stream, const tree decl, + const tree target ATTRIBUTE_UNUSED) { const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0); +#ifdef ASM_OUTPUT_DEF const char *value = IDENTIFIER_POINTER (target); +#endif aarch64_asm_output_variant_pcs (stream, decl, name); +#ifdef ASM_OUTPUT_DEF ASM_OUTPUT_DEF (stream, name, value); +#endif } /* Implement ASM_OUTPUT_EXTERNAL. Output .variant_pcs for undefined @@ -22237,6 +22838,16 @@ aarch64_output_simd_mov_immediate (rtx const_vector, unsigned width, } gcc_assert (CONST_INT_P (info.u.mov.value)); + unsigned HOST_WIDE_INT value = UINTVAL (info.u.mov.value); + + /* We have signed chars which can result in a sign-extended 8bit value + which is then emitted as an unsigned hex value, and the LLVM back end + assembler rejects that as being too big. */ + if (TARGET_MACHO && (known_eq (GET_MODE_BITSIZE (info.elt_mode), 8))) + { + unsigned HOST_WIDE_INT mask = (1U << GET_MODE_BITSIZE (info.elt_mode))-1; + value &= mask; + } if (which == AARCH64_CHECK_MOV) { @@ -22245,16 +22856,16 @@ aarch64_output_simd_mov_immediate (rtx const_vector, unsigned width, ? "msl" : "lsl"); if (lane_count == 1) snprintf (templ, sizeof (templ), "%s\t%%d0, " HOST_WIDE_INT_PRINT_HEX, - mnemonic, UINTVAL (info.u.mov.value)); + mnemonic, value); else if (info.u.mov.shift) snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, " HOST_WIDE_INT_PRINT_HEX ", %s %d", mnemonic, lane_count, - element_char, UINTVAL (info.u.mov.value), shift_op, + element_char, value, shift_op, info.u.mov.shift); else snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, " HOST_WIDE_INT_PRINT_HEX, mnemonic, lane_count, - element_char, UINTVAL (info.u.mov.value)); + element_char, value); } else { @@ -22263,12 +22874,12 @@ aarch64_output_simd_mov_immediate (rtx const_vector, unsigned width, if (info.u.mov.shift) snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, #" HOST_WIDE_INT_PRINT_DEC ", %s #%d", mnemonic, lane_count, - element_char, UINTVAL (info.u.mov.value), "lsl", + element_char, value, "lsl", info.u.mov.shift); else snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, #" HOST_WIDE_INT_PRINT_DEC, mnemonic, lane_count, - element_char, UINTVAL (info.u.mov.value)); + element_char, value); } return templ; } @@ -25213,12 +25824,12 @@ aarch64_libgcc_floating_mode_supported_p (scalar_float_mode mode) } /* Implement TARGET_SCALAR_MODE_SUPPORTED_P - return TRUE - if MODE is HFmode, and punt to the generic implementation otherwise. */ + if MODE is HFmode, or TFmode on Mach-O, and punt to the generic implementation otherwise. */ static bool aarch64_scalar_mode_supported_p (scalar_mode mode) { - return (mode == HFmode + return (mode == HFmode || (mode == TFmode && TARGET_MACHO) ? true : default_scalar_mode_supported_p (mode)); } @@ -25966,19 +26577,37 @@ aarch64_sls_emit_shared_blr_thunks (FILE *out_file) continue; const char *name = indirect_symbol_names[regnum]; - switch_to_section (get_named_section (decl, NULL, 0)); + /* If the target uses a unique section for this switch to it. */ + if (DECL_SECTION_NAME (decl)) + switch_to_section (get_named_section (decl, NULL, 0)); + else + switch_to_section (text_section); ASM_OUTPUT_ALIGN (out_file, 2); - targetm.asm_out.globalize_label (out_file, name); + if (!TARGET_MACHO) + targetm.asm_out.globalize_label (out_file, name); +#ifdef ASM_OUTPUT_TYPE_DIRECTIVE + ASM_OUTPUT_TYPE_DIRECTIVE (out_file, name, "function"); +#endif + if (TARGET_MACHO) + { +#ifdef ASM_WEAKEN_DECL + if (DECL_WEAK (decl)) + ASM_WEAKEN_DECL (out_file, decl, name, 0); + else +#endif + targetm.asm_out.globalize_decl_name (out_file, decl); + } /* Only emits if the compiler is configured for an assembler that can handle visibility directives. */ targetm.asm_out.assemble_visibility (decl, VISIBILITY_HIDDEN); - ASM_OUTPUT_TYPE_DIRECTIVE (out_file, name, "function"); ASM_OUTPUT_LABEL (out_file, name); aarch64_sls_emit_function_stub (out_file, regnum); /* Use the most conservative target to ensure it can always be used by any function in the translation unit. */ asm_fprintf (out_file, "\tdsb\tsy\n\tisb\n"); +#ifdef ASM_DECLARE_FUNCTION_SIZE ASM_DECLARE_FUNCTION_SIZE (out_file, name, decl); +#endif } } @@ -26171,6 +26800,15 @@ aarch64_run_selftests (void) #undef TARGET_ASM_ALIGNED_SI_OP #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t" +#if TARGET_MACHO +#undef TARGET_ASM_UNALIGNED_HI_OP +#define TARGET_ASM_UNALIGNED_HI_OP "\t.short\t" +#undef TARGET_ASM_UNALIGNED_SI_OP +#define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t" +#undef TARGET_ASM_UNALIGNED_DI_OP +#define TARGET_ASM_UNALIGNED_DI_OP "\t.quad\t" +#endif + #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \ hook_bool_const_tree_hwi_hwi_const_tree_true @@ -26257,6 +26895,12 @@ aarch64_run_selftests (void) #undef TARGET_FUNCTION_ARG_BOUNDARY #define TARGET_FUNCTION_ARG_BOUNDARY aarch64_function_arg_boundary +#undef TARGET_FUNCTION_ARG_BOUNDARY_CA +#define TARGET_FUNCTION_ARG_BOUNDARY_CA aarch64_function_arg_boundary_ca + +#undef TARGET_FUNCTION_ARG_ROUND_BOUNDARY_CA +#define TARGET_FUNCTION_ARG_ROUND_BOUNDARY_CA aarch64_function_arg_round_boundary_ca + #undef TARGET_FUNCTION_ARG_PADDING #define TARGET_FUNCTION_ARG_PADDING aarch64_function_arg_padding @@ -26593,7 +27237,7 @@ aarch64_libgcc_floating_mode_supported_p /* The architecture reserves bits 0 and 1 so use bit 2 for descriptors. */ #undef TARGET_CUSTOM_FUNCTION_DESCRIPTORS -#define TARGET_CUSTOM_FUNCTION_DESCRIPTORS 4 +#define TARGET_CUSTOM_FUNCTION_DESCRIPTORS AARCH64_CUSTOM_FUNCTION_TEST #undef TARGET_HARD_REGNO_NREGS #define TARGET_HARD_REGNO_NREGS aarch64_hard_regno_nregs diff --git gcc/config/aarch64/aarch64.h gcc/config/aarch64/aarch64.h index bb383acfa..ae911a8 100644 --- gcc/config/aarch64/aarch64.h +++ gcc/config/aarch64/aarch64.h @@ -58,6 +58,10 @@ #define TARGET_SIMD (!TARGET_GENERAL_REGS_ONLY && AARCH64_ISA_SIMD) #define TARGET_FLOAT (!TARGET_GENERAL_REGS_ONLY && AARCH64_ISA_FP) +/* If this is non-zero then generated code of the object format, ABI and + assembler syntax used by Darwin (Mach-O) platforms. */ +#define TARGET_MACHO 0 + #define UNITS_PER_WORD 8 #define UNITS_PER_VREG 16 @@ -135,6 +139,12 @@ /* Heap alignment (same as BIGGEST_ALIGNMENT and STACK_BOUNDARY). */ #define MALLOC_ABI_ALIGNMENT 128 +/* We will and with this value to test if a custom function descriptor needs + a static chain. The function boundary must the adjusted so that the bit + this represents is no longer part of the address. 0 Disables the custom + function descriptors. */ +#define AARCH64_CUSTOM_FUNCTION_TEST 4 + /* Defined by the ABI */ #define WCHAR_TYPE "unsigned int" #define WCHAR_TYPE_SIZE 32 @@ -974,6 +984,24 @@ typedef struct aapcs_reg == NULL_RTX. */ int aapcs_stack_size; /* The total size (in words, per 8 byte) of the stack arg area so far. */ + + /* In the darwinpcs, items smaller than one word are packed onto the stack + naturally aligned. Unnamed parameters passed in a variadic call are, + however, aligned the same way as the AAPCS64. This means that we need to + pad the last named arg to the next parm boundary (and hence notice when + we are processing that arg). */ + int darwinpcs_stack_bytes; /* If the argument is passed on the stack, this + the byte-size. */ + int darwinpcs_sub_word_offset;/* This is the offset of this arg within a word + when placing smaller items for darwinpcs. */ + int darwinpcs_sub_word_pos; /* The next byte available within the word for + darwinpcs. */ + unsigned darwinpcs_arg_boundary; /* The computed argument boundary. */ + unsigned darwinpcs_arg_padding; /* The computed argument padding. */ + unsigned darwinpcs_n_named; /* Number of named arguments. */ + unsigned darwinpcs_n_args_processed; /* Processed so far. */ + bool named_p; /* Is this arg named? */ + bool last_named_p; /* Is this the last named arg? */ bool silent_p; /* True if we should act silently, rather than raise an error for invalid calls. */ } CUMULATIVE_ARGS; @@ -1257,8 +1285,13 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); #define ASM_CPU_SPEC \ MCPU_TO_MARCH_SPEC +#ifndef SUBTARGET_EXTRA_SPECS +#define SUBTARGET_EXTRA_SPECS +#endif + #define EXTRA_SPECS \ - { "asm_cpu_spec", ASM_CPU_SPEC } + { "asm_cpu_spec", ASM_CPU_SPEC }, \ + SUBTARGET_EXTRA_SPECS #define ASM_OUTPUT_POOL_EPILOGUE aarch64_asm_output_pool_epilogue @@ -1272,6 +1305,10 @@ extern tree aarch64_fp16_ptr_type_node; extern tree aarch64_bf16_type_node; extern tree aarch64_bf16_ptr_type_node; +/* A pointer to the user-visible __float128 (on Mach-O). Defined in + aarch64-builtins.c. */ +extern GTY(()) tree aarch64_float128_ptr_type_node; + /* The generic unwind code in libgcc does not initialize the frame pointer. So in order to unwind a function using a frame pointer, the very first function that is unwound must save the frame pointer. That way the frame diff --git gcc/config/aarch64/aarch64.md gcc/config/aarch64/aarch64.md index 1cca0f5..ae69c04 100644 --- gcc/config/aarch64/aarch64.md +++ gcc/config/aarch64/aarch64.md @@ -295,6 +295,7 @@ UNSPEC_LD1RO UNSPEC_SALT_ADDR UNSPECV_PATCHABLE_AREA + UNSPEC_MACHOPIC_OFFSET ]) (define_c_enum "unspecv" [ @@ -841,6 +842,37 @@ [(set_attr "type" "load_4")] ) +(define_insn "prefetch_unscaled" + [(prefetch (match_operand:DI 0 "aarch64_unscaled_prefetch_operand" "Du") + (match_operand:QI 1 "const_int_operand" "") + (match_operand:QI 2 "const_int_operand" ""))] + "" + { + const char * pftype[2][4] = + { + {"prfum\\tPLDL1STRM, %0", + "prfum\\tPLDL3KEEP, %0", + "prfum\\tPLDL2KEEP, %0", + "prfum\\tPLDL1KEEP, %0"}, + {"prfum\\tPSTL1STRM, %0", + "prfum\\tPSTL3KEEP, %0", + "prfum\\tPSTL2KEEP, %0", + "prfum\\tPSTL1KEEP, %0"}, + }; + + int locality = INTVAL (operands[2]); + + gcc_assert (IN_RANGE (locality, 0, 3)); + + /* PRFUM accepts the same addresses as a 64-bit LDR so wrap + the address into a DImode MEM so that aarch64_print_operand knows + how to print it. */ + operands[0] = gen_rtx_MEM (DImode, operands[0]); + return pftype[INTVAL(operands[1])][locality]; + } + [(set_attr "type" "load_4")] +) + (define_insn "trap" [(trap_if (const_int 1) (const_int 8))] "" @@ -6708,7 +6740,10 @@ (lo_sum:P (match_operand:P 1 "register_operand" "r") (match_operand 2 "aarch64_valid_symref" "S")))] "" - "add\\t%0, %1, :lo12:%c2" + { return TARGET_MACHO + ? "add\\t%0, %1, %K2" + : "add\\t%0, %1, :lo12:%c2"; + } [(set_attr "type" "alu_imm")] ) @@ -6719,7 +6754,10 @@ (match_operand:PTR 2 "aarch64_valid_symref" "S")))] UNSPEC_GOTSMALLPIC))] "" - "ldr\\t%0, [%1, #:got_lo12:%c2]" + { return TARGET_MACHO + ? "ldr\\t%0, [%1, %O2]" + : "ldr\\t%0, [%1, #:got_lo12:%c2]"; + } [(set_attr "type" "load_")] ) diff --git gcc/config/aarch64/aarch64.opt gcc/config/aarch64/aarch64.opt index 32191cf..2c5c503 100644 --- gcc/config/aarch64/aarch64.opt +++ gcc/config/aarch64/aarch64.opt @@ -152,6 +152,13 @@ Enum(aarch64_abi) String(ilp32) Value(AARCH64_ABI_ILP32) EnumValue Enum(aarch64_abi) String(lp64) Value(AARCH64_ABI_LP64) +EnumValue +Enum(aarch64_abi) String(darwinpcs) Value(AARCH64_ABI_LP64) + +m64 +Target RejectNegative Alias(mabi=, darwinpcs) +On Darwin for compatibility with other platform variants. + mpc-relative-literal-loads Target Save Var(pcrelative_literal_loads) Init(2) Save PC relative literal loads. diff --git gcc/config/aarch64/constraints.md gcc/config/aarch64/constraints.md index 3b49b45..ef399a5 100644 --- gcc/config/aarch64/constraints.md +++ gcc/config/aarch64/constraints.md @@ -474,6 +474,11 @@ An address valid for a prefetch instruction." (match_test "aarch64_address_valid_for_prefetch_p (op, true)")) +(define_address_constraint "Du" + "@internal + An address valid for a prefetch instruction with an unscaled offset." + (match_test "aarch64_address_valid_for_unscaled_prefetch_p (op, true)")) + (define_constraint "vgb" "@internal A constraint that matches an immediate offset valid for SVE LD1B diff --git gcc/config/aarch64/darwin.h gcc/config/aarch64/darwin.h new file mode 100644 index 0000000..2a855c1 --- /dev/null +++ gcc/config/aarch64/darwin.h @@ -0,0 +1,280 @@ +/* Target definitions for Arm64/Aarch64 running on macOS/iOS. + +Copyright The GNU Toolchain Authors. +Contributed by Iain Sandoe. + +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 +. */ + +/* Enable Mach-O bits in generic Aarch64 code. */ +#undef TARGET_MACHO +#define TARGET_MACHO 1 + +#undef DARWIN_ARM64 +#define DARWIN_ARM64 1 + +/* FIXME FIXME FIXME - these are mostly guesses right now. */ + +/* FIXME: this is only used in generic code in darwin.c. */ +#undef TARGET_64BIT +#define TARGET_64BIT 1 + +#undef PTRDIFF_TYPE +#define PTRDIFF_TYPE "long int" + +/* NOTE that arm64_32 is a valid thing and corresponds to darwinpcs + and TARGET_ILP32, but we are not implementing that for now. */ +#define TARGET_OS_CPP_BUILTINS() \ + do { \ + builtin_define ("__LITTLE_ENDIAN__"); \ + builtin_define ("__arm64"); \ + builtin_define ("__arm64__"); \ + darwin_cpp_builtins (pfile); \ + } while (0) + +/* In Darwin's arm64 ABI, chars are signed, for consistency with other Darwin + architectures. */ + +#undef DEFAULT_SIGNED_CHAR +#define DEFAULT_SIGNED_CHAR 1 + +#undef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE 64 + +/* Disable custom function descriptors on Darwin, it breaks ABI. */ +#undef AARCH64_CUSTOM_FUNCTION_TEST +#define AARCH64_CUSTOM_FUNCTION_TEST 0 + +/* Non-PIE executables are forbidden by the aarch64-darwin security model; + remove the option from link-lines since they just produce a warning from + ld64 and are then ignored anyway. */ +#undef DARWIN_NOPIE_SPEC +#define DARWIN_NOPIE_SPEC \ +" % 10years). Any symbol that is not 'global' and does not begin + with 'L' (the local symbol designation) is counted as 'linker visible'. + * does _not_ support 'static' code in the user space + + Everything needs to be invoked using the dynamic linker (`dyld`). There is + neither crt0.o nor a static edition of libc. + +Some versions of Darwin have used 'static' code for kernel modules. +FIXME: ??? what is the kernel model here. + +### Darwin Relocations and Assembler syntax + +* `Mach-O` for `Arm64` uses a reduced set of relocations c.f. the ELF set. + + There are only 11 entries but the relocation format allows for multiple sizes +(1, 2, 4, 8) where that's appropriate, and for ancillary data (e.g. a scale), +so the actual number of permutations is larger. + +* Generally, Darwin supports relocations of the form A - B + signed const + + A must be known (i.e. defined in the current TU). + +* `Mach-O` for `Arm64` has postfix assembler syntax. + + Where there's an assembly language representation for the relocation type + it appears after the name (e.g. `foo@PAGE` in contrast to the ELF + `:got:foo`). + +#### Relocs list + +For pointers (no source representation). + +`ARM64_RELOC_UNSIGNED = 0` + +Must be followed by an `ARM64_RELOC_UNSIGNED` + +`ARM64_RELOC_SUBTRACTOR = 1` + +A B/BL instruction with 26-bit displacement. +(no source representation) + +`ARM64_RELOC_BRANCH26 = 2` + +PC-rel distance to page of target [adrp]. + +`foo@PAGE` + +`ARM64_RELOC_PAGE21 = 3` + +Offset within page, scaled by r_length [add imm, ld/st]. + +`foo@PAGEOFF` + +`ARM64_RELOC_PAGEOFF12 = 4` + +PC-rel distance to page of GOT slot [adrp]. + +`foo@GOTPAGE` +`ARM64_RELOC_GOT_LOAD_PAGE21 = 5` + +Offset within page of GOT slot, scaled by r_length [add imm, ld/st]. + +`foo@GOTPAGEOFF` + +`ARM64_RELOC_GOT_LOAD_PAGEOFF12 = 6` + + +For pointers to GOT slots. +(4 and 8 byte versions) + +`foo@GOT` + +`ARM64_RELOC_POINTER_TO_GOT = 7` + + +PC-rel distance to page of TLVP slot [adrp]. + +`foo@TVLPPAGE` + +`ARM64_RELOC_TLVP_LOAD_PAGE21 = 8` + +Offset within page of TLVP slot, scaled by r_length [add imm, ld/st]. + +`foo@TVLPPAGEOFF` + +`ARM64_RELOC_TLVP_LOAD_PAGEOFF12 = 9` + +Must be followed by `ARM64_RELOC_PAGE21` or `ARM64_RELOC_PAGEOFF12`. +(no source representation) + +The addend is a signed 24bit quantity (+/- 8M range). + +`ARM64_RELOC_ADDEND = 10` + +## PART 2 - GCC-12 deviations from the PCS and supporting information. + +### D.3 is not yet supported (github issue #74) + + GCC promotes in the callee not the caller. + +### Support for nested functions + + GCC provides nested functions which are used overtly from C but also to + implement some parts of Ada and Fortran. + + This requires assigning a register to act as the STATIC CHAIN. + For GCC-12 this is X16 + + Support for nested function trampolines is provided by a heap-based table. + +### Support for __float128 + + The darwinpcs has no provision for a 128bit float type. + GCC-12 supports IEEE741 128bit float values by sof-float. + The ABI used for __float128 matches that for AAPCS64 + +## End. + diff --git gcc/config/aarch64/falkor-tag-collision-avoidance.c gcc/config/aarch64/falkor-tag-collision-avoidance.c index de214e4..6b16cd4 100644 --- gcc/config/aarch64/falkor-tag-collision-avoidance.c +++ gcc/config/aarch64/falkor-tag-collision-avoidance.c @@ -740,7 +740,7 @@ dump_insn_list (const rtx &t, const insn_info_list_t &insn_info, void *unused ATTRIBUTE_UNUSED) { gcc_assert (dump_file); - fprintf (dump_file, "Tag 0x%lx ::\n", INTVAL (t)); + fprintf (dump_file, "Tag 0x%lx ::\n", (long unsigned int)INTVAL (t)); for (unsigned i = 0; i < insn_info.length (); i++) dump_insn_slim (dump_file, insn_info[i]->insn); diff --git gcc/config/aarch64/host-aarch64-darwin.c gcc/config/aarch64/host-aarch64-darwin.c new file mode 100644 index 0000000..d70f2df --- /dev/null +++ gcc/config/aarch64/host-aarch64-darwin.c @@ -0,0 +1,33 @@ +/* aarch64/arm64-darwin host-specific hook definitions. + +Copyright The GNU Toolchain Authors. + +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 +. */ + +#define IN_TARGET_CODE 1 + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "hosthooks.h" +#include "hosthooks-def.h" +#include "config/host-darwin.h" + +/* Darwin doesn't do anything special for arm64/aarch64 hosts; this file + exists just to include the generic config/host-darwin.h. */ + +const struct host_hooks host_hooks = HOST_HOOKS_INITIALIZER; diff --git gcc/config/aarch64/predicates.md gcc/config/aarch64/predicates.md index 49f02ae..e2af7bf 100644 --- gcc/config/aarch64/predicates.md +++ gcc/config/aarch64/predicates.md @@ -257,9 +257,24 @@ (define_predicate "aarch64_prefetch_operand" (match_test "aarch64_address_valid_for_prefetch_p (op, false)")) +(define_predicate "aarch64_unscaled_prefetch_operand" + (match_test "aarch64_address_valid_for_unscaled_prefetch_p (op, false)")) + (define_predicate "aarch64_valid_symref" (match_code "const, symbol_ref, label_ref") { + if (TARGET_MACHO) + { + rtx x = op; + rtx offset; + split_const (x, &x, &offset); + if (GET_CODE (x) == CONST) + x = XEXP (x, 0); + if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_SALT_ADDR) + x = XVECEXP (x, 0, 0); + if (SYMBOL_REF_P (x) && INTVAL (offset) < 0) + return false; + } return (aarch64_classify_symbolic_expression (op) != SYMBOL_FORCE_TO_MEM); }) diff --git gcc/config/aarch64/t-aarch64-darwin gcc/config/aarch64/t-aarch64-darwin new file mode 100644 index 0000000..a8bfcff --- /dev/null +++ gcc/config/aarch64/t-aarch64-darwin @@ -0,0 +1,25 @@ +# Machine description for AArch64 architecture. +# 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 +# . + +LIB1ASMSRC = aarch64/lib1funcs.asm +LIB1ASMFUNCS = _aarch64_sync_cache_range + +# FIXME - figure out what multilib provisions we should make for +# a) arm64e +# b) arm64_32 diff --git gcc/config/aarch64/x-darwin gcc/config/aarch64/x-darwin new file mode 100644 index 0000000..6d788d5 --- /dev/null +++ gcc/config/aarch64/x-darwin @@ -0,0 +1,3 @@ +host-aarch64-darwin.o : $(srcdir)/config/aarch64/host-aarch64-darwin.c + $(COMPILE) $< + $(POSTCOMPILE) diff --git gcc/config/avr/avr.c gcc/config/avr/avr.c index 3a250df..4d29e80 100644 --- gcc/config/avr/avr.c +++ gcc/config/avr/avr.c @@ -10221,10 +10221,9 @@ avr_output_bss_section_asm_op (const void *data) /* Unnamed section callback for progmem*.data sections. */ static void -avr_output_progmem_section_asm_op (const void *data) +avr_output_progmem_section_asm_op (const char *data) { - fprintf (asm_out_file, "\t.section\t%s,\"a\",@progbits\n", - (const char*) data); + fprintf (asm_out_file, "\t.section\t%s,\"a\",@progbits\n", data); } diff --git gcc/config/darwin-driver.c gcc/config/darwin-driver.c index 61cbdff..9db19e6 100644 --- gcc/config/darwin-driver.c +++ gcc/config/darwin-driver.c @@ -144,7 +144,7 @@ darwin_find_version_from_kernel (void) if (sysctl (osversion_name, ARRAY_SIZE (osversion_name), osversion, &osversion_len, NULL, 0) == -1) { - warning (0, "sysctl for kern.osversion failed: %m"); + warning (0, "% for % failed: %m"); return NULL; } @@ -183,7 +183,7 @@ darwin_find_version_from_kernel (void) return new_flag; parse_failed: - warning (0, "couldn%'t understand kern.osversion %q.*s", + warning (0, "could not understand % %q.*s", (int) osversion_len, osversion); return NULL; } @@ -223,7 +223,7 @@ darwin_default_min_version (void) const char *checked = validate_macosx_version_min (new_flag); if (checked == NULL) { - warning (0, "could not understand version %s", new_flag); + warning (0, "could not understand version %qs", new_flag); return NULL; } new_flag = xstrndup (checked, strlen (checked)); @@ -268,14 +268,21 @@ darwin_driver_init (unsigned int *decoded_options_count, bool seenX86_64 = false; bool seenPPC = false; bool seenPPC64 = false; +#if !DARWIN_ARM64 + bool seenArm64 = false; bool seenM32 = false; bool seenM64 = false; bool appendM32 = false; bool appendM64 = false; +#endif const char *vers_string = NULL; bool seen_version_min = false; bool seen_sysroot_p = false; bool noexport_p = true; +#ifdef RPATH_SETS_NODEFAULT + bool seen_rpath_p = false; + bool seen_nodefaultrpaths_p = false; +#endif for (i = 1; i < *decoded_options_count; i++) { @@ -296,8 +303,14 @@ darwin_driver_init (unsigned int *decoded_options_count, seenPPC = true; else if (!strcmp ((*decoded_options)[i].arg, "ppc64")) seenPPC64 = true; + else if (!strcmp ((*decoded_options)[i].arg, "arm64")) +#if !DARWIN_ARM64 + seenArm64 = true; +#else + ; /* We accept the option, but don't need to act on it. */ +#endif else - error ("this compiler does not support %s", + error ("this compiler does not support %qs", (*decoded_options)[i].arg); /* Now we've examined it, drop the -arch arg. */ if (*decoded_options_count > i) { @@ -309,7 +322,7 @@ darwin_driver_init (unsigned int *decoded_options_count, --i; --*decoded_options_count; break; - +#if !DARWIN_ARM64 case OPT_m32: seenM32 = true; break; @@ -317,6 +330,7 @@ darwin_driver_init (unsigned int *decoded_options_count, case OPT_m64: seenM64 = true; break; +#endif case OPT_mmacosx_version_min_: seen_version_min = true; @@ -349,8 +363,16 @@ darwin_driver_init (unsigned int *decoded_options_count, gcc_checking_assert ((*decoded_options)[i].arg); if (strncmp ((*decoded_options)[i].arg, "-exported_symbol", 16) == 0) noexport_p = false; +#ifdef RPATH_SETS_NODEFAULT + else if (strncmp ((*decoded_options)[i].arg, "-rpath", 6) == 0) + seen_rpath_p = true; +#endif break; +#ifdef RPATH_SETS_NODEFAULT + case OPT_nodefaultrpaths: + seen_nodefaultrpaths_p = true; +#endif default: break; } @@ -359,53 +381,75 @@ darwin_driver_init (unsigned int *decoded_options_count, /* Turn -arch xxxx into the appropriate -m32/-m64 flag. If the User tried to specify multiple arch flags (which is possible with some Darwin compilers) warn that this mode is not supported by this - compiler (and ignore the arch flags, which means that the default multi- - lib will be generated). */ + compiler. We take arch specifiers that agree with the default multilib + as the first choice and reject others. */ /* TODO: determine if these warnings would better be errors. */ #if DARWIN_X86 if (seenPPC || seenPPC64) - warning (0, "this compiler does not support PowerPC (arch flags ignored)"); + warning (0, "this compiler does not support PowerPC" + " (%<-arch%> option ignored)"); + else if (seenArm64) + warning (0, "this compiler does not support Arm64" + " (%<-arch%> option ignored)"); if (seenX86) { if (seenX86_64 || seenM64) - warning (0, "%s conflicts with i386 (arch flags ignored)", - (seenX86_64? "x86_64": "m64")); - else if (! seenM32) /* Add -m32 if the User didn't. */ + { + const char *op = (seenX86_64? "-arch x86_64": "-m64"); + warning (0, "%qs conflicts with %<-arch i386%> (%qs ignored)", + op, op); + } + if (! seenM32) /* Add -m32 if the User didn't. */ appendM32 = true; } else if (seenX86_64) { - if (seenX86 || seenM32) - warning (0, "%s conflicts with x86_64 (arch flags ignored)", - (seenX86? "i386": "m32")); - else if (! seenM64) /* Add -m64 if the User didn't. */ + if (seenM32) + warning (0, "%<-m32%> conflicts with %<-arch x86_64%>" + " (%<-m32%> ignored)"); + if (! seenM64) /* Add -m64 if the User didn't. */ appendM64 = true; } #elif DARWIN_PPC if (seenX86 || seenX86_64) - warning (0, "this compiler does not support X86 (arch flags ignored)"); + warning (0, "this compiler does not support x86" + " (%<-arch%> option ignored)"); + else if (seenArm64) + warning (0, "this compiler does not support Arm64" + " (%<-arch%> option ignored)"); if (seenPPC) { if (seenPPC64 || seenM64) - warning (0, "%s conflicts with ppc (arch flags ignored)", - (seenPPC64? "ppc64": "m64")); - else if (! seenM32) /* Add -m32 if the User didn't. */ + { + const char *op = (seenPPC64? "-arch ppc64": "-m64"); + warning (0, "%qs conflicts with %<-arch ppc%> (%qs ignored)", + op, op); + } + if (! seenM32) /* Add -m32 if the User didn't. */ appendM32 = true; } else if (seenPPC64) { - if (seenPPC || seenM32) - warning (0, "%s conflicts with ppc64 (arch flags ignored)", - (seenPPC? "ppc": "m32")); - else if (! seenM64) /* Add -m64 if the User didn't. */ + if (seenM32) + warning (0, "%<-m32%> conflicts with %<-arch ppc64%>" + " (%<-m32%> ignored)"); + if (! seenM64) /* Add -m64 if the User didn't. */ appendM64 = true; } +#elif DARWIN_ARM64 + if (seenPPC || seenPPC64) + warning (0, "this compiler does not support PowerPC" + " (%<-arch%> option ignored)"); + if (seenX86 || seenX86_64) + warning (0, "this compiler does not support x86" + " (%<-arch%> option ignored)"); #endif /* If there is nothing else on the command line, do not add sysroot etc. */ if (*decoded_options_count <= 1) return; +#if !DARWIN_ARM64 if (appendM32 || appendM64) { ++*decoded_options_count; @@ -415,6 +459,7 @@ darwin_driver_init (unsigned int *decoded_options_count, generate_option (appendM32 ? OPT_m32 : OPT_m64, NULL, 1, CL_DRIVER, &(*decoded_options)[*decoded_options_count - 1]); } +#endif if (!seen_sysroot_p) { @@ -482,4 +527,16 @@ darwin_driver_init (unsigned int *decoded_options_count, generate_option (OPT_nodefaultexport, NULL, 1, CL_DRIVER, &(*decoded_options)[*decoded_options_count - 1]); } + +#ifdef RPATH_SETS_NODEFAULT + if (seen_rpath_p && !seen_nodefaultrpaths_p) + { + ++*decoded_options_count; + *decoded_options = XRESIZEVEC (struct cl_decoded_option, + *decoded_options, + *decoded_options_count); + generate_option (OPT_nodefaultrpaths, NULL, 1, CL_DRIVER, + &(*decoded_options)[*decoded_options_count - 1]); + } +#endif } diff --git gcc/config/darwin.c gcc/config/darwin.c index b79c0d1..82fa868 100644 --- gcc/config/darwin.c +++ gcc/config/darwin.c @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see #include "explow.h" #include "expr.h" #include "langhooks.h" +#include "targhooks.h" #include "toplev.h" #include "lto-section-names.h" #include "intl.h" @@ -115,7 +116,7 @@ static bool ld_init_term_start_labels = false; section * darwin_sections[NUM_DARWIN_SECTIONS]; /* While we transition to using in-tests instead of ifdef'd code. */ -#if !HAVE_lo_sum +#if !HAVE_lo_sum || DARWIN_ARM64 #define gen_macho_high(m,a,b) (a) #define gen_macho_low(m,a,b,c) (a) #endif @@ -131,7 +132,7 @@ int emit_aligned_common = false; DIRECTIVE is as for output_section_asm_op. */ static void -output_objc_section_asm_op (const void *directive) +output_objc_section_asm_op (const char *directive) { static bool been_here = false; @@ -1049,6 +1050,7 @@ machopic_legitimize_pic_address (rtx orig, machine_mode mode, rtx reg) return pic_ref; } +#if !DARWIN_ARM64 /* Callbacks to output the stub or non-lazy pointers. Each works on the item in *SLOT,if it has been used. DATA is the FILE* for assembly output. @@ -1204,6 +1206,7 @@ machopic_finish (FILE *asm_out_file) machopic_indirections->traverse_noresize (asm_out_file); } +#endif int machopic_operand_p (rtx op) @@ -1933,6 +1936,8 @@ darwin_label_is_anonymous_local_objc_name (const char *name) } else if (!strncmp ((const char *)p, "ClassMethods", 12)) return false; + else if (!strncmp ((const char *)p, "ClassProtocols", 14)) + return false; else if (!strncmp ((const char *)p, "Instance", 8)) { if (p[8] == 'I' || p[8] == 'M') @@ -2236,6 +2241,8 @@ darwin_emit_except_table_label (FILE *file) rtx darwin_make_eh_symbol_indirect (rtx orig, bool ARG_UNUSED (pubvis)) { + if (DARWIN_ARM64) + return orig; if (DARWIN_PPC == 0 && TARGET_64BIT) return orig; @@ -3056,7 +3063,12 @@ darwin_file_end (void) fprintf (asm_out_file, "\t.long\t0\n\t.long\t%u\n", flags); } +#if !DARWIN_ARM64 machopic_finish (asm_out_file); +#else + gcc_checking_assert (!machopic_indirections); +#endif + if (flag_apple_kext) { /* These sections are only used for kernel code. */ @@ -3618,7 +3630,7 @@ tree darwin_fold_builtin (tree fndecl, int n_args, tree *argp, bool ARG_UNUSED (ignore)) { - unsigned int fcode = DECL_MD_FUNCTION_CODE (fndecl); + int fcode = DECL_MD_FUNCTION_CODE (fndecl); if (fcode == darwin_builtin_cfstring) { @@ -3646,19 +3658,22 @@ darwin_rename_builtins (void) { } +/* Implementation for the TARGET_LIBC_HAS_FUNCTION hook. */ + bool darwin_libc_has_function (enum function_class fn_class, tree type ATTRIBUTE_UNUSED) { - if (fn_class == function_sincos) + if (fn_class == function_sincos && darwin_macosx_version_min) return (strverscmp (darwin_macosx_version_min, "10.9") >= 0); - +#if DARWIN_PPC && SUPPORT_DARWIN_LEGACY if (fn_class == function_c99_math_complex || fn_class == function_c99_misc) return (TARGET_64BIT - || strverscmp (darwin_macosx_version_min, "10.3") >= 0); - - return true; + || (darwin_macosx_version_min && + strverscmp (darwin_macosx_version_min, "10.3") >= 0)); +#endif + return default_libc_has_function (fn_class, type); } hashval_t diff --git gcc/config/darwin.h gcc/config/darwin.h index 504dfce..22bacd4 100644 --- gcc/config/darwin.h +++ gcc/config/darwin.h @@ -42,6 +42,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define DARWIN_X86 0 #define DARWIN_PPC 0 +#define DARWIN_ARM64 0 + +#define OBJECT_FORMAT_MACHO 1 /* Suppress g++ attempt to link in the math library automatically. */ #define MATH_LIBRARY "" @@ -275,13 +278,17 @@ extern GTY(()) int darwin_ms_struct; #define DARWIN_RDYNAMIC "%{rdynamic:%nrdynamic is not supported}" #endif -/* FIXME: we should check that the linker supports the -pie and -no_pie. +/* Code built with mdynamic-no-pic does not support PIE/PIC, so we disallow + these combinations; we also ensure that the no_pie option is passed to + ld64 on system versions that default to PIE when mdynamic-no-pic is given. + FIXME: we should check that the linker supports the -pie and -no_pie. options. */ #define DARWIN_PIE_SPEC \ "%{pie|fpie|fPIE:\ %{mdynamic-no-pic: \ %n'-mdynamic-no-pic' overrides '-pie', '-fpie' or '-fPIE'; \ - :%:version-compare(>= 10.5 mmacosx-version-min= -pie) }} " + :%:version-compare(>= 10.5 mmacosx-version-min= -pie) }; \ + mdynamic-no-pic:%:version-compare(>= 10.7 mmacosx-version-min= -no_pie) } " #define DARWIN_NOPIE_SPEC \ "%{no-pie|fno-pie|fno-PIE: \ @@ -290,6 +297,31 @@ extern GTY(()) int darwin_ms_struct; #define DARWIN_CC1_SPEC \ "% 10.11 mmacosx-version-min= -lgcc_s.1.1) \ + %:version-compare(>= 10.11 mmacosx-version-min= -lemutls_w) " +#endif + +/* We might elect to add a path even when this compiler does not use embedded + run paths, so that we can use libraries from an alternate compiler that is + using embedded runpaths. */ +#if DARWIN_DO_EXTRA_RPATH +# define DARWIN_EXTRA_RPATH \ +"%{!r:%{!nostdlib:%{!nodefaultrpaths:\ + %:version-compare(>= 10.5 mmacosx-version-min= -rpath) \ + %:version-compare(>= 10.5 mmacosx-version-min= " DARWIN_ADD_RPATH ") \ + }}}" +#else +# define DARWIN_EXTRA_RPATH "" +#endif + #define SUBSUBTARGET_OVERRIDE_OPTIONS \ do { \ darwin_override_options (); \ @@ -381,7 +413,9 @@ extern GTY(()) int darwin_ms_struct; DARWIN_NOPIE_SPEC \ DARWIN_RDYNAMIC \ DARWIN_NOCOMPACT_UNWIND \ - "}}}}}}} %= 10.6, the unwinder *still* comes from libSystem and - we find the emutls impl from lemutls_w. In either case, the builtins etc. - are linked from -lgcc. - - When we have specified shared-libgcc or any case that might require - exceptions, we pull the libgcc content (including emulated tls) from - -lgcc_s.1 in GCC and the unwinder from /usr/lib/libgcc_s.1 for < 10.6 and - libSystem for >= 10.6 respectively. - Otherwise, we just link the emutls/builtins from convenience libs. - - If we need exceptions, prior to 10.3.9, then we have to link the static - eh lib, since there's no shared version on the system. - - In all cases, libgcc_s.1 will be installed with the compiler, or any app - built using it, so we can link the builtins and emutls shared on all. - We have to work around that DYLD_XXXX are disabled in macOS 10.11+ which means that any bootstrap trying to use a shared libgcc with a bumped SO- name will fail. This means that we do not accept shared libgcc for these - versions. + versions, unless we have embedded run paths enabled, in which case the + compiler will add the appropriate path to find the library. + + For -static-libgcc: < 10.6, use the unwinder in libgcc_eh (and find + the emultls impl. there too). For -static-libgcc: >= 10.6, the unwinder *still* comes from libSystem and we find the emutls impl from lemutls_w. In either case, the builtins etc. are linked from -lgcc. -> + Otherwise, we just link the shared version of gcc_s.1.1 and pick up exceptions: * Prior to 10.3.9, then we have to link the static eh lib, since there @@ -496,6 +515,10 @@ extern GTY(()) int darwin_ms_struct; In all cases, libgcc_s.1.1 will be installed with the compiler, or any app built using it, so we can link the builtins and emutls shared on all. + + On most Darwin systems (other than Arm64) we will also install a legacy + support libgcc_s.1.dylib to support executables linked with libgcc_ext by + earlier GCC versions. */ #undef REAL_LIBGCC_SPEC #define REAL_LIBGCC_SPEC \ @@ -503,8 +526,7 @@ extern GTY(()) int darwin_ms_struct; %:version-compare(!> 10.6 mmacosx-version-min= -lgcc_eh) \ %:version-compare(>= 10.6 mmacosx-version-min= -lemutls_w); \ shared-libgcc|fexceptions|fobjc-exceptions|fgnu-runtime: \ - %:version-compare(!> 10.11 mmacosx-version-min= -lgcc_s.1.1) \ - %:version-compare(>= 10.11 mmacosx-version-min= -lemutls_w) \ + " DARWIN_SHARED_LIBGCC " \ %:version-compare(!> 10.3.9 mmacosx-version-min= -lgcc_eh) \ %:version-compare(>< 10.3.9 10.5 mmacosx-version-min= -lgcc_s.10.4) \ %:version-compare(>< 10.5 10.6 mmacosx-version-min= -lgcc_s.10.5); \ @@ -539,7 +561,8 @@ extern GTY(()) int darwin_ms_struct; { "darwin_crt2", DARWIN_CRT2_SPEC }, \ { "darwin_crt3", DARWIN_CRT3_SPEC }, \ { "darwin_dylib1", DARWIN_DYLIB1_SPEC }, \ - { "darwin_bundle1", DARWIN_BUNDLE1_SPEC }, + { "darwin_bundle1", DARWIN_BUNDLE1_SPEC }, \ + { "darwin_rpaths", DARWIN_RPATH_SPEC }, #define DARWIN_CRT1_SPEC \ "%:version-compare(!> 10.5 mmacosx-version-min= -lcrt1.o) \ @@ -565,6 +588,17 @@ extern GTY(()) int darwin_ms_struct; "%{!static:%:version-compare(< 10.6 mmacosx-version-min= -lbundle1.o) \ %{fgnu-tm: -lcrttms.o}}" +#if DARWIN_AT_RPATH +/* A default rpath, that picks up dependent libraries installed in the same + director as one being loaded. */ +#define DARWIN_RPATH_SPEC \ + "%:version-compare(>= 10.5 mmacosx-version-min= -rpath) \ + %:version-compare(>= 10.5 mmacosx-version-min= @loader_path) \ + %P " +#else +#define DARWIN_RPATH_SPEC "" +#endif + #ifdef HAVE_AS_MMACOSX_VERSION_MIN_OPTION /* Emit macosx version (but only major). */ #define ASM_MMACOSX_VERSION_MIN_SPEC \ diff --git gcc/config/darwin.opt gcc/config/darwin.opt index 48d3aa9..2a435c5 100644 --- gcc/config/darwin.opt +++ gcc/config/darwin.opt @@ -237,6 +237,10 @@ nodefaultexport Driver RejectNegative Do not add a default symbol exports to modules or dynamic libraries. +nodefaultrpaths +Driver RejectNegative +Do not add default run paths (for the compiler library directories) to executables, modules or dynamic libraries. + nofixprebinding Driver RejectNegative (Obsolete after 10.3.9) Set MH_NOPREFIXBINDING, in an executable. diff --git gcc/config/host-darwin.c gcc/config/host-darwin.c index 14a01fe..b578767 100644 --- gcc/config/host-darwin.c +++ gcc/config/host-darwin.c @@ -20,62 +20,164 @@ #include "config.h" #include "system.h" #include "coretypes.h" +#include "options.h" #include "diagnostic-core.h" #include "config/host-darwin.h" - -/* Yes, this is really supposed to work. */ -/* This allows for a pagesize of 16384, which we have on Darwin20, but should - continue to work OK for pagesize 4096 which we have on earlier versions. - The size is 1 (binary) Gb. */ -static char pch_address_space[65536*16384] __attribute__((aligned (16384))); - -/* Return the address of the PCH address space, if the PCH will fit in it. */ +#include + +/* For Darwin (macOS only) platforms, without ASLR (PIE) enabled on the + binaries, the following VM addresses are expected to be available. + NOTE, that for aarch64, ASLR is always enabled - but the VM address + mentioned below is available (at least on Darwin20). + + The spaces should all have 512Mb available c.f. PCH files for large + C++ or Objective-C in the range of 150Mb for 64b hosts. + + We also try to steer clear of places already used for sanitizers. + + If the allocation fails at the 'ideal' address, we go with what the + kernel provides (there is more likelihood that we will need to relocate + on read in). */ + +#define PAGE_SZ 4096 +#if defined(__x86_64) && defined(__LP64__) +# define TRY_EMPTY_VM_SPACE 0x180000000000ULL +#elif defined(__x86_64) +# define TRY_EMPTY_VM_SPACE 0x00006fe00000ULL +#elif defined(__i386) +# define TRY_EMPTY_VM_SPACE 0x00006fe00000ULL +#elif defined(__POWERPC__) && defined(__LP64__) +# define TRY_EMPTY_VM_SPACE 0x180000000000ULL +#elif defined(__POWERPC__) +# define TRY_EMPTY_VM_SPACE 0x00006fe00000ULL +#elif defined(__aarch64__) +# undef PAGE_SZ +# define PAGE_SZ 16384 +# define TRY_EMPTY_VM_SPACE 0x180000000000ULL +#else +# error "unknown Darwin target" +#endif + +/* Try to map a known position in the VM. The current PCH implementation + can adjust values at write-time, but not at read-time thus we need to + pick up the same position when reading as we got at write-time. */ void * -darwin_gt_pch_get_address (size_t sz, int fd ATTRIBUTE_UNUSED) +darwin_gt_pch_get_address (size_t sz, int fd) { - if (sz <= sizeof (pch_address_space)) - return pch_address_space; - else - return NULL; + /* First try with the constraint that we really want this address... */ + void *addr = mmap ((void *)TRY_EMPTY_VM_SPACE, sz, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED, fd, 0); + + if (addr != (void *) MAP_FAILED) + munmap (addr, sz); + + /* This ought to be the only alternative to failure, but there are comments + that suggest some versions of mmap can be buggy and return a different + value. */ + if (addr == (void *) TRY_EMPTY_VM_SPACE) + return addr; + + /* OK try to find a space without the constraint. */ + addr = mmap ((void *) TRY_EMPTY_VM_SPACE, sz, PROT_READ | PROT_WRITE, + MAP_PRIVATE, fd, 0); + + /* We return whatever the kernel gave us. */ + if (addr != (void *) MAP_FAILED) + { + /* Unmap the area before returning. */ + munmap (addr, sz); + return addr; + } + + /* Otherwise, try again but put some arbitrary buffer space first. */ + size_t buffer_size = 64 * 1024 * 1024; + void *buffer = mmap (0, buffer_size, PROT_NONE, + MAP_PRIVATE | MAP_ANON, -1, 0); + addr = mmap ((void *)TRY_EMPTY_VM_SPACE, sz, PROT_READ | PROT_WRITE, + MAP_PRIVATE, fd, 0); + + if (buffer != (void *) MAP_FAILED) + munmap (buffer, buffer_size); + + /* If we failed this time, that means there is *no* large enough free + space. */ + if (addr == (void *) MAP_FAILED) + { + error ("PCH memory not available %m"); + return NULL; + } + + munmap (addr, sz); + return addr; } -/* Check ADDR and SZ for validity, and deallocate (using munmap) that part of - pch_address_space beyond SZ. */ +/* Try to mmap the PCH file at ADDR for SZ bytes at OFF offset in the file. + If we succeed return 1, if we cannot mmap the desired address, then we + fail with -1. */ int -darwin_gt_pch_use_address (void *addr, size_t sz, int fd, size_t off) +darwin_gt_pch_use_address (void *&addr, size_t sz, int fd, size_t off) { - const size_t pagesize = getpagesize(); - void *mmap_result; - int ret; + void *mapped_addr; + + /* We're called with size == 0 if we're not planning to load a PCH + file at all. This allows the hook to free any static space that + we might have allocated at link time. */ + if (sz == 0) + return -1; - gcc_assert ((size_t)pch_address_space % pagesize == 0 - && sizeof (pch_address_space) % pagesize == 0); - - ret = (addr == pch_address_space && sz <= sizeof (pch_address_space)); - if (! ret) - sz = 0; + gcc_checking_assert (!(off % PAGE_SZ)); - /* Round the size to a whole page size. Normally this is a no-op. */ - sz = (sz + pagesize - 1) / pagesize * pagesize; + /* Try to map the file with MAP_PRIVATE and FIXED. */ + mapped_addr = mmap (addr, sz, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED, fd, (off_t) off); - if (munmap (pch_address_space + sz, sizeof (pch_address_space) - sz) != 0) - fatal_error (input_location, - "could not unmap %: %m"); + /* Hopefully, we succeed. */ + if (mapped_addr == addr) + return 1; - if (ret) + /* In theory, the only alternative to success for MAP_FIXED should be FAILED + however, there are some buggy earlier implementations that could return + an address. */ + if (mapped_addr != (void *) MAP_FAILED) + munmap (mapped_addr, sz); + + /* Try to map the file with MAP_PRIVATE but let the kernel move it. */ + mapped_addr = mmap (addr, sz, PROT_READ | PROT_WRITE, + MAP_PRIVATE, fd, (off_t) off); + + /* Hopefully, we succeed. */ + if (mapped_addr != (void *) MAP_FAILED) { - mmap_result = mmap (addr, sz, - PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, - fd, off); + addr = mapped_addr; + return 1; + } - /* The file might not be mmap-able. */ - ret = mmap_result != (void *) MAP_FAILED; + /* Try to make an anonymous private mmap at the desired location in case + the problem is in mapping the file. */ + mapped_addr = mmap (addr, sz, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, (off_t)0); + + /* If this fails, we are out of ideas (and maybe memory). */ + if (mapped_addr == (void *) MAP_FAILED) + return -1; + + addr = mapped_addr; + + if (lseek (fd, off, SEEK_SET) == (off_t) -1) + return -1; + + while (sz) + { + ssize_t nbytes; - /* Sanity check for broken MAP_FIXED. */ - gcc_assert (!ret || mmap_result == addr); + nbytes = read (fd, addr, MIN (sz, (size_t) -1 >> 1)); + if (nbytes <= 0) + return -1; + addr = (char *) addr + nbytes; + sz -= nbytes; } - return ret; + return 1; } diff --git gcc/config/host-darwin.h gcc/config/host-darwin.h index 4acae9c..f3a477e 100644 --- gcc/config/host-darwin.h +++ gcc/config/host-darwin.h @@ -18,7 +18,7 @@ . */ extern void * darwin_gt_pch_get_address (size_t sz, int fd); -extern int darwin_gt_pch_use_address (void *addr, size_t sz, int fd, +extern int darwin_gt_pch_use_address (void *&addr, size_t sz, int fd, size_t off); #undef HOST_HOOKS_GT_PCH_GET_ADDRESS diff --git gcc/config/host-hpux.c gcc/config/host-hpux.c index 6009810..796f501 100644 --- gcc/config/host-hpux.c +++ gcc/config/host-hpux.c @@ -24,7 +24,7 @@ #include "hosthooks-def.h" static void *hpux_gt_pch_get_address (size_t, int); -static int hpux_gt_pch_use_address (void *, size_t, int, size_t); +static int hpux_gt_pch_use_address (void *&, size_t, int, size_t); #undef HOST_HOOKS_GT_PCH_GET_ADDRESS #define HOST_HOOKS_GT_PCH_GET_ADDRESS hpux_gt_pch_get_address @@ -78,7 +78,7 @@ hpux_gt_pch_get_address (size_t size, int fd) little else we can do given the current PCH implementation. */ static int -hpux_gt_pch_use_address (void *base, size_t size, int fd, size_t offset) +hpux_gt_pch_use_address (void *&base, size_t size, int fd, size_t offset) { void *addr; diff --git gcc/config/host-linux.c gcc/config/host-linux.c index 34945f1..0481ecf 100644 --- gcc/config/host-linux.c +++ gcc/config/host-linux.c @@ -181,7 +181,7 @@ linux_gt_pch_get_address (size_t size, int fd) little else we can do given the current PCH implementation. */ static int -linux_gt_pch_use_address (void *base, size_t size, int fd, size_t offset) +linux_gt_pch_use_address (void *&base, size_t size, int fd, size_t offset) { void *addr; @@ -204,24 +204,22 @@ linux_gt_pch_use_address (void *base, size_t size, int fd, size_t offset) addr = mmap (base, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (addr != base) - { - if (addr != (void *) MAP_FAILED) - munmap (addr, size); - return -1; - } + if (addr == (void *) MAP_FAILED) + return -1; if (lseek (fd, offset, SEEK_SET) == (off_t)-1) return -1; + base = addr; + while (size) { ssize_t nbytes; - nbytes = read (fd, base, MIN (size, (size_t)-1 >> 1)); + nbytes = read (fd, addr, MIN (size, (size_t)-1 >> 1)); if (nbytes <= 0) return -1; - base = (char *) base + nbytes; + addr = (char *) addr + nbytes; size -= nbytes; } diff --git gcc/config/host-netbsd.c gcc/config/host-netbsd.c index 818ecb2..32f86c8 100644 --- gcc/config/host-netbsd.c +++ gcc/config/host-netbsd.c @@ -66,7 +66,7 @@ netbsd_gt_pch_get_address (size_t size, int fd) mapping the data at BASE, -1 if we couldn't. */ static int -netbsd_gt_pch_use_address (void *base, size_t size, int fd, size_t offset) +netbsd_gt_pch_use_address (void *&base, size_t size, int fd, size_t offset) { void *addr; diff --git gcc/config/host-openbsd.c gcc/config/host-openbsd.c index c5f8944..f7b9043 100644 --- gcc/config/host-openbsd.c +++ gcc/config/host-openbsd.c @@ -66,7 +66,7 @@ openbsd_gt_pch_get_address (size_t size, int fd) mapping the data at BASE, -1 if we couldn't. */ static int -openbsd_gt_pch_use_address (void *base, size_t size, int fd, size_t offset) +openbsd_gt_pch_use_address (void *&base, size_t size, int fd, size_t offset) { void *addr; diff --git gcc/config/host-solaris.c gcc/config/host-solaris.c index 556e9cf..b08cf51 100644 --- gcc/config/host-solaris.c +++ gcc/config/host-solaris.c @@ -105,7 +105,7 @@ sol_gt_pch_get_address (size_t size, int fd) mapping the data at BASE, -1 if we couldn't. */ static int -sol_gt_pch_use_address (void *base, size_t size, int fd, size_t offset) +sol_gt_pch_use_address (void *&base, size_t size, int fd, size_t offset) { void *addr; diff --git gcc/config/i386/darwin.h gcc/config/i386/darwin.h index 7c2211f..0ad6695 100644 --- gcc/config/i386/darwin.h +++ gcc/config/i386/darwin.h @@ -336,3 +336,15 @@ along with GCC; see the file COPYING3. If not see #undef SUBTARGET_SHADOW_OFFSET #define SUBTARGET_SHADOW_OFFSET \ (TARGET_LP64 ? HOST_WIDE_INT_1 << 44 : HOST_WIDE_INT_1 << 29) + +#undef CLEAR_INSN_CACHE +#define CLEAR_INSN_CACHE(beg, end) \ + extern void sys_icache_invalidate(void *start, size_t len); \ + sys_icache_invalidate ((beg), (size_t)((end)-(beg))) + +/* Disable custom function descriptors for Darwin when we have off-stack + trampolines. */ +#undef X86_CUSTOM_FUNCTION_TEST +#define X86_CUSTOM_FUNCTION_TEST \ + (!flag_off_stack_trampolines && !flag_trampolines) ? 1 : 0 + diff --git gcc/config/i386/host-mingw32.c gcc/config/i386/host-mingw32.c index 360a280..a182563 100644 --- gcc/config/i386/host-mingw32.c +++ gcc/config/i386/host-mingw32.c @@ -32,7 +32,7 @@ #include static void * mingw32_gt_pch_get_address (size_t, int); -static int mingw32_gt_pch_use_address (void *, size_t, int, size_t); +static int mingw32_gt_pch_use_address (void *&, size_t, int, size_t); static size_t mingw32_gt_pch_alloc_granularity (void); #undef HOST_HOOKS_GT_PCH_GET_ADDRESS @@ -118,7 +118,7 @@ mingw32_gt_pch_get_address (size_t size, int) if the memory is allocated but the data not loaded, return 1 if done. */ static int -mingw32_gt_pch_use_address (void *addr, size_t size, int fd, +mingw32_gt_pch_use_address (void *&addr, size_t size, int fd, size_t offset) { void * mmap_addr; diff --git gcc/config/i386/i386.c gcc/config/i386/i386.c index 6c9c99e..618fc39 100644 --- gcc/config/i386/i386.c +++ gcc/config/i386/i386.c @@ -23856,7 +23856,7 @@ ix86_run_selftests (void) #define TARGET_HARD_REGNO_SCRATCH_OK ix86_hard_regno_scratch_ok #undef TARGET_CUSTOM_FUNCTION_DESCRIPTORS -#define TARGET_CUSTOM_FUNCTION_DESCRIPTORS 1 +#define TARGET_CUSTOM_FUNCTION_DESCRIPTORS X86_CUSTOM_FUNCTION_TEST #undef TARGET_ADDR_SPACE_ZERO_ADDRESS_VALID #define TARGET_ADDR_SPACE_ZERO_ADDRESS_VALID ix86_addr_space_zero_address_valid diff --git gcc/config/i386/i386.h gcc/config/i386/i386.h index ac0e5da..bca8315 100644 --- gcc/config/i386/i386.h +++ gcc/config/i386/i386.h @@ -953,6 +953,12 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); /* Minimum allocation boundary for the code of a function. */ #define FUNCTION_BOUNDARY 8 +/* We will and with this value to test if a custom function descriptor needs + a static chain. The function boundary must the adjusted so that the bit + this represents is no longer part of the address. 0 Disables the custom + function descriptors. */ +#define X86_CUSTOM_FUNCTION_TEST 1 + /* C++ stores the virtual bit in the lowest bit of function pointers. */ #define TARGET_PTRMEMFUNC_VBIT_LOCATION ptrmemfunc_vbit_in_pfn diff --git gcc/config/pa/pa.c gcc/config/pa/pa.c index 341c5f0..8ac9c4b 100644 --- gcc/config/pa/pa.c +++ gcc/config/pa/pa.c @@ -10011,7 +10011,7 @@ pa_arg_partial_bytes (cumulative_args_t cum_v, const function_arg_info &arg) to the default text subspace. */ static void -som_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED) +som_output_text_section_asm_op (const char *data ATTRIBUTE_UNUSED) { gcc_assert (TARGET_SOM); if (TARGET_GAS) @@ -10055,7 +10055,7 @@ som_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED) sections. This function is only used with SOM. */ static void -som_output_comdat_data_section_asm_op (const void *data) +som_output_comdat_data_section_asm_op (const char *data) { in_section = NULL; output_section_asm_op (data); diff --git gcc/config/rs6000/rs6000.c gcc/config/rs6000/rs6000.c index eba5b20..1d4ed99 100644 --- gcc/config/rs6000/rs6000.c +++ gcc/config/rs6000/rs6000.c @@ -20241,7 +20241,7 @@ rs6000_ms_bitfield_layout_p (const_tree record_type) /* A get_unnamed_section callback, used for switching to toc_section. */ static void -rs6000_elf_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED) +rs6000_elf_output_toc_section_asm_op (const char *data ATTRIBUTE_UNUSED) { if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2) && TARGET_MINIMAL_TOC) @@ -20945,35 +20945,39 @@ rs6000_xcoff_asm_globalize_label (FILE *stream, const char *name) points to the section string variable. */ static void -rs6000_xcoff_output_readonly_section_asm_op (const void *directive) +rs6000_xcoff_output_readonly_section_asm_op (const char *directive) { fprintf (asm_out_file, "\t.csect %s[RO],%s\n", - *(const char *const *) directive, + directive + ? xcoff_private_rodata_section_name + : xcoff_read_only_section_name, XCOFF_CSECT_DEFAULT_ALIGNMENT_STR); } /* Likewise for read-write sections. */ static void -rs6000_xcoff_output_readwrite_section_asm_op (const void *directive) +rs6000_xcoff_output_readwrite_section_asm_op (const char *) { fprintf (asm_out_file, "\t.csect %s[RW],%s\n", - *(const char *const *) directive, + xcoff_private_data_section_name, XCOFF_CSECT_DEFAULT_ALIGNMENT_STR); } static void -rs6000_xcoff_output_tls_section_asm_op (const void *directive) +rs6000_xcoff_output_tls_section_asm_op (const char *directive) { fprintf (asm_out_file, "\t.csect %s[TL],%s\n", - *(const char *const *) directive, + directive + ? xcoff_private_data_section_name + : xcoff_tls_data_section_name, XCOFF_CSECT_DEFAULT_ALIGNMENT_STR); } /* A get_unnamed_section callback, used for switching to toc_section. */ static void -rs6000_xcoff_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED) +rs6000_xcoff_output_toc_section_asm_op (const char *data ATTRIBUTE_UNUSED) { if (TARGET_MINIMAL_TOC) { @@ -21000,26 +21004,26 @@ rs6000_xcoff_asm_init_sections (void) { read_only_data_section = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op, - &xcoff_read_only_section_name); + NULL); private_data_section = get_unnamed_section (SECTION_WRITE, rs6000_xcoff_output_readwrite_section_asm_op, - &xcoff_private_data_section_name); + NULL); read_only_private_data_section = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op, - &xcoff_private_rodata_section_name); + ""); tls_data_section = get_unnamed_section (SECTION_TLS, rs6000_xcoff_output_tls_section_asm_op, - &xcoff_tls_data_section_name); + NULL); tls_private_data_section = get_unnamed_section (SECTION_TLS, rs6000_xcoff_output_tls_section_asm_op, - &xcoff_private_data_section_name); + ""); toc_section = get_unnamed_section (0, rs6000_xcoff_output_toc_section_asm_op, NULL); diff --git gcc/configure gcc/configure index 327c596..5dfecce 100755 --- gcc/configure +++ gcc/configure @@ -634,6 +634,7 @@ LIBOBJS CET_HOST_FLAGS NO_PIE_FLAG NO_PIE_CFLAGS +enable_pie_tools enable_default_pie PICFLAG enable_host_shared @@ -737,6 +738,8 @@ ORIGINAL_PLUGIN_LD_FOR_TARGET gcc_cv_ld ORIGINAL_AS_FOR_TARGET gcc_cv_as +ENABLE_DARWIN_AT_RPATH_FALSE +ENABLE_DARWIN_AT_RPATH_TRUE enable_fast_install objdir OTOOL64 @@ -996,6 +999,8 @@ enable_static with_pic enable_fast_install enable_libtool_lock +enable_darwin_at_rpath +with_darwin_extra_rpath enable_ld enable_gold with_plugin_ld @@ -1026,6 +1031,7 @@ with_linker_hash_style with_diagnostics_color with_diagnostics_urls enable_default_pie +enable_pie_tools enable_cet enable_s390_excess_float_precision ' @@ -1729,6 +1735,8 @@ Optional Features: --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) + --enable-darwin-at-path install libraries with @rpath/library-name, requires + rpaths to be added to executables --enable-ld[=ARG] build ld [ARG={default,yes,no}] --enable-gold[=ARG] build gold [ARG={default,yes,no}] --enable-gnu-indirect-function @@ -1786,6 +1794,8 @@ Optional Features: --disable-libquadmath-support disable libquadmath support for Fortran --enable-default-pie enable Position Independent Executable as default + --enable-pie-tools build Position Independent Executables for the + compilers and other tools --enable-cet enable Intel CET in host libraries [default=auto] --enable-s390-excess-float-precision on s390 targets, evaluate float with double @@ -1846,6 +1856,9 @@ Optional Packages: --with-pic try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-darwin-extra-rpath=[ARG] + Specify a runpath directory, additional to those + provided by the compiler --with-plugin-ld=[ARG] specify the plugin linker --with-glibc-version=M.N assume GCC used with glibc version M.N or later @@ -3746,31 +3759,53 @@ gcc_gxx_libcxx_include_dir= if test "${with_gxx_libcxx_include_dir+set}" = set; then : withval=$with_gxx_libcxx_include_dir; case "${withval}" in yes) as_fn_error $? "bad value ${withval} given for libc++ include directory" "$LINENO" 5 ;; -no) ;; *) gcc_gxx_libcxx_include_dir=$with_gxx_libcxx_include_dir ;; esac fi +# --with-gxx-libcxx-include-dir controls the enabling of the -stdlib option. +# if --with-gxx-libcxx-include-dir is 'no' we disable the stdlib option. +# if --with-gxx-libcxx-include-dir is unset we enable the stdlib option +# based on the platform (to be available on platform versions where it is the +# default for the system tools). We also use a default path within the compiler +# install tree. +# Otherwise, we use the path provided and enable the stdlib option. # If both --with-sysroot and --with-gxx-libcxx-include-dir are passed, we # check to see if the latter starts with the former and, upon success, compute # gcc_gxx_libcxx_include_dir as relative to the sysroot. gcc_gxx_libcxx_include_dir_add_sysroot=0 - +gcc_enable_stdlib_opt=0 if test x${gcc_gxx_libcxx_include_dir} != x; then + if test x${gcc_gxx_libcxx_include_dir} = xno; then + # set defaults for the dir, but the option is disabled anyway. + gcc_gxx_libcxx_include_dir= + else + gcc_enable_stdlib_opt=1 + fi +else + case $target in + *-darwin1[1-9]* | *-darwin2*) + # Default this on for Darwin versions which default to libcxx, + # and embed the path in the compiler install so that we get a + # self-contained toolchain. + gcc_enable_stdlib_opt=1 + ;; + *) ;; + esac +fi -$as_echo "#define ENABLE_STDLIB_OPTION 1" >>confdefs.h +cat >>confdefs.h <<_ACEOF +#define ENABLE_STDLIB_OPTION $gcc_enable_stdlib_opt +_ACEOF -else - $as_echo "#define ENABLE_STDLIB_OPTION 0" >>confdefs.h -fi -# ??? This logic must match libstdc++-v3/acinclude.m4:GLIBCXX_EXPORT_INSTALL_INFO. if test x${gcc_gxx_libcxx_include_dir} = x; then + # default path,embedded in the compiler tree. + libcxx_incdir='include/c++/v1' if test x${enable_version_specific_runtime_libs} = xyes; then - gcc_gxx_libcxx_include_dir='${libsubdir}/libc++_include/c++/v1' + gcc_gxx_libcxx_include_dir='${libsubdir}/$libcxx_incdir' else - libcxx_incdir='libc++_include/c++/$(version)/v1' if test x$host != x$target; then libcxx_incdir="$target_alias/$libcxx_incdir" fi @@ -17617,6 +17652,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi darwin* | rhapsody*) + + # Publish an arg to allow the user to select that Darwin host (and target) + # libraries should be given install-names like @rpath/libfoo.dylib. This + # requires that the user of the library then adds an 'rpath' to the DSO that + # needs access. + # NOTE: there are defaults below, for systems that support rpaths. The person + # configuring can override the defaults for any system version that supports + # them - they are, however, forced off for system versions without support. + # Check whether --enable-darwin-at-rpath was given. +if test "${enable_darwin_at_rpath+set}" = set; then : + enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then + # This is not supported before macOS 10.5 / Darwin9. + case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in + UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) + echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 + enable_darwin_at_rpath=no + ;; + esac + fi +else + case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in + # As above, before 10.5 / Darwin9 this does not work. + UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) + enable_darwin_at_rpath=no + ;; + + # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use + # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key + # system executables (e.g. /bin/sh). Force rpaths on for these systems. + UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) + echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 + enable_darwin_at_rpath=yes + ;; + # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can + # work with either DYLD_LIBRARY_PATH or embedded rpaths. + + esac + +fi + + archive_cmds_need_lc=no hardcode_direct=no hardcode_automatic=yes @@ -17634,10 +17710,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi 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}" + if test "x$enable_darwin_at_rpath" = "xyes"; then + echo "using Darwin @rpath" 1>&5 + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_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_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 + echo "NOT using Darwin @rpath" 1>&5 + 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}" + fi else ld_shlibs=no @@ -19423,7 +19508,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 19426 "configure" +#line 19511 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -19529,7 +19614,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 19532 "configure" +#line 19617 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -20405,6 +20490,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi darwin* | rhapsody*) + + # Publish an arg to allow the user to select that Darwin host (and target) + # libraries should be given install-names like @rpath/libfoo.dylib. This + # requires that the user of the library then adds an 'rpath' to the DSO that + # needs access. + # NOTE: there are defaults below, for systems that support rpaths. The person + # configuring can override the defaults for any system version that supports + # them - they are, however, forced off for system versions without support. + # Check whether --enable-darwin-at-rpath was given. +if test "${enable_darwin_at_rpath+set}" = set; then : + enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then + # This is not supported before macOS 10.5 / Darwin9. + case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in + UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) + echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 + enable_darwin_at_rpath=no + ;; + esac + fi +else + case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in + # As above, before 10.5 / Darwin9 this does not work. + UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) + enable_darwin_at_rpath=no + ;; + + # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use + # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key + # system executables (e.g. /bin/sh). Force rpaths on for these systems. + UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) + echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 + enable_darwin_at_rpath=yes + ;; + # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can + # work with either DYLD_LIBRARY_PATH or embedded rpaths. + + esac + +fi + + archive_cmds_need_lc_CXX=no hardcode_direct_CXX=no hardcode_automatic_CXX=yes @@ -20422,12 +20548,25 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi 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 "x$enable_darwin_at_rpath" = "xyes"; then + echo "using Darwin @rpath" 1>&5 + archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_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_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}" + else + echo "NOT using Darwin @rpath" 1>&5 + 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}" + fi 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}" + if test "x$enable_darwin_at_rpath" = "xyes"; 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}" + else + 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}" + fi 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 @@ -22778,6 +22917,35 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + if test x$enable_darwin_at_rpath = xyes; then + ENABLE_DARWIN_AT_RPATH_TRUE= + ENABLE_DARWIN_AT_RPATH_FALSE='#' +else + ENABLE_DARWIN_AT_RPATH_TRUE='#' + ENABLE_DARWIN_AT_RPATH_FALSE= +fi + +DARWIN_DO_EXTRA_RPATH=0 + +# Check whether --with-darwin-extra-rpath was given. +if test "${with_darwin_extra_rpath+set}" = set; then : + withval=$with_darwin_extra_rpath; if test x"$withval" != x; then + DARWIN_ADD_RPATH="$withval" + DARWIN_DO_EXTRA_RPATH=1 + fi +fi + + +cat >>confdefs.h <<_ACEOF +#define DARWIN_DO_EXTRA_RPATH $DARWIN_DO_EXTRA_RPATH +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define DARWIN_ADD_RPATH "$DARWIN_ADD_RPATH" +_ACEOF + + # Identify the assembler which will work hand-in-glove with the newly # built GCC, so that we can examine its features. This is the assembler # which will be driven by the driver program. @@ -30675,6 +30843,7 @@ if test x"$ld64_flag" = x"yes"; then # Set defaults for possibly untestable items. gcc_cv_ld64_export_dynamic=0 + gcc_cv_ld64_platform_version=0 if test "$build" = "$host"; then darwin_try_test=1 @@ -30698,9 +30867,12 @@ $as_echo_n "checking ld64 specified version... " >&6; } gcc_cv_ld64_major=`echo "$gcc_cv_ld64_version" | sed -e 's/\..*//'` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_ld64_major" >&5 $as_echo "$gcc_cv_ld64_major" >&6; } - if test "$gcc_cv_ld64_major" -ge 236; then + if test "$gcc_cv_ld64_major" -ge 236; then gcc_cv_ld64_export_dynamic=1 fi + if test "$gcc_cv_ld64_major" -ge 512; then + gcc_cv_ld64_platform_version=1 + fi elif test -x "$gcc_cv_ld" -a "$darwin_try_test" -eq 1; then # If the version was not specified, try to find it. { $as_echo "$as_me:${as_lineno-$LINENO}: checking linker version" >&5 @@ -30719,6 +30891,15 @@ $as_echo_n "checking linker for -export_dynamic support... " >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_ld64_export_dynamic" >&5 $as_echo "$gcc_cv_ld64_export_dynamic" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking linker for -platform_version support" >&5 +$as_echo_n "checking linker for -platform_version support... " >&6; } + gcc_cv_ld64_platform_version=1 + if $gcc_cv_ld -platform_version macos 10.5 0.0 < /dev/null 2>&1 | grep 'unknown option' > /dev/null; then + gcc_cv_ld64_platform_version=0 + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_ld64_platform_version" >&5 +$as_echo "$gcc_cv_ld64_platform_version" >&6; } fi if test x"${gcc_cv_ld64_version}" != x; then @@ -30734,6 +30915,12 @@ cat >>confdefs.h <<_ACEOF #define LD64_HAS_EXPORT_DYNAMIC $gcc_cv_ld64_export_dynamic _ACEOF + + +cat >>confdefs.h <<_ACEOF +#define LD64_HAS_PLATFORM_VERSION $gcc_cv_ld64_platform_version +_ACEOF + fi if test x"$dsymutil_flag" = x"yes"; then @@ -32174,14 +32361,18 @@ fi # Check that we can build shared objects with -fPIC -shared saved_LDFLAGS="$LDFLAGS" saved_CFLAGS="$CFLAGS" + saved_CXXFLAGS="$CXXFLAGS" case "${host}" in *-*-darwin*) CFLAGS=`echo $CFLAGS | sed s/-mdynamic-no-pic//g` CFLAGS="$CFLAGS -fPIC" + CXXFLAGS=`echo $CXXFLAGS | sed s/-mdynamic-no-pic//g` + CXXFLAGS="$CXXFLAGS -fPIC" LDFLAGS="$LDFLAGS -shared -undefined dynamic_lookup" ;; *) CFLAGS="$CFLAGS -fPIC" + CXXFLAGS="$CXXFLAGS -fPIC" LDFLAGS="$LDFLAGS -fPIC -shared" ;; esac @@ -32213,6 +32404,7 @@ rm -f core conftest.err conftest.$ac_objext \ fi LDFLAGS="$saved_LDFLAGS" CFLAGS="$saved_CFLAGS" + CXXFLAGS="$saved_CXXFLAGS" # If plugin support had been requested but not available, fail. if test x"$enable_plugin" = x"no" ; then @@ -32374,6 +32566,22 @@ $as_echo "#define ENABLE_DEFAULT_PIE 1" >>confdefs.h fi +# Check whether --enable-pie-tools was given; this is passed automatically +# from the top level where it has already been validated. +# Check whether --enable-pie-tools was given. +if test "${enable_pie_tools+set}" = set; then : + enableval=$enable_pie_tools; enable_pie_tools=$enableval +else + enable_pie_tools=no +fi + +if test x$enable_pie_tools = xyes ; then + +$as_echo "#define ENABLE_PIE_TOOLS 1" >>confdefs.h + +fi + + # Check if -fno-PIE works. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fno-PIE option" >&5 $as_echo_n "checking for -fno-PIE option... " >&6; } @@ -32882,6 +33090,10 @@ LTLIBOBJS=$ac_ltlibobjs +if test -z "${ENABLE_DARWIN_AT_RPATH_TRUE}" && test -z "${ENABLE_DARWIN_AT_RPATH_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_DARWIN_AT_RPATH\" 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 gcc/configure.ac gcc/configure.ac index 25a0597..5acfc1f 100644 --- gcc/configure.ac +++ gcc/configure.ac @@ -236,27 +236,48 @@ AC_ARG_WITH(gxx-libcxx-include-dir, [specifies directory to find libc++ header files])], [case "${withval}" in yes) AC_MSG_ERROR(bad value ${withval} given for libc++ include directory) ;; -no) ;; *) gcc_gxx_libcxx_include_dir=$with_gxx_libcxx_include_dir ;; esac]) +# --with-gxx-libcxx-include-dir controls the enabling of the -stdlib option. +# if --with-gxx-libcxx-include-dir is 'no' we disable the stdlib option. +# if --with-gxx-libcxx-include-dir is unset we enable the stdlib option +# based on the platform (to be available on platform versions where it is the +# default for the system tools). We also use a default path within the compiler +# install tree. +# Otherwise, we use the path provided and enable the stdlib option. # If both --with-sysroot and --with-gxx-libcxx-include-dir are passed, we # check to see if the latter starts with the former and, upon success, compute # gcc_gxx_libcxx_include_dir as relative to the sysroot. gcc_gxx_libcxx_include_dir_add_sysroot=0 - +gcc_enable_stdlib_opt=0 if test x${gcc_gxx_libcxx_include_dir} != x; then - AC_DEFINE(ENABLE_STDLIB_OPTION, 1, - [Define if the -stdlib= option should be enabled.]) + if test x${gcc_gxx_libcxx_include_dir} = xno; then + # set defaults for the dir, but the option is disabled anyway. + gcc_gxx_libcxx_include_dir= + else + gcc_enable_stdlib_opt=1 + fi else - AC_DEFINE(ENABLE_STDLIB_OPTION, 0) + case $target in + *-darwin1[[1-9]]* | *-darwin2*) + # Default this on for Darwin versions which default to libcxx, + # and embed the path in the compiler install so that we get a + # self-contained toolchain. + gcc_enable_stdlib_opt=1 + ;; + *) ;; + esac fi -# ??? This logic must match libstdc++-v3/acinclude.m4:GLIBCXX_EXPORT_INSTALL_INFO. +AC_DEFINE_UNQUOTED(ENABLE_STDLIB_OPTION, $gcc_enable_stdlib_opt, + [Define if the -stdlib= option should be enabled.]) + if test x${gcc_gxx_libcxx_include_dir} = x; then + # default path,embedded in the compiler tree. + libcxx_incdir='include/c++/v1' if test x${enable_version_specific_runtime_libs} = xyes; then - gcc_gxx_libcxx_include_dir='${libsubdir}/libc++_include/c++/v1' + gcc_gxx_libcxx_include_dir='${libsubdir}/$libcxx_incdir' else - libcxx_incdir='libc++_include/c++/$(version)/v1' if test x$host != x$target; then libcxx_incdir="$target_alias/$libcxx_incdir" fi @@ -2521,6 +2542,21 @@ AC_PROG_LIBTOOL AC_SUBST(objdir) AC_SUBST(enable_fast_install) +AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes]) +DARWIN_DO_EXTRA_RPATH=0 +AC_ARG_WITH(darwin-extra-rpath, +[AS_HELP_STRING( + [[--with-darwin-extra-rpath=[ARG]]], + [Specify a runpath directory, additional to those provided by the compiler])], +[if test x"$withval" != x; then + DARWIN_ADD_RPATH="$withval" + DARWIN_DO_EXTRA_RPATH=1 + fi]) +AC_DEFINE_UNQUOTED(DARWIN_DO_EXTRA_RPATH, $DARWIN_DO_EXTRA_RPATH, + [Should add an extra runpath directory]) +AC_DEFINE_UNQUOTED(DARWIN_ADD_RPATH, "$DARWIN_ADD_RPATH", + [Specify a runpath directory, additional to those provided by the compiler]) + # Identify the assembler which will work hand-in-glove with the newly # built GCC, so that we can examine its features. This is the assembler # which will be driven by the driver program. @@ -6329,6 +6365,7 @@ if test x"$ld64_flag" = x"yes"; then # Set defaults for possibly untestable items. gcc_cv_ld64_export_dynamic=0 + gcc_cv_ld64_platform_version=0 if test "$build" = "$host"; then darwin_try_test=1 @@ -6350,9 +6387,12 @@ if test x"$ld64_flag" = x"yes"; then AC_MSG_CHECKING(ld64 specified version) gcc_cv_ld64_major=`echo "$gcc_cv_ld64_version" | sed -e 's/\..*//'` AC_MSG_RESULT($gcc_cv_ld64_major) - if test "$gcc_cv_ld64_major" -ge 236; then + if test "$gcc_cv_ld64_major" -ge 236; then gcc_cv_ld64_export_dynamic=1 fi + if test "$gcc_cv_ld64_major" -ge 512; then + gcc_cv_ld64_platform_version=1 + fi elif test -x "$gcc_cv_ld" -a "$darwin_try_test" -eq 1; then # If the version was not specified, try to find it. AC_MSG_CHECKING(linker version) @@ -6367,6 +6407,13 @@ if test x"$ld64_flag" = x"yes"; then gcc_cv_ld64_export_dynamic=0 fi AC_MSG_RESULT($gcc_cv_ld64_export_dynamic) + + AC_MSG_CHECKING(linker for -platform_version support) + gcc_cv_ld64_platform_version=1 + if $gcc_cv_ld -platform_version macos 10.5 0.0 < /dev/null 2>&1 | grep 'unknown option' > /dev/null; then + gcc_cv_ld64_platform_version=0 + fi + AC_MSG_RESULT($gcc_cv_ld64_platform_version) fi if test x"${gcc_cv_ld64_version}" != x; then @@ -6376,6 +6423,9 @@ if test x"$ld64_flag" = x"yes"; then AC_DEFINE_UNQUOTED(LD64_HAS_EXPORT_DYNAMIC, $gcc_cv_ld64_export_dynamic, [Define to 1 if ld64 supports '-export_dynamic'.]) + + AC_DEFINE_UNQUOTED(LD64_HAS_PLATFORM_VERSION, $gcc_cv_ld64_platform_version, + [Define to 1 if ld64 supports '-platform_version'.]) fi if test x"$dsymutil_flag" = x"yes"; then @@ -7618,6 +7668,19 @@ if test x$enable_default_pie = xyes ; then fi AC_SUBST([enable_default_pie]) +# Check whether --enable-pie-tools was given; this is passed automatically +# from the top level where it has already been validated. +AC_ARG_ENABLE(pie-tools, +[AS_HELP_STRING([--enable-pie-tools], + [build Position Independent Executables for the compilers and other tools])], +[enable_pie_tools=$enableval], +[enable_pie_tools=no]) +if test x$enable_pie_tools = xyes ; then + AC_DEFINE(ENABLE_PIE_TOOLS, 1, + [Define if you build Position Independent Executables for the compilers and other tools.]) +fi +AC_SUBST([enable_pie_tools]) + # Check if -fno-PIE works. AC_CACHE_CHECK([for -fno-PIE option], [gcc_cv_c_no_fpie], diff --git gcc/coretypes.h gcc/coretypes.h index 732c76f..f4a185e 100644 --- gcc/coretypes.h +++ gcc/coretypes.h @@ -442,8 +442,10 @@ enum optimize_size_level }; /* Support for user-provided GGC and PCH markers. The first parameter - is a pointer to a pointer, the second a cookie. */ -typedef void (*gt_pointer_operator) (void *, void *); + is a pointer to a pointer, the second either NULL if the pointer to + pointer points into a GC object or the actual pointer address if + the first argument points to a temporary and the third a cookie. */ +typedef void (*gt_pointer_operator) (void *, void *, void *); #if !defined (HAVE_UCHAR) typedef unsigned char uchar; diff --git gcc/cp/call.c gcc/cp/call.c index 7c3ce16..c360fcc 100644 --- gcc/cp/call.c +++ gcc/cp/call.c @@ -9435,7 +9435,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) already_used = true; } else - cp_warn_deprecated_use (fn, complain); + cp_handle_deprecated_or_unavailable (fn, complain); if (eliding_temp && DECL_BASE_CONSTRUCTOR_P (fn) && !make_base_init_ok (arg)) @@ -9512,7 +9512,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) TREE_NO_WARNING (val) = 1; } - cp_warn_deprecated_use (fn, complain); + cp_handle_deprecated_or_unavailable (fn, complain); return val; } diff --git gcc/cp/class.c gcc/cp/class.c index 3251aaa..2358b93 100644 --- gcc/cp/class.c +++ gcc/cp/class.c @@ -5768,6 +5768,7 @@ type_build_ctor_call (tree t) tree fn = *iter; if (!DECL_ARTIFICIAL (fn) || TREE_DEPRECATED (fn) + || TREE_UNAVAILABLE (fn) || DECL_DELETED_FN (fn)) return true; } @@ -5796,6 +5797,7 @@ type_build_dtor_call (tree t) tree fn = *iter; if (!DECL_ARTIFICIAL (fn) || TREE_DEPRECATED (fn) + || TREE_UNAVAILABLE (fn) || DECL_DELETED_FN (fn)) return true; } diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h index 8887e94..148ad71 100644 --- gcc/cp/cp-tree.h +++ gcc/cp/cp-tree.h @@ -6503,7 +6503,7 @@ extern void validate_conversion_obstack (void); extern void mark_versions_used (tree); extern int unsafe_return_slot_p (tree); extern bool make_safe_copy_elision (tree, tree); -extern bool cp_warn_deprecated_use (tree, tsubst_flags_t = tf_warning_or_error); +extern bool cp_handle_deprecated_or_unavailable (tree, tsubst_flags_t = tf_warning_or_error); extern void cp_warn_deprecated_use_scopes (tree); extern tree get_function_version_dispatcher (tree); diff --git gcc/cp/decl.c gcc/cp/decl.c index 712e875..b190c83 100644 --- gcc/cp/decl.c +++ gcc/cp/decl.c @@ -2412,6 +2412,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) if (TREE_DEPRECATED (newdecl)) TREE_DEPRECATED (olddecl) = 1; + /* Merge unavailability. */ + if (TREE_UNAVAILABLE (newdecl)) + TREE_UNAVAILABLE (olddecl) = 1; + /* Preserve function specific target and optimization options */ if (TREE_CODE (newdecl) == FUNCTION_DECL) { @@ -11829,20 +11833,24 @@ grokdeclarator (const cp_declarator *declarator, if (attrlist && *attrlist == error_mark_node) *attrlist = NULL_TREE; - /* An object declared as __attribute__((deprecated)) suppresses - warnings of uses of other deprecated items. */ + /* An object declared as __attribute__((unavailable)) suppresses + any reports of being declared with unavailable or deprecated + items. An object declared as __attribute__((deprecated)) + suppresses warnings of uses of other deprecated items. */ auto ds = make_temp_override (deprecated_state); - if (attrlist && lookup_attribute ("deprecated", *attrlist)) + if (attrlist && lookup_attribute ("unavailable", *attrlist)) + deprecated_state = UNAVAILABLE_DEPRECATED_SUPPRESS; + else if (attrlist && lookup_attribute ("deprecated", *attrlist)) deprecated_state = DEPRECATED_SUPPRESS; - cp_warn_deprecated_use (type); + cp_handle_deprecated_or_unavailable (type); if (type && TREE_CODE (type) == TYPE_DECL) { cp_warn_deprecated_use_scopes (CP_DECL_CONTEXT (type)); typedef_decl = type; type = TREE_TYPE (typedef_decl); if (DECL_ARTIFICIAL (typedef_decl)) - cp_warn_deprecated_use (type); + cp_handle_deprecated_or_unavailable (type); } /* No type at all: default to `int', and set DEFAULTED_INT because it was not a user-defined typedef. */ @@ -14488,6 +14496,43 @@ type_is_deprecated (tree type) return NULL_TREE; } +/* Returns an unavailable type used within TYPE, or NULL_TREE if none. */ + +static tree +type_is_unavailable (tree type) +{ + enum tree_code code; + if (TREE_UNAVAILABLE (type)) + return type; + if (TYPE_NAME (type)) + { + if (TREE_UNAVAILABLE (TYPE_NAME (type))) + return type; + else + { + cp_warn_deprecated_use_scopes (CP_DECL_CONTEXT (TYPE_NAME (type))); + return NULL_TREE; + } + } + + /* Do warn about using typedefs to a deprecated class. */ + if (OVERLOAD_TYPE_P (type) && type != TYPE_MAIN_VARIANT (type)) + return type_is_deprecated (TYPE_MAIN_VARIANT (type)); + + code = TREE_CODE (type); + + if (code == POINTER_TYPE || code == REFERENCE_TYPE + || code == OFFSET_TYPE || code == FUNCTION_TYPE + || code == METHOD_TYPE || code == ARRAY_TYPE) + return type_is_unavailable (TREE_TYPE (type)); + + if (TYPE_PTRMEMFUNC_P (type)) + return type_is_unavailable + (TREE_TYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (type)))); + + return NULL_TREE; +} + /* Decode the list of parameter types for a function type. Given the list of things declared inside the parens, return a list of types. @@ -14547,11 +14592,18 @@ grokparms (tree parmlist, tree *parms) if (type != error_mark_node) { - if (deprecated_state != DEPRECATED_SUPPRESS) + if (deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS) + { + tree unavailtype = type_is_unavailable (type); + if (unavailtype) + cp_handle_deprecated_or_unavailable (unavailtype); + } + if (deprecated_state != DEPRECATED_SUPPRESS + && deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS) { tree deptype = type_is_deprecated (type); if (deptype) - cp_warn_deprecated_use (deptype); + cp_handle_deprecated_or_unavailable (deptype); } /* [dcl.fct] "A parameter with volatile-qualified type is diff --git gcc/cp/decl.h gcc/cp/decl.h index 387d807..4a9b399 100644 --- gcc/cp/decl.h +++ gcc/cp/decl.h @@ -44,7 +44,8 @@ extern void name_unnamed_type (tree, tree); enum deprecated_states { DEPRECATED_NORMAL, - DEPRECATED_SUPPRESS + DEPRECATED_SUPPRESS, + UNAVAILABLE_DEPRECATED_SUPPRESS }; extern enum deprecated_states deprecated_state; diff --git gcc/cp/decl2.c gcc/cp/decl2.c index 3ea37e0..107fd91 100644 --- gcc/cp/decl2.c +++ gcc/cp/decl2.c @@ -1617,6 +1617,17 @@ cplus_decl_attributes (tree *decl, tree attributes, int flags) if (*decl == pattern) TREE_DEPRECATED (tmpl) = true; } + + /* Likewise, propagate unavailability out to the template. */ + if (TREE_UNAVAILABLE (*decl)) + if (tree ti = get_template_info (*decl)) + { + tree tmpl = TI_TEMPLATE (ti); + tree pattern = (TYPE_P (*decl) ? TREE_TYPE (tmpl) + : DECL_TEMPLATE_RESULT (tmpl)); + if (*decl == pattern) + TREE_UNAVAILABLE (tmpl) = true; + } } /* Walks through the namespace- or function-scope anonymous union @@ -3498,9 +3509,8 @@ get_tls_init_fn (tree var) if (!flag_extern_tls_init && DECL_EXTERNAL (var)) return NULL_TREE; - /* If the variable is internal, or if we can't generate aliases, - call the local init function directly. */ - if (!TREE_PUBLIC (var) || !TARGET_SUPPORTS_ALIASES) + /* If the variable is internal call the local init function directly. */ + if (!TREE_PUBLIC (var)) return get_local_tls_init_fn (DECL_SOURCE_LOCATION (var)); tree sname = mangle_tls_init_fn (var); @@ -3663,6 +3673,25 @@ generate_tls_wrapper (tree fn) expand_or_defer_fn (finish_function (/*inline_p=*/false)); } +/* A dummy init function to act as a weak placeholder for a (possibly non- + existent) dynamic init. */ +static void +generate_tls_dummy_init (tree fn) +{ + tree var = DECL_BEFRIENDING_CLASSES (fn); + tree init_fn = get_tls_init_fn (var); + /* If have no init fn, or it is non-weak, then we do not need to make a + dummy. */ + if (!init_fn || !lookup_attribute ("weak", DECL_ATTRIBUTES (init_fn))) + return; + start_preparsed_function (init_fn, NULL_TREE, SF_DEFAULT | SF_PRE_PARSED); + tree body = begin_function_body (); + declare_weak (init_fn); + finish_return_stmt (NULL_TREE); + finish_function_body (body); + expand_or_defer_fn (finish_function (/*inline_p=*/false)); +} + /* Start the process of running a particular set of global constructors or destructors. Subroutine of do_[cd]tors. Also called from vtv_start_verification_constructor_init_function. */ @@ -4646,22 +4675,24 @@ handle_tls_init (void) finish_expr_stmt (cp_build_modify_expr (loc, guard, NOP_EXPR, boolean_true_node, tf_warning_or_error)); + auto_vec direct_calls; for (; vars; vars = TREE_CHAIN (vars)) { tree var = TREE_VALUE (vars); tree init = TREE_PURPOSE (vars); one_static_initialization_or_destruction (var, init, true); - /* Output init aliases even with -fno-extern-tls-init. */ - if (TARGET_SUPPORTS_ALIASES && TREE_PUBLIC (var)) + /* Output inits even with -fno-extern-tls-init. + We save the list here and output either an alias or a stub function + below. */ + if (TREE_PUBLIC (var)) { - tree single_init_fn = get_tls_init_fn (var); + tree single_init_fn = get_tls_init_fn (var); if (single_init_fn == NULL_TREE) continue; - cgraph_node *alias - = cgraph_node::get_create (fn)->create_same_body_alias - (single_init_fn, fn); - gcc_assert (alias != NULL); + if (single_init_fn == fn) + continue; + direct_calls.safe_push (single_init_fn); } } @@ -4669,6 +4700,30 @@ handle_tls_init (void) finish_if_stmt (if_stmt); finish_function_body (body); expand_or_defer_fn (finish_function (/*inline_p=*/false)); + + /* For each TLS var that we have an init function, we either emit an alias + between that and the tls_init, or a stub function that just calls the + tls_init. */ + while (!direct_calls.is_empty()) + { + tree single_init_fn = direct_calls.pop (); + if (TARGET_SUPPORTS_ALIASES) + { + cgraph_node *alias + = cgraph_node::get_create (fn)->create_same_body_alias + (single_init_fn, fn); + gcc_assert (alias != NULL); + } + else + { + start_preparsed_function (single_init_fn, NULL_TREE, SF_PRE_PARSED); + tree body = begin_function_body (); + tree r = build_call_expr (fn, 0); + finish_expr_stmt (r); + finish_function_body (body); + expand_or_defer_fn (finish_function (/*inline_p=*/false)); + } + } } /* We're at the end of compilation, so generate any mangling aliases that @@ -5097,7 +5152,14 @@ c_parse_final_cleanups (void) } if (!DECL_INITIAL (decl) && decl_tls_wrapper_p (decl)) - generate_tls_wrapper (decl); + { + generate_tls_wrapper (decl); + /* The wrapper might have a weak reference to an init, we provide + a dummy function to satisfy that here. The linker/dynamic + loader will override this with the actual init, if one is + required. */ + generate_tls_dummy_init (decl); + } if (!DECL_SAVED_TREE (decl)) continue; @@ -5475,14 +5537,47 @@ maybe_instantiate_decl (tree decl) } } -/* Maybe warn if DECL is deprecated, subject to COMPLAIN. Returns whether or - not a warning was emitted. */ +/* Error if the DECL is unavailable (unless this is currently suppressed). + Maybe warn if DECL is deprecated, subject to COMPLAIN. Returns true if + an error or warning was emitted. */ bool -cp_warn_deprecated_use (tree decl, tsubst_flags_t complain) +cp_handle_deprecated_or_unavailable (tree decl, tsubst_flags_t complain) { - if (!(complain & tf_warning) || !decl - || deprecated_state == DEPRECATED_SUPPRESS) + if (!decl) + return false; + + if ((complain & tf_error) + && deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS) + { + if (TREE_UNAVAILABLE (decl)) + { + error_unavailable_use (decl, NULL_TREE); + return true; + } + else + { + /* Perhaps this is an unavailable typedef. */ + if (TYPE_P (decl) + && TYPE_NAME (decl) + && TREE_UNAVAILABLE (TYPE_NAME (decl))) + { + decl = TYPE_NAME (decl); + /* Don't error within members of a unavailable type. */ + if (TYPE_P (decl) + && currently_open_class (decl)) + return false; + + error_unavailable_use (decl, NULL_TREE); + return true; + } + } + /* Carry on to consider deprecatedness. */ + } + + if (!(complain & tf_warning) + || deprecated_state == DEPRECATED_SUPPRESS + || deprecated_state == UNAVAILABLE_DEPRECATED_SUPPRESS) return false; if (!TREE_DEPRECATED (decl)) @@ -5542,7 +5637,7 @@ cp_warn_deprecated_use_scopes (tree scope) && scope != global_namespace) { if ((TREE_CODE (scope) == NAMESPACE_DECL || OVERLOAD_TYPE_P (scope)) - && cp_warn_deprecated_use (scope)) + && cp_handle_deprecated_or_unavailable (scope)) return; if (TYPE_P (scope)) scope = CP_TYPE_CONTEXT (scope); @@ -5655,7 +5750,7 @@ mark_used (tree decl, tsubst_flags_t complain) TREE_USED (decl) = true; } - cp_warn_deprecated_use (decl, complain); + cp_handle_deprecated_or_unavailable (decl, complain); /* We can only check DECL_ODR_USED on variables or functions with DECL_LANG_SPECIFIC set, and these are also the only decls that we diff --git gcc/cp/g++spec.c gcc/cp/g++spec.c index 3c9bd14..984106f 100644 --- gcc/cp/g++spec.c +++ gcc/cp/g++spec.c @@ -222,7 +222,12 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options, case OPT_static_libstdc__: library = library >= 0 ? 2 : library; +#ifdef HAVE_LD_STATIC_DYNAMIC + /* Remove -static-libstdc++ from the command only if target supports + LD_STATIC_DYNAMIC. When not supported, it is left in so that a + back-end target can use outfile substitution. */ args[i] |= SKIPOPT; +#endif break; case OPT_stdlib_: diff --git gcc/cp/module.cc gcc/cp/module.cc index 6cb926c..83ff54d 100644 --- gcc/cp/module.cc +++ gcc/cp/module.cc @@ -11745,7 +11745,7 @@ trees_out::mark_class_def (tree defn) /* Nop sorting, needed for resorting the member vec. */ static void -nop (void *, void *) +nop (void *, void *, void *) { } diff --git gcc/cp/name-lookup.c gcc/cp/name-lookup.c index 2901e04..4f28556 100644 --- gcc/cp/name-lookup.c +++ gcc/cp/name-lookup.c @@ -2126,8 +2126,8 @@ resort_member_name_cmp (const void *a_p, const void *b_p) tree name_a = OVL_NAME (a); tree name_b = OVL_NAME (b); - resort_data.new_value (&name_a, resort_data.cookie); - resort_data.new_value (&name_b, resort_data.cookie); + resort_data.new_value (&name_a, &name_a, resort_data.cookie); + resort_data.new_value (&name_b, &name_b, resort_data.cookie); gcc_checking_assert (name_a != name_b); diff --git gcc/cp/parser.c gcc/cp/parser.c index 98f2661..7a1ca7e 100644 --- gcc/cp/parser.c +++ gcc/cp/parser.c @@ -17772,18 +17772,26 @@ cp_parser_template_name (cp_parser* parser, /* If DECL is a template, then the name was a template-name. */ if (TREE_CODE (decl) == TEMPLATE_DECL) { - if (TREE_DEPRECATED (decl) - && deprecated_state != DEPRECATED_SUPPRESS) + if ((TREE_DEPRECATED (decl) || TREE_UNAVAILABLE (decl)) + && deprecated_state != UNAVAILABLE_DEPRECATED_SUPPRESS) { tree d = DECL_TEMPLATE_RESULT (decl); tree attr; if (TREE_CODE (d) == TYPE_DECL) - attr = lookup_attribute ("deprecated", - TYPE_ATTRIBUTES (TREE_TYPE (d))); + attr = TYPE_ATTRIBUTES (TREE_TYPE (d)); else - attr = lookup_attribute ("deprecated", - DECL_ATTRIBUTES (d)); - warn_deprecated_use (decl, attr); + attr = DECL_ATTRIBUTES (d); + if (TREE_UNAVAILABLE (decl)) + { + attr = lookup_attribute ("unavailable", attr); + error_unavailable_use (decl, attr); + } + else if (TREE_DEPRECATED (decl) + && deprecated_state != DEPRECATED_SUPPRESS) + { + attr = lookup_attribute ("deprecated", attr); + warn_deprecated_use (decl, attr); + } } } else @@ -18035,7 +18043,9 @@ cp_parser_template_argument (cp_parser* parser) } if (cp_parser_parse_definitely (parser)) { - if (TREE_DEPRECATED (argument)) + if (TREE_UNAVAILABLE (argument)) + error_unavailable_use (argument, NULL_TREE); + else if (TREE_DEPRECATED (argument)) warn_deprecated_use (argument, NULL_TREE); return argument; } @@ -23638,9 +23648,9 @@ cp_parser_parameter_declaration_list (cp_parser* parser, cp_parser_flags flags) /*template_parm_p=*/false, &parenthesized_p); - /* We don't know yet if the enclosing context is deprecated, so wait - and warn in grokparms if appropriate. */ - deprecated_state = DEPRECATED_SUPPRESS; + /* We don't know yet if the enclosing context is unavailable or deprecated, + so wait and deal with it in grokparms if appropriate. */ + deprecated_state = UNAVAILABLE_DEPRECATED_SUPPRESS; if (parameter) { diff --git gcc/cp/typeck.c gcc/cp/typeck.c index 6e5a352..741a0a4 100644 --- gcc/cp/typeck.c +++ gcc/cp/typeck.c @@ -2556,7 +2556,10 @@ build_class_member_access_expr (cp_expr object, tree member, member_scope = DECL_CLASS_CONTEXT (member); if (!mark_used (member, complain) && !(complain & tf_error)) return error_mark_node; - if (TREE_DEPRECATED (member)) + + if (TREE_UNAVAILABLE (member)) + error_unavailable_use (member, NULL_TREE); + else if (TREE_DEPRECATED (member)) warn_deprecated_use (member, NULL_TREE); } else @@ -3271,7 +3274,9 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p, } } - if (TREE_DEPRECATED (member)) + if (TREE_UNAVAILABLE (member)) + error_unavailable_use (member, NULL_TREE); + else if (TREE_DEPRECATED (member)) warn_deprecated_use (member, NULL_TREE); if (template_p) diff --git gcc/cp/typeck2.c gcc/cp/typeck2.c index 8628a50..83fffbf 100644 --- gcc/cp/typeck2.c +++ gcc/cp/typeck2.c @@ -2198,7 +2198,7 @@ build_functional_cast_1 (location_t loc, tree exp, tree parms, type = TREE_TYPE (exp); if (DECL_ARTIFICIAL (exp)) - cp_warn_deprecated_use (type); + cp_handle_deprecated_or_unavailable (type); } else type = exp; diff --git gcc/cumulative-args.h gcc/cumulative-args.h new file mode 100644 index 0000000..b60928e --- /dev/null +++ gcc/cumulative-args.h @@ -0,0 +1,20 @@ +#ifndef GCC_CUMULATIVE_ARGS_H +#define GCC_CUMULATIVE_ARGS_H + +#if CHECKING_P + +struct cumulative_args_t { void *magic; void *p; }; + +#else /* !CHECKING_P */ + +/* When using a GCC build compiler, we could use + __attribute__((transparent_union)) to get cumulative_args_t function + arguments passed like scalars where the ABI would mandate a less + efficient way of argument passing otherwise. However, that would come + at the cost of less type-safe !CHECKING_P compilation. */ + +union cumulative_args_t { void *p; }; + +#endif /* !CHECKING_P */ + +#endif /* GCC_CUMULATIVE_ARGS_H */ diff --git gcc/doc/extend.texi gcc/doc/extend.texi index 64bd4c1..b763b45 100644 --- gcc/doc/extend.texi +++ gcc/doc/extend.texi @@ -2866,6 +2866,19 @@ types (@pxref{Variable Attributes}, @pxref{Type Attributes}.) The message attached to the attribute is affected by the setting of the @option{-fmessage-length} option. +@item unavailable +@itemx unavailable (@var{msg}) +@cindex @code{unavailable} function attribute +The @code{unavailable} attribute results in an error if the function +is used anywhere in the source file. This is useful when identifying +functions that have been removed from a particular variation of an +interface. Other than emitting an error rather than a warning, the +@code{unavailable} attribute behaves in the same manner as +@code{deprecated}. + +The @code{unavailable} attribute can also be used for variables and +types (@pxref{Variable Attributes}, @pxref{Type Attributes}.) + @item error ("@var{message}") @itemx warning ("@var{message}") @cindex @code{error} function attribute @@ -7377,6 +7390,22 @@ types (@pxref{Common Function Attributes}, The message attached to the attribute is affected by the setting of the @option{-fmessage-length} option. +@item unavailable +@itemx unavailable (@var{msg}) +@cindex @code{unavailable} variable attribute +The @code{unavailable} attribute indicates that the variable so marked +is not available, if it is used anywhere in the source file. It behaves +in the same manner as the @code{deprecated} attribute except that the +compiler will emit an error rather than a warning. + +It is expected that items marked as @code{deprecated} will eventually be +withdrawn from interfaces, and then become unavailable. This attribute +allows for marking them appropriately. + +The @code{unavailable} attribute can also be used for functions and +types (@pxref{Common Function Attributes}, +@pxref{Common Type Attributes}). + @item mode (@var{mode}) @cindex @code{mode} variable attribute This attribute specifies the data type for the declaration---whichever @@ -8436,6 +8465,17 @@ variables (@pxref{Function Attributes}, @pxref{Variable Attributes}.) The message attached to the attribute is affected by the setting of the @option{-fmessage-length} option. +@item unavailable +@itemx unavailable (@var{msg}) +@cindex @code{unavailable} type attribute +The @code{unavailable} attribute behaves in the same manner as the +@code{deprecated} one, but emits an error rather than a warning. It is +used to indicate that a (perhaps previously @code{deprecated}) type is +no longer usable. + +The @code{unavailable} attribute can also be used for functions and +variables (@pxref{Function Attributes}, @pxref{Variable Attributes}.) + @item designated_init @cindex @code{designated_init} type attribute This attribute may only be applied to structure types. It indicates @@ -8909,6 +8949,12 @@ of the deprecated enumerator, to enable users to easily find further information about why the enumerator is deprecated, or what they should do instead. Note that the warnings only occurs for uses. +@item unavailable +@cindex @code{unavailable} enumerator attribute +The @code{unavailable} attribute results in an error if the enumerator +is used anywhere in the source file. In other respects it behaves in the +same manner as the @code{deprecated} attribute. + @end table @node Statement Attributes diff --git gcc/doc/gty.texi gcc/doc/gty.texi index aaf97ae..2c62ab1 100644 --- gcc/doc/gty.texi +++ gcc/doc/gty.texi @@ -197,6 +197,15 @@ If @code{skip} is applied to a field, the type machinery will ignore it. This is somewhat dangerous; the only safe use is in a union when one field really isn't ever used. +@findex callback +@item callback + +@code{callback} should be applied to fields with pointer to function type +and causes the field to be ignored similarly to @code{skip}, except when +writing PCH and the field is non-NULL it will remember the field's address +for relocation purposes if the process writing PCH has different load base +from a process reading PCH. + @findex for_user @item for_user @@ -466,7 +475,7 @@ void gt_pch_nx (my_struct *p) void gt_pch_nx (my_struct *p, gt_pointer_operator op, void *cookie) @{ /* For every field 'fld', call the given pointer operator. */ - op (&(tp->fld), cookie); + op (&(tp->fld), NULL, cookie); @} @end smallexample @@ -519,7 +528,7 @@ void gt_pch_nx (TP *tp, gt_pointer_operator op, void *cookie) @{ /* For every field 'fld' of 'tp' with type 'T *', call the given pointer operator. */ - op (&(tp->fld), cookie); + op (&(tp->fld), NULL, cookie); @} template diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi index f121781..011a559 100644 --- gcc/doc/invoke.texi +++ gcc/doc/invoke.texi @@ -651,6 +651,7 @@ Objective-C and Objective-C++ Dialects}. @gccoptlist{-fcall-saved-@var{reg} -fcall-used-@var{reg} @gol -ffixed-@var{reg} -fexceptions @gol -fnon-call-exceptions -fdelete-dead-exceptions -funwind-tables @gol +-foff-stack-trampolines @gol -fasynchronous-unwind-tables @gol -fno-gnu-unique @gol -finhibit-size-directive -fcommon -fno-ident @gol @@ -661,6 +662,7 @@ Objective-C and Objective-C++ Dialects}. -fverbose-asm -fpack-struct[=@var{n}] @gol -fleading-underscore -ftls-model=@var{model} @gol -fstack-reuse=@var{reuse_level} @gol +-fstack-use-cumulative-args @gol -ftrampolines -ftrapv -fwrapv @gol -fvisibility=@r{[}default@r{|}internal@r{|}hidden@r{|}protected@r{]} @gol -fstrict-volatile-bitfields -fsync-libcalls} @@ -16120,6 +16122,17 @@ the behavior of older compilers in which temporaries' stack space is not reused, the aggressive stack reuse can lead to runtime errors. This option is used to control the temporary stack reuse optimization. +@item -fstack-use-cumulative-args +@opindex fstack_use_cumulative_args +This option instructs the compiler to use the +@code{cumulative_args_t}-based stack layout target hooks, +@code{TARGET_FUNCTION_ARG_BOUNDARY_CA} and +@code{TARGET_FUNCTION_ARG_ROUND_BOUNDARY_CA}. If a given target does +not define these hooks, the default behaviour is to fallback to using +the standard non-@code{_CA} variants instead. Certain targets (such as +AArch64 Darwin) require using the more advanced @code{_CA}-based +hooks: For these targets this option should be enabled by default. + @item -ftrapv @opindex ftrapv This option generates traps for signed overflow on addition, subtraction, @@ -16177,6 +16190,19 @@ instructions to throw exceptions, i.e.@: memory references or floating-point instructions. It does not allow exceptions to be thrown from arbitrary signal handlers such as @code{SIGALRM}. +@item -foff-stack-trampolines +@opindex foff-stack-trampolines +Certain platforms (such as the Apple M1) do not permit an executable +stack. Generate calls to @code{__builtin_nested_func_ptr_created} and +@code{__builtin_nested_func_ptr_deleted} in order to allocate and +deallocate trampoline space on the executable heap. Please note that +these functions are implemented in libgcc, and will not be compiled in +unless you provide @option{--enable-off-stack-trampolines} when +building gcc. @emph{PLEASE NOTE}: The trampolines are @emph{not} +guaranteed to be correctly deallocated if you @code{setjmp}, +instantiate nested functions, and then @code{longjmp} back to a state +prior to having allocated those nested functions. + @item -fdelete-dead-exceptions @opindex fdelete-dead-exceptions Consider that instructions that may throw exceptions but don't otherwise diff --git gcc/doc/tm.texi gcc/doc/tm.texi index 6029295..21d3fa0 100644 --- gcc/doc/tm.texi +++ gcc/doc/tm.texi @@ -4226,6 +4226,16 @@ with the specified mode and type. The default hook returns @code{PARM_BOUNDARY} for all arguments. @end deftypefn +@deftypefn {Target Hook} {unsigned int} TARGET_FUNCTION_ARG_BOUNDARY_CA (machine_mode @var{mode}, const_tree @var{type}, cumulative_args_t @var{ca}) +This is the @code{cumulative_args_t}-based version of +@code{TARGET_FUNCTION_ARG_BOUNDARY}. Define this hook if you need more +fine-grained control over argument alignment, e.g. depending on whether +it is a named argument or not, or any other criteria that you choose to +place in the @var{ca} structure. + +The default hook will call @code{TARGET_FUNCTION_ARG_BOUNDARY}. +@end deftypefn + @deftypefn {Target Hook} {unsigned int} TARGET_FUNCTION_ARG_ROUND_BOUNDARY (machine_mode @var{mode}, const_tree @var{type}) Normally, the size of an argument is rounded up to @code{PARM_BOUNDARY}, which is the default value for this hook. You can define this hook to @@ -4233,6 +4243,16 @@ return a different value if an argument size must be rounded to a larger value. @end deftypefn +@deftypefn {Target Hook} {unsigned int} TARGET_FUNCTION_ARG_ROUND_BOUNDARY_CA (machine_mode @var{mode}, const_tree @var{type}, cumulative_args_t @var{ca}) +This is the @code{cumulative_args_t}-based version of +@code{TARGET_FUNCTION_ARG_ROUND_BOUNDARY}. Define this hook if you need more +fine-grained control over argument size rounding, e.g. depending on whether +it is a named argument or not, or any other criteria that you choose to +place in the @var{ca} structure. + +The default hook will call @code{TARGET_FUNCTION_ARG_ROUND_BOUNDARY}. +@end deftypefn + @defmac FUNCTION_ARG_REGNO_P (@var{regno}) A C expression that is nonzero if @var{regno} is the number of a hard register in which function arguments are sometimes passed. This does diff --git gcc/doc/tm.texi.in gcc/doc/tm.texi.in index 732396a..7b8e70e 100644 --- gcc/doc/tm.texi.in +++ gcc/doc/tm.texi.in @@ -3334,8 +3334,12 @@ required. @hook TARGET_FUNCTION_ARG_BOUNDARY +@hook TARGET_FUNCTION_ARG_BOUNDARY_CA + @hook TARGET_FUNCTION_ARG_ROUND_BOUNDARY +@hook TARGET_FUNCTION_ARG_ROUND_BOUNDARY_CA + @defmac FUNCTION_ARG_REGNO_P (@var{regno}) A C expression that is nonzero if @var{regno} is the number of a hard register in which function arguments are sometimes passed. This does diff --git gcc/function.c gcc/function.c index 1352863..abab124 100644 --- gcc/function.c +++ gcc/function.c @@ -2443,7 +2443,10 @@ assign_parm_find_data_types (struct assign_parm_data_all *all, tree parm, else if (DECL_CHAIN (parm)) data->arg.named = 1; /* Not the last non-variadic parm. */ else if (targetm.calls.strict_argument_naming (all->args_so_far)) - data->arg.named = 1; /* Only variadic ones are unnamed. */ + { + data->arg.named = 1; /* Only variadic ones are unnamed. */ + data->arg.last_named = 1; + } else data->arg.named = 0; /* Treat as variadic. */ @@ -2500,6 +2503,7 @@ assign_parms_setup_varargs (struct assign_parm_data_all *all, function_arg_info last_named_arg = data->arg; last_named_arg.named = true; + last_named_arg.last_named = true; targetm.calls.setup_incoming_varargs (all->args_so_far, last_named_arg, &varargs_pretend_bytes, no_rtl); @@ -2608,7 +2612,9 @@ assign_parm_find_entry_rtl (struct assign_parm_data_all *all, locate_and_pad_parm (data->arg.mode, data->arg.type, in_regs, all->reg_parm_stack_space, - entry_parm ? data->partial : 0, current_function_decl, + entry_parm ? data->partial : 0, + all->args_so_far, + current_function_decl, &all->stack_args_size, &data->locate); /* Update parm_stack_boundary if this parameter is passed in the @@ -3907,7 +3913,8 @@ gimplify_parameters (gimple_seq *cleanup) if (data.arg.pass_by_reference) { tree type = TREE_TYPE (data.arg.type); - function_arg_info orig_arg (type, data.arg.named); + function_arg_info orig_arg (type, data.arg.named, + data.arg.last_named); if (reference_callee_copied (&all.args_so_far_v, orig_arg)) { tree local, t; @@ -4010,6 +4017,7 @@ gimplify_parameters (gimple_seq *cleanup) void locate_and_pad_parm (machine_mode passed_mode, tree type, int in_regs, int reg_parm_stack_space, int partial, + cumulative_args_t ca, tree fndecl ATTRIBUTE_UNUSED, struct args_size *initial_offset_ptr, struct locate_and_pad_arg_data *locate) @@ -4047,9 +4055,23 @@ locate_and_pad_parm (machine_mode passed_mode, tree type, int in_regs, ? arg_size_in_bytes (type) : size_int (GET_MODE_SIZE (passed_mode))); where_pad = targetm.calls.function_arg_padding (passed_mode, type); - boundary = targetm.calls.function_arg_boundary (passed_mode, type); - round_boundary = targetm.calls.function_arg_round_boundary (passed_mode, - type); + + if (flag_stack_use_cumulative_args) + { + boundary = targetm.calls.function_arg_boundary_ca (passed_mode, + type, + ca); + round_boundary = targetm.calls.function_arg_round_boundary_ca + (passed_mode, type, ca); + } + else + { + boundary = targetm.calls.function_arg_boundary (passed_mode, + type); + round_boundary = targetm.calls.function_arg_round_boundary + (passed_mode, type); + } + locate->where_pad = where_pad; /* Alignment can't exceed MAX_SUPPORTED_STACK_ALIGNMENT. */ diff --git gcc/function.h gcc/function.h index a41514a..9f2f46e 100644 --- gcc/function.h +++ gcc/function.h @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_FUNCTION_H #define GCC_FUNCTION_H +#include "cumulative-args.h" /* Stack of pending (incomplete) sequences saved by `start_sequence'. Each element describes one pending sequence. @@ -654,6 +655,7 @@ extern int aggregate_value_p (const_tree, const_tree); extern bool use_register_for_decl (const_tree); extern gimple_seq gimplify_parameters (gimple_seq *); extern void locate_and_pad_parm (machine_mode, tree, int, int, int, + cumulative_args_t, tree, struct args_size *, struct locate_and_pad_arg_data *); extern void generate_setjmp_warnings (void); diff --git gcc/gcc.c gcc/gcc.c index 20a649e..0c4e3d8 100644 --- gcc/gcc.c +++ gcc/gcc.c @@ -567,6 +567,7 @@ or with constant text in a single argument. %l process LINK_SPEC as a spec. %L process LIB_SPEC as a spec. %M Output multilib_os_dir. + %P Output a RUNPATH_OPTION for each directory in startfile_prefixes. %G process LIBGCC_SPEC as a spec. %R Output the concatenation of target_system_root and target_sysroot_suffix. @@ -1186,6 +1187,10 @@ proper position among the other output files. */ # define SYSROOT_HEADERS_SUFFIX_SPEC "" #endif +#ifndef RUNPATH_OPTION +# define RUNPATH_OPTION "-rpath" +#endif + static const char *asm_debug = ASM_DEBUG_SPEC; static const char *asm_debug_option = ASM_DEBUG_OPTION_SPEC; static const char *cpp_spec = CPP_SPEC; @@ -5788,6 +5793,7 @@ struct spec_path_info { size_t append_len; bool omit_relative; bool separate_options; + bool realpaths; }; static void * @@ -5797,6 +5803,16 @@ spec_path (char *path, void *data) size_t len = 0; char save = 0; + /* The path must exist; we want to resolve it to the realpath so that this + can be embedded as a runpath. */ + if (info->realpaths) + path = lrealpath (path); + + /* However, if we failed to resolve it - perhaps because there was a bogus + -B option on the command line, then punt on this entry. */ + if (!path) + return NULL; + if (info->omit_relative && !IS_ABSOLUTE_PATH (path)) return NULL; @@ -6031,6 +6047,22 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) info.omit_relative = false; #endif info.separate_options = false; + info.realpaths = false; + + for_each_path (&startfile_prefixes, true, 0, spec_path, &info); + } + break; + + case 'P': + { + struct spec_path_info info; + + info.option = RUNPATH_OPTION; + info.append_len = 0; + info.omit_relative = false; + info.separate_options = true; + /* We want to embed the actual paths that have the libraries. */ + info.realpaths = true; for_each_path (&startfile_prefixes, true, 0, spec_path, &info); } @@ -6357,6 +6389,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) info.append_len = strlen (info.append); info.omit_relative = false; info.separate_options = true; + info.realpaths = false; for_each_path (&include_prefixes, false, info.append_len, spec_path, &info); diff --git gcc/gengtype-state.c gcc/gengtype-state.c index 891f2e1..fb99729 100644 --- gcc/gengtype-state.c +++ gcc/gengtype-state.c @@ -57,6 +57,7 @@ type_lineloc (const_type_p ty) case TYPE_STRING: case TYPE_POINTER: case TYPE_ARRAY: + case TYPE_CALLBACK: return NULL; default: gcc_unreachable (); @@ -171,6 +172,7 @@ private: void write_state_version (const char *version); void write_state_scalar_type (type_p current); void write_state_string_type (type_p current); + void write_state_callback_type (type_p current); void write_state_undefined_type (type_p current); void write_state_struct_union_type (type_p current, const char *kindstr); void write_state_struct_type (type_p current); @@ -898,6 +900,20 @@ state_writer::write_state_string_type (type_p current) fatal ("Unexpected type in write_state_string_type"); } +/* Write the callback type. There is only one such thing! */ +void +state_writer::write_state_callback_type (type_p current) +{ + if (current == &callback_type) + { + write_any_indent (0); + fprintf (state_file, "callback "); + write_state_common_type_content (current); + } + else + fatal ("Unexpected type in write_state_callback_type"); +} + /* Write an undefined type. */ void state_writer::write_state_undefined_type (type_p current) @@ -1143,6 +1159,9 @@ state_writer::write_state_type (type_p current) case TYPE_STRING: write_state_string_type (current); break; + case TYPE_CALLBACK: + write_state_callback_type (current); + break; } } @@ -1477,6 +1496,14 @@ read_state_string_type (type_p *type) read_state_common_type_content (*type); } +/* Read the callback_type. */ +static void +read_state_callback_type (type_p *type) +{ + *type = &callback_type; + read_state_common_type_content (*type); +} + /* Read a lang_bitmap representing a set of GCC front-end languages. */ static void @@ -1834,6 +1861,11 @@ read_state_type (type_p *current) next_state_tokens (1); read_state_string_type (current); } + else if (state_token_is_name (t0, "callback")) + { + next_state_tokens (1); + read_state_callback_type (current); + } else if (state_token_is_name (t0, "undefined")) { *current = XCNEW (struct type); diff --git gcc/gengtype.c gcc/gengtype.c index 98d4626..fdddb6f 100644 --- gcc/gengtype.c +++ gcc/gengtype.c @@ -167,6 +167,7 @@ dbgprint_count_type_at (const char *fil, int lin, const char *msg, type_p t) int nb_struct = 0, nb_union = 0, nb_array = 0, nb_pointer = 0; int nb_lang_struct = 0; int nb_user_struct = 0, nb_undefined = 0; + int nb_callback = 0; type_p p = NULL; for (p = t; p; p = p->next) { @@ -197,6 +198,9 @@ dbgprint_count_type_at (const char *fil, int lin, const char *msg, type_p t) case TYPE_ARRAY: nb_array++; break; + case TYPE_CALLBACK: + nb_callback++; + break; case TYPE_LANG_STRUCT: nb_lang_struct++; break; @@ -212,6 +216,8 @@ dbgprint_count_type_at (const char *fil, int lin, const char *msg, type_p t) fprintf (stderr, "@@%%@@ %d structs, %d unions\n", nb_struct, nb_union); if (nb_pointer > 0 || nb_array > 0) fprintf (stderr, "@@%%@@ %d pointers, %d arrays\n", nb_pointer, nb_array); + if (nb_callback > 0) + fprintf (stderr, "@@%%@@ %d callbacks\n", nb_callback); if (nb_lang_struct > 0) fprintf (stderr, "@@%%@@ %d lang_structs\n", nb_lang_struct); if (nb_user_struct > 0) @@ -490,6 +496,10 @@ struct type scalar_char = { TYPE_SCALAR, 0, 0, 0, GC_USED, {0} }; +struct type callback_type = { + TYPE_CALLBACK, 0, 0, 0, GC_USED, {0} +}; + /* Lists of various things. */ pair_p typedefs = NULL; @@ -1459,7 +1469,7 @@ static void set_gc_used (pair_p); static void process_gc_options (options_p opt, enum gc_used_enum level, int *maybe_undef, - int *length, int *skip, type_p *nested_ptr) + int *length, int *skip, int *callback, type_p *nested_ptr) { options_p o; for (o = opt; o; o = o->next) @@ -1473,6 +1483,8 @@ process_gc_options (options_p opt, enum gc_used_enum level, int *maybe_undef, *length = 1; else if (strcmp (o->name, "skip") == 0) *skip = 1; + else if (strcmp (o->name, "callback") == 0) + *callback = 1; else if (strcmp (o->name, "nested_ptr") == 0 && o->kind == OPTION_NESTED) *nested_ptr = ((const struct nested_ptr_data *) o->info.nested)->type; @@ -1521,7 +1533,7 @@ set_gc_used_type (type_p t, enum gc_used_enum level, type_p dummy2; bool allow_undefined_field_types = (t->kind == TYPE_USER_STRUCT); - process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy, + process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy, &dummy, &dummy2); if (t->u.s.base_class) @@ -1537,9 +1549,10 @@ set_gc_used_type (type_p t, enum gc_used_enum level, int maybe_undef = 0; int length = 0; int skip = 0; + int callback = 0; type_p nested_ptr = NULL; process_gc_options (f->opt, level, &maybe_undef, &length, &skip, - &nested_ptr); + &callback, &nested_ptr); if (nested_ptr && f->type->kind == TYPE_POINTER) set_gc_used_type (nested_ptr, GC_POINTED_TO); @@ -1549,6 +1562,8 @@ set_gc_used_type (type_p t, enum gc_used_enum level, set_gc_used_type (f->type->u.p, GC_MAYBE_POINTED_TO); else if (skip) ; /* target type is not used through this field */ + else if (callback) + f->type = &callback_type; else set_gc_used_type (f->type, GC_USED, allow_undefined_field_types); } @@ -2469,6 +2484,7 @@ struct walk_type_data int loopcounter; bool in_ptr_field; bool have_this_obj; + bool in_nested_ptr; }; @@ -2512,6 +2528,7 @@ output_mangled_typename (outf_p of, const_type_p t) { case TYPE_NONE: case TYPE_UNDEFINED: + case TYPE_CALLBACK: gcc_unreachable (); break; case TYPE_POINTER: @@ -2712,6 +2729,8 @@ walk_type (type_p t, struct walk_type_data *d) ; else if (strcmp (oo->name, "for_user") == 0) ; + else if (strcmp (oo->name, "callback") == 0) + ; else error_at_line (d->line, "unknown option `%s'\n", oo->name); @@ -2737,6 +2756,7 @@ walk_type (type_p t, struct walk_type_data *d) { case TYPE_SCALAR: case TYPE_STRING: + case TYPE_CALLBACK: d->process_field (t, d); break; @@ -2781,6 +2801,7 @@ walk_type (type_p t, struct walk_type_data *d) if (nested_ptr_d) { const char *oldprevval2 = d->prev_val[2]; + bool old_in_nested_ptr = d->in_nested_ptr; if (!union_or_struct_p (nested_ptr_d->type)) { @@ -2791,6 +2812,7 @@ walk_type (type_p t, struct walk_type_data *d) } d->prev_val[2] = d->val; + d->in_nested_ptr = true; oprintf (d->of, "%*s{\n", d->indent, ""); d->indent += 2; d->val = xasprintf ("x%d", d->counter++); @@ -2820,6 +2842,7 @@ walk_type (type_p t, struct walk_type_data *d) oprintf (d->of, "%*s}\n", d->indent, ""); d->val = d->prev_val[2]; d->prev_val[2] = oldprevval2; + d->in_nested_ptr = old_in_nested_ptr; } else d->process_field (t->u.p, d); @@ -3268,6 +3291,7 @@ write_types_process_field (type_p f, const struct walk_type_data *d) break; case TYPE_SCALAR: + case TYPE_CALLBACK: break; case TYPE_ARRAY: @@ -3801,18 +3825,24 @@ write_types_local_user_process_field (type_p f, const struct walk_type_data *d) case TYPE_UNION: case TYPE_LANG_STRUCT: case TYPE_STRING: - oprintf (d->of, "%*s op (&(%s), cookie);\n", d->indent, "", d->val); + if (d->in_nested_ptr) + oprintf (d->of, "%*s op (&(%s), &(%s), cookie);\n", + d->indent, "", d->val, d->prev_val[2]); + oprintf (d->of, "%*s op (&(%s), NULL, cookie);\n", + d->indent, "", d->val); break; case TYPE_USER_STRUCT: if (d->in_ptr_field) - oprintf (d->of, "%*s op (&(%s), cookie);\n", d->indent, "", d->val); + oprintf (d->of, "%*s op (&(%s), NULL, cookie);\n", + d->indent, "", d->val); else oprintf (d->of, "%*s gt_pch_nx (&(%s), op, cookie);\n", d->indent, "", d->val); break; case TYPE_SCALAR: + case TYPE_CALLBACK: break; case TYPE_ARRAY: @@ -3883,14 +3913,20 @@ write_types_local_process_field (type_p f, const struct walk_type_data *d) case TYPE_STRING: oprintf (d->of, "%*sif ((void *)(%s) == this_obj)\n", d->indent, "", d->prev_val[3]); - oprintf (d->of, "%*s op (&(%s), cookie);\n", d->indent, "", d->val); + if (d->in_nested_ptr) + oprintf (d->of, "%*s op (&(%s), &(%s), cookie);\n", + d->indent, "", d->val, d->prev_val[2]); + else + oprintf (d->of, "%*s op (&(%s), NULL, cookie);\n", + d->indent, "", d->val); break; case TYPE_USER_STRUCT: oprintf (d->of, "%*sif ((void *)(%s) == this_obj)\n", d->indent, "", d->prev_val[3]); if (d->in_ptr_field) - oprintf (d->of, "%*s op (&(%s), cookie);\n", d->indent, "", d->val); + oprintf (d->of, "%*s op (&(%s), NULL, cookie);\n", + d->indent, "", d->val); else oprintf (d->of, "%*s gt_pch_nx (&(%s), op, cookie);\n", d->indent, "", d->val); @@ -3899,6 +3935,13 @@ write_types_local_process_field (type_p f, const struct walk_type_data *d) case TYPE_SCALAR: break; + case TYPE_CALLBACK: + oprintf (d->of, "%*sif ((void *)(%s) == this_obj)\n", d->indent, "", + d->prev_val[3]); + oprintf (d->of, "%*s gt_pch_note_callback (&(%s), this_obj);\n", + d->indent, "", d->val); + break; + case TYPE_ARRAY: case TYPE_NONE: case TYPE_UNDEFINED: @@ -4427,6 +4470,7 @@ write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length, case TYPE_UNDEFINED: case TYPE_UNION: case TYPE_LANG_STRUCT: + case TYPE_CALLBACK: error_at_line (line, "global `%s' is unimplemented type", name); } } @@ -4721,6 +4765,9 @@ dump_typekind (int indent, enum typekind kind) case TYPE_ARRAY: printf ("TYPE_ARRAY"); break; + case TYPE_CALLBACK: + printf ("TYPE_CALLBACK"); + break; case TYPE_LANG_STRUCT: printf ("TYPE_LANG_STRUCT"); break; @@ -4887,6 +4934,7 @@ dump_type (int indent, type_p t) t->u.scalar_is_char ? "true" : "false"); break; case TYPE_STRING: + case TYPE_CALLBACK: break; case TYPE_STRUCT: case TYPE_UNION: diff --git gcc/gengtype.h gcc/gengtype.h index 4fe8f0f..c32faba 100644 --- gcc/gengtype.h +++ gcc/gengtype.h @@ -149,6 +149,9 @@ enum typekind { TYPE_UNION, /* Type for GTY-ed discriminated unions. */ TYPE_POINTER, /* Pointer type to GTY-ed type. */ TYPE_ARRAY, /* Array of GTY-ed types. */ + TYPE_CALLBACK, /* A function pointer that needs relocation if + the executable has been loaded at a different + address. */ TYPE_LANG_STRUCT, /* GCC front-end language specific structs. Various languages may have homonymous but different structs. */ @@ -326,6 +329,9 @@ extern struct type string_type; extern struct type scalar_nonchar; extern struct type scalar_char; +/* The one and only TYPE_CALLBACK. */ +extern struct type callback_type; + /* Test if a type is a union, either a plain one or a language specific one. */ #define UNION_P(x) \ diff --git gcc/ggc-common.c gcc/ggc-common.c index 357bda1..a130db8 100644 --- gcc/ggc-common.c +++ gcc/ggc-common.c @@ -43,7 +43,7 @@ static ggc_statistics *ggc_stats; struct traversal_state; static int compare_ptr_data (const void *, const void *); -static void relocate_ptrs (void *, void *); +static void relocate_ptrs (void *, void *, void *); static void write_pch_globals (const struct ggc_root_tab * const *tab, struct traversal_state *state); @@ -249,6 +249,8 @@ saving_hasher::equal (const ptr_data *p1, const void *p2) } static hash_table *saving_htab; +static vec callback_vec; +static vec reloc_addrs_vec; /* Register an object in the hash table. */ @@ -281,6 +283,23 @@ gt_pch_note_object (void *obj, void *note_ptr_cookie, return 1; } +/* Register address of a callback pointer. */ +void +gt_pch_note_callback (void *obj, void *base) +{ + void *ptr; + memcpy (&ptr, obj, sizeof (void *)); + if (ptr != NULL) + { + struct ptr_data *data + = (struct ptr_data *) + saving_htab->find_with_hash (base, POINTER_HASH (base)); + gcc_assert (data); + callback_vec.safe_push ((char *) data->new_addr + + ((char *) obj - (char *) base)); + } +} + /* Register an object in the hash table. */ void @@ -348,10 +367,10 @@ compare_ptr_data (const void *p1_p, const void *p2_p) /* Callbacks for note_ptr_fn. */ static void -relocate_ptrs (void *ptr_p, void *state_p) +relocate_ptrs (void *ptr_p, void *real_ptr_p, void *state_p) { void **ptr = (void **)ptr_p; - struct traversal_state *state ATTRIBUTE_UNUSED + struct traversal_state *state = (struct traversal_state *)state_p; struct ptr_data *result; @@ -362,6 +381,19 @@ relocate_ptrs (void *ptr_p, void *state_p) saving_htab->find_with_hash (*ptr, POINTER_HASH (*ptr)); gcc_assert (result); *ptr = result->new_addr; + if (ptr_p == real_ptr_p) + return; + if (real_ptr_p == NULL) + real_ptr_p = ptr_p; + gcc_assert (real_ptr_p >= state->ptrs[state->ptrs_i]->obj + && ((char *) real_ptr_p + sizeof (void *) + <= ((char *) state->ptrs[state->ptrs_i]->obj + + state->ptrs[state->ptrs_i]->size))); + void *addr + = (void *) ((char *) state->ptrs[state->ptrs_i]->new_addr + + ((char *) real_ptr_p + - (char *) state->ptrs[state->ptrs_i]->obj)); + reloc_addrs_vec.safe_push (addr); } /* Write out, after relocation, the pointers in TAB. */ @@ -396,6 +428,61 @@ write_pch_globals (const struct ggc_root_tab * const *tab, } } +/* Callback for qsort. */ + +static int +compare_ptr (const void *p1_p, const void *p2_p) +{ + void *p1 = *(void *const *)p1_p; + void *p2 = *(void *const *)p2_p; + return (((uintptr_t)p1 > (uintptr_t)p2) + - ((uintptr_t)p1 < (uintptr_t)p2)); +} + +/* Decode one uleb128 from P, return first byte after it, store + decoded value into *VAL. */ + +static unsigned char * +read_uleb128 (unsigned char *p, size_t *val) +{ + unsigned int shift = 0; + unsigned char byte; + size_t result; + + result = 0; + do + { + byte = *p++; + result |= ((size_t) byte & 0x7f) << shift; + shift += 7; + } + while (byte & 0x80); + + *val = result; + return p; +} + +/* Store VAL as uleb128 at P, return length in bytes. */ + +static size_t +write_uleb128 (unsigned char *p, size_t val) +{ + size_t len = 0; + do + { + unsigned char byte = (val & 0x7f); + val >>= 7; + if (val != 0) + /* More bytes to follow. */ + byte |= 0x80; + + *p++ = byte; + ++len; + } + while (val != 0); + return len; +} + /* Hold the information we need to mmap the file back in. */ struct mmap_info @@ -443,6 +530,10 @@ gt_pch_save (FILE *f) (The extra work goes in HOST_HOOKS_GT_PCH_GET_ADDRESS and HOST_HOOKS_GT_PCH_USE_ADDRESS.) */ mmi.preferred_base = host_hooks.gt_pch_get_address (mmi.size, fileno (f)); + /* If the host cannot supply any suitable address for this, we are stuck. */ + if (mmi.preferred_base == NULL) + fatal_error (input_location, + "cannot write PCH file: required memory segment unavailable"); ggc_pch_this_base (state.d, mmi.preferred_base); @@ -492,6 +583,7 @@ gt_pch_save (FILE *f) /* Actually write out the objects. */ for (i = 0; i < state.count; i++) { + state.ptrs_i = i; if (this_object_size < state.ptrs[i]->size) { this_object_size = state.ptrs[i]->size; @@ -572,13 +664,59 @@ gt_pch_save (FILE *f) vbits.release (); #endif + reloc_addrs_vec.qsort (compare_ptr); + + size_t reloc_addrs_size = 0; + void *last_addr = NULL; + unsigned char uleb128_buf[sizeof (size_t) * 2]; + for (void *addr : reloc_addrs_vec) + { + gcc_assert ((uintptr_t) addr >= (uintptr_t) mmi.preferred_base + && ((uintptr_t) addr + sizeof (void *) + < (uintptr_t) mmi.preferred_base + mmi.size)); + if (addr == last_addr) + continue; + if (last_addr == NULL) + last_addr = mmi.preferred_base; + size_t diff = (uintptr_t) addr - (uintptr_t) last_addr; + reloc_addrs_size += write_uleb128 (uleb128_buf, diff); + last_addr = addr; + } + if (fwrite (&reloc_addrs_size, sizeof (reloc_addrs_size), 1, f) != 1) + fatal_error (input_location, "cannot write PCH file: %m"); + last_addr = NULL; + for (void *addr : reloc_addrs_vec) + { + if (addr == last_addr) + continue; + if (last_addr == NULL) + last_addr = mmi.preferred_base; + size_t diff = (uintptr_t) addr - (uintptr_t) last_addr; + reloc_addrs_size = write_uleb128 (uleb128_buf, diff); + if (fwrite (uleb128_buf, 1, reloc_addrs_size, f) != reloc_addrs_size) + fatal_error (input_location, "cannot write PCH file: %m"); + last_addr = addr; + } + ggc_pch_finish (state.d, state.f); + gt_pch_fixup_stringpool (); + unsigned num_callbacks = callback_vec.length (); + void (*pch_save) (FILE *) = >_pch_save; + if (fwrite (&pch_save, sizeof (pch_save), 1, f) != 1 + || fwrite (&num_callbacks, sizeof (num_callbacks), 1, f) != 1 + || (num_callbacks + && fwrite (callback_vec.address (), sizeof (void *), num_callbacks, + f) != num_callbacks)) + fatal_error (input_location, "cannot write PCH file: %m"); + XDELETE (state.ptrs); XDELETE (this_object); delete saving_htab; saving_htab = NULL; + callback_vec.release (); + reloc_addrs_vec.release (); } /* Read the state of the compiler back in from F. */ @@ -592,6 +730,13 @@ gt_pch_restore (FILE *f) struct mmap_info mmi; int result; + /* We are about to reload the line maps along with the rest of the PCH + data, which means that the (loaded) ones cannot be guaranteed to be + in any valid state for reporting diagnostics that happen during the + load. Save the current table (and use it during the loading process + below). */ + class line_maps *save_line_table = line_table; + /* Delete any deletable objects. This makes ggc_pch_read much faster, as it can be sure that no GCable objects remain other than the ones just read in. */ @@ -606,20 +751,41 @@ gt_pch_restore (FILE *f) fatal_error (input_location, "cannot read PCH file: %m"); /* Read in all the global pointers, in 6 easy loops. */ + bool error_reading_pointers = false; for (rt = gt_ggc_rtab; *rt; rt++) for (rti = *rt; rti->base != NULL; rti++) for (i = 0; i < rti->nelt; i++) if (fread ((char *)rti->base + rti->stride * i, sizeof (void *), 1, f) != 1) - fatal_error (input_location, "cannot read PCH file: %m"); + error_reading_pointers = true; + + /* Stash the newly read-in line table pointer - it does not point to + anything meaningful yet, so swap the old one back in. */ + class line_maps *new_line_table = line_table; + line_table = save_line_table; + if (error_reading_pointers) + fatal_error (input_location, "cannot read PCH file: %m"); if (fread (&mmi, sizeof (mmi), 1, f) != 1) fatal_error (input_location, "cannot read PCH file: %m"); + void *orig_preferred_base = mmi.preferred_base; result = host_hooks.gt_pch_use_address (mmi.preferred_base, mmi.size, fileno (f), mmi.offset); + + /* We could not mmap or otherwise allocate the required memory at the + address needed. */ if (result < 0) - fatal_error (input_location, "had to relocate PCH"); + { + sorry_at (input_location, "PCH allocation failure"); + /* There is no point in continuing from here, we will only end up + with a crashed (most likely hanging) compiler. */ + exit (-1); + } + + /* (0) We allocated memory, but did not mmap the file, so we need to read + the data in manually. (>0) Otherwise the mmap succeed for the address + we wanted. */ if (result == 0) { if (fseek (f, mmi.offset, SEEK_SET) != 0 @@ -629,9 +795,108 @@ gt_pch_restore (FILE *f) else if (fseek (f, mmi.offset + mmi.size, SEEK_SET) != 0) fatal_error (input_location, "cannot read PCH file: %m"); + size_t reloc_addrs_size; + if (fread (&reloc_addrs_size, sizeof (reloc_addrs_size), 1, f) != 1) + fatal_error (input_location, "cannot read PCH file: %m"); + + if (orig_preferred_base != mmi.preferred_base) + { + uintptr_t bias + = (uintptr_t) mmi.preferred_base - (uintptr_t) orig_preferred_base; + + /* Adjust all the global pointers by bias. */ + line_table = new_line_table; + for (rt = gt_ggc_rtab; *rt; rt++) + for (rti = *rt; rti->base != NULL; rti++) + for (i = 0; i < rti->nelt; i++) + { + char *addr = (char *)rti->base + rti->stride * i; + char *p; + memcpy (&p, addr, sizeof (void *)); + if ((uintptr_t) p >= (uintptr_t) orig_preferred_base + && (uintptr_t) p < (uintptr_t) orig_preferred_base + mmi.size) + { + p = (char *) ((uintptr_t) p + bias); + memcpy (addr, &p, sizeof (void *)); + } + } + new_line_table = line_table; + line_table = save_line_table; + + /* And adjust all the pointers in the image by bias too. */ + char *addr = (char *) mmi.preferred_base; + unsigned char uleb128_buf[4096], *uleb128_ptr = uleb128_buf; + while (reloc_addrs_size != 0) + { + size_t this_size + = MIN (reloc_addrs_size, + (size_t) (4096 - (uleb128_ptr - uleb128_buf))); + if (fread (uleb128_ptr, 1, this_size, f) != this_size) + fatal_error (input_location, "cannot read PCH file: %m"); + unsigned char *uleb128_end = uleb128_ptr + this_size; + if (this_size != reloc_addrs_size) + uleb128_end -= 2 * sizeof (size_t); + uleb128_ptr = uleb128_buf; + while (uleb128_ptr < uleb128_end) + { + size_t diff; + uleb128_ptr = read_uleb128 (uleb128_ptr, &diff); + addr = (char *) ((uintptr_t) addr + diff); + + char *p; + memcpy (&p, addr, sizeof (void *)); + gcc_assert ((uintptr_t) p >= (uintptr_t) orig_preferred_base + && ((uintptr_t) p + < (uintptr_t) orig_preferred_base + mmi.size)); + p = (char *) ((uintptr_t) p + bias); + memcpy (addr, &p, sizeof (void *)); + } + reloc_addrs_size -= this_size; + if (reloc_addrs_size == 0) + break; + this_size = uleb128_end + 2 * sizeof (size_t) - uleb128_ptr; + memcpy (uleb128_buf, uleb128_ptr, this_size); + uleb128_ptr = uleb128_buf + this_size; + } + } + else if (fseek (f, (mmi.offset + mmi.size + sizeof (reloc_addrs_size) + + reloc_addrs_size), SEEK_SET) != 0) + fatal_error (input_location, "cannot read PCH file: %m"); + ggc_pch_read (f, mmi.preferred_base); + void (*pch_save) (FILE *); + unsigned num_callbacks; + if (fread (&pch_save, sizeof (pch_save), 1, f) != 1 + || fread (&num_callbacks, sizeof (num_callbacks), 1, f) != 1) + fatal_error (input_location, "cannot read PCH file: %m"); + if (pch_save != >_pch_save) + { + uintptr_t binbias = (uintptr_t) >_pch_save - (uintptr_t) pch_save; + void **ptrs = XNEWVEC (void *, num_callbacks); + unsigned i; + uintptr_t bias + = (uintptr_t) mmi.preferred_base - (uintptr_t) orig_preferred_base; + + if (fread (ptrs, sizeof (void *), num_callbacks, f) != num_callbacks) + fatal_error (input_location, "cannot read PCH file: %m"); + for (i = 0; i < num_callbacks; ++i) + { + void *ptr = (void *) ((uintptr_t) ptrs[i] + bias); + memcpy (&pch_save, ptr, sizeof (pch_save)); + pch_save = (void (*) (FILE *)) ((uintptr_t) pch_save + binbias); + memcpy (ptr, &pch_save, sizeof (pch_save)); + } + XDELETE (ptrs); + } + else if (fseek (f, num_callbacks * sizeof (void *), SEEK_CUR) != 0) + fatal_error (input_location, "cannot read PCH file: %m"); + gt_pch_restore_stringpool (); + + /* Barring corruption of the PCH file, the restored line table should be + complete and usable. */ + line_table = new_line_table; } /* Default version of HOST_HOOKS_GT_PCH_GET_ADDRESS when mmap is not present. @@ -652,7 +917,7 @@ default_gt_pch_get_address (size_t size ATTRIBUTE_UNUSED, of the PCH file would be required. */ int -default_gt_pch_use_address (void *base, size_t size, int fd ATTRIBUTE_UNUSED, +default_gt_pch_use_address (void *&base, size_t size, int fd ATTRIBUTE_UNUSED, size_t offset ATTRIBUTE_UNUSED) { void *addr = xmalloc (size); @@ -698,7 +963,7 @@ mmap_gt_pch_get_address (size_t size, int fd) mapped with something. */ int -mmap_gt_pch_use_address (void *base, size_t size, int fd, size_t offset) +mmap_gt_pch_use_address (void *&base, size_t size, int fd, size_t offset) { void *addr; diff --git gcc/ggc-tests.c gcc/ggc-tests.c index 4ee9550..03e6ed3 100644 --- gcc/ggc-tests.c +++ gcc/ggc-tests.c @@ -426,7 +426,7 @@ gt_pch_nx (user_struct *p) static void gt_pch_nx (user_struct *p, gt_pointer_operator op, void *cookie) { - op (&(p->m_ptr), cookie); + op (&(p->m_ptr), NULL, cookie); } /* Verify that GTY((user)) works. */ diff --git gcc/ggc.h gcc/ggc.h index 65f6cb4..3339394 100644 --- gcc/ggc.h +++ gcc/ggc.h @@ -46,6 +46,10 @@ typedef void (*gt_handle_reorder) (void *, void *, gt_pointer_operator, /* Used by the gt_pch_n_* routines. Register an object in the hash table. */ extern int gt_pch_note_object (void *, void *, gt_note_pointers); +/* Used by the gt_pch_p_* routines. Register address of a callback + pointer. */ +extern void gt_pch_note_callback (void *, void *); + /* Used by the gt_pch_n_* routines. Register that an object has a reorder function. */ extern void gt_pch_note_reorder (void *, void *, gt_handle_reorder); diff --git gcc/ginclude/stddef.h gcc/ginclude/stddef.h index 66619fe..bc2074a 100644 --- gcc/ginclude/stddef.h +++ gcc/ginclude/stddef.h @@ -418,9 +418,8 @@ typedef struct { /* _Float128 is defined as a basic type, so max_align_t must be sufficiently aligned for it. This code must work in C++, so we use __float128 here; that is only available on some - architectures, but only on i386 is extra alignment needed for - __float128. */ -#ifdef __i386__ + architectures. */ +#if defined(__i386__) || (__APPLE__ && __aarch64__) __float128 __max_align_f128 __attribute__((__aligned__(__alignof(__float128)))); #endif } max_align_t; diff --git gcc/hash-map.h gcc/hash-map.h index 0779c93..eaf0385 100644 --- gcc/hash-map.h +++ gcc/hash-map.h @@ -126,7 +126,7 @@ class GTY((user)) hash_map static void pch_nx_helper (T *&x, gt_pointer_operator op, void *cookie) { - op (&x, cookie); + op (&x, NULL, cookie); } }; @@ -326,7 +326,7 @@ template static inline void gt_pch_nx (hash_map *h, gt_pointer_operator op, void *cookie) { - op (&h->m_table.m_entries, cookie); + op (&h->m_table.m_entries, NULL, cookie); } enum hm_alloc { hm_heap = false, hm_ggc = true }; diff --git gcc/hash-set.h gcc/hash-set.h index 85c31ef..60b3fcb 100644 --- gcc/hash-set.h +++ gcc/hash-set.h @@ -206,7 +206,7 @@ template static inline void gt_pch_nx (hash_set *h, gt_pointer_operator op, void *cookie) { - op (&h->m_table.m_entries, cookie); + op (&h->m_table.m_entries, NULL, cookie); } #endif diff --git gcc/hash-table.h gcc/hash-table.h index a6e0ac8..548a9e2 100644 --- gcc/hash-table.h +++ gcc/hash-table.h @@ -1203,7 +1203,7 @@ template static inline void gt_pch_nx (hash_table *h, gt_pointer_operator op, void *cookie) { - op (&h->m_entries, cookie); + op (&h->m_entries, NULL, cookie); } template diff --git gcc/hash-traits.h gcc/hash-traits.h index 57c81bf..6f0373e 100644 --- gcc/hash-traits.h +++ gcc/hash-traits.h @@ -254,7 +254,7 @@ struct ggc_remove static void pch_nx (T &p, gt_pointer_operator op, void *cookie) { - op (&p, cookie); + op (&p, NULL, cookie); } }; diff --git gcc/hosthooks-def.h gcc/hosthooks-def.h index a87b6d3..8f50932 100644 --- gcc/hosthooks-def.h +++ gcc/hosthooks-def.h @@ -35,10 +35,10 @@ along with GCC; see the file COPYING3. If not see default_gt_pch_alloc_granularity extern void* default_gt_pch_get_address (size_t, int); -extern int default_gt_pch_use_address (void *, size_t, int, size_t); +extern int default_gt_pch_use_address (void *&, size_t, int, size_t); extern size_t default_gt_pch_alloc_granularity (void); extern void* mmap_gt_pch_get_address (size_t, int); -extern int mmap_gt_pch_use_address (void *, size_t, int, size_t); +extern int mmap_gt_pch_use_address (void *&, size_t, int, size_t); /* The structure is defined in hosthooks.h. */ #define HOST_HOOKS_INITIALIZER { \ diff --git gcc/hosthooks.h gcc/hosthooks.h index 42ed3dc..8241a53 100644 --- gcc/hosthooks.h +++ gcc/hosthooks.h @@ -30,10 +30,12 @@ struct host_hooks void * (*gt_pch_get_address) (size_t size, int fd); /* ADDR is an address returned by gt_pch_get_address. Attempt to allocate - SIZE bytes at the same address and load it with the data from FD at - OFFSET. Return -1 if we couldn't allocate memory at ADDR, return 0 - if the memory is allocated but the data not loaded, return 1 if done. */ - int (*gt_pch_use_address) (void *addr, size_t size, int fd, size_t offset); + SIZE bytes at the same address (preferrably) or some other address + and load it with the data from FD at OFFSET. Return -1 if we couldn't + allocate memory, otherwise update ADDR to the actual address where it got + allocated, return 0 if the memory is allocated but the data not loaded, + return 1 if done. */ + int (*gt_pch_use_address) (void *&addr, size_t size, int fd, size_t offset); /* Return the alignment required for allocating virtual memory. Usually this is the same as pagesize. */ diff --git gcc/jit/Make-lang.in gcc/jit/Make-lang.in index 2a774d7..5e93316 100644 --- gcc/jit/Make-lang.in +++ gcc/jit/Make-lang.in @@ -59,7 +59,7 @@ LIBGCCJIT_AGE = 1 LIBGCCJIT_BASENAME = libgccjit LIBGCCJIT_SONAME = \ - ${libdir}/$(LIBGCCJIT_BASENAME).$(LIBGCCJIT_VERSION_NUM).dylib + $(DARWIN_RPATH)/$(LIBGCCJIT_BASENAME).$(LIBGCCJIT_VERSION_NUM).dylib LIBGCCJIT_FILENAME = $(LIBGCCJIT_BASENAME).$(LIBGCCJIT_VERSION_NUM).dylib LIBGCCJIT_LINKER_NAME = $(LIBGCCJIT_BASENAME).dylib diff --git gcc/machmode.h gcc/machmode.h index 1583513..2e5bafd 100644 --- gcc/machmode.h +++ gcc/machmode.h @@ -1199,7 +1199,7 @@ gt_pch_nx (pod_mode *) template void -gt_pch_nx (pod_mode *, void (*) (void *, void *), void *) +gt_pch_nx (pod_mode *, void (*) (void *, void *, void *), void *) { } diff --git gcc/objc/objc-act.c gcc/objc/objc-act.c index 1cbd586..e69bec8 100644 --- gcc/objc/objc-act.c +++ gcc/objc/objc-act.c @@ -1302,6 +1302,7 @@ objc_add_property_declaration (location_t location, tree decl, TREE_TYPE (property_decl) = p_type; DECL_SOURCE_LOCATION (property_decl) = DECL_SOURCE_LOCATION (decl); TREE_DEPRECATED (property_decl) = TREE_DEPRECATED (decl); + TREE_UNAVAILABLE (property_decl) = TREE_UNAVAILABLE (decl); /* Add property-specific information. */ PROPERTY_NAME (property_decl) = DECL_NAME (decl); @@ -1439,6 +1440,7 @@ maybe_make_artificial_property_decl (tree interface, tree implementation, TREE_TYPE (property_decl) = type; DECL_SOURCE_LOCATION (property_decl) = input_location; TREE_DEPRECATED (property_decl) = 0; + TREE_UNAVAILABLE (property_decl) = 0; DECL_ARTIFICIAL (property_decl) = 1; /* Add property-specific information. Note that one of @@ -1717,7 +1719,7 @@ objc_maybe_build_component_ref (tree object, tree property_ident) { tree expression; tree getter_call; - tree deprecated_method_prototype = NULL_TREE; + tree method_prototype_avail = NULL_TREE; /* We have an additional nasty problem here; if this PROPERTY_REF needs to become a 'getter', then the conversion @@ -1751,10 +1753,10 @@ objc_maybe_build_component_ref (tree object, tree property_ident) is deprecated, but record the fact that the getter is deprecated by setting PROPERTY_REF_DEPRECATED_GETTER to the method prototype. */ - &deprecated_method_prototype); + &method_prototype_avail); expression = build4 (PROPERTY_REF, TREE_TYPE(x), object, x, getter_call, - deprecated_method_prototype); + method_prototype_avail); SET_EXPR_LOCATION (expression, input_location); TREE_SIDE_EFFECTS (expression) = 1; @@ -1804,7 +1806,9 @@ objc_build_class_component_ref (tree class_name, tree property_ident) } else { - if (TREE_DEPRECATED (rtype)) + if (TREE_UNAVAILABLE (rtype)) + error ("class %qE is unavailable", class_name); + else if (TREE_DEPRECATED (rtype)) warning (OPT_Wdeprecated_declarations, "class %qE is deprecated", class_name); } @@ -1816,17 +1820,17 @@ objc_build_class_component_ref (tree class_name, tree property_ident) { tree expression; tree getter_call; - tree deprecated_method_prototype = NULL_TREE; + tree method_prototype_avail = NULL_TREE; if (PROPERTY_HAS_NO_GETTER (x)) getter_call = NULL_TREE; else getter_call = objc_finish_message_expr (object, PROPERTY_GETTER_NAME (x), NULL_TREE, - &deprecated_method_prototype); + &method_prototype_avail); expression = build4 (PROPERTY_REF, TREE_TYPE(x), object, x, getter_call, - deprecated_method_prototype); + method_prototype_avail); SET_EXPR_LOCATION (expression, input_location); TREE_SIDE_EFFECTS (expression) = 1; @@ -3376,8 +3380,10 @@ objc_build_string_object (tree string) return addr; } -/* Build a static constant CONSTRUCTOR - with type TYPE and elements ELTS. */ +/* Build a static constant CONSTRUCTOR with type TYPE and elements ELTS. + We might be presented with a NULL for ELTS, which means 'empty ctor' + which will subsequently be converted into a zero initializer in the + middle end. */ tree objc_build_constructor (tree type, vec *elts) @@ -3389,12 +3395,10 @@ objc_build_constructor (tree type, vec *elts) TREE_READONLY (constructor) = 1; #ifdef OBJCPLUS - /* Adjust for impedance mismatch. We should figure out how to build - CONSTRUCTORs that consistently please both the C and C++ gods. */ - if (!(*elts)[0].index) + /* If we know the initializer, then set the type to what C++ expects. */ + if (elts && !(*elts)[0].index) TREE_TYPE (constructor) = init_list_type_node; #endif - return constructor; } @@ -4597,6 +4601,8 @@ build_private_template (tree klass) /* Copy the attributes from the class to the type. */ if (TREE_DEPRECATED (klass)) TREE_DEPRECATED (record) = 1; + if (TREE_UNAVAILABLE (klass)) + TREE_UNAVAILABLE (record) = 1; } } @@ -5022,6 +5028,7 @@ objc_decl_method_attributes (tree *node, tree attributes, int flags) tree name = TREE_PURPOSE (attribute); if (is_attribute_p ("deprecated", name) + || is_attribute_p ("unavailable", name) || is_attribute_p ("sentinel", name) || is_attribute_p ("noreturn", name)) { @@ -5487,9 +5494,9 @@ lookup_method_in_hash_lists (tree sel_name, int is_class) C++ template functions, it is called from 'build_expr_from_tree' (in decl2.c) after RECEIVER and METHOD_PARAMS have been expanded. - If the DEPRECATED_METHOD_PROTOTYPE argument is NULL, then we warn + If the method_prototype_avail argument is NULL, then we warn if the method being used is deprecated. If it is not NULL, instead - of deprecating, we set *DEPRECATED_METHOD_PROTOTYPE to the method + of deprecating, we set *method_prototype_avail to the method prototype that was used and is deprecated. This is useful for getter calls that are always generated when compiling dot-syntax expressions, even if they may not be used. In that case, we don't @@ -5498,7 +5505,7 @@ lookup_method_in_hash_lists (tree sel_name, int is_class) used. */ tree objc_finish_message_expr (tree receiver, tree sel_name, tree method_params, - tree *deprecated_method_prototype) + tree *method_prototype_avail) { tree method_prototype = NULL_TREE, rprotos = NULL_TREE, rtype; tree retval, class_tree; @@ -5810,10 +5817,17 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params, In practice this makes sense since casting an object to 'id' is often used precisely to turn off warnings associated with the object being of a particular class. */ - if (TREE_DEPRECATED (method_prototype) && rtype != NULL_TREE) + if (TREE_UNAVAILABLE (method_prototype) && rtype != NULL_TREE) { - if (deprecated_method_prototype) - *deprecated_method_prototype = method_prototype; + if (method_prototype_avail) + *method_prototype_avail = method_prototype; + else + error_unavailable_use (method_prototype, NULL_TREE); + } + else if (TREE_DEPRECATED (method_prototype) && rtype != NULL_TREE) + { + if (method_prototype_avail) + *method_prototype_avail = method_prototype; else warn_deprecated_use (method_prototype, NULL_TREE); } @@ -6985,7 +6999,9 @@ start_class (enum tree_code code, tree class_name, tree super_name, } else { - if (TREE_DEPRECATED (super_interface)) + if (TREE_UNAVAILABLE (super_interface)) + error ("class %qE is not available", super); + else if (TREE_DEPRECATED (super_interface)) warning (OPT_Wdeprecated_declarations, "class %qE is deprecated", super); super_name = super; @@ -7095,7 +7111,9 @@ start_class (enum tree_code code, tree class_name, tree super_name, /* TODO: Document what the objc_exception attribute is/does. */ /* We handle the 'deprecated', 'visibility' and (undocumented) 'objc_exception' attributes. */ - if (is_attribute_p ("deprecated", name)) + if (is_attribute_p ("unavailable", name)) + TREE_UNAVAILABLE (klass) = 1; + else if (is_attribute_p ("deprecated", name)) TREE_DEPRECATED (klass) = 1; else if (is_attribute_p ("objc_exception", name)) CLASS_HAS_EXCEPTION_ATTR (klass) = 1; @@ -7126,7 +7144,9 @@ start_class (enum tree_code code, tree class_name, tree super_name, } else { - if (TREE_DEPRECATED (class_category_is_assoc_with)) + if (TREE_UNAVAILABLE (class_category_is_assoc_with)) + error ("class %qE is unavailable", class_name); + else if (TREE_DEPRECATED (class_category_is_assoc_with)) warning (OPT_Wdeprecated_declarations, "class %qE is deprecated", class_name); @@ -8153,6 +8173,7 @@ finish_class (tree klass) else objc_add_method (objc_interface_context, getter_decl, false, false); TREE_DEPRECATED (getter_decl) = TREE_DEPRECATED (x); + TREE_UNAVAILABLE (getter_decl) = TREE_UNAVAILABLE (x); METHOD_PROPERTY_CONTEXT (getter_decl) = x; } @@ -8197,6 +8218,7 @@ finish_class (tree klass) else objc_add_method (objc_interface_context, setter_decl, false, false); TREE_DEPRECATED (setter_decl) = TREE_DEPRECATED (x); + TREE_UNAVAILABLE (setter_decl) = TREE_UNAVAILABLE (x); METHOD_PROPERTY_CONTEXT (setter_decl) = x; } } @@ -8250,7 +8272,9 @@ lookup_protocol (tree ident, bool warn_if_deprecated, bool definition_required) for (chain = protocol_chain; chain; chain = TREE_CHAIN (chain)) if (ident == PROTOCOL_NAME (chain)) { - if (warn_if_deprecated && TREE_DEPRECATED (chain)) + if (TREE_UNAVAILABLE (chain)) + error ("protocol %qE is unavailable", PROTOCOL_NAME (chain)); + else if (warn_if_deprecated && TREE_DEPRECATED (chain)) { /* It would be nice to use warn_deprecated_use() here, but we are using TREE_CHAIN (which is supposed to be the @@ -8275,6 +8299,7 @@ void objc_declare_protocol (tree name, tree attributes) { bool deprecated = false; + bool unavailable = false; #ifdef OBJCPLUS if (current_namespace != global_namespace) { @@ -8293,6 +8318,8 @@ objc_declare_protocol (tree name, tree attributes) if (is_attribute_p ("deprecated", name)) deprecated = true; + else if (is_attribute_p ("unavailable", name)) + unavailable = true; else warning (OPT_Wattributes, "%qE attribute directive ignored", name); } @@ -8317,6 +8344,8 @@ objc_declare_protocol (tree name, tree attributes) TYPE_ATTRIBUTES (protocol) = attributes; if (deprecated) TREE_DEPRECATED (protocol) = 1; + if (unavailable) + TREE_UNAVAILABLE (protocol) = 1; } } } @@ -8326,6 +8355,7 @@ start_protocol (enum tree_code code, tree name, tree list, tree attributes) { tree protocol; bool deprecated = false; + bool unavailable = false; #ifdef OBJCPLUS if (current_namespace != global_namespace) { @@ -8344,6 +8374,8 @@ start_protocol (enum tree_code code, tree name, tree list, tree attributes) if (is_attribute_p ("deprecated", name)) deprecated = true; + else if (is_attribute_p ("unavailable", name)) + unavailable = true; else warning (OPT_Wattributes, "%qE attribute directive ignored", name); } @@ -8383,6 +8415,8 @@ start_protocol (enum tree_code code, tree name, tree list, tree attributes) TYPE_ATTRIBUTES (protocol) = attributes; if (deprecated) TREE_DEPRECATED (protocol) = 1; + if (unavailable) + TREE_UNAVAILABLE (protocol) = 1; } return protocol; @@ -8912,6 +8946,8 @@ really_start_method (tree method, warnings are produced), but just in case. */ if (TREE_DEPRECATED (proto)) TREE_DEPRECATED (method) = 1; + if (TREE_UNAVAILABLE (proto)) + TREE_UNAVAILABLE (method) = 1; /* If the method in the @interface was marked as 'noreturn', mark the function implementing the method @@ -9643,12 +9679,17 @@ objc_gimplify_property_ref (tree *expr_p) return; } + /* FIXME, this should be a label indicating availability in general. */ if (PROPERTY_REF_DEPRECATED_GETTER (*expr_p)) { - /* PROPERTY_REF_DEPRECATED_GETTER contains the method prototype + if (TREE_UNAVAILABLE (PROPERTY_REF_DEPRECATED_GETTER (*expr_p))) + error_unavailable_use (PROPERTY_REF_DEPRECATED_GETTER (*expr_p), + NULL_TREE); + else + /* PROPERTY_REF_DEPRECATED_GETTER contains the method prototype that is deprecated. */ - warn_deprecated_use (PROPERTY_REF_DEPRECATED_GETTER (*expr_p), - NULL_TREE); + warn_deprecated_use (PROPERTY_REF_DEPRECATED_GETTER (*expr_p), + NULL_TREE); } call_exp = getter; @@ -9663,7 +9704,9 @@ objc_gimplify_property_ref (tree *expr_p) call_exp = TREE_OPERAND (getter, 1); } #endif - gcc_assert (TREE_CODE (call_exp) == CALL_EXPR); + gcc_checking_assert ((flag_objc_nilcheck + && TREE_CODE (call_exp) == COND_EXPR) + || TREE_CODE (call_exp) == CALL_EXPR); *expr_p = call_exp; } diff --git gcc/objc/objc-next-metadata-tags.h gcc/objc/objc-next-metadata-tags.h index ceb8783..aea1455 100644 --- gcc/objc/objc-next-metadata-tags.h +++ gcc/objc/objc-next-metadata-tags.h @@ -79,6 +79,8 @@ enum objc_runtime_tree_index OCTI_RT_META_MAX }; +extern GTY(()) tree objc_rt_trees[OCTI_RT_META_MAX]; + /* Tags for the META data so that the backend can put them in the correct sections for targets/runtimes (Darwin/NeXT) that require this. This information also survives LTO - which might produce mixed language diff --git gcc/objc/objc-next-runtime-abi-01.c gcc/objc/objc-next-runtime-abi-01.c index 3ec6e17..3d85996 100644 --- gcc/objc/objc-next-runtime-abi-01.c +++ gcc/objc/objc-next-runtime-abi-01.c @@ -54,6 +54,7 @@ along with GCC; see the file COPYING3. If not see #include "objc-runtime-hooks.h" #include "objc-runtime-shared-support.h" +#include "objc-next-metadata-tags.h" #include "objc-encoding.h" /* NeXT ABI 0 and 1 private definitions. */ @@ -98,14 +99,6 @@ along with GCC; see the file COPYING3. If not see #define CLS_HAS_CXX_STRUCTORS 0x2000L -/* rt_trees identifiers - shared between NeXT implementations. These - allow the FE to tag meta-data in a manner that survives LTO and can - be used when the runtime requires that certain meta-data items - appear in particular named sections. */ - -#include "objc-next-metadata-tags.h" -extern GTY(()) tree objc_rt_trees[OCTI_RT_META_MAX]; - static void next_runtime_01_initialize (void); static tree next_runtime_abi_01_super_superclassfield_id (void); diff --git gcc/objc/objc-next-runtime-abi-02.c gcc/objc/objc-next-runtime-abi-02.c index af68c1c..8ea3d61 100644 --- gcc/objc/objc-next-runtime-abi-02.c +++ gcc/objc/objc-next-runtime-abi-02.c @@ -54,6 +54,7 @@ along with GCC; see the file COPYING3. If not see #include "objc-runtime-hooks.h" #include "objc-runtime-shared-support.h" +#include "objc-next-metadata-tags.h" #include "objc-encoding.h" /* ABI 2 Private definitions. */ @@ -179,14 +180,6 @@ enum objc_v2_tree_index #define objc_rethrow_exception_decl \ objc_v2_global_trees[OCTI_V2_RETHROW_DECL] -/* rt_trees identifiers - shared between NeXT implementations. These allow - the FE to tag meta-data in a manner that survives LTO and can be used when - the runtime requires that certain meta-data items appear in particular - named sections. */ - -#include "objc-next-metadata-tags.h" -extern GTY(()) tree objc_rt_trees[OCTI_RT_META_MAX]; - /* The OCTI_V2_... enumeration itself is in above. */ static GTY(()) tree objc_v2_global_trees[OCTI_V2_MAX]; @@ -245,7 +238,7 @@ objc_next_runtime_abi_02_init (objc_runtime_hooks *rthooks) { extern_names = ggc_cleared_vec_alloc (SIZEHASHTABLE); - if (flag_objc_exceptions && flag_objc_sjlj_exceptions) + if (flag_objc_sjlj_exceptions) { inform (UNKNOWN_LOCATION, "%<-fobjc-sjlj-exceptions%> is ignored for " @@ -254,6 +247,10 @@ objc_next_runtime_abi_02_init (objc_runtime_hooks *rthooks) flag_objc_sjlj_exceptions = 0; } + /* NeXT ABI 2 is intended to default to checking for nil receivers. */ + if (! global_options_set.x_flag_objc_nilcheck) + flag_objc_nilcheck = 1; + rthooks->initialize = next_runtime_02_initialize; rthooks->default_constant_string_class_name = DEF_CONSTANT_STRING_CLASS_NAME; rthooks->tag_getclass = TAG_GETCLASS; @@ -507,7 +504,7 @@ static void next_runtime_02_initialize (void) objc_getPropertyStruct_decl = NULL_TREE; objc_setPropertyStruct_decl = NULL_TREE; - gcc_assert (!flag_objc_sjlj_exceptions); + gcc_checking_assert (!flag_objc_sjlj_exceptions); /* Although we warn that fobjc-exceptions is required for exceptions code, we carry on and create it anyway. */ @@ -1035,6 +1032,7 @@ next_runtime_abi_02_protocol_decl (tree p) else decl = start_var_decl (objc_v2_protocol_template, buf); OBJCMETA (decl, objc_meta, meta_protocol); + DECL_PRESERVE_P (decl) = 1; return decl; } @@ -1675,13 +1673,8 @@ build_v2_objc_method_fixup_call (int super_flag, tree method_prototype, if (TREE_CODE (ret_type) == RECORD_TYPE || TREE_CODE (ret_type) == UNION_TYPE) - { - vec *rtt = NULL; - /* ??? CHECKME. hmmm..... think we need something more - here. */ - CONSTRUCTOR_APPEND_ELT (rtt, NULL_TREE, NULL_TREE); - ftree = objc_build_constructor (ret_type, rtt); - } + /* An empty constructor is zero-filled by the middle end. */ + ftree = objc_build_constructor (ret_type, NULL); else ftree = fold_convert (ret_type, integer_zero_node); @@ -1694,11 +1687,11 @@ build_v2_objc_method_fixup_call (int super_flag, tree method_prototype, ifexp, ret_val, ftree, tf_warning_or_error); #else - /* ??? CHECKME. */ ret_val = build_conditional_expr (input_location, - ifexp, 1, + ifexp, 0, ret_val, NULL_TREE, input_location, ftree, NULL_TREE, input_location); + ret_val = fold_convert (ret_type, ret_val); #endif } return ret_val; @@ -1740,15 +1733,16 @@ build_v2_build_objc_method_call (int super, tree method_prototype, /* Param list + 2 slots for object and selector. */ vec_alloc (parms, nparm + 2); - /* If we are returning a struct in memory, and the address - of that memory location is passed as a hidden first - argument, then change which messenger entry point this - expr will call. NB: Note that sender_cast remains - unchanged (it already has a struct return type). */ - if (!targetm.calls.struct_value_rtx (0, 0) - && (TREE_CODE (ret_type) == RECORD_TYPE - || TREE_CODE (ret_type) == UNION_TYPE) - && targetm.calls.return_in_memory (ret_type, 0)) + /* If we are returning an item that must be returned in memory, and the + target ABI does this by an invisible pointer provided as the first arg, + we need to adjust the message signature to include this. The second + part of this excludes targets that provide some alternate scheme for + structure returns. */ + if (ret_type && !VOID_TYPE_P (ret_type) + && targetm.calls.return_in_memory (ret_type, 0) + && !(targetm.calls.struct_value_rtx (0, 0) + && (TREE_CODE (ret_type) == RECORD_TYPE + || TREE_CODE (ret_type) == UNION_TYPE))) { if (super) sender = umsg_id_super2_stret_fixup_decl; @@ -1790,11 +1784,8 @@ build_v2_build_objc_method_call (int super, tree method_prototype, if (TREE_CODE (ret_type) == RECORD_TYPE || TREE_CODE (ret_type) == UNION_TYPE) { - vec *rtt = NULL; - /* ??? CHECKME. hmmm..... think we need something more - here. */ - CONSTRUCTOR_APPEND_ELT (rtt, NULL_TREE, NULL_TREE); - ftree = objc_build_constructor (ret_type, rtt); + /* An empty constructor is zero-filled by the middle end. */ + ftree = objc_build_constructor (ret_type, NULL); } else ftree = fold_convert (ret_type, integer_zero_node); @@ -1807,10 +1798,10 @@ build_v2_build_objc_method_call (int super, tree method_prototype, ret_val = build_conditional_expr (loc, ifexp, ret_val, ftree, tf_warning_or_error); #else - /* ??? CHECKME. */ ret_val = build_conditional_expr (loc, ifexp, 1, ret_val, NULL_TREE, loc, ftree, NULL_TREE, loc); + ret_val = fold_convert (ret_type, ret_val); #endif } return ret_val; @@ -1853,10 +1844,12 @@ next_runtime_abi_02_build_objc_method_call (location_t loc, ? TREE_VALUE (TREE_TYPE (method_prototype)) : objc_object_type; - if (!targetm.calls.struct_value_rtx (0, 0) - && (TREE_CODE (ret_type) == RECORD_TYPE - || TREE_CODE (ret_type) == UNION_TYPE) - && targetm.calls.return_in_memory (ret_type, 0)) + /* See comment for the fixup version above. */ + if (ret_type && !VOID_TYPE_P (ret_type) + && targetm.calls.return_in_memory (ret_type, 0) + && !(targetm.calls.struct_value_rtx (0, 0) + && (TREE_CODE (ret_type) == RECORD_TYPE + || TREE_CODE (ret_type) == UNION_TYPE))) { if (super) message_func_decl = umsg_id_super2_stret_fixup_decl; @@ -2121,8 +2114,8 @@ build_v2_classrefs_table (void) expr = convert (objc_class_type, build_fold_addr_expr (expr)); } /* The runtime wants this, even if it appears unused, so we must force the - output. - DECL_PRESERVE_P (decl) = 1; */ + output. */ + DECL_PRESERVE_P (decl) = 1; finish_var_decl (decl, expr); } } @@ -2324,6 +2317,7 @@ build_v2_protocol_list_address_table (void) expr = convert (objc_protocol_type, build_fold_addr_expr (ref->refdecl)); OBJCMETA (decl, objc_meta, meta_label_protocollist); finish_var_decl (decl, expr); + DECL_PRESERVE_P (decl) = 1; } /* TODO: delete the vec. */ diff --git gcc/objc/objc-runtime-shared-support.c gcc/objc/objc-runtime-shared-support.c index 40f506c..0d3036f 100644 --- gcc/objc/objc-runtime-shared-support.c +++ gcc/objc/objc-runtime-shared-support.c @@ -44,16 +44,11 @@ along with GCC; see the file COPYING3. If not see #include "objc-runtime-hooks.h" #include "objc-runtime-shared-support.h" -#include "objc-encoding.h" - -/* rt_trees identifiers - shared between NeXT implementations. These allow - the FE to tag meta-data in a manner that survives LTO and can be used when - the runtime requires that certain meta-data items appear in particular - named sections. */ #include "objc-next-metadata-tags.h" -extern GTY(()) tree objc_rt_trees[OCTI_RT_META_MAX]; +#include "objc-encoding.h" /* Rather than repeatedly looking up the identifiers, we save them here. */ +extern GTY(()) tree objc_rt_trees[OCTI_RT_META_MAX]; tree objc_rt_trees[OCTI_RT_META_MAX]; /* For building an objc struct. These might not be used when this file diff --git gcc/output.h gcc/output.h index 2bfeed9..7412407 100644 --- gcc/output.h +++ gcc/output.h @@ -458,7 +458,7 @@ struct GTY(()) named_section { /* A callback that writes the assembly code for switching to an unnamed section. The argument provides callback-specific data. */ -typedef void (*unnamed_section_callback) (const void *); +typedef void (*unnamed_section_callback) (const char *); /* Information about a SECTION_UNNAMED section. */ struct GTY(()) unnamed_section { @@ -466,8 +466,8 @@ struct GTY(()) unnamed_section { /* The callback used to switch to the section, and the data that should be passed to the callback. */ - unnamed_section_callback GTY ((skip)) callback; - const void *GTY ((skip)) data; + unnamed_section_callback GTY ((callback)) callback; + const char *data; /* The next entry in the chain of unnamed sections. */ section *next; @@ -491,7 +491,7 @@ struct GTY(()) noswitch_section { struct section_common common; /* The callback used to assemble decls in this section. */ - noswitch_section_callback GTY ((skip)) callback; + noswitch_section_callback GTY ((callback)) callback; }; /* Information about a section, which may be named or unnamed. */ @@ -526,8 +526,8 @@ extern GTY(()) section *bss_noswitch_section; extern GTY(()) section *in_section; extern GTY(()) bool in_cold_section_p; -extern section *get_unnamed_section (unsigned int, void (*) (const void *), - const void *); +extern section *get_unnamed_section (unsigned int, void (*) (const char *), + const char *); extern section *get_section (const char *, unsigned int, tree, bool not_existing = false); extern section *get_named_section (tree, const char *, int); @@ -549,7 +549,7 @@ extern section *get_cdtor_priority_section (int, bool); extern bool unlikely_text_section_p (section *); extern void switch_to_section (section *, tree = nullptr); -extern void output_section_asm_op (const void *); +extern void output_section_asm_op (const char *); extern void record_tm_clone_pair (tree, tree); extern void finish_tm_clone_pairs (void); diff --git gcc/poly-int.h gcc/poly-int.h index f47f9e4..be53307 100644 --- gcc/poly-int.h +++ gcc/poly-int.h @@ -2717,7 +2717,7 @@ gt_pch_nx (poly_int_pod *) template void -gt_pch_nx (poly_int_pod *, void (*) (void *, void *), void *) +gt_pch_nx (poly_int_pod *, void (*) (void *, void *, void *), void *) { } diff --git gcc/print-tree.c gcc/print-tree.c index 8ad0dcf..d1fbd04 100644 --- gcc/print-tree.c +++ gcc/print-tree.c @@ -364,6 +364,8 @@ print_node (FILE *file, const char *prefix, tree node, int indent, fputs (code == CALL_EXPR ? " must-tail-call" : " static", file); if (TREE_DEPRECATED (node)) fputs (" deprecated", file); + if (TREE_UNAVAILABLE (node)) + fputs (" unavailable", file); if (TREE_VISITED (node)) fputs (" visited", file); diff --git gcc/stringpool.c gcc/stringpool.c index e4d79b0..fa4548e 100644 --- gcc/stringpool.c +++ gcc/stringpool.c @@ -219,7 +219,7 @@ gt_pch_nx (unsigned char& x ATTRIBUTE_UNUSED) void gt_pch_nx (unsigned char *x, gt_pointer_operator op, void *cookie) { - op (x, cookie); + op (x, NULL, cookie); } /* Handle saving and restoring the string pool for PCH. */ diff --git gcc/target.def gcc/target.def index 258b414..9deddea 100644 --- gcc/target.def +++ gcc/target.def @@ -4944,6 +4944,18 @@ with the specified mode and type. The default hook returns\n\ default_function_arg_boundary) DEFHOOK +(function_arg_boundary_ca, + "This is the @code{cumulative_args_t}-based version of\n\ +@code{TARGET_FUNCTION_ARG_BOUNDARY}. Define this hook if you need more\n\ +fine-grained control over argument alignment, e.g. depending on whether\n\ +it is a named argument or not, or any other criteria that you choose to\n\ +place in the @var{ca} structure.\n\ +\n\ +The default hook will call @code{TARGET_FUNCTION_ARG_BOUNDARY}.", + unsigned int, (machine_mode mode, const_tree type, cumulative_args_t ca), + default_function_arg_boundary_ca) + +DEFHOOK (function_arg_round_boundary, "Normally, the size of an argument is rounded up to @code{PARM_BOUNDARY},\n\ which is the default value for this hook. You can define this hook to\n\ @@ -4952,6 +4964,18 @@ value.", unsigned int, (machine_mode mode, const_tree type), default_function_arg_round_boundary) +DEFHOOK +(function_arg_round_boundary_ca, + "This is the @code{cumulative_args_t}-based version of\n\ +@code{TARGET_FUNCTION_ARG_ROUND_BOUNDARY}. Define this hook if you need more\n\ +fine-grained control over argument size rounding, e.g. depending on whether\n\ +it is a named argument or not, or any other criteria that you choose to\n\ +place in the @var{ca} structure.\n\ +\n\ +The default hook will call @code{TARGET_FUNCTION_ARG_ROUND_BOUNDARY}.", + unsigned int, (machine_mode mode, const_tree type, cumulative_args_t ca), + default_function_arg_round_boundary_ca) + /* Return the diagnostic message string if function without a prototype is not allowed for this 'val' argument; NULL otherwise. */ DEFHOOK diff --git gcc/target.h gcc/target.h index d8f45fb..5b28ece 100644 --- gcc/target.h +++ gcc/target.h @@ -51,22 +51,7 @@ #include "insn-codes.h" #include "tm.h" #include "hard-reg-set.h" - -#if CHECKING_P - -struct cumulative_args_t { void *magic; void *p; }; - -#else /* !CHECKING_P */ - -/* When using a GCC build compiler, we could use - __attribute__((transparent_union)) to get cumulative_args_t function - arguments passed like scalars where the ABI would mandate a less - efficient way of argument passing otherwise. However, that would come - at the cost of less type-safe !CHECKING_P compilation. */ - -union cumulative_args_t { void *p; }; - -#endif /* !CHECKING_P */ +#include "cumulative-args.h" /* Types of memory operation understood by the "by_pieces" infrastructure. Used by the TARGET_USE_BY_PIECES_INFRASTRUCTURE_P target hook and diff --git gcc/targhooks.c gcc/targhooks.c index 952fad4..a6a0fc3 100644 --- gcc/targhooks.c +++ gcc/targhooks.c @@ -828,12 +828,28 @@ default_function_arg_boundary (machine_mode mode ATTRIBUTE_UNUSED, } unsigned int +default_function_arg_boundary_ca (machine_mode mode ATTRIBUTE_UNUSED, + const_tree type ATTRIBUTE_UNUSED, + cumulative_args_t ca ATTRIBUTE_UNUSED) +{ + return default_function_arg_boundary (mode, type); +} + +unsigned int default_function_arg_round_boundary (machine_mode mode ATTRIBUTE_UNUSED, const_tree type ATTRIBUTE_UNUSED) { return PARM_BOUNDARY; } +unsigned int +default_function_arg_round_boundary_ca (machine_mode mode ATTRIBUTE_UNUSED, + const_tree type ATTRIBUTE_UNUSED, + cumulative_args_t ca ATTRIBUTE_UNUSED) +{ + return default_function_arg_round_boundary (mode, type); +} + void hook_void_bitmap (bitmap regs ATTRIBUTE_UNUSED) { diff --git gcc/targhooks.h gcc/targhooks.h index 9928d06..4efee44 100644 --- gcc/targhooks.h +++ gcc/targhooks.h @@ -158,6 +158,12 @@ extern unsigned int default_function_arg_boundary (machine_mode, const_tree); extern unsigned int default_function_arg_round_boundary (machine_mode, const_tree); +extern unsigned int default_function_arg_boundary_ca (machine_mode, + const_tree, + cumulative_args_t ca); +extern unsigned int default_function_arg_round_boundary_ca (machine_mode, + const_tree, + cumulative_args_t ca); extern bool hook_bool_const_rtx_commutative_p (const_rtx, int); extern rtx default_function_value (const_tree, const_tree, bool); extern HARD_REG_SET default_zero_call_used_regs (HARD_REG_SET); diff --git gcc/testsuite/g++.dg/abi/aarch64_guard1.C gcc/testsuite/g++.dg/abi/aarch64_guard1.C index e2669a8..52be32d 100644 --- gcc/testsuite/g++.dg/abi/aarch64_guard1.C +++ gcc/testsuite/g++.dg/abi/aarch64_guard1.C @@ -12,5 +12,6 @@ int *foo () return &x; } -// { dg-final { scan-assembler _ZGVZ3foovE1x,8,8 } } +// { dg-final { scan-assembler _ZGVZ3foovE1x,8,8 { target { ! *-*-darwin* } } } } +// { dg-final { scan-assembler __DATA,__bss,__ZGVZ3foovE1x,8,3 { target *-*-darwin* } } } // { dg-final { scan-tree-dump "& 1" "original" } } diff --git gcc/testsuite/g++.dg/abi/arm_va_list.C gcc/testsuite/g++.dg/abi/arm_va_list.C index 4f6f3a4..ff9fd8b 100644 --- gcc/testsuite/g++.dg/abi/arm_va_list.C +++ gcc/testsuite/g++.dg/abi/arm_va_list.C @@ -8,8 +8,10 @@ // #include typedef __builtin_va_list va_list; -// { dg-final { scan-assembler "\n_Z1fPSt9__va_list:" } } +// { dg-final { scan-assembler "\n_Z1fPSt9__va_list:" { target { ! *-*-darwin* } } } } +// { dg-final { scan-assembler "\n__Z1fPPc:" { target *-*-darwin* } } } void f(va_list*) {} -// { dg-final { scan-assembler "\n_Z1gSt9__va_listS_:" } } +// { dg-final { scan-assembler "\n_Z1gSt9__va_listS_:" { target { ! *-*-darwin* } } } } +// { dg-final { scan-assembler "\n__Z1gPcS_:" { target *-*-darwin* } } } void g(va_list, va_list) {} diff --git gcc/testsuite/g++.dg/cpp0x/pr106435-b.cc gcc/testsuite/g++.dg/cpp0x/pr106435-b.cc new file mode 100644 index 0000000..4f58169 --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/pr106435-b.cc @@ -0,0 +1,17 @@ +// PR c++/106435 +#include "pr106435.h" + +//#include + +Foo::Foo() { + ++num_calls; +// std::cout << "Foo::Foo(this=" << this << ")\n"; +} + +int Foo::func() { +// std::cout << "Foo::func(this=" << this << ")\n"; + return num_calls; +} + +thread_local Foo Bar::foo; +thread_local Foo Bar::baz; diff --git gcc/testsuite/g++.dg/cpp0x/pr106435.C gcc/testsuite/g++.dg/cpp0x/pr106435.C new file mode 100644 index 0000000..d600976 --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/pr106435.C @@ -0,0 +1,20 @@ +// PR c++/106435 +// { dg-do run { target c++11 } } +// { dg-additional-sources "pr106435-b.cc" } + +#include "pr106435.h" + +int num_calls = 0; + +extern "C" __attribute__((__noreturn__)) void abort(); + +thread_local Foo Bar::bat; + +int main() { + int v = Bar::foo.func(); + if (v != 2) + abort(); + v = Bar::bat.func(); + if (v != 3) + abort(); +} diff --git gcc/testsuite/g++.dg/cpp0x/pr106435.h gcc/testsuite/g++.dg/cpp0x/pr106435.h new file mode 100644 index 0000000..240de1e --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/pr106435.h @@ -0,0 +1,14 @@ +// PR c++/106435 +#pragma once + +extern int num_calls; +struct Foo { + Foo(); + int func(); +}; + +struct Bar { + thread_local static Foo foo; + thread_local static Foo baz; + thread_local static Foo bat; +}; diff --git gcc/testsuite/g++.dg/ext/arm-bf16/bf16-mangle-aarch64-1.C gcc/testsuite/g++.dg/ext/arm-bf16/bf16-mangle-aarch64-1.C index 5426a18..a017ce8 100644 --- gcc/testsuite/g++.dg/ext/arm-bf16/bf16-mangle-aarch64-1.C +++ gcc/testsuite/g++.dg/ext/arm-bf16/bf16-mangle-aarch64-1.C @@ -2,12 +2,12 @@ /* Test mangling */ -/* { dg-final { scan-assembler "\t.global\t_Z1fPu6__bf16" } } */ +/* { dg-final { scan-assembler {\t.globa?l[ \t]_?_Z1fPu6__bf16} } } */ void f (__bf16 *x) { } -/* { dg-final { scan-assembler "\t.global\t_Z1gPu6__bf16S_" } } */ +/* { dg-final { scan-assembler {\t.globa?l[ \t]_?_Z1gPu6__bf16S_} } } */ void g (__bf16 *x, __bf16 *y) { } -/* { dg-final { scan-assembler "\t.global\t_ZN1SIu6__bf16u6__bf16E1iE" } } */ +/* { dg-final { scan-assembler {\t.globa?l[ \t]_?_ZN1SIu6__bf16u6__bf16E1iE} } } */ template struct S { static int i; }; template <> int S<__bf16, __bf16>::i = 3; diff --git gcc/testsuite/g++.dg/ext/attr-unavailable-1.C gcc/testsuite/g++.dg/ext/attr-unavailable-1.C new file mode 100644 index 0000000..862651f --- /dev/null +++ gcc/testsuite/g++.dg/ext/attr-unavailable-1.C @@ -0,0 +1,113 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +typedef int INT1 __attribute__((unavailable)); +typedef INT1 INT2 __attribute__ ((__unavailable__)); + +typedef INT1 INT1a; /* { dg-error "'INT1' is unavailable" "" } */ +typedef INT1 INT1b __attribute__ ((unavailable)); + +INT1 should_be_unavailable; /* { dg-error "'INT1' is unavailable" "" } */ +INT1a should_not_be_unavailable; + +INT1 f1(void) __attribute__ ((unavailable)); +INT1 f2(void) { return 0; } /* { dg-error "'INT1' is unavailable" "" } */ + +INT2 f3(void) __attribute__ ((__unavailable__)); +INT2 f4(void) { return 0; } /* { dg-error "'INT2' is unavailable" "" } */ +int f5(INT2 x); /* { dg-error "'INT2' is unavailable" "" } */ +int f6(INT2 x) __attribute__ ((__unavailable__)); + +typedef enum Color {red, green, blue} Color __attribute__((unavailable)); + +int g1; +int g2 __attribute__ ((unavailable)); +int g3 __attribute__ ((__unavailable__)); +Color k; /* { dg-error "'Color' is unavailable" "" } */ + +typedef struct { + int field1; + int field2 __attribute__ ((unavailable)); + int field3; + int field4 __attribute__ ((__unavailable__)); + union { + int field5; + int field6 __attribute__ ((unavailable)); + } u1; + int field7:1; + int field8:1 __attribute__ ((unavailable)); + union { + int field9; + int field10; + } u2 __attribute__ ((unavailable)); +} S1; + +int func1() +{ + INT1 w; /* { dg-error "'INT1' is unavailable" "" } */ + int x __attribute__ ((unavailable)); + int y __attribute__ ((__unavailable__)); + int z; + int (*pf)() = f1; /* { dg-error "'INT1 f1\\(\\)' is unavailable" "" } */ + + z = w + x + y + g1 + g2 + g3; /* { dg-error "'x' is unavailable" "" } */ + /* { dg-error "'y' is unavailable" "y" { target *-*-* } .-1 } */ + /* { dg-error "'g2' is unavailable" "g2" { target *-*-* } .-2 } */ + /* { dg-error "'g3' is unavailable" "g3" { target *-*-* } .-3 } */ + return f1(); /* { dg-error "'INT1 f1\\(\\)' is unavailable" "f1" } */ +} + +int func2(S1 *p) +{ + S1 lp; + + if (p->field1) + return p->field2; /* { dg-error "'S1::field2' is unavailable" "" } */ + else if (lp.field4) /* { dg-error "'S1::field4' is unavailable" "" } */ + return p->field3; + + p->u1.field5 = g1 + p->field7; + p->u2.field9; /* { dg-error "'S1::u2' is unavailable" "" } */ + return p->u1.field6 + p->field8; /* { dg-error "'S1::::field6' is unavailable" "" } */ + /* { dg-error "'S1::field8' is unavailable" "field8" { target *-*-* } .-1 } */ +} + +struct SS1 { + int x; + INT1 y; /* { dg-error "'INT1' is unavailable" "" } */ +} __attribute__ ((unavailable)); + +struct SS1 *p1; /* { dg-error "'SS1' is unavailable" "" } */ + +struct __attribute__ ((__unavailable__)) SS2 { + int x; + INT1 y; /* { dg-error "'INT1' is unavailable" "" } */ +}; + +struct SS2 *p2; /* { dg-error "'SS2' is unavailable" "" } */ + +#ifdef __cplusplus +class T { + public: + void member1(int) __attribute__ ((unavailable)); + void member2(INT1) __attribute__ ((__unavailable__)); + int member3(T *); + int x; +} __attribute__ ((unavailable)); + +T *p3; // { dg-error "'T' is unavailable" } + +inline void T::member1(int) {} + +int T::member3(T *p) // { dg-error "'T' is unavailable" } +{ + p->member1(1); /* { dg-error "'void T::member1\\(int\\)' is unavailable" "" } */ + (*p).member1(2); /* { dg-error "'void T::member1\\(int\\)' is unavailable" "" } */ + p->member2(1); /* { dg-error "'void T::member2\\(INT1\\)' is unavailable" "" } */ + (*p).member2(2); /* { dg-error "'void T::member2\\(INT1\\)' is unavailable" "" } */ + p->member3(p); + (*p).member3(p); + return f1(); /* { dg-error "'INT1 f1\\(\\)' is unavailable" "" } */ +} +#endif diff --git gcc/testsuite/g++.dg/ext/attr-unavailable-2.C gcc/testsuite/g++.dg/ext/attr-unavailable-2.C new file mode 100644 index 0000000..3de5532 --- /dev/null +++ gcc/testsuite/g++.dg/ext/attr-unavailable-2.C @@ -0,0 +1,10 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +void func(void); +void func(void) __attribute__((unavailable)); + +void f(void) { + func(); /* { dg-error "'void func\\(\\)' is unavailable" } */ +} diff --git gcc/testsuite/g++.dg/ext/attr-unavailable-3.C gcc/testsuite/g++.dg/ext/attr-unavailable-3.C new file mode 100644 index 0000000..1f267ea --- /dev/null +++ gcc/testsuite/g++.dg/ext/attr-unavailable-3.C @@ -0,0 +1,14 @@ +/* Check operator with __attribute__((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +struct Foo +{ + operator int() __attribute__((unavailable)); +}; + +void g(void) +{ + Foo f; + (int)f; // { dg-error "'Foo::operator int\\(\\)' is unavailable" } +} diff --git gcc/testsuite/g++.dg/ext/attr-unavailable-4.C gcc/testsuite/g++.dg/ext/attr-unavailable-4.C new file mode 100644 index 0000000..b7f352e --- /dev/null +++ gcc/testsuite/g++.dg/ext/attr-unavailable-4.C @@ -0,0 +1,11 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +struct B { + virtual int foo() __attribute__((unavailable)); +}; + +int main(void) { + ((B*)0)->foo(); // { dg-error "unavailable" } +} diff --git gcc/testsuite/g++.dg/ext/attr-unavailable-5.C gcc/testsuite/g++.dg/ext/attr-unavailable-5.C new file mode 100644 index 0000000..3beea5d --- /dev/null +++ gcc/testsuite/g++.dg/ext/attr-unavailable-5.C @@ -0,0 +1,6 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +struct Foo { int i; } __attribute__ ((unavailable)); +void foo() { Foo f; } // { dg-error "unavailable" } diff --git gcc/testsuite/g++.dg/ext/attr-unavailable-6.C gcc/testsuite/g++.dg/ext/attr-unavailable-6.C new file mode 100644 index 0000000..8a57ea0 --- /dev/null +++ gcc/testsuite/g++.dg/ext/attr-unavailable-6.C @@ -0,0 +1,110 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +typedef int INT1 __attribute__((unavailable("You can't use INT1"))); +typedef INT1 INT2 __attribute__ ((__unavailable__("You can't use INT2"))); + +typedef INT1 INT1a; /* { dg-error "'INT1' is unavailable: You can't use INT1" "" } */ + +INT1 should_be_unavailable; /* { dg-error "'INT1' is unavailable: You can't use INT1" "" } */ +INT1a should_not_be_unavailable; + +INT1 f1(void) __attribute__ ((unavailable("You can't use f1"))); +INT1 f2(void) { return 0; } /* { dg-error "'INT1' is unavailable: You can't use INT1" "" } */ + +INT2 f3(void) __attribute__ ((__unavailable__("You can't use f3"))); +INT2 f4(void) { return 0; } /* { dg-error "'INT2' is unavailable: You can't use INT2" "" } */ +int f5(INT2 x); /* { dg-error "'INT2' is unavailable" "" } */ +int f6(INT2 x) __attribute__ ((__unavailable__("You can't use f6"))); + +typedef enum Color {red, green, blue} Color __attribute__((unavailable("You can't use Color"))); + +int g1; +int g2 __attribute__ ((unavailable("You can't use g2"))); +int g3 __attribute__ ((__unavailable__("You can't use g3"))); +Color k; /* { dg-error "'Color' is unavailable: You can't use Color" "" } */ + +typedef struct { + int field1; + int field2 __attribute__ ((unavailable("You can't use field2"))); + int field3; + int field4 __attribute__ ((__unavailable__("You can't use field4"))); + union { + int field5; + int field6 __attribute__ ((unavailable("You can't use field6"))); + } u1; + int field7:1; + int field8:1 __attribute__ ((unavailable("You can't use field8"))); + union { + int field9; + int field10; + } u2 __attribute__ ((unavailable("You can't use u2"))); +} S1; + +int func1() +{ + INT1 w; /* { dg-error "'INT1' is unavailable: You can't use INT1" "" } */ + int x __attribute__ ((unavailable("You can't use x"))); + int y __attribute__ ((__unavailable__("You can't use y"))); + int z; + int (*pf)() = f1; /* { dg-error "'INT1 f1\\(\\)' is unavailable: You can't use f1" "" } */ + + z = w + x + y + g1 + g2 + g3; /* { dg-error "'x' is unavailable: You can't use x" "" } */ + /* { dg-error "'y' is unavailable: You can't use y" "y" { target *-*-* } .-1 } */ + /* { dg-error "'g2' is unavailable: You can't use g2" "g2" { target *-*-* } .-2 } */ + /* { dg-error "'g3' is unavailable: You can't use g3" "g3" { target *-*-* } .-3 } */ + return f1(); /* { dg-error "'INT1 f1\\(\\)' is unavailable: You can't use f1" "f1" } */ +} + +int func2(S1 *p) +{ + S1 lp; + + if (p->field1) + return p->field2; /* { dg-error "'S1::field2' is unavailable: You can't use field2" "" } */ + else if (lp.field4) /* { dg-error "'S1::field4' is unavailable: You can't use field4" "" } */ + return p->field3; + + p->u1.field5 = g1 + p->field7; + p->u2.field9; /* { dg-error "'S1::u2' is unavailable: You can't use u2" "" } */ + return p->u1.field6 + p->field8; /* { dg-error "'S1::::field6' is unavailable: You can't use field6" "" } */ + /* { dg-error "'S1::field8' is unavailable: You can't use field8" "field8" { target *-*-* } .-1 } */ +} + +struct SS1 { + int x; + INT1 y; /* { dg-error "'INT1' is unavailable: You can't use INT1" "" } */ +} __attribute__ ((unavailable("You can't use SS1"))); + +struct SS1 *p1; /* { dg-error "'SS1' is unavailable: You can't use SS1" "" } */ + +struct __attribute__ ((__unavailable__("You can't use SS2"))) SS2 { + int x; + INT1 y; /* { dg-error "'INT1' is unavailable: You can't use INT1" "" } */ +}; + +struct SS2 *p2; /* { dg-error "'SS2' is unavailable: You can't use SS2" "" } */ + +class T { + public: + void member1(int) __attribute__ ((unavailable("You can't use member1"))); + void member2(INT1) __attribute__ ((__unavailable__("You can't use member2"))); + int member3(T *); + int x; +} __attribute__ ((unavailable("You can't use T"))); + +T *p3; // { dg-error "'T' is unavailable: You can't use T" } + +inline void T::member1(int) {} + +int T::member3(T *p) // { dg-error "'T' is unavailable: You can't use T" } +{ + p->member1(1); /* { dg-error "'void T::member1\\(int\\)' is unavailable: You can't use member1" "" } */ + (*p).member1(2); /* { dg-error "'void T::member1\\(int\\)' is unavailable: You can't use member1" "" } */ + p->member2(1); /* { dg-error "'void T::member2\\(INT1\\)' is unavailable: You can't use member2" "" } */ + (*p).member2(2); /* { dg-error "'void T::member2\\(INT1\\)' is unavailable: You can't use member2" "" } */ + p->member3(p); + (*p).member3(p); + return f1(); /* { dg-error "'INT1 f1\\(\\)' is unavailable: You can't use f1" "" } */ +} diff --git gcc/testsuite/g++.dg/ext/attr-unavailable-7.C gcc/testsuite/g++.dg/ext/attr-unavailable-7.C new file mode 100644 index 0000000..c061aa3 --- /dev/null +++ gcc/testsuite/g++.dg/ext/attr-unavailable-7.C @@ -0,0 +1,19 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +int g_nn; +int& g_n __attribute__((unavailable)) = g_nn; + +void f() +{ + int f_nn; + int& f_n __attribute__((unavailable)) = f_nn; + f_n = 1; // { dg-error "'f_n' is unavailable" } +} + +int main() +{ + g_n = 1; // { dg-error "'g_n' is unavailable" } + f(); +} diff --git gcc/testsuite/g++.dg/ext/attr-unavailable-8.C gcc/testsuite/g++.dg/ext/attr-unavailable-8.C new file mode 100644 index 0000000..334a2cf --- /dev/null +++ gcc/testsuite/g++.dg/ext/attr-unavailable-8.C @@ -0,0 +1,17 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +class ToBeunavailable { +} __attribute__ ((unavailable ("unavailable!"))); + +typedef ToBeunavailable NotToBeunavailable; // { dg-error "'ToBeunavailable' is unavailable" } + +int main() { + + ToBeunavailable(); // { dg-error "'ToBeunavailable' is unavailable" } + ToBeunavailable x; // { dg-error "'ToBeunavailable' is unavailable" } + + NotToBeunavailable(); + NotToBeunavailable y; +} diff --git gcc/testsuite/g++.dg/ext/attr-unavailable-9.C gcc/testsuite/g++.dg/ext/attr-unavailable-9.C new file mode 100644 index 0000000..4416133 --- /dev/null +++ gcc/testsuite/g++.dg/ext/attr-unavailable-9.C @@ -0,0 +1,17 @@ +/* Test __attribute__ ((unavailable)) */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +template struct __attribute__ ((unavailable)) S {}; +S s; + +template