mirror of git://gcc.gnu.org/git/gcc.git
Merge from transactional-memory branch.
From-SVN: r181154
This commit is contained in:
parent
287188ea07
commit
0a35513e4e
12
ChangeLog
12
ChangeLog
|
@ -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,
|
||||
|
|
|
@ -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; };
|
||||
|
|
495
Makefile.in
495
Makefile.in
|
@ -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@
|
||||
|
|
|
@ -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
|
||||
])
|
|
@ -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-*-*)
|
||||
|
|
19
configure.ac
19
configure.ac
|
@ -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-*-*)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
198
gcc/ChangeLog
198
gcc/ChangeLog
|
@ -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,
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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, \
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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. */
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
353
gcc/c-parser.c
353
gcc/c-parser.c
|
@ -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. */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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. */
|
||||
|
||||
|
|
85
gcc/calls.c
85
gcc/calls.c
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
20
gcc/cgraph.h
20
gcc/cgraph.h
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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. */
|
||||
|
|
154
gcc/cp/class.c
154
gcc/cp/class.c
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
339
gcc/cp/parser.c
339
gcc/cp/parser.c
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
22
gcc/cp/pt.c
22
gcc/cp/pt.c
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
137
gcc/gimple.c
137
gcc/gimple.c
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
168
gcc/gimple.h
168
gcc/gimple.h
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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. */
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 *);
|
||||
|
||||
|
|
|
@ -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 "
|
||||
|
|
10
gcc/passes.c
10
gcc/passes.c
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" } } */
|
|
@ -0,0 +1,6 @@
|
|||
/* { dg-do compile } */
|
||||
|
||||
void f(void)
|
||||
{
|
||||
__transaction_cancel; /* { dg-error "without transactional" } */
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-fgnu-tm" } */
|
||||
|
||||
int g;
|
||||
void f(void)
|
||||
{
|
||||
__transaction_atomic {
|
||||
if (g == 0)
|
||||
__transaction_cancel;
|
||||
}
|
||||
}
|
|
@ -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" } */
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
/* { dg-do compile } */
|
||||
|
||||
int g;
|
||||
void f(void)
|
||||
{
|
||||
__transaction_atomic { /* { dg-error "without transactional memory" } */
|
||||
g++;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-fgnu-tm" } */
|
||||
|
||||
int g;
|
||||
void f(void)
|
||||
{
|
||||
__transaction_atomic {
|
||||
g++;
|
||||
}
|
||||
}
|
|
@ -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" } */
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
// { dg-do compile }
|
||||
// { dg-options "-fgnu-tm" }
|
||||
|
||||
__attribute__((transaction_callable))
|
||||
void func()
|
||||
{
|
||||
__asm__ ("");
|
||||
}
|
|
@ -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 ();
|
||||
}
|
||||
}
|
|
@ -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" } } */
|
|
@ -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" } } */
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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(); }
|
|
@ -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 "" } */
|
||||
}
|
|
@ -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" } } */
|
|
@ -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" } } */
|
|
@ -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/*]
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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" } }
|
|
@ -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" } }
|
|
@ -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" } }
|
|
@ -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." }
|
||||
};
|
|
@ -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) { }
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
Loading…
Reference in New Issue