diff options
author | Balaji V. Iyer <balaji.v.iyer@intel.com> | 2013-10-29 18:37:47 +0000 |
---|---|---|
committer | Balaji V. Iyer <bviyer@gcc.gnu.org> | 2013-10-29 11:37:47 -0700 |
commit | 3038054c687e9400976012eea70333db70ad6a7b (patch) | |
tree | 235d812c6202e962d45c0cce844b2afcc5a0596d | |
parent | 939b37da6ded55070bd78fc28d3fd2222b4278fa (diff) | |
download | gcc-3038054c687e9400976012eea70333db70ad6a7b.tar.gz |
Added Cilk runtime library (libcilkrts) into GCC.
From-SVN: r204173
112 files changed, 58908 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog index 2b27bce6726..f5563b2d3aa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2013-10-29 Balaji V. Iyer <balaji.v.iyer@intel.com> + + * Makefile.def: Add libcilkrts to target_modules. Make libcilkrts + depend on libstdc++ and libgcc. + * configure: Regenerate. + * configure.ac: Added libcilkrts to target binaries. Also, restrict + libcilkrts for POSIX and i*86, and x86_64 architectures. + * Makefile.in: Added libcilkrts related fields to support building it. + 2013-10-26 Jeff Law <law@redhat.com> * Makefile.def (target_modules): Remove libmudflap diff --git a/Makefile.def b/Makefile.def index df4b2242e96..32296d1160f 100644 --- a/Makefile.def +++ b/Makefile.def @@ -125,6 +125,8 @@ target_modules = { module= libvtv; bootstrap=true; lib_path=.libs; raw_cxx=true; }; +target_modules = { module= libcilkrts; + lib_path=.libs; }; target_modules = { module= libssp; lib_path=.libs; }; target_modules = { module= newlib; }; target_modules = { module= libgcc; bootstrap=true; no_check=true; }; @@ -491,6 +493,7 @@ dependencies = { module=all-m4; on=all-build-texinfo; }; // on libgcc and newlib/libgloss. lang_env_dependencies = { module=libjava; cxx=true; }; lang_env_dependencies = { module=libitm; cxx=true; }; +lang_env_dependencies = { module=libcilkrts; cxx=true; }; lang_env_dependencies = { module=newlib; no_c=true; }; lang_env_dependencies = { module=libgloss; no_c=true; }; lang_env_dependencies = { module=libgcc; no_gcc=true; no_c=true; }; @@ -531,6 +534,8 @@ dependencies = { module=install-target-libsanitizer; on=install-target-libstdc++ dependencies = { module=install-target-libsanitizer; on=install-target-libgcc; }; dependencies = { module=install-target-libvtv; on=install-target-libstdc++-v3; }; dependencies = { module=install-target-libvtv; on=install-target-libgcc; }; +dependencies = { module=install-target-libcilkrts; on=install-target-libstdc++-v3; }; +dependencies = { module=install-target-libcilkrts; on=install-target-libgcc; }; dependencies = { module=install-target-libjava; on=install-target-libgcc; }; dependencies = { module=install-target-libitm; on=install-target-libgcc; }; dependencies = { module=install-target-libobjc; on=install-target-libgcc; }; diff --git a/Makefile.in b/Makefile.in index ff434fed315..572b3d0941e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -575,7 +575,7 @@ all: # This is the list of directories that may be needed in RPATH_ENVVAR # so that programs built for the target machine work. -TARGET_LIB_PATH = $(TARGET_LIB_PATH_libstdc++-v3)$(TARGET_LIB_PATH_libsanitizer)$(TARGET_LIB_PATH_libvtv)$(TARGET_LIB_PATH_libssp)$(TARGET_LIB_PATH_libgomp)$(TARGET_LIB_PATH_libitm)$(TARGET_LIB_PATH_libatomic)$(HOST_LIB_PATH_gcc) +TARGET_LIB_PATH = $(TARGET_LIB_PATH_libstdc++-v3)$(TARGET_LIB_PATH_libsanitizer)$(TARGET_LIB_PATH_libvtv)$(TARGET_LIB_PATH_libssp)$(TARGET_LIB_PATH_libgomp)$(TARGET_LIB_PATH_libitm)$(TARGET_LIB_PATH_libatomic)$(HOST_LIB_PATH_gcc)$(HOST_LIB_PATH_libcilkrts) @if target-libstdc++-v3 TARGET_LIB_PATH_libstdc++-v3 = $$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs: @@ -597,6 +597,10 @@ TARGET_LIB_PATH_libssp = $$r/$(TARGET_SUBDIR)/libssp/.libs: TARGET_LIB_PATH_libgomp = $$r/$(TARGET_SUBDIR)/libgomp/.libs: @endif target-libgomp +@if target-libcilkrts +TARGET_LIB_PATH_libcilkrts = $$r/$(TARGET_SUBDIR)/libcilkrts/.libs: +@endif target-libcilkrts + @if target-libitm TARGET_LIB_PATH_libitm = $$r/$(TARGET_SUBDIR)/libitm/.libs: @endif target-libitm @@ -942,6 +946,7 @@ configure-target: \ maybe-configure-target-boehm-gc \ maybe-configure-target-rda \ maybe-configure-target-libada \ + maybe-configure-target-libcilkrts \ maybe-configure-target-libgomp \ maybe-configure-target-libitm \ maybe-configure-target-libatomic @@ -1100,6 +1105,7 @@ all-target: maybe-all-target-libada @if target-libgomp-no-bootstrap all-target: maybe-all-target-libgomp @endif target-libgomp-no-bootstrap +all-target: maybe-all-target-libcilkrts all-target: maybe-all-target-libitm all-target: maybe-all-target-libatomic @@ -1925,6 +1931,7 @@ mostlyclean-target: maybe-mostlyclean-target-boehm-gc mostlyclean-target: maybe-mostlyclean-target-rda mostlyclean-target: maybe-mostlyclean-target-libada mostlyclean-target: maybe-mostlyclean-target-libgomp +mostlyclean-target: maybe-mostlyclean-target-libcilkrts mostlyclean-target: maybe-mostlyclean-target-libitm mostlyclean-target: maybe-mostlyclean-target-libatomic @@ -2007,6 +2014,7 @@ clean-target: maybe-clean-target-boehm-gc clean-target: maybe-clean-target-rda clean-target: maybe-clean-target-libada clean-target: maybe-clean-target-libgomp +clean-target: maybe-clean-target-libcilkrts clean-target: maybe-clean-target-libitm clean-target: maybe-clean-target-libatomic @@ -2089,6 +2097,7 @@ distclean-target: maybe-distclean-target-boehm-gc distclean-target: maybe-distclean-target-rda distclean-target: maybe-distclean-target-libada distclean-target: maybe-distclean-target-libgomp +distclean-target: maybe-distclean-target-libcilkrts distclean-target: maybe-distclean-target-libitm distclean-target: maybe-distclean-target-libatomic @@ -2171,6 +2180,7 @@ maintainer-clean-target: maybe-maintainer-clean-target-boehm-gc maintainer-clean-target: maybe-maintainer-clean-target-rda maintainer-clean-target: maybe-maintainer-clean-target-libada maintainer-clean-target: maybe-maintainer-clean-target-libgomp +maintainer-clean-target: maybe-maintainer-clean-target-libcilkrts maintainer-clean-target: maybe-maintainer-clean-target-libitm maintainer-clean-target: maybe-maintainer-clean-target-libatomic @@ -2463,6 +2473,7 @@ install-target: \ maybe-install-target-rda \ maybe-install-target-libada \ maybe-install-target-libgomp \ + maybe-install-target-libcilkrts \ maybe-install-target-libitm \ maybe-install-target-libatomic @@ -2564,6 +2575,7 @@ install-strip-target: \ maybe-install-strip-target-boehm-gc \ maybe-install-strip-target-rda \ maybe-install-strip-target-libada \ + maybe-install-strip-target-libcilkrts \ maybe-install-strip-target-libgomp \ maybe-install-strip-target-libitm \ maybe-install-strip-target-libatomic @@ -41869,6 +41881,983 @@ maintainer-clean-target-libada: @endif target-libada +.PHONY: configure-target-libcilkrts maybe-configure-target-libcilkrts +maybe-configure-target-libcilkrts: +@if gcc-bootstrap +configure-target-libcilkrts: stage_current +@endif gcc-bootstrap +@if target-libcilkrts +maybe-configure-target-libcilkrts: configure-target-libcilkrts +configure-target-libcilkrts: + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + echo "Checking multilib configuration for libcilkrts...(1)"; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libcilkrts ; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libcilkrts/multilib.tmp 2> /dev/null ; \ + if test -r $(TARGET_SUBDIR)/libcilkrts/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libcilkrts/multilib.tmp $(TARGET_SUBDIR)/libcilkrts/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libcilkrts/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libcilkrts/Makefile; \ + mv $(TARGET_SUBDIR)/libcilkrts/multilib.tmp $(TARGET_SUBDIR)/libcilkrts/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libcilkrts/multilib.tmp $(TARGET_SUBDIR)/libcilkrts/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libcilkrts/Makefile || exit 0; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libcilkrts ; \ + $(NORMAL_TARGET_EXPORTS) \ + echo Configuring in $(TARGET_SUBDIR)/libcilkrts; \ + cd "$(TARGET_SUBDIR)/libcilkrts" || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libcilkrts/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + srcdiroption="--srcdir=$${topdir}/libcilkrts"; \ + libsrcdir="$$s/libcilkrts"; \ + rm -f no-such-file || : ; \ + CONFIG_SITE=no-such-file $(SHELL) $${libsrcdir}/configure \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} $${srcdiroption} \ + || exit 1 +@endif target-libcilkrts + + +.PHONY: configure-stage1-target-libcilkrts maybe-configure-stage1-target-libcilkrts +maybe-configure-stage1-target-libcilkrts: +@if target-libcilkrts-bootstrap +maybe-configure-stage1-target-libcilkrts: configure-stage1-target-libcilkrts +configure-stage1-target-libcilkrts: + @[ $(current_stage) = stage1 ] || $(MAKE) stage1-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libcilkrts + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE1_TFLAGS)"; \ + echo "Checking multilib configuration for libcilkrts...(2)"; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libcilkrts/multilib.tmp 2> /dev/null ; \ + if test -r $(TARGET_SUBDIR)/libcilkrts/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libcilkrts/multilib.tmp $(TARGET_SUBDIR)/libcilkrts/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libcilkrts/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libcilkrts/Makefile; \ + mv $(TARGET_SUBDIR)/libcilkrts/multilib.tmp $(TARGET_SUBDIR)/libcilkrts/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libcilkrts/multilib.tmp $(TARGET_SUBDIR)/libcilkrts/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libcilkrts/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage 1 in $(TARGET_SUBDIR)/libcilkrts ; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libcilkrts ; \ + cd $(TARGET_SUBDIR)/libcilkrts || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libcilkrts/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + srcdiroption="--srcdir=$${topdir}/libcilkrts"; \ + libsrcdir="$$s/libcilkrts"; \ + $(SHELL) $${libsrcdir}/configure \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} $${srcdiroption} \ + $(STAGE1_CONFIGURE_FLAGS) +@endif target-libcilkrts-bootstrap + +.PHONY: configure-stage2-target-libcilkrts maybe-configure-stage2-target-libcilkrts +maybe-configure-stage2-target-libcilkrts: +@if target-libcilkrts-bootstrap +maybe-configure-stage2-target-libcilkrts: configure-stage2-target-libcilkrts +configure-stage2-target-libcilkrts: + @[ $(current_stage) = stage2 ] || $(MAKE) stage2-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libcilkrts + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE2_TFLAGS)"; \ + echo "Checking multilib configuration for libcilkrts...(3)"; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libcilkrts/multilib.tmp 2> /dev/null ; \ + if test -r $(TARGET_SUBDIR)/libcilkrts/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libcilkrts/multilib.tmp $(TARGET_SUBDIR)/libcilkrts/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libcilkrts/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libcilkrts/Makefile; \ + mv $(TARGET_SUBDIR)/libcilkrts/multilib.tmp $(TARGET_SUBDIR)/libcilkrts/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libcilkrts/multilib.tmp $(TARGET_SUBDIR)/libcilkrts/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libcilkrts/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage 2 in $(TARGET_SUBDIR)/libcilkrts ; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libcilkrts ; \ + cd $(TARGET_SUBDIR)/libcilkrts || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libcilkrts/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + srcdiroption="--srcdir=$${topdir}/libcilkrts"; \ + libsrcdir="$$s/libcilkrts"; \ + $(SHELL) $${libsrcdir}/configure \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} $${srcdiroption} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGE2_CONFIGURE_FLAGS) +@endif target-libcilkrts-bootstrap + +.PHONY: configure-stage3-target-libcilkrts maybe-configure-stage3-target-libcilkrts +maybe-configure-stage3-target-libcilkrts: +@if target-libcilkrts-bootstrap +maybe-configure-stage3-target-libcilkrts: configure-stage3-target-libcilkrts +configure-stage3-target-libcilkrts: + @[ $(current_stage) = stage3 ] || $(MAKE) stage3-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libcilkrts + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE3_TFLAGS)"; \ + echo "Checking multilib configuration for libcilkrts...(4)"; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libcilkrts/multilib.tmp 2> /dev/null ; \ + if test -r $(TARGET_SUBDIR)/libcilkrts/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libcilkrts/multilib.tmp $(TARGET_SUBDIR)/libcilkrts/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libcilkrts/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libcilkrts/Makefile; \ + mv $(TARGET_SUBDIR)/libcilkrts/multilib.tmp $(TARGET_SUBDIR)/libcilkrts/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libcilkrts/multilib.tmp $(TARGET_SUBDIR)/libcilkrts/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libcilkrts/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage 3 in $(TARGET_SUBDIR)/libcilkrts ; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libcilkrts ; \ + cd $(TARGET_SUBDIR)/libcilkrts || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libcilkrts/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + srcdiroption="--srcdir=$${topdir}/libcilkrts"; \ + libsrcdir="$$s/libcilkrts"; \ + $(SHELL) $${libsrcdir}/configure \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} $${srcdiroption} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGE3_CONFIGURE_FLAGS) +@endif target-libcilkrts-bootstrap + +.PHONY: configure-stage4-target-libcilkrts maybe-configure-stage4-target-libcilkrts +maybe-configure-stage4-target-libcilkrts: +@if target-libcilkrts-bootstrap +maybe-configure-stage4-target-libcilkrts: configure-stage4-target-libcilkrts +configure-stage4-target-libcilkrts: + @[ $(current_stage) = stage4 ] || $(MAKE) stage4-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libcilkrts + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE4_TFLAGS)"; \ + echo "Checking multilib configuration for libcilkrts...(4)"; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libcilkrts/multilib.tmp 2> /dev/null ; \ + if test -r $(TARGET_SUBDIR)/libcilkrts/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libcilkrts/multilib.tmp $(TARGET_SUBDIR)/libcilkrts/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libcilkrts/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libcilkrts/Makefile; \ + mv $(TARGET_SUBDIR)/libcilkrts/multilib.tmp $(TARGET_SUBDIR)/libcilkrts/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libcilkrts/multilib.tmp $(TARGET_SUBDIR)/libcilkrts/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libcilkrts/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage 4 in $(TARGET_SUBDIR)/libcilkrts ; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libcilkrts ; \ + cd $(TARGET_SUBDIR)/libcilkrts || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libcilkrts/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + srcdiroption="--srcdir=$${topdir}/libcilkrts"; \ + libsrcdir="$$s/libcilkrts"; \ + $(SHELL) $${libsrcdir}/configure \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} $${srcdiroption} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGE4_CONFIGURE_FLAGS) +@endif target-libcilkrts-bootstrap + +.PHONY: configure-stageprofile-target-libcilkrts maybe-configure-stageprofile-target-libcilkrts +maybe-configure-stageprofile-target-libcilkrts: +@if target-libcilkrts-bootstrap +maybe-configure-stageprofile-target-libcilkrts: configure-stageprofile-target-libcilkrts +configure-stageprofile-target-libcilkrts: + @[ $(current_stage) = stageprofile ] || $(MAKE) stageprofile-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libcilkrts + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEprofile_TFLAGS)"; \ + echo "Checking multilib configuration for libcilkrts...(5)"; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libcilkrts/multilib.tmp 2> /dev/null ; \ + if test -r $(TARGET_SUBDIR)/libcilkrts/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libcilkrts/multilib.tmp $(TARGET_SUBDIR)/libcilkrts/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libcilkrts/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libcilkrts/Makefile; \ + mv $(TARGET_SUBDIR)/libcilkrts/multilib.tmp $(TARGET_SUBDIR)/libcilkrts/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libcilkrts/multilib.tmp $(TARGET_SUBDIR)/libcilkrts/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libcilkrts/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage profile in $(TARGET_SUBDIR)/libcilkrts ; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libcilkrts ; \ + cd $(TARGET_SUBDIR)/libcilkrts || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libcilkrts/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + srcdiroption="--srcdir=$${topdir}/libcilkrts"; \ + libsrcdir="$$s/libcilkrts"; \ + $(SHELL) $${libsrcdir}/configure \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} $${srcdiroption} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGEprofile_CONFIGURE_FLAGS) +@endif target-libcilkrts-bootstrap + +.PHONY: configure-stagefeedback-target-libcilkrts maybe-configure-stagefeedback-target-libcilkrts +maybe-configure-stagefeedback-target-libcilkrts: +@if target-libcilkrts-bootstrap +maybe-configure-stagefeedback-target-libcilkrts: configure-stagefeedback-target-libcilkrts +configure-stagefeedback-target-libcilkrts: + @[ $(current_stage) = stagefeedback ] || $(MAKE) stagefeedback-start + @$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libcilkrts + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEfeedback_TFLAGS)"; \ + echo "Checking multilib configuration for libcilkrts...(6)"; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libcilkrts/multilib.tmp 2> /dev/null ; \ + if test -r $(TARGET_SUBDIR)/libcilkrts/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libcilkrts/multilib.tmp $(TARGET_SUBDIR)/libcilkrts/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libcilkrts/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libcilkrts/Makefile; \ + mv $(TARGET_SUBDIR)/libcilkrts/multilib.tmp $(TARGET_SUBDIR)/libcilkrts/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libcilkrts/multilib.tmp $(TARGET_SUBDIR)/libcilkrts/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libcilkrts/Makefile || exit 0; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)"; export LIBCFLAGS; \ + echo Configuring stage feedback in $(TARGET_SUBDIR)/libcilkrts ; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libcilkrts ; \ + cd $(TARGET_SUBDIR)/libcilkrts || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libcilkrts/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + srcdiroption="--srcdir=$${topdir}/libcilkrts"; \ + libsrcdir="$$s/libcilkrts"; \ + $(SHELL) $${libsrcdir}/configure \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} $${srcdiroption} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ + $(STAGEfeedback_CONFIGURE_FLAGS) +@endif target-libcilkrts-bootstrap + + + + + +.PHONY: all-target-libcilkrts maybe-all-target-libcilkrts +maybe-all-target-libcilkrts: +@if gcc-bootstrap +all-target-libcilkrts: stage_current +@endif gcc-bootstrap +@if target-libcilkrts +TARGET-target-libcilkrts=all +maybe-all-target-libcilkrts: all-target-libcilkrts +all-target-libcilkrts: configure-target-libcilkrts + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + (cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) $(EXTRA_TARGET_FLAGS) \ + $(TARGET-target-libcilkrts)) +@endif target-libcilkrts + + + +.PHONY: all-stage1-target-libcilkrts maybe-all-stage1-target-libcilkrts +.PHONY: clean-stage1-target-libcilkrts maybe-clean-stage1-target-libcilkrts +maybe-all-stage1-target-libcilkrts: +maybe-clean-stage1-target-libcilkrts: +@if target-libcilkrts-bootstrap +maybe-all-stage1-target-libcilkrts: all-stage1-target-libcilkrts +all-stage1: all-stage1-target-libcilkrts +TARGET-stage1-target-libcilkrts = $(TARGET-target-libcilkrts) +all-stage1-target-libcilkrts: configure-stage1-target-libcilkrts + @[ $(current_stage) = stage1 ] || $(MAKE) stage1-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE1_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGE1_TFLAGS)" \ + $(TARGET-stage1-target-libcilkrts) + +maybe-clean-stage1-target-libcilkrts: clean-stage1-target-libcilkrts +clean-stage1: clean-stage1-target-libcilkrts +clean-stage1-target-libcilkrts: + @if [ $(current_stage) = stage1 ]; then \ + [ -f $(TARGET_SUBDIR)/libcilkrts/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stage1-libcilkrts/Makefile ] || exit 0; \ + $(MAKE) stage1-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) \ + clean +@endif target-libcilkrts-bootstrap + + +.PHONY: all-stage2-target-libcilkrts maybe-all-stage2-target-libcilkrts +.PHONY: clean-stage2-target-libcilkrts maybe-clean-stage2-target-libcilkrts +maybe-all-stage2-target-libcilkrts: +maybe-clean-stage2-target-libcilkrts: +@if target-libcilkrts-bootstrap +maybe-all-stage2-target-libcilkrts: all-stage2-target-libcilkrts +all-stage2: all-stage2-target-libcilkrts +TARGET-stage2-target-libcilkrts = $(TARGET-target-libcilkrts) +all-stage2-target-libcilkrts: configure-stage2-target-libcilkrts + @[ $(current_stage) = stage2 ] || $(MAKE) stage2-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE2_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGE2_TFLAGS)" \ + $(TARGET-stage2-target-libcilkrts) + +maybe-clean-stage2-target-libcilkrts: clean-stage2-target-libcilkrts +clean-stage2: clean-stage2-target-libcilkrts +clean-stage2-target-libcilkrts: + @if [ $(current_stage) = stage2 ]; then \ + [ -f $(TARGET_SUBDIR)/libcilkrts/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stage2-libcilkrts/Makefile ] || exit 0; \ + $(MAKE) stage2-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) \ + \ + clean +@endif target-libcilkrts-bootstrap + + +.PHONY: all-stage3-target-libcilkrts maybe-all-stage3-target-libcilkrts +.PHONY: clean-stage3-target-libcilkrts maybe-clean-stage3-target-libcilkrts +maybe-all-stage3-target-libcilkrts: +maybe-clean-stage3-target-libcilkrts: +@if target-libcilkrts-bootstrap +maybe-all-stage3-target-libcilkrts: all-stage3-target-libcilkrts +all-stage3: all-stage3-target-libcilkrts +TARGET-stage3-target-libcilkrts = $(TARGET-target-libcilkrts) +all-stage3-target-libcilkrts: configure-stage3-target-libcilkrts + @[ $(current_stage) = stage3 ] || $(MAKE) stage3-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE3_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGE3_TFLAGS)" \ + $(TARGET-stage3-target-libcilkrts) + +maybe-clean-stage3-target-libcilkrts: clean-stage3-target-libcilkrts +clean-stage3: clean-stage3-target-libcilkrts +clean-stage3-target-libcilkrts: + @if [ $(current_stage) = stage3 ]; then \ + [ -f $(TARGET_SUBDIR)/libcilkrts/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stage3-libcilkrts/Makefile ] || exit 0; \ + $(MAKE) stage3-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) \ + \ + clean +@endif target-libcilkrts-bootstrap + + +.PHONY: all-stage4-target-libcilkrts maybe-all-stage4-target-libcilkrts +.PHONY: clean-stage4-target-libcilkrts maybe-clean-stage4-target-libcilkrts +maybe-all-stage4-target-libcilkrts: +maybe-clean-stage4-target-libcilkrts: +@if target-libcilkrts-bootstrap +maybe-all-stage4-target-libcilkrts: all-stage4-target-libcilkrts +all-stage4: all-stage4-target-libcilkrts +TARGET-stage4-target-libcilkrts = $(TARGET-target-libcilkrts) +all-stage4-target-libcilkrts: configure-stage4-target-libcilkrts + @[ $(current_stage) = stage4 ] || $(MAKE) stage4-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGE4_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGE4_TFLAGS)" \ + $(TARGET-stage4-target-libcilkrts) + +maybe-clean-stage4-target-libcilkrts: clean-stage4-target-libcilkrts +clean-stage4: clean-stage4-target-libcilkrts +clean-stage4-target-libcilkrts: + @if [ $(current_stage) = stage4 ]; then \ + [ -f $(TARGET_SUBDIR)/libcilkrts/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stage4-libcilkrts/Makefile ] || exit 0; \ + $(MAKE) stage4-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) \ + \ + clean +@endif target-libcilkrts-bootstrap + + +.PHONY: all-stageprofile-target-libcilkrts maybe-all-stageprofile-target-libcilkrts +.PHONY: clean-stageprofile-target-libcilkrts maybe-clean-stageprofile-target-libcilkrts +maybe-all-stageprofile-target-libcilkrts: +maybe-clean-stageprofile-target-libcilkrts: +@if target-libcilkrts-bootstrap +maybe-all-stageprofile-target-libcilkrts: all-stageprofile-target-libcilkrts +all-stageprofile: all-stageprofile-target-libcilkrts +TARGET-stageprofile-target-libcilkrts = $(TARGET-target-libcilkrts) +all-stageprofile-target-libcilkrts: configure-stageprofile-target-libcilkrts + @[ $(current_stage) = stageprofile ] || $(MAKE) stageprofile-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEprofile_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGEprofile_TFLAGS)" \ + $(TARGET-stageprofile-target-libcilkrts) + +maybe-clean-stageprofile-target-libcilkrts: clean-stageprofile-target-libcilkrts +clean-stageprofile: clean-stageprofile-target-libcilkrts +clean-stageprofile-target-libcilkrts: + @if [ $(current_stage) = stageprofile ]; then \ + [ -f $(TARGET_SUBDIR)/libcilkrts/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stageprofile-libcilkrts/Makefile ] || exit 0; \ + $(MAKE) stageprofile-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) \ + \ + clean +@endif target-libcilkrts-bootstrap + + +.PHONY: all-stagefeedback-target-libcilkrts maybe-all-stagefeedback-target-libcilkrts +.PHONY: clean-stagefeedback-target-libcilkrts maybe-clean-stagefeedback-target-libcilkrts +maybe-all-stagefeedback-target-libcilkrts: +maybe-clean-stagefeedback-target-libcilkrts: +@if target-libcilkrts-bootstrap +maybe-all-stagefeedback-target-libcilkrts: all-stagefeedback-target-libcilkrts +all-stagefeedback: all-stagefeedback-target-libcilkrts +TARGET-stagefeedback-target-libcilkrts = $(TARGET-target-libcilkrts) +all-stagefeedback-target-libcilkrts: configure-stagefeedback-target-libcilkrts + @[ $(current_stage) = stagefeedback ] || $(MAKE) stagefeedback-start + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + TFLAGS="$(STAGEfeedback_TFLAGS)"; \ + $(NORMAL_TARGET_EXPORTS) \ + \ + cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) \ + CFLAGS="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS="$(LIBCFLAGS_FOR_TARGET)" \ + CFLAGS_FOR_TARGET="$(CFLAGS_FOR_TARGET)" \ + CXXFLAGS_FOR_TARGET="$(CXXFLAGS_FOR_TARGET)" \ + LIBCFLAGS_FOR_TARGET="$(LIBCFLAGS_FOR_TARGET)" \ + $(EXTRA_TARGET_FLAGS) \ + TFLAGS="$(STAGEfeedback_TFLAGS)" \ + $(TARGET-stagefeedback-target-libcilkrts) + +maybe-clean-stagefeedback-target-libcilkrts: clean-stagefeedback-target-libcilkrts +clean-stagefeedback: clean-stagefeedback-target-libcilkrts +clean-stagefeedback-target-libcilkrts: + @if [ $(current_stage) = stagefeedback ]; then \ + [ -f $(TARGET_SUBDIR)/libcilkrts/Makefile ] || exit 0; \ + else \ + [ -f $(TARGET_SUBDIR)/stagefeedback-libcilkrts/Makefile ] || exit 0; \ + $(MAKE) stagefeedback-start; \ + fi; \ + cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(EXTRA_TARGET_FLAGS) \ + \ + clean +@endif target-libcilkrts-bootstrap + + + + + + +.PHONY: check-target-libcilkrts maybe-check-target-libcilkrts +maybe-check-target-libcilkrts: +@if target-libcilkrts +maybe-check-target-libcilkrts: check-target-libcilkrts + +check-target-libcilkrts: + @: $(MAKE); $(unstage) + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + (cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(TARGET_FLAGS_TO_PASS) check) + +@endif target-libcilkrts + +.PHONY: install-target-libcilkrts maybe-install-target-libcilkrts +maybe-install-target-libcilkrts: +@if target-libcilkrts +maybe-install-target-libcilkrts: install-target-libcilkrts + +install-target-libcilkrts: installdirs + @: $(MAKE); $(unstage) + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + (cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(TARGET_FLAGS_TO_PASS) install) + +@endif target-libcilkrts + +.PHONY: install-strip-target-libcilkrts maybe-install-strip-target-libcilkrts +maybe-install-strip-target-libcilkrts: +@if target-libcilkrts +maybe-install-strip-target-libcilkrts: install-strip-target-libcilkrts + +install-strip-target-libcilkrts: installdirs + @: $(MAKE); $(unstage) + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + (cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(TARGET_FLAGS_TO_PASS) install-strip) + +@endif target-libcilkrts + +# Other targets (info, dvi, pdf, etc.) + +.PHONY: maybe-info-target-libcilkrts info-target-libcilkrts +maybe-info-target-libcilkrts: +@if target-libcilkrts +maybe-info-target-libcilkrts: info-target-libcilkrts + +info-target-libcilkrts: \ + configure-target-libcilkrts + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libcilkrts/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing info in $(TARGET_SUBDIR)/libcilkrts" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + info) \ + || exit 1 + +@endif target-libcilkrts + +.PHONY: maybe-dvi-target-libcilkrts dvi-target-libcilkrts +maybe-dvi-target-libcilkrts: +@if target-libcilkrts +maybe-dvi-target-libcilkrts: dvi-target-libcilkrts + +dvi-target-libcilkrts: \ + configure-target-libcilkrts + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libcilkrts/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing dvi in $(TARGET_SUBDIR)/libcilkrts" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + dvi) \ + || exit 1 + +@endif target-libcilkrts + +.PHONY: maybe-pdf-target-libcilkrts pdf-target-libcilkrts +maybe-pdf-target-libcilkrts: +@if target-libcilkrts +maybe-pdf-target-libcilkrts: pdf-target-libcilkrts + +pdf-target-libcilkrts: \ + configure-target-libcilkrts + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libcilkrts/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing pdf in $(TARGET_SUBDIR)/libcilkrts" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + pdf) \ + || exit 1 + +@endif target-libcilkrts + +.PHONY: maybe-html-target-libcilkrts html-target-libcilkrts +maybe-html-target-libcilkrts: +@if target-libcilkrts +maybe-html-target-libcilkrts: html-target-libcilkrts + +html-target-libcilkrts: \ + configure-target-libcilkrts + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libcilkrts/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing html in $(TARGET_SUBDIR)/libcilkrts" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + html) \ + || exit 1 + +@endif target-libcilkrts + +.PHONY: maybe-TAGS-target-libcilkrts TAGS-target-libcilkrts +maybe-TAGS-target-libcilkrts: +@if target-libcilkrts +maybe-TAGS-target-libcilkrts: TAGS-target-libcilkrts + +TAGS-target-libcilkrts: \ + configure-target-libcilkrts + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libcilkrts/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing TAGS in $(TARGET_SUBDIR)/libcilkrts" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + TAGS) \ + || exit 1 + +@endif target-libcilkrts + +.PHONY: maybe-install-info-target-libcilkrts install-info-target-libcilkrts +maybe-install-info-target-libcilkrts: +@if target-libcilkrts +maybe-install-info-target-libcilkrts: install-info-target-libcilkrts + +install-info-target-libcilkrts: \ + configure-target-libcilkrts \ + info-target-libcilkrts + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libcilkrts/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing install-info in $(TARGET_SUBDIR)/libcilkrts" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + install-info) \ + || exit 1 + +@endif target-libcilkrts + +.PHONY: maybe-install-pdf-target-libcilkrts install-pdf-target-libcilkrts +maybe-install-pdf-target-libcilkrts: +@if target-libcilkrts +maybe-install-pdf-target-libcilkrts: install-pdf-target-libcilkrts + +install-pdf-target-libcilkrts: \ + configure-target-libcilkrts \ + pdf-target-libcilkrts + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libcilkrts/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing install-pdf in $(TARGET_SUBDIR)/libcilkrts" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + install-pdf) \ + || exit 1 + +@endif target-libcilkrts + +.PHONY: maybe-install-html-target-libcilkrts install-html-target-libcilkrts +maybe-install-html-target-libcilkrts: +@if target-libcilkrts +maybe-install-html-target-libcilkrts: install-html-target-libcilkrts + +install-html-target-libcilkrts: \ + configure-target-libcilkrts \ + html-target-libcilkrts + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libcilkrts/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing install-html in $(TARGET_SUBDIR)/libcilkrts" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + install-html) \ + || exit 1 + +@endif target-libcilkrts + +.PHONY: maybe-installcheck-target-libcilkrts installcheck-target-libcilkrts +maybe-installcheck-target-libcilkrts: +@if target-libcilkrts +maybe-installcheck-target-libcilkrts: installcheck-target-libcilkrts + +installcheck-target-libcilkrts: \ + configure-target-libcilkrts + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libcilkrts/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing installcheck in $(TARGET_SUBDIR)/libcilkrts" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + installcheck) \ + || exit 1 + +@endif target-libcilkrts + +.PHONY: maybe-mostlyclean-target-libcilkrts mostlyclean-target-libcilkrts +maybe-mostlyclean-target-libcilkrts: +@if target-libcilkrts +maybe-mostlyclean-target-libcilkrts: mostlyclean-target-libcilkrts + +mostlyclean-target-libcilkrts: + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libcilkrts/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing mostlyclean in $(TARGET_SUBDIR)/libcilkrts" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + mostlyclean) \ + || exit 1 + +@endif target-libcilkrts + +.PHONY: maybe-clean-target-libcilkrts clean-target-libcilkrts +maybe-clean-target-libcilkrts: +@if target-libcilkrts +maybe-clean-target-libcilkrts: clean-target-libcilkrts + +clean-target-libcilkrts: + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libcilkrts/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing clean in $(TARGET_SUBDIR)/libcilkrts" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + clean) \ + || exit 1 + +@endif target-libcilkrts + +.PHONY: maybe-distclean-target-libcilkrts distclean-target-libcilkrts +maybe-distclean-target-libcilkrts: +@if target-libcilkrts +maybe-distclean-target-libcilkrts: distclean-target-libcilkrts + +distclean-target-libcilkrts: + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libcilkrts/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing distclean in $(TARGET_SUBDIR)/libcilkrts" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + distclean) \ + || exit 1 + +@endif target-libcilkrts + +.PHONY: maybe-maintainer-clean-target-libcilkrts maintainer-clean-target-libcilkrts +maybe-maintainer-clean-target-libcilkrts: +@if target-libcilkrts +maybe-maintainer-clean-target-libcilkrts: maintainer-clean-target-libcilkrts + +maintainer-clean-target-libcilkrts: + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libcilkrts/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing maintainer-clean in $(TARGET_SUBDIR)/libcilkrts" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libcilkrts && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + maintainer-clean) \ + || exit 1 + +@endif target-libcilkrts @@ -45901,6 +46890,7 @@ configure-stage3-target-libvtv: maybe-all-stage3-gcc configure-stage4-target-libvtv: maybe-all-stage4-gcc configure-stageprofile-target-libvtv: maybe-all-stageprofile-gcc configure-stagefeedback-target-libvtv: maybe-all-stagefeedback-gcc +configure-target-libcilkrts: stage_last configure-target-libssp: stage_last configure-target-newlib: stage_last configure-stage1-target-libgcc: maybe-all-stage1-gcc @@ -45955,6 +46945,7 @@ configure-target-boehm-gc: maybe-all-gcc configure-target-rda: maybe-all-gcc configure-target-libada: maybe-all-gcc configure-target-libgomp: maybe-all-gcc +configure-target-libcilkrts: maybe-all-gcc configure-target-libitm: maybe-all-gcc configure-target-libatomic: maybe-all-gcc @endif gcc-no-bootstrap @@ -46720,6 +47711,8 @@ configure-stage3-target-libvtv: maybe-all-stage3-target-libstdc++-v3 configure-stage4-target-libvtv: maybe-all-stage4-target-libstdc++-v3 configure-stageprofile-target-libvtv: maybe-all-stageprofile-target-libstdc++-v3 configure-stagefeedback-target-libvtv: maybe-all-stagefeedback-target-libstdc++-v3 +configure-target-libcilkrts: maybe-all-target-libstdc++-v3 +configure-target-libcilkrts: maybe-all-gcc all-target-libstdc++-v3: maybe-configure-target-libgomp all-stage1-target-libstdc++-v3: maybe-configure-stage1-target-libgomp @@ -46735,6 +47728,8 @@ install-target-libsanitizer: maybe-install-target-libstdc++-v3 install-target-libsanitizer: maybe-install-target-libgcc install-target-libvtv: maybe-install-target-libstdc++-v3 install-target-libvtv: maybe-install-target-libgcc +install-target-libcilkrts: maybe-install-target-libstdc++-v3 +install-target-libcilkrts: maybe-install-target-libgcc install-target-libjava: maybe-install-target-libgcc install-target-libitm: maybe-install-target-libgcc install-target-libobjc: maybe-install-target-libgcc @@ -46783,6 +47778,7 @@ configure-target-libstdc++-v3: maybe-all-target-libgcc configure-target-libsanitizer: maybe-all-target-libgcc configure-target-libvtv: maybe-all-target-libgcc configure-target-libssp: maybe-all-target-libgcc +configure-target-libcilkrts: maybe-all-target-libgcc configure-target-newlib: maybe-all-target-libgcc configure-target-libbacktrace: maybe-all-target-libgcc configure-target-libquadmath: maybe-all-target-libgcc @@ -46830,6 +47826,8 @@ configure-target-winsup: maybe-all-target-newlib maybe-all-target-libgloss configure-target-libffi: maybe-all-target-newlib maybe-all-target-libgloss +configure-target-libcilkrts: maybe-all-target-newlib maybe-all-target-libgloss +configure-target-libcilkrts: maybe-all-target-libstdc++-v3 configure-target-libjava: maybe-all-target-newlib maybe-all-target-libgloss configure-target-libjava: maybe-all-target-libstdc++-v3 diff --git a/configure b/configure index 7bc49f74aef..c95990a6f4c 100755 --- a/configure +++ b/configure @@ -2772,6 +2772,7 @@ target_libraries="target-libgcc \ target-libgloss \ target-newlib \ target-libgomp \ + target-libcilkrts \ target-libatomic \ target-libitm \ target-libstdc++-v3 \ @@ -3164,6 +3165,25 @@ $as_echo "yes" >&6; } fi fi +# Disable libcilkrts on unsupported systems. +if test -d ${srcdir}/libcilkrts; then + if test x$enable_libcilkrts = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libcilkrts support" >&5 +$as_echo_n "checking for libcilkrts support... " >&6; } + if (srcdir=${srcdir}/libcilkrts; \ + . ${srcdir}/configure.tgt; \ + test -n "$UNSUPPORTED") + then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + noconfigdirs="$noconfigdirs target-libcilkrts" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + fi + fi +fi + # Disable libitm on unsupported systems. if test -d ${srcdir}/libitm; then if test x$enable_libitm = x; then diff --git a/configure.ac b/configure.ac index 595b2b92154..140877ffedc 100644 --- a/configure.ac +++ b/configure.ac @@ -156,6 +156,7 @@ target_libraries="target-libgcc \ target-libgloss \ target-newlib \ target-libgomp \ + target-libcilkrts \ target-libatomic \ target-libitm \ target-libstdc++-v3 \ @@ -506,6 +507,22 @@ if test -d ${srcdir}/libatomic; then fi fi +# Disable libcilkrts on unsupported systems. +if test -d ${srcdir}/libcilkrts; then + if test x$enable_libcilkrts = x; then + AC_MSG_CHECKING([for libcilkrts support]) + if (srcdir=${srcdir}/libcilkrts; \ + . ${srcdir}/configure.tgt; \ + test -n "$UNSUPPORTED") + then + AC_MSG_RESULT([no]) + noconfigdirs="$noconfigdirs target-libcilkrts" + else + AC_MSG_RESULT([yes]) + fi + fi +fi + # Disable libitm on unsupported systems. if test -d ${srcdir}/libitm; then if test x$enable_libitm = x; then diff --git a/libcilkrts/ChangeLog b/libcilkrts/ChangeLog new file mode 100644 index 00000000000..884e861b25d --- /dev/null +++ b/libcilkrts/ChangeLog @@ -0,0 +1,105 @@ +2013-10-23 Balaji V. Iyer <balaji.v.iyer@intel.com> + + * libcilkrts/Makefile.am: New file. Libcilkrts version 3902. + * libcilkrts/Makefile.in: Likewise + * libcilkrts/README: Likewise + * libcilkrts/aclocal.m4: Likewise + * libcilkrts/configure: Likewise + * libcilkrts/configure.ac: Likewise + * libcilkrts/include/cilk/cilk.h: Likewise + * libcilkrts/include/cilk/cilk_api.h: Likewise + * libcilkrts/include/cilk/cilk_api_linux.h: Likewise + * libcilkrts/include/cilk/cilk_stub.h: Likewise + * libcilkrts/include/cilk/cilk_undocumented.h: Likewise + * libcilkrts/include/cilk/common.h: Likewise + * libcilkrts/include/cilk/holder.h: Likewise + * libcilkrts/include/cilk/hyperobject_base.h: Likewise + * libcilkrts/include/cilk/metaprogramming.h: Likewise + * libcilkrts/include/cilk/reducer.h: Likewise + * libcilkrts/include/cilk/reducer_file.h: Likewise + * libcilkrts/include/cilk/reducer_list.h: Likewise + * libcilkrts/include/cilk/reducer_max.h: Likewise + * libcilkrts/include/cilk/reducer_min.h: Likewise + * libcilkrts/include/cilk/reducer_min_max.h: Likewise + * libcilkrts/include/cilk/reducer_opadd.h: Likewise + * libcilkrts/include/cilk/reducer_opand.h: Likewise + * libcilkrts/include/cilk/reducer_opmul.h: Likewise + * libcilkrts/include/cilk/reducer_opor.h: Likewise + * libcilkrts/include/cilk/reducer_opxor.h: Likewise + * libcilkrts/include/cilk/reducer_ostream.h: Likewise + * libcilkrts/include/cilk/reducer_string.h: Likewise + * libcilkrts/include/cilktools/cilkscreen.h: Likewise + * libcilkrts/include/cilktools/cilkview.h: Likewise + * libcilkrts/include/cilktools/fake_mutex.h: Likewise + * libcilkrts/include/cilktools/lock_guard.h: Likewise + * libcilkrts/include/internal/abi.h: Likewise + * libcilkrts/include/internal/cilk_fake.h: Likewise + * libcilkrts/include/internal/cilk_version.h: Likewise + * libcilkrts/include/internal/inspector-abi.h: Likewise + * libcilkrts/include/internal/metacall.h: Likewise + * libcilkrts/include/internal/rev.mk: Likewise + * libcilkrts/mk/cilk-version.mk: Likewise + * libcilkrts/mk/unix-common.mk: Likewise + * libcilkrts/runtime/acknowledgements.dox: Likewise + * libcilkrts/runtime/bug.cpp: Likewise + * libcilkrts/runtime/bug.h: Likewise + * libcilkrts/runtime/c_reducers.c: Likewise + * libcilkrts/runtime/cilk-abi-cilk-for.cpp: Likewise + * libcilkrts/runtime/cilk-abi-vla-internal.c: Likewise + * libcilkrts/runtime/cilk-abi-vla-internal.h: Likewise + * libcilkrts/runtime/cilk-abi-vla.c: Likewise + * libcilkrts/runtime/cilk-abi.c: Likewise + * libcilkrts/runtime/cilk-ittnotify.h: Likewise + * libcilkrts/runtime/cilk-tbb-interop.h: Likewise + * libcilkrts/runtime/cilk_api.c: Likewise + * libcilkrts/runtime/cilk_fiber-unix.cpp: Likewise + * libcilkrts/runtime/cilk_fiber-unix.h: Likewise + * libcilkrts/runtime/cilk_fiber.cpp: Likewise + * libcilkrts/runtime/cilk_fiber.h: Likewise + * libcilkrts/runtime/cilk_malloc.c: Likewise + * libcilkrts/runtime/cilk_malloc.h: Likewise + * libcilkrts/runtime/component.h: Likewise + * libcilkrts/runtime/doxygen-layout.xml: Likewise + * libcilkrts/runtime/doxygen.cfg: Likewise + * libcilkrts/runtime/except-gcc.cpp: Likewise + * libcilkrts/runtime/except-gcc.h: Likewise + * libcilkrts/runtime/except.h: Likewise + * libcilkrts/runtime/frame_malloc.c: Likewise + * libcilkrts/runtime/frame_malloc.h: Likewise + * libcilkrts/runtime/full_frame.c: Likewise + * libcilkrts/runtime/full_frame.h: Likewise + * libcilkrts/runtime/global_state.cpp: Likewise + * libcilkrts/runtime/global_state.h: Likewise + * libcilkrts/runtime/jmpbuf.c: Likewise + * libcilkrts/runtime/jmpbuf.h: Likewise + * libcilkrts/runtime/local_state.c: Likewise + * libcilkrts/runtime/local_state.h: Likewise + * libcilkrts/runtime/metacall_impl.c: Likewise + * libcilkrts/runtime/metacall_impl.h: Likewise + * libcilkrts/runtime/os-unix.c: Likewise + * libcilkrts/runtime/os.h: Likewise + * libcilkrts/runtime/os_mutex-unix.c: Likewise + * libcilkrts/runtime/os_mutex.h: Likewise + * libcilkrts/runtime/pedigrees.c: Likewise + * libcilkrts/runtime/pedigrees.h: Likewise + * libcilkrts/runtime/record-replay.cpp: Likewise + * libcilkrts/runtime/record-replay.h: Likewise + * libcilkrts/runtime/reducer_impl.cpp: Likewise + * libcilkrts/runtime/reducer_impl.h: Likewise + * libcilkrts/runtime/rts-common.h: Likewise + * libcilkrts/runtime/scheduler.c: Likewise + * libcilkrts/runtime/scheduler.h: Likewise + * libcilkrts/runtime/signal_node.c: Likewise + * libcilkrts/runtime/signal_node.h: Likewise + * libcilkrts/runtime/spin_mutex.c: Likewise + * libcilkrts/runtime/spin_mutex.h: Likewise + * libcilkrts/runtime/stacks.h: Likewise + * libcilkrts/runtime/stats.c: Likewise + * libcilkrts/runtime/stats.h: Likewise + * libcilkrts/runtime/symbol_test.c: Likewise + * libcilkrts/runtime/sysdep-unix.c: Likewise + * libcilkrts/runtime/sysdep.h: Likewise + * libcilkrts/runtime/unix_symbols.t: Likewise + * libcilkrts/runtime/worker_mutex.c: Likewise + * libcilkrts/runtime/worker_mutex.h: Likewise + diff --git a/libcilkrts/Makefile.am b/libcilkrts/Makefile.am new file mode 100644 index 00000000000..f332cfb13de --- /dev/null +++ b/libcilkrts/Makefile.am @@ -0,0 +1,173 @@ +# @copyright +# Copyright (C) 2011, 2013, Intel Corporation +# All rights reserved. +# +# @copyright +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# @copyright +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY +# WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +AUTOMAKE_OPTIONS = foreign + +# Use when building GCC +ACLOCAL_AMFLAGS = -I .. -I ../config + +# Compiler and linker flags. +GENERAL_FLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/runtime -I$(top_srcdir)/runtime/config/$(config_dir) -DIN_CILK_RUNTIME=1 +GENERAL_FLAGS += -D_Cilk_spawn="" -D_Cilk_sync="" -D_Cilk_for=for + +# Enable Intel Cilk Plus extension +GENERAL_FLAGS += -fcilkplus + +AM_CFLAGS = $(GENERAL_FLAGS) -std=c99 +AM_CPPFLAGS = $(GENERAL_FLAGS) +AM_LDFLAGS = -lpthread -ldl + +# Target list. +toolexeclib_LTLIBRARIES = libcilkrts.la + +libcilkrts_la_SOURCES = \ + runtime/config/$(config_dir)/cilk-abi-vla.c \ + runtime/config/$(config_dir)/os-unix-sysdep.c \ + runtime/bug.cpp \ + runtime/cilk-abi.c \ + runtime/cilk-abi-cilk-for.cpp \ + runtime/cilk-abi-vla-internal.c \ + runtime/cilk_api.c \ + runtime/cilk_fiber.cpp \ + runtime/cilk_fiber-unix.cpp \ + runtime/cilk_malloc.c \ + runtime/c_reducers.c \ + runtime/except-gcc.cpp \ + runtime/frame_malloc.c \ + runtime/full_frame.c \ + runtime/global_state.cpp \ + runtime/jmpbuf.c \ + runtime/local_state.c \ + runtime/metacall_impl.c \ + runtime/os_mutex-unix.c \ + runtime/os-unix.c \ + runtime/pedigrees.c \ + runtime/record-replay.cpp \ + runtime/reducer_impl.cpp \ + runtime/scheduler.c \ + runtime/signal_node.c \ + runtime/spin_mutex.c \ + runtime/stats.c \ + runtime/symbol_test.c \ + runtime/sysdep-unix.c \ + runtime/worker_mutex.c + + +# Load the $(REVISION) value. +include include/internal/rev.mk + +#libcilkrts_la_LDFLAGS = -rpath '$(libdir)' +libcilkrts_la_LDFLAGS = -version-info 5:0:0 +libcilkrts_la_LDFLAGS += -lpthread -ldl + +# If we're building on Linux, use the Linux version script +if LINUX_LINKER_SCRIPT + libcilkrts_la_LDFLAGS += -Wl,--version-script,$(srcdir)/runtime/linux-symbols.ver +endif + +# If we're building on MacOS, use the Mac versioning +if MAC_LINKER_SCRIPT + libcilkrts_la_LDFLAGS += -Wl,-exported_symbols_list,$(srcdir)/runtime/mac-symbols.txt +endif + + +# Hack for Cygwin +libcilkrts_la_LDFLAGS += -no-undefined + +# C/C++ header files for Cilk. +cilkincludedir = $(includedir)/cilk +cilkinclude_HEADERS = \ + include/cilk/cilk_api.h \ + include/cilk/cilk_api_linux.h \ + include/cilk/cilk.h \ + include/cilk/cilk_stub.h \ + include/cilk/cilk_undocumented.h \ + include/cilk/common.h \ + include/cilk/holder.h \ + include/cilk/hyperobject_base.h \ + include/cilk/metaprogramming.h \ + include/cilk/reducer_file.h \ + include/cilk/reducer.h \ + include/cilk/reducer_list.h \ + include/cilk/reducer_max.h \ + include/cilk/reducer_min.h \ + include/cilk/reducer_min_max.h \ + include/cilk/reducer_opadd.h \ + include/cilk/reducer_opand.h \ + include/cilk/reducer_opmul.h \ + include/cilk/reducer_opor.h \ + include/cilk/reducer_opxor.h \ + include/cilk/reducer_ostream.h \ + include/cilk/reducer_string.h + + +# Work around what appears to be a GNU make bug handling MAKEFLAGS +# values defined in terms of make variables, as is the case for CC and +# friends when we are called from the top level Makefile. +AM_MAKEFLAGS = \ + "AR_FLAGS=$(AR_FLAGS)" \ + "CC_FOR_BUILD=$(CC_FOR_BUILD)" \ + "CFLAGS=$(CFLAGS)" \ + "CXXFLAGS=$(CXXFLAGS)" \ + "CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \ + "CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \ + "INSTALL=$(INSTALL)" \ + "INSTALL_DATA=$(INSTALL_DATA)" \ + "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \ + "INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \ + "JC1FLAGS=$(JC1FLAGS)" \ + "LDFLAGS=$(LDFLAGS)" \ + "LIBCFLAGS=$(LIBCFLAGS)" \ + "LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \ + "MAKE=$(MAKE)" \ + "MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \ + "PICFLAG=$(PICFLAG)" \ + "PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \ + "SHELL=$(SHELL)" \ + "RUNTESTFLAGS=$(RUNTESTFLAGS)" \ + "exec_prefix=$(exec_prefix)" \ + "infodir=$(infodir)" \ + "libdir=$(libdir)" \ + "prefix=$(prefix)" \ + "includedir=$(includedir)" \ + "AR=$(AR)" \ + "AS=$(AS)" \ + "LD=$(LD)" \ + "LIBCFLAGS=$(LIBCFLAGS)" \ + "NM=$(NM)" \ + "PICFLAG=$(PICFLAG)" \ + "RANLIB=$(RANLIB)" \ + "DESTDIR=$(DESTDIR)" + +MAKEOVERRIDES= + diff --git a/libcilkrts/Makefile.in b/libcilkrts/Makefile.in new file mode 100644 index 00000000000..ecf8080faf9 --- /dev/null +++ b/libcilkrts/Makefile.in @@ -0,0 +1,1045 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# @copyright +# Copyright (C) 2011, 2013, Intel Corporation +# All rights reserved. +# +# @copyright +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# @copyright +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY +# WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +######################################################################### +# +# @copyright +# Copyright (C) 2011-2013, Intel Corporation +# All rights reserved. +# +# @copyright +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# @copyright +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY +# WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +########################################################################### + +# DO NOT EDIT THIS FILE! +# +# It was automatically generated by cilkrts/include/internal/Makefile + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +DIST_COMMON = $(srcdir)/include/internal/rev.mk README ChangeLog \ + $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/configure $(am__configure_deps) \ + $(srcdir)/../mkinstalldirs $(srcdir)/../depcomp \ + $(cilkinclude_HEADERS) + +# If we're building on Linux, use the Linux version script +@LINUX_LINKER_SCRIPT_TRUE@am__append_1 = -Wl,--version-script,$(srcdir)/runtime/linux-symbols.ver + +# If we're building on MacOS, use the Mac versioning +@MAC_LINKER_SCRIPT_TRUE@am__append_2 = -Wl,-exported_symbols_list,$(srcdir)/runtime/mac-symbols.txt +subdir = . +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \ + $(top_srcdir)/../config/lead-dot.m4 \ + $(top_srcdir)/../config/multi.m4 \ + $(top_srcdir)/../config/override.m4 \ + $(top_srcdir)/../libtool.m4 $(top_srcdir)/../ltoptions.m4 \ + $(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \ + $(top_srcdir)/../lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(toolexeclibdir)" \ + "$(DESTDIR)$(cilkincludedir)" +LTLIBRARIES = $(toolexeclib_LTLIBRARIES) +libcilkrts_la_LIBADD = +am_libcilkrts_la_OBJECTS = cilk-abi-vla.lo os-unix-sysdep.lo bug.lo \ + cilk-abi.lo cilk-abi-cilk-for.lo cilk-abi-vla-internal.lo \ + cilk_api.lo cilk_fiber.lo cilk_fiber-unix.lo cilk_malloc.lo \ + c_reducers.lo except-gcc.lo frame_malloc.lo full_frame.lo \ + global_state.lo jmpbuf.lo local_state.lo metacall_impl.lo \ + os_mutex-unix.lo os-unix.lo pedigrees.lo record-replay.lo \ + reducer_impl.lo scheduler.lo signal_node.lo spin_mutex.lo \ + stats.lo symbol_test.lo sysdep-unix.lo worker_mutex.lo +libcilkrts_la_OBJECTS = $(am_libcilkrts_la_OBJECTS) +libcilkrts_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(libcilkrts_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/../depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libcilkrts_la_SOURCES) +MULTISRCTOP = +MULTIBUILDTOP = +MULTIDIRS = +MULTISUBDIR = +MULTIDO = true +MULTICLEAN = true +HEADERS = $(cilkinclude_HEADERS) +ETAGS = etags +CTAGS = ctags +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +config_dir = @config_dir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +multi_basedir = @multi_basedir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +toolexecdir = @toolexecdir@ +toolexeclibdir = @toolexeclibdir@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = foreign + +# Use when building GCC +ACLOCAL_AMFLAGS = -I .. -I ../config + +# Compiler and linker flags. + +# Enable Intel Cilk Plus extension +GENERAL_FLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/runtime \ + -I$(top_srcdir)/runtime/config/$(config_dir) \ + -DIN_CILK_RUNTIME=1 -D_Cilk_spawn="" -D_Cilk_sync="" \ + -D_Cilk_for=for -fcilkplus +AM_CFLAGS = $(GENERAL_FLAGS) -std=c99 +AM_CPPFLAGS = $(GENERAL_FLAGS) +AM_LDFLAGS = -lpthread -ldl + +# Target list. +toolexeclib_LTLIBRARIES = libcilkrts.la +libcilkrts_la_SOURCES = \ + runtime/config/$(config_dir)/cilk-abi-vla.c \ + runtime/config/$(config_dir)/os-unix-sysdep.c \ + runtime/bug.cpp \ + runtime/cilk-abi.c \ + runtime/cilk-abi-cilk-for.cpp \ + runtime/cilk-abi-vla-internal.c \ + runtime/cilk_api.c \ + runtime/cilk_fiber.cpp \ + runtime/cilk_fiber-unix.cpp \ + runtime/cilk_malloc.c \ + runtime/c_reducers.c \ + runtime/except-gcc.cpp \ + runtime/frame_malloc.c \ + runtime/full_frame.c \ + runtime/global_state.cpp \ + runtime/jmpbuf.c \ + runtime/local_state.c \ + runtime/metacall_impl.c \ + runtime/os_mutex-unix.c \ + runtime/os-unix.c \ + runtime/pedigrees.c \ + runtime/record-replay.cpp \ + runtime/reducer_impl.cpp \ + runtime/scheduler.c \ + runtime/signal_node.c \ + runtime/spin_mutex.c \ + runtime/stats.c \ + runtime/symbol_test.c \ + runtime/sysdep-unix.c \ + runtime/worker_mutex.c + +CILK_REVISION = 3902 + +# Load the $(REVISION) value. + +#libcilkrts_la_LDFLAGS = -rpath '$(libdir)' + +# Hack for Cygwin +libcilkrts_la_LDFLAGS = -version-info 5:0:0 -lpthread -ldl \ + $(am__append_1) $(am__append_2) -no-undefined + +# C/C++ header files for Cilk. +cilkincludedir = $(includedir)/cilk +cilkinclude_HEADERS = \ + include/cilk/cilk_api.h \ + include/cilk/cilk_api_linux.h \ + include/cilk/cilk.h \ + include/cilk/cilk_stub.h \ + include/cilk/cilk_undocumented.h \ + include/cilk/common.h \ + include/cilk/holder.h \ + include/cilk/hyperobject_base.h \ + include/cilk/metaprogramming.h \ + include/cilk/reducer_file.h \ + include/cilk/reducer.h \ + include/cilk/reducer_list.h \ + include/cilk/reducer_max.h \ + include/cilk/reducer_min.h \ + include/cilk/reducer_min_max.h \ + include/cilk/reducer_opadd.h \ + include/cilk/reducer_opand.h \ + include/cilk/reducer_opmul.h \ + include/cilk/reducer_opor.h \ + include/cilk/reducer_opxor.h \ + include/cilk/reducer_ostream.h \ + include/cilk/reducer_string.h + + +# Work around what appears to be a GNU make bug handling MAKEFLAGS +# values defined in terms of make variables, as is the case for CC and +# friends when we are called from the top level Makefile. +AM_MAKEFLAGS = \ + "AR_FLAGS=$(AR_FLAGS)" \ + "CC_FOR_BUILD=$(CC_FOR_BUILD)" \ + "CFLAGS=$(CFLAGS)" \ + "CXXFLAGS=$(CXXFLAGS)" \ + "CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \ + "CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \ + "INSTALL=$(INSTALL)" \ + "INSTALL_DATA=$(INSTALL_DATA)" \ + "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \ + "INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \ + "JC1FLAGS=$(JC1FLAGS)" \ + "LDFLAGS=$(LDFLAGS)" \ + "LIBCFLAGS=$(LIBCFLAGS)" \ + "LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \ + "MAKE=$(MAKE)" \ + "MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \ + "PICFLAG=$(PICFLAG)" \ + "PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \ + "SHELL=$(SHELL)" \ + "RUNTESTFLAGS=$(RUNTESTFLAGS)" \ + "exec_prefix=$(exec_prefix)" \ + "infodir=$(infodir)" \ + "libdir=$(libdir)" \ + "prefix=$(prefix)" \ + "includedir=$(includedir)" \ + "AR=$(AR)" \ + "AS=$(AS)" \ + "LD=$(LD)" \ + "LIBCFLAGS=$(LIBCFLAGS)" \ + "NM=$(NM)" \ + "PICFLAG=$(PICFLAG)" \ + "RANLIB=$(RANLIB)" \ + "DESTDIR=$(DESTDIR)" + +MAKEOVERRIDES = +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .cpp .lo .o .obj +am--refresh: + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/include/internal/rev.mk $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): +install-toolexeclibLTLIBRARIES: $(toolexeclib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(toolexeclibdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibdir)" + @list='$(toolexeclib_LTLIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(toolexeclibdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(toolexeclibdir)"; \ + } + +uninstall-toolexeclibLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(toolexeclib_LTLIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(toolexeclibdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(toolexeclibdir)/$$f"; \ + done + +clean-toolexeclibLTLIBRARIES: + -test -z "$(toolexeclib_LTLIBRARIES)" || rm -f $(toolexeclib_LTLIBRARIES) + @list='$(toolexeclib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libcilkrts.la: $(libcilkrts_la_OBJECTS) $(libcilkrts_la_DEPENDENCIES) + $(libcilkrts_la_LINK) -rpath $(toolexeclibdir) $(libcilkrts_la_OBJECTS) $(libcilkrts_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bug.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/c_reducers.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cilk-abi-cilk-for.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cilk-abi-vla-internal.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cilk-abi-vla.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cilk-abi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cilk_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cilk_fiber-unix.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cilk_fiber.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cilk_malloc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/except-gcc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/frame_malloc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/full_frame.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/global_state.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jmpbuf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/local_state.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/metacall_impl.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os-unix-sysdep.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os-unix.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os_mutex-unix.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pedigrees.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/record-replay.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reducer_impl.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scheduler.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signal_node.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spin_mutex.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stats.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/symbol_test.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sysdep-unix.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/worker_mutex.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +cilk-abi-vla.lo: runtime/config/$(config_dir)/cilk-abi-vla.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cilk-abi-vla.lo -MD -MP -MF $(DEPDIR)/cilk-abi-vla.Tpo -c -o cilk-abi-vla.lo `test -f 'runtime/config/$(config_dir)/cilk-abi-vla.c' || echo '$(srcdir)/'`runtime/config/$(config_dir)/cilk-abi-vla.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/cilk-abi-vla.Tpo $(DEPDIR)/cilk-abi-vla.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/config/$(config_dir)/cilk-abi-vla.c' object='cilk-abi-vla.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cilk-abi-vla.lo `test -f 'runtime/config/$(config_dir)/cilk-abi-vla.c' || echo '$(srcdir)/'`runtime/config/$(config_dir)/cilk-abi-vla.c + +os-unix-sysdep.lo: runtime/config/$(config_dir)/os-unix-sysdep.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT os-unix-sysdep.lo -MD -MP -MF $(DEPDIR)/os-unix-sysdep.Tpo -c -o os-unix-sysdep.lo `test -f 'runtime/config/$(config_dir)/os-unix-sysdep.c' || echo '$(srcdir)/'`runtime/config/$(config_dir)/os-unix-sysdep.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/os-unix-sysdep.Tpo $(DEPDIR)/os-unix-sysdep.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/config/$(config_dir)/os-unix-sysdep.c' object='os-unix-sysdep.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o os-unix-sysdep.lo `test -f 'runtime/config/$(config_dir)/os-unix-sysdep.c' || echo '$(srcdir)/'`runtime/config/$(config_dir)/os-unix-sysdep.c + +cilk-abi.lo: runtime/cilk-abi.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cilk-abi.lo -MD -MP -MF $(DEPDIR)/cilk-abi.Tpo -c -o cilk-abi.lo `test -f 'runtime/cilk-abi.c' || echo '$(srcdir)/'`runtime/cilk-abi.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/cilk-abi.Tpo $(DEPDIR)/cilk-abi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/cilk-abi.c' object='cilk-abi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cilk-abi.lo `test -f 'runtime/cilk-abi.c' || echo '$(srcdir)/'`runtime/cilk-abi.c + +cilk-abi-vla-internal.lo: runtime/cilk-abi-vla-internal.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cilk-abi-vla-internal.lo -MD -MP -MF $(DEPDIR)/cilk-abi-vla-internal.Tpo -c -o cilk-abi-vla-internal.lo `test -f 'runtime/cilk-abi-vla-internal.c' || echo '$(srcdir)/'`runtime/cilk-abi-vla-internal.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/cilk-abi-vla-internal.Tpo $(DEPDIR)/cilk-abi-vla-internal.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/cilk-abi-vla-internal.c' object='cilk-abi-vla-internal.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cilk-abi-vla-internal.lo `test -f 'runtime/cilk-abi-vla-internal.c' || echo '$(srcdir)/'`runtime/cilk-abi-vla-internal.c + +cilk_api.lo: runtime/cilk_api.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cilk_api.lo -MD -MP -MF $(DEPDIR)/cilk_api.Tpo -c -o cilk_api.lo `test -f 'runtime/cilk_api.c' || echo '$(srcdir)/'`runtime/cilk_api.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/cilk_api.Tpo $(DEPDIR)/cilk_api.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/cilk_api.c' object='cilk_api.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cilk_api.lo `test -f 'runtime/cilk_api.c' || echo '$(srcdir)/'`runtime/cilk_api.c + +cilk_malloc.lo: runtime/cilk_malloc.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cilk_malloc.lo -MD -MP -MF $(DEPDIR)/cilk_malloc.Tpo -c -o cilk_malloc.lo `test -f 'runtime/cilk_malloc.c' || echo '$(srcdir)/'`runtime/cilk_malloc.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/cilk_malloc.Tpo $(DEPDIR)/cilk_malloc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/cilk_malloc.c' object='cilk_malloc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cilk_malloc.lo `test -f 'runtime/cilk_malloc.c' || echo '$(srcdir)/'`runtime/cilk_malloc.c + +c_reducers.lo: runtime/c_reducers.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT c_reducers.lo -MD -MP -MF $(DEPDIR)/c_reducers.Tpo -c -o c_reducers.lo `test -f 'runtime/c_reducers.c' || echo '$(srcdir)/'`runtime/c_reducers.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/c_reducers.Tpo $(DEPDIR)/c_reducers.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/c_reducers.c' object='c_reducers.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o c_reducers.lo `test -f 'runtime/c_reducers.c' || echo '$(srcdir)/'`runtime/c_reducers.c + +frame_malloc.lo: runtime/frame_malloc.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT frame_malloc.lo -MD -MP -MF $(DEPDIR)/frame_malloc.Tpo -c -o frame_malloc.lo `test -f 'runtime/frame_malloc.c' || echo '$(srcdir)/'`runtime/frame_malloc.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/frame_malloc.Tpo $(DEPDIR)/frame_malloc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/frame_malloc.c' object='frame_malloc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o frame_malloc.lo `test -f 'runtime/frame_malloc.c' || echo '$(srcdir)/'`runtime/frame_malloc.c + +full_frame.lo: runtime/full_frame.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT full_frame.lo -MD -MP -MF $(DEPDIR)/full_frame.Tpo -c -o full_frame.lo `test -f 'runtime/full_frame.c' || echo '$(srcdir)/'`runtime/full_frame.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/full_frame.Tpo $(DEPDIR)/full_frame.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/full_frame.c' object='full_frame.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o full_frame.lo `test -f 'runtime/full_frame.c' || echo '$(srcdir)/'`runtime/full_frame.c + +jmpbuf.lo: runtime/jmpbuf.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT jmpbuf.lo -MD -MP -MF $(DEPDIR)/jmpbuf.Tpo -c -o jmpbuf.lo `test -f 'runtime/jmpbuf.c' || echo '$(srcdir)/'`runtime/jmpbuf.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/jmpbuf.Tpo $(DEPDIR)/jmpbuf.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/jmpbuf.c' object='jmpbuf.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o jmpbuf.lo `test -f 'runtime/jmpbuf.c' || echo '$(srcdir)/'`runtime/jmpbuf.c + +local_state.lo: runtime/local_state.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT local_state.lo -MD -MP -MF $(DEPDIR)/local_state.Tpo -c -o local_state.lo `test -f 'runtime/local_state.c' || echo '$(srcdir)/'`runtime/local_state.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/local_state.Tpo $(DEPDIR)/local_state.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/local_state.c' object='local_state.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o local_state.lo `test -f 'runtime/local_state.c' || echo '$(srcdir)/'`runtime/local_state.c + +metacall_impl.lo: runtime/metacall_impl.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT metacall_impl.lo -MD -MP -MF $(DEPDIR)/metacall_impl.Tpo -c -o metacall_impl.lo `test -f 'runtime/metacall_impl.c' || echo '$(srcdir)/'`runtime/metacall_impl.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/metacall_impl.Tpo $(DEPDIR)/metacall_impl.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/metacall_impl.c' object='metacall_impl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o metacall_impl.lo `test -f 'runtime/metacall_impl.c' || echo '$(srcdir)/'`runtime/metacall_impl.c + +os_mutex-unix.lo: runtime/os_mutex-unix.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT os_mutex-unix.lo -MD -MP -MF $(DEPDIR)/os_mutex-unix.Tpo -c -o os_mutex-unix.lo `test -f 'runtime/os_mutex-unix.c' || echo '$(srcdir)/'`runtime/os_mutex-unix.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/os_mutex-unix.Tpo $(DEPDIR)/os_mutex-unix.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/os_mutex-unix.c' object='os_mutex-unix.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o os_mutex-unix.lo `test -f 'runtime/os_mutex-unix.c' || echo '$(srcdir)/'`runtime/os_mutex-unix.c + +os-unix.lo: runtime/os-unix.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT os-unix.lo -MD -MP -MF $(DEPDIR)/os-unix.Tpo -c -o os-unix.lo `test -f 'runtime/os-unix.c' || echo '$(srcdir)/'`runtime/os-unix.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/os-unix.Tpo $(DEPDIR)/os-unix.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/os-unix.c' object='os-unix.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o os-unix.lo `test -f 'runtime/os-unix.c' || echo '$(srcdir)/'`runtime/os-unix.c + +pedigrees.lo: runtime/pedigrees.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT pedigrees.lo -MD -MP -MF $(DEPDIR)/pedigrees.Tpo -c -o pedigrees.lo `test -f 'runtime/pedigrees.c' || echo '$(srcdir)/'`runtime/pedigrees.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pedigrees.Tpo $(DEPDIR)/pedigrees.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/pedigrees.c' object='pedigrees.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o pedigrees.lo `test -f 'runtime/pedigrees.c' || echo '$(srcdir)/'`runtime/pedigrees.c + +scheduler.lo: runtime/scheduler.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT scheduler.lo -MD -MP -MF $(DEPDIR)/scheduler.Tpo -c -o scheduler.lo `test -f 'runtime/scheduler.c' || echo '$(srcdir)/'`runtime/scheduler.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/scheduler.Tpo $(DEPDIR)/scheduler.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/scheduler.c' object='scheduler.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o scheduler.lo `test -f 'runtime/scheduler.c' || echo '$(srcdir)/'`runtime/scheduler.c + +signal_node.lo: runtime/signal_node.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT signal_node.lo -MD -MP -MF $(DEPDIR)/signal_node.Tpo -c -o signal_node.lo `test -f 'runtime/signal_node.c' || echo '$(srcdir)/'`runtime/signal_node.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/signal_node.Tpo $(DEPDIR)/signal_node.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/signal_node.c' object='signal_node.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o signal_node.lo `test -f 'runtime/signal_node.c' || echo '$(srcdir)/'`runtime/signal_node.c + +spin_mutex.lo: runtime/spin_mutex.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spin_mutex.lo -MD -MP -MF $(DEPDIR)/spin_mutex.Tpo -c -o spin_mutex.lo `test -f 'runtime/spin_mutex.c' || echo '$(srcdir)/'`runtime/spin_mutex.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/spin_mutex.Tpo $(DEPDIR)/spin_mutex.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/spin_mutex.c' object='spin_mutex.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spin_mutex.lo `test -f 'runtime/spin_mutex.c' || echo '$(srcdir)/'`runtime/spin_mutex.c + +stats.lo: runtime/stats.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stats.lo -MD -MP -MF $(DEPDIR)/stats.Tpo -c -o stats.lo `test -f 'runtime/stats.c' || echo '$(srcdir)/'`runtime/stats.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/stats.Tpo $(DEPDIR)/stats.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/stats.c' object='stats.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stats.lo `test -f 'runtime/stats.c' || echo '$(srcdir)/'`runtime/stats.c + +symbol_test.lo: runtime/symbol_test.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT symbol_test.lo -MD -MP -MF $(DEPDIR)/symbol_test.Tpo -c -o symbol_test.lo `test -f 'runtime/symbol_test.c' || echo '$(srcdir)/'`runtime/symbol_test.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/symbol_test.Tpo $(DEPDIR)/symbol_test.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/symbol_test.c' object='symbol_test.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o symbol_test.lo `test -f 'runtime/symbol_test.c' || echo '$(srcdir)/'`runtime/symbol_test.c + +sysdep-unix.lo: runtime/sysdep-unix.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sysdep-unix.lo -MD -MP -MF $(DEPDIR)/sysdep-unix.Tpo -c -o sysdep-unix.lo `test -f 'runtime/sysdep-unix.c' || echo '$(srcdir)/'`runtime/sysdep-unix.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/sysdep-unix.Tpo $(DEPDIR)/sysdep-unix.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/sysdep-unix.c' object='sysdep-unix.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sysdep-unix.lo `test -f 'runtime/sysdep-unix.c' || echo '$(srcdir)/'`runtime/sysdep-unix.c + +worker_mutex.lo: runtime/worker_mutex.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT worker_mutex.lo -MD -MP -MF $(DEPDIR)/worker_mutex.Tpo -c -o worker_mutex.lo `test -f 'runtime/worker_mutex.c' || echo '$(srcdir)/'`runtime/worker_mutex.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/worker_mutex.Tpo $(DEPDIR)/worker_mutex.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/worker_mutex.c' object='worker_mutex.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o worker_mutex.lo `test -f 'runtime/worker_mutex.c' || echo '$(srcdir)/'`runtime/worker_mutex.c + +.cpp.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cpp.lo: +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +bug.lo: runtime/bug.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT bug.lo -MD -MP -MF $(DEPDIR)/bug.Tpo -c -o bug.lo `test -f 'runtime/bug.cpp' || echo '$(srcdir)/'`runtime/bug.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/bug.Tpo $(DEPDIR)/bug.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runtime/bug.cpp' object='bug.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o bug.lo `test -f 'runtime/bug.cpp' || echo '$(srcdir)/'`runtime/bug.cpp + +cilk-abi-cilk-for.lo: runtime/cilk-abi-cilk-for.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT cilk-abi-cilk-for.lo -MD -MP -MF $(DEPDIR)/cilk-abi-cilk-for.Tpo -c -o cilk-abi-cilk-for.lo `test -f 'runtime/cilk-abi-cilk-for.cpp' || echo '$(srcdir)/'`runtime/cilk-abi-cilk-for.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/cilk-abi-cilk-for.Tpo $(DEPDIR)/cilk-abi-cilk-for.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runtime/cilk-abi-cilk-for.cpp' object='cilk-abi-cilk-for.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o cilk-abi-cilk-for.lo `test -f 'runtime/cilk-abi-cilk-for.cpp' || echo '$(srcdir)/'`runtime/cilk-abi-cilk-for.cpp + +cilk_fiber.lo: runtime/cilk_fiber.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT cilk_fiber.lo -MD -MP -MF $(DEPDIR)/cilk_fiber.Tpo -c -o cilk_fiber.lo `test -f 'runtime/cilk_fiber.cpp' || echo '$(srcdir)/'`runtime/cilk_fiber.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/cilk_fiber.Tpo $(DEPDIR)/cilk_fiber.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runtime/cilk_fiber.cpp' object='cilk_fiber.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o cilk_fiber.lo `test -f 'runtime/cilk_fiber.cpp' || echo '$(srcdir)/'`runtime/cilk_fiber.cpp + +cilk_fiber-unix.lo: runtime/cilk_fiber-unix.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT cilk_fiber-unix.lo -MD -MP -MF $(DEPDIR)/cilk_fiber-unix.Tpo -c -o cilk_fiber-unix.lo `test -f 'runtime/cilk_fiber-unix.cpp' || echo '$(srcdir)/'`runtime/cilk_fiber-unix.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/cilk_fiber-unix.Tpo $(DEPDIR)/cilk_fiber-unix.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runtime/cilk_fiber-unix.cpp' object='cilk_fiber-unix.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o cilk_fiber-unix.lo `test -f 'runtime/cilk_fiber-unix.cpp' || echo '$(srcdir)/'`runtime/cilk_fiber-unix.cpp + +except-gcc.lo: runtime/except-gcc.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT except-gcc.lo -MD -MP -MF $(DEPDIR)/except-gcc.Tpo -c -o except-gcc.lo `test -f 'runtime/except-gcc.cpp' || echo '$(srcdir)/'`runtime/except-gcc.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/except-gcc.Tpo $(DEPDIR)/except-gcc.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runtime/except-gcc.cpp' object='except-gcc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o except-gcc.lo `test -f 'runtime/except-gcc.cpp' || echo '$(srcdir)/'`runtime/except-gcc.cpp + +global_state.lo: runtime/global_state.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT global_state.lo -MD -MP -MF $(DEPDIR)/global_state.Tpo -c -o global_state.lo `test -f 'runtime/global_state.cpp' || echo '$(srcdir)/'`runtime/global_state.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/global_state.Tpo $(DEPDIR)/global_state.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runtime/global_state.cpp' object='global_state.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o global_state.lo `test -f 'runtime/global_state.cpp' || echo '$(srcdir)/'`runtime/global_state.cpp + +record-replay.lo: runtime/record-replay.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT record-replay.lo -MD -MP -MF $(DEPDIR)/record-replay.Tpo -c -o record-replay.lo `test -f 'runtime/record-replay.cpp' || echo '$(srcdir)/'`runtime/record-replay.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/record-replay.Tpo $(DEPDIR)/record-replay.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runtime/record-replay.cpp' object='record-replay.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o record-replay.lo `test -f 'runtime/record-replay.cpp' || echo '$(srcdir)/'`runtime/record-replay.cpp + +reducer_impl.lo: runtime/reducer_impl.cpp +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT reducer_impl.lo -MD -MP -MF $(DEPDIR)/reducer_impl.Tpo -c -o reducer_impl.lo `test -f 'runtime/reducer_impl.cpp' || echo '$(srcdir)/'`runtime/reducer_impl.cpp +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/reducer_impl.Tpo $(DEPDIR)/reducer_impl.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runtime/reducer_impl.cpp' object='reducer_impl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o reducer_impl.lo `test -f 'runtime/reducer_impl.cpp' || echo '$(srcdir)/'`runtime/reducer_impl.cpp + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool config.lt + +# GNU Make needs to see an explicit $(MAKE) variable in the command it +# runs to enable its job server during parallel builds. Hence the +# comments below. +all-multi: + $(MULTIDO) $(AM_MAKEFLAGS) DO=all multi-do # $(MAKE) +install-multi: + $(MULTIDO) $(AM_MAKEFLAGS) DO=install multi-do # $(MAKE) + +mostlyclean-multi: + $(MULTICLEAN) $(AM_MAKEFLAGS) DO=mostlyclean multi-clean # $(MAKE) +clean-multi: + $(MULTICLEAN) $(AM_MAKEFLAGS) DO=clean multi-clean # $(MAKE) +distclean-multi: + $(MULTICLEAN) $(AM_MAKEFLAGS) DO=distclean multi-clean # $(MAKE) +maintainer-clean-multi: + $(MULTICLEAN) $(AM_MAKEFLAGS) DO=maintainer-clean multi-clean # $(MAKE) +install-cilkincludeHEADERS: $(cilkinclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(cilkincludedir)" || $(MKDIR_P) "$(DESTDIR)$(cilkincludedir)" + @list='$(cilkinclude_HEADERS)'; test -n "$(cilkincludedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(cilkincludedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(cilkincludedir)" || exit $$?; \ + done + +uninstall-cilkincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(cilkinclude_HEADERS)'; test -n "$(cilkincludedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(cilkincludedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(cilkincludedir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) all-multi $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(cilkincludedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am clean-multi + +clean-am: clean-generic clean-libtool clean-toolexeclibLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am distclean-multi + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-cilkincludeHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-multi install-toolexeclibLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am maintainer-clean-multi + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am mostlyclean-multi + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-cilkincludeHEADERS \ + uninstall-toolexeclibLTLIBRARIES + +.MAKE: all-multi clean-multi distclean-multi install-am install-multi \ + install-strip maintainer-clean-multi mostlyclean-multi + +.PHONY: CTAGS GTAGS all all-am all-multi am--refresh check check-am \ + clean clean-generic clean-libtool clean-multi \ + clean-toolexeclibLTLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-multi \ + distclean-tags dvi dvi-am html html-am info info-am install \ + install-am install-cilkincludeHEADERS install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-multi install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + install-toolexeclibLTLIBRARIES installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + maintainer-clean-multi mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool mostlyclean-multi pdf \ + pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-cilkincludeHEADERS uninstall-toolexeclibLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libcilkrts/README b/libcilkrts/README new file mode 100644 index 00000000000..7c101150ece --- /dev/null +++ b/libcilkrts/README @@ -0,0 +1,84 @@ +Intel(R) Cilk(TM) Plus runtime library + +Index: +1. BUILDING +2. USING +3. DOXYGEN DOCUMENTATION +4. QUESTIONS OR BUGS +5. CONTRIBUTIONS + +# +# 1. BUILDING: +# + +To distribute applications that use the Intel Cilk Plus language +extensions to non-development systems, you need to build the Intel +Cilk Plus runtime library and distribute it with your application. + +To build the libcilkrts.so runtime library component, you need the +autoconf and automake packages, which are available through your +favorite package manager. You also need a C/C++ compiler that +supports the Intel Cilk Plus language extensions, since the runtime +uses Intel Cilk Plus features internally. Use either the Intel(R) +C++ Compiler (icc command) v12.1 or later, or in GCC 4.9 or later +(gcc command). + +Once you have the necessary prerequisites installed, you can use the +following commands to create the library: + +% libtoolize +% aclocal +% automake --add-missing +% autoconf +% ./configure +% make +% make install + +This will produce the libcilkrts.so shared object. To install the +library in a custom location, set the prefix while running the +configure script: + +% ./configure --prefix=/your/path/to/lib + +# +# 2. USING: +# + +The Intel(R) C++ Compiler will automatically try to bring in the +Intel Cilk Plus runtime in any program that uses the relevant +features. GCC requires explicit linking of both the library and +its dependencies (libpthread, libdl). For example: + +% gcc foo.c -lcilkrts -lpthread -ldl + +# +# 3. DOXYGEN DOCUMENTATION: +# + +The library source has Doxygen markup. Generate HTML documentation +based on the markup by changing directory into runtime and running: + +% doxygen doxygen.cfg + +# +# 4. QUESTIONS OR BUGS: +# + +Issues with the Intel Cilk Plus runtime can be addressed in the Intel +Cilk Plus forums: +http://software.intel.com/en-us/forums/intel-cilk-plus/ + +# +# 5. CONTRIBUTIONS: +# + +The Intel Cilk Plus runtime library is dual licensed. The upstream copy +of the library is maintained via the BSD-licensed version available at: +http://cilkplus.org/ + +Changes to the Intel Cilk Plus runtime are welcome and should be +contributed to the upstream version via http://cilkplus.org/. + +------------------------ +Intel and Cilk are trademarks of Intel Corporation in the U.S. and/or +other countries. diff --git a/libcilkrts/aclocal.m4 b/libcilkrts/aclocal.m4 new file mode 100644 index 00000000000..446bedeffa2 --- /dev/null +++ b/libcilkrts/aclocal.m4 @@ -0,0 +1,939 @@ +# generated automatically by aclocal 1.11.1 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.64],, +[m4_warning([this file was generated for autoconf 2.64. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically `autoreconf'.])]) + +# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.11' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.11.1], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.11.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 +# 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. + +# serial 9 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 +# 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. + +# serial 10 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], UPC, [depcc="$UPC" am_compiler_list=], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 +# 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. + +#serial 5 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2008, 2009 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. + +# serial 16 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.62])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl +]) +_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl +dnl The `parallel-tests' driver may need to know about EXEEXT, so add the +dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro +dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl +]) + +dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST(install_sh)]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2009 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. + +# serial 4 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# 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. + +# serial 6 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check for `mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2008 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. + +# serial 4 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 +# 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. + +# serial 5 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006, 2008 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. + +# serial 2 + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 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. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar <conftest.tar]) + grep GrepMe conftest.dir/file >/dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([../config/depstand.m4]) +m4_include([../config/lead-dot.m4]) +m4_include([../config/multi.m4]) +m4_include([../config/override.m4]) +m4_include([../libtool.m4]) +m4_include([../ltoptions.m4]) +m4_include([../ltsugar.m4]) +m4_include([../ltversion.m4]) +m4_include([../lt~obsolete.m4]) diff --git a/libcilkrts/configure b/libcilkrts/configure new file mode 100644 index 00000000000..18fb408e4a7 --- /dev/null +++ b/libcilkrts/configure @@ -0,0 +1,16649 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.64 for Cilk Runtime Library 2.0. +# +# Report bugs to <cilk@intel.com>. +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software +# Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 + + test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ + || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + # We cannot yet assume a decent shell, so we have to provide a + # neutralization value for shells without unset; and this also + # works around shells that cannot unset nonexistent variables. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org and cilk@intel.com +$0: about your system, including any error possibly output +$0: before this message. Then install a modern shell, or +$0: manually run the script under such a shell if you do +$0: have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error ERROR [LINENO LOG_FD] +# --------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with status $?, using 1 if that was 0. +as_fn_error () +{ + as_status=$?; test $as_status -eq 0 && as_status=1 + if test "$3"; then + as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + fi + $as_echo "$as_me: error: $1" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + +SHELL=${CONFIG_SHELL-/bin/sh} + + +exec 7<&0 </dev/null 6>&1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='Cilk Runtime Library' +PACKAGE_TARNAME='cilk-runtime-library' +PACKAGE_VERSION='2.0' +PACKAGE_STRING='Cilk Runtime Library 2.0' +PACKAGE_BUGREPORT='cilk@intel.com' +PACKAGE_URL='' + +# Factoring default headers for most tests. +ac_includes_default="\ +#include <stdio.h> +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#ifdef STDC_HEADERS +# include <stdlib.h> +# include <stddef.h> +#else +# ifdef HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#ifdef HAVE_STRINGS_H +# include <strings.h> +#endif +#ifdef HAVE_INTTYPES_H +# include <inttypes.h> +#endif +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif" + +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +LIBOBJS +toolexeclibdir +toolexecdir +CXXCPP +CPP +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +RANLIB +AR +OBJDUMP +LN_S +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +EGREP +GREP +SED +LIBTOOL +MAC_LINKER_SCRIPT_FALSE +MAC_LINKER_SCRIPT_TRUE +LINUX_LINKER_SCRIPT_FALSE +LINUX_LINKER_SCRIPT_TRUE +config_dir +multi_basedir +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +ac_ct_CC +CFLAGS +CC +am__fastdepCXX_FALSE +am__fastdepCXX_TRUE +CXXDEPMODE +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__quote +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CXX +CPPFLAGS +LDFLAGS +CXXFLAGS +CXX +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +target_os +target_vendor +target_cpu +target +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_dependency_tracking +enable_multilib +enable_version_specific_runtime_libs +enable_shared +enable_static +with_pic +enable_fast_install +with_gnu_ld +enable_libtool_lock +' + ac_precious_vars='build_alias +host_alias +target_alias +CXX +CXXFLAGS +LDFLAGS +LIBS +CPPFLAGS +CCC +CC +CFLAGS +CPP +CXXCPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information." + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures Cilk Runtime Library 2.0 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root + [DATAROOTDIR/doc/cilk-runtime-library] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of Cilk Runtime Library 2.0:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + --enable-multilib build many library versions (default) + --enable-version-specific-runtime-libs + Specify that runtime libraries should be installed + in a compi ler-specific directory + --enable-shared[=PKGS] build shared libraries [default=yes] + --enable-static[=PKGS] build static libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-pic try to use only PIC/non-PIC objects [default=use + both] + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + +Some influential environment variables: + CXX C++ compiler command + CXXFLAGS C++ compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + LIBS libraries to pass to the linker, e.g. -l<library> + CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I<include dir> if + you have headers in a nonstandard directory <include dir> + CC C compiler command + CFLAGS C compiler flags + CPP C preprocessor + CXXCPP C++ preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to <cilk@intel.com>. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +Cilk Runtime Library configure 2.0 +generated by GNU Autoconf 2.64 + +Copyright (C) 2009 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_cxx_try_compile + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case <limits.h> declares $2. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_func + +# ac_fn_cxx_try_cpp LINENO +# ------------------------ +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_cxx_try_cpp + +# ac_fn_cxx_try_link LINENO +# ------------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_cxx_try_link +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by Cilk Runtime Library $as_me 2.0, which was +generated by GNU Autoconf 2.64. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + ac_site_file1=$CONFIG_SITE +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + +# Needed to define ${target}. Needs to be very early to avoid annoying +# warning about calling AC_ARG_PROGRAM before AC_CANONICAL_SYSTEM +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + for ac_t in install-sh install.sh shtool; do + if test -f "$ac_dir/$ac_t"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/$ac_t -c" + break 2 + fi + done +done +if test -z "$ac_aux_dir"; then + as_fn_error "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if test "${ac_cv_build+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if test "${ac_cv_host+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +$as_echo_n "checking target system type... " >&6; } +if test "${ac_cv_target+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host +else + ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || + as_fn_error "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +$as_echo "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) as_fn_error "invalid value of canonical target" "$LINENO" 5;; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + +am__api_version='1.11' + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error "unsafe absolute working directory name" "$LINENO" 5;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error "ls -t appears to fail. Make sure there is not a broken +alias in your environment" "$LINENO" 5 + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if test "${ac_cv_path_mkdir+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + test -d ./--version && rmdir ./--version + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +mkdir_p="$MKDIR_P" +case $mkdir_p in + [\\/$]* | ?:[\\/]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='cilk-runtime-library' + VERSION='2.0' + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + + +# Build a DLL on Windows +# AC_LIBTOOL_WIN32_DLL +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + rm -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out conftest.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler default output file name" >&5 +$as_echo_n "checking for C++ compiler default output file name... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +if test -z "$ac_file"; then : + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ as_fn_set_status 77 +as_fn_error "C++ compiler cannot create executables +See \`config.log' for more details." "$LINENO" 5; }; } +fi +ac_exeext=$ac_cv_exeext + +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C++ compiler works" >&5 +$as_echo_n "checking whether the C++ compiler works... " >&6; } +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot run C++ compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out conftest.out +ac_clean_files=$ac_clean_files_save +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." "$LINENO" 5; } +fi +rm -f conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if test "${ac_cv_objext+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot compute suffix of object files: cannot compile +See \`config.log' for more details." "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if test "${ac_cv_prog_cxx_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 +$as_echo_n "checking for style of include used by $am_make... " >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 +$as_echo "$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then : + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + +depcc="$CXX" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "no acceptable C compiler found in \$PATH +See \`config.log' for more details." "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + rm -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +# AC_PROG_LIBTOOL +# AC_CONFIG_MACRO_DIR([..]) +ac_config_files="$ac_config_files Makefile" + +# Default to --enable-multilib +# Check whether --enable-multilib was given. +if test "${enable_multilib+set}" = set; then : + enableval=$enable_multilib; case "$enableval" in + yes) multilib=yes ;; + no) multilib=no ;; + *) as_fn_error "bad value $enableval for multilib option" "$LINENO" 5 ;; + esac +else + multilib=yes +fi + + +# We may get other options which we leave undocumented: +# --with-target-subdir, --with-multisrctop, --with-multisubdir +# See config-ml.in if you want the gory details. + +if test "$srcdir" = "."; then + if test "$with_target_subdir" != "."; then + multi_basedir="$srcdir/$with_multisrctop../.." + else + multi_basedir="$srcdir/$with_multisrctop.." + fi +else + multi_basedir="$srcdir/.." +fi + + +# Even if the default multilib is not a cross compilation, +# it may be that some of the other multilibs are. +if test $cross_compiling = no && test $multilib = yes \ + && test "x${with_multisubdir}" != x ; then + cross_compiling=maybe +fi + +ac_config_commands="$ac_config_commands default-1" + + +# Get target configury. +. ${srcdir}/configure.tgt +if test -n "$UNSUPPORTED"; then + as_fn_error "Configuration ${target} is unsupported." "$LINENO" 5 +fi + +if test "${multilib}" = "yes"; then + multilib_arg="--enable-multilib" +else + multilib_arg= +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-version-specific-runtime-libs" >&5 +$as_echo_n "checking for --enable-version-specific-runtime-libs... " >&6; } +# Check whether --enable-version-specific-runtime-libs was given. +if test "${enable_version_specific_runtime_libs+set}" = set; then : + enableval=$enable_version_specific_runtime_libs; case "$enableval" in + yes) enable_version_specific_runtime_libs=yes ;; + no) enable_version_specific_runtime_libs=no ;; + *) as_fn_error "Unknown argument to enable/disable version-specific libs +" "$LINENO" 5;; + esac +else + enable_version_specific_runtime_libs=no +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_version_specific_runtime_libs" >&5 +$as_echo "$enable_version_specific_runtime_libs" >&6; } + + +# Calculate toolexeclibdir +# Also toolexecdir, though it's only used in toolexeclibdir +case ${enable_version_specific_runtime_libs} in + yes) + # Need the gcc compiler version to know where to install libraries + # and header files if --enable-version-specific-runtime-libs option + # is selected. + toolexecdir='$(libdir)/gcc/$(target_alias)' + toolexeclibdir='$(toolexecdir)/$(gcc_version)$(MULTISUBDIR)' + ;; + no) + if test -n "$with_cross_host" && + test x"$with_cross_host" != x"no"; then + # Install a library built with a cross compiler in tooldir, not libdir. + toolexecdir='$(exec_prefix)/$(target_alias)' + toolexeclibdir='$(toolexecdir)/lib' + else + toolexecdir='$(libdir)/gcc-lib/$(target_alias)' + toolexeclibdir='$(libdir)' + fi + multi_os_directory=`$CC -print-multi-os-directory` + case $multi_os_directory in + .) ;; # Avoid trailing /. + *) toolexeclibdir=$toolexeclibdir/$multi_os_directory ;; + esac + ;; +esac + +# Set config_dir based on the target. config_dir specifies where to get +# target-specific files. The generic implementation is incomplete, but +# contains information on what's needed +case "${target}" in + + x86_64-*-*) + config_dir="x86" + ;; + + i45686-*-*) + config_dir="x86" + ;; + + *) + config_dir="generic" + ;; + +esac + + +# We have linker scripts for appropriate operating systems +linux_linker_script=no +case "${host}" in + *-*-linux*) + linux_linker_script=yes + ;; +esac + if test "$linux_linker_script" = "yes"; then + LINUX_LINKER_SCRIPT_TRUE= + LINUX_LINKER_SCRIPT_FALSE='#' +else + LINUX_LINKER_SCRIPT_TRUE='#' + LINUX_LINKER_SCRIPT_FALSE= +fi + + +mac_linker_script=no +case "${host}" in + *-*-apple*) + mac_linker_script=yes + ;; +esac + if test "$mac_linker_script" = "yes"; then + MAC_LINKER_SCRIPT_TRUE= + MAC_LINKER_SCRIPT_FALSE='#' +else + MAC_LINKER_SCRIPT_TRUE='#' + MAC_LINKER_SCRIPT_FALSE= +fi + + +case `pwd` in + *\ * | *\ *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 +$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; +esac + + + +macro_version='2.2.7a' +macro_revision='1.3134' + + + + + + + + + + + + + +ltmain="$ac_aux_dir/ltmain.sh" + +# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 +$as_echo_n "checking how to print strings... " >&6; } +# Test print first, because it will be a builtin if present. +if test "X`print -r -- -n 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "" +} + +case "$ECHO" in + printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 +$as_echo "printf" >&6; } ;; + print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 +$as_echo "print -r" >&6; } ;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 +$as_echo "cat" >&6; } ;; +esac + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if test "${ac_cv_path_SED+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if test "${ac_cv_path_GREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 +$as_echo_n "checking for fgrep... " >&6; } +if test "${ac_cv_path_FGREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 + then ac_cv_path_FGREP="$GREP -F" + else + if test -z "$FGREP"; then + ac_path_FGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in fgrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue +# Check for GNU ac_path_FGREP and select it if it is found. + # Check for GNU $ac_path_FGREP +case `"$ac_path_FGREP" --version 2>&1` in +*GNU*) + ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'FGREP' >> "conftest.nl" + "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_FGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_FGREP="$ac_path_FGREP" + ac_path_FGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_FGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_FGREP"; then + as_fn_error "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_FGREP=$FGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 +$as_echo "$ac_cv_path_FGREP" >&6; } + FGREP="$ac_cv_path_FGREP" + + +test -z "$GREP" && GREP=grep + + + + + + + + + + + + + + + + + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if test "${lt_cv_path_LD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in + *GNU* | *'with BFD'*) + test "$with_gnu_ld" != no && break + ;; + *) + test "$with_gnu_ld" != yes && break + ;; + esac + fi + done + IFS="$lt_save_ifs" +else + lt_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$lt_cv_path_LD" +if test -n "$LD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if test "${lt_cv_prog_gnu_ld+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 </dev/null` in +*GNU* | *'with BFD'*) + lt_cv_prog_gnu_ld=yes + ;; +*) + lt_cv_prog_gnu_ld=no + ;; +esac +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 +$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } +if test "${lt_cv_path_NM+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 +$as_echo "$lt_cv_path_NM" >&6; } +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + if test -n "$ac_tool_prefix"; then + for ac_prog in dumpbin "link -dump" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_DUMPBIN+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DUMPBIN"; then + ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DUMPBIN=$ac_cv_prog_DUMPBIN +if test -n "$DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 +$as_echo "$DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$DUMPBIN" && break + done +fi +if test -z "$DUMPBIN"; then + ac_ct_DUMPBIN=$DUMPBIN + for ac_prog in dumpbin "link -dump" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_DUMPBIN+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DUMPBIN"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN +if test -n "$ac_ct_DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 +$as_echo "$ac_ct_DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_DUMPBIN" && break +done + + if test "x$ac_ct_DUMPBIN" = x; then + DUMPBIN=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DUMPBIN=$ac_ct_DUMPBIN + fi +fi + + case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols" + ;; + *) + DUMPBIN=: + ;; + esac + fi + + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 +$as_echo_n "checking the name lister ($NM) interface... " >&6; } +if test "${lt_cv_nm_interface+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: output\"" >&5) + cat conftest.out >&5 + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 +$as_echo "$lt_cv_nm_interface" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + +# find the maximum length of command line arguments +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 +$as_echo_n "checking the maximum length of command line arguments... " >&6; } +if test "${lt_cv_sys_max_cmd_len+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`func_fallback_echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac + +fi + +if test -n $lt_cv_sys_max_cmd_len ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 +$as_echo "$lt_cv_sys_max_cmd_len" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 +$as_echo "none" >&6; } +fi +max_cmd_len=$lt_cv_sys_max_cmd_len + + + + + + +: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 +$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 +$as_echo "$xsi_shell" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 +$as_echo_n "checking whether the shell understands \"+=\"... " >&6; } +lt_shell_append=no +( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 +$as_echo "$lt_shell_append" >&6; } + + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi + + + + + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 +$as_echo_n "checking for $LD option to reload object files... " >&6; } +if test "${lt_cv_ld_reload_flag+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_reload_flag='-r' +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 +$as_echo "$lt_cv_ld_reload_flag" >&6; } +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + darwin*) + if test "$GCC" = yes; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OBJDUMP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +$as_echo "$OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +$as_echo "$ac_ct_OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 +$as_echo_n "checking how to recognize dependent libraries... " >&6; } +if test "${lt_cv_deplibs_check_method+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[4-9]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. + if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[3-9]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 +$as_echo "$lt_cv_deplibs_check_method" >&6; } +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AR+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_AR+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_AR="ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +else + AR="$ac_cv_prog_AR" +fi + +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +test -z "$STRIP" && STRIP=: + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_RANLIB+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +test -z "$RANLIB" && RANLIB=: + + + + + + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 +$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } +if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[ABCDGISTW]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[ABCDEGRST]' + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK '"\ +" {last_section=section; section=\$ 3};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 + (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +$as_echo "failed" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } +fi + + + + + + + + + + + + + + + + + + + + + + + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then : + enableval=$enable_libtool_lock; +fi + +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '#line '$LINENO' "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + case `/usr/bin/file conftest.o` in + *x86-64*) + LD="${LD-ld} -m elf32_x86_64" + ;; + *) + LD="${LD-ld} -m elf_i386" + ;; + esac + ;; + powerpc64le-*linux*) + LD="${LD-ld} -m elf32lppclinux" + ;; + powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + powerpcle-*linux*) + LD="${LD-ld} -m elf64lppc" + ;; + powerpc-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 +$as_echo_n "checking whether the C compiler needs -belf... " >&6; } +if test "${lt_cv_cc_needs_belf+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_cc_needs_belf=yes +else + lt_cv_cc_needs_belf=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 +$as_echo "$lt_cv_cc_needs_belf" >&6; } + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" + + + case $host_os in + rhapsody* | darwin*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. +set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_DSYMUTIL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DSYMUTIL"; then + ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DSYMUTIL=$ac_cv_prog_DSYMUTIL +if test -n "$DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 +$as_echo "$DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DSYMUTIL"; then + ac_ct_DSYMUTIL=$DSYMUTIL + # Extract the first word of "dsymutil", so it can be a program name with args. +set dummy dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_DSYMUTIL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DSYMUTIL"; then + ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL +if test -n "$ac_ct_DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 +$as_echo "$ac_ct_DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DSYMUTIL" = x; then + DSYMUTIL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DSYMUTIL=$ac_ct_DSYMUTIL + fi +else + DSYMUTIL="$ac_cv_prog_DSYMUTIL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. +set dummy ${ac_tool_prefix}nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_NMEDIT+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NMEDIT"; then + ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +NMEDIT=$ac_cv_prog_NMEDIT +if test -n "$NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 +$as_echo "$NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_NMEDIT"; then + ac_ct_NMEDIT=$NMEDIT + # Extract the first word of "nmedit", so it can be a program name with args. +set dummy nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_NMEDIT+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_NMEDIT"; then + ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_NMEDIT="nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT +if test -n "$ac_ct_NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 +$as_echo "$ac_ct_NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_NMEDIT" = x; then + NMEDIT=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + NMEDIT=$ac_ct_NMEDIT + fi +else + NMEDIT="$ac_cv_prog_NMEDIT" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. +set dummy ${ac_tool_prefix}lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_LIPO+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$LIPO"; then + ac_cv_prog_LIPO="$LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_LIPO="${ac_tool_prefix}lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LIPO=$ac_cv_prog_LIPO +if test -n "$LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 +$as_echo "$LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_LIPO"; then + ac_ct_LIPO=$LIPO + # Extract the first word of "lipo", so it can be a program name with args. +set dummy lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_LIPO+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_LIPO"; then + ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_LIPO="lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO +if test -n "$ac_ct_LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 +$as_echo "$ac_ct_LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_LIPO" = x; then + LIPO=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + LIPO=$ac_ct_LIPO + fi +else + LIPO="$ac_cv_prog_LIPO" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OTOOL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL"; then + ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OTOOL="${ac_tool_prefix}otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL=$ac_cv_prog_OTOOL +if test -n "$OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 +$as_echo "$OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL"; then + ac_ct_OTOOL=$OTOOL + # Extract the first word of "otool", so it can be a program name with args. +set dummy otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OTOOL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL"; then + ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OTOOL="otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL +if test -n "$ac_ct_OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 +$as_echo "$ac_ct_OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL" = x; then + OTOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL=$ac_ct_OTOOL + fi +else + OTOOL="$ac_cv_prog_OTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OTOOL64+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL64"; then + ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL64=$ac_cv_prog_OTOOL64 +if test -n "$OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 +$as_echo "$OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL64"; then + ac_ct_OTOOL64=$OTOOL64 + # Extract the first word of "otool64", so it can be a program name with args. +set dummy otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OTOOL64+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL64"; then + ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OTOOL64="otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 +if test -n "$ac_ct_OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 +$as_echo "$ac_ct_OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL64" = x; then + OTOOL64=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL64=$ac_ct_OTOOL64 + fi +else + OTOOL64="$ac_cv_prog_OTOOL64" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 +$as_echo_n "checking for -single_module linker flag... " >&6; } +if test "${lt_cv_apple_cc_single_mod+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&5 + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 +$as_echo "$lt_cv_apple_cc_single_mod" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 +$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } +if test "${lt_cv_ld_exported_symbols_list+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_ld_exported_symbols_list=yes +else + lt_cv_ld_exported_symbols_list=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 +$as_echo "$lt_cv_ld_exported_symbols_list" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 +$as_echo_n "checking for -force_load linker flag... " >&6; } +if test "${lt_cv_ld_force_load+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 + echo "$AR cru libconftest.a conftest.o" >&5 + $AR cru libconftest.a conftest.o 2>&5 + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&5 + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 +$as_echo "$lt_cv_ld_force_load" >&6; } + case $host_os in + rhapsody* | darwin1.[012]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[91]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[012]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if test "${ac_cv_header_stdc+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <string.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ctype.h> +#include <stdlib.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +eval as_val=\$$as_ac_Header + if test "x$as_val" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in dlfcn.h +do : + ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default +" +if test "x$ac_cv_header_dlfcn_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DLFCN_H 1 +_ACEOF + +fi + +done + + + + + + +# Set options + + + + enable_dlopen=no + + + enable_win32_dll=no + + + # Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then : + enableval=$enable_shared; p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_shared=yes +fi + + + + + + + + + + # Check whether --enable-static was given. +if test "${enable_static+set}" = set; then : + enableval=$enable_static; p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_static=yes +fi + + + + + + + + + + +# Check whether --with-pic was given. +if test "${with_pic+set}" = set; then : + withval=$with_pic; pic_mode="$withval" +else + pic_mode=default +fi + + +test -z "$pic_mode" && pic_mode=default + + + + + + + + # Check whether --enable-fast-install was given. +if test "${enable_fast_install+set}" = set; then : + enableval=$enable_fast_install; p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_fast_install=yes +fi + + + + + + + + + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + + + + + + + + + + + + + + + + + + + + + + + + + +test -z "$LN_S" && LN_S="ln -s" + + + + + + + + + + + + + + +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 +$as_echo_n "checking for objdir... " >&6; } +if test "${lt_cv_objdir+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 +$as_echo "$lt_cv_objdir" >&6; } +objdir=$lt_cv_objdir + + + + + +cat >>confdefs.h <<_ACEOF +#define LT_OBJDIR "$lt_cv_objdir/" +_ACEOF + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` + + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 +$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 +$as_echo_n "checking for file... " >&6; } +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +# Use C for the default configuration in the libtool script + +lt_save_CC="$CC" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + +lt_prog_compiler_no_builtin_flag= + +if test "$GCC" = yes; then + case $cc_basename in + nvcc*) + lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; + *) + lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } +if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + + + + + + + lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } + + if test "$GCC" = yes; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + lt_prog_compiler_pic='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + lt_prog_compiler_wl='-Xlinker ' + lt_prog_compiler_pic='-Xcompiler -fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='--shared' + lt_prog_compiler_static='--static' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-qpic' + lt_prog_compiler_static='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ F* | *Sun*Fortran*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' + ;; + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + esac + ;; + esac + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5 +$as_echo "$lt_prog_compiler_pic" >&6; } + + + + + + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } +if test "${lt_cv_prog_compiler_pic_works+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works" = xyes; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi + + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if test "${lt_cv_prog_compiler_static_works+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works=yes + fi + else + lt_cv_prog_compiler_static_works=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 +$as_echo "$lt_cv_prog_compiler_static_works" >&6; } + +if test x"$lt_cv_prog_compiler_static_works" = xyes; then + : +else + lt_prog_compiler_static= +fi + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test "${lt_cv_prog_compiler_c_o+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test "${lt_cv_prog_compiler_c_o+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + runpath_var= + allow_undefined_flag= + always_export_symbols=no + archive_cmds= + archive_expsym_cmds= + compiler_needs_object=no + enable_shared_with_static_runtimes=no + export_dynamic_flag_spec= + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + hardcode_automatic=no + hardcode_direct=no + hardcode_direct_absolute=no + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld= + hardcode_libdir_separator= + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + inherit_rpath=no + link_all_deplibs=unknown + module_cmds= + module_expsym_cmds= + old_archive_from_new_cmds= + old_archive_from_expsyms_cmds= + thread_safe_flag_spec= + whole_archive_flag_spec= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test "$with_gnu_ld" = yes; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; + *\ \(GNU\ Binutils\)\ [3-9]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test "$lt_use_gnu_ld_interface" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach <jrb3@best.com> says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + export_dynamic_flag_spec='${wl}--export-all-symbols' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + haiku*) + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + link_all_deplibs=yes + ;; + + interix[3-9]*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag= + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + whole_archive_flag_spec= + tmp_sharedflag='--shared' ;; + xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld='-rpath $libdir' + archive_cmds='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + ld_shlibs=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = no; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global + # defined symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_direct_absolute=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + file_list_spec='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' ${wl}-bernotok' + allow_undefined_flag=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + fi + archive_cmds_need_lc=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes=yes + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + else + whole_archive_flag_spec='' + fi + link_all_deplibs=yes + allow_undefined_flag="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + + else + ld_shlibs=no + fi + + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_flag_spec_ld='+b $libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 +$as_echo_n "checking if $CC understands -b... " >&6; } +if test "${lt_cv_prog_compiler__b+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler__b=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -b" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler__b=yes + fi + else + lt_cv_prog_compiler__b=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 +$as_echo "$lt_cv_prog_compiler__b" >&6; } + +if test x"$lt_cv_prog_compiler__b" = xyes; then + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' +else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' +fi + + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo(void) {} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + inherit_rpath=yes + link_all_deplibs=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + hardcode_shlibpath_var=no + hardcode_direct_absolute=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + archive_cmds_need_lc='no' + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag='${wl}-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='${wl}-z,text' + allow_undefined_flag='${wl}-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-R,$libdir' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + export_dynamic_flag_spec='${wl}-Blargedynsym' + ;; + esac + fi + fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 +$as_echo "$ld_shlibs" >&6; } +test "$ld_shlibs" = no && can_build_shared=no + +with_gnu_ld=$with_gnu_ld + + + + + + + + + + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if test "${lt_cv_archive_cmds_need_lc+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc" >&6; } + archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; + *) lt_sed_strip_eq="s,=/,/,g" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[lt_foo]++; } + if (lt_freq[lt_foo] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's,/\([A-Za-z]:\),\1,g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib<name>.so + # instead of lib<name>.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[23].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +haiku*) + version_type=linux + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/beos/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if test "${lt_cv_shlibpath_overrides_runpath+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || + test -n "$runpath_var" || + test "X$hardcode_automatic" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 +$as_echo "$hardcode_action" >&6; } + +if test "$hardcode_action" = relink || + test "$inherit_rpath" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if test "${ac_cv_lib_dl_dlopen+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + *) + ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = x""yes; then : + lt_cv_dlopen="shl_load" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +$as_echo_n "checking for shl_load in -ldld... " >&6; } +if test "${ac_cv_lib_dld_shl_load+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_shl_load=yes +else + ac_cv_lib_dld_shl_load=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +$as_echo "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = x""yes; then : + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" +else + ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if test "${ac_cv_lib_dl_dlopen+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 +$as_echo_n "checking for dlopen in -lsvld... " >&6; } +if test "${ac_cv_lib_svld_dlopen+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_svld_dlopen=yes +else + ac_cv_lib_svld_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 +$as_echo "$ac_cv_lib_svld_dlopen" >&6; } +if test "x$ac_cv_lib_svld_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 +$as_echo_n "checking for dld_link in -ldld... " >&6; } +if test "${ac_cv_lib_dld_dld_link+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (); +int +main () +{ +return dld_link (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_dld_link=yes +else + ac_cv_lib_dld_dld_link=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 +$as_echo "$ac_cv_lib_dld_dld_link" >&6; } +if test "x$ac_cv_lib_dld_dld_link" = x""yes; then : + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 +$as_echo_n "checking whether a program can dlopen itself... " >&6; } +if test "${lt_cv_dlopen_self+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line 10806 "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include <dlfcn.h> +#endif + +#include <stdio.h> + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +void fnord () __attribute__((visibility("default"))); +#endif + +void fnord () { int i=42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 +$as_echo "$lt_cv_dlopen_self" >&6; } + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 +$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } +if test "${lt_cv_dlopen_self_static+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line 10912 "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include <dlfcn.h> +#endif + +#include <stdio.h> + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +void fnord () __attribute__((visibility("default"))); +#endif + +void fnord () { int i=42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 +$as_echo "$lt_cv_dlopen_self_static" >&6; } + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + + + + + + + + + + + + + + + + +striplib= +old_striplib= +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 +$as_echo_n "checking whether stripping libraries is possible... " >&6; } +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; + esac +fi + + + + + + + + + + + + + # Report which library types will actually be built + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 +$as_echo_n "checking if libtool supports shared libraries... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 +$as_echo "$can_build_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 +$as_echo_n "checking whether to build shared libraries... " >&6; } + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[4-9]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 +$as_echo "$enable_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 +$as_echo_n "checking whether to build static libraries... " >&6; } + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 +$as_echo "$enable_static" >&6; } + + + + +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 +$as_echo_n "checking how to run the C++ preprocessor... " >&6; } +if test -z "$CXXCPP"; then + if test "${ac_cv_prog_CXXCPP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 +$as_echo "$CXXCPP" >&6; } +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details." "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +else + _lt_caught_CXX_error=yes +fi + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +archive_cmds_need_lc_CXX=no +allow_undefined_flag_CXX= +always_export_symbols_CXX=no +archive_expsym_cmds_CXX= +compiler_needs_object_CXX=no +export_dynamic_flag_spec_CXX= +hardcode_direct_CXX=no +hardcode_direct_absolute_CXX=no +hardcode_libdir_flag_spec_CXX= +hardcode_libdir_flag_spec_ld_CXX= +hardcode_libdir_separator_CXX= +hardcode_minus_L_CXX=no +hardcode_shlibpath_var_CXX=unsupported +hardcode_automatic_CXX=no +inherit_rpath_CXX=no +module_cmds_CXX= +module_expsym_cmds_CXX= +link_all_deplibs_CXX=unknown +old_archive_cmds_CXX=$old_archive_cmds +reload_flag_CXX=$reload_flag +reload_cmds_CXX=$reload_cmds +no_undefined_flag_CXX= +whole_archive_flag_spec_CXX= +enable_shared_with_static_runtimes_CXX=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +objext_CXX=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + + # save warnings/boilerplate of simple test code + ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + + ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + compiler=$CC + compiler_CXX=$CC + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` + + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' + else + lt_prog_compiler_no_builtin_flag_CXX= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if test "${lt_cv_path_LD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in + *GNU* | *'with BFD'*) + test "$with_gnu_ld" != no && break + ;; + *) + test "$with_gnu_ld" != yes && break + ;; + esac + fi + done + IFS="$lt_save_ifs" +else + lt_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$lt_cv_path_LD" +if test -n "$LD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if test "${lt_cv_prog_gnu_ld+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 </dev/null` in +*GNU* | *'with BFD'*) + lt_cv_prog_gnu_ld=yes + ;; +*) + lt_cv_prog_gnu_ld=no + ;; +esac +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_CXX= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + ld_shlibs_CXX=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_CXX='' + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + file_list_spec_CXX='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct_CXX=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_CXX=yes + hardcode_libdir_flag_spec_CXX='-L$libdir' + hardcode_libdir_separator_CXX= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec_CXX='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + always_export_symbols_CXX=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_CXX='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + + archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_CXX="-z nodefs" + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_CXX=' ${wl}-bernotok' + allow_undefined_flag_CXX=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_CXX='$convenience' + fi + archive_cmds_need_lc_CXX=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_CXX=unsupported + # Joseph Beckenbach <jrb3@best.com> says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_CXX=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_CXX='-L$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-all-symbols' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=no + enable_shared_with_static_runtimes_CXX=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_CXX=no + fi + ;; + darwin* | rhapsody*) + + + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes + hardcode_shlibpath_var_CXX=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + else + whole_archive_flag_spec_CXX='' + fi + link_all_deplibs_CXX=yes + allow_undefined_flag_CXX="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + if test "$lt_cv_apple_cc_single_mod" != "yes"; then + archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi + + else + ld_shlibs_CXX=no + fi + + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + freebsd2.*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + ld_shlibs_CXX=no + ;; + + freebsd-elf*) + archive_cmds_need_lc_CXX=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + ld_shlibs_CXX=yes + ;; + + gnu*) + ;; + + haiku*) + archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + link_all_deplibs_CXX=yes + ;; + + hpux9*) + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + export_dynamic_flag_spec_CXX='${wl}-E' + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + export_dynamic_flag_spec_CXX='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + ;; + *) + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + interix[3-9]*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' + fi + fi + link_all_deplibs_CXX=yes + ;; + esac + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + inherit_rpath_CXX=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + archive_cmds_need_lc_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [1-5].* | *pgcpp\ [1-5].*) + prelink_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"' + old_archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~ + $RANLIB $oldlib' + archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + hardcode_libdir_flag_spec_CXX='-R$libdir' + whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object_CXX=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + ld_shlibs_CXX=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + ld_shlibs_CXX=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + hardcode_direct_absolute_CXX=yes + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + export_dynamic_flag_spec_CXX='${wl}-E' + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + ld_shlibs_CXX=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx*) + case $host in + osf3*) + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + ;; + *) + allow_undefined_flag_CXX=' -expect_unresolved \*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + ;; + esac + + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + archive_cmds_need_lc_CXX=yes + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_shlibpath_var_CXX=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' + ;; + esac + link_all_deplibs_CXX=yes + + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + no_undefined_flag_CXX=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + fi + + hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag_CXX='${wl}-z,text' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag_CXX='${wl}-z,text' + allow_undefined_flag_CXX='${wl}-z,nodefs' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir' + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + export_dynamic_flag_spec_CXX='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~ + '"$old_archive_cmds_CXX" + reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~ + '"$reload_cmds_CXX" + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } + test "$ld_shlibs_CXX" = no && can_build_shared=no + + GCC_CXX="$GXX" + LD_CXX="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + # Dependencies to place before and after the object being linked: +predep_objects_CXX= +postdep_objects_CXX= +predeps_CXX= +postdeps_CXX= +compiler_lib_search_path_CXX= + +cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF + +if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case $p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + else + prev= + fi + + if test "$pre_test_object_deps_done" = no; then + case $p in + -L* | -R*) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$compiler_lib_search_path_CXX"; then + compiler_lib_search_path_CXX="${prev}${p}" + else + compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$postdeps_CXX"; then + postdeps_CXX="${prev}${p}" + else + postdeps_CXX="${postdeps_CXX} ${prev}${p}" + fi + fi + ;; + + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$predep_objects_CXX"; then + predep_objects_CXX="$p" + else + predep_objects_CXX="$predep_objects_CXX $p" + fi + else + if test -z "$postdep_objects_CXX"; then + postdep_objects_CXX="$p" + else + postdep_objects_CXX="$postdep_objects_CXX $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling CXX test program" +fi + +$RM -f confest.$objext + +# PORTME: override above test on systems where it is broken +case $host_os in +interix[3-9]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + predep_objects_CXX= + postdep_objects_CXX= + postdeps_CXX= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac + + +case " $postdeps_CXX " in +*" -lc "*) archive_cmds_need_lc_CXX=no ;; +esac + compiler_lib_search_dirs_CXX= +if test -n "${compiler_lib_search_path_CXX}"; then + compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + lt_prog_compiler_wl_CXX= +lt_prog_compiler_pic_CXX= +lt_prog_compiler_static_CXX= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } + + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + fi + lt_prog_compiler_pic_CXX='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic_CXX='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_CXX='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + lt_prog_compiler_pic_CXX= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static_CXX= + ;; + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_CXX=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + else + case $host_os in + aix[4-9]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + else + lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + lt_prog_compiler_pic_CXX='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + lt_prog_compiler_pic_CXX='+Z' + fi + ;; + aCC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_CXX='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + lt_prog_compiler_wl_CXX='--backend -Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + lt_prog_compiler_static_CXX='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fpic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + xlc* | xlC* | bgxl[cC]* | mpixl[cC]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-qpic' + lt_prog_compiler_static_CXX='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + lt_prog_compiler_pic_CXX='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + lt_prog_compiler_wl_CXX='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + lt_prog_compiler_pic_CXX='-pic' + ;; + cxx*) + # Digital/Compaq C++ + lt_prog_compiler_wl_CXX='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + lt_prog_compiler_pic_CXX='-pic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + lcc*) + # Lucid + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + lt_prog_compiler_pic_CXX='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + lt_prog_compiler_can_build_shared_CXX=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_CXX= + ;; + *) + lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_CXX" >&5 +$as_echo "$lt_prog_compiler_pic_CXX" >&6; } + + + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } +if test "${lt_cv_prog_compiler_pic_works_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works_CXX=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works_CXX=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then + case $lt_prog_compiler_pic_CXX in + "" | " "*) ;; + *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; + esac +else + lt_prog_compiler_pic_CXX= + lt_prog_compiler_can_build_shared_CXX=no +fi + +fi + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if test "${lt_cv_prog_compiler_static_works_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works_CXX=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works_CXX=yes + fi + else + lt_cv_prog_compiler_static_works_CXX=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then + : +else + lt_prog_compiler_static_CXX= +fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix[4-9]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global defined + # symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + export_symbols_cmds_CXX="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;/^.*[ ]__nm__/s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } +test "$ld_shlibs_CXX" = no && can_build_shared=no + +with_gnu_ld_CXX=$with_gnu_ld + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_CXX" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_CXX=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_CXX in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if test "${lt_cv_archive_cmds_need_lc_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_CXX + pic_flag=$lt_prog_compiler_pic_CXX + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_CXX + allow_undefined_flag_CXX= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc_CXX=no + else + lt_cv_archive_cmds_need_lc_CXX=yes + fi + allow_undefined_flag_CXX=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; } + archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib<name>.so + # instead of lib<name>.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[23].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +haiku*) + version_type=linux + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/beos/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if test "${lt_cv_shlibpath_overrides_runpath+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action_CXX= +if test -n "$hardcode_libdir_flag_spec_CXX" || + test -n "$runpath_var_CXX" || + test "X$hardcode_automatic_CXX" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct_CXX" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no && + test "$hardcode_minus_L_CXX" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_CXX=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_CXX=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_CXX=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 +$as_echo "$hardcode_action_CXX" >&6; } + +if test "$hardcode_action_CXX" = relink || + test "$inherit_rpath_CXX" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + + fi # test -n "$compiler" + + CC=$lt_save_CC + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + ac_config_commands="$ac_config_commands libtool" + + + + +# Only expand once: + + + + + +# Must be last +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error "conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + as_fn_error "conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${LINUX_LINKER_SCRIPT_TRUE}" && test -z "${LINUX_LINKER_SCRIPT_FALSE}"; then + as_fn_error "conditional \"LINUX_LINKER_SCRIPT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${MAC_LINKER_SCRIPT_TRUE}" && test -z "${MAC_LINKER_SCRIPT_FALSE}"; then + as_fn_error "conditional \"MAC_LINKER_SCRIPT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: ${CONFIG_STATUS=./config.status} +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error ERROR [LINENO LOG_FD] +# --------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with status $?, using 1 if that was 0. +as_fn_error () +{ + as_status=$?; test $as_status -eq 0 && as_status=1 + if test "$3"; then + as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + fi + $as_echo "$as_me: error: $1" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by Cilk Runtime Library $as_me 2.0, which was +generated by GNU Autoconf 2.64. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Configuration commands: +$config_commands + +Report bugs to <cilk@intel.com>." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_version="\\ +Cilk Runtime Library config.status 2.0 +configured by $0, generated by GNU Autoconf 2.64, + with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2009 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +srcdir="$srcdir" +host="$host" +target="$target" +with_multisubdir="$with_multisubdir" +with_multisrctop="$with_multisrctop" +with_target_subdir="$with_target_subdir" +ac_configure_args="${multilib_arg} ${ac_configure_args}" +multi_basedir="$multi_basedir" +CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} +CC="$CC" +CXX="$CXX" +GFORTRAN="$GFORTRAN" +GCJ="$GCJ" + + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' +macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' +enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' +enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' +pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' +SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' +ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' +host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' +host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' +host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' +build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' +build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' +build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' +SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' +Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' +GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' +EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' +FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' +LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' +NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' +LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' +ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' +exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' +lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' +reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' +AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' +STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' +RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' +lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' +CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' +compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' +GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' +objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' +need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' +LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' +OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' +libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' +module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_ld='`$ECHO "$hardcode_libdir_flag_spec_ld" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' +fix_srcfile_path='`$ECHO "$fix_srcfile_path" | $SED "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' +need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' +version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' +runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' +libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' +soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' +install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' +finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' +sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' +old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' +striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`' +predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`' +postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`' +predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`' +postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`' +LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`' +reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`' +reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' +compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`' +GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`' +archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' +module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' +with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' +no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_ld_CXX='`$ECHO "$hardcode_libdir_flag_spec_ld_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`' +inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`' +link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`' +fix_srcfile_path_CXX='`$ECHO "$fix_srcfile_path_CXX" | $SED "$delay_single_quote_subst"`' +always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`' +exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`' +include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`' +prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`' +file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`' +predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`' +postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`' +predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`' +postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in SHELL \ +ECHO \ +SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +OBJDUMP \ +deplibs_check_method \ +file_magic_cmd \ +AR \ +AR_FLAGS \ +STRIP \ +RANLIB \ +CC \ +CFLAGS \ +compiler \ +lt_cv_sys_global_symbol_pipe \ +lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_c_name_address \ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_wl \ +lt_prog_compiler_pic \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +DSYMUTIL \ +NMEDIT \ +LIPO \ +OTOOL \ +OTOOL64 \ +shrext_cmds \ +export_dynamic_flag_spec \ +whole_archive_flag_spec \ +compiler_needs_object \ +with_gnu_ld \ +allow_undefined_flag \ +no_undefined_flag \ +hardcode_libdir_flag_spec \ +hardcode_libdir_flag_spec_ld \ +hardcode_libdir_separator \ +fix_srcfile_path \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +install_override_mode \ +finish_eval \ +old_striplib \ +striplib \ +compiler_lib_search_dirs \ +predep_objects \ +postdep_objects \ +predeps \ +postdeps \ +compiler_lib_search_path \ +LD_CXX \ +reload_flag_CXX \ +compiler_CXX \ +lt_prog_compiler_no_builtin_flag_CXX \ +lt_prog_compiler_wl_CXX \ +lt_prog_compiler_pic_CXX \ +lt_prog_compiler_static_CXX \ +lt_cv_prog_compiler_c_o_CXX \ +export_dynamic_flag_spec_CXX \ +whole_archive_flag_spec_CXX \ +compiler_needs_object_CXX \ +with_gnu_ld_CXX \ +allow_undefined_flag_CXX \ +no_undefined_flag_CXX \ +hardcode_libdir_flag_spec_CXX \ +hardcode_libdir_flag_spec_ld_CXX \ +hardcode_libdir_separator_CXX \ +fix_srcfile_path_CXX \ +exclude_expsyms_CXX \ +include_expsyms_CXX \ +file_list_spec_CXX \ +compiler_lib_search_dirs_CXX \ +predep_objects_CXX \ +postdep_objects_CXX \ +predeps_CXX \ +postdeps_CXX \ +compiler_lib_search_path_CXX; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in reload_cmds \ +old_postinstall_cmds \ +old_postuninstall_cmds \ +old_archive_cmds \ +extract_expsyms_cmds \ +old_archive_from_new_cmds \ +old_archive_from_expsyms_cmds \ +archive_cmds \ +archive_expsym_cmds \ +module_cmds \ +module_expsym_cmds \ +export_symbols_cmds \ +prelink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +sys_lib_dlsearch_path_spec \ +reload_cmds_CXX \ +old_archive_cmds_CXX \ +old_archive_from_new_cmds_CXX \ +old_archive_from_expsyms_cmds_CXX \ +archive_cmds_CXX \ +archive_expsym_cmds_CXX \ +module_cmds_CXX \ +module_expsym_cmds_CXX \ +export_symbols_cmds_CXX \ +prelink_cmds_CXX; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +ac_aux_dir='$ac_aux_dir' +xsi_shell='$xsi_shell' +lt_shell_append='$lt_shell_append' + +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + + + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile' + + + + + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "default-1") CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + + *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5 + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\).*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\).*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' <conf$$subs.awk | sed ' +/^[^""]/{ + N + s/\n// +} +' >>$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ + || as_fn_error "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + + +eval set X " :F $CONFIG_FILES :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out" && rm -f "$tmp/out";; + *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + esac \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + ;; + + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir=$dirpart/$fdir; as_fn_mkdir_p + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} + ;; + "default-1":C) +# Only add multilib support code if we just rebuilt the top-level +# Makefile. +case " $CONFIG_FILES " in + *" Makefile "*) + ac_file=Makefile . ${multi_basedir}/config-ml.in + ;; +esac ;; + "libtool":C) + + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# The names of the tagged configurations supported by this script. +available_tags="CXX " + +# ### BEGIN LIBTOOL CONFIG + +# Which release of libtool.m4 was used? +macro_version=$macro_version +macro_revision=$macro_revision + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# What type of objects to build. +pic_mode=$pic_mode + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that protects backslashes. +ECHO=$lt_ECHO + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="\$SED -e 1s/^X//" + +# A grep program that handles long lines. +GREP=$lt_GREP + +# An ERE matcher. +EGREP=$lt_EGREP + +# A literal string matcher. +FGREP=$lt_FGREP + +# A BSD- or MS-compatible name lister. +NM=$lt_NM + +# Whether we need soft or hard links. +LN_S=$lt_LN_S + +# What is the maximum length of a command? +max_cmd_len=$max_cmd_len + +# Object file suffix (normally "o"). +objext=$ac_objext + +# Executable file suffix (normally ""). +exeext=$exeext + +# whether the shell understands "unset". +lt_unset=$lt_unset + +# turn spaces into newlines. +SP2NL=$lt_lt_SP2NL + +# turn newlines into spaces. +NL2SP=$lt_lt_NL2SP + +# An object symbol dumper. +OBJDUMP=$lt_OBJDUMP + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == "file_magic". +file_magic_cmd=$lt_file_magic_cmd + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A symbol stripping program. +STRIP=$lt_STRIP + +# Commands used to install an old-style archive. +RANLIB=$lt_RANLIB +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Whether to use a lock for old archive extraction. +lock_old_archive_extraction=$lock_old_archive_extraction + +# A C compiler. +LTCC=$lt_CC + +# LTCC compiler flags. +LTCFLAGS=$lt_CFLAGS + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration. +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair. +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=$MAGIC_CMD + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL=$lt_DSYMUTIL + +# Tool to change global to local symbols on Mac OS X. +NMEDIT=$lt_NMEDIT + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO=$lt_LIPO + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL=$lt_OTOOL + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64=$lt_OTOOL64 + +# Old archive suffix (normally "a"). +libext=$libext + +# Shared library suffix (normally ".so"). +shrext_cmds=$lt_shrext_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink=$lt_variables_saved_for_relink + +# Do we need the "lib" prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Library versioning type. +version_type=$version_type + +# Shared library runtime path variable. +runpath_var=$runpath_var + +# Shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Permission mode override for installation of shared libraries. +install_override_mode=$lt_install_override_mode + +# Command to use after installation of a shared archive. +postinstall_cmds=$lt_postinstall_cmds + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval=$lt_finish_eval + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Compile-time system search path for libraries. +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + + +# The linker used to build libraries. +LD=$lt_LD + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds + +# A language specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU compiler? +with_gcc=$GCC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# If ld is used when linking, flag to hardcode \$libdir into a binary +# during linking. This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects +postdep_objects=$lt_postdep_objects +predeps=$lt_predeps +postdeps=$lt_postdeps + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path + +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + +ltmain="$ac_aux_dir/ltmain.sh" + + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + case $xsi_shell in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac +} + +# func_basename file +func_basename () +{ + func_basename_result="${1##*/}" +} + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}" +} + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +func_stripname () +{ + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"} +} + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=${1%%=*} + func_opt_split_arg=${1#*=} +} + +# func_lo2o object +func_lo2o () +{ + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=${1%.*}.lo +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=$(( $* )) +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=${#1} +} + +_LT_EOF + ;; + *) # Bourne compatible functions. + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "${1}" | $SED "$basename"` +} + + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} + +# sed scripts: +my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q' +my_sed_long_arg='1s/^-[^=]*=//' + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=`$ECHO "${1}" | $SED "$my_sed_long_opt"` + func_opt_split_arg=`$ECHO "${1}" | $SED "$my_sed_long_arg"` +} + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "$@"` +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` +} + +_LT_EOF +esac + +case $lt_shell_append in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$1+=\$2" +} +_LT_EOF + ;; + *) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$1=\$$1\$2" +} + +_LT_EOF + ;; + esac + + + sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + + + cat <<_LT_EOF >> "$ofile" + +# ### BEGIN LIBTOOL TAG CONFIG: CXX + +# The linker used to build libraries. +LD=$lt_LD_CXX + +# How to create reloadable object files. +reload_flag=$lt_reload_flag_CXX +reload_cmds=$lt_reload_cmds_CXX + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds_CXX + +# A language specific compiler. +CC=$lt_compiler_CXX + +# Is the compiler the GNU compiler? +with_gcc=$GCC_CXX + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_CXX + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_CXX + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_CXX + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_CXX + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object_CXX + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds_CXX +archive_expsym_cmds=$lt_archive_expsym_cmds_CXX + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds_CXX +module_expsym_cmds=$lt_module_expsym_cmds_CXX + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld_CXX + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_CXX + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_CXX + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX + +# If ld is used when linking, flag to hardcode \$libdir into a binary +# during linking. This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute_CXX + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L_CXX + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic_CXX + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath_CXX + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_CXX + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path_CXX + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols_CXX + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_CXX + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_CXX + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_CXX + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds_CXX + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec_CXX + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_CXX + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects_CXX +postdep_objects=$lt_postdep_objects_CXX +predeps=$lt_predeps_CXX +postdeps=$lt_postdeps_CXX + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_CXX + +# ### END LIBTOOL TAG CONFIG: CXX +_LT_EOF + + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit $? +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/libcilkrts/configure.ac b/libcilkrts/configure.ac new file mode 100644 index 00000000000..9acdc11027e --- /dev/null +++ b/libcilkrts/configure.ac @@ -0,0 +1,148 @@ +# @copyright +# Copyright (C) 2011-2013, Intel Corporation +# All rights reserved. +# +# @copyright +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# @copyright +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY +# WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +AC_INIT([Cilk Runtime Library], [2.0], [cilk@intel.com]) +AC_PREREQ([2.64]) + +# Needed to define ${target}. Needs to be very early to avoid annoying +# warning about calling AC_ARG_PROGRAM before AC_CANONICAL_SYSTEM +AC_CANONICAL_SYSTEM +AM_INIT_AUTOMAKE(foreign no-dist) + +# Build a DLL on Windows +# AC_LIBTOOL_WIN32_DLL +AC_PROG_CXX +AC_PROG_CC +# AC_PROG_LIBTOOL +# AC_CONFIG_MACRO_DIR([..]) +AC_CONFIG_FILES([Makefile]) +AM_ENABLE_MULTILIB(, ..) + +# Get target configury. +. ${srcdir}/configure.tgt +if test -n "$UNSUPPORTED"; then + AC_MSG_ERROR([Configuration ${target} is unsupported.]) +fi + +if test "${multilib}" = "yes"; then + multilib_arg="--enable-multilib" +else + multilib_arg= +fi + +AC_MSG_CHECKING([for --enable-version-specific-runtime-libs]) +AC_ARG_ENABLE([version-specific-runtime-libs], + AC_HELP_STRING([--enable-version-specific-runtime-libs], + [Specify that runtime libraries should be installed in a compi +ler-specific directory]), + [case "$enableval" in + yes) enable_version_specific_runtime_libs=yes ;; + no) enable_version_specific_runtime_libs=no ;; + *) AC_MSG_ERROR([Unknown argument to enable/disable version-specific libs +]);; + esac], + [enable_version_specific_runtime_libs=no]) +AC_MSG_RESULT($enable_version_specific_runtime_libs) + + +# Calculate toolexeclibdir +# Also toolexecdir, though it's only used in toolexeclibdir +case ${enable_version_specific_runtime_libs} in + yes) + # Need the gcc compiler version to know where to install libraries + # and header files if --enable-version-specific-runtime-libs option + # is selected. + toolexecdir='$(libdir)/gcc/$(target_alias)' + toolexeclibdir='$(toolexecdir)/$(gcc_version)$(MULTISUBDIR)' + ;; + no) + if test -n "$with_cross_host" && + test x"$with_cross_host" != x"no"; then + # Install a library built with a cross compiler in tooldir, not libdir. + toolexecdir='$(exec_prefix)/$(target_alias)' + toolexeclibdir='$(toolexecdir)/lib' + else + toolexecdir='$(libdir)/gcc-lib/$(target_alias)' + toolexeclibdir='$(libdir)' + fi + multi_os_directory=`$CC -print-multi-os-directory` + case $multi_os_directory in + .) ;; # Avoid trailing /. + *) toolexeclibdir=$toolexeclibdir/$multi_os_directory ;; + esac + ;; +esac + +# Set config_dir based on the target. config_dir specifies where to get +# target-specific files. The generic implementation is incomplete, but +# contains information on what's needed +case "${target}" in + + x86_64-*-*) + config_dir="x86" + ;; + + i[456]86-*-*) + config_dir="x86" + ;; + + *) + config_dir="generic" + ;; + +esac +AC_SUBST(config_dir) + +# We have linker scripts for appropriate operating systems +linux_linker_script=no +case "${host}" in + *-*-linux*) + linux_linker_script=yes + ;; +esac +AM_CONDITIONAL(LINUX_LINKER_SCRIPT, test "$linux_linker_script" = "yes") + +mac_linker_script=no +case "${host}" in + *-*-apple*) + mac_linker_script=yes + ;; +esac +AM_CONDITIONAL(MAC_LINKER_SCRIPT, test "$mac_linker_script" = "yes") + +AM_PROG_LIBTOOL +AC_SUBST(toolexecdir) +AC_SUBST(toolexeclibdir) + +# Must be last +AC_OUTPUT diff --git a/libcilkrts/configure.tgt b/libcilkrts/configure.tgt new file mode 100644 index 00000000000..f7663521cda --- /dev/null +++ b/libcilkrts/configure.tgt @@ -0,0 +1,61 @@ +# @copyright +# Copyright (C) 2011-2013, Intel Corporation +# All rights reserved. +# +# @copyright +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# @copyright +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY +# WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +# Disable Cilk Runtime library for non x86 architecture...for now. +case "${target}" in + x86_64-*-*) + ;; + i?86-*-*) + ;; + *-*-*) + UNSUPPORTED=1 + ;; +esac + +# Disable libcilkrts on non POSIX hosted systems. +if test x$enable_libcilkrts = x ; then + # Enable libcilkrts by default on hosted POSIX systems. + case "${target}" in + *-*-linux* | *-*-gnu* | *-*-k*bsd*-gnu | *-*-kopensolaris*-gnu) + ;; + *-*-netbsd* | *-*-freebsd* | *-*-openbsd* | *-*-dragonfly*) + ;; + *-*-solaris2* | *-*-hpux11*) + ;; + *-*-darwin* | *-*-aix*) + ;; + *) + UNSUPPORTED=1 + ;; + esac +fi diff --git a/libcilkrts/include/cilk/cilk.h b/libcilkrts/include/cilk/cilk.h new file mode 100644 index 00000000000..2d0de0d293e --- /dev/null +++ b/libcilkrts/include/cilk/cilk.h @@ -0,0 +1,71 @@ +/* cilk.h -*-C++-*- + * + * @copyright + * Copyright (C) 2010-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file cilk.h + * + * @brief Provides convenient aliases for the Cilk language keywords. + * + * @details + * Since Cilk is a nonstandard extension to both C and C++, the Cilk + * language keywords all begin with “`_Cilk_`â€, which guarantees that they + * will not conflict with user-defined identifiers in properly written + * programs, so that “standard†C and C++ programs can safely be + * compiled a Cilk-enabled C or C++ compiler. + * + * However, this means that the keywords _look_ like something grafted on to + * the base language. Therefore, you can include this header: + * + * #include "cilk/cilk.h" + * + * and then write the Cilk keywords with a “`cilk_`†prefix instead of + * “`_Cilk_`â€. + * + * @ingroup language + */ + + +/** @defgroup language Language Keywords + * Definitions having to do with the Cilk language. + * @{ + */ + +#ifndef cilk_spawn +# define cilk_spawn _Cilk_spawn ///< Spawn a task that can execute in parallel. +# define cilk_sync _Cilk_sync ///< Wait for spawned tasks to complete. +# define cilk_for _Cilk_for ///< Execute iterations of a for loop in parallel. +#endif + +/// @} diff --git a/libcilkrts/include/cilk/cilk_api.h b/libcilkrts/include/cilk/cilk_api.h new file mode 100644 index 00000000000..a21687b7b32 --- /dev/null +++ b/libcilkrts/include/cilk/cilk_api.h @@ -0,0 +1,424 @@ +/* cilk_api.h + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file cilk_api.h + * + * @brief Defines the documented API exposed by the Cilk Plus for use + * by applications. + * + * @ingroup api + */ + +#ifndef INCLUDED_CILK_API_H +#define INCLUDED_CILK_API_H + +/** @defgroup api Runtime API + * API to allow user programs to interact with the Cilk runtime. + * @{ + */ + +#ifndef CILK_STUB /* Real (non-stub) definitions */ + +#if ! defined(__cilk) && ! defined(USE_CILK_API) +# ifdef _WIN32 +# error Cilk API is being used with non-Cilk compiler (or Cilk is disabled) +# else +# warning Cilk API is being used with non-Cilk compiler (or Cilk is disabled) +# endif +#endif + +#include <cilk/common.h> + +#ifdef __cplusplus +# include <cstddef> /* Defines size_t */ +#else +# include <stddef.h> /* Defines size_t */ +#endif + +#ifdef _WIN32 +# ifndef IN_CILK_RUNTIME +/* Ensure the library is brought if any of these functions are being called. */ +# pragma comment(lib, "cilkrts") +# endif + +# ifndef __cplusplus +# include <wchar.h> +# endif +#endif /* _WIN32 */ + +__CILKRTS_BEGIN_EXTERN_C + +/** Return values from __cilkrts_set_param() and __cilkrts_set_param_w() + */ +enum __cilkrts_set_param_status { + __CILKRTS_SET_PARAM_SUCCESS = 0, /**< Success - parameter set */ + __CILKRTS_SET_PARAM_UNIMP = 1, /**< Unimplemented parameter */ + __CILKRTS_SET_PARAM_XRANGE = 2, /**< Parameter value out of range */ + __CILKRTS_SET_PARAM_INVALID = 3, /**< Invalid parameter value */ + __CILKRTS_SET_PARAM_LATE = 4 /**< Too late to change parameter value */ +}; + +/** Set user controllable runtime parameters + * + * Call this function to set runtime parameters that control the behavior + * of the Cilk scheduler. + * + * @param param A string specifying the parameter to be set. One of: + * - `"nworkers"` + * - `"force reduce"` + * @param value A string specifying the parameter value. + * @returns A value from the @ref __cilkrts_set_param_status + * enumeration indicating the result of the operation. + * + * @par The "nworkers" parameter + * + * This parameter specifies the number of worker threads to be created by the + * Cilk runtime. @a Value must be a string of digits to be parsed by + * `strtol()`. + * + * The number of worker threads is: + * 1. the value set with `__cilkrts_set_param("nworkers")`, if it is + * positive; otherwise, + * 2. the value of the CILK_NWORKERS environment variable, if it is + * defined; otherwise + * 3. the number of cores available, as reported by the operating system. + * + * @note + * Technically, Cilk distinguishes between the _user thread_ (the thread that + * the user code was executing on when the Cilk runtime started), and + * _worker threads_ (new threads created by the Cilk runtime to support + * Cilk parallelism). `nworkers` actually includes both the user thread and + * the worker threads; that is, it is one greater than the number of true + * “worker threadsâ€. + * + * @note + * Setting `nworkers = 1` produces serial behavior. Cilk spawns and syncs will + * be executed, but with only one worker, continuations will never be stolen, + * so all code will execute in serial. + * + * @warning + * The number of worker threads can only be set *before* the runtime has + * started. Attempting to set it when the runtime is running will have no + * effect, and will return an error code. You can call __cilkrts_end_cilk() + * to shut down the runtime to change the number of workers. + * + * @warning + * The default Cilk scheduler behavior is usually pretty good. The ability + * to override `nworkers` can be useful for experimentation, but it won’t + * usually be necessary for getting good performance. + * + * @par The "force reduce" parameter + * + * This parameter controls whether the runtime should allocate a new view + * for a reducer for every parallel strand that it is accessed on. (See + * @ref pagereducers.) @a Value must be `"1"` or `"true"` to enable the + * “force reduce†behavior, or `"0"` or `"false"` to disable it. + * + * “Force reduce†behavior will also be enabled if + * `__cilkrts_set_param("force reduce")` is not called, but the + * `CILK_FORCE_REDUCE` environment variable is defined. + * + * @warning + * When this option is enabled, `nworkers` should be set to `1`. Using “force + * reduce†with more than one worker may result in runtime errors. + * + * @warning + * Enabling this option can significantly reduce performance. It should + * _only_ be used as a debugging tool. + */ +CILK_API(int) __cilkrts_set_param(const char *param, const char *value); + +#ifdef _WIN32 +/** + * Set user controllable parameters using wide strings + * + * @note This variant of __cilkrts_set_param() is only available + * on Windows. + * + * @copydetails __cilkrts_set_param + */ +CILK_API(int) __cilkrts_set_param_w(const wchar_t *param, const wchar_t *value); +#endif + +/** Shut down and deallocate all Cilk state. The runtime will abort the + * application if Cilk is still in use by this thread. Otherwise the runtime + * will wait for all other threads using Cilk to exit. + */ +CILK_API(void) __cilkrts_end_cilk(void); + +/** Initialize the Cilk data structures and start the runtime. + */ +CILK_API(void) __cilkrts_init(void); + +/** Return the runtime `nworkers` parameter. (See the discussion of `nworkers` + * in the documentation for __cilkrts_set_param().) + */ +CILK_API(int) __cilkrts_get_nworkers(void); + +/** Return the number of thread data structures. + * + * This function returns the number of data structures that has been allocated + * allocated by the runtime to hold information about user and worker threads. + * + * If you don’t already know what this is good for, then you probably don’t + * need it. + */ +CILK_API(int) __cilkrts_get_total_workers(void); + +/** What thread is the function running on? + * + * Return a small integer identifying the current thread. Each worker thread + * started by the Cilk runtime library has a unique worker number in the range + * `1 .. nworkers - 1`. + * + * All _user_ threads (threads started by the user, or by other libraries) are + * identified as worker number 0. Therefore, the worker number is not unique + * across multiple user threads. + */ +CILK_API(int) __cilkrts_get_worker_number(void); + +/** Test whether “force reduce†behavior is enabled. + * + * @return Non-zero if force-reduce mode is on, zero if it is off. + */ +CILK_API(int) __cilkrts_get_force_reduce(void); + +/** Interact with tools + */ +CILK_API(void) + __cilkrts_metacall(unsigned int tool, unsigned int code, void *data); + +#ifdef _WIN32 +/// Windows exception description record. +typedef struct _EXCEPTION_RECORD _EXCEPTION_RECORD; + +/** Function signature for Windows exception notification callbacks. + */ +typedef void (*__cilkrts_pfn_seh_callback)(const _EXCEPTION_RECORD *exception); + +/** Specify a function to call when a non-C++ exception is caught. + * + * Cilk Plus parallelism plays nicely with C++ exception handling, but the + * Cilk Plus runtime has no way to unwind the stack across a strand boundary + * for Microsoft SEH (“Structured Exception Handlingâ€) exceptions. Therefore, + * when the runtime catches such an exception, it must abort the application. + * + * If an SEH callback has been set, the runtime will call it before aborting. + * + * @param pfn A pointer to a callback function to be called before the + * runtime aborts the program because of an SEH exception. + */ +CILK_API(int) __cilkrts_set_seh_callback(__cilkrts_pfn_seh_callback pfn); +#endif /* _WIN32 */ + +#if __CILKRTS_ABI_VERSION >= 1 +/* Pedigree API is available only for compilers that use ABI version >= 1. */ + + +/** @name Pedigrees + */ +//@{ + +// @cond internal + +/** Support for __cilkrts_get_pedigree. + */ +CILK_API(__cilkrts_pedigree) +__cilkrts_get_pedigree_internal(__cilkrts_worker *w); + +/** Support for __cilkrts_bump_worker_rank. + */ +CILK_API(int) +__cilkrts_bump_worker_rank_internal(__cilkrts_worker* w); + +/// @endcond + + +/** Get the current pedigree, in a linked list representation. + * + * This routine returns a copy of the last node in the pedigree list. + * For example, if the current pedigree (in order) is <1, 2, 3, 4>, + * then this method returns a node with rank == 4, and whose parent + * field points to the node with rank of 3. In summary, following the + * nodes in the chain visits the terms of the pedigree in reverse. + * + * The returned node is guaranteed to be valid only until the caller + * of this routine has returned. + */ +__CILKRTS_INLINE +__cilkrts_pedigree __cilkrts_get_pedigree(void) +{ + return __cilkrts_get_pedigree_internal(__cilkrts_get_tls_worker()); +} + +/** Context used by __cilkrts_get_pedigree_info. + * + * @deprecated + * This data structure is only used by the deprecated + * __cilkrts_get_pedigree_info function. + * + * Callers should initialize the `data` array to NULL and set the `size` + * field to `sizeof(__cilkrts_pedigree_context_t)` before the first call + * to __cilkrts_get_pedigree_info(), and should not examine or modify it + * thereafter. + */ +typedef struct +{ + __STDNS size_t size; /**< Size of the struct in bytes */ + void *data[3]; /**< Opaque context data */ +} __cilkrts_pedigree_context_t; + +/** Get pedigree information. + * + * @deprecated + * Use __cilkrts_get_pedigree() instead. + * + * This routine allows code to walk up the stack of Cilk frames to gather + * the pedigree. + * + * Initialize the pedigree walk by filling the pedigree context with NULLs + * and setting the size field to sizeof(__cilkrts_pedigree_context). + * Other than initialization to NULL to start the walk, user coder should + * consider the pedigree context data opaque and should not examine or + * modify it. + * + * @returns 0 - Success - birthrank is valid + * @returns >0 - End of pedigree walk + * @returns -1 - Failure - No worker bound to thread + * @returns -2 - Failure - Sanity check failed, + * @returns -3 - Failure - Invalid context size + * @returns -4 - Failure - Internal error - walked off end of chain of frames + */ +CILK_API(int) +__cilkrts_get_pedigree_info(/* In/Out */ __cilkrts_pedigree_context_t *context, + /* Out */ uint64_t *sf_birthrank); + +/** Get the rank of the currently executing worker. + * + * @deprecated + * Use `__cilkrts_get_pedigree().rank` instead. + * + * @returns 0 - Success - *rank is valid + * @returns <0 - Failure - *rank is not changed + */ +CILK_EXPORT_AND_INLINE +int __cilkrts_get_worker_rank(uint64_t *rank) +{ + *rank = __cilkrts_get_pedigree().rank; + return 0; +} + +/** Increment the pedigree rank of the currently executing worker. + * + * @returns 0 - Success - rank was incremented + * @returns-1 - Failure + */ +CILK_EXPORT_AND_INLINE +int __cilkrts_bump_worker_rank(void) +{ + return __cilkrts_bump_worker_rank_internal(__cilkrts_get_tls_worker()); +} + +/** Increment the pedigree rank for a cilk_for loop. + * Obsolete. + * + * @deprecated + * This function was provided to allow the user to manipulate the pedigree + * rank of a `cilk_for` loop. The compiler now generates code to do that + * manipulation automatically, so this function is now unnecessary. It may + * be called, but will have no effect. + */ +CILK_EXPORT_AND_INLINE +int __cilkrts_bump_loop_rank(void) +{ + return 0; +} + +//@} + +#endif /* __CILKRTS_ABI_VERSION >= 1 */ + +__CILKRTS_END_EXTERN_C + +#else /* CILK_STUB */ + +// Programs compiled with CILK_STUB are not linked with the Cilk runtime +// library, so they should not have external references to runtime functions. +// Therefore, the functions are replaced with stubs. + +#ifdef _WIN32 +#define __cilkrts_set_param_w(name,value) ((value), 0) +#define __cilkrts_set_seh_callback(pfn) (0) +#endif +#define __cilkrts_set_param(name,value) ((value), 0) +#define __cilkrts_end_cilk() ((void) 0) +#define __cilkrts_init() ((void) 0) +#define __cilkrts_get_nworkers() (1) +#define __cilkrts_get_total_workers() (1) +#define __cilkrts_get_worker_number() (0) +#define __cilkrts_get_force_reduce() (0) +#define __cilkrts_metacall(tool,code,data) ((tool), (code), (data), 0) + +#if __CILKRTS_ABI_VERSION >= 1 +/* Pedigree stubs */ +#define __cilkrts_get_pedigree_info(context, sf_birthrank) (-1) +#define __cilkrts_get_worker_rank(rank) (*(rank) = 0) +#define __cilkrts_bump_worker_rank() (-1) +#define __cilkrts_bump_loop_rank() (-1) + +/* + * A stub method for __cilkrts_get_pedigree. + * Returns an empty __cilkrts_pedigree. + */ +__CILKRTS_INLINE +__cilkrts_pedigree __cilkrts_get_pedigree_stub(void) +{ + __cilkrts_pedigree ans; + ans.rank = 0; + ans.parent = NULL; + return ans; +} + +/* Renamed to an actual stub method. */ +#define __cilkrts_get_pedigree() __cilkrts_get_pedigree_stub() + +#endif /* __CILKRTS_ABI_VERSION >= 1 */ + +#endif /* CILK_STUB */ + +//@} + +#endif /* INCLUDED_CILK_API_H */ diff --git a/libcilkrts/include/cilk/cilk_api_linux.h b/libcilkrts/include/cilk/cilk_api_linux.h new file mode 100644 index 00000000000..ed9e70635f6 --- /dev/null +++ b/libcilkrts/include/cilk/cilk_api_linux.h @@ -0,0 +1,38 @@ +/* + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* THIS FILE IS DEPRECATED. USE cilk_api.h INSTEAD. */ +#include <cilk/cilk_api.h> diff --git a/libcilkrts/include/cilk/cilk_stub.h b/libcilkrts/include/cilk/cilk_stub.h new file mode 100644 index 00000000000..116e3ff5541 --- /dev/null +++ b/libcilkrts/include/cilk/cilk_stub.h @@ -0,0 +1,55 @@ +/* cilk_stub.h -*-C++-*- + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef INCLUDED_CILK_STUB_DOT_H +#define INCLUDED_CILK_STUB_DOT_H + +/* Definitions for creating a serialization from a Cilk program. + * These definitions are suitable for use by a compiler that is not + * Cilk-enabled. + */ + +/* Pretend we are a non-Cilk compiler */ +#undef __cilk +#define CILK_STUB + +/* Replace Cilk keywords with serial equivalents */ +#define _Cilk_spawn +#define _Cilk_sync +#define _Cilk_for for + +#endif /* ! defined(INCLUDED_CILK_STUB_DOT_H) */ diff --git a/libcilkrts/include/cilk/cilk_undocumented.h b/libcilkrts/include/cilk/cilk_undocumented.h new file mode 100644 index 00000000000..81cdd64bb89 --- /dev/null +++ b/libcilkrts/include/cilk/cilk_undocumented.h @@ -0,0 +1,131 @@ +/* + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + * + * cilk_undocumented.h + * + * This file defines exported functions that are not included in the standard + * documentation. + */ + +#ifndef INCLUDED_CILK_UNDOCUMENTED_H +#define INCLUDED_CILK_UNDOCUMENTED_H + +#include <cilk/common.h> + +#ifndef CILK_STUB + +__CILKRTS_BEGIN_EXTERN_C + +/* + * __cilkrts_synched + * + * Allows an application to determine if there are any outstanding children at + * this instant. This function will examine the current full frame to + * determine this. This function will return a valid result only when called + * within a spawn continuation, within the stack frame of the continuation + * itself. + */ + +CILK_EXPORT __CILKRTS_NOTHROW +int __cilkrts_synched(void); + +/* + * __cilkrts_cilkscreen_puts + * + * Allows an application to write a string to the Cilkscreen log. + * The standard error stream will be flushed after the write. + */ + +CILK_EXPORT __CILKRTS_NOTHROW +void __cilkrts_cilkscreen_puts(const char *); + +/* + * __cilkrts_get_sf + * + * A debugging aid that allows an application to get the __cilkrts_stack_frame + * for the current function. Only compiled into the DLL in debug builds. + */ + +CILK_EXPORT __CILKRTS_NOTHROW +void *__cilkrts_get_sf(void); + +/** + * Returns the size of stacks created by Cilk. + */ +CILK_EXPORT __CILKRTS_NOTHROW +size_t __cilkrts_get_stack_size(void); + +/** + * Dumps runtime statistics to stderr. + * Undocumented API for debugging. + */ +CILK_EXPORT __CILKRTS_NOTHROW +void __cilkrts_dump_stats(void); + +CILK_EXPORT __CILKRTS_NOTHROW +int __cilkrts_irml_version(void); + +struct __cilk_tbb_unwatch_thunk; +struct __cilk_tbb_stack_op_thunk; + +CILK_EXPORT __CILKRTS_NOTHROW +int __cilkrts_watch_stack(struct __cilk_tbb_unwatch_thunk *u, + struct __cilk_tbb_stack_op_thunk o); + +#ifndef IN_CILK_RUNTIME +#ifdef _WIN32 +/* Do not use CILK_API because __cilkrts_worker_stub must be __stdcall */ +CILK_EXPORT unsigned __CILKRTS_NOTHROW __stdcall +__cilkrts_worker_stub(void *arg); +#else +/* Do not use CILK_API because __cilkrts_worker_stub have default visibility */ +CILK_EXPORT void* __CILKRTS_NOTHROW +__cilkrts_worker_stub(void *arg); +#endif /* _WIN32 */ +#endif /* IN_CILK_RUNTIME */ + +__CILKRTS_END_EXTERN_C + +#else /* CILK_STUB */ + +/* Stubs for the api functions */ + +#define __cilkrts_get_stack_size() (0) +#define __cilkrts_synched() (1) + +#endif /* CILK_STUB */ + +#endif /* INCLUDED_CILK_UNDOCUMENTED_H */ diff --git a/libcilkrts/include/cilk/common.h b/libcilkrts/include/cilk/common.h new file mode 100644 index 00000000000..8ec19afa922 --- /dev/null +++ b/libcilkrts/include/cilk/common.h @@ -0,0 +1,376 @@ +/** common.h + * + * @copyright + * Copyright (C) 2010-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file common.h + * + * @brief Defines common macros and structures used by the Intel Cilk Plus + * runtime. + * + * @ingroup common + */ + +/** @defgroup common Common Definitions + * Macro, structure, and class definitions used elsewhere in the runtime. + * @{ + */ + +#ifndef INCLUDED_CILK_COMMON +#define INCLUDED_CILK_COMMON + +#ifdef __cplusplus +/** Namespace for all Cilk definitions that can be included in user code. + */ +namespace cilk { + + /** Namespace for definitions that are primarily intended for use + * in other Cilk definitions. + */ + namespace internal {} +} +#endif + +/** Cilk library version = 1.01 + */ +#define CILK_LIBRARY_VERSION 102 + +#ifdef __cplusplus +# include <cassert> +#else +# include <assert.h> +#endif + +/** + * Prefix standard library function and type names with __STDNS in order to + * get correct lookup in both C and C++. + */ +#ifdef __cplusplus +# define __STDNS std:: +#else +# define __STDNS +#endif + +/** + * @def CILK_EXPORT + * Define export of runtime functions from shared library. + * Should be exported only from cilkrts*.dll/cilkrts*.so + * @def CILK_EXPORT_DATA + * Define export of runtime data from shared library. + */ +#ifdef _WIN32 +# ifdef IN_CILK_RUNTIME +# define CILK_EXPORT __declspec(dllexport) +# define CILK_EXPORT_DATA __declspec(dllexport) +# else +# define CILK_EXPORT __declspec(dllimport) +# define CILK_EXPORT_DATA __declspec(dllimport) +# endif /* IN_CILK_RUNTIME */ +#elif defined(__CYGWIN__) || defined(__APPLE__) || defined(_DARWIN_C_SOURCE) +# define CILK_EXPORT /* nothing */ +# define CILK_EXPORT_DATA /* nothing */ +#else /* Unix/gcc */ +# ifdef IN_CILK_RUNTIME +# define CILK_EXPORT __attribute__((visibility("protected"))) +# define CILK_EXPORT_DATA __attribute__((visibility("protected"))) +# else +# define CILK_EXPORT /* nothing */ +# define CILK_EXPORT_DATA /* nothing */ +# endif /* IN_CILK_RUNTIME */ +#endif /* Unix/gcc */ + +/** + * @def __CILKRTS_BEGIN_EXTERN_C + * Macro to denote the start of a section in which all names have "C" linkage. + * That is, none of the names are to be mangled. + * @see __CILKRTS_END_EXTERN_C + * @see __CILKRTS_EXTERN_C + * + * @def __CILKRTS_END_EXTERN_C + * Macro to denote the end of a section in which all names have "C" linkage. + * That is, none of the names are to be mangled. + * @see __CILKRTS_BEGIN_EXTERN_C + * @see __CILKRTS_EXTERN_C + * + * @def __CILKRTS_EXTERN_C + * Macro to prefix a single definition which has "C" linkage. + * That is, the defined name is not to be mangled. + * @see __CILKRTS_BEGIN_EXTERN_C + * @see __CILKRTS_END_EXTERN_C + */ +#ifdef __cplusplus +# define __CILKRTS_BEGIN_EXTERN_C extern "C" { +# define __CILKRTS_END_EXTERN_C } +# define __CILKRTS_EXTERN_C extern "C" +#else +# define __CILKRTS_BEGIN_EXTERN_C +# define __CILKRTS_END_EXTERN_C +# define __CILKRTS_EXTERN_C +#endif + +/** + * OS-independent macro to specify a function which is known to not throw + * an exception. + */ +#ifdef __cplusplus +# ifdef _WIN32 +# define __CILKRTS_NOTHROW __declspec(nothrow) +# else /* Unix/gcc */ +# define __CILKRTS_NOTHROW __attribute__((nothrow)) +# endif /* Unix/gcc */ +#else +# define __CILKRTS_NOTHROW /* nothing */ +#endif /* __cplusplus */ + +/** Cache alignment. (Good enough for most architectures.) + */ +#define __CILKRTS_CACHE_LINE__ 64 + +/** + * Macro to specify alignment of a data member in a structure. + * Because of the way that gcc’s alignment attribute is defined, @a n must + * be a numeric literal, not just a compile-time constant expression. + */ +#ifdef _WIN32 +# define CILK_ALIGNAS(n) __declspec(align(n)) +#else /* Unix/gcc */ +# define CILK_ALIGNAS(n) __attribute__((__aligned__(n))) +#endif + +/** + * Macro to specify cache-line alignment of a data member in a structure. + */ +#define __CILKRTS_CACHE_ALIGN CILK_ALIGNAS(__CILKRTS_CACHE_LINE__) + +/** + * Macro to specify a class as being at least as strictly aligned as some + * type on Windows. gcc does not provide a way of doing this, so on Unix, + * this just specifies the largest natural type alignment. Put the macro + * between the `class` keyword and the class name: + * + * class CILK_ALIGNAS_TYPE(foo) bar { ... }; + */ +#ifdef _WIN32 +# define CILK_ALIGNAS_TYPE(t) __declspec(align(__alignof(t))) +#else /* Unix/gcc */ +# define CILK_ALIGNAS_TYPE(t) __attribute__((__aligned__)) +#endif + +/** + * @def CILK_API(RET_TYPE) + * A function called explicitly by the programmer. + * @def CILK_ABI(RET_TYPE) + * A function called by compiler-generated code. + * @def CILK_ABI_THROWS(RET_TYPE) + * An ABI function that may throw an exception + * + * Even when these are the same definitions, they should be separate macros so + * that they can be easily found in the code. + */ + +#ifdef _WIN32 +# define CILK_API(RET_TYPE) CILK_EXPORT RET_TYPE __CILKRTS_NOTHROW __cdecl +# define CILK_ABI(RET_TYPE) CILK_EXPORT RET_TYPE __CILKRTS_NOTHROW __cdecl +# define CILK_ABI_THROWS(RET_TYPE) CILK_EXPORT RET_TYPE __cdecl +#else +# define CILK_API(RET_TYPE) CILK_EXPORT RET_TYPE __CILKRTS_NOTHROW +# define CILK_ABI(RET_TYPE) CILK_EXPORT RET_TYPE __CILKRTS_NOTHROW +# define CILK_ABI_THROWS(RET_TYPE) CILK_EXPORT RET_TYPE +#endif + +/** + * __CILKRTS_ASSERT should be defined for debugging only, otherwise it + * interferes with vectorization. Since NDEBUG is not reliable (it must be + * set by the user), we must use a platform-specific detection of debug mode. + */ +#if defined(_WIN32) && defined(_DEBUG) + /* Windows debug */ +# define __CILKRTS_ASSERT(e) assert(e) +#elif (! defined(_WIN32)) && ! defined(__OPTIMIZE__) + /* Unix non-optimized */ +# define __CILKRTS_ASSERT(e) assert(e) +#elif defined __cplusplus + /* C++ non-debug */ +# define __CILKRTS_ASSERT(e) static_cast<void>(0) +#else + /* C non-debug */ +# define __CILKRTS_ASSERT(e) ((void) 0) +#endif + +/** + * OS-independent macro to specify a function that should be inlined + */ +#ifdef __cpluspus + // C++ +# define __CILKRTS_INLINE inline +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + // C99 +# define __CILKRTS_INLINE static inline +#elif defined(_MSC_VER) + // C89 on Windows +# define __CILKRTS_INLINE __inline +#else + // C89 on GCC-compatible systems +# define __CILKRTS_INLINE extern __inline__ +#endif + +/** + * Functions marked as CILK_EXPORT_AND_INLINE have both + * inline versions defined in the Cilk API, as well as + * non-inlined versions that are exported (for + * compatibility with previous versions that did not + * inline the functions). + */ +#ifdef COMPILING_CILK_API_FUNCTIONS +# define CILK_EXPORT_AND_INLINE CILK_EXPORT +#else +# define CILK_EXPORT_AND_INLINE __CILKRTS_INLINE +#endif + +/** + * Try to determine if compiler supports rvalue references. + */ +#if defined(__cplusplus) && !defined(__CILKRTS_RVALUE_REFERENCES) +# if __cplusplus >= 201103L // C++11 +# define __CILKRTS_RVALUE_REFERENCES 1 +# elif defined(__GXX_EXPERIMENTAL_CXX0X__) +# define __CILKRTS_RVALUE_REFERENCES 1 +# elif __cplusplus >= 199711L && __cplusplus < 201103L + // Compiler recognizes a language version prior to C++11 +# elif __INTEL_COMPILER == 1200 && defined(__STDC_HOSTED__) + // Intel compiler version 12.0 + // __cplusplus has a non-standard definition. In the absence of a + // proper definition, look for the C++0x macro, __STDC_HOSTED__. +# define __CILKRTS_RVALUE_REFERENCES 1 +# elif __INTEL_COMPILER > 1200 && defined(CHAR16T) + // Intel compiler version >= 12.1 + // __cplusplus has a non-standard definition. In the absence of a + // proper definition, look for the Intel macro, CHAR16T +# define __CILKRTS_RVALUE_REFERENCES 1 +# endif +#endif + +/* + * Include stdint.h to define the standard integer types. + * + * Unfortunately Microsoft doesn't provide stdint.h until Visual Studio 2010, + * so use our own definitions until those are available + */ + +#if ! defined(_MSC_VER) || (_MSC_VER >= 1600) +# include <stdint.h> +#else +# ifndef __MS_STDINT_TYPES_DEFINED__ +# define __MS_STDINT_TYPES_DEFINED__ + typedef signed char int8_t; + typedef short int16_t; + typedef int int32_t; + typedef __int64 int64_t; + + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + typedef unsigned __int64 uint64_t; +# endif /* __MS_STDINT_TYPES_DEFINED__ */ +#endif /* ! defined(_MSC_VER) || (_MSC_VER >= 1600) */ + +/** + * @brief Application Binary Interface version of the Cilk runtime library. + * + * The ABI version is determined by the compiler used. An object file + * compiled with a higher ABI version is not compatible with a library that is + * compiled with a lower ABI version. An object file compiled with a lower + * ABI version, however, can be used with a library compiled with a higher ABI + * version unless otherwise stated. + */ +#ifndef __CILKRTS_ABI_VERSION +# ifdef IN_CILK_RUNTIME +# define __CILKRTS_ABI_VERSION 1 +# elif __INTEL_COMPILER > 1200 + // Intel compiler version >= 12.1 +# define __CILKRTS_ABI_VERSION 1 +# else + // Compiler does not support ABI version 1 + // (Non-Intel compiler or Intel compiler prior to version 12.1). +# define __CILKRTS_ABI_VERSION 0 +# endif +#endif + +// These structs are exported because the inlining of +// the internal version of API methods require a worker +// structure as parameter. +__CILKRTS_BEGIN_EXTERN_C + /// Worker struct, exported for inlined API methods + /// @ingroup api + struct __cilkrts_worker; + + /// Worker struct, exported for inlined API methods + /// @ingroup api + typedef struct __cilkrts_worker __cilkrts_worker; + + /// Worker struct pointer, exported for inlined API methods + /// @ingroup api + typedef struct __cilkrts_worker *__cilkrts_worker_ptr; + + + /// Fetch the worker out of TLS. + CILK_ABI(__cilkrts_worker_ptr) __cilkrts_get_tls_worker(void); + + /// void *, defined to work around complaints from the compiler + /// about using __declspec(nothrow) after the "void *" return type + typedef void * __cilkrts_void_ptr; + +__CILKRTS_END_EXTERN_C + + +#if __CILKRTS_ABI_VERSION >= 1 +// Pedigree API is available only for compilers that use ABI version >= 1. + +/** Pedigree information kept in the worker and stack frame. + * @ingroup api + */ +typedef struct __cilkrts_pedigree +{ + /** Rank at start of spawn helper. Saved rank for spawning functions */ + uint64_t rank; + + /** Link to next in chain */ + const struct __cilkrts_pedigree *parent; +} __cilkrts_pedigree; + +#endif // __CILKRTS_ABI_VERSION >= 1 + +/// @} + +#endif /* INCLUDED_CILK_COMMON */ diff --git a/libcilkrts/include/cilk/holder.h b/libcilkrts/include/cilk/holder.h new file mode 100644 index 00000000000..8620c052f53 --- /dev/null +++ b/libcilkrts/include/cilk/holder.h @@ -0,0 +1,1000 @@ +/* + * @copyright + * Copyright (C) 2011-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * holder.h + * + * Purpose: hyperobject to provide different views of an object to each + * parallel strand. + */ + +#ifndef HOLDER_H_INCLUDED +#define HOLDER_H_INCLUDED + +#include <cilk/reducer.h> +#include <memory> +#include <utility> + +#ifdef __cplusplus + +/* C++ Interface + * + * Classes: holder<Type> + * + * Description: + * ============ + * This component provides a hyperobject that isolates a parallel uses of a + * common variable where it is not necessary to preserve changes from + * different parallel strands. In effect, a holder acts a bit like + * thread-local storage, but has qualities that work better with the + * fork-join structure of Cilk. In particular, a holder has the following + * qualities: + * + * - The view of a holder before the first spawn within a function is the same + * as the view after each sync (as in the case of a reducer). + * - The view of a holder within the first spawned child of a function (or the + * first child spawned after a sync) is the same as the view on entry to the + * function. + * - The view of a holder before entering a _Cilk_for loop is the same as the + * view during the first iteration of the loop and the view at the end of + * the loop. + * - The view of a holder in the continuation of a spawn or in an arbitrary + * iteration of a _Cilk_for loop is *non-deterministic*. It is generally + * recommended that the holder be explicitly put into a known state in these + * situations. + * + * A holder can be used as an alternative to parameter-passing. They are most + * useful for replacing non-local variables without massive refactoring. A + * holder takes advantage of the fact that, most of the time, a holder view + * does not change after a spawn or from one iteration of a parallel for loop + * to the next (i.e., stealing is the exception, not the rule). When the + * holder view is a large object that is expensive to construct, this + * optimization can save significant time versus creating a separate local + * object for each view. In addition, a holder using the "keep last" policy + * will have the same value after a sync as the serialization of the same + * program. The last quality will often allow the program to avoid + * recomputing a value. + * + * Usage Example: + * ============== + * Function 'compute()' is a complex function that computes a value using a + * memoized algorithm, storing intermediate results in a hash table. Compute + * calls several other functions, each of which calls several other functions, + * all of which share a global hash table. In all, there are over a dozen + * functions with a total of about 60 references to the hash table. + *.. + * hash_table<int, X> memos; + * + * void h(const X& x); // Uses memos + * + * double compute(const X& x) + * { + * memos.clear(); + * // ... + * memos[i] = x; + * ... + * g(i); // Uses memos + * // ... + * std::for_each(c.begin(), c.end(), h); // Call h for each element of c + * } + * + * int main() + * { + * const std::size_t ARRAY_SIZE = 1000000; + * extern X myArray[ARRAY_SIZE]; + * + * for (std::size_t i = 0; i < ARRAY_SIZE; ++i) + * { + * compute(myArray[i]); + * } + * } + *.. + * We would like to replace the 'for' loop in 'main' with a 'cilk_for'. + * Although the hash table is cleared on entry to each call to 'compute()', + * and although the values stored in the hash table are no longer used after + * 'compute()' returns, the use of the hash table as a global variable + * prevents 'compute()' from being called safely in parallel. One way to do + * this would be to make 'memos' a private variable within the cilk_for loop + * and pass it down to the actual computation, so that each loop iteration has + * its own private copy: + *.. + * cilk_for (std::size_t i = 0; i < ARRAY_SIZE; ++i) + * { + * hash_table<int, X> memos; + * compute(myArray[i], memos); + * } + *.. + * The problem with this approach is that it requires changing the signature + * of 'compute', 'h', 'g', and every one of the dozen or so functions that + * reference 'memos' as well as any function that calls those functions. This + * may break the abstraction of 'compute' and other functions, exposing an + * implementation detail that was not part of the interface. In addition, the + * function 'h' is called through a templated algorithm, 'for_each', which + * requires a fixed interface. Finally, there is constructor and destructor + * overhead for 'hash_table' each time through the loop. + * + * The alternative approach is to replace 'memos' with a holder. The holder + * would be available to all of the functions involved, but would not cause a + * race between parallel loop iterations. In order to make this work, each + * use of the 'memos' variable must be (mechanically) replaced by a use of the + * holder: + *.. + * cilk::holder<hash_table<int, X> > memos_h; + * + * void h(const X& x); // Uses memos_h + * + * double compute(const X& x) + * { + * memos_h().clear(); // operator() used to "dereference" the holder + * // ... + * memos_h()[i] = x; // operator() used to "dereference" the holder + * ... + * g(i); // Uses memos_h + * // ... + * std::for_each(c.begin(), c.end(), h); // Call h for each element of c + * } + *.. + * Note that each reference to the holder must be modified with an empty pair + * of parenthesis. This syntax is needed because there is no facility in C++ + * for a "smart reference" that would allow 'memos_h' to be a perfect + * replacement for 'memos'. One way that a user can avoid this syntax change + * is to wrap the holder in a class that has the same inteface as + * 'hash_table' but redirects all calls to the holder: + *.. + * template <typename K, typename V> + * class hash_table_holder + * { + * private: + * cilk::holder<hash_table<K, V> > m_holder; + * public: + * void clear() { m_holder().clear(); } + * V& operator[](const K& x) { return m_holder()[x]; } + * std::size_t size() const { return m_holder().size(); } + * // etc. ... + * }; + *.. + * Using the above wrapper, the original code can be left unchanged except for + * replacing 'hash_table' with 'hash_table_holder' and replacing 'for' with + * 'cilk_for': + *.. + * hash_table_holder<int, X> memos; + * + * void h(const X& x); // Uses memos + * + * double compute(const X& x) + * { + * memos.clear(); // Calls hash_table_holder::clear(). + * // ... + * } + *.. + * The above changes have no benefit over the use of thread-local storage. + * What if one of the functions has a 'cilk_spawn', however? + *.. + * void h(const X& x) + * { + * Y y = x.nested(); + * double d, w; + * if (y) + * { + * w = cilk_spawn compute_width(y); // May use 'memos' + * d = compute_depth(y); // Does not use 'memos' + * cilk_sync; + * compute(y); // recursive call. Uses 'memos'. + * } + * } + *.. + * In the above example, the view of the holder within 'compute_width' is the + * same as the view on entry to 'h'. More importantly, the view of the holder + * within the recursive call to 'compute' is the same as the view on entry to + * 'h', even if a different worker is executing the recursive call. Thus, the + * holder view within a Cilk program has useful qualities not found in + * thread-local storage. + */ + +namespace cilk { + + /** + * After a sync, the value stored in a holder matches the most recent + * value stored into the holder by one of the starnds entering the sync. + * The holder policy used to instantiate the holder determines which of + * the entering strands determines the final value of the holder. A policy + * of 'holder_keep_indeterminate' (the default) is the most efficient, and + * results in an indeterminate value depending on the runtime schedule + * (see below for more specifics). An indeterminate value after a sync is + * often acceptable, especially if the value of the holder is not reused + * after the sync. All of the remaining policies retain the value of the + * last strand that would be executed in the serialization of the program. + * They differ in the mechanism used to move the value from one view to + * another. A policy of 'holder_keep_last_copy' moves values by + * copy-assignment. A policy of 'holder_keep_last_swap' moves values by + * calling 'swap'. A policy of 'holder_keep_last_move' is available only + * for compilers that support C++0x rvalue references and moves values by + * move-assignment. A policy of 'holder_keep_last' attempts to choose the + * most efficient mechanism: member-function 'swap' if the view type + * supports it, otherwise move-assignment if supported, otherwise + * copy-assignment. (The swap member function for a class that provides + * one is almost always as fast or faster than move-assignment or + * copy-assignment.) + * + * The behavior of 'holder_keep_indeterminate', while indeterminate, is + * not random and can be used for advanced programming or debugging. With + * a policy of 'holder_keep_intermediate', values are never copied or + * moved between views. The value of the view after a sync is the same as + * the value set in the last spawned child before a steal occurs or the + * last value set in the continuation if no steal occurs. Using this + * knowledge, a programmer can use a holder to detect the earliest steal + * in a piece of code. An indeterminate holder is also useful for keeping + * cached data similar to the way some applications might use thread-local + * storage. + */ + enum holder_policy { + holder_keep_indeterminate, + holder_keep_last, + holder_keep_last_copy, + holder_keep_last_swap, +#ifdef __CILKRTS_RVALUE_REFERENCES + holder_keep_last_move +#endif + }; + + namespace internal { + + // Private special-case holder policy using the swap member-function + const holder_policy holder_keep_last_member_swap = + (holder_policy) (holder_keep_last_swap | 0x10); + + /* The constant, 'has_member_swap<T>::value', will be 'true' if 'T' + * has a non-static member function with prototype 'void swap(T&)'. + * The mechanism used to detect 'swap' is the most portable among + * present-day compilers, but is not the most robust. Specifically, + * the prototype for 'swap' must exactly match 'void swap(T&)'. + * Near-matches like a 'swap' function that returns 'int' instead of + * 'void' will not be detected. Detection will also fail if 'T' + * inherits 'swap' from a base class. + */ + template <typename T> + class has_member_swap + { + // This technique for detecting member functions was described by + // Rani Sharoni in comp.lang.c++.moderated: + // http://groups.google.com/group/comp.lang.c++.moderated/msg/2b06b2432fddfb60 + + // sizeof(notchar) is guaranteed larger than 1 + struct notchar { char x[2]; }; + + // Instantiationg Q<U, &U::swap> will fail unless U contains a + // non-static member with prototype 'void swap(U&)'. + template <class U, void (U::*)(U&)> struct Q { }; + + // First 'test' is preferred overload if U::swap exists with the + // correct prototype. Second 'test' is preferred overload + // otherwise. + template <typename U> static char test(Q<U,&U::swap>*); + template <typename U> static notchar test(...); + + public: + /// 'value' will be true if T has a non-static member function + /// with prototype 'void swap(T&)'. + static const bool value = (1 == sizeof(test<T>(0))); + }; + + template <typename T> const bool has_member_swap<T>::value; + + /** + * @brief Utility class for exception safety. + * + * The constuctor for this class takes a pointer and an allocator and + * holds on to them. The destructor deallocates the pointed-to + * object, without calling its destructor, typically to recover memory + * in case an exception is thrown. The release member clears the + * pointer so that the deallocation is prevented, i.e., when the + * exception danger has passed. The behavior of this class is similar + * to auto_ptr and unique_ptr. + */ + template <typename Type, typename Allocator = std::allocator<Type> > + class auto_deallocator + { + Allocator m_alloc; + Type* m_ptr; + + // Non-copiable + auto_deallocator(const auto_deallocator&); + auto_deallocator& operator=(const auto_deallocator&); + + public: + /// Constructor + explicit auto_deallocator(Type* p, const Allocator& a = Allocator()) + : m_alloc(a), m_ptr(p) { } + + /// Destructor - free allocated resources + ~auto_deallocator() { if (m_ptr) m_alloc.deallocate(m_ptr, 1); } + + /// Remove reference to resource + void release() { m_ptr = 0; } + }; + + /** + * Pure-abstract base class to initialize holder views + */ + template <typename Type, typename Allocator> + class init_base + { + public: + virtual ~init_base() { } + virtual init_base* clone_self(Allocator& a) const = 0; + virtual void delete_self(Allocator& a) = 0; + virtual void construct_view(Type* p, Allocator& a) const = 0; + }; + + /** + * Class to default-initialize a holder view + */ + template <typename Type, typename Allocator> + class default_init : public init_base<Type, Allocator> + { + typedef init_base<Type, Allocator> base; + + /// Private constructor (called from static make() function). + default_init() { } + + // Non-copiable + default_init(const default_init&); + default_init& operator=(const default_init&); + + public: + // Static factory function + static default_init* make(Allocator& a); + + // Virtual function overrides + virtual ~default_init(); + virtual base* clone_self(Allocator& a) const; + virtual void delete_self(Allocator& a); + virtual void construct_view(Type* p, Allocator& a) const; + }; + + template <typename Type, typename Allocator> + default_init<Type, Allocator>* + default_init<Type, Allocator>::make(Allocator&) + { + // Return a pointer to a singleton. All instances of this class + // are identical, so we need only one. + static default_init self; + return &self; + } + + template <typename Type, typename Allocator> + default_init<Type, Allocator>::~default_init() + { + } + + template <typename Type, typename Allocator> + init_base<Type, Allocator>* + default_init<Type, Allocator>::clone_self(Allocator& a) const + { + return make(a); + } + + template <typename Type, typename Allocator> + void default_init<Type, Allocator>::delete_self(Allocator&) + { + // Since make() returned a shared singleton, there is nothing to + // delete here. + } + + template <typename Type, typename Allocator> + void + default_init<Type, Allocator>::construct_view(Type* p, + Allocator&) const + { + ::new((void*) p) Type(); + // TBD: In a C++0x library, this should be rewritten + // std::allocator_traits<Allocator>::construct(a, p); + } + + /** + * Class to copy-construct a view from a stored exemplar. + */ + template <typename Type, typename Allocator> + class exemplar_init : public init_base<Type, Allocator> + { + typedef init_base<Type, Allocator> base; + + Type* m_exemplar; + + // Private constructors (called from make() functions). + exemplar_init(const Type& val, Allocator& a); +#ifdef __CILKRTS_RVALUE_REFERENCES + exemplar_init(Type&& val, Allocator& a); +#endif + + // Non-copyiable + exemplar_init(const exemplar_init&); + exemplar_init& operator=(const exemplar_init&); + + public: + // Static factory functions + static exemplar_init* make(const Type& val, + Allocator& a = Allocator()); +#ifdef __CILKRTS_RVALUE_REFERENCES + static exemplar_init* make(Type&& val, + Allocator& a = Allocator()); +#endif + + // Virtual function overrides + virtual ~exemplar_init(); + virtual base* clone_self(Allocator& a) const; + virtual void delete_self(Allocator& a); + virtual void construct_view(Type* p, Allocator& a) const; + }; + + template <typename Type, typename Allocator> + exemplar_init<Type, Allocator>::exemplar_init(const Type& val, + Allocator& a) + { + m_exemplar = a.allocate(1); + auto_deallocator<Type, Allocator> guard(m_exemplar, a); + a.construct(m_exemplar, val); + guard.release(); + } + +#ifdef __CILKRTS_RVALUE_REFERENCES + template <typename Type, typename Allocator> + exemplar_init<Type, Allocator>::exemplar_init(Type&& val, + Allocator& a) + { + m_exemplar = a.allocate(1); + auto_deallocator<Type, Allocator> guard(m_exemplar, a); + a.construct(m_exemplar, std::forward<Type>(val)); + guard.release(); + } +#endif + + template <typename Type, typename Allocator> + exemplar_init<Type, Allocator>* + exemplar_init<Type, Allocator>::make(const Type& val, + Allocator& a) + { + typedef typename Allocator::template rebind<exemplar_init>::other + self_alloc_t; + self_alloc_t alloc(a); + + exemplar_init *self = alloc.allocate(1); + auto_deallocator<exemplar_init, self_alloc_t> guard(self, alloc); + + // Don't use allocator to construct self. Allocator should be + // used only on elements of type 'Type'. + ::new((void*) self) exemplar_init(val, a); + + guard.release(); + + return self; + } + +#ifdef __CILKRTS_RVALUE_REFERENCES + template <typename Type, typename Allocator> + exemplar_init<Type, Allocator>* + exemplar_init<Type, Allocator>::make(Type&& val, + Allocator& a) + { + typedef typename Allocator::template rebind<exemplar_init>::other + self_alloc_t; + self_alloc_t alloc(a); + + exemplar_init *self = alloc.allocate(1); + auto_deallocator<exemplar_init, self_alloc_t> guard(self, alloc); + + // Don't use allocator to construct self. Allocator should be + // used only on elements of type 'Type'. + ::new((void*) self) exemplar_init(std::forward<Type>(val), a); + + guard.release(); + + return self; + } +#endif + + template <typename Type, typename Allocator> + exemplar_init<Type, Allocator>::~exemplar_init() + { + // Called only by delete_self, which deleted the exemplar using an + // allocator. + __CILKRTS_ASSERT(0 == m_exemplar); + } + + template <typename Type, typename Allocator> + init_base<Type, Allocator>* + exemplar_init<Type, Allocator>::clone_self(Allocator& a) const + { + return make(*m_exemplar, a); + } + + template <typename Type, typename Allocator> + void exemplar_init<Type, Allocator>::delete_self(Allocator& a) + { + typename Allocator::template rebind<exemplar_init>::other alloc(a); + + a.destroy(m_exemplar); + a.deallocate(m_exemplar, 1); + m_exemplar = 0; + + this->~exemplar_init(); + alloc.deallocate(this, 1); + } + + template <typename Type, typename Allocator> + void + exemplar_init<Type, Allocator>::construct_view(Type* p, + Allocator& a) const + { + a.construct(p, *m_exemplar); + // TBD: In a C++0x library, this should be rewritten + // std::allocator_traits<Allocator>::construct(a, p, *m_exemplar); + } + + /** + * Class to construct a view using a stored functor. The functor, + * 'f', must be be invokable using the expression 'Type x = f()'. + */ + template <typename Func, typename Allocator> + class functor_init : + public init_base<typename Allocator::value_type, Allocator> + { + typedef typename Allocator::value_type value_type; + typedef init_base<value_type, Allocator> base; + typedef typename Allocator::template rebind<Func>::other f_alloc; + + Func *m_functor; + + /// Private constructors (called from make() functions + functor_init(const Func& f, Allocator& a); +#ifdef __CILKRTS_RVALUE_REFERENCES + functor_init(Func&& f, Allocator& a); +#endif + + // Non-copiable + functor_init(const functor_init&); + functor_init& operator=(const functor_init&); + + public: + // Static factory functions + static functor_init* make(const Func& val, + Allocator& a = Allocator()); +#ifdef __CILKRTS_RVALUE_REFERENCES + static functor_init* make(Func&& val, + Allocator& a = Allocator()); +#endif + + // Virtual function overrides + virtual ~functor_init(); + virtual base* clone_self(Allocator& a) const; + virtual void delete_self(Allocator& a); + virtual void + construct_view(value_type* p, Allocator& a) const; + }; + + /// Specialization to strip off reference from 'Func&'. + template <typename Func, typename Allocator> + struct functor_init<Func&, Allocator> + : functor_init<Func, Allocator> { }; + + /// Specialization to strip off reference and cvq from 'const Func&'. + template <typename Func, typename Allocator> + struct functor_init<const Func&, Allocator> + : functor_init<Func, Allocator> { }; + + template <typename Func, typename Allocator> + functor_init<Func, Allocator>::functor_init(const Func& f, + Allocator& a) + { + f_alloc alloc(a); + + m_functor = alloc.allocate(1); + auto_deallocator<Func, f_alloc> guard(m_functor, alloc); + alloc.construct(m_functor, f); + guard.release(); + } + +#ifdef __CILKRTS_RVALUE_REFERENCES + template <typename Func, typename Allocator> + functor_init<Func, Allocator>::functor_init(Func&& f, + Allocator& a) + { + f_alloc alloc(a); + + m_functor = alloc.allocate(1); + auto_deallocator<Func, f_alloc> guard(m_functor, alloc); + alloc.construct(m_functor, std::forward<Func>(f)); + guard.release(); + } +#endif + + template <typename Func, typename Allocator> + functor_init<Func, Allocator>* + functor_init<Func, Allocator>::make(const Func& f, Allocator& a) + { + typedef typename Allocator::template rebind<functor_init>::other + self_alloc_t; + self_alloc_t alloc(a); + + functor_init *self = alloc.allocate(1); + auto_deallocator<functor_init, self_alloc_t> guard(self, alloc); + + // Don't use allocator to construct self. Allocator should be + // used only on elements of type 'Func'. + ::new((void*) self) functor_init(f, a); + + guard.release(); + + return self; + } + +#ifdef __CILKRTS_RVALUE_REFERENCES + template <typename Func, typename Allocator> + functor_init<Func, Allocator>* + functor_init<Func, Allocator>::make(Func&& f, Allocator& a) + { + typedef typename Allocator::template rebind<functor_init>::other + self_alloc_t; + self_alloc_t alloc(a); + + functor_init *self = alloc.allocate(1); + auto_deallocator<functor_init, self_alloc_t> guard(self, alloc); + + // Don't use allocator to construct self. Allocator should be + // used only on elements of type 'Func'. + ::new((void*) self) functor_init(std::forward<Func>(f), a); + + guard.release(); + + return self; + } +#endif + + template <typename Func, typename Allocator> + functor_init<Func, Allocator>::~functor_init() + { + // Called only by delete_self, which deleted the functor using an + // allocator. + __CILKRTS_ASSERT(0 == m_functor); + } + + template <typename Func, typename Allocator> + init_base<typename Allocator::value_type, Allocator>* + functor_init<Func, Allocator>::clone_self(Allocator& a) const + { + return make(*m_functor, a); + } + + template <typename Func, typename Allocator> + inline + void functor_init<Func, Allocator>::delete_self(Allocator& a) + { + typename Allocator::template rebind<functor_init>::other alloc(a); + f_alloc fa(a); + + fa.destroy(m_functor); + fa.deallocate(m_functor, 1); + m_functor = 0; + + this->~functor_init(); + alloc.deallocate(this, 1); + } + + template <typename Func, typename Allocator> + void functor_init<Func, Allocator>::construct_view(value_type* p, + Allocator& a) const + { + a.construct(p, (*m_functor)()); + // In C++0x, the above should be written + // std::allocator_traits<Allocator>::construct(a, p, m_functor()); + } + + /** + * Functor called to reduce a holder + */ + template <typename Type, holder_policy Policy> + struct holder_reduce_functor; + + /** + * Specialization to keep the left (first) value. + */ + template <typename Type> + struct holder_reduce_functor<Type, holder_keep_indeterminate> + { + void operator()(Type* left, Type* right) const { } + }; + + /** + * Specialization to copy-assign from the right (last) value. + */ + template <typename Type> + struct holder_reduce_functor<Type, holder_keep_last_copy> + { + void operator()(Type* left, Type* right) const { + *left = *right; + } + }; + + /* + * Specialization to keep the right (last) value via swap. + */ + template <typename Type> + struct holder_reduce_functor<Type, holder_keep_last_swap> + { + void operator()(Type* left, Type* right) const { + using std::swap; + swap(*left, *right); + } + }; + +#ifdef __CILKRTS_RVALUE_REFERENCES + /* + * Specialization to move-assign from the right (last) value. + */ + template <typename Type> + struct holder_reduce_functor<Type, holder_keep_last_move> + { + void operator()(Type* left, Type* right) const { + *left = std::move(*right); + } + }; +#endif + + /* + * Specialization to keep the right (last) value via the swap member + * function. + */ + template <typename Type> + struct holder_reduce_functor<Type, holder_keep_last_member_swap> + { + void operator()(Type* left, Type* right) const { + left->swap(*right); + } + }; + + /* + * Specialization to keep the right (last) value by the most efficient + * means detectable. + */ + template <typename Type> + struct holder_reduce_functor<Type, holder_keep_last> : + holder_reduce_functor<Type, + (holder_policy) + (has_member_swap<Type>::value ? + holder_keep_last_member_swap : +#ifdef __CILKRTS_RVALUE_REFERENCES + holder_keep_last_move +#else + holder_keep_last_copy +#endif + )> + { + }; + } // end namespace internal + + /** + * Monoid for holders. + * Allocator type is required to be thread-safe. + */ + template <typename Type, + holder_policy Policy = holder_keep_indeterminate, + typename Allocator = std::allocator<Type> > + class holder_monoid : public monoid_base<Type> + { + // Allocator is mutable because the copy of the monoid inside the + // reducer is const (to avoid races on the shared state). However, + // the allocator is required to be thread-safe, so it is ok (and + // necessary) to modify. + mutable Allocator m_allocator; + internal::init_base<Type, Allocator> *m_initializer; + + public: + /// This constructor uses default-initialization for both the leftmost + /// view and each identity view. + holder_monoid(const Allocator& a = Allocator()) + : m_allocator(a) + , m_initializer( + internal::default_init<Type, Allocator>::make(m_allocator)) + { } + + /// These constructors use 'val' as an exemplar to copy-construct both + /// the leftmost view and each identity view. + holder_monoid(const Type& val, const Allocator& a = Allocator()) + : m_allocator(a) + , m_initializer(internal::exemplar_init<Type, Allocator>::make( + val, m_allocator)) { } + /// This constructor uses 'f' as a functor to construct both + /// the leftmost view and each identity view. + template <typename Func> + holder_monoid(const Func& f, const Allocator& a = Allocator()) + : m_allocator(a) + , m_initializer( + internal::functor_init<Func, Allocator>::make(f,m_allocator)) + { } + + /// Copy constructor + holder_monoid(const holder_monoid& rhs) + : m_allocator(rhs.m_allocator) + , m_initializer(rhs.m_initializer->clone_self(m_allocator)) { } + + /// "Extended" copy constructor with allocator + holder_monoid(const holder_monoid& rhs, const Allocator& a) + : m_allocator(a) + , m_initializer(rhs.m_initializer->clone_self(m_allocator)) { } + +#ifdef __CILKRTS_RVALUE_REFERENCES + /// Move constructor + holder_monoid(holder_monoid&& rhs) + : m_allocator(rhs.m_allocator) + , m_initializer(rhs.m_initializer) { + rhs.m_initializer = + internal::default_init<Type, Allocator>::make(m_allocator); + } + + /// "Extended" move constructor with allocator + holder_monoid(holder_monoid&& rhs, const Allocator& a) + : m_allocator(a) + , m_initializer(0) { + if (a != rhs.m_allocator) + m_initializer = rhs.m_initializer->clone_self(a); + else { + m_initializer = rhs.m_initializer; + rhs.m_initializer = + internal::default_init<Type, Allocator>::make(m_allocator); + } + } +#endif + /// Destructor + ~holder_monoid() { m_initializer->delete_self(m_allocator); } + + holder_monoid& operator=(const holder_monoid& rhs) { + if (this == &rhs) return *this; + m_initializer->delete_self(m_allocator); + m_initializer = rhs.m_initializer->clone_self(m_allocator); + } + +#ifdef __CILKRTS_RVALUE_REFERENCES + holder_monoid& operator=(holder_monoid&& rhs) { + if (m_allocator != rhs.m_allocator) + // Delegate to copy-assignment on unequal allocators + return operator=(static_cast<const holder_monoid&>(rhs)); + std::swap(m_initializer, rhs.m_initializer); + return *this; + } +#endif + + /// Constructs IDENTITY value into the uninitilized '*p' + void identity(Type* p) const + { m_initializer->construct_view(p, m_allocator); } + + /// Calls the destructor on the object pointed-to by 'p' + void destroy(Type* p) const + { m_allocator.destroy(p); } + + /// Return a pointer to size bytes of raw memory + void* allocate(std::size_t s) const { + __CILKRTS_ASSERT(sizeof(Type) == s); + return m_allocator.allocate(1); + } + + /// Deallocate the raw memory at p + void deallocate(void* p) const { + m_allocator.deallocate(static_cast<Type*>(p), sizeof(Type)); + } + + void reduce(Type* left, Type* right) const { + internal::holder_reduce_functor<Type, Policy>()(left, right); + } + + void swap(holder_monoid& other) { + __CILKRTS_ASSERT(m_allocator == other.m_allocator); + std::swap(m_initializer, other.m_initializer); + } + + Allocator get_allocator() const { + return m_allocator; + } + }; + + // Namespace-scope swap + template <typename Type, holder_policy Policy, typename Allocator> + inline void swap(holder_monoid<Type, Policy, Allocator>& a, + holder_monoid<Type, Policy, Allocator>& b) + { + a.swap(b); + } + + /** + * Hyperobject to provide different views of an object to each + * parallel strand. + */ + template <typename Type, + holder_policy Policy = holder_keep_indeterminate, + typename Allocator = std::allocator<Type> > + class holder : public reducer<holder_monoid<Type, Policy, Allocator> > + { + typedef holder_monoid<Type, Policy, Allocator> monoid_type; + typedef reducer<monoid_type> imp; + + // Return a value of Type constructed using the functor Func. + template <typename Func> + Type make_value(const Func& f) const { + struct obj { + union { + char buf[sizeof(Type)]; + void* align1; + double align2; + }; + + obj(const Func& f) { f(static_cast<Type*>(buf)); } + ~obj() { static_cast<Type*>(buf)->~Type(); } + + operator Type&() { return *static_cast<Type*>(buf); } + }; + + return obj(f); + } + + public: + /// Default constructor uses default-initialization for both the + /// leftmost view and each identity view. + holder(const Allocator& alloc = Allocator()) + : imp(monoid_type(alloc)) { } + + /// Construct from an exemplar that is used to initialize both the + /// leftmost view and each identity view. + holder(const Type& v, const Allocator& alloc = Allocator()) + // Alas, cannot use an rvalue reference for 'v' because it is used + // twice in the same expression for initializing imp. + : imp(monoid_type(v, alloc), v) { } + + /// Construct from a functor that is used to initialize both the + /// leftmost view and each identity view. The functor, 'f', must be be + /// invokable using the expression 'Type x = f()'. + template <typename Func> + holder(const Func& f, const Allocator& alloc = Allocator()) + // Alas, cannot use an rvalue for 'f' because it is used twice in + // the same expression for initializing imp. + : imp(monoid_type(f, alloc), make_value(f)) { } + }; + +} // end namespace cilk + +#else /* C */ +# error Holders are currently available only for C++ +#endif /* __cplusplus */ + +#endif /* HOLDER_H_INCLUDED */ diff --git a/libcilkrts/include/cilk/hyperobject_base.h b/libcilkrts/include/cilk/hyperobject_base.h new file mode 100644 index 00000000000..484bf5f01ea --- /dev/null +++ b/libcilkrts/include/cilk/hyperobject_base.h @@ -0,0 +1,172 @@ +/* + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef INCLUDED_CILK_HYPEROBJECT_BASE +#define INCLUDED_CILK_HYPEROBJECT_BASE + +#ifdef __cplusplus +# include <cstdlib> +# include <cstddef> +#else +# include <stdlib.h> +# include <stddef.h> +#endif + +#include <cilk/common.h> + +#if defined _WIN32 || defined _WIN64 +# if !defined CILK_STUB && !defined IN_CILK_RUNTIME + /* bring in the Cilk library, which has definitions for some of these + * functions. */ +# pragma comment(lib, "cilkrts") +# endif +#endif + +/* The __CILKRTS_STRAND_PURE attribute tells the compiler that the value + * returned by 'func' for a given argument to 'func' will remain valid until + * the next strand boundary (spawn or sync) or until the next call to a + * function with the __CILKRTS_STRAND_STALE attribute using the same function + * argument. + */ +#if 0 && defined __cilk && (defined __GNUC__ && !defined _WIN32) && defined __cilkartsrev +# define __CILKRTS_STRAND_PURE(func) \ + func __attribute__((__cilk_hyper__("lookup"))) +# define __CILKRTS_STRAND_STALE(func) \ + func __attribute__((__cilk_hyper__("flush"))) +#else +# define __CILKRTS_STRAND_PURE(func) func +# define __CILKRTS_STRAND_STALE(func) func +#endif + +/***************************************************************************** + * C runtime interface to the hyperobject subsystem + *****************************************************************************/ + +__CILKRTS_BEGIN_EXTERN_C + +/* Callback function signatures. The 'r' argument always points to the + * reducer itself and is commonly ignored. */ +typedef void (*cilk_c_reducer_reduce_fn_t)(void* r, void* lhs, void* rhs); +typedef void (*cilk_c_reducer_identity_fn_t)(void* r, void* view); +typedef void (*cilk_c_reducer_destroy_fn_t)(void* r, void* view); +typedef void* (*cilk_c_reducer_allocate_fn_t)(void* r, __STDNS size_t bytes); +typedef void (*cilk_c_reducer_deallocate_fn_t)(void* r, void* view); + +/** Representation of the monoid */ +typedef struct cilk_c_monoid { + cilk_c_reducer_reduce_fn_t reduce_fn; + cilk_c_reducer_identity_fn_t identity_fn; + cilk_c_reducer_destroy_fn_t destroy_fn; + cilk_c_reducer_allocate_fn_t allocate_fn; + cilk_c_reducer_deallocate_fn_t deallocate_fn; +} cilk_c_monoid; + +/** Base of the hyperobject */ +typedef struct __cilkrts_hyperobject_base +{ + cilk_c_monoid __c_monoid; + unsigned long long __flags; + __STDNS ptrdiff_t __view_offset; /* offset (in bytes) to leftmost view */ + __STDNS size_t __view_size; /* Size of each view */ +} __cilkrts_hyperobject_base; + + +#ifndef CILK_STUB + +/* Library functions. */ +CILK_EXPORT + void __cilkrts_hyper_create(__cilkrts_hyperobject_base *key); +CILK_EXPORT void __CILKRTS_STRAND_STALE( + __cilkrts_hyper_destroy(__cilkrts_hyperobject_base *key)); +CILK_EXPORT void* __CILKRTS_STRAND_PURE( + __cilkrts_hyper_lookup(__cilkrts_hyperobject_base *key)); + +CILK_EXPORT + void* __cilkrts_hyperobject_alloc(void* ignore, __STDNS size_t bytes); +CILK_EXPORT + void __cilkrts_hyperobject_dealloc(void* ignore, void* view); + +/* No-op destroy function */ +CILK_EXPORT + void __cilkrts_hyperobject_noop_destroy(void* ignore, void* ignore2); + + +#else // CILK_STUB + +// Programs compiled with CILK_STUB are not linked with the Cilk runtime +// library, so they should not have external references to cilkrts functions. +// Furthermore, they don't need the hyperobject functionality, so the +// functions can be stubbed. + +#define __cilkrts_hyperobject_create __cilkrts_hyperobject_create__stub +__CILKRTS_INLINE + void __cilkrts_hyper_create(__cilkrts_hyperobject_base *key) + {} + +#define __cilkrts_hyperobject_destroy __cilkrts_hyperobject_destroy__stub +__CILKRTS_INLINE + void __cilkrts_hyper_destroy(__cilkrts_hyperobject_base *key) + {} + +#define __cilkrts_hyperobject_lookup __cilkrts_hyperobject_lookup__stub +__CILKRTS_INLINE + void* __cilkrts_hyper_lookup(__cilkrts_hyperobject_base *key) + { return (char*)(key) + key->__view_offset; } + +// Pointers to these functions are stored into monoids, so real functions +// are needed. + +#define __cilkrts_hyperobject_alloc __cilkrts_hyperobject_alloc__stub +__CILKRTS_INLINE + void* __cilkrts_hyperobject_alloc(void* ignore, __STDNS size_t bytes) + { assert(0); return __STDNS malloc(bytes); } + +#define __cilkrts_hyperobject_dealloc __cilkrts_hyperobject_dealloc__stub +__CILKRTS_INLINE + void __cilkrts_hyperobject_dealloc(void* ignore, void* view) + { assert(0); __STDNS free(view); } + +#define __cilkrts_hyperobject_noop_destroy \ + __cilkrts_hyperobject_noop_destroy__stub +__CILKRTS_INLINE + void __cilkrts_hyperobject_noop_destroy(void* ignore, void* ignore2) + {} + +#endif + +__CILKRTS_END_EXTERN_C + +#endif /* INCLUDED_CILK_HYPEROBJECT_BASE */ diff --git a/libcilkrts/include/cilk/metaprogramming.h b/libcilkrts/include/cilk/metaprogramming.h new file mode 100644 index 00000000000..5f6f29df87b --- /dev/null +++ b/libcilkrts/include/cilk/metaprogramming.h @@ -0,0 +1,606 @@ +/* metaprogramming.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2012-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file metaprogramming.h + * + * @brief Defines metaprogramming utility classes used in the Cilk library. + * + * @ingroup common + */ + +#ifndef METAPROGRAMMING_H_INCLUDED +#define METAPROGRAMMING_H_INCLUDED + +#ifdef __cplusplus + +#include <functional> +#include <new> +#include <cstdlib> +#ifdef _WIN32 +#include <malloc.h> +#endif +#include <algorithm> + +namespace cilk { + +namespace internal { + +/** Test if a class is empty. + * + * If @a Class is an empty (and therefore necessarily stateless) class, then + * the “empty base-class optimization†guarantees that + * `sizeof(check_for_empty_class<Class>) == sizeof(char)`. Conversely, if + * `sizeof(check_for_empty_class<Class>) > sizeof(char)`, then @a Class is not + * empty, and we must discriminate distinct instances of @a Class. + * + * Typical usage: + * + * // General definition of A<B> for non-empty B: + * template <typename B, bool BIsEmpty = class_is_empty<B>::value> > + * class A { ... }; + * + * // Specialized definition of A<B> for empty B: + * template <typename B> + * class A<B, true> { ... }; + * + * @tparam Class The class to be tested for emptiness. + * + * @result The `value` member will be `true` if @a Class is empty, + * `false` otherwise. + * + * @ingroup common + */ +template <class Class> +class class_is_empty { + class check_for_empty_class : public Class + { + char m_data; + public: + // Declared but not defined + check_for_empty_class(); + check_for_empty_class(const check_for_empty_class&); + check_for_empty_class& operator=(const check_for_empty_class&); + ~check_for_empty_class(); + }; +public: + + /** Constant is true if and only if @a Class is empty. + */ + static const bool value = (sizeof(check_for_empty_class) == sizeof(char)); +}; + + +/** Get the alignment of a type. + * + * For example: + * + * align_of<double>::value == 8 + * + * @tparam Tp The type whose alignment is to be computed. + * + * @result The `value` member of an instantiation of this class template + * will hold the integral alignment requirement of @a Tp. + * + * @pre @a Tp shall be a complete type. + * + * @ingroup common + */ +template <typename Tp> +struct align_of +{ +private: + struct imp { + char m_padding; + Tp m_val; + + // The following declarations exist to suppress compiler-generated + // definitions, in case @a Tp does not have a public default + // constructor, copy constructor, or destructor. + imp(const imp&); // Declared but not defined + ~imp(); // Declared but not defined + }; + +public: + /// The integral alignment requirement of @a Tp. + static const std::size_t value = (sizeof(imp) - sizeof(Tp)); +}; + + +/** A class containing raw bytes with a specified alignment and size. + * + * An object of type `aligned_storage<S, A>` will have alignment `A` and + * size at least `S`. Its contents will be uninitialized bytes. + * + * @tparam Size The required minimum size of the resulting class. + * @tparam Alignment The required alignment of the resulting class. + * + * @pre @a Alignment shall be a power of 2 no greater then 64. + * + * @note This is implemented using the `CILK_ALIGNAS` macro, which uses + * the non-standard, implementation-specific features + * `__declspec(align(N))` on Windows, and + * `__attribute__((__aligned__(N)))` on Unix. The `gcc` implementation + * of `__attribute__((__aligned__(N)))` requires a numeric literal `N` + * (_not_ an arbitrary compile-time constant expression). Therefore, + * this class is implemented using specialization on the required + * alignment. + * + * @note The template class is specialized only for the supported + * alignments. An attempt to instantiate it for an unsupported + * alignment will result in a compilation error. + */ +template <std::size_t Size, std::size_t Alignment> +struct aligned_storage; + +template<std::size_t Size> class aligned_storage<Size, 1> + { CILK_ALIGNAS( 1) char m_bytes[Size]; }; +template<std::size_t Size> class aligned_storage<Size, 2> + { CILK_ALIGNAS( 2) char m_bytes[Size]; }; +template<std::size_t Size> class aligned_storage<Size, 4> + { CILK_ALIGNAS( 4) char m_bytes[Size]; }; +template<std::size_t Size> class aligned_storage<Size, 8> + { CILK_ALIGNAS( 8) char m_bytes[Size]; }; +template<std::size_t Size> class aligned_storage<Size, 16> + { CILK_ALIGNAS(16) char m_bytes[Size]; }; +template<std::size_t Size> class aligned_storage<Size, 32> + { CILK_ALIGNAS(32) char m_bytes[Size]; }; +template<std::size_t Size> class aligned_storage<Size, 64> + { CILK_ALIGNAS(64) char m_bytes[Size]; }; + + +/** A buffer of uninitialized bytes with the same size and alignment as a + * specified type. + * + * The class `storage_for_object<Type>` will have the same size and alignment + * properties as `Type`, but it will contain only raw (uninitialized) bytes. + * This allows the definition of a data member which can contain a `Type` + * object which is initialized explicitly under program control, rather + * than implicitly as part of the initialization of the containing class. + * For example: + * + * class C { + * storage_for_object<MemberClass> _member; + * public: + * C() ... // Does NOT initialize _member + * void initialize(args) + * { new (_member.pointer()) MemberClass(args); } + * const MemberClass& member() const { return _member.object(); } + * MemberClass& member() { return _member.object(); } + * + * @tparam Type The type whose size and alignment are to be reflected + * by this class. + */ +template <typename Type> +class storage_for_object : + aligned_storage< sizeof(Type), align_of<Type>::value > +{ +public: + /// Return a typed reference to the buffer. + const Type& object() const { return *reinterpret_cast<Type*>(this); } + Type& object() { return *reinterpret_cast<Type*>(this); } +}; + + +/** Get the functor class corresponding to a binary function type. + * + * The `binary_functor` template class class can be instantiated with a binary + * functor class or with a real binary function, and will yield an equivalent + * binary functor class class in either case. + * + * @tparam F A binary functor class, a binary function type, or a pointer to + * binary function type. + * + * @result `binary_functor<F>::%type` will be the same as @a F if @a F is + * a class. It will be a `std::pointer_to_binary_function` wrapper + * if @a F is a binary function or binary function pointer type. + * (It will _not_ necessarily be an `Adaptable Binary Function` + * class, since @a F might be a non-adaptable binary functor + * class.) + * + * @ingroup common + */ +template <typename F> +struct binary_functor { + /// The binary functor class equivalent to @a F. + typedef F type; +}; + +/// @copydoc binary_functor +/// Specialization for binary function. +template <typename R, typename A, typename B> +struct binary_functor<R(A,B)> { + /// The binary functor class equivalent to @a F. + typedef std::pointer_to_binary_function<A, B, R> type; +}; + +/// @copydoc binary_functor +/// Specialization for pointer to binary function. +template <typename R, typename A, typename B> +struct binary_functor<R(*)(A,B)> { + /// The binary functor class equivalent to @a F. + typedef std::pointer_to_binary_function<A, B, R> type; +}; + + +/** Indirect binary function class with specified types. + * + * `typed_indirect_binary_function<F>` is an `Adaptable Binary Function` class + * based on an existing binary functor class or binary function type @a F. If + * @a F is a stateless class, then this class will be empty, and its + * `operator()` will invoke @a F’s `operator()`. Otherwise, an object of this + * class will hold a pointer to an object of type @a F, and will refer its + * `operator()` calls to the pointed-to @a F object. + * + * That is, suppose that we have the declarations: + * + * F *p; + * typed_indirect_binary_function<F, int, int, bool> ibf(p); + * + * Then: + * + * - `ibf(x, y) == (*p)(x, y)`. + * - `ibf(x, y)` will not do a pointer dereference if `F` is an empty class. + * + * @note Just to repeat: if `F` is an empty class, then + * `typed_indirect_binary_function\<F\>' is also an empty class. + * This is critical for its use in the @ref min_max::view_base + * "min/max reducer view classes", where it allows the view to + * call a comparison functor in the monoid without actually + * having to allocate a pointer in the view class when the + * comparison class is empty. + * + * @note If you have an `Adaptable Binary Function` class or a binary + * function type, then you can use the + * @ref indirect_binary_function class, which derives the + * argument and result types parameter type instead of requiring + * you to specify them as template arguments. + * + * @tparam F A binary functor class, a binary function type, or a pointer to + * binary function type. + * @param A1 The first argument type. + * @param A2 The second argument type. + * @param R The result type. + * + * @see min_max::comparator_base + * @see indirect_binary_function + * + * @ingroup common + */ +template < typename F + , typename A1 + , typename A2 + , typename R + , typename Functor = typename binary_functor<F>::type + , bool FunctorIsEmpty = class_is_empty<Functor>::value + > +class typed_indirect_binary_function : std::binary_function<A1, A2, R> +{ + const F* f; +public: + /// Constructor captures a pointer to the wrapped function. + typed_indirect_binary_function(const F* f) : f(f) {} + + /// Return the comparator pointer, or `NULL` if the comparator is stateless. + const F* pointer() const { return f; } + + /// Apply the pointed-to functor to the arguments. + R operator()(const A1& a1, const A2& a2) const { return (*f)(a1, a2); } +}; + + +/// @copydoc typed_indirect_binary_function +/// Specialization for an empty functor class. (This is only possible if @a F +/// itself is an empty class. If @a F is a function or pointer-to-function +/// type, then the functor will contain a pointer.) +template <typename F, typename A1, typename A2, typename R, typename Functor> +class typed_indirect_binary_function<F, A1, A2, R, Functor, true> : + std::binary_function<A1, A2, R> +{ +public: + /// Return `NULL` for the comparator pointer of a stateless comparator. + const F* pointer() const { return 0; } + + /// Constructor discards the pointer to a stateless functor class. + typed_indirect_binary_function(const F* f) {} + + /// Create an instance of the stateless functor class and apply it to the arguments. + R operator()(const A1& a1, const A2& a2) const { return F()(a1, a2); } +}; + + +/** Indirect binary function class with inferred types. + * + * This is identical to @ref typed_indirect_binary_function, except that it + * derives the binary function argument and result types from the parameter + * type @a F instead of taking them as additional template parameters. If @a F + * is a class type, then it must be an `Adaptable Binary Function`. + * + * @see typed_indirect_binary_function + * + * @ingroup common + */ +template <typename F, typename Functor = typename binary_functor<F>::type> +class indirect_binary_function : + typed_indirect_binary_function< F + , typename Functor::first_argument_type + , typename Functor::second_argument_type + , typename Functor::result_type + > +{ + typedef typed_indirect_binary_function< F + , typename Functor::first_argument_type + , typename Functor::second_argument_type + , typename Functor::result_type + > + base; +public: + indirect_binary_function(const F* f) : base(f) {} ///< Constructor +}; + + +/** Choose a type based on a boolean constant. + * + * This metafunction is identical to C++11’s condition metafunction. + * It needs to be here until we can reasonably assume that users will be + * compiling with C++11. + * + * @tparam Cond A boolean constant. + * @tparam IfTrue A type. + * @tparam IfFalse A type. + * @result The `type` member will be a typedef of @a IfTrue if @a Cond + * is true, and a typedef of @a IfFalse if @a Cond is false. + * + * @ingroup common + */ +template <bool Cond, typename IfTrue, typename IfFalse> +struct condition +{ + typedef IfTrue type; ///< The type selected by the condition. +}; + +/// @copydoc condition +/// Specialization for @a Cond == `false`. +template <typename IfTrue, typename IfFalse> +struct condition<false, IfTrue, IfFalse> +{ + typedef IfFalse type; ///< The type selected by the condition. +}; + + +/** @def __CILKRTS_STATIC_ASSERT + * + * @brief Compile-time assertion. + * + * Causes a compilation error if a compile-time constant expression is false. + * + * @par Usage example. + * This assertion is used in reducer_min_max.h to avoid defining + * legacy reducer classes that would not be binary-compatible with the + * same classes compiled with earlier versions of the reducer library. + * + * __CILKRTS_STATIC_ASSERT( + * internal::class_is_empty< internal::binary_functor<Compare> >::value, + * "cilk::reducer_max<Value, Compare> only works with an empty Compare class"); + * + * @note In a C++11 compiler, this is just the language predefined + * `static_assert` macro. + * + * @note In a non-C++11 compiler, the @a Msg string is not directly included + * in the compiler error message, but it may appear if the compiler + * prints the source line that the error occurred on. + * + * @param Cond The expression to test. + * @param Msg A string explaining the failure. + * + * @ingroup common + */ +#if defined(__INTEL_CXX11_MODE__) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define __CILKRTS_STATIC_ASSERT(Cond, Msg) static_assert(Cond, Msg) +#else +# define __CILKRTS_STATIC_ASSERT(Cond, Msg) \ + typedef int __CILKRTS_STATIC_ASSERT_DUMMY_TYPE \ + [::cilk::internal::static_assert_failure<(Cond)>::Success] + +/// @cond internal + template <bool> struct static_assert_failure { }; + template <> struct static_assert_failure<true> { enum { Success = 1 }; }; + +# define __CILKRTS_STATIC_ASSERT_DUMMY_TYPE \ + __CILKRTS_STATIC_ASSERT_DUMMY_TYPE1(__cilkrts_static_assert_, __LINE__) +# define __CILKRTS_STATIC_ASSERT_DUMMY_TYPE1(a, b) \ + __CILKRTS_STATIC_ASSERT_DUMMY_TYPE2(a, b) +# define __CILKRTS_STATIC_ASSERT_DUMMY_TYPE2(a, b) a ## b +/// @endcond + +#endif + +/// @cond internal + +/** @name Aligned heap management. + */ +//@{ + +/** Implementation-specific aligned memory allocation function. + * + * @param size The minimum number of bytes to allocate. + * @param alignment The required alignment (must be a power of 2). + * @return The address of a block of memory of at least @a size + * bytes. The address will be a multiple of @a alignment. + * `NULL` if the allocation fails. + * + * @see deallocate_aligned() + */ +inline void* allocate_aligned(std::size_t size, std::size_t alignment) +{ +#ifdef _WIN32 + return _aligned_malloc(size, alignment); +#else +#if defined(ANDROID) || defined(__ANDROID__) + return memalign(std::max(alignment, sizeof(void*)), size); +#else + void* ptr; + return (posix_memalign(&ptr, std::max(alignment, sizeof(void*)), size) == 0) ? ptr : 0; +#endif +#endif +} + +/** Implementation-specific aligned memory deallocation function. + * + * @param ptr A pointer which was returned by a call to alloc_aligned(). + */ +inline void deallocate_aligned(void* ptr) +{ +#ifdef _WIN32 + _aligned_free(ptr); +#else + std::free(ptr); +#endif +} + +/** Class to allocate and guard an aligned pointer. + * + * A new_aligned_pointer object allocates aligned heap-allocated memory when + * it is created, and automatically deallocates it when it is destroyed + * unless its `ok()` function is called. + * + * @tparam T The type of the object to allocate on the heap. The allocated + * will have the size and alignment of an object of type T. + */ +template <typename T> +class new_aligned_pointer { + void* m_ptr; +public: + /// Constructor allocates the pointer. + new_aligned_pointer() : + m_ptr(allocate_aligned(sizeof(T), internal::align_of<T>::value)) {} + /// Destructor deallocates the pointer. + ~new_aligned_pointer() { if (m_ptr) deallocate_aligned(m_ptr); } + /// Get the pointer. + operator void*() { return m_ptr; } + /// Return the pointer and release the guard. + T* ok() { + T* ptr = static_cast<T*>(m_ptr); + m_ptr = 0; + return ptr; + } +}; + +//@} + +/// @endcond + +} // namespace internal + +//@{ + +/** Allocate an aligned data structure on the heap. + * + * `cilk::aligned_new<T>([args])` is equivalent to `new T([args])`, except + * that it guarantees that the returned pointer will be at least as aligned + * as the alignment requirements of type `T`. + * + * @ingroup common + */ +template <typename T> +T* aligned_new() +{ + internal::new_aligned_pointer<T> ptr; + new (ptr) T(); + return ptr.ok(); +} + +template <typename T, typename T1> +T* aligned_new(const T1& x1) +{ + internal::new_aligned_pointer<T> ptr; + new (ptr) T(x1); + return ptr.ok(); +} + +template <typename T, typename T1, typename T2> +T* aligned_new(const T1& x1, const T2& x2) +{ + internal::new_aligned_pointer<T> ptr; + new (ptr) T(x1, x2); + return ptr.ok(); +} + +template <typename T, typename T1, typename T2, typename T3> +T* aligned_new(const T1& x1, const T2& x2, const T3& x3) +{ + internal::new_aligned_pointer<T> ptr; + new (ptr) T(x1, x2, x3); + return ptr.ok(); +} + +template <typename T, typename T1, typename T2, typename T3, typename T4> +T* aligned_new(const T1& x1, const T2& x2, const T3& x3, const T4& x4) +{ + internal::new_aligned_pointer<T> ptr; + new (ptr) T(x1, x2, x3, x4); + return ptr.ok(); +} + +template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5> +T* aligned_new(const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5) +{ + internal::new_aligned_pointer<T> ptr; + new (ptr) T(x1, x2, x3, x4, x5); + return ptr.ok(); +} + +//@} + + +/** Deallocate an aligned data structure on the heap. + * + * `cilk::aligned_delete(ptr)` is equivalent to `delete ptr`, except that it + * operates on a pointer that was allocated by aligned_new(). + * + * @ingroup common + */ +template <typename T> +void aligned_delete(const T* ptr) +{ + ptr->~T(); + internal::deallocate_aligned((void*)ptr); +} + +} // namespace cilk + +#endif // __cplusplus + +#endif // METAPROGRAMMING_H_INCLUDED diff --git a/libcilkrts/include/cilk/reducer.h b/libcilkrts/include/cilk/reducer.h new file mode 100644 index 00000000000..a22651e1e6f --- /dev/null +++ b/libcilkrts/include/cilk/reducer.h @@ -0,0 +1,1900 @@ +/* reducer.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file reducer.h + * + * @brief Defines foundation classes for creating Cilk reducers. + * + * @ingroup Reducers + * + * @see @ref pagereducers + * + * @defgroup Reducers Reducers + */ + +#ifndef REDUCER_H_INCLUDED +#define REDUCER_H_INCLUDED + +#include "cilk/hyperobject_base.h" +#include "cilk/metaprogramming.h" + +#ifdef __cplusplus + +//===================== C++ interfaces =================================== + +#include <new> + +namespace cilk { + +/** Base class for defining monoids. + * + * The monoid_base class template is useful for creating classes that model + * the monoid concept. It provides the core type and memory management + * functionality. A subclass of monoid_base need only declare and implement + * the `identity` and `reduce` functions. + * + * The monoid_base class also manages the integration between the monoid, the + * reducer class that is based on it, and an optional view class which wraps + * value objects and restricts access to their operations. + * + * @tparam Value The value type for the monoid. + * @tparam View An optional view class that serves as a proxy for the value + * type. + * + * @see monoid_with_view + */ +template <typename Value, typename View = Value> +class monoid_base +{ +protected: + + /** Class for provisionally constructed objects. + * + * The monoid_base::construct() functions manually construct both a monoid + * and a view. If one of these is constructed successfully, and the + * construction of the other (or some other initialization) fails, then + * the first one must be destroyed to avoid a memory leak. Because the + * construction is explicit, the destruction must be explicit, too. + * + * A provisional_guard object wraps a pointer to a newly constructed + * object. A call to its confirm() function confirms that the object is + * really going to be used. If the guard is destroyed without being + * confirmed, then the pointed-to object is destroyed (but not + * deallocated). + * + * Expected usage: + * + * provisional_guard<T1> x1_provisional( new (x1) T1() ); + * … more initialization … + * x1_provisional.confirm(); + * + * or + * + * provisional_guard<T1> x1_provisional( new (x1) T1() ); + * x1_provisional.confirm_if( new (x2) T2() ); + * + * If an exception is thrown in the “more initialization†code in the + * first example, or in the `T2` constructor in the second example, then + * `x1_provisional` will not be confirmed, so when its destructor is + * called during exception unwinding, the `T1` object that was constructed + * in `x1` will be destroyed. + * + * @see provisional() + * + * @tparam Type The type of the provisionally constructed object. + */ + template <typename Type> + class provisional_guard { + Type* m_ptr; + + public: + + /** Constructor. Creates a guard for a provisionally constructed object. + * + * @param ptr A pointer to the provisionally constructed object. + */ + provisional_guard(Type* ptr) : m_ptr(ptr) {} + + /** Destructor. Destroy the object pointed to by the contained pointer + * if it has not been confirmed. + */ + ~provisional_guard() { if (m_ptr) m_ptr->~Type(); } + + /** Confirm the provisional construction. Do *not* delete the contained + * pointer when the guard is destroyed. + */ + void confirm() { m_ptr = 0; } + + /** Confirm provisional construction if argument is non-null. Note that + * if an exception is thrown during evaluation of the argument + * expression, then this function will not be called, and the + * provisional object will not be confirmed. This allows the usage: + * + * x1_provisional.confirm_if( new (x2) T2() ); + * + * @param cond An arbitrary pointer. The provisional object will be + * confirmed if @a cond is not null. + * + * @returns The value of the @a cond argument. + */ + template <typename Cond> + Cond* confirm_if(Cond* cond) { if (cond) m_ptr = 0; return cond; } + }; + + + /** Create a provisional_guard object. This function allows simpler code + * when the only use of a provisional_guard is in a + * provisional_guard::confirm_if() call immediately following its + * creation. Instead of + * + * provisional_guard<T>guard( new (ptr_to_T) T() ); + * guard.confirm_if( new (ptr_to_U) U() ); + * + * you can just write + * + * provisional( new (ptr_to_T) T() ).confirm_if( new (ptr_to_U) U() ); + * + * @tparam Type The type of the provisionally constructed object. + * + * @param ptr A pointer to a provisionally constructed object. + * + * @returns A @ref provisional_guard object that guards the + * provisionally constructed object pointed to by @a ptr. + */ + template <typename Type> + static provisional_guard<Type> provisional(Type* ptr) + { return provisional_guard<Type>(ptr); } + +public: + + /** Value type of the monoid. + */ + typedef Value value_type; + + /** View type of the monoid. Defaults to be the same as the value type. + * @see monoid_with_view + */ + typedef View view_type; + + enum { + /** Should reducers created with this monoid be aligned? + * + * @details + * “Aligned†means that the view is allocated at a cache-line aligned + * offset in the reducer, and the reducer must be cache-line aligned. + * “Unaligned†means that the reducer as a whole is just naturally + * aligned, but it contains a large enough block of uninitialized + * storage for a cache-line aligned view to be allocated in it at + * reducer construction time. + * + * Since the standard heap allocator (new reducer) does not allocate + * cache-line aligned storage, only unaligned reducers can be safely + * allocated on the heap. + * + * Default is false (unaligned) unless overridden in a subclass. + * + * @since 1.02 + * (In Cilk library versions 1.0 and 1.01, the default was true. + * In Cilk library versions prior to 1.0, reducers were always aligned, + * and this data member did not exist.) + */ + align_reducer = false + }; + + /** Destroy a view. Destroys (without deallocating) the @a View object + * pointed to by @a p. + * + * @param p The address of the @a View object to be destroyed. + */ + void destroy(view_type* p) const { p->~view_type(); } + + /** Allocate raw memory. Allocate @a s bytes of memory with no + * initialization. + * + * @param s The number of bytes of memory to allocate. + * @return An untyped pointer to the allocated memory. + */ + void* allocate(size_t s) const { return operator new(s); } + + /** Deallocate raw memory. Deallocates the memory pointed to by @a p + * without doing any destruction. + * + * @param p Pointer to the memory to be deallocated. + * + * @pre @a p points to a block of memory that was allocated by a + * call to allocate(). + */ + void deallocate(void* p) const { operator delete(p); } + + /** Create the identity value. Constructs (without allocating) a @a View + * object representing the default value of the @a Value type. + * + * @param p A pointer to a block of raw memory large enough to hold a + * @a View object. + * + * @post The memory pointed to by @a p contains a @a View object that + * represents the default value of the @a View type. + * + * @deprecated This function constructs the @a View object with its default + * constructor, which will often, but not always, yield the + * appropriate identity value. Monoid classes should declare + * their identity function explicitly, rather than relying on + * this default definition. + */ + void identity(View* p) const { new ((void*) p) View(); } + + + /** @name Construct the monoid and the view with arbitrary arguments. + * + * A @ref reducer object contains monoid and view data members, which are + * declared as raw storage (byte arrays), so that they are not implicitly + * constructed when the reducer is constructed. Instead, a reducer + * constructor calls one of the monoid class’s static construct() + * functions with the addresses of the monoid and the view, and the + * construct() function uses placement `new` to construct them. + * + * This allows the monoid to determine the order in which the monoid and + * view are constructed, and to make one of them dependent on the other. + * + * Any arguments to the reducer constructor are just passed on as + * additional arguments to the construct() function (after the monoid + * and view addresses). + * + * Any monoid whose needs are satisfied by the suite of construct() + * functions below, such as @ref monoid_with_view, can just inherit them + * from monoid_base. Other monoids will need to provide their own versions + * to override the monoid_base functions. + */ + //@{ + + /** Default-construct the monoid, and pass zero to five const reference + * arguments to the view constructor. + */ + //@{ + + template <typename Monoid> + static void construct(Monoid* monoid, View* view) + { provisional( new ((void*)monoid) Monoid() ).confirm_if( + (monoid->identity(view), view) ); } + + template <typename Monoid, typename T1> + static void construct(Monoid* monoid, View* view, const T1& x1) + { provisional( new ((void*)monoid) Monoid() ).confirm_if( + new ((void*)view) View(x1) ); } + + template <typename Monoid, typename T1, typename T2> + static void construct(Monoid* monoid, View* view, + const T1& x1, const T2& x2) + { provisional( new ((void*)monoid) Monoid() ).confirm_if( + new ((void*)view) View(x1, x2) ); } + + template <typename Monoid, typename T1, typename T2, typename T3> + static void construct(Monoid* monoid, View* view, + const T1& x1, const T2& x2, const T3& x3) + { provisional( new ((void*)monoid) Monoid() ).confirm_if( + new ((void*)view) View(x1, x2, x3) ); } + + template <typename Monoid, typename T1, typename T2, typename T3, + typename T4> + static void construct(Monoid* monoid, View* view, + const T1& x1, const T2& x2, const T3& x3, + const T4& x4) + { provisional( new ((void*)monoid) Monoid() ).confirm_if( + new ((void*)view) View(x1, x2, x3, x4) ); } + + template <typename Monoid, typename T1, typename T2, typename T3, + typename T4, typename T5> + static void construct(Monoid* monoid, View* view, + const T1& x1, const T2& x2, const T3& x3, + const T4& x4, const T5& x5) + { provisional( new ((void*)monoid) Monoid() ).confirm_if( + new ((void*)view) View(x1, x2, x3, x4, x5) ); } + + //@} + + /** Default-construct the monoid, and pass one non-const reference argument + * to the view constructor. + */ + //@{ + template <typename Monoid, typename T1> + static void construct(Monoid* monoid, View* view, T1& x1) + { provisional( new ((void*)monoid) Monoid() ).confirm_if( + new ((void*)view) View(x1) ); } + //@} + + /** Copy-construct the monoid, and pass zero to four const reference + * arguments to the view constructor. + */ + //@{ + + template <typename Monoid> + static void construct(Monoid* monoid, View* view, const Monoid& m) + { provisional( new ((void*)monoid) Monoid(m) ).confirm_if( + new ((void*)view) View() ); } + + template <typename Monoid, typename T1> + static void construct(Monoid* monoid, View* view, const Monoid& m, + const T1& x1) + { provisional( new ((void*)monoid) Monoid(m) ).confirm_if( + new ((void*)view) View(x1) ); } + + template <typename Monoid, typename T1, typename T2> + static void construct(Monoid* monoid, View* view, const Monoid& m, + const T1& x1, const T2& x2) + { provisional( new ((void*)monoid) Monoid(m) ).confirm_if( + new ((void*)view) View(x1, x2) ); } + + template <typename Monoid, typename T1, typename T2, typename T3> + static void construct(Monoid* monoid, View* view, const Monoid& m, + const T1& x1, const T2& x2, const T3& x3) + { + provisional( new ((void*)monoid) Monoid(m) ).confirm_if( + new ((void*)view) View(x1, x2, x3) ); + } + + template <typename Monoid, typename T1, typename T2, typename T3, + typename T4> + static void construct(Monoid* monoid, View* view, const Monoid& m, + const T1& x1, const T2& x2, const T3& x3, + const T4& x4) + { + provisional( new ((void*)monoid) Monoid(m) ).confirm_if( + new ((void*)view) View(x1, x2, x3, x4) ); + } + + //@} + + //@} +}; + + +/** Monoid class that gets its value type and identity and reduce operations + * from its view. + * + * A simple implementation of the monoid-view-reducer architecture would + * distribute knowledge about the type and operations for the reduction + * between the monoid and the view — the identity and reduction operations are + * specified in the monoid, the reduction operations are implemented in the + * view, and the value type is specified in both the monoid and the view. + * This is inelegant. + * + * monoid_with_view is a subclass of @ref monoid_base that gets its value type + * and its identity and reduction operations from its view class. No + * customization of the monoid_with_view class itself is needed beyond + * instantiating it with an appropriate view class. (Customized subclasses of + * monoid_with_view may be needed for other reasons, such as to keep some + * state for the reducer.) All of the Cilk predefined reducers use + * monoid_with_view or one of its subclasses. + * + * The view class `View` of a monoid_with_view must provide the following public definitions: + * + * Definition | Meaning + * ---------------------------------|-------- + * `value_type` | a typedef of the value type for the reduction + * `View()` | a default constructor which constructs the identity value for the reduction + * `void reduce(const View* other)` | a member function which applies the reduction operation to the values of `this` view and the `other` view, leaving the result as the value of `this` view, and leaving the value of the `other` view undefined (but valid) + * + * @tparam View The view class for the monoid. + * @tparam Align If true, reducers instantiated on this monoid will be + * cache-aligned. By default, library reducers (unlike legacy + * library reducer _wrappers_) are aligned only as required by + * contents. + */ +template <class View, bool Align = false> +class monoid_with_view : public monoid_base<typename View::value_type, View> +{ +public: + /** Should reducers created with this monoid be aligned? + */ + enum { align_reducer = Align }; + + /** Create the identity value. + * + * Implements the monoid `identity` operation by using the @a View class’s + * default constructor. + * + * @param p A pointer to a block of raw memory large enough to hold a + * @p View object. + */ + void identity(View* p) const { new ((void*)p) View(); } + + /** Reduce the values of two views. + * + * Implements the monoid `reduce` operation by calling the left view’s + * `%reduce()` function with the right view as an operand. + * + * @param left The left operand of the reduce operation. + * @param right The right operand of the reduce operation. + * @post The left view contains the result of the reduce + * operation, and the right view is undefined. + */ + void reduce(View* left, View* right) const { left->reduce(right); } +}; + + +/** Base class for simple views with (usually) scalar values. + * + * The scalar_view class is intended as a base class which provides about half + * of the required definitions for simple views. It defines the `value_type` + * required by a @ref monoid_with_view (but not the identity constructor and + * reduce operation, which are inherently specific to a particular kind of + * reduction). It also defines the value access functions which will be called + * by the corresponding @ref reducer functions. (It uses copy semantics for + * the view_move_in() and view_move_out() functions, which is appropriate + * for simple scalar types, but not necessarily for more complex types like + * STL containers. + * + * @tparam Type The type of value wrapped by the view. + */ +template <typename Type> +class scalar_view +{ +protected: + Type m_value; ///< The wrapped accumulator variable. + +public: + /** Value type definition required by @ref monoid_with_view. + */ + typedef Type value_type; + + /** Default constructor. + */ + scalar_view() : m_value() {} + + /** Value constructor. + */ + scalar_view(const Type& v) : m_value(v) {} + + /** @name Value functions required by the reducer class. + * + * Note that the move in/out functions use simple assignment semantics. + */ + //@{ + + /** Set the value of the view. + */ + void view_move_in(Type& v) { m_value = v; } + + /** Get the value of the view. + */ + void view_move_out(Type& v) { v = m_value; } + + /** Set the value of the view. + */ + void view_set_value(const Type& v) { m_value = v; } + + /** Get the value of the view. + */ + Type const& view_get_value() const { return m_value; } + + /** Get a reference to the value contained in the view. For legacy + * reducer support only. + */ + Type & view_get_reference() { return m_value; } + + /** Get a reference to the value contained in the view. For legacy + * reducer support only. + */ + Type const& view_get_reference() const { return m_value; } + //@} +}; + + +/** Wrapper class for move-in construction. + * + * Some types allow their values to be _moved_ as an alternative to copying. + * Moving a value may be much faster than copying it, but may leave the value + * of the move’s source undefined. Consider the `swap` operation provided by + * many STL container classes: + * + * list<T> x, y; + * x = y; // Copy + * x.swap(y); // Move + * + * The assignment _copies_ the value of `y` into `x` in time linear in the + * size of `y`, leaving `y` unchanged. The `swap` _moves_ the value of `y` + * into `x` in constant time, but it also moves the value of `x` into `y`, + * potentially leaving `y` undefined. + * + * A move_in_wrapper simply wraps a pointer to an object. It is created by a + * call to cilk::move_in(). Passing a move_in_wrapper to a view constructor + * (actually, passing it to a reducer constructor, which passes it to the + * monoid `construct()` function, which passes it to the view constructor) + * allows, but does not require, the value pointed to by the wrapper to be + * moved into the view instead of copied. + * + * A view class exercises this option by defining a _move-in constructor_, + * i.e., a constructor with a move_in_wrapper parameter. The constructor calls + * the wrapper’s `value()` function to get a reference to its pointed-to + * value, and can then use that reference in a move operation. + * + * A move_in_wrapper also has an implicit conversion to its pointed-to value, + * so if a view class does not define a move-in constructor, its ordinary + * value constructor will be called with the wrapped value. For example, an + * @ref ReducersAdd "op_add" view does not have a move-in constructor, so + * + * int x; + * reducer< op_add<int> > xr(move_in(x)); + * + * will simply call the `op_add_view(const int &)` constructor. But an + * @ref ReducersList "op_list_append" view does have a move-in constructor, + * so + * + * list<int> x; + * reducer< op_list_append<int> > xr(move_in(x)); + * + * will call the `op_list_append_view(move_in_wrapper<int>)` constructor, + * which can `swap` the value of `x` into the view. + * + * @note Remember that passing the value of a variable to a reducer + * constructor using a move_in_wrapper leaves the variable undefined. + * You cannot assume that the constructor either will or will not copy + * or move the value. + * + * @tparam Type The type of the wrapped value. + * + * @see cilk::move_in() + */ +template <typename Type> +class move_in_wrapper +{ + Type *m_pointer; +public: + + /** Constructor that captures the address of its argument. This is almost + * always called from the @ref move_in function. + */ + explicit move_in_wrapper(Type& ref) : m_pointer(&ref) { } + + /** Implicit conversion to the wrapped value. This allows a move_in_wrapper + * to be used where a value of the wrapped type is expected, in which case + * the wrapper is completely transparent. + */ + operator Type&() const { return *m_pointer; } + + /** Get a reference to the pointed-to value. This has the same effect as + * the implicit conversion, but makes the intent clearer in a move-in + * constructor. + */ + Type& value() const { return *m_pointer; } +}; + +/** Function to create a move_in_wrapper for a value. + * + * @tparam Type The type of the argument, which will be the `type` of the + * created wrapper. + * + * @see move_in_wrapper + */ +template <typename Type> +inline +move_in_wrapper<Type> move_in(Type& ref) + { return move_in_wrapper<Type>(ref); } + + +/** @copydoc move_in(Type&) + * + * @note Applying a function that is explicitly specified as modifying its + * argument to a const argument is obviously an irrational thing to + * do. This move_in() variant is just provided to allow calling a + * move-in constructor with a function return value, which the + * language treats as a const. Using it for any other purpose will + * probably end in tears. + */ +template <typename Type> +inline +move_in_wrapper<Type> move_in(const Type& ref) + { return move_in_wrapper<Type>(ref); } + + +/** Wrapper class to allow implicit downcasts to reducer subclasses. + * + * The Cilk library contains a collection of reducer wrapper classes which + * were created before the `cilk::reducer<Monoid>` style was developed. For + * example, `cilk::reducer_opadd<Type>` provided essentially the same + * functionality that is now provided by + * `cilk::reducer< cilk::op_add<Type> >`. These legacy reducer classes are + * deprecated, but still supported, and they have been reimplemented as + * subclasses of the corresponding `cilk::reducer` classes. For example: + * + * template <class T> + * reducer_opadd<T> : public reducer< op_add<T> > { ... }; + * + * This reimplementation allows transparent conversion between legacy and + * new reducers. That is, a `reducer<op_add>*` or `reducer<op_add>&` can be + * used anywhere that a `reducer_opadd*` or `reducer_opadd&` is expected, + * and vice versa. + * + * The conversion from the legacy reducer to the new reducer is just an + * up-cast, which is provided for free by C++. The conversion from the new + * reducer to the legacy reducer is a down-cast, though, which requires an + * explicit conversion member function in the `reducer` class. The challenge + * is to define a function in the reducer template class which will convert + * each cilk::reducer specialization to the corresponding legacy reducer, + * if there is one. + * + * The trick is in the legacy_reducer_downcast template class, which provides + * a mapping from `cilk::reducer` specializations to legacy reducer classes. + * `reducer<Monoid>` has a conversion function to convert itself to + * `legacy_reducer_downcast< reducer<Monoid> >::%type`. By default, + * `legacy_reducer_downcast<Reducer>::%type` is just a trivial subclass of + * `Reducer`, which is uninteresting, but a reducer with a legacy counterpart + * will have a specialization of `legacy_reducer_downcast` whose `type` is + * the corresponding legacy reducer. For example: + * + * template <typename Type> + * struct legacy_reducer_downcast< reducer< op_add<Type> > > + * { + * typedef reducer_opadd<Type> type; + * }; + * + * + * @tparam Reducer The new-style reducer class whose corresponding legacy reducer class + * is `type`, if there is such a legacy reducer class. + */ +template <typename Reducer> +struct legacy_reducer_downcast +{ + /** The related legacy reducer class. + * + * By default, this is just a trivial subclass of Reducer, but it can be + * overridden in the specialization of legacy_reducer_downcast for + * a reducer that has a corresponding legacy reducers. + */ + struct type : Reducer { }; +}; + + +namespace internal { +/// @cond internal + +template <typename Value, typename View> +struct reducer_set_get +{ + static View theView; // Declared but not defined + + // sizeof(notchar) is guaranteed larger than 1 + struct notchar { char x[2]; }; + + // check_for_ref returns char if 'get_value' returns by value and notchar + // if 'get_value' returns by reference. + static char check_for_ref(Value, ...); + static notchar check_for_ref(Value&, int); + + enum { GET_VALUE_BY_VALUE = + (1 == sizeof(check_for_ref(theView.view_get_value(), 0))) } ; + + typedef typename condition<GET_VALUE_BY_VALUE, + Value, const Value&>::type get_value_type; + + static void move_in(View& view, Value& v) { view.view_move_in(v); } + static void move_out(View& view, Value& v) { view.view_move_out(v); } + + static void set_value(View& view, const Value& v) + { view.view_set_value(v); } + + static get_value_type get_value(const View& view) + { return view.view_get_value(); } +}; + +template <typename Value> +struct reducer_set_get<Value, Value> +{ + typedef const Value& get_value_type; + + static void move_in(Value& view, Value& v) { view = v; } + static void move_out(Value& view, Value& v) { v = view; } + + static void set_value(Value& view, const Value& v) { view = v; } + + static get_value_type get_value(const Value& view) { return view; } +}; + +/// @endcond + + +/** Base class defining the data layout that is common to all reducers. + */ +template <typename Monoid> +class reducer_base { + typedef typename Monoid::view_type view_type; + + // This makes the reducer a hyper-object. (Partially initialized in + // the derived reducer_content class.) + // + __cilkrts_hyperobject_base m_base; + + // The monoid is allocated here as raw bytes, and is constructed explicitly + // by a call to the monoid_type::construct() function in the constructor of + // the `reducer` subclass. + // + storage_for_object<Monoid> m_monoid; + + // Used for sanity checking at destruction. + // + void* m_initialThis; + + // The leftmost view comes next. It is defined in the derived + // reducer_content class. + + /** @name C-callable wrappers for the C++-coded monoid dispatch functions. + */ + //@{ + + static void reduce_wrapper(void* r, void* lhs, void* rhs); + static void identity_wrapper(void* r, void* view); + static void destroy_wrapper(void* r, void* view); + static void* allocate_wrapper(void* r, __STDNS size_t bytes); + static void deallocate_wrapper(void* r, void* view); + + //@} + +protected: + + /** Constructor. + * + * @param leftmost The address of the leftmost view in the reducer. + */ + reducer_base(char* leftmost) + { + static const cilk_c_monoid c_monoid_initializer = { + (cilk_c_reducer_reduce_fn_t) &reduce_wrapper, + (cilk_c_reducer_identity_fn_t) &identity_wrapper, + (cilk_c_reducer_destroy_fn_t) &destroy_wrapper, + (cilk_c_reducer_allocate_fn_t) &allocate_wrapper, + (cilk_c_reducer_deallocate_fn_t) &deallocate_wrapper + }; + + m_base.__c_monoid = c_monoid_initializer; + m_base.__flags = 0; + m_base.__view_offset = (char*)leftmost - (char*)this; + m_base.__view_size = sizeof(view_type); + m_initialThis = this; + + __cilkrts_hyper_create(&m_base); + } + + /** Destructor. + */ + __CILKRTS_STRAND_STALE(~reducer_base()) + { + // Make sure we haven't been memcopy'd or corrupted + __CILKRTS_ASSERT( + this == m_initialThis || + // Allow for a layout bug that may put the initialThis field one + // word later in 1.0 reducers than in 0.9 and 1.1 reducers. + this == *(&m_initialThis + 1) + ); + __cilkrts_hyper_destroy(&m_base); + } + + /** Monoid data member. + * + * @return A pointer to the reducer’s monoid data member. + */ + Monoid* monoid_ptr() { return &m_monoid.object(); } + + /** Leftmost view data member. + * + * @return A pointer to the reducer’s leftmost view data member. + * + * @note This function returns the address of the *leftmost* view, + * which is unique for the lifetime of the reducer. It is + * intended to be used in constructors and destructors. + * Use the reducer::view() function to access the per-strand + * view instance. + */ + view_type* leftmost_ptr() + { + char* view_addr = (char*)this + m_base.__view_offset; + return reinterpret_cast<view_type*>(view_addr); + } + +public: + + /** @name Access the current view. + * + * These functions return a reference to the instance of the reducer’s + * view that was created for the current strand of a parallel computation + * (and create it if it doesn’t already exist). Note the difference from + * the (private) leftmost_ptr() function, which returns a pointer to the + * _leftmost_ view, which is the same in all strands. + */ + //@{ + + /** Per-strand view instance. + * + * @return A reference to the per-strand view instance. + */ + view_type& view() + { + return *static_cast<view_type *>(__cilkrts_hyper_lookup(&m_base)); + } + + /** @copydoc view() + */ + const view_type& view() const + { + return const_cast<reducer_base*>(this)->view(); + } + + //@} + + /** Initial view pointer field. + * + * @internal + * + * @return a reference to the m_initialThis field. + * + * @note This function is provided for “white-box†testing of the + * reducer layout code. There is never any reason for user code + * to call it. + */ + const void* const & initial_this() const { return m_initialThis; } +}; + +template <typename Monoid> +void reducer_base<Monoid>::reduce_wrapper(void* r, void* lhs, void* rhs) +{ + Monoid* monoid = static_cast<reducer_base*>(r)->monoid_ptr(); + monoid->reduce(static_cast<view_type*>(lhs), + static_cast<view_type*>(rhs)); +} + +template <typename Monoid> +void reducer_base<Monoid>::identity_wrapper(void* r, void* view) +{ + Monoid* monoid = static_cast<reducer_base*>(r)->monoid_ptr(); + monoid->identity(static_cast<view_type*>(view)); +} + +template <typename Monoid> +void reducer_base<Monoid>::destroy_wrapper(void* r, void* view) +{ + Monoid* monoid = static_cast<reducer_base*>(r)->monoid_ptr(); + monoid->destroy(static_cast<view_type*>(view)); +} + +template <typename Monoid> +void* reducer_base<Monoid>::allocate_wrapper(void* r, __STDNS size_t bytes) +{ + Monoid* monoid = static_cast<reducer_base*>(r)->monoid_ptr(); + return monoid->allocate(bytes); +} + +template <typename Monoid> +void reducer_base<Monoid>::deallocate_wrapper(void* r, void* view) +{ + Monoid* monoid = static_cast<reducer_base*>(r)->monoid_ptr(); + monoid->deallocate(static_cast<view_type*>(view)); +} + + +/** Base class defining the data members of a reducer. + * + * @tparam Aligned The `m_view` data member, and therefore the entire + * structure, are cache-line aligned if this parameter + * is `true'. + */ +template <typename Monoid, bool Aligned = Monoid::align_reducer> +class reducer_content; + +/** Base class defining the data members of an aligned reducer. + */ +template <typename Monoid> +class reducer_content<Monoid, true> : public reducer_base<Monoid> +{ + typedef typename Monoid::view_type view_type; + + // The leftmost view is defined as raw bytes. It will be constructed + // by the monoid `construct` function. It is cache-aligned, which + // will push it into a new cache line. Furthermore, its alignment causes + // the reducer as a whole to be cache-aligned, which makes the reducer + // size a multiple of a cache line. Since there is nothing in the reducer + // after the view, all this means that the leftmost view gets one or more + // cache lines all to itself, which prevents false sharing. + // + __CILKRTS_CACHE_ALIGN + char m_leftmost[sizeof(view_type)]; + + /** Test if the reducer is cache-line-aligned. + * + * Used in assertions. + */ + bool reducer_is_cache_aligned() const + { return 0 == ((std::size_t) this & (__CILKRTS_CACHE_LINE__ - 1)); } + +protected: + + /** Constructor. + */ + reducer_content() : reducer_base<Monoid>((char*)&m_leftmost) + { +#ifndef CILK_IGNORE_REDUCER_ALIGNMENT + assert(reducer_is_cache_aligned() && + "Reducer should be cache aligned. Please see comments following this assertion for explanation and fixes."); +#endif + /* "REDUCER SHOULD BE CACHE ALIGNED" ASSERTION. + * + * This Reducer class instantiation specifies cache-line alignment of the + * leftmost view field (and, implicitly, of the reducer itself). You got + * this assertion because a reducer with this class was allocated at a + * non-cache-aligned address, probably because it was allocated on the + * heap with `new`. This can be a problem for two reasons: + * + * 1. If the leftmost view is not on a cache line by itself, there might + * be a slowdown resulting from accesses to the same cache line from + * different threads. + * + * 2. The compiler thinks that reducer is cache-line aligned, but it + * really isn't. If the reducer is contained in a structure, then the + * compiler will believe that the containing structure, and other + * fields contained in it, are also more aligned than they really + * are. In particular, if the structure contains a numeric array that + * is used in a vectorizable loop, then the compiler might generate + * invalid vector instructions, resulting in a runtime error. + * + * The compiler will always allocate reducer variables, and structure + * variables containing reducers, with their required alignment. + * Reducers, and structures containing a reducer, which are allocated + * on the heap with `new` will _not_ be properly aligned. + * + * There are three ways that you can fix this assertion failure. + * + * A. Rewrite your code to use the new-style `reducer< op_XXX<Type> >` + * instead of the legacy `reducer_XXX<type>`. The new-style reducers + * are not declared to be cache-aligned, and will work properly if + * they are not cache-aligned. + * + * B. If you must allocate an old-style reducer or a structure containing + * a reducer on the heap, figure out how to align it correctly. The + * suggested fix is to use `cilk::aligned_new()` and + * `cilk::aligned_delete()` instead of `new` and `delete`, as follows: + * + * Type* ptr = cilk::aligned_new<Type>(constructor-arguments); + * cilk::aligned_delete(ptr); + * + * C. Define the macro CILK_IGNORE_REDUCER_ALIGNMENT, which will suppress + * the assertion check. Do this only if you are comfortable that + * problem (2) above will not occur. + */ + } +}; + +/** Base class defining the data members of an unaligned reducer. + */ +template <typename Monoid> +class reducer_content<Monoid, false> : public reducer_base<Monoid> +{ + typedef typename Monoid::view_type view_type; ///< The view type. + + // Reserve space for the leftmost view. The view will be allocated at an + // aligned offset in this space at runtime, to guarantee that the view + // will get one or more cache lines all to itself, to prevent false + // sharing. + // + // The number of bytes to reserve is determined as follows: + // * Start with the view size. + // * Round up to a multiple of the cache line size, to get the total size + // of the cache lines that will be dedicated to the view. + // * Add (cache line size - 1) filler bytes to guarantee that the reserved + // area will contain a cache-aligned block of the required cache lines, + // no matter where the reserved area starts. + // + char m_leftmost[ + // View size rounded up to multiple cache lines + ( (sizeof(view_type) + __CILKRTS_CACHE_LINE__ - 1) + & ~ (__CILKRTS_CACHE_LINE__ - 1) + ) + // plus filler to allow alignment. + + __CILKRTS_CACHE_LINE__ - 1 + ]; + +protected: + + /** Constructor. Find the first cache-aligned position in the reserved + * area, and pass it to the base constructor as the leftmost view + * address. + */ + reducer_content() : + reducer_base<Monoid>( + (char*)( ((std::size_t)&m_leftmost + __CILKRTS_CACHE_LINE__ - 1) + & ~ (__CILKRTS_CACHE_LINE__ - 1) ) ) + {} +}; + + +} // namespace internal + + +// The __cilkrts_hyperobject_ functions are defined differently depending on +// whether a file is compiled with or without the CILK_STUB option. Therefore, +// reducers compiled in the two modes should be link-time incompatible, so that +// object files compiled with stubbed reducers won't be linked into an +// unstubbed program, or vice versa. We achieve this by putting the reducer +// class definition into the cilk::stub namespace in a stubbed compilation. + +#ifdef CILK_STUB +namespace stub { +#endif + +/** Reducer class. + * + * A reducer is instantiated on a Monoid. The Monoid provides the value + * type, associative reduce function, and identity for the reducer. + * + * @tparam Monoid The monoid class that the reducer is instantiated on. It must model + * the @ref reducers_monoid_concept "monoid concept". + * + * @see @ref pagereducers + */ +template <class Monoid> +class reducer : public internal::reducer_content<Monoid> +{ + typedef internal::reducer_content<Monoid> base; + using base::monoid_ptr; + using base::leftmost_ptr; + public: + typedef Monoid monoid_type; ///< The monoid type. + typedef typename Monoid::value_type value_type; ///< The value type. + typedef typename Monoid::view_type view_type; ///< The view type. + + private: + typedef internal::reducer_set_get<value_type, view_type> set_get; + + reducer(const reducer&); ///< Disallow copying. + reducer& operator=(const reducer&); ///< Disallow assignment. + + public: + + /** @name Constructors + * + * All reducer constructors call the static `construct()` function of the monoid class to + * construct the reducer's monoid and leftmost view. + * + * The reducer constructor arguments are simply passed through to the construct() function. + * Thus, the constructor parameters accepted by a particular reducer class are determined + * by its monoid class. + */ + //@{ + + /** 0 – 6 const reference parameters. + */ + //@{ + + reducer() + { + monoid_type::construct(monoid_ptr(), leftmost_ptr()); + } + + template <typename T1> + reducer(const T1& x1) + { + monoid_type::construct(monoid_ptr(), leftmost_ptr(), x1); + } + + template <typename T1, typename T2> + reducer(const T1& x1, const T2& x2) + { + monoid_type::construct(monoid_ptr(), leftmost_ptr(), x1, x2); + } + + template <typename T1, typename T2, typename T3> + reducer(const T1& x1, const T2& x2, const T3& x3) + { + monoid_type::construct(monoid_ptr(), leftmost_ptr(), x1, x2, x3); + } + + template <typename T1, typename T2, typename T3, typename T4> + reducer(const T1& x1, const T2& x2, const T3& x3, const T4& x4) + { + monoid_type::construct(monoid_ptr(), leftmost_ptr(), x1, x2, x3, x4); + } + + template <typename T1, typename T2, typename T3, typename T4, typename T5> + reducer(const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5) + { + monoid_type::construct(monoid_ptr(), leftmost_ptr(), x1, x2, x3, x4, x5); + } + + template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> + reducer(const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5, const T6& x6) + { + monoid_type::construct(monoid_ptr(), leftmost_ptr(), x1, x2, x3, x4, x5, x6); + } + + //@} + + /** 1 non-const reference parameter. + */ + //@{ + + template <typename T1> + reducer(T1& x1) + { + monoid_type::construct(monoid_ptr(), leftmost_ptr(), x1); + } + + //@} + + /** Destructor. + */ + __CILKRTS_STRAND_STALE(~reducer()) + { + leftmost_ptr()->~view_type(); + monoid_ptr()->~monoid_type(); + } + + //@{ + /** Get the monoid. + * + * @return A reference to the monoid object belonging to this reducer. + */ + Monoid& monoid() { return *monoid_ptr(); } + + const Monoid& monoid() const + { return const_cast<reducer*>(this)->monoid(); } + //@} + + //@{ + /** Access the current view. + * + * Return a reference to the instance of the reducer’s view that was + * created for the current strand of a parallel computation (and create + * it if it doesn’t already exist). + */ + view_type& view() { return base::view(); } + const view_type& view() const { return base::view(); } + //@} + + + /** @name Dereference the reducer to get the view. + * + * “Dereferencing†a reducer yields the view for the current strand. The + * view, in turn, acts as a proxy for its contained value, exposing only + * those operations which are consistent with the reducer’s monoid. Thus, + * all modifications of the reducer’s accumulator variable are written as + * + * *reducer OP ... + * + * or + * + * reducer->func(...) + * + * (The permitted operations on a reducer’s accumulator are listed in the + * documentation for that particular kind of reducer.) + * + * @note `*r` is a synonym for `r.view()`. Recommended style is to use + * `*r` (or `r->`) in the common case where code is simply + * updating the accumulator variable wrapped in the view, and to + * use `r.view()` in the unusual case where it is desirable to + * call attention to the view itself. + */ + //@{ + + //@{ + /** Dereference operator. + * + * @return A reference to the per-strand view instance. + */ + view_type& operator*() { return view(); } + view_type const& operator*() const { return view(); } + //@} + + //@{ + /** Pointer operator. + * + * @return A pointer to the per-strand view instance. + */ + view_type* operator->() { return &view(); } + view_type const* operator->() const { return &view(); } + //@} + + //@{ + /** Deprecated view access. + * + * `r()` is a synonym for `*r` which was used with early versions of Cilk + * reducers. `*r` is now the preferred usage. + * + * @deprecated Use operator*() instead of operator()(). + * + * @return A reference to the per-strand view instance. + */ + view_type& operator()() { return view(); } + view_type const& operator()() const { return view(); } + //@} + + //@} + + /** @name Set and get the value. + * + * These functions are used to set an initial value for the reducer before + * starting the reduction, or to get the final value after the reduction + * is complete. + * + * @note These functions are completely different from the view + * operations that are made available via operator*() and + * operator->(), which are used to _modify_ the reducer’s value + * _during_ the reduction. + * + * @warning These functions _can_ be called at any time, and in + * general, they will refer to the value contained in the view + * for the current strand. However, using them other than to + * set the reduction’s initial value or get its final value + * will almost always result in undefined behavior. + */ + //@{ + + /** Move a value into the reducer. + * + * This function is used to set the initial value of the reducer’s + * accumulator variable by either copying or _moving_ the value of @a obj + * into it. Moving a value can often be performed in constant time, even + * for large container objects, but has the side effect of leaving the + * value of @a obj undefined. (See the description of the + * @ref move_in_wrapper class for a discussion of moving values.) + * + * @par Usage + * A move_in() call to initialize a reducer is often paired with a + * move_out() call to get its final value: + * + * reducer<Type> xr; + * xr.move_in(x); + * … do the reduction … + * xr.move_out(x); + * + * @par Assumptions + * - You cannot assume either that this will function will copy its + * value or that it will move it. + * - You must assume that the value of @a obj will be undefined + * after the call to move_in(). + * - You can assume that move_in() will be at least as efficient as + * set_value(), and you should therefore prefer move_in() unless + * you need the value of @a obj to be unchanged after the call. + * (But you should usually prefer the move-in constructor over a + * move_in() call — see the note below.) + * + * @note The behavior of a default constructor followed by move-in + * initialization: + * + * reducer<Type> xr; + * xr.move_in(x); + * + * @note is not necessarily the same as a move-in constructor: + * + * reducer<Type> xr(move_in(x)); + * + * @note In particular, when @a Type is a container type with a + * non-empty allocator, the move-in constructor will create the + * accumulator variable with the same allocator as the input + * argument @a x, while the default constructor will create the + * accumulator variable with a default allocator. The mismatch of + * allocators in the latter case means that the input argument + * @a x may have to be copied in linear time instead of being + * moved in constant time. + * + * @note Best practice is to prefer the move-in constructor over the + * move-in function unless the move-in function is required for + * some specific reason. + * + * @warning Calling this function other than to set the initial value + * for a reduction will almost always result in undefined + * behavior. + * + * @param obj The object containing the value that will be moved into the + * reducer. + * + * @post The reducer contains the value that was initially in @a obj. + * @post The value of @a obj is undefined. + * + * @see set_value() + */ + void move_in(value_type& obj) { set_get::move_in(view(), obj);} + + /** Move the value out of the reducer. + * + * This function is used to retrieve the final value of the reducer’s + * accumulator variable by either copying or _moving_ the value of @a obj + * into it. Moving a value can often be performed in constant time, even + * for large container objects, but has the side effect of leaving the + * value of the reducer’s accumulator variable undefined. (See the + * description of the @ref move_in_wrapper class for a discussion of + * moving values.) + * + * @par Usage + * A move_in() call to initialize a reducer is often paired with a + * move_out() call to get its final value: + * + * reducer<Type> xr; + * xr.move_in(x); + * … do the reduction … + * xr.move_out(x); + * + * @par Assumptions + * - You cannot assume either that this will function will copy its + * value or that it will move it. + * - You must assume that the value of the reducer’s accumulator + * variable will be undefined after the call to move_out(). + * - You can assume that move_out() will be at least as efficient as + * get_value(), and you should therefore prefer move_out() unless + * you need the accumulator variable to be preserved after the + * call. + * + * @warning Calling this function other than to retrieve the final + * value of a reduction will almost always result in undefined + * behavior. + * + * @param obj The object that the value of the reducer will be moved into. + * + * @post @a obj contains the value that was initially in the reducer. + * @post The value of the reducer is undefined. + * + * @see get_value() + */ + void move_out(value_type& obj) { set_get::move_out(view(), obj); } + + /** Set the value of the reducer. + * + * This function sets the initial value of the reducer’s accumulator + * variable to the value of @a obj. + * + * @note The behavior of a default constructor followed by + * initialization: + * + * reducer<Type> xr; + * xr.set_value(x); + * + * @note is not necessarily the same as a value constructor: + * + * reducer<Type> xr(x); + * + * @note In particular, when @a Type is a container type with a + * non-empty allocator, the value constructor will create the + * accumulator variable with the same allocator as the input + * argument @a x, while the default constructor will create the + * accumulator variable with a default allocator. + * + * @warning Calling this function other than to set the initial value + * for a reduction will almost always result in undefined + * behavior. + * + * @param obj The object containing the value that will be copied into + * the reducer. + * + * @post The reducer contains a copy of the value in @a obj. + * + * @see move_in() + */ + void set_value(const value_type& obj) { set_get::set_value(view(), obj); } + + /** Get the value of the reducer. + * + * This function gets the final value of the reducer’s accumulator + * variable. + * + * @warning Calling this function other than to retrieve the final + * value of a reduction will almost always result in undefined + * behavior. + * + * @return A reference to the value contained in the reducer. + * + * @see move_out() + */ + typename set_get::get_value_type get_value() const + { return set_get::get_value(view()); } + + //@} + + /** Implicit downcast to legacy reducer wrapper, if any. + * + * @see legacy_reducer_downcast + */ + operator typename legacy_reducer_downcast<reducer>::type& () + { + typedef typename legacy_reducer_downcast<reducer>::type downcast_type; + return *reinterpret_cast<downcast_type*>(this); + } + + + /** Implicit downcast to legacy reducer wrapper, if any. + * + * @see legacy_reducer_downcast + */ + operator const typename legacy_reducer_downcast<reducer>::type& () const + { + typedef typename legacy_reducer_downcast<reducer>::type downcast_type; + return *reinterpret_cast<const downcast_type*>(this); + } +}; + +#ifdef CILK_STUB +} // namespace stub +using stub::reducer; +#endif + +} // end namespace cilk + +#endif /* __cplusplus */ + +/** @page page_reducers_in_c Creating and Using Reducers in C + * + * @tableofcontents + * + * The Cilk runtime supports reducers written in C as well as in C++. The basic logic is the + * same, but the implementation details are very different. The C++ reducer implementation uses + * templates heavily to create very generic components. The C reducer implementation uses + * macros, which are a much blunter instrument. The most immediate consequence is that the + * monoid/view/reducer architecture is mostly implicit rather than explicit in C reducers. + * + * @section reducers_c_overview Overview of Using Reducers in C + * + * The basic usage pattern for C reducers is: + * + * 1. Create and initialize a reducer object. + * 2. Tell the Cilk runtime about the reducer. + * 3. Update the value contained in the reducer in a parallel computation. + * 4. Tell the Cilk runtime that you are done with the reducer. + * 5. Retrieve the value from the reducer. + * + * @subsection reducers_c_creation Creating and Initializing a C Reducer + * + * The basic pattern for creating and initializing a reducer object in C is + * + * CILK_C_DECLARE_REDUCER(value-type) reducer-name = + * CILK_C_INIT_REDUCER(value-type, + * reduce-function, + * identity-function, + * destroy-function, + * initial-value); + * + * This is simply an initialized definition of a variable named _reducer-name_. The + * @ref CILK_C_DECLARE_REDUCER macro expands to an anonymous `struct` declaration for a reducer + * object containing a view of type _value-type_, and the @ref CILK_C_INIT_REDUCER macro + * expands to a struct initializer. + * + * @subsection reducers_c_reduce_func Reduce Functions + * + * The reduce function for a reducer is called when a parallel execution strand terminates, to + * combine the values computed by the terminating strand and the strand to its left. It takes + * three arguments: + * + * - `void* reducer` — the address of the reducer. + * - `void* left` — the address of the value for the left strand. + * - `void* right` — the address of the value for the right (terminating) strand. + * + * It must apply the reducer’s reduction operation to the `left` and `right` values, leaving + * the result in the `left` value. The `right` value is undefined after the reduce function + * call. + * + * @subsection reducers_c_identity_func Identity Functions + * + * The identity function for a reducer is called when a parallel execution strand begins, to + * initialize its value to the reducer’s identity value. It takes two arguments: + * + * - `void* reducer` — the address of the reducer. + * - `void* v` — the address of a freshly allocated block of memory of size + * `sizeof(value-type)`. + * + * It must initialize the memory pointed to by `v` so that it contains the reducer’s identity + * value. + * + * @subsection reducers_c_destroy_func Destroy Functions + * + * The destroy function for a reducer is called when a parallel execution strand terminates, to + * do any necessary cleanup before its value is deallocated. It takes two arguments: + * + * - `void* reducer` — the address of the reducer. + * - `void* p` — the address of the value for the terminating strand. + * + * It must release any resources belonging to the value pointed to by `p`, to avoid a resource + * leak when the memory containing the value is deallocated. + * + * The runtime function `__cilkrts_hyperobject_noop_destroy` can be used for the destructor + * function if the reducer’s values do not need any cleanup. + * + * @subsection reducers_c_register Tell the Cilk Runtime About the Reducer + * + * Call the @ref CILK_C_REGISTER_REDUCER macro to register the reducer with the Cilk runtime: + * + * CILK_C_REGISTER_REDUCER(reducer-name); + * + * The runtime will manage reducer values for all registered reducers when parallel execution + * strands begin and end. + * + * @subsection reducers_c_update Update the Value Contained in the Reducer + * + * The @ref REDUCER_VIEW macro returns a reference to the reducer’s value for the current + * parallel strand: + * + * REDUCER_VIEW(reducer-name) = REDUCER_VIEW(reducer-name) OP x; + * + * C++ reducer views restrict access to the wrapped value so that it can only be modified in + * ways consistent with the reducer’s operation. No such protection is provided for C reducers. + * It is + * entirely the responsibility of the user to avoid modifying the value in any + * inappropriate way. + * + * @subsection c_reducers_unregister Tell the Cilk Runtime That You Are Done with the Reducer + * + * When the parallel computation is complete, call the @ref CILK_C_UNREGISTER_REDUCER macro to + * unregister the reducer with the Cilk runtime: + * + * CILK_C_UNREGISTER_REDUCER(reducer-name); + * + * The runtime will stop managing reducer values for the reducer. + * + * @subsection c_reducers_retrieve Retrieve the Value from the Reducer + * + * When the parallel computation is complete, use the @ref REDUCER_VIEW macro to retrieve the + * final value computed by the reducer. + * + * @subsection reducers_c_example_custom Example — Creating and Using a Custom C Reducer + * + * The `IntList` type represents a simple list of integers. + * + * struct _intListNode { + * int value; + * _intListNode* next; + * } IntListNode; + * typedef struct { IntListNode* head; IntListNode* tail; } IntList; + * + * // Initialize a list to be empty + * void IntList_init(IntList* list) { list->head = list->tail = 0; } + * + * // Append an integer to the list + * void IntList_append(IntList* list, int x) + * { + * IntListNode* node = (IntListNode*) malloc(sizeof(IntListNode)); + * if (list->tail) list->tail->next = node; else list->head = node; + * list->tail = node; + * } + * + * // Append the right list to the left list, and leave the right list empty + * void IntList_concat(IntList* left, IntList* right) + * { + * if (left->head) { + * left->tail->next = right->head; + * if (right->tail) left->tail = right->tail; + * } + * else { + * *left = *right; + * } + * IntList_init(*right); + * } + * + * This code creates a reducer that supports creating an `IntList` by appending values to it. + * + * void identity_IntList(void* reducer, void* list) + * { + * IntList_init((IntList*)list); + * } + * + * void reduce_IntList(void* reducer, void* left, void* right) + * { + * IntList_concat((IntList*)left, (IntList*)right); + * } + * + * CILK_C_DECLARE_REDUCER(IntList) my_list_int_reducer = + * CILK_C_INIT_REDUCER(IntList, + * reduce_int_list, + * identity_int_list, + * __cilkrts_hyperobject_noop_destroy); + * // Initial value omitted // + * ListInt_init(&REDUCER_VIEW(my_int_list_reducer)); + * + * CILK_C_REGISTER_REDUCER(my_int_list_reducer); + * cilk_for (int i = 0; i != n; ++i) { + * IntList_append(&REDUCER_VIEW(my_int_list_reducer), a[i]); + * } + * CILK_C_UNREGISTER_REDUCER(my_int_list_reducer); + * + * IntList result = REDUCER_VIEW(my_int_list_reducer); + * + * @section reducers_c_predefined Predefined C Reducers + * + * Some of the predefined reducer classes in the Cilk library come with a set of predefined + * macros to provide the same capabilities in C. In general, two macros are provided for each + * predefined reducer family: + * + * - `CILK_C_REDUCER_operation(reducer-name, type-name, initial-value)` — Declares a + * reducer object named _reducer-name_ with initial value _initial-value_ to perform + * a reduction using the _operation_ on values of the type specified by _type-name_. + * This is the equivalent of the general code described in @ref reducers_c_creation : + * + * CILK_C_DECLARE_REDUCER(type) reducer-name = + * CILK_C_INIT_REDUCER(type, ..., initial-value); + * + * where _type_ is the C type corresponding to _type_name_. See @ref reducers_c_type_names + * below for the _type-names_ that you can use. + * + * - `CILK_C_REDUCER_operation_TYPE(type-name)` — Expands to the `typedef` name for the type + * of the reducer object declared by + * `CILK_C_REDUCER_operation(reducer-name, type-name, initial-value)`. + * + * See @ref reducers_c_example_predefined. + * + * The predefined C reducers are: + * + * | Operation | Name | Documentation | + * |-------------------|---------------|-------------------------------| + * | addition | `OPADD` | @ref ReducersAdd | + * | bitwise and | `OPAND` | @ref ReducersAnd | + * | bitwise or | `OPOR` | @ref ReducersOr | + * | bitwise xor | `OPXOR` | @ref ReducersXor | + * | multiplication | `OPMUL` | @ref ReducersMul | + * | minimum | `MIN` | @ref ReducersMinMax | + * | minimum & index | `MIN_INDEX` | @ref ReducersMinMax | + * | maximum | `MIN` | @ref ReducersMinMax | + * | maximum & index | `MIN_INDEX` | @ref ReducersMinMax | + * + * @subsection reducers_c_type_names Numeric Type Names + * + * The type and function names created by the C reducer definition macros incorporate both the + * reducer kind (`opadd`, `opxor`, etc.) and the value type of the reducer (`int`, `double`, + * etc.). The value type is represented by a _numeric type name_ string. The types supported + * in C reducers, and their corresponding numeric type names, are given in the following table: + * + * | Type | Numeric Type Name | + * |-----------------------|-------------------------------| + * | `char` | `char` | + * | `unsigned char` | `uchar` | + * | `signed char` | `schar` | + * | `wchar_t` | `wchar_t` | + * | `short` | `short` | + * | `unsigned short` | `ushort` | + * | `int` | `int` | + * | `unsigned int` | `uint` | + * | `unsigned int` | `unsigned` (alternate name) | + * | `long` | `long` | + * | `unsigned long` | `ulong` | + * | `long long` | `longlong` | + * | `unsigned long long` | `ulonglong` | + * | `float` | `float` | + * | `double` | `double` | + * | `long double` | `longdouble` | + * + * @subsection reducers_c_example_predefined Example — Using a Predefined C Reducer + * + * To compute the sum of all the values in an array of `unsigned int`: + * + * CILK_C_REDUCER_OPADD(sum, uint, 0); + * CILK_C_REGISTER_REDUCER(sum); + * cilk_for(int i = 0; i != n; ++i) { + * REDUCER_VIEW(sum) += a[i]; + * } + * CILK_C_UNREGISTER_REDUCER(sum); + * printf("The sum is %u\n", REDUCER_VIEW(sum)); + */ + + + /** @name C language reducer macros + * + * These macros are used to declare and work with reducers in C code. + * + * @see @ref page_reducers_in_c + */ + //@{ + +/// @cond internal + +/** @name Compound identifier macros. + * + * These macros are used to construct an identifier by concatenating two or three identifiers. + */ +//@{ + +/** Expand to an identifier formed by concatenating two identifiers. + */ +#define __CILKRTS_MKIDENT(a,b) __CILKRTS_MKIDENT_IMP(a,b,) + +/** Expand to an identifier formed by concatenating three identifiers. + */ +#define __CILKRTS_MKIDENT3(a,b,c) __CILKRTS_MKIDENT_IMP(a,b,c) + +/** Helper macro to do the concatenation. + */ +#define __CILKRTS_MKIDENT_IMP(a,b,c) a ## b ## c + +//@} + +/** Compiler-specific keyword for the “type of†operator. + */ +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) +# define _Typeof __typeof__ +#endif + +/** @name Predefined reducer function declaration macros. + * + * These macros are used to create the function headers for the identity, reduction, + * and destructor functions for a builtin reducer family. The macro can be followed by + * a semicolon to create a declaration, or by a brace-enclosed body to create a definition. + */ +//@{ + +/** Create an identity function header. + * + * @note The name of the function’s value pointer parameter will always be `v`. + * + * @param name The reducer family name. + * @param tn The type name. + */ +#define __CILKRTS_DECLARE_REDUCER_IDENTITY(name,tn) CILK_EXPORT \ + void __CILKRTS_MKIDENT3(name,_identity_,tn)(void* key, void* v) + +/** Create a reduction function header. + * + * @param name The reducer family name. + * @param tn The type name. + * @param l The name to use for the function’s left value pointer parameter. + * @param r The name to use for the function’s right value pointer parameter. + */ +#define __CILKRTS_DECLARE_REDUCER_REDUCE(name,tn,l,r) CILK_EXPORT \ + void __CILKRTS_MKIDENT3(name,_reduce_,tn)(void* key, void* l, void* r) + +/** Create a destructor function header. + * + * @param name The reducer family name. + * @param tn The type name. + * @param p The name to use for the function’s value pointer parameter. + */ +#define __CILKRTS_DECLARE_REDUCER_DESTROY(name,tn,p) CILK_EXPORT \ + void __CILKRTS_MKIDENT3(name,_destroy_,tn)(void* key, void* p) + +//@} + +/// @endcond + + +/*************************************************************************** + * Real implementation + ***************************************************************************/ + +/** Declaration of a C reducer structure type. + * + * This macro expands into an anonymous structure declaration for a C reducer structure + * which contains a @a Type value. For example: + * + * CILK_C_DECLARE_REDUCER(int) my_add_int_reducer = + * CILK_C_INIT_REDUCER(int, …); + * + * @param Type The type of the value contained in the reducer object. + * + * @see @ref reducers_c_creation + */ +#define CILK_C_DECLARE_REDUCER(Type) struct { \ + __cilkrts_hyperobject_base __cilkrts_hyperbase; \ + __CILKRTS_CACHE_ALIGN Type value; \ + } + +/** Initializer for a C reducer structure. + * + * This macro expands into a brace-enclosed structure initializer for a C reducer structure + * that was declared with `CILK_C_DECLARE_REDUCER(Type)`. For example: + * + * CILK_C_DECLARE_REDUCER(int) my_add_int_reducer = + * CILK_C_INIT_REDUCER(int, + * add_int_reduce, + * add_int_identity, + * __cilkrts_hyperobject_noop_destroy, + * 0); + * + * @param Type The type of the value contained in the reducer object. Must be the same as + * the @a Type argument of the CILK_C_DECLARE_REDUCER macro call that created + * the reducer. + * @param Reduce The address of the @ref reducers_c_reduce_func "reduce function" for the + * reducer. + * @param Identity The address of the @ref reducers_c_identity_func "identity function" for + * the reducer. + * @param Destroy The address of the @ref reducers_c_destroy_func "destroy function" for the + * reducer. + * @param ... The initial value for the reducer. (A single expression if @a Type is a + * scalar type; a list of values if @a Type is a struct or array type.) + * + * @see @ref reducers_c_creation + */ + +#define CILK_C_INIT_REDUCER(Type, Reduce, Identity, Destroy, ...) \ + { { { Reduce \ + , Identity \ + , Destroy \ + , __cilkrts_hyperobject_alloc \ + , __cilkrts_hyperobject_dealloc \ + } \ + , 0 \ + , __CILKRTS_CACHE_LINE__ \ + , sizeof(Type) \ + } \ + , __VA_ARGS__ \ + } + +/** Register a reducer with the Cilk runtime. + * + * The runtime will manage reducer values for all registered reducers when parallel execution + * strands begin and end. For example: + * + * CILK_C_REGISTER_REDUCER(my_add_int_reducer); + * cilk_for (int i = 0; i != n; ++i) { + * … + * } + * + * @param Expr The reducer to be registered. + * + * @see @ref page_reducers_in_c + */ +#define CILK_C_REGISTER_REDUCER(Expr) \ + __cilkrts_hyper_create(&(Expr).__cilkrts_hyperbase) + +/** Unregister a reducer with the Cilk runtime. + * + * The runtime will stop managing reducer values for a reducer after it is unregistered. For + * example: + * + * cilk_for (int i = 0; i != n; ++i) { + * … + * } + * CILK_C_UNREGISTER_REDUCER(my_add_int_reducer); + * + * @param Expr The reducer to be unregistered. + * + * @see @ref page_reducers_in_c + */ +#define CILK_C_UNREGISTER_REDUCER(Expr) \ + __cilkrts_hyper_destroy(&(Expr).__cilkrts_hyperbase) + +/** Get the current view for a reducer. + * + * The `REDUCER_VIEW(reducer-name)` returns a reference to the reducer’s value for the + * current parallel strand. This can be used to initialize thevalue of the reducer before it + * is used, to modify the value of the reducer on the current parallel strand, or to retrieve + * the final value of the reducer at the end of the parallel computation. + * + * REDUCER_VIEW(my_add_int_reducer) = REDUCER_VIEW(my_add_int_reducer) + x; + * + * @note C++ reducer views restrict access to the wrapped value so that it can only be + * modified in ways consistent with the reducer’s operation. No such protection is provided + * for C reducers. It is entirely the responsibility of the user to refrain from modifying the + * value in any inappropriate way. + * + * @param Expr The reducer whose value is to be returned. + * + * @see @ref page_reducers_in_c + */ +#define REDUCER_VIEW(Expr) (*(_Typeof((Expr).value)*) \ + __cilkrts_hyper_lookup(&(Expr).__cilkrts_hyperbase)) + +//@} C language reducer macros + +#endif // CILK_REDUCER_H_INCLUDED diff --git a/libcilkrts/include/cilk/reducer_file.h b/libcilkrts/include/cilk/reducer_file.h new file mode 100644 index 00000000000..75af994e9d4 --- /dev/null +++ b/libcilkrts/include/cilk/reducer_file.h @@ -0,0 +1,37 @@ +/* + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + + diff --git a/libcilkrts/include/cilk/reducer_list.h b/libcilkrts/include/cilk/reducer_list.h new file mode 100644 index 00000000000..fc0be1e03d3 --- /dev/null +++ b/libcilkrts/include/cilk/reducer_list.h @@ -0,0 +1,1127 @@ +/* reducer_list.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file reducer_list.h + * + * @brief Defines classes for doing parallel list creation by appending or + * prepending. + * + * @ingroup ReducersList + * + * @see ReducersList + */ + +#ifndef REDUCER_LIST_H_INCLUDED +#define REDUCER_LIST_H_INCLUDED + +#include <cilk/reducer.h> +#include <list> + +/** @defgroup ReducersList List Reducers + * + * List append and prepend reducers allow the creation of a standard list by + * concatenating a set of lists or values in parallel. + * + * @ingroup Reducers + * + * You should be familiar with @ref pagereducers "Cilk reducers", described in + * file `reducers.md`, and particularly with @ref reducers_using, before trying + * to use the information in this file. + * + * @section redlist_usage Usage Example + * + * // Create a list containing the labels of the nodes of a tree in + * // “inorder†(left subtree, root, right subtree). + * + * struct Tree { Tree* left; Tree* right; string label; ... }; + * + * list<string> x; + * cilk::reducer< cilk::op_list_append<string> > xr(cilk::move_in(x)); + * collect_labels(tree, xr); + * xr.move_out(x); + * + * void collect_labels(Tree* node, + * cilk::reducer< cilk::op_list_append<string> >& xr) + * { + * if (node) { + * cilk_spawn collect_labels(node->left, xr); + * xr->push_back(node->label); + * collect_labels(node->right, xr); + * cilk_sync; + * } + * } + * + * @section redlist_monoid The Monoid + * + * @subsection redlist_monoid_values Value Set + * + * The value set of a list reducer is the set of values of the class + * `std::list<Type, Allocator>`, which we refer to as “the reducer’s list + * typeâ€. + * + * @subsection redlist_monoid_operator Operator + * + * The operator of a list append reducer is defined as + * + * x CAT y == (every element of x, followed by every element of y) + * + * The operator of a list prepend reducer is defined as + * + * x RCAT y == (every element of y, followed by every element of x) + * + * @subsection redlist_monoid_identity Identity + * + * The identity value of a list reducer is the empty list, which is the value + * of the expression `std::list<Type, Allocator>([allocator])`. + * + * @section redlist_operations Operations + * + * In the operation descriptions below, the type name `List` refers to the + * reducer’s string type, `std::list<Type, Allocator>`. + * + * @subsection redlist_constructors Constructors + * + * Any argument list which is valid for a `std::list` constructor is valid for + * a list reducer constructor. The usual move-in constructor is also provided: + * + * reducer(move_in(List& variable)) + * + * A list reducer with no constructor arguments, or with only an allocator + * argument, will initially contain the identity value, an empty list. + * + * @subsection redlist_get_set Set and Get + * + * r.set_value(const List& value) + * const List& = r.get_value() const + * r.move_in(List& variable) + * r.move_out(List& variable) + * + * @subsection redlist_view_ops View Operations + * + * The view of a list append reducer provides the following member functions: + * + * void push_back(const Type& element) + * void insert_back(List::size_type n, const Type& element) + * template <typename Iter> void insert_back(Iter first, Iter last) + * void splice_back(List& x) + * void splice_back(List& x, List::iterator i) + * void splice_back(List& x, List::iterator first, List::iterator last) + * + * The view of a list prepend reducer provides the following member functions: + * + * void push_front(const Type& element) + * void insert_front(List::size_type n, const Type& element) + * template <typename Iter> void insert_front(Iter first, Iter last) + * void splice_front(List& x) + * void splice_front(List& x, List::iterator i) + * void splice_front(List& x, List::iterator first, List::iterator last) + * + * The `push_back` and `push_front` functions are the same as the + * corresponding `std::list` functions. The `insert_back`, `splice_back`, + * `insert_front`, and `splice_front` functions are the same as the + * `std::list` `insert` and `splice` functions, with the first parameter + * fixed to the end or beginning of the list, respectively. + * + * @section redlist_performance Performance Considerations + * + * An efficient reducer requires that combining the values of two views (using + * the view `reduce()` function) be a constant-time operations. Two lists can + * be merged in constant time using the `splice()` function if they have the + * same allocator. Therefore, the lists for new views are created (by the view + * identity constructor) using the same allocator as the list that was created + * when the reducer was constructed. + * + * The performance of adding elements to a list reducer depends on the view + * operations that are used: + * + * * The `push` functions add a single element to the list, and therefore + * take constant time. + * * An `insert` function that inserts _N_ elements adds each of them + * individually, and therefore takes _O(N)_ time. + * * A `splice` function that inserts _N_ elements just adjusts a couple of + * pointers, and therefore takes constant time, _if the splice is from a + * list with the same allocator as the reducer_. Otherwise, it is + * equivalent to an `insert`, and takes _O(N)_ time. + * + * This means that for best performance, if you will be adding elements to a + * list reducer in batches, you should `splice` them from a list having the + * same allocator as the reducer. + * + * The reducer `move_in` and `move_out` functions do a constant-time `swap` if + * the variable has the same allocator as the reducer, and a linear-time copy + * otherwise. + * + * Note that the allocator of a list reducer is determined when the reducer is + * constructed. The following two examples may have very different behavior: + * + * list<Element, Allocator> a_list; + * + * reducer< list_append<Element, Allocator> reducer1(move_in(a_list)); + * ... parallel computation ... + * reducer1.move_out(a_list); + * + * reducer< list_append<Element, Allocator> reducer2; + * reducer2.move_in(a_list); + * ... parallel computation ... + * reducer2.move_out(a_list); + * + * * `reducer1` will be constructed with the same allocator as `a_list`, + * because the list was was specified in the constructor. The `move_in` + * and`move_out` can therefore be done with a `swap` in constant time. + * * `reducer2` will be constructed with a _default_ allocator, + * “`Allocator()`â€, which may or may not be the same as the allocator of + * `a_list`. Therefore, the `move_in` and `move_out` may have to be done + * with a copy in _O(N)_ time. + * + * (All instances of an allocator type with no internal state (like + * `std::allocator`) are “the sameâ€. You only need to worry about the “same + * allocator†issue when you create list reducers with custom allocator types.) + * + * @section redlist_types Type and Operator Requirements + * + * `std::list<Type, Allocator>` must be a valid type. + */ + + +namespace cilk { + +namespace internal { + +/** @ingroup ReducersList */ +//@{ + +/** Base class for list append and prepend view classes. + * + * @note This class provides the definitions that are required for a class + * that will be used as the parameter of a @ref list_monoid_base + * specialization. + * + * @tparam Type The list element type (not the list type). + * @tparam Allocator The list's allocator class. + * + * @see ReducersList + * @see list_monoid_base + */ +template <typename Type, typename Allocator> +class list_view_base +{ +protected: + /// The type of the contained list. + typedef std::list<Type, Allocator> list_type; + + /// The list accumulator variable. + list_type m_value; + +public: + + /** @name Monoid support. + */ + //@{ + + /// Required by @ref monoid_with_view + typedef list_type value_type; + + /// Required by @ref list_monoid_base + Allocator get_allocator() const + { + return m_value.get_allocator(); + } + + //@} + + + /** @name Constructors. + */ + //@{ + + /// Standard list constructor. + explicit list_view_base(const Allocator& a = Allocator()) : m_value(a) {} + explicit list_view_base( + typename list_type::size_type n, + const Type& value = Type(), + const Allocator& a = Allocator() ) : m_value(n, value, a) {} + template <typename Iter> + list_view_base(Iter first, Iter last, const Allocator& a = Allocator()) : + m_value(first, last, a) {} + list_view_base(const list_type& list) : m_value(list) {} + + /// Move-in constructor. + explicit list_view_base(move_in_wrapper<value_type> w) + : m_value(w.value().get_allocator()) + { + m_value.swap(w.value()); + } + + //@} + + /** @name Reducer support. + */ + //@{ + + /// Required by reducer::move_in() + void view_move_in(value_type& v) + { + if (m_value.get_allocator() == v.get_allocator()) + // Equal allocators. Do a (fast) swap. + m_value.swap(v); + else + // Unequal allocators. Do a (slow) copy. + m_value = v; + v.clear(); + } + + /// Required by reducer::move_out() + void view_move_out(value_type& v) + { + if (m_value.get_allocator() == v.get_allocator()) + // Equal allocators. Do a (fast) swap. + m_value.swap(v); + else + // Unequal allocators. Do a (slow) copy. + v = m_value; + m_value.clear(); + } + + /// Required by reducer::set_value() + void view_set_value(const value_type& v) { m_value = v; } + + /// Required by reducer::get_value() + value_type const& view_get_value() const { return m_value; } + + // Required by legacy wrapper get_reference() + value_type & view_get_reference() { return m_value; } + value_type const& view_get_reference() const { return m_value; } + + //@} +}; + + +/** Base class for list append and prepend monoid classes. + * + * The key to efficient reducers is that the `identity` operation, which + * creates a new per-strand view, and the `reduce` operation, which combines + * two per-strand views, must be constant-time operations. Two lists can be + * concatenated in constant time only if they have the same allocator. + * Therefore, all the per-strand list accumulator variables must be created + * with the same allocator as the leftmost view list. + * + * This means that a list reduction monoid must have a copy of the allocator + * of the leftmost view’s list, so that it can use it in the `identity` + * operation. This, in turn, requires that list reduction monoids have a + * specialized `construct()` function, which constructs the leftmost view + * before the monoid, and then passes the leftmost view’s allocator to the + * monoid constructor. + * + * @tparam View The list append or prepend view class. + * @tparam Align If `false` (the default), reducers instantiated on this + * monoid will be naturally aligned (the Cilk library 1.0 + * behavior). If `true`, reducers instantiated on this monoid + * will be cache-aligned for binary compatibility with + * reducers in Cilk library version 0.9. + * + * @see ReducersList + * @see list_view_base + */ +template <typename View, bool Align> +class list_monoid_base : public monoid_with_view<View, Align> +{ + typedef typename View::value_type list_type; + typedef typename list_type::allocator_type allocator_type; + allocator_type m_allocator; + + using monoid_base<list_type, View>::provisional; + +public: + + /** Constructor. + * + * There is no default constructor for list monoids, because the allocator + * must always be specified. + * + * @param allocator The list allocator to be used when + * identity-constructing new views. + */ + list_monoid_base(const allocator_type& allocator = allocator_type()) : + m_allocator(allocator) {} + + /** Create an identity view. + * + * List view identity constructors take the list allocator as an argument. + * + * @param v The address of the uninitialized memory in which the view + * will be constructed. + */ + void identity(View *v) const { ::new((void*) v) View(m_allocator); } + + /** @name construct functions + * + * All `construct()` functions first construct the leftmost view, using + * the optional @a x1, @a x2, and @a x3 arguments that were passed in from + * the reducer constructor. They then call the view’s `get_allocator()` + * function to get the list allocator from its contained list, and pass it + * to the monoid constructor. + */ + //@{ + + template <typename Monoid> + static void construct(Monoid* monoid, View* view) + { provisional( new ((void*)view) View() ).confirm_if( + new ((void*)monoid) Monoid(view->get_allocator()) ); } + + template <typename Monoid, typename T1> + static void construct(Monoid* monoid, View* view, const T1& x1) + { provisional( new ((void*)view) View(x1) ).confirm_if( + new ((void*)monoid) Monoid(view->get_allocator()) ); } + + template <typename Monoid, typename T1, typename T2> + static void construct(Monoid* monoid, View* view, const T1& x1, const T2& x2) + { provisional( new ((void*)view) View(x1, x2) ).confirm_if( + new ((void*)monoid) Monoid(view->get_allocator()) ); } + + template <typename Monoid, typename T1, typename T2, typename T3> + static void construct(Monoid* monoid, View* view, const T1& x1, const T2& x2, + const T3& x3) + { provisional( new ((void*)view) View(x1, x2, x3) ).confirm_if( + new ((void*)monoid) Monoid(view->get_allocator()) ); } + + //@} +}; + +//@} + +} // namespace internal + + +/** @ingroup ReducersList */ +//@{ + +/** The list append reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer< cilk::op_list_append<Type, Allocator> >`. It holds the + * accumulator variable for the reduction, and allows only append operations + * to be performed on it. + * + * @note The reducer “dereference†operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `push_back` operation would be used in an expression like + * `r->push_back(a)`, where `r` is a list append reducer variable. + * + * @tparam Type The list element type (not the list type). + * @tparam Allocator The list allocator type. + * + * @see ReducersList + * @see op_list_append + */ +template <class Type, + class Allocator = typename std::list<Type>::allocator_type> +class op_list_append_view : public internal::list_view_base<Type, Allocator> +{ + typedef internal::list_view_base<Type, Allocator> base; + typedef std::list<Type, Allocator> list_type; + typedef typename list_type::iterator iterator; + + iterator end() { return this->m_value.end(); } + +public: + + /** @name Constructors. + * + * All op_list_append_view constructors simply pass their arguments on to + * the @ref internal::list_view_base base class constructor. + * + * @ref internal::list_view_base supports all the std::list constructor + * forms, as well as the reducer move_in constructor form. + */ + //@{ + + op_list_append_view() : base() {} + + template <typename T1> + op_list_append_view(const T1& x1) : base(x1) {} + + template <typename T1, typename T2> + op_list_append_view(const T1& x1, const T2& x2) : base(x1, x2) {} + + template <typename T1, typename T2, typename T3> + op_list_append_view(const T1& x1, const T2& x2, const T3& x3) : + base(x1, x2, x3) {} + + //@} + + /** @name View modifier operations. + */ + //@{ + + /** Add an element at the end of the list. + * + * This is equivalent to `list.push_back(element)` + */ + void push_back(const Type& element) + { this->m_value.push_back(element); } + + /** Insert elements at the end of the list. + * + * This is equivalent to `list.insert(list.end(), n, element)` + */ + void insert_back(typename list_type::size_type n, const Type& element) + { this->m_value.insert(end(), n, element); } + + /** Insert elements at the end of the list. + * + * This is equivalent to `list.insert(list.end(), first, last)` + */ + template <typename Iter> + void insert_back(Iter first, Iter last) + { this->m_value.insert(end(), first, last); } + + /** Splice elements at the end of the list. + * + * This is equivalent to `list.splice(list.end(), x)` + */ + void splice_back(list_type& x) { + if (x.get_allocator() == this->m_value.get_allocator()) + this->m_value.splice(end(), x); + else { + insert_back(x.begin(), x.end()); + x.clear(); + } + } + + /** Splice elements at the end of the list. + * + * This is equivalent to `list.splice(list.end(), x, i)` + */ + void splice_back(list_type& x, iterator i) { + if (x.get_allocator() == this->m_value.get_allocator()) + this->m_value.splice(end(), x, i); + else { + push_back(*i); + x.erase(i); + } + } + + /** Splice elements at the end of the list. + * + * This is equivalent to `list.splice(list.end(), x, first, last)` + */ + void splice_back(list_type& x, iterator first, iterator last) { + if (x.get_allocator() == this->m_value.get_allocator()) + this->m_value.splice(end(), x, first, last); + else { + insert_back(first, last); + x.erase(first, last); + } + } + + //@} + + /** Reduction operation. + * + * This function is invoked by the @ref op_list_append monoid to combine + * the views of two strands when the right strand merges with the left + * one. It appends the value contained in the right-strand view to the + * value contained in the left-strand view, and leaves the value in the + * right-strand view undefined. + * + * @param right A pointer to the right-strand view. (`this` points to + * the left-strand view.) + * + * @note Used only by the @ref op_list_append monoid to implement the + * monoid reduce operation. + */ + void reduce(op_list_append_view* right) + { + __CILKRTS_ASSERT( + this->m_value.get_allocator() == right->m_value.get_allocator()); + this->m_value.splice(end(), right->m_value); + } +}; + + +/** The list prepend reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer< cilk::op_list_prepend<Type, Allocator> >`. It holds the + * accumulator variable for the reduction, and allows only prepend operations + * to be performed on it. + * + * @note The reducer “dereference†operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `push_front` operation would be used in an expression like + * `r->push_front(a)`, where `r` is a list prepend reducer variable. + * + * @tparam Type The list element type (not the list type). + * @tparam Allocator The list allocator type. + * + * @see ReducersList + * @see op_list_prepend + */ +template <class Type, + class Allocator = typename std::list<Type>::allocator_type> +class op_list_prepend_view : public internal::list_view_base<Type, Allocator> +{ + typedef internal::list_view_base<Type, Allocator> base; + typedef std::list<Type, Allocator> list_type; + typedef typename list_type::iterator iterator; + + iterator begin() { return this->m_value.begin(); } + +public: + + /** @name Constructors. + * + * All op_list_prepend_view constructors simply pass their arguments on to + * the @ref internal::list_view_base base class constructor. + * + * @ref internal::list_view_base supports all the std::list constructor + * forms, as well as the reducer move_in constructor form. + * + */ + //@{ + + op_list_prepend_view() : base() {} + + template <typename T1> + op_list_prepend_view(const T1& x1) : base(x1) {} + + template <typename T1, typename T2> + op_list_prepend_view(const T1& x1, const T2& x2) : base(x1, x2) {} + + template <typename T1, typename T2, typename T3> + op_list_prepend_view(const T1& x1, const T2& x2, const T3& x3) : + base(x1, x2, x3) {} + + //@} + + /** @name View modifier operations. + */ + //@{ + + /** Add an element at the beginning of the list. + * + * This is equivalent to `list.push_front(element)` + */ + void push_front(const Type& element) + { this->m_value.push_front(element); } + + /** Insert elements at the beginning of the list. + * + * This is equivalent to `list.insert(list.begin(), n, element)` + */ + void insert_front(typename list_type::size_type n, const Type& element) + { this->m_value.insert(begin(), n, element); } + + /** Insert elements at the beginning of the list. + * + * This is equivalent to `list.insert(list.begin(), first, last)` + */ + template <typename Iter> + void insert_front(Iter first, Iter last) + { this->m_value.insert(begin(), first, last); } + + /** Splice elements at the beginning of the list. + * + * This is equivalent to `list.splice(list.begin(), x)` + */ + void splice_front(list_type& x) { + if (x.get_allocator() == this->m_value.get_allocator()) + this->m_value.splice(begin(), x); + else { + insert_front(x.begin(), x.begin()); + x.clear(); + } + } + + /** Splice elements at the beginning of the list. + * + * This is equivalent to `list.splice(list.begin(), x, i)` + */ + void splice_front(list_type& x, iterator i) { + if (x.get_allocator() == this->m_value.get_allocator()) + this->m_value.splice(begin(), x, i); + else { + push_front(*i); + x.erase(i); + } + } + + /** Splice elements at the beginning of the list. + * + * This is equivalent to `list.splice(list.begin(), x, first, last)` + */ + void splice_front(list_type& x, iterator first, iterator last) { + if (x.get_allocator() == this->m_value.get_allocator()) + this->m_value.splice(begin(), x, first, last); + else { + insert_front(first, last); + x.erase(first, last); + } + } + + //@} + + /** Reduction operation. + * + * This function is invoked by the @ref op_list_prepend monoid to combine + * the views of two strands when the right strand merges with the left + * one. It prepends the value contained in the right-strand view to the + * value contained in the left-strand view, and leaves the value in the + * right-strand view undefined. + * + * @param right A pointer to the right-strand view. (`this` points to + * the left-strand view.) + * + * @note Used only by the @ref op_list_prepend monoid to implement the + * monoid reduce operation. + */ + /** Reduce operation. + * + * Required by @ref monoid_base. + */ + void reduce(op_list_prepend_view* right) + { + __CILKRTS_ASSERT( + this->m_value.get_allocator() == right->m_value.get_allocator()); + this->m_value.splice(begin(), right->m_value); + } +}; + + + +/** Monoid class for list append reductions. Instantiate the cilk::reducer + * template class with a op_list_append monoid to create a list append reducer + * class. For example, to create a list of strings: + * + * cilk::reducer< cilk::op_list_append<std::string> > r; + * + * @tparam Type The list element type (not the list type). + * @tparam Alloc The list allocator type. + * @tparam Align If `false` (the default), reducers instantiated on this + * monoid will be naturally aligned (the Cilk library 1.0 + * behavior). If `true`, reducers instantiated on this monoid + * will be cache-aligned for binary compatibility with + * reducers in Cilk library version 0.9. + * + * @see ReducersList + * @see op_list_append_view + */ +template <typename Type, + typename Allocator = typename std::list<Type>::allocator_type, + bool Align = false> +struct op_list_append : + public internal::list_monoid_base<op_list_append_view<Type, Allocator>, Align> +{ + /// Construct with default allocator. + op_list_append() {} + /// Construct with specified allocator. + op_list_append(const Allocator& alloc) : + internal::list_monoid_base<op_list_append_view<Type, Allocator>, Align>(alloc) {} +}; + +/** Monoid class for list prepend reductions. Instantiate the cilk::reducer + * template class with a op_list_prepend monoid to create a list prepend + * reducer class. For example, to create a list of strings: + * + * cilk::reducer< cilk::op_list_prepend<std::string> > r; + * + * @tparam Type The list element type (not the list type). + * @tparam Alloc The list allocator type. + * @tparam Align If `false` (the default), reducers instantiated on this + * monoid will be naturally aligned (the Cilk library 1.0 + * behavior). If `true`, reducers instantiated on this monoid + * will be cache-aligned for binary compatibility with + * reducers in Cilk library version 0.9. + * + * @see ReducersList + * @see op_list_prepend_view + */ +template <typename Type, + typename Allocator = typename std::list<Type>::allocator_type, + bool Align = false> +struct op_list_prepend : + public internal::list_monoid_base<op_list_prepend_view<Type, Allocator>, Align> +{ + /// Construct with default allocator. + op_list_prepend() {} + /// Construct with specified allocator. + op_list_prepend(const Allocator& alloc) : + internal::list_monoid_base<op_list_prepend_view<Type, Allocator>, Align>(alloc) {} +}; + + +/** Deprecated list append reducer wrapper class. + * + * reducer_list_append is the same as + * @ref reducer<@ref op_list_append>, except that reducer_list_append is a + * proxy for the contained view, so that accumulator variable update + * operations can be applied directly to the reducer. For example, an element + * is appended to a `reducer<%op_list_append>` with `r->push_back(a)`, but an + * element can be appended to a `%reducer_list_append` with `r.push_back(a)`. + * + * @deprecated Users are strongly encouraged to use `reducer<monoid>` + * reducers rather than the old wrappers like reducer_list_append. + * The `reducer<monoid>` reducers show the reducer/monoid/view + * architecture more clearly, are more consistent in their + * implementation, and present a simpler model for new + * user-implemented reducers. + * + * @note Implicit conversions are provided between `%reducer_list_append` + * and `reducer<%op_list_append>`. This allows incremental code + * conversion: old code that used `%reducer_list_append` can pass a + * `%reducer_list_append` to a converted function that now expects a + * pointer or reference to a `reducer<%op_list_append>`, and vice + * versa. + * + * @tparam Type The value type of the list. + * @tparam Allocator The allocator type of the list. + * + * @see op_list_append + * @see reducer + * @see ReducersList + */ +template <class Type, class Allocator = std::allocator<Type> > +class reducer_list_append : + public reducer<op_list_append<Type, Allocator, true> > +{ + typedef reducer<op_list_append<Type, Allocator, true> > base; + using base::view; +public: + + /// The reducer’s list type. + typedef typename base::value_type list_type; + + /// The list’s element type. + typedef Type list_value_type; + + /// The reducer’s primitive component type. + typedef Type basic_value_type; + + /// The monoid type. + typedef typename base::monoid_type Monoid; + + /** @name Constructors + */ + //@{ + + /** Construct a reducer with an empty list. + */ + reducer_list_append() {} + + /** Construct a reducer with a specified initial list value. + */ + reducer_list_append(const std::list<Type, Allocator> &initial_value) : + base(initial_value) {} + + //@} + + + /** @name Forwarded functions + * @details Functions that update the contained accumulator variable are + * simply forwarded to the contained @ref op_and_view. */ + //@{ + + /// @copydoc op_list_append_view::push_back(const Type&) + void push_back(const Type& element) { view().push_back(element); } + + //@} + + /** Allow mutable access to the list within the current view. + * + * @warning If this method is called before the parallel calculation is + * complete, the list returned by this method will be a partial + * result. + * + * @returns A mutable reference to the list within the current view. + */ + list_type &get_reference() { return view().view_get_reference(); } + + /** Allow read-only access to the list within the current view. + * + * @warning If this method is called before the parallel calculation is + * complete, the list returned by this method will be a partial + * result. + * + * @returns A const reference to the list within the current view. + */ + list_type const &get_reference() const { return view().view_get_reference(); } + + /// @name Dereference + //@{ + /** Dereferencing a wrapper is a no-op. It simply returns the wrapper. + * Combined with the rule that a wrapper forwards view operations to the + * view, this means that view operations can be written the same way on + * reducers and wrappers, which is convenient for incrementally + * converting code using wrappers to code using reducers. That is: + * + * reducer< op_list_append<int> > r; + * r->push_back(a); // *r returns the view + * // push_back is a view member function + * + * reducer_list_append<int> w; + * w->push_back(a); // *w returns the wrapper + * // push_back is a wrapper member function that + * // calls the corresponding view function + */ + //@{ + reducer_list_append& operator*() { return *this; } + reducer_list_append const& operator*() const { return *this; } + + reducer_list_append* operator->() { return this; } + reducer_list_append const* operator->() const { return this; } + //@} + + /** @name Upcast + * @details In Cilk library 0.9, reducers were always cache-aligned. In + * library 1.0, reducer cache alignment is optional. By default, reducers + * are unaligned (i.e., just naturally aligned), but legacy wrappers + * inherit from cache-aligned reducers for binary compatibility. + * + * This means that a wrapper will automatically be upcast to its aligned + * reducer base class. The following conversion operators provide + * pseudo-upcasts to the corresponding unaligned reducer class. + */ + //@{ + operator reducer< op_list_append<Type, Allocator, false> >& () + { + return *reinterpret_cast< + reducer< op_list_append<Type, Allocator, false> >* + >(this); + } + operator const reducer< op_list_append<Type, Allocator, false> >& () const + { + return *reinterpret_cast< + const reducer< op_list_append<Type, Allocator, false> >* + >(this); + } + //@} + +}; + + +/** Deprecated list prepend reducer wrapper class. + * + * reducer_list_prepend is the same as + * @ref reducer<@ref op_list_prepend>, except that reducer_list_prepend is a + * proxy for the contained view, so that accumulator variable update operations + * can be applied directly to the reducer. For example, an element is prepended + * to a `reducer<op_list_prepend>` with `r->push_back(a)`, but an element is + * prepended to a `reducer_list_prepend` with `r.push_back(a)`. + * + * @deprecated Users are strongly encouraged to use `reducer<monoid>` + * reducers rather than the old wrappers like reducer_list_prepend. + * The `reducer<monoid>` reducers show the reducer/monoid/view + * architecture more clearly, are more consistent in their + * implementation, and present a simpler model for new + * user-implemented reducers. + * + * @note Implicit conversions are provided between `%reducer_list_prepend` + * and `reducer<%op_list_prepend>`. This allows incremental code + * conversion: old code that used `%reducer_list_prepend` can pass a + * `%reducer_list_prepend` to a converted function that now expects a + * pointer or reference to a `reducer<%op_list_prepend>`, and vice + * versa. + * + * @tparam Type The value type of the list. + * @tparam Allocator The allocator type of the list. + * + * @see op_list_prepend + * @see reducer + * @see ReducersList + */ +template <class Type, class Allocator = std::allocator<Type> > +class reducer_list_prepend : + public reducer<op_list_prepend<Type, Allocator, true> > +{ + typedef reducer<op_list_prepend<Type, Allocator, true> > base; + using base::view; +public: + + /** The reducer’s list type. + */ + typedef typename base::value_type list_type; + + /** The list’s element type. + */ + typedef Type list_value_type; + + /** The reducer’s primitive component type. + */ + typedef Type basic_value_type; + + /** The monoid type. + */ + typedef typename base::monoid_type Monoid; + + /** @name Constructors + */ + //@{ + + /** Construct a reducer with an empty list. + */ + reducer_list_prepend() {} + + /** Construct a reducer with a specified initial list value. + */ + reducer_list_prepend(const std::list<Type, Allocator> &initial_value) : + base(initial_value) {} + + //@} + + /** @name Forwarded functions + * @details Functions that update the contained accumulator variable are + * simply forwarded to the contained @ref op_and_view. + */ + //@{ + + /// @copydoc op_list_prepend_view::push_front(const Type&) + void push_front(const Type& element) { view().push_front(element); } + + //@} + + /** Allow mutable access to the list within the current view. + * + * @warning If this method is called before the parallel calculation is + * complete, the list returned by this method will be a partial + * result. + * + * @returns A mutable reference to the list within the current view. + */ + list_type &get_reference() { return view().view_get_reference(); } + + /** Allow read-only access to the list within the current view. + * + * @warning If this method is called before the parallel calculation is + * complete, the list returned by this method will be a partial + * result. + * + * @returns A const reference to the list within the current view. + */ + list_type const &get_reference() const { return view().view_get_reference(); } + + /// @name Dereference + /** Dereferencing a wrapper is a no-op. It simply returns the wrapper. + * Combined with the rule that a wrapper forwards view operations to the + * view, this means that view operations can be written the same way on + * reducers and wrappers, which is convenient for incrementally + * converting code using wrappers to code using reducers. That is: + * + * reducer< op_list_prepend<int> > r; + * r->push_front(a); // *r returns the view + * // push_front is a view member function + * + * reducer_list_prepend<int> w; + * w->push_front(a); // *w returns the wrapper + * // push_front is a wrapper member function that + * // calls the corresponding view function + */ + //@{ + reducer_list_prepend& operator*() { return *this; } + reducer_list_prepend const& operator*() const { return *this; } + + reducer_list_prepend* operator->() { return this; } + reducer_list_prepend const* operator->() const { return this; } + //@} + + /** @name Upcast + * @details In Cilk library 0.9, reducers were always cache-aligned. In + * library 1.0, reducer cache alignment is optional. By default, reducers + * are unaligned (i.e., just naturally aligned), but legacy wrappers + * inherit from cache-aligned reducers for binary compatibility. + * + * This means that a wrapper will automatically be upcast to its aligned + * reducer base class. The following conversion operators provide + * pseudo-upcasts to the corresponding unaligned reducer class. + */ + //@{ + operator reducer< op_list_prepend<Type, Allocator, false> >& () + { + return *reinterpret_cast< + reducer< op_list_prepend<Type, Allocator, false> >* + >(this); + } + operator const reducer< op_list_prepend<Type, Allocator, false> >& () const + { + return *reinterpret_cast< + const reducer< op_list_prepend<Type, Allocator, false> >* + >(this); + } + //@} + +}; + +/// @cond internal + +/** Metafunction specialization for reducer conversion. + * + * This specialization of the @ref legacy_reducer_downcast template class + * defined in reducer.h causes the `reducer< op_list_append<Type, Allocator> >` + * class to have an `operator reducer_list_append<Type, Allocator>& ()` + * conversion operator that statically downcasts the `reducer<op_list_append>` + * to the corresponding `reducer_list_append` type. (The reverse conversion, + * from `reducer_list_append` to `reducer<op_list_append>`, is just an upcast, + * which is provided for free by the language.) + */ +template <class Type, class Allocator, bool Align> +struct legacy_reducer_downcast<reducer<op_list_append<Type, Allocator, Align> > > +{ + typedef reducer_list_append<Type, Allocator> type; +}; + +/** Metafunction specialization for reducer conversion. + * + * This specialization of the @ref legacy_reducer_downcast template class + * defined in reducer.h causes the + * `reducer< op_list_prepend<Type, Allocator> >` class to have an + * `operator reducer_list_prepend<Type, Allocator>& ()` conversion operator + * that statically downcasts the `reducer<op_list_prepend>` to the + * corresponding `reducer_list_prepend` type. (The reverse conversion, from + * `reducer_list_prepend` to `reducer<op_list_prepend>`, is just an upcast, + * which is provided for free by the language.) + */ +template <class Type, class Allocator, bool Align> +struct legacy_reducer_downcast<reducer<op_list_prepend<Type, Allocator, Align> > > +{ + typedef reducer_list_prepend<Type, Allocator> type; +}; + +/// @endcond + +//@} + +} // Close namespace cilk + +#endif // REDUCER_LIST_H_INCLUDED diff --git a/libcilkrts/include/cilk/reducer_max.h b/libcilkrts/include/cilk/reducer_max.h new file mode 100644 index 00000000000..3ba3a0bc8ac --- /dev/null +++ b/libcilkrts/include/cilk/reducer_max.h @@ -0,0 +1,46 @@ +/* reducer_max.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file reducer_max.h + * + * @brief Defines classes for doing parallel maximum reductions. + * + * @ingroup ReducersMinMax + * + * @see ReducersMinMax + */ + +#include "reducer_min_max.h" diff --git a/libcilkrts/include/cilk/reducer_min.h b/libcilkrts/include/cilk/reducer_min.h new file mode 100644 index 00000000000..f5a3910850e --- /dev/null +++ b/libcilkrts/include/cilk/reducer_min.h @@ -0,0 +1,46 @@ +/* reducer_min.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file reducer_min.h + * + * @brief Defines classes for doing parallel minimum reductions. + * + * @ingroup ReducersMinMax + * + * @see ReducersMinMax + */ + +#include "reducer_min_max.h" diff --git a/libcilkrts/include/cilk/reducer_min_max.h b/libcilkrts/include/cilk/reducer_min_max.h new file mode 100644 index 00000000000..55f068c34a3 --- /dev/null +++ b/libcilkrts/include/cilk/reducer_min_max.h @@ -0,0 +1,3606 @@ +/* reducer_min_max.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file reducer_min_max.h + * + * @brief Defines classes for doing parallel minimum and maximum reductions. + * + * @ingroup ReducersMinMax + * + * @see ReducersMinMax + */ + +#ifndef REDUCER_MIN_MAX_H_INCLUDED +#define REDUCER_MIN_MAX_H_INCLUDED + +#include <cilk/reducer.h> + +#ifdef __cplusplus + +#include <algorithm> +#include <limits> + +/** @defgroup ReducersMinMax Minimum and Maximum Reducers + * + * Minimum and maximum reducers allow the computation of the minimum or + * maximum of a set of values in parallel. + * + * @ingroup Reducers + * + * You should be familiar with @ref pagereducers "Cilk reducers", described in + * file `reducers.md`, and particularly with @ref reducers_using, before trying + * to use the information in this file. + * + * @section redminmax_usage Usage Examples + * + * cilk::reducer< cilk::op_max<int> > rm; + * cilk_for (int i = 0; i < ARRAY_SIZE; ++i) + * { + * rm->calc_max(a[i]); // or *rm = cilk::max_of(*max, a[i]) + * } + * std::cout << "maximum value is " << rm.get_value() << std::endl; + * + * and + * + * cilk::reducer< cilk::op_min_index<int, double> > rmi; + * cilk_for (int i = 0; i < ARRAY_SIZE; ++i) + * { + * rmi->calc_min(i, a[i]) // or *rmi = cilk::min_of(*rmi, i, a[i]); + * } + * std::cout << "minimum value a[" << rmi.get_value().first << "] = " + * << rmi.get_value().second << std::endl; + * + * @section redminmax_monoid The Monoid + * + * @subsection redminmax_monoid_values Value Set + * + * The value set of a minimum or maximum reducer is the set of values of + * `Type`, possibly augmented with a special identity value which is greater + * than (less than) any value of `Type`. + * + * @subsection redminmax_monoid_operator Operator + * + * In the most common case, the operator of a minimum reducer is defined as + * + * x MIN y == (x < y) ? x : y + * + * Thus, `a1 MIN a2 MIN … an` is the first `ai` which is not greater than any + * other `ai`. + * + * The operator of a maximum reducer is defined as + * + * x MAX y == (x > y) ? x : y + * + * Thus, `a1 MAX a2 MAX … an` is the first `ai` which is not less than any + * other `ai`. + * + * @subsection redminmax_monoid_comparators Comparators + * + * Min/max reducers are not limited to finding the minimum or maximum value + * determined by the `<` or `>` operator. In fact, all min/max reducers use a + * _comparator_, which is either a function or an object of a function class + * that defines a [strict weak ordering] + * (http://en.wikipedia.org/wiki/Strict_weak_ordering#Strict_weak_orderings) + * on a set of values. (This is exactly the same as the requirement for the + * comparison predicate for STL associative containers and sorting + * algorithms.) + * + * Just as with STL algorithms and containers, the comparator type parameter + * for min/max reducers is optional. If it is omitted, it defaults to + * `std::less`, which gives the behavior described in the previous section. + * Using non-default comparators (anything other than `std::less`) with + * min/max reducers is just like using them with STL containers and + * algorithms. + * + * Taking comparator objects into account, the reduction operation `MIN` for a + * minimum reducer is defined as + * + * x MIN y == compare(x, y) ? x : y + * + * where `compare()` is the reducer’s comparator. Similarly, the reduction + * operation MAX for a maximum reducer is defined as + * + * x MAX y == compare(y, x) ? x : y + * + * (If `compare(x, y) == x < y`, then `compare(y, x) == x > y`.) + * + * @subsection redminmax_monoid_identity Identity + * + * The identity value of the reducer is the value which is greater than (less + * than) any other value in the value set of the reducer. This is the + * [“special identity valueâ€](#redminmax_monoid_values) if the reducer has + * one, or the largest (smallest) value in the value set otherwise. + * + * @section redminmax_index Value and Index Reducers + * + * Min/max reducers come in two families. The _value_ reducers, using `op_min` + * and `op_max` monoids, simply find the smallest or largest value from a set + * of values. The _index_ reducers, using `op_min_index` and `op_max_index` + * monoids, also record an index value associated with the first occurrence of + * the smallest or largest value. + * + * In the `%op_min_index` usage example [above](#redminmax_usage), the values + * are taken from an array, and the index of a value is the index of the array + * element it comes from. More generally, though, an index can be any sort of + * key which identifies a particular value in a collection of values. For + * example, if the values were taken from the nodes of a tree, then the + * “index†of a value might be a pointer to the node containing that value. + * + * A min/max index reducer is essentially the same as a min/max value reducer + * whose value type is an (index, value) pair, and whose comparator ignores + * the index part of the pair. (index, value) pairs are represented by + * `std::pair<Index, Type>` objects. This has the consequence that wherever + * the interface of a min/max value reducer has a `Type`, the interface of the + * corresponding min/max index reducer has a `std::pair<Index, Type>`. (There + * are convenience variants of the `reducer(Type)` constructor and the + * `calc_min()`, `calc_max()`, `%min_of()`, and `%max_of()` functions that + * take an index argument and a value argument instead of an index/value + * pair.) + * + * @section redminmax_operations Operations + * + * @subsection redminmax_constructors Constructors + * + * @subsubsection redminmax_constructors_value Min/Max Value Reducers + * + * reducer() // identity + * reducer(const Compare& compare) // identity + * reducer(const Type& value) + * reducer(move_in(Type& variable)) + * reducer(const Type& value, const Compare& compare) + * reducer(move_in(Type& variable), const Compare& compare) + * + * @subsubsection redminmax_constructors_index Min/Max Index Reducers + * + * reducer() // identity + * reducer(const Compare& compare) // identity + * reducer(const std::pair<Index, Type>& pair) + * reducer(const Index& index, const Type& value) + * reducer(move_in(std::pair<Index, Type>& variable)) + * reducer(const std::pair<Index, Type>& pair, const Compare& compare) + * reducer(const Index& index, const Type& value, const Compare& compare) + * reducer(move_in(std::pair<Index, Type>& variable), const Compare& compare) + * + * @subsection redminmax_get_set Set and Get + * + * r.set_value(const Type& value) + * Type = r.get_value() const + * r.move_in(Type& variable) + * r.move_out(Type& variable) + * + * Note that for an index reducer, the `Type` in these operations is actually a + * `std::pair<Index, Type>`. (See @ref redminmax_index.) There is _not_ a + * `set_value(value, index)` operation. + * + * @subsection redminmax_initial Initial Values and is_set() + * + * A minimum or maximum reducer without a specified initial value, before any + * MIN or MAX operation has been performed on it, represents the [identity + * value](#redminmax_monoid_identity) of its monoid. For value reducers with a + * numeric type and default comparator (`std::less`), this will be a well + * defined value. For example, + * + * reducer< op_max<unsigned> > r1; + * // r1.get_value() == 0 + * + * reducer< op_min<float> > r2; + * // r2.get_value() == std::numeric_limits<float>::infinity + * + * In other cases, though (index reducers, non-numeric types, or non-default + * comparators), the actual identity value for the monoid may be unknown, or + * it may not even be a value of the reducer’s type. For example, there is no + * “largest string†to serve as the initial value for a + * `reducer< op_min<std::string> >`. In these cases, the result of calling + * `get_value()` is undefined. + * + * To avoid calling `get_value()` when its result is undefined, you can call + * the view’s `is_set()` function, which will return true if the reducer + * has a well-defined value — either because a MIN or MAX operation has been + * performed, or because it had a well-defined initial value: + * + * reducer< op_max<unsigned> > r1; + * // r1->is_set() == true + * // r1.get_value() == 0 + * + * reducer< op_min<std::string> > r2; + * // r2->is_set() == false + * // r2.get_value() is undefined + * r2->calc_min("xyzzy"); + * // r2->is_set() == true + * // r2.get_value() == "xyzzy" + * + * > Note: For an index reducer without a specified initial value, the + * > initial value of the index is the default value of the `Index` type. + * + * @subsection redminmax_view_ops View Operations + * + * The basic reduction operation is `x = x MIN a` for a minimum reducer, or + * `x = x MAX a` for a maximum reducer. The basic syntax for these operations + * uses the `calc_min()` and `calc_max()` member functions of the view class. + * An assignment syntax is also provided, using the %cilk::min_of() and + * %cilk::max_of() global functions: + * + * Class | Modifier | Assignment + * ---------------|---------------------|----------- + * `op_min` | `r->calc_min(x)` | `*r = min_of(*r, x)` or `*r = min_of(x, *r)` + * `op_max` | `r->calc_max(x)` | `*r = max_of(*r, x)` or `*r = max_of(x, *r)` + * `op_min_index` | `r->calc_min(i, x)` | `*r = min_of(*r, i, x)` or `*r = min_of(i, x, *r)` + * `op_max_index` | `r->calc_max(i, x)` | `*r = max_of(*r, i, x)` or `*r = max_of(i, x, *r)` + * + * Wherever an “`i`, `x`†argument pair is shown in the table above, a single + * pair argument may be passed instead. For example: + * + * Index index; + * Type value; + * std::pair<Index, Type> ind_val(index, value); + * // The following statements are all equivalent. + * r->calc_min(index, value); + * r->calc_min(ind_val); + * *r = min_of(*r, index, value); + * *r = min_of(*r, ind_val); + * + * The `calc_min()` and `calc_max()` member functions return a reference to + * the view, so they can be chained: + * + * r->calc_max(x).calc_max(y).calc_max(z); + * + * In a `%min_of()` or `%max_of()` assignment, the view on the left-hand side + * of the assignment must be the same as the view argument in the call. + * Otherwise, the behavior is undefined (but an assertion error will occur if + * the code is compiled with debugging enabled). + * + * *r = max_of(*r, x); // OK + * *r1 = max_of(*r2, y); // ERROR + * + * `%min_of()` and `%max_of()` calls can be nested: + * + * *r = max_of(max_of(max_of(*r, x), y), z); + * *r = min_of(i, a[i], min_of(j, a[j], min_of(k, a[k], *r))); + * + * @section redminmax_compatibility Compatibility Issues + * + * Most Cilk library reducers provide + * * Binary compatibility between `reducer_KIND` reducers compiled with Cilk + * library version 0.9 (distributed with Intel® C++ Composer XE version + * 13.0 and earlier) and the same reducers compiled with Cilk library + * version 1.0 and later. + * * Transparent casting between references to `reducer<op_KIND>` and + * `reducer_KIND`. + * + * This compatibility is not available in all cases for min/max reducers. + * There are two areas of incompatibility. + * + * @subsection redminmax_compatibility_stateful Non-empty Comparators + * + * There is no way to provide binary compatibility between the 0.9 and 1.0 + * definitions of min/max reducers that use a non-empty comparator class or a + * comparator function. (Empty comparator classes like `std::less` are not a + * problem.) + * + * To avoid run-time surprises, the legacy `reducer_{min|max}[_index]` classes + * have been coded in the 1.0 library so that they will not even compile when + * instantiated with a non-empty comparator class. + * + * @subsection redminmax_compatibility_optimized Numeric Optimization + * + * Min/max reducers with a numeric value type and the default comparator can + * be implemented slightly more efficiently than other min/max reducers. + * However, the optimization is incompatible with the 0.9 library + * implementation of min/max reducers. + * + * The default min/max reducers implementation in the 1.0 library uses this + * numeric optimization. Code using legacy reducers compiled with the 1.0 + * library can be safely used in the same program as code compiled with the + * 0.9 library, but classes compiled with the different Cilk libraries will be + * defined in different namespaces. + * + * The simplest solution is just to recompile the code that was compiled with + * the older version of Cilk. However, if this is impossible, you can define + * the `CILK_LIBRARY_0_9_REDUCER_MINMAX` macro (on the compiler command line, + * or in your source code before including `reducer_min_max.h`) when compiling + * with the new library. This will cause it to generate numeric reducers that + * will be less efficient, but will be fully compatible with previously + * compiled code. (Note that this macro has no effect on [the non-empty + * comparator incompatibility] (redminmax_compatibility_stateful).) + * + * @section redminmax_types Type Requirements + * + * `Type` and `Index` must be `Copy Constructible`, `Default Constructible`, + * and `Assignable`. + * + * `Compare` must be `Copy Constructible` if the reducer is constructed with a + * `compare` argument, and `Default Constructible` otherwise. + * + * The `Compare` function must induce a strict weak ordering on the elements + * of `Type`. + * + * @section redminmax_in_c Minimum and Maximum Reducers in C + * + * These macros can be used to do minimum and maximum reductions in C: + * + * Declaration | Type | Operation + * -----------------------------|-----------------------------------|---------- + * @ref CILK_C_REDUCER_MIN |@ref CILK_C_REDUCER_MIN_TYPE |@ref CILK_C_REDUCER_MIN_CALC + * @ref CILK_C_REDUCER_MAX |@ref CILK_C_REDUCER_MAX_TYPE |@ref CILK_C_REDUCER_MAX_CALC + * @ref CILK_C_REDUCER_MIN_INDEX |@ref CILK_C_REDUCER_MIN_INDEX_TYPE |@ref CILK_C_REDUCER_MIN_INDEX_CALC + * @ref CILK_C_REDUCER_MAX_INDEX |@ref CILK_C_REDUCER_MAX_INDEX_TYPE |@ref CILK_C_REDUCER_MAX_INDEX_CALC + * + * For example: + * + * CILK_C_REDUCER_MIN(r, int, INT_MAX); + * CILK_C_REGISTER_REDUCER(r); + * cilk_for(int i = 0; i != n; ++i) { + * CILK_C_REDUCER_MIN_CALC(r, a[i]); + * } + * CILK_C_UNREGISTER_REDUCER(r); + * printf("The smallest value in a is %d\n", REDUCER_VIEW(r)); + * + * + * CILK_C_REDUCER_MAX_INDEX(r, uint, 0); + * CILK_C_REGISTER_REDUCER(r); + * cilk_for(int i = 0; i != n; ++i) { + * CILK_C_REDUCER_MAX_INDEX_CALC(r, i, a[i]); + * } + * CILK_C_UNREGISTER_REDUCER(r); + * printf("The largest value in a is %u at %d\n", + * REDUCER_VIEW (r).value, REDUCER_VIEW(r).index); + * + * See @ref reducers_c_predefined. + */ + +namespace cilk { + +/** @defgroup ReducersMinMaxBinComp Binary compatibility + * + * If the macro CILK_LIBRARY_0_9_REDUCER_MINMAX is defined, then we generate + * reducer code and data structures which are binary-compatible with code that + * was compiled with the old min/max wrapper definitions, so we want the + * mangled names of the legacy min/max reducer wrapper classes to be the + * same as the names produced by the old definitions. + * + * Conversely, if the macro is not defined, then we generate binary- + * incompatible code, so we want different mangled names, to make sure that + * the linker does not allow new and old compiled legacy wrappers to be passed + * to one another. (Global variables are a different, and probably insoluble, + * problem.) + * + * Similarly, min/max classes compiled with and without + * CILK_LIBRARY_0_9_REDUCER_MINMAX are binary-incompatible, and must get + * different mangled names. + * + * The trick is, when compiling in normal (non-compatibility) mode, wrap + * everything in an extra namespace, and then `use` it into the top-level cilk + * namespace. Then + * + * * Classes and functions compiled in normal mode will be in + * different namespaces from the same classes and functions compiled in + * compatibility mode. + * * The legacy wrapper classes and functions will be in the same namespace + * as the same classes and functions compiled with the0.9 library if and + * only if the are compiled in compatibility mode. + * + * @ingroup ReducersMinMax + */ + +#ifndef CILK_LIBRARY_0_9_REDUCER_MINMAX +/** Namespace to wrap min/max reducer definitions when not compiling in “binary + * compatibility†mode. + * + * By default, all of the min/max reducer definitions are defined in this + * namespace and then imported into namespace ::cilk, so that they do not + * clash with the legacy definitions with the same names. However, if the + * macro `CILK_LIBRARY_0_9_REDUCER_MINMAX` is defined, then the min/max + * definitions go directly into namespace ::cilk, so that, for example, + * cilk::reducer_max defined with the 1.0 library is equivalent (to the + * linker) to cilk::reducer_max defined with the 0.9 library. + * + * @ingroup ReducersMinMaxBinComp + * @ingroup ReducersMinMax + */ +namespace cilk_lib_1_0 { +#endif + +/** Namespace containing internal implementation classes and functions for + * min/max reducers. + * + * @ingroup ReducersMinMax + */ +namespace min_max_internal { + +using ::cilk::internal::binary_functor; +using ::cilk::internal::typed_indirect_binary_function; +using ::cilk::internal::class_is_empty; + +/** @defgroup ReducersMinMaxIsSet The “is_set optimization†+ * + * The obvious definition of the identity value for a max or min reducer is as + * the smallest (or largest) value of the value type. However, for an + * arbitrary comparator and/or an arbitrary value type, the largest / smallest + * value may not be known. It may not even be defined — what is the largest + * string? + * + * Therefore, min/max reducers represent their value internally as a pair + * `(value, is_set)`. When `is_set` is true, the pair represents the known + * value `value`; when `is_set` is false, the pair represents the identity + * value. + * + * This is an effective solution, but the most common use of min/max reducers + * is probably with numeric types and the default definition of minimum or + * maximum (using `std::less`), in which case there are well-defined, knowable + * smallest and largest values. Testing `is_set` for every comparison is then + * unnecessary and wasteful. + * + * The “is_set optimization†just means generating code that doesn’t use + * `is_set` when it isn’t needed. It is implemented using two metaprogramming + * classes: + * + * - do_is_set_optimization tests whether the optimization is applicable. + * - identity_value gets the appropriate identity value for a type. + * + * The is_set optimization is the reason that min/max reducers compiled with + * Cilk library 1.0 are binary-incompatible with the same reducers compiled + * with library 0.9, and therefore the optimization is suppressed when + * compiling in + * ReducersMinMaxBinComp "binary compatibility mode". + * + * @ingroup ReducersMinMax + */ + +/** Test whether the ReducersMinMaxIsSet "is_set optimization" is + * applicable. + * + * The @ref do_is_set_optimization class is used to test whether the is_set + * optimization should be applied for a particular reducer. It is instantiated + * with a value type and a comparator, and defines a boolean constant, + * `value`. Then `%do_is_set_optimization<Type, Comp>::%value` can be used as + * a boolean template parameter to control the specialization of another + * class. + * + * In ReducersMinMaxBinComp "binary compatibility mode", when the + * `CILK_LIBRARY_0_9_REDUCER_MINMAX` macro is defined, `value` will always + * be false. + * + * @tparam Type The value type for the reducer. + * @tparam Compare The comparator type for the reducer. + * + * @result The `value` data member will be `true` if @a Type is a numeric + * type, @a Compare is `std::less<Type>`, and + * `CILK_LIBRARY_0_9_REDUCER_MINMAX` is not defined. + * + * @see ReducersMinMaxIsSet + * @see @ref view_content + * + * @ingroup ReducersMinMaxIsSet + */ +template < typename Type, + typename Compare > +struct do_is_set_optimization +{ + /// `True` if the is_set optimization should be applied to min/max reducers + /// with this value type and comparator; `false` otherwise. + static const bool value = false; +}; + +#ifndef CILK_LIBRARY_0_9_REDUCER_MINMAX +/// @cond +template <typename Type> +struct do_is_set_optimization<Type, std::less<Type> > +{ + /// True in the special case where optimization is possible. + static const bool value = std::numeric_limits<Type>::is_specialized; +}; +/// @endcond +#endif + + +/** Get the identity value when using the ReducersMinMaxIsSet + * "is_set optimization". + * + * This class defines a function which assigns the appropriate identity value + * to a variable when the is_set optimization is applicable. + * + * @tparam Type The value type for the reducer. + * @tparam Compare The comparator type for the reducer. + * @tparam ForMax `true` to get the identity value for a max reducer (i.e., + * the smallest value of @a Type), `false` to get the identity + * value for a min reducer (i.e., the largest value of + * @a Type). + * + * @result If @a Type and @a Compare qualify for the is_set optimization, the + * `set_identity()' function will set its argument variable to the + * smallest or largest value of @a Type, depending on @a ForMax. + * Otherwise, `set_identity()` will be a no-op. + * + * @see ReducersMinMaxIsSet + * + * @ingroup ReducersMinMaxIsSet + * @see @ref view_content + */ +template < typename Type, + typename Compare, + bool ForMax, + bool = std::numeric_limits<Type>::is_specialized, + bool = std::numeric_limits<Type>::has_infinity > +struct identity_value { + /// Assign the identity value to the reference parameter. + static void set_identity(Type&) {} +}; + +/// @cond +template <typename Type> +struct identity_value<Type, std::less<Type>, true, true, true> { + /// Floating max identity is negative infinity. + static void set_identity(Type& id) + { id = -std::numeric_limits<Type>::infinity(); } +}; + +template <typename Type> +struct identity_value<Type, std::less<Type>, true, true, false> { + /// Integer max identity is minimum value of type. + static void set_identity(Type& id) + { id = std::numeric_limits<Type>::min(); } +}; + +template <typename Type> +struct identity_value<Type, std::less<Type>, false, true, true> { + /// Floating min identity is positive infinity. + static void set_identity(Type& id) + { id = std::numeric_limits<Type>::infinity(); } +}; + +template <typename Type> +struct identity_value<Type, std::less<Type>, false, true, false> { + /// Integer min identity is maximum value of type. + static void set_identity(Type& id) + { id = std::numeric_limits<Type>::max(); } +}; + +/// @endcond + + +/** Adapter class to reverse the arguments of a predicate. + * + * Observe that: + * + * (x < y) == (y > x) + * max(x, y) == (x < y) ? y : x + * min(x, y) == (y < x) ? y : x == (x > y) ? y : x + * + * More generally, if `c` is a predicate defining a `Strict Weak Ordering`, + * and `c*(x, y) == c(y, x)`, then + * + * max(x, y, c) == c(x, y) ? y : x + * min(x, y, c) == c(y, x) ? y : x == c*(x, y) ? y : x == max(x, y, c*) + * + * For any predicate `C` with argument type `T`, the template class + * `%reverse_predicate<C, T>` defines a predicate which is identical to `C`, + * except that its arguments are reversed. Thus, for example, we could + * implement `%op_min_view<Type, Compare>` as + * `%op_max_view<Type, %reverse_predicate<Compare, Type> >`. + * (Actually, op_min_view and op_max_view are both implemented as subclasses + * of a common base class, view_base.) + * + * @note If `C` is an empty functor class, then `reverse_predicate(C)` will + * also be an empty functor class. + * + * @tparam Predicate The predicate whose arguments are to be reversed. + * @tparam Argument @a Predicate’s argument type. + * + * @ingroup ReducersMinMax + */ +template <typename Predicate, + typename Argument = typename Predicate::first_argument_type> +class reverse_predicate : private binary_functor<Predicate>::type { + typedef typename binary_functor<Predicate>::type base; +public: + /// Default constructor + reverse_predicate() : base() {} + /// Constructor with predicate object + reverse_predicate(const Predicate& p) : base(p) {} + /// The reversed predicate operation + bool operator()(const Argument& x, const Argument& y) const + { return base::operator()(y, x); } +}; + + +/** Class to represent the comparator for a min/max view class. + * + * This class is intended to accomplish two objectives in the implementation + * of min/max views. + * + * 1. To minimize data bloat, when we have a reducer with a non-stateless + * comparator, we want to keep a single instance of the comparator object + * in the monoid, and just call it from the views. + * 2. In ReducersMinMaxBinComp "binary compatibility mode", views for + * reducers with a stateless comparator must have the same content as in + * Cilk library 0.9 — that is, they must contain only `value` and + * `is_set` data members. + * + * To achieve the first objective, we use the + * @ref internal::typed_indirect_binary_function class defined in + * metaprogramming.h to wrap a pointer to the actual comparator. If no + * pointer is needed because the actual comparator is stateless, the + * `typed_indirect_binary_function` class will be empty, too. + * + * To achieve the second objective, we make the + * `typed_indirect_binary_function` class a base class of the view rather than + * a data member, so the “empty base class†rule will ensure no that no + * additional space is allocated in the view unless it is needed. + * + * We could simply use typed_indirect_binary_function as the base class of the + * view, but this would mean writing comparisons as `(*this)(x, y)`, which is + * just weird. So, instead, we comparator_base as a subclass of + * typed_indirect_binary_function which provides function `compare()` + * as a synonym for `operator()`. + * + * @tparam Type The value type of the comparator class. + * @tparam Compare A predicate class. + * + * @see internal::typed_indirect_binary_function + * + * @ingroup ReducersMinMax + */ +template <typename Type, typename Compare> +class comparator_base : private typed_indirect_binary_function<Compare, Type, Type, bool> +{ + typedef typed_indirect_binary_function<Compare, Type, Type, bool> base; +protected: + comparator_base(const Compare* f) : base(f) {} ///< Constructor. + + /// Comparison function. + bool compare(const Type& a, const Type& b) const + { + return base::operator()(a, b); + } + + /// Get the comparator pointer. + const Compare* compare_pointer() const { return base::pointer(); } +}; + + +/** @defgroup ReducersMinMaxViewContent Content classes for min/max views + * + * @ingroup ReducersMinMax + * + * Minimum and maximum reducer view classes inherit from a “view content†+ * class. The content class defines the actual data members for the view, + * and provides typedefs and member functions for accessing the data members + * as needed to support the view functionality. + * + * There are two content classes, which encapsulate the differences between + * simple min/max reducers and min/max with index reducers: + * + * - view_content + * - index_view_content + * + * @note An obvious, and arguably simpler, encapsulation strategy would be + * to just let the `Type` of a min/max view be an (index, value) pair + * structure for min_index and max_index reducers. Then all views + * would just have a `Type` data member and an `is_set` data member, + * and the comparator for min_index and max_index views could be + * customized to consider only the value component of the (index, + * value) `Type` pair. Unfortunately, this would break binary + * compatibility with reducer_max_index and reducer_min_index in + * Cilk library 0.9, because the memory layout of an (index, value) + * pair followed by a `bool` is different from the memory layout of an + * index data member followed by a value data member followed by a + * `bool` data member. The content class is designed to exactly + * replicate the layout of the views in library 0.9 reducers. + * + * A content class `C`, and its objects `c`, must define the following: + * + * Definition | Meaning + * ------------------------------------|-------- + * `C::value_type` | A typedef for `Type` of the view. (A `std::pair<Index, Type>` for min_index and max_index views). + * `C::comp_value_type` | A typedef for the type of value compared by the view’s `compare()` function. + * `C()` | Constructs the content with the identity value. + * `C(const value_type&)` | Constructs the content with a specified value. + * `c.is_set()` | Returns true if the content has a known value. + * `c.value()` | Returns the content’s value. + * `c.set_value(const value_type&)` | Sets the content’s value. (The value becomes known.) + * `c.comp_value()` | Returns a const reference to the value or component of the value that is to be compared by the view’s comparator. + * `C::comp_value(const value_type&)` | Returns a const reference to a value or component of a value that is to be compared by the view’s comparator. + * + * @see view_base + */ + +/** Content class for op_min_view and op_max_view. + * + * @tparam Type The value type of the op_min_view or op_max_view. + * @tparam Compare The comparator class specified for the op_min_view or + * op_max_view. (_Not_ the derived comparator class actually + * used by the view_base. For example, the view_content of an + * `op_min_view<int>` will have `Compare = std::less<int>`, + * but its comparator_base will have + * `Compare = reverse_predicate< std::less<int> >`.) + * @tparam ForMax `true` if this is the content class for an op_max_view, + * `false` if it is for an op_min_view. + * + * @note The general implementation of view_content uses an `is_set` data + * member. There is also a specialization which implements the + * ReducersMinMaxIsSet "is_set optimization". View classes that + * inherit from view_content do not need to know anything about the + * difference, though; the details are abstracted away in the + * view_content interface. + * + * @see ReducersMinMaxViewContent + * + * @ingroup ReducersMinMaxViewContent + * @ingroup ReducersMinMax + */ +template < typename Type + , typename Compare + , bool ForMax + , bool = do_is_set_optimization<Type, Compare>::value + > +class view_content { + Type m_value; + bool m_is_set; +public: + /// The value type of the view. + typedef Type value_type; + + /// The type compared by the view’s `compare()` function (which is the same + /// as the value type for view_content). + typedef Type comp_value_type; + + /// Construct with the identity value. + view_content() : m_value(), m_is_set(false) {} + + /// Construct with a defined value. + view_content(const value_type& value) : m_value(value), m_is_set(true) {} + + /// Get the value. + value_type value() const { return m_value; } + + /// Set the value. + void set_value(const value_type& value) + { + m_value = value; + m_is_set = true; + } + + /// Get the comparison value (which is the same as the value for + /// view_content). + const comp_value_type& comp_value() const { return m_value; } + + /// Given an arbitrary value, get the corresponding comparison value (which + /// is the same as the value for view_content). + static const comp_value_type& comp_value(const value_type& value) + { + return value; + } + + /// Get a const reference to value part of the value (which is the same as + /// the value for view_content). + const Type& get_reference() const { return m_value; } + + /// Get a const reference to the index part of the value (which is + /// meaningless for non-index reducers, but required for view_base. + const Type& get_index_reference() const { return m_value; } + + /// Test if the value is defined. + bool is_set() const { return m_is_set; } +}; + +/// @cond + +/* This is the specialization of the view_content class for cases where + * `AssumeIsSet` is true (i.e., where the is_set optimization is applicable). + */ +template < typename Type + , typename Compare + , bool ForMax + > +class view_content<Type, Compare, ForMax, true> { + typedef identity_value<Type, Compare, ForMax> Identity; + Type m_value; +public: + typedef Type value_type; + typedef Type comp_value_type; + + /// Construct with identity value. + view_content() { Identity::set_identity(m_value); } + + view_content(const value_type& value) : m_value(value) {} + + value_type value() const { return m_value; } + + void set_value(const value_type& value) + { + m_value = value; + } + + const comp_value_type& comp_value() const { return m_value; } + + static const comp_value_type& comp_value(const value_type& value) + { + return value; + } + + const Type& get_reference() const { return m_value; } + + const Type& get_index_reference() const { return m_value; } + + /// Test if the value is defined. + bool is_set() const { return true; } +}; + +/// @endcond + + +/** Content class for op_min_index_view and op_max_index_view. + * + * @tparam Index The index type of the op_min_index_view or + op_max_index_view. + * @tparam Type The value type of the op_min_view or op_max_view. (_Not_ + * the value type of the view, which will be + * `std::pair<Index, Type>`.) + * @tparam Compare The comparator class specified for the op_min_index_view or + * op_max_index_view. (_Not_ the derived comparator class + * actually used by the view_base. For example, the + * index_view_content of an `op_min_index_view<int>` will have + * `Compare = std::less<int>`, but its comparator_base will + * have `Compare = reverse_predicate< std::less<int> >`.) + * @tparam ForMax `true` if this is the content class for an + * op_max_index_view, `false` if it is for an + * op_min_index_view. + * + * @see ReducersMinMaxViewContent + * + * @ingroup ReducersMinMaxViewContent + * @ingroup ReducersMinMax + */ +template < typename Index + , typename Type + , typename Compare + , bool ForMax + > +class index_view_content { + typedef identity_value<Type, Compare, ForMax> Identity; + + Index m_index; + Type m_value; + bool m_is_set; +public: + /// The value type of the view (which is an <index, value> pair for + /// index_view_content). + typedef std::pair<Index, Type> value_type; + + /// The type compared by the view’s `compare()` function (which is the data + /// value type for index_view_content). + typedef Type comp_value_type; + + /// Construct with the identity value. + index_view_content() : m_index(), m_value(), m_is_set(false) {} + + /// Construct with an index/value pair. + index_view_content(const value_type& value) : + m_index(value.first), m_value(value.second), m_is_set(true) {} + + /// Construct with an index and a value. + index_view_content(const Index& index, const Type& value) : + m_index(index), m_value(value), m_is_set(true) {} + + /// Construct with just an index. + index_view_content(const Index& index) : + m_index(index), m_value(), m_is_set(false) {} + + /// Get the value. + value_type value() const { return value_type(m_index, m_value); } + + /// Set value. + void set_value(const value_type& value) + { + m_index = value.first; + m_value = value.second; + m_is_set = true; + } + + /// Get the comparison value (which is the value component of the + /// index/value pair for index_view_content). + const comp_value_type& comp_value() const { return m_value; } + + /// Given an arbitrary value (i.e., index/value pair), get the + /// corresponding comparison value (which is the value component of the + /// index/value pair for index_view_content). + static const comp_value_type& comp_value(const value_type& value) + { return value.second; } + + /// Get a const reference to value part of the value. + const Type& get_reference() const { return m_value; } + + /// Get a const reference to the index part of the value. + const Index& get_index_reference() const { return m_index; } + + /// Test if the value is defined. + bool is_set() const { return m_is_set; } +}; + + +template <typename View> class rhs_proxy; + +/** Create an rhs_proxy. + */ +template <typename View> +inline rhs_proxy<View> +make_proxy(const typename View::value_type& value, const View& view); + +template <typename Content, typename Less, typename Compare> class view_base; + + +/** Class to represent the right-hand side of + * `*reducer = {min|max}_of(*reducer, value)`. + * + * The only assignment operator for a min/max view class takes a rhs_proxy as + * its operand. This results in the syntactic restriction that the only + * expressions that can be assigned to a min/max view are ones which generate + * an rhs_proxy — that is, expressions of the form `max_of(view, value)` and + * `min_of(view, value)`. + * + * @warning + * The lhs and rhs views in such an assignment must be the same; otherwise, + * the behavior will be undefined. (I.e., `*r1 = min_of(*r1, x)` is legal; + * `*r1 = min_of(*r2, x)` is illegal.) This condition will be checked with a + * runtime assertion when compiled in debug mode. + * + * @tparam View The view class (op_{min|max}[_index]_view) that this proxy + * was created from. + * + * @see view_base + * + * @ingroup ReducersMinMax + */ +template <typename View> +class rhs_proxy { + typedef typename View::less_type less_type; + typedef typename View::compare_type compare_type; + typedef typename View::value_type value_type; + typedef typename View::content_type content_type; + typedef typename content_type::comp_value_type comp_value_type; + + friend class view_base<content_type, less_type, compare_type>; + friend rhs_proxy make_proxy<View>( + const typename View::value_type& value, + const View& view); + + typed_indirect_binary_function< + compare_type, comp_value_type, comp_value_type, bool> + m_comp; + const View* m_view; + value_type m_value; + + rhs_proxy& operator=(const rhs_proxy&); // Disable assignment operator + rhs_proxy(); // Disable default constructor + + // Constructor (called from view_base::make_proxy). + rhs_proxy(const View* view, + const value_type& value, + const compare_type* compare) : + m_view(view), m_value(value), m_comp(compare) {} + + // Check matching view, then return value (called from view_base::assign). + value_type value(const typename View::base* view) const + { + __CILKRTS_ASSERT(view == m_view); + return m_value; + } + +public: + + /** Support max_of(max_of(view, value), value) and the like. + */ + rhs_proxy calc(const value_type& x) const + { + return rhs_proxy( + m_view, + m_comp( content_type::comp_value(m_value), + content_type::comp_value(x) + ) ? x : m_value, + m_comp.pointer()); + } +}; + + +template <typename View> +inline rhs_proxy<View> +make_proxy(const typename View::value_type& value, const View& view) +{ + return rhs_proxy<View>(&view, value, view.compare_pointer()); +} + +//@} + +/** Base class for min and max view classes. + * + * This class accumulates the minimum or maximum of a set of values which have + * occurred as arguments to the `calc()` function, as determined by a + * comparator. The accumulated value will be the first `calc()` argument value + * `x` such that `compare(x, y)` is false for every `calc()` argument value + * `y`. + * + * If the comparator is `std::less`, then the accumulated value is the first + * argument value which is not less than any other argument value, i.e., the + * maximum. Similarly, if the comparator is `reverse_predicate<std::less>`, + * which is equivalent to `std::greater`, then the accumulated value is the + * first argument value which is not greater than any other argument value, + * i.e., the minimum. + * + * @note This class provides the definitions that are required for a class + * that will be used as the parameter of a + * min_max_internal::monoid_base specialization. + * + * @tparam Content A content class that provides the value types and data + * members for the view. + * @tparam Less A “less than†binary predicate that defines the min or + * max function. + * @tparam Compare A binary predicate to be used to compare the values. + * (The same as @a Less for max reducers; its reversal for + * min reducers.) + * + * @see ReducersMinMaxViewContent + * @see op_max_view + * @see op_min_view + * @see op_max_index_view + * @see op_min_index_view + * @see monoid_base + * + * @ingroup ReducersMinMax + */ +template <typename Content, typename Less, typename Compare> +class view_base : + // comparator_base comes first to ensure that it will get empty base class + // treatment + private comparator_base<typename Content::comp_value_type, Compare>, + private Content +{ + typedef comparator_base<typename Content::comp_value_type, Compare> base; + using base::compare; + using Content::value; + using Content::set_value; + using Content::comp_value; + typedef Content content_type; + + template <typename View> friend class rhs_proxy; + template <typename View> + friend rhs_proxy<View> make_proxy(const typename View::value_type& value, const View& view); + +public: + + /** @name Monoid support. + */ + //@{ + + /** Value type. Required by @ref monoid_with_view. + */ + typedef typename Content::value_type value_type; + + /** The type of the comparator specified by the user, that defines the + * ordering on @a Type. Required by min_max::monoid_base. + */ + typedef Less less_type; + + /** The type of the comparator actually used by the view. Required by + * min_max::monoid_base. (This is the same as the @ref less_type for a + * max reducer, or `reverse_predicate<less_type>` for a min reducer.) + */ + typedef Compare compare_type; + + /** Reduce operation. Required by @ref monoid_with_view. + */ + void reduce(view_base* other) + { + if ( other->is_set() && + ( !this->is_set() || + compare(this->comp_value(), other->comp_value()) ) ) + { + this->set_value(other->value()); + } + } + + //@} + + /** Default constructor. Initializes to identity value. + */ + explicit view_base(const compare_type* compare) : + base(compare), Content() {} + + /** Value constructor. + */ + template <typename T1> + view_base(const T1& x1, const compare_type* compare) : + base(compare), Content(x1) {} + + /** Value constructor. + */ + template <typename T1, typename T2> + view_base(const T1& x1, const T2& x2, const compare_type* compare) : + base(compare), Content(x1, x2) {} + + + /** Move-in constructor. + */ + explicit view_base(move_in_wrapper<value_type> w, const compare_type* compare) : + base(compare), Content(w.value()) {} + + /** @name Reducer support. + */ + //@{ + + void view_move_in(value_type& v) { set_value(v); } + void view_move_out(value_type& v) { v = value(); } + void view_set_value(const value_type& v) { set_value(v); } + value_type view_get_value() const { return value(); } + // view_get_reference() NOT SUPPORTED + + //@} + + /** Is the value defined? + */ + using Content::is_set; + + /** Reference to contained value data member. + * @deprecated For legacy reducers only. + */ + using Content::get_reference; + + /** Reference to contained index data member. + * (Meaningless for non-index reducers.) + * @deprecated For legacy reducers only. + */ + using Content::get_index_reference; + +protected: + + /** Update the min/max value. + */ + void calc(const value_type& x) + { + if (!is_set() || compare(comp_value(), comp_value(x))) set_value(x); + } + + /** Assign the result of a `{min|max}_of(view, value)` expression to the + * view. + * + * @see rhs_proxy + */ + template <typename View> + void assign(const rhs_proxy<View>& rhs) + { + calc(rhs.value(this)); + } + +}; + + +/** Base class for min and max monoid classes. + * + * The unique characteristic of minimum and maximum reducers is that they + * incorporate a comparator functor that defines what “minimum†or “maximum†+ * means. The monoid for a reducer contains the comparator that will be used + * for the reduction. If the comparator is a function or a class with state, + * then each view will have a pointer to the comparator. + * + * This means that the `construct()` functions first construct the monoid + * (possibly with an explicit comparator argument), and then construct the + * view with a pointer to the monoid’s comparator. + * + * @tparam View The view class. + * @tparam Align If true, reducers instantiated on this monoid will be + * aligned. By default, library reducers (unlike legacy + * library reducer _wrappers_) are unaligned. + * + * @see view_base + * + * @ingroup ReducersMinMax + */ +template <typename View, bool Align = false> +class monoid_base : public monoid_with_view<View, Align> +{ + typedef typename View::compare_type compare_type; + typedef typename View::less_type less_type; + const compare_type m_compare; + + const compare_type* compare_pointer() const { return &m_compare; } + + using cilk::monoid_base<typename View::value_type, View>::provisional; + +public: + + /** Default constructor uses default comparator. + */ + monoid_base() : m_compare() {} + + /** Constructor. + * + * @param compare The comparator to use. + */ + monoid_base(const compare_type& compare) : m_compare(compare) {} + + /** Create an identity view. + * + * List view identity constructors take the list allocator as an argument. + * + * @param v The address of the uninitialized memory in which the view + * will be constructed. + */ + void identity(View *v) const { ::new((void*) v) View(compare_pointer()); } + + /** @name construct functions + * + * Min/max monoid `construct()` functions optionally take one or two value + * arguments, a @ref move_in argument, and/or a comparator argument. + */ + //@{ + + template <typename Monoid> + static void construct(Monoid* monoid, View* view) + { provisional( new ((void*)monoid) Monoid() ).confirm_if( + new ((void*)view) View(monoid->compare_pointer()) ); } + + template <typename Monoid, typename T1> + static void construct(Monoid* monoid, View* view, const T1& x1) + { provisional( new ((void*)monoid) Monoid() ).confirm_if( + new ((void*)view) View(x1, monoid->compare_pointer()) ); } + + template <typename Monoid, typename T1, typename T2> + static void construct(Monoid* monoid, View* view, const T1& x1, const T2& x2) + { provisional( new ((void*)monoid) Monoid() ).confirm_if( + new ((void*)view) View(x1, x2, monoid->compare_pointer()) ); } + + template <typename Monoid> + static void construct(Monoid* monoid, View* view, const less_type& compare) + { provisional( new ((void*)monoid) Monoid(compare) ).confirm_if( + new ((void*)view) View(monoid->compare_pointer()) ); } + + template <typename Monoid, typename T1> + static void construct(Monoid* monoid, View* view, const T1& x1, const less_type& compare) + { provisional( new ((void*)monoid) Monoid(compare) ).confirm_if( + new ((void*)view) View(x1, monoid->compare_pointer()) ); } + + template <typename Monoid, typename T1, typename T2> + static void construct(Monoid* monoid, View* view, const T1& x1, const T2& x2, const less_type& compare) + { provisional( new ((void*)monoid) Monoid(compare) ).confirm_if( + new ((void*)view) View(x1, x2, monoid->compare_pointer()) ); } + + //@} +}; + +} //namespace min_max_internal + + +/** @defgroup ReducersMinMaxMaxValue Maximum reducers (value only) + * + * These reducers will find the largest value from a set of values. + * + * @ingroup ReducersMinMax + */ +//@{ + +/** The maximum reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer< cilk::op_max<Type, Compare> >`. It accumulates the maximum, + * as determined by a comparator, of a set of values which have occurred as + * arguments to the `calc_max()` function. The accumulated value will be the + * first argument `x` such that `compare(x, y)` is false for every argument + * `y`. + * + * If the comparator is `std::less`, then the accumulated value is the first + * argument value which is not less than any other argument value, i.e., the + * maximum. + * + * @note The reducer “dereference†operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `calc_max()` function would be used in an expression like + * `r->calc_max(a)` where `r` is an op_max reducer variable. + * + * @tparam Type The type of the values compared by the reducer. This will + * be the value type of a monoid_with_view that is + * instantiated with this view. + * @tparam Compare A `Strict Weak Ordering` whose argument type is @a Type. It + * defines the “less than†relation used to compute the + * maximum. + * + * @see ReducersMinMax + * @see op_max + */ +template <typename Type, typename Compare> +class op_max_view : public min_max_internal::view_base< + min_max_internal::view_content<Type, Compare, true>, + Compare, + Compare> +{ + typedef min_max_internal::view_base< + min_max_internal::view_content<Type, Compare, true>, + Compare, + Compare> base; + using base::calc; + using base::assign; + friend class min_max_internal::rhs_proxy<op_max_view>; + +public: + + /** @name Constructors. + * + * All op_max_view constructors simply pass their arguments on to the + * @ref view_base base class. + */ + //@{ + + op_max_view() : base() {} + + template <typename T1> + op_max_view(const T1& x1) : base(x1) {} + + template <typename T1, typename T2> + op_max_view(const T1& x1, const T2& x2) : base(x1, x2) {} + + //@} + + /** @name View modifier operations. + */ + //@{ + + /** Maximize with a value. + * + * If @a x is greater than the current value of the view (as defined by + * the reducer’s comparator), or if the view was created without an + * initial value and its value has never been updated (with `calc_max()` + * or `= max_of()`), then the value of the view is set to @a x. + * + * @param x The value to maximize the view’s value with. + * + * @return A reference to the view. (Allows chaining + * `view.comp_max(a).comp_max(b)…`.) + */ + op_max_view& calc_max(const Type& x) { calc(x); return *this; } + + /** Assign the result of a `max_of(view, value)` expression to the view. + * + * @param rhs An rhs_proxy value created by a `max_of(view, value)` + * expression. + * + * @return A reference to the view. + * + * @see min_max_internal::view_base::rhs_proxy + */ + op_max_view& operator=(const min_max_internal::rhs_proxy<op_max_view>& rhs) + { assign(rhs); return *this; } + + //@} +}; + + +/** Compute the maximum of the value in an op_max_view and another value. + * + * The result of this computation can only be assigned back to the original + * view or used in another max_of() call. For example, + * + * *reducer = max_of(*reducer, x); + * *reducer = max_of(x, *reducer); + * + * @see min_max_internal::rhs_proxy + */ +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_view<Type, Compare> > +max_of(const op_max_view<Type, Compare>& view, const Type& value) +{ + return min_max_internal::make_proxy(value, view); +} + +/// @copydoc max_of(const op_max_view<Type, Compare>&, const Type&) +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_view<Type, Compare> > +max_of(const Type& value, const op_max_view<Type, Compare>& view) +{ + return min_max_internal::make_proxy(value, view); +} + +/** Nested maximum computation. + * + * Compute the maximum of the result of a max_of() call and another value. + * + * The result of this computation can only be assigned back to the original + * view or wrapper, or used in another max_of() call. For example, + * + * *reducer = max_of(x, max_of(y, *reducer)); + * wrapper = max_of(max_of(wrapper, x), y); + * + * @see min_max_internal::rhs_proxy + */ +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_view<Type, Compare> > +max_of(const min_max_internal::rhs_proxy< op_max_view<Type, Compare> >& proxy, + const Type& value) +{ + return proxy.calc(value); +} + +/// @copydoc max_of(const min_max_internal::rhs_proxy< op_max_view<Type, Compare> >&, const Type&) +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_view<Type, Compare> > +max_of(const Type& value, + const min_max_internal::rhs_proxy< op_max_view<Type, Compare> >& proxy) +{ + return proxy.calc(value); +} + + +/** Monoid class for maximum reductions. Instantiate the cilk::reducer template + * class with an op_max monoid to create a maximum reducer class. For example, + * to compute the maximum of a set of `int` values: + * + * cilk::reducer< cilk::op_max<int> > r; + * + * @see ReducersMinMax + * @see op_max_view + */ +template <typename Type, typename Compare=std::less<Type>, bool Align = false> +class op_max : + public min_max_internal::monoid_base<op_max_view<Type, Compare>, Align> +{ + typedef min_max_internal::monoid_base<op_max_view<Type, Compare>, Align> + base; +public: + /// Construct with default comparator. + op_max() {} + /// Construct with specified comparator. + op_max(const Compare& compare) : base(compare) {} +}; + +//@} + + +/** @defgroup ReducersMinMaxMinValue Minimum reducers (value only) + * + * These reducers will find the smallest value from a set of values. + * + * @ingroup ReducersMinMax + */ +//@{ + +/** The minimum reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer< cilk::op_min<Type, Compare> >`. It accumulates the minimum, + * as determined by a comparator, of a set of values which have occurred as + * arguments to the `calc_min()` function. The accumulated value will be the + * first argument `x` such that `compare(y, x)` is false for every argument + * `y`. + * + * If the comparator is `std::less`, then the accumulated value is the first + * argument value which no other argument value is less than, i.e., the + * minimum. + * + * @note The reducer “dereference†operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `calc_min()` function would be used in an expression like + * `r->calc_min(a)` where `r` is an op_min reducer variable. + * + * @tparam Type The type of the values compared by the reducer. This will + * be the value type of a monoid_with_view that is + * instantiated with this view. + * @tparam Compare A `Strict Weak Ordering` whose argument type is @a Type. It + * defines the “less than†relation used to compute the + * minimum. + * + * @see ReducersMinMax + * @see op_min + */ +template <typename Type, typename Compare> +class op_min_view : public min_max_internal::view_base< + min_max_internal::view_content<Type, Compare, false>, + Compare, + min_max_internal::reverse_predicate<Compare, Type> > +{ + typedef min_max_internal::view_base< + min_max_internal::view_content<Type, Compare, false>, + Compare, + min_max_internal::reverse_predicate<Compare, Type> > base; + using base::calc; + using base::assign; + friend class min_max_internal::rhs_proxy<op_min_view>; + +public: + /** @name Constructors. + * + * All op_min_view constructors simply pass their arguments on to the + * @ref view_base base class. + */ + //@{ + + op_min_view() : base() {} + + template <typename T1> + op_min_view(const T1& x1) : base(x1) {} + + template <typename T1, typename T2> + op_min_view(const T1& x1, const T2& x2) : base(x1, x2) {} + + //@} + + /** @name View modifier operations. + */ + //@{ + + /** Minimize with a value. + * + * If @a x is less than the current value of the view (as defined by the + * reducer’s comparator), or if the view was created without an initial + * value and its value has never been updated (with `calc_min()` or + * `= min_of()`), then the value of the view is set to @a x. + * + * @param x The value to minimize the view’s value with. + * + * @return A reference to the view. (Allows chaining + * `view.comp_min(a).comp_min(b)…`.) + */ + op_min_view& calc_min(const Type& x) { calc(x); return *this; } + + /** Assign the result of a `min_of(view, value)` expression to the view. + * + * @param rhs An rhs_proxy value created by a `min_of(view, value)` + * expression. + * + * @return A reference to the view. + * + * @see min_max_internal::view_base::rhs_proxy + */ + op_min_view& operator=(const min_max_internal::rhs_proxy<op_min_view>& rhs) + { assign(rhs); return *this; } +}; + + +/** Compute the minimum of the value in a view and another value. + * + * The result of this computation can only be assigned back to the original + * view or used in another min_of() call. For example, + * + * *reducer = min_of(*reducer, x); + * *reducer = min_of(x, *reducer); + * + * @see min_max_internal::view_base::rhs_proxy + */ +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_view<Type, Compare> > +min_of(const op_min_view<Type, Compare>& view, const Type& value) +{ + return min_max_internal::make_proxy(value, view); +} + +/// @copydoc min_of(const op_min_view<Type, Compare>&, const Type&) +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_view<Type, Compare> > +min_of(const Type& value, const op_min_view<Type, Compare>& view) +{ + return min_max_internal::make_proxy(value, view); +} + +/** Nested minimum computation. + * + * Compute the minimum of the result of a min_of() call and another value. + * + * The result of this computation can only be assigned back to the original + * view or wrapper, or used in another min_of() call. For example, + * + * *reducer = min_of(x, min_of(y, *reducer)); + * wrapper = min_of(min_of(wrapper, x), y); + * + * @see min_max_internal::rhs_proxy + */ +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_view<Type, Compare> > +min_of(const min_max_internal::rhs_proxy< op_min_view<Type, Compare> >& proxy, + const Type& value) +{ + return proxy.calc(value); +} + +/// @copydoc min_of(const min_max_internal::rhs_proxy< op_min_view<Type, Compare> >&, const Type&) +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_view<Type, Compare> > +min_of(const Type& value, + const min_max_internal::rhs_proxy< op_min_view<Type, Compare> >& proxy) +{ + return proxy.calc(value); +} + + +/** Monoid class for minimum reductions. Instantiate the cilk::reducer template + * class with an op_min monoid to create a minimum reducer class. For example, + * to compute the minimum of a set of `int` values: + * + * cilk::reducer< cilk::op_min<int> > r; + * + * @see ReducersMinMax + * @see op_min_view + */ +template <typename Type, typename Compare=std::less<Type>, bool Align = false> +class op_min : public min_max_internal::monoid_base<op_min_view<Type, Compare>, Align> { + typedef min_max_internal::monoid_base<op_min_view<Type, Compare>, Align> base; +public: + /// Construct with default comparator. + op_min() {} + /// Construct with specified comparator. + op_min(const Compare& compare) : base(compare) {} +}; + +//@} + + +/** @defgroup ReducersMinMaxMaxIndex Maximum reducers (value and index) + * + * These reducers will find the largest value from a set of values, and its + * index in the set. + * + * @ingroup ReducersMinMax + */ +//@{ + +/** The maximum index reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer< cilk::op_max_index<Index, Type, Compare> >`. It accumulates + * the maximum, as determined by a comparator, of a set of values which have + * occurred as arguments to the `calc_max()` function, and records the index + * of the maximum value. The accumulated value will be the first argument `x` + * such that `compare(x, y)` is false for every argument `y`. + * + * If the comparator is `std::less`, then the accumulated value is the first + * argument value which is not less than any other argument value, i.e., the + * maximum. + * + * @note The reducer “dereference†operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `calc_max()` function would be used in an expression like + * `r->calc_max(i, a)`where `r` is an op_max_index reducer + * variable. + * + * @note The word “index†suggests an integer index into an array, but there + * is no restriction on the index type or how it should be used. In + * general, it may be convenient to use it for any kind of key that + * can be used to locate the maximum value in the collection that it + * came from — for example: + * - An index into an array. + * - A key into an STL map. + * - An iterator into any STL container. + * + * @note A max_index reducer is essentially a max reducer whose value type + * is a `std::pair<Index, Type>`. This fact is camouflaged in the view + * `calc_max` function, the global `max_of` functions, and the reducer + * value constructor, which can all take an index argument and a value + * argument as an alternative to a single `std::pair` argument. + * However, the reducer `set_value()`, `get_value()`, `move_in()`, and + * `move_out()` functions work only with pairs, not with individual + * value and/or index arguments. + * + * @tparam Index The type of the indices associated with the values. + * @tparam Type The type of the values compared by the reducer. This will + * be the value type of a monoid_with_view that is + * instantiated with this view. + * @tparam Compare Used to compare the values. It must be a binary predicate. + * If it is omitted, then the view computes the conventional + * arithmetic maximum. + * + * @see ReducersMinMax + * @see op_max_index + */ +template <typename Index, typename Type, typename Compare> +class op_max_index_view : public min_max_internal::view_base< + min_max_internal::index_view_content<Index, Type, Compare, true>, + Compare, + Compare> +{ + typedef min_max_internal::view_base< + min_max_internal::index_view_content<Index, Type, Compare, true>, + Compare, + Compare> base; + using base::calc; + using base::assign; + typedef std::pair<Index, Type> pair_type; + friend class min_max_internal::rhs_proxy<op_max_index_view>; + +public: + /** @name Constructors. + * + * All op_max_index_view constructors simply pass their arguments on to the + * @ref view_base base class, except for the `(index, value [, compare])` + * constructors, which create a `std::pair` containing the index and value. + */ + //@{ + + op_max_index_view() : base() {} + + template <typename T1> + op_max_index_view(const T1& x1) : base(x1) {} + + template <typename T1, typename T2> + op_max_index_view(const T1& x1, const T2& x2) : base(x1, x2) {} + + template <typename T1, typename T2, typename T3> + op_max_index_view(const T1& x1, const T2& x2, const T3& x3) : base(x1, x2, x3) {} + + op_max_index_view(const Index& i, const Type& v) : base(pair_type(i, v)) {} + + op_max_index_view(const Index& i, const Type& v, const typename base::compare_type* c) : + base(pair_type(i, v), c) {} + + //@} + + /** Maximize with a value and index. + * + * If @a x is greater than the current value of the view (as defined by + * the reducer’s comparator), or if the view was created without an + * initial value and its value has never been updated (with `calc_max()` + * or `= max_of()`), then the value of the view is set to @a x, and the + * index is set to @a i.. + * + * @param i The index of the value @a x. + * @param x The value to maximize the view’s value with. + * + * @return A reference to the view. (Allows + * `view.comp_max(i, a).comp_max(j, b)…`.) + */ + op_max_index_view& calc_max(const Index& i, const Type& x) + { calc(pair_type(i, x)); return *this; } + + /** Maximize with an index/value pair. + * + * If @a pair.second is greater than the current value of the view (as + * defined by the reducer’s comparator), or if the view was created + * without an initial value and its value has never been updated (with + * `calc_max()` or `= max_of()`), then the value of the view is set to + * @a pair.second, and the index is set to @a pair.first. + * + * @param pair A pair containing a value to maximize the view’s value + * with and its associated index. + * + * @return A reference to the view. (Allows + * `view.comp_max(p1).comp_max(p2)…`.) + */ + op_max_index_view& calc_max(const pair_type& pair) + { calc(pair); return *this; } + + /** Assign the result of a `max_of(view, index, value)` expression to the + * view. + * + * @param rhs An rhs_proxy value created by a `max_of(view, index, value)` + * expression. + * + * @return A reference to the view. + * + * @see min_max_internal::view_base::rhs_proxy + */ + op_max_index_view& operator=(const min_max_internal::rhs_proxy<op_max_index_view>& rhs) + { assign(rhs); return *this; } +}; + + +/** Compute the maximum of the value in a view and another value. + * + * The result of this computation can only be assigned back to the original + * view or used in another max_of() call. For example, + * + * *reducer = max_of(*reducer, i, x); + * *reducer = max_of(i, x, *reducer); + * + * @see min_max_internal::rhs_proxy + */ +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> > +max_of(const op_max_index_view<Index, Type, Compare>& view, + const Index& index, const Type& value) +{ + return min_max_internal::make_proxy(std::pair<Index, Type>(index, value), view); +} + +/// @copydoc max_of(const op_max_index_view<Index, Type, Compare>&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> > +max_of(const Index& index, const Type& value, + const op_max_index_view<Index, Type, Compare>& view) +{ + return min_max_internal::make_proxy(std::pair<Index, Type>(index, value), view); +} + +/// @copydoc max_of(const op_max_index_view<Index, Type, Compare>&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> > +max_of(const op_max_index_view<Index, Type, Compare>& view, + const std::pair<Index, Type>& pair) +{ + return min_max_internal::make_proxy(pair, view); +} + +/// @copydoc max_of(const op_max_index_view<Index, Type, Compare>&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> > +max_of(const std::pair<Index, Type>& pair, + const op_max_index_view<Index, Type, Compare>& view) +{ + return min_max_internal::make_proxy(pair, view); +} + +/** Nested computation of the maximum of the value in a view and other values. + * + * Compute the maximum of the result of a max_of() call and another value. + * + * The result of this computation can only be assigned back to the original + * view or used in another max_of() call. For example, + * + * *reducer = max_of(x, max_of(y, *reducer)); + * *reducer = max_of(max_of(*reducer, x), y); + * + * @see min_max_internal::rhs_proxy + */ +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> > +max_of(const min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> >& proxy, + const Index& index, const Type& value) +{ + return proxy.calc(std::pair<Index, Type>(index, value)); +} + +/// @copydoc max_of(const min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> >&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> > +max_of(const Index& index, const Type& value, + const min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> >& proxy) +{ + return proxy.calc(std::pair<Index, Type>(index, value)); +} + +/// @copydoc max_of(const min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> >&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> > +max_of(const min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> >& proxy, + const std::pair<Index, Type>& pair) +{ + return proxy.calc(pair); +} + +/// @copydoc max_of(const min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> >&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> > +max_of(const std::pair<Index, Type>& pair, + const min_max_internal::rhs_proxy< op_max_index_view<Index, Type, Compare> >& proxy) +{ + return proxy.calc(pair); +} + + +/** Monoid class for maximum reductions with index. Instantiate the + * cilk::reducer template class with an op_max_index monoid to create a + * max_index reducer class. For example, to compute the maximum of an array of + * `double` values and the array index of the max value: + * + * cilk::reducer< cilk::op_max_index<unsigned, double> > r; + * + * @see ReducersMinMax + * @see op_max_index_view + */ +template < typename Index + , typename Type + , typename Compare=std::less<Type> + , bool Align = false + > +class op_max_index : public min_max_internal::monoid_base<op_max_index_view<Index, Type, Compare>, Align> +{ + typedef min_max_internal::monoid_base< + op_max_index_view<Index, Type, Compare>, Align> base; +public: + /// Construct with default comparator. + op_max_index() {} + /// Construct with specified comparator. + op_max_index(const Compare& compare) : base(compare) {} +}; + +//@} + + + +/** @defgroup ReducersMinMaxMinIndex Minimum reducers (value and index) + * + * These reducers will find the smallest value from a set of values, and its + * index in the set. + * + * @ingroup ReducersMinMax + */ +//@{ + +/** The minimum index reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer<cilk::op_min_index<Index, Type, Compare> >`. It accumulates + * the minimum, as determined by a comparator, of a set of values which have + * occurred as arguments to the `calc_min()` function, and records the index + * of the minimum value. The accumulated value will be the first argument `x` + * such that `compare(y, x)` is false for every argument `y`. + * + * If the comparator is `std::less`, then the accumulated value is the first + * argument value which no other argument value is less than, i.e., the + * minimum. + * + * @note The reducer “dereference†operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `calc_min()` function would be + * used in an expression like `r->calc_min(i, a)`where `r` is an + * op_min_index reducer variable. + * + * @note The word “index†suggests an integer index into an array, but there + * is no restriction on the index type or how it should be used. In + * general, it may be convenient to use it for any kind of key that + * can be used to locate the minimum value in the collection that it + * came from — for example: + * - An index into an array. + * - A key into an STL map. + * - An iterator into any STL container. + * + * @note A min_index reducer is essentially a min reducer whose value type + * is a `std::pair<Index, Type>`. This fact is camouflaged in the view + * `calc_min` function, the global `min_of` functions, and the reducer + * value constructor, which can all take an index argument and a value + * argument as an alternative to a single `std::pair` argument. + * However, the reducer `set_value()`, `get_value()`, `move_in()`, and + * `move_out()` functions work only with pairs, not with individual + * value and/or index arguments. + * + * @tparam Index The type of the indices associated with the values. + * @tparam Type The type of the values compared by the reducer. This will + * be the value type of a monoid_with_view that is + * instantiated with this view. + * @tparam Compare Used to compare the values. It must be a binary predicate. + * If it is omitted, then the view computes the conventional + * arithmetic minimum. + * + * @see ReducersMinMax + * @see op_min_index + */ +template <typename Index, typename Type, typename Compare> +class op_min_index_view : public min_max_internal::view_base< + min_max_internal::index_view_content<Index, Type, Compare, false>, + Compare, + min_max_internal::reverse_predicate<Compare, Type> > +{ + typedef min_max_internal::view_base< + min_max_internal::index_view_content<Index, Type, Compare, false>, + Compare, + min_max_internal::reverse_predicate<Compare, Type> > base; + using base::calc; + using base::assign; + typedef std::pair<Index, Type> pair_type; + friend class min_max_internal::rhs_proxy<op_min_index_view>; + +public: + /** @name Constructors. + * + * All op_min_index_view constructors simply pass their arguments on to the + * @ref view_base base class, except for the `(index, value [, compare])` + * constructors, which create a `std::pair` containing the index and value. + */ + //@{ + + op_min_index_view() : base() {} + + template <typename T1> + op_min_index_view(const T1& x1) : base(x1) {} + + template <typename T1, typename T2> + op_min_index_view(const T1& x1, const T2& x2) : base(x1, x2) {} + + template <typename T1, typename T2, typename T3> + op_min_index_view(const T1& x1, const T2& x2, const T3& x3) : base(x1, x2, x3) {} + + op_min_index_view(const Index& i, const Type& v) : base(pair_type(i, v)) {} + + op_min_index_view(const Index& i, const Type& v, const typename base::compare_type* c) : + base(pair_type(i, v), c) {} + + //@} + + /** Minimize with a value and index. + * + * If @a x is greater than the current value of the view (as defined by + * the reducer’s comparator), or if the view was created without an + * initial value and its value has never been updated (with `calc_min()` + * or `= min_of()`), then the value of the view is set to @a x, and the + * index is set to @a i.. + * + * @param i The index of the value @a x. + * @param x The value to minimize the view’s value with. + * + * @return A reference to the view. (Allows + * `view.comp_min(i, a).comp_min(j, b)…`.) + */ + op_min_index_view& calc_min(const Index& i, const Type& x) + { calc(pair_type(i, x)); return *this; } + + /** Maximize with an index/value pair. + * + * If @a pair.second is less than the current value of the view (as + * defined by the reducer’s comparator), or if the view was created + * without an initial value and its value has never been updated (with + * `calc_min()` or `= min_of()`), then the value of the view is set to + * @a pair.second, and the index is set to @a pair.first. + * + * @param pair A pair containing a value to minimize the view’s value + * with and its associated index. + * + * @return A reference to the view. (Allows + * `view.comp_min(p1).comp_min(p2)…`.) + */ + op_min_index_view& calc_min(const pair_type& pair) + { calc(pair); return *this; } + + /** Assign the result of a `min_of(view, index, value)` expression to the + * view. + * + * @param rhs An rhs_proxy value created by a `min_of(view, index, value)` + * expression. + * + * @return A reference to the view. + * + * @see min_max_internal::view_base::rhs_proxy + */ + op_min_index_view& operator=(const min_max_internal::rhs_proxy<op_min_index_view>& rhs) + { assign(rhs); return *this; } +}; + + +/** Compute the minimum of the value in a view and another value. + * + * The result of this computation can only be assigned back to the original + * view or used in another min_of() call. For example, + * + * *reducer = min_of(*reducer, i, x); + * *reducer = min_of(i, x, *reducer); + * + * @see min_max_internal::min_min_view_base::rhs_proxy + */ +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> > +min_of(const op_min_index_view<Index, Type, Compare>& view, + const Index& index, const Type& value) +{ + return min_max_internal::make_proxy(std::pair<Index, Type>(index, value), view); +} + +/// @copydoc min_of(const op_min_index_view<Index, Type, Compare>&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> > +min_of(const Index& index, const Type& value, + const op_min_index_view<Index, Type, Compare>& view) +{ + return min_max_internal::make_proxy(std::pair<Index, Type>(index, value), view); +} + +/// @copydoc min_of(const op_min_index_view<Index, Type, Compare>&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> > +min_of(const op_min_index_view<Index, Type, Compare>& view, + const std::pair<Index, Type>& pair) +{ + return min_max_internal::make_proxy(pair, view); +} + +/// @copydoc min_of(const op_min_index_view<Index, Type, Compare>&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> > +min_of(const std::pair<Index, Type>& pair, + const op_min_index_view<Index, Type, Compare>& view) +{ + return min_max_internal::make_proxy(pair, view); +} + +/** Nested computation of the minimum of the value in a view and other values. + * + * Compute the minimum of the result of a min_of() call and another value. + * + * The result of this computation can only be assigned back to the original + * view or used in another min_of() call. For example, + * + * *reducer = min_of(x, min_of(y, *reducer)); + * *reducer = min_of(min_of(*reducer, x), y); + * + * @see min_max_internal::min_min_view_base::rhs_proxy + */ +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> > +min_of(const min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> >& proxy, + const Index& index, const Type& value) +{ + return proxy.calc(std::pair<Index, Type>(index, value)); +} + +/// @copydoc min_of(const min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> >&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> > +min_of(const Index& index, const Type& value, + const min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> >& proxy) +{ + return proxy.calc(std::pair<Index, Type>(index, value)); +} + +/// @copydoc min_of(const min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> >&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> > +min_of(const min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> >& proxy, + const std::pair<Index, Type>& pair) +{ + return proxy.calc(pair); +} + +/// @copydoc min_of(const min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> >&, const Index&, const Type&) +template <typename Index, typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> > +min_of(const std::pair<Index, Type>& pair, + const min_max_internal::rhs_proxy< op_min_index_view<Index, Type, Compare> >& proxy) +{ + return proxy.calc(pair); +} + + +/** Monoid class for minimum reductions with index. Instantiate the + * cilk::reducer template class with an op_min_index monoid to create a + * min_index reducer class. For example, to compute the minimum of an array of + * `double` values and the array index of the min value: + * + * cilk::reducer< cilk::op_min_index<unsigned, double> > r; + * + * @see ReducersMinMax + * @see op_min_index_view + */ +template < typename Index + , typename Type + , typename Compare=std::less<Type> + , bool Align = false + > +class op_min_index : public min_max_internal::monoid_base<op_min_index_view<Index, Type, Compare>, Align> +{ + typedef min_max_internal::monoid_base< + op_min_index_view<Index, Type, Compare>, Align> base; +public: + /// Construct with default comparator. + op_min_index() {} + /// Construct with specified comparator. + op_min_index(const Compare& compare) : base(compare) {} +}; + +//@} + + +/** Deprecated maximum reducer wrapper class. + * + * reducer_max is the same as @ref reducer<@ref op_max>, except that + * reducer_max is a proxy for the contained view, so that accumulator + * variable update operations can be applied directly to the reducer. For + * example, a value is maximized with a `reducer<%op_max>` with + * `r->calc_max(a)`, but a value can be maximized with a `%reducer_max` with + * `r.calc_max(a)`. + * + * + * @deprecated Users are strongly encouraged to use `reducer<monoid>` + * reducers rather than the old wrappers like reducer_max. + * The `reducer<monoid>` reducers show the reducer/monoid/view + * architecture more clearly, are more consistent in their + * implementation, and present a simpler model for new + * user-implemented reducers. + * + * @note Implicit conversions are provided between `%reducer_max` + * and `reducer<%op_max>`. This allows incremental code + * conversion: old code that used `%reducer_max` can pass a + * `%reducer_max` to a converted function that now expects a + * pointer or reference to a `reducer<%op_max>`, and vice + * versa. **But see @ref redminmax_compatibility.** + * + * @tparam Type The value type of the reducer. + * @tparam Compare The “less than†comparator type for the reducer. + * + * @see op_max + * @see op_max_view + * @see reducer + * @see ReducersMinMax + * @ingroup ReducersMinMaxMaxValue + */ +template <typename Type, typename Compare=std::less<Type> > +class reducer_max : public reducer< op_max<Type, Compare, true> > +{ + __CILKRTS_STATIC_ASSERT( + ::cilk::internal::class_is_empty< + typename ::cilk::internal::binary_functor<Compare>::type >::value, + "cilk::reducer_max<Type, Compare> only works with " + "an empty Compare class"); + typedef reducer< op_max<Type, Compare, true> > base; +public: + + /// Type of data in a reducer_max. + typedef Type basic_value_type; + + /// The view type for the reducer. + typedef typename base::view_type view_type; + + /// The view type for the reducer. + typedef typename base::view_type View; + + /// The monoid type for the reducer. + typedef typename base::monoid_type monoid_type; + + /// The monoid type for the reducer. + typedef typename base::monoid_type Monoid; + + /// The view’s rhs proxy type. + typedef min_max_internal::rhs_proxy<View> rhs_proxy; + + using base::view; + + /** @name Constructors + */ + //@{ + + /// Construct the wrapper in its identity state (either `!is_set()`, or + /// `value() == identity value`). + reducer_max() : base() {} + + /// Construct the wrapper with a specified initial value. + explicit reducer_max(const Type& initial_value) : base(initial_value) {} + + /// Construct the wrapper in its identity state with a specified + /// comparator. + explicit reducer_max(const Compare& comp) : base(comp) {} + + /// Construct the wrapper with a specified initial value and a specified + /// comparator. + reducer_max(const Type& initial_value, const Compare& comp) + : base(initial_value, comp) {} + + //@} + + /** @name Forwarded functions + * @details Functions that update the contained accumulator variable are + * simply forwarded to the contained @ref op_max_view. */ + //@{ + + /// @copydoc cilk_lib_1_0::min_max_internal::view_content::is_set() const + bool is_set() const { return view().is_set(); } + + /// @copydoc op_max_view::calc_max(const Type&) + reducer_max& calc_max(const Type& x) + { view().calc_max(x); return *this; } + + /// @copydoc op_max_view::operator=(const min_max_internal::rhs_proxy<op_max_view>&) + reducer_max& operator=(const rhs_proxy& rhs) + { view() = rhs; return *this; } + + //@} + + /** Allow read-only access to the value within the current view. + * + * @returns A const reference to the value within the current view. + */ + const Type& get_reference() const { return view().get_reference(); } + + /// @name Dereference + /** Dereferencing a wrapper is a no-op. It simply returns the wrapper. + * Combined with the rule that a wrapper forwards view operations to the + * view, this means that view operations can be written the same way on + * reducers and wrappers, which is convenient for incrementally + * converting code using wrappers to code using reducers. That is: + * + * reducer< op_max<int> > r; + * r->calc_max(a); // *r returns the view + * // calc_max is a view member function + * + * reducer_max<int> w; + * w->calc_max(a); // *w returns the wrapper + * // calc_max is a wrapper member function that + * // calls the corresponding view function + */ + //@{ + reducer_max& operator*() { return *this; } + reducer_max const& operator*() const { return *this; } + + reducer_max* operator->() { return this; } + reducer_max const* operator->() const { return this; } + //@} + + /** @name Upcast + * @details In Cilk library 0.9, reducers were always cache-aligned. In + * library 1.0, reducer cache alignment is optional. By default, reducers + * are unaligned (i.e., just naturally aligned), but legacy wrappers + * inherit from cache-aligned reducers for binary compatibility. + * + * This means that a wrapper will automatically be upcast to its aligned + * reducer base class. The following conversion operators provide + * pseudo-upcasts to the corresponding unaligned reducer class. + */ + //@{ + operator reducer< op_max<Type, Compare, false> >& () + { + return *reinterpret_cast< reducer< op_max<Type, Compare, false> >* >(this); + } + + operator const reducer< op_max<Type, Compare, false> >& () const + { + return *reinterpret_cast< const reducer< op_max<Type, Compare, false> >* >(this); + } + //@} +}; + + +/// @cond internal +// The legacy definition of max_of(reducer_max, value) has different +// behavior and a different return type than this definition. We add an +// unused third argument to this version of the function to give it a different +// signature, so that they won’t end up sharing a single object file entry. +struct max_of_1_0_t {}; +const max_of_1_0_t max_of_1_0 = {}; +/// @endcond + +/** Compute the maximum of the value in a reducer_max and another value. + * + * @deprecated Because reducer_max is deprecated. + * + * The result of this computation can only be assigned back to the original + * reducer or used in another max_of() call. For example, + * + * reducer = max_of(reducer, x); + * reducer = max_of(x, reducer); + * + * @see min_max_internal::rhs_proxy + * + * @ingroup ReducersMinMaxMaxValue + */ +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_view<Type, Compare> > +max_of(const reducer_max<Type, Compare>& r, const Type& value, + const max_of_1_0_t& = max_of_1_0) +{ + return min_max_internal::make_proxy(value, r.view()); +} + +/// @copydoc max_of(const reducer_max<Type, Compare>&, const Type&, const max_of_1_0_t&) +/// @ingroup ReducersMinMaxMaxValue +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_max_view<Type, Compare> > +max_of(const Type& value, const reducer_max<Type, Compare>& r, + const max_of_1_0_t& = max_of_1_0) +{ + return min_max_internal::make_proxy(value, r.view()); +} + + +/** Deprecated minimum reducer wrapper class. + * + * reducer_min is the same as @ref reducer<@ref op_min>, except that + * reducer_min is a proxy for the contained view, so that accumulator + * variable update operations can be applied directly to the reducer. For + * example, a value is minimized with a `reducer<%op_min>` with + * `r->calc_min(a)`, but a value can be minimized with a `%reducer_min` with + * `r.calc_min(a)`. + * + * + * @deprecated Users are strongly encouraged to use `reducer<monoid>` + * reducers rather than the old wrappers like reducer_min. + * The `reducer<monoid>` reducers show the reducer/monoid/view + * architecture more clearly, are more consistent in their + * implementation, and present a simpler model for new + * user-implemented reducers. + * + * @note Implicit conversions are provided between `%reducer_min` + * and `reducer<%op_min>`. This allows incremental code + * conversion: old code that used `%reducer_min` can pass a + * `%reducer_min` to a converted function that now expects a + * pointer or reference to a `reducer<%op_min>`, and vice + * versa. **But see @ref redminmax_compatibility.** + * + * @tparam Type The value type of the reducer. + * @tparam Compare The “less than†comparator type for the reducer. + * + * @see op_min + * @see op_min_view + * @see reducer + * @see ReducersMinMax + * @ingroup ReducersMinMaxMinValue + */ +template <typename Type, typename Compare=std::less<Type> > +class reducer_min : public reducer< op_min<Type, Compare, true> > +{ + __CILKRTS_STATIC_ASSERT( + ::cilk::internal::class_is_empty< + typename ::cilk::internal::binary_functor<Compare>::type >::value, + "cilk::reducer_min<Type, Compare> only works with " + "an empty Compare class"); + typedef reducer< op_min<Type, Compare, true> > base; +public: + + /// Type of data in a reducer_min. + typedef Type basic_value_type; + + /// The view type for the reducer. + typedef typename base::view_type view_type; + + /// The view type for the reducer. + typedef typename base::view_type View; + + /// The monoid type for the reducer. + typedef typename base::monoid_type monoid_type; + + /// The monoid type for the reducer. + typedef typename base::monoid_type Monoid; + + /// The view’s rhs proxy type. + typedef min_max_internal::rhs_proxy<View> rhs_proxy; + + using base::view; + + /** @name Constructors + */ + //@{ + + /// Construct the wrapper in its identity state (either `!is_set()`, or + /// `value() == identity value`). + reducer_min() : base() {} + + /// Construct the wrapper with a specified initial value. + explicit reducer_min(const Type& initial_value) : base(initial_value) {} + + /// Construct the wrapper in its identity state with a specified + /// comparator. + explicit reducer_min(const Compare& comp) : base(comp) {} + + /// Construct the wrapper with a specified initial value and a specified + /// comparator. + reducer_min(const Type& initial_value, const Compare& comp) + : base(initial_value, comp) {} + + //@} + + /** @name Forwarded functions + * @details Functions that update the contained accumulator variable are + * simply forwarded to the contained @ref op_min_view. */ + //@{ + + /// @copydoc cilk_lib_1_0::min_max_internal::view_content::is_set() const + bool is_set() const { return view().is_set(); } + + /// @copydoc op_min_view::calc_min(const Type&) + reducer_min& calc_min(const Type& x) + { view().calc_min(x); return *this; } + + /// @copydoc op_min_view::operator=(const min_max_internal::rhs_proxy<op_min_view>&) + reducer_min& operator=(const rhs_proxy& rhs) + { view() = rhs; return *this; } + + //@} + + /** Allow read-only access to the value within the current view. + * + * @returns A const reference to the value within the current view. + */ + const Type& get_reference() const { return view().get_reference(); } + + /// @name Dereference + /** Dereferencing a wrapper is a no-op. It simply returns the wrapper. + * Combined with the rule that a wrapper forwards view operations to the + * view, this means that view operations can be written the same way on + * reducers and wrappers, which is convenient for incrementally + * converting code using wrappers to code using reducers. That is: + * + * reducer< op_min<int> > r; + * r->calc_min(a); // *r returns the view + * // calc_min is a view member function + * + * reducer_min<int> w; + * w->calc_min(a); // *w returns the wrapper + * // calc_min is a wrapper member function that + * // calls the corresponding view function + */ + //@{ + reducer_min& operator*() { return *this; } + reducer_min const& operator*() const { return *this; } + + reducer_min* operator->() { return this; } + reducer_min const* operator->() const { return this; } + //@} + + /** @name Upcast + * @details In Cilk library 0.9, reducers were always cache-aligned. In + * library 1.0, reducer cache alignment is optional. By default, reducers + * are unaligned (i.e., just naturally aligned), but legacy wrappers + * inherit from cache-aligned reducers for binary compatibility. + * + * This means that a wrapper will automatically be upcast to its aligned + * reducer base class. The following conversion operators provide + * pseudo-upcasts to the corresponding unaligned reducer class. + */ + //@{ + operator reducer< op_min<Type, Compare, false> >& () + { + return *reinterpret_cast< reducer< op_min<Type, Compare, false> >* >(this); + } + + operator const reducer< op_min<Type, Compare, false> >& () const + { + return *reinterpret_cast< const reducer< op_min<Type, Compare, false> >* >(this); + } + //@} +}; + + +/** Compute the minimum of a reducer and a value. + * + * @deprecated Because reducer_min is deprecated. + */ +//@{ +// The legacy definition of min_of(reducer_min, value) has different +// behavior and a different return type than this definition. We add an +// unused third argument to this version of the function to give it a different +// signature, so that they won’t end up sharing a single object file entry. +struct min_of_1_0_t {}; +const min_of_1_0_t min_of_1_0 = {}; + +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_view<Type, Compare> > +min_of(const reducer_min<Type, Compare>& r, const Type& value, + const min_of_1_0_t& = min_of_1_0) +{ + return min_max_internal::make_proxy(value, r.view()); +} + +template <typename Type, typename Compare> +inline min_max_internal::rhs_proxy< op_min_view<Type, Compare> > +min_of(const Type& value, const reducer_min<Type, Compare>& r, + const min_of_1_0_t& = min_of_1_0) +{ + return min_max_internal::make_proxy(value, r.view()); +} +//@} + + +/** Deprecated maximum with index reducer wrapper class. + * + * reducer_max_index is the same as @ref reducer<@ref op_max_index>, except + * that reducer_max_index is a proxy for the contained view, so that + * accumulator variable update operations can be applied directly to the + * reducer. For example, a value is maximized with a `reducer<%op_max_index>` + * with `r->calc_max(i, a)`, but a value can be maximized with a + * `%reducer_max` with `r.calc_max(i, aa)`. + * + * + * @deprecated Users are strongly encouraged to use `reducer<monoid>` + * reducers rather than the old wrappers like reducer_max. + * The `reducer<monoid>` reducers show the reducer/monoid/view + * architecture more clearly, are more consistent in their + * implementation, and present a simpler model for new + * user-implemented reducers. + * + * @note Implicit conversions are provided between `%reducer_max_index` + * and `reducer<%op_max_index>`. This allows incremental code + * conversion: old code that used `%reducer_max_index` can pass a + * `%reducer_max_index` to a converted function that now expects a + * pointer or reference to a `reducer<%op_max_index>`, and vice + * versa. **But see @ref redminmax_compatibility.** + * + * @tparam Index The index type of the reducer. + * @tparam Type The value type of the reducer. + * @tparam Compare The “less than†comparator type for the reducer. + * + * @see op_max_index + * @see op_max_index_view + * @see reducer + * @see ReducersMinMax + * @ingroup ReducersMinMaxMaxIndex + */ +template < typename Index + , typename Type + , typename Compare = std::less<Type> + > +class reducer_max_index : + public reducer< op_max_index<Index, Type, Compare, true> > +{ + __CILKRTS_STATIC_ASSERT( + ::cilk::internal::class_is_empty< + typename ::cilk::internal::binary_functor<Compare>::type >::value, + "cilk::reducer_max_index<Type, Compare> only works with " + "an empty Compare class"); + typedef reducer< op_max_index<Index, Type, Compare, true> > base; +public: + + /// Type of data in a reducer_max_index. + typedef Type basic_value_type; + + /// The view type for the reducer. + typedef typename base::view_type view_type; + + /// The view type for the reducer. + typedef typename base::view_type View; + + /// The monoid type for the reducer. + typedef typename base::monoid_type monoid_type; + + /// The monoid type for the reducer. + typedef typename base::monoid_type Monoid; + + /// The view’s rhs proxy type. + typedef min_max_internal::rhs_proxy<View> rhs_proxy; + + using base::view; + + /** @name Constructors + */ + //@{ + + /// Construct the wrapper in its identity state (`!is_set()`). + reducer_max_index() : base() {} + + /// Construct with a specified initial index and value. + reducer_max_index(const Index& initial_index, + const Type& initial_value) + : base(initial_index, initial_value) {} + + /// Construct the wrapper with a specified comparator. + explicit reducer_max_index(const Compare& comp) : base(comp) {} + + /// Construct the wrapper with a specified initial index, value, + /// and comparator. + reducer_max_index(const Index& initial_index, + const Type& initial_value, + const Compare& comp) + : base(initial_index, initial_value, comp) {} + + //@} + + /** @name Set / Get + */ + //@{ + + /// Set the index and value of this object. + void set_value(const Index& index, const Type& value) + { base::set_value(std::make_pair(index, value)); } + + /// Return the maximum value. + const Type& get_value() const + { return view().get_reference(); } + + /// Return the maximum index. + const Index& get_index() const + { return view().get_index_reference(); } + + /// Return a const reference to value data member in the view. + const Type& get_reference() const + { return view().get_reference(); } + + /// Return a const reference to index data member in the view. + const Index& get_index_reference() const + { return view().get_index_reference(); } + + //@} + + /** @name Forwarded functions + * @details Functions that update the contained accumulator variable are + * simply forwarded to the contained @ref op_max_view. */ + //@{ + + /// @copydoc cilk_lib_1_0::min_max_internal::view_content::is_set() const + bool is_set() const { return view().is_set(); } + + /// @copydoc op_max_index_view::calc_max(const Index&, const Type&) + reducer_max_index& calc_max(const Index& i, const Type& x) + { view().calc_max(i, x); return *this; } + + /// @copydoc op_max_view::operator=(const min_max_internal::rhs_proxy<op_max_view>&) + reducer_max_index& operator=(const rhs_proxy& rhs) + { view() = rhs; return *this; } + + //@} + + /// @name Dereference + /** Dereferencing a wrapper is a no-op. It simply returns the wrapper. + * Combined with the rule that a wrapper forwards view operations to the + * view, this means that view operations can be written the same way on + * reducers and wrappers, which is convenient for incrementally + * converting code using wrappers to code using reducers. That is: + * + * reducer< op_max_index<int, int> > r; + * r->calc_max(i, a); // *r returns the view + * // calc_max is a view member function + * + * reducer_max_index<int, int> w; + * w->calc_max(i, a); // *w returns the wrapper + * // calc_max is a wrapper member function that + * // calls the corresponding view function + */ + //@{ + reducer_max_index& operator*() { return *this; } + reducer_max_index const& operator*() const { return *this; } + + reducer_max_index* operator->() { return this; } + reducer_max_index const* operator->() const { return this; } + //@} + + /** @name Upcast + * @details In Cilk library 0.9, reducers were always cache-aligned. In + * library 1.0, reducer cache alignment is optional. By default, reducers + * are unaligned (i.e., just naturally aligned), but legacy wrappers + * inherit from cache-aligned reducers for binary compatibility. + * + * This means that a wrapper will automatically be upcast to its aligned + * reducer base class. The following conversion operators provide + * pseudo-upcasts to the corresponding unaligned reducer class. + */ + //@{ + operator reducer< op_max_index<Index, Type, Compare, false> >& () + { + return *reinterpret_cast< reducer< op_max_index<Index, Type, Compare, false> >* >(this); + } + + operator const reducer< op_max_index<Index, Type, Compare, false> >& () const + { + return *reinterpret_cast< const reducer< op_max_index<Index, Type, Compare, false> >* >(this); + } + //@} + +}; + + +/** Deprecated minimum with index reducer wrapper class. + * + * reducer_min_index is the same as @ref reducer<@ref op_min_index>, except + * that reducer_min_index is a proxy for the contained view, so that + * accumulator variable update operations can be applied directly to the + * reducer. For example, a value is minimized with a `reducer<%op_min_index>` + * with `r->calc_min(i, a)`, but a value can be minimized with a + * `%reducer_min` with `r.calc_min(i, aa)`. + * + * + * @deprecated Users are strongly encouraged to use `reducer<monoid>` + * reducers rather than the old wrappers like reducer_min. + * The `reducer<monoid>` reducers show the reducer/monoid/view + * architecture more clearly, are more consistent in their + * implementation, and present a simpler model for new + * user-implemented reducers. + * + * @note Implicit conversions are provided between `%reducer_min_index` + * and `reducer<%op_min_index>`. This allows incremental code + * conversion: old code that used `%reducer_min_index` can pass a + * `%reducer_min_index` to a converted function that now expects a + * pointer or reference to a `reducer<%op_min_index>`, and vice + * versa. **But see @ref redminmax_compatibility.** + * + * @tparam Index The index type of the reducer. + * @tparam Type The value type of the reducer. + * @tparam Compare The “less than†comparator type for the reducer. + * + * @see op_min_index + * @see op_min_index_view + * @see reducer + * @see ReducersMinMax + * @ingroup ReducersMinMaxMinIndex + */ +template < typename Index + , typename Type + , typename Compare = std::less<Type> + > +class reducer_min_index : + public reducer< op_min_index<Index, Type, Compare, true> > +{ + __CILKRTS_STATIC_ASSERT( + ::cilk::internal::class_is_empty< + typename ::cilk::internal::binary_functor<Compare>::type >::value, + "cilk::reducer_min_index<Type, Compare> only works with " + "an empty Compare class"); + typedef reducer< op_min_index<Index, Type, Compare, true> > base; +public: + + /// Type of data in a reducer_min_index. + typedef Type basic_value_type; + + /// The view type for the reducer. + typedef typename base::view_type view_type; + + /// The view type for the reducer. + typedef typename base::view_type View; + + /// The monoid type for the reducer. + typedef typename base::monoid_type monoid_type; + + /// The monoid type for the reducer. + typedef typename base::monoid_type Monoid; + + /// The view’s rhs proxy type. + typedef min_max_internal::rhs_proxy<View> rhs_proxy; + + using base::view; + + /** @name Constructors + */ + //@{ + + /// Construct the wrapper in its identity state (`!is_set()`). + reducer_min_index() : base() {} + + /// Construct with a specified initial index and value. + reducer_min_index(const Index& initial_index, + const Type& initial_value) + : base(initial_index, initial_value) {} + + /// Construct the wrapper with a specified comparator. + explicit reducer_min_index(const Compare& comp) : base(comp) {} + + /// Construct the wrapper with a specified initial index, value, + /// and comparator. + reducer_min_index(const Index& initial_index, + const Type& initial_value, + const Compare& comp) + : base(initial_index, initial_value, comp) {} + + //@} + + /** @name Set / Get + */ + //@{ + + /// Set the index and value of this object. + void set_value(const Index& index, const Type& value) + { base::set_value(std::make_pair(index, value)); } + + /// Return the minimum value. + const Type& get_value() const + { return view().get_reference(); } + + /// Return the minimum index. + const Index& get_index() const + { return view().get_index_reference(); } + + /// Return a const reference to value data member in the view. + const Type& get_reference() const + { return view().get_reference(); } + + /// Return a const reference to index data member in the view. + const Index& get_index_reference() const + { return view().get_index_reference(); } + + //@} + + /** @name Forwarded functions + * @details Functions that update the contained accumulator variable are + * simply forwarded to the contained @ref op_min_view. */ + //@{ + + /// @copydoc cilk_lib_1_0::min_max_internal::view_content::is_set() const + bool is_set() const { return view().is_set(); } + + /// @copydoc op_min_index_view::calc_min(const Index&, const Type&) + reducer_min_index& calc_min(const Index& i, const Type& x) + { view().calc_min(i, x); return *this; } + + /// @copydoc op_min_view::operator=(const min_max_internal::rhs_proxy<op_min_view>&) + reducer_min_index& operator=(const rhs_proxy& rhs) + { view() = rhs; return *this; } + + //@} + + /// @name Dereference + /** Dereferencing a wrapper is a no-op. It simply returns the wrapper. + * Combined with the rule that a wrapper forwards view operations to the + * view, this means that view operations can be written the same way on + * reducers and wrappers, which is convenient for incrementally + * converting code using wrappers to code using reducers. That is: + * + * reducer< op_min_index<int, int> > r; + * r->calc_min(i, a); // *r returns the view + * // calc_min is a view member function + * + * reducer_min_index<int, int> w; + * w->calc_min(i, a); // *w returns the wrapper + * // calc_min is a wrapper member function that + * // calls the corresponding view function + */ + //@{ + reducer_min_index& operator*() { return *this; } + reducer_min_index const& operator*() const { return *this; } + + reducer_min_index* operator->() { return this; } + reducer_min_index const* operator->() const { return this; } + //@} + + /** @name Upcast + * @details In Cilk library 0.9, reducers were always cache-aligned. In + * library 1.0, reducer cache alignment is optional. By default, reducers + * are unaligned (i.e., just naturally aligned), but legacy wrappers + * inherit from cache-aligned reducers for binary compatibility. + * + * This means that a wrapper will automatically be upcast to its aligned + * reducer base class. The following conversion operators provide + * pseudo-upcasts to the corresponding unaligned reducer class. + */ + //@{ + operator reducer< op_min_index<Index, Type, Compare, false> >& () + { + return *reinterpret_cast< reducer< op_min_index<Index, Type, Compare, false> >* >(this); + } + + operator const reducer< op_min_index<Index, Type, Compare, false> >& () const + { + return *reinterpret_cast< const reducer< op_min_index<Index, Type, Compare, false> >* >(this); + } + //@} + +}; + + +#ifndef CILK_LIBRARY_0_9_REDUCER_MINMAX +} // namespace cilk_lib_1_0 +using namespace cilk_lib_1_0; +#endif + + +/// @cond internal +/** Metafunction specialization for reducer conversion. + * + * These specializations of the @ref legacy_reducer_downcast template class + * defined in reducer.h causes each `reducer< op_xxxx<Type> >` classes to have + * an `operator reducer_xxxx<Type>& ()` conversion operator that statically + * downcasts the `reducer<op_xxxx>` to the corresponding `reducer_xxxx` type. + * (The reverse conversion, from `reducer_xxxx` to `reducer<op_xxxx>`, is just + * an upcast, which is provided for free by the language.) + */ +template <typename Type, typename Compare, bool Align> +struct legacy_reducer_downcast< reducer< op_max<Type, Compare, Align> > > +{ + typedef reducer_max<Type> type; +}; + +template <typename Type, typename Compare, bool Align> +struct legacy_reducer_downcast< reducer< op_min<Type, Compare, Align> > > +{ + typedef reducer_min<Type> type; +}; + +template <typename Index, typename Type, typename Compare, bool Align> +struct legacy_reducer_downcast< reducer< op_max_index<Index, Type, Compare, Align> > > +{ + typedef reducer_max_index<Index, Type> type; +}; + +template <typename Index, typename Type, typename Compare, bool Align> +struct legacy_reducer_downcast< reducer< op_min_index<Index, Type, Compare, Align> > > +{ + typedef reducer_min_index<Index, Type> type; +}; +/// @endcond + +} // namespace cilk + +#endif // __cplusplus + + +/** @name C language reducer macros + * + * These macros are used to declare and work with numeric minimum and maximum reducers in C + * code. + * + * @see @ref page_reducers_in_c + */ + //@{ + + +#ifdef CILK_C_DEFINE_REDUCERS + +/* Integer min/max constants */ +#include <limits.h> + +/* Wchar_t min/max constants */ +#if defined(_MSC_VER) || defined(ANDROID) +# include <wchar.h> +#else +# include <stdint.h> +#endif + +/* Floating-point min/max constants */ +#include <math.h> +#ifndef HUGE_VALF + static const unsigned int __huge_valf[] = {0x7f800000}; +# define HUGE_VALF (*((const float *)__huge_valf)) +#endif + +#ifndef HUGE_VALL + static const unsigned int __huge_vall[] = {0, 0, 0x00007f80, 0}; +# define HUGE_VALL (*((const long double *)__huge_vall)) +#endif + +#endif + +/** Max reducer type name. + * + * This macro expands into the identifier which is the name of the max reducer + * type for a specified numeric type. + * + * @param tn The @ref reducers_c_type_names "numeric type name" specifying the type of the + * reducer. + * + * @see @ref reducers_c_predefined + */ +#define CILK_C_REDUCER_MAX_TYPE(tn) \ + __CILKRTS_MKIDENT(cilk_c_reducer_max_,tn) + +/** Declare a max reducer object. + * + * This macro expands into a declaration of a max reducer object for a specified numeric + * type. For example: + * + * CILK_C_REDUCER_MAX(my_reducer, double, -DBL_MAX); + * + * @param obj The variable name to be used for the declared reducer object. + * @param tn The @ref reducers_c_type_names "numeric type name" specifying the type of the + * reducer. + * @param v The initial value for the reducer. (A value which can be assigned to the + * numeric type represented by @a tn.) + * + * @see @ref reducers_c_predefined + */ +#define CILK_C_REDUCER_MAX(obj,tn,v) \ + CILK_C_REDUCER_MAX_TYPE(tn) obj = \ + CILK_C_INIT_REDUCER(_Typeof(obj.value), \ + __CILKRTS_MKIDENT(cilk_c_reducer_max_reduce_,tn), \ + __CILKRTS_MKIDENT(cilk_c_reducer_max_identity_,tn), \ + __cilkrts_hyperobject_noop_destroy, v) + +/** Maximize with a value. + * + * `CILK_C_REDUCER_MAX_CALC(reducer, v)` sets the current view of the + * reducer to the max of its previous value and a specified new value. + * This is equivalent to + * + * REDUCER_VIEW(reducer) = max(REDUCER_VIEW(reducer), v) + * + * @param reducer The reducer whose contained value is to be updated. + * @param v The value that it is to be maximized with. + */ +#define CILK_C_REDUCER_MAX_CALC(reducer, v) do { \ + _Typeof((reducer).value)* view = &(REDUCER_VIEW(reducer)); \ + _Typeof(v) __value = (v); \ + if (*view < __value) { \ + *view = __value; \ + } } while (0) + +/// @cond internal + +/** Declare the max reducer functions for a numeric type. + * + * This macro expands into external function declarations for functions which implement + * the reducer functionality for the max reducer type for a specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name†identifier, used to construct the reducer type name, + * function names, etc. + */ +#define CILK_C_REDUCER_MAX_DECLARATION(t,tn,id) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_MAX_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_max,tn,l,r); \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_max,tn); + +/** Define the max reducer functions for a numeric type. + * + * This macro expands into function definitions for functions which implement the + * reducer functionality for the max reducer type for a specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name†identifier, used to construct the reducer type name, + * function names, etc. + */ +#define CILK_C_REDUCER_MAX_DEFINITION(t,tn,id) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_MAX_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_max,tn,l,r) \ + { if (*(t*)l < *(t*)r) *(t*)l = *(t*)r; } \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_max,tn) \ + { *(t*)v = id; } + +//@{ +/** @def CILK_C_REDUCER_MAX_INSTANCE + * @brief Declare or define implementation functions for a reducer type. + * + * In the runtime source file c_reducers.c, the macro `CILK_C_DEFINE_REDUCERS` will be defined, and + * this macro will generate reducer implementation functions. Everywhere else, `CILK_C_DEFINE_REDUCERS` + * will be undefined, and this macro will expand into external declarations for the functions. + */ +#ifdef CILK_C_DEFINE_REDUCERS +# define CILK_C_REDUCER_MAX_INSTANCE(t,tn,id) \ + CILK_C_REDUCER_MAX_DEFINITION(t,tn,id) +#else +# define CILK_C_REDUCER_MAX_INSTANCE(t,tn,id) \ + CILK_C_REDUCER_MAX_DECLARATION(t,tn,id) +#endif +//@} + +/* Declare or define an instance of the reducer type and its functions for each + * numeric type. + */ +__CILKRTS_BEGIN_EXTERN_C +CILK_C_REDUCER_MAX_INSTANCE(char, char, CHAR_MIN) +CILK_C_REDUCER_MAX_INSTANCE(unsigned char, uchar, 0) +CILK_C_REDUCER_MAX_INSTANCE(signed char, schar, SCHAR_MIN) +CILK_C_REDUCER_MAX_INSTANCE(wchar_t, wchar_t, WCHAR_MIN) +CILK_C_REDUCER_MAX_INSTANCE(short, short, SHRT_MIN) +CILK_C_REDUCER_MAX_INSTANCE(unsigned short, ushort, 0) +CILK_C_REDUCER_MAX_INSTANCE(int, int, INT_MIN) +CILK_C_REDUCER_MAX_INSTANCE(unsigned int, uint, 0) +CILK_C_REDUCER_MAX_INSTANCE(unsigned int, unsigned, 0) // alternate name +CILK_C_REDUCER_MAX_INSTANCE(long, long, LONG_MIN) +CILK_C_REDUCER_MAX_INSTANCE(unsigned long, ulong, 0) +CILK_C_REDUCER_MAX_INSTANCE(long long, longlong, LLONG_MIN) +CILK_C_REDUCER_MAX_INSTANCE(unsigned long long, ulonglong, 0) +CILK_C_REDUCER_MAX_INSTANCE(float, float, -HUGE_VALF) +CILK_C_REDUCER_MAX_INSTANCE(double, double, -HUGE_VAL) +CILK_C_REDUCER_MAX_INSTANCE(long double, longdouble, -HUGE_VALL) +__CILKRTS_END_EXTERN_C + +/// @endcond + +/** Max_index reducer type name. + * + * This macro expands into the identifier which is the name of the max_index reducer + * type for a specified numeric type. + * + * @param tn The @ref reducers_c_type_names "numeric type name" specifying the type of the + * reducer. + * + * @see @ref reducers_c_predefined + */ +#define CILK_C_REDUCER_MAX_INDEX_TYPE(tn) \ + __CILKRTS_MKIDENT(cilk_c_reducer_max_index_,tn) + +/** Declare an op_max_index reducer object. + * + * This macro expands into a declaration of a max_index reducer object for a specified + * numeric type. For example: + * + * CILK_C_REDUCER_MAX_INDEX(my_reducer, double, -DBL_MAX_INDEX); + * + * @param obj The variable name to be used for the declared reducer object. + * @param tn The @ref reducers_c_type_names "numeric type name" specifying the type of the + * reducer. + * @param v The initial value for the reducer. (A value which can be assigned to the + * numeric type represented by @a tn.) + * + * @see @ref reducers_c_predefined + */ +#define CILK_C_REDUCER_MAX_INDEX(obj,tn,v) \ + CILK_C_REDUCER_MAX_INDEX_TYPE(tn) obj = \ + CILK_C_INIT_REDUCER(_Typeof(obj.value), \ + __CILKRTS_MKIDENT(cilk_c_reducer_max_index_reduce_,tn), \ + __CILKRTS_MKIDENT(cilk_c_reducer_max_index_identity_,tn), \ + __cilkrts_hyperobject_noop_destroy, {0, v}) + +/** Maximize with a value. + * + * `CILK_C_REDUCER_MAX_INDEX_CALC(reducer, i, v)` sets the current view of the + * reducer to the max of its previous value and a specified new value. + * This is equivalent to + * + * REDUCER_VIEW(reducer) = max_index(REDUCER_VIEW(reducer), v) + * + * If the value of the reducer is changed to @a v, then the index of the reducer is + * changed to @a i. + * + * @param reducer The reducer whose contained value and index are to be updated. + * @param i The index associated with the new value. + * @param v The value that it is to be maximized with. + */ +#define CILK_C_REDUCER_MAX_INDEX_CALC(reducer, i, v) do { \ + _Typeof((reducer).value)* view = &(REDUCER_VIEW(reducer)); \ + _Typeof(v) __value = (v); \ + if (view->value < __value) { \ + view->index = (i); \ + view->value = __value; \ + } } while (0) + +/// @cond internal + +/** Declare the max_index view type. + * + * The view of a max_index reducer is a structure containing both the + * maximum value for the reducer and the index that was associated with + * that value in the sequence of input values. + */ +#define CILK_C_REDUCER_MAX_INDEX_VIEW(t,tn) \ + typedef struct { \ + __STDNS ptrdiff_t index; \ + t value; \ + } __CILKRTS_MKIDENT(cilk_c_reducer_max_index_view_,tn) + +/** Declare the max_index reducer functions for a numeric type. + * + * This macro expands into external function declarations for functions which implement + * the reducer functionality for the max_index reducer type for a specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name†identifier, used to construct the reducer type name, + * function names, etc. + */ +#define CILK_C_REDUCER_MAX_INDEX_DECLARATION(t,tn,id) \ + CILK_C_REDUCER_MAX_INDEX_VIEW(t,tn); \ + typedef CILK_C_DECLARE_REDUCER( \ + __CILKRTS_MKIDENT(cilk_c_reducer_max_index_view_,tn)) \ + CILK_C_REDUCER_MAX_INDEX_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_max_index,tn,l,r); \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_max_index,tn); + +/** Define the max_index reducer functions for a numeric type. + * + * This macro expands into function definitions for functions which implement the + * reducer functionality for the max_index reducer type for a specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name†identifier, used to construct the reducer type name, + * function names, etc. + */ +#define CILK_C_REDUCER_MAX_INDEX_DEFINITION(t,tn,id) \ + CILK_C_REDUCER_MAX_INDEX_VIEW(t,tn); \ + typedef CILK_C_DECLARE_REDUCER( \ + __CILKRTS_MKIDENT(cilk_c_reducer_max_index_view_,tn)) \ + CILK_C_REDUCER_MAX_INDEX_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_max_index,tn,l,r) \ + { typedef __CILKRTS_MKIDENT(cilk_c_reducer_max_index_view_,tn) view_t; \ + if (((view_t*)l)->value < ((view_t*)r)->value) \ + *(view_t*)l = *(view_t*)r; } \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_max_index,tn) \ + { typedef __CILKRTS_MKIDENT(cilk_c_reducer_max_index_view_,tn) view_t; \ + ((view_t*)v)->index = 0; ((view_t*)v)->value = id; } + +//@{ +/** @def CILK_C_REDUCER_MAX_INDEX_INSTANCE + * @brief Declare or define implementation functions for a reducer type. + * + * In the runtime source file c_reducers.c, the macro `CILK_C_DEFINE_REDUCERS` will be defined, and + * this macro will generate reducer implementation functions. Everywhere else, `CILK_C_DEFINE_REDUCERS` + * will be undefined, and this macro will expand into external declarations for the functions. + */ +#ifdef CILK_C_DEFINE_REDUCERS +# define CILK_C_REDUCER_MAX_INDEX_INSTANCE(t,tn,id) \ + CILK_C_REDUCER_MAX_INDEX_DEFINITION(t,tn,id) +#else +# define CILK_C_REDUCER_MAX_INDEX_INSTANCE(t,tn,id) \ + CILK_C_REDUCER_MAX_INDEX_DECLARATION(t,tn,id) +#endif +//@} + +/* Declare or define an instance of the reducer type and its functions for each + * numeric type. + */ +__CILKRTS_BEGIN_EXTERN_C +CILK_C_REDUCER_MAX_INDEX_INSTANCE(char, char, CHAR_MIN) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(unsigned char, uchar, 0) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(signed char, schar, SCHAR_MIN) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(wchar_t, wchar_t, WCHAR_MIN) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(short, short, SHRT_MIN) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(unsigned short, ushort, 0) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(int, int, INT_MIN) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(unsigned int, uint, 0) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(unsigned int, unsigned, 0) // alternate name +CILK_C_REDUCER_MAX_INDEX_INSTANCE(long, long, LONG_MIN) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(unsigned long, ulong, 0) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(long long, longlong, LLONG_MIN) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(unsigned long long, ulonglong, 0) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(float, float, -HUGE_VALF) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(double, double, -HUGE_VAL) +CILK_C_REDUCER_MAX_INDEX_INSTANCE(long double, longdouble, -HUGE_VALL) +__CILKRTS_END_EXTERN_C + +/// @endcond + +/** Min reducer type name. + * + * This macro expands into the identifier which is the name of the min reducer + * type for a specified numeric type. + * + * @param tn The @ref reducers_c_type_names "numeric type name" specifying the type of the + * reducer. + * + * @see @ref reducers_c_predefined + */ +#define CILK_C_REDUCER_MIN_TYPE(tn) \ + __CILKRTS_MKIDENT(cilk_c_reducer_min_,tn) + +/** Declare a min reducer object. + * + * This macro expands into a declaration of a min reducer object for a specified numeric + * type. For example: + * + * CILK_C_REDUCER_MIN(my_reducer, double, DBL_MAX); + * + * @param obj The variable name to be used for the declared reducer object. + * @param tn The @ref reducers_c_type_names "numeric type name" specifying the type of the + * reducer. + * @param v The initial value for the reducer. (A value which can be assigned to the + * numeric type represented by @a tn.) + * + * @see @ref reducers_c_predefined + */ +#define CILK_C_REDUCER_MIN(obj,tn,v) \ + CILK_C_REDUCER_MIN_TYPE(tn) obj = \ + CILK_C_INIT_REDUCER(_Typeof(obj.value), \ + __CILKRTS_MKIDENT(cilk_c_reducer_min_reduce_,tn), \ + __CILKRTS_MKIDENT(cilk_c_reducer_min_identity_,tn), \ + __cilkrts_hyperobject_noop_destroy, v) + +/** Minimize with a value. + * + * `CILK_C_REDUCER_MIN_CALC(reducer, v)` sets the current view of the + * reducer to the min of its previous value and a specified new value. + * This is equivalent to + * + * REDUCER_VIEW(reducer) = min(REDUCER_VIEW(reducer), v) + * + * @param reducer The reducer whose contained value is to be updated. + * @param v The value that it is to be minimized with. + */ +#define CILK_C_REDUCER_MIN_CALC(reducer, v) do { \ + _Typeof((reducer).value)* view = &(REDUCER_VIEW(reducer)); \ + _Typeof(v) __value = (v); \ + if (*view > __value) { \ + *view = __value; \ + } } while (0) + +/// @cond internal + +/** Declare the min reducer functions for a numeric type. + * + * This macro expands into external function declarations for functions which implement + * the reducer functionality for the min reducer type for a specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name†identifier, used to construct the reducer type name, + * function names, etc. + */ +#define CILK_C_REDUCER_MIN_DECLARATION(t,tn,id) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_MIN_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_min,tn,l,r); \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_min,tn); + +/** Define the min reducer functions for a numeric type. + * + * This macro expands into function definitions for functions which implement the + * reducer functionality for the min reducer type for a specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name†identifier, used to construct the reducer type name, + * function names, etc. + */ +#define CILK_C_REDUCER_MIN_DEFINITION(t,tn,id) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_MIN_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_min,tn,l,r) \ + { if (*(t*)l > *(t*)r) *(t*)l = *(t*)r; } \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_min,tn) \ + { *(t*)v = id; } + +//@{ +/** @def CILK_C_REDUCER_MIN_INSTANCE + * @brief Declare or define implementation functions for a reducer type. + * + * In the runtime source file c_reducers.c, the macro `CILK_C_DEFINE_REDUCERS` will be defined, and + * this macro will generate reducer implementation functions. Everywhere else, `CILK_C_DEFINE_REDUCERS` + * will be undefined, and this macro will expand into external declarations for the functions. + */ +#ifdef CILK_C_DEFINE_REDUCERS +# define CILK_C_REDUCER_MIN_INSTANCE(t,tn,id) \ + CILK_C_REDUCER_MIN_DEFINITION(t,tn,id) +#else +# define CILK_C_REDUCER_MIN_INSTANCE(t,tn,id) \ + CILK_C_REDUCER_MIN_DECLARATION(t,tn,id) +#endif +//@} + +/* Declare or define an instance of the reducer type and its functions for each + * numeric type. + */ +__CILKRTS_BEGIN_EXTERN_C +CILK_C_REDUCER_MIN_INSTANCE(char, char, CHAR_MAX) +CILK_C_REDUCER_MIN_INSTANCE(unsigned char, uchar, CHAR_MAX) +CILK_C_REDUCER_MIN_INSTANCE(signed char, schar, SCHAR_MAX) +CILK_C_REDUCER_MIN_INSTANCE(wchar_t, wchar_t, WCHAR_MAX) +CILK_C_REDUCER_MIN_INSTANCE(short, short, SHRT_MAX) +CILK_C_REDUCER_MIN_INSTANCE(unsigned short, ushort, USHRT_MAX) +CILK_C_REDUCER_MIN_INSTANCE(int, int, INT_MAX) +CILK_C_REDUCER_MIN_INSTANCE(unsigned int, uint, UINT_MAX) +CILK_C_REDUCER_MIN_INSTANCE(unsigned int, unsigned, UINT_MAX) // alternate name +CILK_C_REDUCER_MIN_INSTANCE(long, long, LONG_MAX) +CILK_C_REDUCER_MIN_INSTANCE(unsigned long, ulong, ULONG_MAX) +CILK_C_REDUCER_MIN_INSTANCE(long long, longlong, LLONG_MAX) +CILK_C_REDUCER_MIN_INSTANCE(unsigned long long, ulonglong, ULLONG_MAX) +CILK_C_REDUCER_MIN_INSTANCE(float, float, HUGE_VALF) +CILK_C_REDUCER_MIN_INSTANCE(double, double, HUGE_VAL) +CILK_C_REDUCER_MIN_INSTANCE(long double, longdouble, HUGE_VALL) +__CILKRTS_END_EXTERN_C + +/// @endcond + +/** Min_index reducer type name. + * + * This macro expands into the identifier which is the name of the min_index reducer + * type for a specified numeric type. + * + * @param tn The @ref reducers_c_type_names "numeric type name" specifying the type of the + * reducer. + * + * @see @ref reducers_c_predefined + */ +#define CILK_C_REDUCER_MIN_INDEX_TYPE(tn) \ + __CILKRTS_MKIDENT(cilk_c_reducer_min_index_,tn) + +/** Declare an op_min_index reducer object. + * + * This macro expands into a declaration of a min_index reducer object for a specified + * numeric type. For example: + * + * CILK_C_REDUCER_MIN_INDEX(my_reducer, double, -DBL_MIN_INDEX); + * + * @param obj The variable name to be used for the declared reducer object. + * @param tn The @ref reducers_c_type_names "numeric type name" specifying the type of the + * reducer. + * @param v The initial value for the reducer. (A value which can be assigned to the + * numeric type represented by @a tn.) + * + * @see @ref reducers_c_predefined + */ +#define CILK_C_REDUCER_MIN_INDEX(obj,tn,v) \ + CILK_C_REDUCER_MIN_INDEX_TYPE(tn) obj = \ + CILK_C_INIT_REDUCER(_Typeof(obj.value), \ + __CILKRTS_MKIDENT(cilk_c_reducer_min_index_reduce_,tn), \ + __CILKRTS_MKIDENT(cilk_c_reducer_min_index_identity_,tn), \ + __cilkrts_hyperobject_noop_destroy, {0, v}) + +/** Minimize with a value. + * + * `CILK_C_REDUCER_MIN_INDEX_CALC(reducer, i, v)` sets the current view of the + * reducer to the min of its previous value and a specified new value. + * This is equivalent to + * + * REDUCER_VIEW(reducer) = min_index(REDUCER_VIEW(reducer), v) + * + * If the value of the reducer is changed to @a v, then the index of the reducer is + * changed to @a i. + * + * @param reducer The reducer whose contained value and index are to be updated. + * @param i The index associated with the new value. + * @param v The value that it is to be minimized with. + */ +#define CILK_C_REDUCER_MIN_INDEX_CALC(reducer, i, v) do { \ + _Typeof((reducer).value)* view = &(REDUCER_VIEW(reducer)); \ + _Typeof(v) __value = (v); \ + if (view->value > __value) { \ + view->index = (i); \ + view->value = __value; \ + } } while (0) + +/// @cond internal + +/** Declare the min_index view type. + * + * The view of a min_index reducer is a structure containing both the + * minimum value for the reducer and the index that was associated with + * that value in the sequence of input values. + */ +#define CILK_C_REDUCER_MIN_INDEX_VIEW(t,tn) \ + typedef struct { \ + __STDNS ptrdiff_t index; \ + t value; \ + } __CILKRTS_MKIDENT(cilk_c_reducer_min_index_view_,tn) + +/** Declare the min_index reducer functions for a numeric type. + * + * This macro expands into external function declarations for functions which implement + * the reducer functionality for the min_index reducer type for a specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name†identifier, used to construct the reducer type name, + * function names, etc. + */ +#define CILK_C_REDUCER_MIN_INDEX_DECLARATION(t,tn,id) \ + CILK_C_REDUCER_MIN_INDEX_VIEW(t,tn); \ + typedef CILK_C_DECLARE_REDUCER( \ + __CILKRTS_MKIDENT(cilk_c_reducer_min_index_view_,tn)) \ + CILK_C_REDUCER_MIN_INDEX_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_min_index,tn,l,r); \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_min_index,tn); + +/** Define the min_index reducer functions for a numeric type. + * + * This macro expands into function definitions for functions which implement the + * reducer functionality for the min_index reducer type for a specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name†identifier, used to construct the reducer type name, + * function names, etc. + */ +#define CILK_C_REDUCER_MIN_INDEX_DEFINITION(t,tn,id) \ + CILK_C_REDUCER_MIN_INDEX_VIEW(t,tn); \ + typedef CILK_C_DECLARE_REDUCER( \ + __CILKRTS_MKIDENT(cilk_c_reducer_min_index_view_,tn)) \ + CILK_C_REDUCER_MIN_INDEX_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_min_index,tn,l,r) \ + { typedef __CILKRTS_MKIDENT(cilk_c_reducer_min_index_view_,tn) view_t; \ + if (((view_t*)l)->value > ((view_t*)r)->value) \ + *(view_t*)l = *(view_t*)r; } \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_min_index,tn) \ + { typedef __CILKRTS_MKIDENT(cilk_c_reducer_min_index_view_,tn) view_t; \ + ((view_t*)v)->index = 0; ((view_t*)v)->value = id; } + +//@{ +/** @def CILK_C_REDUCER_MIN_INDEX_INSTANCE + * @brief Declare or define implementation functions for a reducer type. + * + * In the runtime source file c_reducers.c, the macro `CILK_C_DEFINE_REDUCERS` will be defined, and + * this macro will generate reducer implementation functions. Everywhere else, `CILK_C_DEFINE_REDUCERS` + * will be undefined, and this macro will expand into external declarations for the functions. + */ +#ifdef CILK_C_DEFINE_REDUCERS +# define CILK_C_REDUCER_MIN_INDEX_INSTANCE(t,tn,id) \ + CILK_C_REDUCER_MIN_INDEX_DEFINITION(t,tn,id) +#else +# define CILK_C_REDUCER_MIN_INDEX_INSTANCE(t,tn,id) \ + CILK_C_REDUCER_MIN_INDEX_DECLARATION(t,tn,id) +#endif +//@} + +/* Declare or define an instance of the reducer type and its functions for each + * numeric type. + */ +__CILKRTS_BEGIN_EXTERN_C +CILK_C_REDUCER_MIN_INDEX_INSTANCE(char, char, CHAR_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(unsigned char, uchar, CHAR_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(signed char, schar, SCHAR_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(wchar_t, wchar_t, WCHAR_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(short, short, SHRT_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(unsigned short, ushort, USHRT_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(int, int, INT_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(unsigned int, uint, UINT_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(unsigned int, unsigned, UINT_MAX) // alternate name +CILK_C_REDUCER_MIN_INDEX_INSTANCE(long, long, LONG_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(unsigned long, ulong, ULONG_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(long long, longlong, LLONG_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(unsigned long long, ulonglong, ULLONG_MAX) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(float, float, HUGE_VALF) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(double, double, HUGE_VAL) +CILK_C_REDUCER_MIN_INDEX_INSTANCE(long double, longdouble, HUGE_VALL) +__CILKRTS_END_EXTERN_C + +/// @endcond + +//@} + +#endif // defined REDUCER_MAX_H_INCLUDED diff --git a/libcilkrts/include/cilk/reducer_opadd.h b/libcilkrts/include/cilk/reducer_opadd.h new file mode 100644 index 00000000000..4b7a83f845d --- /dev/null +++ b/libcilkrts/include/cilk/reducer_opadd.h @@ -0,0 +1,690 @@ +/* reducer_opadd.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file reducer_opadd.h + * + * @brief Defines classes for doing parallel addition reductions. + * + * @ingroup ReducersAdd + * + * @see ReducersAdd + */ + +#ifndef REDUCER_OPADD_H_INCLUDED +#define REDUCER_OPADD_H_INCLUDED + +#include <cilk/reducer.h> + +/** @defgroup ReducersAdd Addition Reducers + * + * Addition reducers allow the computation of the sum of a set of values in + * parallel. + * + * @ingroup Reducers + * + * You should be familiar with @ref pagereducers "Cilk reducers", described in + * file `reducers.md`, and particularly with @ref reducers_using, before trying + * to use the information in this file. + * + * @section redopadd_usage Usage Example + * + * cilk::reducer< cilk::op_add<int> > r; + * cilk_for (int i = 0; i != N; ++i) { + * *r += a[i]; + * } + * return r.get_value(); + * + * @section redopadd_monoid The Monoid + * + * @subsection redopadd_monoid_values Value Set + * + * The value set of an addition reducer is the set of values of `Type`, which + * is expected to be a builtin numeric type (or something like it, such as + * `std::complex`). + * + * @subsection redopadd_monoid_operator Operator + * + * The operator of an addition reducer is the addition operator, defined by + * the “`+`†binary operator on `Type`. + * + * @subsection redopadd_monoid_identity Identity + * + * The identity value of the reducer is the numeric value “`0`â€. This is + * expected to be the value of the default constructor `Type()`. + * + * @section redopadd_operations Operations + * + * @subsection redopadd_constructors Constructors + * + * reducer() // identity + * reducer(const Type& value) + * reducer(move_in(Type& variable)) + * + * @subsection redopadd_get_set Set and Get + * + * r.set_value(const Type& value) + * const Type& = r.get_value() const + * r.move_in(Type& variable) + * r.move_out(Type& variable) + * + * @subsection redopadd_initial Initial Values + * + * If an addition reducer is constructed without an explicit initial value, + * then its initial value will be its identity value, as long as `Type` + * satisfies the requirements of @ref redopadd_types. + * + * @subsection redopadd_view_ops View Operations + * + * *r += a + * *r -= a + * ++*r + * --*r + * (*r)++ + * (*r)-- + * *r = *r + a + * *r = *r - a + * *r = *r ± a1 ± a2 … ± an + * + * The post-increment and post-decrement operations do not return a value. (If + * they did, they would expose the value contained in the view, which is + * non-deterministic in the middle of a reduction.) + * + * Note that subtraction operations are allowed on an addition reducer because + * subtraction is equivalent to addition with a negated operand. It is true + * that `(x - y) - z` is not equivalent to `x - (y - z)`, but + * `(x + (-y)) + (-z)` _is_ equivalent to `x + ((-y) + (-z))`. + * + * @section redopadd_floating_point Issues with Floating-Point Types + * + * Because of precision and round-off issues, floating-point addition is not + * really associative. For example, `(1e30 + -1e30) + 1 == 1`, but + * `1e30 + (-1e30 + 1) == 0`. + * + * In many cases, this won’t matter, but computations which have been + * carefully ordered to control round-off errors may not deal well with + * being reassociated. In general, you should be sure to understand the + * floating-point behavior of your program before doing any transformation + * that will reassociate its computations. + * + * @section redopadd_types Type and Operator Requirements + * + * `Type` must be `Copy Constructible`, `Default Constructible`, and + * `Assignable`. + * + * The operator “`+=`†must be defined on `Type`, with `x += a` having the + * same meaning as `x = x + a`. In addition, if the code uses the “`-=`â€, + * pre-increment, post-increment, pre-decrement, or post-decrement operators, + * then the corresponding operators must be defined on `Type`. + * + * The expression `Type()` must be a valid expression which yields the + * identity value (the value of `Type` whose numeric value is zero). + * + * @section redopadd_in_c Addition Reducers in C + * + * The @ref CILK_C_REDUCER_OPADD and @ref CILK_C_REDUCER_OPADD_TYPE macros can + * be used to do addition reductions in C. For example: + * + * CILK_C_REDUCER_OPADD(r, double, 0); + * CILK_C_REGISTER_REDUCER(r); + * cilk_for(int i = 0; i != n; ++i) { + * REDUCER_VIEW(r) += a[i]; + * } + * CILK_C_UNREGISTER_REDUCER(r); + * printf("The sum of the elements of a is %f\n", REDUCER_VIEW(r)); + * + * See @ref reducers_c_predefined. + */ + +#ifdef __cplusplus + +namespace cilk { + +/** The addition reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer< cilk::op_add<Type> >`. It holds the accumulator variable + * for the reduction, and allows only addition and subtraction operations to + * be performed on it. + * + * @note The reducer “dereference†operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `+=` operation would be used in an expression like `*r += a`, where + * `r` is an op_add reducer variable. + * + * @tparam Type The type of the contained accumulator variable. This will + * be the value type of a monoid_with_view that is + * instantiated with this view. + * + * @see ReducersAdd + * @see op_add + * + * @ingroup ReducersAdd + */ +template <typename Type> +class op_add_view : public scalar_view<Type> +{ + typedef scalar_view<Type> base; + +public: + /** Class to represent the right-hand side of + * `*reducer = *reducer ± value`. + * + * The only assignment operator for the op_add_view class takes an + * rhs_proxy as its operand. This results in the syntactic restriction + * that the only expressions that can be assigned to an op_add_view are + * ones which generate an rhs_proxy — that is, expressions of the form + * `op_add_view ± value ... ± value`. + * + * @warning + * The lhs and rhs views in such an assignment must be the same; + * otherwise, the behavior will be undefined. (I.e., `v1 = v1 + x` is + * legal; `v1 = v2 + x` is illegal.) This condition will be checked with a + * runtime assertion when compiled in debug mode. + * + * @see op_add_view + */ + class rhs_proxy { + friend class op_add_view; + + const op_add_view* m_view; + Type m_value; + + // Constructor is invoked only from op_add_view::operator+() and + // op_add_view::operator-(). + // + rhs_proxy(const op_add_view* view, const Type& value) : + m_view(view), m_value(value) {} + + rhs_proxy& operator=(const rhs_proxy&); // Disable assignment operator + rhs_proxy(); // Disable default constructor + + public: + //@{ + /** Add or subtract an additional rhs value. If `v` is an op_add_view + * and `a1` is a value, then the expression `v + a1` invokes the view’s + * `operator+()` to create an rhs_proxy for `(v, a1)`; then + * `v + a1 + a2` invokes the rhs_proxy’s `operator+()` to create a new + * rhs_proxy for `(v, a1+a2)`. This allows the right-hand side of an + * assignment to be not just `view ± value`, but + * `view ± value ± value ... ± value`. The effect is that + * + * v = v ± a1 ± a2 ... ± an; + * + * is evaluated as + * + * v = v ± (±a1 ± a2 ... ± an); + */ + rhs_proxy& operator+(const Type& x) { m_value += x; return *this; } + rhs_proxy& operator-(const Type& x) { m_value -= x; return *this; } + //@} + }; + + + /** Default/identity constructor. This constructor initializes the + * contained value to `Type()`, which is expected to be the identity value + * for addition on `Type`. + */ + op_add_view() : base() {} + + /** Construct with a specified initial value. + */ + explicit op_add_view(const Type& v) : base(v) {} + + /** Reduction operation. + * + * This function is invoked by the @ref op_add monoid to combine the views + * of two strands when the right strand merges with the left one. It adds + * the value contained in the right-strand view to the value contained in + * the left-strand view, and leaves the value in the right-strand view + * undefined. + * + * @param right A pointer to the right-strand view. (`this` points to + * the left-strand view.) + * + * @note Used only by the @ref op_add monoid to implement the monoid + * reduce operation. + */ + void reduce(op_add_view* right) { this->m_value += right->m_value; } + + /** @name Accumulator variable updates. + * + * These functions support the various syntaxes for incrementing or + * decrementing the accumulator variable contained in the view. + */ + //@{ + + /** Increment the accumulator variable by @a x. + */ + op_add_view& operator+=(const Type& x) { this->m_value += x; return *this; } + + /** Decrement the accumulator variable by @a x. + */ + op_add_view& operator-=(const Type& x) { this->m_value -= x; return *this; } + + /** Pre-increment. + */ + op_add_view& operator++() { ++this->m_value; return *this; } + + /** Post-increment. + * + * @note Conventionally, post-increment operators return the old value + * of the incremented variable. However, reducer views do not + * expose their contained values, so `view++` does not have a + * return value. + */ + void operator++(int) { this->m_value++; } + + /** Pre-decrement. + */ + op_add_view& operator--() { --this->m_value; return *this; } + + /** Post-decrement. + * + * @note Conventionally, post-decrement operators return the old value + * of the decremented variable. However, reducer views do not + * expose their contained values, so `view--` does not have a + * return value. + */ + void operator--(int) { this->m_value--; } + + /** Create an object representing `*this + x`. + * + * @see rhs_proxy + */ + rhs_proxy operator+(const Type& x) const { return rhs_proxy(this, x); } + + /** Create an object representing `*this - x`. + * + * @see rhs_proxy + */ + rhs_proxy operator-(const Type& x) const { return rhs_proxy(this, -x); } + + /** Assign the result of a `view ± value` expression to the view. Note that + * this is the only assignment operator for this class. + * + * @see rhs_proxy + */ + op_add_view& operator=(const rhs_proxy& rhs) { + __CILKRTS_ASSERT(this == rhs.m_view); + this->m_value += rhs.m_value; + return *this; + } + + //@} +}; + + +/** Monoid class for addition reductions. Instantiate the cilk::reducer + * template class with an op_add monoid to create an addition reducer class. + * For example, to compute + * the sum of a set of `int` values: + * + * cilk::reducer< cilk::op_add<int> > r; + * + * @tparam Type The reducer value type. + * @tparam Align If `false` (the default), reducers instantiated on this + * monoid will be naturally aligned (the Cilk library 1.0 + * behavior). If `true`, reducers instantiated on this monoid + * will be cache-aligned for binary compatibility with + * reducers in Cilk library version 0.9. + * + * @see ReducersAdd + * @see op_add_view + * + * @ingroup ReducersAdd + */ +template <typename Type, bool Align = false> +struct op_add : public monoid_with_view<op_add_view<Type>, Align> {}; + +/** **Deprecated** addition reducer wrapper class. + * + * reducer_opadd is the same as @ref reducer<@ref op_add>, except that + * reducer_opadd is a proxy for the contained view, so that accumulator + * variable update operations can be applied directly to the reducer. For + * example, a value is added to a `reducer<%op_add>` with `*r += a`, but a + * value can be added to a `%reducer_opadd` with `r += a`. + * + * @deprecated Users are strongly encouraged to use `reducer<monoid>` + * reducers rather than the old wrappers like reducer_opadd. + * The `reducer<monoid>` reducers show the reducer/monoid/view + * architecture more clearly, are more consistent in their + * implementation, and present a simpler model for new + * user-implemented reducers. + * + * @note Implicit conversions are provided between `%reducer_opadd` + * and `reducer<%op_add>`. This allows incremental code + * conversion: old code that used `%reducer_opadd` can pass a + * `%reducer_opadd` to a converted function that now expects a + * pointer or reference to a `reducer<%op_add>`, and vice + * versa. + * + * @tparam Type The value type of the reducer. + * + * @see op_add + * @see reducer + * @see ReducersAdd + * + * @ingroup ReducersAdd + */ +template <typename Type> +class reducer_opadd : public reducer< op_add<Type, true> > +{ + typedef reducer< op_add<Type, true> > base; + using base::view; + + public: + /// The view type for the reducer. + typedef typename base::view_type view_type; + + /// The view’s rhs proxy type. + typedef typename view_type::rhs_proxy rhs_proxy; + + /// The view type for the reducer. + typedef view_type View; + + /// The monoid type for the reducer. + typedef typename base::monoid_type Monoid; + + /** @name Constructors + */ + //@{ + + /** Default (identity) constructor. + * + * Constructs the wrapper with the default initial value of `Type()`. + */ + reducer_opadd() {} + + /** Value constructor. + * + * Constructs the wrapper with a specified initial value. + */ + explicit reducer_opadd(const Type& initial_value) : base(initial_value) {} + + //@} + + /** @name Forwarded functions + * @details Functions that update the contained accumulator variable are + * simply forwarded to the contained @ref op_add_view. */ + //@{ + + /// @copydoc op_add_view::operator+=(const Type&) + reducer_opadd& operator+=(const Type& x) { view() += x; return *this; } + + /// @copydoc op_add_view::operator-=(const Type&) + reducer_opadd& operator-=(const Type& x) { view() -= x; return *this; } + + /// @copydoc op_add_view::operator++() + reducer_opadd& operator++() { ++view(); return *this; } + + /// @copydoc op_add_view::operator++(int) + void operator++(int) { view()++; } + + /// @copydoc op_add_view::operator-\-() + reducer_opadd& operator--() { --view(); return *this; } + + /// @copydoc op_add_view::operator-\-(int) + void operator--(int) { view()--; } + + // The legacy definitions of reducer_opadd::operator+() and + // reducer_opadd::operator-() have different behavior and a different + // return type than this definition. The legacy version is defined as a + // member function, so this new version is defined as a free function to + // give it a different signature, so that they won’t end up sharing a + // single object file entry. + + /// @copydoc op_add_view::operator+(const Type&) const + friend rhs_proxy operator+(const reducer_opadd& r, const Type& x) + { + return r.view() + x; + } + /// @copydoc op_add_view::operator-(const Type&) const + friend rhs_proxy operator-(const reducer_opadd& r, const Type& x) + { + return r.view() - x; + } + /// @copydoc op_add_view::operator=(const rhs_proxy&) + reducer_opadd& operator=(const rhs_proxy& temp) + { + view() = temp; + return *this; + } + //@} + + /** @name Dereference + * @details Dereferencing a wrapper is a no-op. It simply returns the + * wrapper. Combined with the rule that the wrapper forwards view + * operations to its contained view, this means that view operations can + * be written the same way on reducers and wrappers, which is convenient + * for incrementally converting old code using wrappers to use reducers + * instead. That is: + * + * reducer< op_add<int> > r; + * *r += a; // *r returns the view + * // operator += is a view member function + * + * reducer_opadd<int> w; + * *w += a; // *w returns the wrapper + * // operator += is a wrapper member function that + * // calls the corresponding view function + */ + //@{ + reducer_opadd& operator*() { return *this; } + reducer_opadd const& operator*() const { return *this; } + + reducer_opadd* operator->() { return this; } + reducer_opadd const* operator->() const { return this; } + //@} + + /** @name Upcast + * @details In Cilk library 0.9, reducers were always cache-aligned. In + * library 1.0, reducer cache alignment is optional. By default, reducers + * are unaligned (i.e., just naturally aligned), but legacy wrappers + * inherit from cache-aligned reducers for binary compatibility. + * + * This means that a wrapper will automatically be upcast to its aligned + * reducer base class. The following conversion operators provide + * pseudo-upcasts to the corresponding unaligned reducer class. + */ + //@{ + operator reducer< op_add<Type, false> >& () + { + return *reinterpret_cast< reducer< op_add<Type, false> >* >(this); + } + operator const reducer< op_add<Type, false> >& () const + { + return *reinterpret_cast< const reducer< op_add<Type, false> >* >(this); + } + //@} +}; + +/// @cond internal +/** Metafunction specialization for reducer conversion. + * + * This specialization of the @ref legacy_reducer_downcast template class + * defined in reducer.h causes the `reducer< op_add<Type> >` class to have an + * `operator reducer_opadd<Type>& ()` conversion operator that statically + * downcasts the `reducer<op_add>` to the corresponding `reducer_opadd` type. + * (The reverse conversion, from `reducer_opadd` to `reducer<op_add>`, is just + * an upcast, which is provided for free by the language.) + * + * @ingroup ReducersAdd + */ +template <typename Type, bool Align> +struct legacy_reducer_downcast<reducer<op_add<Type, Align> > > +{ + typedef reducer_opadd<Type> type; +}; +/// @endcond + +} // namespace cilk + +#endif // __cplusplus + + +/** @ingroup ReducersAdd + */ +//@{ + +/** @name C Language Reducer Macros + * + * These macros are used to declare and work with numeric op_add reducers in + * C code. + * + * @see @ref page_reducers_in_c + */ + //@{ + +__CILKRTS_BEGIN_EXTERN_C + +/** Opadd reducer type name. + * + * This macro expands into the identifier which is the name of the op_add + * reducer type for a specified numeric type. + * + * @param tn The @ref reducers_c_type_names "numeric type name" specifying + * the type of the reducer. + * + * @see @ref reducers_c_predefined + * @see ReducersAdd + */ +#define CILK_C_REDUCER_OPADD_TYPE(tn) \ + __CILKRTS_MKIDENT(cilk_c_reducer_opadd_,tn) + +/** Declare an op_add reducer object. + * + * This macro expands into a declaration of an op_add reducer object for a + * specified numeric type. For example: + * + * CILK_C_REDUCER_OPADD(my_reducer, double, 0.0); + * + * @param obj The variable name to be used for the declared reducer object. + * @param tn The @ref reducers_c_type_names "numeric type name" specifying + * the type of the reducer. + * @param v The initial value for the reducer. (A value which can be + * assigned to the numeric type represented by @a tn.) + * + * @see @ref reducers_c_predefined + * @see ReducersAdd + */ +#define CILK_C_REDUCER_OPADD(obj,tn,v) \ + CILK_C_REDUCER_OPADD_TYPE(tn) obj = \ + CILK_C_INIT_REDUCER(_Typeof(obj.value), \ + __CILKRTS_MKIDENT(cilk_c_reducer_opadd_reduce_,tn), \ + __CILKRTS_MKIDENT(cilk_c_reducer_opadd_identity_,tn), \ + __cilkrts_hyperobject_noop_destroy, v) + +/// @cond internal + +/** Declare the op_add reducer functions for a numeric type. + * + * This macro expands into external function declarations for functions which + * implement the reducer functionality for the op_add reducer type for a + * specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name†identifier, used to construct the reducer + * type name, function names, etc. + */ +#define CILK_C_REDUCER_OPADD_DECLARATION(t,tn) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_OPADD_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_opadd,tn,l,r); \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_opadd,tn); + +/** Define the op_add reducer functions for a numeric type. + * + * This macro expands into function definitions for functions which implement + * the reducer functionality for the op_add reducer type for a specified + * numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name†identifier, used to construct the reducer + * type name, function names, etc. + */ +#define CILK_C_REDUCER_OPADD_DEFINITION(t,tn) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_OPADD_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_opadd,tn,l,r) \ + { *(t*)l += *(t*)r; } \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_opadd,tn) \ + { *(t*)v = 0; } + +//@{ +/** @def CILK_C_REDUCER_OPADD_INSTANCE + * @brief Declare or define implementation functions for a reducer type. + * + * In the runtime source file c_reducers.c, the macro `CILK_C_DEFINE_REDUCERS` + * will be defined, and this macro will generate reducer implementation + * functions. Everywhere else, `CILK_C_DEFINE_REDUCERS` will be undefined, + * and this macro will expand into external declarations for the functions. + */ +#ifdef CILK_C_DEFINE_REDUCERS +# define CILK_C_REDUCER_OPADD_INSTANCE(t,tn) \ + CILK_C_REDUCER_OPADD_DEFINITION(t,tn) +#else +# define CILK_C_REDUCER_OPADD_INSTANCE(t,tn) \ + CILK_C_REDUCER_OPADD_DECLARATION(t,tn) +#endif +//@} + +/* Declare or define an instance of the reducer type and its functions for each + * numeric type. + */ +CILK_C_REDUCER_OPADD_INSTANCE(char, char) +CILK_C_REDUCER_OPADD_INSTANCE(unsigned char, uchar) +CILK_C_REDUCER_OPADD_INSTANCE(signed char, schar) +CILK_C_REDUCER_OPADD_INSTANCE(wchar_t, wchar_t) +CILK_C_REDUCER_OPADD_INSTANCE(short, short) +CILK_C_REDUCER_OPADD_INSTANCE(unsigned short, ushort) +CILK_C_REDUCER_OPADD_INSTANCE(int, int) +CILK_C_REDUCER_OPADD_INSTANCE(unsigned int, uint) +CILK_C_REDUCER_OPADD_INSTANCE(unsigned int, unsigned) /* alternate name */ +CILK_C_REDUCER_OPADD_INSTANCE(long, long) +CILK_C_REDUCER_OPADD_INSTANCE(unsigned long, ulong) +CILK_C_REDUCER_OPADD_INSTANCE(long long, longlong) +CILK_C_REDUCER_OPADD_INSTANCE(unsigned long long, ulonglong) +CILK_C_REDUCER_OPADD_INSTANCE(float, float) +CILK_C_REDUCER_OPADD_INSTANCE(double, double) +CILK_C_REDUCER_OPADD_INSTANCE(long double, longdouble) + +//@endcond + +__CILKRTS_END_EXTERN_C + +//@} + +//@} + +#endif /* REDUCER_OPADD_H_INCLUDED */ diff --git a/libcilkrts/include/cilk/reducer_opand.h b/libcilkrts/include/cilk/reducer_opand.h new file mode 100644 index 00000000000..8a086c91818 --- /dev/null +++ b/libcilkrts/include/cilk/reducer_opand.h @@ -0,0 +1,604 @@ +/* reducer_opand.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file reducer_opand.h + * + * @brief Defines classes for doing parallel bitwise and reductions. + * + * @ingroup ReducersAnd + * + * @see ReducersAnd + */ + +#ifndef REDUCER_OPAND_H_INCLUDED +#define REDUCER_OPAND_H_INCLUDED + +#include <cilk/reducer.h> + +/** @defgroup ReducersAnd Bitwise And Reducers + * + * Bitwise and reducers allow the computation of the bitwise and of a set of + * values in parallel. + * + * @ingroup Reducers + * + * You should be familiar with @ref pagereducers "Cilk reducers", described in + * file `reducers.md`, and particularly with @ref reducers_using, before trying + * to use the information in this file. + * + * @section redopand_usage Usage Example + * + * cilk::reducer< cilk::op_and<unsigned> > r; + * cilk_for (int i = 0; i != N; ++i) { + * *r &= a[i]; + * } + * unsigned result; + * r.move_out(result); + * + * @section redopand_monoid The Monoid + * + * @subsection redopand_monoid_values Value Set + * + * The value set of a bitwise and reducer is the set of values of `Type`, + * which is expected to be a builtin integer type which has a representation + * as a sequence of bits (or something like it, such as `bool` or + * `std::bitset`). + * + * @subsection redopand_monoid_operator Operator + * + * The operator of a bitwise and reducer is the bitwise and operator, defined + * by the “`&`†binary operator on `Type`. + * + * @subsection redopand_monoid_identity Identity + * + * The identity value of the reducer is the value whose representation + * contains all 1-bits. This is expected to be the value of the expression + * `~Type()` (i.e., the bitwise negation operator applied to the default value + * of the value type). + * + * @section redopand_operations Operations + * + * @subsection redopand_constructors Constructors + * + * reducer() // identity + * reducer(const Type& value) + * reducer(move_in(Type& variable)) + * + * @subsection redopand_get_set Set and Get + * + * r.set_value(const Type& value) + * const Type& = r.get_value() const + * r.move_in(Type& variable) + * r.move_out(Type& variable) + * + * @subsection redopand_initial Initial Values + * + * If a bitwise and reducer is constructed without an explicit initial value, + * then its initial value will be its identity value, as long as `Type` + * satisfies the requirements of @ref redopand_types. + * + * @subsection redopand_view_ops View Operations + * + * *r &= a + * *r = *r & a + * *r = *r & a1 & a2 … & an + * + * @section redopand_types Type and Operator Requirements + * + * `Type` must be `Copy Constructible`, `Default Constructible`, and + * `Assignable`. + * + * The operator “`&=`†must be defined on `Type`, with `x &= a` having the + * same meaning as `x = x & a`. + * + * The expression `~ Type()` must be a valid expression which yields the + * identity value (the value of `Type` whose representation consists of all + * 1-bits). + * + * @section redopand_in_c Bitwise And Reducers in C + * + * The @ref CILK_C_REDUCER_OPAND and @ref CILK_C_REDUCER_OPAND_TYPE macros can + * be used to do bitwise and reductions in C. For example: + * + * CILK_C_REDUCER_OPAND(r, uint, ~0); + * CILK_C_REGISTER_REDUCER(r); + * cilk_for(int i = 0; i != n; ++i) { + * REDUCER_VIEW(r) &= a[i]; + * } + * CILK_C_UNREGISTER_REDUCER(r); + * printf("The bitwise AND of the elements of a is %x\n", REDUCER_VIEW(r)); + * + * See @ref reducers_c_predefined. + */ + +#ifdef __cplusplus + +namespace cilk { + +/** The bitwise and reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer< cilk::op_and<Type> >`. It holds the accumulator variable + * for the reduction, and allows only `and` operations to be performed on it. + * + * @note The reducer “dereference†operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `&=` operation would be used in an expression like `*r &= a`, where + * `r` is an opmod reducer variable. + * + * @tparam Type The type of the contained accumulator variable. This will + * be the value type of a monoid_with_view that is + * instantiated with this view. + * + * @see ReducersAnd + * @see op_and + * + * @ingroup ReducersAnd + */ +template <typename Type> +class op_and_view : public scalar_view<Type> +{ + typedef scalar_view<Type> base; + +public: + /** Class to represent the right-hand side of `*reducer = *reducer & value`. + * + * The only assignment operator for the op_and_view class takes an + * rhs_proxy as its operand. This results in the syntactic restriction + * that the only expressions that can be assigned to an op_and_view are + * ones which generate an rhs_proxy — that is, expressions of the form + * `op_and_view & value ... & value`. + * + * @warning + * The lhs and rhs views in such an assignment must be the same; + * otherwise, the behavior will be undefined. (I.e., `v1 = v1 & x` is + * legal; `v1 = v2 & x` is illegal.) This condition will be checked with + * a runtime assertion when compiled in debug mode. + * + * @see op_and_view + */ + class rhs_proxy { + private: + friend class op_and_view; + + const op_and_view* m_view; + Type m_value; + + // Constructor is invoked only from op_and_view::operator&(). + // + rhs_proxy(const op_and_view* view, const Type& value) : m_view(view), m_value(value) {} + + rhs_proxy& operator=(const rhs_proxy&); // Disable assignment operator + rhs_proxy(); // Disable default constructor + + public: + /** Bitwise and with an additional rhs value. If `v` is an op_and_view + * and `a1` is a value, then the expression `v & a1` invokes the + * view’s `operator&()` to create an rhs_proxy for `(v, a1)`; then + * `v & a1 & a2` invokes the rhs_proxy’s `operator&()` to create a new + * rhs_proxy for `(v, a1&a2)`. This allows the right-hand side of an + * assignment to be not just `view & value`, but + * `view & value & value ... & value`. The effect is that + * + * v = v & a1 & a2 ... & an; + * + * is evaluated as + * + * v = v & (a1 & a2 ... & an); + */ + rhs_proxy& operator&(const Type& x) { m_value &= x; return *this; } + }; + + + /** Default/identity constructor. This constructor initializes the + * contained value to `~ Type()`. + */ + op_and_view() : base(~Type()) {} + + /** Construct with a specified initial value. + */ + explicit op_and_view(const Type& v) : base(v) {} + + + /** Reduction operation. + * + * This function is invoked by the @ref op_and monoid to combine the views + * of two strands when the right strand merges with the left one. It + * “ands†the value contained in the left-strand view with the value + * contained in the right-strand view, and leaves the value in the + * right-strand view undefined. + * + * @param right A pointer to the right-strand view. (`this` points to + * the left-strand view.) + * + * @note Used only by the @ref op_and monoid to implement the monoid + * reduce operation. + */ + void reduce(op_and_view* right) { this->m_value &= right->m_value; } + + /** @name Accumulator variable updates. + * + * These functions support the various syntaxes for “anding†the + * accumulator variable contained in the view with some value. + */ + //@{ + + /** And the accumulator variable with @a x. + */ + op_and_view& operator&=(const Type& x) { this->m_value &= x; return *this; } + + /** Create an object representing `*this & x`. + * + * @see rhs_proxy + */ + rhs_proxy operator&(const Type& x) const { return rhs_proxy(this, x); } + + /** Assign the result of a `view & value` expression to the view. Note that + * this is the only assignment operator for this class. + * + * @see rhs_proxy + */ + op_and_view& operator=(const rhs_proxy& rhs) { + __CILKRTS_ASSERT(this == rhs.m_view); + this->m_value &= rhs.m_value; + return *this; + } + + //@} +}; + +/** Monoid class for bitwise and reductions. Instantiate the cilk::reducer + * template class with an op_and monoid to create a bitwise and reducer + * class. For example, to compute the bitwise and of a set of `unsigned long` + * values: + * + * cilk::reducer< cilk::op_and<unsigned long> > r; + * + * @tparam Type The reducer value type. + * @tparam Align If `false` (the default), reducers instantiated on this + * monoid will be naturally aligned (the Cilk library 1.0 + * behavior). If `true`, reducers instantiated on this monoid + * will be cache-aligned for binary compatibility with + * reducers in Cilk library version 0.9. + * + * @see ReducersAnd + * @see op_and_view + * + * @ingroup ReducersAnd + */ +template <typename Type, bool Align = false> +struct op_and : public monoid_with_view<op_and_view<Type>, Align> {}; + +/** Deprecated bitwise and reducer class. + * + * reducer_opand is the same as @ref reducer<@ref op_and>, except that + * reducer_opand is a proxy for the contained view, so that accumulator + * variable update operations can be applied directly to the reducer. For + * example, a value is anded with a `reducer<%op_and>` with `*r &= a`, but a + * value can be anded with a `%reducer_opand` with `r &= a`. + * + * @deprecated Users are strongly encouraged to use `reducer<monoid>` + * reducers rather than the old wrappers like reducer_opand. + * The `reducer<monoid>` reducers show the reducer/monoid/view + * architecture more clearly, are more consistent in their + * implementation, and present a simpler model for new + * user-implemented reducers. + * + * @note Implicit conversions are provided between `%reducer_opand` + * and `reducer<%op_and>`. This allows incremental code + * conversion: old code that used `%reducer_opand` can pass a + * `%reducer_opand` to a converted function that now expects a + * pointer or reference to a `reducer<%op_and>`, and vice + * versa. + * + * @tparam Type The value type of the reducer. + * + * @see op_and + * @see reducer + * @see ReducersAnd + * + * @ingroup ReducersAnd + */ +template <typename Type> +class reducer_opand : public reducer< op_and<Type, true> > +{ + typedef reducer< op_and<Type, true> > base; + using base::view; + +public: + /// The view type for the reducer. + typedef typename base::view_type view_type; + + /// The view’s rhs proxy type. + typedef typename view_type::rhs_proxy rhs_proxy; + + /// The view type for the reducer. + typedef view_type View; + + /// The monoid type for the reducer. + typedef typename base::monoid_type Monoid; + + /** @name Constructors + */ + //@{ + + /** Default constructor. + * + * Constructs the wrapper with the default initial value of `Type()` + * (not the identity value). + */ + reducer_opand() : base(Type()) {} + + /** Value constructor. + * + * Constructs the wrapper with a specified initial value. + */ + explicit reducer_opand(const Type& initial_value) : base(initial_value) {} + + //@} + + /** @name Forwarded functions + * @details Functions that update the contained accumulator variable are + * simply forwarded to the contained @ref op_and_view. */ + //@{ + + /// @copydoc op_and_view::operator&=(const Type&) + reducer_opand& operator&=(const Type& x) + { + view() &= x; + return *this; + } + + // The legacy definition of reducer_opand::operator&() has different + // behavior and a different return type than this definition. The legacy + // version is defined as a member function, so this new version is defined + // as a free function to give it a different signature, so that they won’t + // end up sharing a single object file entry. + + /// @copydoc op_and_view::operator&(const Type&) const + friend rhs_proxy operator&(const reducer_opand& r, const Type& x) + { + return r.view() & x; + } + + /// @copydoc op_and_view::operator=(const rhs_proxy&) + reducer_opand& operator=(const rhs_proxy& temp) + { + view() = temp; + return *this; + } + //@} + + /** @name Dereference + * @details Dereferencing a wrapper is a no-op. It simply returns the + * wrapper. Combined with the rule that the wrapper forwards view + * operations to its contained view, this means that view operations can + * be written the same way on reducers and wrappers, which is convenient + * for incrementally converting old code using wrappers to use reducers + * instead. That is: + * + * reducer< op_and<int> > r; + * *r &= a; // *r returns the view + * // operator &= is a view member function + * + * reducer_opand<int> w; + * *w &= a; // *w returns the wrapper + * // operator &= is a wrapper member function that + * // calls the corresponding view function + */ + //@{ + reducer_opand& operator*() { return *this; } + reducer_opand const& operator*() const { return *this; } + + reducer_opand* operator->() { return this; } + reducer_opand const* operator->() const { return this; } + //@} + + /** @name Upcast + * @details In Cilk library 0.9, reducers were always cache-aligned. In + * library 1.0, reducer cache alignment is optional. By default, reducers + * are unaligned (i.e., just naturally aligned), but legacy wrappers + * inherit from cache-aligned reducers for binary compatibility. + * + * This means that a wrapper will automatically be upcast to its aligned + * reducer base class. The following conversion operators provide + * pseudo-upcasts to the corresponding unaligned reducer class. + */ + //@{ + operator reducer< op_and<Type, false> >& () + { + return *reinterpret_cast< reducer< op_and<Type, false> >* >(this); + } + operator const reducer< op_and<Type, false> >& () const + { + return *reinterpret_cast< const reducer< op_and<Type, false> >* >(this); + } + //@} +}; + +/// @cond internal +/** Metafunction specialization for reducer conversion. + * + * This specialization of the @ref legacy_reducer_downcast template class + * defined in reducer.h causes the `reducer< op_and<Type> >` class to have an + * `operator reducer_opand<Type>& ()` conversion operator that statically + * downcasts the `reducer<op_and>` to the corresponding `reducer_opand` type. + * (The reverse conversion, from `reducer_opand` to `reducer<op_and>`, is just + * an upcast, which is provided for free by the language.) + * + * @ingroup ReducersAnd + */ +template <typename Type, bool Align> +struct legacy_reducer_downcast<reducer<op_and<Type, Align> > > +{ + typedef reducer_opand<Type> type; +}; +/// @endcond + +} // namespace cilk + +#endif // __cplusplus + + +/** @ingroup ReducersAdd + */ +//@{ + +/** @name C language reducer macros + * + * These macros are used to declare and work with op_and reducers in C code. + * + * @see @ref page_reducers_in_c + */ + //@{ + +__CILKRTS_BEGIN_EXTERN_C + +/** Opand reducer type name. + * + * This macro expands into the identifier which is the name of the op_and + * reducer type for a specified numeric type. + * + * @param tn The @ref reducers_c_type_names "numeric type name" specifying + * the type of the reducer. + * + * @see @ref reducers_c_predefined + * @see ReducersAnd + */ +#define CILK_C_REDUCER_OPAND_TYPE(tn) \ + __CILKRTS_MKIDENT(cilk_c_reducer_opand_,tn) + +/** Declare an op_and reducer object. + * + * This macro expands into a declaration of an op_and reducer object for a + * specified numeric type. For example: + * + * CILK_C_REDUCER_OPAND(my_reducer, ulong, ~0UL); + * + * @param obj The variable name to be used for the declared reducer object. + * @param tn The @ref reducers_c_type_names "numeric type name" specifying + * the type of the reducer. + * @param v The initial value for the reducer. (A value which can be + * assigned to the numeric type represented by @a tn.) + * + * @see @ref reducers_c_predefined + * @see ReducersAnd + */ +#define CILK_C_REDUCER_OPAND(obj,tn,v) \ + CILK_C_REDUCER_OPAND_TYPE(tn) obj = \ + CILK_C_INIT_REDUCER(_Typeof(obj.value), \ + __CILKRTS_MKIDENT(cilk_c_reducer_opand_reduce_,tn), \ + __CILKRTS_MKIDENT(cilk_c_reducer_opand_identity_,tn), \ + __cilkrts_hyperobject_noop_destroy, v) + +/// @cond internal + +/** Declare the op_and reducer functions for a numeric type. + * + * This macro expands into external function declarations for functions which + * implement the reducer functionality for the op_and reducer type for a + * specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name†identifier, used to construct the reducer + * type name, function names, etc. + */ +#define CILK_C_REDUCER_OPAND_DECLARATION(t,tn) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_OPAND_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_opand,tn,l,r); \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_opand,tn); + +/** Define the op_and reducer functions for a numeric type. + * + * This macro expands into function definitions for functions which implement + * the reducer functionality for the op_and reducer type for a specified + * numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name†identifier, used to construct the reducer + * type name, function names, etc. + */ +#define CILK_C_REDUCER_OPAND_DEFINITION(t,tn) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_OPAND_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_opand,tn,l,r) \ + { *(t*)l &= *(t*)r; } \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_opand,tn) \ + { *(t*)v = ~((t)0); } + +//@{ +/** @def CILK_C_REDUCER_OPAND_INSTANCE + * @brief Declare or define implementation functions for a reducer type. + * + * In the runtime source file c_reducers.c, the macro `CILK_C_DEFINE_REDUCERS` + * will be defined, and this macro will generate reducer implementation + * functions. Everywhere else, `CILK_C_DEFINE_REDUCERS` will be undefined, and + * this macro will expand into external declarations for the functions. + */ +#ifdef CILK_C_DEFINE_REDUCERS +# define CILK_C_REDUCER_OPAND_INSTANCE(t,tn) \ + CILK_C_REDUCER_OPAND_DEFINITION(t,tn) +#else +# define CILK_C_REDUCER_OPAND_INSTANCE(t,tn) \ + CILK_C_REDUCER_OPAND_DECLARATION(t,tn) +#endif +//@} + +/* Declare or define an instance of the reducer type and its functions for + * each numeric type. + */ +CILK_C_REDUCER_OPAND_INSTANCE(char, char) +CILK_C_REDUCER_OPAND_INSTANCE(unsigned char, uchar) +CILK_C_REDUCER_OPAND_INSTANCE(signed char, schar) +CILK_C_REDUCER_OPAND_INSTANCE(wchar_t, wchar_t) +CILK_C_REDUCER_OPAND_INSTANCE(short, short) +CILK_C_REDUCER_OPAND_INSTANCE(unsigned short, ushort) +CILK_C_REDUCER_OPAND_INSTANCE(int, int) +CILK_C_REDUCER_OPAND_INSTANCE(unsigned int, uint) +CILK_C_REDUCER_OPAND_INSTANCE(unsigned int, unsigned) /* alternate name */ +CILK_C_REDUCER_OPAND_INSTANCE(long, long) +CILK_C_REDUCER_OPAND_INSTANCE(unsigned long, ulong) +CILK_C_REDUCER_OPAND_INSTANCE(long long, longlong) +CILK_C_REDUCER_OPAND_INSTANCE(unsigned long long, ulonglong) + +//@endcond + +__CILKRTS_END_EXTERN_C + +//@} + +//@} + +#endif /* REDUCER_OPAND_H_INCLUDED */ diff --git a/libcilkrts/include/cilk/reducer_opmul.h b/libcilkrts/include/cilk/reducer_opmul.h new file mode 100644 index 00000000000..271529d787b --- /dev/null +++ b/libcilkrts/include/cilk/reducer_opmul.h @@ -0,0 +1,442 @@ +/* reducer_opmul.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2012-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file reducer_opmul.h + * + * @brief Defines classes for doing parallel multiplication reductions. + * + * @ingroup ReducersMul + * + * @see ReducersMul + */ + +#ifndef REDUCER_OPMUL_H_INCLUDED +#define REDUCER_OPMUL_H_INCLUDED + +#include <cilk/reducer.h> + +/** @defgroup ReducersMul Multiplication Reducers + * + * Multiplication reducers allow the computation of the product of a set of + * values in parallel. + * + * @ingroup Reducers + * + * You should be familiar with @ref pagereducers "Cilk reducers", described in + * file `reducers.md`, and particularly with @ref reducers_using, before trying + * to use the information in this file. + * + * @section redopmul_usage Usage Example + * + * cilk::reducer< cilk::op_mul<double> > r; + * cilk_for (int i = 0; i != N; ++i) { + * *r *= a[i]; + * } + * double product; + * r.move_out(product); + * + * @section redopmul_monoid The Monoid + * + * @subsection redopmul_monoid_values Value Set + * + * The value set of a multiplication reducer is the set of values of `Type`, + * which is expected to be a builtin numeric type (or something like it, such + * as `std::complex`). + * + * @subsection redopmul_monoid_operator Operator + * + * The operator of a multiplication reducer is the multiplication operation, + * defined by the “`*`†binary operator on `Type`. + * + * @subsection redopmul_monoid_identity Identity + * + * The identity value of the reducer is the numeric value “`1`â€. This is + * expected to be the value of the expression `Type(1)`. + * + * @section redopmul_operations Operations + * + * @subsection redopmul_constructors Constructors + * + * reducer() // identity + * reducer(const Type& value) + * reducer(move_in(Type& variable)) + * + * @subsection redopmul_get_set Set and Get + * + * r.set_value(const Type& value) + * const Type& = r.get_value() const + * r.move_in(Type& variable) + * r.move_out(Type& variable) + * + * @subsection redopmul_initial Initial Values + * + * If a multiplication reducer is constructed without an explicit initial + * value, then its initial value will be its identity value, as long as `Type` + * satisfies the requirements of @ref redopmul_types. + * + * @subsection redopmul_view_ops View Operations + * + * *r *= a + * *r = *r * a + * *r = *r * a1 * a2 … * an + * + * @section redopmul_floating_point Issues with Floating-Point Types + * + * Because of overflow and underflow issues, floating-point multiplication is + * not really associative. For example, `(1e200 * 1e-200) * 1e-200 == 1e-200`, + * but `1e200 * (1e-200 * 1e-200 == 0. + * + * In many cases, this won’t matter, but computations which have been + * carefully ordered to control overflow and underflow may not deal well with + * being reassociated. In general, you should be sure to understand the + * floating-point behavior of your program before doing any transformation + * that will reassociate its computations. + * + * @section redopmul_types Type and Operator Requirements + * + * `Type` must be `Copy Constructible`, `Default Constructible`, and + * `Assignable`. + * + * The operator “`*=`†must be defined on `Type`, with `x *= a` having the same + * meaning as `x = x * a`. + * + * The expression `Type(1)` must be a valid expression which yields the + * identity value (the value of `Type` whose numeric value is `1`). + * + * @section redopmul_in_c Multiplication Reducers in C + * + * The @ref CILK_C_REDUCER_OPMUL and @ref CILK_C_REDUCER_OPMUL_TYPE macros can + * be used to do multiplication reductions in C. For example: + * + * CILK_C_REDUCER_OPMUL(r, double, 1); + * CILK_C_REGISTER_REDUCER(r); + * cilk_for(int i = 0; i != n; ++i) { + * REDUCER_VIEW(r) *= a[i]; + * } + * CILK_C_UNREGISTER_REDUCER(r); + * printf("The product of the elements of a is %f\n", REDUCER_VIEW(r)); + * + * See @ref reducers_c_predefined. + */ + +#ifdef __cplusplus + +namespace cilk { + +/** The multiplication reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer< cilk::op_mul<Type> >`. It holds the accumulator variable + * for the reduction, and allows only multiplication operations to be + * performed on it. + * + * @note The reducer “dereference†operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `*=` operation would be used in an expression like `*r *= a`, where + * `r` is an op_mul reducer variable. + * + * @tparam Type The type of the contained accumulator variable. This will + * be the value type of a monoid_with_view that is + * instantiated with this view. + * + * @see ReducersMul + * @see op_mul + * + * @ingroup ReducersMul + */ +template <typename Type> +class op_mul_view : public scalar_view<Type> +{ + typedef scalar_view<Type> base; + +public: + /** Class to represent the right-hand side of `*reducer = *reducer * value`. + * + * The only assignment operator for the op_mul_view class takes an + * rhs_proxy as its operand. This results in the syntactic restriction + * that the only expressions that can be assigned to an op_mul_view are + * ones which generate an rhs_proxy — that is, expressions of the form + * `op_mul_view * value ... * value`. + * + * @warning + * The lhs and rhs views in such an assignment must be the same; + * otherwise, the behavior will be undefined. (I.e., `v1 = v1 * x` is + * legal; `v1 = v2 * x` is illegal.) This condition will be checked with a + * runtime assertion when compiled in debug mode. + * + * @see op_mul_view + */ + class rhs_proxy { + friend class op_mul_view; + + const op_mul_view* m_view; + Type m_value; + + // Constructor is invoked only from op_mul_view::operator*(). + // + rhs_proxy(const op_mul_view* view, const Type& value) : m_view(view), m_value(value) {} + + rhs_proxy& operator=(const rhs_proxy&); // Disable assignment operator + rhs_proxy(); // Disable default constructor + + public: + /** Multiply by an additional rhs value. If `v` is an op_mul_view and + * `a1` is a value, then the expression `v * a1` invokes the view’s + * `operator*()` to create an rhs_proxy for `(v, a1)`; then + * `v * a1 * a2` invokes the rhs_proxy’s `operator*()` to create a + * new rhs_proxy for `(v, a1*a2)`. This allows the right-hand side of + * an assignment to be not just `view * value`, but + * `view * value * value ... * value`. The effect is that + * + * v = v * a1 * a2 ... * an; + * + * is evaluated as + * + * v = v * (a1 * a2 ... * an); + */ + rhs_proxy& operator*(const Type& x) { m_value *= x; return *this; } + }; + + + /** Default/identity constructor. This constructor initializes the + * contained value to `Type(1)`, which is expected to be the identity + * value for multiplication on `Type`. + */ + op_mul_view() : base(Type(1)) {} + + /** Construct with a specified initial value. + */ + explicit op_mul_view(const Type& v) : base(v) {} + + /** Reduction operation. + * + * This function is invoked by the @ref op_mul monoid to combine the views + * of two strands when the right strand merges with the left one. It + * multiplies the value contained in the left-strand view by the value + * contained in the right-strand view, and leaves the value in the + * right-strand view undefined. + * + * @param right A pointer to the right-strand view. (`this` points to + * the left-strand view.) + * + * @note Used only by the @ref op_mul monoid to implement the monoid + * reduce operation. + */ + void reduce(op_mul_view* right) { this->m_value *= right->m_value; } + + /** @name Accumulator variable updates. + * + * These functions support the various syntaxes for multiplying the + * accumulator variable contained in the view by some value. + */ + //@{ + + /** Multiply the accumulator variable by @a x. + */ + op_mul_view& operator*=(const Type& x) { this->m_value *= x; return *this; } + + /** Create an object representing `*this * x`. + * + * @see rhs_proxy + */ + rhs_proxy operator*(const Type& x) const { return rhs_proxy(this, x); } + + /** Assign the result of a `view * value` expression to the view. Note that + * this is the only assignment operator for this class. + * + * @see rhs_proxy + */ + op_mul_view& operator=(const rhs_proxy& rhs) { + __CILKRTS_ASSERT(this == rhs.m_view); + this->m_value *= rhs.m_value; + return *this; + } + + //@} +}; + +/** Monoid class for multiplication reductions. Instantiate the cilk::reducer + * template class with an op_mul monoid to create a multiplication reducer + * class. For example, to compute the product of a set of `double` values: + * + * cilk::reducer< cilk::op_mul<double> > r; + * + * @see ReducersMul + * @see op_mul_view + * + * @ingroup ReducersMul + */ +template <typename Type> +struct op_mul : public monoid_with_view< op_mul_view<Type> > {}; + +} // namespace cilk + +#endif // __cplusplus + + +/** @ingroup ReducersAdd + */ +//@{ + +/** @name C language reducer macros + * + * These macros are used to declare and work with numeric op_mul reducers in + * C code. + * + * @see @ref page_reducers_in_c + */ + //@{ + +__CILKRTS_BEGIN_EXTERN_C + +/** Opmul reducer type name. + * + * This macro expands into the identifier which is the name of the op_mul + * reducer type for a specified numeric type. + * + * @param tn The @ref reducers_c_type_names "numeric type name" specifying + * the type of the reducer. + * + * @see @ref reducers_c_predefined + * @see ReducersMul + */ +#define CILK_C_REDUCER_OPMUL_TYPE(tn) \ + __CILKRTS_MKIDENT(cilk_c_reducer_opmul_,tn) + +/** Declare an op_mul reducer object. + * + * This macro expands into a declaration of an op_mul reducer object for a + * specified numeric type. For example: + * + * CILK_C_REDUCER_OPMUL(my_reducer, double, 1.0); + * + * @param obj The variable name to be used for the declared reducer object. + * @param tn The @ref reducers_c_type_names "numeric type name" specifying + * the type of the reducer. + * @param v The initial value for the reducer. (A value which can be + * assigned to the numeric type represented by @a tn.) + * + * @see @ref reducers_c_predefined + * @see ReducersMul + */ +#define CILK_C_REDUCER_OPMUL(obj,tn,v) \ + CILK_C_REDUCER_OPMUL_TYPE(tn) obj = \ + CILK_C_INIT_REDUCER(_Typeof(obj.value), \ + __CILKRTS_MKIDENT(cilk_c_reducer_opmul_reduce_,tn), \ + __CILKRTS_MKIDENT(cilk_c_reducer_opmul_identity_,tn), \ + __cilkrts_hyperobject_noop_destroy, v) + +/// @cond internal + +/** Declare the op_mul reducer functions for a numeric type. + * + * This macro expands into external function declarations for functions which + * implement the reducer functionality for the op_mul reducer type for a + * specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name†identifier, used to construct the reducer + * type name, function names, etc. + */ +#define CILK_C_REDUCER_OPMUL_DECLARATION(t,tn) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_OPMUL_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_opmul,tn,l,r); \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_opmul,tn); + +/** Define the op_mul reducer functions for a numeric type. + * + * This macro expands into function definitions for functions which implement + * the reducer functionality for the op_mul reducer type for a specified + * numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name†identifier, used to construct the reducer + * type name, function names, etc. + */ +#define CILK_C_REDUCER_OPMUL_DEFINITION(t,tn) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_OPMUL_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_opmul,tn,l,r) \ + { *(t*)l *= *(t*)r; } \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_opmul,tn) \ + { *(t*)v = 1; } + +//@{ +/** @def CILK_C_REDUCER_OPMUL_INSTANCE + * @brief Declare or define implementation functions for a reducer type. + * + * In the runtime source file c_reducers.c, the macro `CILK_C_DEFINE_REDUCERS` + * will be defined, and this macro will generate reducer implementation + * functions. Everywhere else, `CILK_C_DEFINE_REDUCERS` will be undefined, and + * this macro will expand into external declarations for the functions. + */ +#ifdef CILK_C_DEFINE_REDUCERS +# define CILK_C_REDUCER_OPMUL_INSTANCE(t,tn) \ + CILK_C_REDUCER_OPMUL_DEFINITION(t,tn) +#else +# define CILK_C_REDUCER_OPMUL_INSTANCE(t,tn) \ + CILK_C_REDUCER_OPMUL_DECLARATION(t,tn) +#endif +//@} + +/* Declare or define an instance of the reducer type and its functions for each + * numeric type. + */ +CILK_C_REDUCER_OPMUL_INSTANCE(char, char) +CILK_C_REDUCER_OPMUL_INSTANCE(unsigned char, uchar) +CILK_C_REDUCER_OPMUL_INSTANCE(signed char, schar) +CILK_C_REDUCER_OPMUL_INSTANCE(wchar_t, wchar_t) +CILK_C_REDUCER_OPMUL_INSTANCE(short, short) +CILK_C_REDUCER_OPMUL_INSTANCE(unsigned short, ushort) +CILK_C_REDUCER_OPMUL_INSTANCE(int, int) +CILK_C_REDUCER_OPMUL_INSTANCE(unsigned int, uint) +CILK_C_REDUCER_OPMUL_INSTANCE(unsigned int, unsigned) /* alternate name */ +CILK_C_REDUCER_OPMUL_INSTANCE(long, long) +CILK_C_REDUCER_OPMUL_INSTANCE(unsigned long, ulong) +CILK_C_REDUCER_OPMUL_INSTANCE(long long, longlong) +CILK_C_REDUCER_OPMUL_INSTANCE(unsigned long long, ulonglong) +CILK_C_REDUCER_OPMUL_INSTANCE(float, float) +CILK_C_REDUCER_OPMUL_INSTANCE(double, double) +CILK_C_REDUCER_OPMUL_INSTANCE(long double, longdouble) + +//@endcond + +__CILKRTS_END_EXTERN_C + +//@} + +//@} + +#endif /* REDUCER_OPMUL_H_INCLUDED */ diff --git a/libcilkrts/include/cilk/reducer_opor.h b/libcilkrts/include/cilk/reducer_opor.h new file mode 100644 index 00000000000..5c8e7bd972e --- /dev/null +++ b/libcilkrts/include/cilk/reducer_opor.h @@ -0,0 +1,598 @@ +/* reducer_opor.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file reducer_opor.h + * + * @brief Defines classes for doing parallel bitwise or reductions. + * + * @ingroup ReducersOr + * + * @see ReducersOr + */ + +#ifndef REDUCER_OPOR_H_INCLUDED +#define REDUCER_OPOR_H_INCLUDED + +#include <cilk/reducer.h> + +/** @defgroup ReducersOr Bitwise Or Reducers + * + * Bitwise and reducers allow the computation of the bitwise and of a set of + * values in parallel. + * + * @ingroup Reducers + * + * You should be familiar with @ref pagereducers "Cilk reducers", described in + * file `reducers.md`, and particularly with @ref reducers_using, before trying + * to use the information in this file. + * + * @section redopor_usage Usage Example + * + * cilk::reducer< cilk::op_or<unsigned> > r; + * cilk_for (int i = 0; i != N; ++i) { + * *r |= a[i]; + * } + * unsigned result; + * r.move_out(result); + * + * @section redopor_monoid The Monoid + * + * @subsection redopor_monoid_values Value Set + * + * The value set of a bitwise or reducer is the set of values of `Type`, which + * is expected to be a builtin integer type which has a representation as a + * sequence of bits (or something like it, such as `bool` or `std::bitset`). + * + * @subsection redopor_monoid_operator Operator + * + * The operator of a bitwise or reducer is the bitwise or operator, defined by + * the “`|`†binary operator on `Type`. + * + * @subsection redopor_monoid_identity Identity + * + * The identity value of the reducer is the value whose representation + * contains all 0-bits. This is expected to be the value of the default + * constructor `Type()`. + * + * @section redopor_operations Operations + * + * @subsection redopor_constructors Constructors + * + * reducer() // identity + * reducer(const Type& value) + * reducer(move_in(Type& variable)) + * + * @subsection redopor_get_set Set and Get + * + * r.set_value(const Type& value) + * const Type& = r.get_value() const + * r.move_in(Type& variable) + * r.move_out(Type& variable) + * + * @subsection redopor_initial Initial Values + * + * If a bitwise or reducer is constructed without an explicit initial value, + * then its initial value will be its identity value, as long as `Type` + * satisfies the requirements of @ref redopor_types. + * + * @subsection redopor_view_ops View Operations + * + * *r |= a + * *r = *r | a + * *r = *r | a1 | a2 … | an + * + * @section redopor_types Type and Operator Requirements + * + * `Type` must be `Copy Constructible`, `Default Constructible`, and + * `Assignable`. + * + * The operator “`|=`†must be defined on `Type`, with `x |= a` having the + * same meaning as `x = x | a`. + * + * The expression `Type()` must be a valid expression which yields the + * identity value (the value of `Type` whose representation consists of all + * 0-bits). + * + * @section redopor_in_c Bitwise Or Reducers in C + * + * The @ref CILK_C_REDUCER_OPOR and @ref CILK_C_REDUCER_OPOR_TYPE macros can + * be used to do bitwise or reductions in C. For example: + * + * CILK_C_REDUCER_OPOR(r, uint, 0); + * CILK_C_REGISTER_REDUCER(r); + * cilk_for(int i = 0; i != n; ++i) { + * REDUCER_VIEW(r) |= a[i]; + * } + * CILK_C_UNREGISTER_REDUCER(r); + * printf("The bitwise OR of the elements of a is %x\n", REDUCER_VIEW(r)); + * + * See @ref reducers_c_predefined. + */ + +#ifdef __cplusplus + +namespace cilk { + +/** The bitwise or reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer< cilk::op_or<Type> >`. It holds the accumulator variable for + * the reduction, and allows only `or` operations to be performed on it. + * + * @note The reducer “dereference†operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `|=` operation would be used in an expression like `*r |= a`, where + * `r` is an opmod reducer variable. + * + * @tparam Type The type of the contained accumulator variable. This will + * be the value type of a monoid_with_view that is + * instantiated with this view. + * + * @see ReducersOr + * @see op_or + * + * @ingroup ReducersOr + */ +template <typename Type> +class op_or_view : public scalar_view<Type> +{ + typedef scalar_view<Type> base; + +public: + /** Class to represent the right-hand side of `*reducer = *reducer | value`. + * + * The only assignment operator for the op_or_view class takes an + * rhs_proxy as its operand. This results in the syntactic restriction + * that the only expressions that can be assigned to an op_or_view are + * ones which generate an rhs_proxy — that is, expressions of the form + * `op_or_view | value ... | value`. + * + * @warning + * The lhs and rhs views in such an assignment must be the same; + * otherwise, the behavior will be undefined. (I.e., `v1 = v1 | x` is + * legal; `v1 = v2 | x` is illegal.) This condition will be checked with + * a runtime assertion when compiled in debug mode. + * + * @see op_or_view + */ + class rhs_proxy { + friend class op_or_view; + + const op_or_view* m_view; + Type m_value; + + // Constructor is invoked only from op_or_view::operator|(). + // + rhs_proxy(const op_or_view* view, const Type& value) : m_view(view), m_value(value) {} + + rhs_proxy& operator=(const rhs_proxy&); // Disable assignment operator + rhs_proxy(); // Disable default constructor + + public: + /** Bitwise or with an additional rhs value. If `v` is an op_or_view + * and `a1` is a value, then the expression `v | a1` invokes the + * view’s `operator|()` to create an rhs_proxy for `(v, a1)`; then + * `v | a1 | a2` invokes the rhs_proxy’s `operator|()` to create a new + * rhs_proxy for `(v, a1|a2)`. This allows the right-hand side of an + * assignment to be not just `view | value`, but + ( `view | value | value ... | value`. The effect is that + * + * v = v | a1 | a2 ... | an; + * + * is evaluated as + * + * v = v | (a1 | a2 ... | an); + */ + rhs_proxy& operator|(const Type& x) { m_value |= x; return *this; } + }; + + + /** Default/identity constructor. This constructor initializes the + * contained value to `Type()`. + */ + op_or_view() : base() {} + + /** Construct with a specified initial value. + */ + explicit op_or_view(const Type& v) : base(v) {} + + /** Reduction operation. + * + * This function is invoked by the @ref op_or monoid to combine the views + * of two strands when the right strand merges with the left one. It + * “ors†the value contained in the left-strand view by the value + * contained in the right-strand view, and leaves the value in the + * right-strand view undefined. + * + * @param right A pointer to the right-strand view. (`this` points to + * the left-strand view.) + * + * @note Used only by the @ref op_or monoid to implement the monoid + * reduce operation. + */ + void reduce(op_or_view* right) { this->m_value |= right->m_value; } + + /** @name Accumulator variable updates. + * + * These functions support the various syntaxes for “oring†the + * accumulator variable contained in the view with some value. + */ + //@{ + + /** Or the accumulator variable with @a x. + */ + op_or_view& operator|=(const Type& x) { this->m_value |= x; return *this; } + + /** Create an object representing `*this | x`. + * + * @see rhs_proxy + */ + rhs_proxy operator|(const Type& x) const { return rhs_proxy(this, x); } + + /** Assign the result of a `view | value` expression to the view. Note that + * this is the only assignment operator for this class. + * + * @see rhs_proxy + */ + op_or_view& operator=(const rhs_proxy& rhs) { + __CILKRTS_ASSERT(this == rhs.m_view); + this->m_value |= rhs.m_value; + return *this; + } + + //@} +}; + +/** Monoid class for bitwise or reductions. Instantiate the cilk::reducer + * template class with an op_or monoid to create a bitwise or reducer + * class. For example, to compute the bitwise or of a set of `unsigned long` + * values: + * + * cilk::reducer< cilk::op_or<unsigned long> > r; + * + * @tparam Type The reducer value type. + * @tparam Align If `false` (the default), reducers instantiated on this + * monoid will be naturally aligned (the Cilk library 1.0 + * behavior). If `true`, reducers instantiated on this monoid + * will be cache-aligned for binary compatibility with + * reducers in Cilk library version 0.9. + * + * @see ReducersOr + * @see op_or_view + * + * @ingroup ReducersOr + */ +template <typename Type, bool Align = false> +struct op_or : public monoid_with_view<op_or_view<Type>, Align> {}; + +/** Deprecated bitwise or reducer class. + * + * reducer_opor is the same as @ref reducer<@ref op_or>, except that + * reducer_opor is a proxy for the contained view, so that accumulator + * variable update operations can be applied directly to the reducer. For + * example, a value is ored with a `reducer<%op_or>` with `*r |= a`, but a + * value can be ored with a `%reducer_opor` with `r |= a`. + * + * @deprecated Users are strongly encouraged to use `reducer<monoid>` + * reducers rather than the old wrappers like reducer_opor. + * The `reducer<monoid>` reducers show the reducer/monoid/view + * architecture more clearly, are more consistent in their + * implementation, and present a simpler model for new + * user-implemented reducers. + * + * @note Implicit conversions are provided between `%reducer_opor` + * and `reducer<%op_or>`. This allows incremental code + * conversion: old code that used `%reducer_opor` can pass a + * `%reducer_opor` to a converted function that now expects a + * pointer or reference to a `reducer<%op_or>`, and vice + * versa. + * + * @tparam Type The value type of the reducer. + * + * @see op_or + * @see reducer + * @see ReducersOr + * + * @ingroup ReducersOr + */ +template <typename Type> +class reducer_opor : public reducer< op_or<Type, true> > +{ + typedef reducer< op_or<Type, true> > base; + using base::view; + + public: + /// The view type for the reducer. + typedef typename base::view_type view_type; + + /// The view’s rhs proxy type. + typedef typename view_type::rhs_proxy rhs_proxy; + + /// The view type for the reducer. + typedef view_type View; + + /// The monoid type for the reducer. + typedef typename base::monoid_type Monoid; + + /** @name Constructors + */ + //@{ + + /** Default (identity) constructor. + * + * Constructs the wrapper with the default initial value of `Type()`. + */ + reducer_opor() {} + + /** Value constructor. + * + * Constructs the wrapper with a specified initial value. + */ + explicit reducer_opor(const Type& initial_value) : base(initial_value) {} + + //@} + + /** @name Forwarded functions + * @details Functions that update the contained accumulator variable are + * simply forwarded to the contained @ref op_and_view. */ + //@{ + + /// @copydoc op_or_view::operator|=(const Type&) + reducer_opor& operator|=(const Type& x) + { + view() |= x; return *this; + } + + // The legacy definition of reducer_opor::operator|() has different + // behavior and a different return type than this definition. The legacy + // version is defined as a member function, so this new version is defined + // as a free function to give it a different signature, so that they won’t + // end up sharing a single object file entry. + + /// @copydoc op_or_view::operator|(const Type&) const + friend rhs_proxy operator|(const reducer_opor& r, const Type& x) + { + return r.view() | x; + } + + /// @copydoc op_and_view::operator=(const rhs_proxy&) + reducer_opor& operator=(const rhs_proxy& temp) + { + view() = temp; return *this; + } + //@} + + /** @name Dereference + * @details Dereferencing a wrapper is a no-op. It simply returns the + * wrapper. Combined with the rule that the wrapper forwards view + * operations to its contained view, this means that view operations can + * be written the same way on reducers and wrappers, which is convenient + * for incrementally converting old code using wrappers to use reducers + * instead. That is: + * + * reducer< op_and<int> > r; + * *r &= a; // *r returns the view + * // operator &= is a view member function + * + * reducer_opand<int> w; + * *w &= a; // *w returns the wrapper + * // operator &= is a wrapper member function that + * // calls the corresponding view function + */ + //@{ + reducer_opor& operator*() { return *this; } + reducer_opor const& operator*() const { return *this; } + + reducer_opor* operator->() { return this; } + reducer_opor const* operator->() const { return this; } + //@} + + /** @name Upcast + * @details In Cilk library 0.9, reducers were always cache-aligned. In + * library 1.0, reducer cache alignment is optional. By default, reducers + * are unaligned (i.e., just naturally aligned), but legacy wrappers + * inherit from cache-aligned reducers for binary compatibility. + * + * This means that a wrapper will automatically be upcast to its aligned + * reducer base class. The following conversion operators provide + * pseudo-upcasts to the corresponding unaligned reducer class. + */ + //@{ + operator reducer< op_or<Type, false> >& () + { + return *reinterpret_cast< reducer< op_or<Type, false> >* >(this); + } + operator const reducer< op_or<Type, false> >& () const + { + return *reinterpret_cast< const reducer< op_or<Type, false> >* >(this); + } + //@} + +}; + +/// @cond internal +/** Metafunction specialization for reducer conversion. + * + * This specialization of the @ref legacy_reducer_downcast template class + * defined in reducer.h causes the `reducer< op_or<Type> >` class to have an + * `operator reducer_opor<Type>& ()` conversion operator that statically + * downcasts the `reducer<op_or>` to the corresponding `reducer_opor` type. + * (The reverse conversion, from `reducer_opor` to `reducer<op_or>`, is just + * an upcast, which is provided for free by the language.) + * + * @ingroup ReducersOr + */ +template <typename Type, bool Align> +struct legacy_reducer_downcast<reducer<op_or<Type, Align> > > +{ + typedef reducer_opor<Type> type; +}; +/// @endcond + +} // namespace cilk + +#endif /* __cplusplus */ + + +/** @ingroup ReducersOr + */ +//@{ + +/** @name C language reducer macros + * + * These macros are used to declare and work with op_or reducers in C code. + * + * @see @ref page_reducers_in_c + */ + //@{ + +__CILKRTS_BEGIN_EXTERN_C + +/** Opor reducer type name. + * + * This macro expands into the identifier which is the name of the op_or + * reducer type for a specified numeric type. + * + * @param tn The @ref reducers_c_type_names "numeric type name" specifying + * the type of the reducer. + * + * @see @ref reducers_c_predefined + * @see ReducersOr + */ +#define CILK_C_REDUCER_OPOR_TYPE(tn) \ + __CILKRTS_MKIDENT(cilk_c_reducer_opor_,tn) + +/** Declare an op_or reducer object. + * + * This macro expands into a declaration of an op_or reducer object for a + * specified numeric type. For example: + * + * CILK_C_REDUCER_OPOR(my_reducer, ulong, 0); + * + * @param obj The variable name to be used for the declared reducer object. + * @param tn The @ref reducers_c_type_names "numeric type name" specifying + * the type of the reducer. + * @param v The initial value for the reducer. (A value which can be + * assigned to the numeric type represented by @a tn.) + * + * @see @ref reducers_c_predefined + * @see ReducersOr + */ +#define CILK_C_REDUCER_OPOR(obj,tn,v) \ + CILK_C_REDUCER_OPOR_TYPE(tn) obj = \ + CILK_C_INIT_REDUCER(_Typeof(obj.value), \ + __CILKRTS_MKIDENT(cilk_c_reducer_opor_reduce_,tn), \ + __CILKRTS_MKIDENT(cilk_c_reducer_opor_identity_,tn), \ + __cilkrts_hyperobject_noop_destroy, v) + +/// @cond internal + +/** Declare the op_or reducer functions for a numeric type. + * + * This macro expands into external function declarations for functions which + * implement the reducer functionality for the op_or reducer type for a + * specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name†identifier, used to construct the reducer + * type name, function names, etc. + */ +#define CILK_C_REDUCER_OPOR_DECLARATION(t,tn) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_OPOR_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_opor,tn,l,r); \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_opor,tn); + +/** Define the op_or reducer functions for a numeric type. + * + * This macro expands into function definitions for functions which implement + * the reducer functionality for the op_or reducer type for a specified + * numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name†identifier, used to construct the reducer + * type name, function names, etc. + */ +#define CILK_C_REDUCER_OPOR_DEFINITION(t,tn) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_OPOR_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_opor,tn,l,r) \ + { *(t*)l |= *(t*)r; } \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_opor,tn) \ + { *(t*)v = 0; } + +//@{ +/** @def CILK_C_REDUCER_OPOR_INSTANCE + * @brief Declare or define implementation functions for a reducer type. + * + * In the runtime source file c_reducers.c, the macro `CILK_C_DEFINE_REDUCERS` + * will be defined, and this macro will generate reducer implementation + * functions. Everywhere else, `CILK_C_DEFINE_REDUCERS` will be undefined, and + * this macro will expand into external declarations for the functions. + */ +#ifdef CILK_C_DEFINE_REDUCERS +# define CILK_C_REDUCER_OPOR_INSTANCE(t,tn) \ + CILK_C_REDUCER_OPOR_DEFINITION(t,tn) +#else +# define CILK_C_REDUCER_OPOR_INSTANCE(t,tn) \ + CILK_C_REDUCER_OPOR_DECLARATION(t,tn) +#endif +//@} + +/* Declare or define an instance of the reducer type and its functions for each + * numeric type. + */ +CILK_C_REDUCER_OPOR_INSTANCE(char, char) +CILK_C_REDUCER_OPOR_INSTANCE(unsigned char, uchar) +CILK_C_REDUCER_OPOR_INSTANCE(signed char, schar) +CILK_C_REDUCER_OPOR_INSTANCE(wchar_t, wchar_t) +CILK_C_REDUCER_OPOR_INSTANCE(short, short) +CILK_C_REDUCER_OPOR_INSTANCE(unsigned short, ushort) +CILK_C_REDUCER_OPOR_INSTANCE(int, int) +CILK_C_REDUCER_OPOR_INSTANCE(unsigned int, uint) +CILK_C_REDUCER_OPOR_INSTANCE(unsigned int, unsigned) /* alternate name */ +CILK_C_REDUCER_OPOR_INSTANCE(long, long) +CILK_C_REDUCER_OPOR_INSTANCE(unsigned long, ulong) +CILK_C_REDUCER_OPOR_INSTANCE(long long, longlong) +CILK_C_REDUCER_OPOR_INSTANCE(unsigned long long, ulonglong) + +//@endcond + +__CILKRTS_END_EXTERN_C + +//@} + +//@} + +#endif /* REDUCER_OPOR_H_INCLUDED */ diff --git a/libcilkrts/include/cilk/reducer_opxor.h b/libcilkrts/include/cilk/reducer_opxor.h new file mode 100644 index 00000000000..fed49943ef6 --- /dev/null +++ b/libcilkrts/include/cilk/reducer_opxor.h @@ -0,0 +1,598 @@ +/* reducer_opxor.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file reducer_opxor.h + * + * @brief Defines classes for doing parallel bitwise or reductions. + * + * @ingroup ReducersXor + * + * @see ReducersXor + */ + +#ifndef REDUCER_OPXOR_H_INCLUDED +#define REDUCER_OPXOR_H_INCLUDED + +#include <cilk/reducer.h> + +/** @defgroup ReducersXor Bitwise Xor Reducers + * + * Bitwise and reducers allow the computation of the bitwise and of a set of + * values in parallel. + * + * @ingroup Reducers + * + * You should be familiar with @ref pagereducers "Cilk reducers", described in + * file `reducers.md`, and particularly with @ref reducers_using, before trying + * to use the information in this file. + * + * @section redopxor_usage Usage Example + * + * cilk::reducer< cilk::op_xor<unsigned> > r; + * cilk_for (int i = 0; i != N; ++i) { + * *r ^= a[i]; + * } + * unsigned result; + * r.move_out(result); + * + * @section redopxor_monoid The Monoid + * + * @subsection redopxor_monoid_values Value Set + * + * The value set of a bitwise xor reducer is the set of values of `Type`, which + * is expected to be a builtin integer type which has a representation as a + * sequence of bits (or something like it, such as `bool` or `std::bitset`). + * + * @subsection redopxor_monoid_operator Operator + * + * The operator of a bitwise xor reducer is the bitwise xor operator, defined + * by the “`^`†binary operator on `Type`. + * + * @subsection redopxor_monoid_identity Identity + * + * The identity value of the reducer is the value whose representation + * contains all 0-bits. This is expected to be the value of the default + * constructor `Type()`. + * + * @section redopxor_operations Operations + * + * @subsection redopxor_constructors Constructors + * + * reducer() // identity + * reducer(const Type& value) + * reducer(move_in(Type& variable)) + * + * @subsection redopxor_get_set Set and Get + * + * r.set_value(const Type& value) + * const Type& = r.get_value() const + * r.move_in(Type& variable) + * r.move_out(Type& variable) + * + * @subsection redopxor_initial Initial Values + * + * If a bitwise xor reducer is constructed without an explicit initial value, + * then its initial value will be its identity value, as long as `Type` + * satisfies the requirements of @ref redopxor_types. + * + * @subsection redopxor_view_ops View Operations + * + * *r ^= a + * *r = *r ^ a + * *r = *r ^ a1 ^ a2 … ^ an + * + * @section redopxor_types Type and Operator Requirements + * + * `Type` must be `Copy Constructible`, `Default Constructible`, and + * `Assignable`. + * + * The operator “`^=`†must be defined on `Type`, with `x ^= a` having the + * same meaning as `x = x ^ a`. + * + * The expression `Type()` must be a valid expression which yields the + * identity value (the value of `Type` whose representation consists of all + * 0-bits). + * + * @section redopxor_in_c Bitwise Xor Reducers in C + * + * The @ref CILK_C_REDUCER_OPXOR and @ref CILK_C_REDUCER_OPXOR_TYPE macros can + * be used to do bitwise xor reductions in C. For example: + * + * CILK_C_REDUCER_OPXOR(r, uint, 0); + * CILK_C_REGISTER_REDUCER(r); + * cilk_for(int i = 0; i != n; ++i) { + * REDUCER_VIEW(r) ^= a[i]; + * } + * CILK_C_UNREGISTER_REDUCER(r); + * printf("The bitwise XOR of the elements of a is %x\n", REDUCER_VIEW(r)); + * + * See @ref reducers_c_predefined. + */ + +#ifdef __cplusplus + +namespace cilk { + +/** The bitwise xor reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer< cilk::op_xor<Type> >`. It holds the accumulator variable + * for the reduction, and allows only `xor` operations to be performed on it. + * + * @note The reducer “dereference†operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `^=` operation would be used in an expression like `*r ^= a`, where + * `r` is an opmod reducer variable. + * + * @tparam Type The type of the contained accumulator variable. This will + * be the value type of a monoid_with_view that is + * instantiated with this view. + * + * @see ReducersXor + * @see op_xor + * + * @ingroup ReducersXor + */ +template <typename Type> +class op_xor_view : public scalar_view<Type> +{ + typedef scalar_view<Type> base; + +public: + /** Class to represent the right-hand side of `*reducer = *reducer ^ value`. + * + * The only assignment operator for the op_xor_view class takes an + * rhs_proxy as its operand. This results in the syntactic restriction + * that the only expressions that can be assigned to an op_xor_view are + * ones which generate an rhs_proxy — that is, expressions of the form + * `op_xor_view ^ value ... ^ value`. + * + * @warning + * The lhs and rhs views in such an assignment must be the same; + * otherwise, the behavior will be undefined. (I.e., `v1 = v1 ^ x` is + * legal; `v1 = v2 ^ x` is illegal.) This condition will be checked with + * a runtime assertion when compiled in debug mode. + * + * @see op_xor_view + */ + class rhs_proxy { + friend class op_xor_view; + + const op_xor_view* m_view; + Type m_value; + + // Constructor is invoked only from op_xor_view::operator^(). + // + rhs_proxy(const op_xor_view* view, const Type& value) : m_view(view), m_value(value) {} + + rhs_proxy& operator=(const rhs_proxy&); // Disable assignment operator + rhs_proxy(); // Disable default constructor + + public: + /** Bitwise xor with an additional rhs value. If `v` is an op_xor_view + * and `a1` is a value, then the expression `v ^ a1` invokes the + * view’s `operator^()` to create an rhs_proxy for `(v, a1)`; then + * `v ^ a1 ^ a2` invokes the rhs_proxy’s `operator^()` to create a new + * rhs_proxy for `(v, a1^a2)`. This allows the right-hand side of an + * assignment to be not just `view ^ value`, but + ( `view ^ value ^ value ... ^ value`. The effect is that + * + * v = v ^ a1 ^ a2 ... ^ an; + * + * is evaluated as + * + * v = v ^ (a1 ^ a2 ... ^ an); + */ + rhs_proxy& operator^(const Type& x) { m_value ^= x; return *this; } + }; + + + /** Default/identity constructor. This constructor initializes the + * contained value to `Type()`. + */ + op_xor_view() : base() {} + + /** Construct with a specified initial value. + */ + explicit op_xor_view(const Type& v) : base(v) {} + + /** Reduction operation. + * + * This function is invoked by the @ref op_xor monoid to combine the views + * of two strands when the right strand merges with the left one. It + * “xors†the value contained in the left-strand view by the value + * contained in the right-strand view, and leaves the value in the + * right-strand view undefined. + * + * @param right A pointer to the right-strand view. (`this` points to + * the left-strand view.) + * + * @note Used only by the @ref op_xor monoid to implement the monoid + * reduce operation. + */ + void reduce(op_xor_view* right) { this->m_value ^= right->m_value; } + + /** @name Accumulator variable updates. + * + * These functions support the various syntaxes for “xoring†the + * accumulator variable contained in the view with some value. + */ + //@{ + + /** Xor the accumulator variable with @a x. + */ + op_xor_view& operator^=(const Type& x) { this->m_value ^= x; return *this; } + + /** Create an object representing `*this ^ x`. + * + * @see rhs_proxy + */ + rhs_proxy operator^(const Type& x) const { return rhs_proxy(this, x); } + + /** Assign the result of a `view ^ value` expression to the view. Note that + * this is the only assignment operator for this class. + * + * @see rhs_proxy + */ + op_xor_view& operator=(const rhs_proxy& rhs) { + __CILKRTS_ASSERT(this == rhs.m_view); + this->m_value ^= rhs.m_value; + return *this; + } + + //@} +}; + +/** Monoid class for bitwise xor reductions. Instantiate the cilk::reducer + * template class with an op_xor monoid to create a bitwise xor reducer + * class. For example, to compute the bitwise xor of a set of `unsigned long` + * values: + * + * cilk::reducer< cilk::op_xor<unsigned long> > r; + * + * @tparam Type The reducer value type. + * @tparam Align If `false` (the default), reducers instantiated on this + * monoid will be naturally aligned (the Cilk library 1.0 + * behavior). If `true`, reducers instantiated on this monoid + * will be cache-aligned for binary compatibility with + * reducers in Cilk library version 0.9. + * + * @see ReducersXor + * @see op_xor_view + * + * @ingroup ReducersXor + */ +template <typename Type, bool Align = false> +struct op_xor : public monoid_with_view<op_xor_view<Type>, Align> {}; + +/** Deprecated bitwise xor reducer class. + * + * reducer_opxor is the same as @ref reducer<@ref op_xor>, except that + * reducer_opxor is a proxy for the contained view, so that accumulator + * variable update operations can be applied directly to the reducer. For + * example, a value is xored with a `reducer<%op_xor>` with `*r ^= a`, but a + * value can be xored with a `%reducer_opxor` with `r ^= a`. + * + * @deprecated Users are strongly encouraged to use `reducer<monoid>` + * reducers rather than the old wrappers like reducer_opand. + * The `reducer<monoid>` reducers show the reducer/monoid/view + * architecture more clearly, are more consistent in their + * implementation, and present a simpler model for new + * user-implemented reducers. + * + * @note Implicit conversions are provided between `%reducer_opxor` + * and `reducer<%op_xor>`. This allows incremental code + * conversion: old code that used `%reducer_opxor` can pass a + * `%reducer_opxor` to a converted function that now expects a + * pointer or reference to a `reducer<%op_xor>`, and vice + * versa. + * + * @tparam Type The value type of the reducer. + * + * @see op_xor + * @see reducer + * @see ReducersXor + * + * @ingroup ReducersXor + */ +template <typename Type> +class reducer_opxor : public reducer< op_xor<Type, true> > +{ + typedef reducer< op_xor<Type, true> > base; + using base::view; + + public: + /// The view type for the reducer. + typedef typename base::view_type view_type; + + /// The view’s rhs proxy type. + typedef typename view_type::rhs_proxy rhs_proxy; + + /// The view type for the reducer. + typedef view_type View; + + /// The monoid type for the reducer. + typedef typename base::monoid_type Monoid; + + /** @name Constructors + */ + //@{ + + /** Default (identity) constructor. + * + * Constructs the wrapper with the default initial value of `Type()`. + */ + reducer_opxor() {} + + /** Value constructor. + * + * Constructs the wrapper with a specified initial value. + */ + explicit reducer_opxor(const Type& initial_value) : base(initial_value) {} + + //@} + + /** @name Forwarded functions + * @details Functions that update the contained accumulator variable are + * simply forwarded to the contained @ref op_and_view. */ + //@{ + + /// @copydoc op_xor_view::operator^=(const Type&) + reducer_opxor& operator^=(const Type& x) + { + view() ^= x; return *this; + } + + // The legacy definition of reducer_opxor::operator^() has different + // behavior and a different return type than this definition. The legacy + // version is defined as a member function, so this new version is defined + // as a free function to give it a different signature, so that they won’t + // end up sharing a single object file entry. + + /// @copydoc op_xor_view::operator^(const Type&) const + friend rhs_proxy operator^(const reducer_opxor& r, const Type& x) + { + return r.view() ^ x; + } + + /// @copydoc op_and_view::operator=(const rhs_proxy&) + reducer_opxor& operator=(const rhs_proxy& temp) + { + view() = temp; return *this; + } + //@} + + /** @name Dereference + * @details Dereferencing a wrapper is a no-op. It simply returns the + * wrapper. Combined with the rule that the wrapper forwards view + * operations to its contained view, this means that view operations can + * be written the same way on reducers and wrappers, which is convenient + * for incrementally converting old code using wrappers to use reducers + * instead. That is: + * + * reducer< op_and<int> > r; + * *r &= a; // *r returns the view + * // operator &= is a view member function + * + * reducer_opand<int> w; + * *w &= a; // *w returns the wrapper + * // operator &= is a wrapper member function that + * // calls the corresponding view function + */ + //@{ + reducer_opxor& operator*() { return *this; } + reducer_opxor const& operator*() const { return *this; } + + reducer_opxor* operator->() { return this; } + reducer_opxor const* operator->() const { return this; } + //@} + + /** @name Upcast + * @details In Cilk library 0.9, reducers were always cache-aligned. In + * library 1.0, reducer cache alignment is optional. By default, reducers + * are unaligned (i.e., just naturally aligned), but legacy wrappers + * inherit from cache-aligned reducers for binary compatibility. + * + * This means that a wrapper will automatically be upcast to its aligned + * reducer base class. The following conversion operators provide + * pseudo-upcasts to the corresponding unaligned reducer class. + */ + //@{ + operator reducer< op_xor<Type, false> >& () + { + return *reinterpret_cast< reducer< op_xor<Type, false> >* >(this); + } + operator const reducer< op_xor<Type, false> >& () const + { + return *reinterpret_cast< const reducer< op_xor<Type, false> >* >(this); + } + //@} + +}; + +/// @cond internal +/** Metafunction specialization for reducer conversion. + * + * This specialization of the @ref legacy_reducer_downcast template class + * defined in reducer.h causes the `reducer< op_xor<Type> >` class to have an + * `operator reducer_opxor<Type>& ()` conversion operator that statically + * downcasts the `reducer<op_xor>` to the corresponding `reducer_opxor` type. + * (The reverse conversion, from `reducer_opxor` to `reducer<op_xor>`, is just + * an upcast, which is provided for free by the language.) + * + * @ingroup ReducersXor + */ +template <typename Type, bool Align> +struct legacy_reducer_downcast<reducer<op_xor<Type, Align> > > +{ + typedef reducer_opxor<Type> type; +}; +/// @endcond + +} // namespace cilk + +#endif /* __cplusplus */ + + +/** @ingroup ReducersXor + */ +//@{ + +/** @name C language reducer macros + * + * These macros are used to declare and work with op_xor reducers in C code. + * + * @see @ref page_reducers_in_c + */ + //@{ + +__CILKRTS_BEGIN_EXTERN_C + +/** Opxor reducer type name. + * + * This macro expands into the identifier which is the name of the op_xor + * reducer type for a specified numeric type. + * + * @param tn The @ref reducers_c_type_names "numeric type name" specifying + * the type of the reducer. + * + * @see @ref reducers_c_predefined + * @see ReducersXor + */ +#define CILK_C_REDUCER_OPXOR_TYPE(tn) \ + __CILKRTS_MKIDENT(cilk_c_reducer_opxor_,tn) + +/** Declare an op_xor reducer object. + * + * This macro expands into a declaration of an op_xor reducer object for a + * specified numeric type. For example: + * + * CILK_C_REDUCER_OPXOR(my_reducer, ulong, 0); + * + * @param obj The variable name to be used for the declared reducer object. + * @param tn The @ref reducers_c_type_names "numeric type name" specifying + * the type of the reducer. + * @param v The initial value for the reducer. (A value which can be + * assigned to the numeric type represented by @a tn.) + * + * @see @ref reducers_c_predefined + * @see ReducersXor + */ +#define CILK_C_REDUCER_OPXOR(obj,tn,v) \ + CILK_C_REDUCER_OPXOR_TYPE(tn) obj = \ + CILK_C_INIT_REDUCER(_Typeof(obj.value), \ + __CILKRTS_MKIDENT(cilk_c_reducer_opxor_reduce_,tn), \ + __CILKRTS_MKIDENT(cilk_c_reducer_opxor_identity_,tn), \ + __cilkrts_hyperobject_noop_destroy, v) + +/// @cond internal + +/** Declare the op_xor reducer functions for a numeric type. + * + * This macro expands into external function declarations for functions which + * implement the reducer functionality for the op_xor reducer type for a + * specified numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name†identifier, used to construct the reducer + * type name, function names, etc. + */ +#define CILK_C_REDUCER_OPXOR_DECLARATION(t,tn) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_OPXOR_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_opxor,tn,l,r); \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_opxor,tn); + +/** Define the op_xor reducer functions for a numeric type. + * + * This macro expands into function definitions for functions which implement + * the reducer functionality for the op_xor reducer type for a specified + * numeric type. + * + * @param t The value type of the reducer. + * @param tn The value “type name†identifier, used to construct the reducer + * type name, function names, etc. + */ +#define CILK_C_REDUCER_OPXOR_DEFINITION(t,tn) \ + typedef CILK_C_DECLARE_REDUCER(t) CILK_C_REDUCER_OPXOR_TYPE(tn); \ + __CILKRTS_DECLARE_REDUCER_REDUCE(cilk_c_reducer_opxor,tn,l,r) \ + { *(t*)l ^= *(t*)r; } \ + __CILKRTS_DECLARE_REDUCER_IDENTITY(cilk_c_reducer_opxor,tn) \ + { *(t*)v = 0; } + +//@{ +/** @def CILK_C_REDUCER_OPXOR_INSTANCE + * @brief Declare or define implementation functions for a reducer type. + * + * In the runtime source file c_reducers.c, the macro `CILK_C_DEFINE_REDUCERS` + * will be defined, and this macro will generate reducer implementation + * functions. Everywhere else, `CILK_C_DEFINE_REDUCERS` will be undefined, and + * this macro will expand into external declarations for the functions. + */ +#ifdef CILK_C_DEFINE_REDUCERS +# define CILK_C_REDUCER_OPXOR_INSTANCE(t,tn) \ + CILK_C_REDUCER_OPXOR_DEFINITION(t,tn) +#else +# define CILK_C_REDUCER_OPXOR_INSTANCE(t,tn) \ + CILK_C_REDUCER_OPXOR_DECLARATION(t,tn) +#endif +//@} + +/* Declare or define an instance of the reducer type and its functions for each + * numeric type. + */ +CILK_C_REDUCER_OPXOR_INSTANCE(char, char) +CILK_C_REDUCER_OPXOR_INSTANCE(unsigned char, uchar) +CILK_C_REDUCER_OPXOR_INSTANCE(signed char, schar) +CILK_C_REDUCER_OPXOR_INSTANCE(wchar_t, wchar_t) +CILK_C_REDUCER_OPXOR_INSTANCE(short, short) +CILK_C_REDUCER_OPXOR_INSTANCE(unsigned short, ushort) +CILK_C_REDUCER_OPXOR_INSTANCE(int, int) +CILK_C_REDUCER_OPXOR_INSTANCE(unsigned int, uint) +CILK_C_REDUCER_OPXOR_INSTANCE(unsigned int, unsigned) /* alternate name */ +CILK_C_REDUCER_OPXOR_INSTANCE(long, long) +CILK_C_REDUCER_OPXOR_INSTANCE(unsigned long, ulong) +CILK_C_REDUCER_OPXOR_INSTANCE(long long, longlong) +CILK_C_REDUCER_OPXOR_INSTANCE(unsigned long long, ulonglong) + +//@endcond + +__CILKRTS_END_EXTERN_C + +//@} + +//@} + +#endif /* REDUCER_OPXOR_H_INCLUDED */ diff --git a/libcilkrts/include/cilk/reducer_ostream.h b/libcilkrts/include/cilk/reducer_ostream.h new file mode 100644 index 00000000000..d9addeee89f --- /dev/null +++ b/libcilkrts/include/cilk/reducer_ostream.h @@ -0,0 +1,293 @@ +/* + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * reducer_ostream.h + * + * Purpose: Hyper-object to write to 'std::ostream's + * + * Classes: reducer_ostream + * + * Description: + * ============ + * Output streams ('std::ostream's) are a convenient means of writing text to + * files, the user console, or sockets. In a serial program, text is written + * to an ostream in a specific, logical order. For example, computing while + * traversing a data structure and printing them to an 'ostream' will result + * in the values being printed in the order of traversal. In a parallel + * version of the same program, however, different parts of the data structure + * may be traversed in a different order, resulting in a non-deterministic + * ordering of the stream. Worse, multiple strands may write to the same + * stream simultaneously, resulting in a data race. Replacing the + * 'std::ostream' with a 'cilk::reducer_ostream' will solve both problems: Data + * will appeaer in the stream in the same order as it would for the serial + * program, and there will be no races (no locks) on the common stream. + * + * Usage Example: + * ============== + * Assume we wish to traverse an array of objects, performing an operation on + * each object and writing the result to a file. Without a reducer_ostream, + * we have a race on the 'output' file stream: + *.. + * void compute(std::ostream& os, double x) + * { + * // Perform some significant computation and print the result: + * os << std::asin(x); + * } + * + * int test() + * { + * const std::size_t ARRAY_SIZE = 1000000; + * extern double myArray[ARRAY_SIZE]; + * + * std::ofstream output("output.txt"); + * cilk_for (std::size_t i = 0; i < ARRAY_SIZE; ++i) + * { + * compute(output, myArray[i]); + * } + * + * return 0; + * } + *.. + * The race is solved by using a reducer_ostream to proxy the 'output' file: + *.. + * void compute(cilk::reducer_ostream& os, double x) + * { + * // Perform some significant computation and print the result: + * *os << std::asin(x); + * } + * + * int test() + * { + * const std::size_t ARRAY_SIZE = 1000000; + * extern double myArray[ARRAY_SIZE]; + * + * std::ofstream output("output.txt"); + * cilk::reducer_ostream hyper_output(output); + * cilk_for (std::size_t i = 0; i < ARRAY_SIZE; ++i) + * { + * compute(hyper_output, myArray[i]); + * } + * + * return 0; + * } + *.. + * + * Limitations: + * ============ + * There are two possible values for the formatting flags immediately after a + * 'cilk_spawn' statement: they may either have the value that was set by the + * spawn function, or they may have default values. Because of + * non-determinism in the processor scheduling, there is no way to determine + * which it will be. Similarly, the formatting flags after a 'cilk_sync' may + * or may not have the same value as before the sync. Therefore, one must use + * a disciplined coding style to avoid formatting errors. There are two + * approaches to mitigating the problem: The first is to eliminate the + * difference between the two possible outcomes by ensuring that the spawned + * function always returns the flags to their initial state: + *.. + * void compute(cilk::reducer_ostream& os, double x) + * { + * // Perform some significant computation and print the result: + * int saveprec = os.precision(5); + * os << std::asin(x); + * os.precision(saveprec); + * } + *.. + * The second approach is to write your streaming operations such that they + * don't depend on the previous state of the formatting flags by setting any + * important flags before every block of output: + *.. + * cilk_spawn compute(hyper_output, value); + * + * hyper_output->precision(2); // Don't depend on previous precision + * *hyper_output << f(); + * *hyper_output << g(); + *.. + * Another concern is memory usage. A reducer_ostream will buffer as much text + * as necessary to ensure that the order of output matches that of the serial + * version of the program. If all spawn branches perform an equal amount of + * output, then one can expect that half of the output before a sync will be + * buffered in memory. This hyperobject is therefore not well suited for + * serializing very large quantities of text output. + */ + +#ifndef REDUCER_OSTREAM_H_INCLUDED +#define REDUCER_OSTREAM_H_INCLUDED + +#include <cilk/reducer.h> +#include <iostream> +#include <sstream> + +namespace cilk { + +/** + * @brief Class 'reducer_ostream' is the representation of a hyperobject for + * output text streaming. + */ +class reducer_ostream +{ +public: + /// Internal representation of the per-strand view of the data for reducer_ostream + class View: public std::ostream + { + public: + /// Type of the std::stream reducer_ostream is based on + typedef std::ostream Base; + + friend class reducer_ostream; + + View(): + std::ostream(0) + { + Base::rdbuf(&strbuf_); + }; + + private: + void use_ostream (const std::ostream &os) + { + Base::rdbuf(os.rdbuf()); + Base::flags(os.flags()); // Copy formatting flags + Base::setstate(os.rdstate()); // Copy error state + } + + private: + std::stringbuf strbuf_; + }; + +public: + /// Definition of data view, operation, and identity for reducer_ostream + struct Monoid: monoid_base< View > + { + static void reduce (View *left, View *right); + }; + +private: + // Hyperobject to serve up views + reducer<Monoid> imp_; + + // Methods that provide the API for the reducer +public: + + // Construct an initial 'reducer_ostream' from an 'std::ostream'. The + // specified 'os' stream is used as the eventual destination for all + // text streamed to this hyperobject. + explicit reducer_ostream(const std::ostream &os); + + // Return a modifiable reference to the underlying 'ostream' object. + std::ostream& get_reference(); + + /** + * Append data from some type to the reducer_ostream + * + * @param v Value to be appended to the reducer_ostream + */ + template<typename T> + std::ostream & + operator<< (const T &v) + { + return imp_.view() << v; + } + + /** + * Append data from a std::ostream to the reducer_ostream + * + * @param _Pfn std::ostream to copy from + */ + std::ostream & + operator<< (std::ostream &(*_Pfn)(std::ostream &)) + { + View &v = imp_.view(); + + return ((*_Pfn)(v)); + } + + reducer_ostream& operator*() { return *this; } + reducer_ostream const& operator*() const { return *this; } + + reducer_ostream* operator->() { return this; } + reducer_ostream const* operator->() const { return this; } +}; + + +// ------------------------------------------- +// class reducer_ostream::Monoid +// ------------------------------------------- + +/** + * Appends string from "right" reducer_basic_string onto the end of + * the "left". When done, the "right" reducer_basic_string is empty. + */ +void +reducer_ostream::Monoid::reduce(View *left, View *right) +{ + left->operator<< (&right->strbuf_); +} + +// -------------------------- +// class reducer_ostream +// -------------------------- + +/** + * Construct a reducer_ostream which will write to the specified std::ostream + * + * @param os std::ostream to write to + */ +inline +reducer_ostream::reducer_ostream(const std::ostream &os) : + imp_() +{ + View &v = imp_.view(); + + v.use_ostream(os); +} + +/** + * Get a reference to the std::ostream + */ +inline +std::ostream & +reducer_ostream::get_reference() +{ + View &v = imp_.view(); + + return v; +} + +} // namespace cilk + +#endif // REDUCER_OSTREAM_H_INCLUDED + diff --git a/libcilkrts/include/cilk/reducer_string.h b/libcilkrts/include/cilk/reducer_string.h new file mode 100644 index 00000000000..0d70dd8b30a --- /dev/null +++ b/libcilkrts/include/cilk/reducer_string.h @@ -0,0 +1,729 @@ +/* reducer_string.h -*- C++ -*- + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file reducer_string.h + * + * @brief Defines classes for doing parallel string creation by appending. + * + * @ingroup ReducersString + * + * @see ReducersString + */ + +#ifndef REDUCER_STRING_H_INCLUDED +#define REDUCER_STRING_H_INCLUDED + +#include <cilk/reducer.h> +#include <string> +#include <list> + +/** @defgroup ReducersString String Reducers + * + * String reducers allow the creation of a string by concatenating a set of + * strings or characters in parallel. + * + * @ingroup Reducers + * + * You should be familiar with @ref pagereducers "Cilk reducers", described in + * file reducers.md, and particularly with @ref reducers_using, before trying + * to use the information in this file. + * + * @section redstring_usage Usage Example + * + * vector<Data> data; + * void expensive_string_computation(const Data& x, string& s); + * cilk::reducer<cilk::op_string> r; + * cilk_for (int i = 0; i != data.size(); ++i) { + * string temp; + * expensive_string_computation(data[i], temp); + * *r += temp; + * } + * string result; + * r.move_out(result); + * + * @section redstring_monoid The Monoid + * + * @subsection redstring_monoid_values Value Set + * + * The value set of a string reducer is the set of values of the class + * `std::basic_string<Char, Traits, Alloc>`, which we refer to as “the + * reducer’s string typeâ€. + * + * @subsection redstring_monoid_operator Operator + * + * The operator of a string reducer is the string concatenation operator, + * defined by the “`+`†binary operator on the reducer’s string type. + * + * @subsection redstring_monoid_identity Identity + * + * The identity value of a string reducer is the empty string, which is the + * value of the expression + * `std::basic_string<Char, Traits, Alloc>([allocator])`. + * + * @section redstring_operations Operations + * + * In the operation descriptions below, the type name `String` refers to the + * reducer’s string type, `std::basic_string<Char, Traits, Alloc>`. + * + * @subsection redstring_constructors Constructors + * + * Any argument list which is valid for a `std::basic_string` constructor is + * valid for a string reducer constructor. The usual move-in constructor is + * also provided: + * + * reducer(move_in(String& variable)) + * + * @subsection redstring_get_set Set and Get + * + * r.set_value(const String& value) + * const String& = r.get_value() const + * r.move_in(String& variable) + * r.move_out(String& variable) + * + * @subsection redstring_initial Initial Values + * + * A string reducer with no constructor arguments, or with only an allocator + * argument, will initially contain the identity value, an empty string. + * + * @subsection redstring_view_ops View Operations + * + * *r += a + * r->append(a) + * r->append(a, b) + * r->push_back(a) + * + * These operations on string reducer views are the same as the corresponding + * operations on strings. + * + * @section redstring_performance Performance Considerations + * + * String reducers work by creating a string for each view, collecting those + * strings in a list, and then concatenating them into a single result string + * at the end of the computation. This last step takes place in serial code, + * and necessarily takes time proportional to the length of the result string. + * Thus, a parallel string reducer cannot actually speed up the time spent + * directly creating the string. This trivial example would probably be slower + * (because of reducer overhead) than the corresponding serial code: + * + * vector<string> a; + * reducer<op_string> r; + * cilk_for (int i = 0; i != a.length(); ++i) { + * *r += a[i]; + * } + * string result; + * r.move_out(result); + * + * What a string reducer _can_ do is to allow the _remainder_ of the + * computation to be done in parallel, without having to worry about managing + * the string computation. + * + * The strings for new views are created (by the view identity constructor) + * using the same allocator as the string that was created when the reducer + * was constructed. Note that this allocator is determined when the reducer is + * constructed. The following two examples may have very different behavior: + * + * string<Char, Traits, Allocator> a_string; + * + * reducer< op_string<Char, Traits, Allocator> reducer1(move_in(a_string)); + * ... parallel computation ... + * reducer1.move_out(a_string); + * + * reducer< op_string<Char, Traits, Allocator> reducer2; + * reducer2.move_in(a_string); + * ... parallel computation ... + * reducer2.move_out(a_string); + * + * * `reducer1` will be constructed with the same allocator as `a_string`, + * because the string was specified in the constructor. The `move_in` + * and `move_out` can therefore be done with a `swap` in constant time. + * * `reducer2` will be constructed with a _default_ allocator of type + * `Allocator`, which may not be the same as the allocator of `a_string`. + * Therefore, the `move_in` and `move_out` may have to be done with a copy + * in _O(N)_ time. + * + * (All instances of an allocator type with no internal state (like + * `std::allocator`) are “the sameâ€. You only need to worry about the “same + * allocator†issue when you create string reducers with custom allocator + * types.) + * + * @section redstring_types Type and Operator Requirements + * + * `std::basic_string<Char, Traits, Alloc>` must be a valid type. +*/ + +namespace cilk { + +/** @ingroup ReducersString */ +//@{ + +/** The string append reducer view class. + * + * This is the view class for reducers created with + * `cilk::reducer< cilk::op_basic_string<Type, Traits, Allocator> >`. It holds + * the accumulator variable for the reduction, and allows only append + * operations to be performed on it. + * + * @note The reducer “dereference†operation (`reducer::operator *()`) + * yields a reference to the view. Thus, for example, the view class’s + * `append` operation would be used in an expression like + * `r->append(a)`, where `r` is a string append reducer variable. + * + * @tparam Char The string element type (not the string type). + * @tparam Traits The character traits type. + * @tparam Alloc The string allocator type. + * + * @see ReducersString + * @see op_basic_string + */ +template<typename Char, typename Traits, typename Alloc> +class op_basic_string_view +{ + typedef std::basic_string<Char, Traits, Alloc> string_type; + typedef std::list<string_type> list_type; + typedef typename string_type::size_type size_type; + + // The view's value is represented by a list of strings and a single + // string. The value is the concatenation of the strings in the list with + // the single string at the end. All string operations apply to the single + // string; reduce operations cause lists of partial strings from multiple + // strands to be combined. + // + mutable string_type m_string; + mutable list_type m_list; + + // Before returning the value of the reducer, concatenate all the strings + // in the list with the single string. + // + void flatten() const + { + if (m_list.empty()) return; + + typename list_type::iterator i; + + size_type len = m_string.size(); + for (i = m_list.begin(); i != m_list.end(); ++i) + len += i->size(); + + string_type result(get_allocator()); + result.reserve(len); + + for (i = m_list.begin(); i != m_list.end(); ++i) + result += *i; + m_list.clear(); + + result += m_string; + result.swap(m_string); + } + +public: + + /** @name Monoid support. + */ + //@{ + + /// Required by @ref monoid_with_view + typedef string_type value_type; + + /// Required by @ref op_string + Alloc get_allocator() const + { + return m_string.get_allocator(); + } + + /** Reduction operation. + * + * This function is invoked by the @ref op_basic_string monoid to combine + * the views of two strands when the right strand merges with the left + * one. It appends the value contained in the right-strand view to the + * value contained in the left-strand view, and leaves the value in the + * right-strand view undefined. + * + * @param right A pointer to the right-strand view. (`this` points to + * the left-strand view.) + * + * @note Used only by the @ref op_basic_string monoid to implement the + * monoid reduce operation. + */ + void reduce(op_basic_string_view* right) + { + if (!right->m_string.empty() || !right->m_list.empty()) { + // (list, string) + (right_list, right_string) => + // (list + {string} + right_list, right_string) + if (!m_string.empty()) { + // simulate m_list.push_back(std::move(m_string)) + m_list.push_back(string_type(get_allocator())); + m_list.back().swap(m_string); + } + m_list.splice(m_list.end(), right->m_list); + m_string.swap(right->m_string); + } + } + + //@} + + /** @name Pass constructor arguments through to the string constructor. + */ + //@{ + + op_basic_string_view() : m_string() {} + + template <typename T1> + op_basic_string_view(const T1& x1) : m_string(x1) {} + + template <typename T1, typename T2> + op_basic_string_view(const T1& x1, const T2& x2) : m_string(x1, x2) {} + + template <typename T1, typename T2, typename T3> + op_basic_string_view(const T1& x1, const T2& x2, const T3& x3) : m_string(x1, x2, x3) {} + + template <typename T1, typename T2, typename T3, typename T4> + op_basic_string_view(const T1& x1, const T2& x2, const T3& x3, const T4& x4) : + m_string(x1, x2, x3, x4) {} + + //@} + + /** Move-in constructor. + */ + explicit op_basic_string_view(move_in_wrapper<value_type> w) + : m_string(w.value().get_allocator()) + { + m_string.swap(w.value()); + } + + /** @name @ref reducer support. + */ + //@{ + + void view_move_in(string_type& s) + { + m_list.clear(); + if (m_string.get_allocator() == s.get_allocator()) + // Equal allocators. Do a (fast) swap. + m_string.swap(s); + else + // Unequal allocators. Do a (slow) copy. + m_string = s; + s.clear(); + } + + void view_move_out(string_type& s) + { + flatten(); + if (m_string.get_allocator() == s.get_allocator()) + // Equal allocators. Do a (fast) swap. + m_string.swap(s); + else + // Unequal allocators. Do a (slow) copy. + s = m_string; + m_string.clear(); + } + + void view_set_value(const string_type& s) + { m_list.clear(); m_string = s; } + + string_type const& view_get_value() const + { flatten(); return m_string; } + + string_type & view_get_reference() + { flatten(); return m_string; } + + string_type const& view_get_reference() const + { flatten(); return m_string; } + + //@} + + /** @name View modifier operations. + * + * @details These simply wrap the corresponding operations on the underlying string. + */ + //@{ + + template <typename T> + op_basic_string_view& operator +=(const T& x) + { m_string += x; return *this; } + + template <typename T1> + op_basic_string_view& append(const T1& x1) + { m_string.append(x1); return *this; } + + template <typename T1, typename T2> + op_basic_string_view& append(const T1& x1, const T2& x2) + { m_string.append(x1, x2); return *this; } + + template <typename T1, typename T2, typename T3> + op_basic_string_view& append(const T1& x1, const T2& x2, const T3& x3) + { m_string.append(x1, x2, x3); return *this; } + + void push_back(const Char x) { m_string.push_back(x); } + + //@} +}; + + +/** String append monoid class. Instantiate the cilk::reducer template class + * with an op_basic_string monoid to create a string append reducer class. For + * example, to concatenate a collection of standard strings: + * + * cilk::reducer< cilk::op_basic_string<char> > r; + * + * @tparam Char The string element type (not the string type). + * @tparam Traits The character traits type. + * @tparam Alloc The string allocator type. + * @tparam Align If `false` (the default), reducers instantiated on this + * monoid will be naturally aligned (the Cilk library 1.0 + * behavior). If `true`, reducers instantiated on this monoid + * will be cache-aligned for binary compatibility with + * reducers in Cilk library version 0.9. + * + * @see ReducersString + * @see op_basic_string_view + * @see reducer_basic_string + * @see op_string + * @see op_wstring + */ +template<typename Char, + typename Traits = std::char_traits<Char>, + typename Alloc = std::allocator<Char>, + bool Align = false> +class op_basic_string : + public monoid_with_view< op_basic_string_view<Char, Traits, Alloc>, Align > +{ + typedef monoid_with_view< op_basic_string_view<Char, Traits, Alloc>, Align > + base; + Alloc m_allocator; + +public: + + /** View type of the monoid. + */ + typedef typename base::view_type view_type; + + /** Constructor. + * + * There is no default constructor for string monoids, because the + * allocator must always be specified. + * + * @param allocator The list allocator to be used when + * identity-constructing new views. + */ + op_basic_string(const Alloc& allocator = Alloc()) : m_allocator(allocator) + {} + + /** Create an identity view. + * + * String view identity constructors take the string allocator as an + * argument. + * + * @param v The address of the uninitialized memory in which the view + * will be constructed. + */ + void identity(view_type *v) const { ::new((void*) v) view_type(m_allocator); } + + /** @name Construct functions + * + * A string append reduction monoid must have a copy of the allocator of + * the leftmost view’s string, so that it can use it in the `identity` + * operation. This, in turn, requires that string reduction monoids have a + * specialized `construct()` function. + * + * All string reducer monoid `construct()` functions first construct the + * leftmost view, using the arguments that were passed in from the reducer + * constructor. They then call the view’s `get_allocator()` function to + * get the string allocator from the string in the leftmost view, and pass + * that to the monoid constructor. + */ + //@{ + + static void construct(op_basic_string* monoid, view_type* view) + { provisional( new ((void*)view) view_type() ).confirm_if( + new ((void*)monoid) op_basic_string(view->get_allocator()) ); } + + template <typename T1> + static void construct(op_basic_string* monoid, view_type* view, const T1& x1) + { provisional( new ((void*)view) view_type(x1) ).confirm_if( + new ((void*)monoid) op_basic_string(view->get_allocator()) ); } + + template <typename T1, typename T2> + static void construct(op_basic_string* monoid, view_type* view, const T1& x1, const T2& x2) + { provisional( new ((void*)view) view_type(x1, x2) ).confirm_if( + new ((void*)monoid) op_basic_string(view->get_allocator()) ); } + + template <typename T1, typename T2, typename T3> + static void construct(op_basic_string* monoid, view_type* view, const T1& x1, const T2& x2, + const T3& x3) + { provisional( new ((void*)view) view_type(x1, x2, x3) ).confirm_if( + new ((void*)monoid) op_basic_string(view->get_allocator()) ); } + + template <typename T1, typename T2, typename T3, typename T4> + static void construct(op_basic_string* monoid, view_type* view, const T1& x1, const T2& x2, + const T3& x3, const T4& x4) + { provisional( new ((void*)view) view_type(x1, x2, x3, x4) ).confirm_if( + new ((void*)monoid) op_basic_string(view->get_allocator()) ); } + + //@} +}; + + +/** Convenience typedef for 8-bit strings + */ +typedef op_basic_string<char> op_string; + +/** Convenience typedef for 16-bit strings + */ +typedef op_basic_string<wchar_t> op_wstring; + + +/** Deprecated string append reducer class. + * + * reducer_basic_string is the same as @ref reducer<@ref op_basic_string>, + * except that reducer_basic_string is a proxy for the contained view, so that + * accumulator variable update operations can be applied directly to the + * reducer. For example, a value is appended to a `reducer<%op_basic_string>` + * with `r->push_back(a)`, but a value can be appended to a `%reducer_opand` + * with `r.push_back(a)`. + * + * @deprecated Users are strongly encouraged to use `reducer<monoid>` + * reducers rather than the old wrappers like reducer_basic_string. + * The `reducer<monoid>` reducers show the reducer/monoid/view + * architecture more clearly, are more consistent in their + * implementation, and present a simpler model for new + * user-implemented reducers. + * + * @note Implicit conversions are provided between `%reducer_basic_string` + * and `reducer<%op_basic_string>`. This allows incremental code + * conversion: old code that used `%reducer_basic_string` can pass a + * `%reducer_basic_string` to a converted function that now expects a + * pointer or reference to a `reducer<%op_basic_string>`, and vice + * versa. + * + * @tparam Char The string element type (not the string type). + * @tparam Traits The character traits type. + * @tparam Alloc The string allocator type. + * + * @see op_basic_string + * @see reducer + * @see ReducersString + */ +template<typename Char, + typename Traits = std::char_traits<Char>, + typename Alloc = std::allocator<Char> > +class reducer_basic_string : + public reducer< op_basic_string<Char, Traits, Alloc, true> > +{ + typedef reducer< op_basic_string<Char, Traits, Alloc, true> > base; + using base::view; +public: + + /// The reducer’s string type. + typedef typename base::value_type string_type; + + /// The reducer’s primitive component type. + typedef Char basic_value_type; + + /// The string size type. + typedef typename string_type::size_type size_type; + + /// The view type for the reducer. + typedef typename base::view_type View; + + /// The monoid type for the reducer. + typedef typename base::monoid_type Monoid; + + + /** @name Constructors + */ + //@{ + + /** @name Forward constructor calls to the base class. + * + * All basic_string constructor forms are supported. + */ + //@{ + reducer_basic_string() {} + + template <typename T1> + reducer_basic_string(const T1& x1) : + base(x1) {} + + template <typename T1, typename T2> + reducer_basic_string(const T1& x1, const T2& x2) : + base(x1, x2) {} + + template <typename T1, typename T2, typename T3> + reducer_basic_string(const T1& x1, const T2& x2, const T3& x3) : + base(x1, x2, x3) {} + + template <typename T1, typename T2, typename T3, typename T4> + reducer_basic_string(const T1& x1, const T2& x2, const T3& x3, const T4& x4) : + base(x1, x2, x3, x4) {} + //@} + + /** Allow mutable access to the string within the current view. + * + * @warning If this method is called before the parallel calculation is + * complete, the string returned by this method will be a + * partial result. + * + * @returns A mutable reference to the string within the current view. + */ + string_type &get_reference() + { return view().view_get_reference(); } + + /** Allow read-only access to the string within the current view. + * + * @warning If this method is called before the parallel calculation is + * complete, the string returned by this method will be a + * partial result. + * + * @returns A const reference to the string within the current view. + */ + string_type const &get_reference() const + { return view().view_get_reference(); } + + /** @name Append to the string. + * + * These operations are simply forwarded to the view. + */ + //@{ + void append(const Char *ptr) + { view().append(ptr); } + void append(const Char *ptr, size_type count) + { view().append(ptr, count); } + void append(const string_type &str, size_type offset, size_type count) + { view().append(str, offset, count); } + void append(const string_type &str) + { view().append(str); } + void append(size_type count, Char ch) + { view().append(count, ch); } + + // Append to the string + reducer_basic_string<Char, Traits, Alloc> &operator+=(Char ch) + { view() += ch; return *this; } + reducer_basic_string<Char, Traits, Alloc> &operator+=(const Char *ptr) + { view() += ptr; return *this; } + reducer_basic_string<Char, Traits, Alloc> &operator+=(const string_type &right) + { view() += right; return *this; } + //@} + + /** @name Dereference + * @details Dereferencing a wrapper is a no-op. It simply returns the + * wrapper. Combined with the rule that the wrapper forwards view + * operations to its contained view, this means that view operations can + * be written the same way on reducers and wrappers, which is convenient + * for incrementally converting old code using wrappers to use reducers + * instead. That is: + * + * reducer<op_string> r; + * r->push_back(a); // r-> returns the view + * // push_back() is a view member function + * + * reducer_string w; + * w->push_back(a); // *w returns the wrapper + * // push_back() is a wrapper member function + * // that calls the corresponding view function + */ + //@{ + reducer_basic_string& operator*() { return *this; } + reducer_basic_string const& operator*() const { return *this; } + + reducer_basic_string* operator->() { return this; } + reducer_basic_string const* operator->() const { return this; } + //@} + + /** @name Upcast + * @details In Cilk library 0.9, reducers were always cache-aligned. In + * library 1.0, reducer cache alignment is optional. By default, reducers + * are unaligned (i.e., just naturally aligned), but legacy wrappers + * inherit from cache-aligned reducers for binary compatibility. + * + * This means that a wrapper will automatically be upcast to its aligned + * reducer base class. The following conversion operators provide + * pseudo-upcasts to the corresponding unaligned reducer class. + */ + //@{ + operator reducer< op_basic_string<Char, Traits, Alloc, false> >& () + { + return *reinterpret_cast< reducer< + op_basic_string<Char, Traits, Alloc, false> >* + >(this); + } + operator const reducer< op_basic_string<Char, Traits, Alloc, false> >& () const + { + return *reinterpret_cast< const reducer< + op_basic_string<Char, Traits, Alloc, false> >* + >(this); + } + //@} +}; + + +/** Convenience typedef for 8-bit strings + */ +typedef reducer_basic_string<char> reducer_string; + +/** Convenience typedef for 16-bit strings + */ +typedef reducer_basic_string<wchar_t> reducer_wstring; + +/// @cond internal + +/// @cond internal +/** Metafunction specialization for reducer conversion. + * + * This specialization of the @ref legacy_reducer_downcast template class + * defined in reducer.h causes the `reducer< op_basic_string<Char> >` class to + * have an `operator reducer_basic_string<Char>& ()` conversion operator that + * statically downcasts the `reducer<op_basic_string>` to the corresponding + * `reducer_basic_string` type. (The reverse conversion, from + * `reducer_basic_string` to `reducer<op_basic_string>`, is just an upcast, + * which is provided for free by the language.) + * + * @ingroup ReducersString + */ +template<typename Char, typename Traits, typename Alloc, bool Align> +struct legacy_reducer_downcast< + reducer<op_basic_string<Char, Traits, Alloc, Align> > > +{ + typedef reducer_basic_string<Char, Traits, Alloc> type; +}; + +/// @endcond + +//@} + +} // namespace cilk + +#endif // REDUCER_STRING_H_INCLUDED diff --git a/libcilkrts/include/cilktools/cilkscreen.h b/libcilkrts/include/cilktools/cilkscreen.h new file mode 100644 index 00000000000..c6986ae7b08 --- /dev/null +++ b/libcilkrts/include/cilktools/cilkscreen.h @@ -0,0 +1,108 @@ +/* cilkscreen.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2010-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + +#ifndef INCLUDED_CILKSCREEN_H +#define INCLUDED_CILKSCREEN_H + +#include <cilk/cilk_api.h> + +/* + * Cilkscreen "functions". These macros generate metadata in your application + * to notify Cilkscreen of program state changes + */ + +#if ! defined(CILK_STUB) && defined(__INTEL_COMPILER) +# define __cilkscreen_metacall(annotation,expr) \ + __notify_zc_intrinsic((char *)annotation, expr) +#else +# define __cilkscreen_metacall(annotation,expr) ((void)annotation, (void)(expr)) +#endif + +/* Call once when a user thread enters a spawning function */ +#define __cilkscreen_enable_instrumentation() \ + __cilkscreen_metacall("cilkscreen_enable_instrumentation", 0) + +/* Call once when a user thread exits a spawning function */ +#define __cilkscreen_disable_instrumentation() \ + __cilkscreen_metacall("cilkscreen_disable_instrumentation", 0) + +/* Call to temporarily disable cilkscreen instrumentation */ +#define __cilkscreen_enable_checking() \ + __cilkscreen_metacall("cilkscreen_enable_checking", 0) + +/* Call to re-enable temporarily-disabled cilkscreen instrumentation */ +#define __cilkscreen_disable_checking() \ + __cilkscreen_metacall("cilkscreen_disable_checking", 0) + +/* Inform cilkscreen that memory from begin to end can be reused without + * causing races (e.g., for memory that comes from a memory allocator) */ +#define __cilkscreen_clean(begin, end) \ + do { \ + void *__data[2] = { (begin), (end) }; \ + __cilkscreen_metacall("cilkscreen_clean", &__data); \ + } while(0) + +/* Inform cilkscreen that a lock is being acquired. + * If the lock type is not a handle, then the caller should take its address + * and pass the pointer to the lock. Otherwise, the caller should pass the + * lock handle directly. + */ +#define __cilkscreen_acquire_lock(lock) \ + __cilkscreen_metacall("cilkscreen_acquire_lock", (lock)) + +#define __cilkscreen_release_lock(lock) \ + __cilkscreen_metacall("cilkscreen_release_lock", (lock)) + +/* + * Metacall data + * + * A metacall is a way to pass data to a function implemented by a tool. + * Metacalls are always instrumented when the tool is loaded. + */ + +// Tool code for Cilkscreen +#define METACALL_TOOL_CILKSCREEN 1 + +// Metacall codes implemented by Cilkscreen +#define CS_METACALL_PUTS 0 // Write string to the Cilkscreen log + +#define __cilkscreen_puts(text) \ + __cilkrts_metacall(METACALL_TOOL_CILKSCREEN, CS_METACALL_PUTS, (void *)(const char *)text) + +#endif /* defined(INCLUDED_CILKSCREEN_H) */ diff --git a/libcilkrts/include/cilktools/cilkview.h b/libcilkrts/include/cilktools/cilkview.h new file mode 100644 index 00000000000..eb7d9d8c0e4 --- /dev/null +++ b/libcilkrts/include/cilktools/cilkview.h @@ -0,0 +1,278 @@ +/* cilkview.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2010-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + +#ifndef INCLUDED_CILKVIEW_H +#define INCLUDED_CILKVIEW_H + +#include <cilk/cilk_api.h> + +#ifdef _WIN32 +# ifndef _WINBASE_ +__CILKRTS_BEGIN_EXTERN_C +unsigned long __stdcall GetTickCount(); +__CILKRTS_END_EXTERN_C +# endif +#endif // _WIN32 + +#if defined __unix__ || defined __APPLE__ || defined __VXWORKS__ +# include <sys/time.h> +#endif // defined __unix__ || defined __APPLE__ + +/// @brief Return the system clock with millisecond resolution +/// +/// This function returns a long integer representing the number of +/// milliseconds since an arbitrary starting point, e.g., since the system was +/// started or since the Unix Epoch. The result is meaningless by itself, but +/// the difference between two sequential calls to __cilkview_getticks() +/// represents the time interval that elapsed between them (in ms). +static inline unsigned long long __cilkview_getticks() +{ +#if __INTEL_COMPILER > 1200 + // When inlined, prevent code motion around this call + __notify_zc_intrinsic((void*) "test_getticks_start", 0); +#endif + +#ifdef _WIN32 + // Return milliseconds elapsed since the system started + return GetTickCount(); +#elif defined(__unix__) || defined(__APPLE__) || defined __VXWORKS__ + // Return milliseconds elapsed since the Unix Epoch + // (1-Jan-1970 00:00:00.000 UTC) + struct timeval t; + gettimeofday(&t, 0); + return t.tv_sec * 1000ULL + t.tv_usec / 1000; +#else +# error test_getticks() not implemented for this OS +#endif + +#if __INTEL_COMPILER > 1200 + // When inlined, prevent code motion around this call + __notify_zc_intrinsic((void*) "test_getticks_end", 0); +#endif +} + +typedef struct +{ + unsigned int size; // Size of structure in bytes + unsigned int status; // 1 = success, 0 = failure + unsigned long long time; // Time in milliseconds + unsigned long long work; + unsigned long long span; + unsigned long long burdened_span; + unsigned long long spawns; + unsigned long long syncs; + unsigned long long strands; + unsigned long long atomic_ins; + unsigned long long frames; +} cilkview_data_t; + +typedef struct +{ + cilkview_data_t *start; // Values at start of interval + cilkview_data_t *end; // Values at end of interval + const char *label; // Name for this interval + unsigned int flags; // What to do - see flags below +} cilkview_report_t; + +// What __cilkview_report should do. The flags can be ORed together +enum +{ + CV_REPORT_WRITE_TO_LOG = 1, // Write parallelism report to the log (xml or text) + CV_REPORT_WRITE_TO_RESULTS = 2 // Write parallelism data to results file +}; + +#ifndef CILKVIEW_NO_REPORT +static void __cilkview_do_report(cilkview_data_t *start, + cilkview_data_t *end, + const char *label, + unsigned int flags); +#endif /* CILKVIEW_NO_REPORT */ + +/* + * Metacall data + * + * A metacall is a way to pass data to a function implemented by a tool. + * Metacalls are always instrumented when the tool is loaded. + */ + +// Tool code for Cilkview +#define METACALL_TOOL_CILKVIEW 2 + +// Metacall codes implemented by Cilkview +enum +{ + CV_METACALL_PUTS, + CV_METACALL_QUERY, + CV_METACALL_START, + CV_METACALL_STOP, + CV_METACALL_RESET, + CV_METACALL_USE_DEFAULT_GRAIN, + CV_METACALL_CONNECTED, + CV_METACALL_SUSPEND, + CV_METACALL_RESUME, + CV_METACALL_REPORT +}; + +#if ! defined(CILK_STUB) && defined(__INTEL_COMPILER) +# define __cilkview_metacall(code,data) \ + __cilkrts_metacall(METACALL_TOOL_CILKVIEW, code, data) +#else +# define __cilkview_metacall(annotation,expr) (annotation, (void) (expr)) +#endif + +// Write arbitrary string to the log +#define __cilkview_puts(arg) \ + __cilkview_metacall(CV_METACALL_PUTS, arg) + +// Retrieve the Cilkview performance counters. The parameter must be a +// cilkview_data_t +#define __cilkview_query(d) \ + do { \ + d.size = sizeof(d); \ + d.status = 0; \ + __cilkview_metacall(CV_METACALL_QUERY, &d); \ + if (0 == d.status) \ + d.time = __cilkview_getticks(); \ + } while (0) + +// Write report to log or results file. If end is NULL, Cilkview will +// use the current values. +#define __cilkview_report(start, end, label, flags) \ + __cilkview_do_report(start, end, label, flags) + +// Control the workspan performance counters for the final report +#define __cilkview_workspan_start() \ + __cilkview_metacall(CV_METACALL_START, 0) +#define __cilkview_workspan_stop() \ + __cilkview_metacall(CV_METACALL_STOP, 0) +#define __cilkview_workspan_reset() \ + __cilkview_metacall(CV_METACALL_RESET, 0) +#define __cilkview_workspan_suspend() \ + __cilkview_metacall(CV_METACALL_SUSPEND, 0) +#define __cilkview_workspan_resume() \ + __cilkview_metacall(CV_METACALL_RESUME, 0) + +#define __cilkview_use_default_grain_size() \ + __cilkview_metacall(CV_METACALL_USE_DEFAULT, 0) + +// Sets the int is_connected to 1 if Cilkview is active +#define __cilkview_connected(is_connected) \ + __cilkview_metacall(CV_METACALL_CONNECTED, &is_connected) + + +#ifndef CILKVIEW_NO_REPORT + +// Stop Microsoft include files from complaining about getenv and fopen +#define _CRT_SECURE_NO_WARNINGS + +#include <stdlib.h> +#include <stdio.h> + +#ifdef _WIN32 +#pragma warning(push) +#pragma warning(disable: 1786) // Suppress warnings that getenv, fopen are deprecated +#endif + +static void __cilkview_do_report(cilkview_data_t *start, + cilkview_data_t *end, + const char *label, + unsigned int flags) +{ + int under_cilkview = 0; + unsigned long long elapsed_ms; + int worker_count = 0; + char *nworkers; + char *outfile; + FILE *f; + + // Check whether we're running under Cilkview + __cilkview_connected(under_cilkview); + + // If we're running under Cilkview, let it do those things that need + // to be done + if (under_cilkview) + { + cilkview_report_t d = {start, end, label, flags}; + __cilkview_metacall(CV_METACALL_REPORT, &d); + return; + } + + // We're not running under Cilkview. + // + // If we weren't asked to write to the results file, we're done. + if (0 == (flags & CV_REPORT_WRITE_TO_RESULTS)) + return; + + // Calculate the elapse milliseconds + if (NULL == end) + elapsed_ms = __cilkview_getticks() - start->time; + else + elapsed_ms = end->time - start->time; + + // Determine how many workers we're using for this trial run + nworkers = getenv("CILK_NWORKERS"); + if (NULL != nworkers) + worker_count = atoi(nworkers); + if (0 == worker_count) + worker_count = 16; + + // Open the output file and write the trial data to it + outfile = getenv("CILKVIEW_OUTFILE"); + if (NULL == outfile) + outfile = (char *)"cilkview.out"; + + f = fopen(outfile, "a"); + if (NULL == f) + fprintf(stderr, "__cilkview_do_report: unable to append to file %s\n", outfile); + else + { + fprintf(f, "%s trial %d %f\n", label, + worker_count, + ((float)elapsed_ms) / 1000.0f); + fclose(f); + } +} +#ifdef _WIN32 +#pragma warning(pop) +#endif + +#endif // CILKVIEW_NO_REPORT + + +#endif /* ! defined(INCLUDED_CILKVIEW_H) */ diff --git a/libcilkrts/include/cilktools/fake_mutex.h b/libcilkrts/include/cilktools/fake_mutex.h new file mode 100644 index 00000000000..9ae0678112f --- /dev/null +++ b/libcilkrts/include/cilktools/fake_mutex.h @@ -0,0 +1,92 @@ +/* fake_mutex.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************** + * + * Cilkscreen fake mutexes are provided to indicate to the Cilkscreen race + * detector that a race should be ignored. + * + * NOTE: This class does not provide mutual exclusion. You should use the + * mutual exclusion constructs provided by TBB or your operating system to + * protect against real data races. + */ + +#ifndef FAKE_MUTEX_H_INCLUDED +#define FAKE_MUTEX_H_INCLUDED + +#include <cilktools/cilkscreen.h> + +namespace cilkscreen +{ + class fake_mutex + { + public: + fake_mutex() : locked(false) + { + } + + ~fake_mutex() + { + __CILKRTS_ASSERT(! locked); + } + + // Wait until mutex is available, then enter + void lock() + { + __cilkscreen_acquire_lock(&locked); + __CILKRTS_ASSERT(! locked); + locked = true; + } + + // A fake mutex is always available + bool try_lock() { lock(); return true; } + + // Releases the mutex + void unlock() + { + __CILKRTS_ASSERT(locked); + locked = false; + __cilkscreen_release_lock(&locked); + } + + private: + bool locked; + }; + +} // namespace cilk + +#endif // FAKE_MUTEX_H_INCLUDED diff --git a/libcilkrts/include/cilktools/lock_guard.h b/libcilkrts/include/cilktools/lock_guard.h new file mode 100644 index 00000000000..d513e2b9734 --- /dev/null +++ b/libcilkrts/include/cilktools/lock_guard.h @@ -0,0 +1,86 @@ +/* lock_guard.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2011-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************** + * + * Lock guard patterned after the std::lock_guard class template proposed in + * the C++ 0x draft standard. + * + * An object of type lock_guard controls the ownership of a mutex object + * within a scope. A lock_guard object maintains ownership of a mutex object + * throughout the lock_guard object's lifetime. The behavior of a program is + * undefined if the mutex referenced by pm does not exist for the entire + * lifetime of the lock_guard object. + */ + +#ifndef LOCK_GUARD_H_INCLUDED +#define LOCK_GUARD_H_INCLUDED + +#include <cilk/cilk.h> + +namespace cilkscreen +{ + template <class Mutex> + class lock_guard + { + public: + typedef Mutex mutex_type; + + explicit lock_guard(mutex_type &m) : pm(m) + { + pm.lock(); + locked = true; + } + + ~lock_guard() + { + locked = false; + pm.unlock(); + } + + private: + lock_guard(lock_guard const&); + lock_guard& operator=(lock_guard const&); + + private: + // exposition only: + mutex_type ± + bool locked; + }; +} + +#endif // LOCK_GUARD_H_INCLUDED diff --git a/libcilkrts/include/internal/abi.h b/libcilkrts/include/internal/abi.h new file mode 100644 index 00000000000..f45b5bcb178 --- /dev/null +++ b/libcilkrts/include/internal/abi.h @@ -0,0 +1,639 @@ +/* + * abi.h + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ******************************************************************************/ + +/** + * @file abi.h + * + * @brief Defines the application binary interface between the compiler and + * the Intel Cilk Plus runtime. + */ + +#ifndef CILK_INTERNAL_ABI_H +#define CILK_INTERNAL_ABI_H + + +#include <cilk/common.h> +#include <stddef.h> // Needed to define size_t + +/** + * Jump buffers are OS and architecture dependent + */ +#if ! defined(_MSC_VER) +/* Non-Windows - only need 5 registers for the jump buffer for both IA32 and Intel64 */ +typedef void *__CILK_JUMP_BUFFER[5]; + +/** OS-specific implementation of setjmp */ +# define CILK_SETJMP(X) __builtin_setjmp(X) +/** OS-specific implementation of longjmp */ +# define CILK_LONGJMP(X) __builtin_longjmp(X,1) +#else +/* Windows - things are a little more complicated */ +# if defined(_M_X64) +/* Intel64 - Use an OS-defined jump buffer */ +# include <setjmp.h> +typedef jmp_buf __CILK_JUMP_BUFFER; + +# define CILK_SETJMP(X) setjmp(X) +# define CILK_LONGJMP(X) longjmp(X, 1) +# elif defined(_M_IX86) +/** + * Windows x86 - Use a simplified version of the Windows jump buffer for x86 + * setjmp is provided by __cilkrts_setjmp which passes jump buffer in EAX and + * destination in EDX longjmp is provided by an internal routine which uses + * this structure + */ +typedef struct +{ + unsigned long Ebp; + unsigned long Ebx; + unsigned long Edi; + unsigned long Esi; + unsigned long Esp; + unsigned long Eip; + unsigned long Registration; + unsigned long TryLevel; +} __CILK_JUMP_BUFFER; + +# else +# error Unexpected architecture - Need to define __CILK_JUMP_BUFFER +# endif /* _M_X64 */ + +#endif /* defined(_MSC_VER) */ + +/* struct tags */ +typedef struct __cilkrts_stack_frame __cilkrts_stack_frame; ///< struct tag for stack frame + +// Forwarded declarations +typedef struct global_state_t global_state_t; ///< Forwarded declaration for global state +typedef struct local_state local_state; ///< Forwarded declaration for local state +typedef struct cilkred_map cilkred_map; ///< Forward declaration for reducer map + +/// Forwarded declaration for system-dependent worker state +typedef struct __cilkrts_worker_sysdep_state + __cilkrts_worker_sysdep_state; + +/** + * The worker struct contains per-worker information that needs to be + * visible to the compiler, or rooted here. + * + * For 32-bit Windows we need to be aligning the structures on 4-byte + * boundaries to match where ICL is allocating the birthrank and rank + * in the __cilkrts_stack_frame. It's 4-byte aligned instead of 8-byte + * aligned. This is OK because the compiler is dealing with the 64-bit + * quantities as two 32-bit values. So change the packing to be on + * 4-byte boundaries. + * + * The fields of the worker struct can be classified as either local + * or shared. + * + * Local: This field is only accessed by the thread bound to this + * worker struct. Local fields can be freely accessed without + * acquiring locks. + * + * Shared: This field may be accessed by multiple worker threads. + * Accesses to shared fields usually requires locks, except in + * special situations where one can prove that locks are + * unnecessary. + * + * The fields of the worker struct can also be classified as + * "read-only" if the field does not change after it is initialized. + * Otherwise, the field is "read/write". Read-only fields do not + * require locks to access (ignoring the synchronization that might be + * needed for initialization if this can occur in parallel). + * + * Finally, we explicitly classify some fields as "synchronization" + * fields if they are used as part of a synchronization protocol in + * the runtime. These variables are generally shared and read/write. + * Mostly, this category includes lock variables and other variables + * that are involved in synchronization protocols (i.e., the THE + * protocol). + */ +#if defined(_MSC_VER) && defined(_M_IX86) +#pragma pack(push, 4) +#endif + +struct __cilkrts_worker { + /** + * T, H, and E pointers in the THE protocol See "The implementation of + * the Cilk-5 multithreaded language", PLDI 1998: + * http://portal.acm.org/citation.cfm?doid=277652.277725 + * + * Synchronization fields. [shared read/write] + */ + __cilkrts_stack_frame *volatile *volatile tail; + __cilkrts_stack_frame *volatile *volatile head; /**< @copydoc tail */ + __cilkrts_stack_frame *volatile *volatile exc; /**< @copydoc tail */ + + /** + * Addition to the THE protocol to allow us to protect some set of + * entries in the tail queue from stealing. Normally, this is set + * beyond the end of the task queue, indicating that all entries are + * available for stealing. During exception handling, protected_tail + * may be set to the first entry in the task queue, indicating that + * stealing is not allowed. + * + * Synchronization field. + */ + __cilkrts_stack_frame *volatile *volatile protected_tail; + + /** + * Limit of the Lazy Task Queue, to detect queue overflow + * [local read-only] + */ + __cilkrts_stack_frame *volatile *ltq_limit; + + /** + * Worker id. + * [local read-only] + */ + int32_t self; + + /** + * Global state of the runtime system, opaque to the client. + * [local read-only] + */ + global_state_t *g; + + /** + * Additional per-worker state of the runtime system that we want + * to maintain hidden from the client. + * [shared read-only] + */ + local_state *l; + + /** + * Map from reducer names to reducer values. + * [local read/write] + */ + cilkred_map *reducer_map; + + /** + * A slot that points to the currently executing Cilk frame. + * [local read/write] + */ + __cilkrts_stack_frame *current_stack_frame; + + /** + * Reserved space for a pointer. + * Used to be __cilkrts_stack_frame *volatile *volatile saved_protected_tail; + */ + void* reserved; + + /** + * System-dependent part of the worker state + * [local read-only] + */ + __cilkrts_worker_sysdep_state *sysdep; + +#if __CILKRTS_ABI_VERSION >= 1 + /** + * Per-worker pedigree information used to support scheduling-independent + * pseudo-random numbers. + * [local read/write] + */ + __cilkrts_pedigree pedigree; +#endif /* __CILKRTS_ABI_VERSION >= 1 */ +}; + + +/** + * Every spawning function has a frame descriptor. A spawning function + * is a function that spawns or detaches. Only spawning functions + * are visible to the Cilk runtime. + */ +struct __cilkrts_stack_frame +{ + /** + * flags is an integer with values defined below. Client code + * initializes flags to CILK_FRAME_VERSION before the first Cilk + * operation. + * + * The low 24-bits of the 'flags' field are the flags, proper. The high + * 8-bits are the version number. + * + * IMPORTANT: bits in this word are set and read by the PARENT ONLY, + * not by a spawned child. In particular, the STOLEN and UNSYNCHED + * bits are set on a steal and are read before a sync. Since there + * is no synchronization (locking) on this word, any attempt to set + * or read these bits asynchronously in a child would result in a race. + */ + uint32_t flags; + + /** Not currently used. Not initialized by Intel compiler. */ + int32_t size; + + /** + * call_parent points to the __cilkrts_stack_frame of the closest + * ancestor spawning function, including spawn helpers, of this frame. + * It forms a linked list ending at the first stolen frame. + */ + __cilkrts_stack_frame *call_parent; + + /** + * The client copies the worker from TLS here when initializing + * the structure. The runtime ensures that the field always points + * to the __cilkrts_worker which currently "owns" the frame. + */ + __cilkrts_worker *worker; + + /** + * Unix: Pending exception after sync. The sync continuation + * must call __cilkrts_rethrow to handle the pending exception. + * + * Windows: the handler that _would_ have been registered if our + * handler were not there. We maintain this for unwinding purposes. + * Win32: the value of this field is only defined in spawn helper + * functions + * + * Win64: except_data must be filled in for all functions with a + * __cilkrts_stack_frame + */ + void *except_data; + + /** + * Before every spawn and nontrivial sync the client function + * saves its continuation here. + */ + __CILK_JUMP_BUFFER ctx; + +#if __CILKRTS_ABI_VERSION >= 1 + /** + * Architecture-specific floating point state. mxcsr and fpcsr should be + * set when CILK_SETJMP is called in client code. Note that the Win64 + * jmpbuf for the Intel64 architecture already contains this information + * so there is no need to use these fields on that OS/architecture. + */ + uint32_t mxcsr; + uint16_t fpcsr; /**< @copydoc mxcsr */ + + + /** + * reserved is not used at this time. Client code should initialize it + * to 0 before the first Cilk operation + */ + uint16_t reserved; + + /** + * Pedigree information to support scheduling-independent pseudo-random + * numbers. There are two views of this information. The copy in a + * spawning function is used to stack the rank and communicate to the + * runtime on a steal or continuation. The copy in a spawn helper is + * immutable once the function is detached and is a node in the pedigree. + * The union is used to make clear which view we're using. + * + * In the detach sequence Client code should: + * - copy the worker pedigree into the spawn helper's pedigree + * - copy the worker pedigree into the call parent's pedigree + * - set the worker's rank to 0 + * - set the worker's pedigree.next to the spawn helper's pedigree + */ + union + { + __cilkrts_pedigree spawn_helper_pedigree; /* Used in spawn helpers */ + __cilkrts_pedigree parent_pedigree; /* Used in spawning funcs */ + }; +#endif /* __CILKRTS_ABI_VERSION >= 1 */ +}; + +/* + * Restore previous structure packing for 32-bit Windows + */ +#if defined(_MSC_VER) && defined(_M_IX86) +#pragma pack(pop) +#endif + +/* Values of the flags bitfield */ +/** CILK_FRAME_STOLEN is set if the frame has ever been stolen. */ +#define CILK_FRAME_STOLEN 0x01 + +/** + * CILK_FRAME_UNSYNCHED is set if the frame has been stolen and + * is has not yet executed _Cilk_sync. It is technically a misnomer in that a + * frame can have this flag set even if all children have returned. + */ +#define CILK_FRAME_UNSYNCHED 0x02 + +/** + * Is this frame detached (spawned)? If so the runtime needs + * to undo-detach in the slow path epilogue. + */ +#define CILK_FRAME_DETACHED 0x04 + +/** + * CILK_FRAME_EXCEPTION_PROBED is set if the frame has been probed in the + * exception handler first pass + */ +#define CILK_FRAME_EXCEPTION_PROBED 0x08 + +/** Is this frame receiving an exception after sync? */ +#define CILK_FRAME_EXCEPTING 0x10 + +/** + * Is the pedigree unsynched? That is, has a synch occurred that is not + * yet represented in the pedigree? + */ +#define CILK_FRAME_SF_PEDIGREE_UNSYNCHED 0x20 + +/** Is this the last (oldest) Cilk frame? */ +#define CILK_FRAME_LAST 0x80 + +/** + * Is this frame in the epilogue, or more generally after the last + * sync when it can no longer do any Cilk operations? + */ +#define CILK_FRAME_EXITING 0x0100 + +/** Is this frame suspended? (used for debugging) */ +#define CILK_FRAME_SUSPENDED 0x8000 + +/** Used by Windows exception handling to indicate that __cilkrts_leave_frame should do nothing */ +#define CILK_FRAME_UNWINDING 0x10000 + +/* + * The low 24-bits of the 'flags' field are the flags, proper. The high 8-bits + * are the version number. + */ + +/** ABI version left shifted to the high byte */ +#define CILK_FRAME_VERSION (__CILKRTS_ABI_VERSION << 24) + +/** Mask for the flags field to isolate the version bits */ +#define CILK_FRAME_VERSION_MASK 0xFF000000 + +/** Mask for the flags field to isolate the flag bits */ +#define CILK_FRAME_FLAGS_MASK 0x00FFFFFF + +/** Convenience macro to provide access the version portion of the flags field */ +#define CILK_FRAME_VERSION_VALUE(_flags) (((_flags) & CILK_FRAME_VERSION_MASK) >> 24) + +/** Any undefined bits are reserved and must be zero ("MBZ" = "Must Be Zero") */ +#define CILK_FRAME_MBZ (~ (CILK_FRAME_STOLEN | \ + CILK_FRAME_UNSYNCHED | \ + CILK_FRAME_DETACHED | \ + CILK_FRAME_EXCEPTION_PROBED | \ + CILK_FRAME_EXCEPTING | \ + CILK_FRAME_SF_PEDIGREE_UNSYNCHED | \ + CILK_FRAME_LAST | \ + CILK_FRAME_EXITING | \ + CILK_FRAME_SUSPENDED | \ + CILK_FRAME_UNWINDING | \ + CILK_FRAME_VERSION_MASK)) + +__CILKRTS_BEGIN_EXTERN_C + +/** + * Call __cilkrts_enter_frame to initialize an ABI 0 frame descriptor. + * Initialize the frame descriptor before spawn or detach. A function that + * conditionally does Cilk operations need not initialize the frame descriptor + * in a code path that never uses it. + * + * @param sf The __cilkrts_stack_frame that is to be initialized. + */ +CILK_ABI(void) __cilkrts_enter_frame(__cilkrts_stack_frame* sf); + +/** + * Call __cilkrts_enter_frame to initialize an ABI 1 frame descriptor. + * Initialize the frame descriptor before spawn or detach. A function that + * conditionally does Cilk operations need not initialize the frame descriptor + * in a code path that never uses it. + * + * @param sf The __cilkrts_stack_frame that is to be initialized. + */ +CILK_ABI(void) __cilkrts_enter_frame_1(__cilkrts_stack_frame* sf); + +/** + * __cilkrts_enter_frame_fast is the same as __cilkrts_enter_frame, except it + * assumes that the thread has already been bound to a worker. + * + * @param sf The __cilkrts_stack_frame that is to be initialized. + */ +CILK_ABI(void) __cilkrts_enter_frame_fast(__cilkrts_stack_frame *sf); + +/** + * __cilkrts_enter_frame_fast_1 is the same as __cilkrts_enter_frame_1, + * except it assumes that the thread has already been bound to a worker. + * + * @param sf The __cilkrts_stack_frame that is to be initialized. + */ +CILK_ABI(void) __cilkrts_enter_frame_fast_1(__cilkrts_stack_frame *sf); + +/** + * Call leave_frame before leaving a frame, after sync. This function + * returns except in a spawn wrapper where the parent has been stolen. + * + * @param sf The __cilkrts_stack_frame that is to be left. + */ +CILK_ABI(void) __cilkrts_leave_frame(__cilkrts_stack_frame *sf); + +/** + * Wait for any spawned children of this function to complete before + * continuing. This function will only return when the join counter + * has gone to 0. Other workers will re-enter the scheduling loop to + * attempt to steal additional work. + * + * @param sf The __cilkrts_stack_frame that is to be synched. + */ +CILK_ABI(void) __cilkrts_sync(__cilkrts_stack_frame *sf); + +/** + * Called when an exception is escaping a spawn * wrapper. + * The stack frame's except_data field is the C++ runtime + * exception object. If NULL (temporary workaround) the + * currently caught exception should be rethrown. If this + * function returns normal exit functions must be called; + * undo-detach will have been done. + * + * @param sf The __cilkrts_stack_frame for the function that + * is raising an exception. + */ +CILK_ABI_THROWS(void) + __cilkrts_return_exception(__cilkrts_stack_frame *sf); + +/** + * Called to re-raise an exception. + * + * @param sf The __cilkrts_stack_frame for the function that + * is raising an exception. + */ +CILK_ABI_THROWS(void) __cilkrts_rethrow(__cilkrts_stack_frame *sf); + +/** + * Called at the beginning of a spawning function to get the worker + * that this function is running on. This worker will be used to + * initialize the __cilkrts_stack_frame. + * + * @return The __cilkrts_worker that the function is running on. + * @return NULL if this thread is not yet bound to a worker. + */ +CILK_ABI(__cilkrts_worker_ptr) __cilkrts_get_tls_worker(void); + +/** + * Similar to __cilkrts_get_tls_worker, but assumes that TLS has been + * initialized. + * + * @return The __cilkrts_worker that the function is running on. + * @return NULL if this thread is not yet bound to a worker. + */ +CILK_ABI(__cilkrts_worker_ptr) __cilkrts_get_tls_worker_fast(void); + +/** + * Binds a thread to the runtime by associating a __cilkrts_worker with + * it. Called if __cilkrts_get_tls_worker returns NULL. This function will + * initialize the runtime the first time it is called. + * + * This function is versioned by the ABI version number. The runtime + * will export all previous versions. This prevents using an application + * built with a newer compiler against an old runtime. + * + * @return The __cilkrts_worker bound to the thread the function is running + * on. + */ +CILK_ABI(__cilkrts_worker_ptr) __cilkrts_bind_thread_1(void); + +typedef uint32_t cilk32_t; /**< 32-bit unsigned type for cilk_for loop indicies */ + +typedef uint64_t cilk64_t; /**< 64-bit unsigned type for cilk_for loop indicies */ + +/** + * Signature for the lambda function generated for the body of a cilk_for loop + * which uses 32-bit indicies + */ +typedef void (*__cilk_abi_f32_t)(void *data, cilk32_t low, cilk32_t high); + +/** + * Signature for the lambda function generated for the body of a cilk_for lop + * which uses 64-bit indicies + */ +typedef void (*__cilk_abi_f64_t)(void *data, cilk64_t low, cilk64_t high); + +/** + * @brief cilk_for implementation for 32-bit indexes. + * + * @param body The lambda function for the body of the cilk_for. The lambda + * function will be called to execute each grain of work. + * @param data Data passed by the compiler into the lambda function. Provides + * access to data outside the cilk_for body. + * @param count Number of steps in the loop. + * @param grain This parameter allows the compiler to pass a value from a + * \#pragam(grainsize) statement to allow the user to control the grainsize. If + * there isn't a \#pragma(grainsize) immediately preceeding cilk_for loop, Pass + * 0 to specify that the runtime should calculate the grainsize using its own + * hueristicts. + */ +CILK_ABI_THROWS(void) __cilkrts_cilk_for_32(__cilk_abi_f32_t body, + void *data, + cilk32_t count, + int grain); + +/** + * @brief cilk_for implementation for 64-bit indexes. + * + * @copydetails __cilkrts_cilk_for_32 + */ +CILK_ABI_THROWS(void) __cilkrts_cilk_for_64(__cilk_abi_f64_t body, + void *data, + cilk64_t count, + int grain); + +/** + * @brief Allocate memory for variable length arrays. If the frame is + * sync'd, the memory will be allocated on the stack, otherwise it will + * be allocated from the heap. + * + * @param sf The __cilkrts_stack_frame for the function allocating the + * memory. + * @param size The number of bytes requested. + * @param distance_from_sp_to_alloca_area ?. + * @param align Alignment required. Always >= minimum stack alignment, + * >= ptr_size, and always a power of 2. + * @param needs_tag Non-zero if the pointer being returned needs to be + * tagged + * + * @return The address of the memory block allocated. + */ + +CILK_ABI(__cilkrts_void_ptr) +__cilkrts_stack_alloc(__cilkrts_stack_frame *sf, + size_t size, + size_t distance_from_sp_to_alloca_area, + uint32_t align, + uint32_t needs_tag); + +/** + * @brief Free memory allocated by _cilkrts_stack_alloc() for variable length + * arrays. + * + * @param sf The __cilkrts_stack_frame for the function allocating the + * memory. + * @param p Pointer to the memory block to be freed. + * @param size The number of bytes requested. + * @param distance_from_sp_to_alloca_area ?. + * @param align Alignment required. Always >= minimum stack alignment, + * >= ptr_size, and always a power of 2. + * @param know_from_stack Non-zero if the pointer is known to have been + * allocated on the stack and has no tag. + */ +CILK_ABI(void) +__cilkrts_stack_free(__cilkrts_stack_frame *sf, + void *p, + size_t size, + size_t distance_from_sp_to_alloca_area, + uint32_t align, + uint32_t known_from_stack); + +/** + * @brief System-dependent code to save floating point control information + * to an ABI 1 or higher @c __cilkrts_stack_frame. If possible (and necessary) + * the code to save the floating point control information should be inlined. + * + * Note that this function does *not* save the current floating point + * registers. It saves the floating point control words that control + * precision and rounding and stuff like that. + * + * This function will be a noop for architectures that don't have warts + * like the floating point control words, or where the information is + * already being saved by the setjmp. + * + * @param sf @c __cilkrts_stack_frame for the frame we're saving the + * floating point control information in. + */ +CILK_ABI(void) +__cilkrts_save_fp_ctrl_state(__cilkrts_stack_frame *sf); + +__CILKRTS_END_EXTERN_C +#endif /* include guard */ diff --git a/libcilkrts/include/internal/cilk_fake.h b/libcilkrts/include/internal/cilk_fake.h new file mode 100644 index 00000000000..2386dd6bffa --- /dev/null +++ b/libcilkrts/include/internal/cilk_fake.h @@ -0,0 +1,477 @@ +/* cilk_fake.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2011-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** + * @file cilk_fake.h + * + * @brief Macros to simulate a compiled Cilk program. + * + * Used carefully, these macros can be used to create a Cilk program with a + * non-Cilk compiler by manually inserting the code necessary for interacting + * with the Cilk runtime library. They are not intended to be pretty (you + * wouldn't want to write a whole program using these macros), but they are + * useful for experiments. They also work well as an illustration of what the + * compiler generates. + * + * Details of the mechanisms used in these macros are described in + * design-notes/CilkPlusABI.docx + * + * Example 1: fib in C++ + * --------------------- + * + * #include <internal/cilk_fake.h> + * + * int fib(int n) + * { + * CILK_FAKE_PROLOG(); + * + * if (n < 2) + * return n; + * + * int a, b; + * CILK_FAKE_SPAWN_R(a, fib(n - 1)); + * b = fib(n - 2); + * CILK_FAKE_SYNC(); + * + * return a + b; + * } + * + * + * Example 2: fib in C + * ------------------- + * + * #include <internal/cilk_fake.h> + * + * int fib(int n); + * + * void fib_spawn_helper(__cilkrts_stack_frame* parent_sf, int* a, int n) + * { + * CILK_FAKE_SPAWN_HELPER_PROLOG(*parent_sf); + * *a = fib(n - 1); + * CILK_FAKE_SPAWN_HELPER_EPILOG(); + * } + * + * int fib(int n) + * { + * CILK_FAKE_PROLOG(); + * + * if (n < 2) + * return n; + * + * int a, b; + * CILK_FAKE_CALL_SPAWN_HELPER(fib_spawn_helper(&__cilk_sf, &a, n)); + * b = fib(n - 2); + * CILK_FAKE_SYNC(); + * + * CILK_FAKE_EPILOG(); + * return a + b; + * } + */ + +#ifndef INCLUDED_CILK_FAKE_DOT_H +#define INCLUDED_CILK_FAKE_DOT_H + +// This header implements ABI version 1. If __CILKRTS_ABI_VERSION is already +// defined but is less than 1, then the data structures in <internal/abi.h> +// will not match the expectations of facilities in this header. Therefore, +// for successful compilation, __CILKRTS_ABI_VERSION must either be not +// defined, or defined to be 1 or greater. +#ifndef __CILKRTS_ABI_VERSION + // ABI version was not specified. Set it to 1. +# define __CILKRTS_ABI_VERSION 1 +#elif __CILKRTS_ABI_VERSION < 1 + // ABI version was specified but was too old. Fail compilation. +# error cilk_fake.h requirs an ABI version of 1 or greater +#endif + +#include <internal/abi.h> + +// alloca is defined in malloc.h on Windows, alloca.h on Linux +#ifndef _MSC_VER +#include <alloca.h> +#else +#include <malloc.h> +// Define offsetof +#include <stddef.h> +#endif + +// Allows use of a different version that the one defined in abi.h +#define CILK_FAKE_VERSION_FLAG (__CILKRTS_ABI_VERSION << 24) + +/* Initialize frame. To be called when worker is known */ +__CILKRTS_INLINE void __cilk_fake_enter_frame_fast(__cilkrts_stack_frame *sf, + __cilkrts_worker *w) +{ + sf->call_parent = w->current_stack_frame; + sf->worker = w; + sf->flags = CILK_FAKE_VERSION_FLAG; + w->current_stack_frame = sf; +} + +/* Initialize frame. To be called when worker is not known */ +__CILKRTS_INLINE void __cilk_fake_enter_frame(__cilkrts_stack_frame *sf) +{ + __cilkrts_worker* w = __cilkrts_get_tls_worker(); + uint32_t last_flag = 0; + if (! w) { + w = __cilkrts_bind_thread_1(); + last_flag = CILK_FRAME_LAST; + } + __cilk_fake_enter_frame_fast(sf, w); + sf->flags |= last_flag; +} + +/* Initialize frame. To be called within the spawn helper */ +__CILKRTS_INLINE void __cilk_fake_helper_enter_frame( + __cilkrts_stack_frame *sf, + __cilkrts_stack_frame *parent_sf) +{ + sf->worker = 0; + sf->call_parent = parent_sf; +} + +/* Called from the spawn helper to push the parent continuation on the task + * deque so that it can be stolen. + */ +__CILKRTS_INLINE void __cilk_fake_detach(__cilkrts_stack_frame *sf) +{ + /* Initialize spawn helper frame. + * call_parent was saved in __cilk_fake_helper_enter_frame */ + __cilkrts_stack_frame *parent = sf->call_parent; + __cilkrts_worker *w = parent->worker; + __cilk_fake_enter_frame_fast(sf, w); + + /* Append a node to the pedigree */ + sf->spawn_helper_pedigree = w->pedigree; + parent->parent_pedigree = w->pedigree; + w->pedigree.rank = 0; + w->pedigree.parent = &sf->spawn_helper_pedigree; + + /* Push parent onto the task deque */ + __cilkrts_stack_frame *volatile *tail = w->tail; + *tail++ = sf->call_parent; + /* The stores must be separated by a store fence (noop on x86) + * or the second store is a release (st8.rel on Itanium) */ + w->tail = tail; + sf->flags |= CILK_FRAME_DETACHED; +} + +/* This variable is used in CILK_FAKE_FORCE_FRAME_PTR(), below */ +static int __cilk_fake_dummy = 8; + +/* The following macro is used to force the compiler into generating a frame + * pointer. We never change the value of __cilk_fake_dummy, so the alloca() + * is never called, but we need the 'if' statement and the __cilk_fake_dummy + * variable so that the compiler does not attempt to optimize it away. + */ +#define CILK_FAKE_FORCE_FRAME_PTR(sf) do { \ + if (__builtin_expect(1 & __cilk_fake_dummy, 0)) \ + (sf).worker = (__cilkrts_worker*) alloca(__cilk_fake_dummy); \ +} while (0) + +#ifndef CILK_FAKE_NO_SHRINKWRAP + /* "shrink-wrap" optimization enabled. Do not initialize frame on entry, + * except to clear worker pointer. Instead, defer initialization until + * the first spawn. + */ +# define CILK_FAKE_INITIAL_ENTER_FRAME(sf) ((void) ((sf).worker = 0)) +# define CILK_FAKE_DEFERRED_ENTER_FRAME(sf) do { \ + if (! (sf).worker) __cilk_fake_enter_frame(&(sf)); \ + } while (0) +#else + /* "shrink-wrap" optimization disabled. Initialize frame immediately on + * entry. Do not initialize frame on spawn. + */ +# define CILK_FAKE_INITIAL_ENTER_FRAME(sf) \ + __cilk_fake_enter_frame(&(sf)) +# define CILK_FAKE_DEFERRED_ENTER_FRAME(sf) ((void) &(sf)) +#endif + +/* Prologue of a spawning function. Declares and initializes the stack + * frame. + */ +#define CILK_FAKE_PROLOG() \ + __cilk_fake_stack_frame __cilk_sf; \ + CILK_FAKE_FORCE_FRAME_PTR(__cilk_sf); \ + CILK_FAKE_INITIAL_ENTER_FRAME(__cilk_sf) + +/* Prologue of a spawning function where the current worker is already known. + * Declares and initializes the stack frame without looking up the worker from + * TLS. + */ +#define CILK_FAKE_PROLOG_FAST(w) \ + __cilk_fake_stack_frame __cilk_sf; \ + CILK_FAKE_FORCE_FRAME_PTR(__cilk_sf); \ + __cilk_fake_enter_frame_fast(&__cilk_sf, (w)) + +/* Simulate a cilk_sync */ +#define CILK_FAKE_SYNC() CILK_FAKE_SYNC_IMP(__cilk_sf) + +/* Epilog at the end of a spawning function. Does a sync and calls the + * runtime for leaving the frame. + */ +#ifdef __cplusplus + // Epilogue is run automatically by __cilk_fake_stack_frame destructor. +# define CILK_FAKE_EPILOG() ((void) __cilk_sf) +#else +# define CILK_FAKE_EPILOG() CILK_FAKE_CLEANUP_FRAME(__cilk_sf) +#endif // C + +/* Implementation of spawning function epilog. See CILK_FAKE_EPILOG macro and + * __cilk_fake_stack_frame destructor body. + */ +#define CILK_FAKE_CLEANUP_FRAME(sf) do { \ + if (! (sf).worker) break; \ + CILK_FAKE_SYNC_IMP(sf); \ + CILK_FAKE_POP_FRAME(sf); \ + if ((sf).flags != CILK_FAKE_VERSION_FLAG) \ + __cilkrts_leave_frame(&(sf)); \ +} while (0) + +/* Implementation of CILK_FAKE_SYNC with sf argument */ +#define CILK_FAKE_SYNC_IMP(sf) do { \ + if (__builtin_expect((sf).flags & CILK_FRAME_UNSYNCHED, 0)) { \ + (sf).parent_pedigree = (sf).worker->pedigree; \ + CILK_FAKE_SAVE_FP(sf); \ + if (! CILK_SETJMP((sf).ctx)) \ + __cilkrts_sync(&(sf)); \ + } \ + ++(sf).worker->pedigree.rank; \ +} while (0) + +/* Save the floating-point control registers. + * The definition of CILK_FAKE_SAVE_FP is compiler specific (and + * architecture specific on Windows) + */ +#ifdef _MSC_VER +# define MXCSR_OFFSET offsetof(struct __cilkrts_stack_frame, mxcsr) +# define FPCSR_OFFSET offsetof(struct __cilkrts_stack_frame, fpcsr) +# if defined(_M_IX86) +/* Windows x86 */ +# define CILK_FAKE_SAVE_FP(sf) do { \ + __asm \ + { \ + mov eax, sf \ + stmxcsr [eax+MXCSR_OFFSET] \ + fnstcw [eax+FPCSR_OFFSET] \ + } \ + } while (0) +# elif defined(_M_X64) +/* Windows Intel64 - Not needed - saved by setjmp call */ +# define CILK_FAKE_SAVE_FP(sf) ((void) sf) +# else +# error "Unknown architecture" +# endif /* Microsoft architecture specifics */ +#else +/* Non-Windows */ +# define CILK_FAKE_SAVE_FP(sf) do { \ + __asm__ ( "stmxcsr %0\n\t" \ + "fnstcw %1" : : "m" ((sf).mxcsr), "m" ((sf).fpcsr)); \ + } while (0) +#endif + +/* Call the spawn helper as part of a fake spawn */ +#define CILK_FAKE_CALL_SPAWN_HELPER(helper) do { \ + CILK_FAKE_DEFERRED_ENTER_FRAME(__cilk_sf); \ + CILK_FAKE_SAVE_FP(__cilk_sf); \ + if (__builtin_expect(! CILK_SETJMP(__cilk_sf.ctx), 1)) { \ + helper; \ + } \ +} while (0) + +/* Body of a spawn helper function. In addition to the worker and the + * expression to spawn, pass it any number of statements to be executed before + * detaching. + */ +#define CILK_FAKE_SPAWN_HELPER_BODY(parent_sf, expr, ...) \ + CILK_FAKE_SPAWN_HELPER_PROLOG(parent_sf); \ + __VA_ARGS__; \ + __cilk_fake_detach(&__cilk_sf); \ + expr; \ + CILK_FAKE_SPAWN_HELPER_EPILOG() + +/* Prolog for a spawn helper function */ +#define CILK_FAKE_SPAWN_HELPER_PROLOG(parent_sf) \ + __cilk_fake_spawn_helper_stack_frame __cilk_sf; \ + __cilk_fake_helper_enter_frame(&__cilk_sf, &(parent_sf)) + +/* Implementation of spawn helper epilog. See CILK_FAKE_SPAWN_HELPER_EPILOG + * and the __cilk_fake_spawn_helper_frame destructor. + */ +#define CILK_FAKE_SPAWN_HELPER_CLEANUP_FRAME(sf) do { \ + if (! (sf).worker) break; \ + CILK_FAKE_POP_FRAME(sf); \ + __cilkrts_leave_frame(&(sf)); \ +} while (0) + +/* Epilog to execute at the end of a spawn helper */ +#ifdef __cplusplus + // Epilog handled by __cilk_fake_spawn_helper_stack_frame destructor +# define CILK_FAKE_SPAWN_HELPER_EPILOG() ((void) __cilk_sf) +#else +# define CILK_FAKE_SPAWN_HELPER_EPILOG() \ + CILK_FAKE_SPAWN_HELPER_CLEANUP_FRAME(__cilk_sf) +#endif + +/* Pop the current frame off of the call chain */ +#define CILK_FAKE_POP_FRAME(sf) do { \ + (sf).worker->current_stack_frame = (sf).call_parent; \ + (sf).call_parent = 0; \ +} while (0) + +#ifdef _WIN32 +/* define macros for synching functions before allowing them to propagate. */ +# define CILK_FAKE_EXCEPT_BEGIN \ + if (0 == CILK_SETJMP(__cilk_sf.except_ctx)) { + +# define CILK_FAKE_EXCEPT_END \ + } else { \ + assert((__cilk_sf.flags & (CILK_FRAME_UNSYNCHED|CILK_FRAME_EXCEPTING))\ + == CILK_FRAME_EXCEPTING); \ + __cilkrts_rethrow(&__cilk_sf); \ + exit(0); \ + } +#else +# define CILK_EXCEPT_BEGIN { +# define CILK_EXCEPT_END } +#endif + +#ifdef __cplusplus +// The following definitions depend on C++ features. + +// Wrap a functor (probably a lambda), so that a call to it cannot be +// inlined. +template <typename F> +class __cilk_fake_noinline_wrapper +{ + F&& m_fn; +public: + __cilk_fake_noinline_wrapper(F&& fn) : m_fn(static_cast<F&&>(fn)) { } + +#ifdef _WIN32 + __declspec(noinline) void operator()(__cilkrts_stack_frame *sf); +#else + void operator()(__cilkrts_stack_frame *sf) __attribute__((noinline)); +#endif + +}; + +template <typename F> +void __cilk_fake_noinline_wrapper<F>::operator()(__cilkrts_stack_frame *sf) +{ + m_fn(sf); +} + +template <typename F> +inline +__cilk_fake_noinline_wrapper<F> __cilk_fake_make_noinline_wrapper(F&& fn) +{ + return __cilk_fake_noinline_wrapper<F>(static_cast<F&&>(fn)); +} + +// Simulate "_Cilk_spawn expr", where expr must be a function call. +// +// Note: this macro does not correctly construct function arguments. +// According to the ABI specification, function arguments should be evaluated +// before the detach and destroyed after the detach. This macro both +// evaluates and destroys them after the detach. This means that if any part +// of the function argument expression depends on a value that is modified in +// the continuation of the spawn, race will occur between the continuation and +// the argument evaluation. +// +// To work around this problem, this macro accepts an arbitrary list of +// declarations and statements (separated by semicolons) that are evaluated +// before the detach. Thus, to simulate: +// +// _Cilk_spawn f(expr); +// +// one would write: +// +// CILK_FAKE_SPAWN(f(arg), auto arg = expr); +// +// Despite appearing in the reverse order, the 'arg' variable is created and +// initialized before the detach and the call to f(arg) occurs after the +// detach. +#define CILK_FAKE_SPAWN(expr, ...) \ + CILK_FAKE_CALL_SPAWN_HELPER( \ + CILK_FAKE_SPAWN_HELPER(expr, __VA_ARGS__)(&__cilk_sf)) + +// Simulate "ret = cilk_spawn expr". See CILK_FAKE_SPAWN for constraints. +#define CILK_FAKE_SPAWN_R(ret, expr, ...) \ + CILK_FAKE_SPAWN(((ret) = (expr)), __VA_ARGS__) + +// Create a spawn helper as a C++11 lambda function. In addition to the +// expression to spawn, this macro takes a any number of statements to be +// executed before detaching. +#define CILK_FAKE_SPAWN_HELPER(expr, ...) \ + __cilk_fake_make_noinline_wrapper([&](__cilkrts_stack_frame *parent_sf) { \ + CILK_FAKE_SPAWN_HELPER_BODY(*parent_sf, expr, __VA_ARGS__); \ + }) + +// C++ version of a __cilkrts_stack_frame for a spawning function. +// This struct is identical to __cilkrts_stack_frame except that the +// destructor automatically does frame cleanup. +struct __cilk_fake_stack_frame : __cilkrts_stack_frame +{ + // Extension of __cilkrts_stack_frame with constructor and destructor + __cilk_fake_stack_frame() { } + __forceinline ~__cilk_fake_stack_frame() { + CILK_FAKE_CLEANUP_FRAME(*this); + } +}; + +// C++ version of a __cilkrts_stack_frame for a spawn helper. +// This struct is identical to __cilkrts_stack_frame except that the +// destructor automatically does frame cleanup. +struct __cilk_fake_spawn_helper_stack_frame : __cilkrts_stack_frame +{ + // Extension of __cilkrts_stack_frame with constructor and destructor + __cilk_fake_spawn_helper_stack_frame() { worker = 0; } + __forceinline ~__cilk_fake_spawn_helper_stack_frame() { + CILK_FAKE_SPAWN_HELPER_CLEANUP_FRAME(*this); + } +}; +#else +// For C, __cilk_fake_stack_frame and __cilk_fake_spawn_helper_stack_frame are +// identical to __cilkrts_stack_frame. Frame cleanup must be performed +// excplicitly (in CILK_FAKE_EPILOG and CILK_FAKE_SPAWN_HELPER_EPILOG) +typedef __cilkrts_stack_frame __cilk_fake_stack_frame; +typedef __cilkrts_stack_frame __cilk_fake_spawn_helper_stack_frame; +#endif + +#endif // ! defined(INCLUDED_CILK_FAKE_DOT_H) diff --git a/libcilkrts/include/internal/cilk_version.h b/libcilkrts/include/internal/cilk_version.h new file mode 100644 index 00000000000..f628338f7d2 --- /dev/null +++ b/libcilkrts/include/internal/cilk_version.h @@ -0,0 +1,47 @@ +// cilk_version.h +// +// @copyright +// Copyright (C) 2009-2013, Intel Corporation +// All rights reserved. +// +// @copyright +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Intel Corporation nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// @copyright +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY +// WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// DO NOT EDIT THIS FILE! +// +// It was automatically generated by cilkrts/include/internal/Makefile + +#define VERSION_MAJOR 2 +#define VERSION_MINOR 0 +#define VERSION_BUILD 3902 +#define VERSION_REV 0 +#define VERSION_STRING "2,0,3902,0" +#define VERSION_HASH "b4e38f4f7e3e" +#define VERSION_BRANCH "v14.0" +#define TBB_REV_NUMBER "" +#define VERSION_YEAR "2013" diff --git a/libcilkrts/include/internal/metacall.h b/libcilkrts/include/internal/metacall.h new file mode 100644 index 00000000000..886f49f9f83 --- /dev/null +++ b/libcilkrts/include/internal/metacall.h @@ -0,0 +1,99 @@ +// -*- C++ -*- + +/* + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + * + * metacall.h + * + * This is an internal header file defining part of the metacall + * interface used by Cilkscreen. It is not a stable API and is + * subject to change without notice. + */ + +// Provides the enum of metacall kinds. This is used by Cilkscreen and the +// runtime, and will probably be used by any future ptools. + +#pragma once + +/////////////////////////////////////////////////////////////////////////////// + +enum +{ + // Notify Cilkscreen to stop/start instrumenting code + HYPER_DISABLE_INSTRUMENTATION = 0, + HYPER_ENABLE_INSTRUMENTATION = 1, + + // Write 0 in *(char *)arg if the p-tool is sequential. The Cilk runtime + // system invokes this metacall to know whether to spawn worker threads. + HYPER_ZERO_IF_SEQUENTIAL_PTOOL = 2, + + // Write 0 in *(char *)arg if the runtime must force reducers to + // call the reduce() method even if no actual stealing occurs. + HYPER_ZERO_IF_FORCE_REDUCE = 3, + + // Inform cilkscreen about the current stack pointer. + HYPER_ESTABLISH_C_STACK = 4, + + // Inform Cilkscreen about the current worker + HYPER_ESTABLISH_WORKER = 5, + + // Tell tools to ignore a block of memory. Parameter is a 2 element + // array: void *block[2] = {_begin, _end}; _end is 1 beyond the end + // of the block to be ignored. Essentially, if p is a pointer to an + // array, _begin = &p[0], _end = &p[max] + HYPER_IGNORE_MEMORY_BLOCK = 6 + + // If you add metacalls here, remember to update BOTH workspan.cpp AND + // cilkscreen-common.cpp! +}; + +typedef struct +{ + unsigned int tool; // Specifies tool metacall is for + // (eg. system=0, cilkscreen=1, cilkview=2). + // All tools should understand system codes. + // Tools should ignore all other codes, except + // their own. + + unsigned int code; // Tool-specific code specifies what to do and how to + // interpret data + + void *data; +} metacall_data_t; + +#define METACALL_TOOL_SYSTEM 0 + +/////////////////////////////////////////////////////////////////////////////// diff --git a/libcilkrts/include/internal/rev.mk b/libcilkrts/include/internal/rev.mk new file mode 100644 index 00000000000..f65ad6d57d0 --- /dev/null +++ b/libcilkrts/include/internal/rev.mk @@ -0,0 +1,41 @@ +######################################################################### +# +# @copyright +# Copyright (C) 2011-2013, Intel Corporation +# All rights reserved. +# +# @copyright +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# @copyright +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY +# WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +########################################################################### + +# DO NOT EDIT THIS FILE! +# +# It was automatically generated by cilkrts/include/internal/Makefile + +CILK_REVISION = 3902 diff --git a/libcilkrts/mk/cilk-version.mk b/libcilkrts/mk/cilk-version.mk new file mode 100644 index 00000000000..76f3f4ee38e --- /dev/null +++ b/libcilkrts/mk/cilk-version.mk @@ -0,0 +1,61 @@ +######################################################################### +# +# @copyright +# Copyright (C) 2009-2013, Intel Corporation +# All rights reserved. +# +# @copyright +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# @copyright +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY +# WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +########################################################################### +# cilk-version.mk +# +# The one place we look up information from the code management system +# +# Note that the build number is *only* valid on the build machines + +ifeq ($(wildcard $(TOP)/../.hg),) + # If this is the open source release, there is no Mercurial repository, + # so set some reasonable defaults. + CILK_VERSION_MAJOR := 2 + CILK_VERSION_MINOR := 0 + CILK_VERSION_BUILD := 1 + CILK_VERSION_REV := 0 + + CILK_VERSION_HASH := 000000000000 + CILK_VERSION_BRANCH := oss +else + CILK_VERSION_MAJOR := 2 + CILK_VERSION_MINOR := 0 + CILK_VERSION_BUILD := $(firstword $(subst +, ,$(shell hg id --num))) + CILK_VERSION_REV := 0 + + CILK_VERSION_HASH := $(firstword $(subst +, ,$(shell hg id --id))) + CILK_VERSION_BRANCH := $(shell hg id --branch) +endif + diff --git a/libcilkrts/runtime/acknowledgements.dox b/libcilkrts/runtime/acknowledgements.dox new file mode 100644 index 00000000000..79b5d876f33 --- /dev/null +++ b/libcilkrts/runtime/acknowledgements.dox @@ -0,0 +1,51 @@ +/* acknowledgements.dox
+ *
+ *************************************************************************
+ *
+ * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/
+
+/*
+ * This file contains acknowledgements of community contributions to the
+ * Cilk Plus runtime.
+ */
+
+/**
+ * @mainpage
+ *
+ * @section Acknowledgements Acknowledgements
+ *
+ * Modifications to build the Cilk Plus runtime for VxWorks provided by
+ * Brian Kuhl of Wind River.
+ */
diff --git a/libcilkrts/runtime/bug.cpp b/libcilkrts/runtime/bug.cpp new file mode 100644 index 00000000000..dbdf1fd3216 --- /dev/null +++ b/libcilkrts/runtime/bug.cpp @@ -0,0 +1,139 @@ +/* bug.cpp -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +#include "bug.h" + +#include <exception> +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#ifdef _WIN32 +# include "windows-clean.h" +# include "internal/abi.h" +# include "cilktools/cilkscreen.h" +# include <crtdbg.h> +#endif + +__CILKRTS_BEGIN_EXTERN_C + +COMMON_PORTABLE const char *const __cilkrts_assertion_failed = + "%s:%d: cilk assertion failed: %s\n"; + +COMMON_PORTABLE void __cilkrts_bug(const char *fmt,...) cilk_nothrow +{ +#if defined (_WIN32) && defined(_DEBUG) + _CRTIMP void __cdecl _wassert(__in_z const wchar_t * _Message, + __in_z const wchar_t *_File, + __in unsigned _Line); + char message[256]; + wchar_t wmessage[256]; + va_list l; + va_start(l, fmt); + _vsnprintf_s(message, 256, _TRUNCATE, fmt, l); + va_end(l); + _snwprintf_s(wmessage, 256, _TRUNCATE, _CRT_WIDE("%S"), + message); /* widen */ + + // Force asserts to go to stderr and the debugger. This isn't polite, but + // we're about to kill the app anyway and it will prevent our tests from + // hanging + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE| _CRTDBG_MODE_DEBUG); + _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + + _wassert(wmessage, _CRT_WIDE(__FILE__), __LINE__); + + // If there's a debugger attached, give it a chance to look at the failure + if (IsDebuggerPresent()) + DebugBreak(); + + abort(); +/* __asm int 3 */ +#else + /* To reduce user confusion, write all user-generated output + before the system-generated error message. */ + va_list l; + fflush(NULL); + va_start(l, fmt); + vfprintf(stderr, fmt, l); + va_end(l); + fflush(stderr); + +#ifndef _WIN32 + abort(); +#endif + +#endif + + exit(1); +} + +COMMON_PORTABLE void cilkbug_assert_no_uncaught_exception(void) +{ + bool uncaught = std::uncaught_exception(); + CILK_ASSERT(!uncaught); +} + +COMMON_SYSDEP void abort_because_rts_is_corrupted(void) +{ + __cilkrts_bug("The Cilk Plus runtime system detected a corruption " + "in its data structures. This is most likely caused " + "by an application bug. Aborting execution.\n"); +} + +#ifdef WIN32 +COMMON_SYSDEP void __cilkrts_dbgprintf(const char *fmt,...) +{ + char message[2048]; + va_list l; + + // Cilkscreen shouldn't watch this + __cilkscreen_disable_checking(); + + va_start(l, fmt); + _vsnprintf_s(message, 2048, _TRUNCATE, fmt, l); + va_end(l); + OutputDebugStringA (message); + + // Re-enable Cilkscreen + __cilkscreen_enable_checking(); +} +#endif + +__CILKRTS_END_EXTERN_C + +/* End bug.cpp */ diff --git a/libcilkrts/runtime/bug.h b/libcilkrts/runtime/bug.h new file mode 100644 index 00000000000..bb18913787d --- /dev/null +++ b/libcilkrts/runtime/bug.h @@ -0,0 +1,141 @@ +/* bug.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** + * @file bug.h + * + * @brief Support for reporting bugs and debugging. + */ + +#ifndef INCLUDED_BUG_DOT_H +#define INCLUDED_BUG_DOT_H + +#include "rts-common.h" +#include <cilk/common.h> + +__CILKRTS_BEGIN_EXTERN_C + +/** + * Flush all output, write error message to stderr and abort the execution. + * On Windows the error is also written to the debugger. + * + * @param fmt printf-style format string. Any remaining parameters will be + * be interpreted based on the format string text. + */ +COMMON_PORTABLE NORETURN __cilkrts_bug(const char *fmt,...) cilk_nothrow; + +#ifndef CILK_ASSERT + +/** Standard text for failed assertion */ +COMMON_PORTABLE extern const char *const __cilkrts_assertion_failed; + +/** + * Macro to assert an invariant that must be true. If the statement evalutes + * to false, __cilkrts_bug will be called to report the failure and terminate + * the application. + */ +#define CILK_ASSERT(ex) \ + (__builtin_expect((ex) != 0, 1) ? (void)0 : \ + __cilkrts_bug(__cilkrts_assertion_failed, __FILE__, __LINE__, #ex)) + +#define CILK_ASSERT_MSG(ex, msg) \ + (__builtin_expect((ex) != 0, 1) ? (void)0 : \ + __cilkrts_bug(__cilkrts_assertion_failed, __FILE__, __LINE__, \ + #ex "\n " msg)) +#endif // CILK_ASSERT + +/** + * Assert that there is no uncaught exception. + * + * Not valid on Windows or Android. + * + * On Android, calling std::uncaught_exception with the stlport library causes + * a seg fault. Since we're not supporting exceptions there at this point, + * just don't do the check. It works with the GNU STL library, but that's + * GPL V3 licensed. + */ +COMMON_PORTABLE void cilkbug_assert_no_uncaught_exception(void); +#if defined(_WIN32) || defined(ANDROID) +# define CILKBUG_ASSERT_NO_UNCAUGHT_EXCEPTION() +#else +# define CILKBUG_ASSERT_NO_UNCAUGHT_EXCEPTION() \ + cilkbug_assert_no_uncaught_exception() +#endif + + +/** + * Call __cilkrts_bug with a standard message that the runtime state is + * corrupted and the application is being terminated. + */ +COMMON_SYSDEP void abort_because_rts_is_corrupted(void); + +// Debugging aids +#ifndef _DEBUG +# define DBGPRINTF(_fmt, ...) +#elif defined(_WIN32) + +/** + * Write debugging output. On windows this is written to the debugger. + * + * @param fmt printf-style format string. Any remaining parameters will be + * be interpreted based on the format string text. + */ +COMMON_SYSDEP void __cilkrts_dbgprintf(const char *fmt,...) cilk_nothrow; + +/** + * Macro to write debugging output which will be elided if this is not a + * debug build. The macro is currently always elided on non-Windows builds. + * + * @param _fmt printf-style format string. Any remaining parameters will be + * be interpreted based on the format string text. + */ +# define DBGPRINTF(_fmt, ...) __cilkrts_dbgprintf(_fmt, __VA_ARGS__) + +#else /* if _DEBUG && !_WIN32 */ + /* Non-Windows debug logging. Someday we should make GetCurrentFiber() + * and GetWorkerFiber() do something. + */ +# include <stdio.h> + __CILKRTS_INLINE void* GetCurrentFiber() { return 0; } + __CILKRTS_INLINE void* GetWorkerFiber(__cilkrts_worker* w) { return 0; } +# define DBGPRINTF(_fmt, ...) fprintf(stderr, _fmt, __VA_ARGS__) +#endif // _DEBUG + +__CILKRTS_END_EXTERN_C + +#endif // ! defined(INCLUDED_BUG_DOT_H) diff --git a/libcilkrts/runtime/c_reducers.c b/libcilkrts/runtime/c_reducers.c new file mode 100644 index 00000000000..52615e93f43 --- /dev/null +++ b/libcilkrts/runtime/c_reducers.c @@ -0,0 +1,57 @@ +/* c_reducers.c -*-C-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2010-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + +/* Implementation of C reducers */ + +// Disable warning about integer conversions losing significant bits. +// The code is correct as is. +#ifdef __INTEL_COMPILER +#pragma warning(disable:2259) +#endif + +#define CILK_C_DEFINE_REDUCERS + +#include <cilk/reducer_opadd.h> +#include <cilk/reducer_opand.h> +#include <cilk/reducer_opmul.h> +#include <cilk/reducer_opor.h> +#include <cilk/reducer_opxor.h> +#include <cilk/reducer_min_max.h> + +/* End reducer_opadd.c */ diff --git a/libcilkrts/runtime/cilk-abi-cilk-for.cpp b/libcilkrts/runtime/cilk-abi-cilk-for.cpp new file mode 100644 index 00000000000..4fa6dcec82a --- /dev/null +++ b/libcilkrts/runtime/cilk-abi-cilk-for.cpp @@ -0,0 +1,406 @@ +/* cilk-abi-cilk-for.cpp -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2011, 2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + +/* Implementation of cilk_for ABI. + * + * This file must be C++, not C, in order to handle C++ exceptions correctly + * from within the body of the cilk_for loop + */ + +#include "internal/abi.h" +#include "metacall_impl.h" +#include "global_state.h" + +// Icky macros to determine if we're compiled with optimization. Based on +// the declaration of __CILKRTS_ASSERT in common.h +#if defined(_WIN32) +# if defined (_DEBUG) +# define CILKRTS_OPTIMIZED 0 // Assumes /MDd is always used with /Od +# else +# define CILKRTS_OPTIMIZED 1 +# endif // defined(_DEBUG) +#else +# if defined(__OPTIMIZE__) +# define CILKRTS_OPTIMIZED 1 +# else +# define CILKRTS_OPTIMIZED 0 +# endif +#endif + +template <typename count_t> +static inline int grainsize(int req, count_t count) +{ + // A positive requested grain size comes from the user. A very high grain + // size risks losing parallelism, but the user told us what they want for + // grainsize. Who are we to argue? + if (req > 0) + return req; + + // At present, a negative requested grain size is treated the same way as + // a zero grain size, i.e., the runtime computes the actual grainsize + // using a hueristic. In the future, the compiler may give us additional + // information about the size of the cilk_for body by passing a negative + // grain size. + + // Avoid generating a zero grainsize, even for empty loops. + if (count < 1) + return 1; + + global_state_t* g = cilkg_get_global_state(); + if (g->under_ptool) + { + // Grainsize = 1, when running under PIN, and when the grainsize has + // not explicitly been set by the user. + return 1; + } + else + { + // Divide loop count by 8 times the worker count and round up. + const int Px8 = g->P * 8; + count_t n = (count + Px8 - 1) / Px8; + + // 2K should be enough to amortize the cost of the cilk_for. Any + // larger grainsize risks losing parallelism. + if (n > 2048) + return 2048; + return (int) n; // n <= 2048, so no loss of precision on cast to int + } +} + +/* + * call_cilk_for_loop_body + * + * Centralizes the code to call the loop body. The compiler should be + * inlining this code + * + * low - Low loop index we're considering in this portion of the algorithm + * high - High loop index we're considering in this portion of the algorithm + * body - lambda function for the cilk_for loop body + * data - data used by the lambda function + * w - __cilkrts_worker we're currently executing on + * loop_root_pedigree - __cilkrts_pedigree node we generated for the root of + * the cilk_for loop to flatten out the internal nodes + */ +template <typename count_t, typename F> +inline static +void call_cilk_for_loop_body(count_t low, count_t high, + F body, void *data, + __cilkrts_worker *w, + __cilkrts_pedigree *loop_root_pedigree) +{ + // Cilkscreen should not report this call in a stack trace + NOTIFY_ZC_INTRINSIC((char *)"cilkscreen_hide_call", 0); + + // The worker is only valid until the first spawn. Fetch the + // __cilkrts_stack_frame out of the worker, since it will be stable across + // steals. The sf pointer actually points to the *parent's* + // __cilkrts_stack_frame, since this function is a non-spawning function + // and therefore has no cilk stack frame of its own. + __cilkrts_stack_frame *sf = w->current_stack_frame; + + // Save the pedigree node pointed to by the worker. We'll need to restore + // that when we exit since the spawn helpers in the cilk_for call tree + // will assume that it's valid + const __cilkrts_pedigree *saved_next_pedigree_node = w->pedigree.parent; + + // Add the leaf pedigree node to the chain. The parent is the root node + // to flatten the tree regardless of the DAG branches in the cilk_for + // divide-and-conquer recursion. + // + // The rank is initialized to the low index. The user is + // expected to call __cilkrts_bump_loop_rank at the end of the cilk_for + // loop body. + __cilkrts_pedigree loop_leaf_pedigree; + + loop_leaf_pedigree.rank = (uint64_t)low; + loop_leaf_pedigree.parent = loop_root_pedigree; + + // The worker's pedigree always starts with a rank of 0 + w->pedigree.rank = 0; + w->pedigree.parent = &loop_leaf_pedigree; + + // Call the compiler generated cilk_for loop body lambda function + body(data, low, high); + + // The loop body may have included spawns, so we must refetch the worker + // from the __cilkrts_stack_frame, which is stable regardless of which + // worker we're executing on. + w = sf->worker; + + // Restore the pedigree chain. It must be valid because the spawn helpers + // generated by the cilk_for implementation will access it. + w->pedigree.parent = saved_next_pedigree_node; +} + +/* capture_spawn_arg_stack_frame + * + * Efficiently get the address of the caller's __cilkrts_stack_frame. The + * preconditons are that 'w' is the worker at the time of the call and + * 'w->current_stack_frame' points to the __cilkrts_stack_frame within the + * spawn helper. This function should be called only within the argument list + * of a function that is being spawned because that is the only situation in + * which these preconditions hold. This function returns the worker + * (unchanged) after storing the captured stack frame pointer is stored in the + * sf argument. + * + * The purpose of this function is to get the caller's stack frame in a + * context where the caller's worker is known but its stack frame is not + * necessarily initialized. The "shrink wrap" optimization delays + * initializing the contents of a spawning function's '__cilkrts_stack_frame' + * as well as the 'current_stack_frame' pointer within the worker. By calling + * this function within a spawning function's argument list, we can ensure + * that these initializations have occured but that a detach (which would + * invalidate the worker pointer in the caller) has not yet occured. Once the + * '__cilkrts_stack_frame' has been retrieved in this way, it is stable for the + * remainder of the caller's execution, and becomes an efficient way to get + * the worker (much more efficient than calling '__cilkrts_get_tls_worker()'), + * even after a spawn or sync. + */ +inline __cilkrts_worker* +capture_spawn_arg_stack_frame(__cilkrts_stack_frame* &sf, __cilkrts_worker* w) +{ + // Get current stack frame + sf = w->current_stack_frame; +#ifdef __INTEL_COMPILER +# if __INTEL_COMPILER <= 1300 && __INTEL_COMPILER_BUILD_DATE < 20130101 + // In older compilers 'w->current_stack_frame' points to the + // spawn-helper's stack frame. In newer compiler's however, it points + // directly to the pointer's stack frame. (This change was made to avoid + // having the spawn helper in the frame list when evaluating function + // arguments, thus avoiding corruption when those arguments themselves + // contain cilk_spawns.) + + // w->current_stack_frame is the spawn helper's stack frame. + // w->current_stack_frame->call_parent is the caller's stack frame. + sf = sf->call_parent; +# endif +#endif + return w; +} + +/* + * cilk_for_recursive + * + * Templatized function to implement the recursive divide-and-conquer + * algorithm that's how we implement a cilk_for. + * + * low - Low loop index we're considering in this portion of the algorithm + * high - High loop index we're considering in this portion of the algorithm + * body - lambda function for the cilk_for loop body + * data - data used by the lambda function + * grain - grain size (0 if it should be computed) + * w - __cilkrts_worker we're currently executing on + * loop_root_pedigree - __cilkrts_pedigree node we generated for the root of + * the cilk_for loop to flatten out the internal nodes + */ +template <typename count_t, typename F> +static +void cilk_for_recursive(count_t low, count_t high, + F body, void *data, int grain, + __cilkrts_worker *w, + __cilkrts_pedigree *loop_root_pedigree) +{ +tail_recurse: + // Cilkscreen should not report this call in a stack trace + // This needs to be done everytime the worker resumes + NOTIFY_ZC_INTRINSIC((char *)"cilkscreen_hide_call", 0); + + count_t count = high - low; + // Invariant: count > 0, grain >= 1 + if (count > grain) + { + // Invariant: count >= 2 + count_t mid = low + count / 2; + // The worker is valid only until the first spawn and is expensive to + // retrieve (using '__cilkrts_get_tls_worker') after the spawn. The + // '__cilkrts_stack_frame' is more stable, but isn't initialized until + // the first spawn. Thus, we want to grab the address of the + // '__cilkrts_stack_frame' after it is initialized but before the + // spawn detaches. The only place we can do that is within the + // argument list of the spawned function, hence the call to + // capture_spawn_arg_stack_frame(). + __cilkrts_stack_frame *sf; + _Cilk_spawn cilk_for_recursive(low, mid, body, data, grain, + capture_spawn_arg_stack_frame(sf, w), + loop_root_pedigree); + w = sf->worker; + low = mid; + + goto tail_recurse; + } + + // Call the cilk_for loop body lambda function passed in by the compiler to + // execute one grain + call_cilk_for_loop_body(low, high, body, data, w, loop_root_pedigree); +} + +static void noop() { } + +/* + * cilk_for_root + * + * Templatized function to implement the top level of a cilk_for loop. + * + * body - lambda function for the cilk_for loop body + * data - data used by the lambda function + * count - trip count for loop + * grain - grain size (0 if it should be computed) + */ +template <typename count_t, typename F> +static void cilk_for_root(F body, void *data, count_t count, int grain) +{ + // Cilkscreen should not report this call in a stack trace + NOTIFY_ZC_INTRINSIC((char *)"cilkscreen_hide_call", 0); + + // Pedigree computation: + // + // If the last pedigree node on entry to the _Cilk_for has value X, + // then at the start of each iteration of the loop body, the value of + // the last pedigree node should be 0, the value of the second-to-last + // node should equal the loop counter, and the value of the + // third-to-last node should be X. On return from the _Cilk_for, the + // value of the last pedigree should be incremented to X+2. The + // pedigree within the loop is thus flattened, such that the depth of + // recursion does not affect the results either inside or outside of + // the loop. Note that the pedigree after the loop exists is the same + // as if a single spawn and sync were executed within this function. + + // TBD: Since the shrink-wrap optimization was turned on in the compiler, + // it is not possible to get the current stack frame without actually + // forcing a call to bind-thread. This spurious spawn is a temporary + // stopgap until the correct intrinsics are added to give us total control + // over frame initialization. + _Cilk_spawn noop(); + + // Fetch the current worker. From that we can get the current stack frame + // which will be constant even if we're stolen + __cilkrts_worker *w = __cilkrts_get_tls_worker(); + __cilkrts_stack_frame *sf = w->current_stack_frame; + + // Decrement the rank by one to undo the pedigree change from the + // _Cilk_spawn + --w->pedigree.rank; + + // Save the current worker pedigree into loop_root_pedigree, which will be + // the root node for our flattened pedigree. + __cilkrts_pedigree loop_root_pedigree = w->pedigree; + + // Don't splice the loop_root node in yet. It will be done when we + // call the loop body lambda function +// w->pedigree.rank = 0; +// w->pedigree.next = &loop_root_pedigree; + + /* Spawn is necessary at top-level to force runtime to start up. + * Runtime must be started in order to call the grainsize() function. + */ + int gs = grainsize(grain, count); + cilk_for_recursive((count_t) 0, count, body, data, gs, w, + &loop_root_pedigree); + + // Need to refetch the worker after calling a spawning function. + w = sf->worker; + + // Restore the pedigree in the worker. + w->pedigree = loop_root_pedigree; + + // Bump the worker pedigree. + ++w->pedigree.rank; + + // Implicit sync will increment the pedigree leaf rank again, for a total + // of two increments. If the noop spawn above is removed, then we'll need + // to re-enable the following code: +// // If this is an optimized build, then the compiler will have optimized +// // out the increment of the worker's pedigree in the implied sync. We +// // need to add one to make the pedigree_loop test work correctly. +// #if CILKRTS_OPTIMIZED +// ++sf->worker->pedigree.rank; +// #endif +} + +// Use extern "C" to suppress name mangling of __cilkrts_cilk_for_32 and +// __cilkrts_cilk_for_64. +extern "C" { + +/* + * __cilkrts_cilk_for_32 + * + * Implementation of cilk_for for 32-bit trip counts (regardless of processor + * word size). Assumes that the range is 0 - count. + * + * body - lambda function for the cilk_for loop body + * data - data used by the lambda function + * count - trip count for loop + * grain - grain size (0 if it should be computed) + */ + +CILK_ABI_THROWS_VOID __cilkrts_cilk_for_32(__cilk_abi_f32_t body, void *data, + cilk32_t count, int grain) +{ + // Cilkscreen should not report this call in a stack trace + NOTIFY_ZC_INTRINSIC((char *)"cilkscreen_hide_call", 0); + + // Check for an empty range here as an optimization - don't need to do any + // __cilkrts_stack_frame initialization + if (count > 0) + cilk_for_root(body, data, count, grain); +} + +/* + * __cilkrts_cilk_for_64 + * + * Implementation of cilk_for for 64-bit trip counts (regardless of processor + * word size). Assumes that the range is 0 - count. + * + * body - lambda function for the cilk_for loop body + * data - data used by the lambda function + * count - trip count for loop + * grain - grain size (0 if it should be computed) + */ +CILK_ABI_THROWS_VOID __cilkrts_cilk_for_64(__cilk_abi_f64_t body, void *data, + cilk64_t count, int grain) +{ + // Check for an empty range here as an optimization - don't need to do any + // __cilkrts_stack_frame initialization + if (count > 0) + cilk_for_root(body, data, count, grain); +} + +} // end extern "C" + +/* End cilk-abi-cilk-for.cpp */ diff --git a/libcilkrts/runtime/cilk-abi-vla-internal.c b/libcilkrts/runtime/cilk-abi-vla-internal.c new file mode 100644 index 00000000000..6fb92677ad0 --- /dev/null +++ b/libcilkrts/runtime/cilk-abi-vla-internal.c @@ -0,0 +1,83 @@ +/* cilk-abi-vla-internal.c -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/* + * These functions are provided in their own compilation unit so I can debug + * them. cilk-abi-vla.c must always be compiled with optimization on so that + * inlining occurs. + */ + +#include "internal/abi.h" +#include "cilk-abi-vla-internal.h" +#include "bug.h" +#include "full_frame.h" +#include "local_state.h" + +#include <stdlib.h> +#include <stdint.h> + +#include "bug.h" + +void *vla_internal_heap_alloc(__cilkrts_stack_frame *sf, + size_t full_size, + uint32_t align) +{ + return malloc(full_size); +} + +void vla_internal_heap_free(void *t, size_t size) +{ + free(t); +} + +void vla_free_from_original_stack(__cilkrts_stack_frame *sf, + size_t full_size) +{ + // The __cilkrts_stack_frame must be initialized + CILK_ASSERT(sf->worker); + +#if 1 + // Add full_size to ff->sync_sp so that when we return, the VLA will no + // longer be allocated on the stack + __cilkrts_adjust_stack(sf->worker->l->frame_ff, full_size); +#else + // Inline __cilkrts_adjust_stack for Kevin + full_frame *ff = sf->worker->l->frame_ff; + ff->sync_sp = ff->sync_sp + full_size; +#endif +} diff --git a/libcilkrts/runtime/cilk-abi-vla-internal.h b/libcilkrts/runtime/cilk-abi-vla-internal.h new file mode 100644 index 00000000000..909f08fa471 --- /dev/null +++ b/libcilkrts/runtime/cilk-abi-vla-internal.h @@ -0,0 +1,90 @@ +/* cilk-abi-vla-internal.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** + * @file cilk-abi-vla-internal.h + * + * @brief Allocation/deallocation function for use with Variable Length + * Arrays in spawning functions. + * + * These should be the only functions in the Cilk runtime allocating memory + * from the standard C runtime heap. This memory will be provided to user + * code for use in VLAs, when the memory cannot be allocated from the stack. + * + * While these functions are simply passthroughs to malloc and free at the + * moment, once we've got the basics of VLA allocations working we'll make + * them do fancier tricks. + */ + +/** + * @brief Allocate memory from the heap for use by a Variable Length Array in + * a spawning function. + * + * @param sf The __cilkrts_stack_frame for the spawning function containing + * the VLA. + * @param full_size The number of bytes to be allocated, including any tags + * needed to identify this as allocated from the heap. + * @param align Any alignment necessary for the allocation. + */ + +void *vla_internal_heap_alloc(__cilkrts_stack_frame *sf, + size_t full_size, + uint32_t align); + +/** + * @brief Deallocate memory from the heap used by a Variable Length Array in + * a spawning function. + * + * @param t The address of the memory block to be freed. + * @param size The size of the memory block to be freed. + */ + +void vla_internal_heap_free(void *t, + size_t size); + +/** + * @brief Deallocate memory from the original stack. We'll do this by adding + * full_size to ff->sync_sp. So after the sync, the Variable Length Array + * will no longer be allocated on the stack. + * + * @param sf The __cilkrts_stack_frame for the spawning function that is + * deallocating a VLA. + * @param full_size The size of the VLA, including any alignment and tags. + */ +void vla_free_from_original_stack(__cilkrts_stack_frame *sf, + size_t full_size); diff --git a/libcilkrts/runtime/cilk-abi.c b/libcilkrts/runtime/cilk-abi.c new file mode 100644 index 00000000000..1da05239ebc --- /dev/null +++ b/libcilkrts/runtime/cilk-abi.c @@ -0,0 +1,733 @@ +/* Cilk_abi.c -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2010-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + +/** + * @file cilk-abi.c + * + * @brief cilk-abi.c implements all of the entrypoints to the Intel Cilk + * Plus runtime. + */ + +/* + * Define this macro so that compiliation of this file generates the + * non-inlined versions of certain functions in cilk_api.h. + */ +#include "internal/abi.h" +#include "cilk/cilk_api.h" +#include "cilk/cilk_undocumented.h" +#include "cilktools/cilkscreen.h" + +#include "global_state.h" +#include "os.h" +#include "os_mutex.h" +#include "bug.h" +#include "local_state.h" +#include "full_frame.h" +#include "pedigrees.h" +#include "scheduler.h" +#include "sysdep.h" +#include "except.h" +#include "cilk_malloc.h" +#include "record-replay.h" + +#include <errno.h> +#include <string.h> +#include <stdlib.h> + +#ifdef _MSC_VER +/* Some versions of icc don't support limits.h on Linux if + gcc 4.3 or newer is installed. */ +#include <limits.h> + +/* Declare _ReturnAddress compiler intrinsic */ +void * _ReturnAddress(void); +#pragma intrinsic(_ReturnAddress) + +#include "sysdep-win.h" // Needed for sysdep_init_module() +#endif /* _WIN32 */ + +#include "metacall_impl.h" +#include "reducer_impl.h" +#include "cilk-ittnotify.h" +#include "cilk-tbb-interop.h" + +#define TBB_INTEROP_DATA_DELAYED_UNTIL_BIND (void *)-1 + +/** + * __cilkrts_bind_thread is a versioned entrypoint. The runtime should be + * exporting copies of __cilkrts_bind_version for the current and all previous + * versions of the ABI. + * + * This macro should always be set to generate a version to match the current + * version; __CILKRTS_ABI_VERSION. + */ +#define BIND_THREAD_RTN __cilkrts_bind_thread_1 + +static inline +void enter_frame_internal(__cilkrts_stack_frame *sf, uint32_t version) +{ + __cilkrts_worker *w = __cilkrts_get_tls_worker(); + if (w == 0) { /* slow path */ + w = BIND_THREAD_RTN(); + + sf->flags = CILK_FRAME_LAST | (version << 24); + CILK_ASSERT((sf->flags & CILK_FRAME_FLAGS_MASK) == CILK_FRAME_LAST); + } else { + sf->flags = (version << 24); + CILK_ASSERT((sf->flags & CILK_FRAME_FLAGS_MASK) == 0); + } + sf->call_parent = w->current_stack_frame; + sf->worker = w; + w->current_stack_frame = sf; +} + +CILK_ABI_VOID __cilkrts_enter_frame(__cilkrts_stack_frame *sf) +{ + enter_frame_internal(sf, 0); +} + +CILK_ABI_VOID __cilkrts_enter_frame_1(__cilkrts_stack_frame *sf) +{ + enter_frame_internal(sf, 1); + sf->reserved = 0; +} + +static inline +void enter_frame_fast_internal(__cilkrts_stack_frame *sf, uint32_t version) +{ + __cilkrts_worker *w = __cilkrts_get_tls_worker_fast(); + sf->flags = version << 24; + sf->call_parent = w->current_stack_frame; + sf->worker = w; + w->current_stack_frame = sf; +} + +CILK_ABI_VOID __cilkrts_enter_frame_fast(__cilkrts_stack_frame *sf) +{ + enter_frame_fast_internal(sf, 0); +} + +CILK_ABI_VOID __cilkrts_enter_frame_fast_1(__cilkrts_stack_frame *sf) +{ + enter_frame_fast_internal(sf, 1); + sf->reserved = 0; +} + +/** + * A component of the THE protocol. __cilkrts_undo_detach checks whether + * this frame's parent has been stolen. If it hasn't, the frame can return + * normally. If the parent has been stolen, of if we suspect it might be, + * then __cilkrts_leave_frame() needs to call into the runtime. + * + * @note __cilkrts_undo_detach() is comparing the exception pointer against + * the tail pointer. The exception pointer is modified when another worker + * is considering whether it can steal a frame. The head pointer is updated + * to match when the worker lock is taken out and the thief is sure that + * it can complete the steal. If the steal cannot be completed, the thief + * will restore the exception pointer. + * + * @return true if undo-detach failed. + */ +static int __cilkrts_undo_detach(__cilkrts_stack_frame *sf) +{ + __cilkrts_worker *w = sf->worker; + __cilkrts_stack_frame *volatile *t = w->tail; + +/* DBGPRINTF("%d - __cilkrts_undo_detach - sf %p\n", w->self, sf); */ + + --t; + w->tail = t; + /* On x86 the __sync_fetch_and_<op> family includes a + full memory barrier. In theory the sequence in the + second branch of the #if should be faster, but on + most x86 it is not. */ +#if defined __i386__ || defined __x86_64__ + __sync_fetch_and_and(&sf->flags, ~CILK_FRAME_DETACHED); +#else + __cilkrts_fence(); /* membar #StoreLoad */ + sf->flags &= ~CILK_FRAME_DETACHED; +#endif + + return __builtin_expect(t < w->exc, 0); +} + +CILK_ABI_VOID __cilkrts_leave_frame(__cilkrts_stack_frame *sf) +{ + __cilkrts_worker *w = sf->worker; + +/* DBGPRINTF("%d-%p __cilkrts_leave_frame - sf %p, flags: %x\n", w->self, GetWorkerFiber(w), sf, sf->flags); */ + +#ifdef _WIN32 + /* if leave frame was called from our unwind handler, leave_frame should + proceed no further. */ + if (sf->flags & CILK_FRAME_UNWINDING) + { +/* DBGPRINTF("%d - __cilkrts_leave_frame - aborting due to UNWINDING flag\n", w->self); */ + + // If this is the frame of a spawn helper (indicated by the + // CILK_FRAME_DETACHED flag) we must update the pedigree. The pedigree + // points to nodes allocated on the stack. Failing to update it will + // result in a accvio/segfault if the pedigree is walked. This must happen + // for all spawn helper frames, even if we're processing an exception + if ((sf->flags & CILK_FRAME_DETACHED)) + { + update_pedigree_on_leave_frame(w, sf); + } + return; + } +#endif + +#if CILK_LIB_DEBUG + /* ensure the caller popped itself */ + CILK_ASSERT(w->current_stack_frame != sf); +#endif + + /* The exiting function should have checked for zero flags, + so there is no check for flags == 0 here. */ + +#if CILK_LIB_DEBUG + if (__builtin_expect(sf->flags & (CILK_FRAME_EXITING|CILK_FRAME_UNSYNCHED), 0)) + __cilkrts_bug("W%u: function exiting with invalid flags %02x\n", + w->self, sf->flags); +#endif + + /* Must return normally if (1) the active function was called + and not spawned, or (2) the parent has never been stolen. */ + if ((sf->flags & CILK_FRAME_DETACHED)) { +/* DBGPRINTF("%d - __cilkrts_leave_frame - CILK_FRAME_DETACHED\n", w->self); */ + +#ifndef _WIN32 + if (__builtin_expect(sf->flags & CILK_FRAME_EXCEPTING, 0)) { +// Pedigree will be updated in __cilkrts_leave_frame. We need the +// pedigree before the update for record/replay +// update_pedigree_on_leave_frame(w, sf); + __cilkrts_return_exception(sf); + /* If return_exception returns the caller is attached. + leave_frame is called from a cleanup (destructor) + for the frame object. The caller will reraise the + exception. */ + return; + } +#endif + + // During replay, check whether w was the last worker to continue + replay_wait_for_steal_if_parent_was_stolen(w); + + // Attempt to undo the detach + if (__builtin_expect(__cilkrts_undo_detach(sf), 0)) { + // The update of pedigree for leaving the frame occurs + // inside this call if it does not return. + __cilkrts_c_THE_exception_check(w, sf); + } + + update_pedigree_on_leave_frame(w, sf); + + /* This path is taken when undo-detach wins the race with stealing. + Otherwise this strand terminates and the caller will be resumed + via setjmp at sync. */ + if (__builtin_expect(sf->flags & CILK_FRAME_FLAGS_MASK, 0)) + __cilkrts_bug("W%u: frame won undo-detach race with flags %02x\n", + w->self, sf->flags); + + return; + } + +#if CILK_LIB_DEBUG + sf->flags |= CILK_FRAME_EXITING; +#endif + + if (__builtin_expect(sf->flags & CILK_FRAME_LAST, 0)) + __cilkrts_c_return_from_initial(w); /* does return */ + else if (sf->flags & CILK_FRAME_STOLEN) + __cilkrts_return(w); /* does return */ + +/* DBGPRINTF("%d-%p __cilkrts_leave_frame - returning, StackBase: %p\n", w->self, GetWorkerFiber(w)); */ +} + +/* Caller must have called setjmp. */ +CILK_ABI_VOID __cilkrts_sync(__cilkrts_stack_frame *sf) +{ + __cilkrts_worker *w = sf->worker; +/* DBGPRINTF("%d-%p __cilkrts_sync - sf %p\n", w->self, GetWorkerFiber(w), sf); */ + if (__builtin_expect(!(sf->flags & CILK_FRAME_UNSYNCHED), 0)) + __cilkrts_bug("W%u: double sync %p\n", w->self, sf); +#ifndef _WIN32 + if (__builtin_expect(sf->flags & CILK_FRAME_EXCEPTING, 0)) { + __cilkrts_c_sync_except(w, sf); + } +#endif + + __cilkrts_c_sync(w, sf); +} + +/* + * __cilkrts_get_sf + * + * Debugging aid to provide access to the current __cilkrts_stack_frame. + * + * Not documented! + */ + +CILK_API_VOID_PTR +__cilkrts_get_sf(void) +{ + __cilkrts_worker *w = __cilkrts_get_tls_worker(); + if (0 == w) + return NULL; + + return w->current_stack_frame; +} + +/* Call with global lock held */ +static __cilkrts_worker *find_free_worker(global_state_t *g) +{ + __cilkrts_worker *w = 0; + int i; + + // Scan the non-system workers looking for one which is free so we can + // use it. + for (i = g->P - 1; i < g->total_workers; ++i) { + w = g->workers[i]; + CILK_ASSERT(WORKER_SYSTEM != w->l->type); + if (w->l->type == WORKER_FREE) { + w->l->type = WORKER_USER; + w->l->team = w; + return w; + } + } + + // If we ran out of workers, create a new one. It doesn't actually belong + // to the Cilk global state so nobody will ever try to steal from it. + w = (__cilkrts_worker *)__cilkrts_malloc(sizeof(*w)); + __cilkrts_cilkscreen_ignore_block(w, w+1); + make_worker(g, -1, w); + w->l->type = WORKER_USER; + w->l->team = w; + return w; +} + +/* + * __cilkrts_bind_thread + * + * Exported function to bind a thread to the runtime. + * + * This function name should always have a trailing suffix for the latest ABI + * version. This means that code built with a new compiler will not load + * against an old copy of the runtime. + * + * Symbols for the function called by code compiled with old versions of the + * compiler are created in an OS-specific manner: + * - On Windows the old symbols are defined in the cilk-exports.def linker + * definitions file as aliases of BIND_THREAD_RTN + * - On Linux aliased symbols are created for BIND_THREAD_RTN in this file + * - On MacOS the alternate entrypoints are implemented and simply call + * BIND_THREAD_RTN. + */ +CILK_ABI_WORKER_PTR BIND_THREAD_RTN(void) +{ + __cilkrts_worker *w; + int start_cilkscreen = 0; +#ifdef USE_ITTNOTIFY + static int unique_obj; +#endif + + // Cannot set this pointer until after __cilkrts_init_internal() call: + global_state_t* g; + + ITT_SYNC_CREATE (&unique_obj, "Initialization"); + ITT_SYNC_PREPARE(&unique_obj); + ITT_SYNC_ACQUIRED(&unique_obj); + + + /* 1: Initialize and start the Cilk runtime */ + __cilkrts_init_internal(1); + + /* + * 2: Choose a worker for this thread (fail if none left). The table of + * user workers is protected by the global OS mutex lock. + */ + g = cilkg_get_global_state(); + global_os_mutex_lock(); + if (__builtin_expect(g->work_done, 0)) + __cilkrts_bug("Attempt to enter Cilk while Cilk is shutting down"); + w = find_free_worker(g); + CILK_ASSERT(w); + + __cilkrts_set_tls_worker(w); + __cilkrts_cilkscreen_establish_worker(w); + { + full_frame *ff = __cilkrts_make_full_frame(w, 0); + + ff->fiber_self = cilk_fiber_allocate_from_thread(); + CILK_ASSERT(ff->fiber_self); + + cilk_fiber_set_owner(ff->fiber_self, w); + cilk_fiber_tbb_interop_use_saved_stack_op_info(ff->fiber_self); + + CILK_ASSERT(ff->join_counter == 0); + ff->join_counter = 1; + w->l->frame_ff = ff; + w->reducer_map = __cilkrts_make_reducer_map(w); + __cilkrts_set_leftmost_reducer_map(w->reducer_map, 1); + load_pedigree_leaf_into_user_worker(w); + } + + // Make sure that the head and tail are reset, and saved_protected_tail + // allows all frames to be stolen. + // + // Note that we must NOT check w->exc, since workers that are trying to + // steal from it will be updating w->exc and we don't own the worker lock. + // It's not worth taking out the lock just for an assertion. + CILK_ASSERT(w->head == w->l->ltq); + CILK_ASSERT(w->tail == w->l->ltq); + CILK_ASSERT(w->protected_tail == w->ltq_limit); + + // There may have been an old pending exception which was freed when the + // exception was caught outside of Cilk + w->l->pending_exception = NULL; + + w->reserved = NULL; + + // If we've already created a scheduling fiber for this worker, we'll just + // reuse it. If w->self < 0, it means that this is an ad-hoc user worker + // not known to the global state. Thus, we need to create a scheduling + // stack only if we don't already have one and w->self >= 0. + if (NULL == w->l->scheduling_fiber && w->self >= 0) + { + START_INTERVAL(w, INTERVAL_FIBER_ALLOCATE) { + // Create a scheduling fiber for this worker. + w->l->scheduling_fiber = + cilk_fiber_allocate_from_heap(CILK_SCHEDULING_STACK_SIZE); + cilk_fiber_reset_state(w->l->scheduling_fiber, + scheduler_fiber_proc_for_user_worker); + cilk_fiber_set_owner(w->l->scheduling_fiber, w); + } STOP_INTERVAL(w, INTERVAL_FIBER_ALLOCATE); + } + + // If the scheduling fiber is NULL, we've either exceeded our quota for + // fibers or workers or we're out of memory, so we should lose parallelism + // by disallowing stealing. + if (NULL == w->l->scheduling_fiber) + __cilkrts_disallow_stealing(w, NULL); + + start_cilkscreen = (0 == w->g->Q); + + if (w->self != -1) { + // w->self != -1, means that w is a normal user worker and must be + // accounted for by the global state since other workers can steal from + // it. + + // w->self == -1, means that w is an overflow worker and was created on + // demand. I.e., it does not need to be accounted for by the global + // state. + + __cilkrts_enter_cilk(w->g); + } + + global_os_mutex_unlock(); + + /* If there's only 1 worker, the counts will be started in + * __cilkrts_scheduler */ + if (g->P > 1) + { + START_INTERVAL(w, INTERVAL_IN_SCHEDULER); + START_INTERVAL(w, INTERVAL_WORKING); + } + + ITT_SYNC_RELEASING(&unique_obj); + + /* Turn on Cilkscreen if this is the first worker. This needs to be done + * when we are NOT holding the os mutex. */ + if (start_cilkscreen) + __cilkrts_cilkscreen_enable_instrumentation(); + + return w; +} + +#ifndef _MSC_VER +/* + * Define old version-specific symbols for binding threads (since they exist in + * all Cilk code). These aliases prohibit newly compiled code from loading an + * old version of the runtime. We can handle old code with a new runtime, but + * new code with an old runtime is verboten! + * + * For Windows, the aliased symbol is exported in cilk-exports.def. + */ +#if defined(_DARWIN_C_SOURCE) || defined(__APPLE__) +/** + * Mac OS X: Unfortunately, Darwin doesn't allow aliasing, so we just make a + * call and hope the optimizer does the right thing. + */ +CILK_ABI_WORKER_PTR __cilkrts_bind_thread (void) { + return BIND_THREAD_RTN(); +} +#else + +/** + * Macro to convert a parameter to a string. Used on Linux or BSD. + */ +#define STRINGIFY(x) #x + +/** + * Macro to generate an __attribute__ for an aliased name + */ +#define ALIASED_NAME(x) __attribute__ ((alias (STRINGIFY(x)))) + +/** + * Linux or BSD: Use the alias attribute to make the labels for the versioned + * functions point to the same place in the code as the original. Using + * the two macros is annoying but required. + */ + +CILK_ABI_WORKER_PTR __cilkrts_bind_thread(void) + ALIASED_NAME(BIND_THREAD_RTN); + +#endif // defined _DARWIN_C_SOURCE || defined __APPLE__ +#endif // !defined _MSC_VER + +CILK_API_SIZET +__cilkrts_get_stack_size(void) { + return cilkg_get_stack_size(); +} + +// Method for debugging. +CILK_API_VOID __cilkrts_dump_stats(void) +{ + // While the stats aren't protected by the global OS mutex, the table + // of workers is, so take out the global OS mutex while we're doing this + global_os_mutex_lock(); + if (cilkg_is_published()) { + global_state_t *g = cilkg_get_global_state(); + __cilkrts_dump_stats_to_stderr(g); + } + else { + __cilkrts_bug("Attempting to report Cilk stats before the runtime has started\n"); + } + global_os_mutex_unlock(); +} + +#ifndef _WIN32 +CILK_ABI_THROWS_VOID __cilkrts_rethrow(__cilkrts_stack_frame *sf) +{ + __cilkrts_gcc_rethrow(sf); +} +#endif + +/* + * __cilkrts_unwatch_stack + * + * Callback for TBB to tell us they don't want to watch the stack anymore + */ + +static __cilk_tbb_retcode __cilkrts_unwatch_stack(void *data) +{ + __cilk_tbb_stack_op_thunk o; + + // If the cilk_fiber wasn't available fetch it now + if (TBB_INTEROP_DATA_DELAYED_UNTIL_BIND == data) + { + full_frame *ff; + __cilkrts_worker *w = __cilkrts_get_tls_worker(); + if (NULL == w) + { + // Free any saved stack op information + cilk_fiber_tbb_interop_free_stack_op_info(); + + return 0; /* Success! */ + } + + __cilkrts_worker_lock(w); + ff = w->l->frame_ff; + __cilkrts_frame_lock(w,ff); + data = ff->fiber_self; + __cilkrts_frame_unlock(w,ff); + __cilkrts_worker_unlock(w); + } + +#if CILK_LIB_DEBUG /* Debug code */ + /* Get current stack */ + full_frame *ff; + __cilkrts_worker *w = __cilkrts_get_tls_worker(); + __cilkrts_worker_lock(w); + ff = w->l->frame_ff; + __cilkrts_frame_lock(w,ff); + CILK_ASSERT (data == ff->fiber_self); + __cilkrts_frame_unlock(w,ff); + __cilkrts_worker_unlock(w); +#endif + + /* Clear the callback information */ + o.data = NULL; + o.routine = NULL; + cilk_fiber_set_stack_op((cilk_fiber*)data, o); + + // Note. Do *NOT* free any saved stack information here. If they want to + // free the saved stack op information, they'll do it when the thread is + // unbound + + return 0; /* Success! */ +} + +/* + * __cilkrts_watch_stack + * + * Called by TBB, defined by Cilk. + * + * Requests that Cilk invoke the stack op routine when it orphans a stack. + * Cilk sets *u to a thunk that TBB should call when it is no longer interested + * in watching the stack. + */ + +CILK_API_TBB_RETCODE +__cilkrts_watch_stack(__cilk_tbb_unwatch_thunk *u, + __cilk_tbb_stack_op_thunk o) +{ + cilk_fiber* current_fiber; + __cilkrts_worker *w; + +#ifdef _MSC_VER + // This may be called by TBB *before* the OS has given us our + // initialization call. Make sure the module is initialized. + sysdep_init_module(); +#endif + + // Fetch the __cilkrts_worker bound to this thread + w = __cilkrts_get_tls_worker(); + if (NULL == w) + { + // Save data for later. We'll deal with it when/if this thread binds + // to the runtime + cilk_fiber_tbb_interop_save_stack_op_info(o); + + u->routine = __cilkrts_unwatch_stack; + u->data = TBB_INTEROP_DATA_DELAYED_UNTIL_BIND; + + return 0; + } + + /* Get current stack */ + __cilkrts_worker_lock(w); + current_fiber = w->l->frame_ff->fiber_self; + __cilkrts_worker_unlock(w); + +/* CILK_ASSERT( !sd->stack_op_data ); */ +/* CILK_ASSERT( !sd->stack_op_routine ); */ + + /* Give TBB our callback */ + u->routine = __cilkrts_unwatch_stack; + u->data = current_fiber; + /* Save the callback information */ + cilk_fiber_set_stack_op(current_fiber, o); + + return 0; /* Success! */ +} + + +// This function must be called only within a continuation, within the stack +// frame of the continuation itself. +CILK_API_INT __cilkrts_synched(void) +{ + __cilkrts_worker *w = __cilkrts_get_tls_worker(); + + // If we don't have a worker, then we're synched by definition :o) + if (NULL == w) + return 1; + + // Check to see if we are in a stolen continuation. If not, then + // we are synched. + uint32_t flags = w->current_stack_frame->flags; + if (0 == (flags & CILK_FRAME_UNSYNCHED)) + return 1; + + // We are in a stolen continutation, but the join counter might have been + // decremented to one, making us synched again. Get the full frame so + // that we can check the join counter. ASSUME: frame_ff is stable (can be + // read without a lock) in a stolen continuation -- it can't be stolen + // while it's currently executing. + full_frame *ff = w->l->frame_ff; + + // Make sure we have a full frame + // TBD: Don't think that we should ever not have a full frame here. + // CILK_ASSERT(NULL != ff); ? + if (NULL == ff) + return 1; + + // We're synched if there are no outstanding children at this instant in + // time. Note that this is a known race, but it's ok since we're only + // reading. We can get false negatives, but not false positives. (I.e., + // we can read a non-one join_counter just before it goes to one, but the + // join_counter cannot go from one to greater than one while we're + // reading.) + return 1 == ff->join_counter; +} + + + + +CILK_API_INT +__cilkrts_bump_loop_rank_internal(__cilkrts_worker* w) +{ + // If we don't have a worker, then the runtime is not bound to this + // thread and there is no rank to increment + if (NULL == w) + return -1; + + // We're at the start of the loop body. Advance the cilk_for loop + // body pedigree by following the parent link and updating its + // rank. + + // Normally, we'd just write "w->pedigree.parent->rank++" + // But we need to cast away the "const". + ((__cilkrts_pedigree*) w->pedigree.parent)->rank++; + + // Zero the worker's pedigree rank since this is the start of a new + // pedigree domain. + w->pedigree.rank = 0; + + return 0; +} + +CILK_ABI_VOID +__cilkrts_save_fp_ctrl_state(__cilkrts_stack_frame *sf) +{ + // Pass call onto OS/architecture dependent function + sysdep_save_fp_ctrl_state(sf); +} + +/* end cilk-abi.c */ diff --git a/libcilkrts/runtime/cilk-ittnotify.h b/libcilkrts/runtime/cilk-ittnotify.h new file mode 100644 index 00000000000..ff995db6fbb --- /dev/null +++ b/libcilkrts/runtime/cilk-ittnotify.h @@ -0,0 +1,100 @@ +/* cilk-ittnotify.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +#ifndef INCLUDED_CILK_ITTNOTIFY_DOT_H +#define INCLUDED_CILK_ITTNOTIFY_DOT_H + +#ifdef __INTEL_COMPILER +#endif +#include <stdio.h> + +// ITTNOTIFY does not support ARM at this time +#ifdef __arm__ +#undef USE_ITTNOTIFY +#endif + +#ifdef USE_ITTNOTIFY +#include <ittnotify.h> + +#ifdef _WIN32 +# define ITT_SYNC_CREATE(_address, _description) \ + __itt_sync_createA(_address, \ + "Intel Cilk Plus " _description, \ + "", \ + __itt_attr_barrier) +#else +# define ITT_SYNC_CREATE(_address, _description) \ + __itt_sync_create(_address, \ + "Intel Cilk Plus " _description, \ + "", \ + __itt_attr_barrier) +#endif + +#define ITT_SYNC_PREPARE(_address) __itt_sync_prepare(_address) +#define ITT_SYNC_ACQUIRED(_address) __itt_sync_acquired(_address) +#define ITT_SYNC_RELEASING(_address) __itt_sync_releasing(_address) +#define ITT_SYNC_DESTROY(_address) __itt_sync_destroy(_address) +// Note that we subtract 5 from the return address to find the CALL instruction +// to __cilkrts_sync +#if 1 // Disable renaming for now. Piersol isn't ready yet +#define ITT_SYNC_SET_NAME_AND_PREPARE(_address, _sync_ret_address) __itt_sync_prepare(_address) +#else +#define ITT_SYNC_SET_NAME_AND_PREPARE(_address, _sync_ret_address) \ + if (NULL != __itt_sync_prepare_ptr) { \ + if (0 == _sync_ret_address) \ + __itt_sync_renameA(_address, ""); \ + else \ + { \ + char buf[128]; \ + sprintf_s(buf, 128, "IP:0x%p", (DWORD_PTR)_sync_ret_address - 5); \ + __itt_sync_renameA(_address, buf); \ + _sync_ret_address = 0; \ + } \ + __itt_sync_prepare(_address); \ + } +#endif +#else // USE_ITTNOTIFY not defined, compile out all calls +#define ITT_SYNC_CREATE(_address, _description) +#define ITT_SYNC_PREPARE(_address) +#define ITT_SYNC_ACQUIRED(_address) +#define ITT_SYNC_RELEASING(_addresss) +#define ITT_SYNC_DESTROY(_address) +#define ITT_SYNC_SET_NAME_AND_PREPARE(_sync_address, _wait_address) +#endif + +#endif // ! defined(INCLUDED_CILK_ITTNOTIFY_DOT_H) diff --git a/libcilkrts/runtime/cilk-tbb-interop.h b/libcilkrts/runtime/cilk-tbb-interop.h new file mode 100644 index 00000000000..cc5cff4b57e --- /dev/null +++ b/libcilkrts/runtime/cilk-tbb-interop.h @@ -0,0 +1,192 @@ +/* cilk-tbb-interop.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** + * @file cilk-tbb-interop.h + * + * @brief Interface between TBB and Cilk to allow TBB to associate it's + * per-thread data with Cilk workers, and maintain the association as work + * moves between worker threads. This handles the case where TBB calls + * into a Cilk function which may later call back to a function making + * TBB calls. + * + * Each thunk structure has two pointers: \"routine\" and \"data\". + * The caller of the thunk invokes *routine, passing \"data\" as the void* + * parameter. + */ + +#ifndef INCLUDED_CILK_TBB_INTEROP_DOT_H +#define INCLUDED_CILK_TBB_INTEROP_DOT_H + +#include <cilk/common.h> // for CILK_EXPORT + +__CILKRTS_BEGIN_EXTERN_C + +/** A return code. 0 indicates success. */ +typedef int __cilk_tbb_retcode; + +/** + * Enumeration of reasons that Cilk will call the TBB stack operation + * function. + * + * When a non-empty stack is transfered between threads, the first thread must + * orphan it and the second thread must adopt it. + * + * An empty stack can be transfered similarly, or simply released by the first + * thread. + * + * Here is a summary of the actions as transitions on a state machine. +@verbatim + watch ORPHAN + -->--> -->-- + / \ / \ + (freed empty stack) (TBB sees stack running on thread) (stack in limbo) + \ / \ / + --<-- --<-- + RELEASE or ADOPT + unwatch +@endverbatim + */ +typedef enum __cilk_tbb_stack_op { + /** + * Disconnecting stack from a thread. + * + * The thunk must be invoked on the thread disconnecting itself from the + * stack. Must \"happen before\" the stack is adopted elsewhere. + */ + CILK_TBB_STACK_ORPHAN, + + /** + * Reconnecting orphaned stack to a thread. + * + * The thunk must be invoked on the thread adopting the stack. + */ + CILK_TBB_STACK_ADOPT, + + /** + * Releasing stack. + * + * The thunk must be invoked on the thread doing the releasing, Must + * \"happen before\" the stack is used elsewhere. + */ + CILK_TBB_STACK_RELEASE +} __cilk_tbb_stack_op; + +/** + * Function that will be called by the Cilk runtime to inform TBB of a change + * in the stack associated with the current thread. + * + * It does not matter what stack the thunk runs on. + * The thread (not fiber) on which the thunk runs is important. + * + * @param op Enumerated value indicating what type of change is ocurring. + * @param data Context value provided by TBB in the __cilkrts_watch_stack + * call. This data is opaque to Cilk. + * + * @return 0 indicates success. + */ +typedef __cilk_tbb_retcode (*__cilk_tbb_pfn_stack_op)(enum __cilk_tbb_stack_op op, + void* data); + +/** + * Function that will be called by TBB to inform the Cilk runtime that TBB + * is no longer interested in watching the stack bound to the current thread. + * + * @param data Context value provided to TBB by the __cilkrts_watch_stack + * call. This data is opaque to TBB. + * + * @return 0 indicates success. + */ +typedef __cilk_tbb_retcode (*__cilk_tbb_pfn_unwatch_stacks)(void *data); + +/** + * Thunk invoked by Cilk to call back to TBB to tell it about a change in + * the stack bound to the current thread. + */ +typedef struct __cilk_tbb_stack_op_thunk { + /// Function in TBB the Cilk runtime should call when something + // "interesting" happens involving a stack + __cilk_tbb_pfn_stack_op routine; + + /// TBB context data to pass with the call to the stack_op routine + void* data; +} __cilk_tbb_stack_op_thunk; + +/** + * Thunk invoked by TBB when it is no longer interested in watching the stack + * bound to the current thread. + */ +typedef struct __cilk_tbb_unwatch_thunk { + /// Function in Cilk runtime to call when TBB no longer wants to watch + // stacks + __cilk_tbb_pfn_unwatch_stacks routine; + + /// Cilk runtime context data to pass with the call to the unwatch_stacks + /// routine + void* data; +} __cilk_tbb_unwatch_thunk; + +/** + * Requests that Cilk invoke __cilk_tbb_orphan_thunk when it orphans a stack. + * Cilk sets *u to a thunk that TBB should call when it is no longer + * interested in watching the stack. + * + * If the thread is not yet bound to the Cilk runtime, the Cilk runtime should + * save this data in thread-local storage until __cilkrts_bind_thread is called. + * + * Called by TBB, defined by Cilk. This function is exported from the Cilk + * runtime DLL/shared object. This declaration also appears in + * cilk/cilk_undocumented.h -- don't change one declaration without also + * changing the other. + * + * @param u __cilk_tbb_unwatch_thunk. This structure will be filled in by + * the Cilk runtime to allow TBB to register that it is no longer interested + * in watching the stack bound to the current thread. + * @param o __cilk_tbb_stack_op_thunk. This structure specifies the routine + * that the Cilk runtime should call when an "interesting" change in the stack + * associate with the current worker occurs. + * + * @return 0 indicates success. + */ +CILK_EXPORT +__cilk_tbb_retcode __cilkrts_watch_stack(__cilk_tbb_unwatch_thunk* u, + __cilk_tbb_stack_op_thunk o); + +__CILKRTS_END_EXTERN_C + +#endif // ! defined(INCLUDED_CILK_TBB_INTEROP_DOT_H) diff --git a/libcilkrts/runtime/cilk_api.c b/libcilkrts/runtime/cilk_api.c new file mode 100644 index 00000000000..bbca984bc03 --- /dev/null +++ b/libcilkrts/runtime/cilk_api.c @@ -0,0 +1,255 @@ +/* cilk_api.c -*-C-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/* + * Implementation of functions declared in cilk_api.h + */ + +/* + * Define the COMPILING_CILK_ABI_FUNCTIONS macro, so that + * compilation of this file generates non-inlined definitions for the + * functions marked as CILK_EXPORT_AND_INLINE in cilk_api.h. + * + * We must deal with these functions differently because we need to + * continue to ship nonlined versions of these functions. + * + * CILK_EXPORT_AND_INLINE int __cilkrts_get_worker_rank(uint64_t *rank); + * CILK_EXPORT_AND_INLINE int __cilkrts_bump_worker_rank(); + * CILK_EXPORT_AND_INLINE int __cilkrts_bump_loop_rank(); + */ +#define COMPILING_CILK_API_FUNCTIONS + +#include <internal/abi.h> +#include <cilk/cilk_api.h> + +#include "os.h" +#include "os_mutex.h" +#include "bug.h" +#include "global_state.h" +#include "local_state.h" +#include "scheduler.h" +#include "sysdep.h" + +CILK_API_VOID __cilkrts_init(void) +{ + // Initialize, but don't start, the cilk runtime. + __cilkrts_init_internal(0); +} + +CILK_API_VOID __cilkrts_end_cilk(void) +{ + // Take out the global OS mutex while we do this to protect against + // another thread attempting to bind while we do this + global_os_mutex_lock(); + + if (cilkg_is_published()) { + global_state_t *g = cilkg_get_global_state(); + if (g->Q || __cilkrts_get_tls_worker()) + __cilkrts_bug("Attempt to shut down Cilk while Cilk is still " + "running"); + __cilkrts_stop_workers(g); + __cilkrts_deinit_internal(g); + } + + global_os_mutex_unlock(); +} + +CILK_API_INT +__cilkrts_get_nworkers() +{ + return cilkg_get_nworkers(); +} + +CILK_API_INT +__cilkrts_get_total_workers() +{ + return cilkg_get_total_workers(); +} + +CILK_API_INT __cilkrts_get_force_reduce(void) +{ + return cilkg_get_force_reduce(); +} + +CILK_API_INT __cilkrts_set_param(const char* param, const char* value) +{ + return cilkg_set_param(param, value); +} + +#ifdef _WIN32 +CILK_API_INT __cilkrts_set_param_w(const wchar_t* param, const wchar_t* value) +{ + return cilkg_set_param_w(param, value); +} +#endif // _WIN32 + +/* Return a small integer indicating which Cilk worker the function is + * currently running on. Each thread started by the Cilk runtime library + * (system worker) has a unique worker number in the range 1..P-1, where P is + * the valued returned by __cilkrts_get_nworkers(). All threads started by + * the user or by other libraries (user workers) share the worker number 0. + * Therefore, the worker number is not unique across multiple user threads. + * + * Implementor's note: The value returned from this function is different from + * the value, w->self, used in most debug messages. + */ +CILK_API_INT +__cilkrts_get_worker_number(void) +{ + __cilkrts_worker *w = __cilkrts_get_tls_worker(); + + if (0 == w) + /* A non-worker always has a worker number of zero. */ + return 0; + else if (WORKER_USER == w->l->type) + /* User worker was once a non-worker, so its number should still be + * zero. */ + return 0; + else + /* w->self for a system worker is in range 0..(P-1); adjust to 1..P + * to avoid conflicting with the user thread's worker number. */ + return w->self + 1; +} + +/** + * Internal definition of the pedigree context. The size of the + * structure must match __cilkrts_pedigree_context_t defined in abi.i + */ +typedef struct pedigree_context_t +{ + /** Size of the structure, in bytes */ + size_t size; + + /** Next __cilkrts_pedigree to return */ + const __cilkrts_pedigree *pedigree; + + /** Unused. Left over from previous implementation */ + void *unused1; + + /** Unused. Left over from previous implementation */ + void *unused2; + + // // Debugging aid for pedigree-test: + // __cilkrts_stack_frame *expected_sf; +} pedigree_context_t; + +/* + * __cilkrts_get_pedigree_info + * + * Fetch the birthrank for a stack frame. To initialize the walk, both sf_in + * and frame_in should be NULL. parent_sf_ptr and parent_frame_ptr provide + * context for the stackwalk and should be returned as sf_in and frame_in on + * the next call. + * + * Returns: + * 0 - Success - birthrank, parent_sf_out and parent_frame_out are valid + * >1 - Pedigree walk completed + * <1 - Failure - -1: No worker bound to thread, -2: Sanity check failed + */ + +#define PEDIGREE_WALK_COMPLETE (__cilkrts_pedigree *)-1 + +CILK_API_INT +__cilkrts_get_pedigree_info(__cilkrts_pedigree_context_t *external_context, + uint64_t *sf_birthrank) +{ + pedigree_context_t *context = (pedigree_context_t *)external_context; + + CILK_ASSERT(sizeof(__cilkrts_pedigree_context_t) == + sizeof(pedigree_context_t)); + if (context->size != sizeof(pedigree_context_t)) + return -3; // Invalid size + + // If the pointer to the last __cilkrts_pedigree is -1, we've + // finished the walk. We're still done. + if (PEDIGREE_WALK_COMPLETE == context->pedigree) + return 1; + + // The passed in context value contains a pointer to the last + // __cilkrts_pedigree returned, or NULL if we're starting a + // new walk + if (NULL == context->pedigree) + { + __cilkrts_worker *w = __cilkrts_get_tls_worker(); + __cilkrts_pedigree* pedigree_node; + if (NULL != w) { + pedigree_node = &w->pedigree; + } + else { + pedigree_node = __cilkrts_get_tls_pedigree_leaf(1); + } + context->pedigree = pedigree_node->parent; + } + else + context->pedigree = context->pedigree->parent; + + // Note: If we want to omit the user root node, + // stop at context->pedigree->parent instead. + if (NULL == context->pedigree) + { + context->pedigree = PEDIGREE_WALK_COMPLETE; + return 1; + } + + *sf_birthrank = context->pedigree->rank; + return 0; +} + +CILK_API_PEDIGREE +__cilkrts_get_pedigree_internal(__cilkrts_worker *w) +{ + if (NULL != w) { + return w->pedigree; + } + else { + const __cilkrts_pedigree *pedigree = + __cilkrts_get_tls_pedigree_leaf(1); + return *pedigree; + } +} + + +CILK_API_INT __cilkrts_bump_worker_rank_internal(__cilkrts_worker *w) +{ + __cilkrts_pedigree *pedigree; + pedigree = (w ? &w->pedigree : __cilkrts_get_tls_pedigree_leaf(1)); + pedigree->rank++; + return 0; +} + +/* End cilk_api.c */ diff --git a/libcilkrts/runtime/cilk_fiber-unix.cpp b/libcilkrts/runtime/cilk_fiber-unix.cpp new file mode 100644 index 00000000000..b9b47e364a5 --- /dev/null +++ b/libcilkrts/runtime/cilk_fiber-unix.cpp @@ -0,0 +1,273 @@ +/* cilk_fiber-unix.cpp -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2012-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +#include "cilk_fiber-unix.h" +#include "cilk_malloc.h" +#include "bug.h" +#include "os.h" + +#include <cstdio> +#include <cstdlib> + +#include <alloca.h> +#include <errno.h> +#include <sys/mman.h> +#include <unistd.h> + +// MAP_ANON is deprecated on Linux, but seems to be required on Mac... +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + +// Magic number for sanity checking fiber structure +const unsigned magic_number = 0x5afef00d; + +int cilk_fiber_sysdep::s_page_size = getpagesize(); + +cilk_fiber_sysdep::cilk_fiber_sysdep(std::size_t stack_size) + : cilk_fiber(stack_size) + , m_magic(magic_number) +{ + // Set m_stack and m_stack_base. + make_stack(stack_size); + + // Get high-address of stack, with 32-bytes of spare space, and rounded + // down to the nearest 32-byte boundary. + const uintptr_t align_mask = 32 - 1; + m_stack_base -= ((std::size_t) m_stack_base) & align_mask; +} + +cilk_fiber_sysdep::cilk_fiber_sysdep(from_thread_t) + : cilk_fiber() + , m_magic(magic_number) +{ + this->set_allocated_from_thread(true); + + // Dummy stack data for thread-main fiber + m_stack = NULL; + m_stack_base = NULL; +} + +void cilk_fiber_sysdep::convert_fiber_back_to_thread() +{ + // Does nothing on Linux. +} + +cilk_fiber_sysdep::~cilk_fiber_sysdep() +{ + CILK_ASSERT(magic_number == m_magic); + if (!this->is_allocated_from_thread()) + free_stack(); +} + +#if SUPPORT_GET_CURRENT_FIBER +cilk_fiber_sysdep* cilk_fiber_sysdep::get_current_fiber_sysdep() +{ + return cilkos_get_tls_cilk_fiber(); +} +#endif + +// Jump to resume other fiber. We may or may not come back. +inline void cilk_fiber_sysdep::resume_other_sysdep(cilk_fiber_sysdep* other) +{ + if (other->is_resumable()) { + other->set_resumable(false); + // Resume by longjmp'ing to the place where we suspended. + CILK_LONGJMP(other->m_resume_jmpbuf); + } + else { + // Otherwise, we've never ran this fiber before. Start the + // proc method. + other->run(); + } +} + +void cilk_fiber_sysdep::suspend_self_and_resume_other_sysdep(cilk_fiber_sysdep* other) +{ +#if SUPPORT_GET_CURRENT_FIBER + cilkos_set_tls_cilk_fiber(other); +#endif + CILK_ASSERT(this->is_resumable()); + + + // Jump to the other fiber. We expect to come back. + if (! CILK_SETJMP(m_resume_jmpbuf)) { + resume_other_sysdep(other); + } + + // Return here when another fiber resumes me. + // If the fiber that switched to me wants to be deallocated, do it now. + do_post_switch_actions(); +} + +NORETURN cilk_fiber_sysdep::jump_to_resume_other_sysdep(cilk_fiber_sysdep* other) +{ +#if SUPPORT_GET_CURRENT_FIBER + cilkos_set_tls_cilk_fiber(other); +#endif + CILK_ASSERT(!this->is_resumable()); + + // Jump to the other fiber. But we are never coming back because + // this fiber is being reset. + resume_other_sysdep(other); + + // We should never come back here... + __cilkrts_bug("Should not get here"); +} + + +NORETURN cilk_fiber_sysdep::run() +{ + // Only fibers created from a pool have a proc method to run and execute. + CILK_ASSERT(m_start_proc); + CILK_ASSERT(!this->is_allocated_from_thread()); + CILK_ASSERT(!this->is_resumable()); + + // TBD: This setjmp/longjmp pair simply changes the stack pointer. + // We could probably replace this code with some assembly. + if (! CILK_SETJMP(m_resume_jmpbuf)) + { + // Calculate the size of the current stack frame (i.e., this + // run() function. + size_t frame_size = (size_t)JMPBUF_FP(m_resume_jmpbuf) - (size_t)JMPBUF_SP(m_resume_jmpbuf); + + // Macs require 16-byte alignment. Do it always because it just + // doesn't matter + if (frame_size & (16-1)) + frame_size += 16 - (frame_size & (16-1)); + + // Assert that we are getting a reasonable frame size out of + // it. If this run() function is using more than 4096 bytes + // of space for its local variables / any state that spills to + // registers, something is probably *very* wrong here... + // + // 4096 bytes just happens to be a number that seems "large + // enough" --- for an example GCC 32-bit compilation, the + // frame size was 48 bytes. + CILK_ASSERT(frame_size < 4096); + + // Change stack pointer to fiber stack. Offset the + // calculation by the frame size, so that we've allocated + // enough extra space from the top of the stack we are + // switching to for any temporaries required for this run() + // function. + JMPBUF_SP(m_resume_jmpbuf) = m_stack_base - frame_size; + CILK_LONGJMP(m_resume_jmpbuf); + } + + // Note: our resetting of the stack pointer is valid only if the + // compiler has not saved any temporaries onto the stack for this + // function before the longjmp that we still care about at this + // point. + + // Verify that 1) 'this' is still valid and 2) '*this' has not been + // corrupted. + CILK_ASSERT(magic_number == m_magic); + + // If the fiber that switched to me wants to be deallocated, do it now. + do_post_switch_actions(); + + // Now call the user proc on the new stack + m_start_proc(this); + + // alloca() to force generation of frame pointer. The argument to alloca + // is contrived to prevent the compiler from optimizing it away. This + // code should never actually be executed. + int* dummy = (int*) alloca((sizeof(int) + (std::size_t) m_start_proc) & 0x1); + *dummy = 0xface; + + // User proc should never return. + __cilkrts_bug("Should not get here"); +} + +void cilk_fiber_sysdep::make_stack(size_t stack_size) +{ + char* p; + // We've already validated that the stack size is page-aligned and + // is a reasonable value. No need to do any extra rounding here. + size_t rounded_stack_size = stack_size; + + // Normally, we have already validated that the stack size is + // aligned to 4K. In the rare case that pages are huge though, we + // need to do some extra checks. + if (rounded_stack_size < 3 * (size_t)s_page_size) { + // If the specified stack size is too small, round up to 3 + // pages. We need at least 2 extra for the guard pages. + rounded_stack_size = 3 * (size_t)s_page_size; + } + else { + // Otherwise, the stack size is large enough, but might not be + // a multiple of page size. Round up to nearest multiple of + // s_page_size, just to be safe. + size_t remainder = rounded_stack_size % s_page_size; + if (remainder) { + rounded_stack_size += s_page_size - remainder; + } + } + + p = (char*)mmap(0, rounded_stack_size, + PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, + -1, 0); + if (MAP_FAILED == p) { + // For whatever reason (probably ran out of memory), mmap() failed. + // There is no stack to return, so the program loses parallelism. + m_stack = NULL; + m_stack_base = NULL; + return; + } + + // mprotect guard pages. + mprotect(p + rounded_stack_size - s_page_size, s_page_size, PROT_NONE); + mprotect(p, s_page_size, PROT_NONE); + + m_stack = p; + m_stack_base = p + rounded_stack_size - s_page_size; +} + + +void cilk_fiber_sysdep::free_stack() +{ + if (m_stack) { + size_t rounded_stack_size = m_stack_base - m_stack + s_page_size; + if (munmap(m_stack, rounded_stack_size) < 0) + __cilkrts_bug("Cilk: stack munmap failed error %d\n", errno); + } +} + +/* End cilk_fiber-unix.cpp */ diff --git a/libcilkrts/runtime/cilk_fiber-unix.h b/libcilkrts/runtime/cilk_fiber-unix.h new file mode 100644 index 00000000000..9f47d5b0437 --- /dev/null +++ b/libcilkrts/runtime/cilk_fiber-unix.h @@ -0,0 +1,149 @@ +/* cilk_fiber-unix.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2012-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +#ifndef INCLUDED_CILK_FIBER_UNIX_DOT_H +#define INCLUDED_CILK_FIBER_UNIX_DOT_H + +#ifndef __cplusplus +# error cilk_fiber-unix.h is a C++-only header +#endif + +#include "cilk_fiber.h" +#include "jmpbuf.h" + +/** + * @file cilk_fiber-unix.h + * + * @brief Unix-specific implementation for cilk_fiber. + */ + +/** + * @brief Unix-specific fiber class derived from portable fiber class + */ +struct cilk_fiber_sysdep : public cilk_fiber +{ + public: + +#if SUPPORT_GET_CURRENT_FIBER + /** + * @brief Gets the current fiber from TLS. + */ + static cilk_fiber_sysdep* get_current_fiber_sysdep(); +#endif + + /** + * @brief Construct the system-dependent portion of a fiber. + * + * @param stack_size The size of the stack for this fiber. + */ + cilk_fiber_sysdep(std::size_t stack_size); + + /** + * @brief Construct the system-dependent of a fiber created from a + * thread. + */ + cilk_fiber_sysdep(from_thread_t); + + /** + * @brief Destructor + */ + ~cilk_fiber_sysdep(); + + /** + * @brief OS-specific calls to convert this fiber back to thread. + * + * Nothing to do for Linux. + */ + void convert_fiber_back_to_thread(); + + /** + * @brief System-dependent function to suspend self and resume execution of "other". + * + * This fiber is suspended. + * + * @pre @c is_resumable() should be true. + * + * @param other Fiber to resume. + */ + void suspend_self_and_resume_other_sysdep(cilk_fiber_sysdep* other); + + /** + * @brief System-dependent function called to jump to @p other + * fiber. + * + * @pre @c is_resumable() should be false. + * + * @param other Fiber to resume. + */ + NORETURN jump_to_resume_other_sysdep(cilk_fiber_sysdep* other); + + /** + * @brief Runs the start_proc. + * @pre is_resumable() should be false. + * @pre is_allocated_from_thread() should be false. + * @pre m_start_proc must be valid. + */ + NORETURN run(); + + /** + * @brief Returns the base of this fiber's stack. + */ + inline char* get_stack_base_sysdep() { return m_stack_base; } + + private: + char* m_stack_base; ///< The base of this fiber's stack. + char* m_stack; // Stack memory (low address) + __CILK_JUMP_BUFFER m_resume_jmpbuf; // Place to resume fiber + unsigned m_magic; // Magic number for checking + + static int s_page_size; // Page size for + // stacks. + + // Allocate memory for a stack. This method + // initializes m_stack and m_stack_base. + void make_stack(size_t stack_size); + + // Deallocates memory for the stack. + void free_stack(); + + // Common helper method for implementation of resume_other_sysdep + // variants. + inline void resume_other_sysdep(cilk_fiber_sysdep* other); +}; + +#endif // ! defined(INCLUDED_CILK_FIBER_UNIX_DOT_H) diff --git a/libcilkrts/runtime/cilk_fiber.cpp b/libcilkrts/runtime/cilk_fiber.cpp new file mode 100644 index 00000000000..0c66f234d3b --- /dev/null +++ b/libcilkrts/runtime/cilk_fiber.cpp @@ -0,0 +1,1078 @@ +/* cilk_fiber.cpp -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2012-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/* Implementations of non-platform-specific aspects of cilk_fiber, especially + * the cilk_fiber_pool interface. + */ +#include "cilk_fiber.h" +#ifdef _WIN32 +# include "cilk_fiber-win.h" +#else +# include "cilk_fiber-unix.h" +#endif +#include "cilk_malloc.h" +#include "bug.h" +#include <new> + +#include <climits> +#include <cstdio> +#include <cstdlib> +#include <cstring> + +#include "sysdep.h" + + +extern "C" { + +inline int cilk_fiber_pool_sanity_check(cilk_fiber_pool *pool, const char* desc) +{ + int errors = 0; +#if FIBER_DEBUG >= 1 + if ((NULL != pool) && pool->total > 0) { + + // Root pool should not allocate more fibers than alloc_max + errors += ((pool->parent == NULL) && + (pool->total > pool->alloc_max)); + errors += (pool->total > pool->high_water); + + if (errors) { + fprintf(stderr, "ERROR at %s: pool=%p has max_size=%u, total=%d, high_water=%d\n", + desc, + pool, pool->max_size, pool->total, pool->high_water); + } + } +#endif + return (errors == 0); +} + +inline void increment_pool_total(cilk_fiber_pool* pool) +{ + ++pool->total; + if (pool->high_water < pool->total) + pool->high_water = pool->total; +} + +inline void decrement_pool_total(cilk_fiber_pool* pool, int fibers_freed) +{ + pool->total -= fibers_freed; +} + + +/** + * @brief Free fibers from this pool until we have at most @c + * num_to_keep fibers remaining, and then put a fiber back. + * + * @pre We do not hold @c pool->lock + * @post After completion, we do not hold @c pool->lock + */ +static void cilk_fiber_pool_free_fibers_from_pool(cilk_fiber_pool* pool, + unsigned num_to_keep, + cilk_fiber* fiber_to_return) +{ + // Free our own fibers, until we fall below our desired threshold. + // Each iteration of this loop proceeds in the following stages: + // 1. Acquire the pool lock, + // 2. Grabs up to B fibers from the pool, stores them into a buffer. + // 3. Check if pool is empty enough. If yes, put the last fiber back, + // and remember that we should quit. + // 4. Release the pool lock, and actually free any buffered fibers. + // 5. Check if we are done and should exit the loop. Otherwise, try again. + // + const bool need_lock = pool->lock; + bool last_fiber_returned = false; + + do { + const int B = 10; // Pull at most this many fibers from the + // parent for one lock acquisition. Make + // this value large enough to amortize + // against the cost of acquiring and + // releasing the lock. + int num_to_free = 0; + cilk_fiber* fibers_to_free[B]; + + // Stage 1: Grab the lock. + if (need_lock) { + spin_mutex_lock(pool->lock); + } + + // Stage 2: Grab up to B fibers to free. + int fibers_freed = 0; + while ((pool->size > num_to_keep) && (num_to_free < B)) { + fibers_to_free[num_to_free++] = pool->fibers[--pool->size]; + fibers_freed++; + } + decrement_pool_total(pool, fibers_freed); + + // Stage 3. Pool is below threshold. Put extra fiber back. + if (pool->size <= num_to_keep) { + // Put the last fiber back into the pool. + if (fiber_to_return) { + CILK_ASSERT(pool->size < pool->max_size); + pool->fibers[pool->size] = fiber_to_return; + pool->size++; + } + last_fiber_returned = true; + } + + // Stage 4: Release the lock, and actually free any fibers + // buffered. + if (need_lock) { + spin_mutex_unlock(pool->lock); + } + + for (int i = 0; i < num_to_free; ++i) { + fibers_to_free[i]->deallocate_to_heap(); + } + + } while (!last_fiber_returned); +} + + +/****************************************************************** + * TBD: We want to simplify / rework the logic for allocating and + * deallocating fibers, so that they are hopefully simpler and work + * more elegantly for more than two levels. + ******************************************************************/ + +/** + * @brief Transfer fibers from @c pool to @c pool->parent. + * + * @pre Must hold @c pool->lock if it exists. + * @post After completion, some number of fibers + * have been moved from this pool to the parent. + * The lock @c pool->lock is still held. + * + * TBD: Do we wish to guarantee that the lock has never been + * released? It may depend on the implementation... + */ +static void cilk_fiber_pool_move_fibers_to_parent_pool(cilk_fiber_pool* pool, + unsigned num_to_keep) +{ + // ASSERT: We should hold the lock on pool (if it has one). + CILK_ASSERT(pool->parent); + cilk_fiber_pool* parent_pool = pool->parent; + + // Move fibers from our pool to the parent until we either run out + // of space in the parent, or hit our threshold. + // + // This operation must be done while holding the parent lock. + + // If the parent pool appears to be full, just return early. + if (parent_pool->size >= parent_pool->max_size) + return; + + spin_mutex_lock(pool->parent->lock); + while ((parent_pool->size < parent_pool->max_size) && + (pool->size > num_to_keep)) { + parent_pool->fibers[parent_pool->size++] = + pool->fibers[--pool->size]; + } + + // If the child pool has deallocated more than fibers to the heap + // than it has allocated, then transfer this "surplus" to the + // parent, so that the parent is free to allocate more from the + // heap. + // + // This transfer means that the total in the parent can + // temporarily go negative. + if (pool->total < 0) { + // Reduce parent total by the surplus we have in the local + // pool. + parent_pool->total += pool->total; + pool->total = 0; + } + + spin_mutex_unlock(pool->parent->lock); +} + +void cilk_fiber_pool_init(cilk_fiber_pool* pool, + cilk_fiber_pool* parent, + size_t stack_size, + unsigned buffer_size, + int alloc_max, + int is_shared) +{ +#if FIBER_DEBUG >= 1 + fprintf(stderr, "fiber_pool_init, pool=%p, parent=%p, alloc_max=%u\n", + pool, parent, alloc_max); +#endif + + pool->lock = (is_shared ? spin_mutex_create() : NULL); + pool->parent = parent; + pool->stack_size = stack_size; + pool->max_size = buffer_size; + pool->size = 0; + pool->total = 0; + pool->high_water = 0; + pool->alloc_max = alloc_max; + pool->fibers = + (cilk_fiber**) __cilkrts_malloc(buffer_size * sizeof(cilk_fiber*)); + CILK_ASSERT(NULL != pool->fibers); + +#ifdef __MIC__ +#define PREALLOCATE_FIBERS +#endif + +#ifdef PREALLOCATE_FIBERS + // Pre-allocate 1/4 of fibers in the pools ahead of time. This + // value is somewhat arbitrary. It was chosen to be less than the + // threshold (of about 3/4) of fibers to keep in the pool when + // transferring fibers to the parent. + + int pre_allocate_count = buffer_size/4; + for (pool->size = 0; pool->size < pre_allocate_count; pool->size++) { + pool->fibers[pool->size] = cilk_fiber::allocate_from_heap(pool->stack_size); + } +#endif +} + + +void cilk_fiber_pool_set_fiber_limit(cilk_fiber_pool* root_pool, + unsigned max_fibers_to_allocate) +{ + // Should only set limit on root pool, not children. + CILK_ASSERT(NULL == root_pool->parent); + root_pool->alloc_max = max_fibers_to_allocate; +} + +void cilk_fiber_pool_destroy(cilk_fiber_pool* pool) +{ + CILK_ASSERT(cilk_fiber_pool_sanity_check(pool, "pool_destroy")); + + // Lock my own pool, if I need to. + if (pool->lock) { + spin_mutex_lock(pool->lock); + } + + // Give any remaining fibers to parent pool. + if (pool->parent) { + cilk_fiber_pool_move_fibers_to_parent_pool(pool, 0); + } + + // Unlock pool. + if (pool->lock) { + spin_mutex_unlock(pool->lock); + } + + // If I have any left in my pool, just free them myself. + // This method may acquire the pool lock. + cilk_fiber_pool_free_fibers_from_pool(pool, 0, NULL); + + // Destroy the lock if there is one. + if (pool->lock) { + spin_mutex_destroy(pool->lock); + } + __cilkrts_free(pool->fibers); +} + + +cilk_fiber* cilk_fiber_allocate(cilk_fiber_pool* pool) +{ + CILK_ASSERT(cilk_fiber_pool_sanity_check(pool, "allocate")); + return cilk_fiber::allocate(pool); +} + +cilk_fiber* cilk_fiber_allocate_from_heap(size_t stack_size) +{ + return cilk_fiber::allocate_from_heap(stack_size); +} + +void cilk_fiber_reset_state(cilk_fiber* fiber, cilk_fiber_proc start_proc) +{ + fiber->reset_state(start_proc); +} + +int cilk_fiber_remove_reference(cilk_fiber *fiber, cilk_fiber_pool *pool) +{ + return fiber->remove_reference(pool); +} + +cilk_fiber* cilk_fiber_allocate_from_thread() +{ + return cilk_fiber::allocate_from_thread(); +} + +int cilk_fiber_deallocate_from_thread(cilk_fiber *fiber) +{ + return fiber->deallocate_from_thread(); +} + +int cilk_fiber_remove_reference_from_thread(cilk_fiber *fiber) +{ + return fiber->remove_reference_from_thread(); +} + +int cilk_fiber_is_allocated_from_thread(cilk_fiber *fiber) +{ + return fiber->is_allocated_from_thread(); +} + +#if SUPPORT_GET_CURRENT_FIBER +cilk_fiber* cilk_fiber_get_current_fiber(void) +{ + return cilk_fiber::get_current_fiber(); +} +#endif + +void cilk_fiber_suspend_self_and_resume_other(cilk_fiber* self, + cilk_fiber* other) +{ + self->suspend_self_and_resume_other(other); +} + + +void cilk_fiber::reset_state(cilk_fiber_proc start_proc) +{ + // Setup the fiber and return. + this->m_start_proc = start_proc; + + CILK_ASSERT(!this->is_resumable()); + CILK_ASSERT(NULL == this->m_pending_remove_ref); + CILK_ASSERT(NULL == this->m_pending_pool); +} + +NORETURN +cilk_fiber_remove_reference_from_self_and_resume_other(cilk_fiber* self, + cilk_fiber_pool* self_pool, + cilk_fiber* other) +{ +#if FIBER_DEBUG >= 3 + __cilkrts_worker* w = __cilkrts_get_tls_worker(); + fprintf(stderr, "W=%d: cilk_fiber_deactivate_self_and_resume_other: self=%p, other=%p\n", + w->self, + self, other); +#endif + CILK_ASSERT(cilk_fiber_pool_sanity_check(self_pool, "remove_reference_from_self_resume_other")); + self->remove_reference_from_self_and_resume_other(self_pool, other); + + // We should never return here. +} + +void cilk_fiber_set_post_switch_proc(cilk_fiber *self, + cilk_fiber_proc post_switch_proc) +{ + self->set_post_switch_proc(post_switch_proc); +} + +void cilk_fiber_invoke_tbb_stack_op(cilk_fiber* fiber, + __cilk_tbb_stack_op op) +{ + fiber->invoke_tbb_stack_op(op); +} + +cilk_fiber_data* cilk_fiber_get_data(cilk_fiber* fiber) +{ + return fiber->get_data(); + + /// TBD: Change this code to "return (cilk_fiber_data*)fiber;" + // plus a static assert, so that this function is + // more easily inlined by the compiler. +} + +int cilk_fiber_is_resumable(cilk_fiber *fiber) +{ + return fiber->is_resumable(); +} + +char* cilk_fiber_get_stack_base(cilk_fiber *fiber) +{ + return fiber->get_stack_base(); +} + + +#if defined(_WIN32) && 0 // Only works on Windows. Disable debugging for now. +#define DBG_STACK_OPS(_fmt, ...) __cilkrts_dbgprintf(_fmt, __VA_ARGS__) +#else +#define DBG_STACK_OPS(_fmt, ...) +#endif + +void cilk_fiber_set_stack_op(cilk_fiber *fiber, + __cilk_tbb_stack_op_thunk o) +{ + cilk_fiber_data *fdata = cilk_fiber_get_data(fiber); + DBG_STACK_OPS ("cilk_fiber_set_stack_op - cilk_fiber %p, routine: %p, data: %p\n", + fiber, + o.routine, + o.data); + fdata->stack_op_routine = o.routine; + fdata->stack_op_data = o.data; +} + +#if 0 // Debugging function +static +const char *NameStackOp (enum __cilk_tbb_stack_op op) +{ + switch(op) + { + case CILK_TBB_STACK_ORPHAN: return "CILK_TBB_STACK_ORPHAN"; + case CILK_TBB_STACK_ADOPT: return "CILK_TBB_STACK_ADOPT"; + case CILK_TBB_STACK_RELEASE: return "CILK_TBB_STACK_RELEASE"; + default: return "Unknown"; + } +} +#endif + +/* + * Save TBB interop information for an unbound thread. It will get picked + * up when the thread is bound to the runtime. + */ +void cilk_fiber_tbb_interop_save_stack_op_info(__cilk_tbb_stack_op_thunk o) +{ + __cilk_tbb_stack_op_thunk *saved_thunk = + __cilkrts_get_tls_tbb_interop(); + + DBG_STACK_OPS("Calling save_stack_op; o.routine=%p, o.data=%p, saved_thunk=%p\n", + o.routine, o.data, saved_thunk); + + // If there is not already space allocated, allocate some. + if (NULL == saved_thunk) { + saved_thunk = (__cilk_tbb_stack_op_thunk*) + __cilkrts_malloc(sizeof(__cilk_tbb_stack_op_thunk)); + __cilkrts_set_tls_tbb_interop(saved_thunk); + } + + *saved_thunk = o; + + DBG_STACK_OPS ("Unbound Thread %04x: tbb_interop_save_stack_op_info - saved info\n", + cilkos_get_current_thread_id()); +} + +/* + * Save TBB interop information from the cilk_fiber. It will get picked + * up when the thread is bound to the runtime next time. + */ +void cilk_fiber_tbb_interop_save_info_from_stack(cilk_fiber *fiber) +{ + __cilk_tbb_stack_op_thunk *saved_thunk; + cilk_fiber_data* fdata; + + if (NULL == fiber) + return; + + fdata = cilk_fiber_get_data(fiber); + // If there is no TBB interop data, just return + if (NULL == fdata->stack_op_routine) + return; + + saved_thunk = __cilkrts_get_tls_tbb_interop(); + + // If there is not already space allocated, allocate some. + if (NULL == saved_thunk) { + saved_thunk = (__cilk_tbb_stack_op_thunk*) + __cilkrts_malloc(sizeof(__cilk_tbb_stack_op_thunk)); + __cilkrts_set_tls_tbb_interop(saved_thunk); + } + + saved_thunk->routine = fdata->stack_op_routine; + saved_thunk->data = fdata->stack_op_data; +} + +/* + * If there's TBB interop information that was saved before the thread was + * bound, apply it now + */ +void cilk_fiber_tbb_interop_use_saved_stack_op_info(cilk_fiber* fiber) +{ + __cilk_tbb_stack_op_thunk *saved_thunk = + __cilkrts_get_tls_tbb_interop(); + + CILK_ASSERT(fiber); + // If we haven't allocated a TBB interop index, we don't have any saved info + if (NULL == saved_thunk) { + DBG_STACK_OPS ("cilk_fiber %p: tbb_interop_use_saved_stack_op_info - no saved info\n", + fiber); + return; + } + + DBG_STACK_OPS ("cilk_fiber %p: tbb_interop_use_saved_stack_op_info - using saved info\n", + fiber); + + // Associate the saved info with the __cilkrts_stack + cilk_fiber_set_stack_op(fiber, *saved_thunk); + + // Free the saved data. We'll save it again if needed when the code + // returns from the initial function + cilk_fiber_tbb_interop_free_stack_op_info(); +} + +/* + * Free saved TBB interop memory. Should only be called when the thread is + * not bound. + */ +void cilk_fiber_tbb_interop_free_stack_op_info(void) +{ + __cilk_tbb_stack_op_thunk *saved_thunk = + __cilkrts_get_tls_tbb_interop(); + + // If we haven't allocated a TBB interop index, we don't have any saved info + if (NULL == saved_thunk) + return; + + DBG_STACK_OPS ("tbb_interop_free_stack_op_info - freeing saved info\n"); + + // Free the memory and wipe out the TLS value + __cilkrts_free(saved_thunk); + __cilkrts_set_tls_tbb_interop(NULL); +} + + + +#if NEED_FIBER_REF_COUNTS +int cilk_fiber_has_references(cilk_fiber *fiber) +{ + return (fiber->get_ref_count() > 0); +} + +int cilk_fiber_get_ref_count(cilk_fiber *fiber) +{ + return fiber->get_ref_count(); +} + +void cilk_fiber_add_reference(cilk_fiber *fiber) +{ + fiber->inc_ref_count(); +} +#endif // NEED_FIBER_REF_COUNTS + + +} // End extern "C" + + +cilk_fiber_sysdep* cilk_fiber::sysdep() +{ + return static_cast<cilk_fiber_sysdep*>(this); +} + + +cilk_fiber::cilk_fiber() + : m_start_proc(NULL) + , m_post_switch_proc(NULL) + , m_pending_remove_ref(NULL) + , m_pending_pool(NULL) + , m_flags(0) +{ + // Clear cilk_fiber_data base-class data members + std::memset((cilk_fiber_data*) this, 0, sizeof(cilk_fiber_data)); + + // cilk_fiber data members + init_ref_count(0); +} + +cilk_fiber::cilk_fiber(std::size_t stack_size) +{ + *this = cilk_fiber(); // A delegating constructor would be nice here + this->stack_size = stack_size; +} + +cilk_fiber::~cilk_fiber() +{ + // Empty destructor. +} + + +char* cilk_fiber::get_stack_base() +{ + return this->sysdep()->get_stack_base_sysdep(); +} + +cilk_fiber* cilk_fiber::allocate_from_heap(std::size_t stack_size) +{ + // Case 1: pool is NULL. create a new fiber from the heap + // No need for locks here. + cilk_fiber_sysdep* ret = + (cilk_fiber_sysdep*) __cilkrts_malloc(sizeof(cilk_fiber_sysdep)); + + // Error condition. If we failed to allocate a fiber from the + // heap, we are in trouble though... + if (!ret) + return NULL; + + ::new(ret) cilk_fiber_sysdep(stack_size); + + CILK_ASSERT(0 == ret->m_flags); + CILK_ASSERT(NULL == ret->m_pending_remove_ref); + CILK_ASSERT(NULL == ret->m_pending_pool); + ret->init_ref_count(1); + return ret; +} + + +#if USE_FIBER_TRY_ALLOCATE_FROM_POOL +/** + * Helper method: try to allocate a fiber from this pool or its + * ancestors without going to the OS / heap. + * + * Returns allocated pool, or NULL if no pool is found. + * + * If pool contains a suitable fiber. Return it. Otherwise, try to + * recursively grab a fiber from the parent pool, if there is one. + * + * This method will not allocate a fiber from the heap. + * + * This method could be written either recursively or iteratively. + * It probably does not matter which one we do. + * + * @note This method is compiled, but may not be used unless the + * USE_FIBER_TRY_ALLOCATE_FROM_POOL switch is set. + */ +cilk_fiber* cilk_fiber::try_allocate_from_pool_recursive(cilk_fiber_pool* pool) +{ + cilk_fiber* ret = NULL; + + if (pool->size > 0) { + // Try to get the lock. + if (pool->lock) { + // For some reason, it seems to be better to just block on the parent + // pool lock, instead of using a try-lock? +#define USE_TRY_LOCK_IN_FAST_ALLOCATE 0 +#if USE_TRY_LOCK_IN_FAST_ALLOCATE + int got_lock = spin_mutex_trylock(pool->lock); + if (!got_lock) { + // If we fail, skip to the parent. + if (pool->parent) { + return try_allocate_from_pool_recursive(pool->parent); + } + } +#else + spin_mutex_lock(pool->lock); +#endif + } + + // Check in the pool if we have the lock. + if (pool->size > 0) { + ret = pool->fibers[--pool->size]; + } + + // Release the lock once we are done updating pool fields. + if (pool->lock) { + spin_mutex_unlock(pool->lock); + } + } + + if ((!ret) && (pool->parent)) { + return try_allocate_from_pool_recursive(pool->parent); + } + + if (ret) { + // When we pull a fiber out of the pool, set its reference + // count before we return it. + ret->init_ref_count(1); + } + return ret; +} +#endif // USE_FIBER_TRY_ALLOCATE_FROM_POOL + + +cilk_fiber* cilk_fiber::allocate(cilk_fiber_pool* pool) +{ + // Pool should not be NULL in this method. But I'm not going to + // actually assert it, because we are likely to seg fault anyway + // if it is. + // CILK_ASSERT(NULL != pool); + + cilk_fiber *ret = NULL; + +#if USE_FIBER_TRY_ALLOCATE_FROM_POOL + // "Fast" path, which doesn't go to the heap or OS until checking + // the ancestors first. + ret = try_allocate_from_pool_recursive(pool); + if (ret) + return ret; +#endif + + // If we don't get anything from the "fast path", then go through + // a slower path to look for a fiber. + // + // 1. Lock the pool if it is shared. + // 2. Look in our local pool. If we find one, release the lock + // and quit searching. + // 3. Otherwise, check whether we can allocate from heap. + // 4. Release the lock if it was acquired. + // 5. Try to allocate from the heap, if step 3 said we could. + // If we find a fiber, then quit searching. + // 6. If none of these steps work, just recursively try again + // from the parent. + + // 1. Lock the pool if it is shared. + if (pool->lock) { + spin_mutex_lock(pool->lock); + } + + // 2. Look in local pool. + if (pool->size > 0) { + ret = pool->fibers[--pool->size]; + if (ret) { + // If we found one, release the lock once we are + // done updating pool fields, and break out of the + // loop. + if (pool->lock) { + spin_mutex_unlock(pool->lock); + } + + // When we pull a fiber out of the pool, set its reference + // count just in case. + ret->init_ref_count(1); + return ret; + } + } + + // 3. Check whether we can allocate from the heap. + bool can_allocate_from_heap = false; + if (pool->total < pool->alloc_max) { + // Track that we are allocating a new fiber from the + // heap, originating from this pool. + // This increment may be undone if we happen to fail to + // allocate from the heap. + increment_pool_total(pool); + can_allocate_from_heap = true; + } + + // 4. Unlock the pool, and then allocate from the heap. + if (pool->lock) { + spin_mutex_unlock(pool->lock); + } + + // 5. Actually try to allocate from the heap / OS. + if (can_allocate_from_heap) { + ret = allocate_from_heap(pool->stack_size); + // If we got something from the heap, just return it. + if (ret) { + return ret; + } + + // Otherwise, we failed in our attempt to allocate a + // fiber from the heap. Grab the lock and decrement + // the total again. + if (pool->lock) { + spin_mutex_lock(pool->lock); + } + decrement_pool_total(pool, 1); + if (pool->lock) { + spin_mutex_unlock(pool->lock); + } + } + + // 6. If we get here, then searching this pool failed. Go search + // the parent instead if we have one. + if (pool->parent) { + return allocate(pool->parent); + } + + return ret; +} + +int cilk_fiber::remove_reference(cilk_fiber_pool* pool) +{ + int ref_count = this->dec_ref_count(); + if (ref_count == 0) { + if (pool) { + deallocate_self(pool); + } + else { + deallocate_to_heap(); + } + } + return ref_count; +} + +cilk_fiber* cilk_fiber::allocate_from_thread() +{ + void* retmem = __cilkrts_malloc(sizeof(cilk_fiber_sysdep)); + CILK_ASSERT(retmem); + cilk_fiber_sysdep* ret = ::new(retmem) cilk_fiber_sysdep(from_thread); + + // A fiber allocated from a thread begins with a reference count + // of 2. The first is for being created, and the second is for + // being running. + // + // Suspending this fiber will decrement the count down to 1. + ret->init_ref_count(2); + +#if SUPPORT_GET_CURRENT_FIBER + // We're creating the main fiber for this thread. Set this fiber as the + // current fiber. + cilkos_set_tls_cilk_fiber(ret); +#endif + return ret; +} + +int cilk_fiber::deallocate_from_thread() +{ + CILK_ASSERT(this->is_allocated_from_thread()); +#if SUPPORT_GET_CURRENT_FIBER + CILK_ASSERT(this == cilkos_get_tls_cilk_fiber()); + // Reverse of "allocate_from_thread". + cilkos_set_tls_cilk_fiber(NULL); +#endif + + this->assert_ref_count_at_least(2); + + // Suspending the fiber should conceptually decrement the ref + // count by 1. + cilk_fiber_sysdep* self = this->sysdep(); + self->convert_fiber_back_to_thread(); + + // Then, freeing the fiber itself decrements the ref count again. + int ref_count = this->sub_from_ref_count(2); + if (ref_count == 0) { + self->~cilk_fiber_sysdep(); + __cilkrts_free(self); + } + return ref_count; +} + +int cilk_fiber::remove_reference_from_thread() +{ + int ref_count = dec_ref_count(); + if (ref_count == 0) { + cilk_fiber_sysdep* self = this->sysdep(); + self->~cilk_fiber_sysdep(); + __cilkrts_free(self); + } + return ref_count; +} + + +#if SUPPORT_GET_CURRENT_FIBER +cilk_fiber* cilk_fiber::get_current_fiber() +{ + return cilk_fiber_sysdep::get_current_fiber_sysdep(); +} +#endif + +void cilk_fiber::do_post_switch_actions() +{ + if (m_post_switch_proc) + { + cilk_fiber_proc proc = m_post_switch_proc; + m_post_switch_proc = NULL; + proc(this); + } + + if (m_pending_remove_ref) + { + m_pending_remove_ref->remove_reference(m_pending_pool); + + // Even if we don't free it, + m_pending_remove_ref = NULL; + m_pending_pool = NULL; + } +} + +void cilk_fiber::suspend_self_and_resume_other(cilk_fiber* other) +{ +#if FIBER_DEBUG >=1 + fprintf(stderr, "suspend_self_and_resume_other: self =%p, other=%p [owner=%p, resume_sf=%p]\n", + this, other, other->owner, other->resume_sf); +#endif + + // Decrement my reference count (to suspend) + // Increment other's count (to resume) + // Suspended fiber should have a reference count of at least 1. (It is not in a pool). + this->dec_ref_count(); + other->inc_ref_count(); + this->assert_ref_count_at_least(1); + + // Pass along my owner. + other->owner = this->owner; + this->owner = NULL; + + // Change this fiber to resumable. + CILK_ASSERT(!this->is_resumable()); + this->set_resumable(true); + + // Normally, I'd assert other->is_resumable(). But this flag may + // be false the first time we try to "resume" a fiber. + cilk_fiber_sysdep* self = this->sysdep(); + self->suspend_self_and_resume_other_sysdep(other->sysdep()); + + // HAVE RESUMED EXECUTION + // When we come back here, we should have at least two references: + // one for the fiber being allocated / out of a pool, and one for it being active. + this->assert_ref_count_at_least(2); +} + +NORETURN +cilk_fiber::remove_reference_from_self_and_resume_other(cilk_fiber_pool* self_pool, + cilk_fiber* other) +{ + // Decrement my reference count once (to suspend) + // Increment other's count (to resume) + // Suspended fiber should have a reference count of at least 1. (It is not in a pool). + this->dec_ref_count(); + other->inc_ref_count(); + + // Set a pending remove reference for this fiber, once we have + // actually switched off. + other->m_pending_remove_ref = this; + other->m_pending_pool = self_pool; + + // Pass along my owner. + other->owner = this->owner; + this->owner = NULL; + + // Since we are deallocating self, this fiber does not become + // resumable. + CILK_ASSERT(!this->is_resumable()); + + cilk_fiber_sysdep* self = this->sysdep(); + self->jump_to_resume_other_sysdep(other->sysdep()); + + __cilkrts_bug("Deallocating fiber. We should never come back here."); + std::abort(); +} + + +void cilk_fiber::deallocate_to_heap() +{ + cilk_fiber_sysdep* self = this->sysdep(); + self->~cilk_fiber_sysdep(); + __cilkrts_free(self); +} + +void cilk_fiber::deallocate_self(cilk_fiber_pool* pool) +{ + this->set_resumable(false); + + CILK_ASSERT(NULL != pool); + CILK_ASSERT(!this->is_allocated_from_thread()); + this->assert_ref_count_equals(0); + + // Cases: + // + // 1. pool has space: Add to this pool. + // 2. pool is full: Give some fibers to parent, and then free + // enough to make space for the fiber we are deallocating. + // Then put the fiber back into the pool. + + const bool need_lock = pool->lock; + // Grab the lock for the remaining cases. + if (need_lock) { + spin_mutex_lock(pool->lock); + } + + // Case 1: this pool has space. Return the fiber. + if (pool->size < pool->max_size) + { + // Add this fiber to pool + pool->fibers[pool->size++] = this; + if (need_lock) { + spin_mutex_unlock(pool->lock); + } + return; + } + + // Case 2: Pool is full. + // + // First free up some space by giving fibers to the parent. + if (pool->parent) + { + // Pool is full. Move all but "num_to_keep" fibers to parent, + // if we can. + unsigned num_to_keep = pool->max_size/2 + pool->max_size/4; + cilk_fiber_pool_move_fibers_to_parent_pool(pool, num_to_keep); + } + + if (need_lock) { + spin_mutex_unlock(pool->lock); + } + + // Now, free a fiber to make room for the one we need to put back, + // and then put this fiber back. This step may actually return + // fibers to the heap. + cilk_fiber_pool_free_fibers_from_pool(pool, pool->max_size -1, this); +} + + +// NOTE: Except for print-debug, this code is the same as in Windows. +void cilk_fiber::invoke_tbb_stack_op(__cilk_tbb_stack_op op) +{ + cilk_fiber_data *fdata = this->get_data(); + + if (0 == fdata->stack_op_routine) + { + if (CILK_TBB_STACK_RELEASE != op) + DBG_STACK_OPS ("Wkr %p: invoke_tbb_stack_op - %s (%d) for cilk_fiber %p, fiber %p, thread id %04x - No stack op routine\n", + fdata->owner, + NameStackOp(op), + op, + fdata, + this, + cilkos_get_current_thread_id()); + return; + } + + // Call TBB to do it's thing + DBG_STACK_OPS ("Wkr %p: invoke_tbb_stack_op - op %s data %p for cilk_fiber %p, fiber %p, thread id %04x\n", + fdata->owner, + NameStackOp(op), + fdata->stack_op_data, + fdata, + this, + cilkos_get_current_thread_id()); + + (*fdata->stack_op_routine)(op, fdata->stack_op_data); + if (op == CILK_TBB_STACK_RELEASE) + { + fdata->stack_op_routine = 0; + fdata->stack_op_data = 0; + } +} + + + +#if NEED_FIBER_REF_COUNTS + +void cilk_fiber::atomic_inc_ref_count() +{ + cilkos_atomic_add(&m_outstanding_references, 1); +} + +long cilk_fiber::atomic_dec_ref_count() +{ + return cilkos_atomic_add(&m_outstanding_references, -1); +} + +long cilk_fiber::atomic_sub_from_ref_count(long v) +{ + return cilkos_atomic_add(&m_outstanding_references, -v); +} + +#endif // NEED_FIBER_REF_COUNTS + +/* End cilk_fibers.cpp */ diff --git a/libcilkrts/runtime/cilk_fiber.h b/libcilkrts/runtime/cilk_fiber.h new file mode 100644 index 00000000000..2671f924681 --- /dev/null +++ b/libcilkrts/runtime/cilk_fiber.h @@ -0,0 +1,882 @@ +/* cilk_fiber.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2012-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** + * @file cilk_fiber.h + * + * @brief Abstraction of a "fiber": A coprocess-like stack and auxiliary data + */ + +#ifndef INCLUDED_CILK_FIBER_DOT_H +#define INCLUDED_CILK_FIBER_DOT_H + +#include <cilk/common.h> +#ifdef __cplusplus +# include <cstddef> +#else +# include <stddef.h> +#endif + +#include "bug.h" +#include "cilk-tbb-interop.h" +#include "spin_mutex.h" +#include "internal/abi.h" // Define __cilkrts_stack_frame + +/** + * @brief Debugging level for Cilk fiber code. + * + * A value of 0 means no debugging. + * Higher values generate more debugging output. + */ +#define FIBER_DEBUG 0 + +/** + * @brief Flag for validating reference counts. + * + * Set to 1 to assert that fiber reference counts are reasonable. + */ +#define FIBER_CHECK_REF_COUNTS 1 + +/** + * @brief Flag to determine whether fibers support reference counting. + * We require reference counting only on Windows, for exception + * processing. Unix does not need reference counting. + */ +#if defined(_WIN32) +# define NEED_FIBER_REF_COUNTS 1 +#endif + +/** + * @brief Flag to enable support for the + * cilk_fiber_get_current_fiber() method. + * + * I'd like this flag to be 0. However, the cilk_fiber test depends + * on being able to call this method. + */ +#if !defined(SUPPORT_GET_CURRENT_FIBER) +# define SUPPORT_GET_CURRENT_FIBER 0 +#endif + +/** + * @brief Switch for enabling "fast path" check for fibers, which + * doesn't go to the heap or OS until checking the ancestors first. + * + * Doing this check seems to make the stress test in + * cilk_fiber_pool.t.cpp run faster. But it doesn't seem to make much + * difference in other benchmarks, so it is disabled by default. + */ +#define USE_FIBER_TRY_ALLOCATE_FROM_POOL 0 + + +__CILKRTS_BEGIN_EXTERN_C + +/// @brief Forward reference to fiber pool. +typedef struct cilk_fiber_pool cilk_fiber_pool; + +/** @brief Opaque data structure representing a fiber */ +typedef struct cilk_fiber cilk_fiber; + +/** @brief Function pointer type for use as a fiber's "main" procedure */ +typedef void (*cilk_fiber_proc)(cilk_fiber*); + +/** @brief Data structure associated with each fiber. */ +typedef struct cilk_fiber_data +{ + __STDNS size_t stack_size; /**< Size of stack for fiber */ + __cilkrts_worker* owner; /**< Worker using this fiber */ + __cilkrts_stack_frame* resume_sf; /**< Stack frame to resume */ + __cilk_tbb_pfn_stack_op stack_op_routine; /**< Cilk/TBB interop callback */ + void* stack_op_data; /**< Data for Cilk/TBB callback */ + void* client_data; /**< Data managed by client */ + +#ifdef _WIN32 + char *initial_sp; /**< Initalized in fiber_stub */ +# ifdef _WIN64 + char *steal_frame_sp; /**< RSP for frame stealing work */ + // Needed for exception handling so we can + // identify when about to unwind off stack +# endif +#endif + +} cilk_fiber_data; + +/** @brief Pool of cilk_fiber for fiber reuse + * + * Pools form a hierarchy, with each pool pointing to its parent. When the + * pool undeflows, it gets a fiber from its parent. When a pool overflows, + * it returns some fibers to its parent. If the root pool underflows, it + * allocates and initializes a new fiber from the heap but only if the total + * is less than max_size; otherwise, fiber creation fails. + */ +struct cilk_fiber_pool +{ + spin_mutex* lock; ///< Mutual exclusion for pool operations + __STDNS size_t stack_size; ///< Size of stacks for fibers in this pool. + cilk_fiber_pool* parent; ///< @brief Parent pool. + ///< If this pool is empty, get from parent + + // Describes inactive fibers stored in the pool. + cilk_fiber** fibers; ///< Array of max_size fiber pointers + unsigned max_size; ///< Limit on number of fibers in pool + unsigned size; ///< Number of fibers currently in the pool + + // Statistics on active fibers that were allocated from this pool, + // but no longer in the pool. + int total; ///< @brief Fibers allocated - fiber deallocated from pool + ///< total may be negative for non-root pools. + int high_water; ///< High water mark of total fibers + int alloc_max; ///< Limit on number of fibers allocated from the heap/OS +}; + +/** @brief Initializes a cilk_fiber_pool structure + * + * @param pool - The address of the pool that is to be initialized + * @param parent - The address of this pool's parent, or NULL for root pool + * @param stack_size - Size of stacks for fibers allocated from this pool. + * @param buffer_size - The maximum number of fibers that may be pooled. + * @param alloc_max - Limit on # of fibers this pool can allocate from the heap. + * @param is_shared - True if accessing this pool needs a lock, false otherwise. + */ +void cilk_fiber_pool_init(cilk_fiber_pool* pool, + cilk_fiber_pool* parent, + size_t stack_size, + unsigned buffer_size, + int alloc_max, + int is_shared); + +/** @brief Sets the maximum number of fibers to allocate from a root pool. + * + * @param root_pool - A root fiber pool + * @param max_fibers_to_allocate - The limit on # of fibers to allocate. + * + * Sets the maximum number of fibers that can be allocated from this + * pool and all its descendants. This pool must be a root pool. + */ +void cilk_fiber_pool_set_fiber_limit(cilk_fiber_pool* root_pool, + unsigned max_fibers_to_allocate); + +/** @brief De-initalizes a cilk_fiber_pool + * + * @param pool - The address of the pool that is to be destroyed + */ +void cilk_fiber_pool_destroy(cilk_fiber_pool* pool); + +/** @brief Allocates a new cilk_fiber. + * + * If the specified pool is empty, this method may choose to either + * allocate a fiber from the heap (if pool->total < pool->alloc_max), + * or retrieve a fiber from the parent pool. + * + * @note If a non-null fiber is returned, @c cilk_fiber_reset_state + * should be called on this fiber before using it. + * + * An allocated fiber begins with a reference count of 1. + * This method may lock @c pool or one of its ancestors. + * + * @pre pool should not be NULL. + * + * @param pool The fiber pool from which to retrieve a fiber. + * @return An allocated fiber, or NULL if failed to allocate. + */ +cilk_fiber* cilk_fiber_allocate(cilk_fiber_pool* pool); + +/** @brief Allocate and initialize a new cilk_fiber using memory from + * the heap and/or OS. + * + * The allocated fiber begins with a reference count of 1. + * + * @param stack_size The size (in bytes) to be allocated for the fiber's + * stack. + * @return An initialized fiber. This method should not return NULL + * unless some exceptional condition has occurred. + */ +cilk_fiber* cilk_fiber_allocate_from_heap(size_t stack_size); + + +/** @brief Resets an fiber object just allocated from a pool with the + * specified proc. + * + * After this call, cilk_fiber_data object associated with this fiber + * is filled with zeros. + * + * This function can be called only on a fiber that has been allocated + * from a pool, but never used. + * + * @param fiber The fiber to reset and initialize. + * @param start_proc The function to run when switching to the fiber. If + * null, the fiber can be used with cilk_fiber_run_proc() + * but not with cilk_fiber_resume(). + */ +void cilk_fiber_reset_state(cilk_fiber* fiber, + cilk_fiber_proc start_proc); + +/** @brief Remove a reference from this fiber, possibly deallocating it. + * + * This fiber is deallocated only when there are no other references + * to it. Deallocation happens either by returning the fiber to the + * specified pool, or returning it to the heap. + * + * A fiber that is currently executing should not remove the last + * reference to itself. + * + * When a fiber is deallocated, destructors are not called for the + * objects (if any) still on its stack. The fiber's stack and fiber + * data is returned to the stack pool but the client fiber data is not + * deallocated. + * + * If the pool overflows because of a deallocation, then some fibers + * will be returned to the parent pool. If the root pool overflows, + * then the fiber is returned to the heap. + * + * @param fiber The Cilk fiber to remove a reference to. + * @param pool The fiber pool to which the fiber should be returned. The + * caller is assumed to have exclusive access to the pool + * either because there is no contention for it or because + * its lock has been acquired. If pool is NULL, any + * deallocated fiber is destroyed and returned to the + * heap. + * + * @return Final reference count. If the count is 0, the fiber was + * returned to a pool or the heap. + */ +int cilk_fiber_remove_reference(cilk_fiber *fiber, cilk_fiber_pool *pool); + +/** @brief Allocates and intializes this thread's main fiber + * + * Each thread has an "implicit" main fiber that control's the + * thread's initial stack. This function makes this fiber visible to + * the client and allocates the Cilk-specific aspects of the implicit + * fiber. A call to this function must be paired with a call to + * cilk_fiber_deallocate_fiber_from_thread() + * or a memory leak (or worse) will result. + * + * A fiber allocated from a thread begins with a reference count of 2. + * One is for being allocated, and one is for being active. + * (A fiber created from a thread is automatically currently executing.) + * The matching calls above each decrement the reference count by 1. + * + * @return A fiber for the currently executing thread. + */ +cilk_fiber* cilk_fiber_allocate_from_thread(void); + +/** @brief Remove a fiber created from a thread, + * possibly deallocating it. + * + * Same as cilk_fiber_remove_reference, except that it works on fibers + * created via cilk_fiber_allocate_from_thread(). + * + * Fibers created from a thread are never returned to a pool. + * + * @param fiber The Cilk fiber to remove a reference from. + * @return Final reference count. If the count is 0, the fiber was + * returned to the heap. + */ +int cilk_fiber_remove_reference_from_thread(cilk_fiber *fiber); + +/** @brief Deallocate a fiber created from a thread, + * possibly destroying it. + * + * This method decrements the reference count of the fiber by 2, and + * destroys the fiber struct if the reference count is 0. + * + * OS-specific cleanup for the fiber executes unconditionally with + * this method. The destruction of the actual object, however, does + * not occur unless the reference count is 0. + * + * @param fiber The cilk_fiber to deallocate from a thread. + * @return Final reference count. If the count is 0, the fiber was + * returned to the heap. + */ +int cilk_fiber_deallocate_from_thread(cilk_fiber *fiber); + +/** @brief Returns true if this fiber is allocated from a thread. + */ +int cilk_fiber_is_allocated_from_thread(cilk_fiber *fiber); + + +/** @brief Suspend execution on current fiber resumes other fiber. + * + * Suspends the current fiber and transfers control to a new fiber. Execution + * on the new fiber resumes from the point at which fiber suspended itself to + * run a different fiber. If fiber was freshly allocated, then runs the + * start_proc function specified at allocation. This function returns when + * another fiber resumes the self fiber. Note that the state of the + * floating-point control register (i.e., the register that controls rounding + * mode, etc.) is valid but indeterminate on return -- different + * implementations will have different results. + * + * When the @c self fiber is resumed, execution proceeds as though + * this function call returns. + * + * This operation increments the reference count of @p other. + * This operation decrements the reference count of @p self. + * + * @param self Fiber to switch from. Must equal current fiber. + * @param other Fiber to switch to. + */ +void cilk_fiber_suspend_self_and_resume_other(cilk_fiber* self, + cilk_fiber* other); + +/** @brief Removes a reference from the currently executing fiber and + * resumes other fiber. + * + * Removes a reference from @p self and transfer control to @p other + * fiber. Execution on @p other resumes from the point at which @p + * other suspended itself to run a different fiber. If @p other fiber + * was freshly allocated, then runs the function specified at + * creation. + * + * + * This operation increments the reference count of @p other. + * + * This operation conceptually decrements the reference count of + * @p self twice, once to suspend it, and once to remove a reference to + * it. Then, if the count is 0, it is returned to the specified pool + * or destroyed. + * + * @pre @p self is the currently executing fiber. + * + * @param self Fiber to remove reference switch from. + * @param self_pool Pool to which the current fiber should be returned + * @param other Fiber to switch to. + */ +NORETURN +cilk_fiber_remove_reference_from_self_and_resume_other(cilk_fiber* self, + cilk_fiber_pool* self_pool, + cilk_fiber* other); + +/** @brief Set the proc method to execute immediately after a switch + * to this fiber. + * + * The @c post_switch_proc method executes immediately after switching + * away form @p self fiber to some other fiber, but before @c self + * gets cleaned up. + * + * @note A fiber can have only one post_switch_proc method at a time. + * If this method is called multiple times before switching to the + * fiber, only the last proc method will execute. + * + * @param self Fiber. + * @param post_switch_proc Proc method to execute immediately after switching to this fiber. + */ +void cilk_fiber_set_post_switch_proc(cilk_fiber* self, cilk_fiber_proc post_switch_proc); + +/** @brief Invoke TBB stack op for this fiber. + * + * @param fiber Fiber to invoke stack op for. + * @param op The stack op to invoke + */ +void cilk_fiber_invoke_tbb_stack_op(cilk_fiber* fiber, __cilk_tbb_stack_op op); + +/** @brief Returns the fiber data associated with the specified fiber. + * + * The returned struct is owned by the fiber and is deallocated automatically + * when the fiber is destroyed. However, the client_data field is owned by + * the client and must be deallocated separately. When called for a + * newly-allocated fiber, the returned data is zero-filled. + * + * @param fiber The fiber for which data is being requested. + * @return The fiber data for the specified fiber + */ +cilk_fiber_data* cilk_fiber_get_data(cilk_fiber* fiber); + +/** @brief Retrieve the owner field from the fiber. + * + * This method is provided for convenience. One can also get the + * fiber data, and then get the owner field. + */ +__CILKRTS_INLINE +__cilkrts_worker* cilk_fiber_get_owner(cilk_fiber* fiber) +{ + // TBD: We really want a static assert here, that this cast is + // doing the right thing. + cilk_fiber_data* fdata = (cilk_fiber_data*)fiber; + return fdata->owner; +} + +/** @brief Sets the owner field of a fiber. + * + * This method is provided for convenience. One can also get the + * fiber data, and then get the owner field. + */ +__CILKRTS_INLINE +void cilk_fiber_set_owner(cilk_fiber* fiber, __cilkrts_worker* owner) +{ + // TBD: We really want a static assert here, that this cast is + // doing the right thing. + cilk_fiber_data* fdata = (cilk_fiber_data*)fiber; + fdata->owner = owner; +} + +/** @brief Returns true if this fiber is resumable. + * + * A fiber is considered resumable when it is not currently being + * executed. + * + * This function is used by Windows exception code. + * @param fiber The fiber to check. + * @return Nonzero value if fiber is resumable. + */ +int cilk_fiber_is_resumable(cilk_fiber* fiber); + +/** + * @brief Returns the base of this fiber's stack. + * + * On some platforms (e.g., Windows), the fiber must have started + * running before we can get this information. + * + * @param fiber The fiber to get the stack pointer from. + * @return The base of the stack, or NULL if this + * information is not available yet. + */ +char* cilk_fiber_get_stack_base(cilk_fiber* fiber); + + +/**************************************************************************** + * TBB interop functions + * **************************************************************************/ +/** + * @brief Set the TBB callback information for a stack + * + * @param fiber The fiber to set the TBB callback information for + * @param o The TBB callback thunk. Specifies the callback address and + * context value. + */ +void cilk_fiber_set_stack_op(cilk_fiber *fiber, + __cilk_tbb_stack_op_thunk o); + +/** + * @brief Save the TBB callback address and context value in + * thread-local storage. + * + * We'll use it later when the thread binds to a worker. + * + * @param o The TBB callback thunk which is to be saved. + */ +void cilk_fiber_tbb_interop_save_stack_op_info(__cilk_tbb_stack_op_thunk o); + +/** + * @brief Move TBB stack-op info from thread-local storage and store + * it into the fiber. + * + * Called when we bind a thread to the runtime. If there is any TBB + * interop information in thread-local storage, bind it to the stack + * now. + * + * @pre \c fiber should not be NULL. + * @param fiber The fiber that should take over the TBB interop information. + */ +void cilk_fiber_tbb_interop_use_saved_stack_op_info(cilk_fiber *fiber); + +/** + * @brief Free any TBB interop information saved in thread-local storage + */ +void cilk_fiber_tbb_interop_free_stack_op_info(void); + +/** + * @brief Migrate any TBB interop information from a cilk_fiber to + * thread-local storage. + * + * Returns immediately if no TBB interop information has been + * associated with the stack. + * + * @param fiber The cilk_fiber who's TBB interop information should be + * saved in thread-local storage. + */ +void cilk_fiber_tbb_interop_save_info_from_stack(cilk_fiber* fiber); + + +#if SUPPORT_GET_CURRENT_FIBER +/** @brief Returns the fiber associated with the currently executing thread + * + * @note This function is currently used only for testing the Cilk + * runtime. + * + * @return Fiber associated with the currently executing thread or NULL if no + * fiber was associated with this thread. + */ +cilk_fiber* cilk_fiber_get_current_fiber(void); +#endif + + +#if NEED_FIBER_REF_COUNTS +/** @brief Returns true if this fiber has reference count > 0. + * + * @param fiber The fiber to check for references. + * @return Nonzero value if the fiber has references. + */ +int cilk_fiber_has_references(cilk_fiber *fiber); + +/** @brief Returns the value of the reference count. + * + * @param fiber The fiber to check for references. + * @return The value of the reference count of fiber. + */ +int cilk_fiber_get_ref_count(cilk_fiber *fiber); + +/** @brief Adds a reference to this fiber. + * + * Increments the reference count of a current fiber. Fibers with + * nonzero reference count will not be freed or returned to a fiber + * pool. + * + * @param fiber The fiber to add a reference to. + */ +void cilk_fiber_add_reference(cilk_fiber *fiber); + +#endif // NEED_FIBER_REF_COUNTS + +__CILKRTS_END_EXTERN_C + +#ifdef __cplusplus +// Some C++ implementation details + +/// Opaque declaration of a cilk_fiber_sysdep object. +struct cilk_fiber_sysdep; + +/** + * cilk_fiber is a base-class for system-dependent fiber implementations. + */ +struct cilk_fiber : protected cilk_fiber_data +{ + protected: + // This is a rare acceptable use of protected inheritence and protected + // variable access: when the base class and derived class collaborate + // tightly to comprise a single component. + + /// For overloading constructor of cilk_fiber. + enum from_thread_t { from_thread = 1 }; + + // Boolean flags capturing the status of the fiber. + // Each one can be set independently. + // A default fiber is constructed with a flag value of 0. + static const int RESUMABLE = 0x01; ///< True if the fiber is in a suspended state and can be resumed. + static const int ALLOCATED_FROM_THREAD = 0x02; ///< True if fiber was allocated from a thread. + + cilk_fiber_proc m_start_proc; ///< Function to run on start up/reset + cilk_fiber_proc m_post_switch_proc; ///< Function that executes when we first switch to a new fiber from a different one. + + cilk_fiber* m_pending_remove_ref;///< Fiber to possibly delete on start up or resume + cilk_fiber_pool* m_pending_pool; ///< Pool where m_pending_remove_ref should go if it is deleted. + unsigned m_flags; ///< Captures the status of this fiber. + +#if NEED_FIBER_REF_COUNTS + volatile long m_outstanding_references; ///< Counts references to this fiber. +#endif + + /// Creates a fiber with NULL data. + cilk_fiber(); + + /** + * @brief Creates a fiber with user-specified arguments. + * + * @param stack_size Size of stack to use for this fiber. + */ + cilk_fiber(std::size_t stack_size); + + /// Empty destructor. + ~cilk_fiber(); + + /** + * @brief Performs any actions that happen after switching from + * one fiber to another. + * + * These actions are: + * 1. Execute m_post_switch_proc on a fiber. + * 2. Do any pending deallocations from the previous fiber. + */ + void do_post_switch_actions(); + + /** + *@brief Helper method that converts a @c cilk_fiber object into a + * @c cilk_fiber_sysdep object. + * + * The @c cilk_fiber_sysdep object contains the system-dependent parts + * of the implementation of a @\c cilk_fiber. + * + * We could have @c cilk_fiber_sysdep inherit from @c cilk_fiber and + * then use virtual functions. But since a given platform only uses + * one definition of @c cilk_fiber_sysdep at a time, we statically + * cast between them. + */ + inline cilk_fiber_sysdep* sysdep(); + + /** + * @brief Set resumable flag to specified state. + */ + inline void set_resumable(bool state) { + m_flags = state ? (m_flags | RESUMABLE) : (m_flags & (~RESUMABLE)); + } + + /** + *@brief Set the allocated_from_thread flag. + */ + inline void set_allocated_from_thread(bool state) { + m_flags = state ? (m_flags | ALLOCATED_FROM_THREAD) : (m_flags & (~ALLOCATED_FROM_THREAD)); + } + + public: + + /** + * @brief Allocates and initializes a new cilk_fiber, either from + * the specified pool or from the heap. + * + * @pre pool should not be NULL. + */ + static cilk_fiber* allocate(cilk_fiber_pool* pool); + + /** + * @brief Allocates a fiber from the heap. + */ + static cilk_fiber* allocate_from_heap(size_t stack_size); + + /** + * @brief Return a fiber to the heap. + */ + void deallocate_to_heap(); + + /** + * @brief Reset the state of a fiber just allocated from a pool. + */ + void reset_state(cilk_fiber_proc start_proc); + + /** + * @brief Remove a reference from this fiber, possibly + * deallocating it if the reference count becomes 0. + * + * @param pool The fiber pool to which this fiber should be returned. + * @return The final reference count. + */ + int remove_reference(cilk_fiber_pool* pool); + + /** + * @brief Deallocate the fiber by returning it to the pool. + * @pre This method should only be called if the reference count + * is 0. + * + * @param pool The fiber pool to return this fiber to. If NULL, + * fiber is returned to the heap. + */ + void deallocate_self(cilk_fiber_pool *pool); + + /** @brief Allocates and intializes this thread's main fiber. */ + static cilk_fiber* allocate_from_thread(); + + /** @brief Deallocate a fiber created from a thread, + * possibly destroying it. + * + * This method decrements the reference count of this fiber by 2, + * and destroys the fiber if the reference count is 0. + * + * OS-specific cleanup for the fiber executes unconditionally with for + * this method. The destruction of the actual object, however, does + * not occur unless the reference count is 0. + * + * @return Final reference count. If the count is 0, the fiber was + * returned to the heap. + */ + int deallocate_from_thread(); + + /** @brief Removes a reference from this fiber. + * + * This method deallocates this fiber if the reference count + * becomes 0. + * + * @pre This fiber must be allocated from a thread. + * @return The final reference count of this fiber. + */ + int remove_reference_from_thread(); + +#if SUPPORT_GET_CURRENT_FIBER + /** @brief Get the current fiber from TLS. + * + * @note This function is only used for testing the runtime. + */ + static cilk_fiber* get_current_fiber(); +#endif + + /** @brief Suspend execution on current fiber resumes other fiber. + * + * Control returns after resuming execution of the self fiber. + */ + void suspend_self_and_resume_other(cilk_fiber* other); + + + /** @brief Removes a reference from the currently executing fiber + * and resumes other fiber. + * + * This fiber may be returned to a pool or deallocated. + */ + NORETURN remove_reference_from_self_and_resume_other(cilk_fiber_pool* self_pool, + cilk_fiber* other); + + /** @brief Set the proc method to execute immediately after a switch + * to this fiber. + * + * @param post_switch_proc Proc method to execute immediately + * after switching to this fiber. + */ + inline void set_post_switch_proc(cilk_fiber_proc post_switch_proc) { + m_post_switch_proc = post_switch_proc; + } + + /** @brief Returns true if this fiber is resumable. + * + * A fiber is considered resumable when it is not currently being + * executed. + */ + inline bool is_resumable(void) { + return (m_flags & RESUMABLE); + } + + /** @brief Returns true if fiber was allocated from a thread. */ + inline bool is_allocated_from_thread(void) { + return (m_flags & ALLOCATED_FROM_THREAD); + } + + /** + *@brief Get the address at the base of the stack for this fiber. + */ + inline char* get_stack_base(); + + /** @brief Return the data for this fiber. */ + cilk_fiber_data* get_data() { return this; } + + /** @brief Return the data for this fiber. */ + cilk_fiber_data const* get_data() const { return this; } + + +#if NEED_FIBER_REF_COUNTS + /** @brief Verifies that this fiber's reference count equals v. */ + inline void assert_ref_count_equals(long v) { + #if FIBER_CHECK_REF_COUNTS + CILK_ASSERT(m_outstanding_references >= v); + #endif + } + + /** @brief Verifies that this fiber's reference count is at least v. */ + inline void assert_ref_count_at_least(long v) { + #if FIBER_CHECK_REF_COUNTS + CILK_ASSERT(m_outstanding_references >= v); + #endif + } + + /** @brief Get reference count. */ + inline long get_ref_count() { return m_outstanding_references; } + + /** @brief Initialize reference count. + * Operation is not atomic. + */ + inline void init_ref_count(long v) { m_outstanding_references = v; } + + // For Windows, updates to the fiber reference count need to be + // atomic, because exceptions can live on a stack that we are not + // currently executing on. Thus, we can update the reference + // count of a fiber we are not currently executing on. + + /** @brief Increment reference count for this fiber [Windows]. */ + inline void inc_ref_count() { atomic_inc_ref_count(); } + + /** @brief Decrement reference count for this fiber [Windows]. */ + inline long dec_ref_count() { return atomic_dec_ref_count(); } + + /** @brief Subtract v from the reference count for this fiber [Windows]. */ + inline long sub_from_ref_count(long v) { return atomic_sub_from_ref_count(v); } +#else // NEED_FIBER_REF_COUNTS + + // Without reference counting, we have placeholder methods. + inline void init_ref_count(long v) { } + + inline void inc_ref_count() { } + + // With no reference counting, dec_ref_count always return 0. + // Thus, anyone checking is always the "last" one. + inline long dec_ref_count() { return 0; } + inline long sub_from_ref_count(long v) { return 0; } + + // The assert methods do nothing. + inline void assert_ref_count_equals(long v) { } + inline void assert_ref_count_at_least(long v) { } +#endif + + /** + * @brief Call TBB to tell it about an "interesting" event. + * + * @param op Value specifying the event to track. + */ + void invoke_tbb_stack_op(__cilk_tbb_stack_op op); + +private: + + /** + * @brief Helper method: try to allocate a fiber from this pool or + * its ancestors without going to the OS / heap. + * + * Returns allocated pool, or NULL if no pool is found. + * + * If pool contains a suitable fiber. Return it. Otherwise, try to + * recursively grab a fiber from the parent pool, if there is one. + * + * This method will not allocate a fiber from the heap. + */ + static cilk_fiber* try_allocate_from_pool_recursive(cilk_fiber_pool* pool); + + +#if NEED_FIBER_REF_COUNTS + /** + * @brief Atomic increment of reference count. + */ + void atomic_inc_ref_count(); + + /** + * @brief Atomic decrement of reference count. + */ + long atomic_dec_ref_count(); + + /** + * @brief Atomic subtract of v from reference count. + * @param v Value to subtract. + */ + long atomic_sub_from_ref_count(long v); +#endif // NEED_FIBER_REF_COUNTS + +}; + +#endif // __cplusplus + +#endif // ! defined(INCLUDED_CILK_FIBER_DOT_H) diff --git a/libcilkrts/runtime/cilk_malloc.c b/libcilkrts/runtime/cilk_malloc.c new file mode 100644 index 00000000000..9d02c52d037 --- /dev/null +++ b/libcilkrts/runtime/cilk_malloc.c @@ -0,0 +1,84 @@ +/* cilk_malloc.c -*-C-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +#include "cilk_malloc.h" + +#include <stdlib.h> +#if defined _WIN32 || defined _WIN64 || defined __linux__ +#include <malloc.h> +#define HAS_MEMALIGN 1 +#endif +#ifdef __VXWORKS__ +#define HAS_MEMALIGN 1 +#include <memLib.h> +#endif + +#define PREFERRED_ALIGNMENT 64 /* try to keep runtime system data + structures within one cache line */ + +void *__cilkrts_malloc(size_t size) +{ + /* TODO: check for out of memory */ +#ifdef _WIN32 + return _aligned_malloc(size, PREFERRED_ALIGNMENT); +#elif defined HAS_MEMALIGN + return memalign(PREFERRED_ALIGNMENT, size); +#else + return malloc(size); +#endif +} + +void *__cilkrts_realloc(void *ptr, size_t size) +{ +#ifdef _WIN32 + return _aligned_realloc(ptr, size, PREFERRED_ALIGNMENT); +#else + return realloc(ptr, size); +#endif +} + +void __cilkrts_free(void *ptr) +{ +#ifdef _WIN32 + _aligned_free(ptr); +#else + free(ptr); +#endif +} + +/* End cilk_malloc.c */ diff --git a/libcilkrts/runtime/cilk_malloc.h b/libcilkrts/runtime/cilk_malloc.h new file mode 100644 index 00000000000..fa0fa6d5c9d --- /dev/null +++ b/libcilkrts/runtime/cilk_malloc.h @@ -0,0 +1,90 @@ +/* cilk_malloc.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** + * @file cilk_malloc.h + * + * @brief Provides replacement memory allocation functions to allocate + * (and free) memory on cache line boundaries, if supported by the OS. + * + * If aligned memory functions are not provided by the OS, the calls just + * pass through to the standard memory allocation functions. + */ + +#ifndef INCLUDED_CILK_MALLOC_DOT_H +#define INCLUDED_CILK_MALLOC_DOT_H + +#include <cilk/common.h> +#include <stddef.h> + +#include "rts-common.h" + +__CILKRTS_BEGIN_EXTERN_C + +/** + * malloc replacement function to allocate memory aligned on a cache line + * boundary if aligned memory allocations are supported by the OS. + * + * @param size Number of bytes to allocate. + * + * @return pointer to memory block allocated, or NULL if unsuccessful. + */ +COMMON_PORTABLE void *__cilkrts_malloc(size_t size); + +/** + * realloc replacement function to allocate memory aligned on a cache line + * boundary if aligned memory allocations are supported by the OS. + * + * @param ptr Block to be reallocated. + * @param size Number of bytes to allocate. + * + * @return pointer to memory block allocated, or NULL if unsuccessful. + */ +COMMON_PORTABLE void *__cilkrts_realloc(void *ptr, size_t size); + +/** + * free replacement function to deallocate memory aligned on a cache line + * boundary if aligned memory allocations are supported by the OS. + * + * @param ptr Block to be freed. + */ +COMMON_PORTABLE void __cilkrts_free(void *ptr); + +__CILKRTS_END_EXTERN_C + +#endif // ! defined(INCLUDED_CILK_MALLOC_DOT_H) diff --git a/libcilkrts/runtime/component.h b/libcilkrts/runtime/component.h new file mode 100644 index 00000000000..64ff3e5fc42 --- /dev/null +++ b/libcilkrts/runtime/component.h @@ -0,0 +1,52 @@ +/* component.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +#ifndef INCLUDED_COMPONENT_DOT_H +#define INCLUDED_COMPONENT_DOT_H + +#define COMPONENT_NAME "Intel® Cilk™ Plus Runtime" + +#define COMPONENT_INTERNAL_NAME COMPONENT_NAME + +#define COMPONENT_FILENAME "CILKRTS20" + +#define BuildVersionString(_major, _minor, _build, _rev) #_major "," #_minor "," #_build "," #_rev + +#define COMPONENT_VERSION_STRING BuildVersionString (VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD, VERSION_REVISION) + +#endif // ! defined(INCLUDED_COMPONENT_DOT_H) diff --git a/libcilkrts/runtime/config/generic/cilk-abi-vla.c b/libcilkrts/runtime/config/generic/cilk-abi-vla.c new file mode 100644 index 00000000000..98fefa101bd --- /dev/null +++ b/libcilkrts/runtime/config/generic/cilk-abi-vla.c @@ -0,0 +1,107 @@ +/* cilk-abi-vla.cpp -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + +/* + * Implementation of Variable Length Array (VLA) ABI. + * + * The compiler calls these functions to allocate Variable Length Arrays + * at runtime. The compiler must guarantee that __cilkrts_stack_free() is + * called to cleanup any memory allocated by __cilkrts_stack_alloc(). + * + * This generic implementation always allocates the memory from the heap. + * Optimally, the implementation should expand the frame of the calling + * function if possible, since that will be faster. See the x86 version + * for one possible implementation. + */ + +#include <assert.h> +#include <stdlib.h> +#include <stdint.h> + +#include "internal/abi.h" +#include "cilk-abi-vla-internal.h" + +#define c_cilk_ptr_from_heap 0xc2f2f00d +#define c_cilk_ptr_from_stack 0xc3f30d0f + +// Allocate space for a variable length array +CILK_ABI(__cilkrts_void_ptr) +__cilkrts_stack_alloc( + __cilkrts_stack_frame *sf, + size_t size, + size_t distance_from_sp_to_alloca_area, + uint32_t align, // align is always >= minimum stack alignment and + // >= ptr_size as well, and must be a power of 2. + uint32_t needs_tag // non-zero if the pointer being returned needs to + // be tagged +) +{ + // full_size will be a multiple of align, and contains + // enough extra space to allocate a marker. + size_t full_size = (size + align - 1) & ~(align - 1); + + // Allocate memory from the heap. The compiler is responsible + // for guaranteeing us a chance to free it before the function + // exits + + return (void *)vla_internal_heap_alloc(sf, full_size, align); +} + +// Free the space allocated for a variable length array. +CILK_ABI(void) +__cilkrts_stack_free( + __cilkrts_stack_frame *sf, + void *p, + size_t size, + size_t distance_from_sp_to_alloca_area, + uint32_t align, // same requirements as for align in allocation, + // and must match alignment that was passed when + // doing the allocation + uint32_t known_from_stack // non-zero if this is known to be allocated + // on the stack, and therefore has no tag +) +{ + // full_size will be a multiple of align, and contains + // enough extra space to allocate a marker if one was needed. + size_t full_size = (size + align - 1) & ~(align - 1); + + // Just free the allocated memory to the heap since we don't know + // how to expand/contract the calling frame + vla_internal_heap_free(t, full_size); +} diff --git a/libcilkrts/runtime/config/generic/os-fence.h b/libcilkrts/runtime/config/generic/os-fence.h new file mode 100644 index 00000000000..841307a5296 --- /dev/null +++ b/libcilkrts/runtime/config/generic/os-fence.h @@ -0,0 +1,53 @@ +/* os.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/* + * void __cilkrts_fence(void) + * + * Executes an MFENCE instruction to serialize all load and store instructions + * that were issued prior the MFENCE instruction. This serializing operation + * guarantees that every load and store instruction that precedes the MFENCE + * instruction is globally visible before any load or store instruction that + * follows the MFENCE instruction. The MFENCE instruction is ordered with + * respect to all load and store instructions, other MFENCE instructions, any + * SFENCE and LFENCE instructions, and any serializing instructions (such as + * the CPUID instruction). + */ + +COMMON_SYSDEP void __cilkrts_fence(void); ///< MFENCE instruction + diff --git a/libcilkrts/runtime/config/generic/os-unix-sysdep.c b/libcilkrts/runtime/config/generic/os-unix-sysdep.c new file mode 100644 index 00000000000..fda7fc414bc --- /dev/null +++ b/libcilkrts/runtime/config/generic/os-unix-sysdep.c @@ -0,0 +1,94 @@ +/* os-unix-sysdep.c -*-C-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + ************************************************************************* + * + * This file contains generic implementations of system-specific code for + * Unix-based systems + */ + +#include "os.h" +#include "sysdep.h" + +/* + * The cycle counter is used for debugging. This funciton is only called if + * CILK_PROFILE is defined when the runtime is built. + */ +COMMON_SYSDEP unsigned long long __cilkrts_getticks(void) +{ +# warning "unimplemented cycle counter" + return 0; +} + +/* + * A "short pause" - called from the Cilk runtime's spinloops. + */ +COMMON_SYSDEP void __cilkrts_short_pause(void) +{ +# warning __cilkrts_short_pause empty +} + +/* + * Interlocked exchange - used to implement the Cilk runtime's spinloops + */ +COMMON_SYSDEP int __cilkrts_xchg(volatile int *ptr, int x) +{ + x = __sync_lock_test_and_set(ptr, x); + return x; +} + + +/* + * Restore the floating point state that is stored in a stack frame at each + * spawn. This should be called each time a frame is resumed. + * + * Only valid for IA32 and Intel64 processors. + */ +void restore_x86_fp_state (__cilkrts_stack_frame *sf) +{ +} + + +/* + * Save the floating point state to the __cilkrts_stack_frame at each spawn. + * + * Architecture-specific - Should only be needed on IA32 and Intel64 + * processors. + */ +void sysdep_save_fp_ctrl_state(__cilkrts_stack_frame *sf) +{ +} + diff --git a/libcilkrts/runtime/config/x86/cilk-abi-vla.c b/libcilkrts/runtime/config/x86/cilk-abi-vla.c new file mode 100644 index 00000000000..2d38e7f9a56 --- /dev/null +++ b/libcilkrts/runtime/config/x86/cilk-abi-vla.c @@ -0,0 +1,422 @@ +/* cilk-abi-vla.cpp -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + +/* + * Implementation of Variable Length Array (VLA) ABI. + * + * __cilkrts_stack_alloc() and __cilkrts_stack_free must be compiled + * such that ebp/rbp is used for the stack frames. This is done by having + * each of them use alloca, which forces the special frame types needed on + * each of the ABIs. Additionally, for some forms of stack frame, special + * care must be taken because the alloca space may not be at the bottom of the + * stack frame of the caller. For Intel64 windows, and for some options + * with other ABIs, a preallocated parameter block may exist on the stack + * at a lower address than the alloca. If this is the case, the parameter + * distance_from_sp_to_alloca_area will be non-zero, and will indicate how + * much pre-allocated parameter space resides in the caller's stack frame + * between the alloca area, and the bottom of the stack when the call to + * the cilkrts is made. As such, when non-zero it also includes any space + * used for passing the cilkrts_stack_alloc or cilkrts_stack_free parameters. + */ + +#include <assert.h> +#include <stdlib.h> +#include <stdint.h> +#ifdef _WIN32 +# define alloca _alloca +# define INLINE static __inline +# pragma warning(disable:1025) // Don't whine about zero extending result of unary operation +#else +# include <alloca.h> +# define INLINE static inline +#endif + +#include "internal/abi.h" +#include "cilk-abi-vla-internal.h" + +#if defined(__x86_64) || defined(_M_X64) +INLINE void setsp(void *val) +{ + __asm__("movq %0, %%rsp" : : "r"(val): "rsp"); +} +INLINE char* getsp(void) +{ + void *res; + + __asm__("movq %%rsp, %0" : "=r"(res): : "rsp"); + return res; +} +INLINE char* getbp(void) +{ + void *res; + + __asm__("movq %%rbp, %0" : "=r"(res): : "rbp"); + return res; +} +INLINE void copy_frame_down_and_move_bp( + char *dst, + char *src, + size_t cpy_bytes, + char *new_ebp +) +{ + // In this version, dst is guaranteed to be lower address than src, + // therefore copying upwards from src into dst is safe in case + // there is overlap. The number of bytes is also guaranteed to be + // a multiple of 8, and the copy is done in 64 bit word chunks for + // best efficiency. + __asm__( + "movq %0, %%rdi;" + "movq %1, %%rsi;" + "movq %2, %%rcx;" + "shrq $3, %%rcx;" + "rep movsq;" + "movq %3, %%rbp" : + : + "rm"(dst), "rm"(src), "rm"(cpy_bytes), "rm"(new_ebp) : + "rsi", "rdi", "rcx", "rbp", "memory"); +} +INLINE void copy_frame_up_and_move_bp( + char *dst, + char *src, + size_t cpy_bytes, + char *new_ebp +) +{ + // In this version, dst is guaranteed to be higher address than src, + // therefore copying downwards from src into dst is safe in case + // there is overlap. The number of bytes is also guaranteed to be + // a multiple of 8, and the copy is done in 64 bit word chunks for + // best efficiency. + dst += cpy_bytes - 8; + src += cpy_bytes - 8; + __asm__( + "movq %0, %%rdi;" + "movq %1, %%rsi;" + "movq %2, %%rcx;" + "shrq $3, %%rcx;" + "std; rep movsq; cld;" + "movl %3, %%rbp;" : + : + "rm"(dst), "rm"(src), "rm"(cpy_bytes), "rm"(new_ebp) : + "rsi", "rdi", "rcx", "rbp", "memory"); +} +#else +INLINE void setsp(void *val) +{ + __asm__("movl %0, %%esp" : : "r"(val): "esp"); +} +INLINE char* getsp(void) +{ + void *res; + + __asm__("movl %%esp, %0" : "=r"(res): : "esp"); + return res; +} +INLINE char* getbp(void) +{ + void *res; + + __asm__("movl %%ebp, %0" : "=r"(res): : "ebp"); + return res; +} +INLINE void copy_frame_down_and_move_bp( + char *dst, + char *src, + size_t cpy_bytes, + char *new_ebp +) +{ + // In this version, dst is guaranteed to be lower address than src, + // therefore copying upwards from src into dst is safe in case + // there is overlap. The number of bytes is also guaranteed to be + // a multiple of 4, and the copy is done in 32 bit word chunks for + // best efficiency. + __asm__( + "movl %0, %%edi;" + "movl %1, %%esi;" + "movl %2, %%ecx;" + "shrl $2, %%ecx;" + "rep movsd;" + "movl %3, %%ebp" : + : + "rm"(dst), "rm"(src), "rm"(cpy_bytes), "rm"(new_ebp) : + "esi", "edi", "ecx", "ebp", "memory"); +} +INLINE void copy_frame_up_and_move_bp( + char *dst, + char *src, + size_t cpy_bytes, + char *new_ebp +) +{ + // In this version, dst is guaranteed to be higher address than src, + // therefore copying downwards from src into dst is safe in case + // there is overlap. The number of bytes is also guaranteed to be + // a multiple of 4, and the copy is done in 32 bit word chunks for + // best efficiency. + dst += cpy_bytes - 4; + src += cpy_bytes - 4; + __asm__( + "movl %0, %%edi;" + "movl %1, %%esi;" + "movl %2, %%ecx;" + "shrl $2, %%ecx;" + "std; rep movsd; cld;" + "movl %3, %%ebp" : + // "=D"(dst), "=S"(src), "=C"(cpy_bytes) : + : + "rm"(dst), "rm"(src), "rm"(cpy_bytes), "rm"(new_ebp) : + "esi", "edi", "ecx", "ebp", "memory"); +} +#endif + + +#define c_cilk_ptr_from_heap 0xc2f2f00d +#define c_cilk_ptr_from_stack 0xc3f30d0f + +CILK_ABI(__cilkrts_void_ptr) +__cilkrts_stack_alloc( + __cilkrts_stack_frame *sf, + size_t size, + size_t distance_from_sp_to_alloca_area, + uint32_t align, // align is always >= minimum stack alignment and + // >= ptr_size as well, and must be a power of 2. + uint32_t needs_tag // non-zero if the pointer being returned needs to + // be tagged +) +{ +#ifdef __INTEL_COMPILER + // full_size will be a multiple of align, and contains + // enough extra space to allocate a marker. + size_t full_size = (size + align - 1) & ~(align - 1); + + if (needs_tag) { + full_size += align; + } + + char *t; + if (sf->worker != 0 && + ((sf->flags & CILK_FRAME_UNSYNCHED) != 0)) { + t = vla_internal_heap_alloc(sf, full_size, align); + if (needs_tag) { + t += align; + ((uint32_t*)t)[-1] = c_cilk_ptr_from_heap; + } + return (void *)t; + } + + // stack is still synced, allocate full_size from esp, + // and record in 32 bits immediately below the space + // allocated that this was space that this was + // allocated in the stack. + char *old_ebp = getbp(); + char *old_esp = getsp(); + + // make top_ptr point to base of first parameter. + char *top_ptr = ((char *)(_AddressOfReturnAddress()) + + sizeof(char *)); + size_t param_size = 0; + +#if defined(__x86_64) + // For Intel64 linux & MACH ABI, all the parameters were passed in + // register, so top of the stack frame above the return address + // is just the size of the return address plus + // distance_from_sp_to_alloca_area on the chance that the alloca + // area isn't at the very bottom of the calling functions stack. +#elif defined(__MACH__) + // For ia32 MACH, parameter size is always a mutliple of 16 + // bytes to keep the stack 16 byte aligned. So we need to round + // number of parameters up to multiple of 4. + param_size = 8 * sizeof(char *); +#else + // For both windows Intel64 ABI, and the IA32 windows and + // linux ABIs, space is reserved on the stack for all these + // parameters. param_size is 5 * size of a stack slot. + param_size = 5 * sizeof(char *); +#endif + + // now make top_ptr point above the params, or if + // distance_from_sp_to_alloca_area is not zero, make + // it point above that area. When non-zero, + // distance_from_sp_to_alloca area is expected to contain + // the parameter space, so we only add one or the other, + // not both. + top_ptr += (distance_from_sp_to_alloca_area != 0) ? + distance_from_sp_to_alloca_area : param_size; + + // t needs to end up at current value of top_ptr less full_size and less + // distance_from_sp_to_alloca_area and + // then rounded down to the alignment needed. Then we have to bump + // esp down by current frame_size, so that when all is done with respect + // to executing the return sequence, the final value of esp will be the + // same value as t. + t = (top_ptr - full_size) - distance_from_sp_to_alloca_area; + intptr_t temp = (intptr_t)t; + temp &= ~((intptr_t)(align - 1)); + t = (char *)temp; + + // ok, the value of t is set where we need it. Now set esp + // to the value of t less the current frame size. + // So now when we do regular return esp should be left such + // that it has moved down by full_size. + size_t cur_fm_size = (top_ptr - old_esp); + char *new_esp = t - cur_fm_size; + char *new_ebp = old_ebp - (old_esp - new_esp); + + // extend the stack down by at least the difference between where + // I want it to be and where it currently is. This should take care + // of touching any pages necessary. + char *foo = alloca(old_esp - new_esp); + setsp(foo < new_esp ? foo : new_esp); + + // Now set esp exactly where I want it. + // setsp(new_esp); + + copy_frame_down_and_move_bp(new_esp, old_esp, cur_fm_size, new_ebp); + + if (needs_tag) { + t += align; + ((uint32_t*)t)[-1] = c_cilk_ptr_from_stack; + } + + return t; +#else // Not __INTEL_COMPILER + // Not supported unless we can figure out how to get the size of the frame + return NULL; +#endif +} + +// This frees the space allocated for a variable length array. +CILK_ABI(void) +__cilkrts_stack_free( + __cilkrts_stack_frame *sf, + void *p, + size_t size, + size_t distance_from_sp_to_alloca_area, + uint32_t align, // same requirements as for align in allocation, + // and must match alignment that was passed when + // doing the allocation + uint32_t known_from_stack // non-zero if this is known to be allocated + // on the stack, and therefore has no tag +) +{ +#ifdef __INTEL_COMPILER + uint32_t *t = (uint32_t*)p; + + // full_size will be a multiple of align, and contains + // enough extra space to allocate a marker if one was needed. + size_t full_size = (size + align - 1) & ~(align - 1); + if (known_from_stack == 0) { + // if the compiler hasn't told the run-time that this is + // known to be on the stack, then this pointer must have been + // tagged such that the run-time can tell. + assert(t[-1] == c_cilk_ptr_from_stack || + t[-1] == c_cilk_ptr_from_heap); + + known_from_stack = t[-1] == c_cilk_ptr_from_stack; + full_size += align; // accounts for extra space for marker + t = (uint32_t *)(((char *)t) - align); + } + + if (known_from_stack) { + // alloca useage forces an ebp/rbp based stack frame even though + // 0 and unused. + char *foo = alloca(0); + if (sf->worker == 0 || (sf->flags & CILK_FRAME_UNSYNCHED) == 0) { + // p was allocated from current stack frame and we + // are synced on current stack frame. Return the + // amount of the stack that needs to be freed. + char *old_ebp = getbp(); + char *old_esp = getsp(); + + // make top_ptr point to base of first parameter. + char *top_ptr = ((char *)(_AddressOfReturnAddress()) + + sizeof(char *)); + size_t param_size = 0; + +#if defined(__x86_64) + // For Intel64 linux & MACH ABI, all the parameters were passed in + // register, so top of the stack frame above the return address + // is just the size of the return address plus + // distance_from_sp_to_alloca_area on the chance that the alloca + // area isn't at the very bottom of the calling functions stack. +#elif defined(__MACH__) + // For ia32 MACH, parameter size is always a mutliple of 16 + // bytes to keep the stack 16 byte aligned. So we need to round + // number of parameters up to multiple of 4. + param_size = 8 * sizeof(char *); +#else + // For both windows Intel64 ABI, and the IA32 windows and + // linux ABIs, space is reserved on the stack for all these + // parameters. param_size is 5 * size of a stack slot. + param_size = 6 * sizeof(char *); +#endif + + // now make top_ptr point above the params, or if + // distance_from_sp_to_alloca_area is not zero, make + // it point above that area. When non-zero, + // distance_from_sp_to_alloca area is expected to contain + // the parameter space, so we only add one or the other, + // not both. + top_ptr += (distance_from_sp_to_alloca_area != 0) ? + distance_from_sp_to_alloca_area : param_size; + + size_t cur_fm_size = (top_ptr - old_esp); + char *new_esp = old_esp + full_size; + char *new_ebp = old_ebp + full_size; + + copy_frame_up_and_move_bp(new_esp, old_esp, cur_fm_size, new_ebp); + setsp(new_esp); + } + else { + // p was allocated on stack frame, but that is + // no longer the current stack frame. Need to adjust the + // saved esp that is somewhere in the cilk runtime so that + // on sync, esp will be cut back correctly. + vla_free_from_original_stack(sf, full_size); + } + } + else { + vla_internal_heap_free(t, full_size); + } +#else // Not __INTEL_COMPILER + // Not supported unless we can figure out how to get the size of the frame +#endif +} diff --git a/libcilkrts/runtime/config/x86/os-fence.h b/libcilkrts/runtime/config/x86/os-fence.h new file mode 100644 index 00000000000..ec704e94ef2 --- /dev/null +++ b/libcilkrts/runtime/config/x86/os-fence.h @@ -0,0 +1,72 @@ +/* os.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/* gcc before 4.4 does not implement __sync_synchronize properly */ +#if (__ICC >= 1110 && !(__MIC__ || __MIC2__)) \ + || (!defined __ICC && __GNUC__ * 10 + __GNUC_MINOR__ > 43) +# define HAVE_SYNC_INTRINSICS 1 +#endif + + +/* + * void __cilkrts_fence(void) + * + * Executes an MFENCE instruction to serialize all load and store instructions + * that were issued prior the MFENCE instruction. This serializing operation + * guarantees that every load and store instruction that precedes the MFENCE + * instruction is globally visible before any load or store instruction that + * follows the MFENCE instruction. The MFENCE instruction is ordered with + * respect to all load and store instructions, other MFENCE instructions, any + * SFENCE and LFENCE instructions, and any serializing instructions (such as + * the CPUID instruction). + */ +#ifdef HAVE_SYNC_INTRINSICS +# define __cilkrts_fence() __sync_synchronize() +#elif defined __ICC || defined __GNUC__ + /* mfence is a strict subset of lock add but takes longer on many + * processors. */ +// # define __cilkrts_fence() __asm__ volatile ("mfence") + /* On MIC, fence seems to be completely unnecessary. + * Just for simplicity of 1st implementation, it defaults to x86 */ +# define __cilkrts_fence() __asm__ volatile ("lock addl $0,(%rsp)") +// #elif defined _WIN32 +// # pragma intrinsic(_ReadWriteBarrier) +// # define __cilkrts_fence() _ReadWriteBarrier() +#else +COMMON_SYSDEP void __cilkrts_fence(void); ///< MFENCE instruction +#endif diff --git a/libcilkrts/runtime/config/x86/os-unix-sysdep.c b/libcilkrts/runtime/config/x86/os-unix-sysdep.c new file mode 100644 index 00000000000..881bc3f4283 --- /dev/null +++ b/libcilkrts/runtime/config/x86/os-unix-sysdep.c @@ -0,0 +1,123 @@ +/* os-unix-sysdep.c -*-C-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + ************************************************************************* + * + * This file contains system-specific code for Unix systems + */ + +#include "os.h" +#include "sysdep.h" +#include <internal/abi.h> + +// On x86 processors (but not MIC processors), the compiler generated code to +// save the FP state (rounding mode and the like) before calling setjmp. We +// will need to restore that state when we resume. +#ifndef __MIC__ +# if defined(__i386__) || defined(__x86_64) +# define RESTORE_X86_FP_STATE +# endif // defined(__i386__) || defined(__x86_64) +#endif // __MIC__ + +/* timer support */ +COMMON_SYSDEP unsigned long long __cilkrts_getticks(void) +{ +#if defined __i386__ || defined __x86_64 + unsigned a, d; + __asm__ volatile("rdtsc" : "=a" (a), "=d" (d)); + return ((unsigned long long)a) | (((unsigned long long)d) << 32); +#else +# warning "unimplemented cycle counter" + return 0; +#endif +} + +COMMON_SYSDEP void __cilkrts_short_pause(void) +{ +#if __ICC >= 1110 +# if __MIC__ || __MIC2__ + _mm_delay_32(16); // stall for 16 cycles +# else + _mm_pause(); +# endif +#elif defined __i386__ || defined __x86_64 + __asm__("pause"); +#else +# warning __cilkrts_short_pause empty +#endif +} + +COMMON_SYSDEP int __cilkrts_xchg(volatile int *ptr, int x) +{ +#if defined __i386__ || defined __x86_64 + /* asm statement here works around icc bugs */ + __asm__("xchgl %0,%a1" :"=r" (x) : "r" (ptr), "0" (x) :"memory"); +#else + x = __sync_lock_test_and_set(ptr, x); +#endif + return x; +} + + +/* + * Restore the floating point state that is stored in a stack frame at each + * spawn. This should be called each time a frame is resumed. + * + * Only valid for IA32 and Intel64 processors. + */ +void restore_x86_fp_state (__cilkrts_stack_frame *sf) { +#ifdef RESTORE_X86_FP_STATE + __asm__ ( "ldmxcsr %0\n\t" + "fnclex\n\t" + "fldcw %1" + : + : "m" (sf->mxcsr), "m" (sf->fpcsr)); +#endif +} + + +void sysdep_save_fp_ctrl_state(__cilkrts_stack_frame *sf) +{ +// If we're not going to restore, don't bother saving it +#ifdef RESTORE_X86_FP_STATE + if (CILK_FRAME_VERSION_VALUE(sf->flags) >= 1) + { + __asm__ ("stmxcsr %0" : "=m" (sf->mxcsr)); + __asm__ ("fnstsw %0" : "=m" (sf->fpcsr)); + } +#endif +} + diff --git a/libcilkrts/runtime/doxygen-layout.xml b/libcilkrts/runtime/doxygen-layout.xml new file mode 100644 index 00000000000..fabe0ab3cd8 --- /dev/null +++ b/libcilkrts/runtime/doxygen-layout.xml @@ -0,0 +1,222 @@ +<doxygenlayout version="1.0"> + +<!-- +# @copyright +# Copyright (C) 2011-2013, Intel Corporation +# All rights reserved. +# +# @copyright +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# @copyright +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY +# WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +--> + + <!-- Navigation index tabs for HTML output --> + <navindex> + <tab type="mainpage" visible="yes" title=""/> + <tab type="pages" visible="yes" title="" intro=""/> + <tab type="modules" visible="yes" title="" intro=""/> + <tab type="namespaces" visible="yes" title=""> + <tab type="namespaces" visible="yes" title="" intro=""/> + <tab type="namespacemembers" visible="yes" title="" intro=""/> + </tab> + <tab type="classes" visible="yes" title="Classes, Structs and Unions"> + <tab type="classes" visible="yes" title="Classes, Structs and Unions" intro=""/> + <tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/> + <tab type="hierarchy" visible="yes" title="" intro=""/> + <tab type="classmembers" visible="yes" title="" intro=""/> + </tab> + <tab type="files" visible="yes" title=""> + <tab type="files" visible="yes" title="" intro=""/> + <tab type="globals" visible="yes" title="" intro=""/> + </tab> + <tab type="globals" visible="yes" title="Global Functions" intro=""/> + <tab type="dirs" visible="yes" title="" intro=""/> + <tab type="examples" visible="yes" title="" intro=""/> + </navindex> + + <!-- Layout definition for a class page --> + <class> + <briefdescription visible="yes"/> + <includes visible="$SHOW_INCLUDE_FILES"/> + <inheritancegraph visible="$CLASS_GRAPH"/> + <collaborationgraph visible="$COLLABORATION_GRAPH"/> + <allmemberslink visible="yes"/> + <memberdecl> + <nestedclasses visible="yes" title=""/> + <publictypes title=""/> + <publicslots title=""/> + <signals title=""/> + <publicmethods title=""/> + <publicstaticmethods title=""/> + <publicattributes title=""/> + <publicstaticattributes title=""/> + <protectedtypes title=""/> + <protectedslots title=""/> + <protectedmethods title=""/> + <protectedstaticmethods title=""/> + <protectedattributes title=""/> + <protectedstaticattributes title=""/> + <packagetypes title=""/> + <packagemethods title=""/> + <packagestaticmethods title=""/> + <packageattributes title=""/> + <packagestaticattributes title=""/> + <properties title=""/> + <events title=""/> + <privatetypes title=""/> + <privateslots title=""/> + <privatemethods title=""/> + <privatestaticmethods title=""/> + <privateattributes title=""/> + <privatestaticattributes title=""/> + <friends title=""/> + <related title="" subtitle=""/> + <membergroups visible="yes"/> + </memberdecl> + <detaileddescription title=""/> + <memberdef> + <typedefs title=""/> + <enums title=""/> + <constructors title=""/> + <functions title=""/> + <related title=""/> + <variables title=""/> + <properties title=""/> + <events title=""/> + </memberdef> + <usedfiles visible="$SHOW_USED_FILES"/> + <authorsection visible="yes"/> + </class> + + <!-- Layout definition for a namespace page --> + <namespace> + <briefdescription visible="yes"/> + <memberdecl> + <nestednamespaces visible="yes" title=""/> + <classes visible="yes" title=""/> + <typedefs title=""/> + <enums title=""/> + <functions title=""/> + <variables title=""/> + <membergroups visible="yes"/> + </memberdecl> + <detaileddescription title=""/> + <memberdef> + <typedefs title=""/> + <enums title=""/> + <functions title=""/> + <variables title=""/> + </memberdef> + <authorsection visible="yes"/> + </namespace> + + <!-- Layout definition for a file page --> + <file> + <briefdescription visible="no"/> + <includegraph visible="$INCLUDE_GRAPH"/> + <includedbygraph visible="$INCLUDED_BY_GRAPH"/> + <detaileddescription title="Description"/> + <includes visible="no"/> + <sourcelink visible="yes"/> + <memberdecl> + <classes visible="yes" title="Structures and Classes"/> + <namespaces visible="yes" title=""/> + <defines title=""/> + <typedefs title=""/> + <enums title=""/> + <functions title=""/> + <variables title=""/> + <membergroups visible="yes"/> + </memberdecl> + <memberdef> + <defines title=""/> + <typedefs title=""/> + <enums title=""/> + <functions title=""/> + <variables title=""/> + </memberdef> + <authorsection/> + </file> + + <!-- Layout definition for a group page --> + <group> + <briefdescription visible="yes"/> + <groupgraph visible="$GROUP_GRAPHS"/> + <memberdecl> + <classes visible="yes" title=""/> + <namespaces visible="yes" title=""/> + <dirs visible="yes" title=""/> + <nestedgroups visible="yes" title=""/> + <files visible="yes" title=""/> + <defines title=""/> + <typedefs title=""/> + <enums title=""/> + <enumvalues title=""/> + <functions title=""/> + <variables title=""/> + <signals title=""/> + <publicslots title=""/> + <protectedslots title=""/> + <privateslots title=""/> + <events title=""/> + <properties title=""/> + <friends title=""/> + <membergroups visible="yes"/> + </memberdecl> + <detaileddescription title=""/> + <memberdef> + <pagedocs/> + <inlineclasses title=""/> + <defines title=""/> + <typedefs title=""/> + <enums title=""/> + <enumvalues title=""/> + <functions title=""/> + <variables title=""/> + <signals title=""/> + <publicslots title=""/> + <protectedslots title=""/> + <privateslots title=""/> + <events title=""/> + <properties title=""/> + <friends title=""/> + </memberdef> + <authorsection visible="yes"/> + </group> + + <!-- Layout definition for a directory page --> + <directory> + <briefdescription visible="yes"/> + <directorygraph visible="yes"/> + <memberdecl> + <dirs visible="yes"/> + <files visible="yes"/> + </memberdecl> + <detaileddescription title=""/> + </directory> +</doxygenlayout> diff --git a/libcilkrts/runtime/doxygen.cfg b/libcilkrts/runtime/doxygen.cfg new file mode 100644 index 00000000000..684dcb51b51 --- /dev/null +++ b/libcilkrts/runtime/doxygen.cfg @@ -0,0 +1,1774 @@ +# Doxyfile 1.7.4
+
+# @copyright +# Copyright (C) 2011-2013, Intel Corporation +# All rights reserved. +# +# @copyright +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# @copyright +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY +# WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = "Intel Cilk Plus Runtime"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY =
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this
+# tag. The format is ext=language, where ext is a file extension, and language
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penalty.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = YES
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. The create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE = doxygen-layout.xml
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = ./ \
+ ../include/internal/abi.h \
+ ../include/cilk/cilk_api.h \
+ ../include/cilk/common.h \
+ ./readme.dox
+
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE = attributes.h \
+ cilk-ittnotify.h \
+ component.h \
+ rts-common.h \
+ windows-clean.h
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS = _UNWIND_INFO \
+ _UNWIND_CODE \
+ _DISPATCHER_CONTEXT \
+ __cilkrts_stack \
+ pending_exception_info
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header. Note that when using a custom header you are responsible
+# for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is adviced to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when changing the value of configuration settings such as GENERATE_TREEVIEW!
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the stylesheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = com.Intel.CilkPlusRuntime
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID = com.Intel.CilkPlusRuntime
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME = "Intel Corporation"
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+# will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the
+# mathjax.org site, so you can quickly see the result without installing
+# MathJax, but it is strongly recommended to install a local copy of MathJax
+# before deployment.
+
+MATHJAX_RELPATH = http://www.mathjax.org/mathjax
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvantages are that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = _WIN32 \
+ COMMON_SYSDEP= \
+ COMMON_PORTABLE= \
+ NON_COMMON= \
+ __CILKRTS_BEGIN_EXTERN_C= \
+ __CILKRTS_END_EXTERN_C= \
+ CILK_API(t)=t \
+ CILK_ABI(t)=t \
+ CILK_ABI_THROWS(t)=t \
+ CALLBACK= \
+ __CILKRTS_INLINE=inline \
+ __CILKRTS_ABI_VERSION=1 \
+ __cplusplus \
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that
+# overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS = 0
+
+# By default doxygen will write a font called Helvetica to the output
+# directory and reference it in all dot files that doxygen generates.
+# When you want a differently looking font you can specify the font name
+# using DOT_FONTNAME. You need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
diff --git a/libcilkrts/runtime/except-gcc.cpp b/libcilkrts/runtime/except-gcc.cpp new file mode 100644 index 00000000000..bd08d1826b3 --- /dev/null +++ b/libcilkrts/runtime/except-gcc.cpp @@ -0,0 +1,597 @@ +/* except-gcc.cpp -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +#include "except-gcc.h" +#include "except.h" +#include "sysdep.h" +#include "bug.h" +#include "local_state.h" +#include "full_frame.h" +#include "scheduler.h" +#include "frame_malloc.h" +#include "pedigrees.h" + +#include <stdint.h> +#include <typeinfo> + +#define DEBUG_EXCEPTIONS 0 + +struct pending_exception_info +{ + void make(__cxa_eh_globals *, _Unwind_Exception *, bool); + void destruct(); + bool empty() const; + void check() const; + /* Active exception at time of suspend. */ + _Unwind_Exception *active; + /* If true the most recently caught exception is to be rethrown + on resume. This handling is technically incorrect but allows + running without compiler support; the proper standards-compliant + method is to save the exception in the previous field. */ + bool rethrow; + struct __cxa_eh_globals runtime_state; +}; + +void pending_exception_info::check() const +{ + if (active) + CILK_ASSERT((int)runtime_state.uncaughtExceptions > 0); +} + +void pending_exception_info::make(__cxa_eh_globals *state_in, + _Unwind_Exception *exc_in, bool rethrow_in) +{ + active = exc_in; + rethrow = rethrow_in; + runtime_state = *state_in; + /* Read and clear C++ runtime state. */ + state_in->caughtExceptions = 0; + state_in->uncaughtExceptions = 0; +#if CILK_LIB_DEBUG + check(); +#endif +} + +bool +pending_exception_info::empty() const +{ + return !active && !rethrow && !runtime_state.caughtExceptions && + !runtime_state.uncaughtExceptions; +} + +#if DEBUG_EXCEPTIONS +#include <stdio.h> +static void +decode_exceptions(char *out, size_t len, struct pending_exception_info *info) +{ + if (info->empty()) + snprintf(out, len, "[empty]"); + else if (info->rethrow) + snprintf(out, len, "[rethrow %p]", + info->runtime_state.caughtExceptions); + else + snprintf(out, len, "[throw %p]", (void *)info->active); +} +#endif + +static void +save_exception_info(__cilkrts_worker *w, + __cxa_eh_globals *state, + _Unwind_Exception *exc, + bool rethrow, + const char *why) +{ + struct pending_exception_info *info = + (struct pending_exception_info *)__cilkrts_frame_malloc(w, sizeof (struct pending_exception_info)); + CILK_ASSERT(info); + info->make(state, exc, rethrow); + +#if DEBUG_EXCEPTIONS + { + char buf[40]; + decode_exceptions(buf, sizeof buf, info); + fprintf(stderr, "make exception info W%u %p %s (%s)\n", + w->self, info, buf, why); + } +#endif + + CILK_ASSERT(w->l->pending_exception == 0); + w->l->pending_exception = info; +} + +#if DEBUG_EXCEPTIONS +#include <stdio.h> /* DEBUG */ + +static void decode_flags(int flags, char out[9]) +{ + out[0] = (flags & CILK_FRAME_STOLEN) ? 'S' : '_'; + out[1] = (flags & CILK_FRAME_UNSYNCHED) ? 'U' : '_'; + out[2] = (flags & CILK_FRAME_DETACHED) ? 'D' : '_'; + out[3] = (flags & CILK_FRAME_EXCEPTING) ? 'X' : '_'; + out[4] = '\0'; +} +#endif + +/* __cilkrts_save_except is called from the runtime epilogue + when a function is returning with an exception pending. + + If the function has a parent to which it could return normally, + return and have the caller call _Unwind_Resume, the same as if + an exception filter had not matched. + + Otherwise save the exception in the worker. + + If this is a return from a ordinary call that must go through + the runtime, the assembly epilogue must have saved the call-saved + register state in the parent frame. */ + +extern "C" +CILK_ABI_THROWS_VOID +__cilkrts_return_exception(__cilkrts_stack_frame *sf) +{ + __cilkrts_worker *w = sf->worker; + _Unwind_Exception *exc = (_Unwind_Exception *)sf->except_data; + + CILK_ASSERT(sf->flags & CILK_FRAME_DETACHED); + sf->flags &= ~CILK_FRAME_DETACHED; + + /* + * If we are in replay mode, and a steal occurred during the recording + * phase, stall till a steal actually occurs. + */ + replay_wait_for_steal_if_parent_was_stolen(w); + + /* If this is to be an abnormal return, save the active exception. */ + if (!__cilkrts_pop_tail(w)) { + /* Write a record to the replay log for an attempt to return to a + stolen parent. This must be done before the exception handler + invokes __cilkrts_leave_frame which will bump the pedigree so + the replay_wait_for_steal_if_parent_was_stolen() above will match on + replay */ + replay_record_orphaned(w); + + /* Now that the record/replay stuff is done, update the pedigree */ + update_pedigree_on_leave_frame(w, sf); + + /* Inline pop_frame; this may not be needed. */ + w->current_stack_frame = sf->call_parent; + sf->call_parent = 0; + __cxa_eh_globals *state = __cxa_get_globals(); + +#if DEBUG_EXCEPTIONS + fflush(stdout); + char decoded[9]; + decode_flags(sf->flags, decoded); + fprintf(stderr, "__cilkrts_save_except W%u sf %p/%s exc %p [%u %p] suspend\n", + w->self, sf, decoded, exc, + state->uncaughtExceptions, + state->caughtExceptions); +#endif + + /* Like __cilkrts_save_exception_state except for setting the + rethrow flag. */ + save_exception_info(w, state, exc, exc == NULL, "save_except"); + { + full_frame *ff = w->l->frame_ff; + CILK_ASSERT(NULL == ff->pending_exception); + ff->pending_exception = w->l->pending_exception; + w->l->pending_exception = NULL; + } + __cilkrts_exception_from_spawn(w, sf); /* does not return */ + } + /* This code path is taken when the parent is attached. It is on + the same stack and part of the same full frame. The caller is + cleaning up the Cilk frame during unwind and will reraise the + exception */ + + /* Now that the record/replay stuff is done, update the pedigree */ + update_pedigree_on_leave_frame(w, sf); + +#if DEBUG_EXCEPTIONS /* DEBUG ONLY */ + { + __cxa_eh_globals *state = __cxa_get_globals(); + + fflush(stdout); + char decoded[9]; + decode_flags(sf->flags, decoded); + fprintf(stderr, "__cilkrts_save_except W%d %p/%s %p->%p [%u %p] escape\n", + w->self, sf, decoded, exc, + exc ? to_cxx(exc)->nextException : 0, + state->uncaughtExceptions, + state->caughtExceptions); + + /* XXX This is triggering in the user thread which gets an exception + from somewhere but does not get the corresponding runtime exception + state. + XXX There might be two or more uncaught exceptions. Test could be + (uncaught != 0) == (exc != 0). First, design tests to see if that + case is otherwise handled correctly. And what if there's an uncaught + exception that does not belong to this function? I.e. this is a return + from spawn in a destructor. */ + if (exc) + CILK_ASSERT((int)state->uncaughtExceptions > 0); + /*CILK_ASSERT(state->uncaughtExceptions == (exc != 0));*/ + } +#endif + + /* The parent is attached so this exception can be propagated normally. */ + return; +} + +/* Save the exception state into the full frame, which is exiting + or suspending. */ +extern "C" +void __cilkrts_save_exception_state(__cilkrts_worker *w, full_frame *ff) +{ + save_exception_info(w, __cxa_get_globals(), 0, false, "undo-detach"); + CILK_ASSERT(NULL == ff->pending_exception); + ff->pending_exception = w->l->pending_exception; + w->l->pending_exception = NULL; +} + +/* __cilkrts_c_sync_except is like __cilkrts_c_sync except that it + saves exception state. __cilkrts_c_sync never returns here and + always reinstalls the saved exception state. + + This function must be used because a parent of this function may + be propagating an uncaught exception. The uncaught exception + count must be saved by the child and passed back to the parent. */ + +extern "C" +NORETURN __cilkrts_c_sync_except (__cilkrts_worker *w, __cilkrts_stack_frame *sf) +{ + __cxa_eh_globals *state = __cxa_get_globals(); + _Unwind_Exception *exc = (_Unwind_Exception *)sf->except_data; + + CILK_ASSERT((sf->flags & (CILK_FRAME_UNSYNCHED|CILK_FRAME_EXCEPTING)) == + (CILK_FRAME_UNSYNCHED|CILK_FRAME_EXCEPTING)); + sf->flags &= ~CILK_FRAME_EXCEPTING; + +#if DEBUG_EXCEPTIONS + fflush(stdout); + char decoded[9]; + decode_flags(sf->flags, decoded); + if (exc) + fprintf(stderr, "__cilkrts_sync_except W%u %p/%s %p->%p [%u %p]\n", + w->self, sf, decoded, exc, + to_cxx(exc)->nextException, + state->uncaughtExceptions, + state->caughtExceptions); + else + fprintf(stderr, "__cilkrts_sync_except W%d %p/%s none [%u %p]\n", + w->self, sf, decoded, + state->uncaughtExceptions, + state->caughtExceptions); +#endif + + /* Here the identity of an rethrown exception is always known. + If exc is NULL this call is only to preserve parent state. */ + save_exception_info(w, state, exc, false, "sync_except"); +#if 0 + { + full_frame *ff = w->l->frame_ff; + CILK_ASSERT(NULL == ff->pending_exception); + ff->pending_exception = w->l->pending_exception; + w->l->pending_exception = NULL; + } +#endif + CILK_ASSERT(!std::uncaught_exception()); + __cilkrts_c_sync(w, sf); +} + +void +pending_exception_info::destruct() +{ + if (active) { +#if DEBUG_EXCEPTIONS + fprintf(stderr, "destroy exception info %p %p\n", this, active); +#endif + _Unwind_DeleteException(active); + active = 0; + } else { +#if DEBUG_EXCEPTIONS + fprintf(stderr, "destroy exception info %p\n", this); +#endif + } + while (runtime_state.caughtExceptions) { + __cxa_exception *exc = runtime_state.caughtExceptions; + runtime_state.caughtExceptions = exc->nextException; +#if DEBUG_EXCEPTIONS + fprintf(stderr, "destroy caught exception %p\n", this); +#endif + _Unwind_DeleteException(&exc->unwindHeader); + } +} + +/* + * __cilkrts_merge_pending_exceptions + * + * Merge the right exception record into the left. The left is logically + * earlier. + * + * The active exception of E is + * E->active if it is non-NULL (in which case E->rethrow is false) + * unresolved if E->active is NULL and E->rethrow is true + * nil if E->active is NULL and E->rethrow is false + * + * The merged active exception is left active exception if it is not + * nil, otherwise the right. + * + * On entry the left state is synched and can not have an unresolved + * exception. The merge may result in an unresolved exception. + * + * Due to scoping rules at most one of the caught exception lists is + * non-NULL. + */ + +struct pending_exception_info * +__cilkrts_merge_pending_exceptions ( + __cilkrts_worker *w, + struct pending_exception_info *left, + struct pending_exception_info *right) +{ + /* If we've only got one exception, return it */ + + if (NULL == left) { +#if DEBUG_EXCEPTIONS + if (right) { + char buf[40]; + decode_exceptions(buf, sizeof buf, right); + fprintf(stderr, "__cilkrts merge W%u nil %p -> %p %s\n", + w->self, right, right, buf); + } +#endif + return right; + } + + if (NULL == right) { +#if DEBUG_EXCEPTIONS + if (left) { + char buf[40]; + decode_exceptions(buf, sizeof buf, left); + fprintf(stderr, "__cilkrts merge W%u %p nil -> %p %s\n", + w->self, left, left, buf); + } +#endif + return left; + } + +#if CILK_LIB_DEBUG + /*volatile struct pending_exception_info left_in = *left, right_in = *right;*/ + left->check(); + right->check(); +#endif + +#if DEBUG_EXCEPTIONS + { + char buf1[40], buf2[40]; + decode_exceptions(buf1, sizeof buf1, left); + decode_exceptions(buf2, sizeof buf2, right); + fprintf(stderr, "__cilkrts merge W%u %p %s %p %s\n", + w->self, left, buf1, right, buf2); + } +#endif + + /* It should not be possible for both left and right to + have accumulated catch blocks. + + The left exception record may always have a catch + chain it kept when its parent was stolen. + + If they are siblings, the right sibling should not + have accumulated any net catches. (Catch is lexically + scoped.) + + If the right frame is a parent, it should not have entered + a catch block without syncing first. If it spawned in a + catch block, the child got its catch. */ + __cxa_exception *caught = left->runtime_state.caughtExceptions; + if (caught) + CILK_ASSERT(!right->runtime_state.caughtExceptions); + else { + CILK_ASSERT(!left->rethrow); + left->rethrow = right->rethrow; + left->runtime_state.caughtExceptions = caught = right->runtime_state.caughtExceptions; + right->runtime_state.caughtExceptions = NULL; + } + + /* Merge the uncaught exception and count of uncaught exceptions. */ + const unsigned int right_uncaught = right->runtime_state.uncaughtExceptions; + if (!left->active){ + left->active = right->active; /* could be NULL */ + right->active = 0; + left->runtime_state.uncaughtExceptions += right_uncaught; + if (left->active) + /* assert is C++ exception */ + /*CILK_ASSERT(__cxxabiv1::__is_gxx_exception_class(left->active->exception_class))*/; + } else { + /* Subtract 1 if the right exception is being destructed. */ + left->runtime_state.uncaughtExceptions += right_uncaught - (right->active != 0); + } + + right->destruct(); + __cilkrts_frame_free(w, right, sizeof *right); + + /* If there is no state left, return NULL. */ + if (left->empty()) { + left->destruct(); + __cilkrts_frame_free(w, left, sizeof *left); + left = NULL; + } + +#if CILK_LIB_DEBUG + if (left) + left->check(); +#endif + + return left; +} + +#if 0 +/* __cilkrts_c_resume_except is called from the assembly language + restart code when a resumed frame has a pending exception. + + The handler count negation on rethrow was done when the throw was + resolved. + + The assembly language runtime must make the throw unwind to + the sync, spawn, or other location where the exception should + be injected. (This should not happen after a spawn but nothing + here depends on there being no exception on steal.) + + This function is unused in the Intel stack based system. */ +extern "C" +void __cilkrts_c_resume_except (_Unwind_Exception *exc) +{ +#if DEBUG_EXCEPTIONS + fprintf(stderr, "resume exception %p\n", exc); +#endif + _Unwind_Reason_Code why = _Unwind_RaiseException(exc); + __cilkrts_bug ("Cilk runtime error: failed to reinstate suspended exception %p (%d)\n", exc, why); +} +#endif + +/* Restore the caught exception chain. This assumes no C++ exception + code will run before the frame is resumed. If there is no exception + to be resumed free the object. */ + +extern "C" +void __cilkrts_setup_for_execution_sysdep(__cilkrts_worker *w, full_frame *ff) +{ + // ASSERT: We own w->lock and ff->lock || P == 1 + + __cxa_eh_globals *state = __cxa_get_globals (); + struct pending_exception_info *info = w->l->pending_exception; + + if (info == NULL) + return; + + w->l->pending_exception = 0; + +#if DEBUG_EXCEPTIONS + _Unwind_Exception *exc = info->active; + if (exc) { + fflush(stdout); + fprintf(stderr, "__cilkrts_resume_except W%u %p->%p [%u %p]\n", + w->self, exc, + to_cxx(exc)->nextException, + info->runtime_state.uncaughtExceptions, + info->runtime_state.caughtExceptions); + /*CILK_ASSERT(info->runtime_state.uncaughtExceptions > 0);*/ + } +#endif + + if (state->uncaughtExceptions || state->caughtExceptions) + __cilkrts_bug("W%u: resuming with non-empty prior exception state %u %p\n", state->uncaughtExceptions, state->caughtExceptions); + + *state = info->runtime_state; + info->runtime_state.caughtExceptions = 0; + info->runtime_state.uncaughtExceptions = 0; + + if (info->rethrow) { + info->rethrow = false; + /* Resuming function will rethrow. Runtime calls + std::terminate if there is no caught exception. */ + ff->call_stack->flags |= CILK_FRAME_EXCEPTING; + } + if (info->active) { + ff->call_stack->flags |= CILK_FRAME_EXCEPTING; + ff->call_stack->except_data = info->active; + info->active = 0; + } + + if (info->empty()) { + info->destruct(); + __cilkrts_frame_free(w, info, sizeof *info); + w->l->pending_exception = NULL; + } + +#if CILK_LIB_DEBUG + if (ff->call_stack->except_data) + CILK_ASSERT(std::uncaught_exception()); +#endif +} + +#if 0 +extern "C" +struct pending_exception_info *__cilkrts_get_exception(__cilkrts_worker *w, + __cilkrts_stack_frame *sf) +{ + struct pending_exception_info *info = w->l->pending_exception; + + if (info == NULL) { + sf->flags &= ~CILK_FRAME_EXCEPTING; + return 0; + } + + w->l->pending_exception = NULL; + + /* This exception goes into the frame. */ + + _Unwind_Exception *exc = info->active; + info->active = NULL; + info->destruct(); + __cilkrts_frame_free(w, info, sizeof *info); + info = 0; + sf->flags |= CILK_FRAME_EXCEPTING; + sf->exception = exc; + return 0; +} +#endif + +extern "C" +void __attribute__((nonnull)) __cilkrts_gcc_rethrow(__cilkrts_stack_frame *sf) +{ +#ifdef __CYGWIN__ + // Cygwin doesn't support exceptions, so _Unwind_Resume isn't available + // Which means we can't support exceptions either + __cilkrts_bug("The Cygwin implementation of the Intel Cilk Plus runtime doesn't support exceptions\n"); +#else + if (sf->except_data) { +#if CILK_LIB_DEBUG + CILK_ASSERT(std::uncaught_exception()); +#endif + _Unwind_Resume ((_Unwind_Exception *)sf->except_data); + } else { + throw; + } +#endif // __CYGWIN__ +} + +/* End except-gcc.cpp */ + diff --git a/libcilkrts/runtime/except-gcc.h b/libcilkrts/runtime/except-gcc.h new file mode 100644 index 00000000000..aa76adbc233 --- /dev/null +++ b/libcilkrts/runtime/except-gcc.h @@ -0,0 +1,146 @@ +/* except-gcc.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** + * @file except-gcc.h + * + * @brief ABI for gcc exception handling. + * + * @par Origin + * The code below is generally copied from the Intel Itanium ABI (Intel + * download 245370). + */ + +#ifndef INCLUDED_EXCEPT_GCC_DOT_H +#define INCLUDED_EXCEPT_GCC_DOT_H + +#ifndef __cplusplus +# error except-gcc.h should be used in C++ code only. +#endif + +#include <cilk/common.h> +#include <exception> +#include <typeinfo> + +struct __cxa_exception; + +__CILKRTS_BEGIN_EXTERN_C + +/** Unwind reason code (Itanium ABI 6.1.2.1) */ +typedef enum _Unwind_Reason_Code { + _URC_NO_REASON = 0, + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_FATAL_PHASE2_ERROR = 2, + _URC_FATAL_PHASE1_ERROR = 3, + _URC_NORMAL_STOP = 4, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8 +} _Unwind_Reason_Code; + +typedef struct _Unwind_Exception _Unwind_Exception; + +/** Exception cleanup function pointer (Itanium ABI 6.1.2.2) */ +typedef void (*_Unwind_Exception_Cleanup_Fn)(_Unwind_Reason_Code reason, + _Unwind_Exception *exc); + +/** + * @brief Exception undwinding information + * + * This is copied from the Intel Itanium ABI except that the + * private fields are declared unsigned long for binary + * compatibility with gcc/g++ on 32 bit machines. + */ +struct _Unwind_Exception +{ + uint64_t exception_class; + _Unwind_Exception_Cleanup_Fn exception_cleanup; + unsigned long private_1; + unsigned long private_2; +}; + +/** Throw or rethrow an exception */ +_Unwind_Reason_Code +_Unwind_RaiseException(_Unwind_Exception *exception_object); + +/** Resume an exception other than by rethrowing it. */ +void _Unwind_Resume(_Unwind_Exception *exception_object); + +/** Delete an exception object */ +void _Unwind_DeleteException(_Unwind_Exception *exception_object); + +/** + * C++ exception ABI. + * The following declarations are from + * + * http://www.codesourcery.com/public/cxx-abi/abi-eh.html#cxx-abi + */ + +struct __cxa_exception { + std::type_info * exceptionType; + void (*exceptionDestructor)(void *); + std::unexpected_handler unexpectedHandler; + std::terminate_handler terminateHandler; + __cxa_exception * nextException; + + int handlerCount; + int handlerSwitchValue; + const char * actionRecord; + const char * languageSpecificData; + void * catchTemp; + void * adjustedPtr; + + _Unwind_Exception unwindHeader; +}; + +static inline __cxa_exception *to_cxx(_Unwind_Exception *e) +{ + return ((__cxa_exception *)(e+1)) - 1; +} + +typedef struct __cxa_eh_globals { + __cxa_exception *caughtExceptions; + unsigned int uncaughtExceptions; +} __cxa_eh_globals; + +__cxa_eh_globals*__cxa_get_globals(void) throw(); + +__CILKRTS_END_EXTERN_C + +#endif // ! defined(INCLUDED_EXCEPT_GCC_DOT_H) diff --git a/libcilkrts/runtime/except.h b/libcilkrts/runtime/except.h new file mode 100644 index 00000000000..58e2238c581 --- /dev/null +++ b/libcilkrts/runtime/except.h @@ -0,0 +1,123 @@ +/* except.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** + * @file except.h + * + * @brief Common definitions for the various implementations of exception + * handling. + */ + +#ifndef INCLUDED_EXCEPT_DOT_H +#define INCLUDED_EXCEPT_DOT_H + +#include <cilk/common.h> +#include <internal/abi.h> +#include "full_frame.h" + +__CILKRTS_BEGIN_EXTERN_C + +/** + * OS-dependent information about an exception that's being moved between + * strands. + */ +typedef struct pending_exception_info pending_exception_info; + +/** + * Merge the right exception record into the left. The left is logically + * earlier. + * + * On entry the left state is synched and can not have an unresolved + * exception. The merge may result in an unresolved exception. + * + * If there is both a right and left exception, the right exception will + * be disposed of in preference to the left exception, destructing the + * exception object. + * + * @param w The worker that is preparing to resume execution. + * @param left_exception The exception that would have happened earlier + * if the code executed serially. Can be NULL if the left strand has not + * raised an exception. + * @param right_exception The exception that would have happened later + * if the code executed serially. Can be NULL if the right strand has not + * raised an exception. + * + * @return NULL if there both the right and left exception are NULL. This + * indicates that there are no pending exceptions. + * @return The pending exception that is to be raised to continue searching + * for a catch block to handle the exception. + */ +COMMON_SYSDEP +struct pending_exception_info *__cilkrts_merge_pending_exceptions( + __cilkrts_worker *w, + pending_exception_info *left_exception, + pending_exception_info *right_exception); + +/** + * Move the exception information from the worker to the full_frame. + * + * @param w The worker which is suspending work on a full_frame. + * @param ff The full_frame which is being suspended. + */ +COMMON_SYSDEP +void __cilkrts_save_exception_state(__cilkrts_worker *w, + full_frame *ff); + +/** + * Function to delete pending exception. This will delete the + * exception object and then free the stack/fiber. + * + * @param w The worker we're running on. + * @param pei The pending exception to be delete + * @param delete_object Unused. Should always be 1. + */ +void delete_exception_obj (__cilkrts_worker *w, + struct pending_exception_info *pei, + int delete_object); + +#ifndef _WIN32 +/* gcc-style exception handling */ +NON_COMMON NORETURN __cilkrts_c_sync_except(__cilkrts_worker *w, + __cilkrts_stack_frame *sf); +NON_COMMON void __attribute__((nonnull)) +__cilkrts_gcc_rethrow(__cilkrts_stack_frame *sf); +#endif + +__CILKRTS_END_EXTERN_C + +#endif // ! defined(INCLUDED_EXCEPT_DOT_H) diff --git a/libcilkrts/runtime/frame_malloc.c b/libcilkrts/runtime/frame_malloc.c new file mode 100644 index 00000000000..0b38bd209a9 --- /dev/null +++ b/libcilkrts/runtime/frame_malloc.c @@ -0,0 +1,462 @@ +/* frame_malloc.c -*-C-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +#include "frame_malloc.h" +#include "bug.h" +#include "local_state.h" +#include "cilk_malloc.h" + +#ifndef __VXWORKS__ +#include <memory.h> +#endif + +/* #define USE_MMAP 1 */ +#if USE_MMAP +#define __USE_MISC 1 +#include <sys/mman.h> +#include <errno.h> +#endif + +// Define to fill the stack frame header with the fill character when pushing +// it on a free list. Note that this should be #ifdef'd out when checked in! + +#ifdef _DEBUG +#define HEADER_FILL_CHAR 0xbf +#endif + +// HEADER_FILL_CHAR should not be defined when checked in, so put out a warning +// message if this is a release build + +#if defined(NDEBUG) && defined (HEADER_FILL_CHAR) +#pragma message ("Warning: HEADER_FILL_CHAR defined for a release build") +#endif + +static void allocate_batch(__cilkrts_worker *w, int bucket, size_t size); + +#ifndef _WIN32 + +const unsigned short __cilkrts_bucket_sizes[FRAME_MALLOC_NBUCKETS] = +{ + 64, 128, 256, 512, 1024, 2048 +}; + +#define FRAME_MALLOC_BUCKET_TO_SIZE(bucket) __cilkrts_bucket_sizes[bucket] + +/* threshold above which we use slow malloc */ +#define FRAME_MALLOC_MAX_SIZE 2048 + +#else // _WIN32 + +/* Note that this must match the implementation of framesz_to_bucket in + * asmilator/layout.ml! */ +#define FRAME_MALLOC_BUCKET_TO_SIZE(bucket) ((size_t)(64 << (bucket))) + +/* threshold above which we use slow malloc */ +#define FRAME_MALLOC_MAX_SIZE \ + FRAME_MALLOC_BUCKET_TO_SIZE(FRAME_MALLOC_NBUCKETS - 1) + +#endif // _WIN32 + +/* utility procedures */ +static void push(struct free_list **b, struct free_list *p) +{ +#ifdef HEADER_FILL_CHAR + memset (p, HEADER_FILL_CHAR, FRAME_MALLOC_BUCKET_TO_SIZE(0)); +#endif + /* cons! onto free list */ + p->cdr = *b; + *b = p; +} + +static struct free_list *pop(struct free_list **b) +{ + struct free_list *p = *b; + if (p) + *b = p->cdr; + return p; +} + +/************************************************************* + global allocator: +*************************************************************/ +/* request slightly less than 2^K from the OS, which after malloc + overhead and alignment should end up filling each VM page almost + completely. 128 is a guess of the total malloc overhead and cache + line alignment */ +#define FRAME_MALLOC_CHUNK (32 * 1024 - 128) + +/** Implements linked list of frames */ +struct pool_cons { + char *p; /**< This element of the list */ + struct pool_cons *cdr; /**< Remainder of the list */ +}; + +static void extend_global_pool(global_state_t *g) +{ + /* FIXME: memalign to a cache line? */ + struct pool_cons *c = (struct pool_cons *)__cilkrts_malloc(sizeof(*c)); + g->frame_malloc.pool_begin = + (char *)__cilkrts_malloc((size_t)FRAME_MALLOC_CHUNK); + g->frame_malloc.pool_end = + g->frame_malloc.pool_begin + FRAME_MALLOC_CHUNK; + g->frame_malloc.allocated_from_os += FRAME_MALLOC_CHUNK; + c->p = g->frame_malloc.pool_begin; + c->cdr = g->frame_malloc.pool_list; + g->frame_malloc.pool_list = c; +} + +/* the size is already canonicalized at this point */ +static struct free_list *global_alloc(global_state_t *g, int bucket) +{ + struct free_list *mem; + size_t size; + + CILK_ASSERT(bucket < FRAME_MALLOC_NBUCKETS); + size = FRAME_MALLOC_BUCKET_TO_SIZE(bucket); + g->frame_malloc.allocated_from_global_pool += size; + + if (!(mem = pop(&g->frame_malloc.global_free_list[bucket]))) { + + CILK_ASSERT(g->frame_malloc.pool_begin <= g->frame_malloc.pool_end); + if (g->frame_malloc.pool_begin + size > g->frame_malloc.pool_end) { + /* We waste the fragment of pool. */ + g->frame_malloc.wasted += + g->frame_malloc.pool_end - g->frame_malloc.pool_begin; + extend_global_pool(g); + } + mem = (struct free_list *)g->frame_malloc.pool_begin; + g->frame_malloc.pool_begin += size; + } + + return mem; +} + +static void global_free(global_state_t *g, void *mem, int bucket) +{ + size_t size; + + CILK_ASSERT(bucket < FRAME_MALLOC_NBUCKETS); + size = FRAME_MALLOC_BUCKET_TO_SIZE(bucket); + g->frame_malloc.allocated_from_global_pool -= size; + + push(&g->frame_malloc.global_free_list[bucket], mem); +} + +void __cilkrts_frame_malloc_global_init(global_state_t *g) +{ + int i; + + __cilkrts_mutex_init(&g->frame_malloc.lock); + g->frame_malloc.check_for_leaks = 1; + g->frame_malloc.pool_list = 0; + g->frame_malloc.pool_begin = 0; + g->frame_malloc.pool_end = 0; + g->frame_malloc.batch_size = 8000; + g->frame_malloc.potential_limit = 4 * g->frame_malloc.batch_size; + g->frame_malloc.allocated_from_os = 0; + g->frame_malloc.allocated_from_global_pool = 0; + g->frame_malloc.wasted = 0; + for (i = 0; i < FRAME_MALLOC_NBUCKETS; ++i) + g->frame_malloc.global_free_list[i] = 0; +} + +// Counts how many bytes are in the global free list. +static size_t count_memory_in_global_list(global_state_t *g) +{ + + // Count the memory remaining in the global free list. + size_t size_remaining_in_global_list = 0; + int i; + for (i = 0; i < FRAME_MALLOC_NBUCKETS; ++i) { + struct free_list *p; + size_t size_in_bucket = 0; + p = g->frame_malloc.global_free_list[i]; + + while (p) { + size_in_bucket += FRAME_MALLOC_BUCKET_TO_SIZE(i); + p = p->cdr; + } + size_remaining_in_global_list += size_in_bucket; + } + return size_remaining_in_global_list; +} + + +void __cilkrts_frame_malloc_global_cleanup(global_state_t *g) +{ + struct pool_cons *c; + + if (g->frame_malloc.check_for_leaks) { + size_t memory_in_global_list = count_memory_in_global_list(g); + // TBD: This check is weak. Short of memory corruption, + // I don't see how we have more memory in the free list + // than allocated from the os. + // Ideally, we should count the memory in the global free list + // and check that we have it all. But I believe the runtime + // itself also uses some memory, which is not being tracked. + if (memory_in_global_list > g->frame_malloc.allocated_from_os) { + __cilkrts_bug("\nError. The Cilk runtime data structures may have been corrupted.\n"); + } + } + + while ((c = g->frame_malloc.pool_list)) { + g->frame_malloc.pool_list = c->cdr; + __cilkrts_free(c->p); + __cilkrts_free(c); + } + + __cilkrts_mutex_destroy(0, &g->frame_malloc.lock); + + // Check that all the memory moved from the global pool into + // workers has been returned to the global pool. + if (g->frame_malloc.check_for_leaks + && (g->frame_malloc.allocated_from_global_pool != 0)) + { + __cilkrts_bug("\n" + "---------------------------" "\n" + " MEMORY LEAK DETECTED!!! " "\n" + "---------------------------" "\n" + "\n" + ); + } +} + +/************************************************************* + per-worker allocator +*************************************************************/ +/* allocate a batch of frames of size SIZE from the global pool and + store them in the worker's free list */ +static void allocate_batch(__cilkrts_worker *w, int bucket, size_t size) +{ + global_state_t *g = w->g; + + __cilkrts_mutex_lock(w, &g->frame_malloc.lock); { +#if USE_MMAP + char *p = mmap(0, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + if (p == MAP_FAILED) + __cilkrts_bug("mmap failed %d", errno); + assert(size < 4096); + assert(p != MAP_FAILED); + mprotect(p, 4096, PROT_NONE); + mprotect(p + 8192, 4096, PROT_NONE); + w->l->bucket_potential[bucket] += size; + push(&w->l->free_list[bucket], (struct free_list *)(p + 8192 - size)); +#else + size_t bytes_allocated = 0; + do { + w->l->bucket_potential[bucket] += size; + bytes_allocated += size; + push(&w->l->free_list[bucket], global_alloc(g, bucket)); + } while (bytes_allocated < g->frame_malloc.batch_size); +#endif + } __cilkrts_mutex_unlock(w, &g->frame_malloc.lock); + +} + +static void gc_bucket(__cilkrts_worker *w, int bucket, size_t size) +{ + struct free_list *p, *q; + global_state_t *g = w->g; + size_t pot = w->l->bucket_potential[bucket]; + size_t newpot; + + /* Keep up to POT/2 elements in the free list. The cost of + counting up to POT/2 is amortized against POT. */ + newpot = 0; + for (newpot = 0, p = w->l->free_list[bucket]; p && 2 * newpot < pot; + p = p->cdr, newpot += size) + ; + w->l->bucket_potential[bucket] = newpot; + + if (p) { + /* free the rest of the list. The cost of grabbing the lock + is amortized against POT/2; the cost of traversing the rest + of the list is amortized against the free operation that + puts the element on the list. */ + __cilkrts_mutex_lock(w, &g->frame_malloc.lock); { + while ((q = pop(&p->cdr))) +#if USE_MMAP + munmap((char *)q + size - 8192, 12288); +#else + global_free(g, q, bucket); +#endif + } __cilkrts_mutex_unlock(w, &g->frame_malloc.lock); + } +} + +// Free all the memory in this bucket for the specified worker, +// returning it to the global pool's free list. +static void move_bucket_to_global_free_list(__cilkrts_worker *w, + int bucket) +{ + struct free_list *p, *q; + global_state_t *g = w->g; + p = w->l->free_list[bucket]; + + if (p) { + __cilkrts_mutex_lock(w, &g->frame_malloc.lock); { + while ((q = pop(&p))) { +#if USE_MMAP + size_t size = FRAME_MALLOC_BUCKET_TO_SIZE(bucket); + munmap((char *)q + size - 8192, 12288); +#else + global_free(g, q, bucket); +#endif + } + } __cilkrts_mutex_unlock(w, &g->frame_malloc.lock); + } + + // I'm not sure this does anything useful now, since + // the worker is about to be destroyed. But why not? + w->l->bucket_potential[bucket] = 0; +} + +static int bucket_of_size(size_t size) +{ + int i; + + for (i = 0; i < FRAME_MALLOC_NBUCKETS; ++i) + if (size <= FRAME_MALLOC_BUCKET_TO_SIZE(i)) + return i; + + CILK_ASSERT(0 /* can't happen */); + return -1; +} + +size_t __cilkrts_frame_malloc_roundup(size_t size) +{ + if (size > FRAME_MALLOC_MAX_SIZE) { + /* nothing, leave it alone */ + } else { + int bucket = bucket_of_size(size); + size = FRAME_MALLOC_BUCKET_TO_SIZE(bucket); + } + return size; +} + +size_t __cilkrts_size_of_bucket(int bucket) +{ + CILK_ASSERT(bucket >= 0 && bucket < FRAME_MALLOC_NBUCKETS); + return FRAME_MALLOC_BUCKET_TO_SIZE(bucket); +} + +void *__cilkrts_frame_malloc(__cilkrts_worker *w, size_t size) +{ + int bucket; + void *mem; + + /* if too large, or if no worker, fall back to __cilkrts_malloc() */ + if (!w || size > FRAME_MALLOC_MAX_SIZE) { + NOTE_INTERVAL(w, INTERVAL_FRAME_ALLOC_LARGE); + return __cilkrts_malloc(size); + } + + START_INTERVAL(w, INTERVAL_FRAME_ALLOC); { + bucket = bucket_of_size(size); + size = FRAME_MALLOC_BUCKET_TO_SIZE(bucket); + + while (!(mem = pop(&w->l->free_list[bucket]))) { + /* get a batch of frames from the global pool */ + START_INTERVAL(w, INTERVAL_FRAME_ALLOC_GLOBAL) { + allocate_batch(w, bucket, size); + } STOP_INTERVAL(w, INTERVAL_FRAME_ALLOC_GLOBAL); + } + } STOP_INTERVAL(w, INTERVAL_FRAME_ALLOC); + + return mem; +} + +void __cilkrts_frame_free(__cilkrts_worker *w, void *p0, size_t size) +{ + int bucket; + struct free_list *p = (struct free_list *)p0; + + /* if too large, or if no worker, fall back to __cilkrts_free() */ + if (!w || size > FRAME_MALLOC_MAX_SIZE) { + NOTE_INTERVAL(w, INTERVAL_FRAME_FREE_LARGE); + __cilkrts_free(p); + return; + } + +#if CILK_LIB_DEBUG + *(volatile long *)w; +#endif + + START_INTERVAL(w, INTERVAL_FRAME_FREE); { + bucket = bucket_of_size(size); + size = FRAME_MALLOC_BUCKET_TO_SIZE(bucket); + w->l->bucket_potential[bucket] += size; + push(&w->l->free_list[bucket], p); + if (w->l->bucket_potential[bucket] > + w->g->frame_malloc.potential_limit) { + START_INTERVAL(w, INTERVAL_FRAME_FREE_GLOBAL) { + gc_bucket(w, bucket, size); + } STOP_INTERVAL(w, INTERVAL_FRAME_FREE_GLOBAL); + } + } STOP_INTERVAL(w, INTERVAL_FRAME_FREE); +} + +void __cilkrts_frame_malloc_per_worker_init(__cilkrts_worker *w) +{ + int i; + local_state *l = w->l; + + for (i = 0; i < FRAME_MALLOC_NBUCKETS; ++i) { + l->free_list[i] = 0; + l->bucket_potential[i] = 0; + } +} + +void __cilkrts_frame_malloc_per_worker_cleanup(__cilkrts_worker *w) +{ + int i; + // Move memory to the global pool. This operation + // ensures the memory does not become unreachable / leak + // when the worker is destroyed. + for (i = 0; i < FRAME_MALLOC_NBUCKETS; ++i) { + move_bucket_to_global_free_list(w, i); + } +} + +/* + Local Variables: ** + c-file-style:"bsd" ** + c-basic-offset:4 ** + indent-tabs-mode:nil ** + End: ** +*/ diff --git a/libcilkrts/runtime/frame_malloc.h b/libcilkrts/runtime/frame_malloc.h new file mode 100644 index 00000000000..d412fb620fe --- /dev/null +++ b/libcilkrts/runtime/frame_malloc.h @@ -0,0 +1,205 @@ +/* frame_malloc.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** + * @file frame_malloc.h + * + * @brief The frame allocation routines manage memory in a per-worker pool. + * + * The name "frame malloc" refers to an earlier implementation of Cilk which + * allocated frames from the heap using this allocator. + */ + +#ifndef INCLUDED_FRAME_MALLOC_DOT_H +#define INCLUDED_FRAME_MALLOC_DOT_H + +#include "worker_mutex.h" +#include "rts-common.h" +#include <internal/abi.h> // __cilkrts_worker + +#ifdef __cplusplus +# include <cstddef> +#else +# include <stddef.h> +#endif + +__CILKRTS_BEGIN_EXTERN_C + +/** + * Number of buckets. Gives us buckets to hold 64, 128, 256, 512, 1024 + * and 2048 bytes + */ +#define FRAME_MALLOC_NBUCKETS 6 + +/** Layout of frames when unallocated */ +struct free_list { + /** Pointer to next free frame */ + struct free_list *cdr; +}; + +/** per-worker memory cache */ +struct __cilkrts_frame_cache +{ + /** Mutex to serialize access */ + struct mutex lock; + + /** Linked list of frames */ + struct pool_cons *pool_list; + + /** Low bound of memory in pool */ + char *pool_begin; + + /** High bound of memory in pool */ + char *pool_end; + + /** Global free-list buckets */ + struct free_list *global_free_list[FRAME_MALLOC_NBUCKETS]; + + /** + * How many bytes to obtain at once from the global pool + * (approximately) + */ + size_t batch_size; + + /** Garbage-collect a bucket when its potential exceeds the limit */ + size_t potential_limit; + + /** If TRUE, check for memory leaks at the end of execution */ + int check_for_leaks; + + /** Bytes of memory allocated from the OS by the global cache */ + size_t allocated_from_os; + + /** Tracks memory allocated by a chunk that isn't a full bucket size */ + size_t wasted; + + /** Bytes of memory allocated from the global cache */ + size_t allocated_from_global_pool; +}; + +/** + * Allocate memory from the per-worker pool. If the size is too large, or + * if we're given a NULL worker, the memory is allocated using + * __cilkrts_malloc(). + * + * @param w The worker to allocate the memory from. + * @param size The number of bytes to allocate. + * + * @return pointer to allocated memory block. + */ +COMMON_PORTABLE +void *__cilkrts_frame_malloc(__cilkrts_worker *w, + size_t size) cilk_nothrow; + +/** + * Return memory to the per-worker pool. If the size is too large, or + * if we're given a NULL worker, the memory is freed using + * __cilkrts_free(). + * + * @param w The worker to allocate the memory from. + * @param p The memory block to be released. + * @param size The size of the block, in bytes. + */ +COMMON_PORTABLE +void __cilkrts_frame_free(__cilkrts_worker *w, + void* p, + size_t size) cilk_nothrow; + +/** + * Destroy the global cache stored in the global state, freeing all memory + * to the global heap. Checks whether any memory has been allocated but + * not freed. + * + * @param g The global state. + */ +COMMON_PORTABLE +void __cilkrts_frame_malloc_global_cleanup(global_state_t *g); + +/** + * Initialize a worker's memory cache. Initially it is empty. + * + * @param w The worker who's memory cache is to be initialized. + */ +COMMON_PORTABLE +void __cilkrts_frame_malloc_per_worker_init(__cilkrts_worker *w); + +/** + * If check_for_leaks is set in the global state's memory cache, free any + * memory in the worker's memory cache. + * + * If check_for_leask is not set, nothing happens. + * + * @param w The worker who's memory cache is to be cleaned up. + */ +COMMON_PORTABLE +void __cilkrts_frame_malloc_per_worker_cleanup(__cilkrts_worker *w); + +/** + * Round a number of bytes to the size of the smallest bucket that will + * hold it. If the size is bigger than the largest bucket, the value is + * unchanged. + * + * @param size Number of bytes to be rounded up to the nearest bucket size. + * + * @return The size of the smallest bucket that will hold the specified bytes. + */ +COMMON_PORTABLE +size_t __cilkrts_frame_malloc_roundup(size_t size) cilk_nothrow; + +/** + * Return the number of bytes that can fit into a bucket. + * + * Preconditions: + * - The index must be in the range 0 - FRAME_MALLOC_NBUCKETS + * + * @param bucket Index of the bucket to be sized. + */ +COMMON_PORTABLE +size_t __cilkrts_size_of_bucket(int bucket) cilk_nothrow; + +/** + * Initialize the global memory cache. + * + * @param g The global state. + */ +COMMON_PORTABLE +void __cilkrts_frame_malloc_global_init(global_state_t *g); + +__CILKRTS_END_EXTERN_C + +#endif // ! defined(INCLUDED_FRAME_MALLOC_DOT_H) diff --git a/libcilkrts/runtime/full_frame.c b/libcilkrts/runtime/full_frame.c new file mode 100644 index 00000000000..9ccfd110d6b --- /dev/null +++ b/libcilkrts/runtime/full_frame.c @@ -0,0 +1,181 @@ +/* full_frame.c -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2010-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + +#include "full_frame.h" +#include "stats.h" +#include "os.h" +#include "bug.h" +#include "jmpbuf.h" +#include "frame_malloc.h" + +COMMON_PORTABLE +full_frame *__cilkrts_make_full_frame(__cilkrts_worker *w, + __cilkrts_stack_frame *sf) +{ + full_frame *ff; + + START_INTERVAL(w, INTERVAL_ALLOC_FULL_FRAME) { + ff = (full_frame *)__cilkrts_frame_malloc(w, sizeof(*ff)); + __cilkrts_mutex_init(&ff->lock); + + ff->full_frame_magic_0 = FULL_FRAME_MAGIC_0; + ff->join_counter = 0; + ff->parent = 0; + ff->rightmost_child = 0; + ff->left_sibling = ff->right_sibling = 0; + ff->call_stack = sf; + ff->is_call_child = 0; + ff->simulated_stolen = 0; + ff->children_reducer_map = ff->right_reducer_map = 0; + ff->pending_exception = + ff->child_pending_exception = + ff->right_pending_exception = NULL; + + ff->sync_sp = 0; +#ifdef _WIN32 + ff->exception_sp = 0; + ff->trylevel = (unsigned long)-1; + ff->registration = 0; +#endif + ff->frame_size = 0; + ff->fiber_self = 0; + ff->fiber_child = 0; + + ff->sync_master = 0; + + /*__cilkrts_init_full_frame_sysdep(w, ff);*/ + ff->full_frame_magic_1 = FULL_FRAME_MAGIC_1; + } STOP_INTERVAL(w, INTERVAL_ALLOC_FULL_FRAME); + return ff; +} + +COMMON_PORTABLE void __cilkrts_put_stack(full_frame *ff, + __cilkrts_stack_frame *sf) +{ + /* When suspending frame ff prior to stealing it, __cilkrts_put_stack is + * used to store the stack pointer for eventual sync. When suspending + * frame ff prior to a sync, __cilkrts_put_stack is called to re-establish + * the sync stack pointer, offsetting it by any change in the stack depth + * that occured between the spawn and the sync. + * Although it is not usually meaningful to add two pointers, the value of + * ff->sync_sp at the time of this call is really an integer, not a + * pointer. + */ + ptrdiff_t sync_sp_i = (ptrdiff_t) ff->sync_sp; + char* sp = (char*) __cilkrts_get_sp(sf); + + ff->sync_sp = sp + sync_sp_i; + + DBGPRINTF("%d- __cilkrts_put_stack - adjust (+) sync " + "stack of full frame %p (+sp: %p) to %p\n", + __cilkrts_get_tls_worker()->self, ff, sp, ff->sync_sp); +} + +COMMON_PORTABLE void __cilkrts_take_stack(full_frame *ff, void *sp) +{ + /* When resuming the parent after a steal, __cilkrts_take_stack is used to + * subtract the new stack pointer from the current stack pointer, storing + * the offset in ff->sync_sp. When resuming after a sync, + * __cilkrts_take_stack is used to subtract the new stack pointer from + * itself, leaving ff->sync_sp at zero (null). Although the pointers being + * subtracted are not part of the same contiguous chunk of memory, the + * flat memory model allows us to subtract them and get a useable offset. + */ + ptrdiff_t sync_sp_i = ff->sync_sp - (char*) sp; + + ff->sync_sp = (char *) sync_sp_i; + + DBGPRINTF("%d- __cilkrts_take_stack - adjust (-) sync " + "stack of full frame %p to %p (-sp: %p)\n", + __cilkrts_get_tls_worker()->self, ff, ff->sync_sp, sp); +} + +COMMON_PORTABLE void __cilkrts_adjust_stack(full_frame *ff, size_t size) +{ + /* When resuming the parent after a steal, __cilkrts_take_stack is used to + * subtract the new stack pointer from the current stack pointer, storing + * the offset in ff->sync_sp. When resuming after a sync, + * __cilkrts_take_stack is used to subtract the new stack pointer from + * itself, leaving ff->sync_sp at zero (null). Although the pointers being + * subtracted are not part of the same contiguous chunk of memory, the + * flat memory model allows us to subtract them and get a useable offset. + * + * __cilkrts_adjust_stack() is used to deallocate a Variable Length Array + * by adding it's size to ff->sync_sp. + */ + ff->sync_sp = ff->sync_sp + size; + + DBGPRINTF("%d- __cilkrts_adjust_stack - adjust (+) sync " + "stack of full frame %p to %p (+ size: 0x%x)\n", + __cilkrts_get_tls_worker()->self, ff, ff->sync_sp, size); +} + +COMMON_PORTABLE +void __cilkrts_destroy_full_frame(__cilkrts_worker *w, full_frame *ff) +{ + validate_full_frame(ff); + CILK_ASSERT(ff->children_reducer_map == 0); + CILK_ASSERT(ff->right_reducer_map == 0); + CILK_ASSERT(NULL == ff->pending_exception); + CILK_ASSERT(NULL == ff->child_pending_exception); + CILK_ASSERT(NULL == ff->right_pending_exception); + __cilkrts_mutex_destroy(w, &ff->lock); + __cilkrts_frame_free(w, ff, sizeof(*ff)); +} + +COMMON_PORTABLE void validate_full_frame(full_frame *ff) +{ + /* check the magic numbers, for debugging purposes */ + if (ff->full_frame_magic_0 != FULL_FRAME_MAGIC_0 || + ff->full_frame_magic_1 != FULL_FRAME_MAGIC_1) + abort_because_rts_is_corrupted(); +} + +void __cilkrts_frame_lock(__cilkrts_worker *w, full_frame *ff) +{ + validate_full_frame(ff); + __cilkrts_mutex_lock(w, &ff->lock); +} + +void __cilkrts_frame_unlock(__cilkrts_worker *w, full_frame *ff) +{ + __cilkrts_mutex_unlock(w, &ff->lock); +} + +/* End full_frame.c */ diff --git a/libcilkrts/runtime/full_frame.h b/libcilkrts/runtime/full_frame.h new file mode 100644 index 00000000000..327a3337afe --- /dev/null +++ b/libcilkrts/runtime/full_frame.h @@ -0,0 +1,493 @@ +/* full_frame.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +#ifndef INCLUDED_FULL_FRAME_DOT_H +#define INCLUDED_FULL_FRAME_DOT_H + + +#include "rts-common.h" +#include "worker_mutex.h" + +#include <cilk/common.h> +#include <internal/abi.h> +#include <stddef.h> +#include "cilk_fiber.h" + +__CILKRTS_BEGIN_EXTERN_C + +/** Magic numbers for full_frame, used for debugging */ +typedef unsigned long long ff_magic_t; + +/* COMMON_SYSDEP */ struct pending_exception_info; /* opaque */ + +/************************************************************* + Full frames +*************************************************************/ + +/** + * @file full_frame.h + * @brief A full frame includes additional information such as a join + * counter and parent frame. + * @defgroup FullFrames Full Frames + * A full frame includes additional information such as a join + * counter and parent frame. + * @{ + */ + +/** + * Convenience typedef so we don't have to specify "struct full_frame" + * all over the code. Putting it before the structure definition allows + * us to use the typedef within the structure itself + */ +typedef struct full_frame full_frame; + +/** + * @brief A full frame includes additional information such as a join + * counter and parent frame. + * + * The frame at the top of a worker's stack is promoted into a "full" + * frame, which carries additional information, such as join counter + * and parent frame. Full frames can be suspended at a sync, in which + * case they lie somewhere in memory and do not belong to any + * worker. + * + * Full frames are in contrast to the entries in the worker's deque which + * are only represented by a pointer to their __cilkrts_stack_frame. + * + * At any instant, we say that a full frame ff is either "suspended", + * or "owned" by some worker w. + * + * More precisely, we say that a worker w owns a frame ff under one of + * the following conditions: + * + * 1. Creation: Worker w has just created ff, but not yet linked ff + * into the tree of full frames. This situation can occur when a + * worker is unrolling a call stack to promote a + * __cilkrts_stack_frame to a full_frame. + * 2. Executing frame: We have w->l->frame_ff == ff, i.e,. ff is the + * currently executing frame for w. + * 3. Next frame: We have w->l->next_frame_ff == ff, i.e,. ff is the + * next frame that w is about to execute. + * 4. Resume execution: Worker w has popped ff from + * w->l->next_frame_ff, and is about to resume execution of ff. + * 5. Dying leaf: Worker w has finished executing a frame ff + * that is a leaf the tree of full frames, and is in the process + * of unlinking "ff" from the tree. + * + * Otherwise, the frame ff is suspended, and has no owner. + * Note that work-stealing changes the owner of a full frame from the + * victim to the thief. + * + * Using this notion of ownership, we classify the fields of a full + * frame into one of several categories: + * + * 1. Local: + * These fields are accessed only by the owner of the full frame. + * Because a frame can have only one owner at a time, these fields + * can be modified without any (additional) locking or + * synchronization, assuming the correct synchronization for + * changing the ownership of full frame (e.g., on a successful + * steal) is already in place. + * + * 2. Constant (i.e., read-only): + * This field is constant for the lifetime of the full frame. + * No locks are needed to access this field. + * Technically, a field could be read-only and local, but we assume + * it is shared. + * + * 3. Self-locked: + * To access this field in the frame ff, a worker should acquire + * the lock on ff. + * A self-locked field is conceptually "shared" between the worker + * that owns frame ff (which is a child) and the worker that + * owns the frame ff->parent (which is the parent of ff). + * + * 4. Parent-locked: + * To access this field in the frame ff, a worker should + * acquire the lock on ff->parent. + * A parent-locked field is conceptually "shared" between the worker + * that owns frame ff, and a worker that is either owns the + * parent frame (ff->parent) or owns a sibling frame of ff (i.e., + * any child of ff->parent). + * + * 5. Synchronization + * A field used explicitly for synchronization (i.e., locks). + */ + +/* COMMON_PORTABLE */ +struct full_frame +{ + /** + * Value to detect writes off the beginning of a full_frame. + */ +# define FULL_FRAME_MAGIC_0 ((ff_magic_t)0x361e710b9597d553ULL) + + /** + * Field to detect writes off the beginning of a full_frame. Must be + * FULL_FRAME_MAGIC_0. + * [constant] + */ + ff_magic_t full_frame_magic_0; + + /** + * Used to serialize access to this full_frame + * [synchronization] + */ + struct mutex lock; + + /** + * Count of outstanding children running in parallel + * [self-locked] + */ + int join_counter; + + /** + * If TRUE: frame was called by the parent. + * If FALSE: frame was spawned by parent. + * [constant] + */ + int is_call_child; + + /** + * TRUE if this frame is the loot of a simulated steal. + * + * This situation never happens in normal execution. However, + * when running under cilkscreen, a worker may promote frames and + * then immediately suspend them, in order to simulate an + * execution on an infinite number of processors where all spawns + * are stolen. In this case, the frame is marked as the loot of a fake + * steal. + * [local] + */ + int simulated_stolen; + + /** + * Caller of this full_frame + * [constant] + */ + full_frame *parent; + + /** + * Doubly-linked list of children. The serial execution order is + * by definition from left to right. Because of how we do work + * stealing, the parent is always to the right of all its + * children. + * + * For a frame ff, we lock the ff->parent to follow the sibling + * links for ff. + * + * [parent-locked] + */ + full_frame *left_sibling; + + /** + * @copydoc left_sibling + */ + full_frame *right_sibling; + + /** + * Pointer to rightmost child + * + * [self-locked] + */ + full_frame *rightmost_child; + + /** + * Call stack associated with this frame. + * Set and reset in make_unrunnable and make_runnable + * + * [self-locked] + */ + __cilkrts_stack_frame *call_stack; + + /** + * Accumulated reducers of children + * + * [self-locked] + */ + struct cilkred_map *children_reducer_map; + + /** + * Accumulated reducers of right siblings that have already + * terminated + * + * [parent-locked] + */ + struct cilkred_map *right_reducer_map; + + /** + * Exception that needs to be pass to our parent + * + * [local] + * + * TBD: verify that the exception code satisfies this requirement. + */ + struct pending_exception_info *pending_exception; + + /** + * Exception from one of our children + * + * [self-locked] + */ + struct pending_exception_info *child_pending_exception; + + /** + * Exception from any right siblings + * + * [parent-locked] + */ + struct pending_exception_info *right_pending_exception; + + /** + * Stack pointer to restore on sync. + * [local] + */ + char *sync_sp; + +#ifdef _WIN32 + /** + * Stack pointer to restore on exception. + * [local] + */ + char *exception_sp; + + /** + * Exception trylevel at steal + * [local] + * + * TBD: this field is set but not read? + */ + unsigned long trylevel; + + /** + * Exception registration head pointer to restore on sync. + * [local] + */ + unsigned long registration; +#endif + + /** + * Size of frame to match sync sp + * [local] + * TBD: obsolete field only used in debugging? + */ + ptrdiff_t frame_size; + + /** + * Allocated fibers that need to be freed. The fibers work + * like a reducer. The leftmost frame may have @c fiber_self + * null and owner non-null. + * + * [local] + * TBD: verify exception code satisfies this requirement. + */ + cilk_fiber *fiber_self; + + /** + * Allocated fibers that need to be freed. The fibers work + * like a reducer. The leftmost frame may have @c fiber_self + * null and owner non-null. + * + * [self-locked] + */ + cilk_fiber *fiber_child; + + /** + * If the sync_master is set, this function can only be sync'd by the team + * leader, who first entered Cilk. This is set by the first worker to steal + * from the user worker. + * + * [self-locked] + */ + __cilkrts_worker *sync_master; + + /** + * Value to detect writes off the end of a full_frame. + */ +# define FULL_FRAME_MAGIC_1 ((ff_magic_t)0x189986dcc7aee1caULL) + + /** + * Field to detect writes off the end of a full_frame. Must be + * FULL_FRAME_MAGIC_1. + * + * [constant] + */ + ff_magic_t full_frame_magic_1; +}; + +/* The functions __cilkrts_put_stack and __cilkrts_take_stack keep track of + * changes in the stack's depth between when the point at which a frame is + * stolen and when it is resumed at a sync. A stolen frame typically goes + * through the following phase changes: + * + * 1. Suspend frame while stealing it. + * 2. Resume stolen frame at begining of continuation + * 3. Suspend stolen frame at a sync + * 4. Resume frame (no longer marked stolen) after the sync + * + * When the frame is suspended (steps 1 and 3), __cilkrts_put_stack is called to + * establish the stack pointer for the sync. When the frame is resumed (steps + * 2 and 4), __cilkrts_take_stack is called to indicate the stack pointer + * (which may be on a different stack) at + * the point of resume. If the stack pointer changes between steps 2 and 3, + * e.g., as a result of pushing 4 bytes onto the stack, + * the offset is reflected in the value of ff->sync_sp after step 3 relative to + * its value after step 1 (e.g., the value of ff->sync_sp after step 3 would be + * 4 less than its value after step 1, for a down-growing stack). + * + * Imp detail: The actual call chains for each of these phase-change events is: + * + * 1. unroll_call_stack -> make_unrunnable -> __cilkrts_put_stack + * 2. do_work -> __cilkrts_resume -> __cilkrts_take_stack + * 3. do_sync -> disown -> make_runnable -> __cilkrts_put_stack + * 4. __cilkrts_resume -> __cilkrts_take_stack + * + * (The above is a changeable implementation detail. The resume, sequence, in + * particular, is more complex on some operating systems.) + */ + +/** + * @brief Records the stack pointer within the @c sf stack frame as the + * current stack pointer at the point of suspending full frame @c ff. + * + * @pre @c ff->sync_sp must be either null or contain the result of a prior call to + * @c __cilkrts_take_stack(). + * @pre If @c ff->sync_sp is not null, then @c SP(sf) must refer to the same stack as + * the @c sp argument to the prior call to @c __cilkrts_take_stack(). + * + + * @post If @c ff->sync_sp was null before the call, then @c + * ff->sync_sp will be set to @c SP(sf). + * @post Otherwise, @c ff->sync_sp will be restored to the value it had just prior + * to the last call to @c __cilkrts_take_stack(), except offset by any change + * in the stack pointer between the call to @c __cilkrts_take_stack() and + * this call to @c __cilkrts_put_stack(). + * + * @param ff The full frame that is being suspended. + * @param sf The @c __cilkrts_stack_frame that is being suspended. The stack + * pointer will be taken from the jmpbuf contained within this + * @c __cilkrts_stack_frame. + */ +COMMON_PORTABLE void __cilkrts_put_stack(full_frame *ff, + __cilkrts_stack_frame *sf); + +/** + * @brief Records the stack pointer @c sp as the stack pointer at the point of + * resuming execution on full frame @c ff. + * + * The value of @c sp may be on a different stack than the original + * value recorded for the stack pointer using __cilkrts_put_stack(). + * + * @pre @c ff->sync_sp must contain a value set by @c __cilkrts_put_stack(). + * + * @post @c ff->sync_sp contains an *integer* value used to compute a change in the + * stack pointer upon the next call to @c __cilkrts_take_stack(). + * @post If @c sp equals @c ff->sync_sp, then @c ff->sync_sp is set to null. + * + * @param ff The full frame that is being resumed. + * @param sp The stack pointer for the stack the function is being resumed on. + */ +COMMON_PORTABLE void __cilkrts_take_stack(full_frame *ff, void *sp); + +/* + * @brief Adjust the stack for to deallocate a Variable Length Array + * + * @param ff The full frame that is being adjusted. + * @param size The size of the array being deallocated from the stack + */ +COMMON_PORTABLE void __cilkrts_adjust_stack(full_frame *ff, size_t size); + +/** + * @brief Allocates and initailizes a full_frame. + * + * @param w The memory for the full_frame will be allocated out of the + * worker's pool. + * @param sf The @c __cilkrts_stack_frame which will be saved as the call_stack + * for this full_frame. + * + * @return The newly allocated and initialized full_frame. + */ +COMMON_PORTABLE +full_frame *__cilkrts_make_full_frame(__cilkrts_worker *w, + __cilkrts_stack_frame *sf); + +/** + * @brief Deallocates a full_frame. + * + * @param w The memory for the full_frame will be returned to the worker's pool. + * @param ff The full_frame to be deallocated. + */ +COMMON_PORTABLE +void __cilkrts_destroy_full_frame(__cilkrts_worker *w, full_frame *ff); + +/** + * @brief Performs sanity checks to check the integrity of a full_frame. + * + * @param ff The full_frame to be validated. + */ +COMMON_PORTABLE void validate_full_frame(full_frame *ff); + +/** + * @brief Locks the mutex contained in a full_frame. + * + * The full_frame is validated before the runtime attempts to lock it. + * + * @post @c ff->lock will be owned by @c w. + * + * @param w The worker that will own the full_frame. If the runtime is + * collecting stats, the intervals will be attributed to the worker. + * @param ff The full_frame containing the mutex to be locked. + */ +COMMON_PORTABLE void __cilkrts_frame_lock(__cilkrts_worker *w, + full_frame *ff); + +/** + * @brief Unlocks the mutex contained in a full_frame. + * + * @pre @c ff->lock must must be owned by @c w. + * + * @param w The worker that currently owns the full_frame. + * @param ff The full_frame containing the mutex to be unlocked. + */ +COMMON_PORTABLE void __cilkrts_frame_unlock(__cilkrts_worker *w, + full_frame *ff); +/** @} */ + +__CILKRTS_END_EXTERN_C + +#endif // ! defined(INCLUDED_FULL_FRAME_DOT_H) diff --git a/libcilkrts/runtime/global_state.cpp b/libcilkrts/runtime/global_state.cpp new file mode 100644 index 00000000000..02de54f43b1 --- /dev/null +++ b/libcilkrts/runtime/global_state.cpp @@ -0,0 +1,628 @@ +/* global_state.cpp -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +#include "global_state.h" +#include "os.h" +#include "bug.h" +#include "metacall_impl.h" +#include "stats.h" +#include "cilk/cilk_api.h" +#include "cilk_malloc.h" +#include "record-replay.h" + +#include <algorithm> // For max() +#include <cstring> +#include <cstdlib> +#include <climits> +#include <cerrno> + +#ifdef _WIN32 +# include <wchar.h> +#endif + +// TBD: There is a race when multiple threads try to initialize the +// user_settable_values?? +// +// Set to true if the user settable values portion of the global state +// singleton is initialized, even if the rest of the singleton is not +// initialized. +int cilkg_user_settable_values_initialized = false; + +namespace { + +// Single copy of the global state. Zero-filled until +// cilkg_get_user_settable_values() is called and partially-zero-filled until +// cilkg_init_global_state() is called. The first field is filled in with +// the size of a void* for the debugger and must be valid before initialization +global_state_t global_state_singleton = +{ + sizeof(void *), // addr_size +}; + + +// Variables that need to export C-style names +extern "C" +{ + // Pointer to the global state singleton. + global_state_t *cilkg_singleton_ptr = NULL; + + // __cilkrts_global_state is exported and referenced by the debugger. + // The debugger expects it to be valid when the module loads. +// CILK_EXPORT_DATA + global_state_t *__cilkrts_global_state = &global_state_singleton; +} + +// Returns true if 'a' and 'b' are equal null-terminated strings +inline bool strmatch(const char* a, const char* b) +{ + return 0 == std::strcmp(a, b); +} + +// Returns the integer value represented by the null-terminated string at 's'. +inline long to_long(const char* s) +{ + char *end; + + errno = 0; + return std::strtol(s, &end, 0); +} + +#ifdef _WIN32 +// Returns true if 'a' and 'b' are equal null-terminated wide-char strings +inline bool strmatch(const wchar_t* a, const wchar_t* b) +{ + return 0 == wcscmp(a, b); +} + +// Returns true if the multi-byte character string at 'a' represents the same +// character sequence as the wide-character string at 'b'. The behavior is +// undefined if 'a' contains more than 30 multi-byte characters. +bool strmatch(const char* a, const wchar_t* b) +{ + // Convert 'a' to wide-characters, then compare. + wchar_t wa[31]; + std::size_t count; + errno_t err = mbstowcs_s(&count, wa, a, 30); + CILK_ASSERT(0 == err); + if (err) return false; + return strmatch(wa, b); +} + +// Returns true if the wide-character string at 'a' represents the same +// character sequence as the multi-byte character string at 'b'. The behavior +// id undefined if 'b' contains more than 30 multi-byte characters. +inline +bool strmatch(const wchar_t* a, const char* b) +{ + return strmatch(b, a); +} + + +// Returns the integer value represented by the null-terminated wide-char +// string at 's'. +inline long to_long(const wchar_t* s) +{ + wchar_t *end; + + errno = 0; + return wcstol(s, &end, 0); +} +#endif + +// Check if Cilkscreen or other sequential ptool wants to force reducers. +bool always_force_reduce() +{ + // Metacall *looks* like a no-op. volatile needed to keep compiler from + // optimizing away variable. + volatile char not_force_reduce = '\377'; + __cilkrts_metacall(METACALL_TOOL_SYSTEM, HYPER_ZERO_IF_FORCE_REDUCE, + const_cast<char*>(¬_force_reduce)); + return ! not_force_reduce; +} + +// Stores the boolean value represented by the null-terminated string at 'val' +// into the integer object at 'out'. Returns '__CILKRTS_SET_PARAM_SUCCESS' if +// 'val' is "true", "false", "0" or "1" and '__CILKRTS_SET_PARAM_INVALID' +// otherwise. +template <typename INT_T, typename CHAR_T> +int store_bool(INT_T *out, const CHAR_T *val) +{ + static const char* const s_zero = "0"; + static const char* const s_one = "1"; + static const char* const s_true = "true"; + static const char* const s_false = "false"; + + if (val == 0) + return __CILKRTS_SET_PARAM_INVALID; + + if (strmatch(s_false, val) || strmatch(s_zero, val)) { + *out = 0; + return __CILKRTS_SET_PARAM_SUCCESS; + } + + if (strmatch(s_true, val) || strmatch(s_one, val)) { + *out = 1; + return __CILKRTS_SET_PARAM_SUCCESS; + } + + return __CILKRTS_SET_PARAM_INVALID; +} + +// Stores the integer value represented by the null-terminated string at 'val' +// into the integer object at 'out', restricting the result to the range 'min' +// to 'max', inclusive. Returns '__CILKRTS_SET_PARAM_SUCCESS' if the conversion +// succeeds and is in range, '__CILKRTS_SET_PARAM_XRANGE' if the conversion +// succeeds but is out of range, and '__CILKRTS_SET_PARAM_INVALID' otherwise. In +// the case of any error, '*out' is unchanged. +template <typename INT_T, typename CHAR_T> +int store_int(INT_T *out, const CHAR_T *val, INT_T min, INT_T max) +{ + errno = 0; + long val_as_long = to_long(val); + if (val_as_long == 0 && errno != 0) + return __CILKRTS_SET_PARAM_INVALID; + if (val_as_long < min || val_as_long == LONG_MIN) + return __CILKRTS_SET_PARAM_XRANGE; + else if (val_as_long > max || val_as_long == LONG_MAX) + return __CILKRTS_SET_PARAM_XRANGE; + + *out = val_as_long; + return __CILKRTS_SET_PARAM_SUCCESS; +} + +// Implementaton of cilkg_set_param templatized on character type. +// Windows will instantiate with both char and wchar_t. +// Note that g must have its user settable values set, but need not be fully +// initialized. +template <class CHAR_T> +int set_param_imp(global_state_t* g, const CHAR_T* param, const CHAR_T* value) +{ + static const char* const s_force_reduce = "force reduce"; + static const char* const s_nworkers = "nworkers"; + static const char* const s_max_user_workers = "max user workers"; + static const char* const s_local_stacks = "local stacks"; + static const char* const s_shared_stacks = "shared stacks"; + static const char* const s_nstacks = "nstacks"; + static const char* const s_stack_size = "stack size"; + + // We must have a parameter and a value + if (0 == param) + return __CILKRTS_SET_PARAM_INVALID; + if (0 == value) + return __CILKRTS_SET_PARAM_INVALID; + + if (strmatch(param, s_force_reduce)) + { + // Sets whether we force a reduce operation at every sync. Useful for + // debugging reducers. Off by default. Overridden by Cilkscreen + // + // Documented in cilk_api_<os>.h + if (always_force_reduce()) + // Force reduce is set by cilkscreen. User cannot change it. + return __CILKRTS_SET_PARAM_LATE; + + return store_bool(&g->force_reduce, value); + } + else if (strmatch(param, s_nworkers)) + { + // Set the total number of workers. Overrides count of cores we get + // from the OS and the setting of the CILK_NWORKERS environment + // variable. Setting to 0 indicates that the default worker count + // should be used. + // + // Documented in cilk_api_<os>.h + if (cilkg_singleton_ptr) + return __CILKRTS_SET_PARAM_LATE; + + // Fetch the number of cores. There must be at last 1, since we're + // executing on *something*, aren't we!? + int hardware_cpu_count = __cilkrts_hardware_cpu_count(); + CILK_ASSERT(hardware_cpu_count > 0); + + int max_cpu_count = 16 * hardware_cpu_count; + if (__cilkrts_running_under_sequential_ptool()) + { + hardware_cpu_count = 1; + max_cpu_count = 1; + } + // Allow a value of 0, which means "set to hardware thread count". + int ret = store_int(&g->P, value, 0, max_cpu_count); + if (0 == g->P) + g->P = hardware_cpu_count; + return ret; + } + else if (strmatch(param, s_max_user_workers)) + { + // ** UNDOCUMENTED ** + // + // Sets the number of slots allocated for user worker threads + int hardware_cpu_count = __cilkrts_hardware_cpu_count(); + CILK_ASSERT (hardware_cpu_count > 0); + + return store_int(&g->max_user_workers, value, 1, + 16 * hardware_cpu_count); + } + else if (strmatch(param, s_local_stacks)) + { + // ** UNDOCUMENTED ** + // + // Number of stacks we'll hold in the per-worker stack cache. Maximum + // value is 42. See __cilkrts_make_global_state for details. + return store_int(&g->fiber_pool_size, value, 0, 42); + } + else if (strmatch(param, s_shared_stacks)) + { + // ** UNDOCUMENTED ** + // + // Maximum number of stacks we'll hold in the global stack + // cache. Maximum value is 42. See __cilkrts_make_global_state for + // details. + return store_int(&g->global_fiber_pool_size, value, 0, 42); + } + else if (strmatch(param, s_nstacks)) + { + // Sets the maximum number of stacks permitted at one time. If the + // runtime reaches this maximum, it will cease to allocate stacks and + // the app will lose parallelism. 0 means unlimited. Default is + // unlimited. Minimum is twice the number of worker threads, though + // that cannot be tested at this time. + // + // Undocumented at this time, though there are plans to expose it. + // The current implentation is for Linux debugging only and is not + // robust enough for users. + if (cilkg_singleton_ptr) + return __CILKRTS_SET_PARAM_LATE; + return store_int<unsigned>(&g->max_stacks, value, 0, INT_MAX); + } + else if (strmatch(param, s_stack_size)) + { + // ** UNDOCUMENTED ** + // + // Sets the size (in bytes) of the stacks that Cilk creates. + // Can only be set before the runtime starts. + if (cilkg_singleton_ptr) + return __CILKRTS_SET_PARAM_LATE; + + // Maximum value that can be parsed is MAX_INT (32-bit). + int ret = store_int<size_t>(&g->stack_size, value, 0, INT_MAX); + + // Process the value the user set (or 0 if the user didn't set + // anything) into something nice for the current OS. This + // processing is done immediately and stored into + // g->stack_size so that a call to get stack size will return + // the value that the runtime will actually use. + g->stack_size = cilkos_validate_stack_size(g->stack_size); + return ret; + } + + + // If got here, then didn't match any of the strings + return __CILKRTS_SET_PARAM_UNIMP; +} + +inline +int calc_max_user_workers(global_state_t *g) +{ + // If it's been set by the user, give back what we got + if (g->max_user_workers > 0) + return g->max_user_workers; + + // Calculate it + return std::max(3, g->P * 2); +} + +} // end unnamed namespace + +__CILKRTS_BEGIN_EXTERN_C + +/** + * @brief Returns the global state object. If called for the first time, + * initializes the user-settable values in the global state, but does not + * initialize the rest of the structure. + */ +global_state_t* cilkg_get_user_settable_values() +{ + // Environment variable value. More than big enough for a 64-bit signed + // integer. + char envstr[24]; + + // Abbreviating &global_state_singleton as g is not only shorter, it also + // facilitates grepping for the string "g->", which appears ubiquitously + // in the runtime code. + global_state_t* g = &global_state_singleton; + + // TBD: We need synchronization around this loop to prevent + // multiple threads from initializing this data. + if (! cilkg_user_settable_values_initialized) + { + size_t len; + + // Preserve stealing disabled since it may have been set by the + // debugger + int stealing_disabled = g->stealing_disabled; + + // All fields will be zero until set. In particular + std::memset(g, 0, sizeof(global_state_t)); + + // Fetch the number of cores. There must be at last 1, since we're + // executing on *something*, aren't we!? + int hardware_cpu_count = __cilkrts_hardware_cpu_count(); + CILK_ASSERT(hardware_cpu_count > 0); + + bool under_ptool = __cilkrts_running_under_sequential_ptool(); + if (under_ptool) + hardware_cpu_count = 1; + + g->stealing_disabled = stealing_disabled; + g->under_ptool = under_ptool; + g->force_reduce = 0; // Default Off + g->P = hardware_cpu_count; // Defaults to hardware CPU count + g->max_user_workers = 0; // 0 unless set by user + g->fiber_pool_size = 7; // Arbitrary default + + g->global_fiber_pool_size = 3 * 3* g->P; // Arbitrary default + // 3*P was the default size of the worker array (including + // space for extra user workers). This parameter was chosen + // to match previous versions of the runtime. + + if (4 == sizeof(void *)) + g->max_stacks = 1200; // Only 1GB on 32-bit machines + else + g->max_stacks = 2400; // 2GB on 64-bit machines + + // If we have 2400 1MB stacks, that is 2 gb. If we reach this + // limit on a single-socket machine, we may have other + // problems. Is 2400 too small for large multicore machines? + + // TBD(jsukha, 11/27/2012): I set this limit on stacks to be a + // value independent of P. When running on a Xeon Phi with + // small values of P, I recall seeing a few microbenchmarks + // (e.g., fib) where a limit of 10*P seemed to be + // unnecessarily slowing things down. + // + // That being said, the code has changed sufficiently that + // this observation may no longer be true. + // + // Note: in general, the worst-case number of stacks required + // for a Cilk computation with spawn depth "d" on P workers is + // O(Pd). Code with unbalanced recursion may run into issues + // with this stack usage. + + g->max_steal_failures = 128; // TBD: depend on max_workers? + g->stack_size = 0; // 0 unless set by the user + + // Assume no record or replay log for now + g->record_replay_file_name = NULL; + g->record_or_replay = RECORD_REPLAY_NONE; // set by user + + if (always_force_reduce()) + g->force_reduce = true; + else if (cilkos_getenv(envstr, sizeof(envstr), "CILK_FORCE_REDUCE")) + store_bool(&g->force_reduce, envstr); + + if (under_ptool) + g->P = 1; // Ignore environment variable if under cilkscreen + else if (cilkos_getenv(envstr, sizeof(envstr), "CILK_NWORKERS")) + // Set P to environment variable, but limit to no less than 1 + // and no more than 16 times the number of hardware threads. + store_int(&g->P, envstr, 1, 16 * hardware_cpu_count); + + if (cilkos_getenv(envstr, sizeof(envstr), "CILK_MAX_USER_WORKERS")) + // Set max_user_workers to environment variable, but limit to no + // less than 1 and no more 16 times the number of hardware + // threads. If not specified, defaults (somewhat arbitrarily) to + // the larger of 3 and twice the number of hardware threads. + store_int(&g->max_user_workers, envstr, 1, 16*hardware_cpu_count); + + if (cilkos_getenv(envstr, sizeof(envstr), "CILK_STEAL_FAILURES")) + // Set the number of times a worker should fail to steal before + // it looks to see whether it should suspend itself. + store_int<unsigned>(&g->max_steal_failures, envstr, 1, INT_MAX); + + // Compute the total number of workers to allocate. Subtract one from + // nworkers and user workers so that the first user worker isn't + // factored in twice. + // + // total_workers must be computed now to support __cilkrts_get_total_workers + g->total_workers = g->P + calc_max_user_workers(g) - 1; + +#ifdef CILK_RECORD_REPLAY + // RecordReplay: See if we've been asked to replay a log + len = cilkos_getenv(envstr, 0, "CILK_REPLAY_LOG"); + if (len > 0) + { + len += 1; // Allow for trailing NUL + g->record_or_replay = REPLAY_LOG; + g->record_replay_file_name = (char *)__cilkrts_malloc(len); + cilkos_getenv(g->record_replay_file_name, len, "CILK_REPLAY_LOG"); + } + + // RecordReplay: See if we've been asked to record a log + len = cilkos_getenv(envstr, 0, "CILK_RECORD_LOG"); + if (len > 0) + { + if (RECORD_REPLAY_NONE != g->record_or_replay) + cilkos_warning("CILK_RECORD_LOG ignored since CILK_REPLAY_LOG is defined.\n"); + else + { + len += 1; // Allow for trailing NUL + g->record_or_replay = RECORD_LOG; + g->record_replay_file_name = (char *)__cilkrts_malloc(len); + cilkos_getenv(g->record_replay_file_name, len, "CILK_RECORD_LOG"); + } + } +#endif + + cilkg_user_settable_values_initialized = true; + } + + return g; +} + +int cilkg_calc_total_workers() +{ + global_state_t* g = cilkg_get_user_settable_values(); + + // Compute the total number of workers to allocate. Subtract one from + // nworkers and user workers so that the first user worker isn't + // factored in twice. + return g->P + calc_max_user_workers(g) - 1; +} + +// Should be called while holding the global lock. +global_state_t* cilkg_init_global_state() +{ + if (cilkg_singleton_ptr) + return cilkg_singleton_ptr; + + // Get partially-initialized global state. + global_state_t* g = cilkg_get_user_settable_values(); + + if (g->max_stacks > 0) { + + // nstacks is currently honored on non-Windows systems only. + + // Set an upper bound on the number of stacks that are allocated. If + // nstacks is set, each worker gets up to one stack in its cache so that + // no one worker can hog all of the free stacks and keep work from being + // stolen by the other workers. + + // nstacks corresponds to the number of stacks that will be allocated by + // the runtime apart from the initial stack created for each thread by + // the system. Therefore, if a user asks for n stacks, and there are + // p workers created, the total number of stacks is actually n + p. + + // This feature is primarily for MIC which has flat memory + // instead of virtual addresses and tends to run out really quickly. + // It is not implemented for Windows and it's non-intuitive + // interaction with the local stack cache is specifically to help out + // MIC. + + // About max_stacks / P stacks, except we require at least 1 + // per pool. + if (((int)g->max_stacks / g->P) < g->fiber_pool_size) + g->fiber_pool_size = g->max_stacks / g->P; + + if (g->fiber_pool_size <= 0) { + g->fiber_pool_size = 1; + } + + if ((int)g->max_stacks < g->P) + g->max_stacks = g->P; + + g->global_fiber_pool_size = g->P * (g->fiber_pool_size+1); + } + + // Number of bytes/address - validation for debugger integration + g->addr_size = sizeof(void *); + + __cilkrts_init_stats(&g->stats); + + __cilkrts_frame_malloc_global_init(g); + + g->Q = 0; + g->total_workers = cilkg_calc_total_workers(); + g->system_workers = g->P - 1; // system_workers is here for the debugger. + g->work_done = 0; + g->workers_running = 0; + g->ltqsize = 1024; /* FIXME */ + + g->stack_size = cilkos_validate_stack_size(g->stack_size); + g->failure_to_allocate_stack = 0; + + + return g; +} + +void cilkg_publish_global_state(global_state_t* g) +{ + + // TBD: which one of these needs to be executed first? I say + // cilkg_singleton_ptr needs to be set last, with a mfence in + // between, since it is the flag that cilkg_is_published_is + // checking for. + __cilkrts_global_state = g; + __cilkrts_fence(); + cilkg_singleton_ptr = g; +} + +void cilkg_deinit_global_state() +{ + cilkg_singleton_ptr = NULL; + __cilkrts_global_state = NULL; +} + +int cilkg_is_published(void) +{ + return NULL != cilkg_singleton_ptr; +} + +int cilkg_set_param(const char* param, const char* value) +{ + return set_param_imp(cilkg_get_user_settable_values(), param, value); +} + +#ifdef _WIN32 +int cilkg_set_param_w(const wchar_t* param, const wchar_t* value) +{ + return set_param_imp(cilkg_get_user_settable_values(), param, value); +} +#endif + +extern "C++" { + // C++ scheduler function (that may throw exceptions) + typedef void cpp_scheduler_t(__cilkrts_worker *w); +} + +void __cilkrts_run_scheduler_with_exceptions(__cilkrts_worker *w) +{ + global_state_t* g = cilkg_get_global_state(); + CILK_ASSERT(g->scheduler); + + cpp_scheduler_t* scheduler = (cpp_scheduler_t*) g->scheduler; + + try { + scheduler(w); + } catch (...) { + __cilkrts_bug("Exception escaped Cilk context"); + } +} + +__CILKRTS_END_EXTERN_C + +/* End global_state.cpp */ diff --git a/libcilkrts/runtime/global_state.h b/libcilkrts/runtime/global_state.h new file mode 100644 index 00000000000..ef455e479d5 --- /dev/null +++ b/libcilkrts/runtime/global_state.h @@ -0,0 +1,417 @@ +/* global_state.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** + * @file global_state.h + * + * @brief The global_state_t structure contains most of the global context + * maintained by the Intel Cilk runtime. + */ + +#ifndef INCLUDED_GLOBAL_STATE_DOT_H +#define INCLUDED_GLOBAL_STATE_DOT_H + +#include <cilk/common.h> + +#include "frame_malloc.h" +#include "stats.h" +#include "bug.h" +#include "cilk_fiber.h" + +__CILKRTS_BEGIN_EXTERN_C + +/** + * Non-null place-holder for a stack handle that has no meaningful value. + */ +#define PLACEHOLDER_FIBER ((cilk_fiber *) -2) + +/** + * States for record_or_replay + */ +enum record_replay_t { + RECORD_REPLAY_NONE, + RECORD_LOG, + REPLAY_LOG +}; + +/** + * @brief The global state is a structure that is shared by all workers in + * Cilk. + * + * Make the structure ready for use by calling + * cilkg_init_global_state() and then cilkg_publish_global_state(). + * + * The same global lock should be held while both of these methods are + * called. These methods are split because it is useful to execute + * other runtime initialization code in between. + * + * After cilkg_publish_global_state() has completed, Cilk runtime + * methods may call cilkg_get_global_state() to look at the published + * value without holding the global lock. + * + * Finally, clean up the global state by calling + * cilkg_deinit_global_state(). This method should be called only + * after all calls to cilkg_get_global_state() have completed, and + * while holding the global lock. + * + * Before initialization and after deinitialization, the fields in the + * global state have unspecified values, except for a few special + * fields labeled "USER SETTING", which can be read and written before + * initialization and after deinitialization. + */ + +struct global_state_t { /* COMMON_PORTABLE */ + + /* Fields described as "(fixed)" should not be changed after + * initialization. + */ + + /************************************************************************* + * Note that debugger integration must reach into the + * global state! The debugger integration is depending on the + * offsets of the addr_size, system_workers, total_workers, + * stealing_disabled, sysdep, and workers. If these offsets change, the + * debugger integration library will need to be changed to match!!! + *************************************************************************/ + + int addr_size; ///< Number of bytes for an address, used by debugger (fixed) + + int system_workers; ///< Number of system workers (fixed) + + /** + * @brief USER SETTING: Maximum number of user workers that can be + * bound to cilk workers. + * + * 0 unless set by user. Call cilkg_calc_max_user_workers to get + * the value. + */ + int max_user_workers; + + int total_workers; ///< Total number of worker threads allocated (fixed) + + int workers_running; ///< True when system workers have beens started */ + + /// Set by debugger to disable stealing (fixed) + int stealing_disabled; + + /// System-dependent part of the global state + struct global_sysdep_state *sysdep; + + /// Array of worker structures. + __cilkrts_worker **workers; + + /******* END OF DEBUGGER-INTEGRATION FIELDS ***************/ + + /// Number of frames in each worker's lazy task queue + __STDNS size_t ltqsize; + + /** + * @brief USER SETTING: Force all possible reductions. + * + * TRUE if running a p-tool that requires reducers to call the reduce() + * method even if no actual stealing occurs. + * + * When set to TRUE, runtime will simulate steals, forcing calls to the + * the reduce() methods of reducers. + * + */ + int force_reduce; + + /// USER SETTING: Per-worker fiber pool size + int fiber_pool_size; + + /// USER SETTING: Global fiber pool size + int global_fiber_pool_size; + + /** + * @brief TRUE when workers should exit scheduling loop so we can + * shut down the runtime and free the global state. + * + * @note @c work_done will be checked *FREQUENTLY* in the scheduling loop + * by idle workers. We need to ensure that it's not in a cache line which + * may be invalidated by other cores. The surrounding fields are either + * constant after initialization or not used until shutdown (stats) so we + * should be OK. + */ + volatile int work_done; + + int under_ptool; ///< True when running under a serial PIN tool + + statistics stats; ///< Statistics on use of runtime + + /** + * @brief USER SETTING: Maximum number of stacks the runtime will + * allocate (apart from those created by the OS when worker + * threads are created). + * + * If max_stacks == 0,there is no pre-defined maximum. + */ + unsigned max_stacks; + + /// Size of each stack + size_t stack_size; + + /// Global cache for per-worker memory + struct __cilkrts_frame_cache frame_malloc; + + /// Global fiber pool + cilk_fiber_pool fiber_pool; + + + /** + * @brief Track whether the runtime has failed to allocate a + * stack. + * + * Setting this flag prevents multiple warnings from being + * issued. + */ + int failure_to_allocate_stack; + + /** + * @brief USER SETTING: indicate record or replay log. + * Set to NULL if not used in this run. + */ + char *record_replay_file_name; + + /** + * @brief Record/replay state. + * Valid states are: + * RECORD_REPLAY_NONE - Not recording or replaying a log + * RECORD_LOG - Recording a log for replay later + * REPLAY_LOG - Replay a log recorded earlier + */ + enum record_replay_t record_or_replay; + + /** + * @brief Buffer to force max_steal_failures to appear on a + * different cache line from the previous member variables. + * + * This padding is needed because max_steal_failures is read + * constantly and other modified values in the global state will + * cause thrashing. + */ + char cache_buf[64]; + + /** + * @brief Maximum number of times a thread should fail to steal + * before checking if Cilk is shutting down. + */ + unsigned int max_steal_failures; + + /// Pointer to scheduler entry point + void (*scheduler)(__cilkrts_worker *w); + + /** + * @brief Buffer to force P and Q to appear on a different cache + * line from the previous member variables. + */ + char cache_buf_2[64]; + + int P; ///< USER SETTING: number of system workers + 1 (fixed) + int Q; ///< Number of user threads currently bound to workers +}; + +/** + * @brief Initialize the global state object. This method must both + * complete before referencing any fields in the global state, except + * those specified as "user-settable values". + */ +global_state_t* cilkg_init_global_state(); + +/** + * @brief Publish the global state object, so that + * cilkg_is_published can return true. + * + * @param g - the global state created by cilkg_init_global_state() to + * publish. + * + * After the global state object has been published, a thread should + * not modify this state unless it has exclusive access (i.e., holds + * the global lock). + */ +void cilkg_publish_global_state(global_state_t* g); + +/** + * @brief Return true if the global state has been fully initialized + * and published, and has not been deinitialized. + */ +int cilkg_is_published(void); + +/** + * @brief De-initializes the global state object. Must be called to free + * resources when the global state is no longer needed. + */ +void cilkg_deinit_global_state(void); + +/** + * @brief Returns the global state object. Result is valid only if the + * global state has been published (see cilkg_publish_global_state()). + */ +static inline +global_state_t* cilkg_get_global_state(void) +{ + // "private" extern declaration: + extern global_state_t *cilkg_singleton_ptr; + + __CILKRTS_ASSERT(cilkg_singleton_ptr); // Debug only + return cilkg_singleton_ptr; +} + + +/** + * @brief Implementation of __cilkrts_set_params. + * + * Set user controllable parameters + * @param param - string specifying parameter to be set + * @param value - string specifying new value + * @returns One of: CILKG_SET_PARAM_SUCCESS ( = 0), + * CILKG_SET_PARAM_UNIMP, CILKG_SET_PARAM_XRANGE, + * CILKG_SET_PARAM_INVALID, or CILKG_SET_PARAM_LATE. + * + * @attention The wide character version __cilkrts_set_param_w() is available + * only on Windows. + * + * Allowable parameter names: + * + * - "nworkers" - number of processors that should run Cilk code. + * The value is a string of digits to be parsed by strtol. + * + * - "force reduce" - test reducer callbacks by allocating new views + * for every spawn within which a reducer is accessed. This can + * significantly reduce performance. The value is "1" or "true" + * to enable, "0" or "false" to disable. + * @warning Enabling "force reduce" when running with more than a single + * worker is currently broken. + * + * - "max user workers" - (Not publicly documented) Sets the number of slots + * allocated for user worker threads + * + * - "local stacks" - (Not publicly documented) Number of stacks we'll hold in + * the per-worker stack cache. Range 1 .. 42. See + * cilkg_init_global_state for details. + * + * - "shared stacks" - (Not publicly documented) Maximum number of stacks + * we'll hold in the global stack cache. Maximum value is 42. See + * __cilkrts_make_global_state for details + * + * - "nstacks" - (Not publicly documented at this time, though it may be + * exposed in the future) Sets the maximum number of stacks permitted at one + * time. If the runtime reaches this maximum, it will cease to allocate + * stacks and the app will lose parallelism. 0 means unlimited. Default is + * unlimited. Minimum is twice the number of worker threads, though that + * cannot be tested at this time. + */ +int cilkg_set_param(const char* param, const char* value); +#ifdef _WIN32 +/** + * @brief Implementation of __cilkrts_set_params for Unicode characters on + * Windows. See the documentation on @ref cilkg_set_param for more details. + * + * Set user controllable parameters + * @param param - string specifying parameter to be set + * @param value - string specifying new value + * @returns One of: CILKG_SET_PARAM_SUCCESS ( = 0), + * CILKG_SET_PARAM_UNIMP, CILKG_SET_PARAM_XRANGE, + * CILKG_SET_PARAM_INVALID, or CILKG_SET_PARAM_LATE. + */ +int cilkg_set_param_w(const wchar_t* param, const wchar_t* value); +#endif + +/** + * @brief implementation of __cilkrts_get_nworkers() + */ +static inline +int cilkg_get_nworkers(void) +{ + // "private" extern declaration + extern global_state_t* cilkg_get_user_settable_values(void); + return cilkg_get_user_settable_values()->P; +} + +/** + * @brief implementation of __cilkrts_get_total_workers() + */ +static inline +int cilkg_get_total_workers(void) +{ + // "private" extern declaration + extern int cilkg_calc_total_workers(void); + + // This number can fluctate until initialization so we + // compute it from scratch + return cilkg_calc_total_workers(); +} + +/** + * @brief implementation of __cilkrts_get_force_reduce() + */ +static inline +int cilkg_get_force_reduce(void) +{ + // "private" extern declaration + extern global_state_t* cilkg_get_user_settable_values(void); + return cilkg_get_user_settable_values()->force_reduce; +} + +/** + * @brief implementation of __cilkrts_get_stack_size() + */ +static inline +size_t cilkg_get_stack_size(void) +{ + // "private" extern declaration + extern global_state_t* cilkg_get_user_settable_values(void); + return cilkg_get_user_settable_values()->stack_size; +} + +/** + * @brief Run the scheduler function stored in the global_state + * + * Look up the scheduler function in global_state and run it. Report a fatal + * error if an exception escapes the scheduler function. + * + * @param w - Worker structure to associate with the current thread. + * + * @attention The scheduler field of the global state must be set before this + * function is called. + */ +void __cilkrts_run_scheduler_with_exceptions(__cilkrts_worker *w); + +__CILKRTS_END_EXTERN_C + +#endif // ! defined(INCLUDED_GLOBAL_STATE_DOT_H) diff --git a/libcilkrts/runtime/jmpbuf.c b/libcilkrts/runtime/jmpbuf.c new file mode 100644 index 00000000000..39b51a593ce --- /dev/null +++ b/libcilkrts/runtime/jmpbuf.c @@ -0,0 +1,48 @@ +/* jmpbuf.c -*-C-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +#include "jmpbuf.h" + +/* + * C99 requires that every inline function with external linkage have + * one extern declaration in the program. + */ +extern char *__cilkrts_get_sp(__cilkrts_stack_frame *sf); +extern ptrdiff_t __cilkrts_get_frame_size(__cilkrts_stack_frame *sf); + +/* End jmpbuf.c */ diff --git a/libcilkrts/runtime/jmpbuf.h b/libcilkrts/runtime/jmpbuf.h new file mode 100644 index 00000000000..60573f3a5fa --- /dev/null +++ b/libcilkrts/runtime/jmpbuf.h @@ -0,0 +1,136 @@ +/* jmpbuf.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** + * @file jmpbuf.h + * + * @brief Macros and functions to access the _JUMP_BUFFER initialized by a + * call to CILK_SETJMP before a cilk_spawn or cilk_sync. The definition of + * CILK_SETJMP and CILK_LONGJMP are OS dependent and in abi.h + * + */ + +#ifndef INCLUDED_JMPBUF_DOT_H +#define INCLUDED_JMPBUF_DOT_H + +#include <cilk/common.h> +#include <internal/abi.h> +#include <stddef.h> +#include <setjmp.h> + +#if 0 /* defined CILK_USE_C_SETJMP && defined JB_RSP */ +# define JMPBUF_SP(ctx) (ctx)[0].__jmpbuf[JB_RSP] +# define JMPBUF_FP(ctx) (ctx)[0].__jmpbuf[JB_RBP] +# define JMPBUF_PC(ctx) (ctx)[0].__jmpbuf[JB_PC] +#elif 0 /* defined CILK_USE_C_SETJMP && defined JB_SP */ +# define JMPBUF_SP(ctx) (ctx)[0].__jmpbuf[JB_SP] +# define JMPBUF_FP(ctx) (ctx)[0].__jmpbuf[JB_BP] +# define JMPBUF_PC(ctx) (ctx)[0].__jmpbuf[JB_PC] +#elif defined _WIN64 +# define JMPBUF_SP(ctx) ((_JUMP_BUFFER*)(&(ctx)))->Rsp +# define JMPBUF_FP(ctx) ((_JUMP_BUFFER*)(&(ctx)))->Rbp +# define JMPBUF_PC(ctx) ((_JUMP_BUFFER*)(&(ctx)))->Rip +#elif defined _WIN32 + /** Fetch stack pointer from a __cilkrts_stack_frame */ +# define JMPBUF_SP(ctx) (ctx).Esp + /** Fetch frame pointer from a __cilkrts_stack_frame */ +# define JMPBUF_FP(ctx) (ctx).Ebp + /** Fetch program counter from a __cilkrts_stack_frame */ +# define JMPBUF_PC(ctx) (ctx).Eip +#else /* defined __GNUC__ || defined __ICC */ + /* word 0 is frame address + * word 1 is resume address + * word 2 is stack address */ +# define JMPBUF_FP(ctx) (ctx)[0] +# define JMPBUF_PC(ctx) (ctx)[1] +# define JMPBUF_SP(ctx) (ctx)[2] +#endif + +/** + * @brief Get frame pointer from jump buffer in__cilkrts_stack_frame. + */ +#define FP(SF) JMPBUF_FP((SF)->ctx) + +/** + * @brief Get program counter from jump buffer in__cilkrts_stack_frame. + */ +#define PC(SF) JMPBUF_PC((SF)->ctx) + +/** + * @brief Get stack pointer from jump buffer in__cilkrts_stack_frame. + */ +#define SP(SF) JMPBUF_SP((SF)->ctx) + + +__CILKRTS_BEGIN_EXTERN_C + +/** + * Fetch the stack pointer from a __cilkrts_stack_frame. The jmpbuf was + * initialized before a cilk_spawn or cilk_sync. + * + * @param sf __cilkrts_stack_frame containing the jmpbuf. + * + * @return the stack pointer from the ctx. + */ +inline char *__cilkrts_get_sp(__cilkrts_stack_frame *sf) +{ + return (char *)SP(sf); +} + +/** + * Calculate the frame size from __cilkrts_stack_frame. The jmpbuf was + * initialized before a cilk_spawn or cilk_sync. + * + * @warning Returning an arbitrary value on Windows! + * + * @param sf __cilkrts_stack_frame containing the jmpbuf. + * + * @return the stack pointer from the ctx. + */ +inline ptrdiff_t __cilkrts_get_frame_size(__cilkrts_stack_frame *sf) +{ +#ifdef _WIN32 + if (0 == SP(sf)) + return 256; // Arbitrary! +#endif + return (ptrdiff_t)FP(sf) - (ptrdiff_t)SP(sf); +} + +__CILKRTS_END_EXTERN_C + +#endif // ! defined(INCLUDED_JMPBUF_DOT_H) diff --git a/libcilkrts/runtime/linux-symbols.ver b/libcilkrts/runtime/linux-symbols.ver new file mode 100644 index 00000000000..aeb4a5fb13d --- /dev/null +++ b/libcilkrts/runtime/linux-symbols.ver @@ -0,0 +1,369 @@ +/* + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +CILKABI0 +{ + global: + __cilkrts_bind_thread; + __cilkrts_cilk_for_32; + __cilkrts_cilk_for_64; + __cilkrts_debugger_notification; + __cilkrts_dump_stats; + __cilkrts_end_cilk; + __cilkrts_enter_frame; + __cilkrts_enter_frame_fast; + __cilkrts_get_force_reduce; + __cilkrts_get_nworkers; + __cilkrts_get_tls_worker; + __cilkrts_get_tls_worker_fast; + __cilkrts_get_total_workers; + __cilkrts_get_worker_number; + __cilkrts_global_state; + __cilkrts_hyper_create; + __cilkrts_hyper_destroy; + __cilkrts_hyper_lookup; + __cilkrts_hyperobject_alloc; + __cilkrts_hyperobject_dealloc; + __cilkrts_hyperobject_noop_destroy; + __cilkrts_init; + __cilkrts_irml_version; + __cilkrts_leave_frame; + __cilkrts_metacall; + __cilkrts_rethrow; + __cilkrts_return_exception; + __cilkrts_set_param; + __cilkrts_sync; + __cilkrts_synched; + __cilkrts_worker_stub; + local: *; +}; + +CILKABI1 +{ + global: + __cilkrts_bind_thread_1; + __cilkrts_bump_loop_rank; + __cilkrts_bump_loop_rank_internal; + __cilkrts_bump_worker_rank; + __cilkrts_bump_worker_rank_internal; + __cilkrts_enter_frame_1; + __cilkrts_enter_frame_fast_1; + __cilkrts_get_pedigree_info; + __cilkrts_get_pedigree_internal; + __cilkrts_get_sf; + __cilkrts_get_stack_size; + __cilkrts_get_worker_rank; + __cilkrts_save_fp_ctrl_state; + __cilkrts_stack_alloc; + __cilkrts_stack_free; + __cilkrts_watch_stack; +} CILKABI0; + +CILKLIB1.02 +{ + global: + cilk_c_reducer_max_identity_char; + cilk_c_reducer_max_identity_double; + cilk_c_reducer_max_identity_float; + cilk_c_reducer_max_identity_int; + cilk_c_reducer_max_identity_long; + cilk_c_reducer_max_identity_longdouble; + cilk_c_reducer_max_identity_longlong; + cilk_c_reducer_max_identity_schar; + cilk_c_reducer_max_identity_short; + cilk_c_reducer_max_identity_uchar; + cilk_c_reducer_max_identity_uint; + cilk_c_reducer_max_identity_ulong; + cilk_c_reducer_max_identity_ulonglong; + cilk_c_reducer_max_identity_unsigned; + cilk_c_reducer_max_identity_ushort; + cilk_c_reducer_max_identity_wchar_t; + cilk_c_reducer_max_index_identity_char; + cilk_c_reducer_max_index_identity_double; + cilk_c_reducer_max_index_identity_float; + cilk_c_reducer_max_index_identity_int; + cilk_c_reducer_max_index_identity_long; + cilk_c_reducer_max_index_identity_longdouble; + cilk_c_reducer_max_index_identity_longlong; + cilk_c_reducer_max_index_identity_schar; + cilk_c_reducer_max_index_identity_short; + cilk_c_reducer_max_index_identity_uchar; + cilk_c_reducer_max_index_identity_uint; + cilk_c_reducer_max_index_identity_ulong; + cilk_c_reducer_max_index_identity_ulonglong; + cilk_c_reducer_max_index_identity_unsigned; + cilk_c_reducer_max_index_identity_ushort; + cilk_c_reducer_max_index_identity_wchar_t; + cilk_c_reducer_max_index_reduce_char; + cilk_c_reducer_max_index_reduce_double; + cilk_c_reducer_max_index_reduce_float; + cilk_c_reducer_max_index_reduce_int; + cilk_c_reducer_max_index_reduce_long; + cilk_c_reducer_max_index_reduce_longdouble; + cilk_c_reducer_max_index_reduce_longlong; + cilk_c_reducer_max_index_reduce_schar; + cilk_c_reducer_max_index_reduce_short; + cilk_c_reducer_max_index_reduce_uchar; + cilk_c_reducer_max_index_reduce_uint; + cilk_c_reducer_max_index_reduce_ulong; + cilk_c_reducer_max_index_reduce_ulonglong; + cilk_c_reducer_max_index_reduce_unsigned; + cilk_c_reducer_max_index_reduce_ushort; + cilk_c_reducer_max_index_reduce_wchar_t; + cilk_c_reducer_max_reduce_char; + cilk_c_reducer_max_reduce_double; + cilk_c_reducer_max_reduce_float; + cilk_c_reducer_max_reduce_int; + cilk_c_reducer_max_reduce_long; + cilk_c_reducer_max_reduce_longdouble; + cilk_c_reducer_max_reduce_longlong; + cilk_c_reducer_max_reduce_schar; + cilk_c_reducer_max_reduce_short; + cilk_c_reducer_max_reduce_uchar; + cilk_c_reducer_max_reduce_uint; + cilk_c_reducer_max_reduce_ulong; + cilk_c_reducer_max_reduce_ulonglong; + cilk_c_reducer_max_reduce_unsigned; + cilk_c_reducer_max_reduce_ushort; + cilk_c_reducer_max_reduce_wchar_t; + cilk_c_reducer_min_identity_char; + cilk_c_reducer_min_identity_double; + cilk_c_reducer_min_identity_float; + cilk_c_reducer_min_identity_int; + cilk_c_reducer_min_identity_long; + cilk_c_reducer_min_identity_longdouble; + cilk_c_reducer_min_identity_longlong; + cilk_c_reducer_min_identity_schar; + cilk_c_reducer_min_identity_short; + cilk_c_reducer_min_identity_uchar; + cilk_c_reducer_min_identity_uint; + cilk_c_reducer_min_identity_ulong; + cilk_c_reducer_min_identity_ulonglong; + cilk_c_reducer_min_identity_unsigned; + cilk_c_reducer_min_identity_ushort; + cilk_c_reducer_min_identity_wchar_t; + cilk_c_reducer_min_index_identity_char; + cilk_c_reducer_min_index_identity_double; + cilk_c_reducer_min_index_identity_float; + cilk_c_reducer_min_index_identity_int; + cilk_c_reducer_min_index_identity_long; + cilk_c_reducer_min_index_identity_longdouble; + cilk_c_reducer_min_index_identity_longlong; + cilk_c_reducer_min_index_identity_schar; + cilk_c_reducer_min_index_identity_short; + cilk_c_reducer_min_index_identity_uchar; + cilk_c_reducer_min_index_identity_uint; + cilk_c_reducer_min_index_identity_ulong; + cilk_c_reducer_min_index_identity_ulonglong; + cilk_c_reducer_min_index_identity_unsigned; + cilk_c_reducer_min_index_identity_ushort; + cilk_c_reducer_min_index_identity_wchar_t; + cilk_c_reducer_min_index_reduce_char; + cilk_c_reducer_min_index_reduce_double; + cilk_c_reducer_min_index_reduce_float; + cilk_c_reducer_min_index_reduce_int; + cilk_c_reducer_min_index_reduce_long; + cilk_c_reducer_min_index_reduce_longdouble; + cilk_c_reducer_min_index_reduce_longlong; + cilk_c_reducer_min_index_reduce_schar; + cilk_c_reducer_min_index_reduce_short; + cilk_c_reducer_min_index_reduce_uchar; + cilk_c_reducer_min_index_reduce_uint; + cilk_c_reducer_min_index_reduce_ulong; + cilk_c_reducer_min_index_reduce_ulonglong; + cilk_c_reducer_min_index_reduce_unsigned; + cilk_c_reducer_min_index_reduce_ushort; + cilk_c_reducer_min_index_reduce_wchar_t; + cilk_c_reducer_min_reduce_char; + cilk_c_reducer_min_reduce_double; + cilk_c_reducer_min_reduce_float; + cilk_c_reducer_min_reduce_int; + cilk_c_reducer_min_reduce_long; + cilk_c_reducer_min_reduce_longdouble; + cilk_c_reducer_min_reduce_longlong; + cilk_c_reducer_min_reduce_schar; + cilk_c_reducer_min_reduce_short; + cilk_c_reducer_min_reduce_uchar; + cilk_c_reducer_min_reduce_uint; + cilk_c_reducer_min_reduce_ulong; + cilk_c_reducer_min_reduce_ulonglong; + cilk_c_reducer_min_reduce_unsigned; + cilk_c_reducer_min_reduce_ushort; + cilk_c_reducer_min_reduce_wchar_t; + cilk_c_reducer_opadd_identity_char; + cilk_c_reducer_opadd_identity_double; + cilk_c_reducer_opadd_identity_float; + cilk_c_reducer_opadd_identity_int; + cilk_c_reducer_opadd_identity_long; + cilk_c_reducer_opadd_identity_longdouble; + cilk_c_reducer_opadd_identity_longlong; + cilk_c_reducer_opadd_identity_schar; + cilk_c_reducer_opadd_identity_short; + cilk_c_reducer_opadd_identity_uchar; + cilk_c_reducer_opadd_identity_uint; + cilk_c_reducer_opadd_identity_ulong; + cilk_c_reducer_opadd_identity_ulonglong; + cilk_c_reducer_opadd_identity_unsigned; + cilk_c_reducer_opadd_identity_ushort; + cilk_c_reducer_opadd_identity_wchar_t; + cilk_c_reducer_opadd_reduce_char; + cilk_c_reducer_opadd_reduce_double; + cilk_c_reducer_opadd_reduce_float; + cilk_c_reducer_opadd_reduce_int; + cilk_c_reducer_opadd_reduce_long; + cilk_c_reducer_opadd_reduce_longdouble; + cilk_c_reducer_opadd_reduce_longlong; + cilk_c_reducer_opadd_reduce_schar; + cilk_c_reducer_opadd_reduce_short; + cilk_c_reducer_opadd_reduce_uchar; + cilk_c_reducer_opadd_reduce_uint; + cilk_c_reducer_opadd_reduce_ulong; + cilk_c_reducer_opadd_reduce_ulonglong; + cilk_c_reducer_opadd_reduce_unsigned; + cilk_c_reducer_opadd_reduce_ushort; + cilk_c_reducer_opadd_reduce_wchar_t; + cilk_c_reducer_opand_identity_char; + cilk_c_reducer_opand_identity_int; + cilk_c_reducer_opand_identity_long; + cilk_c_reducer_opand_identity_longlong; + cilk_c_reducer_opand_identity_schar; + cilk_c_reducer_opand_identity_short; + cilk_c_reducer_opand_identity_uchar; + cilk_c_reducer_opand_identity_uint; + cilk_c_reducer_opand_identity_ulong; + cilk_c_reducer_opand_identity_ulonglong; + cilk_c_reducer_opand_identity_unsigned; + cilk_c_reducer_opand_identity_ushort; + cilk_c_reducer_opand_identity_wchar_t; + cilk_c_reducer_opand_reduce_char; + cilk_c_reducer_opand_reduce_int; + cilk_c_reducer_opand_reduce_long; + cilk_c_reducer_opand_reduce_longlong; + cilk_c_reducer_opand_reduce_schar; + cilk_c_reducer_opand_reduce_short; + cilk_c_reducer_opand_reduce_uchar; + cilk_c_reducer_opand_reduce_uint; + cilk_c_reducer_opand_reduce_ulong; + cilk_c_reducer_opand_reduce_ulonglong; + cilk_c_reducer_opand_reduce_unsigned; + cilk_c_reducer_opand_reduce_ushort; + cilk_c_reducer_opand_reduce_wchar_t; + cilk_c_reducer_opmul_identity_char; + cilk_c_reducer_opmul_identity_double; + cilk_c_reducer_opmul_identity_float; + cilk_c_reducer_opmul_identity_int; + cilk_c_reducer_opmul_identity_long; + cilk_c_reducer_opmul_identity_longdouble; + cilk_c_reducer_opmul_identity_longlong; + cilk_c_reducer_opmul_identity_schar; + cilk_c_reducer_opmul_identity_short; + cilk_c_reducer_opmul_identity_uchar; + cilk_c_reducer_opmul_identity_uint; + cilk_c_reducer_opmul_identity_ulong; + cilk_c_reducer_opmul_identity_ulonglong; + cilk_c_reducer_opmul_identity_unsigned; + cilk_c_reducer_opmul_identity_ushort; + cilk_c_reducer_opmul_identity_wchar_t; + cilk_c_reducer_opmul_reduce_char; + cilk_c_reducer_opmul_reduce_double; + cilk_c_reducer_opmul_reduce_float; + cilk_c_reducer_opmul_reduce_int; + cilk_c_reducer_opmul_reduce_long; + cilk_c_reducer_opmul_reduce_longdouble; + cilk_c_reducer_opmul_reduce_longlong; + cilk_c_reducer_opmul_reduce_schar; + cilk_c_reducer_opmul_reduce_short; + cilk_c_reducer_opmul_reduce_uchar; + cilk_c_reducer_opmul_reduce_uint; + cilk_c_reducer_opmul_reduce_ulong; + cilk_c_reducer_opmul_reduce_ulonglong; + cilk_c_reducer_opmul_reduce_unsigned; + cilk_c_reducer_opmul_reduce_ushort; + cilk_c_reducer_opmul_reduce_wchar_t; + cilk_c_reducer_opor_identity_char; + cilk_c_reducer_opor_identity_int; + cilk_c_reducer_opor_identity_long; + cilk_c_reducer_opor_identity_longlong; + cilk_c_reducer_opor_identity_schar; + cilk_c_reducer_opor_identity_short; + cilk_c_reducer_opor_identity_uchar; + cilk_c_reducer_opor_identity_uint; + cilk_c_reducer_opor_identity_ulong; + cilk_c_reducer_opor_identity_ulonglong; + cilk_c_reducer_opor_identity_unsigned; + cilk_c_reducer_opor_identity_ushort; + cilk_c_reducer_opor_identity_wchar_t; + cilk_c_reducer_opor_reduce_char; + cilk_c_reducer_opor_reduce_int; + cilk_c_reducer_opor_reduce_long; + cilk_c_reducer_opor_reduce_longlong; + cilk_c_reducer_opor_reduce_schar; + cilk_c_reducer_opor_reduce_short; + cilk_c_reducer_opor_reduce_uchar; + cilk_c_reducer_opor_reduce_uint; + cilk_c_reducer_opor_reduce_ulong; + cilk_c_reducer_opor_reduce_ulonglong; + cilk_c_reducer_opor_reduce_unsigned; + cilk_c_reducer_opor_reduce_ushort; + cilk_c_reducer_opor_reduce_wchar_t; + cilk_c_reducer_opxor_identity_char; + cilk_c_reducer_opxor_identity_int; + cilk_c_reducer_opxor_identity_long; + cilk_c_reducer_opxor_identity_longlong; + cilk_c_reducer_opxor_identity_schar; + cilk_c_reducer_opxor_identity_short; + cilk_c_reducer_opxor_identity_uchar; + cilk_c_reducer_opxor_identity_uint; + cilk_c_reducer_opxor_identity_ulong; + cilk_c_reducer_opxor_identity_ulonglong; + cilk_c_reducer_opxor_identity_unsigned; + cilk_c_reducer_opxor_identity_ushort; + cilk_c_reducer_opxor_identity_wchar_t; + cilk_c_reducer_opxor_reduce_char; + cilk_c_reducer_opxor_reduce_int; + cilk_c_reducer_opxor_reduce_long; + cilk_c_reducer_opxor_reduce_longlong; + cilk_c_reducer_opxor_reduce_schar; + cilk_c_reducer_opxor_reduce_short; + cilk_c_reducer_opxor_reduce_uchar; + cilk_c_reducer_opxor_reduce_uint; + cilk_c_reducer_opxor_reduce_ulong; + cilk_c_reducer_opxor_reduce_ulonglong; + cilk_c_reducer_opxor_reduce_unsigned; + cilk_c_reducer_opxor_reduce_ushort; + cilk_c_reducer_opxor_reduce_wchar_t; +}; diff --git a/libcilkrts/runtime/local_state.c b/libcilkrts/runtime/local_state.c new file mode 100644 index 00000000000..14ac8271936 --- /dev/null +++ b/libcilkrts/runtime/local_state.c @@ -0,0 +1,68 @@ +/* local_state.c -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2010-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + +#include "local_state.h" +#include "bug.h" +#include "full_frame.h" + +void run_scheduling_stack_fcn(__cilkrts_worker *w) +{ + scheduling_stack_fcn_t fcn = w->l->post_suspend; + full_frame *ff2 = w->l->frame_ff; + __cilkrts_stack_frame *sf2 = w->l->suspended_stack; + + w->l->post_suspend = 0; + w->l->suspended_stack = 0; + + // Conceptually, after clearing w->l->frame_ff, + // w no longer owns the full frame ff. + // The next time another (possibly different) worker takes + // ownership of ff will be at a provably_good_steal on ff. + w->l->frame_ff = NULL; + + CILK_ASSERT(fcn); + CILK_ASSERT(ff2); + fcn(w, ff2, sf2); + + // After we run the scheduling stack function, we shouldn't + // (still) not have a full frame. + CILK_ASSERT(NULL == w->l->frame_ff); +} + +/* End local_state.c */ diff --git a/libcilkrts/runtime/local_state.h b/libcilkrts/runtime/local_state.h new file mode 100644 index 00000000000..03f39897f51 --- /dev/null +++ b/libcilkrts/runtime/local_state.h @@ -0,0 +1,424 @@ +/* local_state.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** + * @file local_state.h + * + * @brief The local_state structure contains additional OS-independent + * information that's associated with a worker, but doesn't need to be visible + * to the code generated by the compiler. + */ + +#ifndef INCLUDED_LOCAL_STATE_DOT_H +#define INCLUDED_LOCAL_STATE_DOT_H + +#include <internal/abi.h> +#include "worker_mutex.h" +#include "global_state.h" +#include "record-replay.h" +#include "signal_node.h" + +#include <setjmp.h> +#include <stddef.h> +#include <stdio.h> + + +#ifndef _WIN32 +# include <pthread.h> +#endif + +__CILKRTS_BEGIN_EXTERN_C + +/* Opaque types. */ + +struct full_frame; +struct free_list; +struct pending_exception_info; +/// Opaque type for replay entry. +typedef struct replay_entry_t replay_entry_t; + +/** + * @brief Magic numbers for local_state, used for debugging + */ +typedef unsigned long long ls_magic_t; + +/** + * @brief Scheduling stack function: A function that is decided on the program stack, + * but that must be executed on the scheduling stack. + */ +typedef void (*scheduling_stack_fcn_t) (__cilkrts_worker *w, + struct full_frame *ff, + __cilkrts_stack_frame *sf); + +/** + * @brief Type of this worker. + **/ +typedef enum cilk_worker_type +{ + WORKER_FREE, ///< Unused worker - available to be bound to user threads + WORKER_SYSTEM, ///< Worker created by runtime - able to steal from any worker + WORKER_USER ///< User thread - able to steal only from team members +} cilk_worker_type; + + +/** + * @brief The local_state structure contains additional OS-independent + * information that's associated with a worker, but doesn't need to be + * visible to the compiler. + * + * No compiler-generated code should need to know the layout of this + * structure. + * + * The fields of this struct can be classified as either local or + * shared. + * + * Local: This field is only accessed by the thread bound to this + * worker struct. Local fields can be freely accessed without + * acquiring locks. + * + * Shared: This field may be accessed by multiple worker threads. + * Accesses to shared fields usually requires locks, except in + * special situations where one can prove that locks are + * unnecessary. + * + * The fields of this can also be classified as "read-only" if the + * field does not change after it is initialized. Otherwise, the + * field is "read/write". Read-only fields do not require locks to + * access (ignoring the synchronization that might be needed for + * initialization if this can occur in parallel). + * + * Finally, we explicitly classify some fields as "synchronization" + * fields if they are used as part of a synchronization protocol in + * the runtime. These variables are generally shared and read/write. + * Mostly, this category includes lock variables and other variables + * that are involved in synchronization protocols (i.e., the THE + * protocol). + */ +struct local_state /* COMMON_PORTABLE */ +{ + /** This value should be in the first field in any local_state */ +# define WORKER_MAGIC_0 ((ls_magic_t)0xe0831a4a940c60b8ULL) + + /** + * Should be WORKER_MAGIC_0 or the local_state has been corrupted + * This magic field is shared because it is read on lock acquisitions. + * + * [shared read-only] + */ + ls_magic_t worker_magic_0; + + /** + * Mutex used to serialize access to the local_state + * Synchronization field. [shared read/write] + */ + struct mutex lock; + + /** + * Flag that indicates that the worker is interested in grabbing + * LOCK, and thus thieves should leave the worker alone. + * Written only by self, may be read by others. + * + * Synchronization field. [shared read/write] + */ + int do_not_steal; + + /** + * Lock that all thieves grab in order to compete for the right + * to disturb this worker. + * + * Synchronization field. [shared read/write] + */ + struct mutex steal_lock; + + /** + * Full frame that the worker is working on. + * + * While a worker w is executing, a thief may change + * w->l->frame_ff (on a successful steal) after acquiring w's + * lock. + * + * Unlocked accesses to w->l->frame_ff are safe (by w itself) when + * w's deque is empty, or when stealing from w has been disabled. + * + * [shared read/write] + */ + struct full_frame *frame_ff; + + /** + * Full frame that the worker will be working on next + * + * This field is normally local for a worker w. Another worker v + * may modify w->l->next_frame_ff, however, in the special case + * when v is returning a frame to a user thread w since w is the + * team leader. + * + * [shared read/write] + */ + struct full_frame *next_frame_ff; + + /** + * This is set iff this is a WORKER_USER and there has been a steal. It + * points to the first frame that was stolen since the team was last fully + * sync'd. Only this worker may continue past a sync in this function. + * + * This field is set by a thief for a victim that is a user + * thread, while holding the victim's lock. + * It can be cleared without a lock by the worker that will + * continue exuecting past the sync. + * + * [shared read/write] + */ + struct full_frame *last_full_frame; + + /** + * Team on which this worker is a participant. When a user worker enters, + * its team is its own worker struct and it can never change teams. When a + * system worker steals, it adopts the team of its victim. + * + * When a system worker w steals, it reads victim->l->team and + * joins this team. w->l->team is constant until the next time w + * returns control to the runtime. + * We must acquire the worker lock to change w->l->team. + * + * @note This field is 64-byte aligned because it is the first in + * the group of shared read-only fields. We want this group to + * fall on a different cache line from the previous group, which + * is shared read-write. + * + * [shared read-only] + */ + __attribute__((aligned(64))) + __cilkrts_worker *team; + + /** + * Type of this worker + * + * This field changes only when a worker binds or unbinds. + * Otherwise, the field is read-only while the worker is bound. + * + * [shared read-only] + */ + cilk_worker_type type; + + /** + * Lazy task queue of this worker - an array of pointers to stack frames. + * + * Read-only because deques are a fixed size in the current + * implementation. + * + * @note This field is 64-byte aligned because it is the first in + * the group of local fields. We want this group to fall on a + * different cache line from the previous group, which is shared + * read-only. + * + * [local read-only] + */ + __attribute__((aligned(64))) + __cilkrts_stack_frame **ltq; + + /** + * Pool of fibers waiting to be reused. + * [local read/write] + */ + cilk_fiber_pool fiber_pool; + + /** + * The fiber for the scheduling stacks. + * [local read/write] + */ + cilk_fiber* scheduling_fiber; + + /** + * Saved pointer to the leaf node in thread-local storage, when a + * user thread is imported. This pointer gets set to a + * meaningful value when binding a user thread, and cleared on + * unbind. + * + * [local read/write] + */ + __cilkrts_pedigree* original_pedigree_leaf; + + /** + * State of the random number generator + * + * [local read/write] + */ + unsigned rand_seed; + + /** + * Function to execute after transferring onto the scheduling stack. + * + * [local read/write] + */ + scheduling_stack_fcn_t post_suspend; + + /** + * __cilkrts_stack_frame we suspended when we transferred onto the + * scheduling stack. + * + * [local read/write] + */ + __cilkrts_stack_frame *suspended_stack; + + /** + * cilk_fiber that should be freed after returning from a + * spawn with a stolen parent or after stalling at a sync. + + * We calculate the stack to free when executing a reduction on + * the user stack, but we can not actually release the stack + * until control longjmps onto a runtime scheduling stack. + * + * This field is used to pass information to the runtime across + * the longjmp onto the scheduling stack. + * + * [local read/write] + */ + cilk_fiber* fiber_to_free; + + /** + * Saved exception object for an exception that is being passed to + * our parent + * + * [local read/write] + */ + struct pending_exception_info *pending_exception; + + /** + * Buckets for the memory allocator + * + * [local read/write] + */ + struct free_list *free_list[FRAME_MALLOC_NBUCKETS]; + + /** + * Potential function for the memory allocator + * + * [local read/write] + */ + size_t bucket_potential[FRAME_MALLOC_NBUCKETS]; + + /** + * Support for statistics + * + * Useful only when CILK_PROFIlE is compiled in. + * [local read/write] + */ + statistics* stats; + + /** + * Count indicates number of failures since last successful steal. This is + * used by the scheduler to reduce contention on shared flags. + * + * [local read/write] + */ + unsigned int steal_failure_count; + + /** + * 1 if work was stolen from another worker. When true, this will flag + * setup_for_execution_pedigree to increment the pedigree when we resume + * execution to match the increment that would have been done on a return + * from a spawn helper. + * + * [local read/write] + */ + int work_stolen; + + /** + * File pointer for record or replay + * Does FILE * work on Windows? + * During record, the file will be opened in write-only mode. + * During replay, the file will be opened in read-only mode. + * + * [local read/write] + */ + FILE *record_replay_fptr; + + /** + * Root of array of replay entries - NULL if we're not replaying a log + * + * [local read/write] + */ + replay_entry_t *replay_list_root; + + /** + * Current replay entry - NULL if we're not replaying a log + * + * [local read/write] + */ + replay_entry_t *replay_list_entry; + + /** + * Separate the signal_node from other things in the local_state by the + * sizeof a cache line for performance reasons. + * + * unused + */ + char buf[64]; + + /** + * Signal object for waking/sleeping the worker. This should be a pointer + * to avoid the possibility of caching problems. + * + * [shared read-only] + */ + signal_node_t *signal_node; + + /** This value should be in the last field in any local_state */ +# define WORKER_MAGIC_1 ((ls_magic_t)0x16164afb0ea0dff9ULL) + + /** + * Should be WORKER_MAGIC_1 or the local_state has been corrupted + * This magic field is shared because it is read on lock acquisitions. + * [shared read-only] + */ + ls_magic_t worker_magic_1; +}; + +/** + * Perform cleanup according to the function set before the longjmp(). + * + * Call this after longjmp() has completed and the worker is back on a + * scheduling stack. + * + * @param w __cilkrts_worker currently executing. + */ +void run_scheduling_stack_fcn(__cilkrts_worker *w); + +__CILKRTS_END_EXTERN_C + +#endif // ! defined(INCLUDED_LOCAL_STATE_DOT_H) diff --git a/libcilkrts/runtime/mac-symbols.txt b/libcilkrts/runtime/mac-symbols.txt new file mode 100644 index 00000000000..38d83a8675d --- /dev/null +++ b/libcilkrts/runtime/mac-symbols.txt @@ -0,0 +1,318 @@ +# Exported symbol list: +___cilkrts_bind_thread +___cilkrts_bind_thread_1 +___cilkrts_bump_loop_rank +___cilkrts_bump_loop_rank_internal +___cilkrts_bump_worker_rank +___cilkrts_bump_worker_rank_internal +___cilkrts_cilk_for_32 +___cilkrts_cilk_for_64 +___cilkrts_debugger_notification +___cilkrts_dump_stats +___cilkrts_end_cilk +___cilkrts_enter_frame +___cilkrts_enter_frame_1 +___cilkrts_enter_frame_fast +___cilkrts_enter_frame_fast_1 +___cilkrts_get_force_reduce +___cilkrts_get_nworkers +___cilkrts_get_pedigree_info +___cilkrts_get_pedigree_internal +___cilkrts_get_sf +___cilkrts_get_stack_size +___cilkrts_get_tls_worker +___cilkrts_get_tls_worker_fast +___cilkrts_get_total_workers +___cilkrts_get_worker_number +___cilkrts_get_worker_rank +___cilkrts_global_state +___cilkrts_hyper_create +___cilkrts_hyper_destroy +___cilkrts_hyper_lookup +___cilkrts_hyperobject_alloc +___cilkrts_hyperobject_dealloc +___cilkrts_hyperobject_noop_destroy +___cilkrts_init +___cilkrts_irml_version +___cilkrts_leave_frame +___cilkrts_metacall +___cilkrts_rethrow +___cilkrts_return_exception +___cilkrts_save_fp_ctrl_state +___cilkrts_set_param +___cilkrts_stack_alloc +___cilkrts_stack_free +___cilkrts_sync +___cilkrts_synched +___cilkrts_watch_stack +___cilkrts_worker_stub +_cilk_c_reducer_max_identity_char +_cilk_c_reducer_max_identity_double +_cilk_c_reducer_max_identity_float +_cilk_c_reducer_max_identity_int +_cilk_c_reducer_max_identity_long +_cilk_c_reducer_max_identity_longdouble +_cilk_c_reducer_max_identity_longlong +_cilk_c_reducer_max_identity_schar +_cilk_c_reducer_max_identity_short +_cilk_c_reducer_max_identity_uchar +_cilk_c_reducer_max_identity_uint +_cilk_c_reducer_max_identity_ulong +_cilk_c_reducer_max_identity_ulonglong +_cilk_c_reducer_max_identity_unsigned +_cilk_c_reducer_max_identity_ushort +_cilk_c_reducer_max_identity_wchar_t +_cilk_c_reducer_max_index_identity_char +_cilk_c_reducer_max_index_identity_double +_cilk_c_reducer_max_index_identity_float +_cilk_c_reducer_max_index_identity_int +_cilk_c_reducer_max_index_identity_long +_cilk_c_reducer_max_index_identity_longdouble +_cilk_c_reducer_max_index_identity_longlong +_cilk_c_reducer_max_index_identity_schar +_cilk_c_reducer_max_index_identity_short +_cilk_c_reducer_max_index_identity_uchar +_cilk_c_reducer_max_index_identity_uint +_cilk_c_reducer_max_index_identity_ulong +_cilk_c_reducer_max_index_identity_ulonglong +_cilk_c_reducer_max_index_identity_unsigned +_cilk_c_reducer_max_index_identity_ushort +_cilk_c_reducer_max_index_identity_wchar_t +_cilk_c_reducer_max_index_reduce_char +_cilk_c_reducer_max_index_reduce_double +_cilk_c_reducer_max_index_reduce_float +_cilk_c_reducer_max_index_reduce_int +_cilk_c_reducer_max_index_reduce_long +_cilk_c_reducer_max_index_reduce_longdouble +_cilk_c_reducer_max_index_reduce_longlong +_cilk_c_reducer_max_index_reduce_schar +_cilk_c_reducer_max_index_reduce_short +_cilk_c_reducer_max_index_reduce_uchar +_cilk_c_reducer_max_index_reduce_uint +_cilk_c_reducer_max_index_reduce_ulong +_cilk_c_reducer_max_index_reduce_ulonglong +_cilk_c_reducer_max_index_reduce_unsigned +_cilk_c_reducer_max_index_reduce_ushort +_cilk_c_reducer_max_index_reduce_wchar_t +_cilk_c_reducer_max_reduce_char +_cilk_c_reducer_max_reduce_double +_cilk_c_reducer_max_reduce_float +_cilk_c_reducer_max_reduce_int +_cilk_c_reducer_max_reduce_long +_cilk_c_reducer_max_reduce_longdouble +_cilk_c_reducer_max_reduce_longlong +_cilk_c_reducer_max_reduce_schar +_cilk_c_reducer_max_reduce_short +_cilk_c_reducer_max_reduce_uchar +_cilk_c_reducer_max_reduce_uint +_cilk_c_reducer_max_reduce_ulong +_cilk_c_reducer_max_reduce_ulonglong +_cilk_c_reducer_max_reduce_unsigned +_cilk_c_reducer_max_reduce_ushort +_cilk_c_reducer_max_reduce_wchar_t +_cilk_c_reducer_min_identity_char +_cilk_c_reducer_min_identity_double +_cilk_c_reducer_min_identity_float +_cilk_c_reducer_min_identity_int +_cilk_c_reducer_min_identity_long +_cilk_c_reducer_min_identity_longdouble +_cilk_c_reducer_min_identity_longlong +_cilk_c_reducer_min_identity_schar +_cilk_c_reducer_min_identity_short +_cilk_c_reducer_min_identity_uchar +_cilk_c_reducer_min_identity_uint +_cilk_c_reducer_min_identity_ulong +_cilk_c_reducer_min_identity_ulonglong +_cilk_c_reducer_min_identity_unsigned +_cilk_c_reducer_min_identity_ushort +_cilk_c_reducer_min_identity_wchar_t +_cilk_c_reducer_min_index_identity_char +_cilk_c_reducer_min_index_identity_double +_cilk_c_reducer_min_index_identity_float +_cilk_c_reducer_min_index_identity_int +_cilk_c_reducer_min_index_identity_long +_cilk_c_reducer_min_index_identity_longdouble +_cilk_c_reducer_min_index_identity_longlong +_cilk_c_reducer_min_index_identity_schar +_cilk_c_reducer_min_index_identity_short +_cilk_c_reducer_min_index_identity_uchar +_cilk_c_reducer_min_index_identity_uint +_cilk_c_reducer_min_index_identity_ulong +_cilk_c_reducer_min_index_identity_ulonglong +_cilk_c_reducer_min_index_identity_unsigned +_cilk_c_reducer_min_index_identity_ushort +_cilk_c_reducer_min_index_identity_wchar_t +_cilk_c_reducer_min_index_reduce_char +_cilk_c_reducer_min_index_reduce_double +_cilk_c_reducer_min_index_reduce_float +_cilk_c_reducer_min_index_reduce_int +_cilk_c_reducer_min_index_reduce_long +_cilk_c_reducer_min_index_reduce_longdouble +_cilk_c_reducer_min_index_reduce_longlong +_cilk_c_reducer_min_index_reduce_schar +_cilk_c_reducer_min_index_reduce_short +_cilk_c_reducer_min_index_reduce_uchar +_cilk_c_reducer_min_index_reduce_uint +_cilk_c_reducer_min_index_reduce_ulong +_cilk_c_reducer_min_index_reduce_ulonglong +_cilk_c_reducer_min_index_reduce_unsigned +_cilk_c_reducer_min_index_reduce_ushort +_cilk_c_reducer_min_index_reduce_wchar_t +_cilk_c_reducer_min_reduce_char +_cilk_c_reducer_min_reduce_double +_cilk_c_reducer_min_reduce_float +_cilk_c_reducer_min_reduce_int +_cilk_c_reducer_min_reduce_long +_cilk_c_reducer_min_reduce_longdouble +_cilk_c_reducer_min_reduce_longlong +_cilk_c_reducer_min_reduce_schar +_cilk_c_reducer_min_reduce_short +_cilk_c_reducer_min_reduce_uchar +_cilk_c_reducer_min_reduce_uint +_cilk_c_reducer_min_reduce_ulong +_cilk_c_reducer_min_reduce_ulonglong +_cilk_c_reducer_min_reduce_unsigned +_cilk_c_reducer_min_reduce_ushort +_cilk_c_reducer_min_reduce_wchar_t +_cilk_c_reducer_opadd_identity_char +_cilk_c_reducer_opadd_identity_double +_cilk_c_reducer_opadd_identity_float +_cilk_c_reducer_opadd_identity_int +_cilk_c_reducer_opadd_identity_long +_cilk_c_reducer_opadd_identity_longdouble +_cilk_c_reducer_opadd_identity_longlong +_cilk_c_reducer_opadd_identity_schar +_cilk_c_reducer_opadd_identity_short +_cilk_c_reducer_opadd_identity_uchar +_cilk_c_reducer_opadd_identity_uint +_cilk_c_reducer_opadd_identity_ulong +_cilk_c_reducer_opadd_identity_ulonglong +_cilk_c_reducer_opadd_identity_unsigned +_cilk_c_reducer_opadd_identity_ushort +_cilk_c_reducer_opadd_identity_wchar_t +_cilk_c_reducer_opadd_reduce_char +_cilk_c_reducer_opadd_reduce_double +_cilk_c_reducer_opadd_reduce_float +_cilk_c_reducer_opadd_reduce_int +_cilk_c_reducer_opadd_reduce_long +_cilk_c_reducer_opadd_reduce_longdouble +_cilk_c_reducer_opadd_reduce_longlong +_cilk_c_reducer_opadd_reduce_schar +_cilk_c_reducer_opadd_reduce_short +_cilk_c_reducer_opadd_reduce_uchar +_cilk_c_reducer_opadd_reduce_uint +_cilk_c_reducer_opadd_reduce_ulong +_cilk_c_reducer_opadd_reduce_ulonglong +_cilk_c_reducer_opadd_reduce_unsigned +_cilk_c_reducer_opadd_reduce_ushort +_cilk_c_reducer_opadd_reduce_wchar_t +_cilk_c_reducer_opand_identity_char +_cilk_c_reducer_opand_identity_int +_cilk_c_reducer_opand_identity_long +_cilk_c_reducer_opand_identity_longlong +_cilk_c_reducer_opand_identity_schar +_cilk_c_reducer_opand_identity_short +_cilk_c_reducer_opand_identity_uchar +_cilk_c_reducer_opand_identity_uint +_cilk_c_reducer_opand_identity_ulong +_cilk_c_reducer_opand_identity_ulonglong +_cilk_c_reducer_opand_identity_unsigned +_cilk_c_reducer_opand_identity_ushort +_cilk_c_reducer_opand_identity_wchar_t +_cilk_c_reducer_opand_reduce_char +_cilk_c_reducer_opand_reduce_int +_cilk_c_reducer_opand_reduce_long +_cilk_c_reducer_opand_reduce_longlong +_cilk_c_reducer_opand_reduce_schar +_cilk_c_reducer_opand_reduce_short +_cilk_c_reducer_opand_reduce_uchar +_cilk_c_reducer_opand_reduce_uint +_cilk_c_reducer_opand_reduce_ulong +_cilk_c_reducer_opand_reduce_ulonglong +_cilk_c_reducer_opand_reduce_unsigned +_cilk_c_reducer_opand_reduce_ushort +_cilk_c_reducer_opand_reduce_wchar_t +_cilk_c_reducer_opmul_identity_char +_cilk_c_reducer_opmul_identity_double +_cilk_c_reducer_opmul_identity_float +_cilk_c_reducer_opmul_identity_int +_cilk_c_reducer_opmul_identity_long +_cilk_c_reducer_opmul_identity_longdouble +_cilk_c_reducer_opmul_identity_longlong +_cilk_c_reducer_opmul_identity_schar +_cilk_c_reducer_opmul_identity_short +_cilk_c_reducer_opmul_identity_uchar +_cilk_c_reducer_opmul_identity_uint +_cilk_c_reducer_opmul_identity_ulong +_cilk_c_reducer_opmul_identity_ulonglong +_cilk_c_reducer_opmul_identity_unsigned +_cilk_c_reducer_opmul_identity_ushort +_cilk_c_reducer_opmul_identity_wchar_t +_cilk_c_reducer_opmul_reduce_char +_cilk_c_reducer_opmul_reduce_double +_cilk_c_reducer_opmul_reduce_float +_cilk_c_reducer_opmul_reduce_int +_cilk_c_reducer_opmul_reduce_long +_cilk_c_reducer_opmul_reduce_longdouble +_cilk_c_reducer_opmul_reduce_longlong +_cilk_c_reducer_opmul_reduce_schar +_cilk_c_reducer_opmul_reduce_short +_cilk_c_reducer_opmul_reduce_uchar +_cilk_c_reducer_opmul_reduce_uint +_cilk_c_reducer_opmul_reduce_ulong +_cilk_c_reducer_opmul_reduce_ulonglong +_cilk_c_reducer_opmul_reduce_unsigned +_cilk_c_reducer_opmul_reduce_ushort +_cilk_c_reducer_opmul_reduce_wchar_t +_cilk_c_reducer_opor_identity_char +_cilk_c_reducer_opor_identity_int +_cilk_c_reducer_opor_identity_long +_cilk_c_reducer_opor_identity_longlong +_cilk_c_reducer_opor_identity_schar +_cilk_c_reducer_opor_identity_short +_cilk_c_reducer_opor_identity_uchar +_cilk_c_reducer_opor_identity_uint +_cilk_c_reducer_opor_identity_ulong +_cilk_c_reducer_opor_identity_ulonglong +_cilk_c_reducer_opor_identity_unsigned +_cilk_c_reducer_opor_identity_ushort +_cilk_c_reducer_opor_identity_wchar_t +_cilk_c_reducer_opor_reduce_char +_cilk_c_reducer_opor_reduce_int +_cilk_c_reducer_opor_reduce_long +_cilk_c_reducer_opor_reduce_longlong +_cilk_c_reducer_opor_reduce_schar +_cilk_c_reducer_opor_reduce_short +_cilk_c_reducer_opor_reduce_uchar +_cilk_c_reducer_opor_reduce_uint +_cilk_c_reducer_opor_reduce_ulong +_cilk_c_reducer_opor_reduce_ulonglong +_cilk_c_reducer_opor_reduce_unsigned +_cilk_c_reducer_opor_reduce_ushort +_cilk_c_reducer_opor_reduce_wchar_t +_cilk_c_reducer_opxor_identity_char +_cilk_c_reducer_opxor_identity_int +_cilk_c_reducer_opxor_identity_long +_cilk_c_reducer_opxor_identity_longlong +_cilk_c_reducer_opxor_identity_schar +_cilk_c_reducer_opxor_identity_short +_cilk_c_reducer_opxor_identity_uchar +_cilk_c_reducer_opxor_identity_uint +_cilk_c_reducer_opxor_identity_ulong +_cilk_c_reducer_opxor_identity_ulonglong +_cilk_c_reducer_opxor_identity_unsigned +_cilk_c_reducer_opxor_identity_ushort +_cilk_c_reducer_opxor_identity_wchar_t +_cilk_c_reducer_opxor_reduce_char +_cilk_c_reducer_opxor_reduce_int +_cilk_c_reducer_opxor_reduce_long +_cilk_c_reducer_opxor_reduce_longlong +_cilk_c_reducer_opxor_reduce_schar +_cilk_c_reducer_opxor_reduce_short +_cilk_c_reducer_opxor_reduce_uchar +_cilk_c_reducer_opxor_reduce_uint +_cilk_c_reducer_opxor_reduce_ulong +_cilk_c_reducer_opxor_reduce_ulonglong +_cilk_c_reducer_opxor_reduce_unsigned +_cilk_c_reducer_opxor_reduce_ushort +_cilk_c_reducer_opxor_reduce_wchar_t diff --git a/libcilkrts/runtime/metacall_impl.c b/libcilkrts/runtime/metacall_impl.c new file mode 100644 index 00000000000..ce1c51a202b --- /dev/null +++ b/libcilkrts/runtime/metacall_impl.c @@ -0,0 +1,167 @@ +/* metacall_impl.c -*-C-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +#include "metacall_impl.h" + +NOINLINE +CILK_API_VOID +__cilkrts_metacall(unsigned int tool, unsigned int code, void *data) +{ +#ifdef ENABLE_NOTIFY_ZC_INTRINSIC + // The metacall type, code and data are packed together into a single + // struct which will be interpreted by the tool. This function is the + // one and only use of a "cilkscreen_metacall" annotation + metacall_data_t d = { tool, code, data }; + + // Note that Inspector uses probe mode, and is implementing the metacall + // interface to force the runtime to run with a single worker. So + // __cilkrts_metacall must use __notify_intrinsic instead of + // __notify_zc_intrinsic + __notify_intrinsic("cilkscreen_metacall", &d); +#endif // ENABLE_NOTIFY_ZC_INTRINSIC +} + +int __cilkrts_running_under_sequential_ptool(void) +{ + static int running_under_sequential_ptool = -1; + volatile char c = ~0; + + // If we haven't been called before, see if we're running under Cilkscreen + // or Cilkview + if (-1 == running_under_sequential_ptool) + { + // metacall #2 writes 0 in C if we are running under + // a p-tools that requires serial execution, and is a + // no-op otherwise + // + // Note that removing the volatile is required to prevent the compiler + // from assuming that the value has not changed + __cilkrts_metacall(METACALL_TOOL_SYSTEM, + HYPER_ZERO_IF_SEQUENTIAL_PTOOL, (void *)&c); + + running_under_sequential_ptool = (0 == c); + } + + return running_under_sequential_ptool; +} + +/* + * __cilkrts_cilkscreen_establish_c_stack + * + * Notify Cilkscreen of the extent of the stack + */ + +void __cilkrts_cilkscreen_establish_c_stack(char *begin, char *end) +{ + char *limits[2] = {begin, end}; + + __cilkrts_metacall(METACALL_TOOL_SYSTEM, HYPER_ESTABLISH_C_STACK, limits); +} + +#ifdef WORKSPAN // Workspan stuff - remove when we're sure what we can drop + +void __cilkview_workspan_start(void) { + __cilkrts_metacall(HYPER_WORKSPAN_START, 0); +} + +void __cilkview_workspan_stop(void) { + __cilkrts_metacall(HYPER_WORKSPAN_STOP, 0); +} + +void __cilkview_workspan_dump(const char *str) { + __cilkrts_metacall(HYPER_WORKSPAN_DUMP, (void*)str); +} + + +void __cilkview_workspan_reset(void) { + __cilkrts_metacall(HYPER_WORKSPAN_RESET, 0); +} + + +void __cilkview_use_default_grain(void) { + __cilkrts_metacall(HYPER_USE_DEFAULT_GRAIN, 0); +} + +void __cilkview_get_workspan_data(unsigned long long *values, int size) +{ + void *data[2]; + + /* reset counters to zero in case we are not running under + a p-tool */ + + values[0] = 0; + + data[0] = (void*) values; + data[1] = (void*) &size; + __cilkrts_metacall(HYPER_WORKSPAN_QUERY, &data); +} + +void __cilkview_workspan_connected (int *flag) { + *flag = 0; + __cilkrts_metacall(HYPER_WORKSPAN_CONNECTED, (void *)flag); +} + +void __cilkview_workspan_suspend() { + __cilkrts_metacall(HYPER_WORKSPAN_SUSPEND, 0); +} + +void __cilkview_workspan_resume() { + __cilkrts_metacall(HYPER_WORKSPAN_RESUME, 0); +} + +/* depreciated interfaces */ +void __cilkometer_workspan_start(void) { + __cilkrts_metacall(HYPER_WORKSPAN_START, 0); +} + +void __cilkometer_workspan_stop(void) { + __cilkrts_metacall(HYPER_WORKSPAN_STOP, 0); +} + +void __cilkometer_workspan_dump(const char *str) { + __cilkrts_metacall(HYPER_WORKSPAN_DUMP, (void*)str); +} + + +void __cilkometer_workspan_reset(void) { + __cilkrts_metacall(HYPER_WORKSPAN_RESET, 0); +} + +#endif // WORKSPAN + +/* End metacall_impl.c */ diff --git a/libcilkrts/runtime/metacall_impl.h b/libcilkrts/runtime/metacall_impl.h new file mode 100644 index 00000000000..90cc7f95168 --- /dev/null +++ b/libcilkrts/runtime/metacall_impl.h @@ -0,0 +1,123 @@ +/* metacall_impl.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2010-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + +/** + * @file metacall_impl.h + * + * @brief Meta-function calls to be used within the Cilk runtime system. + * + * These differ from the macros in cilkscreen.h and cilkview.h because they go + * through the __cilkrts_metacall interface, which ensures that the operation + * is performed even when instrumentation is disabled. + */ + +#ifndef INCLUDED_CILKRTS_METACALL_H +#define INCLUDED_CILKRTS_METACALL_H + +#include "rts-common.h" +#include <internal/metacall.h> +#include <cilk/common.h> + +__CILKRTS_BEGIN_EXTERN_C + +/** + * This function is effectively an unconditional call from the runtime into + * a tool. It is used for operations that must be performed by the tool, + * even when the tool is not instrumenting. For example, Cilkscreen always + * recognizes the address of this function and performs the action specified + * in the contained metadata. + * + * Note that this function MUST NOT BE INLINED within the runtime. This must + * be the ONLY instance of the cilkscreen_metacall metadata. + */ +CILK_API_VOID +__cilkrts_metacall(unsigned int tool, unsigned int code, void *data); + +/** + * Return non-zero if running under Cilkscreen or Cilkview + */ +COMMON_PORTABLE +int __cilkrts_running_under_sequential_ptool(void); + +/** + * Disable Cilkscreen implementation + */ +#define __cilkrts_cilkscreen_disable_instrumentation() \ + __cilkrts_metacall(METACALL_TOOL_SYSTEM, HYPER_DISABLE_INSTRUMENTATION, 0) + +/** + * Enable Cilkscreen implementation + */ +#define __cilkrts_cilkscreen_enable_instrumentation() \ + __cilkrts_metacall(METACALL_TOOL_SYSTEM, HYPER_ENABLE_INSTRUMENTATION, 0) + +/** + * Set the worker on entering runtime. + * + * @attention Deprecated in favor of __cilkrts_cilkscreen_ignore_block. The + * begin/enter pairs in the current metadata mean Cilkscreen no longer has to + * have improper knowledge of the __cilkrts_worker or __cilkrts_stack_frame + * structures. + */ +#define __cilkrts_cilkscreen_establish_worker(w) \ + __cilkrts_metacall(METACALL_TOOL_SYSTEM, HYPER_ESTABLISH_WORKER, w) + +/** + * Notify Cilkscreen of the extent of the stack. + * + * @param[in] begin Start (low address) of stack + * @param[in] end One past high address of stack + */ +void __cilkrts_cilkscreen_establish_c_stack(char *begin, char *end); + +/** + * Tell tools to ignore a block of memory - currently the global state and + * memory allocated for workers. + */ +#define __cilkrts_cilkscreen_ignore_block(_begin, _end) \ +{ \ + void *block[2] = {_begin, _end}; \ + __cilkrts_metacall(METACALL_TOOL_SYSTEM, \ + HYPER_IGNORE_MEMORY_BLOCK, \ + block); \ +} + +__CILKRTS_END_EXTERN_C + +#endif /* ! defined(INCLUDED_CILKRTS_METACALL_H) */ diff --git a/libcilkrts/runtime/os-unix.c b/libcilkrts/runtime/os-unix.c new file mode 100644 index 00000000000..b48fd623c6e --- /dev/null +++ b/libcilkrts/runtime/os-unix.c @@ -0,0 +1,508 @@ +/* os-unix.c -*-C-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +#ifdef __linux__ + // define _GNU_SOURCE before *any* #include. + // Even <stdint.h> will break later #includes if this macro is not + // already defined when it is #included. +# define _GNU_SOURCE +#endif + +#include "os.h" +#include "bug.h" +#include "cilk_malloc.h" +#include <internal/abi.h> + +#if defined __linux__ +# include <sys/sysinfo.h> +# include <sys/syscall.h> +#elif defined __APPLE__ +# include <sys/sysctl.h> + // Uses sysconf(_SC_NPROCESSORS_ONLN) in verbose output +#elif defined __FreeBSD__ +// No additional include files +#elif defined __CYGWIN__ +// Cygwin on Windows - no additional include files +#elif defined __VXWORKS__ +# include <vxWorks.h> +# include <vxCpuLib.h> +# include <taskLib.h> +#else +# error "Unsupported OS" +#endif + +#include <stdarg.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <pthread.h> +#include <sys/types.h> + + + +// /* Thread-local storage */ +// #ifdef _WIN32 +// typedef unsigned cilkos_tls_key_t; +// #else +// typedef pthread_key_t cilkos_tls_key_t; +// #endif +// cilkos_tls_key_t cilkos_allocate_tls_key(); +// void cilkos_set_tls_pointer(cilkos_tls_key_t key, void* ptr); +// void* cilkos_get_tls_pointer(cilkos_tls_key_t key); + +#if !defined CILK_WORKER_TLS +static int cilk_keys_defined; +static pthread_key_t worker_key, pedigree_leaf_key, tbb_interop_key; + +#if SUPPORT_GET_CURRENT_FIBER > 0 +static pthread_key_t fiber_key; +#endif + +static void *serial_worker; + + +// This destructor is called when a pthread dies to deallocate the +// pedigree node. +static void __cilkrts_pedigree_leaf_destructor(void* pedigree_tls_ptr) +{ + __cilkrts_pedigree* pedigree_tls + = (__cilkrts_pedigree*)pedigree_tls_ptr; + if (pedigree_tls) { + // Assert that we have either one or two nodes + // left in the pedigree chain. + // If we have more, then something is going wrong... + CILK_ASSERT(!pedigree_tls->parent || !pedigree_tls->parent->parent); + __cilkrts_free(pedigree_tls); + } +} + +void __cilkrts_init_tls_variables(void) +{ + int status; + /* This will be called once in serial execution before any + Cilk parallelism so we do not need to worry about races + on cilk_keys_defined. */ + if (cilk_keys_defined) + return; + status = pthread_key_create(&worker_key, NULL); + CILK_ASSERT (status == 0); + status = pthread_key_create(&pedigree_leaf_key, + __cilkrts_pedigree_leaf_destructor); + CILK_ASSERT (status == 0); + status = pthread_key_create(&tbb_interop_key, NULL); + CILK_ASSERT (status == 0); + +#if SUPPORT_GET_CURRENT_FIBER > 0 + status = pthread_key_create(&fiber_key, NULL); + CILK_ASSERT (status == 0); +#endif + cilk_keys_defined = 1; + return; +} + +COMMON_SYSDEP +void* cilkos_get_current_thread_id(void) +{ + return (void*)pthread_self(); +} + + +CILK_ABI_WORKER_PTR __cilkrts_get_tls_worker() +{ + if (__builtin_expect(cilk_keys_defined, 1)) + return (__cilkrts_worker *)pthread_getspecific(worker_key); + else + return serial_worker; + +} + +CILK_ABI_WORKER_PTR __cilkrts_get_tls_worker_fast() +{ + return (__cilkrts_worker *)pthread_getspecific(worker_key); +} + +COMMON_SYSDEP +__cilk_tbb_stack_op_thunk *__cilkrts_get_tls_tbb_interop(void) +{ + if (__builtin_expect(cilk_keys_defined, 1)) + return (__cilk_tbb_stack_op_thunk *) + pthread_getspecific(tbb_interop_key); + else + return 0; +} + +// This counter should be updated atomically. +static int __cilkrts_global_pedigree_tls_counter = -1; + +COMMON_SYSDEP +__cilkrts_pedigree *__cilkrts_get_tls_pedigree_leaf(int create_new) +{ + __cilkrts_pedigree *pedigree_tls; + if (__builtin_expect(cilk_keys_defined, 1)) { + pedigree_tls = + (struct __cilkrts_pedigree *)pthread_getspecific(pedigree_leaf_key); + } + else { + return 0; + } + + if (!pedigree_tls && create_new) { + // This call creates two nodes, X and Y. + // X == pedigree_tls[0] is the leaf node, which gets copied + // in and out of a user worker w when w binds and unbinds. + // Y == pedigree_tls[1] is the root node, + // which is a constant node that represents the user worker + // thread w. + pedigree_tls = (__cilkrts_pedigree*) + __cilkrts_malloc(2 * sizeof(__cilkrts_pedigree)); + + // This call sets the TLS pointer to the new node. + __cilkrts_set_tls_pedigree_leaf(pedigree_tls); + + pedigree_tls[0].rank = 0; + pedigree_tls[0].parent = &pedigree_tls[1]; + + // Create Y, whose rank begins as the global counter value. + pedigree_tls[1].rank = + __sync_add_and_fetch(&__cilkrts_global_pedigree_tls_counter, 1); + + pedigree_tls[1].parent = NULL; + CILK_ASSERT(pedigree_tls[1].rank != -1); + } + return pedigree_tls; +} + +#if SUPPORT_GET_CURRENT_FIBER > 0 +COMMON_SYSDEP +cilk_fiber_sysdep* cilkos_get_tls_cilk_fiber(void) +{ + if (__builtin_expect(cilk_keys_defined, 1)) + return (cilk_fiber_sysdep *)pthread_getspecific(fiber_key); + else + return NULL; +} +#endif + +COMMON_SYSDEP +void __cilkrts_set_tls_worker(__cilkrts_worker *w) +{ + if (__builtin_expect(cilk_keys_defined, 1)) { + int status; + status = pthread_setspecific(worker_key, w); + CILK_ASSERT (status == 0); + return; + } + else + { + serial_worker = w; + } +} + +COMMON_SYSDEP +void __cilkrts_set_tls_tbb_interop(__cilk_tbb_stack_op_thunk *t) +{ + if (__builtin_expect(cilk_keys_defined, 1)) { + int status; + status = pthread_setspecific(tbb_interop_key, t); + CILK_ASSERT (status == 0); + return; + } + abort(); +} + +COMMON_SYSDEP +void __cilkrts_set_tls_pedigree_leaf(__cilkrts_pedigree* pedigree_leaf) +{ + if (__builtin_expect(cilk_keys_defined, 1)) { + int status; + status = pthread_setspecific(pedigree_leaf_key, pedigree_leaf); + CILK_ASSERT (status == 0); + return; + } + abort(); +} + +#if SUPPORT_GET_CURRENT_FIBER > 0 +COMMON_SYSDEP +void cilkos_set_tls_cilk_fiber(cilk_fiber_sysdep* fiber) +{ + if (__builtin_expect(cilk_keys_defined, 1)) { + int status; + status = pthread_setspecific(fiber_key, fiber); + CILK_ASSERT (status == 0); + return; + } + abort(); +} +#endif + +#else +void __cilkrts_init_tls_variables(void) +{ +} +#endif + +#if defined (__linux__) && ! defined(ANDROID) +/* + * Get the thread id, rather than the pid. In the case of MIC offload, it's + * possible that we have multiple threads entering Cilk, and each has a + * different affinity. + */ +static pid_t linux_gettid(void) +{ + return syscall(SYS_gettid); +} + +/* + * On Linux we look at the thread affinity mask and restrict ourself to one + * thread for each of the hardware contexts to which we are bound. + * Therefore if user does + * % taskset 0-1 cilkProgram + * # restrict execution to hardware contexts zero and one + * the Cilk program will only use two threads even if it is running on a + * machine that has 32 hardware contexts. + * This is the right thing to do, because the threads are restricted to two + * hardware contexts by the affinity mask set by taskset, and if we were to + * create extra threads they would simply oversubscribe the hardware resources + * we can use. + * This is particularly important on MIC in offload mode, where the affinity + * mask is set by the offload library to force the offload code away from + * cores that have offload support threads running on them. + */ +static int linux_get_affinity_count (int tid) +{ + cpu_set_t process_mask; + + // Extract the thread affinity mask + int err = sched_getaffinity (tid, sizeof(process_mask),&process_mask); + + if (0 != err) + { + return 0; + } + + // We have extracted the mask OK, so now we can count the number of threads + // in it. This is linear in the maximum number of CPUs available, We + // could do a logarithmic version, if we assume the format of the mask, + // but it's not really worth it. We only call this at thread startup + // anyway. + int available_procs = 0; + int i; + for (i = 0; i < CPU_SETSIZE; i++) + { + if (CPU_ISSET(i, &process_mask)) + { + available_procs++; + } + } + + return available_procs; +} +#endif + +/* + * __cilkrts_hardware_cpu_count + * + * Returns the number of available CPUs on this hardware. This is architecture- + * specific. + */ + +COMMON_SYSDEP int __cilkrts_hardware_cpu_count(void) +{ +#if defined ANDROID + return sysconf (_SC_NPROCESSORS_ONLN); +#elif defined __MIC__ + /// HACK: Usually, the 3rd and 4th hyperthreads are not beneficial + /// on KNC. Also, ignore the last core. + int P = sysconf (_SC_NPROCESSORS_ONLN); + return P/2 - 2; +#elif defined __linux__ + int affinity_count = linux_get_affinity_count(linux_gettid()); + + return (0 != affinity_count) ? affinity_count : sysconf (_SC_NPROCESSORS_ONLN); +#elif defined __APPLE__ + int count = 0; + int cmd[2] = { CTL_HW, HW_NCPU }; + size_t len = sizeof count; + int status = sysctl(cmd, 2, &count, &len, 0, 0); + assert(status >= 0); + assert((unsigned)count == count); + + return count; +#elif defined __FreeBSD__ || defined __CYGWIN__ + int ncores = sysconf(_SC_NPROCESSORS_ONLN); + + return ncores; + // Just get the number of processors +// return sysconf(_SC_NPROCESSORS_ONLN); +#elif defined __VXWORKS__ + return __builtin_popcount( vxCpuEnabledGet() ); +#else +#error "Unknown architecture" +#endif +} + +COMMON_SYSDEP void __cilkrts_sleep(void) +{ +#ifdef __VXWORKS__ + taskDelay(1); +#else + usleep(1); +#endif +} + +COMMON_SYSDEP void __cilkrts_yield(void) +{ +#if __APPLE__ || __FreeBSD__ || __VXWORKS__ + // On MacOS, call sched_yield to yield quantum. I'm not sure why we + // don't do this on Linux also. + sched_yield(); +#elif defined(__MIC__) + // On MIC, pthread_yield() really trashes things. Arch's measurements + // showed that calling _mm_delay_32() (or doing nothing) was a better + // option. Delaying 1024 clock cycles is a reasonable compromise between + // giving up the processor and latency starting up when work becomes + // available + _mm_delay_32(1024); +#elif defined(ANDROID) + // On Android, call sched_yield to yield quantum. I'm not sure why we + // don't do this on Linux also. + sched_yield(); +#else + // On Linux, call pthread_yield (which in turn will call sched_yield) + // to yield quantum. + pthread_yield(); +#endif +} + +COMMON_SYSDEP __STDNS size_t cilkos_getenv(char* value, __STDNS size_t vallen, + const char* varname) +{ + CILK_ASSERT(value); + CILK_ASSERT(varname); + + const char* envstr = getenv(varname); + if (envstr) + { + size_t len = strlen(envstr); + if (len > vallen - 1) + return len + 1; + + strcpy(value, envstr); + return len; + } + else + { + value[0] = '\0'; + return 0; + } +} + +/* + * Unrecoverable error: Print an error message and abort execution. + */ +COMMON_SYSDEP void cilkos_error(const char *fmt, ...) +{ + va_list l; + fflush(NULL); + fprintf(stderr, "Cilk error: "); + va_start(l, fmt); + vfprintf(stderr, fmt, l); + va_end(l); + fprintf(stderr, "Exiting.\n"); + fflush(stderr); + + abort(); +} + +/* + * Print a warning message and return. + */ +COMMON_SYSDEP void cilkos_warning(const char *fmt, ...) +{ + va_list l; + fflush(NULL); + fprintf(stderr, "Cilk warning: "); + va_start(l, fmt); + vfprintf(stderr, fmt, l); + va_end(l); + fflush(stderr); +} + +static void __attribute__((constructor)) init_once() +{ + /*__cilkrts_debugger_notification_internal(CILK_DB_RUNTIME_LOADED);*/ + __cilkrts_init_tls_variables(); +} + + +#define PAGE 4096 +#define CILK_MIN_STACK_SIZE (4*PAGE) +// Default size for the stacks that we create in Cilk for Unix. +#define CILK_DEFAULT_STACK_SIZE 0x100000 + +/* + * Convert the user's specified stack size into a "reasonable" value + * for this OS. + */ +size_t cilkos_validate_stack_size(size_t specified_stack_size) { + // Convert any negative value to the default. + if (specified_stack_size == 0) { + CILK_ASSERT((CILK_DEFAULT_STACK_SIZE % PAGE) == 0); + return CILK_DEFAULT_STACK_SIZE; + } + // Round values in between 0 and CILK_MIN_STACK_SIZE up to + // CILK_MIN_STACK_SIZE. + if (specified_stack_size <= CILK_MIN_STACK_SIZE) { + return CILK_MIN_STACK_SIZE; + } + if ((specified_stack_size % PAGE) > 0) { + // Round the user's stack size value up to nearest page boundary. + return (PAGE * (1 + specified_stack_size / PAGE)); + } + return specified_stack_size; +} + +long cilkos_atomic_add(volatile long* p, long x) +{ + return __sync_add_and_fetch(p, x); +} + +/* End os-unix.c */ diff --git a/libcilkrts/runtime/os.h b/libcilkrts/runtime/os.h new file mode 100644 index 00000000000..8066f0313c2 --- /dev/null +++ b/libcilkrts/runtime/os.h @@ -0,0 +1,236 @@ +/* os.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** + * @file os.h + * + * @brief Low-level operating-system dependent facilities, not dependent on + * any Cilk facilities. + */ + +#ifndef INCLUDED_OS_DOT_H +#define INCLUDED_OS_DOT_H + +#include "rts-common.h" +#include "cilk/common.h" +#include "cilk-tbb-interop.h" + +#ifdef __cplusplus +# include <cstddef> +#else +# include <stddef.h> +#endif + +__CILKRTS_BEGIN_EXTERN_C + + +// /* Thread-local storage */ +// #ifdef _WIN32 +// typedef unsigned cilkos_tls_key_t; +// #else +// typedef pthread_key_t cilkos_tls_key_t; +// #endif +// cilkos_tls_key_t cilkos_allocate_tls_key(); +// void cilkos_set_tls_pointer(cilkos_tls_key_t key, void* ptr); +// void* cilkos_get_tls_pointer(cilkos_tls_key_t key); + +/* The RTS assumes that some thread-local state exists that stores the + worker and reducer map currently associated with a thread. These routines + manipulate this state. */ + +/** @brief Thread-local state for cilk fibers. */ +typedef struct cilk_fiber_sysdep cilk_fiber_sysdep; + +/** @brief Initialize all TLS variables for Cilk. */ +COMMON_SYSDEP void __cilkrts_init_tls_variables(void); + +/** @brief Set worker struct in TLS. */ +COMMON_SYSDEP +void __cilkrts_set_tls_worker(__cilkrts_worker *w) cilk_nothrow; + +/** @brief Get stack_op for TBB-interop structures from TLS. */ +COMMON_SYSDEP +__cilk_tbb_stack_op_thunk *__cilkrts_get_tls_tbb_interop(void); + +/** @brief Set stack_op for TBB-interop structures in TLS. */ +COMMON_SYSDEP +void __cilkrts_set_tls_tbb_interop(__cilk_tbb_stack_op_thunk *t); + +/** + * @brief Get the pointer to the pedigree leaf node from TLS. + * + * Function to get a pointer to the thread's pedigree leaf node. This + * pointer can be NULL. + */ +COMMON_SYSDEP +__cilkrts_pedigree * __cilkrts_get_tls_pedigree_leaf(int create_new); + +/** + * @brief Sets the pointer to the pedigree leaf node in TLS. + * + * If the previous pointer value was not NULL, it is the caller's + * responsibility to ensure that previous pointer value is saved and + * freed. + * + * @param pedigree_leaf The leaf node to store into TLS. + */ +COMMON_SYSDEP +void __cilkrts_set_tls_pedigree_leaf(__cilkrts_pedigree* pedigree_leaf); + + +#if SUPPORT_GET_CURRENT_FIBER > 0 +/** + * @brief Get the cilk_fiber from TLS. + */ +COMMON_SYSDEP +cilk_fiber_sysdep* cilkos_get_tls_cilk_fiber(void); + +/** + * @brief Set the cilk_fiber in TLS. + * + * @param fiber The fiber to store into TLS. + */ +COMMON_SYSDEP +void cilkos_set_tls_cilk_fiber(cilk_fiber_sysdep* fiber); +#endif + +/** + * @brief Function for returning the current thread id. + * @warning This function is useful for debugging purposes only. + */ +COMMON_SYSDEP +void* cilkos_get_current_thread_id(void); + +/** @brief Return number of CPUs supported by this hardware, using whatever definition + of CPU is considered appropriate. */ +COMMON_SYSDEP int __cilkrts_hardware_cpu_count(void); + +/** @brief Get current value of timer */ +COMMON_SYSDEP unsigned long long __cilkrts_getticks(void); + +/* Machine instructions */ + +/// Stall execution for a few cycles. +COMMON_SYSDEP void __cilkrts_short_pause(void); +/// Wrapper for xchg instruction +COMMON_SYSDEP int __cilkrts_xchg(volatile int *ptr, int x); + +// Defines __cilkrts_fence - A macro for x86, a function call for other +// architectures +#include "os-fence.h" + +COMMON_SYSDEP void __cilkrts_sleep(void); ///< Sleep briefly +COMMON_SYSDEP void __cilkrts_yield(void); ///< Yield quantum + +/** + * @brief Gets environment variable 'varname' and copy its value into 'value'. + * + * If the entire value, including the null terminator fits into 'vallen' + * bytes, then returns the length of the value excluding the null. Otherwise, + * leaves the contents of 'value' undefined and returns the number of + * characters needed to store the environment variable's value, *including* + * the null terminator. + * + * @param value Buffer to store value. + * @param vallen Length of value buffer + * @param varname Name of the environment variable. + * @return Length of value buffer (excluding the null). + */ +COMMON_SYSDEP __STDNS size_t cilkos_getenv(char* value, __STDNS size_t vallen, + const char* varname); + +/** + * @brief Unrecoverable error: Print an error message and abort execution. + */ +COMMON_SYSDEP void cilkos_error(const char *fmt, ...); + +/** + * @brief Print a warning message and return. + */ +COMMON_SYSDEP void cilkos_warning(const char *fmt, ...); + +/** + * @brief Convert the user's specified stack size into a "reasonable" + * value for the current OS. + * + * @param specified_stack_size User-specified stack size. + * @return New stack size value, modified for the OS. + */ +COMMON_SYSDEP size_t cilkos_validate_stack_size(size_t specified_stack_size); + +/** + * @brief Atomic addition: computes *p += x. + * + * @param p Pointer to value to update + * @param x Value of x. + */ +COMMON_SYSDEP long cilkos_atomic_add(volatile long* p, long x); + +#ifdef _WIN32 + +/** + * @brief Windows-only low-level functions for processor groups. + */ +typedef struct _GROUP_AFFINITY GROUP_AFFINITY; + +/** + * @brief Probe the executing OS to see if it supports processor + * groups. These functions are expected to be available in Windows 7 + * or later. + */ +void win_init_processor_groups(void); + +unsigned long win_get_active_processor_count(unsigned short GroupNumber); +unsigned short win_get_active_processor_group_count(void); +int win_set_thread_group_affinity(/*HANDLE*/ void* hThread, + const GROUP_AFFINITY *GroupAffinity, + GROUP_AFFINITY* PreviousGroupAffinity); + +/** + * @brief Cleans up any state allocated in TLS. + * + * Only defined for Windows because Linux calls destructors for each + * thread-local variable. + */ +void __cilkrts_per_thread_tls_cleanup(void); + +#endif // _WIN32 + +__CILKRTS_END_EXTERN_C + +#endif // ! defined(INCLUDED_OS_DOT_H) diff --git a/libcilkrts/runtime/os_mutex-unix.c b/libcilkrts/runtime/os_mutex-unix.c new file mode 100644 index 00000000000..af398cdd089 --- /dev/null +++ b/libcilkrts/runtime/os_mutex-unix.c @@ -0,0 +1,193 @@ +/* os_mutex-unix.c -*-C-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +#include "os_mutex.h" +#include "bug.h" + +#include <stdlib.h> +#include <errno.h> +#include <pthread.h> + +// contains notification macros for VTune. +#include "cilk-ittnotify.h" + +/* + * OS Mutex functions. + * + * Not to be confused with the spinlock mutexes implemented in cilk_mutex.c + */ + +struct os_mutex { + pthread_mutex_t mutex; ///< On Linux, os_mutex is implemented with a pthreads mutex +}; + +// Unix implementation of the global OS mutex. This will be created by the +// first call to global_os_mutex_lock() and *NEVER* destroyed. On gcc-based +// systems there's no way to guarantee the ordering of constructors and +// destructors, so we can't be guaranteed that our destructor for a static +// object will be called *after* any static destructors that may use Cilk +// in the user's application +static struct os_mutex *global_os_mutex = NULL; + +/* Sometimes during shared library load malloc doesn't work. + To handle that case, preallocate space for one mutex. */ +static struct os_mutex static_mutex; +static int static_mutex_used; + +struct os_mutex *__cilkrts_os_mutex_create(void) +{ + int status; + struct os_mutex *mutex = (struct os_mutex *)malloc(sizeof(struct os_mutex)); + pthread_mutexattr_t attr; + + ITT_SYNC_CREATE(mutex, "OS Mutex"); + + if (!mutex) { + if (static_mutex_used) { + __cilkrts_bug("Cilk RTS library initialization failed"); + } else { + static_mutex_used = 1; + mutex = &static_mutex; + } + } + + status = pthread_mutexattr_init(&attr); + CILK_ASSERT (status == 0); +#if defined DEBUG || CILK_LIB_DEBUG +#ifdef PTHREAD_MUTEX_ERRORCHECK + status = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); +#else + status = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP); +#endif + CILK_ASSERT (status == 0); +#endif + status = pthread_mutex_init (&mutex->mutex, &attr); + CILK_ASSERT (status == 0); + pthread_mutexattr_destroy(&attr); + + return mutex; +} + +void __cilkrts_os_mutex_lock(struct os_mutex *p) +{ + int status; + status = pthread_mutex_lock (&p->mutex); + ITT_SYNC_ACQUIRED(p); + if (__builtin_expect(status, 0) == 0) + return; + if (status == EDEADLK) + __cilkrts_bug("Cilk runtime error: deadlock acquiring mutex %p\n", + p); + else + __cilkrts_bug("Cilk runtime error %d acquiring mutex %p\n", + status, p); +} + +int __cilkrts_os_mutex_trylock(struct os_mutex *p) +{ + int status; + status = pthread_mutex_trylock (&p->mutex); + return (status == 0); +} + +void __cilkrts_os_mutex_unlock(struct os_mutex *p) +{ + int status; + ITT_SYNC_RELEASING(p); + status = pthread_mutex_unlock (&p->mutex); + CILK_ASSERT(status == 0); +} + +void __cilkrts_os_mutex_destroy(struct os_mutex *p) +{ + pthread_mutex_destroy (&p->mutex); + if (p == &static_mutex) { + static_mutex_used = 0; + } else { + free(p); + } +} + +/* + * create_global_os_mutex + * + * Function used with pthread_once to initialize the global OS mutex. Since + * pthread_once requires a function which takes no parameters and has no + * return value, the global OS mutex will be stored in the static (global + * to the compilation unit) variable "global_os_mutex." + * + * + * global_os_mutex will never be destroyed. + */ +static void create_global_os_mutex(void) +{ + CILK_ASSERT(NULL == global_os_mutex); + global_os_mutex = __cilkrts_os_mutex_create(); +} + +void global_os_mutex_lock(void) +{ + // pthread_once_t used with pthread_once to guarantee that + // create_global_os_mutex() is only called once + static pthread_once_t global_os_mutex_is_initialized = PTHREAD_ONCE_INIT; + + // Execute create_global_os_mutex once in a thread-safe manner + // Note that create_global_os_mutex returns the mutex in the static + // (global to the module) variable "global_os_mutex" + pthread_once(&global_os_mutex_is_initialized, + create_global_os_mutex); + + // We'd better have allocated a global_os_mutex + CILK_ASSERT(NULL != global_os_mutex); + + // Acquire the global OS mutex + __cilkrts_os_mutex_lock(global_os_mutex); +} + +void global_os_mutex_unlock(void) +{ + // We'd better have allocated a global_os_mutex. This means you should + // have called global_os_mutex_lock() before calling + // global_os_mutex_unlock(), but this is the only check for it. + CILK_ASSERT(NULL != global_os_mutex); + + // Release the global OS mutex + __cilkrts_os_mutex_unlock(global_os_mutex); +} + +/* End os_mutex-unix.c */ diff --git a/libcilkrts/runtime/os_mutex.h b/libcilkrts/runtime/os_mutex.h new file mode 100644 index 00000000000..71d9eb14e51 --- /dev/null +++ b/libcilkrts/runtime/os_mutex.h @@ -0,0 +1,135 @@ +/* os_mutex.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** + * @file os_mutex.h + * + * @brief Portable interface to operating-system mutexes. + * + * Do not confuse os_mutex with Cilk runtime-specific spinlock mutexes. + */ + +#ifndef INCLUDED_OS_MUTEX_DOT_H +#define INCLUDED_OS_MUTEX_DOT_H + +#include <cilk/common.h> +#include "rts-common.h" + +__CILKRTS_BEGIN_EXTERN_C + +/// Opaque type +typedef struct os_mutex os_mutex; + +/** + * Allocate and initialize an os_mutex + * + * @return A pointer to the initialized os_mutex + */ +COMMON_SYSDEP os_mutex* __cilkrts_os_mutex_create(void); + +/** + * Acquire the os_mutex for exclusive use + * + * @param m The os_mutex that is to be acquired. + */ +COMMON_SYSDEP void __cilkrts_os_mutex_lock(os_mutex *m); + +/** + * Try to acquire the os_mutex. + * + * @param m The os_mutex to try to acquire + * @return 0 if the lock acquire failed + * @return nonzero if the lock was acquired + */ +COMMON_SYSDEP int __cilkrts_os_mutex_trylock(os_mutex *m); + +/** + * Release the os_mutex + * + * @param m The os_mutex that is to be released. + */ +COMMON_SYSDEP void __cilkrts_os_mutex_unlock(os_mutex *m); + +/** + * Release any resources and deallocate the os_mutex. + * + * @param m The os_mutex that is to be deallocated. + */ +COMMON_SYSDEP void __cilkrts_os_mutex_destroy(os_mutex *m); + +/** + * Acquire the global os_mutex for exclusive use. The global os_mutex + * will be initialized the first time this function is called in a + * thread-safe manner. + */ +COMMON_SYSDEP void global_os_mutex_lock(); + +/** + * Release the global os_mutex. global_os_mutex_lock() must have been + * called first. + */ +COMMON_SYSDEP void global_os_mutex_unlock(); + + +#ifdef _MSC_VER + +/** + * @brief Create the global OS mutex - Windows only. + * + * On Windows we use DllMain() to create the global OS mutex when cilkrts20.dll + * is loaded. As opposed to Linux/MacOS where we use pthread_once to implement + * a singleton since there are no guarantees about constructor or destructor + * ordering between shared objects. + */ +NON_COMMON void global_os_mutex_create(); + +/** + * @brief Destroy the global OS mutex - Windows only + * + * On Windows we use DllMain() to destroy the global OS mutex when + * cilkrts20.dll is unloaded. As opposed to Linux/MacOS where we cannot + * know when it's safe to destroy the global OS mutex since there are no + * guarantees about constructor or destructor ordering. + */ +NON_COMMON void global_os_mutex_destroy(); + +#endif // _MSC_VER + +__CILKRTS_END_EXTERN_C + +#endif // ! defined(INCLUDED_OS_MUTEX_DOT_H) diff --git a/libcilkrts/runtime/pedigrees.c b/libcilkrts/runtime/pedigrees.c new file mode 100644 index 00000000000..dee4d9cb411 --- /dev/null +++ b/libcilkrts/runtime/pedigrees.c @@ -0,0 +1,112 @@ +/* pedigrees.c -*-C-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2007-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + +#include "pedigrees.h" +#include "local_state.h" + +/************************************************************* + Pedigree API code. +*************************************************************/ + +/* + * C99 requires that every inline function with external linkage have one + * extern declaration in the program (with the inline definition in scope). + */ +COMMON_PORTABLE +extern void update_pedigree_on_leave_frame(__cilkrts_worker *w, + __cilkrts_stack_frame *sf); + +void __cilkrts_set_pedigree_leaf(__cilkrts_pedigree *leaf) +{ + __cilkrts_set_tls_pedigree_leaf(leaf); +} + +void load_pedigree_leaf_into_user_worker(__cilkrts_worker *w) +{ + __cilkrts_pedigree *pedigree_leaf; + CILK_ASSERT(w->l->type == WORKER_USER); + pedigree_leaf = __cilkrts_get_tls_pedigree_leaf(1); + w->pedigree = *pedigree_leaf; + + // Save a pointer to the old leaf. + // We'll need to restore it later. + CILK_ASSERT(w->l->original_pedigree_leaf == NULL); + w->l->original_pedigree_leaf = pedigree_leaf; + + __cilkrts_set_tls_pedigree_leaf(&w->pedigree); + + // Check that this new pedigree root has at least two values. + CILK_ASSERT(w->pedigree.parent); + CILK_ASSERT(w->pedigree.parent->parent == NULL); +} + +void save_pedigree_leaf_from_user_worker(__cilkrts_worker *w) +{ + CILK_ASSERT(w->l->type == WORKER_USER); + + // Existing leaf in tls should be for the current worker. + // This assert is expensive to check though. + // CILK_ASSERT(&w->pedigree == __cilkrts_get_tls_pedigree_leaf(0)); + CILK_ASSERT(w->l->original_pedigree_leaf); + + // w should finish with a pedigree node that points to + // the same root that we just looked up. + + // TODO: This assert should be valid. + // But we are removing it now to make exceptions (without pedigrees) work. + // Currently, reading the pedigree after an exception is caught + // fails because the pedigree chain not restored correctly. + // CILK_ASSERT(w->l->original_pedigree_leaf->next == w->pedigree.parent); + w->l->original_pedigree_leaf->rank = w->pedigree.rank; + + // Save that leaf pointer back into tls. + __cilkrts_set_tls_pedigree_leaf(w->l->original_pedigree_leaf); + // Null out worker's leaf for paranoia. + w->l->original_pedigree_leaf = NULL; +} + + + +/* + Local Variables: ** + c-file-style:"bsd" ** + c-basic-offset:4 ** + indent-tabs-mode:nil ** + End: ** +*/ diff --git a/libcilkrts/runtime/pedigrees.h b/libcilkrts/runtime/pedigrees.h new file mode 100644 index 00000000000..3f6ebb977f9 --- /dev/null +++ b/libcilkrts/runtime/pedigrees.h @@ -0,0 +1,130 @@ +/* pedigrees.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +#ifndef INCLUDED_PEDIGREES_DOT_H +#define INCLUDED_PEDIGREES_DOT_H + + +#include <cilk/common.h> +#include <internal/abi.h> + +#include "rts-common.h" +#include "global_state.h" +#include "os.h" + +__CILKRTS_BEGIN_EXTERN_C + +/** + * @file pedigrees.h + * + * @brief pedigrees.h declares common routines related to pedigrees + * and the pedigree API. + */ + + +/** + * @brief Sets the leaf pedigree node for the current user thread. + * + * A typical implementation stores this pedigree node in thread-local + * storage. + * + * Preconditions: + * - Current thread should be a user thread. + * + * @param leaf The pedigree node to store as a leaf. + */ +COMMON_PORTABLE +void __cilkrts_set_pedigree_leaf(__cilkrts_pedigree* leaf); + + +/** + * Load the pedigree leaf node from thread-local storage into the + * current user worker. This method should execute as a part of + * binding the user thread to a worker. + * + * Preconditions: + * + * - w should be the worker for the current thread + * - w should be a user thread. + */ +COMMON_PORTABLE +void load_pedigree_leaf_into_user_worker(__cilkrts_worker *w); + +/** + * Save the pedigree leaf node from the worker into thread-local + * storage. This method should execute as part of unbinding a user + * thread from a worker. + * + * Preconditions: + * + * - w should be the worker for the current thread + * - w should be a user thread. + */ +COMMON_PORTABLE +void save_pedigree_leaf_from_user_worker(__cilkrts_worker *w); + + + +/** + * Update pedigree for a worker when leaving a frame. + * + * If this is the frame of a spawn helper (indicated by the + * CILK_FRAME_DETACHED flag) we must update the pedigree. The + * pedigree points to nodes allocated on the stack. Failing to + * update it will result in a accvio/segfault if the pedigree is + * walked. This must happen for all spawn helper frames, even if + * we're processing an exception. + */ +COMMON_PORTABLE +inline void update_pedigree_on_leave_frame(__cilkrts_worker *w, + __cilkrts_stack_frame *sf) +{ + // Update the worker's pedigree information if this is an ABI 1 or later + // frame + if (CILK_FRAME_VERSION_VALUE(sf->flags) >= 1) + { + w->pedigree.rank = sf->spawn_helper_pedigree.rank + 1; + w->pedigree.parent = sf->spawn_helper_pedigree.parent; + } +} + + + +__CILKRTS_END_EXTERN_C + +#endif // ! defined(INCLUDED_PEDIGREES_DOT_H) diff --git a/libcilkrts/runtime/record-replay.cpp b/libcilkrts/runtime/record-replay.cpp new file mode 100644 index 00000000000..bc5a79f2411 --- /dev/null +++ b/libcilkrts/runtime/record-replay.cpp @@ -0,0 +1,770 @@ +/* record-replay.cpp -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2012-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + +/* + * Implementation of the record/replay functionality for Cilk Plus + */ + +#include <cstring> +#include <vector> +#include <stdlib.h> + +// clang is really strict about printf formats, so use the annoying integer +// printf macros. Unfortunately they're not avaiable on Windows +#ifdef _WIN32 +#define PRIu64 "llu" +#else +#define __STDC_FORMAT_MACROS 1 +#include <inttypes.h> +#endif + +#include "record-replay.h" +#include "bug.h" +#include "internal/abi.h" +#include "local_state.h" +#include "full_frame.h" +#include "global_state.h" +#include "cilk_malloc.h" +#include "os.h" // for cilkos_error() + +#if RECORD_ON_REPLAY +#pragma message ("*** Record on Replay is enabled!") +#endif + +// Defined to write sequence number to the logs. Note that you cannot +// diff logs with sequence numbers because the numbers may increment in +// different orders. +//#define INCLUDE_SEQUENCE_NUMBER 1 + +const int PED_VERSION = 1; // Log recording version + +// Log types +enum ped_type_t +{ + ped_type_unknown, + ped_type_steal, + ped_type_sync, + ped_type_orphaned, + ped_type_last // Flags end of the list +}; + +// Log type strings +#define PED_TYPE_STR_STEAL "Steal" +#define PED_TYPE_STR_SYNC "Sync" +#define PED_TYPE_STR_WORKERS "Workers" +#define PED_TYPE_STR_ORPHANED "Orphaned" + +#define PED_TYPE_SIZE 16 // Buffer size for the type of pedigree. Must + // hold largest pedigree record type string. +#define PEDIGREE_BUFF_SIZE 512 // Buffer size for the string representation + // of a pedigree. + +/** + * Data we store for a replay log entry + */ +typedef struct replay_entry_t +{ + uint64_t *m_reverse_pedigree; /**< Reverse pedigree for replay log entry */ + ped_type_t m_type; /**< Type of replay log entry */ + int16_t m_pedigree_len; /**< Number of terms in reverse pedigree */ + int16_t m_value; /**< Victim for STEALs, 0 if matching steal found for ORPHANs */ + + /** + * Load data read from the log into the entry + */ + bool load(const char *type, const char *pedigee_str, int32_t value1, int32_t value2) + { + // Convert the type into an enum + if (0 == strcmp(type, PED_TYPE_STR_STEAL)) + { + m_type = ped_type_steal; + m_value = (int16_t)value1; // Victim + } + else + { + m_value = -1; // Victim not valid + if (0 == strcmp(type, PED_TYPE_STR_SYNC)) + m_type = ped_type_sync; + else if (0 == strcmp(type, PED_TYPE_STR_ORPHANED)) + m_type = ped_type_orphaned; + else + { + m_type = ped_type_unknown; + return false; + } + } + + // Parse the pedigree + m_pedigree_len = 0; + + const char *p = pedigee_str; + char *end; + + uint64_t temp_pedigree[PEDIGREE_BUFF_SIZE/2]; + + while(1) + { + temp_pedigree[m_pedigree_len++] = (uint64_t)strtol(p, &end, 10); + if ('\0' == *end) + break; + p = end + 1; + } + + // Allocate memory to hold the pedigree. + // Copy the pedigree in reverse order since that's the order we'll + // traverse it + m_reverse_pedigree = + (uint64_t *)__cilkrts_malloc(sizeof(int64_t) * m_pedigree_len); + for (int n = 0; n < m_pedigree_len; n++) + m_reverse_pedigree[n] = temp_pedigree[(m_pedigree_len - 1) - n]; + + return true; + } + + /** + * Match this entry against the data supplied. This includes walking the + * pedigree from the specified node. + */ + bool match (ped_type_t type, const __cilkrts_pedigree *node, int victim = -1) + { + int i = 0; + + // If the type isn't what they're seeking, we don't have a match + if (type != m_type) + return false; + + // If we're looking for a STEAL, then the victim must match + if ((type == ped_type_steal) && (victim != m_value)) + return false; + + // Compare the current pedigree against what was recorded + while ((NULL != node) && (i < m_pedigree_len)) + { + // If we've got a pedigree rank difference, then we don't have + // a match + if (node->rank != m_reverse_pedigree[i]) + return false; + node = node->parent; + i++; + } + + // Make sure we exhausted both the pedigree chain and the recorded + // pedigree + return ((NULL == node) && (i == m_pedigree_len)); + } + + /** + * Advance to the next entry, skipping any ORPHANED records we didn't see + * a matching STEAL for + */ + replay_entry_t *next_entry() + { + replay_entry_t *entry = this; + + // You can't go beyond the end + if (ped_type_last == entry->m_type) + return entry; + + // Advance to the next entry + entry++; + + // Skip any ORPHANED records that don't have a matching steal. We + // initialized the value field to -1 for ORPHANED. After loading all + // the log data, we iterated through all the STEAL records setting the + // matching ORPHANED record's value field to 0. So if an ORPHANED + // record's value field is still -1, it doesn't have a matching STEAL + // record, and I don't know why we chose not to return from the + // spawned function. + while ((ped_type_orphaned == entry->m_type) && (-1 == entry->m_value)) + { + entry++; + } + + return entry; + } + + /** + * Release any allocated resources + */ + void unload() + { + __cilkrts_free(m_reverse_pedigree); + m_reverse_pedigree = NULL; + } + +} replay_entry_t; + +__CILKRTS_BEGIN_EXTERN_C + +/** + * Walk the pedigree and generate a string representation with underscores + * between terms. Currently does a recursive walk to generate a forward + * pedigree. + * + * @param p The buffer that is to be filled. Assumed to be PEDIGREE_BUFF_SIZE + * characters long + * @param pnode The initial pedigree term to be written. + * + * @return A pointer into the pedigree string buffer after a term has been + * written. + */ +static +char * walk_pedigree_nodes(char *p, const __cilkrts_pedigree *pnode) +{ + CILK_ASSERT(pnode); + if (pnode->parent) + { + p = walk_pedigree_nodes(p, pnode->parent); + p += sprintf(p, "_"); + } + + return p + sprintf(p, "%" PRIu64, pnode->rank); +} + +/** + * Write a record to a replay log file. + * + * @param w The worker we're writing the pedigree for. + * @param type The type of the pedigree record, as a string + * @param initial_node The initial pedigree node to be written, or NULL if + * there is no pedigree for this record type. + * @param i1 First integer value to be written to the record. + * @param i2 Second integer value to be written to the record. Only applies + * to STEAL records. Defaults to -1 (unused). The second value is always + * written to make parsing easier. + */ +static +void write_to_replay_log (__cilkrts_worker *w, const char *type, + const __cilkrts_pedigree *initial_node, + int i1 = -1, int i2 = -1) +{ + char pedigree[PEDIGREE_BUFF_SIZE]; + + // If we don't have an initial pedigree node, just use "0" to fill the slot + if (NULL == initial_node) + strcpy(pedigree, "0"); + else + walk_pedigree_nodes(pedigree, initial_node); + +#ifndef INCLUDE_SEQUENCE_NUMBER + // Simply write the record + fprintf(w->l->record_replay_fptr, "%s %s %d %d\n", + type, pedigree, i1, i2); +#else + // Write the record with a sequence number. The sequence number should + // always be the last term, and ignored on read + + static long volatile seq_num = 0; + long write_num; + + // Atomic increment functions are compiler/OS-specific +#ifdef _WIN32 + write_num = _InterlockedIncrement(&seq_num); +#else /* GCC */ + write_num = __sync_add_and_fetch(&seq_num, 1); +#endif // _WIN32 + + fprintf(w->l->record_replay_fptr, "%s %s %d %d %ld\n", + type, pedigree, i1, i2, write_num); +#endif // INCLUDE_SEQUENCE_NUMBER + + fflush(w->l->record_replay_fptr); +} + +/** + * Record data for a successful steal. + * + * The pedigree for a STEAL record is the pedigree of the stolen frame. + * + * @note It's assumed that replay_record_steal() has already checked that we're + * recording a log and that the record/replay functionality has not been + * compiled out. + * + * @param w The worker stealing a frame. + * @param victim_id The ID of the worker which had it's frame stolen. + */ +void replay_record_steal_internal(__cilkrts_worker *w, int32_t victim_id) +{ + // Follow the pedigree chain using worker's stack frame + CILK_ASSERT(w->l->next_frame_ff); + CILK_ASSERT(w->l->next_frame_ff->call_stack); + + // Record steal: STEAL pedigree victim_id thief_id + write_to_replay_log (w, PED_TYPE_STR_STEAL, + &(w->l->next_frame_ff->call_stack->parent_pedigree), + victim_id); +} + +/** + * Record data for the worker that continues from a sync + * + * The pedigree for a SYNC record is the pedigree at the sync. + * + * @note It's assumed that replay_record_sync() has already checked that we're + * recording a log and that the record/replay functionality has not been + * compiled out. + * + * @param w The worker continuing from a sync. + */ +void replay_record_sync_internal(__cilkrts_worker *w) +{ + // Record sync: SYNC pedigree last_worker_id + write_to_replay_log (w, PED_TYPE_STR_SYNC, &w->pedigree); +} + +/** + * Record the pedigree of an attempt to return to a stolen parent + * + * The pedigree for an ORPHANED record is the pedigree of our parent + * + * @note It's assumed that replay_record_orphaned() has already checked that + * we're recording a log and that the record/replay functionality has not + * been compiled out. + * + * @param w The worker continuing noting that it has been orphaned. + */ +void replay_record_orphaned_internal(__cilkrts_worker *w) +{ + // Record steal: ORPHANED pedigree self + write_to_replay_log (w, PED_TYPE_STR_ORPHANED, w->pedigree.parent); +} + +/** + * Attempt to match a SYNC record. We have a match when this worker was + * recorded returning from the current call to __cilkrts_sync() with the + * same pedigree and this was the worker that continued from the sync, since + * it was the last to sync. + * + * If we find a match, the caller is expected to stall it is the last worker + * to reach a sync so it will be the worker to continue from the sync. + * + * @note It's assumed that replay_match_sync_pedigree() has already returned + * if we're not replaying a log, or if record/replay functionality has + * been compiled out. + * + * @param w The worker we're checking to see if we've got a match + */ +int replay_match_sync_pedigree_internal(__cilkrts_worker *w) +{ + // Return true if we have a match + if (w->l->replay_list_entry->match(ped_type_sync, &w->pedigree)) + return 1; + else + return 0; +} + +/** + * Advance to the next log entry from a SYNC record. Consume the current + * SYNC record on this worker and advance to the next one. + * + * @note It's assumed that replay_advance_from_sync() has already returned if + * we're not replaying a log, or if record/replay functionality has been + * compiled out. + * + * @param w The worker whose replay log we're advancing. + */ +void replay_advance_from_sync_internal (__cilkrts_worker *w) +{ + // The current replay entry must be a SYNC + CILK_ASSERT(ped_type_sync == w->l->replay_list_entry->m_type); + + // Advance to the next entry + w->l->replay_list_entry = w->l->replay_list_entry->next_entry(); +} + +/** + * Called from random_steal() to override the ID of the randomly chosen victim + * worker which this worker will attempt to steal from. Returns the worker id + * of the next victim this worker was recorded stealing from, or -1 if the + * next record in the log is not a STEAL. + * + * @note This call does NOT attempt to match the pedigree. That will be done + * by replay_match_victim_pedigree() after random_steal() has locked the victim + * worker. + * + * @param w The __cilkrts_worker we're executing on. The worker's replay log + * is checked for a STEAL record. If we've got one, the stolen worker ID is + * returned. + * + * @return -1 if the next record is not a STEAL + * @return recorded stolen worker ID if we've got a matching STEAL record + */ +int replay_get_next_recorded_victim_internal(__cilkrts_worker *w) +{ + // If the next record isn't a STEAL, abort the attempt to steal work + if (ped_type_steal != w->l->replay_list_entry->m_type) + return -1; + + // Return the victim's worker ID from the STEAL record. We'll check + // the pedigree after random_steal has locked the victim worker. + return w->l->replay_list_entry->m_value; +} + +/** + * Called from random_steal() to determine if we have a STEAL record that + * matches the pedigree at the head of the victim worker. If we do have a + * match, the STEAL record is consumed. + * + * @note It's assumed that replay_match_victim_pedigree() has already returned if + * we're not replaying a log, or if record/replay functionality has been + * compiled out. + * + * @return 1 if we have a match + * @return 0 if the current replay record isn't a STEAL record, or the victim + * isn't correct, or the pedigree doesn't match. + */ +int replay_match_victim_pedigree_internal(__cilkrts_worker *w, __cilkrts_worker *victim) +{ + // If we don't have a match, return 0 + if (! w->l->replay_list_entry->match(ped_type_steal, + &((*victim->head)->parent_pedigree), + victim->self)) + return 0; + + // Consume this entry + w->l->replay_list_entry = w->l->replay_list_entry->next_entry(); + + // Return success + return 1; +} + +/** + * If the frame we're about to return to was recorded as being stolen, + * stall until it is. + * + * @note It's assumed that replay_wait_for_steal_if_parent_was_stolen() has + * already returned if we're not replaying a log, or if record/replay + * functionality has been compiled out. + * + * @param w The worker we're executing on. + */ +void replay_wait_for_steal_if_parent_was_stolen_internal(__cilkrts_worker *w) +{ + // If our parent wasn't recorded orphanen, return now + if (! w->l->replay_list_entry->match (ped_type_orphaned, + w->pedigree.parent)) + return; + + // Stall until our parent is stolen. Note that we're comparing head + // and tail, not head and exc. The steal is not completed until tail + // is modified. + while (!((w->tail - 1) < w->head)) + __cilkrts_sleep(); + + // Consume the entry + w->l->replay_list_entry = w->l->replay_list_entry->next_entry(); +} + +/** + * Allocate memory for the list of logged events. + * + * This function will read through the file and count the number of records + * so it can estimate how big a buffer to allocate for the array or replay + * entries. It will then rewind the file to the beginning so it can be + * loaded into memory. + * + * @param w The worker we're loading the file for. + * @param f The file of replay data we're scanning. + */ +static +void allocate_replay_list(__cilkrts_worker *w, FILE *f) +{ + // Count the number of entries - yeah, it's a hack, but it lets me + // allocate the space all at once instead of in chunks + char buf[1024]; + int entries = 1; // Include "LAST" node + + while (! feof(f)) + { + if (fgets(buf, 1024, f)) + { + // Skip the Workers record - should only be in file for Worker 0 + if (0 != strncmp(PED_TYPE_STR_WORKERS, buf, sizeof(PED_TYPE_STR_WORKERS)-1)) + entries++; + } + } + + w->l->replay_list_root = + (replay_entry_t *)__cilkrts_malloc(entries * sizeof(replay_entry_t)); + w->l->replay_list_root[entries - 1].m_type = ped_type_last; + + // Reset the file to the beginning + rewind(f); +} + +/** + * Load the replay log for a worker into memory. + * + * @param w The worker we're loading the replay for. + */ +static +void load_recorded_log(__cilkrts_worker *w) +{ + char ped_type[PED_TYPE_SIZE]; + char ped_str[PEDIGREE_BUFF_SIZE]; + int32_t i1 = -1, i2 = -1; + int fret; + char local_replay_file_name[512]; + FILE *f; + + // Open the log for reading + sprintf(local_replay_file_name, "%s%d.cilklog", w->g->record_replay_file_name, w->self); + f = fopen(local_replay_file_name, "r"); + + // Make sure we found a log! + CILK_ASSERT (NULL != f); + + // Initialize the replay_list + allocate_replay_list(w, f); + replay_entry_t *entry = w->l->replay_list_root; + + // Read the data out and add it to our tables + while (! feof(f)) + { +#ifndef INCLUDE_SEQUENCE_NUMBER + fret = fscanf(f, "%s %s %d %d\n", ped_type, ped_str, &i1, &i2); + if(EOF == fret) + break; + + // We must have read 4 fields + CILK_ASSERT(4 == fret); +#else + int32_t write_num; + fret = fscanf(f, "%s %s %d %d %d\n", ped_type, ped_str, + &i1, &i2, &write_num); + if(EOF == fret) + break; + + // We must have read 5 fields + CILK_ASSERT(5 == fret); +#endif // INCLUDE_SEQUENCE_NUMBER + + // Load the data into the entry + if (0 == strcmp(ped_type, PED_TYPE_STR_WORKERS)) + { + // Verify we're replaying with the same number of workers we recorded with + if (i1 != w->g->P) + { + // Fatal error - does not return + cilkos_error("Cannot continue replay: number of workers(%d) doesn't match " + "that from the recording(%d).\n", w->g->P, i1); + } + + // Verify that we understand this version of the pedigree file + if (PED_VERSION != i2) + { + // Fatal error - does not return + cilkos_error("Pedigree file version %d doesn't match current " + "version %d - cannot continue.\n", + i2, PED_VERSION); + } + } + else + { + entry->load(ped_type, ped_str, i1, i2); + entry++; + } + } + + // Make sure we've filled the allocated memory. We initialized the last + // entry in + CILK_ASSERT(ped_type_last == entry->m_type); + w->l->replay_list_entry = w->l->replay_list_root; + + // Close the log and return + fclose(f); +} + +/** + * Scan a recorded log to match STEALs againsted ORPHANED records. + * + * @param g Cilk Runtime global state. Passed to access the worker array so + * we can scan a worker's ORPHANED entries for one that matches a STEAL entry. + * @param entry The root of a replay_list for a worker. + */ +static +void scan_for_matching_steals(global_state_t *g, replay_entry_t *entry) +{ + // Iterate over all of the entries + while (ped_type_last != entry->m_type) + { + // Look for STEALs. That will tell us which worker the frame was + // stolen from + if (ped_type_steal == entry->m_type) + { + bool found = false; + + // Validate the worker ID and make sure we've got a list + CILK_ASSERT((entry->m_value >= 0) && (entry->m_value < g->total_workers)); + replay_entry_t *victim_entry = g->workers[entry->m_value]->l->replay_list_root; + CILK_ASSERT(NULL != victim_entry); + + // Scan the victim's list for the matching ORPHANED record + while ((ped_type_last != victim_entry->m_type) && ! found) + { + if (ped_type_orphaned == victim_entry->m_type) + { + if (entry->m_pedigree_len == victim_entry->m_pedigree_len) + { + if (0 == memcmp(entry->m_reverse_pedigree, + victim_entry->m_reverse_pedigree, + entry->m_pedigree_len * sizeof(int64_t))) + { + // Note that this ORPHANED record has a matching steal + victim_entry->m_value = 0; + found = true; + } + } + } + victim_entry++; + } + } + entry++; + } +} + + +/* + * Initialize per-worker data for record or replay - See record-replay.h + * for full routine header. + */ +void replay_init_workers(global_state_t *g) +{ + int i; + char worker_file_name[512]; + + // If we're not recording or replaying a log, we're done. All of the + // fields in the global_state_t or local_state_t are already initialized + // to default values. + if (RECORD_REPLAY_NONE == g->record_or_replay) + return; + + // If we're replaying a log, read each worker's log and construct the + // in-memory log + if (REPLAY_LOG == g->record_or_replay) + { + // Read all of the data + for (i = 0; i < g->total_workers; ++i) + { + // This function will also initialize and fill the worker's + // replay list + load_recorded_log(g->workers[i]); + } + + // Scan for orphans with no matching steal. Mark them so they'll be + // skipped as we advance through the log. + for (i = 0; i < g->total_workers; ++i) + { + scan_for_matching_steals(g, g->workers[i]->l->replay_list_root); + } + + // If we're recording the logs while replaying, create the log files. + // This will only be used for debugging. Create the logs in the + // current directory. It should be as good a place as any... +#if RECORD_ON_REPLAY + for(i = 0; i < g->total_workers; ++i) + { + __cilkrts_worker *w = g->workers[i]; + sprintf(worker_file_name, "replay_log_%d.cilklog", w->self); + w->l->record_replay_fptr = fopen(worker_file_name, "w+"); + CILK_ASSERT(NULL != w->l->record_replay_fptr); + } + + // Record the number of workers, file version in Worker 0's file + write_to_replay_log (g->workers[0], PED_TYPE_STR_WORKERS, NULL, g->P, PED_VERSION); +#endif // RECORD_ON_REPLAY + } + + // If we're recording, create the log files + if (RECORD_LOG == g->record_or_replay) + { + for(i = 0; i < g->total_workers; ++i) + { + __cilkrts_worker *w = g->workers[i]; + sprintf(worker_file_name, "%s%d.cilklog", + g->record_replay_file_name, + w->self); + w->l->record_replay_fptr = fopen(worker_file_name, "w+"); + CILK_ASSERT(NULL != w->l->record_replay_fptr); + } + + // Record the number of workers, file version in Worker 0's file + write_to_replay_log (g->workers[0], PED_TYPE_STR_WORKERS, NULL, g->P, PED_VERSION); + } +} + +/* + * Do any necessary cleanup for the logs - See record-replay.h for full + * routine header. + */ +void replay_term(global_state_t *g) +{ + // Free memory for the record/replay log file name, if we've got one + if (g->record_replay_file_name) + __cilkrts_free(g->record_replay_file_name); + + // Per-worker cleanup + for(int i = 0; i < g->total_workers; ++i) + { + __cilkrts_worker *w = g->workers[i]; + + // Close the log files, if we've opened them + if(w->l->record_replay_fptr) + fclose(w->l->record_replay_fptr); + + if (w->l->replay_list_root) + { + // We should have consumed the entire list + CILK_ASSERT(ped_type_last == w->l->replay_list_entry->m_type); + + replay_entry_t *entry = w->l->replay_list_root; + while (ped_type_last != entry->m_type) + { + // Free the pedigree memory for each entry + entry->unload(); + entry++; + } + __cilkrts_free(w->l->replay_list_root); + w->l->replay_list_root = NULL; + w->l->replay_list_entry = NULL; + } + } +} + +__CILKRTS_END_EXTERN_C diff --git a/libcilkrts/runtime/record-replay.h b/libcilkrts/runtime/record-replay.h new file mode 100644 index 00000000000..c1c5a68f579 --- /dev/null +++ b/libcilkrts/runtime/record-replay.h @@ -0,0 +1,432 @@ +/* record_replay.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2012-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + +/** + * @file record-replay.h + * + * @brief record-replay.h and .cpp encapsulate most of the functionality to + * record and play back a Cilk Plus application. + * + * Recording is directed by the setting of the CILK_RECORD_LOG environment + * variable. If it's defined, the value specifies the root we'll use to + * generate files for each worker using the following format string: + * "%s%d.cilklog", where the integer is the value of w->self. + * + * Replay is directed by the setting of the CILK_REPLAY_LOG environment + * variable, interpreted the same way as CILK_RECORD_LOG. If both + * CILK_RECORD_LOG and CILK_REPLAY_LOG are defined, a warning will be given + * and the attempt to record a log will be ignored. + * + * Recording is relatively straightforward. We write all information about a + * worker to a per-worker file. + * + * Each pedigree record consists of the following fields. All fields must be + * present in every record to make parsing easy. + * - Type - A string identifying the pedigree record. See the PED_TYPE_STR_ + * macros for the currently defined values. + * - Pedigree - A string of pedigree values, with underscores between + * adjacent values. + * - i1 - Record type-specific value. -1 if not used. + * - i2 - Record type-specific value. -1 if not used. + * + * WORKERS record - only written to the file for worker 0. Note that this is + * the first worker in the workers array. Worker 0 is the first system worker, + * *NOT* a user worker. + * - Type: "Workers" + * - Pedigree: Always "0" - ignored + * - i1: Number of workers (g->P) when we recorded the log. A mismatch when + * we attempt to replay the log will result in aborting the execution. + * - i2: Log version number - Specified by PED_VERSION in record-replay.cpp + * + * STEAL record - written after a successful steal. + * - Type: "Steal" + * - Pedigree: Pedigree of stolen frame + * - i1: Worker the frame was stolen from + * - i2: -1 + * + * SYNC record - written after a worker continues from a sync. + * - Type: "Sync" + * - Pedigree: Pedigree of sync. Note that this is the pedigree *before* + * the pedigree in incremented in setup_for_execution_pedigree(). + * - i1: -1 + * - i2: -1 + * + * ORPHANED record - saved on a return to a stolen parent. + * - Type: "Orphaned" + * - Pedigree: Pedigree of the parent frame *before* the pedigree is + * incremented by the return + * - i1: -1 + * - i2: -1 + * + * On replay, the data is loaded into a per-worker array, and the data is + * consumed in order as needed. + */ + +#ifndef INCLUDED_RECORD_REPLAY_DOT_H +#define INCLUDED_RECORD_REPLAY_DOT_H + +#include "cilk/common.h" +#include "global_state.h" + +/** + * Define CILK_RECORD_REPLAY to enable record/replay functionality. If + * CILK_RECORD_REPLAY is not defined, all of the record/replay functions in + * record-replay.h will be stubbed out. Since they're declared as inline, + * functions, the resulting build should have no performance impact due to + * the implementation or record/replay. + */ + #define CILK_RECORD_REPLAY 1 + +/** + * Define RECORD_ON_REPLAY=1 to write logs when we're replaying a log. This + * should only be needed when debugging the replay functionality. This should + * always be defined as 0 when record-replay.h is checked in. + */ +#define RECORD_ON_REPLAY 0 + +__CILKRTS_BEGIN_EXTERN_C + +#ifdef CILK_RECORD_REPLAY +// Declarations of internal record/replay functions. The inlined versions +// further down do some preliminary testing (like if we're not recording or +// replaying) and will stub out the functionality if we've compiled out the +// record/replay feature +int replay_match_sync_pedigree_internal(__cilkrts_worker *w); +void replay_wait_for_steal_if_parent_was_stolen_internal(__cilkrts_worker *w); +void replay_record_steal_internal(__cilkrts_worker *w, int32_t victim_id); +void replay_record_sync_internal(__cilkrts_worker *w); +void replay_record_orphaned_internal(__cilkrts_worker *w); +int replay_match_victim_pedigree_internal(__cilkrts_worker *w, __cilkrts_worker *victim); +void replay_advance_from_sync_internal (__cilkrts_worker *w); +int replay_get_next_recorded_victim_internal(__cilkrts_worker *w); +#endif // CILK_RECORD_REPLAY + +// Publically defined record/replay API + +/** + * If we're replaying a log, wait for our parent to be stolen if it was when + * the log was recorded. If record/replay is compiled out, this is a noop. + * + * @param w The __cilkrts_worker we're executing on. The worker's replay + * list will be checked for a ORPHANED record with a matching pedigree. If + * there is a match, the ORPHANED record will be consumed. + */ +#ifdef CILK_RECORD_REPLAY +__CILKRTS_INLINE +void replay_wait_for_steal_if_parent_was_stolen(__cilkrts_worker *w) +{ + // Only check if we're replaying a log + if (REPLAY_LOG == w->g->record_or_replay) + replay_wait_for_steal_if_parent_was_stolen_internal(w); +} +#else +__CILKRTS_INLINE +void replay_wait_for_steal_if_parent_was_stolen(__cilkrts_worker *w) +{ + // If record/replay is disabled, we never wait +} +#endif // CILK_RECORD_REPLAY + +/** + * Called from random_steal() to override the ID of the randomly chosen victim + * worker which this worker will attempt to steal from. Returns the worker id + * of the next victim this worker was recorded stealing from, or -1 if the + * next record in the log is not a STEAL. + * + * @note This call does NOT attempt to match the pedigree. That will be done + * by replay_match_victim_pedigree() after random_steal() has locked the victim + * worker. + * + * @param w The __cilkrts_worker we're executing on. The worker's replay log + * is checked for a STEAL record. If we've got one, the stolen worker ID is + * returned. + * @param id The randomly chosen victim worker ID. If we're not replaying a + * log, or if record/replay has been compiled out, this is the value that + * will be returned. + * + * @return id if we're not replaying a log + * @return -1 if the next record is not a STEAL + * @return recorded stolen worker ID if we've got a matching STEAL record + */ +#ifdef CILK_RECORD_REPLAY +__CILKRTS_INLINE +int replay_get_next_recorded_victim(__cilkrts_worker *w, int id) +{ + // Only check if we're replaying a log + if (REPLAY_LOG == w->g->record_or_replay) + return replay_get_next_recorded_victim_internal(w); + else + return id; +} +#else +__CILKRTS_INLINE +int replay_get_next_recorded_victim(__cilkrts_worker *w, int id) +{ + // Record/replay is disabled. Always return the original worker id + return id; +} +#endif // CILK_RECORD_REPLAY + +/** + * Initialize per-worker data for record/replay. A noop if record/replay + * is disabled, or if we're not recording or replaying anything. + * + * If we're recording a log, this will ready us to create the per-worker + * logs. + * + * If we're replaying a log, this will read the logs into the per-worker + * structures. + * + * @param g Cilk runtime global state + */ +void replay_init_workers(global_state_t *g); + +/** + * Record a record on a successful steal. A noop if record/replay is + * diabled, or if we're not recording anything + * + * @param w The __cilkrts_worker we're executing on. The pedigree of + * the stolen frame will be walked to generate the STEAL record. + * + * @param victim_id The worker ID of the worker w stole from. + */ +#ifdef CILK_RECORD_REPLAY +__CILKRTS_INLINE +void replay_record_steal(__cilkrts_worker *w, int32_t victim_id) +{ +#if RECORD_ON_REPLAY + // If we're recording on replay, write the record if we're recording or + // replaying + if (RECORD_REPLAY_NONE == w->g->record_or_replay) + return; +#else + // Only write the record if we're recording + if (RECORD_LOG != w->g->record_or_replay) + return; +#endif + + replay_record_steal_internal(w, victim_id); +} +#else +__CILKRTS_INLINE +void replay_record_steal(__cilkrts_worker *w, int32_t victim_id) +{ +} +#endif // CILK_RECORD_REPLAY + +/** + * Record a record when continuing after a sync. A noop if record/replay is + * diabled, or if we're not recording anything, or if the sync was abandoned, + * meaning this isn't the worker that continues from the sync. + * + * @param w The __cilkrts_worker for we're executing on. The pedigree of + * the sync-ing frame will be walked to generate the SYNC record. + * + * @param continuing True if this worker will be continuing from the + * cilk_sync. A SYNC record will only be generated if continuing is true. + */ +#ifdef CILK_RECORD_REPLAY +__CILKRTS_INLINE +void replay_record_sync(__cilkrts_worker *w, int continuing) +{ + // If this was not the last worker to the syn, return + if (! continuing) + return; + +#if RECORD_ON_REPLAY + // If we're recording on replay, write the record if we're recording or + // replaying + if (RECORD_REPLAY_NONE == w->g->record_or_replay) + return; +#else + // Only write the record if we're recording + if (RECORD_LOG != w->g->record_or_replay) + return; +#endif + + replay_record_sync_internal(w); +} +#else +__CILKRTS_INLINE +void replay_record_sync(__cilkrts_worker *w, int abandoned) +{ +} +#endif // CILK_RECORD_REPLAY + +/** + * Record a record on a return to a stolen parent. A noop if record/replay is + * diabled, or if we're not recording anything. + * + * @param w The __cilkrts_worker for we're executing on. The pedigree of the + * frame that has discovered that its parent has been stolken will be walked + * to generate the ORPHANED record. + */ +#ifdef CILK_RECORD_REPLAY +__CILKRTS_INLINE +void replay_record_orphaned(__cilkrts_worker *w) +{ +#if RECORD_ON_REPLAY + // If we're recording on replay, write the record if we're recording or + // replaying + if (RECORD_REPLAY_NONE == w->g->record_or_replay) + return; +#else + // Only write the record if we're recording + if (RECORD_LOG != w->g->record_or_replay) + return; +#endif + + replay_record_orphaned_internal(w); +} +#else +__CILKRTS_INLINE +void replay_record_orphaned(__cilkrts_worker *w) +{ +} +#endif // CILK_RECORD_REPLAY + +/** + * Test whether the frame at the head of the victim matches the pedigree of + * the frame that was recorded being stolen. Called in random steal to verify + * that we're about to steal the correct frame. + * + * @param w The __cilkrts_worker for we're executing on. The current worker + * is needed to find the replay entry to be checked. + * + * @param victim The __cilkrts_worker for we're proposing to steal a frame + * from. The victim's head entry is + * is needed to find the replay entry to be checked. + * + * @return 0 if we're replaying a log and the victim's pedigree does NOT match + * the next frame the worker is expected to steal. + * + * @return 1 in all other cases to indicate that the steal attempt should + * continue + */ +#ifdef CILK_RECORD_REPLAY +__CILKRTS_INLINE +int replay_match_victim_pedigree(__cilkrts_worker *w, __cilkrts_worker *victim) +{ + // We're not replaying a log. The victim is always acceptable + if (REPLAY_LOG != w->g->record_or_replay) + return 1; + + // Return 1 if the victim's pedigree matches the frame the worker stole + // when we recorded the log + return replay_match_victim_pedigree_internal(w, victim); +} +#else +__CILKRTS_INLINE +int replay_match_victim_pedigree(__cilkrts_worker *w, __cilkrts_worker *victim) +{ + // Record/replay is disabled. The victim is always acceptable + return 1; +} +#endif // CILK_RECORD_REPLAY + +/** + * Test whether the current replay entry is a sync record matching the + * worker's pedigree. + * + * @param w The __cilkrts_worker for we're executing on. + * + * @return 1 if the current replay entry matches the current pedigree. + * @return 0 if there's no match, or if we're not replaying a log. + */ +#ifdef CILK_RECORD_REPLAY +__CILKRTS_INLINE +int replay_match_sync_pedigree(__cilkrts_worker *w) +{ + // If we're not replaying, assume no match + if (REPLAY_LOG != w->g->record_or_replay) + return 0; + + return replay_match_sync_pedigree_internal(w); +} +#else +__CILKRTS_INLINE +int replay_match_sync_pedigree(__cilkrts_worker *w) +{ + // Record/replay is disabled. Assume no match + return 0; +} +#endif + +/** + * Marks a sync record seen, advancing to the next record in the replay list. + * + * This function will only advance to the next record if: + * - Record/replay hasn't been compiled out AND + * - We're replaying a log AND + * - A match was found AND + * - The sync is not being abandoned + * + * @param w The __cilkrts_worker for we're executing on. + * @param match_found The value returned by replay_match_sync_pedigree(). If + * match_found is false, nothing is done. + * @param continuing Flag indicating whether this worker will continue from + * the sync (it's the last worker to the sync) or if it will abandon the work + * and go to the scheduling loop to look for more work it can steal. + */ +#ifdef CILK_RECORD_REPLAY +__CILKRTS_INLINE +void replay_advance_from_sync(__cilkrts_worker *w, int match_found, int continuing) +{ + // If we're replaying a log, and the current sync wasn't abandoned, and we + // found a match in the log, mark the sync record seen. + if ((REPLAY_LOG == w->g->record_or_replay) && match_found && continuing) + replay_advance_from_sync_internal(w); +} +#else +__CILKRTS_INLINE +void replay_advance_from_sync(__cilkrts_worker *w, int match_found, int continuing) +{ +} +#endif + +/** + * Release any resources used to read or write a replay log. + * + * @param g Cilk runtime global state + */ +void replay_term(global_state_t *g); + +__CILKRTS_END_EXTERN_C + +#endif // ! defined(INCLUDED_RECORD_REPLAY_DOT_H) diff --git a/libcilkrts/runtime/reducer_impl.cpp b/libcilkrts/runtime/reducer_impl.cpp new file mode 100644 index 00000000000..f20b9bc4592 --- /dev/null +++ b/libcilkrts/runtime/reducer_impl.cpp @@ -0,0 +1,1012 @@ +/* reducer_impl.cpp -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Patents Pending, Intel Corporation. + **************************************************************************/ + +/** + * Support for reducers + */ + +// ICL: Don't complain about conversion from pointer to same-sized integral type +// in hashfun. That's why we're using size_t +#ifdef _WIN32 +# pragma warning(disable: 1684) +#endif + +#include "reducer_impl.h" +#include "scheduler.h" +#include "bug.h" +#include "os.h" +#include "global_state.h" +#include "frame_malloc.h" + +#include "cilk/hyperobject_base.h" +#include "cilktools/cilkscreen.h" +#include "internal/abi.h" + +#if REDPAR_DEBUG > 0 +#include <stdio.h> +#include <stdlib.h> +#endif + + +#define DBG if(0) // if(1) enables some internal checks + +// Check that w is the currently executing worker. This method is a +// no-op unless the debug level is set high enough. +static inline void verify_current_wkr(__cilkrts_worker *w) +{ +#if REDPAR_DEBUG >= 5 + __cilkrts_worker* tmp = __cilkrts_get_tls_worker(); + if (w != tmp) { + fprintf(stderr, "W=%d, actual=%d... missing a refresh....\n", + w->self, + tmp->self); + } + CILK_ASSERT(w == tmp); // __cilkrts_get_tls_worker()); +#endif +} + +// Suppress clang warning that the expression result is unused +#if defined(__clang__) && (! defined(__INTEL_COMPILER)) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunused-value" +#endif // __clang__ + +/// Helper class to disable and re-enable Cilkscreen +struct DisableCilkscreen +{ + DisableCilkscreen () { __cilkscreen_disable_checking(); } + ~DisableCilkscreen () { __cilkscreen_enable_checking(); } +}; + +/// Helper class to enable and re-disable Cilkscreen +struct EnableCilkscreen +{ + EnableCilkscreen () { __cilkscreen_enable_checking(); } + ~EnableCilkscreen () { __cilkscreen_disable_checking(); } +}; + +#if defined(__clang__) && (! defined(__INTEL_COMPILER)) +# pragma clang diagnostic pop +#endif // __clang__ + +/** + * @brief Element for a hyperobject + */ +struct elem { + void *key; ///< Shared key for this hyperobject + __cilkrts_hyperobject_base *hb; ///< Base of the hyperobject. + void *view; ///< Strand-private view of this hyperobject + /// Destroy and deallocate the view object for this element and set view to + /// null. + void destroy(); + + /// Returns true if this element contains a leftmost view. + bool is_leftmost() const; +}; + +/** Bucket containing at most NMAX elements */ +struct bucket { + /// Size of the array of elements for this bucket + size_t nmax; + + /** + * We use the ``struct hack'' to allocate an array of variable + * dimension at the end of the struct. However, we allocate a + * total of NMAX+1 elements instead of NMAX. The last one always + * has key == 0, which we use as a termination criterion + */ + elem el[1]; +}; + +/** + * Class that implements the map for reducers so we can find the + * view for a strand. + */ +struct cilkred_map { + /** Handy pointer to the global state */ + global_state_t *g; + + /** Number of elements in table */ + size_t nelem; + + /** Number of buckets */ + size_t nbuckets; + + /** Array of pointers to buckets */ + bucket **buckets; + + /** Set true if merging (for debugging purposes) */ + bool merging; + + /** Set true for leftmost reducer map */ + bool is_leftmost; + + /** @brief Return element mapped to 'key' or null if not found. */ + elem *lookup(void *key); + + /** + * @brief Insert key/value element into hash map without rehashing. + * Does not check for duplicate key. + */ + elem *insert_no_rehash(__cilkrts_worker *w, + void *key, + __cilkrts_hyperobject_base *hb, + void *value); + + /** + * @brief Insert key/value element into hash map, rehashing if necessary. + * Does not check for duplicate key. + */ + inline elem *rehash_and_insert(__cilkrts_worker *w, + void *key, + __cilkrts_hyperobject_base *hb, + void *value); + + /** @brief Grow bucket by one element, reallocating bucket if necessary */ + static elem *grow(__cilkrts_worker *w, bucket **bp); + + /** @brief Rehash a worker's reducer map */ + void rehash(__cilkrts_worker *); + + /** + * @brief Returns true if a rehash is needed due to the number of elements that + * have been inserted. + */ + inline bool need_rehash_p() const; + + /** @brief Allocate and initialize the buckets */ + void make_buckets(__cilkrts_worker *w, size_t nbuckets); + + /** + * Specify behavior when the same key is present in both maps passed + * into merge(). + */ + enum merge_kind + { + MERGE_UNORDERED, ///< Assertion fails + MERGE_INTO_LEFT, ///< Merges the argument from the right into the left + MERGE_INTO_RIGHT ///< Merges the argument from the left into the right + }; + + /** + * @brief Merge another reducer map into this one, destroying the other map in + * the process. + */ + __cilkrts_worker* merge(__cilkrts_worker *current_wkr, + cilkred_map *other_map, + enum merge_kind kind); + + /** @brief check consistency of a reducer map */ + void check(bool allow_null_view); + + /** @brief Test whether the cilkred_map is empty */ + bool is_empty() { return nelem == 0; } +}; + +static inline struct cilkred_map* install_new_reducer_map(__cilkrts_worker *w) { + cilkred_map *h; + h = __cilkrts_make_reducer_map(w); + w->reducer_map = h; + return h; +} + +static size_t sizeof_bucket(size_t nmax) +{ + bucket *b = 0; + return (sizeof(*b) + nmax * sizeof(b->el[0])); +} + +static bucket *alloc_bucket(__cilkrts_worker *w, size_t nmax) +{ + bucket *b = (bucket *) + __cilkrts_frame_malloc(w, sizeof_bucket(nmax)); + b->nmax = nmax; + return b; +} + +static void free_bucket(__cilkrts_worker *w, bucket **bp) +{ + bucket *b = *bp; + if (b) { + __cilkrts_frame_free(w, b, sizeof_bucket(b->nmax)); + *bp = 0; + } +} + +/* round up nmax to fill a memory allocator block completely */ +static size_t roundup(size_t nmax) +{ + size_t sz = sizeof_bucket(nmax); + + /* round up size to a full malloc block */ + sz = __cilkrts_frame_malloc_roundup(sz); + + /* invert sizeof_bucket() */ + nmax = ((sz - sizeof(bucket)) / sizeof(elem)); + + return nmax; +} + +static bool is_power_of_2(size_t n) +{ + return (n & (n - 1)) == 0; +} + +void cilkred_map::make_buckets(__cilkrts_worker *w, + size_t new_nbuckets) +{ + nbuckets = new_nbuckets; + + CILK_ASSERT(is_power_of_2(nbuckets)); +#if defined __GNUC__ && defined __ICC + /* bug workaround -- suppress calls to _intel_fast_memset */ + bucket *volatile*new_buckets = (bucket *volatile*) +#else + bucket **new_buckets = (bucket **) +#endif + __cilkrts_frame_malloc(w, nbuckets * sizeof(*(buckets))); + +#if REDPAR_DEBUG >= 1 + fprintf(stderr, "W=%d, desc=make_buckets, new_buckets=%p, new_nbuckets=%zd\n", + w->self, new_buckets, new_nbuckets); +#endif + + for (size_t i = 0; i < new_nbuckets; ++i) + new_buckets[i] = 0; +#if defined __GNUC__ && defined __ICC + buckets = (bucket **)new_buckets; +#else + buckets = new_buckets; +#endif + nelem = 0; +} + +static void free_buckets(__cilkrts_worker *w, + bucket **buckets, + size_t nbuckets) +{ + size_t i; + +#if REDPAR_DEBUG >= 1 + verify_current_wkr(w); + fprintf(stderr, "W=%d, desc=free_buckets, buckets=%p, size=%zd\n", + w->self, buckets, + nbuckets * sizeof(*buckets)); +#endif + + for (i = 0; i < nbuckets; ++i) + free_bucket(w, buckets + i); + + __cilkrts_frame_free(w, buckets, nbuckets * sizeof(*buckets)); +} + +static size_t minsz(size_t nelem) +{ + return 1U + nelem + nelem / 8U; +} + +static size_t nextsz(size_t nelem) +{ + return 2 * nelem; +} + +bool cilkred_map::need_rehash_p() const +{ + return minsz(nelem) > nbuckets; +} + +static inline size_t hashfun(const cilkred_map *h, void *key) +{ + size_t k = (size_t) key; + + k ^= k >> 21; + k ^= k >> 8; + k ^= k >> 3; + + return k & (h->nbuckets - 1); +} + +// Given a __cilkrts_hyperobject_base, return the key to that hyperobject in +// the reducer map. +static inline void* get_hyperobject_key(__cilkrts_hyperobject_base *hb) +{ + // The current implementation uses the address of the lefmost view as the + // key. + return reinterpret_cast<char*>(hb) + hb->__view_offset; +} + +// Given a hyperobject key, return a pointer to the leftmost object. In the +// current implementation, the address of the leftmost object IS the key, so +// this function is an effective noop. +static inline void* get_leftmost_view(void *key) +{ + return key; +} + +/* debugging support: check consistency of a reducer map */ +void cilkred_map::check(bool allow_null_view) +{ + size_t count = 0; + + CILK_ASSERT(buckets); + for (size_t i = 0; i < nbuckets; ++i) { + bucket *b = buckets[i]; + if (b) + for (elem *el = b->el; el->key; ++el) { + CILK_ASSERT(allow_null_view || el->view); + ++count; + } + } + CILK_ASSERT(nelem == count); + /*global_reducer_map::check();*/ +} + +/* grow bucket by one element, reallocating bucket if necessary */ +elem *cilkred_map::grow(__cilkrts_worker *w, + bucket **bp) +{ + size_t i, nmax, nnmax; + bucket *b, *nb; + + b = *bp; + if (b) { + nmax = b->nmax; + /* find empty element if any */ + for (i = 0; i < nmax; ++i) + if (b->el[i].key == 0) + return &(b->el[i]); + /* do not use the last one even if empty */ + } else { + nmax = 0; + } + + verify_current_wkr(w); + /* allocate a new bucket */ + nnmax = roundup(2 * nmax); + nb = alloc_bucket(w, nnmax); + + + /* copy old bucket into new */ + for (i = 0; i < nmax; ++i) + nb->el[i] = b->el[i]; + + free_bucket(w, bp); *bp = nb; + + /* zero out extra elements */ + for (; i < nnmax; ++i) + nb->el[i].key = 0; + + /* zero out the last one */ + nb->el[i].key = 0; + + return &(nb->el[nmax]); +} + +elem *cilkred_map::insert_no_rehash(__cilkrts_worker *w, + void *key, + __cilkrts_hyperobject_base *hb, + void *view) +{ + +#if REDPAR_DEBUG >= 2 + fprintf(stderr, "[W=%d, desc=insert_no_rehash, this_map=%p]\n", + w->self, this); + verify_current_wkr(w); +#endif + + CILK_ASSERT((w == 0 && g == 0) || w->g == g); + CILK_ASSERT(key != 0); + CILK_ASSERT(view != 0); + + elem *el = grow(w, &(buckets[hashfun(this, key)])); + +#if REDPAR_DEBUG >= 3 + fprintf(stderr, "[W=%d, this=%p, inserting key=%p, view=%p, el = %p]\n", + w->self, this, key, view, el); +#endif + + el->key = key; + el->hb = hb; + el->view = view; + ++nelem; + + return el; +} + +void cilkred_map::rehash(__cilkrts_worker *w) +{ +#if REDPAR_DEBUG >= 1 + fprintf(stderr, "[W=%d, desc=rehash, this_map=%p, g=%p, w->g=%p]\n", + w->self, this, g, w->g); + verify_current_wkr(w); +#endif + CILK_ASSERT((w == 0 && g == 0) || w->g == g); + + size_t onbuckets = nbuckets; + size_t onelem = nelem; + bucket **obuckets = buckets; + size_t i; + bucket *b; + + make_buckets(w, nextsz(nbuckets)); + + for (i = 0; i < onbuckets; ++i) { + b = obuckets[i]; + if (b) { + elem *oel; + for (oel = b->el; oel->key; ++oel) + insert_no_rehash(w, oel->key, oel->hb, oel->view); + } + } + + CILK_ASSERT(nelem == onelem); + + free_buckets(w, obuckets, onbuckets); +} + +elem *cilkred_map::rehash_and_insert(__cilkrts_worker *w, + void *key, + __cilkrts_hyperobject_base *hb, + void *view) +{ + +#if REDPAR_DEBUG >= 1 + fprintf(stderr, "W=%d, this_map =%p, inserting key=%p, view=%p\n", + w->self, this, key, view); + verify_current_wkr(w); +#endif + + if (need_rehash_p()) + rehash(w); + + return insert_no_rehash(w, key, hb, view); +} + + +elem *cilkred_map::lookup(void *key) +{ + bucket *b = buckets[hashfun(this, key)]; + + if (b) { + elem *el; + for (el = b->el; el->key; ++el) { + if (el->key == key) { + CILK_ASSERT(el->view); + return el; + } + } + } + + return 0; +} + +void elem::destroy() +{ + if (! is_leftmost()) { + + // Call destroy_fn and deallocate_fn on the view, but not if it's the + // leftmost view. + cilk_c_monoid *monoid = &(hb->__c_monoid); + cilk_c_reducer_destroy_fn_t destroy_fn = monoid->destroy_fn; + cilk_c_reducer_deallocate_fn_t deallocate_fn = monoid->deallocate_fn; + + destroy_fn((void*)hb, view); + deallocate_fn((void*)hb, view); + } + + view = 0; +} + +inline +bool elem::is_leftmost() const +{ + // implementation uses the address of the leftmost view as the key, so if + // key == view, then this element refers to the leftmost view. + return key == view; +} + +/* remove the reducer from the current reducer map. If the reducer + exists in maps other than the current one, the behavior is + undefined. */ +extern "C" +CILK_EXPORT void __CILKRTS_STRAND_STALE( + __cilkrts_hyper_destroy(__cilkrts_hyperobject_base *hb)) +{ + // Disable Cilkscreen for the duration of this call. The destructor for + // this class will re-enable Cilkscreen when the method returns. This + // will prevent Cilkscreen from reporting apparent races in reducers + DisableCilkscreen x; + + __cilkrts_worker* w = __cilkrts_get_tls_worker(); + if (! w) { + // If no worker, then Cilk is not running and there is no reducer + // map. Do nothing. The reducer's destructor will take care of + // destroying the leftmost view. + return; + } + +const char *UNSYNCED_REDUCER_MSG = + "Destroying a reducer while it is visible to unsynced child tasks, or\n" + "calling CILK_C_UNREGISTER_REDUCER() on an unregistered reducer.\n" + "Did you forget a _Cilk_sync or CILK_C_REGISTER_REDUCER()?"; + + cilkred_map* h = w->reducer_map; + if (NULL == h) + cilkos_error(UNSYNCED_REDUCER_MSG); // Does not return + + if (h->merging) { + verify_current_wkr(w); + __cilkrts_bug("User error: hyperobject used by another hyperobject"); + } + + void* key = get_hyperobject_key(hb); + elem *el = h->lookup(key); + + // Verify that the reducer is being destroyed from the leftmost strand for + // which the reducer is defined. + if (! (el && el->is_leftmost())) + cilkos_error(UNSYNCED_REDUCER_MSG); + +#if REDPAR_DEBUG >= 3 + fprintf(stderr, "[W=%d, key=%p, lookup in map %p, found el=%p, about to destroy]\n", + w->self, key, h, el); +#endif + + // Remove the element from the hash bucket. Do not bother shrinking + // the bucket. Note that the destroy() function does not actually + // call the destructor for the leftmost view. + el->destroy(); + do { + el[0] = el[1]; + ++el; + } while (el->key); + --h->nelem; + +#if REDPAR_DEBUG >= 2 + fprintf(stderr, "[W=%d, desc=hyper_destroy_finish, key=%p, w->reducer_map=%p]\n", + w->self, key, w->reducer_map); +#endif +} + +extern "C" +CILK_EXPORT +void __cilkrts_hyper_create(__cilkrts_hyperobject_base *hb) +{ + // This function registers the specified hyperobject in the current + // reducer map and registers the initial value of the hyperobject as the + // leftmost view of the reducer. + __cilkrts_worker *w = __cilkrts_get_tls_worker(); + if (! w) { + // If there is no worker, then there is nothing to do: The iniitial + // value will automatically be used as the left-most view when we + // enter Cilk. + return; + } + + // Disable Cilkscreen for the duration of this call. The destructor for + // this class will re-enable Cilkscreen when the method returns. This + // will prevent Cilkscreen from reporting apparent races in reducers + DisableCilkscreen x; + + void* key = get_hyperobject_key(hb); + void* view = get_leftmost_view(key); + cilkred_map *h = w->reducer_map; + + if (__builtin_expect(!h, 0)) { + h = install_new_reducer_map(w); +#if REDPAR_DEBUG >= 2 + fprintf(stderr, "[W=%d, hb=%p, hyper_create, isntalled new map %p, view=%p]\n", + w->self, hb, h, view); +#endif + } + + /* Must not exist. */ + CILK_ASSERT(h->lookup(key) == NULL); + +#if REDPAR_DEBUG >= 3 + verify_current_wkr(w); + fprintf(stderr, "[W=%d, hb=%p, lookup in map %p of view %p, should be null]\n", + w->self, hb, h, view); + fprintf(stderr, "W=%d, h=%p, inserting key %p, view%p\n", + w->self, + h, + &(hb->__c_monoid), + view); +#endif + + if (h->merging) + __cilkrts_bug("User error: hyperobject used by another hyperobject"); + + CILK_ASSERT(w->reducer_map == h); + // The address of the leftmost value is the same as the key for lookup. + (void) h->rehash_and_insert(w, view, hb, view); +} + +extern "C" +CILK_EXPORT void* __CILKRTS_STRAND_PURE( + __cilkrts_hyper_lookup(__cilkrts_hyperobject_base *hb)) +{ + __cilkrts_worker* w = __cilkrts_get_tls_worker_fast(); + void* key = get_hyperobject_key(hb); + if (! w) + return get_leftmost_view(key); + + // Disable Cilkscreen for the duration of this call. This will + // prevent Cilkscreen from reporting apparent races in reducers + DisableCilkscreen dguard; + + if (__builtin_expect(w->g->force_reduce, 0)) + __cilkrts_promote_own_deque(w); + cilkred_map* h = w->reducer_map; + + if (__builtin_expect(!h, 0)) { + h = install_new_reducer_map(w); + } + + if (h->merging) + __cilkrts_bug("User error: hyperobject used by another hyperobject"); + elem* el = h->lookup(key); + if (! el) { + /* lookup failed; insert a new default element */ + void *rep; + + { + /* re-enable cilkscreen while calling the constructor */ + EnableCilkscreen eguard; + if (h->is_leftmost) + { + // This special case is called only if the reducer was not + // registered using __cilkrts_hyper_create, e.g., if this is a + // C reducer in global scope or if there is no bound worker. + rep = get_leftmost_view(key); + } + else + { + rep = hb->__c_monoid.allocate_fn((void*)hb, + hb->__view_size); + // TBD: Handle exception on identity function + hb->__c_monoid.identity_fn((void*)hb, rep); + } + } + +#if REDPAR_DEBUG >= 3 + fprintf(stderr, "W=%d, h=%p, inserting key %p, view%p\n", + w->self, + h, + &(hb->__c_monoid), + rep); + CILK_ASSERT(w->reducer_map == h); +#endif + el = h->rehash_and_insert(w, key, hb, rep); + } + + return el->view; +} + +extern "C" CILK_EXPORT +void* __cilkrts_hyperobject_alloc(void* ignore, std::size_t bytes) +{ + return std::malloc(bytes); +} + +extern "C" CILK_EXPORT +void __cilkrts_hyperobject_dealloc(void* ignore, void* view) +{ + std::free(view); +} + +/* No-op destroy function */ +extern "C" CILK_EXPORT +void __cilkrts_hyperobject_noop_destroy(void* ignore, void* ignore2) +{ +} + +cilkred_map *__cilkrts_make_reducer_map(__cilkrts_worker *w) +{ + CILK_ASSERT(w); + + cilkred_map *h; + size_t nbuckets = 1; /* default value */ + + h = (cilkred_map *)__cilkrts_frame_malloc(w, sizeof(*h)); +#if REDPAR_DEBUG >= 1 + fprintf(stderr, "[W=%d, desc=make_reducer_frame_malloc_reducer_map, h=%p]\n", + w->self, h); +#endif + + h->g = w ? w->g : 0; + h->make_buckets(w, nbuckets); + h->merging = false; + h->is_leftmost = false; + + return h; +} + +/* Destroy a reducer map. The map must have been allocated + from the worker's global context and should have been + allocated from the same worker. */ +void __cilkrts_destroy_reducer_map(__cilkrts_worker *w, cilkred_map *h) +{ + CILK_ASSERT((w == 0 && h->g == 0) || w->g == h->g); + verify_current_wkr(w); + + /* the reducer map is allowed to contain el->view == NULL here (and + only here). We set el->view == NULL only when we know that the + map will be destroyed immediately afterwards. */ + DBG h->check(/*allow_null_view=*/true); + + bucket *b; + size_t i; + + for (i = 0; i < h->nbuckets; ++i) { + b = h->buckets[i]; + if (b) { + elem *el; + for (el = b->el; el->key; ++el) { + if (el->view) + el->destroy(); + } + } + } + + free_buckets(w, h->buckets, h->nbuckets); + +#if REDPAR_DEBUG >= 1 + fprintf(stderr, "W=%d, destroy_red_map, freeing map h=%p, size=%zd\n", + w->self, h, sizeof(*h)); +#endif + + __cilkrts_frame_free(w, h, sizeof(*h)); +} + +/* Set the specified reducer map as the leftmost map if is_leftmost is true, + otherwise, set it to not be the leftmost map. */ +void __cilkrts_set_leftmost_reducer_map(cilkred_map *h, int is_leftmost) +{ + h->is_leftmost = is_leftmost; +} + + +__cilkrts_worker* cilkred_map::merge(__cilkrts_worker *w, + cilkred_map *other_map, + enum merge_kind kind) +{ + // Disable Cilkscreen while the we merge the maps. The destructor for + // the guard class will re-enable Cilkscreen when it goes out of scope. + // This will prevent Cilkscreen from reporting apparent races in between + // the reduce function and the reducer operations. The Cilk runtime + // guarantees that a pair of reducer maps will only be merged when no + // other strand will access them. + DisableCilkscreen guard; + +#if REDPAR_DEBUG >= 2 + fprintf(stderr, "[W=%d, desc=merge, this_map=%p, other_map=%p]\n", + w->self, + this, other_map); +#endif + // Remember the current stack frame. + __cilkrts_stack_frame *current_sf = w->current_stack_frame; + merging = true; + other_map->merging = true; + + // Merging to the leftmost view is a special case because every leftmost + // element must be initialized before the merge. + CILK_ASSERT(!other_map->is_leftmost /* || kind == MERGE_UNORDERED */); + bool merge_to_leftmost = (this->is_leftmost + /* && !other_map->is_leftmost */); + + DBG check(/*allow_null_view=*/false); + DBG other_map->check(/*allow_null_view=*/false); + + for (size_t i = 0; i < other_map->nbuckets; ++i) { + bucket *b = other_map->buckets[i]; + if (b) { + for (elem *other_el = b->el; other_el->key; ++other_el) { + /* Steal the value from the other map, which will be + destroyed at the end of this operation. */ + void *other_view = other_el->view; + CILK_ASSERT(other_view); + + void *key = other_el->key; + __cilkrts_hyperobject_base *hb = other_el->hb; + elem *this_el = lookup(key); + + if (this_el == 0 && merge_to_leftmost) { + /* Initialize leftmost view before merging. */ + void* leftmost = get_leftmost_view(key); + // leftmost == other_view can be true if the initial view + // was created in other than the leftmost strand of the + // spawn tree, but then made visible to subsequent strands + // (E.g., the reducer was allocated on the heap and the + // pointer was returned to the caller.) In such cases, + // parallel semantics says that syncing with earlier + // strands will always result in 'this_el' being null, + // thus propagating the initial view up the spawn tree + // until it reaches the leftmost strand. When synching + // with the leftmost strand, leftmost == other_view will be + // true and we must avoid reducing the initial view with + // itself. + if (leftmost != other_view) + this_el = rehash_and_insert(w, key, hb, leftmost); + } + + if (this_el == 0) { + /* move object from other map into this one */ + rehash_and_insert(w, key, hb, other_view); + other_el->view = 0; + continue; /* No element-level merge necessary */ + } + + /* The same key is present in both maps with values + A and B. Three choices: fail, A OP B, B OP A. */ + switch (kind) + { + case MERGE_UNORDERED: + __cilkrts_bug("TLS Reducer race"); + break; + case MERGE_INTO_RIGHT: + /* Swap elements in order to preserve object + identity */ + other_el->view = this_el->view; + this_el->view = other_view; + /* FALL THROUGH */ + case MERGE_INTO_LEFT: { + /* Stealing should be disabled during reduce + (even if force-reduce is enabled). */ + +#if DISABLE_PARALLEL_REDUCERS + __cilkrts_stack_frame * volatile *saved_protected_tail; + saved_protected_tail = __cilkrts_disallow_stealing(w, NULL); +#endif + + { + CILK_ASSERT(current_sf->worker == w); + CILK_ASSERT(w->current_stack_frame == current_sf); + + /* TBD: if reduce throws an exception we need to stop it + here. */ + hb->__c_monoid.reduce_fn((void*)hb, + this_el->view, + other_el->view); + w = current_sf->worker; + +#if REDPAR_DEBUG >= 2 + verify_current_wkr(w); + CILK_ASSERT(w->current_stack_frame == current_sf); +#endif + } + +#if DISABLE_PARALLEL_REDUCERS + /* Restore stealing */ + __cilkrts_restore_stealing(w, saved_protected_tail); +#endif + + } break; + } + } + } + } + this->is_leftmost = this->is_leftmost || other_map->is_leftmost; + merging = false; + other_map->merging = false; + verify_current_wkr(w); + __cilkrts_destroy_reducer_map(w, other_map); + return w; +} + + +/** + * Print routine for debugging the merging of reducer maps. + * A no-op unless REDPAR_DEBUG set high enough. + */ +static inline +void debug_map_merge(__cilkrts_worker *w, + cilkred_map *left_map, + cilkred_map *right_map, + __cilkrts_worker **final_wkr) +{ +#if REDPAR_DEBUG >= 2 + fprintf(stderr, "[W=%d, desc=finish_merge, left_map=%p, right_map=%p, w->reducer_map=%p, right_ans=%p, final_wkr=%d]\n", + w->self, left_map, right_map, w->reducer_map, right_map, (*final_wkr)->self); +#endif +} + + +/** + * merge RIGHT into LEFT; + * return whichever map allows for faster merge, and destroy the other one. + * + * *w_ptr should be the currently executing worker. + * *w_ptr may change during execution if the reduction is parallel. + */ +cilkred_map* +merge_reducer_maps(__cilkrts_worker **w_ptr, + cilkred_map *left_map, + cilkred_map *right_map) +{ + __cilkrts_worker *w = *w_ptr; + if (!left_map) { + debug_map_merge(w, left_map, right_map, w_ptr); + return right_map; + } + + if (!right_map) { + debug_map_merge(w, left_map, right_map, w_ptr); + return left_map; + } + + /* Special case, if left_map is leftmost, then always merge into it. + For C reducers this forces lazy creation of the leftmost views. */ + if (left_map->is_leftmost || left_map->nelem > right_map->nelem) { + *w_ptr = left_map->merge(w, right_map, cilkred_map::MERGE_INTO_LEFT); + debug_map_merge(*w_ptr, left_map, right_map, w_ptr); + return left_map; + } else { + *w_ptr = right_map->merge(w, left_map, cilkred_map::MERGE_INTO_RIGHT); + debug_map_merge(*w_ptr, left_map, right_map, w_ptr); + return right_map; + } +} + +/** + * Merges RIGHT into LEFT, and then repeatedly calls + * merge_reducer_maps_helper() until (*w_ptr)->reducer_map is NULL. + * + * *w_ptr may change as reductions execute. + */ +cilkred_map* +repeated_merge_reducer_maps(__cilkrts_worker **w_ptr, + cilkred_map *left_map, + cilkred_map *right_map) +{ + // Note: if right_map == NULL but w->reducer_map != NULL, then + // this loop will reduce w->reducer_map into left_map. + do { + left_map = merge_reducer_maps(w_ptr, left_map, right_map); + verify_current_wkr(*w_ptr); + + // Pull any newly created reducer map and loop around again. + right_map = (*w_ptr)->reducer_map; + (*w_ptr)->reducer_map = NULL; + } while (right_map); + return left_map; +} + +/* End reducer_impl.cpp */ diff --git a/libcilkrts/runtime/reducer_impl.h b/libcilkrts/runtime/reducer_impl.h new file mode 100644 index 00000000000..3425967ad8d --- /dev/null +++ b/libcilkrts/runtime/reducer_impl.h @@ -0,0 +1,128 @@ +/* reducer_impl.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** + * @file reducer_impl.h + * + * @brief Functions to implement reducers in the runtime. + */ + +#ifndef INCLUDED_REDUCER_IMPL_DOT_H +#define INCLUDED_REDUCER_IMPL_DOT_H + +#include <cilk/common.h> +#include <internal/abi.h> +#include "rts-common.h" + +__CILKRTS_BEGIN_EXTERN_C + +/** + * Construct an empty reducer map from the memory pool associated with the + * given worker. This reducer map must be destroyed before the worker's + * associated global context is destroyed. + * + * @param w __cilkrts_worker the cilkred_map is being created for. + * + * @return Pointer to the initialized cilkred_map. + */ +COMMON_SYSDEP +cilkred_map *__cilkrts_make_reducer_map(__cilkrts_worker *w); + +/** + * Destroy a reducer map. The map must have been allocated from the worker's + * global context and should have been allocated from the same worker. + * + * @param w __cilkrts_worker the cilkred_map was created for. + * @param h The cilkred_map to be deallocated. + */ +COMMON_SYSDEP +void __cilkrts_destroy_reducer_map(__cilkrts_worker *w, + cilkred_map *h); + +/** + * Set the specified reducer map as the leftmost map if is_leftmost is true, + * otherwise, set it to not be the leftmost map. + * + * @param h The cilkred_map to be modified. + * @param is_leftmost true if the reducer map is leftmost. + */ +COMMON_SYSDEP +void __cilkrts_set_leftmost_reducer_map(cilkred_map *h, + int is_leftmost); + +/** + * Merge reducer map RIGHT_MAP into LEFT_MAP and return the result of the + * merge. Both maps must be allocated from the global context associated + * with the specified worker. The returned reducer map must be destroyed + * before the worker's associated global context is destroyed. + * + * If two cilkred_maps are specified, one will be destroyed and the other + * one will be returned as the merged cilkred_map. + * + * When reducers can contain nested parallelism, execution can return + * on a different worker than when it started (but still using the + * same stack). + * + * Upon return, *w_ptr stores the pointer to the worker that execution + * returns on. + * + * @param w_ptr Pointer to the currently executing worker. + * @param left_map The left cilkred_map. + * @param right_map The right cilkred_map. + * + * @return pointer to merged cilkred_map. + */ +extern +cilkred_map *merge_reducer_maps(__cilkrts_worker **w_ptr, + cilkred_map *left_map, + cilkred_map *right_map); + +/** + * Similar to merge_reducer_maps(), except that after merging + * RIGHT_MAP into LEFT_MAP, it repeatedly merges (*w_ptr)->reducer_map + * into LEFT_MAP. This procedure ensures that any new reducers + * created by the reductions themselves also get merged into LEFT_MAP. + */ +extern +cilkred_map *repeated_merge_reducer_maps(__cilkrts_worker **w_ptr, + cilkred_map *left_map, + cilkred_map *right_map); + +__CILKRTS_END_EXTERN_C + +#endif // ! defined(INCLUDED_REDUCER_IMPL_DOT_H) diff --git a/libcilkrts/runtime/rts-common.h b/libcilkrts/runtime/rts-common.h new file mode 100644 index 00000000000..4ffde7ccb1e --- /dev/null +++ b/libcilkrts/runtime/rts-common.h @@ -0,0 +1,132 @@ +/* rts-common.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +#ifndef INCLUDED_RTS_COMMON_DOT_H +#define INCLUDED_RTS_COMMON_DOT_H + +/* Abbreviations API functions returning different types. By using these + * abbreviations instead of using CILK_API(ret) directly, etags and other + * tools can more easily recognize function signatures. + */ +#define CILK_API_VOID CILK_API(void) +#define CILK_API_VOID_PTR CILK_API(void*) +#define CILK_API_INT CILK_API(int) +#define CILK_API_SIZET CILK_API(size_t) +#define CILK_API_TBB_RETCODE CILK_API(__cilk_tbb_retcode) +#define CILK_API_PEDIGREE CILK_API(__cilkrts_pedigree) + +/* Abbreviations ABI functions returning different types. By using these + * abbreviations instead of using CILK_ABI(ret) directly, etags and other + * tools can more easily recognize function signatures. + */ +#define CILK_ABI_VOID CILK_ABI(void) +#define CILK_ABI_WORKER_PTR CILK_ABI(__cilkrts_worker_ptr) +#define CILK_ABI_THROWS_VOID CILK_ABI_THROWS(void) + +/* documentation aid to identify portable vs. nonportable + parts of the runtime. See README for definitions. */ +#define COMMON_PORTABLE +#define COMMON_SYSDEP +#define NON_COMMON + +#if !(defined __GNUC__ || defined __ICC) +# define __builtin_expect(a_, b_) a_ +#endif + +#ifdef __cplusplus +# define cilk_nothrow throw() +#else +# define cilk_nothrow /*empty in C*/ +#endif + +#ifdef __GNUC__ +# define NORETURN void __attribute__((noreturn)) +#else +# define NORETURN void __declspec(noreturn) +#endif + +#ifdef __GNUC__ +# define NOINLINE __attribute__((noinline)) +#else +# define NOINLINE __declspec(noinline) +#endif + +#ifndef __GNUC__ +# define __attribute__(X) +#endif + +/* Microsoft CL accepts "inline" for C++, but not for C. It accepts + * __inline for both. Intel ICL accepts inline for C of /Qstd=c99 + * is set. The Cilk runtime is assumed to be compiled with /Qstd=c99 + */ +#if defined(_MSC_VER) && ! defined(__INTEL_COMPILER) +# error define inline +# define inline __inline +#endif + +/* Compilers that build the Cilk runtime are assumed to know about zero-cost + * intrinsics (__notify_intrinsic()). For those that don't, #undef the + * following definition: + */ +//#define ENABLE_NOTIFY_ZC_INTRINSIC 1 + +#if defined(__INTEL_COMPILER) +/* The notify intrinsic was introduced in ICC 12.0. */ +# if __INTEL_COMPILER <= 1200 +# undef ENABLE_NOTIFY_ZC_INTRINSIC +# endif +#elif defined(__VXWORKS__) +# undef ENABLE_NOTIFY_ZC_INTRINSIC +#elif defined(__clang__) +# if !defined(__has_extension) || !__has_extension(notify_zc_intrinsic) +# undef ENABLE_NOTIFY_ZC_INTRINSIC +# endif +#elif defined(__arm__) +// __notify_zc_intrinsic not yet supported by gcc for ARM +# undef ENABLE_NOTIFY_ZC_INTRINSIC +#endif + +// If ENABLE_NOTIFY_ZC_INTRINSIC is defined, use __notify_zc_intrisic +#ifdef ENABLE_NOTIFY_ZC_INTRINSIC +# define NOTIFY_ZC_INTRINSIC(annotation, data) \ + __notify_zc_intrinsic(annotation, data) +#else +# define NOTIFY_ZC_INTRINSIC(annotation, data) +#endif + +#endif // ! defined(INCLUDED_RTS_COMMON_DOT_H) diff --git a/libcilkrts/runtime/scheduler.c b/libcilkrts/runtime/scheduler.c new file mode 100644 index 00000000000..bab6430d9db --- /dev/null +++ b/libcilkrts/runtime/scheduler.c @@ -0,0 +1,3940 @@ +/* scheduler.c -*-C-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2007-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + +/* + * Cilk scheduler + */ + +#include "scheduler.h" +#include "bug.h" +#include "os.h" +#include "os_mutex.h" +#include "local_state.h" +#include "signal_node.h" +#include "full_frame.h" +#include "sysdep.h" +#include "except.h" +#include "cilk_malloc.h" +#include "pedigrees.h" +#include "record-replay.h" + +#include <limits.h> +#include <string.h> /* memcpy */ +#include <stdio.h> // sprintf +#include <stdlib.h> // malloc, free, abort + +#ifdef _WIN32 +# pragma warning(disable:1786) // disable warning: sprintf is deprecated +# include "sysdep-win.h" +# include "except-win32.h" +#endif // _WIN32 + +// ICL: Don't complain about conversion from pointer to same-sized integral +// type in __cilkrts_put_stack. That's why we're using ptrdiff_t +#ifdef _WIN32 +# pragma warning(disable: 1684) +#endif + +#include "cilk/cilk_api.h" +#include "frame_malloc.h" +#include "metacall_impl.h" +#include "reducer_impl.h" +#include "cilk-tbb-interop.h" +#include "cilk-ittnotify.h" +#include "stats.h" + +// ICL: Don't complain about loss of precision in myrand +// I tried restoring the warning after the function, but it didn't +// suppress it +#ifdef _WIN32 +# pragma warning(disable: 2259) +#endif + +#ifndef _WIN32 +# include <unistd.h> +#endif + +#ifdef __VXWORKS__ +// redeclare longjmp() with noreturn to stop warnings +extern __attribute__((noreturn)) + void longjmp(jmp_buf, int); +#endif + +//#define DEBUG_LOCKS 1 +#ifdef DEBUG_LOCKS +// The currently executing worker must own this worker's lock +# define ASSERT_WORKER_LOCK_OWNED(w) \ + { \ + __cilkrts_worker *tls_worker = __cilkrts_get_tls_worker(); \ + CILK_ASSERT((w)->l->lock.owner == tls_worker); \ + } +#else +# define ASSERT_WORKER_LOCK_OWNED(w) +#endif // DEBUG_LOCKS + +// Options for the scheduler. +enum schedule_t { SCHEDULE_RUN, + SCHEDULE_WAIT, + SCHEDULE_EXIT }; + +// Return values for provably_good_steal() +enum provably_good_steal_t +{ + ABANDON_EXECUTION, // Not the last child to the sync - attempt to steal work + CONTINUE_EXECUTION, // Last child to the sync - continue executing on this worker + WAIT_FOR_CONTINUE // The replay log indicates that this was the worker + // which continued. Loop until we are the last worker + // to the sync. +}; + + +// Verify that "w" is the worker we are currently executing on. +// Because this check is expensive, this method is usually a no-op. +static inline void verify_current_wkr(__cilkrts_worker *w) +{ +#if ((REDPAR_DEBUG >= 3) || (FIBER_DEBUG >= 1)) + // Lookup the worker from TLS and compare to w. + __cilkrts_worker* tmp = __cilkrts_get_tls_worker(); + if (w != tmp) { + fprintf(stderr, "Error. W=%d, actual worker =%d...\n", + w->self, + tmp->self); + } + CILK_ASSERT(w == tmp); +#endif +} + +static enum schedule_t worker_runnable(__cilkrts_worker *w); + +// Scheduling-fiber functions: +static void do_return_from_spawn (__cilkrts_worker *w, + full_frame *ff, + __cilkrts_stack_frame *sf); +static void do_sync (__cilkrts_worker *w, + full_frame *ff, + __cilkrts_stack_frame *sf); + +// max is defined on Windows and VxWorks +#if (! defined(_WIN32)) && (! defined(__VXWORKS__)) + // TBD: definition of max() for Linux. +# define max(a, b) ((a) < (b) ? (b) : (a)) +#endif + +void __cilkrts_dump_stats_to_stderr(global_state_t *g) +{ +#ifdef CILK_PROFILE + int i; + for (i = 0; i < g->total_workers; ++i) { + // Print out statistics for each worker. We collected them, + // so why not print them out? + fprintf(stderr, "Stats for worker %d\n", i); + dump_stats_to_file(stderr, g->workers[i]->l->stats); + __cilkrts_accum_stats(&g->stats, g->workers[i]->l->stats); + } + + // Also print out aggregate statistics. + dump_stats_to_file(stderr, &g->stats); +#endif + fprintf(stderr, + "CILK PLUS Thread Info: P=%d, Q=%d\n", + g->P, + g->Q); + fprintf(stderr, + "CILK PLUS RUNTIME MEMORY USAGE: %lld bytes", + (long long)g->frame_malloc.allocated_from_os); +#ifdef CILK_PROFILE + if (g->stats.stack_hwm) + fprintf(stderr, ", %ld stacks", g->stats.stack_hwm); +#endif + fputc('\n', stderr); +} + +static void validate_worker(__cilkrts_worker *w) +{ + /* check the magic numbers, for debugging purposes */ + if (w->l->worker_magic_0 != WORKER_MAGIC_0 || + w->l->worker_magic_1 != WORKER_MAGIC_1) + abort_because_rts_is_corrupted(); +} + +static void double_link(full_frame *left_ff, full_frame *right_ff) +{ + if (left_ff) + left_ff->right_sibling = right_ff; + if (right_ff) + right_ff->left_sibling = left_ff; +} + +/* add CHILD to the right of all children of PARENT */ +static void push_child(full_frame *parent_ff, full_frame *child_ff) +{ + double_link(parent_ff->rightmost_child, child_ff); + double_link(child_ff, 0); + parent_ff->rightmost_child = child_ff; +} + +/* unlink CHILD from the list of all children of PARENT */ +static void unlink_child(full_frame *parent_ff, full_frame *child_ff) +{ + double_link(child_ff->left_sibling, child_ff->right_sibling); + + if (!child_ff->right_sibling) { + /* this is the rightmost child -- update parent link */ + CILK_ASSERT(parent_ff->rightmost_child == child_ff); + parent_ff->rightmost_child = child_ff->left_sibling; + } + child_ff->left_sibling = child_ff->right_sibling = 0; /* paranoia */ +} + +static void incjoin(full_frame *ff) +{ + ++ff->join_counter; +} + +static int decjoin(full_frame *ff) +{ + CILK_ASSERT(ff->join_counter > 0); + return (--ff->join_counter); +} + +static int simulate_decjoin(full_frame *ff) +{ + CILK_ASSERT(ff->join_counter > 0); + return (ff->join_counter - 1); +} + +/* + * Pseudo-random generator defined by the congruence S' = 69070 * S + * mod (2^32 - 5). Marsaglia (CACM July 1993) says on page 107 that + * this is a ``good one''. There you go. + * + * The literature makes a big fuss about avoiding the division, but + * for us it is not worth the hassle. + */ +static const unsigned RNGMOD = ((1ULL << 32) - 5); +static const unsigned RNGMUL = 69070U; + +static unsigned myrand(__cilkrts_worker *w) +{ + unsigned state = w->l->rand_seed; + state = (unsigned)((RNGMUL * (unsigned long long)state) % RNGMOD); + w->l->rand_seed = state; + return state; +} + +static void mysrand(__cilkrts_worker *w, unsigned seed) +{ + seed %= RNGMOD; + seed += (seed == 0); /* 0 does not belong to the multiplicative + group. Use 1 instead */ + w->l->rand_seed = seed; +} + +/* W grabs its own lock */ +void __cilkrts_worker_lock(__cilkrts_worker *w) +{ + validate_worker(w); + CILK_ASSERT(w->l->do_not_steal == 0); + + /* tell thieves to stay out of the way */ + w->l->do_not_steal = 1; + __cilkrts_fence(); /* probably redundant */ + + __cilkrts_mutex_lock(w, &w->l->lock); +} + +void __cilkrts_worker_unlock(__cilkrts_worker *w) +{ + __cilkrts_mutex_unlock(w, &w->l->lock); + CILK_ASSERT(w->l->do_not_steal == 1); + /* The fence is probably redundant. Use a release + operation when supported (gcc and compatibile); + that is faster on x86 which serializes normal stores. */ +#if defined __GNUC__ && (__GNUC__ * 10 + __GNUC_MINOR__ > 43 || __ICC >= 1110) + __sync_lock_release(&w->l->do_not_steal); +#else + w->l->do_not_steal = 0; + __cilkrts_fence(); /* store-store barrier, redundant on x86 */ +#endif +} + +/* try to acquire the lock of some *other* worker */ +static int worker_trylock_other(__cilkrts_worker *w, + __cilkrts_worker *other) +{ + int status = 0; + + validate_worker(other); + + /* This protocol guarantees that, after setting the DO_NOT_STEAL + flag, worker W can enter its critical section after waiting for + the thief currently in the critical section (if any) and at + most one other thief. + + This requirement is overly paranoid, but it should protect us + against future nonsense from OS implementors. + */ + + /* compete for the right to disturb OTHER */ + if (__cilkrts_mutex_trylock(w, &other->l->steal_lock)) { + if (other->l->do_not_steal) { + /* leave it alone */ + } else { + status = __cilkrts_mutex_trylock(w, &other->l->lock); + } + __cilkrts_mutex_unlock(w, &other->l->steal_lock); + } + + + return status; +} + +static void worker_unlock_other(__cilkrts_worker *w, + __cilkrts_worker *other) +{ + __cilkrts_mutex_unlock(w, &other->l->lock); +} + + +/* Lock macro Usage: + BEGIN_WITH_WORKER_LOCK(w) { + statement; + statement; + BEGIN_WITH_FRAME_LOCK(w, ff) { + statement; + statement; + } END_WITH_FRAME_LOCK(w, ff); + } END_WITH_WORKER_LOCK(w); + */ +#define BEGIN_WITH_WORKER_LOCK(w) __cilkrts_worker_lock(w); do +#define END_WITH_WORKER_LOCK(w) while (__cilkrts_worker_unlock(w), 0) + +// TBD(jsukha): These are worker lock acquistions on +// a worker whose deque is empty. My conjecture is that we +// do not need to hold the worker lock at these points. +// I have left them in for now, however. +// +// #define REMOVE_POSSIBLY_OPTIONAL_LOCKS +#ifdef REMOVE_POSSIBLY_OPTIONAL_LOCKS + #define BEGIN_WITH_WORKER_LOCK_OPTIONAL(w) do + #define END_WITH_WORKER_LOCK_OPTIONAL(w) while (0) +#else + #define BEGIN_WITH_WORKER_LOCK_OPTIONAL(w) __cilkrts_worker_lock(w); do + #define END_WITH_WORKER_LOCK_OPTIONAL(w) while (__cilkrts_worker_unlock(w), 0) +#endif + + +#define BEGIN_WITH_FRAME_LOCK(w, ff) \ + do { full_frame *_locked_ff = ff; __cilkrts_frame_lock(w, _locked_ff); do + +#define END_WITH_FRAME_LOCK(w, ff) \ + while (__cilkrts_frame_unlock(w, _locked_ff), 0); } while (0) + +/* W becomes the owner of F and F can be stolen from W */ +static void make_runnable(__cilkrts_worker *w, full_frame *ff) +{ + w->l->frame_ff = ff; + + /* CALL_STACK is invalid (the information is stored implicitly in W) */ + ff->call_stack = 0; +} + +/* + * The worker parameter is unused, except for print-debugging purposes. + */ +static void make_unrunnable(__cilkrts_worker *w, + full_frame *ff, + __cilkrts_stack_frame *sf, + int is_loot, + const char *why) +{ + /* CALL_STACK becomes valid again */ + ff->call_stack = sf; + + if (sf) { +#if CILK_LIB_DEBUG + if (__builtin_expect(sf->flags & CILK_FRAME_EXITING, 0)) + __cilkrts_bug("W%d suspending exiting frame %p/%p\n", w->self, ff, sf); +#endif + sf->flags |= CILK_FRAME_STOLEN | CILK_FRAME_SUSPENDED; + sf->worker = 0; + + if (is_loot) + __cilkrts_put_stack(ff, sf); + + /* perform any system-dependent action, such as saving the + state of the stack */ + __cilkrts_make_unrunnable_sysdep(w, ff, sf, is_loot, why); + } +} + + +/* Push the next full frame to be made active in this worker and increment its + * join counter. __cilkrts_push_next_frame and pop_next_frame work on a + * one-element queue. This queue is used to communicate across the runtime + * from the code that wants to activate a frame to the code that can actually + * begin execution on that frame. They are asymetrical in that push + * increments the join counter but pop does not decrement it. Rather, a + * single push/pop combination makes a frame active and increments its join + * counter once. */ +void __cilkrts_push_next_frame(__cilkrts_worker *w, full_frame *ff) +{ + CILK_ASSERT(ff); + CILK_ASSERT(!w->l->next_frame_ff); + incjoin(ff); + w->l->next_frame_ff = ff; +} + +/* Get the next full-frame to be made active in this worker. The join count + * of the full frame will have been incremented by the corresponding push + * event. See __cilkrts_push_next_frame, above. + */ +static full_frame *pop_next_frame(__cilkrts_worker *w) +{ + full_frame *ff; + ff = w->l->next_frame_ff; + // Remove the frame from the next_frame field. + // + // If this is a user worker, then there is a chance that another worker + // from our team could push work into our next_frame (if it is the last + // worker doing work for this team). The other worker's setting of the + // next_frame could race with our setting of next_frame to NULL. This is + // the only possible race condition on next_frame. However, if next_frame + // has a non-NULL value, then it means the team still has work to do, and + // there is no chance of another team member populating next_frame. Thus, + // it is safe to set next_frame to NULL, if it was populated. There is no + // need for an atomic op. + if (NULL != ff) { + w->l->next_frame_ff = NULL; + } + return ff; +} + +/* + * Identify the single worker that is allowed to cross a sync in this frame. A + * thief should call this function when it is the first to steal work from a + * user worker. "First to steal work" may mean that there has been parallelism + * in the user worker before, but the whole team sync'd, and this is the first + * steal after that. + * + * This should happen while holding the worker and frame lock. + */ +static void set_sync_master(__cilkrts_worker *w, full_frame *ff) +{ + w->l->last_full_frame = ff; + ff->sync_master = w; +} + +/* + * The sync that ends all parallelism for a particular user worker is about to + * be crossed. Decouple the worker and frame. + * + * No locks need to be held since the user worker isn't doing anything, and none + * of the system workers can steal from it. But unset_sync_master() should be + * called before the user worker knows about this work (i.e., before it is + * inserted into the w->l->next_frame_ff is set). + */ +static void unset_sync_master(__cilkrts_worker *w, full_frame *ff) +{ + CILK_ASSERT(WORKER_USER == w->l->type); + CILK_ASSERT(ff->sync_master == w); + ff->sync_master = NULL; + w->l->last_full_frame = NULL; +} + +/******************************************************************** + * THE protocol: + ********************************************************************/ +/* + * This is a protocol for work stealing that minimizes the overhead on + * the victim. + * + * The protocol uses three shared pointers into the worker's deque: + * - T - the "tail" + * - H - the "head" + * - E - the "exception" NB: In this case, "exception" has nothing to do + * with C++ throw-catch exceptions -- it refers only to a non-normal return, + * i.e., a steal or similar scheduling exception. + * + * with H <= E, H <= T. + * + * Stack frames SF, where H <= E < T, are available for stealing. + * + * The worker operates on the T end of the stack. The frame being + * worked on is not on the stack. To make a continuation available for + * stealing the worker pushes a from onto the stack: stores *T++ = SF. + * To return, it pops the frame off the stack: obtains SF = *--T. + * + * After decrementing T, the condition E > T signals to the victim that + * it should invoke the runtime system's "THE" exception handler. The + * pointer E can become INFINITY, in which case the victim must invoke + * the THE exception handler as soon as possible. + * + * See "The implementation of the Cilk-5 multithreaded language", PLDI 1998, + * http://portal.acm.org/citation.cfm?doid=277652.277725, for more information + * on the THE protocol. + */ + +/* the infinity value of E */ +#define EXC_INFINITY ((__cilkrts_stack_frame **) (-1)) + +static void increment_E(__cilkrts_worker *victim) +{ + __cilkrts_stack_frame *volatile *tmp; + + // The currently executing worker must own the worker lock to touch + // victim->exc + ASSERT_WORKER_LOCK_OWNED(victim); + + tmp = victim->exc; + if (tmp != EXC_INFINITY) { + /* On most x86 this pair of operations would be slightly faster + as an atomic exchange due to the implicit memory barrier in + an atomic instruction. */ + victim->exc = tmp + 1; + __cilkrts_fence(); + } +} + +static void decrement_E(__cilkrts_worker *victim) +{ + __cilkrts_stack_frame *volatile *tmp; + + // The currently executing worker must own the worker lock to touch + // victim->exc + ASSERT_WORKER_LOCK_OWNED(victim); + + tmp = victim->exc; + if (tmp != EXC_INFINITY) { + /* On most x86 this pair of operations would be slightly faster + as an atomic exchange due to the implicit memory barrier in + an atomic instruction. */ + victim->exc = tmp - 1; + __cilkrts_fence(); /* memory fence not really necessary */ + } +} + +#if 0 +/* for now unused, will be necessary if we implement abort */ +static void signal_THE_exception(__cilkrts_worker *wparent) +{ + wparent->exc = EXC_INFINITY; + __cilkrts_fence(); +} +#endif + +static void reset_THE_exception(__cilkrts_worker *w) +{ + // The currently executing worker must own the worker lock to touch + // w->exc + ASSERT_WORKER_LOCK_OWNED(w); + + w->exc = w->head; + __cilkrts_fence(); +} + +/* conditions under which victim->head can be stolen: */ +static int can_steal_from(__cilkrts_worker *victim) +{ + return ((victim->head < victim->tail) && + (victim->head < victim->protected_tail)); +} + +/* Return TRUE if the frame can be stolen, false otherwise */ +static int dekker_protocol(__cilkrts_worker *victim) +{ + // increment_E and decrement_E are going to touch victim->exc. The + // currently executing worker must own victim's lock before they can + // modify it + ASSERT_WORKER_LOCK_OWNED(victim); + + /* ASSERT(E >= H); */ + + increment_E(victim); + + /* ASSERT(E >= H + 1); */ + if (can_steal_from(victim)) { + /* success, we can steal victim->head and set H <- H + 1 + in detach() */ + return 1; + } else { + /* failure, restore previous state */ + decrement_E(victim); + return 0; + } +} + + +/* Link PARENT and CHILD in the spawn tree */ +static full_frame *make_child(__cilkrts_worker *w, + full_frame *parent_ff, + __cilkrts_stack_frame *child_sf, + cilk_fiber *fiber) +{ + full_frame *child_ff = __cilkrts_make_full_frame(w, child_sf); + + child_ff->parent = parent_ff; + push_child(parent_ff, child_ff); + + //DBGPRINTF("%d- make_child - child_frame: %p, parent_frame: %p, child_sf: %p\n" + // " parent - parent: %p, left_sibling: %p, right_sibling: %p, rightmost_child: %p\n" + // " child - parent: %p, left_sibling: %p, right_sibling: %p, rightmost_child: %p\n", + // w->self, child, parent, child_sf, + // parent->parent, parent->left_sibling, parent->right_sibling, parent->rightmost_child, + // child->parent, child->left_sibling, child->right_sibling, child->rightmost_child); + CILK_ASSERT(parent_ff->call_stack); + child_ff->is_call_child = (fiber == NULL); + + /* PLACEHOLDER_FIBER is used as non-null marker indicating that + child should be treated as a spawn child even though we have not + yet assigned a real fiber to its parent. */ + if (fiber == PLACEHOLDER_FIBER) + fiber = NULL; /* Parent actually gets a null fiber, for now */ + + /* perform any system-dependent actions, such as capturing + parameter passing information */ + /*__cilkrts_make_child_sysdep(child, parent);*/ + + /* Child gets reducer map and stack of parent. + Parent gets a new map and new stack. */ + child_ff->fiber_self = parent_ff->fiber_self; + child_ff->sync_master = NULL; + + if (child_ff->is_call_child) { + /* Cause segfault on any attempted access. The parent gets + the child map and stack when the child completes. */ + parent_ff->fiber_self = 0; + } else { + parent_ff->fiber_self = fiber; + } + + incjoin(parent_ff); + return child_ff; +} + +static inline __cilkrts_stack_frame *__cilkrts_advance_frame(__cilkrts_stack_frame *sf) +{ + __cilkrts_stack_frame *p = sf->call_parent; + sf->call_parent = 0; + return p; +} + +/* w should be the currently executing worker. + * loot_sf is the youngest stack frame in the call stack being + * unrolled (i.e., the most deeply nested stack frame.) + * + * When this method is called for a steal, loot_sf should be on a + * victim worker which is different from w. + * For CILK_FORCE_REDUCE, the victim worker will equal w. + * + * Before execution, the __cilkrts_stack_frame's have pointers from + * older to younger, i.e., a __cilkrts_stack_frame points to parent. + * + * This method creates a full frame for each __cilkrts_stack_frame in + * the call stack, with each full frame also pointing to its parent. + * + * The method returns the full frame created for loot_sf, i.e., the + * youngest full frame. + */ +static full_frame *unroll_call_stack(__cilkrts_worker *w, + full_frame *ff, + __cilkrts_stack_frame *const loot_sf) +{ + __cilkrts_stack_frame *sf = loot_sf; + __cilkrts_stack_frame *rev_sf = 0; + __cilkrts_stack_frame *t_sf; + + CILK_ASSERT(sf); + /*CILK_ASSERT(sf->call_parent != sf);*/ + + /* The leafmost frame is unsynched. */ + if (sf->worker != w) + sf->flags |= CILK_FRAME_UNSYNCHED; + + /* Reverse the call stack to make a linked list ordered from parent + to child. sf->call_parent points to the child of SF instead of + the parent. */ + do { + t_sf = (sf->flags & (CILK_FRAME_DETACHED|CILK_FRAME_STOLEN|CILK_FRAME_LAST))? 0 : sf->call_parent; + sf->call_parent = rev_sf; + rev_sf = sf; + sf = t_sf; + } while (sf); + sf = rev_sf; + + /* Promote each stack frame to a full frame in order from parent + to child, following the reversed list we just built. */ + make_unrunnable(w, ff, sf, sf == loot_sf, "steal 1"); + /* T is the *child* of SF, because we have reversed the list */ + for (t_sf = __cilkrts_advance_frame(sf); t_sf; + sf = t_sf, t_sf = __cilkrts_advance_frame(sf)) { + ff = make_child(w, ff, t_sf, NULL); + make_unrunnable(w, ff, t_sf, t_sf == loot_sf, "steal 2"); + } + + /* XXX What if the leafmost frame does not contain a sync + and this steal is from promote own deque? */ + /*sf->flags |= CILK_FRAME_UNSYNCHED;*/ + + CILK_ASSERT(!sf->call_parent); + return ff; +} + +/* detach the top of the deque frame from the VICTIM and install a new + CHILD frame in its place */ +static void detach_for_steal(__cilkrts_worker *w, + __cilkrts_worker *victim, + cilk_fiber* fiber) +{ + /* ASSERT: we own victim->lock */ + + full_frame *parent_ff, *child_ff, *loot_ff; + __cilkrts_stack_frame *volatile *h; + __cilkrts_stack_frame *sf; + + w->l->team = victim->l->team; + + CILK_ASSERT(w->l->frame_ff == 0 || w == victim); + + h = victim->head; + + CILK_ASSERT(*h); + + victim->head = h + 1; + + parent_ff = victim->l->frame_ff; + BEGIN_WITH_FRAME_LOCK(w, parent_ff) { + /* parent no longer referenced by victim */ + decjoin(parent_ff); + + /* obtain the victim call stack */ + sf = *h; + + /* perform system-dependent normalizations */ + /*__cilkrts_normalize_call_stack_on_steal(sf);*/ + + /* unroll PARENT_FF with call stack SF, adopt the youngest + frame LOOT. If loot_ff == parent_ff, then we hold loot_ff->lock, + otherwise, loot_ff is newly created and we can modify it without + holding its lock. */ + loot_ff = unroll_call_stack(w, parent_ff, sf); + + #if REDPAR_DEBUG >= 3 + fprintf(stderr, "[W=%d, victim=%d, desc=detach, parent_ff=%p, loot=%p]\n", + w->self, victim->self, + parent_ff, loot_ff); + #endif + + if (WORKER_USER == victim->l->type && + NULL == victim->l->last_full_frame) { + // Mark this looted frame as special: only the original user worker + // may cross the sync. + // + // This call is a shared access to + // victim->l->last_full_frame. + set_sync_master(victim, loot_ff); + } + + /* LOOT is the next frame that the thief W is supposed to + run, unless the thief is stealing from itself, in which + case the thief W == VICTIM executes CHILD and nobody + executes LOOT. */ + if (w == victim) { + /* Pretend that frame has been stolen */ + loot_ff->call_stack->flags |= CILK_FRAME_UNSYNCHED; + loot_ff->simulated_stolen = 1; + } + else + __cilkrts_push_next_frame(w, loot_ff); + + // After this "push_next_frame" call, w now owns loot_ff. + child_ff = make_child(w, loot_ff, 0, fiber); + + BEGIN_WITH_FRAME_LOCK(w, child_ff) { + /* install child in the victim's work queue, taking + the parent_ff's place */ + /* child is referenced by victim */ + incjoin(child_ff); + + // With this call, w is bestowing ownership of the newly + // created frame child_ff to the victim, and victim is + // giving up ownership of parent_ff. + // + // Worker w will either take ownership of parent_ff + // if parent_ff == loot_ff, or parent_ff will be + // suspended. + // + // Note that this call changes the victim->frame_ff + // while the victim may be executing. + make_runnable(victim, child_ff); + } END_WITH_FRAME_LOCK(w, child_ff); + } END_WITH_FRAME_LOCK(w, parent_ff); +} + +/** + * @brief cilk_fiber_proc that resumes user code after a successful + * random steal. + + * This function longjmps back into the user code whose state is + * stored in cilk_fiber_get_data(fiber)->resume_sf. The stack pointer + * is adjusted so that the code resumes on the specified fiber stack + * instead of its original stack. + * + * This method gets executed only on a fiber freshly allocated from a + * pool. + * + * @param fiber The fiber being used to resume user code. + * @param arg Unused. + */ +static +void fiber_proc_to_resume_user_code_for_random_steal(cilk_fiber *fiber) +{ + cilk_fiber_data *data = cilk_fiber_get_data(fiber); + __cilkrts_stack_frame* sf = data->resume_sf; + full_frame *ff; + + CILK_ASSERT(sf); + + // When we pull the resume_sf out of the fiber to resume it, clear + // the old value. + data->resume_sf = NULL; + CILK_ASSERT(sf->worker == data->owner); + ff = sf->worker->l->frame_ff; + + // For Win32, we need to overwrite the default exception handler + // in this function, so that when the OS exception handling code + // walks off the top of the current Cilk stack, it reaches our stub + // handler. + + // Also, this function needs to be wrapped into a try-catch block + // so the compiler generates the appropriate exception information + // in this frame. + + // TBD: IS THIS HANDLER IN THE WRONG PLACE? Can we longjmp out of + // this function (and does it matter?) +#if defined(_WIN32) && !defined(_WIN64) + install_exception_stub_handler(); + __try +#endif + { + char* new_sp = sysdep_reset_jump_buffers_for_resume(fiber, ff, sf); + + // Notify the Intel tools that we're stealing code + ITT_SYNC_ACQUIRED(sf->worker); + NOTIFY_ZC_INTRINSIC("cilk_continue", sf); + + // TBD: We'd like to move TBB-interop methods into the fiber + // eventually. + cilk_fiber_invoke_tbb_stack_op(fiber, CILK_TBB_STACK_ADOPT); + + sf->flags &= ~CILK_FRAME_SUSPENDED; + + // longjmp to user code. Don't process exceptions here, + // because we are resuming a stolen frame. + sysdep_longjmp_to_sf(new_sp, sf, NULL); + /*NOTREACHED*/ + // Intel's C compiler respects the preceding lint pragma + } +#if defined(_WIN32) && !defined(_WIN64) + __except (CILK_ASSERT(!"should not execute the the stub filter"), + EXCEPTION_EXECUTE_HANDLER) + { + // If we are here, that means something very wrong + // has happened in our exception processing... + CILK_ASSERT(! "should not be here!"); + } +#endif +} + +static void random_steal(__cilkrts_worker *w) +{ + __cilkrts_worker *victim = NULL; + cilk_fiber *fiber = NULL; + int n; + int success = 0; + int32_t victim_id; + + // Nothing's been stolen yet. When true, this will flag + // setup_for_execution_pedigree to increment the pedigree + w->l->work_stolen = 0; + + /* If the user has disabled stealing (using the debugger) we fail */ + if (__builtin_expect(w->g->stealing_disabled, 0)) + return; + + CILK_ASSERT(w->l->type == WORKER_SYSTEM || w->l->team == w); + + /* If there is only one processor work can still be stolen. + There must be only one worker to prevent stealing. */ + CILK_ASSERT(w->g->total_workers > 1); + + /* pick random *other* victim */ + n = myrand(w) % (w->g->total_workers - 1); + if (n >= w->self) + ++n; + + // If we're replaying a log, override the victim. -1 indicates that + // we've exhausted the list of things this worker stole when we recorded + // the log so just return. If we're not replaying a log, + // replay_get_next_recorded_victim() just returns the victim ID passed in. + n = replay_get_next_recorded_victim(w, n); + if (-1 == n) + return; + + victim = w->g->workers[n]; + + START_INTERVAL(w, INTERVAL_FIBER_ALLOCATE) { + /* Verify that we can get a stack. If not, no need to continue. */ + fiber = cilk_fiber_allocate(&w->l->fiber_pool); + } STOP_INTERVAL(w, INTERVAL_FIBER_ALLOCATE); + + + if (NULL == fiber) { +#if FIBER_DEBUG >= 2 + fprintf(stderr, "w=%d: failed steal because we could not get a fiber\n", + w->self); +#endif + return; + } + + /* do not steal from self */ + CILK_ASSERT (victim != w); + + /* Execute a quick check before engaging in the THE protocol. + Avoid grabbing locks if there is nothing to steal. */ + if (!can_steal_from(victim)) { + NOTE_INTERVAL(w, INTERVAL_STEAL_FAIL_EMPTYQ); + START_INTERVAL(w, INTERVAL_FIBER_DEALLOCATE) { + int ref_count = cilk_fiber_remove_reference(fiber, &w->l->fiber_pool); + // Fibers we use when trying to steal should not be active, + // and thus should not have any other references. + CILK_ASSERT(0 == ref_count); + } STOP_INTERVAL(w, INTERVAL_FIBER_DEALLOCATE); + return; + } + + /* Attempt to steal work from the victim */ + if (worker_trylock_other(w, victim)) { + if (w->l->type == WORKER_USER && victim->l->team != w) { + + // Fail to steal if this is a user worker and the victim is not + // on this team. If a user worker were allowed to steal work + // descended from another user worker, the former might not be + // done with its work by the time it was needed to resume and + // unbind. Therefore, user workers are not permitted to change + // teams. + + // There is no race on the victim's team because the victim cannot + // change its team until it runs out of work to do, at which point + // it will try to take out its own lock, and this worker already + // holds it. + NOTE_INTERVAL(w, INTERVAL_STEAL_FAIL_USER_WORKER); + + } else if (victim->l->frame_ff) { + // A successful steal will change victim->frame_ff, even + // though the victim may be executing. Thus, the lock on + // the victim's deque is also protecting victim->frame_ff. + if (dekker_protocol(victim)) { + int proceed_with_steal = 1; // optimistic + + // If we're replaying a log, verify that this the correct frame + // to steal from the victim + if (! replay_match_victim_pedigree(w, victim)) + { + // Abort the steal attempt. decrement_E(victim) to + // counter the increment_E(victim) done by the + // dekker protocol + decrement_E(victim); + proceed_with_steal = 0; + } + + if (proceed_with_steal) + { + START_INTERVAL(w, INTERVAL_STEAL_SUCCESS) { + success = 1; + detach_for_steal(w, victim, fiber); + victim_id = victim->self; + + #if REDPAR_DEBUG >= 1 + fprintf(stderr, "Wkr %d stole from victim %d, fiber = %p\n", + w->self, victim->self, fiber); + #endif + + // The use of victim->self contradicts our + // classification of the "self" field as + // local. But since this code is only for + // debugging, it is ok. + DBGPRINTF ("%d-%p: Stealing work from worker %d\n" + " sf: %p, call parent: %p\n", + w->self, GetCurrentFiber(), victim->self, + w->l->next_frame_ff->call_stack, + w->l->next_frame_ff->call_stack->call_parent); + } STOP_INTERVAL(w, INTERVAL_STEAL_SUCCESS); + } // end if(proceed_with_steal) + } else { + NOTE_INTERVAL(w, INTERVAL_STEAL_FAIL_DEKKER); + } + } else { + NOTE_INTERVAL(w, INTERVAL_STEAL_FAIL_EMPTYQ); + } + worker_unlock_other(w, victim); + } else { + NOTE_INTERVAL(w, INTERVAL_STEAL_FAIL_LOCK); + } + + // Record whether work was stolen. When true, this will flag + // setup_for_execution_pedigree to increment the pedigree + w->l->work_stolen = success; + + if (0 == success) { + // failed to steal work. Return the fiber to the pool. + START_INTERVAL(w, INTERVAL_FIBER_DEALLOCATE) { + int ref_count = cilk_fiber_remove_reference(fiber, &w->l->fiber_pool); + // Fibers we use when trying to steal should not be active, + // and thus should not have any other references. + CILK_ASSERT(0 == ref_count); + } STOP_INTERVAL(w, INTERVAL_FIBER_DEALLOCATE); + } + else + { + // Since our steal was successful, finish initialization of + // the fiber. + cilk_fiber_reset_state(fiber, + fiber_proc_to_resume_user_code_for_random_steal); + // Record the pedigree of the frame that w has stolen. + // record only if CILK_RECORD_LOG is set + replay_record_steal(w, victim_id); + } +} + + + +/** + * At a provably good steal, we need to transfer the child reducer map + * from ff->children_reducer_map into v->reducer_map, where v is the + * worker that resumes execution of ff. + * + * Normally, we have v == w, where w is the currently executing + * worker. In the case where we are resuming a team leader on a user + * worker, however, v might differ from w. + + * Thus, this, operation is a no-op, since we can't really move + * ff->children_reducer_map into w here. + * + * Instead, this work is done in setup_for_execution_reducers(). + */ +static inline void provably_good_steal_reducers(__cilkrts_worker *w, + full_frame *ff) +{ + // No-op. +} + +/* at a provably good steal, incorporate the accumulated exceptions of + children into the parent's exception */ +static void provably_good_steal_exceptions(__cilkrts_worker *w, + full_frame *ff) +{ + // ASSERT: we own ff->lock + ff->pending_exception = + __cilkrts_merge_pending_exceptions(w, + ff->child_pending_exception, + ff->pending_exception); + ff->child_pending_exception = NULL; +} + +/* At sync discard the frame's old stack and take the leftmost child's. */ +static void provably_good_steal_stacks(__cilkrts_worker *w, full_frame *ff) +{ + CILK_ASSERT(NULL == ff->fiber_self); + ff->fiber_self = ff->fiber_child; + ff->fiber_child = NULL; +} + +static void __cilkrts_mark_synched(full_frame *ff) +{ + ff->call_stack->flags &= ~CILK_FRAME_UNSYNCHED; + ff->simulated_stolen = 0; +} + +static +enum provably_good_steal_t provably_good_steal(__cilkrts_worker *w, + full_frame *ff) +{ + // ASSERT: we hold w->lock and ff->lock + + enum provably_good_steal_t result = ABANDON_EXECUTION; + + // If the current replay entry is a sync record matching the worker's + // pedigree, AND this isn't the last child to the sync, return + // WAIT_FOR_CONTINUE to indicate that the caller should loop until + // we find the right frame to steal and CONTINUE_EXECUTION is returned. + int match_found = replay_match_sync_pedigree(w); + if (match_found && (0 != simulate_decjoin(ff))) + return WAIT_FOR_CONTINUE; + + START_INTERVAL(w, INTERVAL_PROVABLY_GOOD_STEAL) { + if (decjoin(ff) == 0) { + provably_good_steal_reducers(w, ff); + provably_good_steal_exceptions(w, ff); + provably_good_steal_stacks(w, ff); + __cilkrts_mark_synched(ff); + + // If the original owner wants this frame back (to resume + // it on its original thread) pass it back now. + if (NULL != ff->sync_master) { + // The frame wants to go back and be executed by the original + // user thread. We can throw caution to the wind and push the + // frame straight onto its queue because the only way we have + // gotten to this point of being able to continue execution of + // the frame is if the original user worker is spinning without + // work. + + unset_sync_master(w->l->team, ff); + __cilkrts_push_next_frame(w->l->team, ff); + + // If this is the team leader we're not abandoning the work + if (w == w->l->team) + result = CONTINUE_EXECUTION; + } else { + __cilkrts_push_next_frame(w, ff); + result = CONTINUE_EXECUTION; // Continue working on this thread + } + + // The __cilkrts_push_next_frame() call changes ownership + // of ff to the specified worker. + } + } STOP_INTERVAL(w, INTERVAL_PROVABLY_GOOD_STEAL); + + // Only write a SYNC record if: + // - We're recording a log *AND* + // - We're the worker continuing from this sync + replay_record_sync(w, result == CONTINUE_EXECUTION); + + // If we're replaying a log, and matched a sync from the log, mark the + // sync record seen if the sync isn't going to be abandoned. + replay_advance_from_sync (w, match_found, result == CONTINUE_EXECUTION); + + return result; +} + +static void unconditional_steal(__cilkrts_worker *w, + full_frame *ff) +{ + // ASSERT: we hold ff->lock + + START_INTERVAL(w, INTERVAL_UNCONDITIONAL_STEAL) { + decjoin(ff); + __cilkrts_push_next_frame(w, ff); + } STOP_INTERVAL(w, INTERVAL_UNCONDITIONAL_STEAL); +} + + +/* CHILD is about to die. Give its exceptions to a sibling or to the + parent. */ +static inline void splice_exceptions_for_call(__cilkrts_worker *w, + full_frame *parent_ff, + full_frame *child_ff) +{ + // ASSERT: We own parent_ff->lock + CILK_ASSERT(child_ff->is_call_child); + CILK_ASSERT(NULL == child_ff->right_pending_exception); + CILK_ASSERT(NULL == parent_ff->pending_exception); + + parent_ff->pending_exception = child_ff->pending_exception; + child_ff->pending_exception = NULL; +} + +/** + * Merge exceptions for a dying child. + * + * @param w The currently executing worker. + * @param ff The child frame that is dying. + * @param left_exception_ptr Pointer to the exception that is to our left. + */ +static inline +void splice_exceptions_for_spawn(__cilkrts_worker *w, + full_frame *ff, + struct pending_exception_info **left_exception_ptr) +{ + // ASSERT: parent_ff == child_ff->parent. + // ASSERT: We own parent_ff->lock + + // Merge current exception into the slot where the left + // exception should go. + *left_exception_ptr = + __cilkrts_merge_pending_exceptions(w, + *left_exception_ptr, + ff->pending_exception); + ff->pending_exception = NULL; + + + // Merge right exception into the slot where the left exception + // should go. + *left_exception_ptr = + __cilkrts_merge_pending_exceptions(w, + *left_exception_ptr, + ff->right_pending_exception); + ff->right_pending_exception = NULL; +} + + +static inline void splice_stacks_for_call(__cilkrts_worker *w, + full_frame *parent_ff, + full_frame *child_ff) +{ +#if CILK_LIB_DEBUG + if (parent_ff->call_stack) + CILK_ASSERT(!(parent_ff->call_stack->flags & CILK_FRAME_MBZ)); +#endif + + /* A synched frame does not have accumulated child reducers. */ + CILK_ASSERT(!child_ff->fiber_child); + CILK_ASSERT(child_ff->is_call_child); + + /* An attached parent has no self fiber. It may have + accumulated child fibers or child owners, which should be + ignored until sync. */ + CILK_ASSERT(!parent_ff->fiber_self); + parent_ff->fiber_self = child_ff->fiber_self; + child_ff->fiber_self = NULL; +} + +static void finalize_child_for_call(__cilkrts_worker *w, + full_frame *parent_ff, + full_frame *child_ff) +{ + // ASSERT: we hold w->lock and parent_ff->lock + + START_INTERVAL(w, INTERVAL_FINALIZE_CHILD) { + CILK_ASSERT(child_ff->is_call_child); + CILK_ASSERT(child_ff->join_counter == 0); + CILK_ASSERT(!child_ff->rightmost_child); + CILK_ASSERT(child_ff == parent_ff->rightmost_child); + + // CHILD is about to die. + // Splicing out reducers is a no-op for a call since + // w->reducer_map should already store the correct + // reducer map. + + // ASSERT there are no maps left to reduce. + CILK_ASSERT(NULL == child_ff->children_reducer_map); + CILK_ASSERT(NULL == child_ff->right_reducer_map); + + splice_exceptions_for_call(w, parent_ff, child_ff); + + splice_stacks_for_call(w, parent_ff, child_ff); + + /* remove CHILD from list of children of PARENT */ + unlink_child(parent_ff, child_ff); + + /* continue with the parent. */ + unconditional_steal(w, parent_ff); + __cilkrts_destroy_full_frame(w, child_ff); + } STOP_INTERVAL(w, INTERVAL_FINALIZE_CHILD); +} + + +/** + * The invariant on ff->children_reducer_map is that when ff is + * synched and when we are about to resume execution of ff, at least + * one of ff->children_reducer_map and w->reducer_map must be NULL. + * + * Consider the two possibilities before resuming execution of ff: + * + * 1. Suppose ff is synched and suspended. Then either + * + * (a) ff->children_reducer_map stores the reducer map that w + * should use, where w is the worker resuming execution of ff, + * OR + * (b) w already has a user map, and ff->children_reducer_map is NULL. + * + * Case (a) happens when we are resuming execution of ff as a + * provably good steal. In this case, w->reducer_map should be + * NULL and ff->children_reducer_map is valid. To resume + * execution of ff on w, set w->reducer_map to + * ff->children_reducer_map. + * + * Case (b) occurs when we resume execution of ff because ff is a + * called child. Then, ff->children_reducer_map should be NULL, + * and w should already have a valid reducer map when resuming + * execution of ff. We resume execution of ff without changing + * w->reducer_map. + * + * 2. Suppose frame ff is not synched (i.e., it is active and might have + * active children). Then ff->children_reducer_map is the slot for + * storing the reducer map from ff's leftmost child, as in the reducer + * protocol. The runtime may resume execution of ff while it is not + * synched only because of a steal. + * In this case, while we are resuming ff, ff->children_reducer_map + * may be non-NULL (because one of ff's children has completed). + * We resume execution of ff without changing w->reducer_map. + */ +static void setup_for_execution_reducers(__cilkrts_worker *w, + full_frame *ff) +{ + // We only need to move ff->children_reducer_map into + // w->reducer_map in case 1(a). + // + // First check whether ff is synched. + __cilkrts_stack_frame *sf = ff->call_stack; + if (!(sf->flags & CILK_FRAME_UNSYNCHED)) { + // In this case, ff is synched. (Case 1). + CILK_ASSERT(!ff->rightmost_child); + + // Test whether we are in case 1(a) and have + // something to do. Note that if both + // ff->children_reducer_map and w->reducer_map are NULL, we + // can't distinguish between cases 1(a) and 1(b) here. + if (ff->children_reducer_map) { + // We are in Case 1(a). + CILK_ASSERT(!w->reducer_map); + w->reducer_map = ff->children_reducer_map; + ff->children_reducer_map = NULL; + } + } +} + +static void setup_for_execution_exceptions(__cilkrts_worker *w, + full_frame *ff) +{ + CILK_ASSERT(NULL == w->l->pending_exception); + w->l->pending_exception = ff->pending_exception; + ff->pending_exception = NULL; +} + +#if 0 /* unused */ +static void setup_for_execution_stack(__cilkrts_worker *w, + full_frame *ff) +{ +} +#endif + +/* + * setup_for_execution_pedigree + * + * Copies the pedigree information from the frame we're resuming to the + * worker. Increments the pedigree if this is work that has been stolen + * to match the increment on a return from a spawn helper. + */ +static void setup_for_execution_pedigree(__cilkrts_worker *w) +{ + int pedigree_unsynched; + __cilkrts_stack_frame *sf = w->current_stack_frame; + + CILK_ASSERT(NULL != sf); + + // If this isn't an ABI 1 or later frame, there's no pedigree information + if (0 == CILK_FRAME_VERSION_VALUE(sf->flags)) + return; + + // Note whether the pedigree is unsynched and clear the flag before + // we forget + pedigree_unsynched = sf->flags & CILK_FRAME_SF_PEDIGREE_UNSYNCHED; + sf->flags &= ~CILK_FRAME_SF_PEDIGREE_UNSYNCHED; + + // If we're just marshalling onto this worker, do not increment + // the rank since that wouldn't happen in a sequential execution + if (w->l->work_stolen || pedigree_unsynched) + { + if (w->l->work_stolen) + w->pedigree.rank = sf->parent_pedigree.rank + 1; + else + w->pedigree.rank = sf->parent_pedigree.rank; + } + + w->pedigree.parent = sf->parent_pedigree.parent; + w->l->work_stolen = 0; +} + +static void setup_for_execution(__cilkrts_worker *w, + full_frame *ff, + int is_return_from_call) +{ + // ASSERT: We own w->lock and ff->lock || P == 1 + + setup_for_execution_reducers(w, ff); + setup_for_execution_exceptions(w, ff); + /*setup_for_execution_stack(w, ff);*/ + + ff->call_stack->worker = w; + w->current_stack_frame = ff->call_stack; + + // If this is a return from a call, leave the pedigree alone + if (! is_return_from_call) + setup_for_execution_pedigree(w); + + __cilkrts_setup_for_execution_sysdep(w, ff); + + w->head = w->tail = w->l->ltq; + reset_THE_exception(w); + + make_runnable(w, ff); +} + + +/* + * Called by the scheduling fiber, right before + * resuming a sf/ff for user code. + * + * This method associates the specified sf with the worker. + * + * It also asserts that w, ff, and sf all have the expected properties + * for resuming user code. + */ +void scheduling_fiber_prepare_to_resume_user_code(__cilkrts_worker *w, + full_frame *ff, + __cilkrts_stack_frame *sf) +{ + w->current_stack_frame = sf; + sf->worker = w; + + // Lots of debugging checks on the state of the fiber we might be + // resuming. +#if FIBER_DEBUG >= 1 +# if FIBER_DEBUG >= 3 + { + fprintf(stderr, "w=%d: ff=%p, sf=%p. about to resume user code\n", + w->self, ff, sf); + } +# endif + + const int flags = sf->flags; + CILK_ASSERT(flags & CILK_FRAME_SUSPENDED); + CILK_ASSERT(!sf->call_parent); + CILK_ASSERT(w->head == w->tail); + + /* A frame can not be resumed unless it was suspended. */ + CILK_ASSERT(ff->sync_sp != NULL); + + /* The leftmost frame has no allocated stack */ + if (ff->simulated_stolen) + CILK_ASSERT(flags & CILK_FRAME_UNSYNCHED); + else if (flags & CILK_FRAME_UNSYNCHED) + /* XXX By coincidence sync_sp could be null. */ + CILK_ASSERT(ff->fiber_self != NULL); + else + /* XXX This frame could be resumed unsynched on the leftmost stack */ + CILK_ASSERT((ff->sync_master == 0 || ff->sync_master == w)); + CILK_ASSERT(w->l->frame_ff == ff); +#endif +} + + +/** + * This method is the first method that should execute after we've + * switched to a scheduling fiber from user code. + * + * @param fiber The scheduling fiber for the current worker. + * @param wptr The current worker. + */ +static void enter_runtime_transition_proc(cilk_fiber *fiber) +{ + // We can execute this method for one of three reasons: + // 1. Undo-detach finds parent stolen. + // 2. Sync suspends frame. + // 3. Return from Cilk entry point. + // + // + // In cases 1 and 2, the frame may be truly suspended or + // may be immediately executed by this worker after provably_good_steal. + // + // + // There is a fourth case, which can, but does not need to execute + // this function: + // 4. Starting up the scheduling loop on a user or + // system worker. In this case, we won't have + // a scheduling stack function to run. + __cilkrts_worker* w = cilk_fiber_get_owner(fiber); + if (w->l->post_suspend) { + // Run the continuation function passed to longjmp_into_runtime + run_scheduling_stack_fcn(w); + + // After we have jumped into the runtime and run the + // scheduling function, any reducer map the worker had before entering the runtime + // should have already been saved into the appropriate full + // frame. + CILK_ASSERT(NULL == w->reducer_map); + + // There shouldn't be any uncaught exceptions. + // + // In Windows, the OS catches any exceptions not caught by the + // user code. Thus, we are omitting the check on Windows. + // + // On Android, calling std::uncaught_exception with the stlport + // library causes a seg fault. Since we're not supporting + // exceptions there at this point, just don't do the check + // + // TBD: Is this check also safe to do on Windows? + CILKBUG_ASSERT_NO_UNCAUGHT_EXCEPTION(); + } +} + + +/** + * Method called to jump back to executing user code. + * + * A normal return from the runtime back to resuming user code calls + * this method. A computation executed using force_reduce also calls + * this method to return to user code. + * + * This function should not contain any code that depends on a fiber. + * In a force-reduce case, the user worker may not have a fiber. In + * the force-reduce case, we call this method directly instead of + * calling @c user_code_resume_after_switch_into_runtime. + */ +static inline NORETURN +cilkrts_resume(__cilkrts_stack_frame *sf, full_frame *ff) +{ + // Save the sync stack pointer, and do the bookkeeping + char* sync_sp = ff->sync_sp; + __cilkrts_take_stack(ff, sync_sp); // leaves ff->sync_sp null + + sf->flags &= ~CILK_FRAME_SUSPENDED; + // Actually longjmp to the user code. + // We may have exceptions to deal with, since we are resuming + // a previous-suspended frame. + sysdep_longjmp_to_sf(sync_sp, sf, ff); +} + + +/** + * Called by the user-code fiber right before resuming a full frame + * (sf/ff). + * + * This method pulls sf/ff out of the worker, and then calls + * cilkrts_resume to jump to user code. + */ +static NORETURN +user_code_resume_after_switch_into_runtime(cilk_fiber *fiber) +{ + __cilkrts_worker *w = cilk_fiber_get_owner(fiber); + __cilkrts_stack_frame *sf; + full_frame *ff; + sf = w->current_stack_frame; + ff = sf->worker->l->frame_ff; + +#if FIBER_DEBUG >= 1 + CILK_ASSERT(ff->fiber_self == fiber); + cilk_fiber_data *fdata = cilk_fiber_get_data(fiber); + DBGPRINTF ("%d-%p: resume_after_switch_into_runtime, fiber=%p\n", + w->self, w, fiber); + CILK_ASSERT(sf == fdata->resume_sf); +#endif + + // Notify the Intel tools that we're stealing code + ITT_SYNC_ACQUIRED(sf->worker); + NOTIFY_ZC_INTRINSIC("cilk_continue", sf); + cilk_fiber_invoke_tbb_stack_op(fiber, CILK_TBB_STACK_ADOPT); + + // Actually jump to user code. + cilkrts_resume(sf, ff); + } + + +/* The current stack is about to either be suspended or destroyed. This + * function will switch to the stack on which the scheduler is suspended and + * resume running the scheduler within function do_work(). Upon waking up, + * the scheduler will run the 'cont' function, using the supplied worker and + * frame. + */ +static NORETURN +longjmp_into_runtime(__cilkrts_worker *w, + scheduling_stack_fcn_t fcn, + __cilkrts_stack_frame *sf) +{ + full_frame *ff, *ff2; + + CILK_ASSERT(!w->l->post_suspend); + ff = w->l->frame_ff; + + // If we've got only one worker, stealing shouldn't be possible. + // Assume that this is a steal or return from spawn in a force-reduce case. + // We don't have a scheduling stack to switch to, so call the continuation + // function directly. + if (1 == w->g->P) { + fcn(w, ff, sf); + + /* The call to function c() will have pushed ff as the next frame. If + * this were a normal (non-forced-reduce) execution, there would have + * been a pop_next_frame call in a separate part of the runtime. We + * must call pop_next_frame here to complete the push/pop cycle. */ + ff2 = pop_next_frame(w); + + setup_for_execution(w, ff2, 0); + scheduling_fiber_prepare_to_resume_user_code(w, ff2, w->current_stack_frame); + cilkrts_resume(w->current_stack_frame, ff2); + +// Suppress clang warning that the expression result is unused +#if defined(__clang__) && (! defined(__INTEL_COMPILER)) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunused-value" +#endif // __clang__ + /* no return */ + CILK_ASSERT(((void)"returned from __cilkrts_resume", 0)); +#if defined(__clang__) && (! defined(__INTEL_COMPILER)) +# pragma clang diagnostic pop +#endif // __clang__ + } + + w->l->post_suspend = fcn; + w->l->suspended_stack = sf; + + ITT_SYNC_RELEASING(w); + ITT_SYNC_PREPARE(w); + +#if FIBER_DEBUG >= 2 + fprintf(stderr, "ThreadId=%p, W=%d: about to switch into runtime... w->l->frame_ff = %p, sf=%p\n", + cilkos_get_current_thread_id(), + w->self, w->l->frame_ff, + sf); +#endif + + // Current fiber is either the (1) one we are about to free, + // or (2) it has been passed up to the parent. + cilk_fiber *current_fiber = ( w->l->fiber_to_free ? + w->l->fiber_to_free : + w->l->frame_ff->parent->fiber_child ); + cilk_fiber_data* fdata = cilk_fiber_get_data(current_fiber); + CILK_ASSERT(NULL == w->l->frame_ff->fiber_self); + + // Clear the sf in the current fiber for cleanliness, to prevent + // us from accidentally resuming a bad sf. + // Technically, resume_sf gets overwritten for a fiber when + // we are about to resume it anyway. + fdata->resume_sf = NULL; + CILK_ASSERT(fdata->owner == w); + + // Set the function to execute immediately after switching to the + // scheduling fiber, but before freeing any fibers. + cilk_fiber_set_post_switch_proc(w->l->scheduling_fiber, + enter_runtime_transition_proc); + cilk_fiber_invoke_tbb_stack_op(current_fiber, CILK_TBB_STACK_ORPHAN); + + if (w->l->fiber_to_free) { + // Case 1: we are freeing this fiber. We never + // resume this fiber again after jumping into the runtime. + w->l->fiber_to_free = NULL; + + // Extra check. Normally, the fiber we are about to switch to + // should have a NULL owner. + CILK_ASSERT(NULL == cilk_fiber_get_data(w->l->scheduling_fiber)->owner); +#if FIBER_DEBUG >= 4 + fprintf(stderr, "ThreadId=%p, W=%d: about to switch into runtime.. current_fiber = %p, deallcoate, switch to fiber %p\n", + cilkos_get_current_thread_id(), + w->self, + current_fiber, w->l->scheduling_fiber); +#endif + cilk_fiber_invoke_tbb_stack_op(current_fiber, CILK_TBB_STACK_RELEASE); + NOTE_INTERVAL(w, INTERVAL_DEALLOCATE_RESUME_OTHER); + cilk_fiber_remove_reference_from_self_and_resume_other(current_fiber, + &w->l->fiber_pool, + w->l->scheduling_fiber); + // We should never come back here! + CILK_ASSERT(0); + } + else { + // Case 2: We are passing the fiber to our parent because we + // are leftmost. We should come back later to + // resume execution of user code. + // + // If we are not freeing a fiber, there we must be + // returning from a spawn or processing an exception. The + // "sync" path always frees a fiber. + // + // We must be the leftmost child, and by left holder logic, we + // have already moved the current fiber into our parent full + // frame. +#if FIBER_DEBUG >= 2 + fprintf(stderr, "ThreadId=%p, W=%d: about to suspend self into runtime.. current_fiber = %p, deallcoate, switch to fiber %p\n", + cilkos_get_current_thread_id(), + w->self, + current_fiber, w->l->scheduling_fiber); +#endif + + NOTE_INTERVAL(w, INTERVAL_SUSPEND_RESUME_OTHER); + + cilk_fiber_suspend_self_and_resume_other(current_fiber, + w->l->scheduling_fiber); + // Resuming this fiber returns control back to + // this function because our implementation uses OS fibers. + // + // On Unix, we could have the choice of passing the + // user_code_resume_after_switch_into_runtime as an extra "resume_proc" + // that resumes execution of user code instead of the + // jumping back here, and then jumping back to user code. +#if FIBER_DEBUG >= 2 + CILK_ASSERT(fdata->owner == __cilkrts_get_tls_worker()); +#endif + user_code_resume_after_switch_into_runtime(current_fiber); + } +} + +/* + * Send a message to the children of the specified worker: run or wait. + */ +static void notify_children(__cilkrts_worker *w, unsigned int msg) +{ + int child_num; + __cilkrts_worker *child; + int num_sys_workers = w->g->P - 1; + + // If worker is "n", then its children are 2n + 1, and 2n + 2. + child_num = (w->self << 1) + 1; + if (child_num < num_sys_workers) { + child = w->g->workers[child_num]; + CILK_ASSERT(child->l->signal_node); + signal_node_msg(child->l->signal_node, msg); + child_num++; + if (child_num < num_sys_workers) { + child = w->g->workers[child_num]; + CILK_ASSERT(child->l->signal_node); + signal_node_msg(child->l->signal_node, msg); + } + } +} + +/* + * Notify this worker's children that they need to wait. + */ +static void notify_children_wait(__cilkrts_worker *w) +{ + notify_children(w, 0); +} + +/* + * Notify this worker's children to run and start trying to steal. + */ +static void notify_children_run(__cilkrts_worker *w) +{ + notify_children(w, 1); +} + +/** + * A single "check" to find work, either on our queue or through a + * steal attempt. This method checks our local queue once, and + * performs one steal attempt. + */ +static full_frame* check_for_work(__cilkrts_worker *w) +{ + full_frame *ff = NULL; + ff = pop_next_frame(w); + // If there is no work on the queue, try to steal some. + if (NULL == ff) { + START_INTERVAL(w, INTERVAL_STEALING) { + if (w->l->type != WORKER_USER && w->l->team != NULL) { + // At this point, the worker knows for certain that it has run + // out of work. Therefore, it loses its team affiliation. User + // workers never change teams, of course. + __cilkrts_worker_lock(w); + w->l->team = NULL; + __cilkrts_worker_unlock(w); + } + + // If we are about to do a random steal, we should have no + // full frame... + CILK_ASSERT(NULL == w->l->frame_ff); + random_steal(w); + } STOP_INTERVAL(w, INTERVAL_STEALING); + + // If the steal was successful, then the worker has populated its next + // frame with the work to resume. + ff = pop_next_frame(w); + if (NULL == ff) { + // Punish the worker for failing to steal. + // No quantum for you! + __cilkrts_yield(); + w->l->steal_failure_count++; + } else { + // Reset steal_failure_count since there is obviously still work to + // be done. + w->l->steal_failure_count = 0; + } + } + return ff; +} + +/** + * Keep stealing or looking on our queue. + * + * Returns either when a full frame is found, or NULL if the + * computation is done. + */ +static full_frame* search_until_work_found_or_done(__cilkrts_worker *w) +{ + full_frame *ff = NULL; + // Find a full frame to execute (either through random stealing, + // or because we pull it off w's 1-element queue). + while (!ff) { + // Check worker state to figure out our next action. + switch (worker_runnable(w)) + { + case SCHEDULE_RUN: // One attempt at checking for work. + ff = check_for_work(w); + break; + case SCHEDULE_WAIT: // go into wait-mode. + CILK_ASSERT(WORKER_SYSTEM == w->l->type); + // If we are about to wait, then we better not have + // a frame that we should execute... + CILK_ASSERT(NULL == w->l->next_frame_ff); + notify_children_wait(w); + signal_node_wait(w->l->signal_node); + // ... + // Runtime is waking up. + notify_children_run(w); + w->l->steal_failure_count = 0; + break; + case SCHEDULE_EXIT: // exit the scheduler. + CILK_ASSERT(WORKER_USER != w->l->type); + return NULL; + default: + CILK_ASSERT(0); + abort(); + } + } + return ff; +} + +/** + * The proc method for a scheduling fiber on a user worker. + * + * When a user worker jumps into the runtime, it jumps into this + * method by either starting it if the scheduling fiber has never run + * before, or resuming the fiber if it was previously suspended. + */ +COMMON_PORTABLE +void scheduler_fiber_proc_for_user_worker(cilk_fiber *fiber) +{ + __cilkrts_worker* w = cilk_fiber_get_owner(fiber); + CILK_ASSERT(w); + + // This must be a user worker + CILK_ASSERT(WORKER_USER == w->l->type); + + // If we aren't the current worker, then something is very wrong + // here.. + verify_current_wkr(w); + + __cilkrts_run_scheduler_with_exceptions(w); +} + + +/** + * The body of the runtime scheduling loop. This function executes in + * 4 stages: + * + * 1. Transitions from the user code into the runtime by + * executing any scheduling-stack functions. + * 2. Looks for a full frame enqueued from a successful provably + * good steal. + * 3. If no full frame is found in step 2, steal until + * a frame is found or we are done. If we are done, finish + * the scheduling loop. + * 4. When a frame is found, setup to resume user code. + * In particular, suspend the current fiber and resume the + * user fiber to execute the frame. + * + * Returns a fiber object that we should switch to after completing + * the body of the loop, or NULL if we should continue executing on + * this fiber. + * + * @pre @c current_fiber should equal @c wptr->l->scheduling_fiber + * + * @param current_fiber The currently executing (scheduling_ fiber + * @param wptr The currently executing worker. + * @param return The next fiber we should switch to. + */ +static cilk_fiber* worker_scheduling_loop_body(cilk_fiber* current_fiber, + void* wptr) +{ + __cilkrts_worker *w = (__cilkrts_worker*) wptr; + CILK_ASSERT(current_fiber == w->l->scheduling_fiber); + + // Stage 1: Transition from executing user code to the runtime code. + // We don't need to do this call here any more, because + // every switch to the scheduling fiber should make this call + // using a post_switch_proc on the fiber. + // + // enter_runtime_transition_proc(w->l->scheduling_fiber, wptr); + + // After Stage 1 is complete, w should no longer have + // an associated full frame. + CILK_ASSERT(NULL == w->l->frame_ff); + + // Stage 2. First do a quick check of our 1-element queue. + full_frame *ff = pop_next_frame(w); + + if (!ff) { + // Stage 3. We didn't find anything from our 1-element + // queue. Now go through the steal loop to find work. + ff = search_until_work_found_or_done(w); + if (!ff) { + CILK_ASSERT(w->g->work_done); + return NULL; + } + } + + // Stage 4. Now that we have found a full frame to work on, + // actually execute it. + __cilkrts_stack_frame *sf; + + // There shouldn't be any uncaught exceptions. + // + // In Windows, the OS catches any exceptions not caught by the + // user code. Thus, we are omitting the check on Windows. + // + // On Android, calling std::uncaught_exception with the stlport + // library causes a seg fault. Since we're not supporting + // exceptions there at this point, just don't do the check + CILKBUG_ASSERT_NO_UNCAUGHT_EXCEPTION(); + + BEGIN_WITH_WORKER_LOCK(w) { + CILK_ASSERT(!w->l->frame_ff); + BEGIN_WITH_FRAME_LOCK(w, ff) { + sf = ff->call_stack; + CILK_ASSERT(sf && !sf->call_parent); + setup_for_execution(w, ff, 0); + } END_WITH_FRAME_LOCK(w, ff); + } END_WITH_WORKER_LOCK(w); + + /* run it */ + // + // Prepare to run the full frame. To do so, we need to: + // (a) Execute some code on this fiber (the scheduling + // fiber) to set up data structures, and + // (b) Suspend the scheduling fiber, and resume the + // user-code fiber. + + // Part (a). Set up data structures. + scheduling_fiber_prepare_to_resume_user_code(w, ff, sf); + + cilk_fiber *other = w->l->frame_ff->fiber_self; + cilk_fiber_data* other_data = cilk_fiber_get_data(other); + cilk_fiber_data* current_fiber_data = cilk_fiber_get_data(current_fiber); + + // I believe two cases are possible here, both of which + // should have other_data->resume_sf as NULL. + // + // 1. Resuming a fiber that was previously executing + // user code (i.e., a provably-good-steal). + // In this case, resume_sf should have been + // set to NULL when it was suspended. + // + // 2. Resuming code on a steal. In this case, since we + // grabbed a new fiber, resume_sf should be NULL. + CILK_ASSERT(NULL == other_data->resume_sf); + +#if FIBER_DEBUG >= 2 + fprintf(stderr, "W=%d: other fiber=%p, setting resume_sf to %p\n", + w->self, other, other_data->resume_sf); +#endif + // Update our own fiber's data. + current_fiber_data->resume_sf = NULL; + // The scheduling fiber should have the right owner from before. + CILK_ASSERT(current_fiber_data->owner == w); + other_data->resume_sf = sf; + + +#if FIBER_DEBUG >= 3 + fprintf(stderr, "ThreadId=%p (about to suspend self resume other), W=%d: current_fiber=%p, other=%p, current_fiber->resume_sf = %p, other->resume_sf = %p\n", + cilkos_get_current_thread_id(), + w->self, + current_fiber, other, + current_fiber_data->resume_sf, + other_data->resume_sf); +#endif + return other; +} + + +/** + * This function is executed once by each worker, to initialize its + * scheduling loop. + */ +static void worker_scheduler_init_function(__cilkrts_worker *w) +{ + // First, execute the startup tasks that must happen for all + // worker types. + ITT_SYNC_PREPARE(w); + /* Notify tools about the new worker. Inspector needs this, but we + don't want to confuse Cilkscreen with system threads. User threads + do this notification in bind_thread */ + if (! w->g->under_ptool) + __cilkrts_cilkscreen_establish_worker(w); + + // Seed the initial random number generator. + // If we forget to do this, then the worker always steals from 0. + // Programs will still execute correctly, but + // you may see a subtle performance bug... + mysrand(w, (w->self + 1)); + + // The startup work varies, depending on the worker type. + switch (w->l->type) { + case WORKER_USER: + // Stop working once we've entered the scheduler. + // For user workers, INTERVAL_IN_SCHEDULER counts the time + // since we called bind_thread. + break; + + case WORKER_SYSTEM: + // If a system worker is starting, we must also be starting + // the runtime. + + // Runtime begins in a wait-state and is woken up by the first user + // worker when the runtime is ready. + signal_node_wait(w->l->signal_node); + // ... + // Runtime is waking up. + notify_children_run(w); + w->l->steal_failure_count = 0; + + // For system threads, count all the time this thread is + // alive in the scheduling loop. + START_INTERVAL(w, INTERVAL_IN_SCHEDULER); + START_INTERVAL(w, INTERVAL_WORKING); + break; + default: + __cilkrts_bug("Unknown worker %p of type %d entering scheduling loop\n", + w, w->l->type); + } +} + +/** + * This function is executed once by each worker, to finish its + * scheduling loop. + * + * @note Currently, only system workers finish their loops. User + * workers will jump away to user code without exiting their + * scheduling loop. + */ +static void worker_scheduler_terminate_function(__cilkrts_worker *w) +{ + // A user worker should never finish by falling through the + // scheduling loop. + CILK_ASSERT(WORKER_USER != w->l->type); + STOP_INTERVAL(w, INTERVAL_IN_RUNTIME); + STOP_INTERVAL(w, INTERVAL_IN_SCHEDULER); +} + +/** + * The main scheduler function executed by a worker's scheduling + * fiber. + * + * This method is started by either a new system worker, or a user + * worker that has stalled and just been imported into the runtime. + */ +static void worker_scheduler_function(__cilkrts_worker *w) +{ + worker_scheduler_init_function(w); + + // The main scheduling loop body. + + while (!w->g->work_done) { + // Set intervals. Now we are in the runtime instead of working. + START_INTERVAL(w, INTERVAL_IN_RUNTIME); + STOP_INTERVAL(w, INTERVAL_WORKING); + + // Execute the "body" of the scheduling loop, and figure + // out the fiber to jump to next. + cilk_fiber* fiber_to_resume + = worker_scheduling_loop_body(w->l->scheduling_fiber, w); + + if (fiber_to_resume) { + // Suspend the current fiber and resume next one. + NOTE_INTERVAL(w, INTERVAL_SUSPEND_RESUME_OTHER); + STOP_INTERVAL(w, INTERVAL_IN_RUNTIME); + START_INTERVAL(w, INTERVAL_WORKING); + cilk_fiber_suspend_self_and_resume_other(w->l->scheduling_fiber, + fiber_to_resume); + + // Return here only when this (scheduling) fiber is + // resumed (i.e., this worker wants to reenter the runtime). + } + } + + // Finish the scheduling loop. + worker_scheduler_terminate_function(w); +} + + +/************************************************************* + Forward declarations for reduction protocol. +*************************************************************/ + +static __cilkrts_worker* +execute_reductions_for_sync(__cilkrts_worker *w, + full_frame *ff, + __cilkrts_stack_frame *sf_at_sync); + +static __cilkrts_worker* +execute_reductions_for_spawn_return(__cilkrts_worker *w, + full_frame *ff, + __cilkrts_stack_frame *returning_sf); + + + +/************************************************************* + Scheduler functions that are callable by client code +*************************************************************/ +static full_frame *disown(__cilkrts_worker *w, + full_frame *ff, + __cilkrts_stack_frame *sf, + const char *why) +{ + CILK_ASSERT(ff); + make_unrunnable(w, ff, sf, sf != 0, why); + w->l->frame_ff = 0; + return ff->parent; +} + +/** + * Called when ff is returning from a spawn, and we need to execute a + * reduction. + * + * @param w The currently executing worker. + * @param ff The full frame for w. + * @param returning_sf The stack frame for the spawn helper that is returning. + * + * Normally, by the time we gain control in the runtime, the worker + * has already popped off the __cilkrts_stack_frame "returning_sf" + * from its call chain. + * + * When we have only serial reductions, w->current_stack_frame is not + * needed any more, because w is about to enter the runtime scheduling + * loop anyway. Similarly, the frame "ff" is slated to be destroyed + * after the runtime finishes the return from spawn and splices ff out + * of the tree of full frames. + * + * To execute a parallel reduction, however, we still want + * w->current_stack_frame == returning_sf, and we are going to use the + * frame ff for a little bit longer. + * + * This method: + * + * 1. Puts returning_sf back as w's current stack frame. + * 2. Makes "ff" runnable again on w. + */ +static inline +void restore_frame_for_spawn_return_reduction(__cilkrts_worker *w, + full_frame *ff, + __cilkrts_stack_frame *returning_sf) { +#if REDPAR_DEBUG >= 2 + CILK_ASSERT(returning_sf); + CILK_ASSERT(returning_sf->worker == w); +#endif + // Change w's current stack frame back to "returning_sf". + // + // Intuitively, w->current_stack_frame should be + // returning_sf->call_parent at this point. + // + // We can not assert this, however, because the pop of + // returning_sf from the call chain has already cleared + // returning_sf->call_parent. We don't want to restore the call + // parent of returning_sf, because its parent has been stolen, and + // the runtime assumes that steals break this link. + + // We cannot assert call_parent is NULL either, since that's not true for + // Win64 exception handling +// CILK_ASSERT(returning_sf->call_parent == NULL); + w->current_stack_frame = returning_sf; + + // Make the full frame "ff" runnable again, in preparation for + // executing the reduction. + make_runnable(w, ff); +} + + +NORETURN __cilkrts_c_sync(__cilkrts_worker *w, + __cilkrts_stack_frame *sf_at_sync) +{ + full_frame *ff; + + // Claim: This read of w->l->frame_ff can occur without + // holding the worker lock because when w has reached a sync + // and entered the runtime (because it stalls), w's deque is empty + // and no one else can steal and change w->l->frame_ff. + + ff = w->l->frame_ff; +#ifdef _WIN32 + __cilkrts_save_exception_state(w, ff); +#else + // Move any pending exceptions into the full frame + CILK_ASSERT(NULL == ff->pending_exception); + ff->pending_exception = w->l->pending_exception; + w->l->pending_exception = NULL; +#endif + + w = execute_reductions_for_sync(w, ff, sf_at_sync); + +#if FIBER_DEBUG >= 3 + fprintf(stderr, "ThreadId=%p, w->self = %d. about to longjmp_into_runtim[c_sync] with ff=%p\n", + cilkos_get_current_thread_id(), w->self, ff); +#endif + + longjmp_into_runtime(w, do_sync, sf_at_sync); +} + +static void do_sync(__cilkrts_worker *w, full_frame *ff, + __cilkrts_stack_frame *sf) +{ + //int abandoned = 1; + enum provably_good_steal_t steal_result = ABANDON_EXECUTION; + + START_INTERVAL(w, INTERVAL_SYNC_CHECK) { + BEGIN_WITH_WORKER_LOCK_OPTIONAL(w) { + + CILK_ASSERT(ff); + BEGIN_WITH_FRAME_LOCK(w, ff) { + CILK_ASSERT(sf->call_parent == 0); + CILK_ASSERT(sf->flags & CILK_FRAME_UNSYNCHED); + + // Before switching into the scheduling fiber, we should have + // already taken care of deallocating the current + // fiber. + CILK_ASSERT(NULL == ff->fiber_self); + + // Update the frame's pedigree information if this is an ABI 1 + // or later frame + if (CILK_FRAME_VERSION_VALUE(sf->flags) >= 1) + { + sf->parent_pedigree.rank = w->pedigree.rank; + sf->parent_pedigree.parent = w->pedigree.parent; + + // Note that the pedigree rank needs to be updated + // when setup_for_execution_pedigree runs + sf->flags |= CILK_FRAME_SF_PEDIGREE_UNSYNCHED; + } + + /* the decjoin() occurs in provably_good_steal() */ + steal_result = provably_good_steal(w, ff); + + } END_WITH_FRAME_LOCK(w, ff); + // set w->l->frame_ff = NULL after checking abandoned + if (WAIT_FOR_CONTINUE != steal_result) { + w->l->frame_ff = NULL; + } + } END_WITH_WORKER_LOCK_OPTIONAL(w); + } STOP_INTERVAL(w, INTERVAL_SYNC_CHECK); + + // Now, if we are in a replay situation and provably_good_steal() returned + // WAIT_FOR_CONTINUE, we should sleep, reacquire locks, call + // provably_good_steal(), and release locks until we get a value other + // than WAIT_FOR_CONTINUE from the function. +#ifdef CILK_RECORD_REPLAY + // We don't have to explicitly check for REPLAY_LOG below because + // steal_result can only be set to WAIT_FOR_CONTINUE during replay + while(WAIT_FOR_CONTINUE == steal_result) + { + __cilkrts_sleep(); + BEGIN_WITH_WORKER_LOCK_OPTIONAL(w) + { + ff = w->l->frame_ff; + BEGIN_WITH_FRAME_LOCK(w, ff) + { + steal_result = provably_good_steal(w, ff); + } END_WITH_FRAME_LOCK(w, ff); + if (WAIT_FOR_CONTINUE != steal_result) + w->l->frame_ff = NULL; + } END_WITH_WORKER_LOCK_OPTIONAL(w); + } +#endif // CILK_RECORD_REPLAY + +#ifdef ENABLE_NOTIFY_ZC_INTRINSIC + // If we can't make any further progress on this thread, tell Inspector + // that we're abandoning the work and will go find something else to do. + if (ABANDON_EXECUTION == steal_result) + { + NOTIFY_ZC_INTRINSIC("cilk_sync_abandon", 0); + } +#endif // defined ENABLE_NOTIFY_ZC_INTRINSIC + + return; /* back to scheduler loop */ +} + +/* worker W completely promotes its own deque, simulating the case + where the whole deque is stolen. We use this mechanism to force + the allocation of new storage for reducers for race-detection + purposes. */ +void __cilkrts_promote_own_deque(__cilkrts_worker *w) +{ + // Remember the fiber we start this method on. + CILK_ASSERT(w->l->frame_ff); + cilk_fiber* starting_fiber = w->l->frame_ff->fiber_self; + + BEGIN_WITH_WORKER_LOCK(w) { + while (dekker_protocol(w)) { + /* PLACEHOLDER_FIBER is used as non-null marker to tell detach() + and make_child() that this frame should be treated as a spawn + parent, even though we have not assigned it a stack. */ + detach_for_steal(w, w, PLACEHOLDER_FIBER); + } + } END_WITH_WORKER_LOCK(w); + + + // TBD: The management of full frames and fibers is a bit + // sketchy here. We are promoting stack frames into full frames, + // and pretending they are stolen away, but no other worker is + // actually working on them. Some runtime invariants + // may be broken here. + // + // Technically, if we are simulating a steal from w + // w should get a new full frame, but + // keep the same fiber. A real thief would be taking the + // loot frame away, get a new fiber, and starting executing the + // loot frame. + // + // What should a fake thief do? Where does the frame go? + + // In any case, we should be finishing the promotion process with + // the same fiber with. + CILK_ASSERT(w->l->frame_ff); + CILK_ASSERT(w->l->frame_ff->fiber_self == starting_fiber); +} + + + +/* the client code calls this function after a spawn when the dekker + protocol fails. The function may either return or longjmp + into the rts + + This function takes in a "returning_sf" argument which corresponds + to the __cilkrts_stack_frame that we are finishing (i.e., the + argument to __cilkrts_leave_frame). + */ +void __cilkrts_c_THE_exception_check(__cilkrts_worker *w, + __cilkrts_stack_frame *returning_sf) +{ + full_frame *ff; + int stolen_p; + __cilkrts_stack_frame *saved_sf = NULL; + + START_INTERVAL(w, INTERVAL_THE_EXCEPTION_CHECK); + + BEGIN_WITH_WORKER_LOCK(w) { + ff = w->l->frame_ff; + CILK_ASSERT(ff); + /* This code is called only upon a normal return and never + upon an exceptional return. Assert that this is the + case. */ + CILK_ASSERT(!w->l->pending_exception); + + reset_THE_exception(w); + stolen_p = !(w->head < (w->tail + 1)); /* +1 because tail was + speculatively + decremented by the + compiled code */ + + if (stolen_p) { + /* XXX This will be charged to THE for accounting purposes */ + __cilkrts_save_exception_state(w, ff); + + // Save the value of the current stack frame. + saved_sf = w->current_stack_frame; + + // Reverse the decrement from undo_detach. + // This update effectively resets the deque to be + // empty (i.e., changes w->tail back to equal w->head). + // We need to reset the deque to execute parallel + // reductions. When we have only serial reductions, it + // does not matter, since serial reductions do not + // change the deque. + w->tail++; +#if REDPAR_DEBUG > 1 + // ASSERT our deque is empty. + CILK_ASSERT(w->head == w->tail); +#endif + } + } END_WITH_WORKER_LOCK(w); + + STOP_INTERVAL(w, INTERVAL_THE_EXCEPTION_CHECK); + + if (stolen_p) + { + w = execute_reductions_for_spawn_return(w, ff, returning_sf); + + // "Mr. Policeman? My parent always told me that if I was in trouble + // I should ask a nice policeman for help. I can't find my parent + // anywhere..." + // + // Write a record to the replay log for an attempt to return to a stolen parent + replay_record_orphaned(w); + + // Update the pedigree only after we've finished the + // reductions. + update_pedigree_on_leave_frame(w, returning_sf); + + // Notify Inspector that the parent has been stolen and we're + // going to abandon this work and go do something else. This + // will match the cilk_leave_begin in the compiled code + NOTIFY_ZC_INTRINSIC("cilk_leave_stolen", saved_sf); + + DBGPRINTF ("%d: longjmp_into_runtime from __cilkrts_c_THE_exception_check\n", w->self); + longjmp_into_runtime(w, do_return_from_spawn, 0); + DBGPRINTF ("%d: returned from longjmp_into_runtime from __cilkrts_c_THE_exception_check?!\n", w->self); + } + else + { + NOTE_INTERVAL(w, INTERVAL_THE_EXCEPTION_CHECK_USELESS); + return; + } +} + +/* Return an exception to a stolen parent. */ +NORETURN __cilkrts_exception_from_spawn(__cilkrts_worker *w, + __cilkrts_stack_frame *returning_sf) +{ + full_frame *ff = w->l->frame_ff; + // This is almost the same as THE_exception_check, except + // the detach didn't happen, we don't need to undo the tail + // update. + CILK_ASSERT(w->head == w->tail); + w = execute_reductions_for_spawn_return(w, ff, returning_sf); + + longjmp_into_runtime(w, do_return_from_spawn, 0); + CILK_ASSERT(0); +} + +static void do_return_from_spawn(__cilkrts_worker *w, + full_frame *ff, + __cilkrts_stack_frame *sf) +{ + full_frame *parent_ff; + enum provably_good_steal_t steal_result = ABANDON_EXECUTION; + + BEGIN_WITH_WORKER_LOCK_OPTIONAL(w) { + CILK_ASSERT(ff); + CILK_ASSERT(!ff->is_call_child); + CILK_ASSERT(sf == NULL); + parent_ff = ff->parent; + + BEGIN_WITH_FRAME_LOCK(w, ff) { + decjoin(ff); + } END_WITH_FRAME_LOCK(w, ff); + + BEGIN_WITH_FRAME_LOCK(w, parent_ff) { + if (parent_ff->simulated_stolen) + unconditional_steal(w, parent_ff); + else + steal_result = provably_good_steal(w, parent_ff); + } END_WITH_FRAME_LOCK(w, parent_ff); + + } END_WITH_WORKER_LOCK_OPTIONAL(w); + + // Loop here in replay mode +#ifdef CILK_RECORD_REPLAY + // We don't have to explicitly check for REPLAY_LOG below because + // steal_result can only get set to WAIT_FOR_CONTINUE during replay. + // We also don't have to worry about the simulated_stolen flag + // because steal_result can only be set to WAIT_FOR_CONTINUE by + // provably_good_steal(). + while(WAIT_FOR_CONTINUE == steal_result) + { + __cilkrts_sleep(); + BEGIN_WITH_WORKER_LOCK_OPTIONAL(w) + { + BEGIN_WITH_FRAME_LOCK(w, parent_ff) + { + steal_result = provably_good_steal(w, parent_ff); + } END_WITH_FRAME_LOCK(w, parent_ff); + } END_WITH_WORKER_LOCK_OPTIONAL(w); + } +#endif // CILK_RECORD_REPLAY + + // Cleanup the child frame. + __cilkrts_destroy_full_frame(w, ff); + return; +} + +#ifdef _WIN32 +/* migrate an exception across fibers. Call this function when an exception has + * been thrown and has to traverse across a steal. The exception has already + * been wrapped up, so all that remains is to longjmp() into the continuation, + * sync, and re-raise it. + */ +void __cilkrts_migrate_exception(__cilkrts_stack_frame *sf) { + + __cilkrts_worker *w = sf->worker; + full_frame *ff; + + BEGIN_WITH_WORKER_LOCK(w) { + ff = w->l->frame_ff; + reset_THE_exception(w); + /* there is no need to check for a steal because we wouldn't be here if + there weren't a steal. */ + __cilkrts_save_exception_state(w, ff); + + CILK_ASSERT(w->head == w->tail); + } END_WITH_WORKER_LOCK(w); + + { + // TBD(jsukha): This function emulates the + // the "do_return_from_spawn" path. + w = execute_reductions_for_spawn_return(w, ff, sf); + } + + longjmp_into_runtime(w, do_return_from_spawn, 0); /* does not return. */ + CILK_ASSERT(! "Shouldn't be here..."); +} +#endif + + +/* Pop a call stack from TAIL. Return the call stack, or NULL if the + queue is empty */ +__cilkrts_stack_frame *__cilkrts_pop_tail(__cilkrts_worker *w) +{ + __cilkrts_stack_frame *sf; + BEGIN_WITH_WORKER_LOCK(w) { + __cilkrts_stack_frame *volatile *tail = w->tail; + if (w->head < tail) { + --tail; + sf = *tail; + w->tail = tail; + } else { + sf = 0; + } + } END_WITH_WORKER_LOCK(w); + return sf; +} + +#ifdef CILK_RECORD_REPLAY +__cilkrts_stack_frame *simulate_pop_tail(__cilkrts_worker *w) +{ + __cilkrts_stack_frame *sf; + BEGIN_WITH_WORKER_LOCK(w) { + if (w->head < w->tail) { + sf = *(w->tail-1); + } else { + sf = 0; + } + } END_WITH_WORKER_LOCK(w); + return sf; +} +#endif + + +/* Return from a call, not a spawn. */ +void __cilkrts_return(__cilkrts_worker *w) +{ + full_frame *ff, *parent_ff; + START_INTERVAL(w, INTERVAL_RETURNING); + + BEGIN_WITH_WORKER_LOCK_OPTIONAL(w) { + ff = w->l->frame_ff; + CILK_ASSERT(ff); + CILK_ASSERT(ff->join_counter == 1); + /* This path is not used to return from spawn. */ + CILK_ASSERT(ff->is_call_child); + + BEGIN_WITH_FRAME_LOCK(w, ff) { + // After this call, w->l->frame_ff != ff. + // Technically, w will "own" ff until ff is freed, + // however, because ff is a dying leaf full frame. + parent_ff = disown(w, ff, 0, "return"); + decjoin(ff); + +#ifdef _WIN32 + __cilkrts_save_exception_state(w, ff); +#else + // Move the pending exceptions into the full frame + // This should always be NULL if this isn't a + // return with an exception + CILK_ASSERT(NULL == ff->pending_exception); + ff->pending_exception = w->l->pending_exception; + w->l->pending_exception = NULL; +#endif // _WIN32 + + } END_WITH_FRAME_LOCK(w, ff); + + __cilkrts_fence(); /* redundant */ + + CILK_ASSERT(parent_ff); + + BEGIN_WITH_FRAME_LOCK(w, parent_ff) { + finalize_child_for_call(w, parent_ff, ff); + } END_WITH_FRAME_LOCK(w, parent_ff); + + ff = pop_next_frame(w); + /* ff will be non-null except when the parent frame is owned + by another worker. + CILK_ASSERT(ff) + */ + CILK_ASSERT(!w->l->frame_ff); + if (ff) { + BEGIN_WITH_FRAME_LOCK(w, ff) { + __cilkrts_stack_frame *sf = ff->call_stack; + CILK_ASSERT(sf && !sf->call_parent); + setup_for_execution(w, ff, 1); + } END_WITH_FRAME_LOCK(w, ff); + } + } END_WITH_WORKER_LOCK_OPTIONAL(w); + + STOP_INTERVAL(w, INTERVAL_RETURNING); +} + +static void __cilkrts_unbind_thread() +{ + int stop_cilkscreen = 0; + global_state_t *g; + + // Take out the global OS mutex to protect accesses to the table of workers + global_os_mutex_lock(); + + if (cilkg_is_published()) { + __cilkrts_worker *w = __cilkrts_get_tls_worker(); + if (w) { + g = w->g; + + // If there's only 1 worker, the counts will be stopped in + // __cilkrts_scheduler + if (g->P > 1) + { + STOP_INTERVAL(w, INTERVAL_WORKING); + STOP_INTERVAL(w, INTERVAL_IN_SCHEDULER); + } + + __cilkrts_set_tls_worker(0); + + if (w->self == -1) { + // This worker is an overflow worker. I.e., it was created on- + // demand when the global pool ran out of workers. + destroy_worker(w); + __cilkrts_free(w); + } else { + // This is a normal user worker and needs to be counted by the + // global state for the purposes of throttling system workers. + w->l->type = WORKER_FREE; + __cilkrts_leave_cilk(g); + } + + stop_cilkscreen = (0 == g->Q); + } + } + global_os_mutex_unlock(); + + /* Turn off Cilkscreen. This needs to be done when we are NOT holding the + * os mutex. */ + if (stop_cilkscreen) + __cilkrts_cilkscreen_disable_instrumentation(); +} + +/* special return from the initial frame */ + +void __cilkrts_c_return_from_initial(__cilkrts_worker *w) +{ + struct cilkred_map *rm; + + /* This is only called on a user thread worker. */ + CILK_ASSERT(w->l->type == WORKER_USER); + + #if REDPAR_DEBUG >= 3 + fprintf(stderr, "[W=%d, desc=cilkrts_c_return_from_initial, ff=%p]\n", + w->self, w->l->frame_ff); + #endif + + BEGIN_WITH_WORKER_LOCK_OPTIONAL(w) { + full_frame *ff = w->l->frame_ff; + CILK_ASSERT(ff); + CILK_ASSERT(ff->join_counter == 1); + w->l->frame_ff = 0; + + CILK_ASSERT(ff->fiber_self); + // Save any TBB interop data for the next time this thread enters Cilk + cilk_fiber_tbb_interop_save_info_from_stack(ff->fiber_self); + + // Deallocate cilk_fiber that mapped to the user stack. The stack + // itself does not get deallocated (of course) but our data + // structure becomes divorced from it. + +#if FIBER_DEBUG >= 1 + fprintf(stderr, "ThreadId=%p: w=%d: We are about to deallocate ff->fiber_self = %p here. w->l->scheduling_fiber = %p. w->l->type = %d\n", + cilkos_get_current_thread_id(), + w->self, + ff->fiber_self, + w->l->scheduling_fiber, + w->l->type); +#endif + // The fiber in ff is a user-code fiber. The fiber in + // w->l->scheduling_fiber is a scheduling fiber. These fibers should + // never be equal. When a user worker returns (and will unbind), we + // should destroy only the fiber in ff. The scheduling fiber will be + // re-used. + + CILK_ASSERT(ff->fiber_self != w->l->scheduling_fiber); + + START_INTERVAL(w, INTERVAL_FIBER_DEALLOCATE) { + // This fiber might not be deallocated here if there + // is a pending exception on Windows that refers + // to this fiber. + // + // First "suspend" the fiber, and then try to delete it. + cilk_fiber_deallocate_from_thread(ff->fiber_self); + } STOP_INTERVAL(w, INTERVAL_FIBER_DEALLOCATE); + ff->fiber_self = NULL; + + /* Save reducer map into global_state object */ + rm = w->reducer_map; + w->reducer_map = NULL; + +#if REDPAR_DEBUG >= 3 + fprintf(stderr, "W=%d, reducer_map_to_delete=%p, was in ff=%p\n", + w->self, + rm, + ff); +#endif + __cilkrts_destroy_full_frame(w, ff); + + + /* Work is never done. w->g->work_done = 1; __cilkrts_fence(); */ + } END_WITH_WORKER_LOCK_OPTIONAL(w); + + + save_pedigree_leaf_from_user_worker(w); + + // Workers can have NULL reducer maps now. + if (rm) { + __cilkrts_destroy_reducer_map(w, rm); + } + + +#if FIBER_DEBUG >= 1 + __cilkrts_worker* tmp = w; + int tmp_id = w->self; + fprintf(stderr, "w=%d: We are about unbind thread (w= %p)\n", + w->self, + w); +#endif + + w = NULL; + + __cilkrts_unbind_thread(); + +#if FIBER_DEBUG >= 1 + + fprintf(stderr, "w=%p, %d: Finished unbind\n", + tmp, tmp_id); +#endif + + /* Other workers will stop trying to steal if this was the last worker. */ + + return; +} + + +/* + * __cilkrts_restore_stealing + * + * Restore the protected_tail to a previous state, possibly allowing frames + * to be stolen. The dekker_protocol has been extended to steal only if + * head+1 is < protected_tail. + */ + +void __cilkrts_restore_stealing( + __cilkrts_worker *w, + __cilkrts_stack_frame *volatile *saved_protected_tail) +{ + /* On most x86 this pair of operations would be slightly faster + as an atomic exchange due to the implicit memory barrier in + an atomic instruction. */ + w->protected_tail = saved_protected_tail; + __cilkrts_fence(); +} + +/* + * __cilkrts_disallow_stealing + * + * Move the protected_tail to NEW_PROTECTED_TAIL, preventing any + * frames from being stolen. If NEW_PROTECTED_TAIL is NULL, prevent + * stealing from the whole queue. The dekker_protocol has been + * extended to only steal if head+1 is also < protected_tail. + */ + +__cilkrts_stack_frame *volatile *__cilkrts_disallow_stealing( + __cilkrts_worker *w, + __cilkrts_stack_frame *volatile *new_protected_tail) +{ + __cilkrts_stack_frame *volatile *saved_protected_tail = w->protected_tail; + + if (!new_protected_tail) + new_protected_tail = w->l->ltq; + + if (w->protected_tail > new_protected_tail) { + w->protected_tail = new_protected_tail; + /* Issue a store-store barrier. The update to protected_tail + here must precede the update to tail in the next spawn. + On x86 this is probably not needed. */ +#if defined __GNUC__ && __ICC >= 1200 && !(__MIC__ ||__MIC2__) + _mm_sfence(); +#else + __cilkrts_fence(); +#endif + } + + return saved_protected_tail; +} + +/************************************************************* + Initialization and startup +*************************************************************/ + +__cilkrts_worker *make_worker(global_state_t *g, + int self, __cilkrts_worker *w) +{ + w->self = self; + w->g = g; + + w->pedigree.rank = 0; // Initial rank is 0 + w->pedigree.parent = NULL; + + w->l = (local_state *)__cilkrts_malloc(sizeof(*w->l)); + + __cilkrts_frame_malloc_per_worker_init(w); + + w->reducer_map = NULL; + w->current_stack_frame = NULL; + w->reserved = NULL; + + w->l->worker_magic_0 = WORKER_MAGIC_0; + w->l->team = NULL; + w->l->type = WORKER_FREE; + + __cilkrts_mutex_init(&w->l->lock); + __cilkrts_mutex_init(&w->l->steal_lock); + w->l->do_not_steal = 0; + w->l->frame_ff = 0; + w->l->next_frame_ff = 0; + w->l->last_full_frame = NULL; + + w->l->ltq = (__cilkrts_stack_frame **) + __cilkrts_malloc(g->ltqsize * sizeof(*w->l->ltq)); + w->ltq_limit = w->l->ltq + g->ltqsize; + w->head = w->tail = w->l->ltq; + + cilk_fiber_pool_init(&w->l->fiber_pool, + &g->fiber_pool, + g->stack_size, + g->fiber_pool_size, + 0, // alloc_max is 0. We don't allocate from the heap directly without checking the parent pool. + 0); +#if FIBER_DEBUG >= 2 + fprintf(stderr, "ThreadId=%p: Making w=%d (%p), pool = %p\n", + cilkos_get_current_thread_id(), + w->self, w, + &w->l->fiber_pool); +#endif + w->l->scheduling_fiber = NULL; + w->l->original_pedigree_leaf = NULL; + w->l->rand_seed = 0; /* the scheduler will overwrite this field */ + + w->l->post_suspend = 0; + w->l->suspended_stack = 0; + w->l->fiber_to_free = NULL; + w->l->pending_exception = NULL; + +#if CILK_PROFILE + w->l->stats = __cilkrts_malloc(sizeof(statistics)); + __cilkrts_init_stats(w->l->stats); +#else + w->l->stats = NULL; +#endif + w->l->steal_failure_count = 0; + + w->l->work_stolen = 0; + + // Initialize record/replay assuming we're doing neither + w->l->record_replay_fptr = NULL; + w->l->replay_list_root = NULL; + w->l->replay_list_entry = NULL; + w->l->signal_node = NULL; + // Nothing's been stolen yet + w->l->worker_magic_1 = WORKER_MAGIC_1; + + /*w->parallelism_disabled = 0;*/ + + // Allow stealing all frames. Sets w->saved_protected_tail + __cilkrts_restore_stealing(w, w->ltq_limit); + + __cilkrts_init_worker_sysdep(w); + + reset_THE_exception(w); + + return w; +} + +void destroy_worker(__cilkrts_worker *w) +{ + CILK_ASSERT (NULL == w->l->pending_exception); + + // Deallocate the scheduling fiber + if (NULL != w->l->scheduling_fiber) + { + // The scheduling fiber is the main fiber for system workers and must + // be deallocated by the thread that created it. Thus, we can + // deallocate only free workers' (formerly user workers) scheduling + // fibers here. + CILK_ASSERT(WORKER_FREE == w->l->type); + +#if FIBER_DEBUG >=1 + fprintf(stderr, "ThreadId=%p, w=%p, %d, deallocating scheduling fiber = %p, \n", + cilkos_get_current_thread_id(), + w, + w->self, + w->l->scheduling_fiber); +#endif + int ref_count = cilk_fiber_remove_reference(w->l->scheduling_fiber, NULL); + // Scheduling fiber should never have extra references because of exceptions. + CILK_ASSERT(0 == ref_count); + w->l->scheduling_fiber = NULL; + } + +#if CILK_PROFILE + if (w->l->stats) { + __cilkrts_free(w->l->stats); + } +#else + CILK_ASSERT(NULL == w->l->stats); +#endif + + /* Free any cached fibers. */ + cilk_fiber_pool_destroy(&w->l->fiber_pool); + + __cilkrts_destroy_worker_sysdep(w); + + if (w->l->signal_node) { + CILK_ASSERT(WORKER_SYSTEM == w->l->type); + signal_node_destroy(w->l->signal_node); + } + + __cilkrts_free(w->l->ltq); + __cilkrts_mutex_destroy(0, &w->l->lock); + __cilkrts_mutex_destroy(0, &w->l->steal_lock); + __cilkrts_frame_malloc_per_worker_cleanup(w); + + __cilkrts_free(w->l); + + // The caller is responsible for freeing the worker memory +} + +/* + * Make a worker into a system worker. + */ +static void make_worker_system(__cilkrts_worker *w) { + CILK_ASSERT(WORKER_FREE == w->l->type); + w->l->type = WORKER_SYSTEM; + w->l->signal_node = signal_node_create(); +} + +void __cilkrts_deinit_internal(global_state_t *g) +{ + int i; + __cilkrts_worker *w; + + // If there's no global state then we're done + if (NULL == g) + return; + +#ifdef CILK_PROFILE + __cilkrts_dump_stats_to_stderr(g); +#endif + + w = g->workers[0]; + if (w->l->frame_ff) { + __cilkrts_destroy_full_frame(w, w->l->frame_ff); + w->l->frame_ff = 0; + } + + // Release any resources used for record/replay + replay_term(g); + + // Destroy any system dependent global state + __cilkrts_destroy_global_sysdep(g); + + for (i = 0; i < g->total_workers; ++i) + destroy_worker(g->workers[i]); + + // Free memory for all worker blocks which were allocated contiguously + __cilkrts_free(g->workers[0]); + + __cilkrts_free(g->workers); + + cilk_fiber_pool_destroy(&g->fiber_pool); + __cilkrts_frame_malloc_global_cleanup(g); + + cilkg_deinit_global_state(); +} + +/* + * Wake the runtime by notifying the system workers that they can steal. The + * first user worker into the runtime should call this. + */ +static void wake_runtime(global_state_t *g) +{ + __cilkrts_worker *root; + if (g->P > 1) { + // Send a message to the root node. The message will propagate. + root = g->workers[0]; + CILK_ASSERT(root->l->signal_node); + signal_node_msg(root->l->signal_node, 1); + } +} + +/* + * Put the runtime to sleep. The last user worker out of the runtime should + * call this. Like Dad always said, turn out the lights when nobody's in the + * room. + */ +static void sleep_runtime(global_state_t *g) +{ + __cilkrts_worker *root; + if (g->P > 1) { + // Send a message to the root node. The message will propagate. + root = g->workers[0]; + CILK_ASSERT(root->l->signal_node); + signal_node_msg(root->l->signal_node, 0); + } +} + +/* Called when a user thread joins Cilk. + Global lock must be held. */ +void __cilkrts_enter_cilk(global_state_t *g) +{ + if (g->Q++ == 0) { + // If this is the first user thread to enter Cilk wake + // up all the workers. + wake_runtime(g); + } +} + +/* Called when a user thread leaves Cilk. + Global lock must be held. */ +void __cilkrts_leave_cilk(global_state_t *g) +{ + if (--g->Q == 0) { + // Put the runtime to sleep. + sleep_runtime(g); + } +} + +/* + * worker_runnable + * + * Return true if the worker should continue to try to steal. False, otherwise. + */ + +NOINLINE +static enum schedule_t worker_runnable(__cilkrts_worker *w) +{ + global_state_t *g = w->g; + + /* If this worker has something to do, do it. + Otherwise the work would be lost. */ + if (w->l->next_frame_ff) + return SCHEDULE_RUN; + + // If Cilk has explicitly (by the user) been told to exit (i.e., by + // __cilkrts_end_cilk() -> __cilkrts_stop_workers(g)), then return 0. + if (g->work_done) + return SCHEDULE_EXIT; + + if (0 == w->self) { + // This worker is the root node and is the only one that may query the + // global state to see if there are still any user workers in Cilk. + if (w->l->steal_failure_count > g->max_steal_failures) { + if (signal_node_should_wait(w->l->signal_node)) { + return SCHEDULE_WAIT; + } else { + // Reset the steal_failure_count since we have verified that + // user workers are still in Cilk. + w->l->steal_failure_count = 0; + } + } + } else if (WORKER_SYSTEM == w->l->type && + signal_node_should_wait(w->l->signal_node)) { + // This worker has been notified by its parent that it should stop + // trying to steal. + return SCHEDULE_WAIT; + } + + return SCHEDULE_RUN; +} + + + +// Initialize the worker structs, but don't start the workers themselves. +static void init_workers(global_state_t *g) +{ + int total_workers = g->total_workers; + int i; + struct CILK_ALIGNAS(256) buffered_worker { + __cilkrts_worker w; + char buf[64]; + } *workers_memory; + + /* not needed if only one worker */ + cilk_fiber_pool_init(&g->fiber_pool, + NULL, + g->stack_size, + g->global_fiber_pool_size, // buffer_size + g->max_stacks, // maximum # to allocate + 1); + + cilk_fiber_pool_set_fiber_limit(&g->fiber_pool, + (g->max_stacks ? g->max_stacks : INT_MAX)); + + g->workers = (__cilkrts_worker **) + __cilkrts_malloc(total_workers * sizeof(*g->workers)); + + // Allocate 1 block of memory for workers to make life easier for tools + // like Inspector which run multithreaded and need to know the memory + // range for all the workers that will be accessed in a user's program + workers_memory = (struct buffered_worker*) + __cilkrts_malloc(sizeof(*workers_memory) * total_workers); + + // Notify any tools that care (Cilkscreen and Inspector) that they should + // ignore memory allocated for the workers + __cilkrts_cilkscreen_ignore_block(&workers_memory[0], + &workers_memory[total_workers]); + + // Initialize worker structs, including unused worker slots. + for (i = 0; i < total_workers; ++i) { + g->workers[i] = make_worker(g, i, &workers_memory[i].w); + } + + // Set the workers in the first P - 1 slots to be system workers. + // Remaining worker structs already have type == 0. + for (i = 0; i < g->system_workers; ++i) { + make_worker_system(g->workers[i]); + } +} + +void __cilkrts_init_internal(int start) +{ + global_state_t *g = NULL; + + if (cilkg_is_published()) { + g = cilkg_init_global_state(); + } + else { + + // We think the state has not been published yet. + // Grab the lock and try to initialize/publish. + global_os_mutex_lock(); + + if (cilkg_is_published()) { + // Some other thread must have snuck in and published. + g = cilkg_init_global_state(); + } + else { + // Initialize and retrieve global state + g = cilkg_init_global_state(); + + // Set the scheduler pointer + g->scheduler = worker_scheduler_function; + + // If we're running under a sequential P-Tool (Cilkscreen or + // Cilkview) then there's only one worker and we need to tell + // the tool about the extent of the stack + if (g->under_ptool) + __cilkrts_establish_c_stack(); + init_workers(g); + + // Initialize per-work record/replay logging + replay_init_workers(g); + + // Initialize any system dependent global state + __cilkrts_init_global_sysdep(g); + + + cilkg_publish_global_state(g); + } + + global_os_mutex_unlock(); + } + + CILK_ASSERT(g); + + if (start && !g->workers_running) + { + // Acquire the global OS mutex while we're starting the workers + global_os_mutex_lock(); + if (!g->workers_running) + // Start P - 1 system workers since P includes the first user + // worker. + __cilkrts_start_workers(g, g->P - 1); + global_os_mutex_unlock(); + } +} + + +/************************************************************************ + Methods for reducer protocol. + + Reductions occur in two places: + A. A full frame "ff" is returning from a spawn with a stolen parent. + B. A full frame "ff" is stalling at a sync. + + To support parallel reductions, reduction functions need to be + executed while control is on a user stack, before jumping into the + runtime. These reductions can not occur while holding a worker or + frame lock. + + Before a worker w executes a reduction in either Case A or B, w's + deque is empty. + + Since parallel reductions push work onto the deque, we must do extra + work to set up runtime data structures properly before reductions + begin to allow stealing. ( Normally, when we have only serial + reductions, once a worker w starts a reduction, its deque remains + empty until w either steals another frame or resumes a suspended + frame. Thus, we don't care about the state of the deque, since w + will reset its deque when setting up execution of a frame. ) + + To allow for parallel reductions, we coerce the runtime data + structures so that, from their perspective, it looks as though we + have spliced in an "execute_reductions()" function. Consider the + two cases for reductions: + + Case A: Return from a spawn with a stolen parent. + Consider a spawned function g is returning on a worker w. + Assume: + - g was spawned from a parent function f. + - ff is the full frame for g's spawn helper + - sf be the __cilkrts_stack_frame for g's spawn helper. + + We are conceptually splicing "execute_reductions()" so that it + occurs immediately before the spawn helper of g returns to f. + + We do so by creating two different world views --- one for the + runtime data structures, and one for the actual control flow. + + - Before reductions begin, the runtime data structures should + look as though the spawn helper of g is calling + "execute_reductions()", in terms of both the user stack and + worker deque. More precisely, w should satisfy the + following properties: + + (a) w has ff as its full frame, + (b) w has sf as its __cilkrts_stack_frame, and + (c) w has an empty deque. + + If the runtime satisfies these properties, then if w + encounters a spawn in a parallel reduction, it can push onto + a valid deque. Also, when a steal from w occurs, it will + build the correct tree of full frames when w is stolen from. + + - In actual control flow, however, once the + "execute_reductions()" function returns, it is actually + returning to runtime code instead of g's spawn helper. + + At the point a worker w began executing reductions, the + control flow / compiled code had already finished g's spawn + helper, and w was about to enter the runtime. With parallel + reductions, some worker v (which might be different from w) + is the one returning to the runtime. + + + The reduction logic consists of 4 steps: + + A1. Restore runtime data structures to make it look as though + the spawn helper of g() is still the currently executing + frame for w. + + A2. Execute reductions on the user stack. Reductions also + includes the logic for exceptions and stacks. Note that + reductions start on w, but may finish on a different + worker if there is parallelism in the reduce. + + A3. Splice out ff from the tree of full frames. + + A4. Jump into the runtime/scheduling stack and execute + "do_return_from_spawn". This method + + (a) Frees the user stack we were just on if it is no longer needed. + (b) Decrement the join counter on ff->parent, and tries to do a + provably good steal. + (c) Clean up the full frame ff. + + + Case B: Stalling at a sync. + + Consider a function g(), with full frame ff and + __cilkrts_stack_frame sf. Suppose g() stalls at a sync, and we + are executing reductions. + + Conceptually, we are splicing in an "execute_reductions()" + function into g() as the last action that g() takes immediately + before it executes the cilk_sync. + + The reduction logic for this case is similar to Case A. + + B1. Restore the runtime data structures. + + The main difference from Case A is that ff/sf is still a + frame that needs to be executed later (since it is stalling + at a cilk_sync). Thus, we also need to save the current + stack information into "ff" so that we can correctly resume + execution of "ff" after the sync. + + B2. Execute reductions on the user stack. + + B3. No frame to splice out of the tree. + + B4. Jump into the runtime/scheduling stack and execute "do_sync". + This method: + (a) Frees the user stack we were just on if it is no longer needed. + (b) Tries to execute a provably good steal. + + Finally, for the reducer protocol, we consider two reduction paths, + namely a "fast" and "slow" path. On a fast path, only trivial + merges of reducer maps happen (i.e., one or both of the maps are + NULL). Otherwise, on the slow path, a reduction actually needs to + happen. + +*****************************************************************/ + +/** + * @brief Locations to store the result of a reduction. + * + * Struct storing pointers to the fields in our "left" sibling that we + * should update when splicing out a full frame or stalling at a sync. + */ +typedef struct { + /** A pointer to the location of our left reducer map. */ + struct cilkred_map **map_ptr; + + /** A pointer to the location of our left exception. */ + struct pending_exception_info **exception_ptr; +} splice_left_ptrs; + +/** + * For a full frame returning from a spawn, calculate the pointers to + * the maps and exceptions to my left. + * + * @param w The currently executing worker. + * @param ff Full frame that is dying + * @return Pointers to our "left" for reducers and exceptions. + */ +static inline +splice_left_ptrs compute_left_ptrs_for_spawn_return(__cilkrts_worker *w, + full_frame *ff) +{ + // ASSERT: we hold the lock on ff->parent + + splice_left_ptrs left_ptrs; + if (ff->left_sibling) { + left_ptrs.map_ptr = &ff->left_sibling->right_reducer_map; + left_ptrs.exception_ptr = &ff->left_sibling->right_pending_exception; + } + else { + full_frame *parent_ff = ff->parent; + left_ptrs.map_ptr = &parent_ff->children_reducer_map; + left_ptrs.exception_ptr = &parent_ff->child_pending_exception; + } + return left_ptrs; +} + +/** + * For a full frame at a sync, calculate the pointers to the maps and + * exceptions to my left. + * + * @param w The currently executing worker. + * @param ff Full frame that is stalling at a sync. + * @return Pointers to our "left" for reducers and exceptions. + */ +static inline +splice_left_ptrs compute_left_ptrs_for_sync(__cilkrts_worker *w, + full_frame *ff) +{ + // ASSERT: we hold the lock on ff + splice_left_ptrs left_ptrs; + + // Figure out which map to the left we should merge into. + if (ff->rightmost_child) { + CILK_ASSERT(ff->rightmost_child->parent == ff); + left_ptrs.map_ptr = &(ff->rightmost_child->right_reducer_map); + left_ptrs.exception_ptr = &(ff->rightmost_child->right_pending_exception); + } + else { + // We have no children. Then, we should be the last + // worker at the sync... "left" is our child map. + left_ptrs.map_ptr = &(ff->children_reducer_map); + left_ptrs.exception_ptr = &(ff->child_pending_exception); + } + return left_ptrs; +} + +/** + * After we have completed all reductions on a spawn return, call this + * method to finish up before jumping into the runtime. + * + * 1. Perform the "reduction" on stacks, i.e., execute the left + * holder logic to pass the leftmost stack up. + * + * w->l->fiber_to_free holds any stack that needs to be freed + * when control switches into the runtime fiber. + * + * 2. Unlink and remove child_ff from the tree of full frames. + * + * @param w The currently executing worker. + * @param parent_ff The parent of child_ff. + * @param child_ff The full frame returning from a spawn. + */ +static inline +void finish_spawn_return_on_user_stack(__cilkrts_worker *w, + full_frame *parent_ff, + full_frame *child_ff) +{ + CILK_ASSERT(w->l->fiber_to_free == NULL); + + // Execute left-holder logic for stacks. + if (child_ff->left_sibling || parent_ff->fiber_child) { + // Case where we are not the leftmost stack. + CILK_ASSERT(parent_ff->fiber_child != child_ff->fiber_self); + + // Remember any fiber we need to free in the worker. + // After we jump into the runtime, we will actually do the + // free. + w->l->fiber_to_free = child_ff->fiber_self; + } + else { + // We are leftmost, pass stack/fiber up to parent. + // Thus, no stack/fiber to free. + parent_ff->fiber_child = child_ff->fiber_self; + w->l->fiber_to_free = NULL; + } + + child_ff->fiber_self = NULL; + + unlink_child(parent_ff, child_ff); +} + + +/** + * Executes any fast reductions necessary to splice ff out of the tree + * of full frames. + * + * This "fast" path performs only trivial merges of reducer maps, + * i.e,. when one of them is NULL. + * (See slow_path_reductions_for_spawn_return() for slow path.) + * + * Returns: 1 if we finished all reductions. + * Returns: 0 if there are still reductions to execute, and + * we should execute the slow path. + * + * This method assumes w holds the frame lock on parent_ff. + * After this method completes: + * 1. We have spliced ff out of the tree of full frames. + * 2. The reducer maps of child_ff have been deposited + * "left" according to the reducer protocol. + * 3. w->l->stack_to_free stores the stack + * that needs to be freed once we jump into the runtime. + * + * We have not, however, decremented the join counter on ff->parent. + * This prevents any other workers from resuming execution of the parent. + * + * @param w The currently executing worker. + * @param ff The full frame returning from a spawn. + * @return NULL if we finished all reductions. + * @return The address where the left map is stored (which should be passed to + * slow_path_reductions_for_spawn_return()) if there are + * still reductions to execute. + */ +struct cilkred_map** +fast_path_reductions_for_spawn_return(__cilkrts_worker *w, + full_frame *ff) +{ + // ASSERT: we hold ff->parent->lock. + splice_left_ptrs left_ptrs; + + CILK_ASSERT(NULL == w->l->pending_exception); + + // Figure out the pointers to the left where I want + // to put reducers and exceptions. + left_ptrs = compute_left_ptrs_for_spawn_return(w, ff); + + // Go ahead and merge exceptions while holding the lock. + splice_exceptions_for_spawn(w, ff, left_ptrs.exception_ptr); + + // Now check if we have any reductions to perform. + // + // Consider all the cases of left, middle and right maps. + // 0. (-, -, -) : finish and return 1 + // 1. (L, -, -) : finish and return 1 + // 2. (-, M, -) : slide over to left, finish, and return 1. + // 3. (L, M, -) : return 0 + // 4. (-, -, R) : slide over to left, finish, and return 1. + // 5. (L, -, R) : return 0 + // 6. (-, M, R) : return 0 + // 7. (L, M, R) : return 0 + // + // In terms of code: + // L == *left_ptrs.map_ptr + // M == w->reducer_map + // R == f->right_reducer_map. + // + // The goal of the code below is to execute the fast path with + // as few branches and writes as possible. + + int case_value = (*(left_ptrs.map_ptr) != NULL); + case_value += ((w->reducer_map != NULL) << 1); + case_value += ((ff->right_reducer_map != NULL) << 2); + + // Fastest path is case_value == 0 or 1. + if (case_value >=2) { + switch (case_value) { + case 2: + *(left_ptrs.map_ptr) = w->reducer_map; + w->reducer_map = NULL; + return NULL; + break; + case 4: + *(left_ptrs.map_ptr) = ff->right_reducer_map; + ff->right_reducer_map = NULL; + return NULL; + default: + // If we have to execute the slow path, then + // return the pointer to the place to deposit the left + // map. + return left_ptrs.map_ptr; + } + } + + // Do nothing + return NULL; +} + + +/** + * Executes any reductions necessary to splice "ff" frame out of + * the steal tree. + * + * This method executes the "slow" path for reductions on a spawn + * return, i.e., there are non-NULL maps that need to be merged + * together. + * + * This method should execute only if + * fast_path_reductions_for_spawn_return() returns a non-NULL + * left_map_ptr. + * + * Upon entry, left_map_ptr should be the location of the left map + * at the start of the reduction, as calculated by + * fast_path_reductions_for_spawn_return(). + * + * After this method completes: + * 1. We have spliced ff out of the tree of full frames. + * 2. The reducer maps of child_ff have been deposited + * "left" according to the reducer protocol. + * 3. w->l->stack_to_free stores the stack + * that needs to be freed once we jump into the runtime. + * We have not, however, decremented the join counter on ff->parent, + * so no one can resume execution of the parent yet. + * + * WARNING: + * This method assumes the lock on ff->parent is held upon entry, and + * Upon exit, the worker that returns still holds a lock on ff->parent + * This method can, however, release and reacquire the lock on ff->parent. + * + * @param w The currently executing worker. + * @param ff The full frame returning from a spawn. + * @param left_map_ptr Pointer to our initial left map. + * @return The worker that this method returns on. + */ +static __cilkrts_worker* +slow_path_reductions_for_spawn_return(__cilkrts_worker *w, + full_frame *ff, + struct cilkred_map **left_map_ptr) +{ + + // CILK_ASSERT: w is holding frame lock on parent_ff. +#if REDPAR_DEBUG > 0 + CILK_ASSERT(!ff->rightmost_child); + CILK_ASSERT(!ff->is_call_child); +#endif + + // Loop invariant: + // When beginning this loop, we should + // 1. Be holding the lock on ff->parent. + // 2. left_map_ptr should be the address of the pointer to the left map. + // 3. All maps should be slid over left by one, if possible. + // 4. All exceptions should be merged so far. + while (1) { + + // Slide middle map left if possible. + if (!(*left_map_ptr)) { + *left_map_ptr = w->reducer_map; + w->reducer_map = NULL; + } + // Slide right map to middle if possible. + if (!w->reducer_map) { + w->reducer_map = ff->right_reducer_map; + ff->right_reducer_map = NULL; + } + + // Since we slid everything left by one, + // we are finished if there is no middle map. + if (!w->reducer_map) { + verify_current_wkr(w); + return w; + } + else { + struct cilkred_map* left_map; + struct cilkred_map* middle_map; + struct cilkred_map* right_map; + + // Take all the maps from their respective locations. + // We can't leave them in place and execute a reduction because these fields + // might change once we release the lock. + left_map = *left_map_ptr; + *left_map_ptr = NULL; + middle_map = w->reducer_map; + w->reducer_map = NULL; + right_map = ff->right_reducer_map; + ff->right_reducer_map = NULL; + + // WARNING!!! Lock release here. + // We have reductions to execute (and we can't hold locks). + __cilkrts_frame_unlock(w, ff->parent); + + // Merge all reducers into the left map. + left_map = repeated_merge_reducer_maps(&w, + left_map, + middle_map); + verify_current_wkr(w); + left_map = repeated_merge_reducer_maps(&w, + left_map, + right_map); + verify_current_wkr(w); + CILK_ASSERT(NULL == w->reducer_map); + // Put the final answer back into w->reducer_map. + w->reducer_map = left_map; + + // Save any exceptions generated because of the reduction + // process from the returning worker. These get merged + // the next time around the loop. + CILK_ASSERT(NULL == ff->pending_exception); + ff->pending_exception = w->l->pending_exception; + w->l->pending_exception = NULL; + + // Lock ff->parent for the next loop around. + __cilkrts_frame_lock(w, ff->parent); + + // Once we have the lock again, recompute who is to our + // left. + splice_left_ptrs left_ptrs; + left_ptrs = compute_left_ptrs_for_spawn_return(w, ff); + + // Update the pointer for the left map. + left_map_ptr = left_ptrs.map_ptr; + // Splice the exceptions for spawn. + splice_exceptions_for_spawn(w, ff, left_ptrs.exception_ptr); + } + } + // We should never break out of this loop. + + CILK_ASSERT(0); + return NULL; +} + + + +/** + * Execute reductions when returning from a spawn whose parent has + * been stolen. + * + * Execution may start on w, but may finish on a different worker. + * This method acquires/releases the lock on ff->parent. + * + * @param w The currently executing worker. + * @param ff The full frame of the spawned function that is returning. + * @param returning_sf The __cilkrts_stack_frame for this returning function. + * @return The worker returning from this method. + */ +static __cilkrts_worker* +execute_reductions_for_spawn_return(__cilkrts_worker *w, + full_frame *ff, + __cilkrts_stack_frame *returning_sf) +{ + // Step A1 from reducer protocol described above. + // + // Coerce the runtime into thinking that + // ff/returning_sf are still on the bottom of + // w's deque. + restore_frame_for_spawn_return_reduction(w, ff, returning_sf); + + // Step A2 and A3: Execute reductions on user stack. + BEGIN_WITH_FRAME_LOCK(w, ff->parent) { + struct cilkred_map **left_map_ptr; + left_map_ptr = fast_path_reductions_for_spawn_return(w, ff); + + // Pointer will be non-NULL if there are + // still reductions to execute. + if (left_map_ptr) { + // WARNING: This method call may release the lock + // on ff->parent and re-acquire it (possibly on a + // different worker). + // We can't hold locks while actually executing + // reduce functions. + w = slow_path_reductions_for_spawn_return(w, + ff, + left_map_ptr); + verify_current_wkr(w); + } + + finish_spawn_return_on_user_stack(w, ff->parent, ff); + // WARNING: the use of this lock macro is deceptive. + // The worker may have changed here. + } END_WITH_FRAME_LOCK(w, ff->parent); + return w; +} + + + +/** + * Execute fast "reductions" when ff stalls at a sync. + * + * @param w The currently executing worker. + * @param ff The full frame stalling at a sync. + * @return 1 if we are finished with all reductions after calling this method. + * @return 0 if we still need to execute the slow path reductions. + */ +static inline +int fast_path_reductions_for_sync(__cilkrts_worker *w, + full_frame *ff) { + // Return 0 if there is some reduction that needs to happen. + return !(w->reducer_map || ff->pending_exception); +} + +/** + * Executes slow reductions when ff stalls at a sync. + * This method should execute only if + * fast_path_reductions_for_sync(w, ff) returned 0. + * + * After this method completes: + * 1. ff's current reducer map has been deposited into + * right_reducer_map of ff's rightmost child, or + * ff->children_reducer_map if ff has no children. + * 2. Similarly for ff's current exception. + * 3. Nothing to calculate for stacks --- if we are stalling + * we will always free a stack. + * + * This method may repeatedly acquire/release the lock on ff. + * + * @param w The currently executing worker. + * @param ff The full frame stalling at a sync. + * @return The worker returning from this method. + */ +static __cilkrts_worker* +slow_path_reductions_for_sync(__cilkrts_worker *w, + full_frame *ff) +{ + struct cilkred_map *left_map; + struct cilkred_map *middle_map; + +#if (REDPAR_DEBUG > 0) + CILK_ASSERT(ff); + CILK_ASSERT(w->head == w->tail); +#endif + + middle_map = w->reducer_map; + w->reducer_map = NULL; + + // Loop invariant: middle_map should be valid (the current map to reduce). + // left_map is junk. + // w->reducer_map == NULL. + while (1) { + BEGIN_WITH_FRAME_LOCK(w, ff) { + splice_left_ptrs left_ptrs = compute_left_ptrs_for_sync(w, ff); + + // Grab the "left" map and store pointers to those locations. + left_map = *(left_ptrs.map_ptr); + *(left_ptrs.map_ptr) = NULL; + + // Slide the maps in our struct left as far as possible. + if (!left_map) { + left_map = middle_map; + middle_map = NULL; + } + + *(left_ptrs.exception_ptr) = + __cilkrts_merge_pending_exceptions(w, + *left_ptrs.exception_ptr, + ff->pending_exception); + ff->pending_exception = NULL; + + // If there is no middle map, then we are done. + // Deposit left and return. + if (!middle_map) { + *(left_ptrs).map_ptr = left_map; + #if (REDPAR_DEBUG > 0) + CILK_ASSERT(NULL == w->reducer_map); + #endif + // Sanity check upon leaving the loop. + verify_current_wkr(w); + // Make sure to unlock before we return! + __cilkrts_frame_unlock(w, ff); + return w; + } + } END_WITH_FRAME_LOCK(w, ff); + + // If we get here, we have a nontrivial reduction to execute. + middle_map = repeated_merge_reducer_maps(&w, + left_map, + middle_map); + verify_current_wkr(w); + + // Save any exceptions generated because of the reduction + // process. These get merged the next time around the + // loop. + CILK_ASSERT(NULL == ff->pending_exception); + ff->pending_exception = w->l->pending_exception; + w->l->pending_exception = NULL; + } + + // We should never break out of the loop above. + CILK_ASSERT(0); + return NULL; +} + + +/** + * Execute reductions when ff stalls at a sync. + * + * Execution starts on w, but may finish on a different worker. + * This method may acquire/release the lock on ff. + * + * @param w The currently executing worker. + * @param ff The full frame of the spawned function at the sync + * @param sf_at_sync The __cilkrts_stack_frame stalling at a sync + * @return The worker returning from this method. + */ +static __cilkrts_worker* +execute_reductions_for_sync(__cilkrts_worker *w, + full_frame *ff, + __cilkrts_stack_frame *sf_at_sync) +{ + int finished_reductions; + // Step B1 from reducer protocol above: + // Restore runtime invariants. + // + // The following code for this step is almost equivalent to + // the following sequence: + // 1. disown(w, ff, sf_at_sync, "sync") (which itself + // calls make_unrunnable(w, ff, sf_at_sync)) + // 2. make_runnable(w, ff, sf_at_sync). + // + // The "disown" will mark the frame "sf_at_sync" + // as stolen and suspended, and save its place on the stack, + // so it can be resumed after the sync. + // + // The difference is, that we don't want the disown to + // break the following connections yet, since we are + // about to immediately make sf/ff runnable again anyway. + // sf_at_sync->worker == w + // w->l->frame_ff == ff. + // + // These connections are needed for parallel reductions, since + // we will use sf / ff as the stack frame / full frame for + // executing any potential reductions. + // + // TBD: Can we refactor the disown / make_unrunnable code + // to avoid the code duplication here? + + ff->call_stack = NULL; + + // Normally, "make_unrunnable" would add CILK_FRAME_STOLEN and + // CILK_FRAME_SUSPENDED to sf_at_sync->flags and save the state of + // the stack so that a worker can resume the frame in the correct + // place. + // + // But on this path, CILK_FRAME_STOLEN should already be set. + // Also, we technically don't want to suspend the frame until + // the reduction finishes. + // We do, however, need to save the stack before + // we start any reductions, since the reductions might push more + // data onto the stack. + CILK_ASSERT(sf_at_sync->flags | CILK_FRAME_STOLEN); + + __cilkrts_put_stack(ff, sf_at_sync); + __cilkrts_make_unrunnable_sysdep(w, ff, sf_at_sync, 1, + "execute_reductions_for_sync"); + CILK_ASSERT(w->l->frame_ff == ff); + + // Step B2: Execute reductions on user stack. + // Check if we have any "real" reductions to do. + finished_reductions = fast_path_reductions_for_sync(w, ff); + + if (!finished_reductions) { + // Still have some real reductions to execute. + // Run them here. + + // This method may acquire/release the lock on ff. + w = slow_path_reductions_for_sync(w, ff); + + // The previous call may return on a different worker. + // than what we started on. + verify_current_wkr(w); + } + +#if REDPAR_DEBUG >= 0 + CILK_ASSERT(w->l->frame_ff == ff); + CILK_ASSERT(ff->call_stack == NULL); +#endif + + // Now we suspend the frame ff (since we've + // finished the reductions). Roughly, we've split apart the + // "make_unrunnable" call here --- we've already saved the + // stack info earlier before the reductions execute. + // All that remains is to restore the call stack back into the + // full frame, and mark the frame as suspended. + ff->call_stack = sf_at_sync; + sf_at_sync->flags |= CILK_FRAME_SUSPENDED; + + // At a nontrivial sync, we should always free the current fiber, + // because it can not be leftmost. + w->l->fiber_to_free = ff->fiber_self; + ff->fiber_self = NULL; + return w; +} + + +/* + Local Variables: ** + c-file-style:"bsd" ** + c-basic-offset:4 ** + indent-tabs-mode:nil ** + End: ** +*/ diff --git a/libcilkrts/runtime/scheduler.h b/libcilkrts/runtime/scheduler.h new file mode 100644 index 00000000000..543adaf68e0 --- /dev/null +++ b/libcilkrts/runtime/scheduler.h @@ -0,0 +1,421 @@ +/* scheduler.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** + * @file scheduler.h + * + * @brief scheduler.h declares routines for the Intel Cilk Plus scheduler, + * making it the heart of the Intel Cilk Plus implementation. + */ + +#ifndef INCLUDED_SCHEDULER_DOT_H +#define INCLUDED_SCHEDULER_DOT_H + +#include <cilk/common.h> +#include <internal/abi.h> + +#include "rts-common.h" +#include "full_frame.h" +#include "reducer_impl.h" +#include "global_state.h" + +#ifdef CILK_RECORD_REPLAY +#include "record-replay.h" +#endif + +__CILKRTS_BEGIN_EXTERN_C + + +/** + * @brief Flag to disable parallel reductions. + * + * Set to 0 to allow parallel reductions. + */ +#define DISABLE_PARALLEL_REDUCERS 0 + +/** + * @brief Debugging level for parallel reductions. + * + * Print debugging messages and assertions for parallel reducers. 0 is + * no debugging. A higher value generates more output. + */ +#define REDPAR_DEBUG 0 + +/** + * @brief Lock the worker mutex to allow exclusive access to the + * values in the @c __cilkrts_worker and local_state structures. + * + * @pre @c w->l->do_not_steal must not be set. Essentially this + * condition asserts that the worker is not locked recursively. + * + * @param w The worker to lock. + */ +COMMON_PORTABLE +void __cilkrts_worker_lock(__cilkrts_worker *w); + +/** + * @brief Unlock the worker mutex. + * + * @pre @c w->l->do_not_steal must be set. Essentially this condition + * asserts that the worker has been previously locked. + * + * @param w The worker to unlock. + */ +COMMON_PORTABLE +void __cilkrts_worker_unlock(__cilkrts_worker *w); + +/** + * @brief Push the next full frame to be made active in this worker + * and increment its join counter. + * + * __cilkrts_push_next_frame and pop_next_frame work on a one-element queue. + * This queue is used to communicate across the runtime from the code that + * wants to activate a frame to the code that can actually begin execution + * on that frame. They are asymetrical in that push increments the join + * counter but pop does not decrement it. Rather, a single push/pop + * combination makes a frame active and increments its join counter once. + * + * @note A system worker may chose to push work onto a user worker if + * the work is the continuation from a sync which only the user worker + * may complete. + * + * @param w The worker which the frame is to be pushed onto. + * @param ff The full_frame which is to be continued by the worker. + */ +COMMON_PORTABLE +void __cilkrts_push_next_frame(__cilkrts_worker *w, + full_frame *ff); + +/** + * @brief Sync on this worker. + * + * If this worker is the last to reach the sync, execution may resume + * on this worker after the sync. + * + * If this worker is not the last spawned child to reach the sync, + * then execution is suspended and the worker will re-enter the + * scheduling loop, looking for work it can steal. + * + * This function will jump into the runtime to switch to the scheduling + * stack to implement most of its logic. + * + * @param w The worker which is executing the sync. + * @param sf The __cilkrts_stack_frame containing the sync. + */ +COMMON_PORTABLE +NORETURN __cilkrts_c_sync(__cilkrts_worker *w, + __cilkrts_stack_frame *sf); + +/** + * @brief Worker @c w completely promotes its own deque, simulating the case + * where the whole deque is stolen. + * + * We use this mechanism to force the allocation of new storage for + * reducers for race-detection purposes. + * + * This method is called from the reducer lookup logic when + * @c g->force_reduce is set. + * + * @warning Use of "force_reduce" is known to have bugs when run with + * more than 1 worker. + * + * @param w The worker which is to have all entries in its deque + * promoted to full frames. + */ +COMMON_PORTABLE +void __cilkrts_promote_own_deque(__cilkrts_worker *w); + +/** + * Called when a spawned function attempts to return and + * __cilkrts_undo_detach() fails. This can happen for two reasons: + * + * @li If another worker is considering stealing our parent, it bumps the + * exception pointer while it did so, which will cause __cilkrts_undo_detach() + * to fail. If the other worker didn't complete the steal of our parent, we + * still may be able to return to it, either because the steal attempt failed, + * or we won the race for the tail pointer. + * + * @li If the function's parent has been stolen then we cannot return. Instead + * we'll longjmp into the runtime to switch onto the scheduling stack to + * execute do_return_from_spawn() and determine what to do. Either this + * worker is the last one to the sync, in which case we need to jump to the + * sync, or this worker is not the last one to the sync, in which case we'll + * abandon this work and jump to the scheduling loop to search for more work + * we can steal. + * + * @param w The worker which attempting to return from a spawn to + * a stolen parent. + * @param returning_sf The stack frame which is returning. + */ +COMMON_PORTABLE +void __cilkrts_c_THE_exception_check(__cilkrts_worker *w, + __cilkrts_stack_frame *returning_sf); + +/** + * @brief Return an exception to an stolen parent. + * + * Used by the gcc implementation of exceptions to return an exception + * to a stolen parent + * + * @param w The worker which attempting to return from a spawn with an + * exception to a stolen parent. + * @param returning_sf The stack frame which is returning. + */ +COMMON_PORTABLE +NORETURN __cilkrts_exception_from_spawn(__cilkrts_worker *w, + __cilkrts_stack_frame *returning_sf); + +/** + * @brief Used by the Windows implementations of exceptions to migrate an exception + * across fibers. + * + * Call this function when an exception has been thrown and has to + * traverse across a steal. The exception has already been wrapped + * up, so all that remains is to longjmp() into the continuation, + * sync, and re-raise it. + * + * @param sf The __cilkrts_stack_frame for the frame that is attempting to + * return an exception to a stolen parent. + */ +void __cilkrts_migrate_exception (__cilkrts_stack_frame *sf); + +/** + * @brief Return from a call, not a spawn, where this frame has ever + * been stolen. + * + * @param w The worker that is returning from a frame which was ever stolen. + */ +COMMON_PORTABLE +void __cilkrts_return(__cilkrts_worker *w); + +/** + * @brief Special return from the initial frame. + * + * This method will be called from @c __cilkrts_leave_frame if + * @c CILK_FRAME_LAST is set. + * + * This function will do the things necessary to cleanup, and unbind the + * thread from the Intel Cilk Plus runtime. If this is the last user + * worker unbinding from the runtime, all system worker threads will be + * suspended. + * + * @pre @c w must be the currently executing worker, and must be a user + * worker. + * + * @param w The worker that's returning from the initial frame. + */ +COMMON_PORTABLE +void __cilkrts_c_return_from_initial(__cilkrts_worker *w); + +/** + * @brief Used by exception handling code to pop an entry from the + * worker's deque. + * + * @param w Worker to pop the entry from + * + * @return __cilkrts_stack_frame of parent call + * @return NULL if the deque is empty + */ +COMMON_PORTABLE +__cilkrts_stack_frame *__cilkrts_pop_tail(__cilkrts_worker *w); + +/** + * @brief Modifies the worker's protected_tail to prevent frames from + * being stolen. + * + * The Dekker protocol has been extended to only steal if head+1 is also + * less than protected_tail. + * + * @param w The worker to be modified. + * @param new_protected_tail The new setting for protected_tail, or NULL if the + * entire deque is to be protected + * + * @return Previous value of protected tail. + */ +COMMON_PORTABLE +__cilkrts_stack_frame *volatile *__cilkrts_disallow_stealing( + __cilkrts_worker *w, + __cilkrts_stack_frame *volatile *new_protected_tail); + +/** + * @brief Restores the protected tail to a previous state, possibly + * allowing frames to be stolen. + * + * @param w The worker to be modified. + * @param saved_protected_tail A previous setting for protected_tail that is + * to be restored + */ +COMMON_PORTABLE +void __cilkrts_restore_stealing( + __cilkrts_worker *w, + __cilkrts_stack_frame *volatile *saved_protected_tail); + +/** + * @brief Initialize a @c __cilkrts_worker. + * + * @note The memory for the worker must have been allocated outside + * this call. + * + * @param g The global_state_t. + * @param self The index into the global_state's array of workers for this + * worker, or -1 if this worker was allocated from the heap and cannot be + * stolen from. + * @param w The worker to be initialized. + * + * @return The initialized __cilkrts_worker. + */ +COMMON_PORTABLE +__cilkrts_worker *make_worker(global_state_t *g, + int self, + __cilkrts_worker *w); + +/** + * @brief Free up any resources allocated for a worker. + * + * @note The memory for the @c __cilkrts_worker itself must be + * deallocated outside this call. + * + * @param w The worker to be destroyed. + */ +COMMON_PORTABLE +void destroy_worker (__cilkrts_worker *w); + +/** + * @brief Initialize the runtime. + * + * If necessary, allocates and initializes the global state. If + * necessary, unsuspends the system workers. + * + * @param start Specifies whether the workers are to be unsuspended if + * they are suspended. Allows __cilkrts_init() to start up the runtime without + * releasing the system threads. + */ +COMMON_PORTABLE +void __cilkrts_init_internal(int start); + +/** + * @brief Part of the sequence to shutdown the runtime. + * + * Specifically, this call frees the @c global_state_t for the runtime. + * + * @param g The global_state_t. + */ +COMMON_PORTABLE +void __cilkrts_deinit_internal(global_state_t *g); + +/** + * Obsolete. We no longer need to import or export reducer maps. + */ +COMMON_PORTABLE +cilkred_map *__cilkrts_xchg_reducer( + __cilkrts_worker *w, cilkred_map *newmap) cilk_nothrow; + +/** + * @brief Called when a user thread is bound to the runtime. + * + * If this action increments the count of bound user threads from 0 to + * 1, the system worker threads are unsuspended. + * + * If this action increments the count of bound user threads from 0 to + * 1, the system worker threads are unsuspended. + * + * @pre Global lock must be held. + * @param g The runtime global state. + */ +COMMON_PORTABLE +void __cilkrts_enter_cilk(global_state_t *g); + +/** + * @brief Called when a user thread is unbound from the runtime. + * + * If this action decrements the count of bound user threads to 0, the + * system worker threads are suspended. + * + * + * @pre Global lock must be held. + * + * @param g The runtime global state. + */ +COMMON_PORTABLE +void __cilkrts_leave_cilk(global_state_t *g); + + +/** + * @brief cilk_fiber_proc that runs the main scheduler loop on a + * user worker. + * + * @pre fiber's owner field should be set to the correct __cilkrts_worker + * @pre fiber must be a user worker. + * + * @param fiber The scheduling fiber object. + */ +void scheduler_fiber_proc_for_user_worker(cilk_fiber *fiber); + + +/** + * @brief Prints out Cilk runtime statistics. + * + * @param g The runtime global state. + * + * This method is useful only for debugging purposes. No guarantees + * are made as to the validity of this data. :) + */ +COMMON_PORTABLE +void __cilkrts_dump_stats_to_stderr(global_state_t *g); + +#ifdef CILK_RECORD_REPLAY +COMMON_PORTABLE +char * walk_pedigree_nodes(char *p, const __cilkrts_pedigree *pnode); + +/** + * @brief Used by exception handling code to simulate the popping of + * an entry from the worker's deque. + * + * @param w Worker whose deque we want to check + * + * @return @c __cilkrts_stack_frame of parent call + * @return NULL if the deque is empty + */ +COMMON_PORTABLE +__cilkrts_stack_frame *simulate_pop_tail(__cilkrts_worker *w); + +#endif + +__CILKRTS_END_EXTERN_C + +#endif // ! defined(INCLUDED_SCHEDULER_DOT_H) diff --git a/libcilkrts/runtime/signal_node.c b/libcilkrts/runtime/signal_node.c new file mode 100644 index 00000000000..92c404b482c --- /dev/null +++ b/libcilkrts/runtime/signal_node.c @@ -0,0 +1,241 @@ +/* signal_node.c -*-C-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2011-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + +#include "signal_node.h" +#include <stdlib.h> + +/* Define cilk_semaphore_t for all of the respective systems. */ +#if defined __APPLE__ +# include <mach/mach_init.h> +# include <mach/semaphore.h> +# include <mach/task.h> + typedef semaphore_t cilk_semaphore_t; +#elif defined _WIN32 +# include "windows-clean.h" + typedef HANDLE cilk_semaphore_t; +#else // Linux/MIC +# include <errno.h> +# include <semaphore.h> +# include <stdio.h> + typedef sem_t cilk_semaphore_t; +#endif // Linux/MIC + +#include "bug.h" +#include "cilk_malloc.h" +#include "signal_node.h" + +/** + * Interface within the tree to notify workers to wait without consuming cycles + * to expend cycles trying to steal. + * + * cilk_semaphore_t is implemented as an auto-reset event on Windows, and + * as a semaphore_t on Linux and MacOS. + */ +struct signal_node_t +{ + /** 0 if the worker should wait, 1 if it should be running. */ + volatile unsigned int run; + + /** OS-specific semaphore on which the worker can wait. */ + cilk_semaphore_t sem; +}; + +/******************************************************************************/ +/* Semaphore-abstraction functions */ +/******************************************************************************/ + +/* + * All of these functions are simple wrappers for the system-specific semaphore + * functions. This keeps the rest of the code reasonably clean and readable. + */ + +#if defined __APPLE__ +static void initialize_cilk_semaphore (cilk_semaphore_t *sem) +{ + kern_return_t kstatus + = semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, 0); + assert(kstatus == KERN_SUCCESS); +} +static void deinitialize_cilk_semaphore (cilk_semaphore_t *sem) +{ + kern_return_t kstatus = semaphore_destroy(mach_task_self(), *sem); + assert(kstatus == KERN_SUCCESS); +} +static void wait_on_cilk_semaphore (cilk_semaphore_t *sem) +{ + kern_return_t kstatus = semaphore_wait(*sem); + assert(kstatus == KERN_SUCCESS); +} +static void signal_cilk_semaphore (cilk_semaphore_t *sem) +{ + kern_return_t kstatus = semaphore_signal(*sem); + assert(kstatus == KERN_SUCCESS); +} +#elif defined _WIN32 +// Note: Windows only provides counting semaphores, and we don't really +// care about the count. So this is implemented using an auto-reset +// event which will automatically reset after the WaitForSingleObject +// call +static void initialize_cilk_semaphore (cilk_semaphore_t *sem) +{ + // Create an auto-reset event + *sem = CreateEvent(NULL, // Security attributes + FALSE, // Manual reset + FALSE, // Initial state (initially reset) + NULL); // Name (anonymous) + CILK_ASSERT (NULL != *sem); +} + +static void deinitialize_cilk_semaphore (cilk_semaphore_t *sem) +{ + BOOL result = CloseHandle(*sem); + CILK_ASSERT (0 != result); +} + +static void wait_on_cilk_semaphore (cilk_semaphore_t *sem) +{ + // WaitForSingleObject will reset the event + DWORD result = WaitForSingleObject (*sem, INFINITE); + CILK_ASSERT (WAIT_OBJECT_0 == result); +} +static void signal_cilk_semaphore (cilk_semaphore_t *sem) +{ + BOOL result = SetEvent (*sem); + CILK_ASSERT (0 != result); +} +#else // Linux/MIC +static void initialize_cilk_semaphore (cilk_semaphore_t *sem) +{ + int status = sem_init(sem, 0, 0); + assert(0 == status); +} +static void deinitialize_cilk_semaphore (cilk_semaphore_t *sem) +{ + int status = sem_destroy(sem); + assert(0 == status); +} +static void wait_on_cilk_semaphore (cilk_semaphore_t *sem) +{ + int status; + + do { + status = sem_wait(sem); + } while (status != 0 && errno == EINTR); + + if (status != 0) { + perror("sem_wait"); + abort(); + } +} +static void signal_cilk_semaphore (cilk_semaphore_t *sem) +{ + sem_post(sem); +} +#endif // Linux/MIC + +/******************************************************************************/ +/* Runtime interface functions */ +/******************************************************************************/ + +/* + * Return a newly malloc'd and initialized signal_node_t. + */ +COMMON_SYSDEP +signal_node_t *signal_node_create(void) +{ + signal_node_t *node; + + node = ( signal_node_t*) + __cilkrts_malloc(sizeof( signal_node_t)); + node->run = 0; + initialize_cilk_semaphore(&node->sem); + + return node; +} + +/* + * Clean and free a signal_node_t. + */ +void signal_node_destroy(signal_node_t *node) +{ + CILK_ASSERT(node); + deinitialize_cilk_semaphore(&node->sem); + __cilkrts_free(node); +} + +/* + * Return 1 if the node thinks the worker should go to sleep, 0 otherwise. + */ +unsigned int signal_node_should_wait(signal_node_t *node) +{ + CILK_ASSERT(node); + return !node->run; +} + +/* + * Send a message to the node that the worker will eventually read. + */ +void signal_node_msg(signal_node_t *node, unsigned int msg) +{ + CILK_ASSERT(node); + switch (msg) { + case 0: // worker should go to sleep. + node->run = msg; + break; + case 1: // worker should be awake. + node->run = msg; + signal_cilk_semaphore(&node->sem); + break; + default: // error. + CILK_ASSERT(0 == "Bad signal_node_t message."); + } +} + +/* + * The current worker will wait on the semaphore. + */ +void signal_node_wait(signal_node_t *node) +{ + CILK_ASSERT(node); + while (signal_node_should_wait(node)) { + // The loop is here to consume extra semaphore signals that might have + // accumulated. No point in passing on the accumulation. + wait_on_cilk_semaphore(&node->sem); + } +} diff --git a/libcilkrts/runtime/signal_node.h b/libcilkrts/runtime/signal_node.h new file mode 100644 index 00000000000..0a1fe200201 --- /dev/null +++ b/libcilkrts/runtime/signal_node.h @@ -0,0 +1,109 @@ +/* signal_node.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** + * @file signal_node.h + * + * @brief Signal nodes allow coordinated waking and sleeping of the runtime + * without hammering on a single location in memory. + * + * The workers are logically arranged in a binary tree and propagate messages + * leaf-ward. User workers notify the root about waking and sleeping, so only + * that one node need share a cache line with a user worker. + */ + +#ifndef INCLUDED_SIGNAL_NODE_DOT_H +#define INCLUDED_SIGNAL_NODE_DOT_H + +#include "rts-common.h" +#include <cilk/common.h> + +__CILKRTS_BEGIN_EXTERN_C + +/** Opaque type. */ +typedef struct signal_node_t signal_node_t; + +/** + * Allocate and initialize a signal_node_t + * + * @return The initialized signal_node_t + */ +COMMON_SYSDEP +signal_node_t *signal_node_create(void); + +/** + * Free any resources and deallocate a signal_node_t + * + * @param node The node to be deallocated. + */ +COMMON_SYSDEP void signal_node_destroy(signal_node_t *node); + +/** + * Test whether the node thinks the worker should go to sleep + * + * @param node The node to be tested. + * + * @return 1 If the worker should go to sleep + * @return 0 If the worker should not go to sleep + */ +COMMON_SYSDEP +unsigned int signal_node_should_wait(signal_node_t *node); + +/** + * Specify whether the worker should go to sleep + * + * @param node The node to be set. + * @param msg The value to be set. Valid values are: + * - 0 - the worker should go to sleep + * - 1 - the worker should stay active + */ +COMMON_SYSDEP +void signal_node_msg(signal_node_t *node, unsigned int msg); + + +/** + * Wait for the node to be set + * + * @param node The node to wait on + */ +COMMON_SYSDEP +void signal_node_wait(signal_node_t *node); + +__CILKRTS_END_EXTERN_C + +#endif // ! defined(INCLUDED_SIGNAL_NODE_DOT_H) diff --git a/libcilkrts/runtime/spin_mutex.c b/libcilkrts/runtime/spin_mutex.c new file mode 100644 index 00000000000..03908f26322 --- /dev/null +++ b/libcilkrts/runtime/spin_mutex.c @@ -0,0 +1,109 @@ +/* spin_mutex.c -*-C-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +#include "spin_mutex.h" +#include "bug.h" +#include "os.h" +#include "stats.h" + +// TBD (11/30/12): We should be doing a conditional test-xchg instead +// of an unconditional xchg operation for the spin mutex. + +/* m->lock == 1 means that mutex M is locked */ +#define TRY_ACQUIRE(m) (__cilkrts_xchg(&(m)->lock, 1) == 0) + +/* ICC 11.1+ understands release semantics and generates an + ordinary store with a software memory barrier. */ +#if __ICC >= 1110 +#define RELEASE(m) __sync_lock_release(&(m)->lock) +#else +#define RELEASE(m) __cilkrts_xchg(&(m)->lock, 0) +#endif + + +spin_mutex* spin_mutex_create() +{ + spin_mutex* mutex = (spin_mutex*)__cilkrts_malloc(sizeof(spin_mutex)); + spin_mutex_init(mutex); + return mutex; +} + +void spin_mutex_init(struct spin_mutex *m) +{ + // Use a simple assignment so Inspector doesn't bug us about the + // interlocked exchange doing a read of an uninitialized variable. + // By definition there can't be a race when we're initializing the + // lock... + m->lock = 0; +} + +void spin_mutex_lock(struct spin_mutex *m) +{ + int count; + const int maxspin = 1000; /* SWAG */ + if (!TRY_ACQUIRE(m)) { + count = 0; + do { + do { + __cilkrts_short_pause(); + if (++count >= maxspin) { + /* let the OS reschedule every once in a while */ + __cilkrts_yield(); + count = 0; + } + } while (m->lock != 0); + } while (!TRY_ACQUIRE(m)); + } +} + +int spin_mutex_trylock(struct spin_mutex *m) +{ + return TRY_ACQUIRE(m); +} + +void spin_mutex_unlock(struct spin_mutex *m) +{ + RELEASE(m); +} + +void spin_mutex_destroy(struct spin_mutex *m) +{ + __cilkrts_free(m); +} + +/* End spin_mutex.c */ diff --git a/libcilkrts/runtime/spin_mutex.h b/libcilkrts/runtime/spin_mutex.h new file mode 100644 index 00000000000..b0045ab9313 --- /dev/null +++ b/libcilkrts/runtime/spin_mutex.h @@ -0,0 +1,129 @@ +/* spin_mutex.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** + * @file spin_mutex.h + * + * @brief Support for Cilk runtime mutexes. + * + * Cilk runtime mutexes are implemented as simple spin loops. + * + * This file is similar to a worker_mutex, except it does not have an + * owner field. + * + * TBD: This class, worker_mutex, and os_mutex overlap quite a bit in + * functionality. Can we unify these mutexes somehow? + */ +#ifndef INCLUDED_SPIN_MUTEX_DOT_H +#define INCLUDED_SPIN_MUTEX_DOT_H + +#include <cilk/common.h> +#include "rts-common.h" +#include "cilk_malloc.h" + +__CILKRTS_BEGIN_EXTERN_C + +/** + * Mutexes are treated as an abstract data type within the Cilk + * runtime system. They are implemented as simple spin loops. + */ +typedef struct spin_mutex { + /** Mutex spin loop variable. 0 if unowned, 1 if owned. */ + volatile int lock; + + /** Padding so the mutex takes up a cache line. */ + char pad[64/sizeof(int) - 1]; +} spin_mutex; + + +/** + * @brief Create a new Cilk spin_mutex. + * + * @return Returns an initialized spin mutex. + */ +COMMON_PORTABLE +spin_mutex* spin_mutex_create(); + +/** + * @brief Initialize a Cilk spin_mutex. + * + * @param m Spin_Mutex to be initialized. + */ +COMMON_PORTABLE +void spin_mutex_init(spin_mutex *m); + +/** + * @brief Acquire a Cilk spin_mutex. + * + * If statistics are being gathered, the time spent + * acquiring the spin_mutex will be attributed to the specified worker. + * + * @param m Spin_Mutex to be initialized. + */ +COMMON_PORTABLE +void spin_mutex_lock(struct spin_mutex *m); +/** + * @brief Attempt to lock a Cilk spin_mutex and fail if it isn't available. + * + * @param m Spin_Mutex to be acquired. + * + * @return 1 if the spin_mutex was acquired. + * @return 0 if the spin_mutex was not acquired. + */ +COMMON_PORTABLE +int spin_mutex_trylock(struct spin_mutex *m); + +/** + * @brief Release a Cilk spin_mutex. + * + * @param m Spin_Mutex to be released. + */ +COMMON_PORTABLE +void spin_mutex_unlock(struct spin_mutex *m); + +/** + * @brief Deallocate a Cilk spin_mutex. Currently does nothing. + * + * @param m Spin_Mutex to be deallocated. + */ +COMMON_PORTABLE +void spin_mutex_destroy(struct spin_mutex *m); + +__CILKRTS_END_EXTERN_C + +#endif // ! defined(INCLUDED_SPIN_MUTEX_DOT_H) diff --git a/libcilkrts/runtime/stats.c b/libcilkrts/runtime/stats.c new file mode 100644 index 00000000000..3a420745039 --- /dev/null +++ b/libcilkrts/runtime/stats.c @@ -0,0 +1,172 @@ +/* stats.c -*-C-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +#include "stats.h" +#include "bug.h" +#include "os.h" +#include "local_state.h" + +#include <stdio.h> + +#define INVALID_START (0ULL - 1ULL) + +#ifdef CILK_PROFILE +/* MSVC does not support designated initializers, grrrr... */ +static const char *names[] = { + /*[INTERVAL_IN_SCHEDULER]*/ "in scheduler", + /*[INTERVAL_WORKING]*/ " of which: working", + /*[INTERVAL_IN_RUNTIME]*/ " of which: in runtime", + /*[INTERVAL_STEALING]*/ " of which: stealing", + /*[INTERVAL_STEAL_SUCCESS]*/ "steal success: detach", + /*[INTERVAL_STEAL_FAIL_EMPTYQ]*/ "steal fail: empty queue", + /*[INTERVAL_STEAL_FAIL_LOCK]*/ "steal fail: victim locked", + /*[INTERVAL_STEAL_FAIL_USER_WORKER]*/ "steal fail: user worker", + /*[INTERVAL_STEAL_FAIL_DEKKER]*/ "steal fail: dekker", + /*[INTERVAL_SYNC_CHECK]*/ "sync check", + /*[INTERVAL_THE_EXCEPTION_CHECK]*/ "THE exception check", + /*[INTERVAL_THE_EXCEPTION_CHECK_USELESS]*/ " of which: useless", + /*[INTERVAL_RETURNING]*/ "returning", + /*[INTERVAL_FINALIZE_CHILD]*/ "finalize child", + /*[INTERVAL_PROVABLY_GOOD_STEAL]*/ "provably good steal", + /*[INTERVAL_UNCONDITIONAL_STEAL]*/ "unconditional steal", + /*[INTERVAL_ALLOC_FULL_FRAME]*/ "alloc full frame", + /*[INTERVAL_FRAME_ALLOC_LARGE]*/ "large frame alloc", + /*[INTERVAL_FRAME_ALLOC]*/ "small frame alloc", + /*[INTERVAL_FRAME_ALLOC_GLOBAL]*/ " of which: to global pool", + /*[INTERVAL_FRAME_FREE_LARGE]*/ "large frame free", + /*[INTERVAL_FRAME_FREE]*/ "small frame free", + /*[INTERVAL_FRAME_FREE_GLOBAL]*/ " of which: to global pool", + /*[INTERVAL_MUTEX_LOCK]*/ "mutex lock", + /*[INTERVAL_MUTEX_LOCK_SPINNING]*/ " spinning", + /*[INTERVAL_MUTEX_LOCK_YIELDING]*/ " yielding", + /*[INTERVAL_MUTEX_TRYLOCK]*/ "mutex trylock", + /*[INTERVAL_FIBER_ALLOCATE]*/ "fiber_allocate", + /*[INTERVAL_FIBER_DEALLOCATE]*/ "fiber_deallocate", + /*[INTERVAL_FIBER_ALLOCATE_FROM_THREAD]*/ "fiber_allocate_from_thread", + /*[INTERVAL_FIBER_DEALLOCATE_FROM_THREAD]*/ "fiber_deallocate (thread)", + /*[INTERVAL_SUSPEND_RESUME_OTHER]*/ "fiber suspend self + resume", + /*[INTERVAL_DEALLOCATE_RESUME_OTHER]*/ "fiber deallocate self + resume", +}; +#endif + +void __cilkrts_init_stats(statistics *s) +{ + int i; + for (i = 0; i < INTERVAL_N; ++i) { + s->start[i] = INVALID_START; + s->accum[i] = 0; + s->count[i] = 0; + } + + s->stack_hwm = 0; +} + +#ifdef CILK_PROFILE +void __cilkrts_accum_stats(statistics *to, statistics *from) +{ + int i; + + for (i = 0; i < INTERVAL_N; ++i) { + to->accum[i] += from->accum[i]; + to->count[i] += from->count[i]; + from->accum[i] = 0; + from->count[i] = 0; + } + + if (from->stack_hwm > to->stack_hwm) + to->stack_hwm = from->stack_hwm; + from->stack_hwm = 0; +} + +void __cilkrts_note_interval(__cilkrts_worker *w, enum interval i) +{ + if (w) { + statistics *s = w->l->stats; + CILK_ASSERT(s->start[i] == INVALID_START); + s->count[i]++; + } +} + +void __cilkrts_start_interval(__cilkrts_worker *w, enum interval i) +{ + if (w) { + statistics *s = w->l->stats; + CILK_ASSERT(s->start[i] == INVALID_START); + s->start[i] = __cilkrts_getticks(); + s->count[i]++; + } +} + +void __cilkrts_stop_interval(__cilkrts_worker *w, enum interval i) +{ + if (w) { + statistics *s = w->l->stats; + CILK_ASSERT(s->start[i] != INVALID_START); + s->accum[i] += __cilkrts_getticks() - s->start[i]; + s->start[i] = INVALID_START; + } +} + +void dump_stats_to_file(FILE *stat_file, statistics *s) +{ + int i; + fprintf(stat_file, "\nCILK PLUS RUNTIME SYSTEM STATISTICS:\n\n"); + + fprintf(stat_file, + " %-32s: %15s %10s %12s %10s\n", + "event", + "count", + "ticks", + "ticks/count", + "%total" + ); + for (i = 0; i < INTERVAL_N; ++i) { + fprintf(stat_file, " %-32s: %15llu", names[i], s->count[i]); + if (s->accum[i]) { + fprintf(stat_file, " %10.3g %12.3g %10.2f", + (double)s->accum[i], + (double)s->accum[i] / (double)s->count[i], + 100.0 * (double)s->accum[i] / + (double)s->accum[INTERVAL_IN_SCHEDULER]); + } + fprintf(stat_file, "\n"); + } +} +#endif // CILK_PROFILE + +/* End stats.c */ diff --git a/libcilkrts/runtime/stats.h b/libcilkrts/runtime/stats.h new file mode 100644 index 00000000000..aaa99274765 --- /dev/null +++ b/libcilkrts/runtime/stats.h @@ -0,0 +1,208 @@ +/* stats.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** + * @file stats.h + * + * @brief Support for gathering and reporting statistics on Cilk applications. + * + * Note that stats are normally NOT compiled in because it increases the + * overhead of stealing. To compile in profiling support, define CILK_PROFILE. + */ + +#ifndef INCLUDED_STATS_DOT_H +#define INCLUDED_STATS_DOT_H + +/* #define CILK_PROFILE 1 */ +// @note The CILK_PROFILE flag and intervals is known to be broken +// in at least programs with Windows exceptions. +// Enable this flag at your own peril. :) + +#include <cilk/common.h> +#include "rts-common.h" +#include "internal/abi.h" + +#ifdef CILK_PROFILE +#include <stdio.h> // Define FILE * +#endif + +__CILKRTS_BEGIN_EXTERN_C + +/** @brief Events that we measure. */ +enum interval +{ + INTERVAL_IN_SCHEDULER, ///< Time threads spend "bound" to Cilk + INTERVAL_WORKING, ///< Time spent working + INTERVAL_IN_RUNTIME, ///< Time spent executing runtime scheduling loop + INTERVAL_STEALING, ///< Time spent stealing work + INTERVAL_STEAL_SUCCESS, ///< Time to do a successful steal + INTERVAL_STEAL_FAIL_EMPTYQ, ///< Count of steal failures due to lack of stealable work + INTERVAL_STEAL_FAIL_LOCK, ///< Count of steal failures due to failure to lock worker + INTERVAL_STEAL_FAIL_USER_WORKER, ///< Count of steal failures by user workers which attempt to steal from another team + INTERVAL_STEAL_FAIL_DEKKER, ///< Count of steal failures due to Dekker protocol failure + INTERVAL_SYNC_CHECK, ///< Time spent processing syncs + INTERVAL_THE_EXCEPTION_CHECK, ///< Time spent performing THE exception checks + INTERVAL_THE_EXCEPTION_CHECK_USELESS, ///< Count of useless THE exception checks + INTERVAL_RETURNING, ///< Time spent returning from calls + INTERVAL_FINALIZE_CHILD, ///< Time spent in finalize_child + INTERVAL_PROVABLY_GOOD_STEAL, ///< Time spent in provably_good_steal + INTERVAL_UNCONDITIONAL_STEAL, ///< Time spent in unconditional_steal + INTERVAL_ALLOC_FULL_FRAME, ///< Time spent in __cilkrts_make_full_frame + INTERVAL_FRAME_ALLOC_LARGE, ///< Count of calls to __cilkrts_frame_malloc for buffers bigger than FRAME_MALLOC_MAX_SIZE or with a NULL worker + INTERVAL_FRAME_ALLOC, ///< Time spent allocating memory from worker buckets + INTERVAL_FRAME_ALLOC_GLOBAL, ///< Time spent calling memory allocator when buckets are empty + INTERVAL_FRAME_FREE_LARGE, ///< Count of calls to __cilkrts_frame_malloc for buffers bigger than FRAME_MALLOC_MAX_SIZE or with a NULL worker + INTERVAL_FRAME_FREE, ///< Time spent freeing memory to worker buckets + INTERVAL_FRAME_FREE_GLOBAL, ///< Time spent calling memory deallocator when buckets are full + INTERVAL_MUTEX_LOCK, ///< Count of calls to __cilkrts_mutex_lock for a worker + INTERVAL_MUTEX_LOCK_SPINNING, ///< Time spent spinning in __cilkrts_mutex_lock for a worker + INTERVAL_MUTEX_LOCK_YIELDING, ///< Time spent yielding in __cilkrts_mutex_lock for a worker + INTERVAL_MUTEX_TRYLOCK, ///< Count of calls to __cilkrts_mutex_trylock + INTERVAL_FIBER_ALLOCATE, ///< Time spent calling cilk_fiber_allocate + INTERVAL_FIBER_DEALLOCATE, ///< Time spent calling cilk_fiber_deallocate (not from thread) + INTERVAL_FIBER_ALLOCATE_FROM_THREAD, ///< Time spent calling cilk_fiber_allocate_from_thread + INTERVAL_FIBER_DEALLOCATE_FROM_THREAD, ///< Time spent calling cilk_fiber_deallocate (from thread) + INTERVAL_SUSPEND_RESUME_OTHER, ///< Count of fiber suspend_self_and_resume_other + INTERVAL_DEALLOCATE_RESUME_OTHER, ///< Count of fiber deallocate_self_and_resume_other + INTERVAL_N ///< Number of intervals, must be last +}; + +/** + * @brief Struct that collects of all runtime statistics. + * + * There is an instance of this structure in each worker's + * local_state, as well as one in the @c global_state_t which will be + * used to accumulate the per-worker stats. + */ +typedef struct statistics +{ + /** Number of times each interval is entered */ + unsigned long long count[INTERVAL_N]; + + /** + * Time when the system entered each interval, in system-dependent + * "ticks" + */ + unsigned long long start[INTERVAL_N]; + + /** Total time spent in each interval, in system-dependent "ticks" */ + unsigned long long accum[INTERVAL_N]; + + /** + * Largest global number of stacks seen by this worker. + * The true maximum at end of execution is the max of the + * worker maxima. + */ + long stack_hwm; +} statistics; + +/** + * Initializes a statistics structure + * + * @param s The statistics structure to be initialized. + */ +COMMON_PORTABLE void __cilkrts_init_stats(statistics *s); + +/** + * @brief Sums statistics from worker to the global struct + * + * @param to The statistics structure that will accumulate the information. + * This structure is usually @c g->stats. + * @param from The statistics structure that will be accumulated. + * This structure is usually statistics kept per worker. + */ +COMMON_PORTABLE +void __cilkrts_accum_stats(statistics *to, statistics *from); + +/** + * @brief Mark the start of an interval by saving the current tick count. + * + * @pre Start time == INVALID_START + * + * @param w The worker we're accumulating stats for. + * @param i The interval we're accumulating stats for. + */ +COMMON_PORTABLE +void __cilkrts_start_interval(__cilkrts_worker *w, enum interval i); + +/** + * @brief Mark the end of an interval by adding the ticks since the + * start to the accumulated time. + * + * @pre Start time != INVALID_START + * + * @param w The worker we're accumulating stats for. + * @param i The interval we're accumulating stats for. + */ +COMMON_PORTABLE +void __cilkrts_stop_interval(__cilkrts_worker *w, enum interval i); + +/** + * @brief Start and stop interval I, charging zero time against it + * + * Precondition: + * - Start time == INVALID_START + * + * @param w The worker we're accumulating stats for. + * @param i The interval we're accumulating stats for. + */ +COMMON_PORTABLE +void __cilkrts_note_interval(__cilkrts_worker *w, enum interval i); + +#ifdef CILK_PROFILE +COMMON_PORTABLE +void dump_stats_to_file(FILE *stat_file, statistics *s); +#endif + + +#ifdef CILK_PROFILE +# define START_INTERVAL(w, i) __cilkrts_start_interval(w, i); +# define STOP_INTERVAL(w, i) __cilkrts_stop_interval(w, i); +# define NOTE_INTERVAL(w, i) __cilkrts_note_interval(w, i); +#else +/** Start an interval. No effect unless CILK_PROFILE is defined. */ +# define START_INTERVAL(w, i) +/** End an interval. No effect unless CILK_PROFILE is defined. */ +# define STOP_INTERVAL(w, i) +/** Increment a counter. No effect unless CILK_PROFILE is defined. */ +# define NOTE_INTERVAL(w, i) +#endif + +__CILKRTS_END_EXTERN_C + +#endif // ! defined(INCLUDED_STATS_DOT_H) diff --git a/libcilkrts/runtime/symbol_test.c b/libcilkrts/runtime/symbol_test.c new file mode 100644 index 00000000000..1113ecd44cd --- /dev/null +++ b/libcilkrts/runtime/symbol_test.c @@ -0,0 +1,62 @@ +/* symbol_test.c -*-C-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/* simple program to verify that there are no undefined symbols in the runtime. + * If the runtime uses any symbols that are not defined, compiling this program + * will cause a linker error. + */ + +extern void* __cilkrts_global_state; +void *volatile p; + +void foo () { } +int main () +{ + int i; + long long j; + + _Cilk_spawn foo(); + _Cilk_for (i = 0; i < 2; ++i) + foo(); + _Cilk_for (j = 0; j < 2; ++j) + foo(); + p = __cilkrts_global_state; + return 0; +} + +/* End symbol_test.c */ diff --git a/libcilkrts/runtime/sysdep-unix.c b/libcilkrts/runtime/sysdep-unix.c new file mode 100644 index 00000000000..194681fffc5 --- /dev/null +++ b/libcilkrts/runtime/sysdep-unix.c @@ -0,0 +1,794 @@ +/* + * sysdep-unix.c + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2010-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************** + */ + +#ifdef __linux__ + // define _GNU_SOURCE before *any* #include. + // Even <stdint.h> will break later #includes if this macro is not + // already defined when it is #included. +# define _GNU_SOURCE +#endif + +#include "sysdep.h" +#include "os.h" +#include "bug.h" +#include "local_state.h" +#include "signal_node.h" +#include "full_frame.h" +#include "jmpbuf.h" +#include "cilk_malloc.h" +#include "reducer_impl.h" +#include "metacall_impl.h" + + +// On x86 processors (but not MIC processors), the compiler generated code to +// save the FP state (rounding mode and the like) before calling setjmp. We +// will need to restore that state when we resume. +#ifndef __MIC__ +# if defined(__i386__) || defined(__x86_64) +# define RESTORE_X86_FP_STATE +# endif // defined(__i386__) || defined(__x86_64) +#endif // __MIC__ + +// contains notification macros for VTune. +#include "cilk-ittnotify.h" + +#include <stddef.h> + +#ifdef __CYGWIN__ +// On Cygwin, string.h doesnt declare strcasecmp if __STRICT_ANSI__ is defined +# undef __STRICT_ANSI__ +#endif + +#include <string.h> +#include <pthread.h> +#include <unistd.h> +#include <alloca.h> + +#ifdef __APPLE__ +//# include <scheduler.h> // Angle brackets include Apple's scheduler.h, not ours. +#endif + +#ifdef __linux__ +# include <sys/resource.h> +# include <sys/sysinfo.h> +#endif + +#ifdef __FreeBSD__ +# include <sys/resource.h> +// BSD does not define MAP_ANONYMOUS, but *does* define MAP_ANON. Aren't standards great! +# define MAP_ANONYMOUS MAP_ANON +#endif + +#ifdef __VXWORKS__ +# include <vxWorks.h> +# include <vxCpuLib.h> +#endif + +struct global_sysdep_state +{ + pthread_t *threads; ///< Array of pthreads for system workers + size_t pthread_t_size; ///< for cilk_db +}; + +static void internal_enforce_global_visibility(); + + +COMMON_SYSDEP +void __cilkrts_init_worker_sysdep(struct __cilkrts_worker *w) +{ + ITT_SYNC_CREATE(w, "Scheduler"); +} + +COMMON_SYSDEP +void __cilkrts_destroy_worker_sysdep(struct __cilkrts_worker *w) +{ +} + +COMMON_SYSDEP +void __cilkrts_init_global_sysdep(global_state_t *g) +{ + internal_enforce_global_visibility(); + + __cilkrts_init_tls_variables(); + + CILK_ASSERT(g->total_workers >= g->P - 1); + g->sysdep = __cilkrts_malloc(sizeof (struct global_sysdep_state)); + CILK_ASSERT(g->sysdep); + g->sysdep->pthread_t_size = sizeof (pthread_t); + + // TBD: Should this value be g->total_workers, or g->P? + // Need to check what we are using this field for. + g->sysdep->threads = __cilkrts_malloc(sizeof(pthread_t) * g->total_workers); + CILK_ASSERT(g->sysdep->threads); + + return; +} + +COMMON_SYSDEP +void __cilkrts_destroy_global_sysdep(global_state_t *g) +{ + if (g->sysdep->threads) + __cilkrts_free(g->sysdep->threads); + __cilkrts_free(g->sysdep); +} + +/************************************************************* + Creation of worker threads: +*************************************************************/ + +static void internal_run_scheduler_with_exceptions(__cilkrts_worker *w) +{ + /* We assume the stack grows down. */ + char var; + __cilkrts_cilkscreen_establish_c_stack(&var - 1000000, &var); + + __cilkrts_run_scheduler_with_exceptions(w); +} + + + +/* + * scheduler_thread_proc_for_system_worker + * + * Thread start function called when we start a new worker. + * + */ +NON_COMMON void* scheduler_thread_proc_for_system_worker(void *arg) +{ + /*int status;*/ + __cilkrts_worker *w = (__cilkrts_worker *)arg; + +#ifdef __INTEL_COMPILER +#ifdef USE_ITTNOTIFY + // Name the threads for Advisor. They don't want a worker number. + __itt_thread_set_name("Cilk Worker"); +#endif // defined USE_ITTNOTIFY +#endif // defined __INTEL_COMPILER + + /* Worker startup is serialized + status = pthread_mutex_lock(&__cilkrts_global_mutex); + CILK_ASSERT(status == 0);*/ + CILK_ASSERT(w->l->type == WORKER_SYSTEM); + /*status = pthread_mutex_unlock(&__cilkrts_global_mutex); + CILK_ASSERT(status == 0);*/ + + __cilkrts_set_tls_worker(w); + + // Create a cilk fiber for this worker on this thread. + START_INTERVAL(w, INTERVAL_FIBER_ALLOCATE_FROM_THREAD) { + w->l->scheduling_fiber = cilk_fiber_allocate_from_thread(); + cilk_fiber_set_owner(w->l->scheduling_fiber, w); + } STOP_INTERVAL(w, INTERVAL_FIBER_ALLOCATE_FROM_THREAD); + + internal_run_scheduler_with_exceptions(w); + + START_INTERVAL(w, INTERVAL_FIBER_DEALLOCATE_FROM_THREAD) { + // Deallocate the scheduling fiber. This operation reverses the + // effect cilk_fiber_allocate_from_thread() and must be done in this + // thread before it exits. + int ref_count = cilk_fiber_deallocate_from_thread(w->l->scheduling_fiber); + // Scheduling fibers should never have extra references to them. + // We only get extra references into fibers because of Windows + // exceptions. + CILK_ASSERT(0 == ref_count); + w->l->scheduling_fiber = NULL; + } STOP_INTERVAL(w, INTERVAL_FIBER_DEALLOCATE_FROM_THREAD); + + return 0; +} + + +/* + * __cilkrts_user_worker_scheduling_stub + * + * Routine for the scheduling fiber created for an imported user + * worker thread. This method is analogous to + * scheduler_thread_proc_for_system_worker. + * + */ +void __cilkrts_user_worker_scheduling_stub(cilk_fiber* fiber, void* null_arg) +{ + __cilkrts_worker *w = __cilkrts_get_tls_worker(); + + // Sanity check. + CILK_ASSERT(WORKER_USER == w->l->type); + + // Enter the scheduling loop on the user worker. + // This function will never return. + __cilkrts_run_scheduler_with_exceptions(w); + + // A WORKER_USER, at some point, will resume on the original stack and leave + // Cilk. Under no circumstances do we ever exit off of the bottom of this + // stack. + CILK_ASSERT(0); +} + +/** + * We are exporting a function with this name to Inspector? + * What a confusing name... + * + * This function is exported so Piersol's stack trace displays + * reasonable information. + */ +void* __cilkrts_worker_stub(void* arg) +{ + return scheduler_thread_proc_for_system_worker(arg); +} + + + +// /* Return the lesser of the argument and the operating system +// limit on the number of workers (threads) that may or ought +// to be created. */ +// int sysdep_thread_limit(int n, int physical_cpus) +// { +// /* On Linux thread creation fails somewhere short of the +// number of available processes. */ +// struct rlimit lim; + +// if (n > 256 + 2 * physical_cpus) +// n = 256 + 2 * physical_cpus; + +// if (getrlimit(RLIMIT_NPROC, &lim) == 0 && lim.rlim_cur != RLIM_INFINITY) +// { +// /* If the limit reads 0 or absurdly small, ignore it. */ +// unsigned int maxproc = (lim.rlim_cur * 3 + 3) / 4; +// if (maxproc > 8 + 2 * physical_cpus && maxproc < n) +// n = maxproc; +// } +// return n; +// } + + + +static void write_version_file (global_state_t *, int); + +/* Create n worker threads from base..top-1 + */ +static void create_threads(global_state_t *g, int base, int top) +{ + // TBD(11/30/12): We want to insert code providing the option of + // pinning system workers to cores. + for (int i = base; i < top; i++) { + int status = pthread_create(&g->sysdep->threads[i], + NULL, + scheduler_thread_proc_for_system_worker, + g->workers[i]); + if (status != 0) + __cilkrts_bug("Cilk runtime error: thread creation (%d) failed: %d\n", i, status); + } +} + +#if PARALLEL_THREAD_CREATE +static int volatile threads_created = 0; + +// Create approximately half of the worker threads, and then become a worker +// ourselves. +static void * create_threads_and_work (void * arg) +{ + global_state_t *g = ((__cilkrts_worker *)arg)->g; + + create_threads(g, g->P/2, g->P-1); + // Let the initial thread know that we're done. + threads_created = 1; + + // Ideally this turns into a tail call that wipes out this stack frame. + return scheduler_thread_proc_for_system_worker(arg); +} +#endif +void __cilkrts_start_workers(global_state_t *g, int n) +{ + g->workers_running = 1; + g->work_done = 0; + + if (!g->sysdep->threads) + return; + + // Do we actually have any threads to create? + if (n > 0) + { +#if PARALLEL_THREAD_CREATE + int status; + // We create (a rounded up) half of the threads, thread one creates the rest + int half_threads = (n+1)/2; + + // Create the first thread passing a different thread function, so that it creates threads itself + status = pthread_create(&g->sysdep->threads[0], NULL, create_threads_and_work, g->workers[0]); + + if (status != 0) + __cilkrts_bug("Cilk runtime error: thread creation (0) failed: %d\n", status); + + // Then the rest of the ones we have to create + create_threads(g, 1, half_threads); + + // Now wait for the first created thread to tell us it's created all of its threads. + // We could maybe drop this a bit lower and overlap with write_version_file. + while (!threads_created) + __cilkrts_yield(); +#else + // Simply create all the threads linearly here. + create_threads(g, 0, n); +#endif + } + // write the version information to a file if the environment is configured + // for it (the function makes the check). + write_version_file(g, n); + + + return; +} + +void __cilkrts_stop_workers(global_state_t *g) +{ + int i; + + // Tell the workers to give up + + g->work_done = 1; + + if (g->workers_running == 0) + return; + + if (!g->sysdep->threads) + return; + + /* Make them all runnable. */ + if (g->P > 1) { + CILK_ASSERT(g->workers[0]->l->signal_node); + signal_node_msg(g->workers[0]->l->signal_node, 1); + } + + for (i = 0; i < g->P - 1; ++i) { + int sc_status; + void *th_status; + + sc_status = pthread_join(g->sysdep->threads[i], &th_status); + if (sc_status != 0) + __cilkrts_bug("Cilk runtime error: thread join (%d) failed: %d\n", i, sc_status); + } + + g->workers_running = 0; + + + return; +} + + +/* + * @brief Returns the stack address for resuming execution of sf. + * + * This method takes in the top of the stack to use, and then returns + * a properly aligned address for resuming execution of sf. + * + * @param sf - The stack frame we want to resume executing. + * @param stack_base - The top of the stack we want to execute sf on. + * + */ +static char* get_sp_for_executing_sf(char* stack_base, + full_frame *ff, + __cilkrts_stack_frame *sf) +{ +// The original calculation that had been done to correct the stack +// pointer when resuming execution. +// +// But this code was never getting called in the eng branch anyway... +// +// TBD(11/30/12): This logic needs to be revisited to make sure that +// we are doing the proper calculation in reserving space for outgoing +// arguments on all platforms and architectures. +#if 0 + /* Preserve outgoing argument space and stack alignment on steal. + Outgoing argument space is bounded by the difference between + stack and frame pointers. Some user code is known to rely on + 16 byte alignment. Maintain 32 byte alignment for future + compatibility. */ +#define SMASK 31 /* 32 byte alignment */ + if (sf) { + char *fp = FP(sf), *sp = SP(sf); + int fp_align = (int)(size_t)fp & SMASK; + ptrdiff_t space = fp - sp; + + fprintf(stderr, "Here: fp = %p, sp = %p\n", fp, sp); + char *top_aligned = (char *)((((size_t)stack_base - SMASK) & ~(size_t)SMASK) | fp_align); + /* Don't allocate an unreasonable amount of stack space. */ + + fprintf(stderr, "Here: stack_base = %p, top_aligned=%p, space=%ld\n", + stack_base, top_aligned, space); + if (space < 32) + space = 32 + (space & SMASK); + else if (space > 40 * 1024) + space = 40 * 1024 + (space & SMASK); + + return top_aligned - space; + } +#endif + +#define PERFORM_FRAME_SIZE_CALCULATION 0 + + char* new_stack_base = stack_base - 256; + +#if PERFORM_FRAME_SIZE_CALCULATION + // If there is a frame size saved, then use that as the + // correction instead of 256. + if (ff->frame_size > 0) { + if (ff->frame_size < 40*1024) { + new_stack_base = stack_base - ff->frame_size; + } + else { + // If for some reason, our frame size calculation is giving us + // a number which is bigger than about 10 pages, then + // there is likely something wrong here? Don't allocate + // an unreasonable amount of space. + new_stack_base = stack_base - 40*1024; + } + } +#endif + + // Whatever correction we choose, align the final stack top. + // This alignment seems to be necessary in particular on 32-bit + // Linux, and possibly Mac. (Is 32-byte alignment is sufficient?) + /* 256-byte alignment. Why not? */ + const uintptr_t align_mask = ~(256 -1); + new_stack_base = (char*)((size_t)new_stack_base & align_mask); + return new_stack_base; +} + +char* sysdep_reset_jump_buffers_for_resume(cilk_fiber* fiber, + full_frame *ff, + __cilkrts_stack_frame *sf) +{ +#if FIBER_DEBUG >= 4 + fprintf(stderr, "ThreadId=%p (fiber_proc_to_resume), Fiber %p. sf = %p. ff=%p, ff->sync_sp=%p\n", + cilkos_get_current_thread_id(), + fiber, + sf, + ff, ff->sync_sp); +#endif + + CILK_ASSERT(fiber); + void* sp = (void*)get_sp_for_executing_sf(cilk_fiber_get_stack_base(fiber), ff, sf); + SP(sf) = sp; + + /* Debugging: make sure stack is accessible. */ + ((volatile char *)sp)[-1]; + + // Adjust the saved_sp to account for the SP we're about to run. This will + // allow us to track fluctations in the stack +#if FIBER_DEBUG >= 4 + fprintf(stderr, "ThreadId=%p, about to take stack ff=%p, sp=%p, sync_sp=%p\n", + cilkos_get_current_thread_id(), + ff, + sp, + ff->sync_sp); +#endif + __cilkrts_take_stack(ff, sp); + return sp; +} + + +NORETURN sysdep_longjmp_to_sf(char* new_sp, + __cilkrts_stack_frame *sf, + full_frame *ff_for_exceptions /* UNUSED on Unix */) +{ +#if FIBER_DEBUG >= 3 + fprintf(stderr, + "ThreadId=%p. resume user code, sf=%p, new_sp = %p, original SP(sf) = %p, FP(sf) = %p\n", + cilkos_get_current_thread_id(), sf, new_sp, SP(sf), FP(sf)); +#endif + + // Set the stack pointer. + SP(sf) = new_sp; + +#ifdef RESTORE_X86_FP_STATE + if (CILK_FRAME_VERSION_VALUE(sf->flags) >= 1) { + // Restore the floating point state that was set in this frame at the + // last spawn. + // + // This feature is only available in ABI 1 or later frames, and only + // needed on IA64 or Intel64 processors. + restore_x86_fp_state(sf); + } +#endif + + CILK_LONGJMP(sf->ctx); +} + + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <errno.h> + + +void __cilkrts_make_unrunnable_sysdep(__cilkrts_worker *w, + full_frame *ff, + __cilkrts_stack_frame *sf, + int is_loot, + const char *why) +{ + (void)w; /* unused */ + sf->except_data = 0; + + if (is_loot) + { + if (ff->frame_size == 0) + ff->frame_size = __cilkrts_get_frame_size(sf); + + // Null loot's sp for debugging purposes (so we'll know it's not valid) + SP(sf) = 0; + } +} + +/* + * __cilkrts_sysdep_is_worker_thread_id + * + * Returns true if the thread ID specified matches the thread ID we saved + * for a worker. + */ + +int __cilkrts_sysdep_is_worker_thread_id(global_state_t *g, + int i, + void *thread_id) +{ +#if defined( __linux__) || defined(__VXWORKS__) + pthread_t tid = *(pthread_t *)thread_id; + if (i < 0 || i > g->total_workers) + return 0; + return g->sysdep->threads[i] == tid; +#else + // Needs to be implemented + return 0; +#endif +} + + + + +/************************************************************* + Version information: +*************************************************************/ + +#include <dlfcn.h> +#include "internal/cilk_version.h" +#include <stdio.h> +#include <sys/utsname.h> + +#ifdef __VXWORKS__ +#include <version.h> +# endif + +/* (Non-static) dummy function is used by get_runtime_path() to find the path + * to the .so containing the Cilk runtime. + */ +void dummy_function() { } + +/* return a string with the path to the Cilk runtime, or "unknown" if the path + * cannot be determined. + */ +static const char *get_runtime_path () +{ +#ifdef __CYGWIN__ + // Cygwin doesn't support dladdr, which sucks + return "unknown"; +#else + Dl_info info; + if (0 == dladdr(dummy_function, &info)) return "unknown"; + return info.dli_fname; +#endif +} + +/* if the environment variable, CILK_VERSION, is defined, writes the version + * information to the specified file. + * g is the global state that was just created, and n is the number of workers + * that were made (or requested from RML) for it. + */ +static void write_version_file (global_state_t *g, int n) +{ + const char *env; // environment variable. + char buf[256]; // print buffer. + time_t t; + FILE *fp; + struct utsname sys_info; + int err; // error code from system calls. + + // if CILK_VERSION is not set, or if the file cannot be opened, fail + // silently. Otherwise open the file for writing (or use stderr or stdout + // if the user specifies). + if (NULL == (env = getenv("CILK_VERSION"))) return; + if (0 == strcasecmp(env, "stderr")) fp = stderr; + else if (0 == strcasecmp(env, "stdout")) fp = stdout; + else if (NULL == (fp = fopen(env, "w"))) return; + + // get a string for the current time. E.g., + // Cilk runtime initialized: Thu Jun 10 13:28:00 2010 + t = time(NULL); + strftime(buf, 256, "%a %b %d %H:%M:%S %Y", localtime(&t)); + fprintf(fp, "Cilk runtime initialized: %s\n", buf); + + // Print runtime info. E.g., + // Cilk runtime information + // ======================== + // Cilk version: 2.0.0 Build 9184 + // Built by willtor on host willtor-desktop + // Compilation date: Thu Jun 10 13:27:42 2010 + // Compiled with ICC V99.9.9, ICC build date: 20100610 + + fprintf(fp, "\nCilk runtime information\n"); + fprintf(fp, "========================\n"); + fprintf(fp, "Cilk version: %d.%d.%d Build %d\n", + VERSION_MAJOR, + VERSION_MINOR, + VERSION_REV, + VERSION_BUILD); +#ifdef __VXWORKS__ + char * vxWorksVer = VXWORKS_VERSION; + fprintf(fp, "Cross compiled for %s\n",vxWorksVer); + // user and host not avalible if VxWorks cross compiled on windows build host +#else + + // User and host are not available for GCC builds +#ifdef BUILD_USER + fprintf(fp, "Built by "BUILD_USER" on host "BUILD_HOST"\n"); +#endif // BUILD_USER +#endif // __VXWORKS__ + + // GCC has requested that this be removed for GCC builds +#ifdef BUILD_USER + fprintf(fp, "Compilation date: "__DATE__" "__TIME__"\n"); +#endif // BUILD_USER + +#ifdef __INTEL_COMPILER + // Compiled by the Intel C/C++ compiler. + fprintf(fp, "Compiled with ICC V%d.%d.%d, ICC build date: %d\n", + __INTEL_COMPILER / 100, + (__INTEL_COMPILER / 10) % 10, + __INTEL_COMPILER % 10, + __INTEL_COMPILER_BUILD_DATE); +#else + // Compiled by GCC. + fprintf(fp, "Compiled with GCC V%d.%d.%d\n", + __GNUC__, + __GNUC_MINOR__, + __GNUC_PATCHLEVEL__); +#endif // defined __INTEL_COMPILER + + // Print system info. E.g., + // System information + // ================== + // Cilk runtime path: /opt/icc/64/lib/libcilkrts.so.5 + // System OS: Linux, release 2.6.28-19-generic + // System architecture: x86_64 + + err = uname(&sys_info); + fprintf(fp, "\nSystem information\n"); + fprintf(fp, "==================\n"); + fprintf(fp, "Cilk runtime path: %s\n", get_runtime_path()); + fprintf(fp, "System OS: %s, release %s\n", + err < 0 ? "unknown" : sys_info.sysname, + err < 0 ? "?" : sys_info.release); + fprintf(fp, "System architecture: %s\n", + err < 0 ? "unknown" : sys_info.machine); + + // Print thread info. E.g., + // Thread information + // ================== + // System cores: 8 + // Cilk workers requested: 8 + // Thread creator: Private + + fprintf(fp, "\nThread information\n"); + fprintf(fp, "==================\n"); +#ifdef __VXWORKS__ + fprintf(fp, "System cores: %d\n", (int)__builtin_popcount(vxCpuEnabledGet())); +#else + fprintf(fp, "System cores: %d\n", (int)sysconf(_SC_NPROCESSORS_ONLN)); +#endif + fprintf(fp, "Cilk workers requested: %d\n", n); +#if (PARALLEL_THREAD_CREATE) + fprintf(fp, "Thread creator: Private (parallel)\n"); +#else + fprintf(fp, "Thread creator: Private\n"); +#endif + + if (fp != stderr && fp != stdout) fclose(fp); + else fflush(fp); // flush the handle buffer if it is stdout or stderr. +} + + +/* + * __cilkrts_establish_c_stack + * + * Tell Cilkscreen about the user stack bounds. + * + * Note that the Cilk V1 runtime only included the portion of the stack from + * the entry into Cilk, down. We don't appear to be able to find that, but + * I think this will be sufficient. + */ + +void __cilkrts_establish_c_stack(void) +{ + /* FIXME: Not implemented. */ + + /* TBD: Do we need this */ + /* + void __cilkrts_cilkscreen_establish_c_stack(char *begin, char *end); + + size_t r; + MEMORY_BASIC_INFORMATION mbi; + + r = VirtualQuery (&mbi, + &mbi, + sizeof(mbi)); + + __cilkrts_cilkscreen_establish_c_stack((char *)mbi.BaseAddress, + (char *)mbi.BaseAddress + mbi.RegionSize); + */ +} + + +/* + * internal_enforce_global_visibility + * + * Ensure global visibility of public symbols, for proper Cilk-TBB interop. + * + * If Cilk runtime is loaded dynamically, its symbols might remain unavailable + * for global search with dladdr; that might prevent TBB from finding Cilk + * in the process address space and initiating the interop protocol. + * The workaround is for the library to open itself with RTLD_GLOBAL flag. + */ + +static __attribute__((noinline)) +void internal_enforce_global_visibility() +{ + void* handle = dlopen( get_runtime_path(), RTLD_GLOBAL|RTLD_LAZY ); + + /* For proper reference counting, close the handle immediately. */ + if( handle) dlclose(handle); +} + +/* + Local Variables: ** + c-file-style:"bsd" ** + c-basic-offset:4 ** + indent-tabs-mode:nil ** + End: ** +*/ diff --git a/libcilkrts/runtime/sysdep.h b/libcilkrts/runtime/sysdep.h new file mode 100644 index 00000000000..ea939acc124 --- /dev/null +++ b/libcilkrts/runtime/sysdep.h @@ -0,0 +1,285 @@ +/* sysdep.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** + * @file sysdep.h + * + * @brief Common system-dependent functions + */ + +#ifndef INCLUDED_SYSDEP_DOT_H +#define INCLUDED_SYSDEP_DOT_H + +#include <cilk/common.h> +#include <internal/abi.h> + +#include "global_state.h" +#include "full_frame.h" +#include "os.h" +#include "os_mutex.h" + +/** + * @brief Default page size for Cilk stacks. + * + * All Cilk stacks should have size that is a multiple of this value. + */ +#define PAGE 4096 + +/** + * @brief Size of a scheduling stack. + * + * A scheduling stack is used to by system workers to execute runtime + * code. Since this stack is only executing runtime functions, we + * don't need it to be a full size stack. + * + * The number "18" should be small since the runtime doesn't require a + * large stack, but large enough to call "printf" for debugging. + */ +#define CILK_SCHEDULING_STACK_SIZE (18*PAGE) + +__CILKRTS_BEGIN_EXTERN_C + + +/** + * Code to initialize the system-dependent portion of the global_state_t + * + * @param g Pointer to the global state. + */ +COMMON_SYSDEP +void __cilkrts_init_global_sysdep(global_state_t *g); + +/** + * Code to clean up the system-dependent portion of the global_state_t + * + * @param g Pointer to the global state. + */ +COMMON_SYSDEP +void __cilkrts_destroy_global_sysdep(global_state_t *g); + +/** + * Passes stack range to Cilkscreen. This functionality should be moved + * into Cilkscreen. + */ +COMMON_SYSDEP +void __cilkrts_establish_c_stack(void); + + +/** + * Save system dependent information in the full_frame and + * __cilkrts_stack_frame. Part of promoting a + * __cilkrts_stack_frame to a full_frame. + * + * @param w The worker the frame was running on. Not used. + * @param ff The full frame that is being created for the + * __cilkrts_stack_frame. + * @param sf The __cilkrts_stack_frame that's being promoted + * to a full frame. + * @param state_valid ? + * @param why A description of why make_unrunnable was called. + * Used for debugging. + */ +COMMON_SYSDEP +void __cilkrts_make_unrunnable_sysdep(__cilkrts_worker *w, + full_frame *ff, + __cilkrts_stack_frame *sf, + int state_valid, + const char *why); + + +/** + * OS-specific code to spawn worker threads. + * + * @param g The global state. + * @param n Number of worker threads to start. + */ +COMMON_SYSDEP +void __cilkrts_start_workers(global_state_t *g, int n); + +/** + * @brief OS-specific code to stop worker threads. + * + * @param g The global state. + */ +COMMON_SYSDEP +void __cilkrts_stop_workers(global_state_t *g); + +/** + * @brief Imports a user thread the first time it returns to a stolen parent. + * + * The thread has been bound to a worker, but additional steps need to + * be taken to start running a scheduling loop. + * + * @param w The worker bound to the thread. + */ +COMMON_SYSDEP +void __cilkrts_sysdep_import_user_thread(__cilkrts_worker *w); + +/** + * @brief Function to be run for each of the system worker threads. + * + * This declaration also appears in cilk/cilk_undocumented.h -- don't + * change one declaration without also changing the other. + * + * @param arg The context value passed to the thread creation routine for + * the OS we're running on. + * + * @returns OS dependent. + */ +#ifdef _WIN32 +/* Do not use CILK_API because __cilkrts_worker_stub must be __stdcall */ +CILK_EXPORT unsigned __CILKRTS_NOTHROW __stdcall +__cilkrts_worker_stub(void *arg); +#else +/* Do not use CILK_API because __cilkrts_worker_stub have default visibility */ +__attribute__((visibility("default"))) +void* __CILKRTS_NOTHROW __cilkrts_worker_stub(void *arg); +#endif + +/** + * Initialize any OS-depenendent portions of a newly created + * __cilkrts_worker. + * + * Exported for Piersol. Without the export, Piersol doesn't display + * useful information in the stack trace. This declaration also appears in + * cilk/cilk_undocumented.h -- do not modify one without modifying the other. + * + * @param w The worker being initialized. + */ +COMMON_SYSDEP +CILK_EXPORT +void __cilkrts_init_worker_sysdep(__cilkrts_worker *w); + +/** + * Deallocate any OS-depenendent portions of a __cilkrts_worker. + * + * @param w The worker being deallocaed. + */ +COMMON_SYSDEP +void __cilkrts_destroy_worker_sysdep(__cilkrts_worker *w); + +/** + * Called to do any OS-dependent setup before starting execution on a + * frame. Mostly deals with exception handling data. + * + * @param w The worker the frame will run on. + * @param ff The full_frame that is about to be resumed. + */ +COMMON_SYSDEP +void __cilkrts_setup_for_execution_sysdep(__cilkrts_worker *w, + full_frame *ff); + +/** + * @brief OS-specific implementaton of resetting fiber and frame state + * to resume exeuction. + * + * This method: + * 1. Calculates the value of stack pointer where we should resume + * execution of "sf". This calculation uses info stored in the + * fiber, and takes into account alignment and frame size. + * 2. Updates sf and ff to match the calculated stack pointer. + * + * On Unix, the stack pointer calculation looks up the base of the + * stack from the fiber. + * + * On Windows, this calculation is calls "alloca" to find a stack + * pointer on the currently executing stack. Thus, the Windows code + * assumes @c fiber is the currently executing fiber. + * + * @param fiber fiber to resume execution on. + * @param ff full_frame for the frame we're resuming. + * @param sf __cilkrts_stack_frame that we should resume + * @return The calculated stack pointer. + */ +COMMON_SYSDEP +char* sysdep_reset_jump_buffers_for_resume(cilk_fiber* fiber, + full_frame *ff, + __cilkrts_stack_frame *sf); + +/** + * @brief System-dependent longjmp to user code for resuming execution + * of a @c __cilkrts_stack_frame. + * + * This method: + * - Changes the stack pointer in @c sf to @c new_sp. + * - If @c ff_for_exceptions is not NULL, changes fields in @c sf and + * @c ff_for_exceptions for exception processing. + * - Restores any floating point state + * - Finishes with a longjmp to user code, never to return. + * + * @param new_sp stack pointer where we should resume execution + * @param sf @c __cilkrts_stack_frame for the frame we're resuming. + * @param ff_for_exceptions full_frame to safe exception info into, if necessary + */ +COMMON_SYSDEP +NORETURN +sysdep_longjmp_to_sf(char* new_sp, + __cilkrts_stack_frame *sf, + full_frame *ff_for_exceptions); + +/** + * @brief System-dependent code to save floating point control information + * to a @c __cilkrts_stack_frame. This function will be called by compilers + * that cannot inline the code. + * + * Note that this function does *not* save the current floating point + * registers. It saves the floating point control words that control + * precision and rounding and stuff like that. + * + * This function will be a noop for architectures that don't have warts + * like the floating point control words, or where the information is + * already being saved by the setjmp. + * + * @param sf @c __cilkrts_stack_frame for the frame we're + * saving the floating point control information in. + */ +COMMON_SYSDEP +void +sysdep_save_fp_ctrl_state(__cilkrts_stack_frame *sf); + + +/** + * @brief restore x86 floating point state + * + * Only used for x86 and Intel64 processors + */ +COMMON_SYSDEP +void restore_x86_fp_state(__cilkrts_stack_frame *sf); + +__CILKRTS_END_EXTERN_C + +#endif // ! defined(INCLUDED_SYSDEP_DOT_H) diff --git a/libcilkrts/runtime/worker_mutex.c b/libcilkrts/runtime/worker_mutex.c new file mode 100644 index 00000000000..380d6255a0c --- /dev/null +++ b/libcilkrts/runtime/worker_mutex.c @@ -0,0 +1,121 @@ +/* worker_mutex.c -*-C-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +#include "worker_mutex.h" +#include "bug.h" +#include "os.h" +#include "stats.h" + +/* m->lock == 1 means that mutex M is locked */ +#define TRY_ACQUIRE(m) (__cilkrts_xchg(&(m)->lock, 1) == 0) + +/* ICC 11.1+ understands release semantics and generates an + ordinary store with a software memory barrier. */ +#if __ICC >= 1110 +#define RELEASE(m) __sync_lock_release(&(m)->lock) +#else +#define RELEASE(m) __cilkrts_xchg(&(m)->lock, 0) +#endif + +void __cilkrts_mutex_init(struct mutex *m) +{ + m->owner = 0; + + // Use a simple assignment so Inspector doesn't bug us about the + // interlocked exchange doing a read of an uninitialized variable. + // By definition there can't be a race when we're initializing the + // lock... + m->lock = 0; +} + +void __cilkrts_mutex_lock(__cilkrts_worker *w, struct mutex *m) +{ + int count; + const int maxspin = 1000; /* SWAG */ + + NOTE_INTERVAL(w, INTERVAL_MUTEX_LOCK); + if (!TRY_ACQUIRE(m)) { + START_INTERVAL(w, INTERVAL_MUTEX_LOCK_SPINNING); + count = 0; + do { + do { + __cilkrts_short_pause(); + if (++count >= maxspin) { + STOP_INTERVAL(w, INTERVAL_MUTEX_LOCK_SPINNING); + START_INTERVAL(w, INTERVAL_MUTEX_LOCK_YIELDING); + /* let the OS reschedule every once in a while */ + __cilkrts_yield(); + STOP_INTERVAL(w, INTERVAL_MUTEX_LOCK_YIELDING); + START_INTERVAL(w, INTERVAL_MUTEX_LOCK_SPINNING); + count = 0; + } + } while (m->lock != 0); + } while (!TRY_ACQUIRE(m)); + STOP_INTERVAL(w, INTERVAL_MUTEX_LOCK_SPINNING); + } + + CILK_ASSERT(m->owner == 0); + m->owner = w; +} + +int __cilkrts_mutex_trylock(__cilkrts_worker *w, struct mutex *m) +{ + NOTE_INTERVAL(w, INTERVAL_MUTEX_TRYLOCK); + if (TRY_ACQUIRE(m)) { + CILK_ASSERT(m->owner == 0); + m->owner = w; + return 1; + } else { + return 0; + } +} + +void __cilkrts_mutex_unlock(__cilkrts_worker *w, struct mutex *m) +{ + CILK_ASSERT(m->owner == w); + m->owner = 0; + RELEASE(m); +} + +void __cilkrts_mutex_destroy(__cilkrts_worker *w, struct mutex *m) +{ + (void)w; /* unused */ + (void)m; /* unused */ +} + +/* End worker_mutex.c */ diff --git a/libcilkrts/runtime/worker_mutex.h b/libcilkrts/runtime/worker_mutex.h new file mode 100644 index 00000000000..c2c68247e0b --- /dev/null +++ b/libcilkrts/runtime/worker_mutex.h @@ -0,0 +1,131 @@ +/* worker_mutex.h -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2009-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** + * @file worker_mutex.h + * + * @brief Support for Cilk runtime mutexes. + * + * Cilk runtime mutexes are implemented as simple spin loops. + */ + +#ifndef INCLUDED_WORKER_MUTEX_DOT_H +#define INCLUDED_WORKER_MUTEX_DOT_H + +#include <cilk/common.h> +#include "rts-common.h" + +__CILKRTS_BEGIN_EXTERN_C + +/** + * Mutexes are treated as an abstract data type within the Cilk + * runtime system. They are implemented as simple spin loops and + * owned by a __cilkrts_worker. + */ +typedef struct mutex { + /** Mutex spin loop variable. 0 if unowned, 1 if owned. */ + volatile int lock; + + /** Worker that owns the mutex. Must be 0 if mutex is unowned. */ + __cilkrts_worker *owner; +} mutex; + +/** + * @brief Initialize a Cilk mutex. + * + * @param m Mutex to be initialized. + */ +COMMON_PORTABLE +void __cilkrts_mutex_init(struct mutex *m); + +/** + * @brief Acquire a Cilk mutex. + * + * If statistics are being gathered, the time spent + * acquiring the mutex will be attributed to the specified worker. + * + * @param w Worker that will become the owner of this mutex. + * @param m Mutex to be initialized. + */ +COMMON_PORTABLE +void __cilkrts_mutex_lock(__cilkrts_worker *w, + struct mutex *m); +/** + * @brief Attempt to lock a Cilk mutex and fail if it isn't available. + * + * If statistics are being gathered, the time spent acquiring the + * mutex will be attributed to the specified worker. + * + * @param w Worker that will become the owner of this mutex. + * @param m Mutex to be acquired. + * + * @return 1 if the mutex was acquired. + * @return 0 if the mutex was not acquired. + */ +COMMON_PORTABLE +int __cilkrts_mutex_trylock(__cilkrts_worker *w, + struct mutex *m); + +/** + * @brief Release a Cilk mutex. + * + * If statistics are being gathered, the time spent + * acquiring the mutex will be attributed to the specified worker. + * + * @pre The mutex must be owned by the worker. + * + * @param w Worker that owns this mutex. + * @param m Mutex to be released. + */ +COMMON_PORTABLE +void __cilkrts_mutex_unlock(__cilkrts_worker *w, + struct mutex *m); + +/** + * @brief Deallocate a Cilk mutex. Currently does nothing. + * + * @param w Unused. + * @param m Mutex to be deallocated. + */ +COMMON_PORTABLE +void __cilkrts_mutex_destroy(__cilkrts_worker *w, + struct mutex *m); + +__CILKRTS_END_EXTERN_C + +#endif // ! defined(INCLUDED_WORKER_MUTEX_DOT_H) |