Merge from transactional-memory branch.

From-SVN: r181154
This commit is contained in:
Aldy Hernandez 2011-11-08 11:13:41 +00:00
parent 287188ea07
commit 0a35513e4e
304 changed files with 53781 additions and 231 deletions

View File

@ -1,3 +1,15 @@
2011-11-07 Aldy Hernandez <aldyh@redhat.com>
Richard Henderson <rth@redhat.com>
Merged from transactional-memory.
* Makefile.def (lang_env_dependencies): libitm is c++.
Add libitm target module.
* configure.ac: Likewise.
* config/mmap.m4: New file.
* contrib/gcc_update: Add libitm to touch data.
* Makefile.in, configure: Rebuild.
2011-11-02 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
* Makefile.tpl (EXTRA_GCC_FLAGS): Remove LIBGCC2_CFLAGS,

View File

@ -139,6 +139,7 @@ target_modules = { module= boehm-gc; };
target_modules = { module= rda; };
target_modules = { module= libada; };
target_modules = { module= libgomp; bootstrap= true; lib_path=.libs; };
target_modules = { module= libitm; lib_path=.libs; };
// These are (some of) the make targets to be done in each subdirectory.
// Not all; these are the ones which don't have special options.
@ -470,6 +471,7 @@ dependencies = { module=all-m4; on=all-build-texinfo; };
// environment (e.g. on libstdc++). By default target modules depend
// on libgcc and newlib/libgloss.
lang_env_dependencies = { module=libjava; cxx=true; };
lang_env_dependencies = { module=libitm; cxx=true; };
lang_env_dependencies = { module=newlib; no_c=true; };
lang_env_dependencies = { module=libgloss; no_c=true; };
lang_env_dependencies = { module=libgcc; no_gcc=true; no_c=true; };

View File

@ -594,7 +594,7 @@ all:
# This is the list of directories that may be needed in RPATH_ENVVAR
# so that programs built for the target machine work.
TARGET_LIB_PATH = $(TARGET_LIB_PATH_libstdc++-v3)$(TARGET_LIB_PATH_libmudflap)$(TARGET_LIB_PATH_libssp)$(TARGET_LIB_PATH_libgomp)$(HOST_LIB_PATH_gcc)
TARGET_LIB_PATH = $(TARGET_LIB_PATH_libstdc++-v3)$(TARGET_LIB_PATH_libmudflap)$(TARGET_LIB_PATH_libssp)$(TARGET_LIB_PATH_libgomp)$(TARGET_LIB_PATH_libitm)$(HOST_LIB_PATH_gcc)
@if target-libstdc++-v3
TARGET_LIB_PATH_libstdc++-v3 = $$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs:
@ -612,6 +612,10 @@ TARGET_LIB_PATH_libssp = $$r/$(TARGET_SUBDIR)/libssp/.libs:
TARGET_LIB_PATH_libgomp = $$r/$(TARGET_SUBDIR)/libgomp/.libs:
@endif target-libgomp
@if target-libitm
TARGET_LIB_PATH_libitm = $$r/$(TARGET_SUBDIR)/libitm/.libs:
@endif target-libitm
# This is the list of directories that may be needed in RPATH_ENVVAR
@ -947,7 +951,8 @@ configure-target: \
maybe-configure-target-boehm-gc \
maybe-configure-target-rda \
maybe-configure-target-libada \
maybe-configure-target-libgomp
maybe-configure-target-libgomp \
maybe-configure-target-libitm
# The target built for a native non-bootstrap build.
.PHONY: all
@ -1094,6 +1099,7 @@ all-target: maybe-all-target-libada
@if target-libgomp-no-bootstrap
all-target: maybe-all-target-libgomp
@endif target-libgomp-no-bootstrap
all-target: maybe-all-target-libitm
# Do a target for all the subdirectories. A ``make do-X'' will do a
# ``make X'' in all subdirectories (because, in general, there is a
@ -1176,6 +1182,7 @@ info-target: maybe-info-target-boehm-gc
info-target: maybe-info-target-rda
info-target: maybe-info-target-libada
info-target: maybe-info-target-libgomp
info-target: maybe-info-target-libitm
.PHONY: do-dvi
do-dvi:
@ -1253,6 +1260,7 @@ dvi-target: maybe-dvi-target-boehm-gc
dvi-target: maybe-dvi-target-rda
dvi-target: maybe-dvi-target-libada
dvi-target: maybe-dvi-target-libgomp
dvi-target: maybe-dvi-target-libitm
.PHONY: do-pdf
do-pdf:
@ -1330,6 +1338,7 @@ pdf-target: maybe-pdf-target-boehm-gc
pdf-target: maybe-pdf-target-rda
pdf-target: maybe-pdf-target-libada
pdf-target: maybe-pdf-target-libgomp
pdf-target: maybe-pdf-target-libitm
.PHONY: do-html
do-html:
@ -1407,6 +1416,7 @@ html-target: maybe-html-target-boehm-gc
html-target: maybe-html-target-rda
html-target: maybe-html-target-libada
html-target: maybe-html-target-libgomp
html-target: maybe-html-target-libitm
.PHONY: do-TAGS
do-TAGS:
@ -1484,6 +1494,7 @@ TAGS-target: maybe-TAGS-target-boehm-gc
TAGS-target: maybe-TAGS-target-rda
TAGS-target: maybe-TAGS-target-libada
TAGS-target: maybe-TAGS-target-libgomp
TAGS-target: maybe-TAGS-target-libitm
.PHONY: do-install-info
do-install-info:
@ -1561,6 +1572,7 @@ install-info-target: maybe-install-info-target-boehm-gc
install-info-target: maybe-install-info-target-rda
install-info-target: maybe-install-info-target-libada
install-info-target: maybe-install-info-target-libgomp
install-info-target: maybe-install-info-target-libitm
.PHONY: do-install-pdf
do-install-pdf:
@ -1638,6 +1650,7 @@ install-pdf-target: maybe-install-pdf-target-boehm-gc
install-pdf-target: maybe-install-pdf-target-rda
install-pdf-target: maybe-install-pdf-target-libada
install-pdf-target: maybe-install-pdf-target-libgomp
install-pdf-target: maybe-install-pdf-target-libitm
.PHONY: do-install-html
do-install-html:
@ -1715,6 +1728,7 @@ install-html-target: maybe-install-html-target-boehm-gc
install-html-target: maybe-install-html-target-rda
install-html-target: maybe-install-html-target-libada
install-html-target: maybe-install-html-target-libgomp
install-html-target: maybe-install-html-target-libitm
.PHONY: do-installcheck
do-installcheck:
@ -1792,6 +1806,7 @@ installcheck-target: maybe-installcheck-target-boehm-gc
installcheck-target: maybe-installcheck-target-rda
installcheck-target: maybe-installcheck-target-libada
installcheck-target: maybe-installcheck-target-libgomp
installcheck-target: maybe-installcheck-target-libitm
.PHONY: do-mostlyclean
do-mostlyclean:
@ -1869,6 +1884,7 @@ mostlyclean-target: maybe-mostlyclean-target-boehm-gc
mostlyclean-target: maybe-mostlyclean-target-rda
mostlyclean-target: maybe-mostlyclean-target-libada
mostlyclean-target: maybe-mostlyclean-target-libgomp
mostlyclean-target: maybe-mostlyclean-target-libitm
.PHONY: do-clean
do-clean:
@ -1946,6 +1962,7 @@ clean-target: maybe-clean-target-boehm-gc
clean-target: maybe-clean-target-rda
clean-target: maybe-clean-target-libada
clean-target: maybe-clean-target-libgomp
clean-target: maybe-clean-target-libitm
.PHONY: do-distclean
do-distclean:
@ -2023,6 +2040,7 @@ distclean-target: maybe-distclean-target-boehm-gc
distclean-target: maybe-distclean-target-rda
distclean-target: maybe-distclean-target-libada
distclean-target: maybe-distclean-target-libgomp
distclean-target: maybe-distclean-target-libitm
.PHONY: do-maintainer-clean
do-maintainer-clean:
@ -2100,6 +2118,7 @@ maintainer-clean-target: maybe-maintainer-clean-target-boehm-gc
maintainer-clean-target: maybe-maintainer-clean-target-rda
maintainer-clean-target: maybe-maintainer-clean-target-libada
maintainer-clean-target: maybe-maintainer-clean-target-libgomp
maintainer-clean-target: maybe-maintainer-clean-target-libitm
# Here are the targets which correspond to the do-X targets.
@ -2231,7 +2250,8 @@ check-target: \
maybe-check-target-boehm-gc \
maybe-check-target-rda \
maybe-check-target-libada \
maybe-check-target-libgomp
maybe-check-target-libgomp \
maybe-check-target-libitm
do-check:
@: $(MAKE); $(unstage)
@ -2380,7 +2400,8 @@ install-target: \
maybe-install-target-boehm-gc \
maybe-install-target-rda \
maybe-install-target-libada \
maybe-install-target-libgomp
maybe-install-target-libgomp \
maybe-install-target-libitm
uninstall:
@echo "the uninstall target is not supported in this tree"
@ -2476,7 +2497,8 @@ install-strip-target: \
maybe-install-strip-target-boehm-gc \
maybe-install-strip-target-rda \
maybe-install-strip-target-libada \
maybe-install-strip-target-libgomp
maybe-install-strip-target-libgomp \
maybe-install-strip-target-libitm
### other supporting targets
@ -40142,6 +40164,463 @@ maintainer-clean-target-libgomp:
.PHONY: configure-target-libitm maybe-configure-target-libitm
maybe-configure-target-libitm:
@if gcc-bootstrap
configure-target-libitm: stage_current
@endif gcc-bootstrap
@if target-libitm
maybe-configure-target-libitm: configure-target-libitm
configure-target-libitm:
@: $(MAKE); $(unstage)
@r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
echo "Checking multilib configuration for libitm..."; \
$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libitm ; \
$(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libitm/multilib.tmp 2> /dev/null ; \
if test -r $(TARGET_SUBDIR)/libitm/multilib.out; then \
if cmp -s $(TARGET_SUBDIR)/libitm/multilib.tmp $(TARGET_SUBDIR)/libitm/multilib.out; then \
rm -f $(TARGET_SUBDIR)/libitm/multilib.tmp; \
else \
rm -f $(TARGET_SUBDIR)/libitm/Makefile; \
mv $(TARGET_SUBDIR)/libitm/multilib.tmp $(TARGET_SUBDIR)/libitm/multilib.out; \
fi; \
else \
mv $(TARGET_SUBDIR)/libitm/multilib.tmp $(TARGET_SUBDIR)/libitm/multilib.out; \
fi; \
test ! -f $(TARGET_SUBDIR)/libitm/Makefile || exit 0; \
$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libitm ; \
$(NORMAL_TARGET_EXPORTS) \
echo Configuring in $(TARGET_SUBDIR)/libitm; \
cd "$(TARGET_SUBDIR)/libitm" || exit 1; \
case $(srcdir) in \
/* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
*) topdir=`echo $(TARGET_SUBDIR)/libitm/ | \
sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
esac; \
srcdiroption="--srcdir=$${topdir}/libitm"; \
libsrcdir="$$s/libitm"; \
rm -f no-such-file || : ; \
CONFIG_SITE=no-such-file $(SHELL) $${libsrcdir}/configure \
$(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \
--target=${target_alias} $${srcdiroption} \
|| exit 1
@endif target-libitm
.PHONY: all-target-libitm maybe-all-target-libitm
maybe-all-target-libitm:
@if gcc-bootstrap
all-target-libitm: stage_current
@endif gcc-bootstrap
@if target-libitm
TARGET-target-libitm=all
maybe-all-target-libitm: all-target-libitm
all-target-libitm: configure-target-libitm
@: $(MAKE); $(unstage)
@r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(NORMAL_TARGET_EXPORTS) \
(cd $(TARGET_SUBDIR)/libitm && \
$(MAKE) $(BASE_FLAGS_TO_PASS) $(EXTRA_TARGET_FLAGS) \
$(TARGET-target-libitm))
@endif target-libitm
.PHONY: check-target-libitm maybe-check-target-libitm
maybe-check-target-libitm:
@if target-libitm
maybe-check-target-libitm: check-target-libitm
check-target-libitm:
@: $(MAKE); $(unstage)
@r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(NORMAL_TARGET_EXPORTS) \
(cd $(TARGET_SUBDIR)/libitm && \
$(MAKE) $(TARGET_FLAGS_TO_PASS) check)
@endif target-libitm
.PHONY: install-target-libitm maybe-install-target-libitm
maybe-install-target-libitm:
@if target-libitm
maybe-install-target-libitm: install-target-libitm
install-target-libitm: installdirs
@: $(MAKE); $(unstage)
@r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(NORMAL_TARGET_EXPORTS) \
(cd $(TARGET_SUBDIR)/libitm && \
$(MAKE) $(TARGET_FLAGS_TO_PASS) install)
@endif target-libitm
.PHONY: install-strip-target-libitm maybe-install-strip-target-libitm
maybe-install-strip-target-libitm:
@if target-libitm
maybe-install-strip-target-libitm: install-strip-target-libitm
install-strip-target-libitm: installdirs
@: $(MAKE); $(unstage)
@r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(NORMAL_TARGET_EXPORTS) \
(cd $(TARGET_SUBDIR)/libitm && \
$(MAKE) $(TARGET_FLAGS_TO_PASS) install-strip)
@endif target-libitm
# Other targets (info, dvi, pdf, etc.)
.PHONY: maybe-info-target-libitm info-target-libitm
maybe-info-target-libitm:
@if target-libitm
maybe-info-target-libitm: info-target-libitm
info-target-libitm: \
configure-target-libitm
@: $(MAKE); $(unstage)
@[ -f $(TARGET_SUBDIR)/libitm/Makefile ] || exit 0 ; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(NORMAL_TARGET_EXPORTS) \
echo "Doing info in $(TARGET_SUBDIR)/libitm" ; \
for flag in $(EXTRA_TARGET_FLAGS); do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
(cd $(TARGET_SUBDIR)/libitm && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
info) \
|| exit 1
@endif target-libitm
.PHONY: maybe-dvi-target-libitm dvi-target-libitm
maybe-dvi-target-libitm:
@if target-libitm
maybe-dvi-target-libitm: dvi-target-libitm
dvi-target-libitm: \
configure-target-libitm
@: $(MAKE); $(unstage)
@[ -f $(TARGET_SUBDIR)/libitm/Makefile ] || exit 0 ; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(NORMAL_TARGET_EXPORTS) \
echo "Doing dvi in $(TARGET_SUBDIR)/libitm" ; \
for flag in $(EXTRA_TARGET_FLAGS); do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
(cd $(TARGET_SUBDIR)/libitm && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
dvi) \
|| exit 1
@endif target-libitm
.PHONY: maybe-pdf-target-libitm pdf-target-libitm
maybe-pdf-target-libitm:
@if target-libitm
maybe-pdf-target-libitm: pdf-target-libitm
pdf-target-libitm: \
configure-target-libitm
@: $(MAKE); $(unstage)
@[ -f $(TARGET_SUBDIR)/libitm/Makefile ] || exit 0 ; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(NORMAL_TARGET_EXPORTS) \
echo "Doing pdf in $(TARGET_SUBDIR)/libitm" ; \
for flag in $(EXTRA_TARGET_FLAGS); do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
(cd $(TARGET_SUBDIR)/libitm && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
pdf) \
|| exit 1
@endif target-libitm
.PHONY: maybe-html-target-libitm html-target-libitm
maybe-html-target-libitm:
@if target-libitm
maybe-html-target-libitm: html-target-libitm
html-target-libitm: \
configure-target-libitm
@: $(MAKE); $(unstage)
@[ -f $(TARGET_SUBDIR)/libitm/Makefile ] || exit 0 ; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(NORMAL_TARGET_EXPORTS) \
echo "Doing html in $(TARGET_SUBDIR)/libitm" ; \
for flag in $(EXTRA_TARGET_FLAGS); do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
(cd $(TARGET_SUBDIR)/libitm && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
html) \
|| exit 1
@endif target-libitm
.PHONY: maybe-TAGS-target-libitm TAGS-target-libitm
maybe-TAGS-target-libitm:
@if target-libitm
maybe-TAGS-target-libitm: TAGS-target-libitm
TAGS-target-libitm: \
configure-target-libitm
@: $(MAKE); $(unstage)
@[ -f $(TARGET_SUBDIR)/libitm/Makefile ] || exit 0 ; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(NORMAL_TARGET_EXPORTS) \
echo "Doing TAGS in $(TARGET_SUBDIR)/libitm" ; \
for flag in $(EXTRA_TARGET_FLAGS); do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
(cd $(TARGET_SUBDIR)/libitm && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
TAGS) \
|| exit 1
@endif target-libitm
.PHONY: maybe-install-info-target-libitm install-info-target-libitm
maybe-install-info-target-libitm:
@if target-libitm
maybe-install-info-target-libitm: install-info-target-libitm
install-info-target-libitm: \
configure-target-libitm \
info-target-libitm
@: $(MAKE); $(unstage)
@[ -f $(TARGET_SUBDIR)/libitm/Makefile ] || exit 0 ; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(NORMAL_TARGET_EXPORTS) \
echo "Doing install-info in $(TARGET_SUBDIR)/libitm" ; \
for flag in $(EXTRA_TARGET_FLAGS); do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
(cd $(TARGET_SUBDIR)/libitm && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
install-info) \
|| exit 1
@endif target-libitm
.PHONY: maybe-install-pdf-target-libitm install-pdf-target-libitm
maybe-install-pdf-target-libitm:
@if target-libitm
maybe-install-pdf-target-libitm: install-pdf-target-libitm
install-pdf-target-libitm: \
configure-target-libitm \
pdf-target-libitm
@: $(MAKE); $(unstage)
@[ -f $(TARGET_SUBDIR)/libitm/Makefile ] || exit 0 ; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(NORMAL_TARGET_EXPORTS) \
echo "Doing install-pdf in $(TARGET_SUBDIR)/libitm" ; \
for flag in $(EXTRA_TARGET_FLAGS); do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
(cd $(TARGET_SUBDIR)/libitm && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
install-pdf) \
|| exit 1
@endif target-libitm
.PHONY: maybe-install-html-target-libitm install-html-target-libitm
maybe-install-html-target-libitm:
@if target-libitm
maybe-install-html-target-libitm: install-html-target-libitm
install-html-target-libitm: \
configure-target-libitm \
html-target-libitm
@: $(MAKE); $(unstage)
@[ -f $(TARGET_SUBDIR)/libitm/Makefile ] || exit 0 ; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(NORMAL_TARGET_EXPORTS) \
echo "Doing install-html in $(TARGET_SUBDIR)/libitm" ; \
for flag in $(EXTRA_TARGET_FLAGS); do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
(cd $(TARGET_SUBDIR)/libitm && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
install-html) \
|| exit 1
@endif target-libitm
.PHONY: maybe-installcheck-target-libitm installcheck-target-libitm
maybe-installcheck-target-libitm:
@if target-libitm
maybe-installcheck-target-libitm: installcheck-target-libitm
installcheck-target-libitm: \
configure-target-libitm
@: $(MAKE); $(unstage)
@[ -f $(TARGET_SUBDIR)/libitm/Makefile ] || exit 0 ; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(NORMAL_TARGET_EXPORTS) \
echo "Doing installcheck in $(TARGET_SUBDIR)/libitm" ; \
for flag in $(EXTRA_TARGET_FLAGS); do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
(cd $(TARGET_SUBDIR)/libitm && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
installcheck) \
|| exit 1
@endif target-libitm
.PHONY: maybe-mostlyclean-target-libitm mostlyclean-target-libitm
maybe-mostlyclean-target-libitm:
@if target-libitm
maybe-mostlyclean-target-libitm: mostlyclean-target-libitm
mostlyclean-target-libitm:
@: $(MAKE); $(unstage)
@[ -f $(TARGET_SUBDIR)/libitm/Makefile ] || exit 0 ; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(NORMAL_TARGET_EXPORTS) \
echo "Doing mostlyclean in $(TARGET_SUBDIR)/libitm" ; \
for flag in $(EXTRA_TARGET_FLAGS); do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
(cd $(TARGET_SUBDIR)/libitm && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
mostlyclean) \
|| exit 1
@endif target-libitm
.PHONY: maybe-clean-target-libitm clean-target-libitm
maybe-clean-target-libitm:
@if target-libitm
maybe-clean-target-libitm: clean-target-libitm
clean-target-libitm:
@: $(MAKE); $(unstage)
@[ -f $(TARGET_SUBDIR)/libitm/Makefile ] || exit 0 ; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(NORMAL_TARGET_EXPORTS) \
echo "Doing clean in $(TARGET_SUBDIR)/libitm" ; \
for flag in $(EXTRA_TARGET_FLAGS); do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
(cd $(TARGET_SUBDIR)/libitm && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
clean) \
|| exit 1
@endif target-libitm
.PHONY: maybe-distclean-target-libitm distclean-target-libitm
maybe-distclean-target-libitm:
@if target-libitm
maybe-distclean-target-libitm: distclean-target-libitm
distclean-target-libitm:
@: $(MAKE); $(unstage)
@[ -f $(TARGET_SUBDIR)/libitm/Makefile ] || exit 0 ; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(NORMAL_TARGET_EXPORTS) \
echo "Doing distclean in $(TARGET_SUBDIR)/libitm" ; \
for flag in $(EXTRA_TARGET_FLAGS); do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
(cd $(TARGET_SUBDIR)/libitm && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
distclean) \
|| exit 1
@endif target-libitm
.PHONY: maybe-maintainer-clean-target-libitm maintainer-clean-target-libitm
maybe-maintainer-clean-target-libitm:
@if target-libitm
maybe-maintainer-clean-target-libitm: maintainer-clean-target-libitm
maintainer-clean-target-libitm:
@: $(MAKE); $(unstage)
@[ -f $(TARGET_SUBDIR)/libitm/Makefile ] || exit 0 ; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(NORMAL_TARGET_EXPORTS) \
echo "Doing maintainer-clean in $(TARGET_SUBDIR)/libitm" ; \
for flag in $(EXTRA_TARGET_FLAGS); do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
(cd $(TARGET_SUBDIR)/libitm && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
maintainer-clean) \
|| exit 1
@endif target-libitm
@if target-libmudflap
.PHONY: check-target-libmudflap-c++
check-target-libmudflap-c++:
@ -42233,6 +42712,7 @@ configure-stage3-target-libgomp: maybe-all-stage3-gcc
configure-stage4-target-libgomp: maybe-all-stage4-gcc
configure-stageprofile-target-libgomp: maybe-all-stageprofile-gcc
configure-stagefeedback-target-libgomp: maybe-all-stagefeedback-gcc
configure-target-libitm: stage_last
@endif gcc-bootstrap
@if gcc-no-bootstrap
@ -42255,6 +42735,7 @@ configure-target-boehm-gc: maybe-all-gcc
configure-target-rda: maybe-all-gcc
configure-target-libada: maybe-all-gcc
configure-target-libgomp: maybe-all-gcc
configure-target-libitm: maybe-all-gcc
@endif gcc-no-bootstrap
@ -43028,6 +43509,7 @@ configure-target-boehm-gc: maybe-all-target-libgcc
configure-target-rda: maybe-all-target-libgcc
configure-target-libada: maybe-all-target-libgcc
configure-target-libgomp: maybe-all-target-libgcc
configure-target-libitm: maybe-all-target-libgcc
@endif gcc-no-bootstrap
@ -43067,6 +43549,9 @@ configure-target-libada: maybe-all-target-newlib maybe-all-target-libgloss
configure-target-libgomp: maybe-all-target-newlib maybe-all-target-libgloss
configure-target-libitm: maybe-all-target-newlib maybe-all-target-libgloss
configure-target-libitm: maybe-all-target-libstdc++-v3
CONFIGURE_GDB_TK = @CONFIGURE_GDB_TK@
GDB_TK = @GDB_TK@

97
config/mmap.m4 Normal file
View File

@ -0,0 +1,97 @@
dnl ----------------------------------------------------------------------
dnl This whole bit snagged from gcc
dnl
dnl mmap(2) blacklisting. Some platforms provide the mmap library routine
dnl but don't support all of the features we need from it.
dnl
AC_DEFUN([GCC_AC_FUNC_MMAP_BLACKLIST],
[
AC_CHECK_HEADER([sys/mman.h],
[gcc_header_sys_mman_h=yes], [gcc_header_sys_mman_h=no])
AC_CHECK_FUNC([mmap], [gcc_func_mmap=yes], [gcc_func_mmap=no])
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
AC_CACHE_CHECK([whether read-only mmap of a plain file works],
gcc_cv_func_mmap_file,
[# 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])
AC_CACHE_CHECK([whether mmap from /dev/zero works],
gcc_cv_func_mmap_dev_zero,
[# 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])
# Unlike /dev/zero, the MAP_ANON(YMOUS) defines can be probed for.
AC_CACHE_CHECK([for MAP_ANON(YMOUS)], gcc_cv_decl_map_anon,
[AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
[#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif
],
[int n = MAP_ANONYMOUS;])],
gcc_cv_decl_map_anon=yes,
gcc_cv_decl_map_anon=no)])
if test $gcc_cv_decl_map_anon = no; then
gcc_cv_func_mmap_anon=no
else
AC_CACHE_CHECK([whether mmap with MAP_ANON(YMOUS) works],
gcc_cv_func_mmap_anon,
[# 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
fi
if test $gcc_cv_func_mmap_file = yes; then
AC_DEFINE(HAVE_MMAP_FILE, 1,
[Define if read-only mmap of a plain file works.])
fi
if test $gcc_cv_func_mmap_dev_zero = yes; then
AC_DEFINE(HAVE_MMAP_DEV_ZERO, 1,
[Define if mmap of /dev/zero works.])
fi
if test $gcc_cv_func_mmap_anon = yes; then
AC_DEFINE(HAVE_MMAP_ANON, 1,
[Define if mmap with MAP_ANON(YMOUS) works.])
fi
])

19
configure vendored
View File

@ -2681,6 +2681,7 @@ target_libraries="target-libgcc \
target-libgloss \
target-newlib \
target-libgomp \
target-libitm \
target-libstdc++-v3 \
target-libmudflap \
target-libssp \
@ -3056,6 +3057,24 @@ if test x$enable_libgomp = x ; then
esac
fi
# Disable libitm on non POSIX hosted systems.
if test x$enable_libitm = x ; then
# Enable libitm by default on hosted POSIX systems.
case "${target}" in
*-*-linux* | *-*-gnu* | *-*-k*bsd*-gnu)
;;
*-*-netbsd* | *-*-freebsd* | *-*-openbsd*)
;;
*-*-solaris2* | *-*-sysv4* | *-*-irix6* | *-*-osf* | *-*-hpux11*)
;;
*-*-darwin* | *-*-aix*)
;;
*)
noconfigdirs="$noconfigdirs target-libitm"
;;
esac
fi
# Disable libssp for some systems.
case "${target}" in
avr-*-*)

View File

@ -154,6 +154,7 @@ target_libraries="target-libgcc \
target-libgloss \
target-newlib \
target-libgomp \
target-libitm \
target-libstdc++-v3 \
target-libmudflap \
target-libssp \
@ -492,6 +493,24 @@ if test x$enable_libgomp = x ; then
esac
fi
# Disable libitm on non POSIX hosted systems.
if test x$enable_libitm = x ; then
# Enable libitm by default on hosted POSIX systems.
case "${target}" in
*-*-linux* | *-*-gnu* | *-*-k*bsd*-gnu)
;;
*-*-netbsd* | *-*-freebsd* | *-*-openbsd*)
;;
*-*-solaris2* | *-*-sysv4* | *-*-irix6* | *-*-osf* | *-*-hpux11*)
;;
*-*-darwin* | *-*-aix*)
;;
*)
noconfigdirs="$noconfigdirs target-libitm"
;;
esac
fi
# Disable libssp for some systems.
case "${target}" in
avr-*-*)

View File

@ -1,3 +1,9 @@
2011-11-07 Richard Henderson <rth@redhat.com>
Merged from transactional-memory.
* gcc_update: Add libitm to touch data.
2011-11-07 Quentin Neill <quentin.neill@amd.com>
* compare_tests: Add ability to compare all .sum

View File

@ -136,6 +136,11 @@ libgomp/Makefile.in: libgomp/Makefile.am libgomp/aclocal.m4
libgomp/testsuite/Makefile.in: libgomp/Makefile.am libgomp/aclocal.m4
libgomp/configure: libgomp/configure.ac libgomp/aclocal.m4
libgomp/config.h.in: libgomp/configure.ac libgomp/aclocal.m4
libitm/aclocal.m4: libitm/configure.ac libitm/acinclude.m4
libitm/Makefile.in: libitm/Makefile.am libitm/aclocal.m4
libitm/testsuite/Makefile.in: libitm/testsuite/Makefile.am libitm/aclocal.m4
libitm/configure: libitm/configure.ac libitm/aclocal.m4
libitm/config.h.in: libitm/configure.ac libitm/aclocal.m4
# Top level
Makefile.in: Makefile.tpl Makefile.def
configure: configure.ac config/acx.m4

View File

@ -1,3 +1,201 @@
2011-11-07 Richard Henderson <rth@redhat.com>
Aldy Hernandez <aldyh@redhat.com>
Andrew MacLeod <amacleod@redhat.com>
Torvald Riegel <triegel@redhat.com>
Merged from transactional-memory.
* gtm-builtins.def: New file.
* trans-mem.c: New file.
* trans-mem.h: New file.
* opts.c (finish_options): Error out when using -flto and
-fgnu-tm.
* config/i386/i386.c: Define TARGET_VECTORIZE* transactional variants.
(ix86_handle_tm_regparm_attribute, struct bdesc_tm,
ix86_builtin_tm_load, ix86_builtin_tm_store,
ix86_init_tm_builtins): New.
(ix86_init_builtins): Initialize TM builtins.
(struct ix86_attribute_table): Add "*tm regparm".
* config/i386/i386-builtin-types.def (PV2SI): Define.
(PCV2SI): Define.
Define V2SI_FTYPE_PCV2SI.
Define V4SF_FTYPE_PCV4SF.
Define V8SF_FTYPE_PCV8SF.
Define VOID_PV2SI_V2SI.
* doc/invoke.texi (C Dialect Options): Document -fgnu-tm and
tm-max-aggregate-size.
* doc/tm.texi.in: Add TARGET_VECTORIZE_BUILTIN_TM_LOAD and
TARGET_VECTORIZE_BUILTIN_TM_STORE hooks.
* doc/tm.texi: Regenerate.
* attribs.c (apply_tm_attr): New.
(init_attributes): Allow '*' prefix for overrides.
(register_attribute): Likewise.
* builtin-attrs.def (ATTR_TM_TMPURE, ATTR_TM_REGPARM): New.
(ATTR_TM_NOTHROW_LIST, ATTR_TM_TMPURE_NOTHROW_LIST,
ATTR_TM_PURE_TMPURE_NOTHROW_LIST, ATTR_TM_NORETURN_NOTHROW_LIST,
ATTR_TM_CONST_NOTHROW_LIST, ATTR_TMPURE_MALLOC_NOTHROW_LIST,
ATTR_TMPURE_NOTHROW_LIST): New.
* builtin-types.def (BT_FN_I[1248]_VPTR, BT_FN_FLOAT_VPTR,
BT_FN_DOUBLE_VPTR, BT_FN_LDOUBLE_VPTR, BT_FN_VOID_VPTR_I[1248],
BT_FN_VOID_VPTR_FLOAT, BT_FN_VOID_VPTR_DOUBLE,
BT_FN_VOID_VPTR_LDOUBLE, BT_FN_VOID_VPTR_SIZE): New.
* builtins.def: Include gtm-builtins.def. Add comments regarding
transactional memory synchronization.
(DEF_TM_BUILTIN): New.
* c-parser.c (struct c_parser): Add in_transaction.
(c_parser_transaction, c_parser_transaction_expression,
c_parser_transaction_cancel, c_parser_transaction_attributes): New.
(c_parser_attribute_any_word): Split out from c_parser_attributes.
(c_parser_statement_after_labels): Handle RID_TRANSACTION*.
(c_parser_unary_expression): Same.
* c-tree.h (c_finish_transaction): Declare.
* c-typeck.c (c_finish_transaction): New.
(build_function_call_vec): Call tm_malloc_replacement.
* calls.c (is_tm_builtin): New.
(flags_from_decl_or_type): Add ECF_TM_BUILTIN and ECF_TM_PURE.
* cfgbuild.c (make_edges): Add edges for REG_TM notes.
* cfgexpand.c (expand_call_stmt): Call
mark_transaction_restart_calls.
(gimple_expand_cfg): Free the tm_restart map.
(mark_transaction_restart_calls): New.
* cfgrtl.c (purge_dead_edges): Look for REG_TM notes.
* cgraph.c (dump_cgraph_node): Handle tm_clone.
* cgraph.h (struct cgraph_node): Add tm_clone field.
(decl_is_tm_clone): New.
(struct cgraph_local_info): Add tm_may_enter_irr.
(cgraph_copy_node_for_versioning): Declare.
* cgraphunit.c (cgraph_copy_node_for_versioning): Export;
copy analyzed from old version.
* combine.c (distribute_notes): Handle REG_TM notes.
* common.opt: Add -fgnu-tm.
* crtstuff.c (__TMC_LIST__, __TMC_END__): New.
(__do_global_dtors_aux): Deregister clone table.
(frame_dummy): Register clone table.
* emit-rtl.c (try_split): Handle REG_TM. Early return if no function
body.
* gimple-low.c (lower_stmt): Handle GIMPLE_EH_ELSE and
GIMPLE_TRANSACTION.
(gimple_stmt_may_fallthru): Handle GIMPLE_EH_ELSE.
* gimple-pretty-print.c: Include trans-mem.h.
(dump_gimple_fmt): Add %x.
(dump_gimple_call): Dump arguments for calls to _ITM_beginTransaction.
(dump_gimple_eh_else, dump_gimple_transaction): New.
(dump_gimple_stmt): Handle GIMPLE_EH_ELSE and GIMPLE_TRANSACTION.
* gimple.c (gimple_build_eh_else, gimple_build_transaction): New.
(walk_gimple_seq): Honor removed_stmt. Document usage of removed_stmt
field.
(walk_gimple_op): Handle GIMPLE_TRANSACTION.
(walk_gimple_stmt): Initialize and honor removed_stmt.
Handle GIMPLE_EH_ELSE and GIMPLE_TRANSACTION.
(gimple_copy): Handle GIMPLE_EH_ELSE and GIMPLE_TRANSACTION.
* gimple.def (GIMPLE_TRANSACTION, GIMPLE_EH_ELSE): New.
* gimple.h (struct gimple_statement_eh_else,
gimple_statement_transaction, GTMA_*): New.
(gimple_statement_d): Add gimple_statement_eh_else and
gimple_transaction.
(gimple_build_eh_else, gimple_build_transaction,
gimple_fold_call, diagnose_tm_safe_errors): Declare.
(get_call_expr_in): Remove prototype.
(gimple_has_substatements): Add GIMPLE_EH_ELSE and GIMPLE_TRANSACTION.
(gimple_eh_else_n_body, gimple_eh_else_e_body,
gimple_eh_else_set_n_body, gimple_eh_else_set_e_body,
gimple_transaction_body, gimple_transaction_label,
gimple_transaction_label_ptr, gimple_transaction_subcode,
gimple_transaction_set_body, gimple_transaction_set_label,
gimple_transaction_set_subcode): New.
(struct walk_stmt_info): Use BOOL_BITFIELD; add removed_stmt.
* gimplify.c (create_tmp_var_name): Use clean_symbol_name.
(voidify_wrapper_expr): Handle TRANSACTION_EXPR.
(gimplify_transaction): New.
(gimplify_expr): Handle TRANSACTION_EXPR.
* gsstruct.def (GSS_EH_ELSE, GSS_TRANSACTION): New.
* ipa-inline.c (can_inline_edge_p): Do not inline TM safe calling
TM pure functions.
* Makefile.in: Add trans-mem.o and dependencies.
(BUILTINS_DEF): Add gtm-builtins.def.
(gimple-pretty-print.o): Depend on TRANS_MEM_H.
(GTFILES): Add trans-mem.c.
* omp-low.c (WALK_SUBSTMTS): Add GIMPLE_TRANSACTION.
* output.h (record_tm_clone_pair, finish_tm_clone_pairs,
get_tm_clone_pair): Declare.
* params.def (PARAM_TM_MAX_AGGREGATE_SIZE): New.
* passes.c (init_optimization_passes): Place transactional memory
passes.
* print-tree.c (print_node): Dump tm-clone.
* recog.c (peep2_attempt): Handle REG_TM.
* reg-notes.def (TM): New.
* rtlanal.c (alloc_reg_note): Handle REG_TM.
* target.def (builtin_tm_load, builtin_tm_store): New.
* targhooks.c (default_builtin_tm_load_store): New.
* targhooks.h (default_builtin_tm_load_store): Declare.
* timevar.def (TV_TRANS_MEM): New.
* toplev.c (compile_file): Call finish_tm_clone_pairs.
* tree-cfg.c (make_edges): Handle GIMPLE_TRANSACTION.
(cleanup_dead_labels): Handle GIMPLE_TRANSACTION. Avoid unnecessary
writes into the statements to update labels.
(is_ctrl_altering_stmt): Add TM ending statements. Handle
GIMPLE_TRANSACTION.
(verify_gimple_transaction): New.
(verify_gimple_stmt): Handle GIMPLE_TRANSACTION.
(verify_gimple_in_seq_2): Handle GIMPLE_EH_ELSE and GIMPLE_TRANSACTION.
(gimple_redirect_edge_and_branch): Handle TM_TRANSACTION.
(dump_function_to_file): Display [tm-clone] if applicable.
* tree-eh.c (struct_ptr_eq): Make inline and move to tree.h.
(struct_ptr_hash): Same.
(collect_finally_tree): Handle GIMPLE_EH_ELSE.
(replace_goto_queue_1): Likewise.
(get_eh_else): New.
(honor_protect_cleanup_actions): Handle GIMPLE_EH_ELSE.
(lower_try_finally_nofallthru): Likewise.
(lower_try_finally_onedest): Likewise.
(lower_try_finally_copy): Likewise.
(lower_try_finally_switch): Likewise.
(lower_try_finally): Likewise.
(decide_copy_try_finally): Likewise.
(lower_eh_constructs_2): Likewise.
(refactor_eh_r): Likewise.
* tree-flow.h (struct gimple_df): Add tm_restart field.
Define tm_restart_node.
* tree-inline.c (remap_gimple_stmt): Handle GIMPLE_TRANSACTION.
(estimate_num_insns): Likewise.
(init_inline_once): Init tm_cost.
* tree-inline.h (struct eni_weights_d): Add tm_cost.
* tree-pass.h (pass_diagnose_tm_blocks, pass_lower_tm, pass_tm_init,
pass_tm_mark, pass_tm_memopt, pass_tm_edges, pass_ipa_tm): Declare.
* tree-pretty-print.c (dump_generic_node): Handle TRANSACTION_EXPR.
* tree-ssa-alias.c (ref_maybe_used_by_call_p_1): Handle
BUILT_IN_TM_MEMSET, BUILT_IN_TM_MEMCPY, BUILT_IN_TM_MEMMOVE.
Add support for TM vector loads. Add support for TM logging builtins.
(call_may_clobber_ref_p_1): Add support for vector stores.
* tree-ssa-structalias.c (find_func_aliases): Add support for TM
vector stores and loads. Handle BUILT_IN_TM_MEMSET,
BUILT_IN_TM_MEMCPY, BUILT_IN_TM_MEMMOVE.
* tree.c (strip_invariant_refs): Moved from gimple.c to here.
(local_define_builtin): Handle ECF_TM_PURE.
(build_common_builtin_nodes): Set __builtin_eh_pointer to ECF_TM_PURE.
* tree.def (TRANSACTION_EXPR): New.
* tree.h (strip_invariant_refs): Moved from gimple.h to here.
(TRANSACTION_EXPR_BODY, TRANSACTION_EXPR_CHECK,
TRANSACTION_EXPR_OUTER, TRANSACTION_EXPR_RELAXED,
BUILTIN_TM_LOAD_STORE_P, BUILTIN_TM_LOAD_P, BUILTIN_TM_STORE_P,
CASE_BUILT_IN_TM_LOAD, CASE_BUILT_IN_TM_STORE): New.
(ECF_TM_PURE, ECF_TM_BUILTIN): New.
(struct tree_function_decl): Add tm_clone_flag.
(struct_ptr_eq, struct_ptr_hash): New.
(apply_tm_attr): Declare.
(is_tm_safe_or_pure): New.
(build_tm_abort_call, is_tm_safe, is_tm_pure,
is_tm_may_cancel_outer, is_tm_ending_fndecl, record_tm_replacement,
tm_malloc_replacement): Declare.
* varasm.c (tm_clone_hash): New.
(record_tm_clone_pair, finish_tm_clone_pairs, get_tm_clone_pair,
dump_tm_clone_to_vec, dump_tm_clone_pairs, tm_alias_pair_cmp): New.
(struct tm_alias_pair): New. Declare VEC types for object.
2011-11-07 Richard Henderson <rth@redhat.com>
* optabs.h (OTI_sync_compare_and_swap, OTI_sync_lock_test_and_set,

View File

@ -856,7 +856,8 @@ RTL_H = $(RTL_BASE_H) genrtl.h vecir.h
RTL_ERROR_H = $(RTL_H) $(DIAGNOSTIC_CORE_H)
READ_MD_H = $(OBSTACK_H) $(HASHTAB_H) read-md.h
PARAMS_H = params.h params.def
BUILTINS_DEF = builtins.def sync-builtins.def omp-builtins.def
BUILTINS_DEF = builtins.def sync-builtins.def omp-builtins.def \
gtm-builtins.def
INTERNAL_FN_DEF = internal-fn.def
INTERNAL_FN_H = internal-fn.h $(INTERNAL_FN_DEF)
TREE_H = tree.h all-tree.def tree.def c-family/c-common.def \
@ -869,6 +870,7 @@ BASIC_BLOCK_H = basic-block.h $(PREDICT_H) $(VEC_H) $(FUNCTION_H) cfghooks.h
GIMPLE_H = gimple.h gimple.def gsstruct.def pointer-set.h $(VEC_H) \
vecir.h $(GGC_H) $(BASIC_BLOCK_H) $(TARGET_H) tree-ssa-operands.h \
tree-ssa-alias.h $(INTERNAL_FN_H)
TRANS_MEM_H = trans-mem.h
GCOV_IO_H = gcov-io.h gcov-iov.h auto-host.h
COVERAGE_H = coverage.h $(GCOV_IO_H)
DEMANGLE_H = $(srcdir)/../include/demangle.h
@ -1352,6 +1354,7 @@ OBJS = \
timevar.o \
toplev.o \
tracer.o \
trans-mem.o \
tree-affine.o \
tree-call-cdce.o \
tree-cfg.o \
@ -2158,6 +2161,12 @@ gtype-desc.o: gtype-desc.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(CFGLOOP_H) $(TARGET_H) $(IPA_PROP_H) $(LTO_STREAMER_H) \
target-globals.h
trans-mem.o : trans-mem.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TREE_H) $(GIMPLE_H) $(TREE_FLOW_H) $(TREE_PASS_H) $(TREE_INLINE_H) \
$(DIAGNOSTIC_CORE_H) $(DEMANGLE_H) output.h $(TRANS_MEM_H) \
$(PARAMS_H) $(TARGET_H) langhooks.h \
tree-pretty-print.h gimple-pretty-print.h
ggc-common.o: ggc-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(GGC_H) $(HASHTAB_H) $(DIAGNOSTIC_CORE_H) $(PARAMS_H) hosthooks.h \
$(HOSTHOOKS_DEF_H) $(VEC_H) $(PLUGIN_H) $(GGC_INTERNAL_H) $(TIMEVAR_H)
@ -2684,6 +2693,7 @@ gimple.o : gimple.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
gimple-pretty-print.o : gimple-pretty-print.c $(CONFIG_H) $(SYSTEM_H) \
$(TREE_H) $(DIAGNOSTIC_H) $(HASHTAB_H) $(TREE_FLOW_H) \
$(TM_H) coretypes.h $(TREE_PASS_H) $(GIMPLE_H) value-prof.h \
$(TRANS_MEM_H) \
tree-pretty-print.h gimple-pretty-print.h
tree-mudflap.o : $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(TREE_INLINE_H) \
$(GIMPLE_H) $(DIAGNOSTIC_H) $(DEMANGLE_H) $(HASHTAB_H) langhooks.h tree-mudflap.h \
@ -3733,6 +3743,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
$(srcdir)/lto-symtab.c \
$(srcdir)/tree-ssa-alias.h \
$(srcdir)/ipa-prop.h \
$(srcdir)/trans-mem.c \
$(srcdir)/lto-streamer.h \
$(srcdir)/target-globals.h \
$(srcdir)/ipa-inline.h \

View File

@ -166,7 +166,8 @@ init_attributes (void)
gcc_assert (strcmp (attribute_tables[i][j].name,
attribute_tables[i][k].name));
}
/* Check that no name occurs in more than one table. */
/* Check that no name occurs in more than one table. Names that
begin with '*' are exempt, and may be overridden. */
for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
{
size_t j, k, l;
@ -174,8 +175,9 @@ init_attributes (void)
for (j = i + 1; j < ARRAY_SIZE (attribute_tables); j++)
for (k = 0; attribute_tables[i][k].name != NULL; k++)
for (l = 0; attribute_tables[j][l].name != NULL; l++)
gcc_assert (strcmp (attribute_tables[i][k].name,
attribute_tables[j][l].name));
gcc_assert (attribute_tables[i][k].name[0] == '*'
|| strcmp (attribute_tables[i][k].name,
attribute_tables[j][l].name));
}
#endif
@ -207,7 +209,7 @@ register_attribute (const struct attribute_spec *attr)
slot = htab_find_slot_with_hash (attribute_hash, &str,
substring_hash (str.str, str.length),
INSERT);
gcc_assert (!*slot);
gcc_assert (!*slot || attr->name[0] == '*');
*slot = (void *) CONST_CAST (struct attribute_spec *, attr);
}
@ -484,3 +486,12 @@ decl_attributes (tree *node, tree attributes, int flags)
return returned_attrs;
}
/* Subroutine of set_method_tm_attributes. Apply TM attribute ATTR
to the method FNDECL. */
void
apply_tm_attr (tree fndecl, tree attr)
{
decl_attributes (&TREE_TYPE (fndecl), tree_cons (attr, NULL, NULL), 0);
}

