diff options
author | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-11-12 22:44:25 +0000 |
---|---|---|
committer | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-11-12 22:44:25 +0000 |
commit | 71557f40388d63f90772e131647e3945acae850a (patch) | |
tree | abfdf21b9b9e181b7c87659d760cf46b5478d42c | |
parent | f0f80a6fb019976c280ff8587fbc7ba36a51625f (diff) | |
download | gcc-71557f40388d63f90772e131647e3945acae850a.tar.gz |
Merge branch 'libitm-cpp'
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/transactional-memory@154130 138bc75d-0d04-0410-961f-82ee72b054a4
65 files changed, 9068 insertions, 3315 deletions
diff --git a/libitm/ChangeLog b/libitm/ChangeLog index 67c918ca1e7..0e74790323f 100644 --- a/libitm/ChangeLog +++ b/libitm/ChangeLog @@ -1,3 +1,7 @@ +2009-11-12 Richard Henderson <rth@redhat.com> + + * Rewrite everything in C++. + 2009-11-03 Richard Henderson <rth@redhat.com> * config/x86/x86_sse.c, config/x86/x86_avx.c: New files. diff --git a/libitm/Makefile.am b/libitm/Makefile.am index 8a9ae5c5a2e..5dbefb01fcd 100644 --- a/libitm/Makefile.am +++ b/libitm/Makefile.am @@ -16,6 +16,7 @@ vpath % $(strip $(search_path)) AM_CPPFLAGS = $(addprefix -I, $(search_path)) AM_CFLAGS = $(XCFLAGS) +AM_CXXFLAGS = -std=gnu++0x -fno-rtti $(XCFLAGS) AM_CCASFLAGS = $(XCFLAGS) AM_LDFLAGS = $(XLDFLAGS) $(SECTION_LDFLAGS) $(OPT_LDFLAGS) @@ -28,17 +29,25 @@ else libitm_version_script = endif libitm_version_info = -version-info $(libtool_VERSION) + +## Force link with C, not C++. For now, while we're using C++ we don't +## want or need libstdc++. +libitm_la_LINK = $(LINK) libitm_la_LDFLAGS = $(libitm_version_info) $(libitm_version_script) \ -no-undefined libitm_la_SOURCES = \ - aatree.c alloc.c alloc_c.c alloc_cpp.c barrier.c beginend.c \ - clone.c copymask.c eh_cpp.c local.c memcpy.c memset.c page.c \ - query.c retry.c rwlock.c serial.c useraction.c sjlj.S futex.c \ - method-readonly.c method-wbetl.c + aatree.cc alloc.cc alloc_c.cc alloc_cpp.cc barrier.cc beginend.cc \ + clone.cc cacheline.cc cachepage.cc eh_cpp.cc local.cc memcpy.cc \ + memset.cc query.cc retry.cc rwlock.cc serial.cc useraction.cc util.cc \ + sjlj.S method-readonly.cc method-wbetl.cc if ARCH_X86 -libitm_la_SOURCES += x86_sse.c x86_avx.c -x86_sse.lo : AM_CFLAGS += -msse -x86_avx.lo : AM_CFLAGS += -mavx +libitm_la_SOURCES += x86_sse.cc x86_avx.cc +x86_sse.lo : XCFLAGS += -msse +x86_avx.lo : XCFLAGS += -mavx +endif + +if ARCH_FUTEX +libitm_la_SOURCES += futex.cc endif diff --git a/libitm/Makefile.in b/libitm/Makefile.in index d19215da759..f46c1725cef 100644 --- a/libitm/Makefile.in +++ b/libitm/Makefile.in @@ -36,7 +36,8 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ -@ARCH_X86_TRUE@am__append_1 = x86_sse.c x86_avx.c +@ARCH_X86_TRUE@am__append_1 = x86_sse.cc x86_avx.cc +@ARCH_FUTEX_TRUE@am__append_2 = futex.cc subdir = . DIST_COMMON = $(am__configure_deps) $(srcdir)/../config.guess \ $(srcdir)/../config.sub $(srcdir)/../depcomp \ @@ -92,21 +93,21 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)" \ "$(DESTDIR)$(toolexeclibdir)" LTLIBRARIES = $(toolexeclib_LTLIBRARIES) libitm_la_LIBADD = -am__libitm_la_SOURCES_DIST = aatree.c alloc.c alloc_c.c alloc_cpp.c \ - barrier.c beginend.c clone.c copymask.c eh_cpp.c local.c \ - memcpy.c memset.c page.c query.c retry.c rwlock.c serial.c \ - useraction.c sjlj.S futex.c method-readonly.c method-wbetl.c \ - x86_sse.c x86_avx.c +am__libitm_la_SOURCES_DIST = aatree.cc alloc.cc alloc_c.cc \ + alloc_cpp.cc barrier.cc beginend.cc clone.cc cacheline.cc \ + cachepage.cc eh_cpp.cc local.cc memcpy.cc memset.cc query.cc \ + retry.cc rwlock.cc serial.cc useraction.cc util.cc sjlj.S \ + method-readonly.cc method-wbetl.cc x86_sse.cc x86_avx.cc \ + futex.cc @ARCH_X86_TRUE@am__objects_1 = x86_sse.lo x86_avx.lo +@ARCH_FUTEX_TRUE@am__objects_2 = futex.lo am_libitm_la_OBJECTS = aatree.lo alloc.lo alloc_c.lo alloc_cpp.lo \ - barrier.lo beginend.lo clone.lo copymask.lo eh_cpp.lo local.lo \ - memcpy.lo memset.lo page.lo query.lo retry.lo rwlock.lo \ - serial.lo useraction.lo sjlj.lo futex.lo method-readonly.lo \ - method-wbetl.lo $(am__objects_1) + barrier.lo beginend.lo clone.lo cacheline.lo cachepage.lo \ + eh_cpp.lo local.lo memcpy.lo memset.lo query.lo retry.lo \ + rwlock.lo serial.lo useraction.lo util.lo sjlj.lo \ + method-readonly.lo method-wbetl.lo $(am__objects_1) \ + $(am__objects_2) libitm_la_OBJECTS = $(am_libitm_la_OBJECTS) -libitm_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(libitm_la_LDFLAGS) $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/../depcomp am__depfiles_maybe = depfiles @@ -116,6 +117,15 @@ CPPASCOMPILE = $(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ LTCPPASCOMPILE = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CCASFLAGS) $(CCASFLAGS) +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 $@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ @@ -200,6 +210,10 @@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ @@ -260,6 +274,7 @@ 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@ ac_ct_FC = @ac_ct_FC@ am__include = @am__include@ @@ -328,6 +343,7 @@ fincludedir = $(libdir)/gcc/$(target_alias)/$(gcc_version)/finclude libsubincludedir = $(libdir)/gcc/$(target_alias)/$(gcc_version)/include AM_CPPFLAGS = $(addprefix -I, $(search_path)) AM_CFLAGS = $(XCFLAGS) +AM_CXXFLAGS = -std=gnu++0x -fno-rtti $(XCFLAGS) AM_CCASFLAGS = $(XCFLAGS) AM_LDFLAGS = $(XLDFLAGS) $(SECTION_LDFLAGS) $(OPT_LDFLAGS) toolexeclib_LTLIBRARIES = libitm.la @@ -335,19 +351,21 @@ nodist_toolexeclib_HEADERS = libitm.spec @LIBITM_BUILD_VERSIONED_SHLIB_FALSE@libitm_version_script = @LIBITM_BUILD_VERSIONED_SHLIB_TRUE@libitm_version_script = -Wl,--version-script,$(top_srcdir)/libitm.map libitm_version_info = -version-info $(libtool_VERSION) +libitm_la_LINK = $(LINK) libitm_la_LDFLAGS = $(libitm_version_info) $(libitm_version_script) \ -no-undefined -libitm_la_SOURCES = aatree.c alloc.c alloc_c.c alloc_cpp.c barrier.c \ - beginend.c clone.c copymask.c eh_cpp.c local.c memcpy.c \ - memset.c page.c query.c retry.c rwlock.c serial.c useraction.c \ - sjlj.S futex.c method-readonly.c method-wbetl.c \ - $(am__append_1) +libitm_la_SOURCES = aatree.cc alloc.cc alloc_c.cc alloc_cpp.cc \ + barrier.cc beginend.cc clone.cc cacheline.cc cachepage.cc \ + eh_cpp.cc local.cc memcpy.cc memset.cc query.cc retry.cc \ + rwlock.cc serial.cc useraction.cc util.cc sjlj.S \ + method-readonly.cc method-wbetl.cc $(am__append_1) \ + $(am__append_2) all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: -.SUFFIXES: .S .c .lo .o .obj +.SUFFIXES: .S .cc .lo .o .obj am--refresh: @: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @@ -447,8 +465,9 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alloc_cpp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/barrier.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/beginend.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cacheline.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cachepage.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clone.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/copymask.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eh_cpp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/futex.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/local.Plo@am__quote@ @@ -456,13 +475,13 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memset.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/method-readonly.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/method-wbetl.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/page.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/query.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/retry.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rwlock.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/serial.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sjlj.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/useraction.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x86_avx.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x86_sse.Plo@am__quote@ @@ -487,26 +506,26 @@ distclean-compile: @AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCCAS_FALSE@ $(LTCPPASCOMPILE) -c -o $@ $< -.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 $@ $< +.cc.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 $@ $< + +.cc.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) '$<'` + +.cc.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 $@ $< mostlyclean-libtool: -rm -f *.lo @@ -1001,8 +1020,8 @@ uninstall-am: uninstall-nodist_toolexeclibHEADERS \ vpath % $(strip $(search_path)) -@ARCH_X86_TRUE@x86_sse.lo : AM_CFLAGS += -msse -@ARCH_X86_TRUE@x86_avx.lo : AM_CFLAGS += -mavx +@ARCH_X86_TRUE@x86_sse.lo : XCFLAGS += -msse +@ARCH_X86_TRUE@x86_avx.lo : XCFLAGS += -mavx # 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. diff --git a/libitm/aatree.c b/libitm/aatree.c deleted file mode 100644 index 88164ac4662..00000000000 --- a/libitm/aatree.c +++ /dev/null @@ -1,298 +0,0 @@ -/* Copyright (C) 2009 Free Software Foundation, Inc. - Contributed by Richard Henderson <rth@redhat.com>. - - This file is part of the GNU Transactional Memory Library (libitm). - - Libitm is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - Libitm is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - <http://www.gnu.org/licenses/>. */ - -/* Implements an AA tree (http://en.wikipedia.org/wiki/AA_tree) with an - integer key, and data attached to the node via flexible array member. */ - -#include "libitm_i.h" - - -typedef unsigned int aa_level; - -typedef struct aa_node -{ - struct aa_node *link[2]; - aa_key key; - aa_level level; - char data[] __attribute__((aligned)); -} aa_node; - -#define L 0 -#define R 1 -#define NIL ((aa_tree)&aa_nil) - -/* The code for rebalancing the tree is greatly simplified by never - having to check for null pointers. Instead, leaf node links point - to this node, NIL, which points to itself. */ -static const aa_node aa_nil = { { NIL, NIL }, 0, 0 }; - -/* Remove left horizontal links. Swap the pointers of - horizontal left links. */ - -static aa_tree -skew (aa_tree t) -{ - aa_tree l = t->link[L]; - if (t->level != 0 && l->level == t->level) - { - t->link[L] = l->link[R]; - l->link[R] = t; - return l; - } - return t; -} - -/* Remove consecutive horizontal links. Take the middle node, - elevate it, and return it. */ - -static aa_tree -split (aa_tree t) -{ - aa_tree r = t->link[R]; - if (t->level != 0 && r->link[R]->level == t->level) - { - t->link[R] = r->link[L]; - r->link[L] = t; - r->level += 1; - return r; - } - return t; -} - -/* Decrease the level of T to be one more than the level of its children. */ - -static void -decrease_level (aa_tree t) -{ - aa_tree l = t->link[L]; - aa_tree r = t->link[R]; - aa_level llev = l->level; - aa_level rlev = r->level; - aa_level should_be = (llev < rlev ? llev : rlev) + 1; - - if (should_be < t->level) - { - t->level = should_be; - if (should_be < rlev) - r->level = should_be; - } -} - -/* Allocate a new node for KEY, with extra memory SIZE. */ - -static aa_tree -aa_new (uintptr_t key, size_t size) -{ - aa_tree n = malloc (sizeof (*n) + size); - - n->link[0] = NIL; - n->link[1] = NIL; - n->key = key; - n->level = 1; - - return n; -} - -/* Find the node within T that has KEY. If found, return the data - associated with the key. */ - -void * -aa_find (aa_tree t, aa_key key) -{ - if (t != NULL) - while (t != NIL) - { - if (t->key == key) - return t->data; - t = t->link[key > t->key]; - } - - return NULL; -} - -/* Insert N into T and rebalance. Return the new balanced tree. */ - -static aa_tree -aa_insert_1 (aa_tree t, aa_tree n) -{ - int dir = n->key > t->key; - aa_tree c = t->link[dir]; - - /* Insert the node, recursively. */ - if (c == NIL) - c = n; - else - c = aa_insert_1 (c, n); - t->link[dir] = c; - - /* Rebalance the tree, as needed. */ - t = skew (t); - t = split (t); - - return t; -} - -/* Insert a new node with KEY into the tree rooted at *PTREE. Create - the new node with extra memory SIZE. Return a pointer to the extra - memory associated with the new node. It is invalid to insert a - duplicate key. */ - -void * -aa_insert (aa_tree *ptree, aa_key key, size_t size) -{ - aa_tree n = aa_new (key, size); - aa_tree t = *ptree; - - if (t == NULL) - t = n; - else - t = aa_insert_1 (t, n); - *ptree = t; - - return n->data; -} - -/* Delete KEY from T and rebalance. Return the new balanced tree. */ - -static aa_tree -aa_delete_1 (aa_tree t, aa_key key, bool do_free) -{ - aa_tree r; - int dir; - - /* If this is the node we're looking for, delete it. Else recurse. */ - if (key == t->key) - { - aa_tree l, sub, end; - - l = t->link[L]; - r = t->link[R]; - - if (do_free) - free (t); - - /* If this is a leaf node, simply remove the node. Otherwise, - we have to find either a predecessor or a successor node to - replace this one. */ - if (l == NIL) - { - if (r == NIL) - return NIL; - sub = r, dir = L; - } - else - sub = l, dir = R; - - /* Find the successor or predecessor. */ - for (end = sub; end->link[dir] != NIL; end = end->link[dir]) - continue; - - /* Remove it (but don't free) from the subtree. */ - sub = aa_delete_1 (sub, end->key, false); - - /* Replace T with the successor we just extracted. */ - end->link[1-dir] = sub; - t = end; - } - else - { - dir = key > t->key; - t->link[dir] = aa_delete_1 (t->link[dir], key, do_free); - } - - /* Rebalance the tree. */ - decrease_level (t); - t = skew (t); - t->link[R] = r = skew (t->link[R]); - r->link[R] = skew (r->link[R]); - t = split (t); - t->link[R] = split (t->link[R]); - - return t; -} - -/* Delete KEY from the tree rooted at *PTREE. */ - -void -aa_delete (aa_tree *ptree, aa_key key) -{ - aa_tree t = *ptree; - - if (t == NULL) - return; - - t = aa_delete_1 (t, key, true); - if (t == NIL) - t = NULL; - *ptree = t; -} - -/* Free the tree at T. */ - -static void -aa_free_1 (aa_tree t) -{ - int dir; - for (dir = 0; dir < 2; ++dir) - { - aa_tree c = t->link[dir]; - if (c != NIL) - aa_free_1 (c); - } - free (t); -} - -/* Free the tree rooted at *PTREE. */ - -void -aa_free (aa_tree *ptree) -{ - aa_tree t = *ptree; - if (t != NULL) - aa_free_1 (t); - *ptree = NULL; -} - -/* Invoke CALLBACK on each node of T. */ - -static void -aa_traverse_1 (aa_tree t, void (*callback)(aa_key, void *, void *), - void *callback_data) -{ - if (t == NIL) - return; - - callback (t->key, t->data, callback_data); - - aa_traverse (t->link[L], callback, callback_data); - aa_traverse (t->link[R], callback, callback_data); -} - -void -aa_traverse (aa_tree t, void (*callback)(aa_key, void *, void *), - void *callback_data) -{ - if (t != NULL) - aa_traverse_1 (t, callback, callback_data); -} diff --git a/libitm/aatree.cc b/libitm/aatree.cc new file mode 100644 index 00000000000..a930e7199e9 --- /dev/null +++ b/libitm/aatree.cc @@ -0,0 +1,222 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +// Implements an AA tree (http://en.wikipedia.org/wiki/AA_tree) with an +// integer key, and data attached to the node via flexible array member. + +#include "libitm_i.h" + +namespace GTM HIDDEN { + +// The code for rebalancing the tree is greatly simplified by never +// having to check for null pointers. Instead, leaf node links point +// to this node, NIL, which points to itself. +const aa_node_base aa_node_base::s_nil(0); + + +// Remove left horizontal links. Swap the pointers of horizontal left links. + +aa_node_base * +aa_node_base::skew () +{ + aa_node_base *l = this->link(L); + if (this->m_level != 0 && l->m_level == this->m_level) + { + this->set_link(L, l->link(R)); + l->set_link(R, this); + return l; + } + return this; +} + + +// Remove consecutive horizontal links. Take the middle node, +// elevate it, and return it. + +aa_node_base * +aa_node_base::split () +{ + aa_node_base *r = this->link(R); + if (this->m_level != 0 && r->link(R)->m_level == this->m_level) + { + this->set_link(R, r->link(L)); + r->set_link(L, this); + r->m_level += 1; + return r; + } + return this; +} + +// Decrease the level of THIS to be one more than the level of its children. + +void +aa_node_base::decrease_level () +{ + aa_node_base *l = this->link(L); + aa_node_base *r = this->link(R); + level_type llev = l->m_level; + level_type rlev = r->m_level; + level_type should_be = (llev < rlev ? llev : rlev) + 1; + + if (should_be < this->m_level) + { + this->m_level = should_be; + if (should_be < rlev) + r->m_level = should_be; + } +} + +// Find and return the node in the tree with key K. + +template<typename KEY> +typename aa_tree_key<KEY>::node_ptr +aa_tree_key<KEY>::find(KEY k) const +{ + node_ptr t = m_tree; + if (t != 0) + do + { + if (t->key == k) + return t; + t = t->link(k > t->key); + } + while (!t->is_nil()); + return 0; +} + +// Insert N into T and rebalance. Return the new balanced tree. + +template<typename KEY> +typename aa_tree_key<KEY>::node_ptr +aa_tree_key<KEY>::insert_1 (node_ptr t, node_ptr n) +{ + bool dir = n->key > t->key; + node_ptr c = t->link(dir); + + // Insert the node, recursively. + if (c->is_nil()) + c = n; + else + c = insert_1 (c, n); + t->set_link(dir, c); + + // Rebalance the tree, as needed. + t = t->skew(); + t = t->split(); + + return t; +} + +template<typename KEY> +void +aa_tree_key<KEY>::insert(node_ptr n) +{ + if (m_tree == 0) + m_tree = n; + else + m_tree = insert_1 (m_tree, n); +} + +// Delete K from T and rebalance. Return the new balanced tree. + +template<typename KEY> +typename aa_tree_key<KEY>::node_ptr +aa_tree_key<KEY>::erase_1 (node_ptr t, KEY k, node_ptr *pfree) +{ + node_ptr r; + bool dir; + + // If this is the node we're looking for, delete it. Else recurse. + if (k == t->key) + { + node_ptr l, sub, end; + + l = t->link(node::L); + r = t->link(node::R); + + if (pfree) + *pfree = t; + + // If this is a leaf node, simply remove the node. Otherwise, + // we have to find either a predecessor or a successor node to + // replace this one. + if (l->is_nil()) + { + if (r->is_nil()) + return r; + sub = r, dir = node::L; + } + else + sub = l, dir = node::R; + + // Find the successor or predecessor. + for (end = sub; !end->link(dir)->is_nil(); end = end->link(dir)) + continue; + + // Remove it (but don't free) from the subtree. + sub = erase_1 (sub, end->key, 0); + + // Replace T with the successor we just extracted. + end->set_link(!dir, sub); + t = end; + } + else + { + dir = k > t->key; + t->set_link(dir, erase_1 (t->link(dir), k, pfree)); + } + + // Rebalance the tree. + t->decrease_level(); + t = t->skew(); + r = t->link(node::R)->skew(); + t->set_link(node::R, r); + r->set_link(node::R, r->link(node::R)->skew()); + t = t->split (); + t->set_link(node::R, t->link(node::R)->split()); + + return t; +} + +template<typename KEY> +typename aa_tree_key<KEY>::node_ptr +aa_tree_key<KEY>::erase (KEY k) +{ + node_ptr t = m_tree; + if (t == 0) + return 0; + + node_ptr do_free = 0; + t = erase_1 (t, k, &do_free); + if (t->is_nil()) + t = 0; + m_tree = t; + return do_free; +} + +// Instantiate key classes. + +template class aa_tree_key<uintptr_t>; + +} // namespace GTM diff --git a/libitm/aatree.h b/libitm/aatree.h index 582eb652177..6d28890c7b1 100644 --- a/libitm/aatree.h +++ b/libitm/aatree.h @@ -25,11 +25,182 @@ /* Implements an AA tree (http://en.wikipedia.org/wiki/AA_tree) with an integer key, and data attached to the node via flexible array member. */ -typedef uintptr_t aa_key; -typedef struct aa_node *aa_tree; - -extern void *aa_find (aa_tree, aa_key); -extern void *aa_insert (aa_tree *, aa_key, size_t); -extern void aa_delete (aa_tree *, aa_key); -extern void aa_free (aa_tree *); -extern void aa_traverse (aa_tree, void (*)(aa_key, void *, void *), void *); +#ifndef LIBITM_AATREE_H +#define LIBITM_AATREE_H 1 + +namespace GTM HIDDEN { + +template<typename KEY> class aa_tree_key; + +class aa_node_base +{ + public: + static const bool L = false; + static const bool R = true; + + private: + typedef unsigned int level_type; + + aa_node_base *m_link[2]; + level_type m_level; + + static const aa_node_base s_nil; + + public: + aa_node_base(level_type l = 1) + : m_link({ const_cast<aa_node_base *>(&s_nil), + const_cast<aa_node_base *>(&s_nil) }), + m_level(l) + { } + + bool is_nil() const { return this == &s_nil; } + + aa_node_base * link(bool d) { return m_link[d]; } + void set_link(bool d, aa_node_base *val) { m_link[d] = val; } + + aa_node_base *skew(); + aa_node_base *split(); + void decrease_level(); + + static void *operator new (size_t s) { return xmalloc (s); } + static void operator delete (void *p) { free (p); } +}; + +template<typename KEY> +struct aa_node_key : public aa_node_base +{ + typedef aa_node_base base; + + KEY key; + + explicit aa_node_key(KEY k) : key(k) { } + + aa_node_key * link(bool d) + { + return static_cast<aa_node_key *>(base::link(d)); + } + + aa_node_key *skew() { return static_cast<aa_node_key *>(base::skew()); } + aa_node_key *split() { return static_cast<aa_node_key *>(base::split()); } +}; + +template<typename KEY, typename DATA> +struct aa_node : public aa_node_key<KEY> +{ + typedef aa_node_key<KEY> base; + + DATA data; + + explicit aa_node(KEY k) : base(k) { } + + aa_node * link(bool d) + { + return static_cast<aa_node *>(base::link(d)); + } +}; + +template<typename KEY> +class aa_tree_key +{ + public: + typedef aa_node_key<KEY> node; + typedef node *node_ptr; + + protected: + node_ptr m_tree; + + protected: + aa_tree_key() : m_tree(0) { } + + node_ptr find(KEY k) const; + + static node_ptr insert_1 (node_ptr t, node_ptr n); + void insert(node_ptr n); + + static node_ptr erase_1 (node_ptr t, KEY k, node_ptr *pfree); + node_ptr erase(KEY k); +}; + +extern template class aa_tree_key<uintptr_t>; + +template<typename KEY, typename DATA> +class aa_tree : public aa_tree_key<KEY> +{ + public: + typedef aa_tree_key<KEY> base; + typedef aa_node<KEY, DATA> node; + typedef node *node_ptr; + + typedef void (*trav_callback)(KEY, DATA *, void *); + + private: + static void clear_1 (node_ptr); + static void traverse_1 (node_ptr, trav_callback, void *); + + public: + aa_tree() = default; + ~aa_tree() { clear(); } + + DATA *find(KEY k) const + { + node_ptr n = static_cast<node_ptr>(base::find (k)); + return n ? &n->data : 0; + } + + DATA *insert(KEY k) + { + node_ptr n = new node(k); + base::insert(n); + return &n->data; + } + + void erase(KEY k) + { + node_ptr n = static_cast<node_ptr>(base::erase (k)); + delete n; + } + + void clear() + { + node_ptr n = static_cast<node_ptr>(this->m_tree); + if (n) + { + this->m_tree = 0; + clear_1 (n); + } + } + + void traverse (trav_callback cb, void *cb_data) + { + node_ptr t = static_cast<node_ptr>(this->m_tree); + if (t != 0) + traverse_1 (t, cb, cb_data); + } +}; + + +template<typename KEY, typename DATA> +void +aa_tree<KEY, DATA>::clear_1 (node_ptr t) +{ + if (t->is_nil()) + return; + clear_1 (t->link(node::L)); + clear_1 (t->link(node::R)); + delete t; +} + +template<typename KEY, typename DATA> +void +aa_tree<KEY, DATA>::traverse_1 (node_ptr t, trav_callback cb, void *cb_data) +{ + if (t->is_nil()) + return; + cb (t->key, &t->data, cb_data); + traverse_1 (t->link(node::L), cb, cb_data); + traverse_1 (t->link(node::R), cb, cb_data); +} + +} // namespace GTM + +#endif // LIBITM_AATREE_H diff --git a/libitm/alloc.c b/libitm/alloc.cc index d2bd4380454..2729760a1aa 100644 --- a/libitm/alloc.c +++ b/libitm/alloc.cc @@ -24,26 +24,25 @@ #include "libitm_i.h" +namespace GTM HIDDEN { -/* This is extra data attached to each node of an AA tree. */ -typedef struct gtm_alloc_action +struct gtm_alloc_action { void (*free_fn)(void *); size_t size; bool allocated; -} gtm_alloc_action; +}; void -GTM_record_allocation (void *ptr, size_t size, void (*free_fn)(void *)) +gtm_transaction::record_allocation (void *ptr, size_t size, + void (*free_fn)(void *)) { - gtm_transaction *tx = gtm_tx (); - gtm_alloc_action *a; uintptr_t iptr = (uintptr_t) ptr; - a = aa_find (tx->alloc_actions, iptr); - if (a == NULL) - a = aa_insert (&tx->alloc_actions, iptr, sizeof (*a)); + gtm_alloc_action *a = this->alloc_actions.find(iptr); + if (a == 0) + a = this->alloc_actions.insert(iptr); a->free_fn = free_fn; a->size = size; @@ -51,15 +50,13 @@ GTM_record_allocation (void *ptr, size_t size, void (*free_fn)(void *)) } void -GTM_forget_allocation (void *ptr, void (*free_fn)(void *)) +gtm_transaction::forget_allocation (void *ptr, void (*free_fn)(void *)) { - gtm_transaction *tx = gtm_tx (); - gtm_alloc_action *a; uintptr_t iptr = (uintptr_t) ptr; - a = aa_find (tx->alloc_actions, iptr); - if (a == NULL) - a = aa_insert (&tx->alloc_actions, iptr, sizeof (*a)); + gtm_alloc_action *a = this->alloc_actions.find(iptr); + if (a == 0) + a = this->alloc_actions.insert(iptr); a->free_fn = free_fn; a->size = 0; @@ -67,21 +64,18 @@ GTM_forget_allocation (void *ptr, void (*free_fn)(void *)) } size_t -GTM_get_allocation_size (void *ptr) +gtm_transaction::get_allocation_size (void *ptr) { - gtm_transaction *tx = gtm_tx (); - gtm_alloc_action *a; uintptr_t iptr = (uintptr_t) ptr; - a = aa_find (tx->alloc_actions, iptr); + gtm_alloc_action *a = this->alloc_actions.find(iptr); return a ? a->size : 0; } static void -commit_allocations_1 (aa_key key, void *node_data, void *cb_data) +commit_allocations_1 (uintptr_t key, gtm_alloc_action *a, void *cb_data) { void *ptr = (void *)key; - gtm_alloc_action *a = node_data; uintptr_t revert_p = (uintptr_t) cb_data; if (a->allocated == revert_p) @@ -89,8 +83,11 @@ commit_allocations_1 (aa_key key, void *node_data, void *cb_data) } void -GTM_commit_allocations (bool revert_p) +gtm_transaction::commit_allocations (bool revert_p) { - aa_traverse (gtm_tx()->alloc_actions, commit_allocations_1, - (void *)(uintptr_t)revert_p); + this->alloc_actions.traverse (commit_allocations_1, + (void *)(uintptr_t)revert_p); + this->alloc_actions.clear (); } + +} // namespace GTM diff --git a/libitm/alloc_c.c b/libitm/alloc_c.cc index c66ee7900b6..641d915cfd1 100644 --- a/libitm/alloc_c.c +++ b/libitm/alloc_c.cc @@ -25,13 +25,16 @@ #include "libitm_i.h" +using namespace GTM; + + /* Wrap: malloc (size_t sz) */ void * _ITM_malloc (size_t sz) { void *r = malloc (sz); if (r) - GTM_record_allocation (r, sz, free); + gtm_tx()->record_allocation (r, sz, free); return r; } @@ -41,7 +44,7 @@ _ITM_calloc (size_t nm, size_t sz) { void *r = calloc (nm, sz); if (r) - GTM_record_allocation (r, nm*sz, free); + gtm_tx()->record_allocation (r, nm*sz, free); return r; } @@ -49,12 +52,13 @@ _ITM_calloc (size_t nm, size_t sz) void * _ITM_realloc (void *ptr, size_t sz) { + gtm_transaction *tx = gtm_tx(); void *r; if (sz == 0) { /* If sz == 0, then realloc == free. */ if (ptr) - GTM_forget_allocation (ptr, free); + tx->forget_allocation (ptr, free); r = NULL; } else if (ptr == NULL) @@ -62,17 +66,17 @@ _ITM_realloc (void *ptr, size_t sz) /* If ptr == NULL, then realloc == malloc. */ r = malloc (sz); if (r) - GTM_record_allocation (r, sz, free); + tx->record_allocation (r, sz, free); } else if (ptr) { /* We may have recorded the size of the allocation earlier in this transaction. If so, fine, we can reallocate. Otherwise we're stuck and we'll have to go irrevokable. */ - size_t osz = GTM_get_allocation_size (ptr); + size_t osz = tx->get_allocation_size (ptr); if (osz == 0) { - GTM_serialmode (false, true); + tx->serialirr_mode (); return realloc (ptr, sz); } @@ -84,8 +88,8 @@ _ITM_realloc (void *ptr, size_t sz) method is write-back, we have to be careful to use memory from the cache if locks were taken. */ _ITM_memcpyRnWt (r, ptr, (sz < osz ? sz : osz)); - GTM_record_allocation (r, sz, free); - GTM_forget_allocation (ptr, free); + tx->record_allocation (r, sz, free); + tx->forget_allocation (ptr, free); } } return r; @@ -96,5 +100,5 @@ void _ITM_free (void *ptr) { if (ptr) - GTM_forget_allocation (ptr, free); + gtm_tx()->forget_allocation (ptr, free); } diff --git a/libitm/alloc_cpp.c b/libitm/alloc_cpp.cc index bbeb3e0d872..b5ff790b528 100644 --- a/libitm/alloc_cpp.c +++ b/libitm/alloc_cpp.cc @@ -24,9 +24,13 @@ #include "libitm_i.h" +using namespace GTM; + /* Everything from libstdc++ is weak, to avoid requiring that library to be linked into plain C applications using libitm.so. */ +extern "C" { + extern void *_Znwm (size_t) __attribute__((weak)); extern void _ZdlPv (void *) __attribute__((weak)); extern void *_Znam (size_t) __attribute__((weak)); @@ -62,7 +66,7 @@ _ZGTtnwm (size_t sz) { void *r = _Znwm (sz); if (r) - GTM_record_allocation (r, sz, _ZdlPv); + gtm_tx()->record_allocation (r, sz, _ZdlPv); return r; } @@ -72,7 +76,7 @@ _ZGTtnwmRKSt9nothrow_t (size_t sz, c_nothrow_p nt) { void *r = _ZnwmRKSt9nothrow_t (sz, nt); if (r) - GTM_record_allocation (r, sz, del_opnt); + gtm_tx()->record_allocation (r, sz, del_opnt); return r; } @@ -82,7 +86,7 @@ _ZGTtnam (size_t sz) { void *r = _Znam (sz); if (r) - GTM_record_allocation (r, sz, _ZdaPv); + gtm_tx()->record_allocation (r, sz, _ZdaPv); return r; } @@ -92,7 +96,7 @@ _ZGTtnamRKSt9nothrow_t (size_t sz, c_nothrow_p nt) { void *r = _ZnamRKSt9nothrow_t (sz, nt); if (r) - GTM_record_allocation (r, sz, del_opvnt); + gtm_tx()->record_allocation (r, sz, del_opvnt); return r; } @@ -101,7 +105,7 @@ void _ZGTtdlPv (void *ptr) { if (ptr) - GTM_forget_allocation (ptr, _ZdlPv); + gtm_tx()->forget_allocation (ptr, _ZdlPv); } /* Wrap: operator delete (void *ptr, const std::nothrow_t&) */ @@ -109,7 +113,7 @@ void _ZGTtdlPvRKSt9nothrow_t (void *ptr, c_nothrow_p nt UNUSED) { if (ptr) - GTM_forget_allocation (ptr, del_opnt); + gtm_tx()->forget_allocation (ptr, del_opnt); } /* Wrap: operator delete[] (void *ptr) */ @@ -117,7 +121,7 @@ void _ZGTtdaPv (void *ptr) { if (ptr) - GTM_forget_allocation (ptr, _ZdaPv); + gtm_tx()->forget_allocation (ptr, _ZdaPv); } /* Wrap: operator delete[] (void *ptr, const std::nothrow_t&) */ @@ -125,5 +129,7 @@ void _ZGTtdaPvRKSt9nothrow_t (void *ptr, c_nothrow_p nt UNUSED) { if (ptr) - GTM_forget_allocation (ptr, del_opvnt); + gtm_tx()->forget_allocation (ptr, del_opvnt); } + +} // extern "C" diff --git a/libitm/barrier.c b/libitm/barrier.c deleted file mode 100644 index 805549b4461..00000000000 --- a/libitm/barrier.c +++ /dev/null @@ -1,107 +0,0 @@ -/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. - Contributed by Richard Henderson <rth@redhat.com>. - - This file is part of the GNU Transactional Memory Library (libitm). - - Libitm is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - Libitm is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - <http://www.gnu.org/licenses/>. */ - -#include "libitm_i.h" - - -#define ITM_READ(T, LOCK) \ -_ITM_TYPE_##T ITM_REGPARM _ITM_##LOCK##T(const _ITM_TYPE_##T *ptr) \ -{ \ - uintptr_t iptr = (uintptr_t) ptr; \ - uintptr_t iline = iptr & -CACHELINE_SIZE; \ - uintptr_t iofs = iptr & (CACHELINE_SIZE - 1); \ - gtm_cacheline *line = gtm_disp()->LOCK (iline); \ - _ITM_TYPE_##T ret; \ - \ - if (STRICT_ALIGNMENT \ - ? (iofs & (sizeof (ret) - 1)) == 0 \ - : iofs + sizeof(ret) <= CACHELINE_SIZE) \ - { \ - return *(_ITM_TYPE_##T *)&line->b[iofs]; \ - } \ - else if (STRICT_ALIGNMENT && iofs + sizeof(ret) <= CACHELINE_SIZE) \ - { \ - memcpy (&ret, &line->b[iofs], sizeof (ret)); \ - } \ - else \ - { \ - uintptr_t ileft = CACHELINE_SIZE - iofs; \ - memcpy (&ret, &line->b[iofs], ileft); \ - line = gtm_disp()->LOCK (iline + CACHELINE_SIZE); \ - memcpy ((char *)&ret + ileft, line, sizeof(ret) - ileft); \ - } \ - return ret; \ -} - -#define ITM_WRITE(T, LOCK) \ -void ITM_REGPARM _ITM_##LOCK##T(_ITM_TYPE_##T *ptr, _ITM_TYPE_##T val) \ -{ \ - uintptr_t iptr = (uintptr_t) ptr; \ - uintptr_t iline = iptr & -CACHELINE_SIZE; \ - uintptr_t iofs = iptr & (CACHELINE_SIZE - 1); \ - gtm_cacheline_mask m = ((gtm_cacheline_mask)1 << sizeof(val)) - 1; \ - gtm_cacheline_mask_pair pair = gtm_disp()->LOCK (iline); \ - \ - if (STRICT_ALIGNMENT \ - ? (iofs & (sizeof (val) - 1)) == 0 \ - : iofs + sizeof(val) <= CACHELINE_SIZE) \ - { \ - *(_ITM_TYPE_##T *)&pair.line->b[iofs] = val; \ - *pair.mask |= m << iofs; \ - } \ - else if (STRICT_ALIGNMENT && iofs + sizeof(val) <= CACHELINE_SIZE) \ - { \ - memcpy (&pair.line->b[iofs], &val, sizeof (val)); \ - *pair.mask |= m << iofs; \ - } \ - else \ - { \ - uintptr_t ileft = CACHELINE_SIZE - iofs; \ - memcpy (&pair.line->b[iofs], &val, ileft); \ - *pair.mask |= m << iofs; \ - pair = gtm_disp()->LOCK (iline + CACHELINE_SIZE); \ - memcpy (pair.line, (char *)&val + ileft, sizeof(val) - ileft); \ - *pair.mask |= m >> ileft; \ - } \ -} - -#define ITM_BARRIERS(T) \ - ITM_READ(T, R) \ - ITM_READ(T, RaR) \ - ITM_READ(T, RaW) \ - ITM_READ(T, RfW) \ - ITM_WRITE(T, W) \ - ITM_WRITE(T, WaR) \ - ITM_WRITE(T, WaW) - -ITM_BARRIERS(U1) -ITM_BARRIERS(U2) -ITM_BARRIERS(U4) -ITM_BARRIERS(U8) -ITM_BARRIERS(F) -ITM_BARRIERS(D) -ITM_BARRIERS(E) -ITM_BARRIERS(CF) -ITM_BARRIERS(CD) -ITM_BARRIERS(CE) diff --git a/libitm/config/alpha/target_i.h b/libitm/barrier.cc index fae14007a3a..52e5a081d18 100644 --- a/libitm/config/alpha/target_i.h +++ b/libitm/barrier.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Free Software Foundation, Inc. +/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. Contributed by Richard Henderson <rth@redhat.com>. This file is part of the GNU Transactional Memory Library (libitm). @@ -22,21 +22,16 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see <http://www.gnu.org/licenses/>. */ - -static inline void -cpu_relax (void) -{ - __asm volatile ("" : : : "memory"); -} - -static inline void -atomic_read_barrier (void) -{ - __sync_synchronize (); -} - -static inline void -atomic_write_barrier (void) -{ - __asm volatile ("wmb" : : : "memory"); -} +#include "libitm_i.h" +#include "barrier.tpl" + +ITM_BARRIERS(U1) +ITM_BARRIERS(U2) +ITM_BARRIERS(U4) +ITM_BARRIERS(U8) +ITM_BARRIERS(F) +ITM_BARRIERS(D) +ITM_BARRIERS(E) +ITM_BARRIERS(CF) +ITM_BARRIERS(CD) +ITM_BARRIERS(CE) diff --git a/libitm/barrier.tpl b/libitm/barrier.tpl new file mode 100644 index 00000000000..c1b22026c6d --- /dev/null +++ b/libitm/barrier.tpl @@ -0,0 +1,137 @@ +/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "unaligned.h" + +namespace { + +using namespace GTM; + +template<typename T> +T do_read (const T *ptr, gtm_dispatch::lock_type lock) +{ + gtm_dispatch *disp = gtm_disp(); + uintptr_t iptr = reinterpret_cast<uintptr_t>(ptr); + uintptr_t iline = iptr & -CACHELINE_SIZE; + uintptr_t iofs = iptr & (CACHELINE_SIZE - 1); + const gtm_cacheline *pline = reinterpret_cast<const gtm_cacheline *>(iline); + const gtm_cacheline *line = disp->read_lock(pline, lock); + + ptr = reinterpret_cast<const T *>(&line->b[iofs]); + + if (__builtin_expect (strict_alignment<T>::value + ? (iofs & (sizeof (T) - 1)) == 0 + : iofs + sizeof(T) <= CACHELINE_SIZE, 1)) + { + do_normal_load: + return *ptr; + } + else if (__builtin_expect (strict_alignment<T>::value + && iofs + sizeof(T) <= CACHELINE_SIZE, 1)) + { + do_unaligned_load: + return unaligned_load<T>(ptr); + } + else + { + const gtm_cacheline *line2 = disp->read_lock(pline + 1, lock); + + if (line2 == line + 1) + { + if (!strict_alignment<T>::value) + goto do_normal_load; + else + goto do_unaligned_load; + } + else + return unaligned_load2<T>(line, line2, iofs); + } +} + +template<typename T> +void do_write (T *ptr, T val, gtm_dispatch::lock_type lock) +{ + gtm_dispatch *disp = gtm_disp(); + uintptr_t iptr = reinterpret_cast<uintptr_t>(ptr); + uintptr_t iline = iptr & -CACHELINE_SIZE; + uintptr_t iofs = iptr & (CACHELINE_SIZE - 1); + gtm_cacheline *pline = reinterpret_cast<gtm_cacheline *>(iline); + gtm_cacheline_mask m = ((gtm_cacheline_mask)2 << (sizeof(T) - 1)) - 1; + gtm_dispatch::mask_pair pair = disp->write_lock(pline, lock); + + ptr = reinterpret_cast<T *>(&pair.line->b[iofs]); + + if (__builtin_expect (strict_alignment<T>::value + ? (iofs & (sizeof (val) - 1)) == 0 + : iofs + sizeof(val) <= CACHELINE_SIZE, 1)) + { + *pair.mask |= m << iofs; + do_normal_store: + *ptr = val; + } + else if (__builtin_expect (strict_alignment<T>::value + && iofs + sizeof(val) <= CACHELINE_SIZE, 1)) + { + *pair.mask |= m << iofs; + do_unaligned_store: + unaligned_store<T>(ptr, val); + } + else + { + *pair.mask |= m << iofs; + gtm_dispatch::mask_pair pair2 = disp->write_lock(pline + 1, lock); + + uintptr_t ileft = CACHELINE_SIZE - iofs; + *pair2.mask |= m >> ileft; + + if (pair2.line == pair.line + 1) + { + if (!strict_alignment<T>::value) + goto do_normal_store; + else + goto do_unaligned_store; + } + else + unaligned_store2<T>(pair.line, pair2.line, iofs, val); + } +} + +} /* anonymous namespace */ + +#define ITM_READ(T, LOCK) \ + _ITM_TYPE_##T ITM_REGPARM _ITM_##LOCK##T (const _ITM_TYPE_##T *ptr) \ + { return do_read (ptr, gtm_dispatch::LOCK); } + +#define ITM_WRITE(T, LOCK) \ + void ITM_REGPARM _ITM_##LOCK##T (_ITM_TYPE_##T *ptr, _ITM_TYPE_##T val) \ + { do_write (ptr, val, gtm_dispatch::LOCK); } + +#define ITM_BARRIERS(T) \ + ITM_READ(T, R) \ + ITM_READ(T, RaR) \ + ITM_READ(T, RaW) \ + ITM_READ(T, RfW) \ + ITM_WRITE(T, W) \ + ITM_WRITE(T, WaR) \ + ITM_WRITE(T, WaW) diff --git a/libitm/beginend.c b/libitm/beginend.cc index 3689aa02128..0ca0f6f7a25 100644 --- a/libitm/beginend.c +++ b/libitm/beginend.cc @@ -25,14 +25,16 @@ #include "libitm_i.h" -__thread gtm_thread _gtm_thr; -gtm_rwlock gtm_serial_lock; +using namespace GTM; -gtm_stmlock gtm_stmlock_array[LOCK_ARRAY_SIZE]; -gtm_version gtm_clock; +__thread gtm_thread GTM::_gtm_thr; +gtm_rwlock GTM::gtm_transaction::serial_lock; + +gtm_stmlock GTM::gtm_stmlock_array[LOCK_ARRAY_SIZE]; +gtm_version GTM::gtm_clock; /* ??? Move elsewhere when we figure out library initialization. */ -uint64_t gtm_spin_count_var = 1000; +uint64_t GTM::gtm_spin_count_var = 1000; static _ITM_transactionId_t global_tid; @@ -45,13 +47,14 @@ alloc_tx (void) gtm_thread *thr = gtm_thr (); if (thr->free_tx_count == 0) - tx = malloc (sizeof (*tx)); + tx = static_cast<gtm_transaction *>(xmalloc (sizeof (gtm_transaction))); else { thr->free_tx_count--; tx = thr->free_tx[thr->free_tx_idx]; - thr->free_tx_idx = (thr->free_tx_idx + 1) % MAX_FREE_TX; + thr->free_tx_idx = (thr->free_tx_idx + 1) % gtm_thread::MAX_FREE_TX; } + memset (tx, 0, sizeof (*tx)); return tx; } @@ -65,11 +68,12 @@ static void free_tx (gtm_transaction *tx) { gtm_thread *thr = gtm_thr (); - unsigned idx = (thr->free_tx_idx + thr->free_tx_count) % MAX_FREE_TX; + unsigned idx + = (thr->free_tx_idx + thr->free_tx_count) % gtm_thread::MAX_FREE_TX; - if (thr->free_tx_count == MAX_FREE_TX) + if (thr->free_tx_count == gtm_thread::MAX_FREE_TX) { - thr->free_tx_idx = (thr->free_tx_idx + 1) % MAX_FREE_TX; + thr->free_tx_idx = (thr->free_tx_idx + 1) % gtm_thread::MAX_FREE_TX; free (thr->free_tx[idx]); } else @@ -80,15 +84,15 @@ free_tx (gtm_transaction *tx) uint32_t -GTM_begin_transaction (uint32_t prop, const gtm_jmpbuf *jb) +GTM::gtm_transaction::begin_transaction (uint32_t prop, const gtm_jmpbuf *jb) { gtm_transaction *tx; - const gtm_dispatch *disp; + gtm_dispatch *disp; + uint32_t ret; setup_gtm_thr (); tx = alloc_tx (); - memset (tx, 0, sizeof (*tx)); tx->prop = prop; tx->prev = gtm_tx(); @@ -101,54 +105,63 @@ GTM_begin_transaction (uint32_t prop, const gtm_jmpbuf *jb) if ((prop & pr_doesGoIrrevocable) || !(prop & pr_instrumentedCode)) { - GTM_serialmode (true, true); - return (prop & pr_uninstrumentedCode - ? a_runUninstrumentedCode : a_runInstrumentedCode); - } + serial_lock.write_lock (); + + tx->state = (STATE_SERIAL | STATE_IRREVOCABLE); + + disp = dispatch_serial (); - /* ??? Probably want some environment variable to choose the default - STM implementation once we have more than one implemented. */ - if (prop & pr_readOnly) - disp = &dispatch_readonly; + ret = a_runUninstrumentedCode; + if ((prop & pr_multiwayCode) == pr_instrumentedCode) + ret = a_runInstrumentedCode; + } else - disp = &dispatch_wbetl; - set_gtm_disp (disp); - disp->init (true); + { + serial_lock.read_lock (); + + // ??? Probably want some environment variable to choose the default + // STM implementation once we have more than one implemented. + if (prop & pr_readOnly) + disp = dispatch_readonly (); + else + disp = dispatch_wbetl (); + + ret = a_runInstrumentedCode | a_saveLiveVariables; + } - gtm_rwlock_read_lock (>m_serial_lock); + set_gtm_disp (disp); - return a_runInstrumentedCode | a_saveLiveVariables; + return ret; } -static void -GTM_rollback_transaction (void) +void +GTM::gtm_transaction::rollback () { - gtm_transaction *tx; - gtm_disp()->rollback (); - GTM_rollback_local (); + rollback_local (); - tx = gtm_tx(); - GTM_free_actions (&tx->commit_actions); - GTM_run_actions (&tx->undo_actions); - GTM_commit_allocations (true); + free_actions (&this->commit_actions); + run_actions (&this->undo_actions); + commit_allocations (true); + revert_cpp_exceptions (); - GTM_revert_cpp_exceptions (); - if (tx->eh_in_flight) + if (this->eh_in_flight) { - _Unwind_DeleteException (tx->eh_in_flight); - tx->eh_in_flight = NULL; + _Unwind_DeleteException ((_Unwind_Exception *) this->eh_in_flight); + this->eh_in_flight = NULL; } } void ITM_REGPARM _ITM_rollbackTransaction (void) { - assert ((gtm_tx()->prop & pr_hasNoAbort) == 0); - assert ((gtm_tx()->state & STATE_ABORTING) == 0); + gtm_transaction *tx = gtm_tx(); + + assert ((tx->prop & pr_hasNoAbort) == 0); + assert ((tx->state & gtm_transaction::STATE_ABORTING) == 0); - GTM_rollback_transaction (); - gtm_tx()->state |= STATE_ABORTING; + tx->rollback (); + tx->state |= gtm_transaction::STATE_ABORTING; } void ITM_REGPARM @@ -158,18 +171,18 @@ _ITM_abortTransaction (_ITM_abortReason reason) assert (reason == userAbort); assert ((tx->prop & pr_hasNoAbort) == 0); - assert ((tx->state & STATE_ABORTING) == 0); + assert ((tx->state & gtm_transaction::STATE_ABORTING) == 0); - if (tx->state & STATE_IRREVOKABLE) + if (tx->state & gtm_transaction::STATE_IRREVOCABLE) abort (); - GTM_rollback_transaction (); + tx->rollback (); gtm_disp()->fini (); - if (tx->state & STATE_SERIAL) - gtm_rwlock_write_unlock (>m_serial_lock); + if (tx->state & gtm_transaction::STATE_SERIAL) + gtm_transaction::serial_lock.write_unlock (); else - gtm_rwlock_read_unlock (>m_serial_lock); + gtm_transaction::serial_lock.read_unlock (); set_gtm_tx (tx->prev); free_tx (tx); @@ -177,30 +190,28 @@ _ITM_abortTransaction (_ITM_abortReason reason) GTM_longjmp (&tx->jb, a_abortTransaction | a_restoreLiveVariables, tx->prop); } -static inline bool -GTM_trycommit_transaction (void) +bool +GTM::gtm_transaction::trycommit () { if (gtm_disp()->trycommit ()) { - GTM_commit_local (); - GTM_free_actions (>m_tx()->undo_actions); - GTM_run_actions (>m_tx()->commit_actions); - GTM_commit_allocations (false); + commit_local (); + free_actions (&this->undo_actions); + run_actions (&this->commit_actions); + commit_allocations (false); return true; } return false; } -static bool -GTM_trycommit_and_finalize_transaction (void) +bool +GTM::gtm_transaction::trycommit_and_finalize () { - gtm_transaction *tx = gtm_tx(); - - if ((tx->state & STATE_ABORTING) || GTM_trycommit_transaction ()) + if ((this->state & gtm_transaction::STATE_ABORTING) || trycommit ()) { gtm_disp()->fini (); - set_gtm_tx (tx->prev); - free_tx (tx); + set_gtm_tx (this->prev); + free_tx (this); return true; } return false; @@ -209,39 +220,42 @@ GTM_trycommit_and_finalize_transaction (void) bool ITM_REGPARM _ITM_tryCommitTransaction (void) { - assert ((gtm_tx()->state & STATE_ABORTING) == 0); - return GTM_trycommit_transaction (); + gtm_transaction *tx = gtm_tx(); + assert ((tx->state & gtm_transaction::STATE_ABORTING) == 0); + return tx->trycommit (); } void ITM_NORETURN -GTM_restart_transaction (gtm_restart_reason r) +GTM::gtm_transaction::restart (gtm_restart_reason r) { - gtm_transaction *tx = gtm_tx(); uint32_t actions; - GTM_rollback_transaction (); - GTM_decide_retry_strategy (r); + rollback (); + decide_retry_strategy (r); actions = a_runInstrumentedCode | a_restoreLiveVariables; - if ((tx->prop & pr_uninstrumentedCode) && (tx->state & STATE_IRREVOKABLE)) + if ((this->prop & pr_uninstrumentedCode) + && (this->state & gtm_transaction::STATE_IRREVOCABLE)) actions = a_runUninstrumentedCode | a_restoreLiveVariables; - GTM_longjmp (&tx->jb, actions, tx->prop); + GTM_longjmp (&this->jb, actions, this->prop); } void ITM_REGPARM _ITM_commitTransaction(void) { - if (!GTM_trycommit_and_finalize_transaction ()) - GTM_restart_transaction (RESTART_VALIDATE_COMMIT); + gtm_transaction *tx = gtm_tx(); + if (!tx->trycommit_and_finalize ()) + tx->restart (RESTART_VALIDATE_COMMIT); } void ITM_REGPARM _ITM_commitTransactionEH(void *exc_ptr) { - if (!GTM_trycommit_and_finalize_transaction ()) + gtm_transaction *tx = gtm_tx(); + if (!tx->trycommit_and_finalize ()) { - gtm_tx()->eh_in_flight = exc_ptr; - GTM_restart_transaction (RESTART_VALIDATE_COMMIT); + tx->eh_in_flight = exc_ptr; + tx->restart (RESTART_VALIDATE_COMMIT); } } diff --git a/libitm/clone.c b/libitm/clone.cc index 46e9f4f24ca..25078205d7f 100644 --- a/libitm/clone.c +++ b/libitm/clone.cc @@ -24,6 +24,7 @@ #include "libitm_i.h" +using namespace GTM; static gtm_rwlock table_lock; @@ -34,24 +35,24 @@ struct clone_entry struct clone_table { - struct clone_entry *table; + clone_entry *table; size_t size; - struct clone_table *next; + clone_table *next; }; -static struct clone_table *all_tables; +static clone_table *all_tables; static void * -GTM_find_clone (void *ptr) +find_clone (void *ptr) { - struct clone_table *table; + clone_table *table; void *ret = NULL; - gtm_rwlock_read_lock (&table_lock); + table_lock.read_lock (); for (table = all_tables; table ; table = table->next) { - struct clone_entry *t = table->table; + clone_entry *t = table->table; size_t lo = 0, hi = table->size, i; /* Quick test for whether PTR is present in this table. */ @@ -79,7 +80,7 @@ GTM_find_clone (void *ptr) } found: - gtm_rwlock_read_unlock (&table_lock); + table_lock.read_unlock (); return ret; } @@ -87,18 +88,18 @@ GTM_find_clone (void *ptr) void * ITM_REGPARM _ITM_getTMCloneOrIrrevokable (void *ptr) { - void *ret = GTM_find_clone (ptr); + void *ret = find_clone (ptr); if (ret) return ret; - GTM_serialmode (false, true); + gtm_tx()->serialirr_mode (); return ptr; } void * ITM_REGPARM _ITM_getTMCloneSafe (void *ptr) { - void *ret = GTM_find_clone (ptr); + void *ret = find_clone (ptr); if (ret == NULL) abort (); return ret; @@ -107,8 +108,8 @@ _ITM_getTMCloneSafe (void *ptr) static int clone_entry_compare (const void *a, const void *b) { - const struct clone_entry *aa = (const struct clone_entry *)a; - const struct clone_entry *bb = (const struct clone_entry *)b; + const clone_entry *aa = (const clone_entry *)a; + const clone_entry *bb = (const clone_entry *)b; if (aa->orig < bb->orig) return -1; @@ -119,14 +120,16 @@ clone_entry_compare (const void *a, const void *b) } void -_ITM_registerTMCloneTable (void *t, size_t size) +_ITM_registerTMCloneTable (void *xent, size_t size) { - struct clone_table *old, *table = malloc (sizeof (*table)); + clone_entry *ent = static_cast<clone_entry *>(xent); + clone_table *old, *table; - table->table = t; + table = (clone_table *) xmalloc (sizeof (clone_table)); + table->table = ent; table->size = size; - qsort (t, size, sizeof (struct clone_entry), clone_entry_compare); + qsort (ent, size, sizeof (clone_entry), clone_entry_compare); old = all_tables; do @@ -138,15 +141,21 @@ _ITM_registerTMCloneTable (void *t, size_t size) } void -_ITM_deregisterTMCloneTable (void *t) +_ITM_deregisterTMCloneTable (void *xent) { - struct clone_table **pprev = &all_tables; + clone_entry *ent = static_cast<clone_entry *>(xent); + clone_table **pprev = &all_tables; + clone_table *tab; - gtm_rwlock_write_lock (&table_lock); + table_lock.write_lock (); - for (pprev = &all_tables; (*pprev)->table != t; pprev = &(*pprev)->next) + for (pprev = &all_tables; + tab = *pprev, tab->table != ent; + pprev = &tab->next) continue; - *pprev = (*pprev)->next; + *pprev = tab->next; - gtm_rwlock_write_unlock (&table_lock); + table_lock.write_unlock (); + + free (tab); } diff --git a/libitm/config.h.in b/libitm/config.h.in index 24bf065483b..574b5776985 100644 --- a/libitm/config.h.in +++ b/libitm/config.h.in @@ -1,5 +1,8 @@ /* config.h.in. Generated from configure.ac by autoheader. */ +/* Define if building universal (internal helper macro) */ +#undef AC_APPLE_UNIVERSAL_BUILD + /* Define to 1 if the target supports __attribute__((alias(...))). */ #undef HAVE_ATTRIBUTE_ALIAS @@ -132,3 +135,19 @@ /* Version number of package */ #undef VERSION + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +# undef WORDS_BIGENDIAN +# endif +#endif + +#ifndef WORDS_BIGENDIAN +#define WORDS_BIGENDIAN 0 +#endif diff --git a/libitm/config/alpha/cacheline.h b/libitm/config/alpha/cacheline.h new file mode 100644 index 00000000000..02d3a69ae5a --- /dev/null +++ b/libitm/config/alpha/cacheline.h @@ -0,0 +1,122 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef LIBITM_ALPHA_CACHELINE_H +#define LIBITM_ALPHA_CACHELINE_H 1 + +// A cacheline is the smallest unit with which locks are associated. +// The current implementation of the _ITM_[RW] barriers assumes that +// all data types can fit (aligned) within a cachline, which means +// in practice sizeof(complex long double) is the smallest cacheline size. +// It ought to be small enough for efficient manipulation of the +// modification mask, below. +#define CACHELINE_SIZE 64 + +#ifdef __alpha_bwx__ +# include "config/generic/cacheline.h" +#else +// If we don't have byte-word stores, then we'll never be able to +// adjust *all* of the byte loads/stores to be truely atomic. So +// only guarantee 4-byte aligned values atomicly stored, exactly +// like the native system. Use byte zap instructions to accelerate +// sub-word masked stores. + +namespace GTM HIDDEN { + +// A gtm_cacheline_mask stores a modified bit for every modified byte +// in the cacheline with which it is associated. +typedef sized_integral<CACHELINE_SIZE / 8>::type gtm_cacheline_mask; + +union gtm_cacheline +{ + // Byte access to the cacheline. + unsigned char b[CACHELINE_SIZE] __attribute__((aligned(CACHELINE_SIZE))); + + // Larger sized access to the cacheline. + uint16_t u16[CACHELINE_SIZE / sizeof(uint16_t)]; + uint32_t u32[CACHELINE_SIZE / sizeof(uint32_t)]; + uint64_t u64[CACHELINE_SIZE / sizeof(uint64_t)]; + gtm_word w[CACHELINE_SIZE / sizeof(gtm_word)]; + + // Store S into D, but only the bytes specified by M. + static void store_mask(uint32_t *d, uint32_t s, uint8_t m); + static void store_mask(uint64_t *d, uint64_t s, uint8_t m); + + // Copy S to D, but only the bytes specified by M. + static void copy_mask (gtm_cacheline * __restrict d, + const gtm_cacheline * __restrict s, + gtm_cacheline_mask m); + + // A write barrier to emit after (a series of) copy_mask. + static void copy_mask_wb () { atomic_write_barrier(); } +}; + +inline void ALWAYS_INLINE +gtm_cacheline::store_mask (uint32_t *d, uint32_t s, uint8_t m) +{ + const uint8_t tm = (1 << sizeof(uint32_t)) - 1; + + m &= tm; + if (__builtin_expect (m, tm)) + { + if (__builtin_expect (m == tm, 1)) + *d = s; + else + *d = __builtin_alpha_zap (*d, m) | __builtin_alpha_zapnot (s, m); + } +} + +inline void ALWAYS_INLINE +gtm_cacheline::store_mask (uint64_t *d, uint64_t s, uint8_t m) +{ + if (__builtin_expect (m, 0xff)) + { + if (__builtin_expect (m == 0xff, 1)) + *d = s; + else + { + typedef uint32_t *p32 __attribute__((may_alias)); + p32 d32 = reinterpret_cast<p32>(d); + + if ((m & 0x0f) == 0x0f) + { + d32[0] = s; + m &= 0xf0; + } + else if ((m & 0xf0) == 0xf0) + { + d32[1] = s >> 32; + m &= 0x0f; + } + + if (m) + *d = __builtin_alpha_zap (*d, m) | __builtin_alpha_zapnot (s, m); + } + } +} + +} // namespace GTM + +#endif // __alpha_bwx__ +#endif // LIBITM_ALPHA_CACHELINE_H diff --git a/libitm/config/alpha/copymask.c b/libitm/config/alpha/copymask.c deleted file mode 100644 index 179bcc38466..00000000000 --- a/libitm/config/alpha/copymask.c +++ /dev/null @@ -1,90 +0,0 @@ -/* Copyright (C) 2009 Free Software Foundation, Inc. - Contributed by Richard Henderson <rth@redhat.com>. - - This file is part of the GNU Transactional Memory Library (libitm). - - Libitm is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - Libitm is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - <http://www.gnu.org/licenses/>. */ - -#include "libitm_i.h" - - -#if ALLOW_UNMASKED_STORES || !defined(__alpha_bwx__) -/* If we're allowing unmasked stores, then the ZAP/ZAPNOT instructions - provide a builtin version of the default bit_to_byte_mask operation. - - If we don't allow unmasked stores, and we don't have byte-word stores, - then we *must* implement the copymask with ll/sc instructions. However, - these are slow enough that we'd rather implement this feature with the - generic store avoidance algorithm if possible. */ - -static void __attribute__((always_inline)) -copy_mask_w (gtm_word * __restrict d, - const gtm_word * __restrict s, - gtm_cacheline_mask m) -{ - gtm_cacheline_mask tm = (1 << sizeof (gtm_word)) - 1; - - if (__builtin_expect (m & tm, tm)) - { - if (__builtin_expect ((m & tm) == tm, 1)) - *d = *s; - else if (ALLOW_UNMASKED_STORES) - { - *d = (__builtin_alpha_zap (*d, m) - | __builtin_alpha_zapnot (*s, m)); - } - else - { - gtm_word t; - asm ("\n0:\t" - "ldq_l %[t], %[d]\n\t" - "zap %[t], %[m], %[t]\n\t" - "or %[s], %[t], %[t]\n\t" - "stq_c %[t], %[d]\n\t" - "beq %[t], 0b" - : [d] "+m" (*d), [t] "=&r" (t) - : [m] "r" (m), [s] "r" (__builtin_alpha_zapnot (*s, m))); - } - } -} - -void -gtm_cacheline_copy_mask (gtm_cacheline * __restrict d, - const gtm_cacheline * __restrict s, - gtm_cacheline_mask m) -{ - const size_t n = sizeof (gtm_word); - size_t i; - - if (m == (gtm_cacheline_mask)-1) - { - gtm_cacheline_copy (d, s); - return; - } - if (__builtin_expect (m == 0, 0)) - return; - - for (i = 0; i < CACHELINE_SIZE / n; ++i, m >>= n) - copy_mask_w (&d->w[i], &s->w[i], m); -} - -#else -# include "../../copymask.c" -#endif /* ALLOW_UNMASKED_STORES || !defined(__alpha_bwx__) */ diff --git a/libitm/config/alpha/target.h b/libitm/config/alpha/target.h index e516f3384d7..2c0f448bceb 100644 --- a/libitm/config/alpha/target.h +++ b/libitm/config/alpha/target.h @@ -22,6 +22,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see <http://www.gnu.org/licenses/>. */ +namespace GTM HIDDEN { + typedef struct gtm_jmpbuf { unsigned long pc; @@ -30,15 +32,26 @@ typedef struct gtm_jmpbuf unsigned long f[8]; } gtm_jmpbuf; -/* The "cacheline" as defined by the STM need not be the same as the - cacheline defined by the processor. It ought to be big enough for - any of the basic types to be stored (aligned) in one line. It ought - to be small enough for efficient manipulation of the modification mask. */ -#define CACHELINE_SIZE 64 - -/* Alpha requires strict alignment for the basic types. */ -#define STRICT_ALIGNMENT 1 - /* Alpha generally uses a fixed page size of 8K. */ #define PAGE_SIZE 8192 #define FIXED_PAGE_SIZE 1 + +static inline void +cpu_relax (void) +{ + __asm volatile ("" : : : "memory"); +} + +static inline void +atomic_read_barrier (void) +{ + __sync_synchronize (); +} + +static inline void +atomic_write_barrier (void) +{ + __asm volatile ("wmb" : : : "memory"); +} + +} // namespace GTM diff --git a/libitm/config/alpha/unaligned.h b/libitm/config/alpha/unaligned.h new file mode 100644 index 00000000000..6d68f050c06 --- /dev/null +++ b/libitm/config/alpha/unaligned.h @@ -0,0 +1,118 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef LIBITM_ALPHA_UNALIGNED_H +#define LIBITM_ALPHA_UNALIGNED_H 1 + +#define HAVE_ARCH_UNALIGNED_LOAD2_U2 1 +#define HAVE_ARCH_UNALIGNED_LOAD2_U4 1 +#define HAVE_ARCH_UNALIGNED_LOAD2_U8 1 + +#ifndef __alpha_bwx__ +#define HAVE_ARCH_UNALIGNED_STORE2_U2 1 +#endif +#define HAVE_ARCH_UNALIGNED_STORE2_U4 1 +#define HAVE_ARCH_UNALIGNED_STORE2_U8 1 + +#include "config/generic/unaligned.h" + +namespace GTM HIDDEN { + +template<> +inline uint16_t ALWAYS_INLINE +unaligned_load2<uint16_t>(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ + uint64_t v1 = c1->u64[CACHELINE_SIZE / sizeof(uint64_t) - 1]; + uint64_t v2 = c2->u64[0]; + + return __builtin_alpha_extwl (v1, ofs) | __builtin_alpha_extwh (v2, ofs); +} + +template<> +inline uint32_t ALWAYS_INLINE +unaligned_load2<uint32_t>(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ + uint64_t v1 = c1->u64[CACHELINE_SIZE / sizeof(uint64_t) - 1]; + uint64_t v2 = c2->u64[0]; + + return __builtin_alpha_extll (v1, ofs) + __builtin_alpha_extlh (v2, ofs); +} + +template<> +inline uint64_t ALWAYS_INLINE +unaligned_load2<uint64_t>(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ + uint64_t v1 = c1->u64[CACHELINE_SIZE / sizeof(uint64_t) - 1]; + uint64_t v2 = c2->u64[0]; + + return __builtin_alpha_extql (v1, ofs) | __builtin_alpha_extqh (v2, ofs); +} + +#ifndef __alpha_bwx__ +template<> +inline void +unaligned_store2<uint16_t>(gtm_cacheline *c1, gtm_cacheline *c2, + size_t ofs, uint16_t val) +{ + uint32_t vl = (uint32_t)val << 24, vh = val >> 8; + + gtm_cacheline::store_mask (&c1->u32[CACHELINE_SIZE / 4 - 1], vl, 4); + gtm_cacheline::store_mask (&c2->u32[0], vh, 1); +} +#endif + +template<> +inline void +unaligned_store2<uint32_t>(gtm_cacheline *c1, gtm_cacheline *c2, + size_t ofs, uint32_t val) +{ + uint64_t vl = __builtin_alpha_insll (val, ofs); + uint64_t ml = __builtin_alpha_insll (~0u, ofs); + uint64_t vh = __builtin_alpha_inslh (val, ofs); + uint64_t mh = __builtin_alpha_inslh (~0u, ofs); + + gtm_cacheline::store_mask (&c1->u64[CACHELINE_SIZE / 8 - 1], vl, ml); + gtm_cacheline::store_mask (&c2->u64[0], vh, mh); +} + +template<> +inline void +unaligned_store2<uint64_t>(gtm_cacheline *c1, gtm_cacheline *c2, + size_t ofs, uint64_t val) +{ + uint64_t vl = __builtin_alpha_insql (val, ofs); + uint64_t ml = __builtin_alpha_insql (~0u, ofs); + uint64_t vh = __builtin_alpha_insqh (val, ofs); + uint64_t mh = __builtin_alpha_insqh (~0u, ofs); + + gtm_cacheline::store_mask (&c1->u64[CACHELINE_SIZE / 8 - 1], vl, ml); + gtm_cacheline::store_mask (&c2->u64[0], vh, mh); +} + +} // namespace GTM + +#endif // LIBITM_ALPHA_UNALIGNED_H diff --git a/libitm/retry.c b/libitm/config/generic/cacheline.cc index c89cd684a62..1fb5676fa97 100644 --- a/libitm/retry.c +++ b/libitm/config/generic/cacheline.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. +/* Copyright (C) 2009 Free Software Foundation, Inc. Contributed by Richard Henderson <rth@redhat.com>. This file is part of the GNU Transactional Memory Library (libitm). @@ -25,31 +25,25 @@ #include "libitm_i.h" +namespace GTM HIDDEN { + void -GTM_decide_retry_strategy (gtm_restart_reason r) +gtm_cacheline::copy_mask (gtm_cacheline * __restrict d, + const gtm_cacheline * __restrict s, + gtm_cacheline_mask m) { - struct gtm_transaction *tx = gtm_tx(); - const struct gtm_dispatch *disp; - - tx->restart_reason[r]++; - tx->restart_total++; + const size_t n = sizeof (gtm_word); - if (r == RESTART_NOT_READONLY) + if (m == (gtm_cacheline_mask) -1) { - assert ((tx->prop & pr_readOnly) == 0); - disp = gtm_disp (); - if (disp == &dispatch_readonly) - { - disp->fini (); - disp = &dispatch_wbetl; - disp->init (true); - return; - } + *d = *s; + return; } - if (tx->state & STATE_SERIAL) - ; - else if (tx->restart_total > 100) - GTM_serialmode (false, false); - else - gtm_disp()->init (false); + if (__builtin_expect (m == 0, 0)) + return; + + for (size_t i = 0; i < CACHELINE_SIZE / n; ++i, m >>= n) + store_mask (&d->w[i], s->w[i], m); } + +} // namespace GTM diff --git a/libitm/config/generic/cacheline.h b/libitm/config/generic/cacheline.h new file mode 100644 index 00000000000..14c08c215d3 --- /dev/null +++ b/libitm/config/generic/cacheline.h @@ -0,0 +1,107 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef LIBITM_CACHELINE_H +#define LIBITM_CACHELINE_H 1 + +namespace GTM HIDDEN { + +// A cacheline is the smallest unit with which locks are associated. +// The current implementation of the _ITM_[RW] barriers assumes that +// all data types can fit (aligned) within a cachline, which means +// in practice sizeof(complex long double) is the smallest cacheline size. +// It ought to be small enough for efficient manipulation of the +// modification mask, below. +#ifndef CACHELINE_SIZE +# define CACHELINE_SIZE 32 +#endif + +// A gtm_cacheline_mask stores a modified bit for every modified byte +// in the cacheline with which it is associated. +typedef sized_integral<CACHELINE_SIZE / 8>::type gtm_cacheline_mask; + +union gtm_cacheline +{ + // Byte access to the cacheline. + unsigned char b[CACHELINE_SIZE] __attribute__((aligned(CACHELINE_SIZE))); + + // Larger sized access to the cacheline. + uint16_t u16[CACHELINE_SIZE / sizeof(uint16_t)]; + uint32_t u32[CACHELINE_SIZE / sizeof(uint32_t)]; + uint64_t u64[CACHELINE_SIZE / sizeof(uint64_t)]; + gtm_word w[CACHELINE_SIZE / sizeof(gtm_word)]; + + // Store S into D, but only the bytes specified by M. + template<typename T> static void store_mask (T *d, T s, uint8_t m); + + // Copy S to D, but only the bytes specified by M. + static void copy_mask (gtm_cacheline * __restrict d, + const gtm_cacheline * __restrict s, + gtm_cacheline_mask m); + + // A write barrier to emit after (a series of) copy_mask. + // When we're emitting non-temporal stores, the normal strong + // ordering of the machine doesn't apply. + static void copy_mask_wb () { atomic_write_barrier(); } +}; + +template<typename T> +inline void +gtm_cacheline::store_mask (T *d, T s, uint8_t m) +{ + const uint8_t tm = (1 << sizeof(T)) - 1; + + if (__builtin_expect (m & tm, tm)) + { + if (__builtin_expect ((m & tm) == tm, 1)) + *d = s; + else + { + const int half = sizeof(T) / 2; + typedef typename sized_integral<half>::type half_t; + half_t *dhalf = reinterpret_cast<half_t *>(d); + half_t s1, s2; + + if (WORDS_BIGENDIAN) + s1 = s >> half*8, s2 = s; + else + s1 = s, s2 = s >> half*8; + + store_mask (dhalf, s1, m); + store_mask (dhalf + 1, s2, m >> half); + } + } +} + +template<> +inline void ALWAYS_INLINE +gtm_cacheline::store_mask<uint8_t> (uint8_t *d, uint8_t s, uint8_t m) +{ + if (m & 1) + *d = s; +} + +} // namespace GTM + +#endif // LIBITM_CACHELINE_H diff --git a/libitm/config/generic/cachepage.h b/libitm/config/generic/cachepage.h new file mode 100644 index 00000000000..7febbe882c5 --- /dev/null +++ b/libitm/config/generic/cachepage.h @@ -0,0 +1,77 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef LIBITM_CACHEPAGE_H +#define LIBITM_CACHEPAGE_H 1 + +namespace GTM HIDDEN { + +// A "page" worth of saved cachelines plus modification masks. This +// arrangement is intended to minimize the overhead of alignment. The +// PAGE_SIZE defined by the target must be a constant for this to work, +// which means that this definition may not be the same as the real +// system page size. An additional define of FIXED_PAGE_SIZE by the +// target indicates that PAGE_SIZE exactly matches the system page size. + +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + +struct gtm_cacheline_page +{ + static const size_t LINES + = ((PAGE_SIZE - sizeof(gtm_cacheline_page *)) + / (CACHELINE_SIZE + sizeof(gtm_cacheline_mask))); + + gtm_cacheline lines[LINES] __attribute__((aligned(PAGE_SIZE))); + gtm_cacheline_mask masks[LINES]; + gtm_cacheline_page *prev; + + static gtm_cacheline_page * + page_for_line (gtm_cacheline *c) + { + return (gtm_cacheline_page *)((uintptr_t)c & -PAGE_SIZE); + } + + gtm_cacheline_mask * + mask_for_line (gtm_cacheline *c) + { + size_t index = c - &this->lines[0]; + return &this->masks[index]; + } + + static gtm_cacheline_mask * + mask_for_page_line (gtm_cacheline *c) + { + gtm_cacheline_page *p = page_for_line (c); + return p->mask_for_line (c); + } + + static void *operator new (size_t); + static void operator delete (void *); +}; + +} // namespace GTM + +#endif // LIBITM_CACHEPAGE_H diff --git a/libitm/config/generic/tls.h b/libitm/config/generic/tls.h new file mode 100644 index 00000000000..d6c2bc8b0a9 --- /dev/null +++ b/libitm/config/generic/tls.h @@ -0,0 +1,90 @@ +/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef LIBITM_TLS_H +#define LIBITM_TLS_H 1 + +namespace GTM HIDDEN { + +// All thread-local data required by the entire library. +struct gtm_thread +{ +#ifndef HAVE_ARCH_GTM_THREAD_TX + // The currently active transaction. Elided if the target provides + // some efficient mechanism for storing this. + gtm_transaction *tx; +#endif +#ifndef HAVE_ARCH_GTM_THREAD_DISP + // The dispatch table for the STM implementation currently in use. Elided + // if the target provides some efficient mechanism for storing this. + gtm_dispatch *disp; +#endif + + // The maximum number of free gtm_transaction structs to be kept. + // This number must be greater than 1 in order for transaction abort + // to be handled properly. + static const unsigned MAX_FREE_TX = 8; + + // A queue of free gtm_transaction structs. + gtm_transaction *free_tx[MAX_FREE_TX]; + unsigned free_tx_idx, free_tx_count; + + // The value returned by _ITM_getThreadnum to identify this thread. + // ??? At present, this is densely allocated beginning with 1 and + // we don't bother filling in this value until it is requested. + // Which means that the value returned is, as far as the user is + // concerned, essentially arbitrary. We wouldn't need this at all + // if we knew that pthread_t is integral and fits into an int. + // ??? Consider using gettid on Linux w/ NPTL. At least that would + // be a value meaningful to the user. + int thread_num; +}; + +// Don't access this variable directly; use the functions below. +extern __thread gtm_thread _gtm_thr; + +#ifndef HAVE_ARCH_GTM_THREAD +// If the target does not provide optimized access to the thread-local +// data, simply access the TLS variable defined above. +static inline void setup_gtm_thr(void) { } +static inline gtm_thread *gtm_thr(void) { return &_gtm_thr; } +#endif + +#ifndef HAVE_ARCH_GTM_THREAD_TX +// If the target does not provide optimized access to the currently +// active transaction, simply access via GTM_THR. +static inline gtm_transaction * gtm_tx(void) { return gtm_thr()->tx; } +static inline void set_gtm_tx(gtm_transaction *x) { gtm_thr()->tx = x; } +#endif + +#ifndef HAVE_ARCH_GTM_THREAD_DISP +// If the target does not provide optimized access to the currently +// active dispatch table, simply access via GTM_THR. +static inline gtm_dispatch * gtm_disp(void) { return gtm_thr()->disp; } +static inline void set_gtm_disp(gtm_dispatch *x) { gtm_thr()->disp = x; } +#endif + +} // namespace GTM + +#endif // LIBITM_TLS_H diff --git a/libitm/config/generic/unaligned.h b/libitm/config/generic/unaligned.h new file mode 100644 index 00000000000..66295f1a08c --- /dev/null +++ b/libitm/config/generic/unaligned.h @@ -0,0 +1,228 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef LIBITM_UNALIGNED_H +#define LIBITM_UNALIGNED_H 1 + +namespace GTM HIDDEN { + +#ifndef STRICT_ALIGNMENT +#define STRICT_ALIGNMENT 1 +#endif + +// A type trait for whether type T requires strict alignment. +// The generic types are assumed to all be the same; specializations +// for target-specific types should be done in config/cpu/unaligned.h. +template<typename T> + struct strict_alignment + : public std::integral_constant<bool, STRICT_ALIGNMENT> + { }; + +// A helper template for accessing an integral type the same size as T +template<typename T> + struct make_integral + : public sized_integral<sizeof(T)> + { }; + +// A helper class for accessing T as an unaligned value. +template<typename T> +struct __attribute__((packed)) unaligned_helper + { T x; }; + +// A helper class for view-converting T as an integer. +template<typename T> +union view_convert_helper +{ + typedef T type; + typedef make_integral<T> itype; + + type t; + itype i; +}; + +// Generate an unaligned load sequence. +// The compiler knows how to do this for any specific type. +template<typename T> +inline T ALWAYS_INLINE +unaligned_load(const void *t) +{ + typedef unaligned_helper<T> UT; + const UT *ut = reinterpret_cast<const UT *>(t); + return ut->x; +} + +// Generate an unaligned store sequence. +template<typename T> +inline void ALWAYS_INLINE +unaligned_store(void *t, T val) +{ + typedef unaligned_helper<T> UT; + UT *ut = reinterpret_cast<UT *>(t); + ut->x = val; +} + +// Generate an unaligned load from two different cachelines. +// It is known that OFS + SIZEOF(T) > CACHELINE_SIZE. +template<typename T> +inline T ALWAYS_INLINE +unaligned_load2(const gtm_cacheline *c1, const gtm_cacheline *c2, size_t ofs) +{ + size_t left = CACHELINE_SIZE - ofs; + T ret; + + memcpy (&ret, &c1->b[ofs], left); + memcpy ((char *)&ret + ofs, c2, sizeof(T) - left); + + return ret; +} + +// Generate an unaligned store into two different cachelines. +// It is known that OFS + SIZEOF(T) > CACHELINE_SIZE. +template<typename T> +inline void ALWAYS_INLINE +unaligned_store2(gtm_cacheline *c1, gtm_cacheline *c2, size_t ofs, T val) +{ + size_t left = CACHELINE_SIZE - ofs; + memcpy (&c1->b[ofs], &val, left); + memcpy (c2, (char *)&val + left, sizeof(T) - left); +} + +#ifndef HAVE_ARCH_UNALIGNED_LOAD2_U2 +template<> +inline uint16_t ALWAYS_INLINE +unaligned_load2<uint16_t>(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ + uint16_t v1 = c1->b[CACHELINE_SIZE - 1]; + uint16_t v2 = c2->b[0]; + + if (WORDS_BIGENDIAN) + return v1 << 8 | v2; + else + return v2 << 8 | v1; +} +#endif + +#ifndef HAVE_ARCH_UNALIGNED_LOAD2_U4 +template<> +inline uint32_t ALWAYS_INLINE +unaligned_load2<uint32_t>(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ + uint32_t v1 = c1->u32[CACHELINE_SIZE / sizeof(uint32_t) - 1]; + uint32_t v2 = c2->u32[0]; + int s2 = (ofs & (sizeof(uint32_t) - 1)) * 8; + int s1 = sizeof(uint32_t) * 8 - s2; + + if (WORDS_BIGENDIAN) + return v1 << s2 | v2 >> s1; + else + return v2 << s2 | v1 >> s1; +} +#endif + +#ifndef HAVE_ARCH_UNALIGNED_LOAD2_U8 +template<> +inline uint64_t ALWAYS_INLINE +unaligned_load2<uint64_t>(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ + uint64_t v1 = c1->u64[CACHELINE_SIZE / sizeof(uint64_t) - 1]; + uint64_t v2 = c2->u64[0]; + int s2 = (ofs & (sizeof(uint64_t) - 1)) * 8; + int s1 = sizeof(uint64_t) * 8 - s2; + + if (WORDS_BIGENDIAN) + return v1 << s2 | v2 >> s1; + else + return v2 << s2 | v1 >> s1; +} +#endif + +template<> +inline float ALWAYS_INLINE +unaligned_load2<float>(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ + typedef view_convert_helper<float> VC; VC vc; + vc.i = unaligned_load2<VC::itype>(c1, c2, ofs); + return vc.t; +} + +template<> +inline double ALWAYS_INLINE +unaligned_load2<double>(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ + typedef view_convert_helper<double> VC; VC vc; + vc.i = unaligned_load2<VC::itype>(c1, c2, ofs); + return vc.t; +} + +#ifndef HAVE_ARCH_UNALIGNED_STORE2_U2 +template<> +inline void ALWAYS_INLINE +unaligned_store2<uint16_t>(gtm_cacheline *c1, gtm_cacheline *c2, + size_t ofs, uint16_t val) +{ + uint8_t vl = val, vh = val >> 8; + + if (WORDS_BIGENDIAN) + { + c1->b[CACHELINE_SIZE - 1] = vh; + c2->b[0] = vl; + } + else + { + c1->b[CACHELINE_SIZE - 1] = vl; + c2->b[0] = vh; + } +} +#endif + +#if 0 +#ifndef HAVE_ARCH_UNALIGNED_STORE2_U4 +template<> +inline void ALWAYS_INLINE +unaligned_store2<uint32_t>(gtm_cacheline *c1, gtm_cacheline *c2, + size_t ofs, uint32_t val) +{ + // ??? We could reuse the store_mask stuff here. +} +#endif + +template<> +inline void ALWAYS_INLINE +unaligned_store2<float>(gtm_cacheline *c1, gtm_cacheline *c2, + size_t ofs, float val) +{ + typedef view_convert_helper<float> VC; VC vc; + vc.t = val; + unaligned_store2(c1, c2, ofs, vc.i); +} +#endif + +} // namespace GTM + +#endif // LIBITM_UNALIGNED_H diff --git a/libitm/config/linux/futex.c b/libitm/config/linux/futex.cc index 2c122ad917c..f70144996ba 100644 --- a/libitm/config/linux/futex.c +++ b/libitm/config/linux/futex.cc @@ -28,6 +28,7 @@ #include "futex.h" #include <errno.h> +namespace GTM HIDDEN { #define FUTEX_WAIT 0 #define FUTEX_WAKE 1 @@ -55,7 +56,16 @@ futex_wait (int *addr, int val) { gtm_futex_wait = FUTEX_WAIT; gtm_futex_wake = FUTEX_WAKE; - sys_futex0 (addr, FUTEX_WAIT, val); + res = sys_futex0 (addr, FUTEX_WAIT, val); + } + if (__builtin_expect (res < 0, 0)) + { + if (res == -EWOULDBLOCK || res == -ETIMEDOUT) + ; + else if (res == -EFAULT) + GTM_fatal ("futex failed (EFAULT %p)", addr); + else + GTM_fatal ("futex failed (%s)", strerror(-res)); } } @@ -68,6 +78,10 @@ futex_wake (int *addr, int count) { gtm_futex_wait = FUTEX_WAIT; gtm_futex_wake = FUTEX_WAKE; - sys_futex0 (addr, FUTEX_WAKE, count); + res = sys_futex0 (addr, FUTEX_WAKE, count); } + if (__builtin_expect (res < 0, 0)) + GTM_fatal ("futex failed (%s)", strerror(-res)); } + +} // namespace GTM diff --git a/libitm/config/linux/futex.h b/libitm/config/linux/futex.h index c45c2ca1314..7275dbf5fd1 100644 --- a/libitm/config/linux/futex.h +++ b/libitm/config/linux/futex.h @@ -27,17 +27,13 @@ #ifndef GTM_FUTEX_H #define GTM_FUTEX_H 1 -#ifdef HAVE_ATTRIBUTE_VISIBILITY -# pragma GCC visibility push(hidden) -#endif +namespace GTM HIDDEN { #include "futex_bits.h" extern void futex_wait (int *addr, int val); extern void futex_wake (int *addr, int count); -#ifdef HAVE_ATTRIBUTE_VISIBILITY -# pragma GCC visibility pop -#endif +} #endif /* GTM_FUTEX_H */ diff --git a/libitm/config/linux/rwlock.c b/libitm/config/linux/rwlock.c deleted file mode 100644 index 2f0b752566f..00000000000 --- a/libitm/config/linux/rwlock.c +++ /dev/null @@ -1,257 +0,0 @@ -/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. - Contributed by Richard Henderson <rth@redhat.com>. - - This file is part of the GNU Transactional Memory Library (libitm). - - Libitm is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - Libitm is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - <http://www.gnu.org/licenses/>. */ - -#include <limits.h> -#include "libitm_i.h" -#include "futex.h" - - -#define EZ(X) __builtin_expect((X), 0) - - -/* Lock the summary bit on LOCK. Return the contents of the summary word - (without the summary lock bit included). */ - -static int -rwlock_lock_summary (gtm_rwlock *lock) -{ - int o; - - restart: - o = __sync_fetch_and_or (&lock->summary, RWLOCK_S_LOCK); - if (EZ (o & RWLOCK_S_LOCK)) - { - do - cpu_relax (); - while (lock->summary & RWLOCK_S_LOCK); - goto restart; - } - - return o; -} - - -/* Acquire a RW lock for reading. */ - -void -gtm_rwlock_read_lock (gtm_rwlock *lock) -{ - int o, n; - - while (1) - { - o = rwlock_lock_summary (lock); - - /* If there is an active or waiting writer, then new readers - must wait. Increment the waiting reader count, then wait - on the reader queue. */ - if (EZ (o & (RWLOCK_A_WRITER | RWLOCK_W_WRITER | RWLOCK_RW_UPGRADE))) - { - n = ++lock->w_readers; - atomic_write_barrier (); - lock->summary = o | RWLOCK_W_READER; - futex_wait (&lock->w_readers, n); - continue; - } - - /* Otherwise, we may become a reader. */ - ++lock->a_readers; - atomic_write_barrier (); - lock->summary = o | RWLOCK_A_READER; - return; - } -} - - -/* Acquire a RW lock for writing. */ - -void -gtm_rwlock_write_lock (gtm_rwlock *lock) -{ - int o, n; - - restart: - o = lock->summary; - - /* If anyone is manipulating the summary lock, the rest of the - data structure is volatile. */ - if (EZ (o & RWLOCK_S_LOCK)) - { - cpu_relax (); - goto restart; - } - - /* If there is an active reader or active writer, then new writers - must wait. Increment the waiting writer count, then wait - on the writer queue. */ - if (EZ (o & (RWLOCK_A_WRITER | RWLOCK_A_READER | RWLOCK_RW_UPGRADE))) - { - /* Grab the summary lock. We'll need it for incrementing - the waiting reader. */ - n = o | RWLOCK_S_LOCK; - if (!__sync_bool_compare_and_swap (&lock->summary, o, n)) - goto restart; - - n = ++lock->w_writers; - atomic_write_barrier (); - lock->summary = o | RWLOCK_W_WRITER; - futex_wait (&lock->w_writers, n); - goto restart; - } - - /* Otherwise, may become a writer. */ - n = o | RWLOCK_A_WRITER; - if (EZ (!__sync_bool_compare_and_swap (&lock->summary, o, n))) - goto restart; -} - - -/* Upgrade a RW lock that has been locked for reading to a writing lock. - Do this without possibility of another writer incoming. Return false - if this attempt fails. */ - -bool -gtm_rwlock_write_upgrade (gtm_rwlock *lock) -{ - int o, n; - - restart: - o = lock->summary; - - /* If anyone is manipulating the summary lock, the rest of the - data structure is volatile. */ - if (EZ (o & RWLOCK_S_LOCK)) - { - cpu_relax (); - goto restart; - } - - /* If there's already someone trying to upgrade, then we fail. */ - if (EZ (o & RWLOCK_RW_UPGRADE)) - return false; - - /* Grab the summary lock. We'll need it for manipulating the - active reader count or the waiting writer count. */ - n = o | RWLOCK_S_LOCK; - if (EZ (!__sync_bool_compare_and_swap (&lock->summary, o, n))) - goto restart; - - /* If there are more active readers, then we have to wait. */ - if (--lock->a_readers > 0) - { - atomic_write_barrier (); - o |= RWLOCK_RW_UPGRADE; - lock->summary = o; - do - { - futex_wait (&lock->summary, o); - o = lock->summary; - } - while (o & RWLOCK_A_READER); - } - - atomic_write_barrier (); - o &= ~(RWLOCK_A_READER | RWLOCK_RW_UPGRADE); - o |= RWLOCK_A_WRITER; - lock->summary = o; - return true; -} - - -/* Release a RW lock from reading. */ - -void -gtm_rwlock_read_unlock (gtm_rwlock *lock) -{ - int o; - - o = rwlock_lock_summary (lock); - - /* If there are still active readers, nothing else to do. */ - if (--lock->a_readers > 0) - { - atomic_write_barrier (); - lock->summary = o; - return; - } - o &= ~RWLOCK_A_READER; - - /* If there is a waiting upgrade, wake it. */ - if (EZ (o & RWLOCK_RW_UPGRADE)) - { - atomic_write_barrier (); - lock->summary = o; - futex_wake (&lock->summary, 1); - return; - } - - /* If there is a waiting writer, wake it. */ - if (EZ (o & RWLOCK_W_WRITER)) - { - if (--lock->w_writers == 0) - o &= ~RWLOCK_W_WRITER; - atomic_write_barrier (); - lock->summary = o; - futex_wake (&lock->w_writers, 1); - return; - } - - atomic_write_barrier (); - lock->summary = o; -} - - -/* Release a RW lock from writing. */ - -void -gtm_rwlock_write_unlock (gtm_rwlock *lock) -{ - int o; - - o = rwlock_lock_summary (lock); - o &= ~RWLOCK_A_WRITER; - - /* If there is a waiting writer, wake it. */ - if (EZ (o & RWLOCK_W_WRITER)) - { - if (--lock->w_writers == 0) - o &= ~RWLOCK_W_WRITER; - atomic_write_barrier (); - lock->summary = o; - futex_wake (&lock->w_writers, 1); - return; - } - - /* If there are waiting readers, wake them. */ - if (EZ (o & RWLOCK_W_READER)) - { - lock->w_readers = 0; - atomic_write_barrier (); - lock->summary = o & ~RWLOCK_W_READER; - futex_wake (&lock->w_readers, INT_MAX); - return; - } - - lock->summary = o; -} diff --git a/libitm/config/linux/rwlock.cc b/libitm/config/linux/rwlock.cc new file mode 100644 index 00000000000..d5379c864b4 --- /dev/null +++ b/libitm/config/linux/rwlock.cc @@ -0,0 +1,246 @@ +/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#include <climits> +#include "libitm_i.h" +#include "futex.h" + +namespace GTM HIDDEN { + +// Lock the summary bit on LOCK. Return the contents of the summary +// word (without the summary lock bit included). + +int +gtm_rwlock::lock_summary () +{ + int o; + + restart: + o = __sync_fetch_and_or (&this->summary, s_lock); + if (unlikely (o & s_lock)) + { + do + cpu_relax (); + while (this->summary & s_lock); + goto restart; + } + + return o; +} + + +// Acquire a RW lock for reading. + +void +gtm_rwlock::read_lock () +{ + restart: + int o = lock_summary (); + + // If there is an active or waiting writer, then new readers must wait. + // Increment the waiting reader count, then wait on the reader queue. + if (unlikely (o & (a_writer | w_writer | rw_upgrade))) + { + int n = ++this->w_readers; + atomic_write_barrier (); + this->summary = o | w_reader; + futex_wait (&this->w_readers, n); + goto restart; + } + + // Otherwise, we may become a reader. + ++this->a_readers; + atomic_write_barrier (); + this->summary = o | a_reader; +} + + +// Acquire a RW lock for writing. + +void +gtm_rwlock::write_lock () +{ + int o, n; + + restart: + o = this->summary; + + // If anyone is manipulating the summary lock, the rest of the + // data structure is volatile. + if (unlikely (o & s_lock)) + { + cpu_relax (); + goto restart; + } + + // If there is an active reader or active writer, then new writers must wait. + // Increment the waiting writer count, then wait on the writer queue. + if (unlikely (o & (a_writer | a_reader | rw_upgrade))) + { + // Grab the summary lock. We'll need it for incrementing + // the waiting reader. + n = o | s_lock; + if (!__sync_bool_compare_and_swap (&this->summary, o, n)) + goto restart; + + n = ++this->w_writers; + atomic_write_barrier (); + this->summary = o | w_writer; + futex_wait (&this->w_writers, n); + goto restart; + } + + // Otherwise, we may become a writer. + n = o | a_writer; + if (unlikely (!__sync_bool_compare_and_swap (&this->summary, o, n))) + goto restart; +} + + +// Upgrade a RW lock that has been locked for reading to a writing lock. +// Do this without possibility of another writer incoming. Return false +// if this attempt fails (i.e. another thread also upgraded). + +bool +gtm_rwlock::write_upgrade () +{ + int o, n; + + restart: + o = this->summary; + + // If anyone is manipulating the summary lock, the rest of the + // data structure is volatile. + if (unlikely (o & s_lock)) + { + cpu_relax (); + goto restart; + } + + // If there's already someone trying to upgrade, then we fail. + if (unlikely (o & rw_upgrade)) + return false; + + // Grab the summary lock. We'll need it for manipulating the + // active reader count or the waiting writer count. + n = o | s_lock; + if (unlikely (!__sync_bool_compare_and_swap (&this->summary, o, n))) + goto restart; + + // If there are more active readers, then we have to wait. + if (--this->a_readers > 0) + { + atomic_write_barrier (); + o |= rw_upgrade; + this->summary = o; + do + { + futex_wait (&this->summary, o); + o = this->summary; + } + while (o & a_reader); + } + + atomic_write_barrier (); + o &= ~(a_reader | rw_upgrade); + o |= a_writer; + this->summary = o; + return true; +} + + +// Release a RW lock from reading. + +void +gtm_rwlock::read_unlock () +{ + int o = lock_summary (); + + // If there are still active readers, nothing else to do. + if (--this->a_readers > 0) + { + atomic_write_barrier (); + this->summary = o; + return; + } + o &= ~a_reader; + + // If there is a waiting upgrade, wake it. + if (unlikely (o & rw_upgrade)) + { + atomic_write_barrier (); + this->summary = o; + futex_wake (&this->summary, 1); + return; + } + + // If there is a waiting writer, wake it. + if (unlikely (o & w_writer)) + { + if (--this->w_writers == 0) + o &= ~w_writer; + atomic_write_barrier (); + this->summary = o; + futex_wake (&this->w_writers, 1); + return; + } + + atomic_write_barrier (); + this->summary = o; +} + + +// Release a RW lock from writing. + +void +gtm_rwlock::write_unlock () +{ + int o = lock_summary (); + o &= ~a_writer; + + // If there is a waiting writer, wake it. + if (unlikely (o & w_writer)) + { + if (--this->w_writers == 0) + o &= ~w_writer; + atomic_write_barrier (); + this->summary = o; + futex_wake (&this->w_writers, 1); + return; + } + + // If there are waiting readers, wake them. + if (unlikely (o & w_reader)) + { + this->w_readers = 0; + atomic_write_barrier (); + this->summary = o & ~w_reader; + futex_wake (&this->w_readers, INT_MAX); + return; + } + + this->summary = o; +} + +} // namespace GTM diff --git a/libitm/config/linux/rwlock.h b/libitm/config/linux/rwlock.h index d969a407e6c..1a8104e78f2 100644 --- a/libitm/config/linux/rwlock.h +++ b/libitm/config/linux/rwlock.h @@ -25,26 +25,48 @@ #ifndef GTM_RWLOCK_H #define GTM_RWLOCK_H -/* The read-write summary definition. */ +namespace GTM HIDDEN { -#define RWLOCK_S_LOCK 1 -#define RWLOCK_A_WRITER 2 -#define RWLOCK_W_WRITER 4 -#define RWLOCK_A_READER 8 -#define RWLOCK_W_READER 16 -#define RWLOCK_RW_UPGRADE 32 +// This datastructure is similar to the POSIX pthread_rwlock_t except +// that we also provide for upgrading a reader->writer lock, with a +// positive indication of failure (another writer acquired the lock +// before we were able to acquire). +// +// In this implementation, rw upgrade is given highest priority access, +// and writers are given priority over readers. -typedef struct { +class gtm_rwlock +{ + private: + // A collection of bits that may be set in SUMMARY: + static const int s_lock = 1; // The strucure as a whole is locked. + static const int a_writer = 2; // An active writer. + static const int w_writer = 4; // The w_writers field != 0 + static const int a_reader = 8; // The a_readers field != 0 + static const int w_reader = 16; // The w_readers field != 0 + static const int rw_upgrade = 32; // A reader waiting for upgrade. + + // All fields must be "int", since they're all given to the futex syscall. int summary; int a_readers; int w_readers; int w_writers; -} gtm_rwlock; -extern void gtm_rwlock_read_lock (gtm_rwlock *); -extern void gtm_rwlock_write_lock (gtm_rwlock *); -extern bool gtm_rwlock_write_upgrade (gtm_rwlock *); -extern void gtm_rwlock_read_unlock (gtm_rwlock *); -extern void gtm_rwlock_write_unlock (gtm_rwlock *); + int lock_summary (); + + public: + // ??? Uncomment if we have non-static users or if constexpr is supported. + // gtm_rwlock() : summary(0), a_readers(0), w_readers(0), w_writers(0) { } + + void read_lock (); + void read_unlock (); + + void write_lock (); + void write_unlock (); + + bool write_upgrade (); +}; + +} // namespace GTM -#endif /* GTM_RWLOCK_H */ +#endif // GTM_RWLOCK_H diff --git a/libitm/config/linux/x86/tls.h b/libitm/config/linux/x86/tls.h new file mode 100644 index 00000000000..df0e5977c8c --- /dev/null +++ b/libitm/config/linux/x86/tls.h @@ -0,0 +1,84 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 10) +/* Use slots in the TCB head rather than __thread lookups. + GLIBC has reserved words 10 through 15 for TM. */ +# define HAVE_ARCH_GTM_THREAD 1 +# define HAVE_ARCH_GTM_THREAD_TX 1 +# define HAVE_ARCH_GTM_THREAD_DISP 1 + +# include "config/generic/tls.h" + +namespace GTM HIDDEN { + +# ifdef __LP64__ +# define SEG_READ(OFS) "movq\t%%fs:(" #OFS "*8),%0" +# define SEG_WRITE(OFS) "movq\t%0,%%fs:(" #OFS "*8)" +# else +# define SEG_READ(OFS) "movl\t%%gs:(" #OFS "*4),%0" +# define SEG_WRITE(OFS) "movl\t%0,%%gs:(" #OFS "*4)" +# endif + +static inline struct gtm_thread *gtm_thr(void) +{ + struct gtm_thread *r; + asm (SEG_READ(10) : "=r"(r)); + return r; +} + +static inline void setup_gtm_thr(void) +{ + if (gtm_thr() == NULL) + asm volatile (SEG_WRITE(10) : : "r"(&_gtm_thr)); +} + +static inline struct gtm_transaction * gtm_tx(void) +{ + struct gtm_transaction *r; + asm (SEG_READ(11) : "=r"(r)); + return r; +} + +static inline void set_gtm_tx(struct gtm_transaction *x) +{ + asm volatile (SEG_WRITE(11) : : "r"(x)); +} + +static inline struct gtm_dispatch *gtm_disp(void) +{ + struct gtm_dispatch *r; + asm (SEG_READ(12) : "=r"(r)); + return r; +} + +static inline void set_gtm_disp(struct gtm_dispatch *x) +{ + asm volatile (SEG_WRITE(12) : : "r"(x)); +} + +} // namespace GTM +#else +# include "config/generic/tls.h" +#endif /* >= GLIBC 2.10 */ diff --git a/libitm/config/posix/page.c b/libitm/config/posix/cachepage.cc index 43b840366c0..9888ef5028c 100644 --- a/libitm/config/posix/page.c +++ b/libitm/config/posix/cachepage.cc @@ -24,6 +24,10 @@ #include "libitm_i.h" +// +// We have three possibilities for alloction: mmap, memalign, posix_memalign +// + #if defined(HAVE_MMAP_ANON) || defined(HAVE_MMAP_DEV_ZERO) #include <sys/mman.h> #include <fcntl.h> @@ -32,8 +36,7 @@ #include <malloc.h> #endif - -static gtm_cacheline_page *free_pages; +namespace GTM HIDDEN { #if defined(HAVE_MMAP_ANON) # if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) @@ -50,7 +53,8 @@ static int dev_zero = -1; #if defined(HAVE_MMAP_ANON) || defined(HAVE_MMAP_DEV_ZERO) /* If we get here, we've already opened /dev/zero and verified that PAGE_SIZE is valid for the system. */ -static gtm_cacheline_page * UNUSED +static gtm_cacheline_page * alloc_mmap (void) UNUSED; +static gtm_cacheline_page * alloc_mmap (void) { gtm_cacheline_page *r; @@ -131,12 +135,15 @@ init_alloc_page (void) # error "No aligned memory allocation method" #endif +static gtm_cacheline_page *free_pages; -gtm_cacheline_page * -GTM_page_alloc (void) +void * +gtm_cacheline_page::operator new (size_t size) { - gtm_cacheline_page *r = free_pages; + assert (size == sizeof (gtm_cacheline_page)); + assert (size <= PAGE_SIZE); + gtm_cacheline_page *r = free_pages; restart: if (r) { @@ -155,12 +162,20 @@ GTM_page_alloc (void) } void -GTM_page_release (gtm_cacheline_page *head, gtm_cacheline_page *tail) +gtm_cacheline_page::operator delete (void *xhead) { - gtm_cacheline_page *n, *p = free_pages; + gtm_cacheline_page *head = static_cast<gtm_cacheline_page *>(xhead); + gtm_cacheline_page *tail, *n, *p; + + if (head == 0) + return; - /* ??? We should eventually free some of these. */ + /* ??? We should eventually really free some of these. */ + for (tail = head; tail->prev != 0; tail = tail->prev) + continue; + + p = free_pages; restart: tail->prev = p; n = __sync_val_compare_and_swap (&free_pages, p, head); @@ -170,3 +185,5 @@ GTM_page_release (gtm_cacheline_page *head, gtm_cacheline_page *tail) goto restart; } } + +} // namespace GTM diff --git a/libitm/config/posix/rwlock.cc b/libitm/config/posix/rwlock.cc new file mode 100644 index 00000000000..069eec257f7 --- /dev/null +++ b/libitm/config/posix/rwlock.cc @@ -0,0 +1,189 @@ +/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "libitm_i.h" + +namespace GTM HIDDEN { + +// Initialize a new RW lock. +// ??? Move this back to the header file when constexpr is implemented. + +gtm_rwlock::gtm_rwlock() + : mutex (PTHREAD_MUTEX_INITIALIZER), + c_readers (PTHREAD_COND_INITIALIZER), + c_writers (PTHREAD_COND_INITIALIZER), + c_upgrade (PTHREAD_COND_INITIALIZER), + summary (0), + a_readers (0), + w_readers (0), + w_writers (0) +{ } + +gtm_rwlock::~gtm_rwlock() +{ + pthread_mutex_destroy (&this->mutex); + pthread_cond_destroy (&this->c_readers); + pthread_cond_destroy (&this->c_writers); + pthread_cond_destroy (&this->c_upgrade); +} + +// Acquire a RW lock for reading. + +void +gtm_rwlock::read_lock () +{ + pthread_mutex_lock (&this->mutex); + + unsigned int sum = this->summary; + + // If there is a waiting upgrade, or an active writer, we must wait. + while (sum & (w_upgrade | a_writer | w_writer)) + { + this->summary = sum | w_reader; + this->w_readers++; + pthread_cond_wait (&this->c_readers, &this->mutex); + sum = this->summary; + if (--this->w_readers == 0) + sum &= ~w_reader; + } + + // Otherwise we can acquire the lock for read. + this->summary = sum | a_reader; + this->a_readers++; + + pthread_mutex_unlock(&this->mutex); +} + + +// Acquire a RW lock for writing. + +void +gtm_rwlock::write_lock () +{ + pthread_mutex_lock (&this->mutex); + + unsigned int sum = this->summary; + + // If there is a waiting upgrade, or an active reader or writer, wait. + while (sum & (w_upgrade | a_writer | a_reader)) + { + this->summary = sum | w_writer; + this->w_writers++; + pthread_cond_wait (&this->c_writers, &this->mutex); + sum = this->summary; + if (--this->w_writers == 0) + sum &= ~w_writer; + } + + // Otherwise we can acquire the lock for write. + this->summary = sum | a_writer; + + pthread_mutex_unlock(&this->mutex); +} + + +// Upgrade a RW lock that has been locked for reading to a writing lock. +// Do this without possibility of another writer incoming. Return false +// if this attempt fails (i.e. another thread also upgraded). + +bool +gtm_rwlock::write_upgrade () +{ + pthread_mutex_lock (&this->mutex); + + unsigned int sum = this->summary; + + // If there's already someone trying to upgrade, then we fail. + if (unlikely (sum & w_upgrade)) + { + pthread_mutex_unlock (&this->mutex); + return false; + } + + // If there are more active readers, then we have to wait. + if (--this->a_readers > 0) + { + this->summary = sum | w_upgrade; + pthread_cond_wait (&this->c_upgrade, &this->mutex); + sum = this->summary & ~w_upgrade; + // We only return from upgrade when we've got it; don't loop. + assert ((sum & (a_reader | a_writer)) == 0); + } + + // Otherwise we can upgrade to writer. + this->summary = sum | a_writer; + + pthread_mutex_unlock (&this->mutex); + return true; +} + + +// Release a RW lock from reading. + +void +gtm_rwlock::read_unlock () +{ + pthread_mutex_lock (&this->mutex); + + // If there are no more active readers, we may need to wake someone. + if (--this->a_readers == 0) + { + unsigned int sum = this->summary; + this->summary = sum & ~a_reader; + + // If there is a waiting upgrade, wake it. + if (unlikely (sum & w_upgrade)) + pthread_cond_signal (&this->c_upgrade); + + // If there is a waiting writer, wake it. + else if (unlikely (sum & w_writer)) + pthread_cond_signal (&this->c_writers); + } + + pthread_mutex_unlock (&this->mutex); +} + + +// Release a RW lock from writing. + +void +gtm_rwlock::write_unlock () +{ + pthread_mutex_lock (&this->mutex); + + unsigned int sum = this->summary; + this->summary = sum & ~a_writer; + + // If there is a waiting writer, wake it. + if (unlikely (sum & w_writer)) + pthread_cond_signal (&this->c_writers); + + // If there are waiting readers, wake them. + else if (unlikely (sum & w_reader)) + pthread_cond_broadcast (&this->c_readers); + + pthread_mutex_unlock (&this->mutex); +} + +} // namespace GTM diff --git a/libitm/config/posix/rwlock.h b/libitm/config/posix/rwlock.h new file mode 100644 index 00000000000..85544455da8 --- /dev/null +++ b/libitm/config/posix/rwlock.h @@ -0,0 +1,73 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef GTM_RWLOCK_H +#define GTM_RWLOCK_H + +#include <pthread.h> + +namespace GTM HIDDEN { + +// This datastructure is similar to the POSIX pthread_rwlock_t except +// that we also provide for upgrading a reader->writer lock, with a +// positive indication of failure (another writer acquired the lock +// before we were able to acquire). +// +// In this implementation, rw upgrade is given highest priority access, +// and writers are given priority over readers. + +class gtm_rwlock +{ + pthread_mutex_t mutex; // Held if manipulating any field. + pthread_cond_t c_readers; // Readers wait here + pthread_cond_t c_writers; // Writers wait here + pthread_cond_t c_upgrade; // An upgrader waits here + + static const unsigned w_upgrade = 1; // A reader waiting for upgrade + static const unsigned a_writer = 2; // An active writer. + static const unsigned w_writer = 4; // The w_writers field != 0 + static const unsigned a_reader = 8; // The a_readers field != 0 + static const unsigned w_reader = 16; // The w_readers field != 0 + + unsigned int summary; // Bitmask of the above. + unsigned int a_readers; // Nr active readers + unsigned int w_readers; // Nr waiting readers + unsigned int w_writers; // Nr waiting writers + + public: + gtm_rwlock(); + ~gtm_rwlock(); + + void read_lock (); + void read_unlock (); + + void write_lock (); + void write_unlock (); + + bool write_upgrade (); +}; + +} // namespace GTM + +#endif // GTM_RWLOCK_H diff --git a/libitm/config/x86/cacheline.cc b/libitm/config/x86/cacheline.cc new file mode 100644 index 00000000000..631b11abefd --- /dev/null +++ b/libitm/config/x86/cacheline.cc @@ -0,0 +1,73 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "libitm_i.h" + +namespace GTM HIDDEN { + +uint32_t const gtm_bit_to_byte_mask[16] = +{ + 0x00000000, + 0x000000ff, + 0x0000ff00, + 0x0000ffff, + 0x00ff0000, + 0x00ff00ff, + 0x00ffff00, + 0x00ffffff, + 0xff000000, + 0xff0000ff, + 0xff00ff00, + 0xff00ffff, + 0xffff0000, + 0xffff00ff, + 0xffffff00, + 0xffffffff +}; + +#ifdef __SSE2__ +# define MEMBER m128i +#else +# define MEMBER w +#endif + +void +gtm_cacheline::copy_mask (gtm_cacheline * __restrict d, + const gtm_cacheline * __restrict s, + gtm_cacheline_mask m) +{ + if (m == (gtm_cacheline_mask)-1) + { + *d = *s; + return; + } + if (__builtin_expect (m == 0, 0)) + return; + + size_t n = sizeof(d->MEMBER[0]); + for (size_t i = 0; i < CACHELINE_SIZE / n; ++i, m >>= n) + store_mask (&d->MEMBER[i], s->MEMBER[i], m); +} + +} // namespace GTM diff --git a/libitm/config/x86/cacheline.h b/libitm/config/x86/cacheline.h new file mode 100644 index 00000000000..24902f47296 --- /dev/null +++ b/libitm/config/x86/cacheline.h @@ -0,0 +1,242 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef LIBITM_CACHELINE_H +#define LIBITM_CACHELINE_H 1 + +// Minimum cacheline size is 32, due to both complex long double and __m256. +// There's no requirement that 64-bit use a 64-byte cacheline size, but do +// so for now to make sure everything is parameterized properly. +#ifdef __x86_64__ +# define CACHELINE_SIZE 64 +#else +# define CACHELINE_SIZE 32 +#endif + +namespace GTM HIDDEN { + +// A gtm_cacheline_mask stores a modified bit for every modified byte +// in the cacheline with which it is associated. +typedef sized_integral<CACHELINE_SIZE / 8>::type gtm_cacheline_mask; + +extern uint32_t const gtm_bit_to_byte_mask[16]; + +union gtm_cacheline +{ + // Byte access to the cacheline. + unsigned char b[CACHELINE_SIZE] __attribute__((aligned(CACHELINE_SIZE))); + + // Larger sized access to the cacheline. + uint16_t u16[CACHELINE_SIZE / sizeof(uint16_t)]; + uint32_t u32[CACHELINE_SIZE / sizeof(uint32_t)]; + uint64_t u64[CACHELINE_SIZE / sizeof(uint64_t)]; + gtm_word w[CACHELINE_SIZE / sizeof(gtm_word)]; + +#ifdef __MMX__ + __m64 m64[CACHELINE_SIZE / sizeof(__m64)]; +#endif +#ifdef __SSE__ + __m128 m128[CACHELINE_SIZE / sizeof(__m128)]; +#endif +#ifdef __SSE2__ + __m128i m128i[CACHELINE_SIZE / sizeof(__m128i)]; +#endif +#ifdef __AVX__ + __m256 m256[CACHELINE_SIZE / sizeof(__m256)]; + __m256i m256i[CACHELINE_SIZE / sizeof(__m256i)]; +#endif + + // Store S into D, but only the bytes specified by M. + static void store_mask (uint32_t *d, uint32_t s, uint8_t m); + static void store_mask (uint64_t *d, uint64_t s, uint8_t m); +#ifdef __SSE2__ + static void store_mask (__m128i *d, __m128i s, uint16_t m); +#endif + + // Copy S to D, but only the bytes specified by M. + static void copy_mask (gtm_cacheline * __restrict d, + const gtm_cacheline * __restrict s, + gtm_cacheline_mask m); + + // A write barrier to emit after (a series of) copy_mask. + // When we're emitting non-temporal stores, the normal strong + // ordering of the machine doesn't apply. + static void copy_mask_wb (); + +#if defined(__SSE__) || defined(__AVX__) + // Copy S to D; only bother defining if we can do this more efficiently + // than the compiler-generated default implementation. + gtm_cacheline& operator= (const gtm_cacheline &s); +#endif // SSE, AVX +}; + +inline void +gtm_cacheline::copy_mask_wb () +{ +#ifdef __SSE2__ + _mm_sfence (); +#endif +} + +#if defined(__SSE__) || defined(__AVX__) +inline gtm_cacheline& ALWAYS_INLINE +gtm_cacheline::operator= (const gtm_cacheline & __restrict s) +{ +#ifdef __AVX__ +# define CP m256 +# define TYPE __m256 +#else +# define CP m128 +# define TYPE __m128 +#endif + + TYPE w, x, y, z; + + // ??? Wouldn't it be nice to have a pragma to tell the compiler + // to completely unroll a given loop? + switch (CACHELINE_SIZE / sizeof(TYPE)) + { + case 1: + this->CP[0] = s.CP[0]; + break; + case 2: + x = s.CP[0]; + y = s.CP[1]; + this->CP[0] = x; + this->CP[1] = y; + break; + case 4: + w = s.CP[0]; + x = s.CP[1]; + y = s.CP[2]; + z = s.CP[3]; + this->CP[0] = w; + this->CP[1] = x; + this->CP[2] = y; + this->CP[3] = z; + break; + default: + __builtin_trap (); + } + + return *this; +} +#endif + +// ??? Support masked integer stores more efficiently with an unlocked cmpxchg +// insn. My reasoning is that while we write to locations that we do not wish +// to modify, we do it in an uninterruptable insn, and so we either truely +// write back the original data or the insn fails -- unlike with a +// load/and/or/write sequence which can be interrupted either by a kernel +// task switch or an unlucky cacheline steal by another processor. Avoiding +// the LOCK prefix improves performance by a factor of 10, and we don't need +// the memory barrier semantics implied by that prefix. + +inline void ALWAYS_INLINE +gtm_cacheline::store_mask (uint32_t *d, uint32_t s, uint8_t m) +{ + gtm_cacheline_mask tm = (1 << sizeof (s)) - 1; + if (__builtin_expect (m & tm, tm)) + { + if (__builtin_expect ((m & tm) == tm, 1)) + *d = s; + else + { + gtm_cacheline_mask bm = gtm_bit_to_byte_mask[m & 15]; + gtm_word n, o = *d; + + __asm("\n0:\t" + "mov %[o], %[n]\n\t" + "and %[m], %[n]\n\t" + "or %[s], %[n]\n\t" + "cmpxchg %[n], %[d]\n\t" + "jnz,pn 0b" + : [d] "+m"(*d), [n] "=&r" (n), [o] "+a"(o) + : [s] "r" (s & bm), [m] "r" (~bm)); + } + } +} + +inline void ALWAYS_INLINE +gtm_cacheline::store_mask (uint64_t *d, uint64_t s, uint8_t m) +{ + gtm_cacheline_mask tm = (1 << sizeof (s)) - 1; + if (__builtin_expect (m & tm, tm)) + { + if (__builtin_expect ((m & tm) == tm, 1)) + *d = s; + else + { +#ifdef __x86_64__ + uint32_t bl = gtm_bit_to_byte_mask[m & 15]; + uint32_t bh = gtm_bit_to_byte_mask[(m >> 4) & 15]; + gtm_cacheline_mask bm = bl | ((gtm_cacheline_mask)bh << 31 << 1); + uint64_t n, o = *d; + __asm("\n0:\t" + "mov %[o], %[n]\n\t" + "and %[m], %[n]\n\t" + "or %[s], %[n]\n\t" + "cmpxchg %[n], %[d]\n\t" + "jnz,pn 0b" + : [d] "+m"(*d), [n] "=&r" (n), [o] "+a"(o) + : [s] "r" (s & bm), [m] "r" (~bm)); +#else + /* ??? While it's possible to perform this operation with + cmpxchg8b, the sequence requires all 7 general registers + and thus cannot be performed with -fPIC. Don't even try. */ + uint32_t *d32 = reinterpret_cast<uint32_t *>(d); + store_mask (d32, s, m); + store_mask (d32 + 1, s >> 32, m >> 4); +#endif + } + } +} + +#ifdef __SSE2__ +inline void ALWAYS_INLINE +gtm_cacheline::store_mask (__m128i *d, __m128i s, uint16_t m) +{ + if (__builtin_expect (m == 0, 0)) + return; + if (__builtin_expect (m == 0xffff, 1)) + *d = s; + else + { + __m128i bm0, bm1, bm2, bm3; + bm0 = _mm_set_epi32 (0, 0, 0, gtm_bit_to_byte_mask[m & 15]); m >>= 4; + bm1 = _mm_set_epi32 (0, 0, 0, gtm_bit_to_byte_mask[m & 15]); m >>= 4; + bm2 = _mm_set_epi32 (0, 0, 0, gtm_bit_to_byte_mask[m & 15]); m >>= 4; + bm3 = _mm_set_epi32 (0, 0, 0, gtm_bit_to_byte_mask[m & 15]); m >>= 4; + bm0 = _mm_unpacklo_epi32 (bm0, bm1); + bm2 = _mm_unpacklo_epi32 (bm2, bm3); + bm0 = _mm_unpacklo_epi64 (bm0, bm2); + + _mm_maskmoveu_si128 (s, bm0, (char *)d); + } +} +#endif // SSE2 + +} // namespace GTM + +#endif // LIBITM_CACHELINE_H diff --git a/libitm/config/x86/copymask.c b/libitm/config/x86/copymask.c deleted file mode 100644 index 9cabbe6a753..00000000000 --- a/libitm/config/x86/copymask.c +++ /dev/null @@ -1,187 +0,0 @@ -/* Copyright (C) 2009 Free Software Foundation, Inc. - Contributed by Richard Henderson <rth@redhat.com>. - - This file is part of the GNU Transactional Memory Library (libitm). - - Libitm is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - Libitm is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - <http://www.gnu.org/licenses/>. */ - -#include "libitm_i.h" - - -static uint32_t const bit_to_byte_mask[16] = -{ - 0x00000000, - 0x000000ff, - 0x0000ff00, - 0x0000ffff, - 0x00ff0000, - 0x00ff00ff, - 0x00ffff00, - 0x00ffffff, - 0xff000000, - 0xff0000ff, - 0xff00ff00, - 0xff00ffff, - 0xffff0000, - 0xffff00ff, - 0xffffff00, - 0xffffffff -}; - -#ifdef __SSE2__ - -void -gtm_cacheline_copy_mask (gtm_cacheline * __restrict d, - const gtm_cacheline * __restrict s, - gtm_cacheline_mask m) -{ - int i; - - if (m == (gtm_cacheline_mask)-1) - { - gtm_cacheline_copy (d, s); - return; - } - if (__builtin_expect (m == 0, 0)) - return; - - for (i = 0; i < CACHELINE_SIZE / 16; ++i) - { - gtm_cacheline_mask m16 = m & 0xffff; - if (__builtin_expect (m16 == 0, 0)) - goto skip16; - if (__builtin_expect (m16 == 0xffff, 1)) - { - d->m128i[i] = s->m128i[i]; - skip16: - m >>= 16; - } - else - { - __m128i bm0, bm1, bm2, bm3; - bm0 = _mm_set_epi32 (0, 0, 0, bit_to_byte_mask[m & 15]); m >>= 4; - bm1 = _mm_set_epi32 (0, 0, 0, bit_to_byte_mask[m & 15]); m >>= 4; - bm2 = _mm_set_epi32 (0, 0, 0, bit_to_byte_mask[m & 15]); m >>= 4; - bm3 = _mm_set_epi32 (0, 0, 0, bit_to_byte_mask[m & 15]); m >>= 4; - bm0 = _mm_unpacklo_epi32 (bm0, bm1); - bm2 = _mm_unpacklo_epi32 (bm2, bm3); - bm0 = _mm_unpacklo_epi64 (bm0, bm2); - - if (ALLOW_UNMASKED_STORES) - d->m128i[i] = (d->m128i[i] & ~bm0) | (s->m128i[i] & bm0); - else - _mm_maskmoveu_si128 (s->m128i[i], bm0, (char *)&d->m128i[i]); - } - } -} - -#else -/* ??? If we don't have SSE2, I believe we can honor !ALLOW_UNMASKED_STORES - more efficiently with an unlocked cmpxchg insn. My reasoning is that - while we write to locations that we do not wish to modify, we do it in - an uninterruptable insn, and so we either truely write back the original - data or the insn fails -- unlike with a load/and/or/write sequence which - can be interrupted either by a kernel task switch or an unlucky cacheline - steal by another processor. Avoiding the LOCK prefix improves performance - by a factor of 10, and we don't need the memory barrier semantics - implied by that prefix. */ - -static void __attribute__((always_inline)) -copy_mask_w (gtm_word * __restrict d, - const gtm_word * __restrict s, - gtm_cacheline_mask m) -{ - gtm_cacheline_mask tm = (1 << sizeof (gtm_word)) - 1; - - if (__builtin_expect (m & tm, tm)) - { - if (__builtin_expect ((m & tm) == tm, 1)) - *d = *s; - else if (sizeof (gtm_word) == 4) - { - gtm_cacheline_mask bm = bit_to_byte_mask[m & 15]; - - if (ALLOW_UNMASKED_STORES) - *d = (*d & ~bm) | (*s & bm); - else - { - gtm_word n, o = *d; - asm ("\n0:\t" - "mov %[o], %[n]\n\t" - "and %[m], %[n]\n\t" - "or %[s], %[n]\n\t" - "cmpxchg %[n], %[d]\n\t" - "jnz,pn 0b" - : [d] "+m"(*d), [n] "=&r" (n), [o] "+a"(o) - : [s] "r" (*s & bm), [m] "r" (~bm)); - } - } - else if (sizeof (gtm_word) == 8) - { - uint32_t bl = bit_to_byte_mask[m & 15]; - uint32_t bh = bit_to_byte_mask[(m >> 4) & 15]; - gtm_cacheline_mask bm = bl | ((gtm_cacheline_mask)bh << 31 << 1); - - if (ALLOW_UNMASKED_STORES) - *d = (*d & ~bm) | (*s & bm); - else - { -#ifdef __x86_64__ - gtm_word n, o = *d; - asm ("\n0:\t" - "mov %[o], %[n]\n\t" - "and %[m], %[n]\n\t" - "or %[s], %[n]\n\t" - "cmpxchg %[n], %[d]\n\t" - "jnz,pn 0b" - : [d] "+m"(*d), [n] "=&r" (n), [o] "+a"(o) - : [s] "r" (*s & bm), [m] "r" (~bm)); -#else - /* ??? While it's possible to perform this operation with - cmpxchg8b, the sequence requires all 7 general registers - and thus cannot be performed with -fPIC. Don't even try. */ - __builtin_trap (); -#endif - } - } - } -} - -void -gtm_cacheline_copy_mask (gtm_cacheline * __restrict d, - const gtm_cacheline * __restrict s, - gtm_cacheline_mask m) -{ - const size_t n = sizeof (gtm_word); - size_t i; - - if (m == (gtm_cacheline_mask)-1) - { - gtm_cacheline_copy (d, s); - return; - } - if (__builtin_expect (m == 0, 0)) - return; - - for (i = 0; i < CACHELINE_SIZE / n; ++i, m >>= n) - copy_mask_w (&d->w[i], &s->w[i], m); -} - -#endif /* SSE2 */ diff --git a/libitm/config/x86/target.h b/libitm/config/x86/target.h index 20235b10c07..375891b0ada 100644 --- a/libitm/config/x86/target.h +++ b/libitm/config/x86/target.h @@ -22,6 +22,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see <http://www.gnu.org/licenses/>. */ +namespace GTM HIDDEN { + #ifdef __x86_64__ /* ??? This doesn't work for Win64. */ typedef struct gtm_jmpbuf @@ -47,18 +49,6 @@ typedef struct gtm_jmpbuf } gtm_jmpbuf; #endif -/* The "cacheline" as defined by the STM need not be the same as the - cacheline defined by the processor. It ought to be big enough for - any of the basic types to be stored (aligned) in one line. It ought - to be small enough for efficient manipulation of the modification - mask. The cacheline copy routines assume that if SSE is present - that we can use it, which implies a minimum cacheline size of 16. */ -#ifdef __x86_64__ -# define CACHELINE_SIZE 64 -#else -# define CACHELINE_SIZE 32 -#endif - /* x86 doesn't require strict alignment for the basic types. */ #define STRICT_ALIGNMENT 0 @@ -66,5 +56,39 @@ typedef struct gtm_jmpbuf #define PAGE_SIZE 4096 #define FIXED_PAGE_SIZE 1 -/* We'll be using some of the cpu builtins, and their associated types. */ +static inline void +cpu_relax (void) +{ + __asm volatile ("rep; nop" : : : "memory"); +} + +static inline void +atomic_read_barrier (void) +{ + /* x86 is a strong memory ordering machine. */ + __asm volatile ("" : : : "memory"); +} + +static inline void +atomic_write_barrier (void) +{ + /* x86 is a strong memory ordering machine. */ + __asm volatile ("" : : : "memory"); +} + +} // namespace GTM + +// We'll be using some of the cpu builtins, and their associated types. +#ifndef __cplusplus +/* ??? It's broken for C++. */ #include <x86intrin.h> +#else +# ifdef __SSE2__ +# include <emmintrin.h> +# elif defined(__SSE__) +# include <xmmintrin.h> +# endif +# ifdef __AVX__ +# include <immintrin.h> +# endif +#endif diff --git a/libitm/config/x86/target_i.h b/libitm/config/x86/target_i.h deleted file mode 100644 index be801254748..00000000000 --- a/libitm/config/x86/target_i.h +++ /dev/null @@ -1,155 +0,0 @@ -/* Copyright (C) 2009 Free Software Foundation, Inc. - Contributed by Richard Henderson <rth@redhat.com>. - - This file is part of the GNU Transactional Memory Library (libitm). - - Libitm is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - Libitm is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - <http://www.gnu.org/licenses/>. */ - -static inline void -cpu_relax (void) -{ - __asm volatile ("rep; nop" : : : "memory"); -} - -static inline void -atomic_read_barrier (void) -{ - /* x86 is a strong memory ordering machine. */ - __asm volatile ("" : : : "memory"); -} - -static inline void -atomic_write_barrier (void) -{ - /* x86 is a strong memory ordering machine. */ - __asm volatile ("" : : : "memory"); -} - - -/* Copy a cacheline with the widest available vector type. */ -#if defined(__SSE__) || defined(__AVX__) -# define HAVE_ARCH_GTM_CACHELINE_COPY 1 -static inline void -gtm_cacheline_copy (gtm_cacheline * __restrict d, - const gtm_cacheline * __restrict s) -{ -#ifdef __AVX__ -# define CP m256 -# define TYPE __m256 -#else -# define CP m128 -# define TYPE __m128 -#endif - - TYPE w, x, y, z; - - /* ??? Wouldn't it be nice to have a pragma to tell the compiler - to completely unroll a given loop? */ - switch (CACHELINE_SIZE / sizeof(s->CP[0])) - { - case 1: - d->CP[0] = s->CP[0]; - break; - case 2: - x = s->CP[0]; - y = s->CP[1]; - d->CP[0] = x; - d->CP[1] = y; - break; - case 4: - w = s->CP[0]; - x = s->CP[1]; - y = s->CP[2]; - z = s->CP[3]; - d->CP[0] = w; - d->CP[1] = x; - d->CP[2] = y; - d->CP[3] = z; - break; - default: - __builtin_trap (); - } -} -#endif - -#if !ALLOW_UNMASKED_STORES && defined(__SSE2__) -# define HAVE_ARCH_GTM_CCM_WRITE_BARRIER 1 -/* A write barrier to emit after (a series of) gtm_copy_cacheline_mask. - Since we'll be emitting non-temporal stores, the normal strong ordering - of the machine doesn't apply and we have to emit an SFENCE. */ -static inline void -gtm_ccm_write_barrier (void) -{ - _mm_sfence (); -} -#endif - -#if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 10) -/* Use slots in the TCB head rather than __thread lookups. - GLIBC has reserved words 10 through 15 for TM. */ -#define HAVE_ARCH_GTM_THREAD -#define HAVE_ARCH_GTM_THREAD_TX -#define HAVE_ARCH_GTM_THREAD_DISP - -#ifdef __LP64__ -# define SEG_READ(OFS) "movq\t%%fs:(" #OFS "*8),%0" -# define SEG_WRITE(OFS) "movq\t%0,%%fs:(" #OFS "*8)" -#else -# define SEG_READ(OFS) "movl\t%%gs:(" #OFS "*4),%0" -# define SEG_WRITE(OFS) "movl\t%0,%%gs:(" #OFS "*4)" -#endif - -static inline struct gtm_thread *gtm_thr(void) -{ - struct gtm_thread *r; - asm (SEG_READ(10) : "=r"(r)); - return r; -} - -static inline void setup_gtm_thr(void) -{ - if (gtm_thr() == NULL) - asm volatile (SEG_WRITE(10) : : "r"(&_gtm_thr)); -} - -static inline struct gtm_transaction * gtm_tx(void) -{ - struct gtm_transaction *r; - asm (SEG_READ(11) : "=r"(r)); - return r; -} - -static inline void set_gtm_tx(struct gtm_transaction *x) -{ - asm volatile (SEG_WRITE(11) : : "r"(x)); -} - -static inline const struct gtm_dispatch *gtm_disp(void) -{ - const struct gtm_dispatch *r; - asm (SEG_READ(12) : "=r"(r)); - return r; -} - -static inline void set_gtm_disp(const struct gtm_dispatch *x) -{ - asm volatile (SEG_WRITE(12) : : "r"(x)); -} -#endif /* >= GLIBC 2.10 */ diff --git a/libitm/config/x86/unaligned.h b/libitm/config/x86/unaligned.h new file mode 100644 index 00000000000..422cb88b2a5 --- /dev/null +++ b/libitm/config/x86/unaligned.h @@ -0,0 +1,241 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef LIBITM_X86_UNALIGNED_H +#define LIBITM_X86_UNALIGNED_H 1 + +#define HAVE_ARCH_UNALIGNED_LOAD2_U4 1 +#define HAVE_ARCH_UNALIGNED_LOAD2_U8 1 + +#include "config/generic/unaligned.h" + +namespace GTM HIDDEN { + +// ??? C++ currently has ambiguous name mangling, with __m128 and __m256 +// mangling to the same thing. "Fix" this by forcing these inline +// functions to be always inline. + +template<> +inline uint32_t +unaligned_load2<uint32_t>(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ + uint32_t r, lo, hi; + lo = c1->u32[CACHELINE_SIZE / sizeof(uint32_t) - 1]; + hi = c2->u32[0]; + asm("shrd %b2, %1, %0" : "=r"(r) : "r"(hi), "c"((ofs & 3) * 8), "0"(lo)); + return r; +} + +template<> +inline uint64_t +unaligned_load2<uint64_t>(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ +#ifdef __x86_64__ + uint64_t r, lo, hi; + lo = c1->u64[CACHELINE_SIZE / sizeof(uint64_t) - 1]; + hi = c2->u64[0]; + asm("shrd %b2, %1, %0" : "=r"(r) : "r"(hi), "c"((ofs & 3) * 8), "0"(lo)); + return r; +#else + uint32_t v0, v1, v2; + uint64_t r; + + if (ofs < CACHELINE_SIZE - 4) + { + v0 = c1->u32[CACHELINE_SIZE / sizeof(uint32_t) - 2]; + v1 = c1->u32[CACHELINE_SIZE / sizeof(uint32_t) - 1]; + v2 = c2->u32[0]; + } + else + { + v0 = c1->u32[CACHELINE_SIZE / sizeof(uint32_t) - 1]; + v1 = c2->u32[0]; + v2 = c2->u32[1]; + } + ofs = (ofs & 3) * 8; + asm("shrd %%cl, %[v1], %[v0]; shrd %%cl, %[v2], %[v1]" + : "=A"(r) : "c"(ofs), [v0] "a"(v0), [v1] "d"(v1), [v2] "r"(v2)); + + return r; +#endif +} + +#if defined(__SSE2__) || defined(__MMX__) +template<> +inline _ITM_TYPE_M64 +unaligned_load2<_ITM_TYPE_M64>(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ +# ifdef __x86_64__ + __m128i lo = _mm_movpi64_epi64 (c1->m64[CACHELINE_SIZE / 8 - 1]); + __m128i hi = _mm_movpi64_epi64 (c2->m64[0]); + + ofs = (ofs & 7) * 8; + lo = _mm_srli_epi64 (lo, ofs); + hi = _mm_slli_epi64 (hi, 64 - ofs); + lo = lo | hi; + return _mm_movepi64_pi64 (lo); +# else + // On 32-bit we're about to return the result in an MMX register, so go + // ahead and do the computation in that unit, even if SSE2 is available. + __m64 lo = c1->m64[CACHELINE_SIZE / 8 - 1]; + __m64 hi = c2->m64[0]; + + ofs = (ofs & 7) * 8; + lo = _mm_srli_si64 (lo, ofs); + hi = _mm_slli_si64 (hi, 64 - ofs); + return lo | hi; +# endif +} +#endif // SSE2 or MMX + +// The SSE types are strictly aligned. +#ifdef __SSE__ +template<> + struct strict_alignment<_ITM_TYPE_M128> + : public std::true_type + { }; + +// Expand the unaligned SSE move instructions. +template<> +inline _ITM_TYPE_M128 ALWAYS_INLINE +unaligned_load<_ITM_TYPE_M128>(const void *t) +{ + return _mm_loadu_ps (static_cast<const float *>(t)); +} + +template<> +inline void ALWAYS_INLINE +unaligned_store<_ITM_TYPE_M128>(void *t, _ITM_TYPE_M128 val) +{ + _mm_storeu_ps (static_cast<float *>(t), val); +} +#endif // SSE + +#ifdef __AVX__ +// The AVX types are strictly aligned when it comes to vmovaps vs vmovups. +template<> + struct strict_alignment<_ITM_TYPE_M256> + : public std::true_type + { }; + +template<> +inline _ITM_TYPE_M256 ALWAYS_INLINE +unaligned_load<_ITM_TYPE_M256>(const void *t) +{ + return _mm256_loadu_ps (static_cast<const float *>(t)); +} + +template<> +inline void ALWAYS_INLINE +unaligned_store<_ITM_TYPE_M256>(void *t, _ITM_TYPE_M256 val) +{ + _mm256_storeu_ps (static_cast<float *>(t), val); +} +#endif // AVX + +#ifdef __XOP__ +# define HAVE_ARCH_REALIGN_M128I 1 +extern const __v16qi GTM_vpperm_shift[16]; +inline __m128i ALWAYS_INLINE +realign_m128i (__m128i lo, __m128i hi, unsigned byte_count) +{ + return _mm_perm_epi8 (lo, hi, GTM_vpperm_shift[byte_count]); +} +#elif defined(__AVX__) +# define HAVE_ARCH_REALIGN_M128I 1 +extern "C" const uint64_t GTM_vpalignr_table[16]; +inline __m128i ALWAYS_INLINE +realign_m128i (__m128i lo, __m128i hi, unsigned byte_count) +{ + register __m128i xmm0 __asm__("xmm0") = hi; + register __m128i xmm1 __asm__("xmm1") = lo; + __asm("call *%2" : "+x"(xmm0) : "x"(xmm1), + "r"(>M_vpalignr_table[byte_count])); + return xmm0; +} +#elif defined(__SSSE3__) +# define HAVE_ARCH_REALIGN_M128I 1 +extern "C" const uint64_t GTM_palignr_table[16]; +inline __m128i ALWAYS_INLINE +realign_m128i (__m128i lo, __m128i hi, unsigned byte_count) +{ + register __m128i xmm0 __asm__("xmm0") = hi; + register __m128i xmm1 __asm__("xmm1") = lo; + __asm("call *%2" : "+x"(xmm0) : "x"(xmm1), + "r"(>M_palignr_table[byte_count])); + return xmm0; +} +#elif defined(__SSE2__) +# define HAVE_ARCH_REALIGN_M128I 1 +extern "C" const char GTM_pshift_table[16 * 16]; +inline __m128i ALWAYS_INLINE +realign_m128i (__m128i lo, __m128i hi, unsigned byte_count) +{ + register __m128i xmm0 __asm__("xmm0") = lo; + register __m128i xmm1 __asm__("xmm1") = hi; + __asm("call *%2" : "+x"(xmm0), "+x"(xmm1) + : "r"(GTM_pshift_table + byte_count*16)); + return xmm0; +} +#endif // XOP, AVX, SSSE3, SSE2 + +#ifdef HAVE_ARCH_REALIGN_M128I +template<> +inline _ITM_TYPE_M128 ALWAYS_INLINE +unaligned_load2<_ITM_TYPE_M128>(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ + return (_ITM_TYPE_M128) + realign_m128i (c1->m128i[CACHELINE_SIZE / 16 - 1], + c2->m128i[0], ofs & 15); +} +#endif // HAVE_ARCH_REALIGN_M128I + +#ifdef __AVX__ +template<> +inline _ITM_TYPE_M256 ALWAYS_INLINE +unaligned_load2<_ITM_TYPE_M256>(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ + __m128i v0, v1; + __m256i r; + + v0 = (__m128i) unaligned_load2<_ITM_TYPE_M128>(c1, c2, ofs); + if (ofs < CACHELINE_SIZE - 16) + v1 = v0, v0 = _mm_loadu_si128 ((const __m128i *) &c1->b[ofs]); + else + v1 = _mm_loadu_si128((const __m128i *)&c2->b[ofs + 16 - CACHELINE_SIZE]); + + r = _mm256_castsi128_si256 ((__m128i)v0); + r = _mm256_insertf128_si256 (r, (__m128i)v1, 1); + return (_ITM_TYPE_M256) r; +} +#endif // AVX + +} // namespace GTM + +#endif // LIBITM_X86_UNALIGNED_H diff --git a/libitm/config/x86/x86_avx.c b/libitm/config/x86/x86_avx.c deleted file mode 100644 index b2bd5e9cc40..00000000000 --- a/libitm/config/x86/x86_avx.c +++ /dev/null @@ -1,88 +0,0 @@ -/* Copyright (C) 2009 Free Software Foundation, Inc. - Contributed by Richard Henderson <rth@redhat.com>. - - This file is part of the GNU Transactional Memory Library (libitm). - - Libitm is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - Libitm is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - <http://www.gnu.org/licenses/>. */ - -#include "libitm_i.h" - -#define M256_READ(LOCK) \ -_ITM_TYPE_M256 ITM_REGPARM _ITM_##LOCK##M256(const _ITM_TYPE_M256 *ptr) \ -{ \ - uintptr_t iptr = (uintptr_t) ptr; \ - uintptr_t iline = iptr & -CACHELINE_SIZE; \ - uintptr_t iofs = iptr & (CACHELINE_SIZE - 1); \ - gtm_cacheline *line = gtm_disp()->LOCK (iline); \ - _ITM_TYPE_M256 ret; \ - \ - if (iofs + sizeof(ret) <= CACHELINE_SIZE) \ - { \ - return *(_ITM_TYPE_M256 *)&line->b[iofs]; \ - } \ - else \ - { \ - uintptr_t ileft = CACHELINE_SIZE - iofs; \ - memcpy (&ret, &line->b[iofs], ileft); \ - line = gtm_disp()->LOCK (iline + CACHELINE_SIZE); \ - memcpy ((char *)&ret + ileft, line, sizeof(ret) - ileft); \ - } \ - return ret; \ -} - -#define M256_WRITE(LOCK) \ -void ITM_REGPARM _ITM_##LOCK##M256(_ITM_TYPE_M256 *ptr, _ITM_TYPE_M256 val) \ -{ \ - uintptr_t iptr = (uintptr_t) ptr; \ - uintptr_t iline = iptr & -CACHELINE_SIZE; \ - uintptr_t iofs = iptr & (CACHELINE_SIZE - 1); \ - gtm_cacheline_mask m = ((gtm_cacheline_mask)2 << (sizeof(val)-1))-1; \ - gtm_cacheline_mask_pair pair = gtm_disp()->LOCK (iline); \ - \ - if (iofs + sizeof(val) <= CACHELINE_SIZE) \ - { \ - *(_ITM_TYPE_M256 *)&pair.line->b[iofs] = val; \ - *pair.mask |= m << iofs; \ - } \ - else \ - { \ - _ITM_TYPE_M256 sval = val; \ - uintptr_t ileft = CACHELINE_SIZE - iofs; \ - memcpy (&pair.line->b[iofs], &sval, ileft); \ - *pair.mask |= m << iofs; \ - pair = gtm_disp()->LOCK (iline + CACHELINE_SIZE); \ - memcpy (pair.line, (char *)&sval + ileft, sizeof(sval) - ileft); \ - *pair.mask |= m >> ileft; \ - } \ -} - -M256_READ(R) -M256_READ(RaR) -M256_READ(RaW) -M256_READ(RfW) -M256_WRITE(W) -M256_WRITE(WaR) -M256_WRITE(WaW) - -void ITM_REGPARM -_ITM_LM256 (const _ITM_TYPE_M256 *ptr) -{ - GTM_LB (ptr, sizeof (*ptr)); -} diff --git a/libitm/config/x86/x86_avx.cc b/libitm/config/x86/x86_avx.cc new file mode 100644 index 00000000000..ee073d56986 --- /dev/null +++ b/libitm/config/x86/x86_avx.cc @@ -0,0 +1,93 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "libitm_i.h" +#include "barrier.tpl" + +ITM_BARRIERS(M256) + +void ITM_REGPARM +_ITM_LM256 (const _ITM_TYPE_M256 *ptr) +{ + GTM_LB (ptr, sizeof (*ptr)); +} + +// Helpers for re-aligning two 128-bit values. +#ifdef __XOP__ +const __v16qi GTM::GTM_vpperm_shift[16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, + { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }, + { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }, + { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }, + { 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }, + { 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }, + { 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 }, + { 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }, + { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }, + { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 }, + { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }, + { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 }, + { 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 }, + { 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 }, + { 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }, +}; +#else +# define INSN0 "movdqa %xmm1, %xmm0" +# define INSN(N) "vpalignr $" #N ", %xmm0, %xmm1, %xmm0" +# define TABLE_ENT_0 INSN0 "\n\tret\n\t" +# define TABLE_ENT(N) ".balign 8\n\t" INSN(N) "\n\tret\n\t" + +asm(".pushsection .text\n\ + .balign 16\n\ + .globl GTM_vpalignr_table\n\ + .hidden GTM_vpalignr_table\n\ + .type GTM_vpalignr_table, @function\n\ +GTM_vpalignr_table:\n\t" + TABLE_ENT_0 + TABLE_ENT(1) + TABLE_ENT(2) + TABLE_ENT(3) + TABLE_ENT(4) + TABLE_ENT(5) + TABLE_ENT(6) + TABLE_ENT(7) + TABLE_ENT(8) + TABLE_ENT(9) + TABLE_ENT(10) + TABLE_ENT(11) + TABLE_ENT(12) + TABLE_ENT(13) + TABLE_ENT(14) + TABLE_ENT(15) + ".balign 8\n\ + .size GTM_vpalignr_table, .-GTM_vpalignr_table\n\ + .popsection"); + +# undef INSN0 +# undef INSN +# undef TABLE_ENT_0 +# undef TABLE_ENT +#endif diff --git a/libitm/config/x86/x86_sse.c b/libitm/config/x86/x86_sse.c deleted file mode 100644 index eaf2676ca1c..00000000000 --- a/libitm/config/x86/x86_sse.c +++ /dev/null @@ -1,166 +0,0 @@ -/* Copyright (C) 2009 Free Software Foundation, Inc. - Contributed by Richard Henderson <rth@redhat.com>. - - This file is part of the GNU Transactional Memory Library (libitm). - - Libitm is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - Libitm is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - <http://www.gnu.org/licenses/>. */ - -#include "libitm_i.h" - - -#define M64_READ(LOCK) \ -_ITM_TYPE_M64 ITM_REGPARM _ITM_##LOCK##M64(const _ITM_TYPE_M64 *ptr) \ -{ \ - uintptr_t iptr = (uintptr_t) ptr; \ - uintptr_t iline = iptr & -CACHELINE_SIZE; \ - uintptr_t iofs = iptr & (CACHELINE_SIZE - 1); \ - gtm_cacheline *line = gtm_disp()->LOCK (iline); \ - _ITM_TYPE_M64 ret; \ - \ - if (iofs + sizeof(ret) <= CACHELINE_SIZE) \ - { \ - return *(_ITM_TYPE_M64 *)&line->b[iofs]; \ - } \ - else \ - { \ - uintptr_t ileft = CACHELINE_SIZE - iofs; \ - memcpy (&ret, &line->b[iofs], ileft); \ - line = gtm_disp()->LOCK (iline + CACHELINE_SIZE); \ - memcpy ((char *)&ret + ileft, line, sizeof(ret) - ileft); \ - } \ - return ret; \ -} - -#define M64_WRITE(LOCK) \ -void ITM_REGPARM _ITM_##LOCK##M64(_ITM_TYPE_M64 *ptr, _ITM_TYPE_M64 val) \ -{ \ - uintptr_t iptr = (uintptr_t) ptr; \ - uintptr_t iline = iptr & -CACHELINE_SIZE; \ - uintptr_t iofs = iptr & (CACHELINE_SIZE - 1); \ - gtm_cacheline_mask m = ((gtm_cacheline_mask)1 << sizeof(val)) - 1; \ - gtm_cacheline_mask_pair pair = gtm_disp()->LOCK (iline); \ - \ - if (iofs + sizeof(val) <= CACHELINE_SIZE) \ - { \ - *(_ITM_TYPE_M64 *)&pair.line->b[iofs] = val; \ - *pair.mask |= m << iofs; \ - } \ - else \ - { \ - _ITM_TYPE_M64 sval = val; \ - uintptr_t ileft = CACHELINE_SIZE - iofs; \ - memcpy (&pair.line->b[iofs], &sval, ileft); \ - *pair.mask |= m << iofs; \ - pair = gtm_disp()->LOCK (iline + CACHELINE_SIZE); \ - memcpy (pair.line, (char *)&sval + ileft, sizeof(sval) - ileft); \ - *pair.mask |= m >> ileft; \ - } \ -} - -/* Note that unlike all other X86 types, the SSE vector types do - require strict alignment by default. Use the unaligned load - and store builtins when necessary. */ - -#define M128_READ(LOCK) \ -_ITM_TYPE_M128 ITM_REGPARM _ITM_##LOCK##M128(const _ITM_TYPE_M128 *ptr) \ -{ \ - uintptr_t iptr = (uintptr_t) ptr; \ - uintptr_t iline = iptr & -CACHELINE_SIZE; \ - uintptr_t iofs = iptr & (CACHELINE_SIZE - 1); \ - gtm_cacheline *line = gtm_disp()->LOCK (iline); \ - _ITM_TYPE_M128 ret; \ - \ - if ((iofs & (sizeof (ret) - 1)) == 0) \ - { \ - return *(_ITM_TYPE_M128 *)&line->b[iofs]; \ - } \ - else if (iofs + sizeof(ret) <= CACHELINE_SIZE) \ - { \ - return _mm_loadu_ps ((const float *) &line->b[iofs]); \ - } \ - else \ - { \ - uintptr_t ileft = CACHELINE_SIZE - iofs; \ - memcpy (&ret, &line->b[iofs], ileft); \ - line = gtm_disp()->LOCK (iline + CACHELINE_SIZE); \ - memcpy ((char *)&ret + ileft, line, sizeof(ret) - ileft); \ - } \ - return ret; \ -} - -#define M128_WRITE(LOCK) \ -void ITM_REGPARM _ITM_##LOCK##M128(_ITM_TYPE_M128 *ptr, _ITM_TYPE_M128 val) \ -{ \ - uintptr_t iptr = (uintptr_t) ptr; \ - uintptr_t iline = iptr & -CACHELINE_SIZE; \ - uintptr_t iofs = iptr & (CACHELINE_SIZE - 1); \ - gtm_cacheline_mask m = ((gtm_cacheline_mask)1 << sizeof(val)) - 1; \ - gtm_cacheline_mask_pair pair = gtm_disp()->LOCK (iline); \ - \ - if ((iofs & (sizeof (val) - 1)) == 0) \ - { \ - *(_ITM_TYPE_M128 *)&pair.line->b[iofs] = val; \ - *pair.mask |= m << iofs; \ - } \ - else if (iofs + sizeof(val) <= CACHELINE_SIZE) \ - { \ - _mm_storeu_ps ((float *) &pair.line->b[iofs], val); \ - *pair.mask |= m << iofs; \ - } \ - else \ - { \ - _ITM_TYPE_M128 sval = val; \ - uintptr_t ileft = CACHELINE_SIZE - iofs; \ - memcpy (&pair.line->b[iofs], &sval, ileft); \ - *pair.mask |= m << iofs; \ - pair = gtm_disp()->LOCK (iline + CACHELINE_SIZE); \ - memcpy (pair.line, (char *)&sval + ileft, sizeof(sval) - ileft); \ - *pair.mask |= m >> ileft; \ - } \ -} - -M64_READ(R) -M64_READ(RaR) -M64_READ(RaW) -M64_READ(RfW) -M64_WRITE(W) -M64_WRITE(WaR) -M64_WRITE(WaW) - -M128_READ(R) -M128_READ(RaR) -M128_READ(RaW) -M128_READ(RfW) -M128_WRITE(W) -M128_WRITE(WaR) -M128_WRITE(WaW) - - -void ITM_REGPARM -_ITM_LM64 (const _ITM_TYPE_M64 *ptr) -{ - GTM_LB (ptr, sizeof (*ptr)); -} - -void ITM_REGPARM -_ITM_LM128 (const _ITM_TYPE_M128 *ptr) -{ - GTM_LB (ptr, sizeof (*ptr)); -} diff --git a/libitm/config/x86/x86_sse.cc b/libitm/config/x86/x86_sse.cc new file mode 100644 index 00000000000..5bb97664d81 --- /dev/null +++ b/libitm/config/x86/x86_sse.cc @@ -0,0 +1,120 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "libitm_i.h" +#include "barrier.tpl" + +ITM_BARRIERS(M64) +ITM_BARRIERS(M128) + +void ITM_REGPARM +_ITM_LM64 (const _ITM_TYPE_M64 *ptr) +{ + GTM_LB (ptr, sizeof (*ptr)); +} + +void ITM_REGPARM +_ITM_LM128 (const _ITM_TYPE_M128 *ptr) +{ + GTM_LB (ptr, sizeof (*ptr)); +} + +// Helpers for re-aligning two 128-bit values. +#ifdef __SSSE3__ +# define INSN0 "movdqa %xmm1, %xmm0" +# define INSN(N) "palignr $" #N ", %xmm1, %xmm0" +# define TABLE_ENT_0 INSN0 "\n\tret\n\t" +# define TABLE_ENT(N) ".balign 8\n\t" INSN(N) "\n\tret\n\t" + +asm(".pushsection .text\n\ + .balign 16\n\ + .globl GTM_palignr_table\n\ + .hidden GTM_palignr_table\n\ + .type GTM_palignr_table, @function\n\ +GTM_palignr_table:\n\t" + TABLE_ENT_0 + TABLE_ENT(1) + TABLE_ENT(2) + TABLE_ENT(3) + TABLE_ENT(4) + TABLE_ENT(5) + TABLE_ENT(6) + TABLE_ENT(7) + TABLE_ENT(8) + TABLE_ENT(9) + TABLE_ENT(10) + TABLE_ENT(11) + TABLE_ENT(12) + TABLE_ENT(13) + TABLE_ENT(14) + TABLE_ENT(15) + ".balign 8\n\ + .size GTM_palignr_table, .-GTM_palignr_table\n\ + .popsection"); + +# undef INSN0 +# undef INSN +# undef TABLE_ENT_0 +# undef TABLE_ENT +#elif defined(__SSE2__) +# define INSNS_8 "punpcklqdq %xmm1, %xmm0" +# define INSNS(N) "psrldq $"#N", %xmm0\n\t" \ + "pslldq $(16-"#N"), %xmm1\n\t" \ + "por %xmm1, %xmm0" +# define TABLE_ENT_0 "ret\n\t" +# define TABLE_ENT_8 ".balign 16\n\t" INSNS_8 "\n\tret\n\t" +# define TABLE_ENT(N) ".balign 16\n\t" INSNS(N) "\n\tret\n\t" + +asm(".pushsection .text\n\ + .balign 16\n\ + .globl GTM_pshift_table\n\ + .hidden GTM_pshift_table\n\ + .type GTM_pshift_table, @function\n\ +GTM_pshift_table:\n\t" + TABLE_ENT_0 + TABLE_ENT(1) + TABLE_ENT(2) + TABLE_ENT(3) + TABLE_ENT(4) + TABLE_ENT(5) + TABLE_ENT(6) + TABLE_ENT(7) + TABLE_ENT_8 + TABLE_ENT(9) + TABLE_ENT(10) + TABLE_ENT(11) + TABLE_ENT(12) + TABLE_ENT(13) + TABLE_ENT(14) + TABLE_ENT(15) + ".balign 8\n\ + .size GTM_pshift_table, .-GTM_pshift_table\n\ + .popsection"); + +# undef INSNS_8 +# undef INSNS +# undef TABLE_ENT_0 +# undef TABLE_ENT_8 +# undef TABLE_ENT +#endif diff --git a/libitm/configure b/libitm/configure index 453f465e868..9585c11e4f4 100755 --- a/libitm/configure +++ b/libitm/configure @@ -740,6 +740,8 @@ ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS +ARCH_FUTEX_FALSE +ARCH_FUTEX_TRUE ARCH_X86_FALSE ARCH_X86_TRUE link_itm @@ -759,6 +761,7 @@ MAINTAINER_MODE_FALSE MAINTAINER_MODE_TRUE enable_static enable_shared +CXXCPP CPP OTOOL64 OTOOL @@ -787,6 +790,12 @@ am__fastdepCCAS_TRUE CCASDEPMODE CCASFLAGS CCAS +am__fastdepCXX_FALSE +am__fastdepCXX_TRUE +CXXDEPMODE +ac_ct_CXX +CXXFLAGS +CXX am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE @@ -904,10 +913,14 @@ host_alias target_alias CPP CPPFLAGS -FC -FCFLAGS +CXX +CXXFLAGS LDFLAGS -LIBS' +LIBS +CCC +CXXCPP +FC +FCFLAGS' # Initialize some variables set by options. @@ -1565,9 +1578,12 @@ Some influential environment variables: 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> + CXX C++ compiler command + CXXFLAGS C++ compiler flags CCAS assembler compiler command (defaults to CC) CCASFLAGS assembler compiler flags (defaults to CFLAGS) CPP C preprocessor + CXXCPP C++ preprocessor FC Fortran compiler command FCFLAGS Fortran compiler flags @@ -1691,6 +1707,44 @@ fi } # ac_fn_c_try_compile +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_cxx_try_compile + # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. @@ -1914,6 +1968,89 @@ $as_echo "$ac_res" >&6; } } # 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 + # ac_fn_fc_try_compile LINENO # --------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. @@ -4400,6 +4537,390 @@ else fi +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if 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 + +{ $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 + +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 + + # By default we simply use the C compiler to build assembly code. test "${CCAS+set}" = set || CCAS=$CC @@ -5486,13 +6007,13 @@ if test "${lt_cv_nm_interface+set}" = set; then : else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:5489: $ac_compile\"" >&5) + (eval echo "\"\$as_me:6010: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 - (eval echo "\"\$as_me:5492: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval echo "\"\$as_me:6013: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 - (eval echo "\"\$as_me:5495: output\"" >&5) + (eval echo "\"\$as_me:6016: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" @@ -6698,7 +7219,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 6701 "configure"' > conftest.$ac_ext + echo '#line 7222 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -7728,6 +8249,533 @@ done +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 + +{ $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 + +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 + + +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;} +_lt_caught_CXX_error=yes; } +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 + + + + + # Set options @@ -8228,11 +9276,11 @@ else -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:8231: $lt_compile\"" >&5) + (eval echo "\"\$as_me:9279: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:8235: \$? = $ac_status" >&5 + echo "$as_me:9283: \$? = $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. @@ -8567,11 +9615,11 @@ else -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:8570: $lt_compile\"" >&5) + (eval echo "\"\$as_me:9618: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:8574: \$? = $ac_status" >&5 + echo "$as_me:9622: \$? = $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. @@ -8672,11 +9720,11 @@ else -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:8675: $lt_compile\"" >&5) + (eval echo "\"\$as_me:9723: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:8679: \$? = $ac_status" >&5 + echo "$as_me:9727: \$? = $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 @@ -8727,11 +9775,11 @@ else -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:8730: $lt_compile\"" >&5) + (eval echo "\"\$as_me:9778: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:8734: \$? = $ac_status" >&5 + echo "$as_me:9782: \$? = $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 @@ -11109,7 +12157,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11112 "configure" +#line 12160 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11205,7 +12253,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11208 "configure" +#line 12256 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11413,6 +12461,2853 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" +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 +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 "X$cc_temp" | $Xsed -e 's%.*/%%' -e "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 "^ .* -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 $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; 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' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_CXX='$convenience' + 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' + 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 + whole_archive_flag_spec_CXX='' + 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=echo + 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 + ;; + + freebsd[12]*) + # 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*) + ;; + + 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) | $GREP "^ .* -L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + 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; $ECHO "X$list" | $Xsed' + ;; + *) + 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" && $ECHO "X-set_version $verstring" | $Xsed` -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" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${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" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -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; $ECHO "X$list" | $Xsed' + + 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 will 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; $ECHO \"$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=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + xl*) + # 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; $ECHO \"$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='echo' + + # 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=echo + 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" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -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" && $ECHO "X-set_version $verstring" | $Xsed` -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 "X-set_version $verstring" | $Xsed` -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=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + 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" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${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" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${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 "^ .* -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='echo' + + # 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 "^ .* -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 "^ .* -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' + ;; + *) + 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 + ;; + + 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= + ;; + 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*) + # IBM XL 8.0 on PPC + 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:14212: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:14216: \$? = $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 "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/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 "X$_lt_linker_boilerplate" | $Xsed -e '/^$/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:14311: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:14315: \$? = $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 "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/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:14363: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:14367: \$? = $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 "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/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 + 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")) && (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=`$ECHO "X$lib" | $Xsed -e '\''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="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + 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 + ;; + +freebsd1*) + dynamic_linker=no + ;; + +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[123]*) 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 + ;; + +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' + ;; + +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;/^$/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 + + @@ -12152,24 +16047,6 @@ fi - - - - - - - - - - - - - - - - - - lt_prog_compiler_wl_FC= lt_prog_compiler_pic_FC= lt_prog_compiler_static_FC= @@ -12473,11 +16350,11 @@ else -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:12476: $lt_compile\"" >&5) + (eval echo "\"\$as_me:16353: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:12480: \$? = $ac_status" >&5 + echo "$as_me:16357: \$? = $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. @@ -12572,11 +16449,11 @@ else -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:12575: $lt_compile\"" >&5) + (eval echo "\"\$as_me:16452: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:12579: \$? = $ac_status" >&5 + echo "$as_me:16456: \$? = $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 @@ -12624,11 +16501,11 @@ else -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:12627: $lt_compile\"" >&5) + (eval echo "\"\$as_me:16504: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:12631: \$? = $ac_status" >&5 + echo "$as_me:16508: \$? = $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 @@ -15118,6 +18995,375 @@ ac_config_commands="$ac_config_commands gstdint.h" + +ac_fn_c_check_header_mongrel "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_mman_h" = x""yes; then : + gcc_header_sys_mman_h=yes +else + gcc_header_sys_mman_h=no +fi + + +ac_fn_c_check_func "$LINENO" "mmap" "ac_cv_func_mmap" +if test "x$ac_cv_func_mmap" = x""yes; then : + gcc_func_mmap=yes +else + gcc_func_mmap=no +fi + +if test "$gcc_header_sys_mman_h" != yes \ + || test "$gcc_func_mmap" != yes; then + gcc_cv_func_mmap_file=no + gcc_cv_func_mmap_dev_zero=no + gcc_cv_func_mmap_anon=no +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether read-only mmap of a plain file works" >&5 +$as_echo_n "checking whether read-only mmap of a plain file works... " >&6; } +if test "${gcc_cv_func_mmap_file+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # Add a system to this blacklist if + # mmap(0, stat_size, PROT_READ, MAP_PRIVATE, fd, 0) doesn't return a + # memory area containing the same data that you'd get if you applied + # read() to the same fd. The only system known to have a problem here + # is VMS, where text files have record structure. + case "$host_os" in + vms* | ultrix*) + gcc_cv_func_mmap_file=no ;; + *) + gcc_cv_func_mmap_file=yes;; + esac +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_func_mmap_file" >&5 +$as_echo "$gcc_cv_func_mmap_file" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mmap from /dev/zero works" >&5 +$as_echo_n "checking whether mmap from /dev/zero works... " >&6; } +if test "${gcc_cv_func_mmap_dev_zero+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # Add a system to this blacklist if it has mmap() but /dev/zero + # does not exist, or if mmapping /dev/zero does not give anonymous + # zeroed pages with both the following properties: + # 1. If you map N consecutive pages in with one call, and then + # unmap any subset of those pages, the pages that were not + # explicitly unmapped remain accessible. + # 2. If you map two adjacent blocks of memory and then unmap them + # both at once, they must both go away. + # Systems known to be in this category are Windows (all variants), + # VMS, and Darwin. + case "$host_os" in + vms* | cygwin* | pe | mingw* | darwin* | ultrix* | hpux10* | hpux11.00) + gcc_cv_func_mmap_dev_zero=no ;; + *) + gcc_cv_func_mmap_dev_zero=yes;; + esac +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_func_mmap_dev_zero" >&5 +$as_echo "$gcc_cv_func_mmap_dev_zero" >&6; } + + # Unlike /dev/zero, the MAP_ANON(YMOUS) defines can be probed for. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for MAP_ANON(YMOUS)" >&5 +$as_echo_n "checking for MAP_ANON(YMOUS)... " >&6; } +if test "${gcc_cv_decl_map_anon+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/types.h> +#include <sys/mman.h> +#include <unistd.h> + +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + +int +main () +{ +int n = MAP_ANONYMOUS; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gcc_cv_decl_map_anon=yes +else + gcc_cv_decl_map_anon=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_decl_map_anon" >&5 +$as_echo "$gcc_cv_decl_map_anon" >&6; } + + if test $gcc_cv_decl_map_anon = no; then + gcc_cv_func_mmap_anon=no + else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mmap with MAP_ANON(YMOUS) works" >&5 +$as_echo_n "checking whether mmap with MAP_ANON(YMOUS) works... " >&6; } +if test "${gcc_cv_func_mmap_anon+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # Add a system to this blacklist if it has mmap() and MAP_ANON or + # MAP_ANONYMOUS, but using mmap(..., MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) + # doesn't give anonymous zeroed pages with the same properties listed + # above for use of /dev/zero. + # Systems known to be in this category are Windows, VMS, and SCO Unix. + case "$host_os" in + vms* | cygwin* | pe | mingw* | sco* | udk* ) + gcc_cv_func_mmap_anon=no ;; + *) + gcc_cv_func_mmap_anon=yes;; + esac +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_func_mmap_anon" >&5 +$as_echo "$gcc_cv_func_mmap_anon" >&6; } + fi +fi + +if test $gcc_cv_func_mmap_file = yes; then + +$as_echo "#define HAVE_MMAP_FILE 1" >>confdefs.h + +fi +if test $gcc_cv_func_mmap_dev_zero = yes; then + +$as_echo "#define HAVE_MMAP_DEV_ZERO 1" >>confdefs.h + +fi +if test $gcc_cv_func_mmap_anon = yes; then + +$as_echo "#define HAVE_MMAP_ANON 1" >>confdefs.h + +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 +$as_echo_n "checking whether byte ordering is bigendian... " >&6; } +if test "${ac_cv_c_bigendian+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_bigendian=unknown + # See if we're dealing with a universal compiler. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __APPLE_CC__ + not a universal capable compiler + #endif + typedef int dummy; + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # Check for potential -arch flags. It is not universal unless + # there are at least two -arch flags with different values. + ac_arch= + ac_prev= + for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do + if test -n "$ac_prev"; then + case $ac_word in + i?86 | x86_64 | ppc | ppc64) + if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then + ac_arch=$ac_word + else + ac_cv_c_bigendian=universal + break + fi + ;; + esac + ac_prev= + elif test "x$ac_word" = "x-arch"; then + ac_prev=arch + fi + done +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test $ac_cv_c_bigendian = unknown; then + # See if sys/param.h defines the BYTE_ORDER macro. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/types.h> + #include <sys/param.h> + +int +main () +{ +#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ + && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ + && LITTLE_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/types.h> + #include <sys/param.h> + +int +main () +{ +#if BYTE_ORDER != BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +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 + if test $ac_cv_c_bigendian = unknown; then + # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <limits.h> + +int +main () +{ +#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to _BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <limits.h> + +int +main () +{ +#ifndef _BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +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 + if test $ac_cv_c_bigendian = unknown; then + # Compile a test program. + if test "$cross_compiling" = yes; then : + # Try to guess by grepping values from an object file. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +short int ascii_mm[] = + { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; + short int ascii_ii[] = + { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; + int use_ascii (int i) { + return ascii_mm[i] + ascii_ii[i]; + } + short int ebcdic_ii[] = + { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; + short int ebcdic_mm[] = + { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; + int use_ebcdic (int i) { + return ebcdic_mm[i] + ebcdic_ii[i]; + } + extern int foo; + +int +main () +{ +return use_ascii (foo) == use_ebcdic (foo); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then + ac_cv_c_bigendian=yes + fi + if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if test "$ac_cv_c_bigendian" = unknown; then + ac_cv_c_bigendian=no + else + # finding both strings is unlikely to happen, but who knows? + ac_cv_c_bigendian=unknown + fi + fi +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long int l; + char c[sizeof (long int)]; + } u; + u.l = 1; + return u.c[sizeof (long int) - 1] == 1; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_c_bigendian=no +else + ac_cv_c_bigendian=yes +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_c_bigendian" >&5 +$as_echo "$ac_cv_c_bigendian" >&6; } + case $ac_cv_c_bigendian in #( + yes) + $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h +;; #( + no) + ;; #( + universal) + +$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h + + ;; #( + *) + as_fn_error "unknown endianness + presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; + esac + +# I don't like the default behaviour of WORDS_BIGENDIAN undefined for LE. + + # Check to see if -pthread or -lpthread is needed. Prefer the former. # In case the pthread.h system header is not found, this test will fail. # ??? Not needed if linux futexes are used. @@ -15993,159 +20239,6 @@ $as_echo "#define HAVE_SYNC_BUILTINS 1" >>confdefs.h fi - -ac_fn_c_check_header_mongrel "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_mman_h" = x""yes; then : - gcc_header_sys_mman_h=yes -else - gcc_header_sys_mman_h=no -fi - - -ac_fn_c_check_func "$LINENO" "mmap" "ac_cv_func_mmap" -if test "x$ac_cv_func_mmap" = x""yes; then : - gcc_func_mmap=yes -else - gcc_func_mmap=no -fi - -if test "$gcc_header_sys_mman_h" != yes \ - || test "$gcc_func_mmap" != yes; then - gcc_cv_func_mmap_file=no - gcc_cv_func_mmap_dev_zero=no - gcc_cv_func_mmap_anon=no -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether read-only mmap of a plain file works" >&5 -$as_echo_n "checking whether read-only mmap of a plain file works... " >&6; } -if test "${gcc_cv_func_mmap_file+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - # Add a system to this blacklist if - # mmap(0, stat_size, PROT_READ, MAP_PRIVATE, fd, 0) doesn't return a - # memory area containing the same data that you'd get if you applied - # read() to the same fd. The only system known to have a problem here - # is VMS, where text files have record structure. - case "$host_os" in - vms* | ultrix*) - gcc_cv_func_mmap_file=no ;; - *) - gcc_cv_func_mmap_file=yes;; - esac -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_func_mmap_file" >&5 -$as_echo "$gcc_cv_func_mmap_file" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mmap from /dev/zero works" >&5 -$as_echo_n "checking whether mmap from /dev/zero works... " >&6; } -if test "${gcc_cv_func_mmap_dev_zero+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - # Add a system to this blacklist if it has mmap() but /dev/zero - # does not exist, or if mmapping /dev/zero does not give anonymous - # zeroed pages with both the following properties: - # 1. If you map N consecutive pages in with one call, and then - # unmap any subset of those pages, the pages that were not - # explicitly unmapped remain accessible. - # 2. If you map two adjacent blocks of memory and then unmap them - # both at once, they must both go away. - # Systems known to be in this category are Windows (all variants), - # VMS, and Darwin. - case "$host_os" in - vms* | cygwin* | pe | mingw* | darwin* | ultrix* | hpux10* | hpux11.00) - gcc_cv_func_mmap_dev_zero=no ;; - *) - gcc_cv_func_mmap_dev_zero=yes;; - esac -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_func_mmap_dev_zero" >&5 -$as_echo "$gcc_cv_func_mmap_dev_zero" >&6; } - - # Unlike /dev/zero, the MAP_ANON(YMOUS) defines can be probed for. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for MAP_ANON(YMOUS)" >&5 -$as_echo_n "checking for MAP_ANON(YMOUS)... " >&6; } -if test "${gcc_cv_decl_map_anon+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <sys/types.h> -#include <sys/mman.h> -#include <unistd.h> - -#ifndef MAP_ANONYMOUS -#define MAP_ANONYMOUS MAP_ANON -#endif - -int -main () -{ -int n = MAP_ANONYMOUS; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - gcc_cv_decl_map_anon=yes -else - gcc_cv_decl_map_anon=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_decl_map_anon" >&5 -$as_echo "$gcc_cv_decl_map_anon" >&6; } - - if test $gcc_cv_decl_map_anon = no; then - gcc_cv_func_mmap_anon=no - else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mmap with MAP_ANON(YMOUS) works" >&5 -$as_echo_n "checking whether mmap with MAP_ANON(YMOUS) works... " >&6; } -if test "${gcc_cv_func_mmap_anon+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - # Add a system to this blacklist if it has mmap() and MAP_ANON or - # MAP_ANONYMOUS, but using mmap(..., MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) - # doesn't give anonymous zeroed pages with the same properties listed - # above for use of /dev/zero. - # Systems known to be in this category are Windows, VMS, and SCO Unix. - case "$host_os" in - vms* | cygwin* | pe | mingw* | sco* | udk* ) - gcc_cv_func_mmap_anon=no ;; - *) - gcc_cv_func_mmap_anon=yes;; - esac -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_func_mmap_anon" >&5 -$as_echo "$gcc_cv_func_mmap_anon" >&6; } - fi -fi - -if test $gcc_cv_func_mmap_file = yes; then - -$as_echo "#define HAVE_MMAP_FILE 1" >>confdefs.h - -fi -if test $gcc_cv_func_mmap_dev_zero = yes; then - -$as_echo "#define HAVE_MMAP_DEV_ZERO 1" >>confdefs.h - -fi -if test $gcc_cv_func_mmap_anon = yes; then - -$as_echo "#define HAVE_MMAP_ANON 1" >>confdefs.h - -fi - - -# Add -Wall -Werror if we are using GCC. -if test "x$GCC" = "xyes"; then - XCFLAGS="$XCFLAGS -Wall -Werror" -fi - -XCFLAGS="$XCFLAGS $XPCFLAGS" - - - - - # Cleanup and exit. CFLAGS="$save_CFLAGS" cat >confcache <<\_ACEOF @@ -16223,6 +20316,17 @@ $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi rm -f confcache +# Add -Wall -Werror if we are using GCC. +if test "x$GCC" = "xyes"; then + XCFLAGS="$XCFLAGS -Wall -Werror" +fi + +XCFLAGS="$XCFLAGS $XPCFLAGS" + + + + + if test ${multilib} = yes; then multilib_arg="--enable-multilib" else @@ -16248,6 +20352,14 @@ else ARCH_X86_FALSE= fi + if test $enable_linux_futex = yes; then + ARCH_FUTEX_TRUE= + ARCH_FUTEX_FALSE='#' +else + ARCH_FUTEX_TRUE='#' + ARCH_FUTEX_FALSE= +fi + ac_config_files="$ac_config_files Makefile testsuite/Makefile libitm.spec" @@ -16368,6 +20480,10 @@ if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + as_fn_error "conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${am__fastdepCCAS_TRUE}" && test -z "${am__fastdepCCAS_FALSE}"; then as_fn_error "conditional \"am__fastdepCCAS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 @@ -16376,10 +20492,15 @@ if test -z "${BUILD_INFO_TRUE}" && test -z "${BUILD_INFO_FALSE}"; then as_fn_error "conditional \"BUILD_INFO\" 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 "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then as_fn_error "conditional \"MAINTAINER_MODE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi + if test -z "${LIBITM_BUILD_VERSIONED_SHLIB_TRUE}" && test -z "${LIBITM_BUILD_VERSIONED_SHLIB_FALSE}"; then as_fn_error "conditional \"LIBITM_BUILD_VERSIONED_SHLIB\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 @@ -16388,6 +20509,10 @@ if test -z "${ARCH_X86_TRUE}" && test -z "${ARCH_X86_FALSE}"; then as_fn_error "conditional \"ARCH_X86\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${ARCH_FUTEX_TRUE}" && test -z "${ARCH_FUTEX_FALSE}"; then + as_fn_error "conditional \"ARCH_FUTEX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi : ${CONFIG_STATUS=./config.status} ac_write_fail=0 @@ -17121,52 +21246,99 @@ postdep_objects='`$ECHO "X$postdep_objects" | $Xsed -e "$delay_single_quote_subs predeps='`$ECHO "X$predeps" | $Xsed -e "$delay_single_quote_subst"`' postdeps='`$ECHO "X$postdeps" | $Xsed -e "$delay_single_quote_subst"`' compiler_lib_search_path='`$ECHO "X$compiler_lib_search_path" | $Xsed -e "$delay_single_quote_subst"`' +LD_CXX='`$ECHO "X$LD_CXX" | $Xsed -e "$delay_single_quote_subst"`' LD_FC='`$ECHO "X$LD_FC" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_cmds_CXX='`$ECHO "X$old_archive_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' old_archive_cmds_FC='`$ECHO "X$old_archive_cmds_FC" | $Xsed -e "$delay_single_quote_subst"`' +compiler_CXX='`$ECHO "X$compiler_CXX" | $Xsed -e "$delay_single_quote_subst"`' compiler_FC='`$ECHO "X$compiler_FC" | $Xsed -e "$delay_single_quote_subst"`' +GCC_CXX='`$ECHO "X$GCC_CXX" | $Xsed -e "$delay_single_quote_subst"`' GCC_FC='`$ECHO "X$GCC_FC" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "X$lt_prog_compiler_no_builtin_flag_CXX" | $Xsed -e "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag_FC='`$ECHO "X$lt_prog_compiler_no_builtin_flag_FC" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_wl_CXX='`$ECHO "X$lt_prog_compiler_wl_CXX" | $Xsed -e "$delay_single_quote_subst"`' lt_prog_compiler_wl_FC='`$ECHO "X$lt_prog_compiler_wl_FC" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_pic_CXX='`$ECHO "X$lt_prog_compiler_pic_CXX" | $Xsed -e "$delay_single_quote_subst"`' lt_prog_compiler_pic_FC='`$ECHO "X$lt_prog_compiler_pic_FC" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_static_CXX='`$ECHO "X$lt_prog_compiler_static_CXX" | $Xsed -e "$delay_single_quote_subst"`' lt_prog_compiler_static_FC='`$ECHO "X$lt_prog_compiler_static_FC" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o_CXX='`$ECHO "X$lt_cv_prog_compiler_c_o_CXX" | $Xsed -e "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o_FC='`$ECHO "X$lt_cv_prog_compiler_c_o_FC" | $Xsed -e "$delay_single_quote_subst"`' +archive_cmds_need_lc_CXX='`$ECHO "X$archive_cmds_need_lc_CXX" | $Xsed -e "$delay_single_quote_subst"`' archive_cmds_need_lc_FC='`$ECHO "X$archive_cmds_need_lc_FC" | $Xsed -e "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes_CXX='`$ECHO "X$enable_shared_with_static_runtimes_CXX" | $Xsed -e "$delay_single_quote_subst"`' enable_shared_with_static_runtimes_FC='`$ECHO "X$enable_shared_with_static_runtimes_FC" | $Xsed -e "$delay_single_quote_subst"`' +export_dynamic_flag_spec_CXX='`$ECHO "X$export_dynamic_flag_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`' export_dynamic_flag_spec_FC='`$ECHO "X$export_dynamic_flag_spec_FC" | $Xsed -e "$delay_single_quote_subst"`' +whole_archive_flag_spec_CXX='`$ECHO "X$whole_archive_flag_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`' whole_archive_flag_spec_FC='`$ECHO "X$whole_archive_flag_spec_FC" | $Xsed -e "$delay_single_quote_subst"`' +compiler_needs_object_CXX='`$ECHO "X$compiler_needs_object_CXX" | $Xsed -e "$delay_single_quote_subst"`' compiler_needs_object_FC='`$ECHO "X$compiler_needs_object_FC" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_from_new_cmds_CXX='`$ECHO "X$old_archive_from_new_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' old_archive_from_new_cmds_FC='`$ECHO "X$old_archive_from_new_cmds_FC" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds_CXX='`$ECHO "X$old_archive_from_expsyms_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds_FC='`$ECHO "X$old_archive_from_expsyms_cmds_FC" | $Xsed -e "$delay_single_quote_subst"`' +archive_cmds_CXX='`$ECHO "X$archive_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' archive_cmds_FC='`$ECHO "X$archive_cmds_FC" | $Xsed -e "$delay_single_quote_subst"`' +archive_expsym_cmds_CXX='`$ECHO "X$archive_expsym_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' archive_expsym_cmds_FC='`$ECHO "X$archive_expsym_cmds_FC" | $Xsed -e "$delay_single_quote_subst"`' +module_cmds_CXX='`$ECHO "X$module_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' module_cmds_FC='`$ECHO "X$module_cmds_FC" | $Xsed -e "$delay_single_quote_subst"`' +module_expsym_cmds_CXX='`$ECHO "X$module_expsym_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' module_expsym_cmds_FC='`$ECHO "X$module_expsym_cmds_FC" | $Xsed -e "$delay_single_quote_subst"`' +with_gnu_ld_CXX='`$ECHO "X$with_gnu_ld_CXX" | $Xsed -e "$delay_single_quote_subst"`' with_gnu_ld_FC='`$ECHO "X$with_gnu_ld_FC" | $Xsed -e "$delay_single_quote_subst"`' +allow_undefined_flag_CXX='`$ECHO "X$allow_undefined_flag_CXX" | $Xsed -e "$delay_single_quote_subst"`' allow_undefined_flag_FC='`$ECHO "X$allow_undefined_flag_FC" | $Xsed -e "$delay_single_quote_subst"`' +no_undefined_flag_CXX='`$ECHO "X$no_undefined_flag_CXX" | $Xsed -e "$delay_single_quote_subst"`' no_undefined_flag_FC='`$ECHO "X$no_undefined_flag_FC" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_CXX='`$ECHO "X$hardcode_libdir_flag_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`' hardcode_libdir_flag_spec_FC='`$ECHO "X$hardcode_libdir_flag_spec_FC" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_ld_CXX='`$ECHO "X$hardcode_libdir_flag_spec_ld_CXX" | $Xsed -e "$delay_single_quote_subst"`' hardcode_libdir_flag_spec_ld_FC='`$ECHO "X$hardcode_libdir_flag_spec_ld_FC" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_separator_CXX='`$ECHO "X$hardcode_libdir_separator_CXX" | $Xsed -e "$delay_single_quote_subst"`' hardcode_libdir_separator_FC='`$ECHO "X$hardcode_libdir_separator_FC" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_direct_CXX='`$ECHO "X$hardcode_direct_CXX" | $Xsed -e "$delay_single_quote_subst"`' hardcode_direct_FC='`$ECHO "X$hardcode_direct_FC" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_direct_absolute_CXX='`$ECHO "X$hardcode_direct_absolute_CXX" | $Xsed -e "$delay_single_quote_subst"`' hardcode_direct_absolute_FC='`$ECHO "X$hardcode_direct_absolute_FC" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_minus_L_CXX='`$ECHO "X$hardcode_minus_L_CXX" | $Xsed -e "$delay_single_quote_subst"`' hardcode_minus_L_FC='`$ECHO "X$hardcode_minus_L_FC" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_shlibpath_var_CXX='`$ECHO "X$hardcode_shlibpath_var_CXX" | $Xsed -e "$delay_single_quote_subst"`' hardcode_shlibpath_var_FC='`$ECHO "X$hardcode_shlibpath_var_FC" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_automatic_CXX='`$ECHO "X$hardcode_automatic_CXX" | $Xsed -e "$delay_single_quote_subst"`' hardcode_automatic_FC='`$ECHO "X$hardcode_automatic_FC" | $Xsed -e "$delay_single_quote_subst"`' +inherit_rpath_CXX='`$ECHO "X$inherit_rpath_CXX" | $Xsed -e "$delay_single_quote_subst"`' inherit_rpath_FC='`$ECHO "X$inherit_rpath_FC" | $Xsed -e "$delay_single_quote_subst"`' +link_all_deplibs_CXX='`$ECHO "X$link_all_deplibs_CXX" | $Xsed -e "$delay_single_quote_subst"`' link_all_deplibs_FC='`$ECHO "X$link_all_deplibs_FC" | $Xsed -e "$delay_single_quote_subst"`' +fix_srcfile_path_CXX='`$ECHO "X$fix_srcfile_path_CXX" | $Xsed -e "$delay_single_quote_subst"`' fix_srcfile_path_FC='`$ECHO "X$fix_srcfile_path_FC" | $Xsed -e "$delay_single_quote_subst"`' +always_export_symbols_CXX='`$ECHO "X$always_export_symbols_CXX" | $Xsed -e "$delay_single_quote_subst"`' always_export_symbols_FC='`$ECHO "X$always_export_symbols_FC" | $Xsed -e "$delay_single_quote_subst"`' +export_symbols_cmds_CXX='`$ECHO "X$export_symbols_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' export_symbols_cmds_FC='`$ECHO "X$export_symbols_cmds_FC" | $Xsed -e "$delay_single_quote_subst"`' +exclude_expsyms_CXX='`$ECHO "X$exclude_expsyms_CXX" | $Xsed -e "$delay_single_quote_subst"`' exclude_expsyms_FC='`$ECHO "X$exclude_expsyms_FC" | $Xsed -e "$delay_single_quote_subst"`' +include_expsyms_CXX='`$ECHO "X$include_expsyms_CXX" | $Xsed -e "$delay_single_quote_subst"`' include_expsyms_FC='`$ECHO "X$include_expsyms_FC" | $Xsed -e "$delay_single_quote_subst"`' +prelink_cmds_CXX='`$ECHO "X$prelink_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' prelink_cmds_FC='`$ECHO "X$prelink_cmds_FC" | $Xsed -e "$delay_single_quote_subst"`' +file_list_spec_CXX='`$ECHO "X$file_list_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`' file_list_spec_FC='`$ECHO "X$file_list_spec_FC" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_action_CXX='`$ECHO "X$hardcode_action_CXX" | $Xsed -e "$delay_single_quote_subst"`' hardcode_action_FC='`$ECHO "X$hardcode_action_FC" | $Xsed -e "$delay_single_quote_subst"`' +compiler_lib_search_dirs_CXX='`$ECHO "X$compiler_lib_search_dirs_CXX" | $Xsed -e "$delay_single_quote_subst"`' compiler_lib_search_dirs_FC='`$ECHO "X$compiler_lib_search_dirs_FC" | $Xsed -e "$delay_single_quote_subst"`' +predep_objects_CXX='`$ECHO "X$predep_objects_CXX" | $Xsed -e "$delay_single_quote_subst"`' predep_objects_FC='`$ECHO "X$predep_objects_FC" | $Xsed -e "$delay_single_quote_subst"`' +postdep_objects_CXX='`$ECHO "X$postdep_objects_CXX" | $Xsed -e "$delay_single_quote_subst"`' postdep_objects_FC='`$ECHO "X$postdep_objects_FC" | $Xsed -e "$delay_single_quote_subst"`' +predeps_CXX='`$ECHO "X$predeps_CXX" | $Xsed -e "$delay_single_quote_subst"`' predeps_FC='`$ECHO "X$predeps_FC" | $Xsed -e "$delay_single_quote_subst"`' +postdeps_CXX='`$ECHO "X$postdeps_CXX" | $Xsed -e "$delay_single_quote_subst"`' postdeps_FC='`$ECHO "X$postdeps_FC" | $Xsed -e "$delay_single_quote_subst"`' +compiler_lib_search_path_CXX='`$ECHO "X$compiler_lib_search_path_CXX" | $Xsed -e "$delay_single_quote_subst"`' compiler_lib_search_path_FC='`$ECHO "X$compiler_lib_search_path_FC" | $Xsed -e "$delay_single_quote_subst"`' LTCC='$LTCC' @@ -17238,31 +21410,57 @@ postdep_objects \ predeps \ postdeps \ compiler_lib_search_path \ +LD_CXX \ LD_FC \ +compiler_CXX \ compiler_FC \ +lt_prog_compiler_no_builtin_flag_CXX \ lt_prog_compiler_no_builtin_flag_FC \ +lt_prog_compiler_wl_CXX \ lt_prog_compiler_wl_FC \ +lt_prog_compiler_pic_CXX \ lt_prog_compiler_pic_FC \ +lt_prog_compiler_static_CXX \ lt_prog_compiler_static_FC \ +lt_cv_prog_compiler_c_o_CXX \ lt_cv_prog_compiler_c_o_FC \ +export_dynamic_flag_spec_CXX \ export_dynamic_flag_spec_FC \ +whole_archive_flag_spec_CXX \ whole_archive_flag_spec_FC \ +compiler_needs_object_CXX \ compiler_needs_object_FC \ +with_gnu_ld_CXX \ with_gnu_ld_FC \ +allow_undefined_flag_CXX \ allow_undefined_flag_FC \ +no_undefined_flag_CXX \ no_undefined_flag_FC \ +hardcode_libdir_flag_spec_CXX \ hardcode_libdir_flag_spec_FC \ +hardcode_libdir_flag_spec_ld_CXX \ hardcode_libdir_flag_spec_ld_FC \ +hardcode_libdir_separator_CXX \ hardcode_libdir_separator_FC \ +fix_srcfile_path_CXX \ fix_srcfile_path_FC \ +exclude_expsyms_CXX \ exclude_expsyms_FC \ +include_expsyms_CXX \ include_expsyms_FC \ +file_list_spec_CXX \ file_list_spec_FC \ +compiler_lib_search_dirs_CXX \ compiler_lib_search_dirs_FC \ +predep_objects_CXX \ predep_objects_FC \ +postdep_objects_CXX \ postdep_objects_FC \ +predeps_CXX \ predeps_FC \ +postdeps_CXX \ postdeps_FC \ +compiler_lib_search_path_CXX \ compiler_lib_search_path_FC; do case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in *[\\\\\\\`\\"\\\$]*) @@ -17293,14 +21491,23 @@ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ sys_lib_dlsearch_path_spec \ +old_archive_cmds_CXX \ old_archive_cmds_FC \ +old_archive_from_new_cmds_CXX \ old_archive_from_new_cmds_FC \ +old_archive_from_expsyms_cmds_CXX \ old_archive_from_expsyms_cmds_FC \ +archive_cmds_CXX \ archive_cmds_FC \ +archive_expsym_cmds_CXX \ archive_expsym_cmds_FC \ +module_cmds_CXX \ module_cmds_FC \ +module_expsym_cmds_CXX \ module_expsym_cmds_FC \ +export_symbols_cmds_CXX \ export_symbols_cmds_FC \ +prelink_cmds_CXX \ prelink_cmds_FC; do case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in *[\\\\\\\`\\"\\\$]*) @@ -17340,6 +21547,8 @@ fi + + GCC="$GCC" CC="$CC" acx_cv_header_stdint="$acx_cv_header_stdint" @@ -18110,7 +22319,7 @@ $as_echo X"$file" | # The names of the tagged configurations supported by this script. -available_tags="FC " +available_tags="CXX FC " # ### BEGIN LIBTOOL CONFIG @@ -18712,6 +22921,159 @@ _LT_EOF cat <<_LT_EOF >> "$ofile" +# ### BEGIN LIBTOOL TAG CONFIG: CXX + +# The linker used to build libraries. +LD=$lt_LD_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 + + + cat <<_LT_EOF >> "$ofile" + # ### BEGIN LIBTOOL TAG CONFIG: FC # The linker used to build libraries. diff --git a/libitm/configure.ac b/libitm/configure.ac index 577a5f7c5a9..4c732a14b9c 100644 --- a/libitm/configure.ac +++ b/libitm/configure.ac @@ -103,6 +103,7 @@ AC_SUBST(toolexeclibdir) m4_rename([_AC_ARG_VAR_PRECIOUS],[real_PRECIOUS]) m4_define([_AC_ARG_VAR_PRECIOUS],[]) AC_PROG_CC +AC_PROG_CXX AM_PROG_AS m4_rename_force([real_PRECIOUS],[_AC_ARG_VAR_PRECIOUS]) @@ -154,6 +155,15 @@ AC_CHECK_HEADERS(unistd.h semaphore.h sys/time.h malloc.h) GCC_HEADER_STDINT(gstdint.h) +GCC_AC_FUNC_MMAP_BLACKLIST + +AC_C_BIGENDIAN +# I don't like the default behaviour of WORDS_BIGENDIAN undefined for LE. +AH_BOTTOM( +[#ifndef WORDS_BIGENDIAN +#define WORDS_BIGENDIAN 0 +#endif]) + # Check to see if -pthread or -lpthread is needed. Prefer the former. # In case the pthread.h system header is not found, this test will fail. # ??? Not needed if linux futexes are used. @@ -210,7 +220,9 @@ CFLAGS="$save_CFLAGS $XCFLAGS" # had a chance to set XCFLAGS. LIBITM_CHECK_SYNC_BUILTINS -GCC_AC_FUNC_MMAP_BLACKLIST +# Cleanup and exit. +CFLAGS="$save_CFLAGS" +AC_CACHE_SAVE # Add -Wall -Werror if we are using GCC. if test "x$GCC" = "xyes"; then @@ -223,10 +235,6 @@ AC_SUBST(config_path) AC_SUBST(XCFLAGS) AC_SUBST(XLDFLAGS) -# Cleanup and exit. -CFLAGS="$save_CFLAGS" -AC_CACHE_SAVE - if test ${multilib} = yes; then multilib_arg="--enable-multilib" else @@ -245,6 +253,7 @@ fi AC_SUBST(link_itm) AM_CONDITIONAL([ARCH_X86], [test "$ARCH" = x86]) +AM_CONDITIONAL([ARCH_FUTEX], [test $enable_linux_futex = yes]) AC_CONFIG_FILES(Makefile testsuite/Makefile libitm.spec) AC_OUTPUT diff --git a/libitm/configure.tgt b/libitm/configure.tgt index 5aef3fa4e44..5293fa96f1e 100644 --- a/libitm/configure.tgt +++ b/libitm/configure.tgt @@ -84,7 +84,7 @@ case "${target_cpu}" in esac # Since we require POSIX threads, assume a POSIX system by default. -config_path="$ARCH posix" +config_path="$ARCH posix generic" # Other system configury case "${target}" in @@ -100,15 +100,15 @@ case "${target}" in ;; *-*-mingw32*) - config_path="$ARCH mingw32 posix" + config_path="$ARCH mingw32 posix generic" ;; *-*-solaris2.[56]*) - config_path="$ARCH posix95 posix" + config_path="$ARCH posix95 posix generic" XLDFLAGS="${XLDFLAGS} -lposix4" ;; *-*-darwin*) - config_path="$ARCH bsd posix" + config_path="$ARCH bsd posix generic" ;; esac diff --git a/libitm/copymask.c b/libitm/copymask.c deleted file mode 100644 index 2a92710a3a9..00000000000 --- a/libitm/copymask.c +++ /dev/null @@ -1,195 +0,0 @@ -/* Copyright (C) 2009 Free Software Foundation, Inc. - Contributed by Richard Henderson <rth@redhat.com>. - - This file is part of the GNU Transactional Memory Library (libitm). - - Libitm is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - Libitm is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - <http://www.gnu.org/licenses/>. */ - -#include "libitm_i.h" - -#if ALLOW_UNMASKED_STORES -static uint32_t const bit_to_byte_mask[16] = -{ - 0x00000000, - 0x000000ff, - 0x0000ff00, - 0x0000ffff, - 0x00ff0000, - 0x00ff00ff, - 0x00ffff00, - 0x00ffffff, - 0xff000000, - 0xff0000ff, - 0xff00ff00, - 0xff00ffff, - 0xffff0000, - 0xffff00ff, - 0xffffff00, - 0xffffffff -}; - -static void __attribute__((always_inline)) -copy_mask_w (gtm_word * __restrict d, - const gtm_word * __restrict s, - gtm_cacheline_mask m) -{ - gtm_cacheline_mask tm = (1 << sizeof (gtm_word)) - 1; - - if (m & tm) - { - if ((m & tm) == tm) - *d = *s; - else - { - gtm_cacheline_mask bm; - - switch (sizeof (gtm_word)) - { - case 8: - bm = bit_to_byte_mask[(m >> 4) & 15]; - bm <<= 4 * sizeof (gtm_word); - bm |= bit_to_byte_mask[m & 15]; - break; - case 4: - bm = bit_to_byte_mask[m & 15]; - break; - default: - __builtin_trap (); - } - *d = (*d & ~bm) | (*s & bm); - } - } -} - -void -gtm_cacheline_copy_mask (gtm_cacheline * __restrict d, - const gtm_cacheline * __restrict s, - gtm_cacheline_mask m) -{ - const size_t n = sizeof (gtm_word); - size_t i; - - if (m == (gtm_cacheline_mask)-1) - { - gtm_cacheline_copy (d, s); - return; - } - if (__builtin_expect (m == 0), 0) - return; - - for (i = 0; i < CACHELINE_SIZE / n; ++i, m >>= n) - copy_mask_w (&d->w[i], &s->w[i], m); -} - -#else -static inline void __attribute__((always_inline)) -copy_mask_1 (gtm_cacheline * __restrict d, - const gtm_cacheline * __restrict s, - gtm_cacheline_mask m, size_t ofs, size_t idx) -{ - if (m & (1ul << ofs)) - d->b[idx] = s->b[idx]; -} - -static inline void __attribute__((always_inline)) -copy_mask_2 (gtm_cacheline * __restrict d, - const gtm_cacheline * __restrict s, - gtm_cacheline_mask m, size_t ofs, size_t idx) -{ - gtm_cacheline_mask tm = 3ul << ofs; - if (m & tm) - { - if ((m & tm) == tm) - d->u16[idx] = s->u16[idx]; - else - { - copy_mask_1 (d, s, m, ofs, idx*2); - copy_mask_1 (d, s, m, ofs + 1, idx*2 + 1); - } - } -} - -static inline void __attribute__((always_inline)) -copy_mask_4 (gtm_cacheline * __restrict d, - const gtm_cacheline * __restrict s, - gtm_cacheline_mask m, size_t ofs, size_t idx) -{ - gtm_cacheline_mask tm = 15ul << ofs; - if (m & tm) - { - if ((m & tm) == tm) - d->u32[idx] = s->u32[idx]; - else - { - copy_mask_2 (d, s, m, ofs, idx*2); - copy_mask_2 (d, s, m, ofs + 2, idx*2 + 1); - } - } -} - -static inline void __attribute__((always_inline)) -copy_mask_8 (gtm_cacheline * __restrict d, - const gtm_cacheline * __restrict s, - gtm_cacheline_mask m, size_t ofs, size_t idx) -{ - gtm_cacheline_mask tm = 0xfful << ofs; - if (m & tm) - { - if ((m & tm) == tm) - d->u64[idx] = s->u64[idx]; - else - { - copy_mask_4 (d, s, m, ofs, idx*2); - copy_mask_4 (d, s, m, ofs + 4, idx*2 + 1); - } - } -} - -void -gtm_cacheline_copy_mask (gtm_cacheline * __restrict d, - const gtm_cacheline * __restrict s, - gtm_cacheline_mask m) -{ - const size_t n = sizeof (gtm_word); - size_t i; - - if (m == (gtm_cacheline_mask)-1) - { - gtm_cacheline_copy (d, s); - return; - } - if (__builtin_expect (m == 0, 0)) - return; - - for (i = 0; i < CACHELINE_SIZE / n; ++i, m >>= n) - switch (n) - { - case 8: - copy_mask_8 (d, s, m, 0, i); - break; - case 4: - copy_mask_4 (d, s, m, 0, i); - break; - default: - __builtin_trap (); - } -} - -#endif /* ALLOW_UNMASKED_STORES */ diff --git a/libitm/eh_cpp.c b/libitm/eh_cpp.cc index bb6c71d9808..bd83f7295d8 100644 --- a/libitm/eh_cpp.c +++ b/libitm/eh_cpp.cc @@ -24,17 +24,23 @@ #include "libitm_i.h" +using namespace GTM; + /* Everything from libstdc++ is weak, to avoid requiring that library to be linked into plain C applications using libitm.so. */ #define WEAK __attribute__((weak)) +extern "C" { + extern void *__cxa_allocate_exception (size_t) WEAK; extern void __cxa_throw (void *, void *, void *) WEAK; extern void *__cxa_begin_catch (void *) WEAK; extern void *__cxa_end_catch (void) WEAK; extern void __cxa_tm_cleanup (void *, void *, unsigned int) WEAK; +} + void * _ITM_cxa_allocate_exception (size_t size) @@ -66,16 +72,14 @@ _ITM_cxa_end_catch (void) } void -GTM_revert_cpp_exceptions (void) +GTM::gtm_transaction::revert_cpp_exceptions (void) { - struct gtm_transaction *tx = gtm_tx(); - - if (tx->cxa_unthrown || tx->cxa_catch_count) + if (this->cxa_unthrown || this->cxa_catch_count) { - __cxa_tm_cleanup (tx->cxa_unthrown, tx->eh_in_flight, - tx->cxa_catch_count); - tx->cxa_catch_count = 0; - tx->cxa_unthrown = NULL; - tx->eh_in_flight = NULL; + __cxa_tm_cleanup (this->cxa_unthrown, this->eh_in_flight, + this->cxa_catch_count); + this->cxa_catch_count = 0; + this->cxa_unthrown = NULL; + this->eh_in_flight = NULL; } } diff --git a/libitm/libitm.h b/libitm/libitm.h index ac07a402b3b..b1e0bca1298 100644 --- a/libitm/libitm.h +++ b/libitm/libitm.h @@ -32,6 +32,9 @@ #include <stdbool.h> #include <stdint.h> +#ifdef __cplusplus +extern "C" { +#endif #ifdef __i386__ # define ITM_REGPARM __attribute__((regparm(2))) @@ -264,4 +267,21 @@ extern void _ITM_memsetW(void *, int, size_t) ITM_REGPARM; extern void _ITM_memsetWaR(void *, int, size_t) ITM_REGPARM; extern void _ITM_memsetWaW(void *, int, size_t) ITM_REGPARM; +// ??? These are not yet in the official spec; still work-in-progress. + +extern void *_ITM_getTMCloneOrIrrevokable (void *) ITM_REGPARM; +extern void *_ITM_getTMCloneSafe (void *) ITM_REGPARM; +extern void _ITM_registerTMCloneTable (void *, size_t); +extern void _ITM_deregisterTMCloneTable (void *); + +extern void *_ITM_cxa_allocate_exception (size_t); +extern void _ITM_cxa_throw (void *obj, void *tinfo, void *dest); +extern void *_ITM_cxa_begin_catch (void *exc_ptr); +extern void _ITM_cxa_end_catch (void); +extern void _ITM_commitTransactionEH(void *exc_ptr) ITM_REGPARM; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + #endif /* LIBITM_H */ diff --git a/libitm/libitm_i.h b/libitm/libitm_i.h index d7dcdec56ad..52b6a15c6f5 100644 --- a/libitm/libitm_i.h +++ b/libitm/libitm_i.h @@ -30,222 +30,113 @@ #define LIBITM_I_H 1 #include "libitm.h" - #include "config.h" -#include <assert.h> -#include <stdlib.h> -#include <string.h> +#include <cassert> +#include <cstdlib> +#include <cstring> #include <unwind.h> +#include <type_traits> #define UNUSED __attribute__((unused)) - -/* Control how gtm_copy_cacheline_mask operates. If set, we use byte masking - to update D, which *does* write to bytes not affected by the mask. It's - unclear if this optimization is correct. */ -#define ALLOW_UNMASKED_STORES 0 - +#define ALWAYS_INLINE __attribute__((always_inline)) #ifdef HAVE_ATTRIBUTE_VISIBILITY -# pragma GCC visibility push(hidden) -#endif - -#include "target.h" -#include "rwlock.h" -#include "aatree.h" - -/* A gtm_cacheline_mask stores a modified bit for every modified byte - in the cacheline with which it is associated. */ -#if CACHELINE_SIZE == 8 -typedef uint8_t gtm_cacheline_mask; -#elif CACHELINE_SIZE == 16 -typedef uint16_t gtm_cacheline_mask; -#elif CACHELINE_SIZE == 32 -typedef uint32_t gtm_cacheline_mask; -#elif CACHELINE_SIZE == 64 -typedef uint64_t gtm_cacheline_mask; +# define HIDDEN __attribute__((visibility("hidden"))) #else -#error "Unsupported cacheline size" +# define HIDDEN #endif -typedef unsigned int gtm_word __attribute__((mode (word))); - -/* A cacheline. The smallest unit with which locks are associated. */ -typedef union gtm_cacheline -{ - /* Byte access to the cacheline. */ - unsigned char b[CACHELINE_SIZE] __attribute__((aligned(CACHELINE_SIZE))); - - /* Larger sized access to the cacheline. */ - uint16_t u16[CACHELINE_SIZE / sizeof(uint16_t)]; - uint32_t u32[CACHELINE_SIZE / sizeof(uint32_t)]; - uint64_t u64[CACHELINE_SIZE / sizeof(uint64_t)]; - gtm_word w[CACHELINE_SIZE / sizeof(gtm_word)]; - -#if defined(__i386__) || defined(__x86_64__) - /* ??? The definitions of gtm_cacheline_copy{,_mask} require all three - of these types depending on the implementation, making it difficult - to hide these inside the target header file. */ -# ifdef __SSE__ - __m128 m128[CACHELINE_SIZE / sizeof(__m128)]; -# endif -# ifdef __SSE2__ - __m128i m128i[CACHELINE_SIZE / sizeof(__m128i)]; -# endif -# ifdef __AVX__ - __m256 m256[CACHELINE_SIZE / sizeof(__m256)]; -# endif -#endif -} gtm_cacheline; - -/* A "page" worth of saved cachelines plus modification masks. This - arrangement is intended to minimize the overhead of alignment. The - PAGE_SIZE defined by the target must be a constant for this to work, - which means that this definition may not be the same as the real - system page size. */ - -#define CACHELINES_PER_PAGE \ - ((PAGE_SIZE - sizeof(void *)) \ - / (CACHELINE_SIZE + sizeof(gtm_cacheline_mask))) +#define likely(X) __builtin_expect((X) != 0, 1) +#define unlikely(X) __builtin_expect((X), 0) -typedef struct gtm_cacheline_page -{ - gtm_cacheline lines[CACHELINES_PER_PAGE] __attribute__((aligned(PAGE_SIZE))); - gtm_cacheline_mask masks[CACHELINES_PER_PAGE]; - struct gtm_cacheline_page *prev; -} gtm_cacheline_page; - -static inline gtm_cacheline_page * -gtm_page_for_line (gtm_cacheline *c) -{ - return (gtm_cacheline_page *)((uintptr_t)c & -PAGE_SIZE); -} +namespace GTM HIDDEN { -static inline gtm_cacheline_mask * -gtm_mask_for_line (gtm_cacheline *c) -{ - gtm_cacheline_page *p = gtm_page_for_line (c); - size_t index = c - &p->lines[0]; - return &p->masks[index]; -} - -/* A read lock function locks a cacheline. PTR must be cacheline aligned. - The return value is the cacheline address (equal to PTR for a write-through - implementation, and something else for a write-back implementation). */ -typedef gtm_cacheline *(*gtm_read_lock_fn)(uintptr_t cacheline); - -/* A write lock function locks a cacheline. PTR must be cacheline aligned. - The return value is a pair of the cacheline address and a mask that must - be updated with the bytes that are subsequently modified. We hope that - the target implements small structure return efficiently so that this - comes back in a pair of registers. If not, we're not really worse off - than returning the second value via a second argument to the function. */ - -typedef struct gtm_cacheline_mask_pair -{ - gtm_cacheline *line; - gtm_cacheline_mask *mask; -} gtm_cacheline_mask_pair; - -typedef gtm_cacheline_mask_pair (*gtm_write_lock_fn)(uintptr_t cacheline); - -/* A versioned write lock on a cacheline. This must be wide enough to - store a pointer, and preferably wide enough to avoid overflowing the - version counter. Thus we use a "word", which should be 64-bits on - 64-bit systems even when their pointer size is forced smaller. */ -typedef gtm_word gtm_stmlock; - -/* This has to be the same size as gtm_stmlock, we just use this name - for documentation purposes. */ -typedef gtm_word gtm_version; - -/* The maximum value a version number can have. This is a consequence - of having the low bit of gtm_stmlock reserved for the owned bit. */ -#define GTM_VERSION_MAX (~(gtm_version)0 >> 1) - -/* A value that may be used to indicate "uninitialized" for a version. */ -#define GTM_VERSION_INVALID (~(gtm_version)0) - -/* This bit is set when the write lock is held. When set, the balance of - the bits in the lock is a pointer that references STM backend specific - data; it is up to the STM backend to determine if this thread holds the - lock. If this bit is clear, the balance of the bits are the last - version number committed to the cacheline. */ -static inline bool -gtm_stmlock_owned_p (gtm_stmlock lock) -{ - return lock & 1; -} +using namespace std; -static inline gtm_stmlock -gtm_stmlock_set_owned (void *data) -{ - return (gtm_stmlock)(uintptr_t)data | 1; -} +// A helper template for accessing an unsigned integral of SIZE bytes. +template<size_t SIZE> struct sized_integral { }; +template<> struct sized_integral<1> { typedef uint8_t type; }; +template<> struct sized_integral<2> { typedef uint16_t type; }; +template<> struct sized_integral<4> { typedef uint32_t type; }; +template<> struct sized_integral<8> { typedef uint64_t type; }; -static inline void * -gtm_stmlock_get_addr (gtm_stmlock lock) -{ - return (void *)((uintptr_t)lock & ~(uintptr_t)1); -} +typedef unsigned int gtm_word __attribute__((mode (word))); -static inline gtm_version -gtm_stmlock_get_version (gtm_stmlock lock) -{ - return lock >> 1; -} +// Locally defined protected allocation functions. +// +// To avoid dependency on libstdc++ new/delete, as well as to not +// interfere with the wrapping of the global new/delete we wrap for +// the user in alloc_cpp.cc, use class-local versions that defer +// to malloc/free. Recall that operator new/delete does not go through +// normal lookup and so we cannot simply inject a version into the +// GTM namespace. -static inline gtm_stmlock -gtm_stmlock_set_version (gtm_version ver) -{ - return ver << 1; -} +extern void * xmalloc (size_t s) __attribute__((malloc, nothrow)); +extern void * xrealloc (void *p, size_t s) __attribute__((malloc, nothrow)); -/* We use a fixed set of locks for all memory, hashed into the - following table. */ -#define LOCK_ARRAY_SIZE (1024 * 1024) -extern gtm_stmlock gtm_stmlock_array[LOCK_ARRAY_SIZE]; +} // namespace GTM -static inline gtm_stmlock * -gtm_get_stmlock (uintptr_t addr) -{ - size_t idx = (addr / CACHELINE_SIZE) % LOCK_ARRAY_SIZE; - return gtm_stmlock_array + idx; -} +#include "target.h" +#include "rwlock.h" +#include "aatree.h" +#include "cacheline.h" +#include "cachepage.h" +#include "stmlock.h" -/* The current global version number. */ -extern gtm_version gtm_clock; +namespace GTM HIDDEN { -/* A dispatch table parameterizes the implementation of the STM. */ -typedef struct gtm_dispatch +// A dispatch table parameterizes the implementation of the STM. +struct gtm_dispatch { - gtm_read_lock_fn R; - gtm_read_lock_fn RaR; - gtm_read_lock_fn RaW; - gtm_read_lock_fn RfW; - - gtm_write_lock_fn W; - gtm_write_lock_fn WaR; - gtm_write_lock_fn WaW; - - bool (*trycommit) (void); - void (*rollback) (void); - void (*init) (bool); - void (*fini) (void); - - bool write_through; -} gtm_dispatch; - - -/* These values define a mask used in gtm_transaction.state. */ -#define STATE_READONLY 0x0001 -#define STATE_SERIAL 0x0002 -#define STATE_IRREVOKABLE 0x0004 -#define STATE_ABORTING 0x0008 - -/* These values are given to GTM_restart_transaction and indicate the - reason for the restart. The reason is used to decide what STM - implementation should be used during the next iteration. */ -typedef enum gtm_restart_reason + public: + enum lock_type { NOLOCK, R, RaR, RaW, RfW, W, WaR, WaW }; + + struct mask_pair + { + gtm_cacheline *line; + gtm_cacheline_mask *mask; + + mask_pair() = default; + mask_pair(gtm_cacheline *l, gtm_cacheline_mask *m) : line(l), mask(m) { } + }; + + private: + // Disallow copies + gtm_dispatch(const gtm_dispatch &) = delete; + gtm_dispatch& operator=(const gtm_dispatch &) = delete; + + public: + // The default version of these is pass-through. This merely gives the + // a single location to instantiate the base class vtable. + virtual const gtm_cacheline *read_lock(const gtm_cacheline *, lock_type); + virtual mask_pair write_lock(gtm_cacheline *, lock_type); + + virtual bool trycommit() = 0; + virtual void rollback() = 0; + virtual void reinit() = 0; + + // Use fini instead of dtor to support a static subclasses that uses + // a unique object and so we don't want to destroy it from common code. + virtual void fini() = 0; + + bool read_only () const { return m_read_only; } + bool write_through() const { return m_write_through; } + + static void *operator new(size_t s) { return xmalloc (s); } + static void operator delete(void *p) { free (p); } + + protected: + const bool m_read_only; + const bool m_write_through; + gtm_dispatch(bool ro, bool wt) : m_read_only(ro), m_write_through(wt) { } + + static gtm_cacheline_mask mask_sink; +}; + +// These values are given to GTM_restart_transaction and indicate the +// reason for the restart. The reason is used to decide what STM +// implementation should be used during the next iteration. +enum gtm_restart_reason { RESTART_REALLOCATE, RESTART_LOCKED_READ, @@ -253,220 +144,140 @@ typedef enum gtm_restart_reason RESTART_VALIDATE_READ, RESTART_VALIDATE_WRITE, RESTART_VALIDATE_COMMIT, + RESTART_SERIAL_IRR, RESTART_NOT_READONLY, NUM_RESTARTS -} gtm_restart_reason; +}; +// This type is private to alloc.c. +struct gtm_alloc_action; -/* This type is private to local.c. */ +// This type is private to local.c. struct gtm_local_undo; -/* This type is private to useraction.c. */ +// This type is private to useraction.c. struct gtm_user_action; -/* This type is private to the STM implementation. */ -struct gtm_method; - - -/* All data relevant to a single transaction. */ -typedef struct gtm_transaction +// All data relevant to a single transaction. +struct gtm_transaction { - /* The jump buffer by which GTM_longjmp restarts the transaction. - This field *must* be at the beginning of the transaction. */ + // The jump buffer by which GTM_longjmp restarts the transaction. + // This field *must* be at the beginning of the transaction. gtm_jmpbuf jb; - /* Data used by local.c for the local memory undo log. */ + // Data used by local.c for the local memory undo log. struct gtm_local_undo **local_undo; size_t n_local_undo; size_t size_local_undo; - /* Data used by alloc.c for the malloc/free undo log. */ - aa_tree alloc_actions; + // Data used by alloc.c for the malloc/free undo log. + aa_tree<uintptr_t, gtm_alloc_action> alloc_actions; - /* Data used by useraction.c for the user defined undo log. */ + // Data used by useraction.c for the user defined undo log. struct gtm_user_action *commit_actions; struct gtm_user_action *undo_actions; - /* Data used by the STM implementation. */ - struct gtm_method *m; - - /* A pointer to the "outer" transaction. */ + // A pointer to the "outer" transaction. struct gtm_transaction *prev; - /* A numerical identifier for this transaction. */ + // A numerical identifier for this transaction. _ITM_transactionId_t id; - /* The _ITM_codeProperties of this transaction as given by the compiler. */ + // The _ITM_codeProperties of this transaction as given by the compiler. uint32_t prop; - /* The nesting depth of this transaction. */ + // The nesting depth of this transaction. uint32_t nesting; - /* A mask of bits indicating the current status of the transaction. */ + // Set if this transaction owns the serial write lock. + static const uint32_t STATE_SERIAL = 0x0001; + // Set if the serial-irrevocable dispatch table is installed. + // Implies that no logging is being done, and abort is not possible. + static const uint32_t STATE_IRREVOCABLE = 0x0002; + // Set if we're in the process of aborting the transaction. This is + // used when _ITM_rollbackTransaction is called to begin the abort + // and ends with _ITM_commitTransaction. + static const uint32_t STATE_ABORTING = 0x0004; + + // A bitmask of the above. uint32_t state; - /* Data used by eh_cpp.c for managing exceptions within the transaction. */ + // Data used by eh_cpp.c for managing exceptions within the transaction. uint32_t cxa_catch_count; void *cxa_unthrown; void *eh_in_flight; - /* Data used by retry.c for deciding what STM implementation should - be used for the next iteration of the transaction. */ + // Data used by retry.c for deciding what STM implementation should + // be used for the next iteration of the transaction. uint32_t restart_reason[NUM_RESTARTS]; uint32_t restart_total; -} gtm_transaction; -/* The maximum number of free gtm_transaction structs to be kept. - This number must be greater than 1 in order for transaction abort - to be handled properly. */ -#define MAX_FREE_TX 8 + // The lock that provides access to serial mode. Non-serialized + // transactions acquire read locks; a serialized transaction aquires + // a write lock. + static gtm_rwlock serial_lock; -/* All thread-local data required by the entire library. */ -typedef struct gtm_thread -{ -#ifndef HAVE_ARCH_GTM_THREAD_TX - /* The currently active transaction. Elided if the target provides - some efficient mechanism for storing this. */ - gtm_transaction *tx; -#endif -#ifndef HAVE_ARCH_GTM_THREAD_DISP - /* The dispatch table for the STM implementation currently in use. Elided - if the target provides some efficient mechanism for storing this. */ - const gtm_dispatch *disp; -#endif + // In alloc.cc + void commit_allocations (bool); + void record_allocation (void *, size_t, void (*)(void *)); + void forget_allocation (void *, void (*)(void *)); + size_t get_allocation_size (void *); - /* A queue of free gtm_transaction structs. */ - gtm_transaction *free_tx[MAX_FREE_TX]; - unsigned free_tx_idx, free_tx_count; - - /* The value returned by _ITM_getThreadnum to identify this thread. */ - /* ??? At present, this is densely allocated beginning with 1 and - we don't bother filling in this value until it is requested. - Which means that the value returned is, as far as the user is - concerned, essentially arbitrary. We wouldn't need this at all - if we knew that pthread_t is integral and fits into an int. */ - /* ??? Consider using gettid on Linux w/ NPTL. At least that would - be a value meaningful to the user. */ - int thread_num; -} gtm_thread; - -/* Don't access this variable directly; use the functions below. */ -extern __thread gtm_thread _gtm_thr; - -#include "target_i.h" - -#ifndef HAVE_ARCH_GTM_THREAD -/* If the target does not provide optimized access to the thread-local - data, simply access the TLS variable defined above. */ -static inline void setup_gtm_thr(void) { } -static inline gtm_thread *gtm_thr(void) { return &_gtm_thr; } -#endif + // In beginend.cc + void rollback (); + bool trycommit (); + bool trycommit_and_finalize (); + void restart (gtm_restart_reason) ITM_NORETURN; -#ifndef HAVE_ARCH_GTM_THREAD_TX -/* If the target does not provide optimized access to the currently - active transaction, simply access via GTM_THR. */ -static inline gtm_transaction * gtm_tx(void) { return gtm_thr()->tx; } -static inline void set_gtm_tx(gtm_transaction *x) { gtm_thr()->tx = x; } -#endif + // Invoked from assembly language, thus the "asm" specifier on + // the name, avoiding complex name mangling. + static uint32_t begin_transaction(uint32_t, const gtm_jmpbuf *) + __asm__("GTM_begin_transaction"); -#ifndef HAVE_ARCH_GTM_THREAD_DISP -/* If the target does not provide optimized access to the currently - active dispatch table, simply access via GTM_THR. */ -static inline const gtm_dispatch * gtm_disp(void) { return gtm_thr()->disp; } -static inline void set_gtm_disp(const gtm_dispatch *x) { gtm_thr()->disp = x; } -#endif + // In eh_cpp.cc + void revert_cpp_exceptions (); -#ifndef HAVE_ARCH_GTM_CACHELINE_COPY -/* Copy S to D, with S and D both aligned no overlap. */ -static inline void -gtm_cacheline_copy (gtm_cacheline * __restrict d, - const gtm_cacheline * __restrict s) -{ - *d = *s; -} -#endif + // In local.cc + void commit_local (void); + void rollback_local (void); -/* Similarly, but only modify bytes with bits set in M. */ -extern void gtm_cacheline_copy_mask (gtm_cacheline * __restrict d, - const gtm_cacheline * __restrict s, - gtm_cacheline_mask m); + // In retry.cc + void decide_retry_strategy (gtm_restart_reason); -#ifndef HAVE_ARCH_GTM_CCM_WRITE_BARRIER -/* A write barrier to emit after gtm_copy_cacheline_mask. */ -static inline void -gtm_ccm_write_barrier (void) -{ - atomic_write_barrier (); -} -#endif + // In serial.cc + void serialirr_mode (); -/* The lock that provides access to serial mode. Non-serialized transactions - acquire read locks; the serialized transaction aquires a write lock. */ -extern gtm_rwlock gtm_serial_lock; + // In useraction.cc + static void run_actions (struct gtm_user_action **); + static void free_actions (struct gtm_user_action **); +}; -/* An unscaled count of the number of times we should spin attempting to - acquire locks before we block the current thread and defer to the OS. - This variable isn't used when the standard POSIX lock implementations - are used. */ -extern uint64_t gtm_spin_count_var; +} // namespace GTM -extern uint32_t GTM_begin_transaction(uint32_t, const gtm_jmpbuf *); -extern uint32_t GTM_longjmp (const gtm_jmpbuf *, uint32_t, uint32_t) - ITM_NORETURN; +#include "tls.h" -extern void GTM_commit_local (void); -extern void GTM_rollback_local (void); -extern void GTM_LB (const void *, size_t) ITM_REGPARM; +namespace GTM HIDDEN { -extern void GTM_serialmode (bool, bool); -extern void GTM_decide_retry_strategy (gtm_restart_reason); -extern void GTM_restart_transaction (gtm_restart_reason) ITM_NORETURN; - -extern void GTM_run_actions (struct gtm_user_action **); -extern void GTM_free_actions (struct gtm_user_action **); - -extern void GTM_record_allocation (void *, size_t, void (*)(void *)); -extern void GTM_forget_allocation (void *, void (*)(void *)); -extern size_t GTM_get_allocation_size (void *); -extern void GTM_commit_allocations (bool); - -extern void GTM_revert_cpp_exceptions (void); - -extern gtm_cacheline_page *GTM_page_alloc (void); -extern void GTM_page_release (gtm_cacheline_page *, gtm_cacheline_page *); - -extern gtm_cacheline *GTM_null_read_lock (uintptr_t); -extern gtm_cacheline_mask_pair GTM_null_write_lock (uintptr_t); - -static inline gtm_version -gtm_get_clock (void) -{ - gtm_version r; - - __sync_synchronize (); - r = gtm_clock; - atomic_read_barrier (); - - return r; -} +// An unscaled count of the number of times we should spin attempting to +// acquire locks before we block the current thread and defer to the OS. +// This variable isn't used when the standard POSIX lock implementations +// are used. +extern uint64_t gtm_spin_count_var; -static inline gtm_version -gtm_inc_clock (void) -{ - gtm_version r = __sync_add_and_fetch (>m_clock, 1); +extern "C" uint32_t GTM_longjmp (const gtm_jmpbuf *, uint32_t, uint32_t) + ITM_NORETURN; - /* ??? Ought to handle wraparound for 32-bit. */ - if (sizeof(r) < 8 && r > GTM_VERSION_MAX) - abort (); +extern "C" void GTM_LB (const void *, size_t) ITM_REGPARM; - return r; -} +extern void GTM_error (const char *fmt, ...) + __attribute__((format (printf, 1, 2))); +extern void GTM_fatal (const char *fmt, ...) + __attribute__((noreturn, format (printf, 1, 2))); -extern const gtm_dispatch dispatch_wbetl; -extern const gtm_dispatch dispatch_readonly; +extern gtm_dispatch *dispatch_wbetl(); +extern gtm_dispatch *dispatch_readonly(); +extern gtm_dispatch *dispatch_serial(); -#ifdef HAVE_ATTRIBUTE_VISIBILITY -# pragma GCC visibility pop -#endif +} // namespace GTM -#endif /* LIBITM_I_H */ +#endif // LIBITM_I_H diff --git a/libitm/local.c b/libitm/local.cc index 17358ad44ae..31c35222519 100644 --- a/libitm/local.c +++ b/libitm/local.cc @@ -24,42 +24,41 @@ #include "libitm_i.h" +namespace GTM HIDDEN { -typedef struct gtm_local_undo +struct gtm_local_undo { void *addr; size_t len; char saved[]; -} gtm_local_undo; +}; void -GTM_commit_local (void) +gtm_transaction::commit_local () { - gtm_transaction *tx = gtm_tx(); - gtm_local_undo **local_undo = tx->local_undo; - size_t i, n = tx->n_local_undo; + gtm_local_undo **local_undo = this->local_undo; + size_t i, n = this->n_local_undo; if (n > 0) { for (i = 0; i < n; ++i) free (local_undo[i]); - tx->n_local_undo = 0; + this->n_local_undo = 0; } if (local_undo) { free (local_undo); - tx->local_undo = NULL; - tx->size_local_undo = 0; + this->local_undo = NULL; + this->size_local_undo = 0; } } void -GTM_rollback_local (void) +gtm_transaction::rollback_local (void) { - gtm_transaction *tx = gtm_tx(); - gtm_local_undo **local_undo = tx->local_undo; - size_t i, n = tx->n_local_undo; + gtm_local_undo **local_undo = this->local_undo; + size_t i, n = this->n_local_undo; if (n > 0) { @@ -69,7 +68,7 @@ GTM_rollback_local (void) memcpy (u->addr, u->saved, u->len); free (u); } - tx->n_local_undo = 0; + this->n_local_undo = 0; } } @@ -79,26 +78,31 @@ GTM_LB (const void *ptr, size_t len) gtm_transaction *tx = gtm_tx(); gtm_local_undo *undo; - undo = malloc (sizeof (struct gtm_local_undo) + len); + undo = (gtm_local_undo *) xmalloc (sizeof (struct gtm_local_undo) + len); undo->addr = (void *) ptr; undo->len = len; if (tx->local_undo == NULL) { tx->size_local_undo = 32; - tx->local_undo = malloc (sizeof (undo) * tx->size_local_undo); + tx->local_undo = (gtm_local_undo **) + xmalloc (sizeof (undo) * tx->size_local_undo); } else if (tx->n_local_undo == tx->size_local_undo) { tx->size_local_undo *= 2; - tx->local_undo = realloc (tx->local_undo, - sizeof (undo) * tx->size_local_undo); + tx->local_undo = (gtm_local_undo **) + xrealloc (tx->local_undo, sizeof (undo) * tx->size_local_undo); } tx->local_undo[tx->n_local_undo++] = undo; memcpy (undo->saved, ptr, len); } +} // namespace GTM + +using namespace GTM; + void _ITM_LB (const void *ptr, size_t len) ITM_REGPARM __attribute__((alias("GTM_LB"))); diff --git a/libitm/memcpy.c b/libitm/memcpy.cc index cf01371b21b..672af98fb16 100644 --- a/libitm/memcpy.c +++ b/libitm/memcpy.cc @@ -24,22 +24,25 @@ #include "libitm_i.h" +using namespace GTM; static void -do_memcpy (uintptr_t dst, uintptr_t src, size_t size, - gtm_write_lock_fn W, gtm_read_lock_fn R) +do_memcpy (uintptr_t idst, uintptr_t isrc, size_t size, + gtm_dispatch::lock_type W, gtm_dispatch::lock_type R) { - uintptr_t dofs = dst & (CACHELINE_SIZE - 1); - uintptr_t sofs = src & (CACHELINE_SIZE - 1); - gtm_cacheline *sline; - gtm_cacheline_mask_pair dpair; + gtm_dispatch *disp = gtm_disp(); + uintptr_t dofs = idst & (CACHELINE_SIZE - 1); + uintptr_t sofs = isrc & (CACHELINE_SIZE - 1); + const gtm_cacheline *src + = reinterpret_cast<const gtm_cacheline *>(isrc & -CACHELINE_SIZE); + gtm_cacheline *dst + = reinterpret_cast<gtm_cacheline *>(idst & -CACHELINE_SIZE); + const gtm_cacheline *sline; + gtm_dispatch::mask_pair dpair; if (size == 0) return; - dst &= -CACHELINE_SIZE; - src &= -CACHELINE_SIZE; - if (dofs == sofs) { if (sofs != 0) @@ -47,30 +50,30 @@ do_memcpy (uintptr_t dst, uintptr_t src, size_t size, size_t sleft = CACHELINE_SIZE - sofs; size_t min = (size <= sleft ? size : sleft); - dpair = W(dst); - sline = R(src); + dpair = disp->write_lock(dst, W); + sline = disp->read_lock(src, R); *dpair.mask |= (((gtm_cacheline_mask)1 << min) - 1) << sofs; memcpy (&dpair.line->b[sofs], &sline->b[sofs], min); - dst += CACHELINE_SIZE; - src += CACHELINE_SIZE; + dst++; + src++; size -= min; } while (size >= CACHELINE_SIZE) { - dpair = W(dst); - sline = R(src); + dpair = disp->write_lock(dst, W); + sline = disp->read_lock(src, R); *dpair.mask = -1; - gtm_cacheline_copy (dpair.line, sline); - dst += CACHELINE_SIZE; - src += CACHELINE_SIZE; + *dpair.line = *sline; + dst++; + src++; size -= CACHELINE_SIZE; } if (size != 0) { - dpair = W(dst); - sline = R(src); + dpair = disp->write_lock(dst, W); + sline = disp->read_lock(src, R); *dpair.mask |= ((gtm_cacheline_mask)1 << size) - 1; memcpy (dpair.line, sline, size); } @@ -80,13 +83,13 @@ do_memcpy (uintptr_t dst, uintptr_t src, size_t size, gtm_cacheline c; size_t sleft = CACHELINE_SIZE - sofs; - sline = R(src); + sline = disp->read_lock(src, R); if (dofs != 0) { size_t dleft = CACHELINE_SIZE - dofs; size_t min = (size <= dleft ? size : dleft); - dpair = W(dst); + dpair = disp->write_lock(dst, W); *dpair.mask |= (((gtm_cacheline_mask)1 << min) - 1) << dofs; if (min <= sleft) { @@ -96,44 +99,41 @@ do_memcpy (uintptr_t dst, uintptr_t src, size_t size, else { memcpy (&c, &sline->b[sofs], sleft); - src += CACHELINE_SIZE; - sline = R(src); + sline = disp->read_lock(++src, R); sofs = min - sleft; memcpy (&c.b[sleft], sline, sofs); memcpy (&dpair.line->b[dofs], &c, min); } sleft = CACHELINE_SIZE - sofs; - dst += CACHELINE_SIZE; + dst++; size -= min; } while (size >= CACHELINE_SIZE) { memcpy (&c, &sline->b[sofs], sleft); - src += CACHELINE_SIZE; - sline = R(src); + sline = disp->read_lock(++src, R); memcpy (&c.b[sleft], sline, sofs); - dpair = W(dst); + dpair = disp->write_lock(dst, W); *dpair.mask = -1; - gtm_cacheline_copy (dpair.line, &c); + *dpair.line = c; - dst += CACHELINE_SIZE; + dst++; size -= CACHELINE_SIZE; } if (size != 0) { - dpair = W(dst); + dpair = disp->write_lock(dst, W); *dpair.mask |= ((gtm_cacheline_mask)1 << size) - 1; if (size <= sleft) memcpy (dpair.line, &sline->b[sofs], size); else { memcpy (&c, &sline->b[sofs], sleft); - src += CACHELINE_SIZE; - sline = R(src); + sline = disp->read_lock(++src, R); memcpy (&c.b[sleft], sline, size - sleft); memcpy (dpair.line, &c, size); } @@ -142,12 +142,13 @@ do_memcpy (uintptr_t dst, uintptr_t src, size_t size, } static void -do_memmove (uintptr_t dst, uintptr_t src, size_t size, - gtm_write_lock_fn W, gtm_read_lock_fn R) +do_memmove (uintptr_t idst, uintptr_t isrc, size_t size, + gtm_dispatch::lock_type W, gtm_dispatch::lock_type R) { + gtm_dispatch *disp = gtm_disp(); uintptr_t dleft, sleft, sofs, dofs; - gtm_cacheline *sline; - gtm_cacheline_mask_pair dpair; + const gtm_cacheline *sline; + gtm_dispatch::mask_pair dpair; if (size == 0) return; @@ -156,46 +157,47 @@ do_memmove (uintptr_t dst, uintptr_t src, size_t size, that out. It's tempting to just return here, as this is a no-op move. However, our caller has the right to expect the locks to be acquired as advertized. */ - if (__builtin_expect (dst == src, 0)) + if (__builtin_expect (idst == isrc, 0)) { - const gtm_dispatch *disp = gtm_disp(); - /* If the write lock is already acquired, nothing to do. */ - if (W == disp->WaW) + if (W == gtm_dispatch::WaW) return; /* If the destination is protected, acquire a write lock. */ - if (W != GTM_null_write_lock) - R = disp->RfW; + if (W != gtm_dispatch::NOLOCK) + R = gtm_dispatch::RfW; /* Notice serial mode, where we don't acquire locks at all. */ - if (R == GTM_null_read_lock) + if (R == gtm_dispatch::NOLOCK) return; - dst = src + size; - for (src &= -CACHELINE_SIZE; src < dst; src += CACHELINE_SIZE) - R(src); + idst = isrc + size; + for (isrc &= -CACHELINE_SIZE; isrc < idst; isrc += CACHELINE_SIZE) + disp->read_lock(reinterpret_cast<const gtm_cacheline *>(isrc), R); return; } /* Fall back to memcpy if the implementation above can handle it. */ - if (dst < src || src + size <= dst) + if (idst < isrc || isrc + size <= idst) { - do_memcpy (dst, src, size, W, R); + do_memcpy (idst, isrc, size, W, R); return; } /* What remains requires a backward copy from the end of the blocks. */ - dst += size; - src += size; - dofs = dst & (CACHELINE_SIZE - 1); - sofs = src & (CACHELINE_SIZE - 1); + idst += size; + isrc += size; + dofs = idst & (CACHELINE_SIZE - 1); + sofs = isrc & (CACHELINE_SIZE - 1); dleft = CACHELINE_SIZE - dofs; sleft = CACHELINE_SIZE - sofs; - dst &= -CACHELINE_SIZE; - src &= -CACHELINE_SIZE; + + gtm_cacheline *dst + = reinterpret_cast<gtm_cacheline *>(idst & -CACHELINE_SIZE); + const gtm_cacheline *src + = reinterpret_cast<const gtm_cacheline *>(isrc & -CACHELINE_SIZE); if (dofs == 0) - dst -= CACHELINE_SIZE; + dst--; if (sofs == 0) - src -= CACHELINE_SIZE; + src--; if (dofs == sofs) { @@ -203,31 +205,31 @@ do_memmove (uintptr_t dst, uintptr_t src, size_t size, optimization above, that implies that SIZE > CACHELINE_SIZE. */ if (sofs != 0) { - dpair = W(dst); - sline = R(src); + dpair = disp->write_lock(dst, W); + sline = disp->read_lock(src, R); *dpair.mask |= ((gtm_cacheline_mask)1 << sleft) - 1; memcpy (dpair.line, sline, sleft); - dst -= CACHELINE_SIZE; - src -= CACHELINE_SIZE; + dst--; + src--; size -= sleft; } while (size >= CACHELINE_SIZE) { - dpair = W(dst); - sline = R(src); + dpair = disp->write_lock(dst, W); + sline = disp->read_lock(src, R); *dpair.mask = -1; - gtm_cacheline_copy (dpair.line, sline); - dst -= CACHELINE_SIZE; - src -= CACHELINE_SIZE; + *dpair.line = *sline; + dst--; + src--; size -= CACHELINE_SIZE; } if (size != 0) { size_t ofs = CACHELINE_SIZE - size; - dpair = W(dst); - sline = R(src); + dpair = disp->write_lock(dst, W); + sline = disp->read_lock(src, R); *dpair.mask |= (((gtm_cacheline_mask)1 << size) - 1) << ofs; memcpy (&dpair.line->b[ofs], &sline->b[ofs], size); } @@ -236,7 +238,7 @@ do_memmove (uintptr_t dst, uintptr_t src, size_t size, { gtm_cacheline c; - sline = R(src); + sline = disp->read_lock(src, R); if (dofs != 0) { size_t min = (size <= dofs ? size : dofs); @@ -250,34 +252,32 @@ do_memmove (uintptr_t dst, uintptr_t src, size_t size, { size_t min_ofs = min - sofs; memcpy (&c.b[min_ofs], sline, sofs); - src -= CACHELINE_SIZE; - sline = R(src); + sline = disp->read_lock(--src, R); sofs = CACHELINE_SIZE - min_ofs; memcpy (&c, &sline->b[sofs], min_ofs); } dofs = dleft - min; - dpair = W(dst); + dpair = disp->write_lock(dst, W); *dpair.mask |= (((gtm_cacheline_mask)1 << min) - 1) << dofs; memcpy (&dpair.line->b[dofs], &c, min); sleft = CACHELINE_SIZE - sofs; - dst -= CACHELINE_SIZE; + dst--; size -= min; } while (size >= CACHELINE_SIZE) { memcpy (&c.b[sleft], sline, sofs); - src -= CACHELINE_SIZE; - sline = R(src); + sline = disp->read_lock(--src, R); memcpy (&c, &sline->b[sofs], sleft); - dpair = W(dst); + dpair = disp->write_lock(dst, W); *dpair.mask = -1; - gtm_cacheline_copy (dpair.line, &c); + *dpair.line = c; - dst -= CACHELINE_SIZE; + dst--; size -= CACHELINE_SIZE; } @@ -288,12 +288,11 @@ do_memmove (uintptr_t dst, uintptr_t src, size_t size, memcpy (&c.b[sleft], sline, sofs); if (sleft > dofs) { - src -= CACHELINE_SIZE; - sline = R(src); + sline = disp->read_lock(--src, R); memcpy (&c, &sline->b[sofs], sleft); } - dpair = W(dst); + dpair = disp->write_lock(dst, W); *dpair.mask |= (gtm_cacheline_mask)-1 << dofs; memcpy (&dpair.line->b[dofs], &c.b[dofs], size); } @@ -303,30 +302,30 @@ do_memmove (uintptr_t dst, uintptr_t src, size_t size, #define ITM_MEM_DEF(NAME, READ, WRITE) \ void ITM_REGPARM _ITM_memcpy##NAME(void *dst, const void *src, size_t size) \ { \ - const gtm_dispatch *disp = gtm_disp(); \ - do_memcpy ((uintptr_t)dst, (uintptr_t)src, size, WRITE, READ); \ + do_memcpy ((uintptr_t)dst, (uintptr_t)src, size, \ + gtm_dispatch::WRITE, gtm_dispatch::READ); \ } \ void ITM_REGPARM _ITM_memmove##NAME(void *dst, const void *src, size_t size) \ { \ - const gtm_dispatch *disp = gtm_disp(); \ - do_memmove ((uintptr_t)dst, (uintptr_t)src, size, WRITE, READ); \ + do_memmove ((uintptr_t)dst, (uintptr_t)src, size, \ + gtm_dispatch::WRITE, gtm_dispatch::READ); \ } -ITM_MEM_DEF(RnWt, GTM_null_read_lock, disp->W) -ITM_MEM_DEF(RnWtaR, GTM_null_read_lock, disp->WaR) -ITM_MEM_DEF(RnWtaW, GTM_null_read_lock, disp->WaW) +ITM_MEM_DEF(RnWt, NOLOCK, W) +ITM_MEM_DEF(RnWtaR, NOLOCK, WaR) +ITM_MEM_DEF(RnWtaW, NOLOCK, WaW) -ITM_MEM_DEF(RtWn, disp->R, GTM_null_write_lock) -ITM_MEM_DEF(RtWt, disp->R, disp->W) -ITM_MEM_DEF(RtWtaR, disp->R, disp->WaR) -ITM_MEM_DEF(RtWtaW, disp->R, disp->WaW) +ITM_MEM_DEF(RtWn, R, NOLOCK) +ITM_MEM_DEF(RtWt, R, W) +ITM_MEM_DEF(RtWtaR, R, WaR) +ITM_MEM_DEF(RtWtaW, R, WaW) -ITM_MEM_DEF(RtaRWn, disp->RaR, GTM_null_write_lock) -ITM_MEM_DEF(RtaRWt, disp->RaR, disp->W) -ITM_MEM_DEF(RtaRWtaR, disp->RaR, disp->WaR) -ITM_MEM_DEF(RtaRWtaW, disp->RaR, disp->WaW) +ITM_MEM_DEF(RtaRWn, RaR, NOLOCK) +ITM_MEM_DEF(RtaRWt, RaR, W) +ITM_MEM_DEF(RtaRWtaR, RaR, WaR) +ITM_MEM_DEF(RtaRWtaW, RaR, WaW) -ITM_MEM_DEF(RtaWWn, disp->RaW, GTM_null_write_lock) -ITM_MEM_DEF(RtaWWt, disp->RaW, disp->W) -ITM_MEM_DEF(RtaWWtaR, disp->RaW, disp->WaR) -ITM_MEM_DEF(RtaWWtaW, disp->RaW, disp->WaW) +ITM_MEM_DEF(RtaWWn, RaW, NOLOCK) +ITM_MEM_DEF(RtaWWt, RaW, W) +ITM_MEM_DEF(RtaWWtaR, RaW, WaR) +ITM_MEM_DEF(RtaWWtaW, RaW, WaW) diff --git a/libitm/memset.c b/libitm/memset.cc index d4a9fc63b14..d77b6264e21 100644 --- a/libitm/memset.c +++ b/libitm/memset.cc @@ -24,42 +24,44 @@ #include "libitm_i.h" +using namespace GTM; static void -do_memset(uintptr_t dst, int c, size_t size, gtm_write_lock_fn W) +do_memset(uintptr_t idst, int c, size_t size, gtm_dispatch::lock_type W) { - uintptr_t dofs = dst & (CACHELINE_SIZE - 1); - gtm_cacheline_mask_pair dpair; + gtm_dispatch *disp = gtm_disp(); + uintptr_t dofs = idst & (CACHELINE_SIZE - 1); + gtm_dispatch::mask_pair dpair; + gtm_cacheline *dst + = reinterpret_cast<gtm_cacheline *>(idst & -CACHELINE_SIZE); if (size == 0) return; - dst &= -CACHELINE_SIZE; - if (dofs != 0) { size_t dleft = CACHELINE_SIZE - dofs; size_t min = (size <= dleft ? size : dleft); - dpair = W(dst); + dpair = disp->write_lock(dst, W); *dpair.mask |= (((gtm_cacheline_mask)1 << min) - 1) << dofs; memset (&dpair.line->b[dofs], c, min); - dst += CACHELINE_SIZE; + dst++; size -= min; } while (size >= CACHELINE_SIZE) { - dpair = W(dst); + dpair = disp->write_lock(dst, W); *dpair.mask = -1; memset (dpair.line, c, CACHELINE_SIZE); - dst += CACHELINE_SIZE; + dst++; size -= CACHELINE_SIZE; } if (size != 0) { - dpair = W(dst); + dpair = disp->write_lock(dst, W); *dpair.mask |= ((gtm_cacheline_mask)1 << size) - 1; memset (dpair.line, c, size); } @@ -67,10 +69,7 @@ do_memset(uintptr_t dst, int c, size_t size, gtm_write_lock_fn W) #define ITM_MEM_DEF(WRITE) \ void ITM_REGPARM _ITM_memset##WRITE(void *dst, int c, size_t size) \ -{ \ - const gtm_dispatch *disp = gtm_disp(); \ - do_memset ((uintptr_t)dst, c, size, disp->WRITE); \ -} +{ do_memset ((uintptr_t)dst, c, size, gtm_dispatch::WRITE); } ITM_MEM_DEF(W) ITM_MEM_DEF(WaR) diff --git a/libitm/method-readonly.c b/libitm/method-readonly.c deleted file mode 100644 index 611bc8fc1ec..00000000000 --- a/libitm/method-readonly.c +++ /dev/null @@ -1,115 +0,0 @@ -/* Copyright (C) 2009 Free Software Foundation, Inc. - Contributed by Richard Henderson <rth@redhat.com>. - - This file is part of the GNU Transactional Memory Library (libitm). - - Libitm is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - Libitm is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - <http://www.gnu.org/licenses/>. */ - -#include "libitm_i.h" - -struct gtm_method -{ - gtm_version start; -}; - -/* Acquire a read lock on ADDR. */ - -static gtm_cacheline * -readonly_R (uintptr_t addr) -{ - return (gtm_cacheline *) addr; -} - -static gtm_cacheline * -readonly_RaW (uintptr_t addr) -{ - abort (); -} - -static gtm_cacheline * -readonly_RfW (uintptr_t addr) -{ - GTM_restart_transaction (RESTART_NOT_READONLY); -} - -static gtm_cacheline_mask_pair -readonly_W (uintptr_t addr) -{ - GTM_restart_transaction (RESTART_NOT_READONLY); -} - -static gtm_cacheline_mask_pair -readonly_WaW (uintptr_t addr) -{ - abort (); -} - -/* Commit the transaction. */ - -static bool -readonly_trycommit (void) -{ - struct gtm_method *m = gtm_tx()->m; - return gtm_get_clock () == m->start; -} - -static void -readonly_rollback (void) -{ - /* Nothing to do. */ -} - -static void -readonly_init (bool first) -{ - struct gtm_method *m; - - if (first) - gtm_tx()->m = m = calloc (1, sizeof (*m)); - else - m = gtm_tx()->m; - - m->start = gtm_get_clock (); -} - -static void -readonly_fini (void) -{ - struct gtm_method *m = gtm_tx()->m; - free (m); -} - -const struct gtm_dispatch dispatch_readonly = { - .R = readonly_R, - .RaR = readonly_R, - .RaW = readonly_RaW, - .RfW = readonly_RfW, - - .W = readonly_W, - .WaR = readonly_W, - .WaW = readonly_WaW, - - .trycommit = readonly_trycommit, - .rollback = readonly_rollback, - .init = readonly_init, - .fini = readonly_fini, - - .write_through = true -}; diff --git a/libitm/method-readonly.cc b/libitm/method-readonly.cc new file mode 100644 index 00000000000..70f5bed946e --- /dev/null +++ b/libitm/method-readonly.cc @@ -0,0 +1,123 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "libitm_i.h" + +namespace { + +using namespace GTM; + +class readonly_dispatch : public gtm_dispatch +{ + private: + gtm_version m_start; + + public: + readonly_dispatch(); + + virtual const gtm_cacheline *read_lock(const gtm_cacheline *, lock_type); + virtual mask_pair write_lock(gtm_cacheline *, lock_type); + virtual bool trycommit(); + virtual void rollback(); + virtual void reinit(); + virtual void fini(); +}; + +inline +readonly_dispatch::readonly_dispatch() + : gtm_dispatch(true, true), m_start(gtm_get_clock ()) +{ } + + +const gtm_cacheline * +readonly_dispatch::read_lock(const gtm_cacheline *line, lock_type lock) +{ + switch (lock) + { + case NOLOCK: + case R: + case RaR: + return line; + + case RfW: + gtm_tx()->restart (RESTART_NOT_READONLY); + + case RaW: + default: + abort (); + } +} + +gtm_dispatch::mask_pair +readonly_dispatch::write_lock(gtm_cacheline *line, lock_type lock) +{ + switch (lock) + { + case NOLOCK: + { + gtm_dispatch::mask_pair pair; + pair.line = line; + pair.mask = &mask_sink; + return pair; + } + + case WaW: + abort (); + + default: + gtm_tx()->restart (RESTART_NOT_READONLY); + } +} + +bool +readonly_dispatch::trycommit () +{ + return gtm_get_clock () == m_start; +} + +void +readonly_dispatch::rollback () +{ + /* Nothing to do. */ +} + +void +readonly_dispatch::reinit () +{ + m_start = gtm_get_clock (); +} + +void +readonly_dispatch::fini () +{ + delete this; +} + +} // anon namespace + +gtm_dispatch * +GTM::dispatch_readonly () +{ + return new readonly_dispatch(); +} diff --git a/libitm/method-wbetl.c b/libitm/method-wbetl.c deleted file mode 100644 index a3549e33362..00000000000 --- a/libitm/method-wbetl.c +++ /dev/null @@ -1,527 +0,0 @@ -/* Copyright (C) 2009 Free Software Foundation, Inc. - Contributed by Richard Henderson <rth@redhat.com>. - - This file is part of the GNU Transactional Memory Library (libitm). - - Libitm is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - Libitm is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - <http://www.gnu.org/licenses/>. */ - -#include "libitm_i.h" - - -typedef struct r_entry -{ - gtm_version version; - volatile gtm_stmlock *lock; -} r_entry_t; - -typedef struct r_set -{ - r_entry_t *entries; - int nb_entries; - int size; -} r_set_t; - -typedef struct w_entry -{ - struct w_entry *next; - uintptr_t addr; - volatile gtm_stmlock *lock; - gtm_cacheline *value; - gtm_version version; -} w_entry_t; - -typedef struct w_set -{ - w_entry_t *entries; - int nb_entries; - int size; - int reallocate; -} w_set_t; - -struct gtm_method -{ - gtm_version start; - gtm_version end; - - r_set_t r_set; - w_set_t w_set; - - gtm_cacheline_page *cache_page; - int n_cache_page; -}; - -#define RW_SET_SIZE 4096 - -/* Check if W is one of our write locks. */ -static inline bool -wbetl_local_w_entry_p (struct gtm_method *m, w_entry_t *w) -{ - return (m->w_set.entries <= w - && w < m->w_set.entries + m->w_set.nb_entries); -} - -/* Check if stripe has been read previously. */ - -static inline r_entry_t * -wbetl_has_read (struct gtm_method *m, volatile gtm_word *lock) -{ - r_entry_t *r; - int i; - - r = m->r_set.entries; - for (i = m->r_set.nb_entries; i > 0; i--, r++) - if (r->lock == lock) - return r; - - return NULL; -} - -/* Validate read set, i.e. check if all read addresses are still valid now. */ - -static bool -wbetl_validate (struct gtm_method *m) -{ - r_entry_t *r; - int i; - gtm_word l; - - __sync_synchronize (); - - r = m->r_set.entries; - for (i = m->r_set.nb_entries; i > 0; i--, r++) - { - l = *r->lock; - if (gtm_stmlock_owned_p (l)) - { - w_entry_t *w = gtm_stmlock_get_addr (l); - - if (!wbetl_local_w_entry_p (m, w)) - return false; - } - else - { - if (gtm_stmlock_get_version (l) != r->version) - return false; - } - } - - return true; -} - -/* Extend the snapshot range. */ - -static bool -wbetl_extend (struct gtm_method *m) -{ - gtm_word now = gtm_get_clock (); - - if (wbetl_validate (m)) - { - m->end = now; - return true; - } - return false; -} - -/* Acquire a write lock on ADDR. */ - -static gtm_cacheline * -wbetl_write_lock (uintptr_t addr) -{ - volatile gtm_stmlock *lock; - gtm_stmlock l, l2; - gtm_version version; - w_entry_t *w, *prev = NULL; - struct gtm_method *m; - - m = gtm_tx()->m; - lock = gtm_get_stmlock (addr); - l = *lock; - - restart_no_load: - if (gtm_stmlock_owned_p (l)) - { - w = gtm_stmlock_get_addr (l); - - /* Did we previously write the same address? */ - if (wbetl_local_w_entry_p (m, w)) - { - prev = w; - while (1) - { - if (addr == prev->addr) - return prev->value; - if (prev->next == NULL) - break; - prev = prev->next; - } - - /* Get version from previous entry write set. */ - version = prev->version; - - /* If there's not enough entries, we must reallocate the array, - which invalidates all pointers to write set entries, which - means we have to restart the transaction. */ - if (m->w_set.nb_entries == m->w_set.size) - { - m->w_set.size *= 2; - m->w_set.reallocate = 1; - GTM_restart_transaction (RESTART_REALLOCATE); - } - - w = &m->w_set.entries[m->w_set.nb_entries]; - goto do_write; - } - - GTM_restart_transaction (RESTART_LOCKED_WRITE); - } - else - { - version = gtm_stmlock_get_version (l); - - /* We might have read an older version previously. */ - if (version > m->end) - { - if (wbetl_has_read (m, lock) != NULL) - GTM_restart_transaction (RESTART_VALIDATE_WRITE); - } - - /* Extend write set, aborting to reallocate write set entries. */ - if (m->w_set.nb_entries == m->w_set.size) - { - m->w_set.size *= 2; - m->w_set.reallocate = 1; - GTM_restart_transaction (RESTART_REALLOCATE); - } - - /* Acquire the lock. */ - w = &m->w_set.entries[m->w_set.nb_entries]; - l2 = gtm_stmlock_set_owned (w); - l = __sync_val_compare_and_swap (lock, l, l2); - if (l != l2) - goto restart_no_load; - } - - do_write: - m->w_set.nb_entries++; - w->addr = addr; - w->lock = lock; - w->version = version; - w->next = NULL; - if (prev != NULL) - prev->next = w; - - { - gtm_cacheline_page *page = m->cache_page; - unsigned index = m->n_cache_page; - gtm_cacheline *line; - - if (page == NULL || index == CACHELINES_PER_PAGE) - { - gtm_cacheline_page *npage = GTM_page_alloc (); - npage->prev = page; - m->cache_page = page = npage; - m->n_cache_page = 1; - index = 0; - } - else - m->n_cache_page = index + 1; - - w->value = line = &page->lines[index]; - page->masks[index] = 0; - gtm_cacheline_copy (line, (const gtm_cacheline *) addr); - - return line; - } -} - -/* Acquire a read lock on ADDR. */ - -static gtm_cacheline * -wbetl_read_lock (uintptr_t addr, bool after_read) -{ - volatile gtm_stmlock *lock; - gtm_stmlock l, l2; - gtm_version version; - w_entry_t *w; - struct gtm_method *m; - - m = gtm_tx()->m; - lock = gtm_get_stmlock (addr); - l = *lock; - - restart_no_load: - if (gtm_stmlock_owned_p (l)) - { - w = gtm_stmlock_get_addr (l); - - /* Did we previously write the same address? */ - if (wbetl_local_w_entry_p (m, w)) - { - while (1) - { - if (addr == w->addr) - return w->value; - if (w->next == NULL) - return (gtm_cacheline *) addr; - w = w->next; - } - } - - GTM_restart_transaction (RESTART_LOCKED_READ); - } - - version = gtm_stmlock_get_version (l); - - /* If version is no longer valid, re-validate the read set. */ - if (version > m->end) - { - if (!wbetl_extend (m)) - GTM_restart_transaction (RESTART_VALIDATE_READ); - - /* Verify that the version has not yet been overwritten. The read - value has not yet bee added to read set and may not have been - checked during the extend. */ - __sync_synchronize (); - l2 = *lock; - if (l != l2) - { - l = l2; - goto restart_no_load; - } - } - - if (!after_read) - { - r_entry_t *r; - - /* Add the address and version to the read set. */ - if (m->r_set.nb_entries == m->r_set.size) - { - m->r_set.size *= 2; - - m->r_set.entries = (r_entry_t *) - realloc (m->r_set.entries, m->r_set.size * sizeof(r_entry_t)); - if (m->r_set.entries == NULL) - abort (); - } - r = &m->r_set.entries[m->r_set.nb_entries++]; - r->version = version; - r->lock = lock; - } - - return (gtm_cacheline *) addr; -} - -static gtm_cacheline * -wbetl_after_write_lock (uintptr_t addr) -{ - volatile gtm_stmlock *lock; - gtm_stmlock l; - w_entry_t *w; - struct gtm_method *m; - - m = gtm_tx()->m; - lock = gtm_get_stmlock (addr); - - l = *lock; - assert (gtm_stmlock_owned_p (l)); - - w = gtm_stmlock_get_addr (l); - assert (wbetl_local_w_entry_p (m, w)); - - while (1) - { - if (addr == w->addr) - return w->value; - w = w->next; - } -} - -static gtm_cacheline * -wbetl_R (uintptr_t addr) -{ - return wbetl_read_lock (addr, false); -} - -static gtm_cacheline * -wbetl_RaR (uintptr_t addr) -{ - return wbetl_read_lock (addr, true); -} - -static gtm_cacheline_mask_pair -wbetl_W (uintptr_t addr) -{ - gtm_cacheline_mask_pair pair; - pair.line = wbetl_write_lock (addr); - pair.mask = gtm_mask_for_line (pair.line); - return pair; -} - -static gtm_cacheline_mask_pair -wbetl_WaW (uintptr_t addr) -{ - gtm_cacheline_mask_pair pair; - pair.line = wbetl_after_write_lock (addr); - pair.mask = gtm_mask_for_line (pair.line); - return pair; -} - -/* Commit the transaction. */ - -static bool -wbetl_trycommit (void) -{ - struct gtm_method *m = gtm_tx()->m; - w_entry_t *w; - gtm_word t; - int i; - - if (m->w_set.nb_entries > 0) - { - /* Get commit timestamp. */ - t = gtm_inc_clock (); - - /* Validate only if a concurrent transaction has started since. */ - if (m->start != t - 1 && !wbetl_validate (m)) - return false; - - /* Install new versions, drop locks and set new timestamp. */ - w = m->w_set.entries; - for (i = m->w_set.nb_entries; i > 0; i--, w++) - gtm_cacheline_copy_mask ((gtm_cacheline *) w->addr, - w->value, *gtm_mask_for_line (w->value)); - - /* Only emit barrier after all cachelines are copied. */ - gtm_ccm_write_barrier (); - - w = m->w_set.entries; - for (i = m->w_set.nb_entries; i > 0; i--, w++) - if (w->next == NULL) - *w->lock = gtm_stmlock_set_version (t); - - __sync_synchronize (); - } - - return true; -} - -static void -wbetl_rollback (void) -{ - struct gtm_method *m = gtm_tx()->m; - w_entry_t *w; - int i; - - /* Drop locks. */ - w = m->w_set.entries; - for (i = m->w_set.nb_entries; i > 0; i--, w++) - if (w->next == NULL) - *w->lock = gtm_stmlock_set_version (w->version); - - __sync_synchronize (); -} - -static void -wbetl_init (bool first) -{ - struct gtm_method *m; - - if (first) - { - gtm_tx()->m = m = calloc (1, sizeof (*m)); - m->r_set.size = RW_SET_SIZE; - m->r_set.entries = malloc (RW_SET_SIZE * sizeof(r_entry_t)); - m->w_set.size = RW_SET_SIZE; - m->w_set.entries = malloc (RW_SET_SIZE * sizeof(w_entry_t)); - } - else - { - gtm_cacheline_page *page; - - m = gtm_tx()->m; - m->r_set.nb_entries = 0; - - m->w_set.nb_entries = 0; - if (m->w_set.reallocate) - { - m->w_set.reallocate = 0; - m->w_set.entries = realloc (m->w_set.entries, - m->w_set.size * sizeof(w_entry_t)); - } - - page = m->cache_page; - if (page) - { - /* Release all but one of the pages of cachelines. */ - gtm_cacheline_page *prev = page->prev; - if (prev) - { - gtm_cacheline_page *tail; - for (tail = prev; tail->prev; tail = tail->prev) - continue; - page->prev = NULL; - GTM_page_release (prev, tail); - } - /* Start the next cacheline allocation from the beginning. */ - m->n_cache_page = 0; - } - } - - m->start = m->end = gtm_get_clock (); -} - -static void -wbetl_fini (void) -{ - struct gtm_method *m = gtm_tx()->m; - gtm_cacheline_page *page, *tail; - - page = m->cache_page; - if (page) - { - for (tail = page; tail->prev; tail = tail->prev) - continue; - GTM_page_release (page, tail); - } - - free (m->r_set.entries); - free (m->w_set.entries); - free (m); -} - -const struct gtm_dispatch dispatch_wbetl = { - .R = wbetl_R, - .RaR = wbetl_RaR, - .RaW = wbetl_after_write_lock, - .RfW = wbetl_write_lock, - - .W = wbetl_W, - .WaR = wbetl_W, - .WaW = wbetl_WaW, - - .trycommit = wbetl_trycommit, - .rollback = wbetl_rollback, - .init = wbetl_init, - .fini = wbetl_fini, - - .write_through = false -}; diff --git a/libitm/method-wbetl.cc b/libitm/method-wbetl.cc new file mode 100644 index 00000000000..98ce1e4ef3a --- /dev/null +++ b/libitm/method-wbetl.cc @@ -0,0 +1,530 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "libitm_i.h" + +namespace { + +using namespace GTM; + +class wbetl_dispatch : public gtm_dispatch +{ + private: + static const size_t RW_SET_SIZE = 4096; + + struct r_entry + { + gtm_version version; + gtm_stmlock *lock; + }; + + r_entry *m_rset_entries; + size_t m_rset_nb_entries; + size_t m_rset_size; + + struct w_entry + { + struct w_entry *next; + gtm_stmlock *lock; + gtm_cacheline *addr; + gtm_cacheline *value; + gtm_version version; + }; + + w_entry *m_wset_entries; + size_t m_wset_nb_entries; + size_t m_wset_size; + bool m_wset_reallocate; + + gtm_version m_start; + gtm_version m_end; + + gtm_cacheline_page *m_cache_page; + unsigned m_n_cache_page; + + private: + bool local_w_entry_p (w_entry *w); + bool has_read (gtm_stmlock *lock); + bool validate(); + bool extend(); + + gtm_cacheline *do_write_lock(gtm_cacheline *); + gtm_cacheline *do_after_write_lock(gtm_cacheline *); + const gtm_cacheline *do_read_lock(const gtm_cacheline *, bool); + + public: + wbetl_dispatch(); + + virtual const gtm_cacheline *read_lock(const gtm_cacheline *, lock_type); + virtual mask_pair write_lock(gtm_cacheline *, lock_type); + + virtual bool trycommit(); + virtual void rollback(); + virtual void reinit(); + virtual void fini(); +}; + +/* Check if W is one of our write locks. */ + +inline bool +wbetl_dispatch::local_w_entry_p (w_entry *w) +{ + return (m_wset_entries <= w && w < m_wset_entries + m_wset_nb_entries); +} + +/* Check if stripe has been read previously. */ + +inline bool +wbetl_dispatch::has_read (gtm_stmlock *lock) +{ + // ??? Consider using an AA tree to lookup the r_set entries. + size_t n = m_rset_nb_entries; + for (size_t i = 0; i < n; ++i) + if (m_rset_entries[i].lock == lock) + return true; + + return false; +} + +/* Validate read set, i.e. check if all read addresses are still valid now. */ + +bool +wbetl_dispatch::validate () +{ + __sync_synchronize (); + + size_t n = m_rset_nb_entries; + for (size_t i = 0; i < n; ++i) + { + r_entry *r = &m_rset_entries[i]; + gtm_stmlock l = *r->lock; + + if (gtm_stmlock_owned_p (l)) + { + w_entry *w = (w_entry *) gtm_stmlock_get_addr (l); + + if (!local_w_entry_p (w)) + return false; + } + else if (gtm_stmlock_get_version (l) != r->version) + return false; + } + + return true; +} + +/* Extend the snapshot range. */ + +bool +wbetl_dispatch::extend () +{ + gtm_version now = gtm_get_clock (); + + if (validate ()) + { + m_end = now; + return true; + } + return false; +} + +/* Acquire a write lock on ADDR. */ + +gtm_cacheline * +wbetl_dispatch::do_write_lock(gtm_cacheline *addr) +{ + gtm_stmlock *lock; + gtm_stmlock l, l2; + gtm_version version; + w_entry *w, *prev = NULL; + + lock = gtm_get_stmlock (addr); + l = *lock; + + restart_no_load: + if (gtm_stmlock_owned_p (l)) + { + w = (w_entry *) gtm_stmlock_get_addr (l); + + /* Did we previously write the same address? */ + if (local_w_entry_p (w)) + { + prev = w; + while (1) + { + if (addr == prev->addr) + return prev->value; + if (prev->next == NULL) + break; + prev = prev->next; + } + + /* Get version from previous entry write set. */ + version = prev->version; + + /* If there's not enough entries, we must reallocate the array, + which invalidates all pointers to write set entries, which + means we have to restart the transaction. */ + if (m_wset_nb_entries == m_wset_size) + { + m_wset_size *= 2; + m_wset_reallocate = true; + gtm_tx()->restart (RESTART_REALLOCATE); + } + + w = &m_wset_entries[m_wset_nb_entries]; + goto do_write; + } + + gtm_tx()->restart (RESTART_LOCKED_WRITE); + } + else + { + version = gtm_stmlock_get_version (l); + + /* We might have read an older version previously. */ + if (version > m_end) + { + if (has_read (lock)) + gtm_tx()->restart (RESTART_VALIDATE_WRITE); + } + + /* Extend write set, aborting to reallocate write set entries. */ + if (m_wset_nb_entries == m_wset_size) + { + m_wset_size *= 2; + m_wset_reallocate = true; + gtm_tx()->restart (RESTART_REALLOCATE); + } + + /* Acquire the lock. */ + w = &m_wset_entries[m_wset_nb_entries]; + l2 = gtm_stmlock_set_owned (w); + l = __sync_val_compare_and_swap (lock, l, l2); + if (l != l2) + goto restart_no_load; + } + + do_write: + m_wset_nb_entries++; + if (prev != NULL) + prev->next = w; + w->next = 0; + w->lock = lock; + w->addr = addr; + w->version = version; + + gtm_cacheline_page *page = m_cache_page; + unsigned index = m_n_cache_page; + + if (page == NULL || index == gtm_cacheline_page::LINES) + { + gtm_cacheline_page *npage = new gtm_cacheline_page; + npage->prev = page; + m_cache_page = page = npage; + m_n_cache_page = 1; + index = 0; + } + else + m_n_cache_page = index + 1; + + gtm_cacheline *line = &page->lines[index]; + w->value = line; + page->masks[index] = 0; + *line = *addr; + + return line; +} + +gtm_cacheline * +wbetl_dispatch::do_after_write_lock (gtm_cacheline *addr) +{ + gtm_stmlock *lock; + gtm_stmlock l; + w_entry *w; + + lock = gtm_get_stmlock (addr); + l = *lock; + assert (gtm_stmlock_owned_p (l)); + + w = (w_entry *) gtm_stmlock_get_addr (l); + assert (local_w_entry_p (w)); + + while (1) + { + if (addr == w->addr) + return w->value; + w = w->next; + } +} + +/* Acquire a read lock on ADDR. */ + +const gtm_cacheline * +wbetl_dispatch::do_read_lock (const gtm_cacheline *addr, bool after_read) +{ + gtm_stmlock *lock; + gtm_stmlock l, l2; + gtm_version version; + w_entry *w; + + lock = gtm_get_stmlock (addr); + l = *lock; + + restart_no_load: + if (gtm_stmlock_owned_p (l)) + { + w = (w_entry *) gtm_stmlock_get_addr (l); + + /* Did we previously write the same address? */ + if (local_w_entry_p (w)) + { + while (1) + { + if (addr == w->addr) + return w->value; + if (w->next == NULL) + return addr; + w = w->next; + } + } + + gtm_tx()->restart (RESTART_LOCKED_READ); + } + + version = gtm_stmlock_get_version (l); + + /* If version is no longer valid, re-validate the read set. */ + if (version > m_end) + { + if (!extend ()) + gtm_tx()->restart (RESTART_VALIDATE_READ); + + if (!after_read) + { + // Verify that the version has not yet been overwritten. The read + // value has not yet been added to read set and may not have been + // checked during the extend. + // + // ??? This only makes sense if we're actually reading the value + // and returning it now -- which I believe the original TinySTM + // did. This doesn't make a whole lot of sense when we're + // manipulating cachelines as we are now. Do we need some other + // form of lock verification here, or is the validate call in + // trycommit sufficient? + + __sync_synchronize (); + l2 = *lock; + if (l != l2) + { + l = l2; + goto restart_no_load; + } + } + } + + if (!after_read) + { + r_entry *r; + + /* Add the address and version to the read set. */ + if (m_rset_nb_entries == m_rset_size) + { + m_rset_size *= 2; + + m_rset_entries = (r_entry *) + xrealloc (m_rset_entries, m_rset_size * sizeof(r_entry)); + } + r = &m_rset_entries[m_rset_nb_entries++]; + r->version = version; + r->lock = lock; + } + + return addr; +} + +const gtm_cacheline * +wbetl_dispatch::read_lock (const gtm_cacheline *addr, lock_type ltype) +{ + switch (ltype) + { + case NOLOCK: + return addr; + case R: + return do_read_lock (addr, false); + case RaR: + return do_read_lock (addr, true); + case RaW: + return do_after_write_lock (const_cast<gtm_cacheline *>(addr)); + case RfW: + return do_write_lock (const_cast<gtm_cacheline *>(addr)); + default: + abort (); + } +} + +gtm_dispatch::mask_pair +wbetl_dispatch::write_lock (gtm_cacheline *addr, lock_type ltype) +{ + gtm_cacheline *line; + + switch (ltype) + { + case NOLOCK: + return mask_pair (addr, &mask_sink); + case W: + case WaR: + line = do_write_lock (addr); + break; + case WaW: + line = do_after_write_lock (addr); + break; + default: + abort (); + } + + return mask_pair (line, gtm_cacheline_page::mask_for_page_line (line)); +} + +/* Commit the transaction. */ + +bool +wbetl_dispatch::trycommit () +{ + const size_t n = m_wset_nb_entries; + if (n != 0) + { + /* Get commit timestamp. */ + gtm_version t = gtm_inc_clock (); + + /* Validate only if a concurrent transaction has started since. */ + if (m_start != t - 1 && !validate ()) + return false; + + /* Install new versions. */ + for (size_t i = 0; i < n; ++i) + { + w_entry *w = &m_wset_entries[i]; + gtm_cacheline::copy_mask (w->addr, w->value, + *gtm_cacheline_page::mask_for_page_line (w->value)); + } + + /* Only emit barrier after all cachelines are copied. */ + gtm_cacheline::copy_mask_wb (); + + /* Drop locks. */ + for (size_t i = 0; i < n; ++i) + { + w_entry *w = &m_wset_entries[i]; + if (w->next == NULL) + *w->lock = gtm_stmlock_set_version (t); + } + } + + __sync_synchronize (); + return true; +} + +void +wbetl_dispatch::rollback () +{ + /* Drop locks. */ + const size_t n = m_wset_nb_entries; + for (size_t i = 0; i < n; ++i) + { + w_entry *w = &m_wset_entries[i]; + if (w->next == NULL) + *w->lock = gtm_stmlock_set_version (w->version); + } + + __sync_synchronize (); +} + +void +wbetl_dispatch::reinit () +{ + gtm_cacheline_page *page; + + m_rset_nb_entries = 0; + m_wset_nb_entries = 0; + + if (m_wset_reallocate) + { + m_wset_reallocate = 0; + m_wset_entries = (w_entry *) + xrealloc (m_wset_entries, m_wset_size * sizeof(w_entry)); + } + + page = m_cache_page; + if (page) + { + /* Release all but one of the pages of cachelines. */ + gtm_cacheline_page *prev = page->prev; + if (prev) + { + page->prev = 0; + delete prev; + } + + /* Start the next cacheline allocation from the beginning. */ + m_n_cache_page = 0; + } + + m_start = m_end = gtm_get_clock (); +} + +void +wbetl_dispatch::fini () +{ + delete m_cache_page; + free (m_rset_entries); + free (m_wset_entries); + delete this; +} + +wbetl_dispatch::wbetl_dispatch () + : gtm_dispatch (false, false) +{ + m_rset_entries = (r_entry *) xmalloc (RW_SET_SIZE * sizeof(r_entry)); + m_rset_nb_entries = 0; + m_rset_size = RW_SET_SIZE; + + m_wset_entries = (w_entry *) xmalloc (RW_SET_SIZE * sizeof(w_entry)); + m_wset_nb_entries = 0; + m_wset_size = RW_SET_SIZE; + m_wset_reallocate = false; + + m_start = m_end = gtm_get_clock (); + + m_cache_page = 0; + m_n_cache_page = 0; +} + +} // anon namespace + +gtm_dispatch * +GTM::dispatch_wbetl () +{ + return new wbetl_dispatch (); +} diff --git a/libitm/query.c b/libitm/query.cc index a4f2d7e0209..1f03ddf20fe 100644 --- a/libitm/query.c +++ b/libitm/query.cc @@ -24,6 +24,7 @@ #include "libitm_i.h" +using namespace GTM; int ITM_REGPARM _ITM_versionCompatible (int version) @@ -45,7 +46,7 @@ _ITM_inTransaction (void) struct gtm_transaction *tx = gtm_tx(); if (tx) { - if (tx->state & STATE_IRREVOKABLE) + if (tx->state & gtm_transaction::STATE_IRREVOCABLE) return inIrrevocableTransaction; else return inRetryableTransaction; diff --git a/libitm/retry.cc b/libitm/retry.cc new file mode 100644 index 00000000000..c68b0d50698 --- /dev/null +++ b/libitm/retry.cc @@ -0,0 +1,80 @@ +/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "libitm_i.h" + +void +GTM::gtm_transaction::decide_retry_strategy (gtm_restart_reason r) +{ + struct gtm_dispatch *disp = gtm_disp (); + + this->restart_reason[r]++; + this->restart_total++; + + bool retry_irr = (r == RESTART_SERIAL_IRR); + bool retry_serial = (this->restart_total > 100 || retry_irr); + + if (retry_serial) + { + // In serialirr_mode we can succeed with the upgrade to + // write-lock but fail the trycommit. In any case, if the + // write lock is not yet held, grab it. Don't do this with + // an upgrade, since we've no need to preserve the state we + // acquired with the read. + if ((this->state & STATE_SERIAL) == 0) + { + serial_lock.read_unlock (); + serial_lock.write_lock (); + } + + // ??? We can only retry with dispatch_serial when the transaction + // doesn't contain an abort. TODO: Create a serial mode dispatch + // that does logging in order to support abort. + if (this->prop & pr_hasNoAbort) + retry_irr = true; + } + + if (retry_irr) + { + this->state = (STATE_SERIAL | STATE_IRREVOCABLE); + disp->fini (); + disp = dispatch_serial (); + set_gtm_disp (disp); + } + else + { + if (r == RESTART_NOT_READONLY) + { + assert ((this->prop & pr_readOnly) == 0); + if (disp->read_only ()) + { + disp->fini (); + disp = dispatch_wbetl (); + set_gtm_disp (disp); + return; + } + } + disp->reinit (); + } +} diff --git a/libitm/serial.c b/libitm/serial.c deleted file mode 100644 index 52673d75e15..00000000000 --- a/libitm/serial.c +++ /dev/null @@ -1,126 +0,0 @@ -/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. - Contributed by Richard Henderson <rth@redhat.com>. - - This file is part of the GNU Transactional Memory Library (libitm). - - Libitm is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - Libitm is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - <http://www.gnu.org/licenses/>. */ - -#include "libitm_i.h" - - -static gtm_cacheline_mask gtm_cacheline_mask_sink; - -gtm_cacheline * -GTM_null_read_lock (uintptr_t ptr) -{ - return (gtm_cacheline *) ptr; -} - -gtm_cacheline_mask_pair -GTM_null_write_lock (uintptr_t ptr) -{ - gtm_cacheline_mask_pair pair; - pair.line = (gtm_cacheline *) ptr; - pair.mask = >m_cacheline_mask_sink; - return pair; -} - -static bool -serial_trycommit (void) -{ - return true; -} - -static void -serial_rollback (void) -{ - abort (); -} - -static void -serial_init (bool first UNUSED) -{ -} - -static void -serial_fini (void) -{ -} - -const static struct gtm_dispatch serial_dispatch = -{ - .R = GTM_null_read_lock, - .RaR = GTM_null_read_lock, - .RaW = GTM_null_read_lock, - .RfW = GTM_null_read_lock, - - .W = GTM_null_write_lock, - .WaR = GTM_null_write_lock, - .WaW = GTM_null_write_lock, - - .trycommit = serial_trycommit, - .rollback = serial_rollback, - .init = serial_init, - .fini = serial_fini, -}; - - -/* Put the transaction into serial mode. */ - -void -GTM_serialmode (bool initial, bool irrevokable) -{ - struct gtm_transaction *tx = gtm_tx(); - const struct gtm_dispatch *old_disp; - - if (tx->state & STATE_SERIAL) - { - if (irrevokable) - tx->state |= STATE_IRREVOKABLE; - return; - } - - old_disp = gtm_disp (); - set_gtm_disp (&serial_dispatch); - - if (initial) - gtm_rwlock_write_lock (>m_serial_lock); - else - { - gtm_rwlock_write_upgrade (>m_serial_lock); - if (old_disp->trycommit ()) - old_disp->fini (); - else - { - tx->state = STATE_SERIAL; - GTM_restart_transaction (RESTART_VALIDATE_COMMIT); - } - } - - tx->state = STATE_SERIAL | (irrevokable ? STATE_IRREVOKABLE : 0); -} - - -void ITM_REGPARM -_ITM_changeTransactionMode (_ITM_transactionState state) -{ - assert (state == modeSerialIrrevocable); - GTM_serialmode (false, true); -} diff --git a/libitm/serial.cc b/libitm/serial.cc new file mode 100644 index 00000000000..2a69d48a406 --- /dev/null +++ b/libitm/serial.cc @@ -0,0 +1,122 @@ +/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "libitm_i.h" + +namespace GTM HIDDEN { + +gtm_cacheline_mask gtm_dispatch::mask_sink; + +const gtm_cacheline * +gtm_dispatch::read_lock(const gtm_cacheline *addr, lock_type) +{ + return addr; +} + +gtm_dispatch::mask_pair +gtm_dispatch::write_lock(gtm_cacheline *addr, lock_type) +{ + return mask_pair (addr, &mask_sink); +} + +} // namespace GTM + +// Avoid a dependency on libstdc++ for the pure virtuals in gtm_dispatch. +extern "C" void HIDDEN +__cxa_pure_virtual () +{ + abort (); +} + +using namespace GTM; + +namespace { + +class serial_dispatch : public gtm_dispatch +{ + public: + serial_dispatch() : gtm_dispatch(false, true) { } + + // The read_lock and write_lock methods are implented by the base class. + + virtual bool trycommit() { return true; } + virtual void rollback() { abort(); } + virtual void reinit() { } + virtual void fini() { } +}; + +} // anon namespace + +static const serial_dispatch o_serial_dispatch; + +gtm_dispatch * +GTM::dispatch_serial () +{ + return const_cast<serial_dispatch *>(&o_serial_dispatch); +} + +// Put the transaction into serial-irrevocable mode. + +void +GTM::gtm_transaction::serialirr_mode () +{ + struct gtm_dispatch *disp = gtm_disp (); + bool need_restart = true; + + if (this->state & STATE_SERIAL) + { + if (this->state & STATE_IRREVOCABLE) + return; + + // Given that we're already serial, the trycommit better work. + bool ok = disp->trycommit (); + assert (ok); + disp->fini (); + need_restart = false; + } + else if (serial_lock.write_upgrade ()) + { + this->state |= STATE_SERIAL; + if (disp->trycommit ()) + { + disp->fini (); + need_restart = false; + } + } + + if (need_restart) + restart (RESTART_SERIAL_IRR); + else + { + this->state |= (STATE_SERIAL | STATE_IRREVOCABLE); + set_gtm_disp (dispatch_serial ()); + } +} + +void ITM_REGPARM +_ITM_changeTransactionMode (_ITM_transactionState state) +{ + assert (state == modeSerialIrrevocable); + gtm_tx()->serialirr_mode (); +} diff --git a/libitm/stmlock.h b/libitm/stmlock.h new file mode 100644 index 00000000000..e3b76627289 --- /dev/null +++ b/libitm/stmlock.h @@ -0,0 +1,123 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef LIBITM_STMLOCK_H +#define LIBITM_STMLOCK_H 1 + +namespace GTM HIDDEN { + +/* A versioned write lock on a cacheline. This must be wide enough to + store a pointer, and preferably wide enough to avoid overflowing the + version counter. Thus we use a "word", which should be 64-bits on + 64-bit systems even when their pointer size is forced smaller. */ +typedef gtm_word gtm_stmlock; + +/* This has to be the same size as gtm_stmlock, we just use this name + for documentation purposes. */ +typedef gtm_word gtm_version; + +/* The maximum value a version number can have. This is a consequence + of having the low bit of gtm_stmlock reserved for the owned bit. */ +#define GTM_VERSION_MAX (~(gtm_version)0 >> 1) + +/* A value that may be used to indicate "uninitialized" for a version. */ +#define GTM_VERSION_INVALID (~(gtm_version)0) + +/* This bit is set when the write lock is held. When set, the balance of + the bits in the lock is a pointer that references STM backend specific + data; it is up to the STM backend to determine if this thread holds the + lock. If this bit is clear, the balance of the bits are the last + version number committed to the cacheline. */ +static inline bool +gtm_stmlock_owned_p (gtm_stmlock lock) +{ + return lock & 1; +} + +static inline gtm_stmlock +gtm_stmlock_set_owned (void *data) +{ + return (gtm_stmlock)(uintptr_t)data | 1; +} + +static inline void * +gtm_stmlock_get_addr (gtm_stmlock lock) +{ + return (void *)((uintptr_t)lock & ~(uintptr_t)1); +} + +static inline gtm_version +gtm_stmlock_get_version (gtm_stmlock lock) +{ + return lock >> 1; +} + +static inline gtm_stmlock +gtm_stmlock_set_version (gtm_version ver) +{ + return ver << 1; +} + +/* We use a fixed set of locks for all memory, hashed into the + following table. */ +#define LOCK_ARRAY_SIZE (1024 * 1024) +extern gtm_stmlock gtm_stmlock_array[LOCK_ARRAY_SIZE]; + +static inline gtm_stmlock * +gtm_get_stmlock (const gtm_cacheline *addr) +{ + size_t idx = ((uintptr_t) addr / CACHELINE_SIZE) % LOCK_ARRAY_SIZE; + return gtm_stmlock_array + idx; +} + +/* The current global version number. */ +extern gtm_version gtm_clock; + +static inline gtm_version +gtm_get_clock (void) +{ + gtm_version r; + + __sync_synchronize (); + r = gtm_clock; + atomic_read_barrier (); + + return r; +} + +static inline gtm_version +gtm_inc_clock (void) +{ + gtm_version r = __sync_add_and_fetch (>m_clock, 1); + + /* ??? Ought to handle wraparound for 32-bit. */ + if (sizeof(r) < 8 && r > GTM_VERSION_MAX) + abort (); + + return r; +} + +} // namespace GTM + +#endif // LIBITM_STMLOCK_H diff --git a/libitm/testsuite/Makefile.in b/libitm/testsuite/Makefile.in index 9b377788145..a84a14b14bc 100644 --- a/libitm/testsuite/Makefile.in +++ b/libitm/testsuite/Makefile.in @@ -76,6 +76,10 @@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ @@ -136,6 +140,7 @@ 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@ ac_ct_FC = @ac_ct_FC@ am__include = @am__include@ diff --git a/libitm/useraction.c b/libitm/useraction.cc index 2847741b065..adbe470f6cc 100644 --- a/libitm/useraction.c +++ b/libitm/useraction.cc @@ -24,17 +24,18 @@ #include "libitm_i.h" +namespace GTM HIDDEN { -typedef struct gtm_user_action +struct gtm_user_action { struct gtm_user_action *next; _ITM_userCommitFunction fn; void *arg; -} gtm_user_action; +}; void -GTM_run_actions (gtm_user_action **list) +gtm_transaction::run_actions (gtm_user_action **list) { gtm_user_action *a = *list; @@ -54,7 +55,7 @@ GTM_run_actions (gtm_user_action **list) void -GTM_free_actions (gtm_user_action **list) +gtm_transaction::free_actions (gtm_user_action **list) { gtm_user_action *a = *list; @@ -71,6 +72,9 @@ GTM_free_actions (gtm_user_action **list) while (a); } +} // namespace GTM + +using namespace GTM; void ITM_REGPARM _ITM_addUserCommitAction(_ITM_userCommitFunction fn, @@ -82,7 +86,7 @@ _ITM_addUserCommitAction(_ITM_userCommitFunction fn, for (tx = gtm_tx(); tx->id != tid; tx = tx->prev) continue; - a = malloc (sizeof (*a)); + a = (gtm_user_action *) xmalloc (sizeof (*a)); a->next = tx->commit_actions; a->fn = fn; a->arg = arg; @@ -96,7 +100,7 @@ _ITM_addUserUndoAction(_ITM_userUndoFunction fn, void * arg) gtm_transaction *tx = gtm_tx(); gtm_user_action *a; - a = malloc (sizeof (*a)); + a = (gtm_user_action *) xmalloc (sizeof (*a)); a->next = tx->undo_actions; a->fn = fn; a->arg = arg; diff --git a/libitm/util.cc b/libitm/util.cc new file mode 100644 index 00000000000..b9a8727de21 --- /dev/null +++ b/libitm/util.cc @@ -0,0 +1,79 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson <rth@redhat.com>. + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#include "libitm_i.h" +#include <stdarg.h> +#include <stdio.h> + +namespace GTM HIDDEN { + +static void +gtm_verror (const char *fmt, va_list list) +{ + fputs ("\nlibitm: ", stderr); + vfprintf (stderr, fmt, list); + fputc ('\n', stderr); +} + +void +GTM_error (const char *fmt, ...) +{ + va_list list; + + va_start (list, fmt); + gtm_verror (fmt, list); + va_end (list); +} + +void +GTM_fatal (const char *fmt, ...) +{ + va_list list; + + va_start (list, fmt); + gtm_verror (fmt, list); + va_end (list); + + exit (EXIT_FAILURE); +} + +void * +xmalloc (size_t size) +{ + void *r = malloc (size); + if (r == 0) + GTM_fatal ("Out of memory allocating %lu bytes", (unsigned long) size); + return r; +} + +void * +xrealloc (void *old, size_t size) +{ + void *r = realloc (old, size); + if (r == 0) + GTM_fatal ("Out of memory allocating %lu bytes", (unsigned long) size); + return r; +} + +} // namespace GTM |