View File

@ -96,6 +96,8 @@ DEF_ATTR_IDENT (ATTR_SENTINEL, "sentinel")
DEF_ATTR_IDENT (ATTR_STRFMON, "strfmon")
DEF_ATTR_IDENT (ATTR_STRFTIME, "strftime")
DEF_ATTR_IDENT (ATTR_TYPEGENERIC, "type generic")
DEF_ATTR_IDENT (ATTR_TM_REGPARM, "*tm regparm")
DEF_ATTR_IDENT (ATTR_TM_TMPURE, "transaction_pure")
DEF_ATTR_TREE_LIST (ATTR_NOVOPS_LIST, ATTR_NOVOPS, ATTR_NULL, ATTR_NULL)
@ -227,6 +229,26 @@ DEF_FORMAT_ATTRIBUTE_NOTHROW(STRFMON,3,3_4)
#undef DEF_FORMAT_ATTRIBUTE_NOTHROW
#undef DEF_FORMAT_ATTRIBUTE_BOTH
/* Transactional memory variants of the above. */
DEF_ATTR_TREE_LIST (ATTR_TM_NOTHROW_LIST,
ATTR_TM_REGPARM, ATTR_NULL, ATTR_NOTHROW_LIST)
DEF_ATTR_TREE_LIST (ATTR_TM_TMPURE_NOTHROW_LIST,
ATTR_TM_TMPURE, ATTR_NULL, ATTR_TM_NOTHROW_LIST)
DEF_ATTR_TREE_LIST (ATTR_TM_PURE_TMPURE_NOTHROW_LIST,
ATTR_PURE, ATTR_NULL, ATTR_TM_TMPURE_NOTHROW_LIST)
DEF_ATTR_TREE_LIST (ATTR_TM_NORETURN_NOTHROW_LIST,
ATTR_TM_REGPARM, ATTR_NULL, ATTR_NORETURN_NOTHROW_LIST)
DEF_ATTR_TREE_LIST (ATTR_TM_CONST_NOTHROW_LIST,
ATTR_TM_REGPARM, ATTR_NULL, ATTR_CONST_NOTHROW_LIST)
/* Same attributes used for BUILT_IN_MALLOC except with TM_PURE thrown in. */
DEF_ATTR_TREE_LIST (ATTR_TMPURE_MALLOC_NOTHROW_LIST,
ATTR_TM_TMPURE, ATTR_NULL, ATTR_MALLOC_NOTHROW_LIST)
/* Same attributes used for BUILT_IN_FREE except with TM_PURE thrown in. */
DEF_ATTR_TREE_LIST (ATTR_TMPURE_NOTHROW_LIST,
ATTR_TM_TMPURE, ATTR_NULL, ATTR_NOTHROW_LIST)
/* Construct a tree for a format_arg attribute. */
#define DEF_FORMAT_ARG_ATTRIBUTE(FA) \
DEF_ATTR_TREE_LIST (ATTR_FORMAT_ARG_##FA, ATTR_FORMAT_ARG, \

View File

@ -530,3 +530,24 @@ DEF_FUNCTION_TYPE_VAR_5 (BT_FN_INT_INT_INT_INT_INT_INT_VAR,
DEF_POINTER_TYPE (BT_PTR_FN_VOID_VAR, BT_FN_VOID_VAR)
DEF_FUNCTION_TYPE_3 (BT_FN_PTR_PTR_FN_VOID_VAR_PTR_SIZE,
BT_PTR, BT_PTR_FN_VOID_VAR, BT_PTR, BT_SIZE)
DEF_FUNCTION_TYPE_1 (BT_FN_I1_VPTR, BT_I1, BT_VOLATILE_PTR)
DEF_FUNCTION_TYPE_1 (BT_FN_I2_VPTR, BT_I2, BT_VOLATILE_PTR)
DEF_FUNCTION_TYPE_1 (BT_FN_I4_VPTR, BT_I4, BT_VOLATILE_PTR)
DEF_FUNCTION_TYPE_1 (BT_FN_I8_VPTR, BT_I8, BT_VOLATILE_PTR)
DEF_FUNCTION_TYPE_1 (BT_FN_FLOAT_VPTR, BT_FLOAT, BT_VOLATILE_PTR)
DEF_FUNCTION_TYPE_1 (BT_FN_DOUBLE_VPTR, BT_DOUBLE, BT_VOLATILE_PTR)
DEF_FUNCTION_TYPE_1 (BT_FN_LDOUBLE_VPTR, BT_LONGDOUBLE, BT_VOLATILE_PTR)
DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_I1, BT_VOID, BT_VOLATILE_PTR, BT_I1)
DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_I2, BT_VOID, BT_VOLATILE_PTR, BT_I2)
DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_I4, BT_VOID, BT_VOLATILE_PTR, BT_I4)
DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_I8, BT_VOID, BT_VOLATILE_PTR, BT_I8)
DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_FLOAT, BT_VOID, BT_VOLATILE_PTR, BT_FLOAT)
DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_DOUBLE, BT_VOID,
BT_VOLATILE_PTR, BT_DOUBLE)
DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_LDOUBLE, BT_VOID,
BT_VOLATILE_PTR, BT_LONGDOUBLE)
DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_SIZE, BT_VOID,
BT_VOLATILE_PTR, BT_SIZE)

View File

@ -142,6 +142,13 @@ along with GCC; see the file COPYING3. If not see
false, true, true, ATTRS, false, \
(flag_openmp || flag_tree_parallelize_loops))
/* Builtin used by the implementation of GNU TM. These
functions are mapped to the actual implementation of the STM library. */
#undef DEF_TM_BUILTIN
#define DEF_TM_BUILTIN(ENUM, NAME, TYPE, ATTRS) \
DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE, \
false, true, true, ATTRS, false, flag_tm)
/* Define an attribute list for math functions that are normally
"impure" because some of them may write into global memory for
`errno'. If !flag_errno_math they are instead "const". */
@ -624,6 +631,7 @@ DEF_GCC_BUILTIN (BUILT_IN_APPLY_ARGS, "apply_args", BT_FN_PTR_VAR, ATTR_L
DEF_GCC_BUILTIN (BUILT_IN_BSWAP32, "bswap32", BT_FN_UINT32_UINT32, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_BSWAP64, "bswap64", BT_FN_UINT64_UINT64, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_EXT_LIB_BUILTIN (BUILT_IN_CLEAR_CACHE, "__clear_cache", BT_FN_VOID_PTR_PTR, ATTR_NOTHROW_LEAF_LIST)
/* [trans-mem]: Adjust BUILT_IN_TM_CALLOC if BUILT_IN_CALLOC is changed. */
DEF_LIB_BUILTIN (BUILT_IN_CALLOC, "calloc", BT_FN_PTR_SIZE_SIZE, ATTR_MALLOC_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_CLASSIFY_TYPE, "classify_type", BT_FN_INT_VAR, ATTR_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_CLZ, "clz", BT_FN_INT_UINT, ATTR_CONST_NOTHROW_LEAF_LIST)
@ -662,6 +670,7 @@ DEF_EXT_LIB_BUILTIN (BUILT_IN_FFSL, "ffsl", BT_FN_INT_LONG, ATTR_CONST_NOTHRO
DEF_EXT_LIB_BUILTIN (BUILT_IN_FFSLL, "ffsll", BT_FN_INT_LONGLONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_EXT_LIB_BUILTIN (BUILT_IN_FORK, "fork", BT_FN_PID, ATTR_NOTHROW_LIST)
DEF_GCC_BUILTIN (BUILT_IN_FRAME_ADDRESS, "frame_address", BT_FN_PTR_UINT, ATTR_NULL)
/* [trans-mem]: Adjust BUILT_IN_TM_FREE if BUILT_IN_FREE is changed. */
DEF_LIB_BUILTIN (BUILT_IN_FREE, "free", BT_FN_VOID_PTR, ATTR_NOTHROW_LIST)
DEF_GCC_BUILTIN (BUILT_IN_FROB_RETURN_ADDR, "frob_return_addr", BT_FN_PTR_PTR, ATTR_NULL)
DEF_EXT_LIB_BUILTIN (BUILT_IN_GETTEXT, "gettext", BT_FN_STRING_CONST_STRING, ATTR_FORMAT_ARG_1)
@ -698,6 +707,7 @@ DEF_GCC_BUILTIN (BUILT_IN_ISUNORDERED, "isunordered", BT_FN_INT_VAR, ATTR
DEF_LIB_BUILTIN (BUILT_IN_LABS, "labs", BT_FN_LONG_LONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_C99_BUILTIN (BUILT_IN_LLABS, "llabs", BT_FN_LONGLONG_LONGLONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_LONGJMP, "longjmp", BT_FN_VOID_PTR_INT, ATTR_NORETURN_NOTHROW_LEAF_LIST)
/* [trans-mem]: Adjust BUILT_IN_TM_MALLOC if BUILT_IN_MALLOC is changed. */
DEF_LIB_BUILTIN (BUILT_IN_MALLOC, "malloc", BT_FN_PTR_SIZE, ATTR_MALLOC_NOTHROW_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_NEXT_ARG, "next_arg", BT_FN_PTR_VAR, ATTR_LEAF_LIST)
DEF_GCC_BUILTIN (BUILT_IN_PARITY, "parity", BT_FN_INT_UINT, ATTR_CONST_NOTHROW_LEAF_LIST)
@ -793,3 +803,6 @@ DEF_BUILTIN_STUB (BUILT_IN_EH_COPY_VALUES, "__builtin_eh_copy_values")
/* OpenMP builtins. */
#include "omp-builtins.def"
/* GTM builtins. */
#include "gtm-builtins.def"

View File

@ -1,3 +1,19 @@
2011-11-07 Richard Henderson <rth@redhat.com>
Aldy Hernandez <aldyh@redhat.com>
Torvald Riegel <triegel@redhat.com>
Merged from transactional-memory.
* c-common.c (handle_tm_wrap_attribute,
handle_tm_attribute, ignore_attribute, parse_tm_stmt_attr): New.
(struct c_common_reswords): Added __transaction* keywords.
(struct c_common_attribute_table): Added transaction* and tm_regparm
attributes.
* c-common.h: Added RID_TRANSACTION*. Added TM_ATTR* and TM_STMT*
masks.
(parse_tm_stmt_attr, tm_attr_to_mask, tm_mask_to_attr,
find_tm_attribute): Declare.
2011-11-07 Jason Merrill <jason@redhat.com>
PR c++/35688

View File

@ -357,6 +357,8 @@ static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
static tree handle_no_limit_stack_attribute (tree *, tree, tree, int,
bool *);
static tree handle_pure_attribute (tree *, tree, tree, int, bool *);
static tree handle_tm_attribute (tree *, tree, tree, int, bool *);
static tree handle_tm_wrap_attribute (tree *, tree, tree, int, bool *);
static tree handle_novops_attribute (tree *, tree, tree, int, bool *);
static tree handle_deprecated_attribute (tree *, tree, tree, int,
bool *);
@ -372,6 +374,7 @@ static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
static tree handle_alloc_size_attribute (tree *, tree, tree, int, bool *);
static tree handle_target_attribute (tree *, tree, tree, int, bool *);
static tree handle_optimize_attribute (tree *, tree, tree, int, bool *);
static tree ignore_attribute (tree *, tree, tree, int, bool *);
static tree handle_no_split_stack_attribute (tree *, tree, tree, int, bool *);
static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
@ -474,6 +477,9 @@ const struct c_common_resword c_common_reswords[] =
{ "__signed", RID_SIGNED, 0 },
{ "__signed__", RID_SIGNED, 0 },
{ "__thread", RID_THREAD, 0 },
{ "__transaction_atomic", RID_TRANSACTION_ATOMIC, 0 },
{ "__transaction_relaxed", RID_TRANSACTION_RELAXED, 0 },
{ "__transaction_cancel", RID_TRANSACTION_CANCEL, 0 },
{ "__typeof", RID_TYPEOF, 0 },
{ "__typeof__", RID_TYPEOF, 0 },
{ "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY },
@ -666,6 +672,20 @@ const struct attribute_spec c_common_attribute_table[] =
handle_no_limit_stack_attribute, false },
{ "pure", 0, 0, true, false, false,
handle_pure_attribute, false },
{ "transaction_callable", 0, 0, false, true, false,
handle_tm_attribute, false },
{ "transaction_unsafe", 0, 0, false, true, false,
handle_tm_attribute, false },
{ "transaction_safe", 0, 0, false, true, false,
handle_tm_attribute, false },
{ "transaction_may_cancel_outer", 0, 0, false, true, false,
handle_tm_attribute, false },
/* ??? These two attributes didn't make the transition from the
Intel language document to the multi-vendor language document. */
{ "transaction_pure", 0, 0, false, true, false,
handle_tm_attribute, false },
{ "transaction_wrap", 1, 1, true, false, false,
handle_tm_wrap_attribute, false },
/* For internal use (marking of builtins) only. The name contains space
to prevent its usage in source code. */
{ "no vops", 0, 0, true, false, false,
@ -707,6 +727,10 @@ const struct attribute_spec c_common_attribute_table[] =
handle_target_attribute, false },
{ "optimize", 1, -1, true, false, false,
handle_optimize_attribute, false },
/* For internal use only. The leading '*' both prevents its usage in
source code and signals that it may be overridden by machine tables. */
{ "*tm regparm", 0, 0, false, true, true,
ignore_attribute, false },
{ "no_split_stack", 0, 0, true, false, false,
handle_no_split_stack_attribute, false },
/* For internal use (marking of builtins and runtime functions) only.
@ -7315,6 +7339,223 @@ handle_pure_attribute (tree *node, tree name, tree ARG_UNUSED (args),
return NULL_TREE;
}
/* Digest an attribute list destined for a transactional memory statement.
ALLOWED is the set of attributes that are allowed for this statement;
return the attribute we parsed. Multiple attributes are never allowed. */
int
parse_tm_stmt_attr (tree attrs, int allowed)
{
tree a_seen = NULL;
int m_seen = 0;
for ( ; attrs ; attrs = TREE_CHAIN (attrs))
{
tree a = TREE_PURPOSE (attrs);
int m = 0;
if (is_attribute_p ("outer", a))
m = TM_STMT_ATTR_OUTER;
if ((m & allowed) == 0)
{
warning (OPT_Wattributes, "%qE attribute directive ignored", a);
continue;
}
if (m_seen == 0)
{
a_seen = a;
m_seen = m;
}
else if (m_seen == m)
warning (OPT_Wattributes, "%qE attribute duplicated", a);
else
warning (OPT_Wattributes, "%qE attribute follows %qE", a, a_seen);
}
return m_seen;
}
/* Transform a TM attribute name into a maskable integer and back.
Note that NULL (i.e. no attribute) is mapped to UNKNOWN, corresponding
to how the lack of an attribute is treated. */
int
tm_attr_to_mask (tree attr)
{
if (attr == NULL)
return 0;
if (is_attribute_p ("transaction_safe", attr))
return TM_ATTR_SAFE;
if (is_attribute_p ("transaction_callable", attr))
return TM_ATTR_CALLABLE;
if (is_attribute_p ("transaction_pure", attr))
return TM_ATTR_PURE;
if (is_attribute_p ("transaction_unsafe", attr))
return TM_ATTR_IRREVOCABLE;
if (is_attribute_p ("transaction_may_cancel_outer", attr))
return TM_ATTR_MAY_CANCEL_OUTER;
return 0;
}
tree
tm_mask_to_attr (int mask)
{
const char *str;
switch (mask)
{
case TM_ATTR_SAFE:
str = "transaction_safe";
break;
case TM_ATTR_CALLABLE:
str = "transaction_callable";
break;
case TM_ATTR_PURE:
str = "transaction_pure";
break;
case TM_ATTR_IRREVOCABLE:
str = "transaction_unsafe";
break;
case TM_ATTR_MAY_CANCEL_OUTER:
str = "transaction_may_cancel_outer";
break;
default:
gcc_unreachable ();
}
return get_identifier (str);
}
/* Return the first TM attribute seen in LIST. */
tree
find_tm_attribute (tree list)
{
for (; list ; list = TREE_CHAIN (list))
{
tree name = TREE_PURPOSE (list);
if (tm_attr_to_mask (name) != 0)
return name;
}
return NULL_TREE;
}
/* Handle the TM attributes; arguments as in struct attribute_spec.handler.
Here we accept only function types, and verify that none of the other
function TM attributes are also applied. */
/* ??? We need to accept class types for C++, but not C. This greatly
complicates this function, since we can no longer rely on the extra
processing given by function_type_required. */
static tree
handle_tm_attribute (tree *node, tree name, tree args,
int flags, bool *no_add_attrs)
{
/* Only one path adds the attribute; others don't. */
*no_add_attrs = true;
switch (TREE_CODE (*node))
{
case RECORD_TYPE:
case UNION_TYPE:
/* Only tm_callable and tm_safe apply to classes. */
if (tm_attr_to_mask (name) & ~(TM_ATTR_SAFE | TM_ATTR_CALLABLE))
goto ignored;
/* FALLTHRU */
case FUNCTION_TYPE:
case METHOD_TYPE:
{
tree old_name = find_tm_attribute (TYPE_ATTRIBUTES (*node));
if (old_name == name)
;
else if (old_name != NULL_TREE)
error ("type was previously declared %qE", old_name);
else
*no_add_attrs = false;
}
break;
case POINTER_TYPE:
{
enum tree_code subcode = TREE_CODE (TREE_TYPE (*node));
if (subcode == FUNCTION_TYPE || subcode == METHOD_TYPE)
{
tree fn_tmp = TREE_TYPE (*node);
decl_attributes (&fn_tmp, tree_cons (name, args, NULL), 0);
*node = build_pointer_type (fn_tmp);
break;
}
}
/* FALLTHRU */
default:
/* If a function is next, pass it on to be tried next. */
if (flags & (int) ATTR_FLAG_FUNCTION_NEXT)
return tree_cons (name, args, NULL);
ignored:
warning (OPT_Wattributes, "%qE attribute ignored", name);
break;
}
return NULL_TREE;
}
/* Handle the TM_WRAP attribute; arguments as in
struct attribute_spec.handler. */
static tree
handle_tm_wrap_attribute (tree *node, tree name, tree args,
int ARG_UNUSED (flags), bool *no_add_attrs)
{
tree decl = *node;
/* We don't need the attribute even on success, since we
record the entry in an external table. */
*no_add_attrs = true;
if (TREE_CODE (decl) != FUNCTION_DECL)
warning (OPT_Wattributes, "%qE attribute ignored", name);
else
{
tree wrap_decl = TREE_VALUE (args);
if (TREE_CODE (wrap_decl) != IDENTIFIER_NODE
&& TREE_CODE (wrap_decl) != VAR_DECL
&& TREE_CODE (wrap_decl) != FUNCTION_DECL)
error ("%qE argument not an identifier", name);
else
{
if (TREE_CODE (wrap_decl) == IDENTIFIER_NODE)
wrap_decl = lookup_name (wrap_decl);
if (wrap_decl && TREE_CODE (wrap_decl) == FUNCTION_DECL)
{
if (lang_hooks.types_compatible_p (TREE_TYPE (decl),
TREE_TYPE (wrap_decl)))
record_tm_replacement (wrap_decl, decl);
else
error ("%qD is not compatible with %qD", wrap_decl, decl);
}
else
error ("transaction_wrap argument is not a function");
}
}
return NULL_TREE;
}
/* Ignore the given attribute. Used when this attribute may be usefully
overridden by the target, but is not used generically. */
static tree
ignore_attribute (tree * ARG_UNUSED (node), tree ARG_UNUSED (name),
tree ARG_UNUSED (args), int ARG_UNUSED (flags),
bool *no_add_attrs)
{
*no_add_attrs = true;
return NULL_TREE;
}
/* Handle a "no vops" attribute; arguments as in
struct attribute_spec.handler. */

View File

@ -113,6 +113,9 @@ enum rid
as a normal identifier. */
RID_CXX_COMPAT_WARN,
/* GNU transactional memory extension */
RID_TRANSACTION_ATOMIC, RID_TRANSACTION_RELAXED, RID_TRANSACTION_CANCEL,
/* Too many ways of getting the name of a function as a string */
RID_FUNCTION_NAME, RID_PRETTY_FUNCTION_NAME, RID_C99_FUNCTION_NAME,
@ -1073,6 +1076,28 @@ c_tree_chain_next (tree t)
return NULL;
}
/* Mask used by tm_stmt_attr. */
#define TM_STMT_ATTR_OUTER 2
#define TM_STMT_ATTR_ATOMIC 4
#define TM_STMT_ATTR_RELAXED 8
extern int parse_tm_stmt_attr (tree, int);
/* Mask used by tm_attr_to_mask and tm_mask_to_attr. Note that these
are ordered specifically such that more restrictive attributes are
at lower bit positions. This fact is known by the C++ tm attribute
inheritance code such that least bit extraction (mask & -mask) results
in the most restrictive attribute. */
#define TM_ATTR_SAFE 1
#define TM_ATTR_CALLABLE 2
#define TM_ATTR_PURE 4
#define TM_ATTR_IRREVOCABLE 8
#define TM_ATTR_MAY_CANCEL_OUTER 16
extern int tm_attr_to_mask (tree);
extern tree tm_mask_to_attr (int);
extern tree find_tm_attribute (tree);
/* A suffix-identifier value doublet that represents user-defined literals
for C++-0x. */
struct GTY(()) tree_userdef_literal {

View File

@ -195,6 +195,9 @@ typedef struct GTY(()) c_parser {
undesirable to bind an identifier to an Objective-C class, even
if a class with that name exists. */
BOOL_BITFIELD objc_need_raw_identifier : 1;
/* Nonzero if we're processing a __transaction statement. The value
is 1 | TM_STMT_ATTR_*. */
unsigned int in_transaction : 4;
/* True if we are in a context where the Objective-C "Property attribute"
keywords are valid. */
BOOL_BITFIELD objc_property_attr_context : 1;
@ -1171,6 +1174,9 @@ static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *,
static struct c_expr c_parser_postfix_expression_after_primary (c_parser *,
location_t loc,
struct c_expr);
static tree c_parser_transaction (c_parser *, enum rid);
static struct c_expr c_parser_transaction_expression (c_parser *, enum rid);
static tree c_parser_transaction_cancel (c_parser *);
static struct c_expr c_parser_expression (c_parser *);
static struct c_expr c_parser_expression_conv (c_parser *);
static VEC(tree,gc) *c_parser_expr_list (c_parser *, bool, bool,
@ -3413,6 +3419,66 @@ c_parser_simple_asm_expr (c_parser *parser)
return str;
}
static tree
c_parser_attribute_any_word (c_parser *parser)
{
tree attr_name = NULL_TREE;
if (c_parser_next_token_is (parser, CPP_KEYWORD))
{
/* ??? See comment above about what keywords are accepted here. */
bool ok;
switch (c_parser_peek_token (parser)->keyword)
{
case RID_STATIC:
case RID_UNSIGNED:
case RID_LONG:
case RID_INT128:
case RID_CONST:
case RID_EXTERN:
case RID_REGISTER:
case RID_TYPEDEF:
case RID_SHORT:
case RID_INLINE:
case RID_NORETURN:
case RID_VOLATILE:
case RID_SIGNED:
case RID_AUTO:
case RID_RESTRICT:
case RID_COMPLEX:
case RID_THREAD:
case RID_INT:
case RID_CHAR:
case RID_FLOAT:
case RID_DOUBLE:
case RID_VOID:
case RID_DFLOAT32:
case RID_DFLOAT64:
case RID_DFLOAT128:
case RID_BOOL:
case RID_FRACT:
case RID_ACCUM:
case RID_SAT:
case RID_TRANSACTION_ATOMIC:
case RID_TRANSACTION_CANCEL:
ok = true;
break;
default:
ok = false;
break;
}
if (!ok)
return NULL_TREE;
/* Accept __attribute__((__const)) as __attribute__((const)) etc. */
attr_name = ridpointers[(int) c_parser_peek_token (parser)->keyword];
}
else if (c_parser_next_token_is (parser, CPP_NAME))
attr_name = c_parser_peek_token (parser)->value;
return attr_name;
}
/* Parse (possibly empty) attributes. This is a GNU extension.
attributes:
@ -3473,57 +3539,10 @@ c_parser_attributes (c_parser *parser)
c_parser_consume_token (parser);
continue;
}
if (c_parser_next_token_is (parser, CPP_KEYWORD))
{
/* ??? See comment above about what keywords are
accepted here. */
bool ok;
switch (c_parser_peek_token (parser)->keyword)
{
case RID_STATIC:
case RID_UNSIGNED:
case RID_LONG:
case RID_INT128:
case RID_CONST:
case RID_EXTERN:
case RID_REGISTER:
case RID_TYPEDEF:
case RID_SHORT:
case RID_INLINE:
case RID_NORETURN:
case RID_VOLATILE:
case RID_SIGNED:
case RID_AUTO:
case RID_RESTRICT:
case RID_COMPLEX:
case RID_THREAD:
case RID_INT:
case RID_CHAR:
case RID_FLOAT:
case RID_DOUBLE:
case RID_VOID:
case RID_DFLOAT32:
case RID_DFLOAT64:
case RID_DFLOAT128:
case RID_BOOL:
case RID_FRACT:
case RID_ACCUM:
case RID_SAT:
ok = true;
break;
default:
ok = false;
break;
}
if (!ok)
break;
/* Accept __attribute__((__const)) as __attribute__((const))
etc. */
attr_name
= ridpointers[(int) c_parser_peek_token (parser)->keyword];
}
else
attr_name = c_parser_peek_token (parser)->value;
attr_name = c_parser_attribute_any_word (parser);
if (attr_name == NULL)
break;
c_parser_consume_token (parser);
if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
{
@ -4394,7 +4413,14 @@ c_parser_label (c_parser *parser)
atomic-directive expression-statement
ordered-construct:
ordered-directive structured-block */
ordered-directive structured-block
Transactional Memory:
statement:
transaction-statement
transaction-cancel-statement
*/
static void
c_parser_statement (c_parser *parser)
@ -4485,6 +4511,14 @@ c_parser_statement_after_labels (c_parser *parser)
case RID_ASM:
stmt = c_parser_asm_statement (parser);
break;
case RID_TRANSACTION_ATOMIC:
case RID_TRANSACTION_RELAXED:
stmt = c_parser_transaction (parser,
c_parser_peek_token (parser)->keyword);
break;
case RID_TRANSACTION_CANCEL:
stmt = c_parser_transaction_cancel (parser);
goto expect_semicolon;
case RID_AT_THROW:
gcc_assert (c_dialect_objc ());
c_parser_consume_token (parser);
@ -5812,6 +5846,11 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after)
unary-operator: one of
__extension__ __real__ __imag__
Transactional Memory:
unary-expression:
transaction-expression
In addition, the GNU syntax treats ++ and -- as unary operators, so
they may be applied to cast expressions with errors for non-lvalues
given later. */
@ -5919,6 +5958,10 @@ c_parser_unary_expression (c_parser *parser)
op = c_parser_cast_expression (parser, NULL);
op = default_function_array_conversion (exp_loc, op);
return parser_build_unary_op (op_loc, IMAGPART_EXPR, op);
case RID_TRANSACTION_ATOMIC:
case RID_TRANSACTION_RELAXED:
return c_parser_transaction_expression (parser,
c_parser_peek_token (parser)->keyword);
default:
return c_parser_postfix_expression (parser);
}
@ -10535,6 +10578,212 @@ c_parser_omp_threadprivate (c_parser *parser)
c_parser_skip_to_pragma_eol (parser);
}
/* Parse a transaction attribute (GCC Extension).
transaction-attribute:
attributes
[ [ any-word ] ]
The transactional memory language description is written for C++,
and uses the C++0x attribute syntax. For compatibility, allow the
bracket style for transactions in C as well. */
static tree
c_parser_transaction_attributes (c_parser *parser)
{
tree attr_name, attr = NULL;
if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
return c_parser_attributes (parser);
if (!c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
return NULL_TREE;
c_parser_consume_token (parser);
if (!c_parser_require (parser, CPP_OPEN_SQUARE, "expected %<[%>"))
goto error1;
attr_name = c_parser_attribute_any_word (parser);
if (attr_name)
{
c_parser_consume_token (parser);
attr = build_tree_list (attr_name, NULL_TREE);
}
else
c_parser_error (parser, "expected identifier");
c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>");
error1:
c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>");
return attr;
}
/* Parse a __transaction_atomic or __transaction_relaxed statement
(GCC Extension).
transaction-statement:
__transaction_atomic transaction-attribute[opt] compound-statement
__transaction_relaxed compound-statement
Note that the only valid attribute is: "outer".
*/
static tree
c_parser_transaction (c_parser *parser, enum rid keyword)
{
unsigned int old_in = parser->in_transaction;
unsigned int this_in = 1, new_in;
location_t loc = c_parser_peek_token (parser)->location;
tree stmt, attrs;
gcc_assert ((keyword == RID_TRANSACTION_ATOMIC
|| keyword == RID_TRANSACTION_RELAXED)
&& c_parser_next_token_is_keyword (parser, keyword));
c_parser_consume_token (parser);
if (keyword == RID_TRANSACTION_RELAXED)
this_in |= TM_STMT_ATTR_RELAXED;
else
{
attrs = c_parser_transaction_attributes (parser);
if (attrs)
this_in |= parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER);
}
/* Keep track if we're in the lexical scope of an outer transaction. */
new_in = this_in | (old_in & TM_STMT_ATTR_OUTER);
parser->in_transaction = new_in;
stmt = c_parser_compound_statement (parser);
parser->in_transaction = old_in;
if (flag_tm)
stmt = c_finish_transaction (loc, stmt, this_in);
else
error_at (loc, (keyword == RID_TRANSACTION_ATOMIC ?
"%<__transaction_atomic%> without transactional memory support enabled"
: "%<__transaction_relaxed %> "
"without transactional memory support enabled"));
return stmt;
}
/* Parse a __transaction_atomic or __transaction_relaxed expression
(GCC Extension).
transaction-expression:
__transaction_atomic ( expression )
__transaction_relaxed ( expression )
*/
static struct c_expr
c_parser_transaction_expression (c_parser *parser, enum rid keyword)
{
struct c_expr ret;
unsigned int old_in = parser->in_transaction;
unsigned int this_in = 1;
location_t loc = c_parser_peek_token (parser)->location;
tree attrs;
gcc_assert ((keyword == RID_TRANSACTION_ATOMIC
|| keyword == RID_TRANSACTION_RELAXED)
&& c_parser_next_token_is_keyword (parser, keyword));
c_parser_consume_token (parser);
if (keyword == RID_TRANSACTION_RELAXED)
this_in |= TM_STMT_ATTR_RELAXED;
else
{
attrs = c_parser_transaction_attributes (parser);
if (attrs)
this_in |= parse_tm_stmt_attr (attrs, 0);
}
parser->in_transaction = this_in;
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
{
tree expr = c_parser_expression (parser).value;
ret.original_type = TREE_TYPE (expr);
ret.value = build1 (TRANSACTION_EXPR, ret.original_type, expr);
if (this_in & TM_STMT_ATTR_RELAXED)
TRANSACTION_EXPR_RELAXED (ret.value) = 1;
SET_EXPR_LOCATION (ret.value, loc);
ret.original_code = TRANSACTION_EXPR;
}
else
{
c_parser_error (parser, "expected %<(%>");
ret.value = error_mark_node;
ret.original_code = ERROR_MARK;
ret.original_type = NULL;
}
parser->in_transaction = old_in;
if (!flag_tm)
error_at (loc, (keyword == RID_TRANSACTION_ATOMIC ?
"%<__transaction_atomic%> without transactional memory support enabled"
: "%<__transaction_relaxed %> "
"without transactional memory support enabled"));
return ret;
}
/* Parse a __transaction_cancel statement (GCC Extension).
transaction-cancel-statement:
__transaction_cancel transaction-attribute[opt] ;
Note that the only valid attribute is "outer".
*/
static tree
c_parser_transaction_cancel(c_parser *parser)
{
location_t loc = c_parser_peek_token (parser)->location;
tree attrs;
bool is_outer = false;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_TRANSACTION_CANCEL));
c_parser_consume_token (parser);
attrs = c_parser_transaction_attributes (parser);
if (attrs)
is_outer = (parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER) != 0);
if (!flag_tm)
{
error_at (loc, "%<__transaction_cancel%> without "
"transactional memory support enabled");
goto ret_error;
}
else if (parser->in_transaction & TM_STMT_ATTR_RELAXED)
{
error_at (loc, "%<__transaction_cancel%> within a "
"%<__transaction_relaxed%>");
goto ret_error;
}
else if (is_outer)
{
if ((parser->in_transaction & TM_STMT_ATTR_OUTER) == 0
&& !is_tm_may_cancel_outer (current_function_decl))
{
error_at (loc, "outer %<__transaction_cancel%> not "
"within outer %<__transaction_atomic%>");
error_at (loc, " or a %<transaction_may_cancel_outer%> function");
goto ret_error;
}
}
else if (parser->in_transaction == 0)
{
error_at (loc, "%<__transaction_cancel%> not within "
"%<__transaction_atomic%>");
goto ret_error;
}
return add_stmt (build_tm_abort_call (loc, is_outer));
ret_error:
return build1 (NOP_EXPR, void_type_node, error_mark_node);
}
/* Parse a single source file. */

View File

@ -603,6 +603,7 @@ extern tree c_begin_omp_task (void);
extern tree c_finish_omp_task (location_t, tree, tree);
extern tree c_finish_omp_clauses (tree);
extern tree c_build_va_arg (location_t, tree, tree);
extern tree c_finish_transaction (location_t, tree, int);
extern tree c_build_vec_perm_expr (location_t, tree, tree, tree);
/* Set to 0 at beginning of a function definition, set to 1 if

View File

@ -2716,6 +2716,9 @@ build_function_call_vec (location_t loc, tree function, VEC(tree,gc) *params,
return tem;
name = DECL_NAME (function);
if (flag_tm)
tm_malloc_replacement (function);
fundecl = function;
/* Atomic functions have type checking/casting already done. They are
often rewritten and don't match the original parameter list. */
@ -10922,6 +10925,19 @@ c_finish_omp_clauses (tree clauses)
return clauses;
}
/* Create a transaction node. */
tree
c_finish_transaction (location_t loc, tree block, int flags)
{
tree stmt = build_stmt (loc, TRANSACTION_EXPR, block);
if (flags & TM_STMT_ATTR_OUTER)
TRANSACTION_EXPR_OUTER (stmt) = 1;
if (flags & TM_STMT_ATTR_RELAXED)
TRANSACTION_EXPR_RELAXED (stmt) = 1;
return add_stmt (stmt);
}
/* Make a variant type in the proper way for C/C++, propagating qualifiers
down to the element type of an array. */

View File

@ -611,6 +611,69 @@ alloca_call_p (const_tree exp)
return false;
}
/* Return TRUE if FNDECL is either a TM builtin or a TM cloned
function. Return FALSE otherwise. */
static bool
is_tm_builtin (const_tree fndecl)
{
if (fndecl == NULL)
return false;
if (decl_is_tm_clone (fndecl))
return true;
if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
{
switch (DECL_FUNCTION_CODE (fndecl))
{
case BUILT_IN_TM_COMMIT:
case BUILT_IN_TM_COMMIT_EH:
case BUILT_IN_TM_ABORT:
case BUILT_IN_TM_IRREVOCABLE:
case BUILT_IN_TM_GETTMCLONE_IRR:
case BUILT_IN_TM_MEMCPY:
case BUILT_IN_TM_MEMMOVE:
case BUILT_IN_TM_MEMSET:
CASE_BUILT_IN_TM_STORE (1):
CASE_BUILT_IN_TM_STORE (2):
CASE_BUILT_IN_TM_STORE (4):
CASE_BUILT_IN_TM_STORE (8):
CASE_BUILT_IN_TM_STORE (FLOAT):
CASE_BUILT_IN_TM_STORE (DOUBLE):
CASE_BUILT_IN_TM_STORE (LDOUBLE):
CASE_BUILT_IN_TM_STORE (M64):
CASE_BUILT_IN_TM_STORE (M128):
CASE_BUILT_IN_TM_STORE (M256):
CASE_BUILT_IN_TM_LOAD (1):
CASE_BUILT_IN_TM_LOAD (2):
CASE_BUILT_IN_TM_LOAD (4):
CASE_BUILT_IN_TM_LOAD (8):
CASE_BUILT_IN_TM_LOAD (FLOAT):
CASE_BUILT_IN_TM_LOAD (DOUBLE):
CASE_BUILT_IN_TM_LOAD (LDOUBLE):
CASE_BUILT_IN_TM_LOAD (M64):
CASE_BUILT_IN_TM_LOAD (M128):
CASE_BUILT_IN_TM_LOAD (M256):
case BUILT_IN_TM_LOG:
case BUILT_IN_TM_LOG_1:
case BUILT_IN_TM_LOG_2:
case BUILT_IN_TM_LOG_4:
case BUILT_IN_TM_LOG_8:
case BUILT_IN_TM_LOG_FLOAT:
case BUILT_IN_TM_LOG_DOUBLE:
case BUILT_IN_TM_LOG_LDOUBLE:
case BUILT_IN_TM_LOG_M64:
case BUILT_IN_TM_LOG_M128:
case BUILT_IN_TM_LOG_M256:
return true;
default:
break;
}
}
return false;
}
/* Detect flags (function attributes) from the function decl or type node. */
int
@ -644,10 +707,28 @@ flags_from_decl_or_type (const_tree exp)
if (TREE_NOTHROW (exp))
flags |= ECF_NOTHROW;
if (flag_tm)
{
if (is_tm_builtin (exp))
flags |= ECF_TM_BUILTIN;
else if ((flags & ECF_CONST) != 0
|| lookup_attribute ("transaction_pure",
TYPE_ATTRIBUTES (TREE_TYPE (exp))))
flags |= ECF_TM_PURE;
}
flags = special_function_p (exp, flags);
}
else if (TYPE_P (exp) && TYPE_READONLY (exp))
flags |= ECF_CONST;
else if (TYPE_P (exp))
{
if (TYPE_READONLY (exp))
flags |= ECF_CONST;
if (flag_tm
&& ((flags & ECF_CONST) != 0
|| lookup_attribute ("transaction_pure", TYPE_ATTRIBUTES (exp))))
flags |= ECF_TM_PURE;
}
if (TREE_THIS_VOLATILE (exp))
{

View File

@ -338,18 +338,30 @@ make_edges (basic_block min, basic_block max, int update_p)
/* Add any appropriate EH edges. */
rtl_make_eh_edge (edge_cache, bb, insn);
if (code == CALL_INSN && nonlocal_goto_handler_labels)
if (code == CALL_INSN)
{
/* ??? This could be made smarter: in some cases it's possible
to tell that certain calls will not do a nonlocal goto.
For example, if the nested functions that do the nonlocal
gotos do not have their addresses taken, then only calls to
those functions or to other nested functions that use them
could possibly do nonlocal gotos. */
if (can_nonlocal_goto (insn))
for (x = nonlocal_goto_handler_labels; x; x = XEXP (x, 1))
make_label_edge (edge_cache, bb, XEXP (x, 0),
EDGE_ABNORMAL | EDGE_ABNORMAL_CALL);
{
/* ??? This could be made smarter: in some cases it's
possible to tell that certain calls will not do a
nonlocal goto. For example, if the nested functions
that do the nonlocal gotos do not have their addresses
taken, then only calls to those functions or to other
nested functions that use them could possibly do
nonlocal gotos. */
for (x = nonlocal_goto_handler_labels; x; x = XEXP (x, 1))
make_label_edge (edge_cache, bb, XEXP (x, 0),
EDGE_ABNORMAL | EDGE_ABNORMAL_CALL);
}
if (flag_tm)
{
rtx note;
for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
if (REG_NOTE_KIND (note) == REG_TM)
make_label_edge (edge_cache, bb, XEXP (note, 0),
EDGE_ABNORMAL | EDGE_ABNORMAL_CALL);
}
}
}

View File

@ -1802,6 +1802,38 @@ expand_gimple_cond (basic_block bb, gimple stmt)
return new_bb;
}
/* Mark all calls that can have a transaction restart. */
static void
mark_transaction_restart_calls (gimple stmt)
{
struct tm_restart_node dummy;
void **slot;
if (!cfun->gimple_df->tm_restart)
return;
dummy.stmt = stmt;
slot = htab_find_slot (cfun->gimple_df->tm_restart, &dummy, NO_INSERT);
if (slot)
{
struct tm_restart_node *n = (struct tm_restart_node *) *slot;
tree list = n->label_or_list;
rtx insn;
for (insn = next_real_insn (get_last_insn ());
!CALL_P (insn);
insn = next_real_insn (insn))
continue;
if (TREE_CODE (list) == LABEL_DECL)
add_reg_note (insn, REG_TM, label_rtx (list));
else
for (; list ; list = TREE_CHAIN (list))
add_reg_note (insn, REG_TM, label_rtx (TREE_VALUE (list)));
}
}
/* A subroutine of expand_gimple_stmt_1, expanding one GIMPLE_CALL
statement STMT. */
@ -1888,6 +1920,8 @@ expand_call_stmt (gimple stmt)
expand_assignment (lhs, exp, false);
else
expand_expr_real_1 (exp, const0_rtx, VOIDmode, EXPAND_NORMAL, NULL);
mark_transaction_restart_calls (stmt);
}
/* A subroutine of expand_gimple_stmt, expanding one gimple statement
@ -4455,6 +4489,14 @@ gimple_expand_cfg (void)
/* After expanding, the return labels are no longer needed. */
return_label = NULL;
naked_return_label = NULL;
/* After expanding, the tm_restart map is no longer needed. */
if (cfun->gimple_df->tm_restart)
{
htab_delete (cfun->gimple_df->tm_restart);
cfun->gimple_df->tm_restart = NULL;
}
/* Tag the blocks with a depth number so that change_scope can find
the common parent easily. */
set_block_levels (DECL_INITIAL (cfun->decl), 0);

View File

@ -2246,6 +2246,8 @@ purge_dead_edges (basic_block bb)
;
else if ((e->flags & EDGE_EH) && can_throw_internal (insn))
;
else if (flag_tm && find_reg_note (insn, REG_TM, NULL))
;
else
remove = true;
}

View File

@ -1840,6 +1840,8 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
fprintf (f, " only_called_at_exit");
else if (node->alias)
fprintf (f, " alias");
if (node->tm_clone)
fprintf (f, " tm_clone");
fprintf (f, "\n");

View File

@ -98,6 +98,9 @@ struct GTY(()) cgraph_local_info {
/* True when the function has been originally extern inline, but it is
redefined now. */
unsigned redefined_extern_inline : 1;
/* True if the function may enter serial irrevocable mode. */
unsigned tm_may_enter_irr : 1;
};
/* Information about the function that needs to be computed globally
@ -245,6 +248,11 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node {
unsigned only_called_at_startup : 1;
/* True when function can only be called at startup (from static dtor). */
unsigned only_called_at_exit : 1;
/* True when function is the transactional clone of a function which
is called only from inside transactions. */
/* ?? We should be able to remove this. We have enough bits in
cgraph to calculate it. */
unsigned tm_clone : 1;
};
typedef struct cgraph_node *cgraph_node_ptr;
@ -565,6 +573,8 @@ void verify_cgraph_node (struct cgraph_node *);
void cgraph_build_static_cdtor (char which, tree body, int priority);
void cgraph_reset_static_var_maps (void);
void init_cgraph (void);
struct cgraph_node * cgraph_copy_node_for_versioning (struct cgraph_node *,
tree, VEC(cgraph_edge_p,heap)*, bitmap);
struct cgraph_node *cgraph_function_versioning (struct cgraph_node *,
VEC(cgraph_edge_p,heap)*,
VEC(ipa_replace_map_p,gc)*,
@ -1082,4 +1092,14 @@ cgraph_edge_recursive_p (struct cgraph_edge *e)
else
return e->caller->decl == callee->decl;
}
/* Return true if the TM_CLONE bit is set for a given FNDECL. */
static inline bool
decl_is_tm_clone (const_tree fndecl)
{
struct cgraph_node *n = cgraph_get_node (fndecl);
if (n)
return n->tm_clone;
return false;
}
#endif /* GCC_CGRAPH_H */

View File

@ -2272,7 +2272,7 @@ update_call_expr (struct cgraph_node *new_version)
was copied to prevent duplications of calls that are dead
in the clone. */
static struct cgraph_node *
struct cgraph_node *
cgraph_copy_node_for_versioning (struct cgraph_node *old_version,
tree new_decl,
VEC(cgraph_edge_p,heap) *redirect_callers,
@ -2286,7 +2286,7 @@ cgraph_copy_node_for_versioning (struct cgraph_node *old_version,
new_version = cgraph_create_node (new_decl);
new_version->analyzed = true;
new_version->analyzed = old_version->analyzed;
new_version->local = old_version->local;
new_version->local.externally_visible = false;
new_version->local.local = true;

View File

@ -13286,6 +13286,7 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
case REG_NORETURN:
case REG_SETJMP:
case REG_TM:
/* These notes must remain with the call. It should not be
possible for both I2 and I3 to be a call. */
if (CALL_P (i3))

View File

@ -1194,6 +1194,10 @@ floop-block
Common Report Var(flag_loop_block) Optimization
Enable Loop Blocking transformation
fgnu-tm
Common Report Var(flag_tm)
Enable support for GNU transactional memory
floop-flatten
Common Report Var(flag_loop_flatten) Optimization
Enable Loop Flattening transformation

View File

@ -114,6 +114,7 @@ DEF_POINTER_TYPE (PINT, INT)
DEF_POINTER_TYPE (PULONGLONG, ULONGLONG)
DEF_POINTER_TYPE (PUNSIGNED, UNSIGNED)
DEF_POINTER_TYPE (PV2SI, V2SI)
DEF_POINTER_TYPE (PV2DF, V2DF)
DEF_POINTER_TYPE (PV2DI, V2DI)
DEF_POINTER_TYPE (PV2SF, V2SF)
@ -124,6 +125,7 @@ DEF_POINTER_TYPE (PV8SF, V8SF)
DEF_POINTER_TYPE (PV4SI, V4SI)
DEF_POINTER_TYPE (PV8SI, V8SI)
DEF_POINTER_TYPE (PCV2SI, V2SI, CONST)
DEF_POINTER_TYPE (PCV2DF, V2DF, CONST)
DEF_POINTER_TYPE (PCV2SF, V2SF, CONST)
DEF_POINTER_TYPE (PCV4DF, V4DF, CONST)
@ -175,6 +177,7 @@ DEF_FUNCTION_TYPE (V2SF, V2SI)
DEF_FUNCTION_TYPE (V2SI, V2DF)
DEF_FUNCTION_TYPE (V2SI, V2SF)
DEF_FUNCTION_TYPE (V2SI, V2SI)
DEF_FUNCTION_TYPE (V2SI, PCV2SI)
DEF_FUNCTION_TYPE (V2SI, V4SF)
DEF_FUNCTION_TYPE (V32QI, PCCHAR)
DEF_FUNCTION_TYPE (V4DF, PCDOUBLE)
@ -188,6 +191,7 @@ DEF_FUNCTION_TYPE (V4SF, PCFLOAT)
DEF_FUNCTION_TYPE (V4SF, V2DF)
DEF_FUNCTION_TYPE (V4SF, V4DF)
DEF_FUNCTION_TYPE (V4SF, V4SF)
DEF_FUNCTION_TYPE (V4SF, PCV4SF)
DEF_FUNCTION_TYPE (V4SF, V4SI)
DEF_FUNCTION_TYPE (V4SF, V8SF)
DEF_FUNCTION_TYPE (V4SF, V8HI)
@ -203,6 +207,7 @@ DEF_FUNCTION_TYPE (V8HI, V8HI)
DEF_FUNCTION_TYPE (V8QI, V8QI)
DEF_FUNCTION_TYPE (V8SF, PCFLOAT)
DEF_FUNCTION_TYPE (V8SF, PCV4SF)
DEF_FUNCTION_TYPE (V8SF, PCV8SF)
DEF_FUNCTION_TYPE (V8SF, V4SF)
DEF_FUNCTION_TYPE (V8SF, V8SF)
DEF_FUNCTION_TYPE (V8SF, V8SI)
@ -353,9 +358,12 @@ DEF_FUNCTION_TYPE (VOID, PFLOAT, V4SF)
DEF_FUNCTION_TYPE (VOID, PFLOAT, V8SF)
DEF_FUNCTION_TYPE (VOID, PINT, INT)
DEF_FUNCTION_TYPE (VOID, PULONGLONG, ULONGLONG)
DEF_FUNCTION_TYPE (VOID, PV2SI, V2SI)
DEF_FUNCTION_TYPE (VOID, PV2DI, V2DI)
DEF_FUNCTION_TYPE (VOID, PV2SF, V4SF)
DEF_FUNCTION_TYPE (VOID, PV4DI, V4DI)
DEF_FUNCTION_TYPE (VOID, PV4SF, V4SF)
DEF_FUNCTION_TYPE (VOID, PV8SF, V8SF)
DEF_FUNCTION_TYPE (VOID, UNSIGNED, UNSIGNED)
DEF_FUNCTION_TYPE (INT, V16QI, V16QI, INT)

View File

@ -5028,6 +5028,40 @@ ix86_handle_cconv_attribute (tree *node, tree name,
return NULL_TREE;
}
/* The transactional memory builtins are implicitly regparm or fastcall
depending on the ABI. Override the generic do-nothing attribute that
these builtins were declared with, and replace it with one of the two
attributes that we expect elsewhere. */
static tree
ix86_handle_tm_regparm_attribute (tree *node, tree name ATTRIBUTE_UNUSED,
tree args ATTRIBUTE_UNUSED,
int flags ATTRIBUTE_UNUSED,
bool *no_add_attrs)
{
tree alt;
/* In no case do we want to add the placeholder attribute. */
*no_add_attrs = true;
/* The 64-bit ABI is unchanged for transactional memory. */
if (TARGET_64BIT)
return NULL_TREE;
/* ??? Is there a better way to validate 32-bit windows? We have
cfun->machine->call_abi, but that seems to be set only for 64-bit. */
if (CHECK_STACK_LIMIT > 0)
alt = tree_cons (get_identifier ("fastcall"), NULL, NULL);
else
{
alt = tree_cons (NULL, build_int_cst (NULL, 2), NULL);
alt = tree_cons (get_identifier ("regparm"), alt, NULL);
}
decl_attributes (node, alt, flags);
return NULL_TREE;
}
/* This function determines from TYPE the calling-convention. */
unsigned int
@ -26790,6 +26824,154 @@ static const struct builtin_description bdesc_multi_arg[] =
{ OPTION_MASK_ISA_XOP, CODE_FOR_xop_vpermil2v8sf3, "__builtin_ia32_vpermil2ps256", IX86_BUILTIN_VPERMIL2PS256, UNKNOWN, (int)MULTI_ARG_4_SF2_SI_I1 },
};
/* TM vector builtins. */
/* Reuse the existing x86-specific `struct builtin_description' cause
we're lazy. Add casts to make them fit. */
static const struct builtin_description bdesc_tm[] =
{
{ OPTION_MASK_ISA_MMX, CODE_FOR_nothing, "__builtin__ITM_WM64", (enum ix86_builtins) BUILT_IN_TM_STORE_M64, UNKNOWN, VOID_FTYPE_PV2SI_V2SI },
{ OPTION_MASK_ISA_MMX, CODE_FOR_nothing, "__builtin__ITM_WaRM64", (enum ix86_builtins) BUILT_IN_TM_STORE_WAR_M64, UNKNOWN, VOID_FTYPE_PV2SI_V2SI },
{ OPTION_MASK_ISA_MMX, CODE_FOR_nothing, "__builtin__ITM_WaWM64", (enum ix86_builtins) BUILT_IN_TM_STORE_WAW_M64, UNKNOWN, VOID_FTYPE_PV2SI_V2SI },
{ OPTION_MASK_ISA_MMX, CODE_FOR_nothing, "__builtin__ITM_RM64", (enum ix86_builtins) BUILT_IN_TM_LOAD_M64, UNKNOWN, V2SI_FTYPE_PCV2SI },
{ OPTION_MASK_ISA_MMX, CODE_FOR_nothing, "__builtin__ITM_RaRM64", (enum ix86_builtins) BUILT_IN_TM_LOAD_RAR_M64, UNKNOWN, V2SI_FTYPE_PCV2SI },
{ OPTION_MASK_ISA_MMX, CODE_FOR_nothing, "__builtin__ITM_RaWM64", (enum ix86_builtins) BUILT_IN_TM_LOAD_RAW_M64, UNKNOWN, V2SI_FTYPE_PCV2SI },
{ OPTION_MASK_ISA_MMX, CODE_FOR_nothing, "__builtin__ITM_RfWM64", (enum ix86_builtins) BUILT_IN_TM_LOAD_RFW_M64, UNKNOWN, V2SI_FTYPE_PCV2SI },
{ OPTION_MASK_ISA_SSE, CODE_FOR_nothing, "__builtin__ITM_WM128", (enum ix86_builtins) BUILT_IN_TM_STORE_M128, UNKNOWN, VOID_FTYPE_PV4SF_V4SF },
{ OPTION_MASK_ISA_SSE, CODE_FOR_nothing, "__builtin__ITM_WaRM128", (enum ix86_builtins) BUILT_IN_TM_STORE_WAR_M128, UNKNOWN, VOID_FTYPE_PV4SF_V4SF },
{ OPTION_MASK_ISA_SSE, CODE_FOR_nothing, "__builtin__ITM_WaWM128", (enum ix86_builtins) BUILT_IN_TM_STORE_WAW_M128, UNKNOWN, VOID_FTYPE_PV4SF_V4SF },
{ OPTION_MASK_ISA_SSE, CODE_FOR_nothing, "__builtin__ITM_RM128", (enum ix86_builtins) BUILT_IN_TM_LOAD_M128, UNKNOWN, V4SF_FTYPE_PCV4SF },
{ OPTION_MASK_ISA_SSE, CODE_FOR_nothing, "__builtin__ITM_RaRM128", (enum ix86_builtins) BUILT_IN_TM_LOAD_RAR_M128, UNKNOWN, V4SF_FTYPE_PCV4SF },
{ OPTION_MASK_ISA_SSE, CODE_FOR_nothing, "__builtin__ITM_RaWM128", (enum ix86_builtins) BUILT_IN_TM_LOAD_RAW_M128, UNKNOWN, V4SF_FTYPE_PCV4SF },
{ OPTION_MASK_ISA_SSE, CODE_FOR_nothing, "__builtin__ITM_RfWM128", (enum ix86_builtins) BUILT_IN_TM_LOAD_RFW_M128, UNKNOWN, V4SF_FTYPE_PCV4SF },
{ OPTION_MASK_ISA_AVX, CODE_FOR_nothing, "__builtin__ITM_WM256", (enum ix86_builtins) BUILT_IN_TM_STORE_M256, UNKNOWN, VOID_FTYPE_PV8SF_V8SF },
{ OPTION_MASK_ISA_AVX, CODE_FOR_nothing, "__builtin__ITM_WaRM256", (enum ix86_builtins) BUILT_IN_TM_STORE_WAR_M256, UNKNOWN, VOID_FTYPE_PV8SF_V8SF },
{ OPTION_MASK_ISA_AVX, CODE_FOR_nothing, "__builtin__ITM_WaWM256", (enum ix86_builtins) BUILT_IN_TM_STORE_WAW_M256, UNKNOWN, VOID_FTYPE_PV8SF_V8SF },
{ OPTION_MASK_ISA_AVX, CODE_FOR_nothing, "__builtin__ITM_RM256", (enum ix86_builtins) BUILT_IN_TM_LOAD_M256, UNKNOWN, V8SF_FTYPE_PCV8SF },
{ OPTION_MASK_ISA_AVX, CODE_FOR_nothing, "__builtin__ITM_RaRM256", (enum ix86_builtins) BUILT_IN_TM_LOAD_RAR_M256, UNKNOWN, V8SF_FTYPE_PCV8SF },
{ OPTION_MASK_ISA_AVX, CODE_FOR_nothing, "__builtin__ITM_RaWM256", (enum ix86_builtins) BUILT_IN_TM_LOAD_RAW_M256, UNKNOWN, V8SF_FTYPE_PCV8SF },
{ OPTION_MASK_ISA_AVX, CODE_FOR_nothing, "__builtin__ITM_RfWM256", (enum ix86_builtins) BUILT_IN_TM_LOAD_RFW_M256, UNKNOWN, V8SF_FTYPE_PCV8SF },
{ OPTION_MASK_ISA_MMX, CODE_FOR_nothing, "__builtin__ITM_LM64", (enum ix86_builtins) BUILT_IN_TM_LOG_M64, UNKNOWN, VOID_FTYPE_PCVOID },
{ OPTION_MASK_ISA_SSE, CODE_FOR_nothing, "__builtin__ITM_LM128", (enum ix86_builtins) BUILT_IN_TM_LOG_M128, UNKNOWN, VOID_FTYPE_PCVOID },
{ OPTION_MASK_ISA_AVX, CODE_FOR_nothing, "__builtin__ITM_LM256", (enum ix86_builtins) BUILT_IN_TM_LOG_M256, UNKNOWN, VOID_FTYPE_PCVOID },
};
/* TM callbacks. */
/* Return the builtin decl needed to load a vector of TYPE. */
static tree
ix86_builtin_tm_load (tree type)
{
if (TREE_CODE (type) == VECTOR_TYPE)
{
switch (tree_low_cst (TYPE_SIZE (type), 1))
{
case 64:
return builtin_decl_explicit (BUILT_IN_TM_LOAD_M64);
case 128:
return builtin_decl_explicit (BUILT_IN_TM_LOAD_M128);
case 256:
return builtin_decl_explicit (BUILT_IN_TM_LOAD_M256);
}
}
return NULL_TREE;
}
/* Return the builtin decl needed to store a vector of TYPE. */
static tree
ix86_builtin_tm_store (tree type)
{
if (TREE_CODE (type) == VECTOR_TYPE)
{
switch (tree_low_cst (TYPE_SIZE (type), 1))
{
case 64:
return builtin_decl_explicit (BUILT_IN_TM_STORE_M64);
case 128:
return builtin_decl_explicit (BUILT_IN_TM_STORE_M128);
case 256:
return builtin_decl_explicit (BUILT_IN_TM_STORE_M256);
}
}
return NULL_TREE;
}
/* Initialize the transactional memory vector load/store builtins. */
static void
ix86_init_tm_builtins (void)
{
enum ix86_builtin_func_type ftype;
const struct builtin_description *d;
size_t i;
tree decl;
tree attrs_load, attrs_type_load, attrs_store, attrs_type_store;
tree attrs_log, attrs_type_log;
if (!flag_tm)
return;
/* Use whatever attributes a normal TM load has. */
decl = builtin_decl_explicit (BUILT_IN_TM_LOAD_1);
attrs_load = DECL_ATTRIBUTES (decl);
attrs_type_load = TYPE_ATTRIBUTES (TREE_TYPE (decl));
/* Use whatever attributes a normal TM store has. */
decl = builtin_decl_explicit (BUILT_IN_TM_STORE_1);
attrs_store = DECL_ATTRIBUTES (decl);
attrs_type_store = TYPE_ATTRIBUTES (TREE_TYPE (decl));
/* Use whatever attributes a normal TM log has. */
decl = builtin_decl_explicit (BUILT_IN_TM_LOG);
attrs_log = DECL_ATTRIBUTES (decl);
attrs_type_log = TYPE_ATTRIBUTES (TREE_TYPE (decl));
for (i = 0, d = bdesc_tm;
i < ARRAY_SIZE (bdesc_tm);
i++, d++)
{
if ((d->mask & ix86_isa_flags) != 0
|| (lang_hooks.builtin_function
== lang_hooks.builtin_function_ext_scope))
{
tree type, attrs, attrs_type;
enum built_in_function code = (enum built_in_function) d->code;
ftype = (enum ix86_builtin_func_type) d->flag;
type = ix86_get_builtin_func_type (ftype);
if (BUILTIN_TM_LOAD_P (code))
{
attrs = attrs_load;
attrs_type = attrs_type_load;
}
else if (BUILTIN_TM_STORE_P (code))
{
attrs = attrs_store;
attrs_type = attrs_type_store;
}
else
{
attrs = attrs_log;
attrs_type = attrs_type_log;
}
decl = add_builtin_function (d->name, type, code, BUILT_IN_NORMAL,
/* The builtin without the prefix for
calling it directly. */
d->name + strlen ("__builtin_"),
attrs);
/* add_builtin_function() will set the DECL_ATTRIBUTES, now
set the TYPE_ATTRIBUTES. */
decl_attributes (&TREE_TYPE (decl), attrs_type, ATTR_FLAG_BUILT_IN);
set_builtin_decl (code, decl, false);
}
}
}
/* Set up all the MMX/SSE builtins, even builtins for instructions that are not
in the current target ISA to allow the user to compile particular modules
@ -27163,6 +27345,7 @@ ix86_init_builtins (void)
TREE_READONLY (t) = 1;
ix86_builtins[(int) IX86_BUILTIN_COPYSIGNQ] = t;
ix86_init_tm_builtins ();
ix86_init_mmx_sse_builtins ();
if (TARGET_LP64)
@ -29921,7 +30104,6 @@ avx_vperm2f128_parallel (rtx par, enum machine_mode mode)
return mask + 1;
}
/* Store OPERAND to the memory after reload is completed. This means
that we can't easily use assign_stack_local. */
rtx
@ -34784,6 +34966,11 @@ static const struct attribute_spec ix86_attribute_table[] =
for FP arguments. */
{ "sseregparm", 0, 0, false, true, true, ix86_handle_cconv_attribute,
true },
/* The transactional memory builtins are implicitly regparm or fastcall
depending on the ABI. Override the generic do-nothing attribute that
these builtins were declared with. */
{ "*tm regparm", 0, 0, false, true, true, ix86_handle_tm_regparm_attribute,
true },
/* force_align_arg_pointer says this function realigns the stack at entry. */
{ (const char *)&ix86_force_align_arg_pointer_string, 0, 0,
false, true, true, ix86_handle_cconv_attribute, false },
@ -37954,6 +38141,12 @@ ix86_autovectorize_vector_sizes (void)
#define TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION \
ix86_builtin_vectorized_function
#undef TARGET_VECTORIZE_BUILTIN_TM_LOAD
#define TARGET_VECTORIZE_BUILTIN_TM_LOAD ix86_builtin_tm_load
#undef TARGET_VECTORIZE_BUILTIN_TM_STORE
#define TARGET_VECTORIZE_BUILTIN_TM_STORE ix86_builtin_tm_store
#undef TARGET_VECTORIZE_BUILTIN_GATHER
#define TARGET_VECTORIZE_BUILTIN_GATHER ix86_vectorize_builtin_gather

View File

@ -1,3 +1,40 @@
2011-11-07 Richard Henderson <rth@redhat.com>
Aldy Hernandez <aldyh@redhat.com>
Torvald Riegel <triegel@redhat.com>
Merged from transactional-memory.
* call.c (build_new_function_call): Call tm_malloc_replacement.
* class.c (check_bases): Compute transaction attributes for the
class based on its base classes.
(look_for_tm_attr_overrides, set_one_vmethod_tm_attributes,
set_method_tm_attributes): New.
(finish_struct_1): Call set_method_tm_attributes.
* cp-tree.h (begin_transaction_stmt, finish_transaction_stmt,
build_transaction_expr): Declare.
(TRANSACTION_EXPR_IS_STMT): New.
* decl.c (push_cp_library_fn): Set attribute to transaction_safe.
* except.c (do_get_exception_ptr): Apply transaction_pure.
(do_begin_catch): Mark _ITM_cxa_begin_catch transaction_pure and
record as transactional-memory wrapper.
(do_end_catch): Similarly for _ITM_cxa_end_catch.
(do_allocate_exception): Similarly for _ITM_cxa_allocate_exception.
(build_throw): Similarly for _ITM_cxa_throw. Make __cxa_rethrow pure.
* parser.h (struct cp_parser): Add in_transaction flag.
* parser.c (enum non_integral_constant): Add NIC_TRANSACTION.
(cp_parser_non_integral_constant_expression): Handle NIC_TRANSACTION.
(enum required_token): Add transaction tokens.
(cp_parser_transaction, cp_parser_transaction_expression,
cp_parser_function_transaction, cp_parser_transaction_cancel,
cp_parser_txn_attribute_opt): New.
(cp_parser_unary_expression): Handle RID_TRANSACTION*.
(cp_parser_statement, cp_parser_function_definition_after_declarator,
cp_parser_token_starts_function_definition_p): Same.
(cp_parser_required_error): Handle RT_TRANSACTION*.
* pt.c (tsubst_expr): Handle TRANSACTION_EXPR.
* semantics.c (begin_transaction_stmt, finish_transaction_stmt,
build_transaction_expr): New.
2011-11-08 Dodji Seketeli <dodji@redhat.com>
Fix context handling of alias-declaration

View File

@ -3826,6 +3826,9 @@ build_new_function_call (tree fn, VEC(tree,gc) **args, bool koenig_p,
return error_mark_node;
}
if (flag_tm)
tm_malloc_replacement (fn);
/* If this function was found without using argument dependent
lookup, then we want to ignore any undeclared friend
functions. */

View File

@ -1227,13 +1227,12 @@ check_bases (tree t,
int* no_const_asn_ref_p)
{
int i;
int seen_non_virtual_nearly_empty_base_p;
bool seen_non_virtual_nearly_empty_base_p = 0;
int seen_tm_mask = 0;
tree base_binfo;
tree binfo;
tree field = NULL_TREE;
seen_non_virtual_nearly_empty_base_p = 0;
if (!CLASSTYPE_NON_STD_LAYOUT (t))
for (field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
if (TREE_CODE (field) == FIELD_DECL)
@ -1338,6 +1337,23 @@ check_bases (tree t,
break;
}
}
/* Don't bother collecting tm attributes if transactional memory
support is not enabled. */
if (flag_tm)
{
tree tm_attr = find_tm_attribute (TYPE_ATTRIBUTES (basetype));
if (tm_attr)
seen_tm_mask |= tm_attr_to_mask (tm_attr);
}
}
/* If one of the base classes had TM attributes, and the current class
doesn't define its own, then the current class inherits one. */
if (seen_tm_mask && !find_tm_attribute (TYPE_ATTRIBUTES (t)))
{
tree tm_attr = tm_mask_to_attr (seen_tm_mask & -seen_tm_mask);
TYPE_ATTRIBUTES (t) = tree_cons (tm_attr, NULL, TYPE_ATTRIBUTES (t));
}
}
@ -4258,6 +4274,137 @@ clone_constructors_and_destructors (tree t)
clone_function_decl (OVL_CURRENT (fns), /*update_method_vec_p=*/1);
}
/* Subroutine of set_one_vmethod_tm_attributes. Search base classes
of TYPE for virtual functions which FNDECL overrides. Return a
mask of the tm attributes found therein. */
static int
look_for_tm_attr_overrides (tree type, tree fndecl)
{
tree binfo = TYPE_BINFO (type);
tree base_binfo;
int ix, found = 0;
for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ++ix)
{
tree o, basetype = BINFO_TYPE (base_binfo);
if (!TYPE_POLYMORPHIC_P (basetype))
continue;
o = look_for_overrides_here (basetype, fndecl);
if (o)
found |= tm_attr_to_mask (find_tm_attribute
(TYPE_ATTRIBUTES (TREE_TYPE (o))));
else
found |= look_for_tm_attr_overrides (basetype, fndecl);
}
return found;
}
/* Subroutine of set_method_tm_attributes. Handle the checks and
inheritance for one virtual method FNDECL. */
static void
set_one_vmethod_tm_attributes (tree type, tree fndecl)
{
tree tm_attr;
int found, have;
found = look_for_tm_attr_overrides (type, fndecl);
/* If FNDECL doesn't actually override anything (i.e. T is the
class that first declares FNDECL virtual), then we're done. */
if (found == 0)
return;
tm_attr = find_tm_attribute (TYPE_ATTRIBUTES (TREE_TYPE (fndecl)));
have = tm_attr_to_mask (tm_attr);
/* Intel STM Language Extension 3.0, Section 4.2 table 4:
tm_pure must match exactly, otherwise no weakening of
tm_safe > tm_callable > nothing. */
/* ??? The tm_pure attribute didn't make the transition to the
multivendor language spec. */
if (have == TM_ATTR_PURE)
{
if (found != TM_ATTR_PURE)
{
found &= -found;
goto err_override;
}
}
/* If the overridden function is tm_pure, then FNDECL must be. */
else if (found == TM_ATTR_PURE && tm_attr)
goto err_override;
/* Look for base class combinations that cannot be satisfied. */
else if (found != TM_ATTR_PURE && (found & TM_ATTR_PURE))
{
found &= ~TM_ATTR_PURE;
found &= -found;
error_at (DECL_SOURCE_LOCATION (fndecl),
"method overrides both %<transaction_pure%> and %qE methods",
tm_mask_to_attr (found));
}
/* If FNDECL did not declare an attribute, then inherit the most
restrictive one. */
else if (tm_attr == NULL)
{
apply_tm_attr (fndecl, tm_mask_to_attr (found & -found));
}
/* Otherwise validate that we're not weaker than a function
that is being overridden. */
else
{
found &= -found;
if (found <= TM_ATTR_CALLABLE && have > found)
goto err_override;
}
return;
err_override:
error_at (DECL_SOURCE_LOCATION (fndecl),
"method declared %qE overriding %qE method",
tm_attr, tm_mask_to_attr (found));
}
/* For each of the methods in T, propagate a class-level tm attribute. */
static void
set_method_tm_attributes (tree t)
{
tree class_tm_attr, fndecl;
/* Don't bother collecting tm attributes if transactional memory
support is not enabled. */
if (!flag_tm)
return;
/* Process virtual methods first, as they inherit directly from the
base virtual function and also require validation of new attributes. */
if (TYPE_CONTAINS_VPTR_P (t))
{
tree vchain;
for (vchain = BINFO_VIRTUALS (TYPE_BINFO (t)); vchain;
vchain = TREE_CHAIN (vchain))
set_one_vmethod_tm_attributes (t, BV_FN (vchain));
}
/* If the class doesn't have an attribute, nothing more to do. */
class_tm_attr = find_tm_attribute (TYPE_ATTRIBUTES (t));
if (class_tm_attr == NULL)
return;
/* Any method that does not yet have a tm attribute inherits
the one from the class. */
for (fndecl = TYPE_METHODS (t); fndecl; fndecl = TREE_CHAIN (fndecl))
{
if (!find_tm_attribute (TYPE_ATTRIBUTES (TREE_TYPE (fndecl))))
apply_tm_attr (fndecl, class_tm_attr);
}
}
/* Returns true iff class T has a user-defined constructor other than
the default constructor. */
@ -5841,6 +5988,7 @@ finish_struct_1 (tree t)
}
finish_struct_bits (t);
set_method_tm_attributes (t);
/* Complete the rtl for any static member objects of the type we're
working on. */

View File

@ -73,6 +73,7 @@ c-common.h, not after.
VEC_INIT_EXPR_IS_CONSTEXPR (in VEC_INIT_EXPR)
DECL_OVERRIDE_P (in FUNCTION_DECL)
IMPLICIT_CONV_EXPR_DIRECT_INIT (in IMPLICIT_CONV_EXPR)
TRANSACTION_EXPR_IS_STMT (in TRANSACTION_EXPR)
1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
TI_PENDING_TEMPLATE_FLAG.
TEMPLATE_PARMS_FOR_INLINE.
@ -3890,6 +3891,10 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
TREE_TYPE (OMP_CLAUSE_RANGE_CHECK (NODE, OMP_CLAUSE_PRIVATE, \
OMP_CLAUSE_COPYPRIVATE))
/* Nonzero if this transaction expression's body contains statements. */
#define TRANSACTION_EXPR_IS_STMT(NODE) \
TREE_LANG_FLAG_0 (TRANSACTION_EXPR_CHECK (NODE))
/* These macros provide convenient access to the various _STMT nodes
created when parsing template declarations. */
#define TRY_STMTS(NODE) TREE_OPERAND (TRY_BLOCK_CHECK (NODE), 0)
@ -5556,6 +5561,9 @@ extern void finish_omp_atomic (enum tree_code, enum tree_code,
extern void finish_omp_barrier (void);
extern void finish_omp_flush (void);
extern void finish_omp_taskwait (void);
extern tree begin_transaction_stmt (location_t, tree *, int);
extern void finish_transaction_stmt (tree, tree, int);
extern tree build_transaction_expr (location_t, tree, int);
extern void finish_omp_taskyield (void);
extern bool cxx_omp_create_clause_info (tree, tree, bool, bool, bool);
extern tree baselink_for_fns (tree);

View File

@ -4001,6 +4001,8 @@ push_cp_library_fn (enum tree_code operator_code, tree type)
operator_code,
type);
pushdecl (fn);
if (flag_tm)
apply_tm_attr (fn, get_identifier ("transaction_safe"));
return fn;
}

View File

@ -173,6 +173,9 @@ do_get_exception_ptr (void)
{
/* Declare void* __cxa_get_exception_ptr (void *) throw(). */
fn = declare_nothrow_library_fn (fn, ptr_type_node, ptr_type_node);
if (flag_tm)
apply_tm_attr (fn, get_identifier ("transaction_pure"));
}
return cp_build_function_call_nary (fn, tf_warning_or_error,
@ -192,6 +195,17 @@ do_begin_catch (void)
{
/* Declare void* __cxa_begin_catch (void *) throw(). */
fn = declare_nothrow_library_fn (fn, ptr_type_node, ptr_type_node);
/* Create its transactional-memory equivalent. */
if (flag_tm)
{
tree fn2 = get_identifier ("_ITM_cxa_begin_catch");
if (!get_global_value_if_present (fn2, &fn2))
fn2 = declare_nothrow_library_fn (fn2, ptr_type_node,
ptr_type_node);
apply_tm_attr (fn2, get_identifier ("transaction_pure"));
record_tm_replacement (fn, fn2);
}
}
return cp_build_function_call_nary (fn, tf_warning_or_error,
@ -231,6 +245,19 @@ do_end_catch (tree type)
fn = push_void_library_fn (fn, void_list_node);
/* This can throw if the destructor for the exception throws. */
TREE_NOTHROW (fn) = 0;
/* Create its transactional-memory equivalent. */
if (flag_tm)
{
tree fn2 = get_identifier ("_ITM_cxa_end_catch");
if (!get_global_value_if_present (fn2, &fn2))
{
fn2 = push_void_library_fn (fn2, void_list_node);
TREE_NOTHROW (fn2) = 0;
}
apply_tm_attr (fn2, get_identifier ("transaction_pure"));
record_tm_replacement (fn, fn2);
}
}
cleanup = cp_build_function_call_vec (fn, NULL, tf_warning_or_error);
@ -581,6 +608,16 @@ do_allocate_exception (tree type)
{
/* Declare void *__cxa_allocate_exception(size_t) throw(). */
fn = declare_nothrow_library_fn (fn, ptr_type_node, size_type_node);
if (flag_tm)
{
tree fn2 = get_identifier ("_ITM_cxa_allocate_exception");
if (!get_global_value_if_present (fn2, &fn2))
fn2 = declare_nothrow_library_fn (fn2, ptr_type_node,
size_type_node);
apply_tm_attr (fn2, get_identifier ("transaction_pure"));
record_tm_replacement (fn, fn2);
}
}
return cp_build_function_call_nary (fn, tf_warning_or_error,
@ -712,6 +749,15 @@ build_throw (tree exp)
ptr_type_node, ptr_type_node,
cleanup_type, NULL_TREE);
fn = push_throw_library_fn (fn, tmp);
if (flag_tm)
{
tree fn2 = get_identifier ("_ITM_cxa_throw");
if (!get_global_value_if_present (fn2, &fn2))
fn2 = push_throw_library_fn (fn2, tmp);
apply_tm_attr (fn2, get_identifier ("transaction_pure"));
record_tm_replacement (fn, fn2);
}
}
/* [except.throw]
@ -831,6 +877,9 @@ build_throw (tree exp)
(fn, build_function_type_list (void_type_node, NULL_TREE));
}
if (flag_tm)
apply_tm_attr (fn, get_identifier ("transaction_pure"));
/* ??? Indicate that this function call allows exceptions of the type
of the enclosing catch block (if known). */
exp = cp_build_function_call_vec (fn, NULL, tf_warning_or_error);

View File

@ -106,7 +106,9 @@ typedef enum non_integral_constant {
/* a comma operator */
NIC_COMMA,
/* a call to a constructor */
NIC_CONSTRUCTOR
NIC_CONSTRUCTOR,
/* a transaction expression */
NIC_TRANSACTION
} non_integral_constant;
/* The various kinds of errors about name-lookup failing. */
@ -171,7 +173,10 @@ typedef enum required_token {
RT_INTERATION, /* iteration-statement */
RT_JUMP, /* jump-statement */
RT_CLASS_KEY, /* class-key */
RT_CLASS_TYPENAME_TEMPLATE /* class, typename, or template */
RT_CLASS_TYPENAME_TEMPLATE, /* class, typename, or template */
RT_TRANSACTION_ATOMIC, /* __transaction_atomic */
RT_TRANSACTION_RELAXED, /* __transaction_relaxed */
RT_TRANSACTION_CANCEL /* __transaction_cancel */
} required_token;
/* Prototypes. */
@ -2106,6 +2111,17 @@ static bool cp_parser_extension_opt
static void cp_parser_label_declaration
(cp_parser *);
/* Transactional Memory Extensions */
static tree cp_parser_transaction
(cp_parser *, enum rid);
static tree cp_parser_transaction_expression
(cp_parser *, enum rid);
static bool cp_parser_function_transaction
(cp_parser *, enum rid);
static tree cp_parser_transaction_cancel
(cp_parser *);
enum pragma_context { pragma_external, pragma_stmt, pragma_compound };
static bool cp_parser_pragma
(cp_parser *, enum pragma_context);
@ -2671,6 +2687,10 @@ cp_parser_non_integral_constant_expression (cp_parser *parser,
error ("a call to a constructor "
"cannot appear in a constant-expression");
return true;
case NIC_TRANSACTION:
error ("a transaction expression "
"cannot appear in a constant-expression");
return true;
case NIC_THIS:
msg = "this";
break;
@ -6372,6 +6392,10 @@ cp_parser_unary_expression (cp_parser *parser, bool address_p, bool cast_p,
}
break;
case RID_TRANSACTION_ATOMIC:
case RID_TRANSACTION_RELAXED:
return cp_parser_transaction_expression (parser, keyword);
case RID_NOEXCEPT:
{
tree expr;
@ -8506,6 +8530,11 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
declaration-statement
try-block
TM Extension:
statement:
atomic-statement
IN_COMPOUND is true when the statement is nested inside a
cp_parser_compound_statement; this matters for certain pragmas.
@ -8582,6 +8611,14 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
cp_parser_declaration_statement (parser);
return;
case RID_TRANSACTION_ATOMIC:
case RID_TRANSACTION_RELAXED:
statement = cp_parser_transaction (parser, keyword);
break;
case RID_TRANSACTION_CANCEL:
statement = cp_parser_transaction_cancel (parser);
break;
default:
/* It might be a keyword like `int' that can start a
declaration-statement. */
@ -15194,6 +15231,11 @@ cp_parser_asm_definition (cp_parser* parser)
function-definition:
__extension__ function-definition
TM Extension:
function-definition:
decl-specifier-seq [opt] declarator function-transaction-block
The DECL_SPECIFIERS apply to this declarator. Returns a
representation of the entity declared. If MEMBER_P is TRUE, then
this declarator appears in a class scope. The new DECL created by
@ -20911,12 +20953,19 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
start_lambda_scope (current_function_decl);
/* If the next token is `try', then we are looking at a
function-try-block. */
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY))
/* If the next token is `try', `__transaction_atomic', or
`__transaction_relaxed`, then we are looking at either function-try-block
or function-transaction-block. Note that all of these include the
function-body. */
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRANSACTION_ATOMIC))
ctor_initializer_p = cp_parser_function_transaction (parser,
RID_TRANSACTION_ATOMIC);
else if (cp_lexer_next_token_is_keyword (parser->lexer,
RID_TRANSACTION_RELAXED))
ctor_initializer_p = cp_parser_function_transaction (parser,
RID_TRANSACTION_RELAXED);
else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY))
ctor_initializer_p = cp_parser_function_try_block (parser);
/* A function-try-block includes the function-body, so we only do
this next part if we're not processing a function-try-block. */
else
ctor_initializer_p
= cp_parser_ctor_initializer_opt_and_function_body (parser);
@ -22073,6 +22122,12 @@ cp_parser_required_error (cp_parser *parser,
case RT_AT_THROW:
cp_parser_error (parser, "expected %<@throw%>");
return;
case RT_TRANSACTION_ATOMIC:
cp_parser_error (parser, "expected %<__transaction_atomic%>");
return;
case RT_TRANSACTION_RELAXED:
cp_parser_error (parser, "expected %<__transaction_relaxed%>");
return;
default:
break;
}
@ -22303,6 +22358,10 @@ cp_parser_token_starts_function_definition_p (cp_token* token)
|| token->type == CPP_COLON
/* A function-try-block begins with `try'. */
|| token->keyword == RID_TRY
/* A function-transaction-block begins with `__transaction_atomic'
or `__transaction_relaxed'. */
|| token->keyword == RID_TRANSACTION_ATOMIC
|| token->keyword == RID_TRANSACTION_RELAXED
/* The named return value extension begins with `return'. */
|| token->keyword == RID_RETURN);
}
@ -26623,6 +26682,272 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok)
SET_EXPR_LOCATION (stmt, pragma_tok->location);
}
/* Transactional Memory parsing routines. */
/* Parse a transaction attribute.
txn-attribute:
attribute
[ [ identifier ] ]
??? Simplify this when C++0x bracket attributes are
implemented properly. */
static tree
cp_parser_txn_attribute_opt (cp_parser *parser)
{
cp_token *token;
tree attr_name, attr = NULL;
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE))
return cp_parser_attributes_opt (parser);
if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_SQUARE))
return NULL_TREE;
cp_lexer_consume_token (parser->lexer);
if (!cp_parser_require (parser, CPP_OPEN_SQUARE, RT_OPEN_SQUARE))
goto error1;
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_NAME || token->type == CPP_KEYWORD)
{
token = cp_lexer_consume_token (parser->lexer);
attr_name = (token->type == CPP_KEYWORD
/* For keywords, use the canonical spelling,
not the parsed identifier. */
? ridpointers[(int) token->keyword]
: token->u.value);
attr = build_tree_list (attr_name, NULL_TREE);
}
else
cp_parser_error (parser, "expected identifier");
cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
error1:
cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
return attr;
}
/* Parse a __transaction_atomic or __transaction_relaxed statement.
transaction-statement:
__transaction_atomic txn-attribute[opt] txn-exception-spec[opt]
compound-statement
__transaction_relaxed txn-exception-spec[opt] compound-statement
??? The exception specification is not yet implemented.
*/
static tree
cp_parser_transaction (cp_parser *parser, enum rid keyword)
{
unsigned char old_in = parser->in_transaction;
unsigned char this_in = 1, new_in;
cp_token *token;
tree stmt, attrs;
gcc_assert (keyword == RID_TRANSACTION_ATOMIC
|| keyword == RID_TRANSACTION_RELAXED);
token = cp_parser_require_keyword (parser, keyword,
(keyword == RID_TRANSACTION_ATOMIC ? RT_TRANSACTION_ATOMIC
: RT_TRANSACTION_RELAXED));
gcc_assert (token != NULL);
if (keyword == RID_TRANSACTION_RELAXED)
this_in |= TM_STMT_ATTR_RELAXED;
else
{
attrs = cp_parser_txn_attribute_opt (parser);
if (attrs)
this_in |= parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER);
}
/* Keep track if we're in the lexical scope of an outer transaction. */
new_in = this_in | (old_in & TM_STMT_ATTR_OUTER);
stmt = begin_transaction_stmt (token->location, NULL, this_in);
parser->in_transaction = new_in;
cp_parser_compound_statement (parser, NULL, false, false);
parser->in_transaction = old_in;
finish_transaction_stmt (stmt, NULL, this_in);
return stmt;
}
/* Parse a __transaction_atomic or __transaction_relaxed expression.
transaction-expression:
__transaction_atomic txn-exception-spec[opt] ( expression )
__transaction_relaxed txn-exception-spec[opt] ( expression )
??? The exception specification is not yet implemented.
*/
static tree
cp_parser_transaction_expression (cp_parser *parser, enum rid keyword)
{
unsigned char old_in = parser->in_transaction;
unsigned char this_in = 1;
cp_token *token;
tree ret;
gcc_assert (keyword == RID_TRANSACTION_ATOMIC
|| keyword == RID_TRANSACTION_RELAXED);
if (!flag_tm)
error (keyword == RID_TRANSACTION_RELAXED
? G_("%<__transaction_relaxed%> without transactional memory "
"support enabled")
: G_("%<__transaction_atomic%> without transactional memory "
"support enabled"));
token = cp_parser_require_keyword (parser, keyword,
(keyword == RID_TRANSACTION_ATOMIC ? RT_TRANSACTION_ATOMIC
: RT_TRANSACTION_RELAXED));
gcc_assert (token != NULL);
if (keyword == RID_TRANSACTION_RELAXED)
this_in |= TM_STMT_ATTR_RELAXED;
parser->in_transaction = this_in;
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
{
tree expr = cp_parser_expression (parser, /*cast_p=*/false, NULL);
ret = build_transaction_expr (token->location, expr, this_in);
}
else
{
cp_parser_error (parser, "expected %<(%>");
ret = error_mark_node;
}
parser->in_transaction = old_in;
if (cp_parser_non_integral_constant_expression (parser, NIC_TRANSACTION))
return error_mark_node;
return (flag_tm ? ret : error_mark_node);
}
/* Parse a function-transaction-block.
function-transaction-block:
__transaction_atomic txn-attribute[opt] ctor-initializer[opt]
function-body
__transaction_atomic txn-attribute[opt] function-try-block
__transaction_relaxed ctor-initializer[opt] function-body
__transaction_relaxed function-try-block
*/
static bool
cp_parser_function_transaction (cp_parser *parser, enum rid keyword)
{
unsigned char old_in = parser->in_transaction;
unsigned char new_in = 1;
tree compound_stmt, stmt, attrs;
bool ctor_initializer_p;
cp_token *token;
gcc_assert (keyword == RID_TRANSACTION_ATOMIC
|| keyword == RID_TRANSACTION_RELAXED);
token = cp_parser_require_keyword (parser, keyword,
(keyword == RID_TRANSACTION_ATOMIC ? RT_TRANSACTION_ATOMIC
: RT_TRANSACTION_RELAXED));
gcc_assert (token != NULL);
if (keyword == RID_TRANSACTION_RELAXED)
new_in |= TM_STMT_ATTR_RELAXED;
else
{
attrs = cp_parser_txn_attribute_opt (parser);
if (attrs)
new_in |= parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER);
}
stmt = begin_transaction_stmt (token->location, &compound_stmt, new_in);
parser->in_transaction = new_in;
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY))
ctor_initializer_p = cp_parser_function_try_block (parser);
else
ctor_initializer_p
= cp_parser_ctor_initializer_opt_and_function_body (parser);
parser->in_transaction = old_in;
finish_transaction_stmt (stmt, compound_stmt, new_in);
return ctor_initializer_p;
}
/* Parse a __transaction_cancel statement.
cancel-statement:
__transaction_cancel txn-attribute[opt] ;
__transaction_cancel txn-attribute[opt] throw-expression ;
??? Cancel and throw is not yet implemented. */
static tree
cp_parser_transaction_cancel (cp_parser *parser)
{
cp_token *token;
bool is_outer = false;
tree stmt, attrs;
token = cp_parser_require_keyword (parser, RID_TRANSACTION_CANCEL,
RT_TRANSACTION_CANCEL);
gcc_assert (token != NULL);
attrs = cp_parser_txn_attribute_opt (parser);
if (attrs)
is_outer = (parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER) != 0);
/* ??? Parse cancel-and-throw here. */
cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
if (!flag_tm)
{
error_at (token->location, "%<__transaction_cancel%> without "
"transactional memory support enabled");
return error_mark_node;
}
else if (parser->in_transaction & TM_STMT_ATTR_RELAXED)
{
error_at (token->location, "%<__transaction_cancel%> within a "
"%<__transaction_relaxed%>");
return error_mark_node;
}
else if (is_outer)
{
if ((parser->in_transaction & TM_STMT_ATTR_OUTER) == 0
&& !is_tm_may_cancel_outer (current_function_decl))
{
error_at (token->location, "outer %<__transaction_cancel%> not "
"within outer %<__transaction_atomic%>");
error_at (token->location,
" or a %<transaction_may_cancel_outer%> function");
return error_mark_node;
}
}
else if (parser->in_transaction == 0)
{
error_at (token->location, "%<__transaction_cancel%> not within "
"%<__transaction_atomic%>");
return error_mark_node;
}
stmt = build_tm_abort_call (token->location, is_outer);
add_stmt (stmt);
finish_stmt ();
return stmt;
}
/* The parser. */
static GTY (()) cp_parser *the_parser;

View File

@ -329,6 +329,10 @@ typedef struct GTY(()) cp_parser {
a local class. */
bool in_function_body;
/* Nonzero if we're processing a __transaction_atomic or
__transaction_relaxed statement. */
unsigned char in_transaction;
/* TRUE if we can auto-correct a colon to a scope operator. */
bool colon_corrects_to_scope_p;

View File

@ -13108,6 +13108,28 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
}
break;
case TRANSACTION_EXPR:
{
int flags = 0;
flags |= (TRANSACTION_EXPR_OUTER (t) ? TM_STMT_ATTR_OUTER : 0);
flags |= (TRANSACTION_EXPR_RELAXED (t) ? TM_STMT_ATTR_RELAXED : 0);
if (TRANSACTION_EXPR_IS_STMT (t))
{
stmt = begin_transaction_stmt (input_location, NULL, flags);
RECUR (TRANSACTION_EXPR_BODY (t));
finish_transaction_stmt (stmt, NULL, flags);
}
else
{
stmt = build_transaction_expr (EXPR_LOCATION (t),
RECUR (TRANSACTION_EXPR_BODY (t)),
flags);
return stmt;
}
}
break;
case EXPR_PACK_EXPANSION:
error ("invalid use of pack expansion expression");
return error_mark_node;

View File

@ -4968,6 +4968,64 @@ finish_omp_taskyield (void)
finish_expr_stmt (stmt);
}
/* Begin a __transaction_atomic or __transaction_relaxed statement.
If PCOMPOUND is non-null, this is for a function-transaction-block, and we
should create an extra compound stmt. */
tree
begin_transaction_stmt (location_t loc, tree *pcompound, int flags)
{
tree r;
if (pcompound)
*pcompound = begin_compound_stmt (0);
r = build_stmt (loc, TRANSACTION_EXPR, NULL_TREE);
/* Only add the statement to the function if support enabled. */
if (flag_tm)
add_stmt (r);
else
error_at (loc, ((flags & TM_STMT_ATTR_RELAXED) != 0
? G_("%<__transaction_relaxed%> without "
"transactional memory support enabled")
: G_("%<__transaction_atomic%> without "
"transactional memory support enabled")));
TRANSACTION_EXPR_BODY (r) = push_stmt_list ();
return r;
}
/* End a __transaction_atomic or __transaction_relaxed statement.
If COMPOUND_STMT is non-null, this is for a function-transaction-block,
and we should end the compound. */
void
finish_transaction_stmt (tree stmt, tree compound_stmt, int flags)
{
TRANSACTION_EXPR_BODY (stmt) = pop_stmt_list (TRANSACTION_EXPR_BODY (stmt));
TRANSACTION_EXPR_OUTER (stmt) = (flags & TM_STMT_ATTR_OUTER) != 0;
TRANSACTION_EXPR_RELAXED (stmt) = (flags & TM_STMT_ATTR_RELAXED) != 0;
TRANSACTION_EXPR_IS_STMT (stmt) = 1;
if (compound_stmt)
finish_compound_stmt (compound_stmt);
finish_stmt ();
}
/* Build a __transaction_atomic or __transaction_relaxed expression. */
tree
build_transaction_expr (location_t loc, tree expr, int flags)
{
tree ret;
ret = build1 (TRANSACTION_EXPR, TREE_TYPE (expr), expr);
if (flags & TM_STMT_ATTR_RELAXED)
TRANSACTION_EXPR_RELAXED (ret) = 1;
SET_EXPR_LOCATION (ret, loc);
return ret;
}
void
init_cp_semantics (void)
{
@ -8099,6 +8157,7 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
case STMT_EXPR:
case EXPR_STMT:
case BIND_EXPR:
case TRANSACTION_EXPR:
if (flags & tf_error)
error ("expression %qE is not a constant-expression", t);
return false;

View File

@ -1723,6 +1723,19 @@ Program Interface v3.0 @w{@uref{http://www.openmp.org/}}. This option
implies @option{-pthread}, and thus is only supported on targets that
have support for @option{-pthread}.
@item -fgnu-tm
@opindex fgnu-tm
When the option @option{-fgnu-tm} is specified, the compiler will
generate code for the Linux variant of Intel's current Transactional
Memory ABI specification document (Revision 1.1, May 6 2009). This is
an experimental feature whose interface may change in future versions
of GCC, as the official specification changes. Please note that not
all architectures are supported for this feature.
For more information on GCC's support for transactional memory,
@xref{Enabling libitm,,The GNU Transactional Memory Library,libitm,GNU
Transactional Memory Library}.
@item -fms-extensions
@opindex fms-extensions
Accept some non-standard constructs used in Microsoft header files.
@ -9113,6 +9126,13 @@ parameters only when their cumulative size is less or equal to
@option{ipa-sra-ptr-growth-factor} times the size of the original
pointer parameter.
@item tm-max-aggregate-size
When making copies of thread-local variables in a transaction, this
parameter specifies the size in bytes after which variables will be
saved with the logging functions as opposed to save/restore code
sequence pairs. This option only applies when using
@option{-fgnu-tm}.
@item graphite-max-nb-scop-params
To avoid exponential effects in the Graphite loop transforms, the
number of parameters in a Static Control Part (SCoP) is bounded. The

View File

@ -5758,6 +5758,14 @@ mode returned by @code{TARGET_VECTORIZE_PREFERRED_SIMD_MODE}.
The default is zero which means to not iterate over other vector sizes.
@end deftypefn
@deftypefn {Target Hook} tree TARGET_VECTORIZE_BUILTIN_TM_LOAD (tree)
This hook should return the built-in decl needed to load a vector of the given type within a transaction.
@end deftypefn
@deftypefn {Target Hook} tree TARGET_VECTORIZE_BUILTIN_TM_STORE (tree)
This hook should return the built-in decl needed to store a vector of the given type within a transaction.
@end deftypefn
@deftypefn {Target Hook} tree TARGET_VECTORIZE_BUILTIN_GATHER (const_tree @var{mem_vectype}, const_tree @var{index_type}, int @var{scale})
Target builtin that implements vector gather operation. @var{mem_vectype}
is the vector type of the load and @var{index_type} is scalar type of

View File

@ -5696,6 +5696,10 @@ mode returned by @code{TARGET_VECTORIZE_PREFERRED_SIMD_MODE}.
The default is zero which means to not iterate over other vector sizes.
@end deftypefn
@hook TARGET_VECTORIZE_BUILTIN_TM_LOAD
@hook TARGET_VECTORIZE_BUILTIN_TM_STORE
@hook TARGET_VECTORIZE_BUILTIN_GATHER
Target builtin that implements vector gather operation. @var{mem_vectype}
is the vector type of the load and @var{index_type} is scalar type of

View File

@ -3595,6 +3595,7 @@ try_split (rtx pat, rtx trial, int last)
case REG_NORETURN:
case REG_SETJMP:
case REG_TM:
for (insn = insn_last; insn != NULL_RTX; insn = PREV_INSN (insn))
{
if (CALL_P (insn))

View File

@ -396,6 +396,11 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
lower_sequence (gimple_eh_filter_failure (stmt), data);
break;
case GIMPLE_EH_ELSE:
lower_sequence (gimple_eh_else_n_body (stmt), data);
lower_sequence (gimple_eh_else_e_body (stmt), data);
break;
case GIMPLE_NOP:
case GIMPLE_ASM:
case GIMPLE_ASSIGN:
@ -446,6 +451,10 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
data->cannot_fallthru = false;
return;
case GIMPLE_TRANSACTION:
lower_sequence (gimple_transaction_body (stmt), data);
break;
default:
gcc_unreachable ();
}
@ -727,6 +736,10 @@ gimple_stmt_may_fallthru (gimple stmt)
return (gimple_seq_may_fallthru (gimple_try_eval (stmt))
&& gimple_seq_may_fallthru (gimple_try_cleanup (stmt)));
case GIMPLE_EH_ELSE:
return (gimple_seq_may_fallthru (gimple_eh_else_n_body (stmt))
|| gimple_seq_may_fallthru (gimple_eh_else_e_body (stmt)));
case GIMPLE_CALL:
/* Functions that do not return do not fall through. */
return (gimple_call_flags (stmt) & ECF_NORETURN) == 0;

View File

@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pass.h"
#include "gimple.h"
#include "value-prof.h"
#include "trans-mem.h"
#define INDENT(SPACE) \
do { int i; for (i = 0; i < SPACE; i++) pp_space (buffer); } while (0)
@ -162,6 +163,7 @@ debug_gimple_seq (gimple_seq seq)
'd' - outputs an int as a decimal,
's' - outputs a string,
'n' - outputs a newline,
'x' - outputs an int as hexadecimal,
'+' - increases indent by 2 then outputs a newline,
'-' - decreases indent by 2 then outputs a newline. */
@ -216,6 +218,10 @@ dump_gimple_fmt (pretty_printer *buffer, int spc, int flags,
newline_and_indent (buffer, spc);
break;
case 'x':
pp_scalar (buffer, "%x", va_arg (args, int));
break;
case '+':
spc += 2;
newline_and_indent (buffer, spc);
@ -622,6 +628,7 @@ static void
dump_gimple_call (pretty_printer *buffer, gimple gs, int spc, int flags)
{
tree lhs = gimple_call_lhs (gs);
tree fn = gimple_call_fn (gs);
if (flags & TDF_ALIAS)
{
@ -648,8 +655,7 @@ dump_gimple_call (pretty_printer *buffer, gimple gs, int spc, int flags)
dump_gimple_fmt (buffer, spc, flags, "%G <%s, %T", gs,
internal_fn_name (gimple_call_internal_fn (gs)), lhs);
else
dump_gimple_fmt (buffer, spc, flags, "%G <%T, %T",
gs, gimple_call_fn (gs), lhs);
dump_gimple_fmt (buffer, spc, flags, "%G <%T, %T", gs, fn, lhs);
if (gimple_call_num_args (gs) > 0)
{
pp_string (buffer, ", ");
@ -672,7 +678,7 @@ dump_gimple_call (pretty_printer *buffer, gimple gs, int spc, int flags)
if (gimple_call_internal_p (gs))
pp_string (buffer, internal_fn_name (gimple_call_internal_fn (gs)));
else
print_call_name (buffer, gimple_call_fn (gs), flags);
print_call_name (buffer, fn, flags);
pp_string (buffer, " (");
dump_gimple_call_args (buffer, gs, flags);
pp_character (buffer, ')');
@ -689,9 +695,59 @@ dump_gimple_call (pretty_printer *buffer, gimple gs, int spc, int flags)
if (gimple_call_return_slot_opt_p (gs))
pp_string (buffer, " [return slot optimization]");
if (gimple_call_tail_p (gs))
pp_string (buffer, " [tail call]");
/* Dump the arguments of _ITM_beginTransaction sanely. */
if (TREE_CODE (fn) == ADDR_EXPR)
fn = TREE_OPERAND (fn, 0);
if (TREE_CODE (fn) == FUNCTION_DECL && decl_is_tm_clone (fn))
pp_string (buffer, " [tm-clone]");
if (TREE_CODE (fn) == FUNCTION_DECL
&& DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL
&& DECL_FUNCTION_CODE (fn) == BUILT_IN_TM_START
&& gimple_call_num_args (gs) > 0)
{
tree t = gimple_call_arg (gs, 0);
unsigned HOST_WIDE_INT props;
gcc_assert (TREE_CODE (t) == INTEGER_CST);
pp_string (buffer, " [ ");
/* Get the transaction code properties. */
props = TREE_INT_CST_LOW (t);
if (props & PR_INSTRUMENTEDCODE)
pp_string (buffer, "instrumentedCode ");
if (props & PR_UNINSTRUMENTEDCODE)
pp_string (buffer, "uninstrumentedCode ");
if (props & PR_HASNOXMMUPDATE)
pp_string (buffer, "hasNoXMMUpdate ");
if (props & PR_HASNOABORT)
pp_string (buffer, "hasNoAbort ");
if (props & PR_HASNOIRREVOCABLE)
pp_string (buffer, "hasNoIrrevocable ");
if (props & PR_DOESGOIRREVOCABLE)
pp_string (buffer, "doesGoIrrevocable ");
if (props & PR_HASNOSIMPLEREADS)
pp_string (buffer, "hasNoSimpleReads ");
if (props & PR_AWBARRIERSOMITTED)
pp_string (buffer, "awBarriersOmitted ");
if (props & PR_RARBARRIERSOMITTED)
pp_string (buffer, "RaRBarriersOmitted ");
if (props & PR_UNDOLOGCODE)
pp_string (buffer, "undoLogCode ");
if (props & PR_PREFERUNINSTRUMENTED)
pp_string (buffer, "preferUninstrumented ");
if (props & PR_EXCEPTIONBLOCK)
pp_string (buffer, "exceptionBlock ");
if (props & PR_HASELSE)
pp_string (buffer, "hasElse ");
if (props & PR_READONLY)
pp_string (buffer, "readOnly ");
pp_string (buffer, "]");
}
}
@ -947,6 +1003,24 @@ dump_gimple_eh_must_not_throw (pretty_printer *buffer, gimple gs,
}
/* Dump a GIMPLE_EH_ELSE tuple on the pretty_printer BUFFER, SPC spaces of
indent. FLAGS specifies details to show in the dump (see TDF_* in
tree-pass.h). */
static void
dump_gimple_eh_else (pretty_printer *buffer, gimple gs, int spc, int flags)
{
if (flags & TDF_RAW)
dump_gimple_fmt (buffer, spc, flags,
"%G <%+N_BODY <%S>%nE_BODY <%S>%->", gs,
gimple_eh_else_n_body (gs), gimple_eh_else_e_body (gs));
else
dump_gimple_fmt (buffer, spc, flags,
"<<<if_normal_exit>>>%+{%S}%-<<<else_eh_exit>>>%+{%S}",
gimple_eh_else_n_body (gs), gimple_eh_else_e_body (gs));
}
/* Dump a GIMPLE_RESX tuple on the pretty_printer BUFFER, SPC spaces of
indent. FLAGS specifies details to show in the dump (see TDF_* in
tree-pass.h). */
@ -1269,6 +1343,86 @@ dump_gimple_omp_return (pretty_printer *buffer, gimple gs, int spc, int flags)
}
}
/* Dump a GIMPLE_TRANSACTION tuple on the pretty_printer BUFFER. */
static void
dump_gimple_transaction (pretty_printer *buffer, gimple gs, int spc, int flags)
{
unsigned subcode = gimple_transaction_subcode (gs);
if (flags & TDF_RAW)
{
dump_gimple_fmt (buffer, spc, flags,
"%G [SUBCODE=%x,LABEL=%T] <%+BODY <%S> >",
gs, subcode, gimple_transaction_label (gs),
gimple_transaction_body (gs));
}
else
{
if (subcode & GTMA_IS_OUTER)
pp_string (buffer, "__transaction_atomic [[outer]]");
else if (subcode & GTMA_IS_RELAXED)
pp_string (buffer, "__transaction_relaxed");
else
pp_string (buffer, "__transaction_atomic");
subcode &= ~GTMA_DECLARATION_MASK;
if (subcode || gimple_transaction_label (gs))
{
pp_string (buffer, " //");
if (gimple_transaction_label (gs))
{
pp_string (buffer, " LABEL=");
dump_generic_node (buffer, gimple_transaction_label (gs),
spc, flags, false);
}
if (subcode)
{
pp_string (buffer, " SUBCODE=[ ");
if (subcode & GTMA_HAVE_ABORT)
{
pp_string (buffer, "GTMA_HAVE_ABORT ");
subcode &= ~GTMA_HAVE_ABORT;
}
if (subcode & GTMA_HAVE_LOAD)
{
pp_string (buffer, "GTMA_HAVE_LOAD ");
subcode &= ~GTMA_HAVE_LOAD;
}
if (subcode & GTMA_HAVE_STORE)
{
pp_string (buffer, "GTMA_HAVE_STORE ");
subcode &= ~GTMA_HAVE_STORE;
}
if (subcode & GTMA_MAY_ENTER_IRREVOCABLE)
{
pp_string (buffer, "GTMA_MAY_ENTER_IRREVOCABLE ");
subcode &= ~GTMA_MAY_ENTER_IRREVOCABLE;
}
if (subcode & GTMA_DOES_GO_IRREVOCABLE)
{
pp_string (buffer, "GTMA_DOES_GO_IRREVOCABLE ");
subcode &= ~GTMA_DOES_GO_IRREVOCABLE;
}
if (subcode)
pp_printf (buffer, "0x%x ", subcode);
pp_string (buffer, "]");
}
}
if (!gimple_seq_empty_p (gimple_transaction_body (gs)))
{
newline_and_indent (buffer, spc + 2);
pp_character (buffer, '{');
pp_newline (buffer);
dump_gimple_seq (buffer, gimple_transaction_body (gs),
spc + 4, flags);
newline_and_indent (buffer, spc + 2);
pp_character (buffer, '}');
}
}
}
/* Dump a GIMPLE_ASM tuple on the pretty_printer BUFFER, SPC spaces of
indent. FLAGS specifies details to show in the dump (see TDF_* in
tree-pass.h). */
@ -1855,6 +2009,10 @@ dump_gimple_stmt (pretty_printer *buffer, gimple gs, int spc, int flags)
dump_gimple_eh_must_not_throw (buffer, gs, spc, flags);
break;
case GIMPLE_EH_ELSE:
dump_gimple_eh_else (buffer, gs, spc, flags);
break;
case GIMPLE_RESX:
dump_gimple_resx (buffer, gs, spc, flags);
break;
@ -1877,6 +2035,10 @@ dump_gimple_stmt (pretty_printer *buffer, gimple gs, int spc, int flags)
pp_string (buffer, " predictor.");
break;
case GIMPLE_TRANSACTION:
dump_gimple_transaction (buffer, gs, spc, flags);
break;
default:
GIMPLE_NIY;
}

View File

@ -743,6 +743,17 @@ gimple_build_eh_must_not_throw (tree decl)
return p;
}
/* Build a GIMPLE_EH_ELSE statement. */
gimple
gimple_build_eh_else (gimple_seq n_body, gimple_seq e_body)
{
gimple p = gimple_alloc (GIMPLE_EH_ELSE, 0);
gimple_eh_else_set_n_body (p, n_body);
gimple_eh_else_set_e_body (p, e_body);
return p;
}
/* Build a GIMPLE_TRY statement.
EVAL is the expression to evaluate.
@ -1146,6 +1157,17 @@ gimple_build_omp_atomic_store (tree val)
return p;
}
/* Build a GIMPLE_TRANSACTION statement. */
gimple
gimple_build_transaction (gimple_seq body, tree label)
{
gimple p = gimple_alloc (GIMPLE_TRANSACTION, 0);
gimple_transaction_set_body (p, body);
gimple_transaction_set_label (p, label);
return p;
}
/* Build a GIMPLE_PREDICT statement. PREDICT is one of the predictors from
predict.def, OUTCOME is NOT_TAKEN or TAKEN. */
@ -1319,9 +1341,11 @@ gimple_seq_copy (gimple_seq src)
/* Walk all the statements in the sequence SEQ calling walk_gimple_stmt
on each one. WI is as in walk_gimple_stmt.
If walk_gimple_stmt returns non-NULL, the walk is stopped, the
value is stored in WI->CALLBACK_RESULT and the statement that
produced the value is returned.
If walk_gimple_stmt returns non-NULL, the walk is stopped, and the
value is stored in WI->CALLBACK_RESULT. Also, the statement that
produced the value is returned if this statement has not been
removed by a callback (wi->removed_stmt). If the statement has
been removed, NULL is returned.
Otherwise, all the statements are walked and NULL returned. */
@ -1331,7 +1355,7 @@ walk_gimple_seq (gimple_seq seq, walk_stmt_fn callback_stmt,
{
gimple_stmt_iterator gsi;
for (gsi = gsi_start (seq); !gsi_end_p (gsi); gsi_next (&gsi))
for (gsi = gsi_start (seq); !gsi_end_p (gsi); )
{
tree ret = walk_gimple_stmt (&gsi, callback_stmt, callback_op, wi);
if (ret)
@ -1340,8 +1364,12 @@ walk_gimple_seq (gimple_seq seq, walk_stmt_fn callback_stmt,
to hold it. */
gcc_assert (wi);
wi->callback_result = ret;
return gsi_stmt (gsi);
return wi->removed_stmt ? NULL : gsi_stmt (gsi);
}
if (!wi->removed_stmt)
gsi_next (&gsi);
}
if (wi)
@ -1680,6 +1708,13 @@ walk_gimple_op (gimple stmt, walk_tree_fn callback_op,
return ret;
break;
case GIMPLE_TRANSACTION:
ret = walk_tree (gimple_transaction_label_ptr (stmt), callback_op,
wi, pset);
if (ret)
return ret;
break;
/* Tuples that do not have operands. */
case GIMPLE_NOP:
case GIMPLE_RESX:
@ -1730,10 +1765,13 @@ walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt,
gimple stmt = gsi_stmt (*gsi);
if (wi)
wi->gsi = *gsi;
{
wi->gsi = *gsi;
wi->removed_stmt = false;
if (wi && wi->want_locations && gimple_has_location (stmt))
input_location = gimple_location (stmt);
if (wi->want_locations && gimple_has_location (stmt))
input_location = gimple_location (stmt);
}
ret = NULL;
@ -1750,6 +1788,9 @@ walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt,
a value to return. */
gcc_assert (tree_ret == NULL);
if (wi && wi->removed_stmt)
return NULL;
/* Re-read stmt in case the callback changed it. */
stmt = gsi_stmt (*gsi);
}
@ -1786,6 +1827,17 @@ walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt,
return wi->callback_result;
break;
case GIMPLE_EH_ELSE:
ret = walk_gimple_seq (gimple_eh_else_n_body (stmt),
callback_stmt, callback_op, wi);
if (ret)
return wi->callback_result;
ret = walk_gimple_seq (gimple_eh_else_e_body (stmt),
callback_stmt, callback_op, wi);
if (ret)
return wi->callback_result;
break;
case GIMPLE_TRY:
ret = walk_gimple_seq (gimple_try_eval (stmt), callback_stmt, callback_op,
wi);
@ -1813,8 +1865,8 @@ walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt,
case GIMPLE_OMP_TASK:
case GIMPLE_OMP_SECTIONS:
case GIMPLE_OMP_SINGLE:
ret = walk_gimple_seq (gimple_omp_body (stmt), callback_stmt, callback_op,
wi);
ret = walk_gimple_seq (gimple_omp_body (stmt), callback_stmt,
callback_op, wi);
if (ret)
return wi->callback_result;
break;
@ -1826,6 +1878,13 @@ walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt,
return wi->callback_result;
break;
case GIMPLE_TRANSACTION:
ret = walk_gimple_seq (gimple_transaction_body (stmt),
callback_stmt, callback_op, wi);
if (ret)
return wi->callback_result;
break;
default:
gcc_assert (!gimple_has_substatements (stmt));
break;
@ -2252,6 +2311,13 @@ gimple_copy (gimple stmt)
gimple_eh_filter_set_types (copy, t);
break;
case GIMPLE_EH_ELSE:
new_seq = gimple_seq_copy (gimple_eh_else_n_body (stmt));
gimple_eh_else_set_n_body (copy, new_seq);
new_seq = gimple_seq_copy (gimple_eh_else_e_body (stmt));
gimple_eh_else_set_e_body (copy, new_seq);
break;
case GIMPLE_TRY:
new_seq = gimple_seq_copy (gimple_try_eval (stmt));
gimple_try_set_eval (copy, new_seq);
@ -2327,6 +2393,11 @@ gimple_copy (gimple stmt)
gimple_omp_set_body (copy, new_seq);
break;
case GIMPLE_TRANSACTION:
new_seq = gimple_seq_copy (gimple_transaction_body (stmt));
gimple_transaction_set_body (copy, new_seq);
break;
case GIMPLE_WITH_CLEANUP_EXPR:
new_seq = gimple_seq_copy (gimple_wce_cleanup (stmt));
gimple_wce_set_cleanup (copy, new_seq);
@ -2782,37 +2853,6 @@ is_gimple_address (const_tree t)
}
}
/* Strip out all handled components that produce invariant
offsets. */
static const_tree
strip_invariant_refs (const_tree op)
{
while (handled_component_p (op))
{
switch (TREE_CODE (op))
{
case ARRAY_REF:
case ARRAY_RANGE_REF:
if (!is_gimple_constant (TREE_OPERAND (op, 1))
|| TREE_OPERAND (op, 2) != NULL_TREE
|| TREE_OPERAND (op, 3) != NULL_TREE)
return NULL;
break;
case COMPONENT_REF:
if (TREE_OPERAND (op, 2) != NULL_TREE)
return NULL;
break;
default:;
}
op = TREE_OPERAND (op, 0);
}
return op;
}
/* Return true if T is a gimple invariant address. */
bool
@ -3075,21 +3115,6 @@ is_gimple_mem_ref_addr (tree t)
|| decl_address_invariant_p (TREE_OPERAND (t, 0)))));
}
/* If T makes a function call, return the corresponding CALL_EXPR operand.
Otherwise, return NULL_TREE. */
tree
get_call_expr_in (tree t)
{
if (TREE_CODE (t) == MODIFY_EXPR)
t = TREE_OPERAND (t, 1);
if (TREE_CODE (t) == WITH_SIZE_EXPR)
t = TREE_OPERAND (t, 0);
if (TREE_CODE (t) == CALL_EXPR)
return t;
return NULL_TREE;
}
/* Given a memory reference expression T, return its base address.
The base address of a memory reference expression is the main

View File

@ -124,6 +124,14 @@ DEFGSCODE(GIMPLE_ASM, "gimple_asm", GSS_ASM)
CHAIN is the optional static chain link for nested functions. */
DEFGSCODE(GIMPLE_CALL, "gimple_call", GSS_CALL)
/* GIMPLE_TRANSACTION <BODY, LABEL> represents __transaction_atomic and
__transaction_relaxed blocks.
BODY is the sequence of statements inside the transaction.
LABEL is a label for the statement immediately following the
transaction. This is before RETURN so that it has MEM_OPS,
so that it can clobber global memory. */
DEFGSCODE(GIMPLE_TRANSACTION, "gimple_transaction", GSS_TRANSACTION)
/* GIMPLE_RETURN <RETVAL> represents return statements.
RETVAL is the value to return or NULL. If a value is returned it
@ -151,6 +159,12 @@ DEFGSCODE(GIMPLE_EH_FILTER, "gimple_eh_filter", GSS_EH_FILTER)
be invoked if an exception propagates to this point. */
DEFGSCODE(GIMPLE_EH_MUST_NOT_THROW, "gimple_eh_must_not_throw", GSS_EH_MNT)
/* GIMPLE_EH_ELSE <N_BODY, E_BODY> must be the sole contents of
a GIMPLE_TRY_FINALLY node. For all normal exits from the try block,
N_BODY is run; for all exception exits from the try block,
E_BODY is run. */
DEFGSCODE(GIMPLE_EH_ELSE, "gimple_eh_else", GSS_EH_ELSE)
/* GIMPLE_RESX resumes execution after an exception. */
DEFGSCODE(GIMPLE_RESX, "gimple_resx", GSS_EH_CTRL)

View File

@ -487,6 +487,15 @@ struct GTY(()) gimple_statement_eh_filter {
gimple_seq failure;
};
/* GIMPLE_EH_ELSE */
struct GTY(()) gimple_statement_eh_else {
/* [ WORD 1-4 ] */
struct gimple_statement_base gsbase;
/* [ WORD 5,6 ] */
gimple_seq n_body, e_body;
};
/* GIMPLE_EH_MUST_NOT_THROW */
@ -757,6 +766,43 @@ struct GTY(()) gimple_statement_omp_atomic_store {
tree val;
};
/* GIMPLE_TRANSACTION. */
/* Bits to be stored in the GIMPLE_TRANSACTION subcode. */
/* The __transaction_atomic was declared [[outer]] or it is
__transaction_relaxed. */
#define GTMA_IS_OUTER (1u << 0)
#define GTMA_IS_RELAXED (1u << 1)
#define GTMA_DECLARATION_MASK (GTMA_IS_OUTER | GTMA_IS_RELAXED)
/* The transaction is seen to not have an abort. */
#define GTMA_HAVE_ABORT (1u << 2)
/* The transaction is seen to have loads or stores. */
#define GTMA_HAVE_LOAD (1u << 3)
#define GTMA_HAVE_STORE (1u << 4)
/* The transaction MAY enter serial irrevocable mode in its dynamic scope. */
#define GTMA_MAY_ENTER_IRREVOCABLE (1u << 5)
/* The transaction WILL enter serial irrevocable mode.
An irrevocable block post-dominates the entire transaction, such
that all invocations of the transaction will go serial-irrevocable.
In such case, we don't bother instrumenting the transaction, and
tell the runtime that it should begin the transaction in
serial-irrevocable mode. */
#define GTMA_DOES_GO_IRREVOCABLE (1u << 6)
struct GTY(()) gimple_statement_transaction
{
/* [ WORD 1-10 ] */
struct gimple_statement_with_memory_ops_base gsbase;
/* [ WORD 11 ] */
gimple_seq body;
/* [ WORD 12 ] */
tree label;
};
#define DEFGSSTRUCT(SYM, STRUCT, HAS_TREE_OP) SYM,
enum gimple_statement_structure_enum {
#include "gsstruct.def"
@ -779,6 +825,7 @@ union GTY ((desc ("gimple_statement_structure (&%h)"), variable_size)) gimple_st
struct gimple_statement_catch GTY ((tag ("GSS_CATCH"))) gimple_catch;
struct gimple_statement_eh_filter GTY ((tag ("GSS_EH_FILTER"))) gimple_eh_filter;
struct gimple_statement_eh_mnt GTY ((tag ("GSS_EH_MNT"))) gimple_eh_mnt;
struct gimple_statement_eh_else GTY ((tag ("GSS_EH_ELSE"))) gimple_eh_else;
struct gimple_statement_phi GTY ((tag ("GSS_PHI"))) gimple_phi;
struct gimple_statement_eh_ctrl GTY ((tag ("GSS_EH_CTRL"))) gimple_eh_ctrl;
struct gimple_statement_try GTY ((tag ("GSS_TRY"))) gimple_try;
@ -793,6 +840,7 @@ union GTY ((desc ("gimple_statement_structure (&%h)"), variable_size)) gimple_st
struct gimple_statement_omp_continue GTY ((tag ("GSS_OMP_CONTINUE"))) gimple_omp_continue;
struct gimple_statement_omp_atomic_load GTY ((tag ("GSS_OMP_ATOMIC_LOAD"))) gimple_omp_atomic_load;
struct gimple_statement_omp_atomic_store GTY ((tag ("GSS_OMP_ATOMIC_STORE"))) gimple_omp_atomic_store;
struct gimple_statement_transaction GTY((tag ("GSS_TRANSACTION"))) gimple_transaction;
};
/* In gimple.c. */
@ -846,6 +894,7 @@ gimple gimple_build_asm_vec (const char *, VEC(tree,gc) *, VEC(tree,gc) *,
gimple gimple_build_catch (tree, gimple_seq);
gimple gimple_build_eh_filter (tree, gimple_seq);
gimple gimple_build_eh_must_not_throw (tree);
gimple gimple_build_eh_else (gimple_seq, gimple_seq);
gimple gimple_build_try (gimple_seq, gimple_seq, enum gimple_try_flags);
gimple gimple_build_wce (gimple_seq);
gimple gimple_build_resx (int);
@ -868,6 +917,7 @@ gimple gimple_build_omp_single (gimple_seq, tree);
gimple gimple_build_cdt (tree, tree);
gimple gimple_build_omp_atomic_load (tree, tree);
gimple gimple_build_omp_atomic_store (tree);
gimple gimple_build_transaction (gimple_seq, tree);
gimple gimple_build_predict (enum br_predictor, enum prediction);
enum gimple_statement_structure_enum gss_for_assign (enum tree_code);
void sort_case_labels (VEC(tree,heap) *);
@ -963,8 +1013,6 @@ extern bool is_gimple_non_addressable (tree t);
/* Returns true iff T is a valid call address expression. */
extern bool is_gimple_call_addr (tree);
/* If T makes a function call, returns the CALL_EXPR operand. */
extern tree get_call_expr_in (tree t);
extern void recalculate_side_effects (tree);
extern bool gimple_compare_field_offset (tree, tree);
@ -1076,6 +1124,9 @@ extern tree canonicalize_cond_expr_cond (tree);
/* In omp-low.c. */
extern tree omp_reduction_init (tree, tree);
/* In trans-mem.c. */
extern void diagnose_tm_safe_errors (tree);
/* In tree-nested.c. */
extern void lower_nested_functions (tree);
extern void insert_field_into_struct (tree, tree);
@ -1134,6 +1185,7 @@ gimple_has_substatements (gimple g)
case GIMPLE_BIND:
case GIMPLE_CATCH:
case GIMPLE_EH_FILTER:
case GIMPLE_EH_ELSE:
case GIMPLE_TRY:
case GIMPLE_OMP_FOR:
case GIMPLE_OMP_MASTER:
@ -1145,6 +1197,7 @@ gimple_has_substatements (gimple g)
case GIMPLE_OMP_SINGLE:
case GIMPLE_OMP_CRITICAL:
case GIMPLE_WITH_CLEANUP_EXPR:
case GIMPLE_TRANSACTION:
return true;
default:
@ -3177,6 +3230,35 @@ gimple_eh_must_not_throw_set_fndecl (gimple gs, tree decl)
gs->gimple_eh_mnt.fndecl = decl;
}
/* GIMPLE_EH_ELSE accessors. */
static inline gimple_seq
gimple_eh_else_n_body (gimple gs)
{
GIMPLE_CHECK (gs, GIMPLE_EH_ELSE);
return gs->gimple_eh_else.n_body;
}
static inline gimple_seq
gimple_eh_else_e_body (gimple gs)
{
GIMPLE_CHECK (gs, GIMPLE_EH_ELSE);
return gs->gimple_eh_else.e_body;
}
static inline void
gimple_eh_else_set_n_body (gimple gs, gimple_seq seq)
{
GIMPLE_CHECK (gs, GIMPLE_EH_ELSE);
gs->gimple_eh_else.n_body = seq;
}
static inline void
gimple_eh_else_set_e_body (gimple gs, gimple_seq seq)
{
GIMPLE_CHECK (gs, GIMPLE_EH_ELSE);
gs->gimple_eh_else.e_body = seq;
}
/* GIMPLE_TRY accessors. */
@ -4555,6 +4637,67 @@ gimple_omp_continue_set_control_use (gimple g, tree use)
g->gimple_omp_continue.control_use = use;
}
/* Return the body for the GIMPLE_TRANSACTION statement GS. */
static inline gimple_seq
gimple_transaction_body (gimple gs)
{
GIMPLE_CHECK (gs, GIMPLE_TRANSACTION);
return gs->gimple_transaction.body;
}
/* Return the label associated with a GIMPLE_TRANSACTION. */
static inline tree
gimple_transaction_label (const_gimple gs)
{
GIMPLE_CHECK (gs, GIMPLE_TRANSACTION);
return gs->gimple_transaction.label;
}
static inline tree *
gimple_transaction_label_ptr (gimple gs)
{
GIMPLE_CHECK (gs, GIMPLE_TRANSACTION);
return &gs->gimple_transaction.label;
}
/* Return the subcode associated with a GIMPLE_TRANSACTION. */
static inline unsigned int
gimple_transaction_subcode (const_gimple gs)
{
GIMPLE_CHECK (gs, GIMPLE_TRANSACTION);
return gs->gsbase.subcode;
}
/* Set BODY to be the body for the GIMPLE_TRANSACTION statement GS. */
static inline void
gimple_transaction_set_body (gimple gs, gimple_seq body)
{
GIMPLE_CHECK (gs, GIMPLE_TRANSACTION);
gs->gimple_transaction.body = body;
}
/* Set the label associated with a GIMPLE_TRANSACTION. */
static inline void
gimple_transaction_set_label (gimple gs, tree label)
{
GIMPLE_CHECK (gs, GIMPLE_TRANSACTION);
gs->gimple_transaction.label = label;
}
/* Set the subcode associated with a GIMPLE_TRANSACTION. */
static inline void
gimple_transaction_set_subcode (gimple gs, unsigned int subcode)
{
GIMPLE_CHECK (gs, GIMPLE_TRANSACTION);
gs->gsbase.subcode = subcode;
}
/* Return a pointer to the return value for GIMPLE_RETURN GS. */
@ -4981,6 +5124,12 @@ struct walk_stmt_info
will be visited more than once. */
struct pointer_set_t *pset;
/* Operand returned by the callbacks. This is set when calling
walk_gimple_seq. If the walk_stmt_fn or walk_tree_fn callback
returns non-NULL, this field will contain the tree returned by
the last callback. */
tree callback_result;
/* Indicates whether the operand being examined may be replaced
with something that matches is_gimple_val (if true) or something
slightly more complicated (if false). "Something" technically
@ -4993,23 +5142,20 @@ struct walk_stmt_info
statement 'foo (&var)', the flag VAL_ONLY will initially be set
to true, however, when walking &var, the operand of that
ADDR_EXPR does not need to be a GIMPLE value. */
bool val_only;
BOOL_BITFIELD val_only : 1;
/* True if we are currently walking the LHS of an assignment. */
bool is_lhs;
BOOL_BITFIELD is_lhs : 1;
/* Optional. Set to true by the callback functions if they made any
changes. */
bool changed;
BOOL_BITFIELD changed : 1;
/* True if we're interested in location information. */
bool want_locations;
BOOL_BITFIELD want_locations : 1;
/* Operand returned by the callbacks. This is set when calling
walk_gimple_seq. If the walk_stmt_fn or walk_tree_fn callback
returns non-NULL, this field will contain the tree returned by
the last callback. */
tree callback_result;
/* True if we've removed the statement that was processed. */
BOOL_BITFIELD removed_stmt : 1;
};
/* Callback for walk_gimple_stmt. Called for every statement found

View File

@ -413,6 +413,8 @@ create_tmp_var_name (const char *prefix)
char *preftmp = ASTRDUP (prefix);
remove_suffix (preftmp, strlen (preftmp));
clean_symbol_name (preftmp);
prefix = preftmp;
}
@ -1072,6 +1074,12 @@ voidify_wrapper_expr (tree wrapper, tree temp)
}
break;
case TRANSACTION_EXPR:
TREE_SIDE_EFFECTS (*p) = 1;
TREE_TYPE (*p) = void_type_node;
p = &TRANSACTION_EXPR_BODY (*p);
break;
default:
goto out;
}
@ -6527,6 +6535,53 @@ gimplify_omp_atomic (tree *expr_p, gimple_seq *pre_p)
return GS_ALL_DONE;
}
/* Gimplify a TRANSACTION_EXPR. This involves gimplification of the
body, and adding some EH bits. */
static enum gimplify_status
gimplify_transaction (tree *expr_p, gimple_seq *pre_p)
{
tree expr = *expr_p, temp, tbody = TRANSACTION_EXPR_BODY (expr);
gimple g;
gimple_seq body = NULL;
struct gimplify_ctx gctx;
int subcode = 0;
/* Wrap the transaction body in a BIND_EXPR so we have a context
where to put decls for OpenMP. */
if (TREE_CODE (tbody) != BIND_EXPR)
{
tree bind = build3 (BIND_EXPR, void_type_node, NULL, tbody, NULL);
TREE_SIDE_EFFECTS (bind) = 1;
SET_EXPR_LOCATION (bind, EXPR_LOCATION (tbody));
TRANSACTION_EXPR_BODY (expr) = bind;
}
push_gimplify_context (&gctx);
temp = voidify_wrapper_expr (*expr_p, NULL);
g = gimplify_and_return_first (TRANSACTION_EXPR_BODY (expr), &body);
pop_gimplify_context (g);
g = gimple_build_transaction (body, NULL);
if (TRANSACTION_EXPR_OUTER (expr))
subcode = GTMA_IS_OUTER;
else if (TRANSACTION_EXPR_RELAXED (expr))
subcode = GTMA_IS_RELAXED;
gimple_transaction_set_subcode (g, subcode);
gimplify_seq_add_stmt (pre_p, g);
if (temp)
{
*expr_p = temp;
return GS_OK;
}
*expr_p = NULL_TREE;
return GS_ALL_DONE;
}
/* Convert the GENERIC expression tree *EXPR_P to GIMPLE. If the
expression produces a value to be used as an operand inside a GIMPLE
statement, the value will be stored back in *EXPR_P. This value will
@ -7251,6 +7306,10 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
ret = gimplify_omp_atomic (expr_p, pre_p);
break;
case TRANSACTION_EXPR:
ret = gimplify_transaction (expr_p, pre_p);
break;
case TRUTH_AND_EXPR:
case TRUTH_OR_EXPR:
case TRUTH_XOR_EXPR:

View File

@ -38,6 +38,7 @@ DEFGSSTRUCT(GSS_CATCH, gimple_statement_catch, false)
DEFGSSTRUCT(GSS_EH_FILTER, gimple_statement_eh_filter, false)
DEFGSSTRUCT(GSS_EH_MNT, gimple_statement_eh_mnt, false)
DEFGSSTRUCT(GSS_EH_CTRL, gimple_statement_eh_ctrl, false)
DEFGSSTRUCT(GSS_EH_ELSE, gimple_statement_eh_else, false)
DEFGSSTRUCT(GSS_WCE, gimple_statement_wce, false)
DEFGSSTRUCT(GSS_OMP, gimple_statement_omp, false)
DEFGSSTRUCT(GSS_OMP_CRITICAL, gimple_statement_omp_critical, false)
@ -49,3 +50,4 @@ DEFGSSTRUCT(GSS_OMP_SINGLE, gimple_statement_omp_single, false)
DEFGSSTRUCT(GSS_OMP_CONTINUE, gimple_statement_omp_continue, false)
DEFGSSTRUCT(GSS_OMP_ATOMIC_LOAD, gimple_statement_omp_atomic_load, false)
DEFGSSTRUCT(GSS_OMP_ATOMIC_STORE, gimple_statement_omp_atomic_store, false)
DEFGSSTRUCT(GSS_TRANSACTION, gimple_statement_transaction, false)

208
gcc/gtm-builtins.def Normal file
View File

@ -0,0 +1,208 @@
DEF_TM_BUILTIN (BUILT_IN_TM_START, "_ITM_beginTransaction",
BT_FN_UINT_UINT, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_COMMIT, "_ITM_commitTransaction",
BT_FN_VOID, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_COMMIT_EH, "_ITM_commitTransactionEH",
BT_FN_VOID_PTR, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_ABORT, "_ITM_abortTransaction",
BT_FN_INT, ATTR_TM_NORETURN_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_IRREVOCABLE, "_ITM_changeTransactionMode",
BT_FN_INT_INT, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_MEMCPY, "_ITM_memcpyRtWt",
BT_FN_PTR_PTR_CONST_PTR_SIZE, ATTR_TM_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_MEMMOVE, "_ITM_memmoveRtWt",
BT_FN_PTR_PTR_CONST_PTR_SIZE, ATTR_TM_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_MEMSET, "_ITM_memsetW",
BT_FN_PTR_PTR_INT_SIZE, ATTR_TM_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_GETTMCLONE_IRR, "_ITM_getTMCloneOrIrrevocable",
BT_FN_PTR_PTR, ATTR_TM_CONST_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_GETTMCLONE_SAFE, "_ITM_getTMCloneSafe",
BT_FN_PTR_PTR, ATTR_TM_CONST_NOTHROW_LIST)
/* Memory allocation builtins. */
DEF_TM_BUILTIN (BUILT_IN_TM_MALLOC, "_ITM_malloc",
BT_FN_PTR_SIZE, ATTR_TMPURE_MALLOC_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_CALLOC, "_ITM_calloc",
BT_FN_PTR_SIZE_SIZE, ATTR_TMPURE_MALLOC_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_FREE, "_ITM_free",
BT_FN_VOID_PTR, ATTR_TMPURE_NOTHROW_LIST)
/* Logging builtins. */
DEF_TM_BUILTIN (BUILT_IN_TM_LOG_1, "_ITM_LU1",
BT_FN_VOID_VPTR, ATTR_TM_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOG_2, "_ITM_LU2",
BT_FN_VOID_VPTR, ATTR_TM_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOG_4, "_ITM_LU4",
BT_FN_VOID_VPTR, ATTR_TM_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOG_8, "_ITM_LU8",
BT_FN_VOID_VPTR, ATTR_TM_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOG_FLOAT, "_ITM_LF",
BT_FN_VOID_VPTR, ATTR_TM_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOG_DOUBLE, "_ITM_LD",
BT_FN_VOID_VPTR, ATTR_TM_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOG_LDOUBLE, "_ITM_LE",
BT_FN_VOID_VPTR, ATTR_TM_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOG, "_ITM_LB",
BT_FN_VOID_VPTR_SIZE, ATTR_TM_TMPURE_NOTHROW_LIST)
/* These stubs should get defined in the backend if applicable. */
DEF_BUILTIN_STUB (BUILT_IN_TM_LOG_M64, "__builtin__ITM_LM64")
DEF_BUILTIN_STUB (BUILT_IN_TM_LOG_M128, "__builtin__ITM_LM128")
DEF_BUILTIN_STUB (BUILT_IN_TM_LOG_M256, "__builtin__ITM_LM256")
/* Writes.
Note: The writes must follow the following order: STORE, WAR, WAW.
The TM optimizations depend on this order.
BUILT_IN_TM_STORE_1 must be the first builtin.
BUILTIN_TM_LOAD_STORE_P depends on this. */
DEF_TM_BUILTIN (BUILT_IN_TM_STORE_1, "_ITM_WU1",
BT_FN_VOID_VPTR_I1, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_STORE_WAR_1, "_ITM_WaRU1",
BT_FN_VOID_VPTR_I1, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_STORE_WAW_1, "_ITM_WaWU1",
BT_FN_VOID_VPTR_I1, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_STORE_2, "_ITM_WU2",
BT_FN_VOID_VPTR_I2, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_STORE_WAR_2, "_ITM_WaRU2",
BT_FN_VOID_VPTR_I2, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_STORE_WAW_2, "_ITM_WaWU2",
BT_FN_VOID_VPTR_I2, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_STORE_4, "_ITM_WU4",
BT_FN_VOID_VPTR_I4, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_STORE_WAR_4, "_ITM_WaRU4",
BT_FN_VOID_VPTR_I4, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_STORE_WAW_4, "_ITM_WaWU4",
BT_FN_VOID_VPTR_I4, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_STORE_8, "_ITM_WU8",
BT_FN_VOID_VPTR_I8, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_STORE_WAR_8, "_ITM_WaRU8",
BT_FN_VOID_VPTR_I8, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_STORE_WAW_8, "_ITM_WaWU8",
BT_FN_VOID_VPTR_I8, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_STORE_FLOAT, "_ITM_WF",
BT_FN_VOID_VPTR_FLOAT, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_STORE_WAR_FLOAT, "_ITM_WaRF",
BT_FN_VOID_VPTR_FLOAT, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_STORE_WAW_FLOAT, "_ITM_WaWF",
BT_FN_VOID_VPTR_FLOAT, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_STORE_DOUBLE, "_ITM_WD",
BT_FN_VOID_VPTR_DOUBLE, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_STORE_WAR_DOUBLE, "_ITM_WaRD",
BT_FN_VOID_VPTR_DOUBLE, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_STORE_WAW_DOUBLE, "_ITM_WaWD",
BT_FN_VOID_VPTR_DOUBLE, ATTR_TM_NOTHROW_LIST)
/* These stubs should get defined in the backend if applicable. */
DEF_BUILTIN_STUB (BUILT_IN_TM_STORE_M64, "__builtin__ITM_WM64")
DEF_BUILTIN_STUB (BUILT_IN_TM_STORE_WAR_M64, "__builtin__ITM_WaRM64")
DEF_BUILTIN_STUB (BUILT_IN_TM_STORE_WAW_M64, "__builtin__ITM_WaWM64")
DEF_BUILTIN_STUB (BUILT_IN_TM_STORE_M128, "__builtin__ITM_WM128")
DEF_BUILTIN_STUB (BUILT_IN_TM_STORE_WAR_M128, "__builtin__ITM_WaRM128")
DEF_BUILTIN_STUB (BUILT_IN_TM_STORE_WAW_M128, "__builtin__ITM_WaWM128")
DEF_BUILTIN_STUB (BUILT_IN_TM_STORE_M256, "__builtin__ITM_WM256")
DEF_BUILTIN_STUB (BUILT_IN_TM_STORE_WAR_M256, "__builtin__ITM_WaRM256")
DEF_BUILTIN_STUB (BUILT_IN_TM_STORE_WAW_M256, "__builtin__ITM_WaWM256")
DEF_TM_BUILTIN (BUILT_IN_TM_STORE_LDOUBLE, "_ITM_WE",
BT_FN_VOID_VPTR_LDOUBLE, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_STORE_WAR_LDOUBLE, "_ITM_WaRE",
BT_FN_VOID_VPTR_LDOUBLE, ATTR_TM_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_STORE_WAW_LDOUBLE, "_ITM_WaWE",
BT_FN_VOID_VPTR_LDOUBLE, ATTR_TM_NOTHROW_LIST)
/* Note: BUILT_IN_TM_STORE_WAW_LDOUBLE must be the last TM store.
BUILTIN_TM_STORE_P depends on this. */
/* Reads.
Note: The reads must follow the following order: LOAD, RAR, RAW, RFW.
The TM optimizations depend on this order. */
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_1, "_ITM_RU1",
BT_FN_I1_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_RAR_1, "_ITM_RaRU1",
BT_FN_I1_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_RAW_1, "_ITM_RaWU1",
BT_FN_I1_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_RFW_1, "_ITM_RfWU1",
BT_FN_I1_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_2, "_ITM_RU2",
BT_FN_I2_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_RAR_2, "_ITM_RaRU2",
BT_FN_I2_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_RAW_2, "_ITM_RaWU2",
BT_FN_I2_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_RFW_2, "_ITM_RfWU2",
BT_FN_I2_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_4, "_ITM_RU4",
BT_FN_I4_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_RAR_4, "_ITM_RaRU4",
BT_FN_I4_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_RAW_4, "_ITM_RaWU4",
BT_FN_I4_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_RFW_4, "_ITM_RfWU4",
BT_FN_I4_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_8, "_ITM_RU8",
BT_FN_I8_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_RAR_8, "_ITM_RaRU8",
BT_FN_I8_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_RAW_8, "_ITM_RaWU8",
BT_FN_I8_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_RFW_8, "_ITM_RfWU8",
BT_FN_I8_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_FLOAT, "_ITM_RF",
BT_FN_FLOAT_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_RAR_FLOAT, "_ITM_RaRF",
BT_FN_FLOAT_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_RAW_FLOAT, "_ITM_RaWF",
BT_FN_FLOAT_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_RFW_FLOAT, "_ITM_RfWF",
BT_FN_FLOAT_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_DOUBLE, "_ITM_RD",
BT_FN_DOUBLE_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_RAR_DOUBLE, "_ITM_RaRD",
BT_FN_FLOAT_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_RAW_DOUBLE, "_ITM_RaWD",
BT_FN_FLOAT_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_RFW_DOUBLE, "_ITM_RfWD",
BT_FN_FLOAT_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
/* These stubs should get defined in the backend if applicable. */
DEF_BUILTIN_STUB (BUILT_IN_TM_LOAD_M64, "__builtin__ITM_RM64")
DEF_BUILTIN_STUB (BUILT_IN_TM_LOAD_RAR_M64, "__builtin__ITM_RaRM64")
DEF_BUILTIN_STUB (BUILT_IN_TM_LOAD_RAW_M64, "__builtin__ITM_RaRM64")
DEF_BUILTIN_STUB (BUILT_IN_TM_LOAD_RFW_M64, "__builtin__ITM_RfWM64")
DEF_BUILTIN_STUB (BUILT_IN_TM_LOAD_M128, "__builtin__ITM_RM128")
DEF_BUILTIN_STUB (BUILT_IN_TM_LOAD_RAR_M128, "__builtin__ITM_RaRM128")
DEF_BUILTIN_STUB (BUILT_IN_TM_LOAD_RAW_M128, "__builtin__ITM_RaRM128")
DEF_BUILTIN_STUB (BUILT_IN_TM_LOAD_RFW_M128, "__builtin__ITM_RfWM128")
DEF_BUILTIN_STUB (BUILT_IN_TM_LOAD_M256, "__builtin__ITM_RM256")
DEF_BUILTIN_STUB (BUILT_IN_TM_LOAD_RAR_M256, "__builtin__ITM_RaRM256")
DEF_BUILTIN_STUB (BUILT_IN_TM_LOAD_RAW_M256, "__builtin__ITM_RaRM256")
DEF_BUILTIN_STUB (BUILT_IN_TM_LOAD_RFW_M256, "__builtin__ITM_RfWM256")
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_LDOUBLE, "_ITM_RE",
BT_FN_LDOUBLE_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_RAR_LDOUBLE, "_ITM_RaRE",
BT_FN_LDOUBLE_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_RAW_LDOUBLE, "_ITM_RaWE",
BT_FN_LDOUBLE_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
DEF_TM_BUILTIN (BUILT_IN_TM_LOAD_RFW_LDOUBLE, "_ITM_RfWE",
BT_FN_LDOUBLE_VPTR, ATTR_TM_PURE_TMPURE_NOTHROW_LIST)
/* Note: BUILT_IN_TM_LOAD_RFW_LDOUBLE must be the last TM load as well
as the last builtin. BUILTIN_TM_LOAD_STORE_P and BUILTIN_TM_LOAD_P
depend on this. */

View File

@ -284,6 +284,14 @@ can_inline_edge_p (struct cgraph_edge *e, bool report)
e->inline_failed = CIF_EH_PERSONALITY;
inlinable = false;
}
/* TM pure functions should not get inlined if the outer function is
a TM safe function. */
else if (is_tm_pure (callee->decl)
&& is_tm_safe (e->caller->decl))
{
e->inline_failed = CIF_UNSPECIFIED;
inlinable = false;
}
/* Don't inline if the callee can throw non-call exceptions but the
caller cannot.
FIXME: this is obviously wrong for LTO where STRUCT_FUNCTION is missing.

View File

@ -139,6 +139,7 @@ static tree scan_omp_1_op (tree *, int *, void *);
case GIMPLE_TRY: \
case GIMPLE_CATCH: \
case GIMPLE_EH_FILTER: \
case GIMPLE_TRANSACTION: \
/* The sub-statements for these should be walked. */ \
*handled_ops_p = false; \
break;

View File

@ -784,6 +784,8 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
#endif
if (!opts->x_flag_fat_lto_objects && !HAVE_LTO_PLUGIN)
error_at (loc, "-fno-fat-lto-objects are supported only with linker plugin.");
if (opts->x_flag_tm)
error_at (loc, "LTO is currently not supported with transactional memory");
}
if ((opts->x_flag_lto_partition_balanced != 0) + (opts->x_flag_lto_partition_1to1 != 0)
+ (opts->x_flag_lto_partition_none != 0) >= 1)

View File

@ -606,6 +606,10 @@ extern bool unlikely_text_section_p (section *);
extern void switch_to_section (section *);
extern void output_section_asm_op (const void *);
extern void record_tm_clone_pair (tree, tree);
extern void finish_tm_clone_pairs (void);
extern tree get_tm_clone_pair (tree);
extern void default_asm_output_source_filename (FILE *, const char *);
extern void output_file_directive (FILE *, const char *);

View File

@ -872,6 +872,13 @@ DEFPARAM (PARAM_IPA_SRA_PTR_GROWTH_FACTOR,
"a pointer to an aggregate with",
2, 0, 0)
DEFPARAM (PARAM_TM_MAX_AGGREGATE_SIZE,
"tm-max-aggregate-size",
"Size in bytes after which thread-local aggregates should be "
"instrumented with the logging functions instead of save/restore "
"pairs",
9, 0, 0)
DEFPARAM (PARAM_IPA_CP_VALUE_LIST_SIZE,
"ipa-cp-value-list-size",
"Maximum size of a list of values associated with each parameter for "

View File

@ -1174,9 +1174,11 @@ init_optimization_passes (void)
p = &all_lowering_passes;
NEXT_PASS (pass_warn_unused_result);
NEXT_PASS (pass_diagnose_omp_blocks);
NEXT_PASS (pass_diagnose_tm_blocks);
NEXT_PASS (pass_mudflap_1);
NEXT_PASS (pass_lower_omp);
NEXT_PASS (pass_lower_cf);
NEXT_PASS (pass_lower_tm);
NEXT_PASS (pass_refactor_eh);
NEXT_PASS (pass_lower_eh);
NEXT_PASS (pass_build_cfg);
@ -1241,6 +1243,7 @@ init_optimization_passes (void)
}
NEXT_PASS (pass_ipa_increase_alignment);
NEXT_PASS (pass_ipa_matrix_reorg);
NEXT_PASS (pass_ipa_tm);
NEXT_PASS (pass_ipa_lower_emutls);
*p = NULL;
@ -1400,6 +1403,13 @@ init_optimization_passes (void)
NEXT_PASS (pass_uncprop);
NEXT_PASS (pass_local_pure_const);
}
NEXT_PASS (pass_tm_init);
{
struct opt_pass **p = &pass_tm_init.pass.sub;
NEXT_PASS (pass_tm_mark);
NEXT_PASS (pass_tm_memopt);
NEXT_PASS (pass_tm_edges);
}
NEXT_PASS (pass_lower_complex_O0);
NEXT_PASS (pass_cleanup_eh);
NEXT_PASS (pass_lower_resx);

View File

@ -424,6 +424,8 @@ print_node (FILE *file, const char *prefix, tree node, int indent)
fputs (" built-in", file);
if (code == FUNCTION_DECL && DECL_STATIC_CHAIN (node))
fputs (" static-chain", file);
if (TREE_CODE (node) == FUNCTION_DECL && decl_is_tm_clone (node))
fputs (" tm-clone", file);
if (code == FIELD_DECL && DECL_PACKED (node))
fputs (" packed", file);

View File

@ -3287,6 +3287,7 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt)
{
case REG_NORETURN:
case REG_SETJMP:
case REG_TM:
add_reg_note (new_insn, REG_NOTE_KIND (note),
XEXP (note, 0));
break;

View File

@ -203,6 +203,11 @@ REG_NOTE (CROSSING_JUMP)
functions that can return twice. */
REG_NOTE (SETJMP)
/* This kind of note is generated at each transactional memory
builtin, to indicate we need to generate transaction restart
edges for this insn. */
REG_NOTE (TM)
/* Indicates the cumulative offset of the stack pointer accounting
for pushed arguments. This will only be generated when
ACCUMULATE_OUTGOING_ARGS is false. */

View File

@ -1918,6 +1918,7 @@ alloc_reg_note (enum reg_note kind, rtx datum, rtx list)
case REG_CC_USER:
case REG_LABEL_TARGET:
case REG_LABEL_OPERAND:
case REG_TM:
/* These types of register notes use an INSN_LIST rather than an
EXPR_LIST, so that copying is done right and dumps look
better. */

View File

@ -1003,6 +1003,24 @@ DEFHOOK
(enum machine_mode mode, const_tree type, int misalignment, bool is_packed),
default_builtin_support_vector_misalignment)
/* Return the builtin decl needed to load a vector of TYPE. */
DEFHOOK
(builtin_tm_load,
"This hook should return the built-in decl needed to load a vector of the "
"given type within a transaction.",
tree,
(tree),
default_builtin_tm_load_store)
/* Return the builtin decl needed to store a vector of TYPE. */
DEFHOOK
(builtin_tm_store,
"This hook should return the built-in decl needed to store a vector of the "
"given type within a transaction.",
tree,
(tree),
default_builtin_tm_load_store)
/* Returns the preferred mode for SIMD operations for the specified
scalar mode. */
DEFHOOK

View File

@ -1214,6 +1214,12 @@ default_have_conditional_execution (void)
#endif
}
tree
default_builtin_tm_load_store (tree ARG_UNUSED (type))
{
return NULL_TREE;
}
/* Compute cost of moving registers to/from memory. */
int

View File

@ -152,6 +152,9 @@ extern bool default_addr_space_subset_p (addr_space_t, addr_space_t);
extern rtx default_addr_space_convert (rtx, tree, tree);
extern unsigned int default_case_values_threshold (void);
extern bool default_have_conditional_execution (void);
extern tree default_builtin_tm_load_store (tree);
extern int default_memory_move_cost (enum machine_mode, reg_class_t, bool);
extern int default_register_move_cost (enum machine_mode, reg_class_t,
reg_class_t);

View File

@ -1,3 +1,14 @@
2011-11-07 Richard Henderson <rth@redhat.com>
Aldy Hernandez <aldyh@redhat.com>
Torvald Riegel <triegel@redhat.com>
Merged from transactional-memory.
* g++.dg/dg.exp: Run transactional memory tests.
* g++.dg/tm: New directory with new tests.
* gcc.dg/tm: New directory with new tests.
* c-c++-common/tm: New directory with new tests.
2011-11-08 Dodji Seketeli <dodji@redhat.com>
Fix context handling of alias-declaration

View File

@ -0,0 +1,36 @@
/* { dg-do compile } */
/* { dg-options "-fgnu-tm -O -fdump-tree-tmmark" } */
/* Test that `nontrxn' doesn't end up inside the transaction. */
typedef struct node {
int * val;
struct node *next;
} node_t;
node_t *next;
int nontrxn1, nontrxn;
static int set_remove(int * val)
{
int result;
int * v;
__transaction_relaxed {
v = next->val;
result = (v == val);
if (result)
result = 2;
}
return result;
}
void test(void *data)
{
extern void bark(void);
if (set_remove(0))
bark();
nontrxn = 99; /* Should be outside transaction. */
}
/* { dg-final { scan-tree-dump-times "_ITM_W.*nontrxn" 0 "tmmark" } } */
/* { dg-final { cleanup-tree-dump "tmmark" } } */

View File

@ -0,0 +1,6 @@
/* { dg-do compile } */
void f(void)
{
__transaction_cancel; /* { dg-error "without transactional" } */
}

View File

@ -0,0 +1,11 @@
/* { dg-do compile } */
/* { dg-options "-fgnu-tm" } */
int g;
void f(void)
{
__transaction_atomic {
if (g == 0)
__transaction_cancel;
}
}

View File

@ -0,0 +1,8 @@
/* { dg-do compile } */
void f(void)
{
__transaction_atomic { /* { dg-error "__transaction_atomic. without trans" } */
__transaction_cancel; /* { dg-error "_cancel. without trans" } */
}
}

View File

@ -0,0 +1,9 @@
/* { dg-do compile } */
int g;
void f(void)
{
__transaction_atomic { /* { dg-error "without transactional memory" } */
g++;
}
}

View File

@ -0,0 +1,10 @@
/* { dg-do compile } */
/* { dg-options "-fgnu-tm" } */
int g;
void f(void)
{
__transaction_atomic {
g++;
}
}

View File

@ -0,0 +1,25 @@
/* { dg-do compile } */
/* { dg-options "-fgnu-tm" } */
#define TC __attribute__((transaction_callable))
#define TU __attribute__((transaction_unsafe))
#define TP __attribute__((transaction_pure))
#define TS __attribute__((transaction_safe))
extern void f1(void) TC;
extern void f2(void) TU;
extern void f3(void) TP;
extern void f4(void) TS;
extern void g1(void) TC TS; /* { dg-error "previously declared" } */
extern int v1 TP; /* { dg-warning "ignored" } */
typedef void t1(void) TC;
typedef void (*t2)(void) TC;
typedef int t3 TC; /* { dg-warning "ignored" } */
typedef void u0(void);
typedef u0 u1 TC;
typedef u1 u2 TP; /* { dg-error "previously declared" } */
typedef u0 *u3 TS;
typedef u3 u4 TU; /* { dg-error "previously declared" } */

View File

@ -0,0 +1,17 @@
/* { dg-do compile } */
/* { dg-options "-fgnu-tm" } */
void unsafe(void) __attribute__((transaction_unsafe));
void
f(void)
{
int a;
__transaction_atomic {
a = 1;
__transaction_atomic {
__transaction_cancel;
}
}
unsafe();
}

View File

@ -0,0 +1,14 @@
/* { dg-do compile } */
/* { dg-options "-fgnu-tm -O" } */
extern __attribute__((transaction_safe)) void TMreleaseNode ();
int global;
__attribute__((transaction_safe))
void
TMrbtree_insert ()
{
if (global)
TMreleaseNode();
}

View File

@ -0,0 +1,8 @@
// { dg-do compile }
// { dg-options "-fgnu-tm" }
__attribute__((transaction_callable))
void func()
{
__asm__ ("");
}

View File

@ -0,0 +1,17 @@
/* { dg-do compile } */
/* { dg-options "-fgnu-tm -O1" } */
static inline void
inline_death ()
{
__asm__ (""); /* { dg-error "asm not allowed" } */
}
void
tranfunction ()
{
__transaction_atomic
{
inline_death ();
}
}

View File

@ -0,0 +1,23 @@
/* { dg-do compile } */
/* { dg-options "-fgnu-tm -O -fdump-ipa-tmipa" } */
int val, george;
extern void func();
int set_remove(void)
{
int result = 8;
__transaction_atomic {
result = george;
if (val)
goto out;
}
out:
func();
return result;
}
/* { dg-final { scan-ipa-dump-not "getTMCloneOrIrrevocable" "tmipa" } } */
/* { dg-final { cleanup-ipa-dump "tmipa" } } */

View File

@ -0,0 +1,24 @@
/* { dg-do compile } */
/* { dg-options "-fgnu-tm -fdump-tree-tmmark" } */
#include <stdlib.h>
char *z;
void foobar(void)
{
char *p, *q;
__transaction_atomic {
p = (char *)malloc(123);
q = (char *)calloc(555,1);
free(q);
free(p);
}
z = (char *)malloc (666);
}
/* { dg-final { scan-tree-dump-times " malloc .666" 1 "tmmark" } } */
/* { dg-final { scan-tree-dump-times "__builtin__ITM_malloc" 1 "tmmark" } } */
/* { dg-final { scan-tree-dump-times "__builtin__ITM_calloc" 1 "tmmark" } } */
/* { dg-final { scan-tree-dump-times "__builtin__ITM_free" 2 "tmmark" } } */
/* { dg-final { cleanup-tree-dump "tmmark" } } */

View File

@ -0,0 +1,9 @@
/* { dg-do compile } */
/* { dg-options "-fgnu-tm" } */
#include <string.h>
__attribute__((transaction_safe))
void *wmemcpy(void *dest, const void *src, size_t n)
{
return memcpy(dest, src, n);
}

View File

@ -0,0 +1,22 @@
/* { dg-do compile } */
/* { dg-options "-fgnu-tm -fopenmp" } */
__attribute__ ((transaction_pure))
unsigned long rdtsc();
typedef struct ENTER_EXIT_TIMES
{
unsigned long enter;
} times_t;
void ParClassify()
{
void * Parent;
#pragma omp parallel private(Parent)
{
times_t inside;
__transaction_atomic {
inside.enter = rdtsc();
}
}
}

View File

@ -0,0 +1,31 @@
/* { dg-do compile } */
/* { dg-options "-fgnu-tm" } */
void mco(void) __attribute__((transaction_may_cancel_outer));
void
f(void)
{
mco(); /* { dg-error "" } */
__transaction_atomic {
mco(); /* { dg-error "" } */
}
__transaction_relaxed {
mco(); /* { dg-error "" } */
}
__transaction_atomic [[outer]] {
mco();
}
}
void __attribute__((transaction_may_cancel_outer))
g(void)
{
mco();
__transaction_atomic {
mco();
}
__transaction_atomic [[outer]] { /* { dg-error "" } */
mco();
}
}

View File

@ -0,0 +1,69 @@
/* { dg-do compile } */
/* { dg-options "-fgnu-tm" } */
void ts(void) __attribute__((transaction_safe));
void tp(void) __attribute__((transaction_pure));
void tc(void) __attribute__((transaction_callable));
void ti(void) __attribute__((transaction_unsafe));
void tm(void) __attribute__((transaction_may_cancel_outer));
void tu(void);
int fc(int) __attribute__((const));
typedef void (*Fs) (void) __attribute__((transaction_safe));
typedef void (*Fc) (void) __attribute__((transaction_callable));
typedef void (*Fi) (void) __attribute__((transaction_unsafe));
typedef void (*Fm) (void) __attribute__((transaction_may_cancel_outer));
extern Fs ps;
extern Fc pc;
extern Fi pi;
extern Fm pm;
extern void (*pu)(void);
int __attribute__((transaction_safe))
foo(void)
{
int i;
ts();
tp();
tc(); /* { dg-error "unsafe function call" } */
ti(); /* { dg-error "unsafe function call" } */
/* ??? Direct function calls without markups are handled later
than pass_diagnose_tm_blocks, which means we'll exit with
errors before getting there. This test moved to safe-3.c. */
/* tu(); */
(*ps)();
(*pc)(); /* { dg-error "unsafe function call" } */
(*pi)(); /* { dg-error "unsafe function call" } */
(*pu)(); /* { dg-error "unsafe function call" } */
asm(""); /* { dg-error "asm not allowed" } */
asm("" : "=g"(i)); /* { dg-error "asm not allowed" } */
return fc(i);
}
int __attribute__((transaction_may_cancel_outer))
bar(void)
{
int i;
ts();
tp();
tc(); /* { dg-error "unsafe function call" } */
ti(); /* { dg-error "unsafe function call" } */
tm();
(*ps)();
(*pc)(); /* { dg-error "unsafe function call" } */
(*pi)(); /* { dg-error "unsafe function call" } */
(*pm)();
(*pu)(); /* { dg-error "unsafe function call" } */
asm(""); /* { dg-error "asm not allowed" } */
asm("" : "=g"(i)); /* { dg-error "asm not allowed" } */
return fc(i);
}

View File

@ -0,0 +1,43 @@
/* { dg-do compile } */
/* { dg-options "-fgnu-tm" } */
void mco(void) __attribute__((transaction_may_cancel_outer));
void
f(void)
{
mco(); /* { dg-error "" } */
__transaction_atomic {
mco(); /* { dg-error "" } */
}
__transaction_relaxed {
mco(); /* { dg-error "" } */
}
__transaction_atomic [[outer]] {
mco();
}
__transaction_atomic [[outer]] {
__transaction_atomic {
__transaction_atomic {
__transaction_atomic {
mco();
}
}
}
}
}
void __attribute__((transaction_may_cancel_outer))
g(void)
{
mco();
__transaction_atomic {
__transaction_atomic {
__transaction_atomic {
__transaction_atomic {
mco();
}
}
}
}
}

View File

@ -0,0 +1,48 @@
/* { dg-do compile } */
/* { dg-options "-fgnu-tm" } */
void f_extern (void);
void f_first (void);
void f_later (void);
extern int x;
void f_first (void) { x++; }
void __attribute__((transaction_safe))
test_safe (void)
{
f_extern (); /* { dg-error "unsafe function call" } */
f_first ();
f_later ();
}
void __attribute__((transaction_may_cancel_outer))
test_mco (void)
{
f_extern (); /* { dg-error "unsafe function call" } */
f_first ();
f_later ();
}
void
test_atomic (void)
{
__transaction_atomic {
f_extern (); /* { dg-error "unsafe function call" } */
f_first ();
f_later ();
}
__transaction_relaxed {
f_extern ();
f_first ();
f_later ();
}
__transaction_atomic [[outer]] {
f_extern (); /* { dg-error "unsafe function call" } */
f_first ();
f_later ();
}
}
void f_later () { f_first(); test_safe(); }

View File

@ -0,0 +1,15 @@
/* { dg-do compile } */
/* Make sure that we don't just crash without -fgnu-tm enabled. */
/* { dg-options "" } */
int x;
int foo(void)
{
return __transaction_atomic (x + 1); /* { dg-error "" } */
}
int bar(void)
{
return __transaction_relaxed (x + 1); /* { dg-error "" } */
}

View File

@ -0,0 +1,13 @@
/* { dg-do compile } */
/* { dg-options "-fgnu-tm -fdump-tree-tmmark" } */
int y, x, york;
void foobar(void)
{
x = y + __transaction_atomic (york);
}
/* { dg-final { scan-tree-dump-times "_ITM_RU.*york" 1 "tmmark" } } */
/* { dg-final { scan-tree-dump-times "_ITM_RU" 1 "tmmark" } } */
/* { dg-final { cleanup-tree-dump "tmmark" } } */

View File

@ -0,0 +1,10 @@
/* { dg-do compile } */
/* { dg-options "-fgnu-tm -fdump-tree-optimized" } */
void orig(void);
void xyzzy(void) __attribute__((transaction_wrap (orig)));
void foo() { __transaction_relaxed { orig (); } }
/* { dg-final { scan-tree-dump-times "xyzzy" 1 "optimized" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */

View File

@ -47,6 +47,7 @@ set tests [prune $tests $srcdir/$subdir/gomp/*]
set tests [prune $tests $srcdir/$subdir/tree-prof/*]
set tests [prune $tests $srcdir/$subdir/torture/*]
set tests [prune $tests $srcdir/$subdir/graphite/*]
set tests [prune $tests $srcdir/$subdir/tm/*]
set tests [prune $tests $srcdir/$subdir/guality/*]
set tests [prune $tests $srcdir/$subdir/simulate-thread/*]

View File

@ -0,0 +1,15 @@
// { dg-do compile }
// { dg-options "-fgnu-tm" }
int foo(int a);
int foo(float a);
int
bar(int a)
{
int r;
__transaction_atomic
{
r = foo(a); // { dg-error "unsafe function call 'int foo\\(int\\)'" }
}
return r;
}

View File

@ -0,0 +1,796 @@
// { dg-do compile }
// { dg-options "-fgnu-tm" }
typedef long int ptrdiff_t;
typedef long unsigned int size_t;
namespace std __attribute__ ((__visibility__ ("default")))
{
using::ptrdiff_t;
using::size_t;
}
namespace std __attribute__ ((__visibility__ ("default")))
{
struct input_iterator_tag
{
};
struct output_iterator_tag
{
};
struct forward_iterator_tag:public input_iterator_tag
{
};
struct bidirectional_iterator_tag:public forward_iterator_tag
{
};
struct random_access_iterator_tag:public bidirectional_iterator_tag
{
};
template < typename _Category, typename _Tp, typename _Distance =
ptrdiff_t, typename _Pointer = _Tp *, typename _Reference =
_Tp & >struct iterator
{
typedef _Category iterator_category;
typedef _Tp value_type;
typedef _Distance difference_type;
typedef _Pointer pointer;
typedef _Reference reference;
};
template < typename _Iterator > struct iterator_traits
{
typedef typename _Iterator::iterator_category iterator_category;
typedef typename _Iterator::value_type value_type;
typedef typename _Iterator::difference_type difference_type;
typedef typename _Iterator::pointer pointer;
typedef typename _Iterator::reference reference;
};
template < typename _Tp > struct iterator_traits <_Tp * >
{
typedef random_access_iterator_tag iterator_category;
typedef _Tp value_type;
typedef ptrdiff_t difference_type;
typedef _Tp *pointer;
typedef _Tp & reference;
};
template < typename _Tp > struct iterator_traits <const _Tp *>
{
typedef random_access_iterator_tag iterator_category;
typedef _Tp value_type;
typedef ptrdiff_t difference_type;
typedef const _Tp *pointer;
typedef const _Tp & reference;
};
template < typename _Iter > inline typename iterator_traits <
_Iter >::iterator_category __iterator_category (const _Iter &)
{
return typename iterator_traits < _Iter >::iterator_category ();
}
}
namespace std __attribute__ ((__visibility__ ("default")))
{
template < typename _Iterator > class reverse_iterator:public iterator < typename iterator_traits < _Iterator >::iterator_category,
typename iterator_traits < _Iterator >::value_type,
typename iterator_traits < _Iterator >::difference_type,
typename iterator_traits < _Iterator >::pointer,
typename iterator_traits < _Iterator >::reference >
{
protected:_Iterator current;
typedef iterator_traits < _Iterator > __traits_type;
public:typedef _Iterator iterator_type;
typedef typename __traits_type::difference_type difference_type;
typedef typename __traits_type::pointer pointer;
typedef typename __traits_type::reference reference;
reverse_iterator ():current ()
{
} explicit reverse_iterator (iterator_type __x):current (__x)
{
} reverse_iterator (const reverse_iterator & __x):current (__x.current)
{
} template < typename _Iter > reverse_iterator (const reverse_iterator <
_Iter >
&__x):current (__x.
base ())
{
} iterator_type base () const
{
return current;
}
reference operator* () const
{
_Iterator __tmp = current;
return *--__tmp;
}
pointer operator-> () const
{
return &(operator* ());
}
reverse_iterator & operator++ ()
{
--current;
return *this;
}
reverse_iterator operator++ (int)
{
reverse_iterator __tmp = *this;
--current;
return __tmp;
}
reverse_iterator & operator-- ()
{
++current;
return *this;
}
reverse_iterator operator-- (int)
{
reverse_iterator __tmp = *this;
++current;
return __tmp;
}
reverse_iterator operator+ (difference_type __n) const
{
return reverse_iterator (current - __n);
}
reverse_iterator & operator+= (difference_type __n)
{
current -= __n;
return *this;
}
reverse_iterator operator- (difference_type __n) const
{
return reverse_iterator (current + __n);
}
reverse_iterator & operator-= (difference_type __n)
{
current += __n;
return *this;
}
reference operator[] (difference_type __n) const
{
return *(*this + __n);
}
};
template < typename _Iterator >
inline bool operator== (const reverse_iterator < _Iterator > &__x,
const reverse_iterator < _Iterator > &__y)
{
return __x.base () == __y.base ();
}
template < typename _Iterator >
inline bool operator< (const reverse_iterator < _Iterator > &__x,
const reverse_iterator < _Iterator > &__y)
{
return __y.base () < __x.base ();
}
template < typename _Iterator >
inline bool operator!= (const reverse_iterator < _Iterator > &__x,
const reverse_iterator < _Iterator > &__y)
{
return !(__x == __y);
}
template < typename _Iterator >
inline bool operator> (const reverse_iterator < _Iterator > &__x,
const reverse_iterator < _Iterator > &__y)
{
return __y < __x;
}
template < typename _Iterator >
inline bool operator<= (const reverse_iterator < _Iterator > &__x,
const reverse_iterator < _Iterator > &__y)
{
return !(__y < __x);
}
template < typename _Iterator >
inline bool operator>= (const reverse_iterator < _Iterator > &__x,
const reverse_iterator < _Iterator > &__y)
{
return !(__x < __y);
}
template < typename _Iterator > inline typename reverse_iterator <
_Iterator >::difference_type operator- (const reverse_iterator <
_Iterator > &__x,
const reverse_iterator <
_Iterator > &__y)
{
return __y.base () - __x.base ();
}
template < typename _Iterator > inline reverse_iterator < _Iterator >
operator+ (typename reverse_iterator < _Iterator >::difference_type __n,
const reverse_iterator < _Iterator > &__x)
{
return reverse_iterator < _Iterator > (__x.base () - __n);
}
template < typename _IteratorL,
typename _IteratorR > inline bool operator== (const reverse_iterator <
_IteratorL > &__x,
const reverse_iterator <
_IteratorR > &__y)
{
return __x.base () == __y.base ();
}
template < typename _IteratorL,
typename _IteratorR > inline bool operator< (const reverse_iterator <
_IteratorL > &__x,
const reverse_iterator <
_IteratorR > &__y)
{
return __y.base () < __x.base ();
}
template < typename _IteratorL,
typename _IteratorR > inline bool operator!= (const reverse_iterator <
_IteratorL > &__x,
const reverse_iterator <
_IteratorR > &__y)
{
return !(__x == __y);
}
template < typename _IteratorL,
typename _IteratorR > inline bool operator> (const reverse_iterator <
_IteratorL > &__x,
const reverse_iterator <
_IteratorR > &__y)
{
return __y < __x;
}
template < typename _IteratorL,
typename _IteratorR > inline bool operator<= (const reverse_iterator <
_IteratorL > &__x,
const reverse_iterator <
_IteratorR > &__y)
{
return !(__y < __x);
}
template < typename _IteratorL,
typename _IteratorR > inline bool operator>= (const reverse_iterator <
_IteratorL > &__x,
const reverse_iterator <
_IteratorR > &__y)
{
return !(__x < __y);
}
template < typename _IteratorL,
typename _IteratorR > inline typename reverse_iterator <
_IteratorL >::difference_type operator- (const reverse_iterator <
_IteratorL > &__x,
const reverse_iterator <
_IteratorR > &__y)
{
return __y.base () - __x.base ();
}
template < typename _Container > class back_insert_iterator:public iterator < output_iterator_tag, void, void, void,
void >
{
protected:_Container * container;
public:typedef _Container container_type;
explicit back_insert_iterator (_Container & __x):container (&__x)
{
} back_insert_iterator & operator= (typename _Container::
const_reference __value)
{
container->push_back (__value);
return *this;
}
back_insert_iterator & operator* ()
{
return *this;
}
back_insert_iterator & operator++ ()
{
return *this;
}
back_insert_iterator operator++ (int)
{
return *this;
}
};
template < typename _Container > inline back_insert_iterator < _Container >
back_inserter (_Container & __x)
{
return back_insert_iterator < _Container > (__x);
}
template < typename _Container > class front_insert_iterator:public iterator < output_iterator_tag, void, void, void,
void >
{
protected:_Container * container;
public:typedef _Container container_type;
explicit front_insert_iterator (_Container & __x):container (&__x)
{
} front_insert_iterator & operator= (typename _Container::
const_reference __value)
{
container->push_front (__value);
return *this;
}
front_insert_iterator & operator* ()
{
return *this;
}
front_insert_iterator & operator++ ()
{
return *this;
}
front_insert_iterator operator++ (int)
{
return *this;
}
};
template < typename _Container > inline front_insert_iterator < _Container >
front_inserter (_Container & __x)
{
return front_insert_iterator < _Container > (__x);
}
template < typename _Container > class insert_iterator:public iterator < output_iterator_tag, void, void, void,
void >
{
protected:_Container * container;
typename _Container::iterator iter;
public:typedef _Container container_type;
insert_iterator (_Container & __x,
typename _Container::iterator __i):container (&__x),
iter (__i)
{
} insert_iterator & operator= (typename _Container::
const_reference __value)
{
iter = container->insert (iter, __value);
++iter;
return *this;
}
insert_iterator & operator* ()
{
return *this;
}
insert_iterator & operator++ ()
{
return *this;
}
insert_iterator & operator++ (int)
{
return *this;
}
};
template < typename _Container,
typename _Iterator > inline insert_iterator < _Container >
inserter (_Container & __x, _Iterator __i)
{
return insert_iterator < _Container > (__x,
typename _Container::
iterator (__i));
}
}
namespace __gnu_cxx __attribute__ ((__visibility__ ("default")))
{
using std::size_t;
using std::ptrdiff_t;
template < typename _Tp > class new_allocator
{
public:typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef _Tp *pointer;
typedef const _Tp *const_pointer;
typedef _Tp & reference;
typedef const _Tp & const_reference;
typedef _Tp value_type;
template < typename _Tp1 > struct rebind
{
typedef new_allocator < _Tp1 > other;
};
new_allocator ()throw ()
{
} new_allocator (const new_allocator &) throw ()
{
} template < typename _Tp1 > new_allocator (const new_allocator < _Tp1 >
&) throw ()
{
} ~new_allocator ()throw ()
{
} pointer address (reference __x) const
{
return &__x;
}
const_pointer address (const_reference __x) const
{
return &__x;
}
pointer allocate (size_type __n, const void * = 0)
{
return static_cast < _Tp * >(::operator new (__n * sizeof (_Tp)));
}
void deallocate (pointer __p, size_type)
{
::operator delete (__p);
} size_type max_size () const throw ()
{
return size_t (-1) / sizeof (_Tp);
}
void construct (pointer __p, const _Tp & __val)
{
::new ((void *) __p) _Tp (__val);
} void destroy (pointer __p)
{
__p->~_Tp ();
}};
template < typename _Tp > inline bool operator== (const new_allocator <
_Tp > &,
const new_allocator <
_Tp > &)
{
return true;
}
template < typename _Tp > inline bool operator!= (const new_allocator <
_Tp > &,
const new_allocator <
_Tp > &)
{
return false;
}
}
namespace std __attribute__ ((__visibility__ ("default")))
{
template < typename _Tp > class allocator;
template <> class allocator < void >
{
public:typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef void *pointer;
typedef const void *const_pointer;
typedef void value_type;
template < typename _Tp1 > struct rebind
{
typedef allocator < _Tp1 > other;
};
};
template < typename _Tp > class allocator:public __gnu_cxx::new_allocator <
_Tp >
{
public:typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef _Tp *pointer;
typedef const _Tp *const_pointer;
typedef _Tp & reference;
typedef const _Tp & const_reference;
typedef _Tp value_type;
template < typename _Tp1 > struct rebind
{
typedef allocator < _Tp1 > other;
};
allocator ()throw ()
{
} allocator (const allocator & __a) throw ():__gnu_cxx::new_allocator <
_Tp > (__a)
{
} template < typename _Tp1 > allocator (const allocator < _Tp1 >
&) throw ()
{
} ~allocator ()throw ()
{
}};
template < typename _T1,
typename _T2 > inline bool operator== (const allocator < _T1 > &,
const allocator < _T2 > &)
{
return true;
}
template < typename _Tp > inline bool operator== (const allocator < _Tp > &,
const allocator < _Tp > &)
{
return true;
}
template < typename _T1,
typename _T2 > inline bool operator!= (const allocator < _T1 > &,
const allocator < _T2 > &)
{
return false;
}
template < typename _Tp > inline bool operator!= (const allocator < _Tp > &,
const allocator < _Tp > &)
{
return false;
}
template < typename _Alloc, bool = __is_empty (_Alloc) > struct __alloc_swap
{
static void _S_do_it (_Alloc &, _Alloc &)
{
}};
template < typename _Alloc > struct __alloc_swap <_Alloc, false >
{
static void _S_do_it (_Alloc & __one, _Alloc & __two)
{
if (__one != __two)
swap (__one, __two);
}
};
template < typename _Alloc, bool = __is_empty (_Alloc) > struct __alloc_neq
{
static bool _S_do_it (const _Alloc &, const _Alloc &)
{
return false;
}
};
template < typename _Alloc > struct __alloc_neq <_Alloc, false >
{
static bool _S_do_it (const _Alloc & __one, const _Alloc & __two)
{
return __one != __two;
}
};
}
namespace std __attribute__ ((__visibility__ ("default")))
{
struct _List_node_base
{
_List_node_base *_M_next;
_List_node_base *_M_prev;
static void swap (_List_node_base & __x, _List_node_base & __y) throw ();
void _M_transfer (_List_node_base * const __first,
_List_node_base * const __last) throw ();
void _M_reverse () throw ();
void _M_hook (_List_node_base * const __position) throw ();
void _M_unhook () throw ();
};
template < typename _Tp > struct _List_node:public _List_node_base
{
_Tp _M_data;
};
template < typename _Tp > struct _List_iterator
{
typedef _List_iterator < _Tp > _Self;
typedef _List_node < _Tp > _Node;
typedef ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
typedef _Tp value_type;
typedef _Tp *pointer;
typedef _Tp & reference;
_List_iterator ():_M_node ()
{
} explicit _List_iterator (_List_node_base * __x):_M_node (__x)
{
} reference operator* () const
{
return static_cast < _Node * >(_M_node)->_M_data;
}
pointer operator-> () const
{
return &static_cast < _Node * >(_M_node)->_M_data;
}
_Self & operator++ ()
{
_M_node = _M_node->_M_next;
return *this;
}
_Self operator++ (int)
{
_Self __tmp = *this;
_M_node = _M_node->_M_next;
return __tmp;
}
_Self & operator-- ()
{
_M_node = _M_node->_M_prev;
return *this;
}
_Self operator-- (int)
{
_Self __tmp = *this;
_M_node = _M_node->_M_prev;
return __tmp;
}
bool operator== (const _Self & __x) const
{
return _M_node == __x._M_node;
}
bool operator!= (const _Self & __x) const
{
return _M_node != __x._M_node;
}
_List_node_base *_M_node;
};
template < typename _Tp > struct _List_const_iterator
{
typedef _List_const_iterator < _Tp > _Self;
typedef const _List_node < _Tp > _Node;
typedef _List_iterator < _Tp > iterator;
typedef ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
typedef _Tp value_type;
typedef const _Tp *pointer;
typedef const _Tp & reference;
_List_const_iterator ():_M_node ()
{
} explicit _List_const_iterator (const _List_node_base *
__x):_M_node (__x)
{
} _List_const_iterator (const iterator & __x):_M_node (__x._M_node)
{
} reference operator* () const
{
return static_cast < _Node * >(_M_node)->_M_data;
}
pointer operator-> () const
{
return &static_cast < _Node * >(_M_node)->_M_data;
}
_Self & operator++ ()
{
_M_node = _M_node->_M_next;
return *this;
}
_Self operator++ (int)
{
_Self __tmp = *this;
_M_node = _M_node->_M_next;
return __tmp;
}
_Self & operator-- ()
{
_M_node = _M_node->_M_prev;
return *this;
}
_Self operator-- (int)
{
_Self __tmp = *this;
_M_node = _M_node->_M_prev;
return __tmp;
}
bool operator== (const _Self & __x) const
{
return _M_node == __x._M_node;
}
bool operator!= (const _Self & __x) const
{
return _M_node != __x._M_node;
}
const _List_node_base *_M_node;
};
template < typename _Tp, typename _Alloc > class _List_base
{
protected:typedef typename _Alloc::template rebind < _List_node < _Tp >
>::other _Node_alloc_type;
typedef typename _Alloc::template rebind < _Tp >::other _Tp_alloc_type;
struct _List_impl:public _Node_alloc_type
{
_List_node_base _M_node;
_List_impl ():_Node_alloc_type (), _M_node ()
{
} _List_impl (const _Node_alloc_type & __a):_Node_alloc_type (__a),
_M_node ()
{
}};
_List_impl _M_impl;
_List_node < _Tp > *_M_get_node ()
{
return _M_impl._Node_alloc_type::allocate (1);
}
void _M_put_node (_List_node < _Tp > *__p)
{
_M_impl._Node_alloc_type::deallocate (__p, 1);
} public:typedef _Alloc allocator_type;
_Node_alloc_type & _M_get_Node_allocator ()
{
return *static_cast < _Node_alloc_type * >(&this->_M_impl);
}
const _Node_alloc_type & _M_get_Node_allocator () const
{
return *static_cast < const _Node_alloc_type *>(&this->_M_impl);
} _Tp_alloc_type _M_get_Tp_allocator () const
{
return _Tp_alloc_type (_M_get_Node_allocator ());
}
allocator_type get_allocator () const
{
return allocator_type (_M_get_Node_allocator ());
}
_List_base ():_M_impl ()
{
_M_init ();
}
_List_base (const allocator_type & __a):_M_impl (__a)
{
_M_init ();
} ~_List_base ()
{
_M_clear ();
} void _M_clear ();
void _M_init ()
{
this->_M_impl._M_node._M_next = &this->_M_impl._M_node;
this->_M_impl._M_node._M_prev = &this->_M_impl._M_node;
}};
template < typename _Tp, typename _Alloc = std::allocator < _Tp > >class list:protected _List_base < _Tp,
_Alloc
>
{
typedef typename _Alloc::value_type _Alloc_value_type;
typedef _List_base < _Tp, _Alloc > _Base;
typedef typename _Base::_Tp_alloc_type _Tp_alloc_type;
public:typedef _Tp value_type;
typedef typename _Tp_alloc_type::pointer pointer;
typedef typename _Tp_alloc_type::const_pointer const_pointer;
typedef typename _Tp_alloc_type::reference reference;
typedef typename _Tp_alloc_type::const_reference const_reference;
typedef _List_iterator < _Tp > iterator;
typedef _List_const_iterator < _Tp > const_iterator;
typedef std::reverse_iterator < const_iterator > const_reverse_iterator;
typedef std::reverse_iterator < iterator > reverse_iterator;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef _Alloc allocator_type;
protected:typedef _List_node < _Tp > _Node;
using _Base::_M_impl;
using _Base::_M_put_node;
using _Base::_M_get_node;
using _Base::_M_get_Tp_allocator;
using _Base::_M_get_Node_allocator;
public:iterator begin ()
{
return iterator (this->_M_impl._M_node._M_next);
}
const_iterator begin () const
{
return const_iterator (this->_M_impl._M_node._M_next);
}
iterator end ()
{
return iterator (&this->_M_impl._M_node);
}
void remove (const _Tp & __value);
template < typename _Predicate > void remove_if (_Predicate);
void _M_erase (iterator __position)
{
__position._M_node->_M_unhook ();
_Node *__n = static_cast < _Node * >(__position._M_node);
_M_get_Tp_allocator ().destroy (&__n->_M_data);
_M_put_node (__n);
} void _M_check_equal_allocators (list & __x)
{
if (std::__alloc_neq <
typename _Base::_Node_alloc_type >::
_S_do_it (_M_get_Node_allocator (), __x._M_get_Node_allocator ()));
}
};
}
namespace std __attribute__ ((__visibility__ ("default")))
{
template < typename _Tp, typename _Alloc > void list < _Tp,
_Alloc >::remove (const value_type & __value)
{
iterator __first = begin ();
iterator __last = end ();
iterator __extra = __last;
while (__first != __last)
{
iterator __next = __first;
++__next;
if (*__first == __value)
{
if (&*__first != &__value)
_M_erase (__first);
else
__extra = __first;
}
__first = __next;
}
if (__extra != __last)
_M_erase (__extra);
}
}
class Unit
{
public:int dummy;
};
class Building
{
public:__attribute__ ((transaction_callable)) void removeUnitFromInside (Unit *
unit);
std::list < Unit * >unitsInside;
};
void
Building::removeUnitFromInside (Unit * unit)
{
unitsInside.remove (unit);
}

View File

@ -0,0 +1,20 @@
// { dg-do compile }
// { dg-options "-fgnu-tm -O0" }
/* Test that we generate transactional clones for both the base and
the complete dtor for class Itemset. */
class Itemset {
public:
__attribute__((transaction_safe)) ~Itemset();
__attribute__((transaction_safe)) void operator delete(void *);
private:
};
__attribute__((transaction_safe))
Itemset::~Itemset()
{
}
// { dg-final { scan-assembler "_ZGTtN7ItemsetD1Ev" } }
// { dg-final { scan-assembler "_ZGTtN7ItemsetD2Ev" } }

View File

@ -0,0 +1,22 @@
// { dg-do compile }
// { dg-options "-fgnu-tm -fdump-tree-optimized-asmname" }
struct __attribute__((transaction_safe)) Tsafe
{
void f();
};
void Tsafe::f() { }
struct __attribute__((transaction_callable)) Tcall
{
void f();
};
void Tcall::f() { }
// { dg-final { scan-tree-dump-times "_ZN5Tsafe1fEv" 1 "optimized" } }
// { dg-final { scan-tree-dump-times "_ZN5Tcall1fEv" 1 "optimized" } }
// { dg-final { scan-tree-dump-times "_ZGTtN5Tsafe1fEv" 1 "optimized" } }
// { dg-final { scan-tree-dump-times "_ZGTtN5Tcall1fEv" 1 "optimized" } }
// { dg-final { cleanup-tree-dump "optimized" } }

View File

@ -0,0 +1,33 @@
// { dg-do compile }
// { dg-options "-fgnu-tm -fdump-tree-optimized-asmname" }
struct __attribute__((transaction_safe)) A
{
};
struct B : public A
{
void f();
};
struct C
{
};
struct D : public C
{
};
struct E : public D, public A
{
void f();
};
void B::f() { }
void E::f() { }
// { dg-final { scan-tree-dump-times "_ZN1B1fEv" 1 "optimized" } }
// { dg-final { scan-tree-dump-times "_ZGTtN1B1fEv" 1 "optimized" } }
// { dg-final { scan-tree-dump-times "_ZN1E1fEv" 1 "optimized" } }
// { dg-final { scan-tree-dump-times "_ZGTtN1E1fEv" 1 "optimized" } }
// { dg-final { cleanup-tree-dump "optimized" } }

View File

@ -0,0 +1,48 @@
// { dg-do compile }
// { dg-options "-fgnu-tm" }
#define __ts __attribute__((transaction_safe))
#define __tc __attribute__((transaction_callable))
#define __tp __attribute__((transaction_pure))
#define __tu __attribute__((transaction_unsafe))
struct __ts A
{
virtual void f();
virtual void g();
};
struct __tc B : public A
{
void f() __tc; // { dg-error ".transaction_callable. overriding .transaction_safe." }
void g();
virtual void h();
};
struct C : public B
{
void g() __tc; // { dg-error ".transaction_callable. overriding .transaction_safe." }
};
struct C2 : public B
{
void g() __ts;
void h() __tu; // { dg-error ".transaction_unsafe. overriding .transaction_callable." }
};
struct D
{
virtual void f() __tp;
virtual void g() __tp;
};
struct E : public D
{
void f() __ts; // { dg-error ".transaction_safe. overriding .transaction_pure." }
void g();
};
struct F : public E
{
void g() __ts; // { dg-error ".transaction_safe. overriding .transaction_pure." }
};

View File

@ -0,0 +1,10 @@
// { dg-do compile }
// { dg-options "-fgnu-tm" }
struct S
{
int i, j, k;
S();
};
S::S() __transaction_atomic : i(1), j(2), k(3) { }

View File

@ -0,0 +1,22 @@
// { dg-do compile }
// { dg-options "-fgnu-tm" }
class HashTree
{
public:
__attribute__((transaction_safe))
int add_element2();
private:
int Count;
};
__attribute__((transaction_safe))
int HashTree::add_element2()
{
int tt;
__transaction_atomic {
tt = Count;
}
return tt;
}

View File

@ -0,0 +1,41 @@
// { dg-do compile }
// { dg-options "-fgnu-tm -O" }
typedef unsigned long int uint64_t;
extern int *hash_indx;
typedef struct
{
uint64_t exit_atomicsec_time;
} ent_ex_times;
class HashTree
{
public:
__attribute__((transaction_safe))
void *operator new(__SIZE_TYPE__);
__attribute__((transaction_safe))
int add_element();
private:
HashTree **Hash_table;
int Count;
};
__attribute__((transaction_safe))
int HashTree::add_element()
{
ent_ex_times enter_exit_times_inside;
int val = hash_indx[5];
int tt;
if (Hash_table[val] == __null)
{
__transaction_atomic {
Hash_table[val] = new HashTree;
}
}
__transaction_atomic {
tt = Count++;
enter_exit_times_inside.exit_atomicsec_time = 5;
}
return tt;
}

View File

@ -0,0 +1,43 @@
// { dg-do compile }
// { dg-options "-fgnu-tm -O0" }
// Same as nested-2.C but with no optimization.
typedef unsigned long int uint64_t;
extern int *hash_indx;
typedef struct
{
uint64_t exit_atomicsec_time;
} ent_ex_times;
class HashTree
{
public:
__attribute__((transaction_safe))
void *operator new(__SIZE_TYPE__);
__attribute__((transaction_safe))
int add_element();
private:
HashTree **Hash_table;
int Count;
};
__attribute__((transaction_safe))
int HashTree::add_element()
{
ent_ex_times enter_exit_times_inside;
int val = hash_indx[5];
int tt;
if (Hash_table[val] == __null)
{
__transaction_atomic {
Hash_table[val] = new HashTree;
}
}
__transaction_atomic {
tt = Count++;
enter_exit_times_inside.exit_atomicsec_time = 5;
}
return tt;
}

Some files were not shown because too many files have changed in this diff Show More