aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2021-06-23 10:20:15 +0200
committerMartin Liska <mliska@suse.cz>2021-06-23 10:20:15 +0200
commit0c6508fe976763cf4fe57c3cb6954b7ab7d55619 (patch)
tree371963812b9df9853216acf70d031962332785e3
parent272625aab59a0ff3eddf1da2afc6416703eaf24d (diff)
parentc2124b51a9b83c76400ebb1862b26f61410e77db (diff)
downloadgcc-0c6508fe976763cf4fe57c3cb6954b7ab7d55619.zip
gcc-0c6508fe976763cf4fe57c3cb6954b7ab7d55619.tar.gz
gcc-0c6508fe976763cf4fe57c3cb6954b7ab7d55619.tar.bz2
Merge branch 'master' into devel/sphinx
-rw-r--r--ChangeLog4
-rw-r--r--MAINTAINERS1
-rw-r--r--contrib/ChangeLog4
-rwxr-xr-xcontrib/gcc-git-customization.sh2
-rwxr-xr-xcontrib/git-commit-mklog.py53
-rwxr-xr-xcontrib/mklog.py2
-rwxr-xr-xcontrib/prepare-commit-msg2
-rw-r--r--gcc/ChangeLog193
-rw-r--r--gcc/DATESTAMP2
-rw-r--r--gcc/Makefile.in1
-rw-r--r--gcc/analyzer/ChangeLog8
-rw-r--r--gcc/analyzer/region-model.cc19
-rw-r--r--gcc/config/i386/i386-expand.c3
-rw-r--r--gcc/config/i386/i386-protos.h1
-rw-r--r--gcc/config/i386/i386.c1
-rw-r--r--gcc/config/i386/i386.md87
-rw-r--r--gcc/config/riscv/riscv.c14
-rw-r--r--gcc/doc/rtl.texi2
-rw-r--r--gcc/fold-const.c2
-rw-r--r--gcc/function.c21
-rw-r--r--gcc/gimple-range-cache.cc10
-rw-r--r--gcc/gimple-range.cc355
-rw-r--r--gcc/gimple-range.h24
-rw-r--r--gcc/gimplify.c15
-rw-r--r--gcc/range-op.cc774
-rw-r--r--gcc/range-op.h24
-rw-r--r--gcc/testsuite/ChangeLog87
-rw-r--r--gcc/testsuite/g++.dg/modules/omp-1_a.C2
-rw-r--r--gcc/testsuite/g++.dg/modules/omp-2_a.C2
-rw-r--r--gcc/testsuite/g++.dg/opt/pr101162.C21
-rw-r--r--gcc/testsuite/g++.target/i386/empty-class1.C2
-rw-r--r--gcc/testsuite/g++.target/i386/empty-class2.C20
-rw-r--r--gcc/testsuite/gcc.c-torture/compile/pr101159.c10
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/pr101143.c18
-rw-r--r--gcc/testsuite/gcc.dg/pr101156.c8
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr101151.c19
-rw-r--r--gcc/testsuite/gcc.target/i386/pr11877-2.c26
-rw-r--r--gcc/testsuite/gfortran.dg/pr101158.f9025
-rw-r--r--gcc/testsuite/gfortran.dg/pr93524.c33
-rw-r--r--gcc/testsuite/gfortran.dg/pr93524.f9017
-rw-r--r--gcc/tree-data-ref.c2
-rw-r--r--gcc/tree-ssa-sink.c9
-rw-r--r--gcc/tree-vect-patterns.c14
-rw-r--r--gcc/tree-vect-slp.c52
-rw-r--r--gcc/value-query.cc50
-rw-r--r--gcc/value-query.h11
-rw-r--r--gcc/value-relation.cc932
-rw-r--r--gcc/value-relation.h159
-rw-r--r--libgcc/config/rs6000/float128-ifunc.c9
-rw-r--r--libgcc/config/rs6000/t-float128-hw16
-rw-r--r--libgcc/config/rs6000/t-float128-p10-hw4
-rwxr-xr-xlibgcc/configure18
-rw-r--r--libgcc/configure.ac14
-rw-r--r--libgfortran/ChangeLog7
-rw-r--r--libgfortran/runtime/ISO_Fortran_binding.c5
-rw-r--r--libstdc++-v3/ChangeLog41
-rw-r--r--libstdc++-v3/include/bits/random.h2
-rw-r--r--libstdc++-v3/include/bits/random.tcc2
-rw-r--r--libstdc++-v3/include/bits/semaphore_base.h4
-rw-r--r--libstdc++-v3/include/std/memory4
-rw-r--r--libstdc++-v3/include/std/mutex108
-rw-r--r--libstdc++-v3/testsuite/20_util/pointer_safety/1.cc2
-rw-r--r--libstdc++-v3/testsuite/26_numerics/random/seed_seq/cons/default.cc4
-rw-r--r--libstdc++-v3/testsuite/26_numerics/random/seed_seq/cons/initlist.cc7
-rw-r--r--libstdc++-v3/testsuite/30_threads/lock/3.cc4
-rw-r--r--libstdc++-v3/testsuite/30_threads/lock/4.cc124
-rw-r--r--libstdc++-v3/testsuite/30_threads/semaphore/100806.cc57
-rw-r--r--libstdc++-v3/testsuite/30_threads/try_lock/5.cc41
-rw-r--r--libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc6
69 files changed, 3259 insertions, 363 deletions
diff --git a/ChangeLog b/ChangeLog
index 61fc3e8..285648d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2021-06-22 liuhongt <hongtao.liu@intel.com>
+
+ * MAINTAINERS: Remove my Write After Approval entry.
+
2021-06-21 liuhongt <hongtao.liu@intel.com>
* MAINTAINERS: Add myself as maintainer of the i386 vector
diff --git a/MAINTAINERS b/MAINTAINERS
index 4ac4fc5..b4c50a9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -472,7 +472,6 @@ Nicolas Koenig <koenigni@student.ethz.ch>
Boris Kolpackov <boris@codesynthesis.com>
Dave Korn <dave.korn.cygwin@gmail.com>
Julia Koval <julia.koval@intel.com>
-Hongtao Liu <hongtao.liu@intel.com>
Matt Kraai <kraai@ftbfs.org>
Jan Kratochvil <jan.kratochvil@redhat.com>
Louis Krupp <louis.krupp@zoho.com>
diff --git a/contrib/ChangeLog b/contrib/ChangeLog
index 9b31022..b46a215 100644
--- a/contrib/ChangeLog
+++ b/contrib/ChangeLog
@@ -1,3 +1,7 @@
+2021-06-22 Martin Liska <mliska@suse.cz>
+
+ * mklog.py: Fix flake8 issue.
+
2021-06-21 Tobias Burnus <tobias@codesourcery.com>
Martin Sebor <msebor@redhat.com>
diff --git a/contrib/gcc-git-customization.sh b/contrib/gcc-git-customization.sh
index e7e6662..6f8f23d 100755
--- a/contrib/gcc-git-customization.sh
+++ b/contrib/gcc-git-customization.sh
@@ -28,7 +28,7 @@ git config alias.gcc-undescr \!"f() { o=\$(git config --get gcc-config.upstream)
git config alias.gcc-verify '!f() { "`git rev-parse --show-toplevel`/contrib/gcc-changelog/git_check_commit.py" $@; } ; f'
git config alias.gcc-backport '!f() { "`git rev-parse --show-toplevel`/contrib/git-backport.py" $@; } ; f'
git config alias.gcc-mklog '!f() { "`git rev-parse --show-toplevel`/contrib/mklog.py" $@; } ; f'
-git config alias.gcc-commit-mklog '!f() { GCC_FORCE_MKLOG=1 git commit "$@"; }; f'
+git config alias.gcc-commit-mklog '!f() { "`git rev-parse --show-toplevel`/contrib/git-commit-mklog.py" $@; }; f'
# Make diff on MD files use "(define" as a function marker.
# Use this in conjunction with a .gitattributes file containing
diff --git a/contrib/git-commit-mklog.py b/contrib/git-commit-mklog.py
new file mode 100755
index 0000000..9c59fb9
--- /dev/null
+++ b/contrib/git-commit-mklog.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2020 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING. If not, write to
+# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+#
+# The script is wrapper for git commit-mklog alias where it parses
+# -b/--pr-numbers argument and passes it via environment variable
+# to mklog.py script.
+
+import argparse
+import os
+import subprocess
+
+if __name__ == '__main__':
+ children_args = []
+ myenv = os.environ.copy()
+
+ parser = argparse.ArgumentParser(description='git-commit-mklog wrapped')
+ parser.add_argument('-b', '--pr-numbers', action='store',
+ type=lambda arg: arg.split(','), nargs='?',
+ help='Add the specified PRs (comma separated)')
+ parser.add_argument('-p', '--fill-up-bug-titles', action='store_true',
+ help='Download title of mentioned PRs')
+ args, unknown_args = parser.parse_known_args()
+
+ myenv['GCC_FORCE_MKLOG'] = '1'
+ mklog_args = []
+ if args.pr_numbers:
+ mklog_args.append(f'-b {",".join(args.pr_numbers)}')
+ if args.fill_up_bug_titles:
+ mklog_args.append('-p')
+
+ if mklog_args:
+ myenv['GCC_MKLOG_ARGS'] = ' '.join(mklog_args)
+
+ commit_args = ' '.join(unknown_args)
+ subprocess.run(f'git commit {commit_args}', shell=True, env=myenv)
diff --git a/contrib/mklog.py b/contrib/mklog.py
index 0b434f6..674c1dc 100755
--- a/contrib/mklog.py
+++ b/contrib/mklog.py
@@ -304,7 +304,7 @@ if __name__ == '__main__':
parser.add_argument('input', nargs='?',
help='Patch file (or missing, read standard input)')
parser.add_argument('-b', '--pr-numbers', action='store',
- type=lambda arg: arg.split(','), nargs="?",
+ type=lambda arg: arg.split(','), nargs='?',
help='Add the specified PRs (comma separated)')
parser.add_argument('-s', '--no-functions', action='store_true',
help='Do not generate function names in ChangeLogs')
diff --git a/contrib/prepare-commit-msg b/contrib/prepare-commit-msg
index 969847d..5da8784 100755
--- a/contrib/prepare-commit-msg
+++ b/contrib/prepare-commit-msg
@@ -78,4 +78,4 @@ else
tee="cat"
fi
-git $cmd | $tee | git gcc-mklog -c "$COMMIT_MSG_FILE"
+git $cmd | $tee | git gcc-mklog $GCC_MKLOG_ARGS -c "$COMMIT_MSG_FILE"
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5e73922..502a814 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,196 @@
+2021-06-22 Sergei Trofimovich <siarheit@google.com>
+
+ * doc/rtl.texi: drop unbalanced parenthesis.
+
+2021-06-22 Richard Biener <rguenther@suse.de>
+
+ PR middle-end/101156
+ * gimplify.c (gimplify_expr): Remove premature incorrect
+ optimization.
+
+2021-06-22 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/101159
+ * tree-vect-patterns.c (vect_recog_popcount_pattern): Fix some
+ comment typos.
+
+2021-06-22 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/101160
+ * function.c (assign_parms): For decl_result with TYPE_EMPTY_P type
+ clear crtl->return_rtx instead of keeping it referencing a pseudo.
+
+2021-06-22 Jakub Jelinek <jakub@redhat.com>
+ Andrew Pinski <apinski@marvell.com>
+
+ PR tree-optimization/101162
+ * fold-const.c (range_check_type): Handle OFFSET_TYPE like pointer
+ types.
+
+2021-06-22 Andrew MacLeod <amacleod@redhat.com>
+
+ * range-op.cc (range_relational_tests): New.
+ (range_op_tests): Call range_relational_tests.
+
+2021-06-22 Andrew MacLeod <amacleod@redhat.com>
+
+ * range-op.cc (operator_cast::lhs_op1_relation): New.
+ (operator_identity::lhs_op1_relation): Mew.
+
+2021-06-22 Andrew MacLeod <amacleod@redhat.com>
+
+ * range-op.cc (operator_minus::op1_op2_relation_effect): New.
+
+2021-06-22 Andrew MacLeod <amacleod@redhat.com>
+
+ * range-op.cc (operator_plus::lhs_op1_relation): New.
+ (operator_plus::lhs_op2_relation): New.
+
+2021-06-22 Andrew MacLeod <amacleod@redhat.com>
+
+ * gimple-range-cache.cc (ranger_cache::ranger_cache): Create a
+ relation_oracle if dominators exist.
+ (ranger_cache::~ranger_cache): Dispose of oracle.
+ (ranger_cache::dump_bb): Dump oracle.
+ * gimple-range.cc (fur_source::fur_source): New.
+ (fur_source::get_operand): Use mmeber query.
+ (fur_source::get_phi_operand): Use member_query.
+ (fur_source::query_relation): New.
+ (fur_source::register_dependency): Delete.
+ (fur_source::register_relation): New.
+ (fur_edge::fur_edge): Adjust.
+ (fur_edge::get_phi_operand): Fix comment.
+ (fur_edge::query): Delete.
+ (fur_stmt::fur_stmt): Adjust.
+ (fur_stmt::query): Delete.
+ (fur_depend::fur_depend): Adjust.
+ (fur_depend::register_relation): New.
+ (fur_depend::register_relation): New.
+ (fur_list::fur_list): Adjust.
+ (fur_list::get_operand): Use member query.
+ (fold_using_range::range_of_range_op): Process and query relations.
+ (fold_using_range::range_of_address): Adjust dependency call.
+ (fold_using_range::range_of_phi): Ditto.
+ (gimple_ranger::gimple_ranger): New. Use ranger_ache oracle.
+ (fold_using_range::relation_fold_and_or): New.
+ (fold_using_range::postfold_gcond_edges): New.
+ * gimple-range.h (class gimple_ranger): Adjust.
+ (class fur_source): Adjust members.
+ (class fur_stmt): Ditto.
+ (class fold_using_range): Ditto.
+
+2021-06-22 Andrew MacLeod <amacleod@redhat.com>
+
+ * range-op.cc (range_operator::wi_fold): Apply relation effect.
+ (range_operator::fold_range): Adjust and apply relation effect.
+ (*::fold_range): Add relation parameters.
+ (*::op1_range): Ditto.
+ (*::op2_range): Ditto.
+ (range_operator::lhs_op1_relation): New.
+ (range_operator::lhs_op2_relation): New.
+ (range_operator::op1_op2_relation): New.
+ (range_operator::op1_op2_relation_effect): New.
+ (relop_early_resolve): New.
+ (operator_equal::op1_op2_relation): New.
+ (operator_equal::fold_range): Call relop_early_resolve.
+ (operator_not_equal::op1_op2_relation): New.
+ (operator_not_equal::fold_range): Call relop_early_resolve.
+ (operator_lt::op1_op2_relation): New.
+ (operator_lt::fold_range): Call relop_early_resolve.
+ (operator_le::op1_op2_relation): New.
+ (operator_le::fold_range): Call relop_early_resolve.
+ (operator_gt::op1_op2_relation): New.
+ (operator_gt::fold_range): Call relop_early_resolve.
+ (operator_ge::op1_op2_relation): New.
+ (operator_ge::fold_range): Call relop_early_resolve.
+ * range-op.h (class range_operator): Adjust parameters and methods.
+
+2021-06-22 Andrew MacLeod <amacleod@redhat.com>
+
+ * Makefile.in (OBJS): Add value-relation.o.
+ * gimple-range.h: Adjust include files.
+ * tree-data-ref.c: Adjust include file order.
+ * value-query.cc (range_query::get_value_range): Default to no oracle.
+ (range_query::query_relation): New.
+ (range_query::query_relation): New.
+ * value-query.h (class range_query): Adjust.
+ * value-relation.cc: New.
+ * value-relation.h: New.
+
+2021-06-22 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/101151
+ * tree-ssa-sink.c (statement_sink_location): Expand irreducible
+ region check.
+
+2021-06-22 Jojo R <rjiejie@linux.alibaba.com>
+
+ * config/riscv/riscv.c (thead_c906_tune_info): New.
+ (riscv_tune_info_table): Use new tune.
+
+2021-06-22 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/101158
+ * tree-vect-slp.c (vect_build_slp_tree_1): Move same operand
+ checking after checking for matching operation.
+
+2021-06-22 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/101159
+ * tree-vect-patterns.c (vect_recog_popcount_pattern): Add
+ missing NULL vectype check.
+
+2021-06-22 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/101154
+ * tree-vect-slp.c (vect_build_slp_tree_2): Fix out-of-bound access.
+
+2021-06-22 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/11877
+ * config/i386/i386-protos.h (ix86_last_zero_store_uid): Declare.
+ * config/i386/i386-expand.c (ix86_last_zero_store_uid): New variable.
+ * config/i386/i386.c (ix86_expand_prologue): Clear it.
+ * config/i386/i386.md (peephole2s for 1/2/4 stores of const0_rtx):
+ Remove "" from match_operand. Emit new insns using emit_move_insn and
+ set ix86_last_zero_store_uid to INSN_UID of the last store.
+ Add peephole2s for 1/2/4 stores of const0_rtx following previous
+ successful peep2s.
+
+2021-06-22 Martin Liska <mliska@suse.cz>
+
+ * auto-profile.c (AUTO_PROFILE_VERSION): Bump as string format
+ was changed.
+
+2021-06-22 Martin Liska <mliska@suse.cz>
+
+ * gcov-io.h: Remove padding entries.
+
+2021-06-22 liuhongt <hongtao.liu@intel.com>
+
+ PR tree-optimization/97770
+ * tree-vect-patterns.c (vect_recog_popcount_pattern):
+ New.
+ (vect_recog_func vect_vect_recog_func_ptrs): Add new pattern.
+
+2021-06-22 liuhongt <hongtao.liu@intel.com>
+
+ PR target/100267
+ * config/i386/i386-builtin.def (BDESC): Adjust builtin name.
+ * config/i386/sse.md (<avx512>_expand<mode>_mask): Rename to ..
+ (expand<mode>_mask): this ..
+ (*expand<mode>_mask): New pre_reload splitter to transform
+ v{,p}expand* to vmov* when mask is zero, all ones, or has all
+ ones in it's lower part, otherwise still generate
+ v{,p}expand*.
+
+2021-06-22 liuhongt <hongtao.liu@intel.com>
+
+ PR target/100310
+ * config/i386/i386-expand.c
+ (ix86_expand_special_args_builtin): Keep constm1_operand only
+ if it satisfies insn's operand predicate.
+
2021-06-21 Jason Merrill <jason@redhat.com>
PR target/88529
diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP
index bb14796..e8c8a9f 100644
--- a/gcc/DATESTAMP
+++ b/gcc/DATESTAMP
@@ -1 +1 @@
-20210622
+20210623
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 4cb2966..ebf2644 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1688,6 +1688,7 @@ OBJS = \
value-query.o \
value-range.o \
value-range-equiv.o \
+ value-relation.o \
value-prof.o \
var-tracking.o \
varasm.o \
diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog
index 84fa208..3630b2e 100644
--- a/gcc/analyzer/ChangeLog
+++ b/gcc/analyzer/ChangeLog
@@ -1,3 +1,11 @@
+2021-06-22 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/101143
+ * region-model.cc (compat_types_p): New function.
+ (region_model::create_region_for_heap_alloc): Convert assertion to
+ an error check.
+ (region_model::create_region_for_alloca): Likewise.
+
2021-06-18 David Malcolm <dmalcolm@redhat.com>
* store.cc (binding_cluster::get_any_binding): Make symbolic reads
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 462fe6d..ee11e82 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -1443,6 +1443,17 @@ assert_compat_types (tree src_type, tree dst_type)
}
}
+/* Return true if SRC_TYPE can be converted to DST_TYPE as a no-op. */
+
+static bool
+compat_types_p (tree src_type, tree dst_type)
+{
+ if (src_type && dst_type && !VOID_TYPE_P (dst_type))
+ if (!(useless_type_conversion_p (src_type, dst_type)))
+ return false;
+ return true;
+}
+
/* Get the region for PV within this region_model,
emitting any diagnostics to CTXT. */
@@ -3402,8 +3413,8 @@ const region *
region_model::create_region_for_heap_alloc (const svalue *size_in_bytes)
{
const region *reg = m_mgr->create_region_for_heap_alloc ();
- assert_compat_types (size_in_bytes->get_type (), size_type_node);
- set_dynamic_extents (reg, size_in_bytes);
+ if (compat_types_p (size_in_bytes->get_type (), size_type_node))
+ set_dynamic_extents (reg, size_in_bytes);
return reg;
}
@@ -3414,8 +3425,8 @@ const region *
region_model::create_region_for_alloca (const svalue *size_in_bytes)
{
const region *reg = m_mgr->create_region_for_alloca (m_current_frame);
- assert_compat_types (size_in_bytes->get_type (), size_type_node);
- set_dynamic_extents (reg, size_in_bytes);
+ if (compat_types_p (size_in_bytes->get_type (), size_type_node))
+ set_dynamic_extents (reg, size_in_bytes);
return reg;
}
diff --git a/gcc/config/i386/i386-expand.c b/gcc/config/i386/i386-expand.c
index cc2eaee..2986b49 100644
--- a/gcc/config/i386/i386-expand.c
+++ b/gcc/config/i386/i386-expand.c
@@ -1316,6 +1316,9 @@ find_nearest_reg_def (rtx_insn *insn, int regno1, int regno2)
return false;
}
+/* INSN_UID of the last insn emitted by zero store peephole2s. */
+int ix86_last_zero_store_uid;
+
/* Split lea instructions into a sequence of instructions
which are executed on ALU to avoid AGU stalls.
It is assumed that it is allowed to clobber flags register
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index e6ac939..1d05206 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -111,6 +111,7 @@ extern bool ix86_use_lea_for_mov (rtx_insn *, rtx[]);
extern bool ix86_avoid_lea_for_addr (rtx_insn *, rtx[]);
extern void ix86_split_lea_for_addr (rtx_insn *, rtx[], machine_mode);
extern bool ix86_lea_for_add_ok (rtx_insn *, rtx[]);
+extern int ix86_last_zero_store_uid;
extern bool ix86_vec_interleave_v2df_operator_ok (rtx operands[3], bool high);
extern bool ix86_dep_by_shift_count (const_rtx set_insn, const_rtx use_insn);
extern bool ix86_agi_dependent (rtx_insn *set_insn, rtx_insn *use_insn);
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index c3740ff..3d5883b 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -8196,6 +8196,7 @@ ix86_expand_prologue (void)
bool save_stub_call_needed;
rtx static_chain = NULL_RTX;
+ ix86_last_zero_store_uid = 0;
if (ix86_function_naked (current_function_decl))
{
if (flag_stack_usage_info)
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 9116828..700c158 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -19360,37 +19360,96 @@
;; When optimizing for size, zeroing memory should use a register.
(define_peephole2
[(match_scratch:SWI48 0 "r")
- (set (match_operand:SWI48 1 "memory_operand" "") (const_int 0))
- (set (match_operand:SWI48 2 "memory_operand" "") (const_int 0))
- (set (match_operand:SWI48 3 "memory_operand" "") (const_int 0))
- (set (match_operand:SWI48 4 "memory_operand" "") (const_int 0))]
+ (set (match_operand:SWI48 1 "memory_operand") (const_int 0))
+ (set (match_operand:SWI48 2 "memory_operand") (const_int 0))
+ (set (match_operand:SWI48 3 "memory_operand") (const_int 0))
+ (set (match_operand:SWI48 4 "memory_operand") (const_int 0))]
"optimize_insn_for_size_p () && peep2_regno_dead_p (0, FLAGS_REG)"
- [(set (match_dup 1) (match_dup 0))
- (set (match_dup 2) (match_dup 0))
- (set (match_dup 3) (match_dup 0))
- (set (match_dup 4) (match_dup 0))]
+ [(const_int 0)]
{
ix86_expand_clear (operands[0]);
+ emit_move_insn (operands[1], operands[0]);
+ emit_move_insn (operands[2], operands[0]);
+ emit_move_insn (operands[3], operands[0]);
+ ix86_last_zero_store_uid
+ = INSN_UID (emit_move_insn (operands[4], operands[0]));
+ DONE;
})
(define_peephole2
[(match_scratch:SWI48 0 "r")
- (set (match_operand:SWI48 1 "memory_operand" "") (const_int 0))
- (set (match_operand:SWI48 2 "memory_operand" "") (const_int 0))]
+ (set (match_operand:SWI48 1 "memory_operand") (const_int 0))
+ (set (match_operand:SWI48 2 "memory_operand") (const_int 0))]
"optimize_insn_for_size_p () && peep2_regno_dead_p (0, FLAGS_REG)"
- [(set (match_dup 1) (match_dup 0))
- (set (match_dup 2) (match_dup 0))]
+ [(const_int 0)]
{
ix86_expand_clear (operands[0]);
+ emit_move_insn (operands[1], operands[0]);
+ ix86_last_zero_store_uid
+ = INSN_UID (emit_move_insn (operands[2], operands[0]));
+ DONE;
})
(define_peephole2
[(match_scratch:SWI48 0 "r")
- (set (match_operand:SWI48 1 "memory_operand" "") (const_int 0))]
+ (set (match_operand:SWI48 1 "memory_operand") (const_int 0))]
"optimize_insn_for_size_p () && peep2_regno_dead_p (0, FLAGS_REG)"
- [(set (match_dup 1) (match_dup 0))]
+ [(const_int 0)]
{
ix86_expand_clear (operands[0]);
+ ix86_last_zero_store_uid
+ = INSN_UID (emit_move_insn (operands[1], operands[0]));
+ DONE;
+})
+
+(define_peephole2
+ [(set (match_operand:SWI48 5 "memory_operand")
+ (match_operand:SWI48 0 "general_reg_operand"))
+ (set (match_operand:SWI48 1 "memory_operand") (const_int 0))
+ (set (match_operand:SWI48 2 "memory_operand") (const_int 0))
+ (set (match_operand:SWI48 3 "memory_operand") (const_int 0))
+ (set (match_operand:SWI48 4 "memory_operand") (const_int 0))]
+ "optimize_insn_for_size_p ()
+ && INSN_UID (peep2_next_insn (0)) == ix86_last_zero_store_uid"
+ [(const_int 0)]
+{
+ emit_move_insn (operands[5], operands[0]);
+ emit_move_insn (operands[1], operands[0]);
+ emit_move_insn (operands[2], operands[0]);
+ emit_move_insn (operands[3], operands[0]);
+ ix86_last_zero_store_uid
+ = INSN_UID (emit_move_insn (operands[4], operands[0]));
+ DONE;
+})
+
+(define_peephole2
+ [(set (match_operand:SWI48 3 "memory_operand")
+ (match_operand:SWI48 0 "general_reg_operand"))
+ (set (match_operand:SWI48 1 "memory_operand") (const_int 0))
+ (set (match_operand:SWI48 2 "memory_operand") (const_int 0))]
+ "optimize_insn_for_size_p ()
+ && INSN_UID (peep2_next_insn (0)) == ix86_last_zero_store_uid"
+ [(const_int 0)]
+{
+ emit_move_insn (operands[3], operands[0]);
+ emit_move_insn (operands[1], operands[0]);
+ ix86_last_zero_store_uid
+ = INSN_UID (emit_move_insn (operands[2], operands[0]));
+ DONE;
+})
+
+(define_peephole2
+ [(set (match_operand:SWI48 2 "memory_operand")
+ (match_operand:SWI48 0 "general_reg_operand"))
+ (set (match_operand:SWI48 1 "memory_operand") (const_int 0))]
+ "optimize_insn_for_size_p ()
+ && INSN_UID (peep2_next_insn (0)) == ix86_last_zero_store_uid"
+ [(const_int 0)]
+{
+ emit_move_insn (operands[2], operands[0]);
+ ix86_last_zero_store_uid
+ = INSN_UID (emit_move_insn (operands[1], operands[0]));
+ DONE;
})
;; Reload dislikes loading constants directly into class_likely_spilled
diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c
index 1baa299..576960b 100644
--- a/gcc/config/riscv/riscv.c
+++ b/gcc/config/riscv/riscv.c
@@ -300,6 +300,19 @@ static const struct riscv_tune_param sifive_7_tune_info = {
true, /* slow_unaligned_access */
};
+/* Costs to use when optimizing for T-HEAD c906. */
+static const struct riscv_tune_param thead_c906_tune_info = {
+ {COSTS_N_INSNS (4), COSTS_N_INSNS (5)}, /* fp_add */
+ {COSTS_N_INSNS (4), COSTS_N_INSNS (5)}, /* fp_mul */
+ {COSTS_N_INSNS (20), COSTS_N_INSNS (20)}, /* fp_div */
+ {COSTS_N_INSNS (4), COSTS_N_INSNS (4)}, /* int_mul */
+ {COSTS_N_INSNS (6), COSTS_N_INSNS (6)}, /* int_div */
+ 1, /* issue_rate */
+ 3, /* branch_cost */
+ 5, /* memory_cost */
+ false, /* slow_unaligned_access */
+};
+
/* Costs to use when optimizing for size. */
static const struct riscv_tune_param optimize_size_tune_info = {
{COSTS_N_INSNS (1), COSTS_N_INSNS (1)}, /* fp_add */
@@ -348,6 +361,7 @@ static const struct riscv_tune_info riscv_tune_info_table[] = {
{ "sifive-3-series", generic, &rocket_tune_info },
{ "sifive-5-series", generic, &rocket_tune_info },
{ "sifive-7-series", sifive_7, &sifive_7_tune_info },
+ { "thead-c906", generic, &thead_c906_tune_info },
{ "size", generic, &optimize_size_tune_info },
};
diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index 5af7113..e1e76a9 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -144,7 +144,7 @@ Currently, @file{rtl.def} defines these classes:
@item RTX_OBJ
An RTX code that represents an actual object, such as a register
(@code{REG}) or a memory location (@code{MEM}, @code{SYMBOL_REF}).
-@code{LO_SUM}) is also included; instead, @code{SUBREG} and
+@code{LO_SUM} is also included; instead, @code{SUBREG} and
@code{STRICT_LOW_PART} are not in this class, but in class
@code{RTX_EXTRA}.
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 95673d2..0b33ee9 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -5360,7 +5360,7 @@ range_check_type (tree etype)
else
return NULL_TREE;
}
- else if (POINTER_TYPE_P (etype))
+ else if (POINTER_TYPE_P (etype) || TREE_CODE (etype) == OFFSET_TYPE)
etype = unsigned_type_for (etype);
return etype;
}
diff --git a/gcc/function.c b/gcc/function.c
index 6abaf3d..00b2fe7 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -3821,17 +3821,22 @@ assign_parms (tree fndecl)
tree decl_result = DECL_RESULT (fndecl);
rtx decl_rtl = DECL_RTL (decl_result);
- if ((REG_P (decl_rtl)
- ? REGNO (decl_rtl) >= FIRST_PSEUDO_REGISTER
- : DECL_REGISTER (decl_result))
- /* Unless the psABI says not to. */
- && !TYPE_EMPTY_P (TREE_TYPE (decl_result)))
+ if (REG_P (decl_rtl)
+ ? REGNO (decl_rtl) >= FIRST_PSEUDO_REGISTER
+ : DECL_REGISTER (decl_result))
{
rtx real_decl_rtl;
- real_decl_rtl = targetm.calls.function_value (TREE_TYPE (decl_result),
- fndecl, true);
- REG_FUNCTION_VALUE_P (real_decl_rtl) = 1;
+ /* Unless the psABI says not to. */
+ if (TYPE_EMPTY_P (TREE_TYPE (decl_result)))
+ real_decl_rtl = NULL_RTX;
+ else
+ {
+ real_decl_rtl
+ = targetm.calls.function_value (TREE_TYPE (decl_result),
+ fndecl, true);
+ REG_FUNCTION_VALUE_P (real_decl_rtl) = 1;
+ }
/* The delay slot scheduler assumes that crtl->return_rtx
holds the hard register containing the return value, not a
temporary pseudo. */
diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index def604dc..4347485 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -714,6 +714,12 @@ ranger_cache::ranger_cache ()
m_update_list.safe_grow_cleared (last_basic_block_for_fn (cfun));
m_update_list.truncate (0);
m_temporal = new temporal_cache;
+ // If DOM info is available, spawn an oracle as well.
+ if (dom_info_available_p (CDI_DOMINATORS))
+ m_oracle = new relation_oracle ();
+ else
+ m_oracle = NULL;
+
unsigned x, lim = last_basic_block_for_fn (cfun);
// Calculate outgoing range info upfront. This will fully populate the
// m_maybe_variant bitmap which will help eliminate processing of names
@@ -728,6 +734,8 @@ ranger_cache::ranger_cache ()
ranger_cache::~ranger_cache ()
{
+ if (m_oracle)
+ delete m_oracle;
delete m_temporal;
m_workback.release ();
m_update_list.release ();
@@ -750,6 +758,8 @@ ranger_cache::dump_bb (FILE *f, basic_block bb)
{
m_gori.gori_map::dump (f, bb, false);
m_on_entry.dump (f, bb);
+ if (m_oracle)
+ m_oracle->dump (f, bb);
}
// Get the global range for NAME, and return in R. Return false if the
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 0a2c72b..385cecf 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -47,14 +47,25 @@ along with GCC; see the file COPYING3. If not see
#include "vr-values.h"
#include "gimple-range.h"
-// Evaluate expression EXPR using the source information the class was
-// instantiated with. Place the result in R, and return TRUE. If a range
-// cannot be calculated, return FALSE.
+// Construct a fur_source, and set the m_query field.
+
+fur_source::fur_source (range_query *q)
+{
+ if (q)
+ m_query = q;
+ else if (cfun)
+ m_query = get_range_query (cfun);
+ else
+ m_query = get_global_range_query ();
+ m_gori = NULL;
+}
+
+// Invoke range_of_expr on EXPR.
bool
fur_source::get_operand (irange &r, tree expr)
{
- return get_range_query (cfun)->range_of_expr (r, expr);
+ return m_query->range_of_expr (r, expr);
}
// Evaluate EXPR for this stmt as a PHI argument on edge E. Use the current
@@ -63,23 +74,36 @@ fur_source::get_operand (irange &r, tree expr)
bool
fur_source::get_phi_operand (irange &r, tree expr, edge e)
{
- return get_range_query (cfun)->range_on_edge (r, e, expr);
+ return m_query->range_on_edge (r, e, expr);
+}
+
+// Default is no relation.
+
+relation_kind
+fur_source::query_relation (tree op1 ATTRIBUTE_UNUSED,
+ tree op2 ATTRIBUTE_UNUSED)
+{
+ return VREL_NONE;
}
-// Default is to not register any dependencies from fold_using_range.
+// Default registers nothing.
void
-fur_source::register_dependency (tree lhs ATTRIBUTE_UNUSED,
- tree rhs ATTRIBUTE_UNUSED)
+fur_source::register_relation (gimple *s ATTRIBUTE_UNUSED,
+ relation_kind k ATTRIBUTE_UNUSED,
+ tree op1 ATTRIBUTE_UNUSED,
+ tree op2 ATTRIBUTE_UNUSED)
{
}
-// Default object is the current range query.
+// Default registers nothing.
-range_query *
-fur_source::query ()
+void
+fur_source::register_relation (edge e ATTRIBUTE_UNUSED,
+ relation_kind k ATTRIBUTE_UNUSED,
+ tree op1 ATTRIBUTE_UNUSED,
+ tree op2 ATTRIBUTE_UNUSED)
{
- return get_range_query (cfun);
}
// This version of fur_source will pick a range up off an edge.
@@ -90,22 +114,16 @@ public:
fur_edge (edge e, range_query *q = NULL);
virtual bool get_operand (irange &r, tree expr) OVERRIDE;
virtual bool get_phi_operand (irange &r, tree expr, edge e) OVERRIDE;
- virtual range_query *query () OVERRIDE;
private:
- range_query *m_query;
edge m_edge;
};
// Instantiate an edge based fur_source.
inline
-fur_edge::fur_edge (edge e, range_query *q)
+fur_edge::fur_edge (edge e, range_query *q) : fur_source (q)
{
m_edge = e;
- if (q)
- m_query = q;
- else
- m_query = get_range_query (cfun);
}
// Get the value of EXPR on edge m_edge.
@@ -122,31 +140,19 @@ fur_edge::get_operand (irange &r, tree expr)
bool
fur_edge::get_phi_operand (irange &r, tree expr, edge e)
{
- // edge to edge recalculations not supoprted yet, until we sort it out.
+ // Edge to edge recalculations not supoprted yet, until we sort it out.
gcc_checking_assert (e == m_edge);
return m_query->range_on_edge (r, e, expr);
}
-// Return the current range_query object.
-
-range_query *
-fur_edge::query ()
-{
- return m_query;
-}
-
// Instantiate a stmt based fur_source.
-fur_stmt::fur_stmt (gimple *s, range_query *q)
+fur_stmt::fur_stmt (gimple *s, range_query *q) : fur_source (q)
{
m_stmt = s;
- if (q)
- m_query = q;
- else
- m_query = get_global_range_query ();
}
-// Retrieve range of EXPR as it occurs as a use on stmt M_STMT.
+// Retreive range of EXPR as it occurs as a use on stmt M_STMT.
bool
fur_stmt::get_operand (irange &r, tree expr)
@@ -165,12 +171,12 @@ fur_stmt::get_phi_operand (irange &r, tree expr, edge e)
return e_src.get_operand (r, expr);
}
-// Return the current range_query object.
+// Return relation based from m_stmt.
-range_query *
-fur_stmt::query ()
+relation_kind
+fur_stmt::query_relation (tree op1, tree op2)
{
- return m_query;
+ return m_query->query_relation (m_stmt, op1, op2);
}
// This version of fur_source will pick a range from a stmt, and also register
@@ -180,12 +186,15 @@ class fur_depend : public fur_stmt
{
public:
fur_depend (gimple *s, gori_compute *gori, range_query *q = NULL);
- virtual void register_dependency (tree lhs, tree rhs) OVERRIDE;
+ virtual void register_relation (gimple *stmt, relation_kind k, tree op1,
+ tree op2) OVERRIDE;
+ virtual void register_relation (edge e, relation_kind k, tree op1,
+ tree op2) OVERRIDE;
private:
- gori_compute *m_gori;
+ relation_oracle *m_oracle;
};
-// Instantiate a stmt based fur_source with a GORI object
+// Instantiate a stmt based fur_source with a GORI object.
inline
fur_depend::fur_depend (gimple *s, gori_compute *gori, range_query *q)
@@ -193,14 +202,28 @@ fur_depend::fur_depend (gimple *s, gori_compute *gori, range_query *q)
{
gcc_checking_assert (gori);
m_gori = gori;
+ // Set relations if there is an oracle in the range_query.
+ // This will enable registering of relationships as they are discovered.
+ m_oracle = q->oracle ();
+
+}
+
+// Register a relation on a stmt if there is an oracle.
+
+void
+fur_depend::register_relation (gimple *s, relation_kind k, tree op1, tree op2)
+{
+ if (m_oracle)
+ m_oracle->register_relation (s, k, op1, op2);
}
-// find and add any dependnecy between LHS and RHS
+// Register a relation on an edge if there is an oracle.
void
-fur_depend::register_dependency (tree lhs, tree rhs)
+fur_depend::register_relation (edge e, relation_kind k, tree op1, tree op2)
{
- m_gori->register_dependency (lhs, rhs);
+ if (m_oracle)
+ m_oracle->register_relation (e, k, op1, op2);
}
// This version of fur_source will pick a range up from a list of ranges
@@ -223,7 +246,7 @@ private:
// One range supplied for unary operations.
-fur_list::fur_list (irange &r1)
+fur_list::fur_list (irange &r1) : fur_source (NULL)
{
m_list = m_local;
m_index = 0;
@@ -233,7 +256,7 @@ fur_list::fur_list (irange &r1)
// Two ranges supplied for binary operations.
-fur_list::fur_list (irange &r1, irange &r2)
+fur_list::fur_list (irange &r1, irange &r2) : fur_source (NULL)
{
m_list = m_local;
m_index = 0;
@@ -244,7 +267,7 @@ fur_list::fur_list (irange &r1, irange &r2)
// Arbitrary number of ranges in a vector.
-fur_list::fur_list (unsigned num, irange *list)
+fur_list::fur_list (unsigned num, irange *list) : fur_source (NULL)
{
m_list = list;
m_index = 0;
@@ -257,7 +280,7 @@ bool
fur_list::get_operand (irange &r, tree expr)
{
if (m_index >= m_limit)
- return get_range_query (cfun)->range_of_expr (r, expr);
+ return m_query->range_of_expr (r, expr);
r = m_list[m_index++];
gcc_checking_assert (range_compatible_p (TREE_TYPE (expr), r.type ()));
return true;
@@ -290,7 +313,6 @@ fold_range (irange &r, gimple *s, irange &r1, irange &r2)
return f.fold_stmt (r, s, src);
}
-
// Fold stmt S into range R using NUM_ELEMENTS from VECTOR as the initial
// operands encountered.
@@ -636,18 +658,50 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
// Fold range, and register any dependency if available.
int_range<2> r2 (type);
handler->fold_range (r, type, range1, r2);
- if (lhs)
- src.register_dependency (lhs, op1);
+ if (lhs && gimple_range_ssa_p (op1))
+ {
+ if (src.gori ())
+ src.gori ()->register_dependency (lhs, op1);
+ relation_kind rel;
+ rel = handler->lhs_op1_relation (r, range1, range1);
+ if (rel != VREL_NONE)
+ src.register_relation (s, rel, lhs, op1);
+ }
}
else if (src.get_operand (range2, op2))
{
+ relation_kind rel = src.query_relation (op1, op2);
+ if (dump_file && (dump_flags & TDF_DETAILS) && rel != VREL_NONE)
+ {
+ fprintf (dump_file, " folding with relation ");
+ print_relation (dump_file, rel);
+ fputc ('\n', dump_file);
+ }
// Fold range, and register any dependency if available.
- handler->fold_range (r, type, range1, range2);
+ handler->fold_range (r, type, range1, range2, rel);
+ relation_fold_and_or (r, s, src);
if (lhs)
{
- src.register_dependency (lhs, op1);
- src.register_dependency (lhs, op2);
+ if (src.gori ())
+ {
+ src.gori ()->register_dependency (lhs, op1);
+ src.gori ()->register_dependency (lhs, op2);
+ }
+ if (gimple_range_ssa_p (op1))
+ {
+ rel = handler->lhs_op1_relation (r, range1, range2);
+ if (rel != VREL_NONE)
+ src.register_relation (s, rel, lhs, op1);
+ }
+ if (gimple_range_ssa_p (op2))
+ {
+ rel= handler->lhs_op2_relation (r, range1, range2);
+ if (rel != VREL_NONE)
+ src.register_relation (s, rel, lhs, op2);
+ }
}
+ else if (is_a<gcond *> (s))
+ postfold_gcond_edges (as_a<gcond *> (s), src);
}
else
r.set_varying (type);
@@ -686,8 +740,8 @@ fold_using_range::range_of_address (irange &r, gimple *stmt, fur_source &src)
{
tree ssa = TREE_OPERAND (base, 0);
tree lhs = gimple_get_lhs (stmt);
- if (lhs && gimple_range_ssa_p (ssa))
- src.register_dependency (lhs, ssa);
+ if (lhs && gimple_range_ssa_p (ssa) && src.gori ())
+ src.gori ()->register_dependency (lhs, ssa);
gcc_checking_assert (irange::supports_type_p (TREE_TYPE (ssa)));
src.get_operand (r, ssa);
range_cast (r, TREE_TYPE (gimple_assign_rhs1 (stmt)));
@@ -764,8 +818,8 @@ fold_using_range::range_of_phi (irange &r, gphi *phi, fur_source &src)
edge e = gimple_phi_arg_edge (phi, x);
// Register potential dependencies for stale value tracking.
- if (gimple_range_ssa_p (arg))
- src.register_dependency (phi_def, arg);
+ if (gimple_range_ssa_p (arg) && src.gori ())
+ src.gori ()->register_dependency (phi_def, arg);
// Get the range of the argument on its edge.
src.get_phi_operand (arg_range, arg, e);
@@ -1149,6 +1203,12 @@ fold_using_range::range_of_cond_expr (irange &r, gassign *s, fur_source &src)
return true;
}
+gimple_ranger::gimple_ranger ()
+{
+ // If the cache has a relation oracle, use it.
+ m_oracle = m_cache.oracle ();
+}
+
bool
gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt)
{
@@ -1464,6 +1524,185 @@ fold_using_range::range_of_ssa_name_with_loop_info (irange &r, tree name,
r.set_varying (type);
}
+// -----------------------------------------------------------------------
+
+// Check if an && or || expression can be folded based on relations. ie
+// c_2 = a_6 > b_7
+// c_3 = a_6 < b_7
+// c_4 = c_2 && c_3
+// c_2 and c_3 can never be true at the same time,
+// Therefore c_4 can always resolve to false based purely on the relations.
+
+void
+fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
+ fur_source &src)
+{
+ // No queries or already folded.
+ if (!src.gori () || !src.query ()->oracle () || lhs_range.singleton_p ())
+ return;
+
+ // Only care about AND and OR expressions.
+ enum tree_code code = gimple_expr_code (s);
+ bool is_and = false;
+ if (code == BIT_AND_EXPR || code == TRUTH_AND_EXPR)
+ is_and = true;
+ else if (code != BIT_IOR_EXPR && code != TRUTH_OR_EXPR)
+ return;
+
+ tree lhs = gimple_get_lhs (s);
+ tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (s));
+ tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (s));
+
+ // Deal with || and && only when there is a full set of symbolics.
+ if (!lhs || !ssa1 || !ssa2
+ || (TREE_CODE (TREE_TYPE (lhs)) != BOOLEAN_TYPE)
+ || (TREE_CODE (TREE_TYPE (ssa1)) != BOOLEAN_TYPE)
+ || (TREE_CODE (TREE_TYPE (ssa2)) != BOOLEAN_TYPE))
+ return;
+
+ // Now we know its a boolean AND or OR expression with boolean operands.
+ // Ideally we search dependencies for common names, and see what pops out.
+ // until then, simply try to resolve direct dependencies.
+
+ // Both names will need to have 2 direct dependencies.
+ tree ssa1_dep2 = src.gori ()->depend2 (ssa1);
+ tree ssa2_dep2 = src.gori ()->depend2 (ssa2);
+ if (!ssa1_dep2 || !ssa2_dep2)
+ return;
+
+ tree ssa1_dep1 = src.gori ()->depend1 (ssa1);
+ tree ssa2_dep1 = src.gori ()->depend1 (ssa2);
+ // Make sure they are the same dependencies, and detect the order of the
+ // relationship.
+ bool reverse_op2 = true;
+ if (ssa1_dep1 == ssa2_dep1 && ssa1_dep2 == ssa2_dep2)
+ reverse_op2 = false;
+ else if (ssa1_dep1 != ssa2_dep2 || ssa1_dep2 != ssa2_dep1)
+ return;
+
+ range_operator *handler1 = gimple_range_handler (SSA_NAME_DEF_STMT (ssa1));
+ range_operator *handler2 = gimple_range_handler (SSA_NAME_DEF_STMT (ssa2));
+
+ int_range<2> bool_one (boolean_true_node, boolean_true_node);
+
+ relation_kind relation1 = handler1->op1_op2_relation (bool_one);
+ relation_kind relation2 = handler2->op1_op2_relation (bool_one);
+ if (relation1 == VREL_NONE || relation2 == VREL_NONE)
+ return;
+
+ if (reverse_op2)
+ relation2 = relation_negate (relation2);
+
+ // x && y is false if the relation intersection of the true cases is NULL.
+ if (is_and && relation_intersect (relation1, relation2) == VREL_EMPTY)
+ lhs_range = int_range<2> (boolean_false_node, boolean_false_node);
+ // x || y is true if the union of the true cases is NO-RELATION..
+ // ie, one or the other being true covers the full range of possibilties.
+ else if (!is_and && relation_union (relation1, relation2) == VREL_NONE)
+ lhs_range = bool_one;
+ else
+ return;
+
+ range_cast (lhs_range, TREE_TYPE (lhs));
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, " Relation adjustment: ");
+ print_generic_expr (dump_file, ssa1, TDF_SLIM);
+ fprintf (dump_file, " and ");
+ print_generic_expr (dump_file, ssa2, TDF_SLIM);
+ fprintf (dump_file, " combine to produce ");
+ lhs_range.dump (dump_file);
+ fputc ('\n', dump_file);
+ }
+
+ return;
+}
+
+// Register any outgoing edge relations from a conditional branch.
+
+void
+fold_using_range::postfold_gcond_edges (gcond *s, fur_source &src)
+{
+ int_range_max r;
+ tree name;
+ range_operator *handler;
+ basic_block bb = gimple_bb (s);
+
+ edge e0 = EDGE_SUCC (bb, 0);
+ if (!single_pred_p (e0->dest))
+ e0 = NULL;
+
+ edge e1 = EDGE_SUCC (bb, 1);
+ if (!single_pred_p (e1->dest))
+ e1 = NULL;
+
+ // At least one edge needs to be single pred.
+ if (!e0 && !e1)
+ return;
+
+ // First, register the gcond itself. This will catch statements like
+ // if (a_2 < b_5)
+ tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (s));
+ tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (s));
+ if (ssa1 && ssa2)
+ {
+ handler = gimple_range_handler (s);
+ gcc_checking_assert (handler);
+ if (e0)
+ {
+ gcond_edge_range (r, e0);
+ relation_kind relation = handler->op1_op2_relation (r);
+ if (relation != VREL_NONE)
+ src.register_relation (e0, relation, ssa1, ssa2);
+ }
+ if (e1)
+ {
+ gcond_edge_range (r, e1);
+ relation_kind relation = handler->op1_op2_relation (r);
+ if (relation != VREL_NONE)
+ src.register_relation (e1, relation, ssa1, ssa2);
+ }
+ }
+
+ // Outgoing relations of GORI exports require a gori engine.
+ if (!src.gori ())
+ return;
+
+ range_query *q = src.query ();
+ // Now look for other relations in the exports. This will find stmts
+ // leading to the condition such as:
+ // c_2 = a_4 < b_7
+ // if (c_2)
+
+ FOR_EACH_GORI_EXPORT_NAME (*(src.gori ()), bb, name)
+ {
+ if (TREE_CODE (TREE_TYPE (name)) != BOOLEAN_TYPE)
+ continue;
+ gimple *stmt = SSA_NAME_DEF_STMT (name);
+ handler = gimple_range_handler (stmt);
+ if (!handler)
+ continue;
+ tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (stmt));
+ tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (stmt));
+ if (ssa1 && ssa2)
+ {
+ if (e0 && src.gori ()->outgoing_edge_range_p (r, e0, name, *q)
+ && r.singleton_p ())
+ {
+ relation_kind relation = handler->op1_op2_relation (r);
+ if (relation != VREL_NONE)
+ src.register_relation (e0, relation, ssa1, ssa2);
+ }
+ if (e1 && src.gori ()->outgoing_edge_range_p (r, e1, name, *q)
+ && r.singleton_p ())
+ {
+ relation_kind relation = handler->op1_op2_relation (r);
+ if (relation != VREL_NONE)
+ src.register_relation (e1, relation, ssa1, ssa2);
+ }
+ }
+ }
+}
// --------------------------------------------------------------------------
// trace_ranger implementation.
diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h
index fc28123..87911b9 100644
--- a/gcc/gimple-range.h
+++ b/gcc/gimple-range.h
@@ -24,8 +24,8 @@ along with GCC; see the file COPYING3. If not see
#include "range.h"
-#include "range-op.h"
#include "value-query.h"
+#include "range-op.h"
#include "gimple-range-edge.h"
#include "gimple-range-gori.h"
#include "gimple-range-cache.h"
@@ -58,6 +58,7 @@ along with GCC; see the file COPYING3. If not see
class gimple_ranger : public range_query
{
public:
+ gimple_ranger ();
virtual bool range_of_stmt (irange &r, gimple *, tree name = NULL) OVERRIDE;
virtual bool range_of_expr (irange &r, tree name, gimple * = NULL) OVERRIDE;
virtual bool range_on_edge (irange &r, edge e, tree name) OVERRIDE;
@@ -74,15 +75,25 @@ protected:
// Source of all operands for fold_using_range and gori_compute.
// It abstracts out the source of an operand so it can come from a stmt or
-// and edge or anywhere a derived classof fur_source wants.
+// and edge or anywhere a derived class of fur_source wants.
+// THe default simply picks up ranges from the current range_query.
class fur_source
{
public:
+ fur_source (range_query *q = NULL);
+ inline range_query *query () { return m_query; }
+ inline class gori_compute *gori () { return m_gori; };
virtual bool get_operand (irange &r, tree expr);
virtual bool get_phi_operand (irange &r, tree expr, edge e);
- virtual void register_dependency (tree lhs, tree rhs);
- virtual range_query *query ();
+ virtual relation_kind query_relation (tree op1, tree op2);
+ virtual void register_relation (gimple *stmt, relation_kind k, tree op1,
+ tree op2);
+ virtual void register_relation (edge e, relation_kind k, tree op1,
+ tree op2);
+protected:
+ range_query *m_query;
+ gori_compute *m_gori;
};
// fur_stmt is the specification for drawing an operand from range_query Q
@@ -94,9 +105,8 @@ public:
fur_stmt (gimple *s, range_query *q = NULL);
virtual bool get_operand (irange &r, tree expr) OVERRIDE;
virtual bool get_phi_operand (irange &r, tree expr, edge e) OVERRIDE;
- virtual range_query *query () OVERRIDE;
+ virtual relation_kind query_relation (tree op1, tree op2) OVERRIDE;
private:
- range_query *m_query;
gimple *m_stmt;
};
@@ -132,6 +142,8 @@ protected:
bool range_of_phi (irange &r, gphi *phi, fur_source &src);
void range_of_ssa_name_with_loop_info (irange &, tree, class loop *, gphi *,
fur_source &src);
+ void relation_fold_and_or (irange& lhs_range, gimple *s, fur_source &src);
+ void postfold_gcond_edges (gcond *s, fur_source &src);
};
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 41bae9c..21e7a6c 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -15128,24 +15128,11 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
bool (*gimple_test_f) (tree), fallback_t fallback,
bool allow_ssa)
{
- bool was_ssa_name_p = TREE_CODE (*expr_p) == SSA_NAME;
enum gimplify_status ret = gimplify_expr (expr_p, pre_p, post_p,
gimple_test_f, fallback);
if (! allow_ssa
&& TREE_CODE (*expr_p) == SSA_NAME)
- {
- tree name = *expr_p;
- if (was_ssa_name_p)
- *expr_p = get_initialized_tmp_var (*expr_p, pre_p, NULL, false);
- else
- {
- /* Avoid the extra copy if possible. */
- *expr_p = create_tmp_reg (TREE_TYPE (name));
- if (!gimple_nop_p (SSA_NAME_DEF_STMT (name)))
- gimple_set_lhs (SSA_NAME_DEF_STMT (name), *expr_p);
- release_ssa_name (name);
- }
- }
+ *expr_p = get_initialized_tmp_var (*expr_p, pre_p, NULL, false);
return ret;
}
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index e805f26..1692a09 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-walk.h"
#include "tree-cfg.h"
#include "wide-int.h"
+#include "value-relation.h"
#include "range-op.h"
// Return the upper limit for a type.
@@ -138,7 +139,8 @@ range_operator::wi_fold (irange &r, tree type,
bool
range_operator::fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const
+ const irange &rh,
+ relation_kind rel) const
{
gcc_checking_assert (irange::supports_type_p (type));
if (empty_range_varying (r, type, lh, rh))
@@ -152,6 +154,7 @@ range_operator::fold_range (irange &r, tree type,
{
wi_fold (r, type, lh.lower_bound (0), lh.upper_bound (0),
rh.lower_bound (0), rh.upper_bound (0));
+ op1_op2_relation_effect (r, type, lh, rh, rel);
return true;
}
@@ -167,8 +170,12 @@ range_operator::fold_range (irange &r, tree type,
wi_fold (tmp, type, lh_lb, lh_ub, rh_lb, rh_ub);
r.union_ (tmp);
if (r.varying_p ())
- return true;
+ {
+ op1_op2_relation_effect (r, type, lh, rh, rel);
+ return true;
+ }
}
+ op1_op2_relation_effect (r, type, lh, rh, rel);
return true;
}
@@ -178,7 +185,8 @@ bool
range_operator::op1_range (irange &r ATTRIBUTE_UNUSED,
tree type ATTRIBUTE_UNUSED,
const irange &lhs ATTRIBUTE_UNUSED,
- const irange &op2 ATTRIBUTE_UNUSED) const
+ const irange &op2 ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return false;
}
@@ -189,11 +197,47 @@ bool
range_operator::op2_range (irange &r ATTRIBUTE_UNUSED,
tree type ATTRIBUTE_UNUSED,
const irange &lhs ATTRIBUTE_UNUSED,
- const irange &op1 ATTRIBUTE_UNUSED) const
+ const irange &op1 ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return false;
}
+// The default relation routines return VREL_NONE.
+
+enum tree_code
+range_operator::lhs_op1_relation (const irange &lhs ATTRIBUTE_UNUSED,
+ const irange &op1 ATTRIBUTE_UNUSED,
+ const irange &op2 ATTRIBUTE_UNUSED) const
+{
+ return VREL_NONE;
+}
+
+enum tree_code
+range_operator::lhs_op2_relation (const irange &lhs ATTRIBUTE_UNUSED,
+ const irange &op1 ATTRIBUTE_UNUSED,
+ const irange &op2 ATTRIBUTE_UNUSED) const
+{
+ return VREL_NONE;
+}
+
+enum tree_code
+range_operator::op1_op2_relation (const irange &lhs ATTRIBUTE_UNUSED) const
+{
+ return VREL_NONE;
+}
+
+// Default is no relation affects the LHS.
+
+bool
+range_operator::op1_op2_relation_effect (irange &lhs_range ATTRIBUTE_UNUSED,
+ tree type ATTRIBUTE_UNUSED,
+ const irange &op1_range ATTRIBUTE_UNUSED,
+ const irange &op2_range ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
+{
+ return false;
+}
// Create and return a range from a pair of wide-ints that are known
// to have overflowed (or underflowed).
@@ -385,27 +429,82 @@ get_bool_state (irange &r, const irange &lhs, tree val_type)
return BRS_TRUE;
}
+// For relation opcodes, first try to see if the supplied relation
+// forces a true or false result, and return that.
+// Then check for undefined operands. If none of this applies,
+// return false.
+
+static inline bool
+relop_early_resolve (irange &r, tree type, const irange &op1,
+ const irange &op2, relation_kind rel,
+ relation_kind my_rel)
+{
+ // If known relation is a complete subset of this relation, always true.
+ if (relation_union (rel, my_rel) == my_rel)
+ {
+ r = range_true (type);
+ return true;
+ }
+
+ // If known relation has no subset of this relation, always false.
+ if (relation_intersect (rel, my_rel) == VREL_EMPTY)
+ {
+ r = range_false (type);
+ return true;
+ }
+
+ // If either operand is undefined, return VARYING.
+ if (empty_range_varying (r, type, op1, op2))
+ return true;
+
+ return false;
+}
+
class operator_equal : public range_operator
{
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &val) const;
+ const irange &val,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &val) const;
+ const irange &val,
+ relation_kind rel = VREL_NONE) const;
+ virtual enum tree_code op1_op2_relation (const irange &lhs) const;
} op_equal;
+// Check if the LHS range indicates a relation between OP1 and OP2.
+
+enum tree_code
+operator_equal::op1_op2_relation (const irange &lhs) const
+{
+ if (lhs.undefined_p ())
+ return VREL_EMPTY;
+
+ // FALSE = op1 == op2 indicates NE_EXPR.
+ if (lhs.zero_p ())
+ return NE_EXPR;
+
+ // TRUE = op1 == op2 indicates EQ_EXPR.
+ if (!lhs.contains_p (build_zero_cst (lhs.type ())))
+ return EQ_EXPR;
+ return VREL_NONE;
+}
+
+
bool
operator_equal::fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel) const
{
- if (empty_range_varying (r, type, op1, op2))
+ if (relop_early_resolve (r, type, op1, op2, rel, EQ_EXPR))
return true;
// We can be sure the values are always equal or not if both ranges
@@ -435,7 +534,8 @@ operator_equal::fold_range (irange &r, tree type,
bool
operator_equal::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -465,32 +565,55 @@ operator_equal::op1_range (irange &r, tree type,
bool
operator_equal::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel) const
{
- return operator_equal::op1_range (r, type, lhs, op1);
+ return operator_equal::op1_range (r, type, lhs, op1, rel);
}
-
class operator_not_equal : public range_operator
{
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel = VREL_NONE) const;
+ virtual enum tree_code op1_op2_relation (const irange &lhs) const;
} op_not_equal;
+// Check if the LHS range indicates a relation between OP1 and OP2.
+
+enum tree_code
+operator_not_equal::op1_op2_relation (const irange &lhs) const
+{
+ if (lhs.undefined_p ())
+ return VREL_EMPTY;
+
+ // FALSE = op1 != op2 indicates EQ_EXPR.
+ if (lhs.zero_p ())
+ return EQ_EXPR;
+
+ // TRUE = op1 != op2 indicates NE_EXPR.
+ if (!lhs.contains_p (build_zero_cst (lhs.type ())))
+ return NE_EXPR;
+ return VREL_NONE;
+}
+
bool
operator_not_equal::fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel) const
{
- if (empty_range_varying (r, type, op1, op2))
+ if (relop_early_resolve (r, type, op1, op2, rel, NE_EXPR))
return true;
// We can be sure the values are always equal or not if both ranges
@@ -520,7 +643,8 @@ operator_not_equal::fold_range (irange &r, tree type,
bool
operator_not_equal::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -551,9 +675,10 @@ operator_not_equal::op1_range (irange &r, tree type,
bool
operator_not_equal::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel) const
{
- return operator_not_equal::op1_range (r, type, lhs, op1);
+ return operator_not_equal::op1_range (r, type, lhs, op1, rel);
}
// (X < VAL) produces the range of [MIN, VAL - 1].
@@ -607,21 +732,44 @@ class operator_lt : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel = VREL_NONE) const;
+ virtual enum tree_code op1_op2_relation (const irange &lhs) const;
} op_lt;
+// Check if the LHS range indicates a relation between OP1 and OP2.
+
+enum tree_code
+operator_lt::op1_op2_relation (const irange &lhs) const
+{
+ if (lhs.undefined_p ())
+ return VREL_EMPTY;
+
+ // FALSE = op1 < op2 indicates GE_EXPR.
+ if (lhs.zero_p ())
+ return GE_EXPR;
+
+ // TRUE = op1 < op2 indicates LT_EXPR.
+ if (!lhs.contains_p (build_zero_cst (lhs.type ())))
+ return LT_EXPR;
+ return VREL_NONE;
+}
+
bool
operator_lt::fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel) const
{
- if (empty_range_varying (r, type, op1, op2))
+ if (relop_early_resolve (r, type, op1, op2, rel, LT_EXPR))
return true;
signop sign = TYPE_SIGN (op1.type ());
@@ -639,7 +787,8 @@ operator_lt::fold_range (irange &r, tree type,
bool
operator_lt::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -660,7 +809,8 @@ operator_lt::op1_range (irange &r, tree type,
bool
operator_lt::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -684,21 +834,44 @@ class operator_le : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel = VREL_NONE) const;
+ virtual enum tree_code op1_op2_relation (const irange &lhs) const;
} op_le;
+// Check if the LHS range indicates a relation between OP1 and OP2.
+
+enum tree_code
+operator_le::op1_op2_relation (const irange &lhs) const
+{
+ if (lhs.undefined_p ())
+ return VREL_EMPTY;
+
+ // FALSE = op1 <= op2 indicates GT_EXPR.
+ if (lhs.zero_p ())
+ return GT_EXPR;
+
+ // TRUE = op1 <= op2 indicates LE_EXPR.
+ if (!lhs.contains_p (build_zero_cst (lhs.type ())))
+ return LE_EXPR;
+ return VREL_NONE;
+}
+
bool
operator_le::fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel) const
{
- if (empty_range_varying (r, type, op1, op2))
+ if (relop_early_resolve (r, type, op1, op2, rel, LE_EXPR))
return true;
signop sign = TYPE_SIGN (op1.type ());
@@ -716,7 +889,8 @@ operator_le::fold_range (irange &r, tree type,
bool
operator_le::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -737,7 +911,8 @@ operator_le::op1_range (irange &r, tree type,
bool
operator_le::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -761,20 +936,44 @@ class operator_gt : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel = VREL_NONE) const;
+ virtual enum tree_code op1_op2_relation (const irange &lhs) const;
} op_gt;
+// Check if the LHS range indicates a relation between OP1 and OP2.
+
+enum tree_code
+operator_gt::op1_op2_relation (const irange &lhs) const
+{
+ if (lhs.undefined_p ())
+ return VREL_EMPTY;
+
+ // FALSE = op1 > op2 indicates LE_EXPR.
+ if (lhs.zero_p ())
+ return LE_EXPR;
+
+ // TRUE = op1 > op2 indicates GT_EXPR.
+ if (!lhs.contains_p (build_zero_cst (lhs.type ())))
+ return GT_EXPR;
+ return VREL_NONE;
+}
+
+
bool
operator_gt::fold_range (irange &r, tree type,
- const irange &op1, const irange &op2) const
+ const irange &op1, const irange &op2,
+ relation_kind rel) const
{
- if (empty_range_varying (r, type, op1, op2))
+ if (relop_early_resolve (r, type, op1, op2, rel, GT_EXPR))
return true;
signop sign = TYPE_SIGN (op1.type ());
@@ -791,7 +990,8 @@ operator_gt::fold_range (irange &r, tree type,
bool
operator_gt::op1_range (irange &r, tree type,
- const irange &lhs, const irange &op2) const
+ const irange &lhs, const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -812,7 +1012,8 @@ operator_gt::op1_range (irange &r, tree type,
bool
operator_gt::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -836,21 +1037,44 @@ class operator_ge : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel = VREL_NONE) const;
+ virtual enum tree_code op1_op2_relation (const irange &lhs) const;
} op_ge;
+// Check if the LHS range indicates a relation between OP1 and OP2.
+
+enum tree_code
+operator_ge::op1_op2_relation (const irange &lhs) const
+{
+ if (lhs.undefined_p ())
+ return VREL_EMPTY;
+
+ // FALSE = op1 >= op2 indicates LT_EXPR.
+ if (lhs.zero_p ())
+ return LT_EXPR;
+
+ // TRUE = op1 >= op2 indicates GE_EXPR.
+ if (!lhs.contains_p (build_zero_cst (lhs.type ())))
+ return GE_EXPR;
+ return VREL_NONE;
+}
+
bool
operator_ge::fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel) const
{
- if (empty_range_varying (r, type, op1, op2))
+ if (relop_early_resolve (r, type, op1, op2, rel, GE_EXPR))
return true;
signop sign = TYPE_SIGN (op1.type ());
@@ -868,7 +1092,8 @@ operator_ge::fold_range (irange &r, tree type,
bool
operator_ge::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -889,7 +1114,8 @@ operator_ge::op1_range (irange &r, tree type,
bool
operator_ge::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -913,17 +1139,99 @@ class operator_plus : public range_operator
public:
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const;
virtual void wi_fold (irange &r, tree type,
const wide_int &lh_lb,
const wide_int &lh_ub,
const wide_int &rh_lb,
const wide_int &rh_ub) const;
+ virtual enum tree_code lhs_op1_relation (const irange &lhs, const irange &op1,
+ const irange &op2) const;
+ virtual enum tree_code lhs_op2_relation (const irange &lhs, const irange &op1,
+ const irange &op2) const;
} op_plus;
+// Check to see if the range of OP2 indicates anything about the relation
+// between LHS and OP1.
+
+enum tree_code
+operator_plus::lhs_op1_relation (const irange &lhs,
+ const irange &op1,
+ const irange &op2) const
+{
+ if (lhs.undefined_p () || op1.undefined_p () || op2.undefined_p ())
+ return VREL_NONE;
+
+ tree type = lhs.type ();
+ unsigned prec = TYPE_PRECISION (type);
+ wi::overflow_type ovf1, ovf2;
+ signop sign = TYPE_SIGN (type);
+
+ // LHS = OP1 + 0 indicates LHS == OP1.
+ if (op2.zero_p ())
+ return EQ_EXPR;
+
+ if (TYPE_OVERFLOW_WRAPS (type))
+ {
+ wi::add (op1.lower_bound (), op2.lower_bound (), sign, &ovf1);
+ wi::add (op1.upper_bound (), op2.upper_bound (), sign, &ovf2);
+ }
+ else
+ ovf1 = ovf2 = wi::OVF_NONE;
+
+ // Never wrapping additions.
+ if (!ovf1 && !ovf2)
+ {
+ // Positive op2 means lhs > op1.
+ if (wi::gt_p (op2.lower_bound (), wi::zero (prec), sign))
+ return GT_EXPR;
+ if (wi::ge_p (op2.lower_bound (), wi::zero (prec), sign))
+ return GE_EXPR;
+
+ // Negative op2 means lhs < op1.
+ if (wi::lt_p (op2.upper_bound (), wi::zero (prec), sign))
+ return LT_EXPR;
+ if (wi::le_p (op2.upper_bound (), wi::zero (prec), sign))
+ return LE_EXPR;
+ }
+ // Always wrapping additions.
+ else if (ovf1 && ovf1 == ovf2)
+ {
+ // Positive op2 means lhs < op1.
+ if (wi::gt_p (op2.lower_bound (), wi::zero (prec), sign))
+ return LT_EXPR;
+ if (wi::ge_p (op2.lower_bound (), wi::zero (prec), sign))
+ return LE_EXPR;
+
+ // Negative op2 means lhs > op1.
+ if (wi::lt_p (op2.upper_bound (), wi::zero (prec), sign))
+ return GT_EXPR;
+ if (wi::le_p (op2.upper_bound (), wi::zero (prec), sign))
+ return GE_EXPR;
+ }
+
+ // If op2 does not contain 0, then LHS and OP1 can never be equal.
+ if (!range_includes_zero_p (&op2))
+ return NE_EXPR;
+
+ return VREL_NONE;
+}
+
+// PLUS is symmetrical, so we can simply call lhs_op1_relation with reversed
+// operands.
+
+enum tree_code
+operator_plus::lhs_op2_relation (const irange &lhs, const irange &op1,
+ const irange &op2) const
+{
+ return lhs_op1_relation (lhs, op2, op1);
+}
+
void
operator_plus::wi_fold (irange &r, tree type,
const wide_int &lh_lb, const wide_int &lh_ub,
@@ -939,7 +1247,8 @@ operator_plus::wi_fold (irange &r, tree type,
bool
operator_plus::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op2);
}
@@ -947,7 +1256,8 @@ operator_plus::op1_range (irange &r, tree type,
bool
operator_plus::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op1);
}
@@ -958,15 +1268,22 @@ class operator_minus : public range_operator
public:
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const;
virtual void wi_fold (irange &r, tree type,
const wide_int &lh_lb,
const wide_int &lh_ub,
const wide_int &rh_lb,
const wide_int &rh_ub) const;
+ virtual bool op1_op2_relation_effect (irange &lhs_range,
+ tree type,
+ const irange &op1_range,
+ const irange &op2_range,
+ relation_kind rel) const;
} op_minus;
void
@@ -981,10 +1298,50 @@ operator_minus::wi_fold (irange &r, tree type,
value_range_with_overflow (r, type, new_lb, new_ub, ov_lb, ov_ub);
}
+// Check to see if the relation REL between OP1 and OP2 has any effect on the
+// LHS of the epxression. If so, apply it to LHS_RANGE.
+
+bool
+operator_minus::op1_op2_relation_effect (irange &lhs_range, tree type,
+ const irange &op1_range ATTRIBUTE_UNUSED,
+ const irange &op2_range ATTRIBUTE_UNUSED,
+ relation_kind rel) const
+{
+ if (rel == VREL_NONE)
+ return false;
+
+ int_range<2> rel_range;
+ unsigned prec = TYPE_PRECISION (type);
+ signop sgn = TYPE_SIGN (type);
+
+ switch (rel)
+ {
+ // op1 > op2, op1 - op2 can be restricted to [1, max]
+ case GT_EXPR:
+ rel_range = int_range<2> (type, wi::one (prec),
+ wi::max_value (prec, sgn));
+ break;
+ // op1 >= op2, op1 - op2 can be restricted to [0, max]
+ case GE_EXPR:
+ rel_range = int_range<2> (type, wi::zero (prec),
+ wi::max_value (prec, sgn));
+ break;
+ // op1 == op2, op1 - op2 can be restricted to [0, 0]
+ case EQ_EXPR:
+ rel_range = int_range<2> (type, wi::zero (prec), wi::zero (prec));
+ break;
+ default:
+ return false;
+ }
+ lhs_range.intersect (rel_range);
+ return true;
+}
+
bool
operator_minus::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return range_op_handler (PLUS_EXPR, type)->fold_range (r, type, lhs, op2);
}
@@ -992,7 +1349,8 @@ operator_minus::op1_range (irange &r, tree type,
bool
operator_minus::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return fold_range (r, type, op1, lhs);
}
@@ -1127,15 +1485,18 @@ public:
const wide_int &w0, const wide_int &w1) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const;
} op_mult;
bool
operator_mult::op1_range (irange &r, tree type,
- const irange &lhs, const irange &op2) const
+ const irange &lhs, const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
tree offset;
@@ -1153,9 +1514,10 @@ operator_mult::op1_range (irange &r, tree type,
bool
operator_mult::op2_range (irange &r, tree type,
- const irange &lhs, const irange &op1) const
+ const irange &lhs, const irange &op1,
+ relation_kind rel) const
{
- return operator_mult::op1_range (r, type, lhs, op1);
+ return operator_mult::op1_range (r, type, lhs, op1, rel);
}
bool
@@ -1391,14 +1753,16 @@ public:
operator_exact_divide () : operator_div (TRUNC_DIV_EXPR) { }
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const;
} op_exact_div;
bool
operator_exact_divide::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
tree offset;
// [2, 4] = op1 / [3,3] since its exact divide, no need to worry about
@@ -1419,10 +1783,12 @@ class operator_lshift : public cross_product_operator
public:
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual void wi_fold (irange &r, tree type,
const wide_int &lh_lb, const wide_int &lh_ub,
@@ -1438,7 +1804,8 @@ class operator_rshift : public cross_product_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual void wi_fold (irange &r, tree type,
const wide_int &lh_lb,
const wide_int &lh_ub,
@@ -1450,14 +1817,16 @@ public:
const wide_int &w1) const;
virtual bool op1_range (irange &, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
} op_rshift;
bool
operator_lshift::fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
int_range_max shift_range;
if (!get_shift_range (shift_range, type, op2))
@@ -1572,7 +1941,8 @@ bool
operator_lshift::op1_range (irange &r,
tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
tree shift_amount;
if (op2.singleton_p (&shift_amount))
@@ -1632,7 +2002,8 @@ bool
operator_rshift::op1_range (irange &r,
tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
tree shift;
if (op2.singleton_p (&shift))
@@ -1708,7 +2079,8 @@ operator_rshift::wi_op_overflows (wide_int &res,
bool
operator_rshift::fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
int_range_max shift;
if (!get_shift_range (shift, type, op2))
@@ -1737,10 +2109,16 @@ class operator_cast: public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
+ virtual enum tree_code lhs_op1_relation (const irange &lhs,
+ const irange &op1,
+ const irange &op2) const;
+
private:
bool truncating_cast_p (const irange &inner, const irange &outer) const;
bool inside_domain_p (const wide_int &min, const wide_int &max,
@@ -1749,6 +2127,27 @@ private:
const irange &outer) const;
} op_convert;
+// Determine if there is a relationship between LHS and OP1.
+
+enum tree_code
+operator_cast::lhs_op1_relation (const irange &lhs,
+ const irange &op1,
+ const irange &op2 ATTRIBUTE_UNUSED) const
+{
+ if (op1.undefined_p ())
+ return VREL_NONE;
+ // We can't make larger types equivalent to smaller types because we can
+ // miss sign extensions in a chain of casts.
+ // u32 = 0xfffff
+ // s32 = (s32) u32
+ // s64 = (s64) s32
+ // we cant simply "convert" s64 = (s64)u32 or we get positive 0xffff
+ // value instead of sign extended negative value.
+ if (TYPE_PRECISION (lhs.type ()) == TYPE_PRECISION (op1.type ()))
+ return EQ_EXPR;
+ return VREL_NONE;
+}
+
// Return TRUE if casting from INNER to OUTER is a truncating cast.
inline bool
@@ -1818,7 +2217,8 @@ operator_cast::fold_pair (irange &r, unsigned index,
bool
operator_cast::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
const irange &inner,
- const irange &outer) const
+ const irange &outer,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (empty_range_varying (r, type, inner, outer))
return true;
@@ -1844,7 +2244,8 @@ operator_cast::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
bool
operator_cast::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
tree lhs_type = lhs.type ();
gcc_checking_assert (types_compatible_p (op2.type(), type));
@@ -1954,20 +2355,24 @@ class operator_logical_and : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const;
+ const irange &rh,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel = VREL_NONE) const;
} op_logical_and;
bool
operator_logical_and::fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const
+ const irange &rh,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (empty_range_varying (r, type, lh, rh))
return true;
@@ -1989,7 +2394,8 @@ operator_logical_and::fold_range (irange &r, tree type,
bool
operator_logical_and::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2 ATTRIBUTE_UNUSED) const
+ const irange &op2 ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -2010,7 +2416,8 @@ operator_logical_and::op1_range (irange &r, tree type,
bool
operator_logical_and::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return operator_logical_and::op1_range (r, type, lhs, op1);
}
@@ -2021,13 +2428,16 @@ class operator_bitwise_and : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const;
+ const irange &rh,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel = VREL_NONE) const;
virtual void wi_fold (irange &r, tree type,
const wide_int &lh_lb,
const wide_int &lh_ub,
@@ -2106,7 +2516,8 @@ operator_bitwise_and::remove_impossible_ranges (irange &r,
bool
operator_bitwise_and::fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const
+ const irange &rh,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (range_operator::fold_range (r, type, lh, rh))
{
@@ -2397,7 +2808,8 @@ operator_bitwise_and::simple_op1_range_solver (irange &r, tree type,
bool
operator_bitwise_and::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (types_compatible_p (type, boolean_type_node))
return op_logical_and.op1_range (r, type, lhs, op2);
@@ -2420,7 +2832,8 @@ operator_bitwise_and::op1_range (irange &r, tree type,
bool
operator_bitwise_and::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return operator_bitwise_and::op1_range (r, type, lhs, op1);
}
@@ -2431,19 +2844,23 @@ class operator_logical_or : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const;
+ const irange &rh,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel = VREL_NONE) const;
} op_logical_or;
bool
operator_logical_or::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
const irange &lh,
- const irange &rh) const
+ const irange &rh,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (empty_range_varying (r, type, lh, rh))
return true;
@@ -2456,7 +2873,8 @@ operator_logical_or::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
bool
operator_logical_or::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2 ATTRIBUTE_UNUSED) const
+ const irange &op2 ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
switch (get_bool_state (r, lhs, type))
{
@@ -2477,7 +2895,8 @@ operator_logical_or::op1_range (irange &r, tree type,
bool
operator_logical_or::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return operator_logical_or::op1_range (r, type, lhs, op1);
}
@@ -2488,10 +2907,12 @@ class operator_bitwise_or : public range_operator
public:
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel= VREL_NONE) const;
virtual void wi_fold (irange &r, tree type,
const wide_int &lh_lb,
const wide_int &lh_ub,
@@ -2553,7 +2974,8 @@ operator_bitwise_or::wi_fold (irange &r, tree type,
bool
operator_bitwise_or::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
// If this is really a logical wi_fold, call that.
if (types_compatible_p (type, boolean_type_node))
@@ -2572,7 +2994,8 @@ operator_bitwise_or::op1_range (irange &r, tree type,
bool
operator_bitwise_or::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return operator_bitwise_or::op1_range (r, type, lhs, op1);
}
@@ -2588,10 +3011,12 @@ public:
const wide_int &rh_ub) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel = VREL_NONE) const;
} op_bitwise_xor;
void
@@ -2628,7 +3053,8 @@ operator_bitwise_xor::wi_fold (irange &r, tree type,
bool
operator_bitwise_xor::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (lhs.undefined_p () || lhs.varying_p ())
{
@@ -2662,7 +3088,8 @@ operator_bitwise_xor::op1_range (irange &r, tree type,
bool
operator_bitwise_xor::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return operator_bitwise_xor::op1_range (r, type, lhs, op1);
}
@@ -2677,10 +3104,12 @@ public:
const wide_int &rh_ub) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const;
} op_trunc_mod;
void
@@ -2730,7 +3159,8 @@ operator_trunc_mod::wi_fold (irange &r, tree type,
bool
operator_trunc_mod::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &) const
+ const irange &,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
// PR 91029.
signop sign = TYPE_SIGN (type);
@@ -2753,7 +3183,8 @@ operator_trunc_mod::op1_range (irange &r, tree type,
bool
operator_trunc_mod::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &) const
+ const irange &,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
// PR 91029.
signop sign = TYPE_SIGN (type);
@@ -2792,10 +3223,12 @@ class operator_logical_not : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const;
+ const irange &rh,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
} op_logical_not;
// Folding a logical NOT, oddly enough, involves doing nothing on the
@@ -2815,7 +3248,8 @@ public:
bool
operator_logical_not::fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh ATTRIBUTE_UNUSED) const
+ const irange &rh ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (empty_range_varying (r, type, lh, rh))
return true;
@@ -2831,7 +3265,8 @@ bool
operator_logical_not::op1_range (irange &r,
tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
// Logical NOT is involutary...do it again.
return fold_range (r, type, lhs, op2);
@@ -2843,16 +3278,19 @@ class operator_bitwise_not : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const;
+ const irange &rh,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
} op_bitwise_not;
bool
operator_bitwise_not::fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const
+ const irange &rh,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (empty_range_varying (r, type, lh, rh))
return true;
@@ -2870,7 +3308,8 @@ operator_bitwise_not::fold_range (irange &r, tree type,
bool
operator_bitwise_not::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (types_compatible_p (type, boolean_type_node))
return op_logical_not.op1_range (r, type, lhs, op2);
@@ -2885,13 +3324,15 @@ class operator_cst : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
} op_integer_cst;
bool
operator_cst::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
const irange &lh,
- const irange &rh ATTRIBUTE_UNUSED) const
+ const irange &rh ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
r = lh;
return true;
@@ -2903,16 +3344,35 @@ class operator_identity : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
+ virtual enum tree_code lhs_op1_relation (const irange &lhs,
+ const irange &op1,
+ const irange &op2) const;
} op_identity;
+// Determine if there is a relationship between LHS and OP1.
+
+enum tree_code
+operator_identity::lhs_op1_relation (const irange &lhs,
+ const irange &op1 ATTRIBUTE_UNUSED,
+ const irange &op2 ATTRIBUTE_UNUSED) const
+{
+ if (lhs.undefined_p ())
+ return VREL_NONE;
+ // Simply a copy, so they are equivalent.
+ return EQ_EXPR;
+}
+
bool
operator_identity::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
const irange &lh,
- const irange &rh ATTRIBUTE_UNUSED) const
+ const irange &rh ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
r = lh;
return true;
@@ -2921,7 +3381,8 @@ operator_identity::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
bool
operator_identity::op1_range (irange &r, tree type ATTRIBUTE_UNUSED,
const irange &lhs,
- const irange &op2 ATTRIBUTE_UNUSED) const
+ const irange &op2 ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
r = lhs;
return true;
@@ -2933,13 +3394,15 @@ class operator_unknown : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
} op_unknown;
bool
operator_unknown::fold_range (irange &r, tree type,
const irange &lh ATTRIBUTE_UNUSED,
- const irange &rh ATTRIBUTE_UNUSED) const
+ const irange &rh ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
r.set_varying (type);
return true;
@@ -2956,7 +3419,8 @@ class operator_abs : public range_operator
const wide_int &rh_ub) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const;
} op_abs;
void
@@ -3036,7 +3500,8 @@ operator_abs::wi_fold (irange &r, tree type,
bool
operator_abs::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (empty_range_varying (r, type, lhs, op2))
return true;
@@ -3108,16 +3573,19 @@ class operator_negate : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
} op_negate;
bool
operator_negate::fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const
+ const irange &rh,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (empty_range_varying (r, type, lh, rh))
return true;
@@ -3130,7 +3598,8 @@ operator_negate::fold_range (irange &r, tree type,
bool
operator_negate::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
// NEGATE is involutory.
return fold_range (r, type, lhs, op2);
@@ -3142,16 +3611,19 @@ class operator_addr_expr : public range_operator
public:
virtual bool fold_range (irange &r, tree type,
const irange &op1,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
} op_addr;
bool
operator_addr_expr::fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const
+ const irange &rh,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (empty_range_varying (r, type, lh, rh))
return true;
@@ -3169,7 +3641,8 @@ operator_addr_expr::fold_range (irange &r, tree type,
bool
operator_addr_expr::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &op2,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return operator_addr_expr::fold_range (r, type, lhs, op2);
}
@@ -3288,10 +3761,12 @@ class pointer_or_operator : public range_operator
public:
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel = VREL_NONE) const;
virtual void wi_fold (irange &r, tree type,
const wide_int &lh_lb, const wide_int &lh_ub,
const wide_int &rh_lb, const wide_int &rh_ub) const;
@@ -3300,7 +3775,8 @@ public:
bool
pointer_or_operator::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2 ATTRIBUTE_UNUSED) const
+ const irange &op2 ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
if (lhs.zero_p ())
{
@@ -3315,7 +3791,8 @@ pointer_or_operator::op1_range (irange &r, tree type,
bool
pointer_or_operator::op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const
+ const irange &op1,
+ relation_kind rel ATTRIBUTE_UNUSED) const
{
return pointer_or_operator::op1_range (r, type, lhs, op1);
}
@@ -3767,6 +4244,30 @@ range_op_bitwise_and_tests ()
ASSERT_FALSE (res.contains_p (INT (0)));
}
+static void
+range_relational_tests ()
+{
+ int_range<2> lhs (unsigned_char_type_node);
+ int_range<2> op1 (UCHAR (8), UCHAR (10));
+ int_range<2> op2 (UCHAR (20), UCHAR (20));
+
+ // Never wrapping additions mean LHS > OP1.
+ tree_code code = op_plus.lhs_op1_relation (lhs, op1, op2);
+ ASSERT_TRUE (code == GT_EXPR);
+
+ // Most wrapping additions mean nothing...
+ op1 = int_range<2> (UCHAR (8), UCHAR (10));
+ op2 = int_range<2> (UCHAR (0), UCHAR (255));
+ code = op_plus.lhs_op1_relation (lhs, op1, op2);
+ ASSERT_TRUE (code == VREL_NONE);
+
+ // However, always wrapping additions mean LHS < OP1.
+ op1 = int_range<2> (UCHAR (1), UCHAR (255));
+ op2 = int_range<2> (UCHAR (255), UCHAR (255));
+ code = op_plus.lhs_op1_relation (lhs, op1, op2);
+ ASSERT_TRUE (code == LT_EXPR);
+}
+
void
range_op_tests ()
{
@@ -3774,6 +4275,7 @@ range_op_tests ()
range_op_lshift_tests ();
range_op_bitwise_and_tests ();
range_op_cast_tests ();
+ range_relational_tests ();
}
} // namespace selftest
diff --git a/gcc/range-op.h b/gcc/range-op.h
index d3d4408..2b5db64 100644
--- a/gcc/range-op.h
+++ b/gcc/range-op.h
@@ -52,7 +52,8 @@ public:
// Perform an operation between 2 ranges and return it.
virtual bool fold_range (irange &r, tree type,
const irange &lh,
- const irange &rh) const;
+ const irange &rh,
+ relation_kind rel = VREL_NONE) const;
// Return the range for op[12] in the general case. LHS is the range for
// the LHS of the expression, OP[12]is the range for the other
@@ -67,11 +68,23 @@ public:
// is re-formed as R = [LHS] - OP2.
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const;
+ const irange &op2,
+ relation_kind rel = VREL_NONE) const;
virtual bool op2_range (irange &r, tree type,
const irange &lhs,
- const irange &op1) const;
+ const irange &op1,
+ relation_kind rel = VREL_NONE) const;
+ // The following routines are used to represent relations between the
+ // various operations. If the caller knows where the symbolics are,
+ // it can query for relationships between them given known ranges.
+ virtual enum tree_code lhs_op1_relation (const irange &lhs,
+ const irange &op1,
+ const irange &op2) const;
+ virtual enum tree_code lhs_op2_relation (const irange &lhs,
+ const irange &op1,
+ const irange &op2) const;
+ virtual enum tree_code op1_op2_relation (const irange &lhs) const;
protected:
// Perform an integral operation between 2 sub-ranges and return it.
virtual void wi_fold (irange &r, tree type,
@@ -79,6 +92,11 @@ protected:
const wide_int &lh_ub,
const wide_int &rh_lb,
const wide_int &rh_ub) const;
+ // Side effect of relation for generic fold_range clients.
+ virtual bool op1_op2_relation_effect (irange &lhs_range, tree type,
+ const irange &op1_range,
+ const irange &op2_range,
+ relation_kind rel) const;
};
extern range_operator *range_op_handler (enum tree_code code, tree type);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 3b11dcf..b2de840 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,90 @@
+2021-06-22 Sandra Loosemore <sandra@codesourcery.com>
+ Tobias Burnus <tobias@codesourcery.com>
+
+ PR fortran/93524
+ * gfortran.dg/pr93524.c: New.
+ * gfortran.dg/pr93524.f90: New.
+
+2021-06-22 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/101143
+ * gcc.dg/analyzer/pr101143.c: New test.
+
+2021-06-22 Richard Biener <rguenther@suse.de>
+
+ PR middle-end/101156
+ * gcc.dg/pr101156.c: New testcase.
+
+2021-06-22 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/101159
+ * gcc.c-torture/compile/pr101159.c: New test.
+
+2021-06-22 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/101160
+ * g++.target/i386/empty-class1.C: Require lp64 effective target
+ instead of x86_64-*-*.
+ * g++.target/i386/empty-class2.C: New test.
+
+2021-06-22 Jakub Jelinek <jakub@redhat.com>
+ Andrew Pinski <apinski@marvell.com>
+
+ PR tree-optimization/101162
+ * g++.dg/opt/pr101162.C: New test.
+
+2021-06-22 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/101151
+ * gcc.dg/torture/pr101151.c: New testcase.
+
+2021-06-22 Kito Cheng <kito.cheng@sifive.com>
+
+ * g++.dg/modules/omp-1_a.C: Check pthread is available for
+ dg-module-cmi.
+ * g++.dg/modules/omp-2_a.C: Ditto.
+
+2021-06-22 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/101158
+ * gfortran.dg/pr101158.f90: New testcase.
+
+2021-06-22 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/11877
+ * gcc.target/i386/pr11877-2.c: New test.
+
+2021-06-22 liuhongt <hongtao.liu@intel.com>
+
+ PR tree-optimization/97770
+ * gcc.target/i386/avx512bitalg-pr97770-1.c: Remove xfail.
+ * gcc.target/i386/avx512vpopcntdq-pr97770-1.c: Remove xfail.
+
+2021-06-22 liuhongt <hongtao.liu@intel.com>
+
+ PR target/100267
+ * gcc.target/i386/avx512bw-pr100267-1.c: New test.
+ * gcc.target/i386/avx512bw-pr100267-b-2.c: New test.
+ * gcc.target/i386/avx512bw-pr100267-d-2.c: New test.
+ * gcc.target/i386/avx512bw-pr100267-q-2.c: New test.
+ * gcc.target/i386/avx512bw-pr100267-w-2.c: New test.
+ * gcc.target/i386/avx512f-pr100267-1.c: New test.
+ * gcc.target/i386/avx512f-pr100267-pd-2.c: New test.
+ * gcc.target/i386/avx512f-pr100267-ps-2.c: New test.
+ * gcc.target/i386/avx512vl-pr100267-1.c: New test.
+ * gcc.target/i386/avx512vl-pr100267-pd-2.c: New test.
+ * gcc.target/i386/avx512vl-pr100267-ps-2.c: New test.
+ * gcc.target/i386/avx512vlbw-pr100267-1.c: New test.
+ * gcc.target/i386/avx512vlbw-pr100267-b-2.c: New test.
+ * gcc.target/i386/avx512vlbw-pr100267-d-2.c: New test.
+ * gcc.target/i386/avx512vlbw-pr100267-q-2.c: New test.
+ * gcc.target/i386/avx512vlbw-pr100267-w-2.c: New test.
+
+2021-06-22 liuhongt <hongtao.liu@intel.com>
+
+ PR target/100310
+ * gcc.target/i386/pr100310.c: New test.
+
2021-06-21 Jason Merrill <jason@redhat.com>
PR target/88529
diff --git a/gcc/testsuite/g++.dg/modules/omp-1_a.C b/gcc/testsuite/g++.dg/modules/omp-1_a.C
index 94e1171..7ddb776 100644
--- a/gcc/testsuite/g++.dg/modules/omp-1_a.C
+++ b/gcc/testsuite/g++.dg/modules/omp-1_a.C
@@ -2,7 +2,7 @@
// { dg-require-effective-target pthread }
export module foo;
-// { dg-module-cmi foo }
+// { dg-module-cmi foo { target pthread } }
export inline void frob (unsigned (&ary)[64])
{
diff --git a/gcc/testsuite/g++.dg/modules/omp-2_a.C b/gcc/testsuite/g++.dg/modules/omp-2_a.C
index b0d4bbc..e030ac7 100644
--- a/gcc/testsuite/g++.dg/modules/omp-2_a.C
+++ b/gcc/testsuite/g++.dg/modules/omp-2_a.C
@@ -2,7 +2,7 @@
// { dg-require-effective-target pthread }
export module foo;
-// { dg-module-cmi foo }
+// { dg-module-cmi foo { target pthread } }
// The OpenMPness doesn't escape to the interface.
export void frob (unsigned (&ary)[64])
diff --git a/gcc/testsuite/g++.dg/opt/pr101162.C b/gcc/testsuite/g++.dg/opt/pr101162.C
new file mode 100644
index 0000000..4032189
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/pr101162.C
@@ -0,0 +1,21 @@
+// PR tree-optimization/101162
+// { dg-do compile }
+// { dg-options "-O2" }
+
+struct A { int i1, i2, i3, i4, i5, i6; };
+
+int A::*
+foo (int i)
+{
+ switch (i)
+ {
+ case 1: return &A::i1;
+ case 2: return &A::i2;
+ case 3: return &A::i3;
+ case 4: return &A::i4;
+ case 5: return &A::i5;
+ case 6: return &A::i6;
+ }
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.target/i386/empty-class1.C b/gcc/testsuite/g++.target/i386/empty-class1.C
index c199277..96a1fad 100644
--- a/gcc/testsuite/g++.target/i386/empty-class1.C
+++ b/gcc/testsuite/g++.target/i386/empty-class1.C
@@ -1,5 +1,5 @@
// PR target/88529
-// { dg-do compile { target { c++11 && x86_64-*-* } } }
+// { dg-do compile { target { c++11 && lp64 } } }
// { dg-additional-options -fdump-rtl-expand }
// { dg-final { scan-rtl-dump-not "set" "expand" } }
// The x86_64 psABI says that f() doesn't put the return value anywhere.
diff --git a/gcc/testsuite/g++.target/i386/empty-class2.C b/gcc/testsuite/g++.target/i386/empty-class2.C
new file mode 100644
index 0000000..b9317c5
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/empty-class2.C
@@ -0,0 +1,20 @@
+// PR middle-end/101160
+// Test passing aligned empty aggregate
+// { dg-do compile }
+// { dg-options "-O2" }
+// { dg-additional-options "-Wno-psabi" { target { { i?86-*-* x86_64-*-* } && ilp32 } } }
+
+struct S { union {} a; } __attribute__((aligned));
+
+S
+foo (S arg)
+{
+ return arg;
+}
+
+void
+bar (void)
+{
+ S arg;
+ foo (arg);
+}
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr101159.c b/gcc/testsuite/gcc.c-torture/compile/pr101159.c
new file mode 100644
index 0000000..81b2d2c
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr101159.c
@@ -0,0 +1,10 @@
+/* PR tree-optimization/101159 */
+
+unsigned long a;
+long b;
+
+void
+foo (void)
+{
+ a += __builtin_popcountl (b);
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/pr101143.c b/gcc/testsuite/gcc.dg/analyzer/pr101143.c
new file mode 100644
index 0000000..bcc0974
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/pr101143.c
@@ -0,0 +1,18 @@
+/* { dg-additional-options "-Wno-builtin-declaration-mismatch" } */
+
+extern void *malloc (unsigned int);
+extern void *alloca (unsigned int);
+extern void unknown_fn (void *);
+
+void *
+test_malloc (void)
+{
+ return malloc (sizeof (int));
+}
+
+void *
+test_alloca (void)
+{
+ void *p = alloca (sizeof (int));
+ unknown_fn (p);
+}
diff --git a/gcc/testsuite/gcc.dg/pr101156.c b/gcc/testsuite/gcc.dg/pr101156.c
new file mode 100644
index 0000000..5c25bd7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr101156.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-fchecking" } */
+
+struct S { int i; };
+void baz(struct S *p)
+{
+ __builtin_setjmp(p--);
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr101151.c b/gcc/testsuite/gcc.dg/torture/pr101151.c
new file mode 100644
index 0000000..15c9a7b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr101151.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+
+int a, *b = &a, c, d;
+int main() {
+ *b;
+ if (a) {
+ L1:
+ a = 0;
+ L2:
+ if (d) {
+ while (b)
+ ;
+ goto L1;
+ }
+ }
+ if (c)
+ goto L2;
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr11877-2.c b/gcc/testsuite/gcc.target/i386/pr11877-2.c
new file mode 100644
index 0000000..4782dd2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr11877-2.c
@@ -0,0 +1,26 @@
+/* PR target/11877 */
+/* { dg-do compile } */
+/* { dg-options "-Os" } */
+
+void
+foo (int *p)
+{
+ p[0] = 0;
+ p[7] = 0;
+ p[23] = 0;
+ p[41] = 0;
+ p[48] = 0;
+ p[59] = 0;
+ p[69] = 0;
+ p[78] = 0;
+ p[83] = 0;
+ p[89] = 0;
+ p[98] = 0;
+ p[121] = 0;
+ p[132] = 0;
+ p[143] = 0;
+ p[154] = 0;
+}
+
+/* { dg-final { scan-assembler-times "xorl\[ \t\]" 1 } } */
+/* { dg-final { scan-assembler-not "\\\$0," } } */
diff --git a/gcc/testsuite/gfortran.dg/pr101158.f90 b/gcc/testsuite/gfortran.dg/pr101158.f90
new file mode 100644
index 0000000..9a4d9a2
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr101158.f90
@@ -0,0 +1,25 @@
+! { dg-do compile }
+! { dg-options "-O1 -ftree-slp-vectorize -fwrapv" }
+! { dg-additional-options "-march=armv8-a+sve" { target aarch64-*-* } }
+
+subroutine sprpl5 (left)
+ implicit none
+
+ integer :: left
+ integer :: avail1, avail2, delx1, delx2, i2, ic
+
+ ic = left
+ delx1 = ic / 2
+ delx2 = delx1 + 1
+ i2 = ic + delx2
+ avail1 = i2
+ avail2 = 1
+
+ do delx1 = 1, 2
+ ic = left + nint (real (left) / 2)
+ if (ic .ge. avail1) avail1 = ic + 1
+
+ i2 = ic + delx2
+ if (i2 .le. avail2) avail2 = i2 + 1
+ end do
+end subroutine sprpl5
diff --git a/gcc/testsuite/gfortran.dg/pr93524.c b/gcc/testsuite/gfortran.dg/pr93524.c
new file mode 100644
index 0000000..24e5e09
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr93524.c
@@ -0,0 +1,33 @@
+/* Test the fix for PR93524, in which CFI_allocate was computing
+ sm incorrectly for dimensions > 2. */
+
+#include <stdlib.h> // For size_t
+#include "../../../libgfortran/ISO_Fortran_binding.h"
+
+void my_fortran_sub_1 (CFI_cdesc_t *dv);
+void my_fortran_sub_2 (CFI_cdesc_t *dv);
+
+int main ()
+{
+ CFI_CDESC_T (3) a;
+ CFI_cdesc_t *dv = (CFI_cdesc_t *) &a;
+ // dv, base_addr, attribute, type, elem_len, rank, extents
+ CFI_establish (dv, NULL, CFI_attribute_allocatable, CFI_type_float, 0, 3, NULL);
+
+ if (dv->base_addr != NULL)
+ return 1; // shall not be allocated
+
+ CFI_index_t lower_bounds[] = {-10, 0, 3};
+ CFI_index_t upper_bounds[] = {10, 5, 10};
+ size_t elem_len = 0; // only needed for strings
+ if (CFI_SUCCESS != CFI_allocate (dv, lower_bounds, upper_bounds, elem_len))
+ return 2;
+
+ if (!CFI_is_contiguous (dv))
+ return 2; // allocatables shall be contiguous,unless a strided section is used
+
+ my_fortran_sub_1 (dv);
+ my_fortran_sub_2 (dv);
+ CFI_deallocate (dv);
+ return 0;
+}
diff --git a/gcc/testsuite/gfortran.dg/pr93524.f90 b/gcc/testsuite/gfortran.dg/pr93524.f90
new file mode 100644
index 0000000..0cebc8f
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr93524.f90
@@ -0,0 +1,17 @@
+! { dg-additional-sources pr93524.c }
+! { dg-do run }
+!
+! Test the fix for PR93524. The main program is in pr93524.c.
+
+subroutine my_fortran_sub_1 (A) bind(C)
+ real :: A(:, :, :)
+ if (any (lbound(A) /= 1)) stop 1
+ if (any (ubound(A) /= [21,6,8])) stop 2
+ if (.not. is_contiguous (A)) stop 3
+end
+subroutine my_fortran_sub_2 (A) bind(C)
+ real, ALLOCATABLE :: A(:, :, :)
+ if (any (lbound(A) /= [-10,0,3])) stop 1
+ if (any (ubound(A) /= [10,5,10])) stop 2
+ if (.not. is_contiguous (A)) stop 3
+end subroutine my_fortran_sub_2
diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
index 6f3352f..b6abd8b 100644
--- a/gcc/tree-data-ref.c
+++ b/gcc/tree-data-ref.c
@@ -97,8 +97,8 @@ along with GCC; see the file COPYING3. If not see
#include "tree-eh.h"
#include "ssa.h"
#include "internal-fn.h"
-#include "range-op.h"
#include "vr-values.h"
+#include "range-op.h"
static struct datadep_stats
{
diff --git a/gcc/tree-ssa-sink.c b/gcc/tree-ssa-sink.c
index d252cbb..92f444e 100644
--- a/gcc/tree-ssa-sink.c
+++ b/gcc/tree-ssa-sink.c
@@ -398,7 +398,14 @@ statement_sink_location (gimple *stmt, basic_block frombb,
&& dominated_by_p (CDI_POST_DOMINATORS, commondom, bb)
/* If the blocks are possibly within the same irreducible
cycle the above check breaks down. */
- && !(bb->flags & commondom->flags & BB_IRREDUCIBLE_LOOP))
+ && !((bb->flags & commondom->flags & BB_IRREDUCIBLE_LOOP)
+ && bb->loop_father == commondom->loop_father)
+ && !((commondom->flags & BB_IRREDUCIBLE_LOOP)
+ && flow_loop_nested_p (commondom->loop_father,
+ bb->loop_father))
+ && !((bb->flags & BB_IRREDUCIBLE_LOOP)
+ && flow_loop_nested_p (bb->loop_father,
+ commondom->loop_father)))
continue;
bb = EDGE_PRED (bb, PHI_ARG_INDEX_FROM_USE (use_p))->src;
}
diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c
index 5972705..b2e7fc2 100644
--- a/gcc/tree-vect-patterns.c
+++ b/gcc/tree-vect-patterns.c
@@ -1300,7 +1300,7 @@ vect_recog_widen_minus_pattern (vec_info *vinfo, stmt_vec_info last_stmt_info,
TYPE1 B;
UTYPE2 temp_in;
TYPE3 temp_out;
- temp_in = (TYPE2)A;
+ temp_in = (UTYPE2)A;
temp_out = __builtin_popcount{,l,ll} (temp_in);
B = (TYPE1) temp_out;
@@ -1372,8 +1372,8 @@ vect_recog_popcount_pattern (vec_info *vinfo,
if (!rhs_origin)
return NULL;
- /* Input and outout of .POPCOUNT should be same-precision integer.
- Also A should be unsigned or same presion as temp_in,
+ /* Input and output of .POPCOUNT should be same-precision integer.
+ Also A should be unsigned or same precision as temp_in,
otherwise there would be sign_extend from A to temp_in. */
if (TYPE_PRECISION (unprom_diff.type) != TYPE_PRECISION (lhs_type)
|| (!TYPE_UNSIGNED (unprom_diff.type)
@@ -1384,10 +1384,10 @@ vect_recog_popcount_pattern (vec_info *vinfo,
vect_pattern_detected ("vec_regcog_popcount_pattern", popcount_stmt);
vec_type = get_vectype_for_scalar_type (vinfo, lhs_type);
- /* Do it only the backend existed popcount<vector_mode>2. */
- if (!direct_internal_fn_supported_p (IFN_POPCOUNT,
- vec_type,
- OPTIMIZE_FOR_SPEED))
+ /* Do it only if the backend has popcount<vector_mode>2 pattern. */
+ if (!vec_type
+ || !direct_internal_fn_supported_p (IFN_POPCOUNT, vec_type,
+ OPTIMIZE_FOR_SPEED))
return NULL;
/* Create B = .POPCOUNT (A). */
diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c
index a32f86b..6c98acb 100644
--- a/gcc/tree-vect-slp.c
+++ b/gcc/tree-vect-slp.c
@@ -1177,21 +1177,6 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap,
continue;
}
- if (need_same_oprnds)
- {
- tree other_op1 = (call_stmt
- ? gimple_call_arg (call_stmt, 1)
- : gimple_assign_rhs2 (stmt));
- if (!operand_equal_p (first_op1, other_op1, 0))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "Build SLP failed: different shift "
- "arguments in %G", stmt);
- /* Mismatch. */
- continue;
- }
- }
if (!load_p
&& first_stmt_code == BIT_FIELD_REF
&& (TREE_OPERAND (gimple_assign_rhs1 (first_stmt_info->stmt), 0)
@@ -1231,6 +1216,22 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap,
continue;
}
+ if (need_same_oprnds)
+ {
+ tree other_op1 = (call_stmt
+ ? gimple_call_arg (call_stmt, 1)
+ : gimple_assign_rhs2 (stmt));
+ if (!operand_equal_p (first_op1, other_op1, 0))
+ {
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ "Build SLP failed: different shift "
+ "arguments in %G", stmt);
+ /* Mismatch. */
+ continue;
+ }
+ }
+
if (!types_compatible_p (vectype, *node_vectype))
{
if (dump_enabled_p ())
@@ -1963,15 +1964,15 @@ vect_build_slp_tree_2 (vec_info *vinfo, slp_tree node,
if (dt == vect_constant_def
|| dt == vect_external_def)
{
- /* We can always build those. Might want to sort last
- or defer building. */
- vec<tree> ops;
- ops.create (group_size);
- for (lane = 0; lane < group_size; ++lane)
- ops.quick_push (chains[lane][n].op);
- slp_tree child = vect_create_new_slp_node (ops);
- SLP_TREE_DEF_TYPE (child) = dt;
- children.safe_push (child);
+ /* We can always build those. Might want to sort last
+ or defer building. */
+ vec<tree> ops;
+ ops.create (group_size);
+ for (lane = 0; lane < group_size; ++lane)
+ ops.quick_push (chains[lane][n].op);
+ slp_tree child = vect_create_new_slp_node (ops);
+ SLP_TREE_DEF_TYPE (child) = dt;
+ children.safe_push (child);
}
else if (dt != vect_internal_def)
{
@@ -2036,9 +2037,10 @@ vect_build_slp_tree_2 (vec_info *vinfo, slp_tree node,
dump_printf_loc (MSG_NOTE, vect_location,
"failed to match up op %d\n", n);
op_stmts.release ();
- matches[lane] = false;
if (lane != group_size - 1)
matches[0] = false;
+ else
+ matches[lane] = false;
goto out;
}
if (dump_enabled_p ())
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index 93609f3..17dfdb1 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -174,6 +174,7 @@ range_query::get_value_range (const_tree expr, gimple *stmt)
range_query::range_query ()
{
equiv_alloc = new equiv_allocator;
+ m_oracle = NULL;
}
range_query::~range_query ()
@@ -452,3 +453,52 @@ global_range_query::range_of_expr (irange &r, tree expr, gimple *stmt)
return true;
}
+
+// Return any known relation between SSA1 and SSA2 before stmt S is executed.
+// If GET_RANGE is true, query the range of both operands first to ensure
+// the defintions have been processed and any relations have be created.
+
+relation_kind
+range_query::query_relation (gimple *s, tree ssa1, tree ssa2, bool get_range)
+{
+ int_range_max tmp;
+ if (!m_oracle || TREE_CODE (ssa1) != SSA_NAME || TREE_CODE (ssa2) != SSA_NAME)
+ return VREL_NONE;
+
+ // Ensure ssa1 and ssa2 have both been evaluated.
+ if (get_range)
+ {
+ range_of_expr (tmp, ssa1, s);
+ range_of_expr (tmp, ssa2, s);
+ }
+ return m_oracle->query_relation (gimple_bb (s), ssa1, ssa2);
+}
+
+// Return any known relation between SSA1 and SSA2 on edge E.
+// If GET_RANGE is true, query the range of both operands first to ensure
+// the defintions have been processed and any relations have be created.
+
+relation_kind
+range_query::query_relation (edge e, tree ssa1, tree ssa2, bool get_range)
+{
+ basic_block bb;
+ int_range_max tmp;
+ if (!m_oracle || TREE_CODE (ssa1) != SSA_NAME || TREE_CODE (ssa2) != SSA_NAME)
+ return VREL_NONE;
+
+ // Use destination block if it has a single predecessor, and this picks
+ // up any relation on the edge.
+ // Otherwise choose the src edge and the result is the same as on-exit.
+ if (!single_pred_p (e->dest))
+ bb = e->src;
+ else
+ bb = e->dest;
+
+ // Ensure ssa1 and ssa2 have both been evaluated.
+ if (get_range)
+ {
+ range_on_edge (tmp, e, ssa1);
+ range_on_edge (tmp, e, ssa2);
+ }
+ return m_oracle->query_relation (bb, ssa1, ssa2);
+}
diff --git a/gcc/value-query.h b/gcc/value-query.h
index 54af031..5161d23 100644
--- a/gcc/value-query.h
+++ b/gcc/value-query.h
@@ -22,6 +22,8 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_QUERY_H
#define GCC_QUERY_H
+#include "value-relation.h"
+
// The value_query class is used by optimization passes that require
// valueizing SSA names in terms of a tree value, but have no neeed
// for ranges.
@@ -91,6 +93,14 @@ public:
virtual bool range_on_edge (irange &r, edge, tree expr);
virtual bool range_of_stmt (irange &r, gimple *, tree name = NULL);
+ // Query if there is any relation between SSA1 and SSA2.
+ relation_kind query_relation (gimple *s, tree ssa1, tree ssa2,
+ bool get_range = true);
+ relation_kind query_relation (edge e, tree ssa1, tree ssa2,
+ bool get_range = true);
+ // If present, Access relation oracle for more advanced uses.
+ inline relation_oracle *oracle () const { return m_oracle; }
+
// DEPRECATED: This method is used from vr-values. The plan is to
// rewrite all uses of it to the above API.
virtual const class value_range_equiv *get_value_range (const_tree,
@@ -102,6 +112,7 @@ protected:
void free_value_range_equiv (class value_range_equiv *);
bool get_tree_range (irange &r, tree expr, gimple *stmt);
bool get_arith_expr_range (irange &r, tree expr, gimple *stmt);
+ relation_oracle *m_oracle;
private:
class equiv_allocator *equiv_alloc;
diff --git a/gcc/value-relation.cc b/gcc/value-relation.cc
new file mode 100644
index 0000000..3c8698f
--- /dev/null
+++ b/gcc/value-relation.cc
@@ -0,0 +1,932 @@
+/* Header file for the value range relational processing.
+ Copyright (C) 2020-2021 Free Software Foundation, Inc.
+ Contributed by Andrew MacLeod <amacleod@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "ssa.h"
+
+#include "gimple-range.h"
+#include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
+#include "alloc-pool.h"
+#include "dominance.h"
+
+// These VREL codes are arranged such that VREL_NONE is the first
+// code, and all the rest are contiguous up to and including VREL_LAST.
+
+#define VREL_FIRST VREL_NONE
+#define VREL_LAST NE_EXPR
+#define VREL_COUNT (VREL_LAST - VREL_FIRST + 1)
+
+// vrel_range_assert will either assert that the tree code passed is valid,
+// or mark invalid codes as unreachable to help with table optimation.
+#if CHECKING_P
+ #define vrel_range_assert(c) \
+ gcc_checking_assert ((c) >= VREL_FIRST && (c) <= VREL_LAST)
+#else
+ #define vrel_range_assert(c) \
+ if ((c) < VREL_FIRST || (c) > VREL_LAST) \
+ gcc_unreachable ();
+#endif
+
+static const char *kind_string[VREL_COUNT] =
+{ "none", "<", "<=", ">", ">=", "empty", "==", "!=" };
+
+// Print a relation_kind REL to file F.
+
+void
+print_relation (FILE *f, relation_kind rel)
+{
+ vrel_range_assert (rel);
+ fprintf (f, " %s ", kind_string[rel - VREL_FIRST]);
+}
+
+// This table is used to negate the operands. op1 REL op2 -> !(op1 REL op2).
+relation_kind rr_negate_table[VREL_COUNT] = {
+// NONE, LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, EMPTY, EQ_EXPR, NE_EXPR
+ VREL_NONE, GE_EXPR, GT_EXPR, LE_EXPR, LT_EXPR, VREL_EMPTY, NE_EXPR, EQ_EXPR };
+
+// Negate the relation, as in logical negation.
+
+relation_kind
+relation_negate (relation_kind r)
+{
+ vrel_range_assert (r);
+ return rr_negate_table [r - VREL_FIRST];
+}
+
+// This table is used to swap the operands. op1 REL op2 -> op2 REL op1.
+relation_kind rr_swap_table[VREL_COUNT] = {
+// NONE, LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, EMPTY, EQ_EXPR, NE_EXPR
+ VREL_NONE, GT_EXPR, GE_EXPR, LT_EXPR, LE_EXPR, VREL_EMPTY, EQ_EXPR, NE_EXPR };
+
+// Return the relation as if the operands were swapped.
+
+relation_kind
+relation_swap (relation_kind r)
+{
+ vrel_range_assert (r);
+ return rr_swap_table [r - VREL_FIRST];
+}
+
+// This table is used to perform an intersection between 2 relations.
+
+relation_kind rr_intersect_table[VREL_COUNT][VREL_COUNT] = {
+// NONE, LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, EMPTY, EQ_EXPR, NE_EXPR
+// VREL_NONE
+ { VREL_NONE, LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, VREL_EMPTY, EQ_EXPR, NE_EXPR },
+// LT_EXPR
+ { LT_EXPR, LT_EXPR, LT_EXPR, VREL_EMPTY, VREL_EMPTY, VREL_EMPTY, VREL_EMPTY, LT_EXPR },
+// LE_EXPR
+ { LE_EXPR, LT_EXPR, LE_EXPR, VREL_EMPTY, EQ_EXPR, VREL_EMPTY, EQ_EXPR, LT_EXPR },
+// GT_EXPR
+ { GT_EXPR, VREL_EMPTY, VREL_EMPTY, GT_EXPR, GT_EXPR, VREL_EMPTY, VREL_EMPTY, GT_EXPR },
+// GE_EXPR
+ { GE_EXPR, VREL_EMPTY, EQ_EXPR, GT_EXPR, GE_EXPR, VREL_EMPTY, EQ_EXPR, GT_EXPR },
+// VREL_EMPTY
+ { VREL_EMPTY, VREL_EMPTY, VREL_EMPTY, VREL_EMPTY, VREL_EMPTY, VREL_EMPTY, VREL_EMPTY, VREL_EMPTY },
+// EQ_EXPR
+ { EQ_EXPR, VREL_EMPTY, EQ_EXPR, VREL_EMPTY, EQ_EXPR, VREL_EMPTY, EQ_EXPR, VREL_EMPTY },
+// NE_EXPR
+ { NE_EXPR, LT_EXPR, LT_EXPR, GT_EXPR, GT_EXPR, VREL_EMPTY, VREL_EMPTY, NE_EXPR } };
+
+
+// Intersect relation R! with relation R2 and return the resulting relation.
+
+relation_kind
+relation_intersect (relation_kind r1, relation_kind r2)
+{
+ vrel_range_assert (r1);
+ vrel_range_assert (r2);
+ return rr_intersect_table[r1 - VREL_FIRST][r2 - VREL_FIRST];
+}
+
+
+// This table is used to perform a union between 2 relations.
+
+relation_kind rr_union_table[VREL_COUNT][VREL_COUNT] = {
+// NONE, LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, EMPTY, EQ_EXPR, NE_EXPR
+// VREL_NONE
+ { VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE, VREL_NONE },
+// LT_EXPR
+ { VREL_NONE, LT_EXPR, LE_EXPR, NE_EXPR, VREL_NONE, LT_EXPR, LE_EXPR, NE_EXPR },
+// LE_EXPR
+ { VREL_NONE, LE_EXPR, LE_EXPR, VREL_NONE, VREL_NONE, LE_EXPR, LE_EXPR, VREL_NONE },
+// GT_EXPR
+ { VREL_NONE, NE_EXPR, VREL_NONE, GT_EXPR, GE_EXPR, GT_EXPR, GE_EXPR, NE_EXPR },
+// GE_EXPR
+ { VREL_NONE, VREL_NONE, VREL_NONE, GE_EXPR, GE_EXPR, GE_EXPR, GE_EXPR, VREL_NONE },
+// VREL_EMPTY
+ { VREL_NONE, LT_EXPR, LE_EXPR, GT_EXPR, GE_EXPR, VREL_EMPTY, EQ_EXPR, NE_EXPR },
+// EQ_EXPR
+ { VREL_NONE, LE_EXPR, LE_EXPR, GE_EXPR, GE_EXPR, EQ_EXPR, EQ_EXPR, VREL_NONE },
+// NE_EXPR
+ { VREL_NONE, NE_EXPR, VREL_NONE, NE_EXPR, VREL_NONE, NE_EXPR, VREL_NONE, NE_EXPR } };
+
+// Union relation R1 with relation R2 and return the result.
+
+relation_kind
+relation_union (relation_kind r1, relation_kind r2)
+{
+ vrel_range_assert (r1);
+ vrel_range_assert (r2);
+ return rr_union_table[r1 - VREL_FIRST][r2 - VREL_FIRST];
+}
+
+
+// -------------------------------------------------------------------------
+
+// This class represents an equivalency set, and contains a link to the next
+// one in the list to be searched.
+
+// The very first element in the m_equiv chain is actually just a summary
+// element in which the m_names bitmap is used to indicate that an ssa_name
+// has an equivalence set in this block.
+// This allows for much faster traversal of the DOM chain, as a search for
+// SSA_NAME simply requires walking the DOM chain until a block is found
+// which has the bit for SSA_NAME set. Then scan for the equivalency set in
+// that block. No previous blcoks need be searched.
+
+class equiv_chain
+{
+public:
+ bitmap m_names; // ssa-names in equiv set.
+ basic_block m_bb; // Block this belongs to
+ equiv_chain *m_next; // Next in block list.
+ void dump (FILE *f) const; // Show names in this list.
+};
+
+
+// Dump the names in this equivalence set.
+
+void
+equiv_chain::dump (FILE *f) const
+{
+ bitmap_iterator bi;
+ unsigned i;
+
+ if (!m_names)
+ return;
+ fprintf (f, "Equivalence set : [");
+ unsigned c = 0;
+ EXECUTE_IF_SET_IN_BITMAP (m_names, 0, i, bi)
+ {
+ if (ssa_name (i))
+ {
+ if (c++)
+ fprintf (f, ", ");
+ print_generic_expr (f, ssa_name (i), TDF_SLIM);
+ }
+ }
+ fprintf (f, "]\n");
+}
+
+// Instantiate an equivalency oracle.
+
+equiv_oracle::equiv_oracle ()
+{
+ bitmap_obstack_initialize (&m_bitmaps);
+ m_equiv.create (0);
+ m_equiv.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1);
+ m_equiv_set = BITMAP_ALLOC (&m_bitmaps);
+ obstack_init (&m_chain_obstack);
+}
+
+// Destruct an equivalency oracle.
+
+equiv_oracle::~equiv_oracle ()
+{
+ obstack_free (&m_chain_obstack, NULL);
+ m_equiv.release ();
+ bitmap_obstack_release (&m_bitmaps);
+}
+
+// Find and return the equivalency set for SSA along the dominators of BB.
+// This is the external API.
+
+const_bitmap
+equiv_oracle::equiv_set (tree ssa, basic_block bb) const
+{
+ // Search the dominator tree for an equivalency.
+ equiv_chain *equiv = find_equiv_dom (ssa, bb);
+ if (equiv)
+ return equiv->m_names;
+
+ return NULL;
+}
+
+
+// If SSA has an equivalence in block BB, find and return it.
+// Otherwise return NULL.
+
+equiv_chain *
+equiv_oracle::find_equiv_block (unsigned ssa, int bb) const
+{
+ equiv_chain *ptr = NULL;
+ if (bb >= (int)m_equiv.length ())
+ return NULL;
+
+ // If there are equiv sets and SSA is in one in this block, find it.
+ // Otherwise return NULL.
+ if (m_equiv[bb] && bitmap_bit_p (m_equiv[bb]->m_names, ssa))
+ {
+ for (ptr = m_equiv[bb]->m_next; ptr; ptr = ptr->m_next)
+ if (bitmap_bit_p (ptr->m_names, ssa))
+ break;
+ }
+ return ptr;
+}
+
+// Starting at block BB, walk the dominator chain looking for the nearest
+// equivalence set containing NAME.
+
+equiv_chain *
+equiv_oracle::find_equiv_dom (tree name, basic_block bb) const
+{
+ unsigned v = SSA_NAME_VERSION (name);
+ // Short circuit looking for names which have no equivalences.
+ // Saves time looking for something which does not exist.
+ if (!bitmap_bit_p (m_equiv_set, v))
+ return NULL;
+
+ // NAME has at least once equivalence set, check to see if it has one along
+ // the dominator tree.
+ for ( ; bb; bb = get_immediate_dominator (CDI_DOMINATORS, bb))
+ {
+ equiv_chain *ptr = find_equiv_block (v, bb->index);
+ if (ptr)
+ return ptr;
+ }
+ return NULL;
+}
+
+// Register equivalance between ssa_name V and set EQUIV in block BB,
+
+bitmap
+equiv_oracle::register_equiv (basic_block bb, unsigned v, equiv_chain *equiv)
+{
+ // V will have an equivalency now.
+ bitmap_set_bit (m_equiv_set, v);
+
+ // If that equiv chain is in this block, simply use it.
+ if (equiv->m_bb == bb)
+ {
+ bitmap_set_bit (equiv->m_names, v);
+ bitmap_set_bit (m_equiv[bb->index]->m_names, v);
+ return NULL;
+ }
+
+ // Otherwise create an equivalence for this block which is a copy
+ // of equiv, the add V to the set.
+ bitmap b = BITMAP_ALLOC (&m_bitmaps);
+ bitmap_copy (b, equiv->m_names);
+ bitmap_set_bit (b, v);
+ return b;
+}
+
+// Register equivalence between set equiv_1 and equiv_2 in block BB.
+// Return NULL if either name can be merged with the other. Otherwise
+// return a pointer to the combined bitmap of names. This allows the
+// caller to do any setup required for a new element.
+
+bitmap
+equiv_oracle::register_equiv (basic_block bb, equiv_chain *equiv_1,
+ equiv_chain *equiv_2)
+{
+ // If equiv_1 is alreayd in BB, use it as the combined set.
+ if (equiv_1->m_bb == bb)
+ {
+ bitmap_ior_into (equiv_1->m_names, equiv_2->m_names);
+ // Its hard to delete from a single linked list, so
+ // just clear the second one.
+ if (equiv_2->m_bb == bb)
+ bitmap_clear (equiv_2->m_names);
+ else
+ // Ensure equiv_2s names are in the summary for BB.
+ bitmap_ior_into (m_equiv[bb->index]->m_names, equiv_2->m_names);
+ return NULL;
+ }
+ // If equiv_2 is in BB, use it for the combined set.
+ if (equiv_2->m_bb == bb)
+ {
+ bitmap_ior_into (equiv_2->m_names, equiv_1->m_names);
+ // Add equiv_1 names into the summary.
+ bitmap_ior_into (m_equiv[bb->index]->m_names, equiv_1->m_names);
+ return NULL;
+ }
+
+ // At this point, neither equivalence is from this block.
+ bitmap b = BITMAP_ALLOC (&m_bitmaps);
+ bitmap_copy (b, equiv_1->m_names);
+ bitmap_ior_into (b, equiv_2->m_names);
+ return b;
+}
+
+
+// Register an equivalence between SSA1 and SSA2 in block BB.
+// The equivalence oracle maintains a vector of equivalencies indexed by basic
+// block. When an equivalence bteween SSA1 and SSA2 is registered in block BB,
+// a query is made as to what equivalences both names have already, and
+// any preexisting equivalences are merged to create a single equivalence
+// containing all the ssa_names in this basic block.
+
+void
+equiv_oracle::register_equiv (basic_block bb, tree ssa1, tree ssa2)
+{
+ unsigned v1 = SSA_NAME_VERSION (ssa1);
+ unsigned v2 = SSA_NAME_VERSION (ssa2);
+ equiv_chain *equiv_1 = find_equiv_dom (ssa1, bb);
+ equiv_chain *equiv_2 = find_equiv_dom (ssa2, bb);
+
+ // Check if they are the same set
+ if (equiv_1 && equiv_1 == equiv_2)
+ return;
+
+ bitmap equiv_set;
+
+ // Case where we have 2 SSA_NAMEs that are not in any set.
+ if (!equiv_1 && !equiv_2)
+ {
+ bitmap_set_bit (m_equiv_set, v1);
+ bitmap_set_bit (m_equiv_set, v2);
+
+ equiv_set = BITMAP_ALLOC (&m_bitmaps);
+ bitmap_set_bit (equiv_set, v1);
+ bitmap_set_bit (equiv_set, v2);
+ }
+ else if (!equiv_1 && equiv_2)
+ equiv_set = register_equiv (bb, v1, equiv_2);
+ else if (equiv_1 && !equiv_2)
+ equiv_set = register_equiv (bb, v2, equiv_1);
+ else
+ equiv_set = register_equiv (bb, equiv_1, equiv_2);
+
+ // A non-null return is a bitmap that is to be added to the current
+ // block as a new equivalence.
+ if (!equiv_set)
+ return;
+
+ equiv_chain *ptr;
+
+ // Check if this is the first time a block has an equivalence added.
+ // and create a header block. And set the summary for this block.
+ if (!m_equiv[bb->index])
+ {
+ ptr = (equiv_chain *) obstack_alloc (&m_chain_obstack,
+ sizeof (equiv_chain));
+ ptr->m_names = BITMAP_ALLOC (&m_bitmaps);
+ bitmap_copy (ptr->m_names, equiv_set);
+ ptr->m_bb = bb;
+ ptr->m_next = NULL;
+ m_equiv[bb->index] = ptr;
+ }
+
+ // Now create the element for this equiv set and initialize it.
+ ptr = (equiv_chain *) obstack_alloc (&m_chain_obstack, sizeof (equiv_chain));
+ ptr->m_names = equiv_set;
+ ptr->m_bb = bb;
+ gcc_checking_assert (bb->index < (int)m_equiv.length ());
+ ptr->m_next = m_equiv[bb->index]->m_next;
+ m_equiv[bb->index]->m_next = ptr;
+ bitmap_ior_into (m_equiv[bb->index]->m_names, equiv_set);
+}
+
+// Make sure the BB vector is big enough and grow it if needed.
+
+void
+equiv_oracle::limit_check (basic_block bb)
+{
+ int i = (bb) ? bb->index : last_basic_block_for_fn (cfun);
+ if (i >= (int)m_equiv.length ())
+ m_equiv.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1);
+}
+
+// Dump the equivalence sets in BB to file F.
+
+void
+equiv_oracle::dump (FILE *f, basic_block bb) const
+{
+ if (bb->index >= (int)m_equiv.length ())
+ return;
+ if (!m_equiv[bb->index])
+ return;
+
+ equiv_chain *ptr = m_equiv[bb->index]->m_next;
+ for (; ptr; ptr = ptr->m_next)
+ ptr->dump (f);
+}
+
+// Dump all equivalence sets known to the oracle.
+
+void
+equiv_oracle::dump (FILE *f) const
+{
+ fprintf (f, "Equivalency dump\n");
+ for (unsigned i = 0; i < m_equiv.length (); i++)
+ if (m_equiv[i])
+ {
+ fprintf (f, "BB%d\n", i);
+ dump (f, BASIC_BLOCK_FOR_FN (cfun, i));
+ }
+}
+
+
+// --------------------------------------------------------------------------
+
+// The value-relation class is used to encapsulate the represention of an
+// individual relation between 2 ssa-names, and to facilitate operating on
+// the relation.
+
+class value_relation
+{
+public:
+ value_relation ();
+ value_relation (relation_kind kind, tree n1, tree n2);
+ void set_relation (relation_kind kind, tree n1, tree n2);
+
+ inline relation_kind kind () const { return related; }
+ inline tree op1 () const { return name1; }
+ inline tree op2 () const { return name2; }
+
+ bool union_ (value_relation &p);
+ bool intersect (value_relation &p);
+ void negate ();
+ void swap ();
+
+ void dump (FILE *f) const;
+private:
+ relation_kind related;
+ tree name1, name2;
+};
+
+// Set relation R between ssa_name N1 and N2.
+
+inline void
+value_relation::set_relation (relation_kind r, tree n1, tree n2)
+{
+ gcc_checking_assert (SSA_NAME_VERSION (n1) != SSA_NAME_VERSION (n2));
+ related = r;
+ name1 = n1;
+ name2 = n2;
+}
+
+// Default constructor.
+
+inline
+value_relation::value_relation ()
+{
+ related = VREL_NONE;
+ name1 = NULL_TREE;
+ name2 = NULL_TREE;
+}
+
+// Constructor for relation R between SSA version N1 nd N2.
+
+inline
+value_relation::value_relation (relation_kind kind, tree n1, tree n2)
+{
+ set_relation (kind, n1, n2);
+}
+
+// Negate the current relation.
+
+void
+value_relation::negate ()
+{
+ related = relation_negate (related);
+}
+
+// Modify the relation as if the operands were being swapped.
+
+void
+value_relation::swap ()
+{
+ related = relation_swap (related);
+}
+
+// Perform an intersection between 2 relations. *this &&= p.
+
+bool
+value_relation::intersect (value_relation &p)
+{
+ // Save previous value
+ relation_kind old = related;
+
+ if (p.op1 () == op1 () && p.op2 () == op2 ())
+ related = relation_intersect (kind (), p.kind ());
+ else if (p.op2 () == op1 () && p.op1 () == op2 ())
+ related = relation_intersect (kind (), relation_swap (p.kind ()));
+ else
+ return false;
+
+ return old != related;
+}
+
+// Perform a union between 2 relations. *this ||= p.
+
+bool
+value_relation::union_ (value_relation &p)
+{
+ // Save previous value
+ relation_kind old = related;
+
+ if (p.op1 () == op1 () && p.op2 () == op2 ())
+ related = relation_union (kind(), p.kind());
+ else if (p.op2 () == op1 () && p.op1 () == op2 ())
+ related = relation_union (kind(), relation_swap (p.kind ()));
+ else
+ return false;
+
+ return old != related;
+}
+
+
+// Dump the relation to file F.
+
+void
+value_relation::dump (FILE *f) const
+{
+ if (!name1 || !name2)
+ {
+ fprintf (f, "uninitialized");
+ return;
+ }
+ fputc ('(', f);
+ print_generic_expr (f, op1 (), TDF_SLIM);
+ print_relation (f, kind ());
+ print_generic_expr (f, op2 (), TDF_SLIM);
+ fputc(')', f);
+}
+
+// This container is used to link relations in a chain.
+
+class relation_chain : public value_relation
+{
+public:
+ relation_chain *m_next;
+};
+
+// ------------------------------------------------------------------------
+
+// Instantiate a relation oracle.
+
+relation_oracle::relation_oracle ()
+{
+ m_relations.create (0);
+ m_relations.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1);
+ m_relation_set = BITMAP_ALLOC (&m_bitmaps);
+ m_tmp = BITMAP_ALLOC (&m_bitmaps);
+}
+
+// Destruct a relation oracle.
+
+relation_oracle::~relation_oracle ()
+{
+ m_relations.release ();
+}
+
+// Register relation K between ssa_name OP1 and OP2 on STMT.
+
+void
+relation_oracle::register_relation (gimple *stmt, relation_kind k, tree op1,
+ tree op2)
+{
+ gcc_checking_assert (TREE_CODE (op1) == SSA_NAME);
+ gcc_checking_assert (TREE_CODE (op2) == SSA_NAME);
+ gcc_checking_assert (stmt && gimple_bb (stmt));
+
+ // Don't register lack of a relation.
+ if (k == VREL_NONE)
+ return;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ value_relation vr (k, op1, op2);
+ fprintf (dump_file, " Registering value_relation ");
+ vr.dump (dump_file);
+ fprintf (dump_file, " (bb%d) at ", gimple_bb (stmt)->index);
+ print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
+ }
+
+ // This relation applies to the entire block, use STMT's block.
+ // Equivalencies are handled by the equivalence oracle.
+ if (k == EQ_EXPR)
+ register_equiv (gimple_bb (stmt), op1, op2);
+ else
+ register_relation (gimple_bb (stmt), k, op1, op2);
+}
+
+// Register relation K between ssa_name OP1 and OP2 on edge E.
+
+void
+relation_oracle::register_relation (edge e, relation_kind k, tree op1,
+ tree op2)
+{
+ gcc_checking_assert (TREE_CODE (op1) == SSA_NAME);
+ gcc_checking_assert (TREE_CODE (op2) == SSA_NAME);
+
+ // Do not register lack of relation, or blocks which have more than
+ // edge E for a predecessor.
+ if (k == VREL_NONE || !single_pred_p (e->dest))
+ return;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ value_relation vr (k, op1, op2);
+ fprintf (dump_file, " Registering value_relation ");
+ vr.dump (dump_file);
+ fprintf (dump_file, " on (%d->%d)\n", e->src->index, e->dest->index);
+ }
+
+ // Equivalencies are handled by the equivalence oracle.
+ if (k == EQ_EXPR)
+ register_equiv (e->dest, op1, op2);
+ else
+ register_relation (e->dest, k, op1, op2);
+}
+
+// Register relation K between OP! and OP2 in block BB.
+// This creates the record and searches for existing records in the dominator
+// tree to merge with.
+
+void
+relation_oracle::register_relation (basic_block bb, relation_kind k, tree op1,
+ tree op2)
+{
+ gcc_checking_assert (k != VREL_NONE);
+
+ value_relation vr(k, op1, op2);
+ int bbi = bb->index;
+
+ if (bbi >= (int)m_relations.length())
+ m_relations.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1);
+
+ // Summary bitmap indicating what ssa_names have relations in this BB.
+ bitmap bm = m_relations[bbi].m_names;
+ if (!bm)
+ bm = m_relations[bbi].m_names = BITMAP_ALLOC (&m_bitmaps);
+ unsigned v1 = SSA_NAME_VERSION (op1);
+ unsigned v2 = SSA_NAME_VERSION (op2);
+
+ relation_kind curr;
+ relation_chain *ptr;
+ curr = find_relation_block (bbi, v1, v2, &ptr);
+ // There is an existing relation in this block, just intersect with it.
+ if (curr != VREL_NONE)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, " Intersecting with existing ");
+ ptr->dump (dump_file);
+ }
+ // Check into whether we can simply replace the relation rather than
+ // intersecting it. THis may help with some optimistic iterative
+ // updating algorithms.
+ ptr->intersect (vr);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, " to produce ");
+ ptr->dump (dump_file);
+ fprintf (dump_file, "\n");
+ }
+ return;
+ }
+
+ // Check for an existing relation further up the DOM chain.
+ // By including dominating relations, The first one found in any search
+ // will be the aggregate of all the previous ones.
+ curr = find_relation_dom (bb, v1, v2);
+ if (curr != VREL_NONE)
+ k = relation_intersect (curr, k);
+
+ bitmap_set_bit (bm, v1);
+ bitmap_set_bit (bm, v2);
+ bitmap_set_bit (m_relation_set, v1);
+ bitmap_set_bit (m_relation_set, v2);
+
+ ptr = (relation_chain *) obstack_alloc (&m_chain_obstack,
+ sizeof (relation_chain));
+ ptr->set_relation (k, op1, op2);
+ ptr->m_next = m_relations[bbi].m_head;
+ m_relations[bbi].m_head = ptr;;
+}
+
+// Find the relation between any ssa_name in B1 and any name in B2 in block BB.
+// This will allow equivalencies to be applied to any SSA_NAME in a relation.
+
+relation_kind
+relation_oracle::find_relation_block (unsigned bb, const_bitmap b1,
+ const_bitmap b2)
+{
+ const_bitmap bm;
+ if (bb >= m_relations.length())
+ return VREL_NONE;
+
+ bm = m_relations[bb].m_names;
+ if (!bm)
+ return VREL_NONE;
+
+ // If both b1 and b2 aren't referenced in thie block, cant be a relation
+ if (!bitmap_intersect_p (bm, b1) || !bitmap_intersect_p (bm, b2))
+ return VREL_NONE;
+
+ // Search for the fiorst relation that contains BOTH an element from B1
+ // and B2, and return that relation.
+ for (relation_chain *ptr = m_relations[bb].m_head; ptr ; ptr = ptr->m_next)
+ {
+ unsigned op1 = SSA_NAME_VERSION (ptr->op1 ());
+ unsigned op2 = SSA_NAME_VERSION (ptr->op2 ());
+ if (bitmap_bit_p (b1, op1) && bitmap_bit_p (b1, op2))
+ return ptr->kind ();
+ if (bitmap_bit_p (b1, op2) && bitmap_bit_p (b1, op1))
+ return relation_swap (ptr->kind ());
+ }
+
+ return VREL_NONE;
+}
+
+// Search the DOM tree for a relation between an element of B1 and B2, starting
+// with block BB.
+
+relation_kind
+relation_oracle::find_relation_dom (basic_block bb, const_bitmap b1,
+ const_bitmap b2)
+{
+ relation_kind r;
+ // If either name does not occur in a relation anywhere, there isnt one.
+ if (!bitmap_intersect_p (m_relation_set, b1)
+ || !bitmap_intersect_p (m_relation_set, b2))
+ return VREL_NONE;
+
+ // Search each block in the DOM tree checking.
+ for ( ; bb; bb = get_immediate_dominator (CDI_DOMINATORS, bb))
+ {
+ r = find_relation_block (bb->index, b1, b2);
+ if (r != VREL_NONE)
+ return r;
+ }
+ return VREL_NONE;
+
+}
+
+// Find a relation in block BB between ssa version V1 and V2. If a relation
+// is found, return a pointer to the chain object in OBJ.
+
+relation_kind
+relation_oracle::find_relation_block (int bb, unsigned v1, unsigned v2,
+ relation_chain **obj)
+{
+ if (bb >= (int)m_relations.length())
+ return VREL_NONE;
+
+ const_bitmap bm = m_relations[bb].m_names;
+ if (!bm)
+ return VREL_NONE;
+
+ // If both b1 and b2 aren't referenced in thie block, cant be a relation
+ if (!bitmap_bit_p (bm, v1) || !bitmap_bit_p (bm, v2))
+ return VREL_NONE;
+
+ relation_chain *ptr;
+ for (ptr = m_relations[bb].m_head; ptr ; ptr = ptr->m_next)
+ {
+ unsigned op1 = SSA_NAME_VERSION (ptr->op1 ());
+ unsigned op2 = SSA_NAME_VERSION (ptr->op2 ());
+ if (v1 == op1 && v2 == op2)
+ {
+ if (obj)
+ *obj = ptr;
+ return ptr->kind ();
+ }
+ if (v1 == op2 && v2 == op1)
+ {
+ if (obj)
+ *obj = ptr;
+ return relation_swap (ptr->kind ());
+ }
+ }
+
+ return VREL_NONE;
+}
+
+// Find a relation between SSA version V1 and V2 in the dominator tree
+// starting with block BB
+
+relation_kind
+relation_oracle::find_relation_dom (basic_block bb, unsigned v1, unsigned v2)
+{
+ relation_kind r;
+ // IF either name does not occur in a relation anywhere, there isnt one.
+ if (!bitmap_bit_p (m_relation_set, v1) || !bitmap_bit_p (m_relation_set, v2))
+ return VREL_NONE;
+
+ for ( ; bb; bb = get_immediate_dominator (CDI_DOMINATORS, bb))
+ {
+ r = find_relation_block (bb->index, v1, v2);
+ if (r != VREL_NONE)
+ return r;
+ }
+ return VREL_NONE;
+
+}
+
+// Query if there is a relation between SSA1 and SS2 in block BB or a
+// dominator of BB
+
+relation_kind
+relation_oracle::query_relation (basic_block bb, tree ssa1, tree ssa2)
+{
+ relation_kind kind;
+ unsigned v1 = SSA_NAME_VERSION (ssa1);
+ unsigned v2 = SSA_NAME_VERSION (ssa2);
+ if (v1 == v2)
+ return EQ_EXPR;
+
+ // Check for equivalence first.
+ const_bitmap equiv1 = equiv_set (ssa1, bb);
+ if (equiv1 && bitmap_bit_p (equiv1, v2))
+ return EQ_EXPR;
+
+ // Initially look for a direct relationship and just return that.
+ kind = find_relation_dom (bb, v1, v2);
+ if (kind != VREL_NONE)
+ return kind;
+
+ // If one is not found, see if there is a relationship between equivalences.
+ // If v2 isn't in v1s equiv set, then v1 shouldn't be in v2's set either.
+ const_bitmap equiv2 = equiv_set (ssa2, bb);
+ gcc_checking_assert (!equiv2 || !bitmap_bit_p (equiv2, v1));
+
+ if (!equiv1 && !equiv2)
+ kind = VREL_NONE;
+ else if (!equiv1)
+ {
+ bitmap_clear (m_tmp);
+ bitmap_set_bit (m_tmp, v1);
+ kind = find_relation_dom (bb, m_tmp, equiv2);
+ }
+ else if (!equiv2)
+ {
+ bitmap_clear (m_tmp);
+ bitmap_set_bit (m_tmp, v2);
+ kind = find_relation_dom (bb, equiv1, m_tmp);
+ }
+ else
+ kind = find_relation_dom (bb, equiv1, equiv2);
+ return kind;
+}
+
+// Dump all the relations in block BB to file F.
+
+void
+relation_oracle::dump (FILE *f, basic_block bb) const
+{
+ equiv_oracle::dump (f,bb);
+
+ if (bb->index >= (int)m_relations.length ())
+ return;
+ if (!m_relations[bb->index].m_names)
+ return;
+
+ relation_chain *ptr = m_relations[bb->index].m_head;
+ for (; ptr; ptr = ptr->m_next)
+ {
+ fprintf (f, "Relational : ");
+ ptr->dump (f);
+ fprintf (f, "\n");
+ }
+}
+
+// Dump all the relations known to file F.
+
+void
+relation_oracle::dump (FILE *f) const
+{
+ fprintf (f, "Relation dump\n");
+ for (unsigned i = 0; i < m_relations.length (); i++)
+ {
+ fprintf (f, "BB%d\n", i);
+ dump (f, BASIC_BLOCK_FOR_FN (cfun, i));
+ }
+}
diff --git a/gcc/value-relation.h b/gcc/value-relation.h
new file mode 100644
index 0000000..1148854
--- /dev/null
+++ b/gcc/value-relation.h
@@ -0,0 +1,159 @@
+/* Header file for the value range relational processing.
+ Copyright (C) 2020-2021 Free Software Foundation, Inc.
+ Contributed by Andrew MacLeod <amacleod@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_VALUE_RELATION_H
+#define GCC_VALUE_RELATION_H
+
+
+// This file provides access to a relation oracle which can be used to
+// maintain and query relations and equivalences between SSA_NAMES.
+//
+// The general range_query object provided in value-query.h provides
+// access to an oracle, if one is available, via the oracle() method.
+// Thre are also a couple of access routines provided, which even if there is
+// no oracle, will return the default VREL_NONE no relation.
+//
+// Typically, when a ranger object is active, there will be an oracle, and
+// any information available can be directly queried. Ranger also sets and
+// utilizes the relation information to enhance it's range calculations, this
+// is totally transparent to the client, and they are free to make queries.
+//
+//
+// relation_kind is a typedef of enum tree_code, but has restricted range
+// and a couple of extra values.
+//
+// A query is made requesting the relation between SSA1 and SSA@ in a basic
+// block, or on an edge, the possible return values are:
+//
+// EQ_EXPR, NE_EXPR, LT_EXPR, LE_EXPR, GT_EXPR, and GE_EXPR mean the same.
+// VREL_NONE : No relation between the 2 names.
+// VREL_EMPTY : Impossible relation (ie, A < B && A > B produces VREL_EMPTY.
+//
+// The oracle maintains EQ_EXPR relations with equivalency sets, so if a
+// relation comes back EQ_EXPR, it is also possible to query the set of
+// equivlaencies. These are basically bitmaps over ssa_names.
+//
+// relations are maintained via the dominace trees, are are optimized assuming
+// they are registered in dominance order. When a new relation is added, it
+// is intersected with whatever existing relation exists in the dominance tree
+// and registered at the specified block.
+
+
+// Rather than introduce a new enumerated type for relations, we can use the
+// existing tree_codes for relations, plus add a couple of #defines for
+// the other cases. These codes are arranged such that VREL_NONE is the first
+// code, and all the rest are contiguous.
+
+typedef enum tree_code relation_kind;
+
+#define VREL_NONE TRUTH_NOT_EXPR
+#define VREL_EMPTY LTGT_EXPR
+
+// General relation kind transformations.
+relation_kind relation_union (relation_kind r1, relation_kind r2);
+relation_kind relation_intersect (relation_kind r1, relation_kind r2);
+relation_kind relation_negate (relation_kind r);
+relation_kind relation_swap (relation_kind r);
+void print_relation (FILE *f, relation_kind rel);
+
+// Declared internally in value-relation.cc
+class equiv_chain;
+
+// The equivalency oracle maintains equivalencies using the dominator tree.
+// Equivalencies apply to an entire basic block. Equivalencies on edges
+// can be represented only on edges whose destination is a single-pred block,
+// and the equivalence is simply applied to that succesor block.
+
+class equiv_oracle
+{
+public:
+ equiv_oracle ();
+ ~equiv_oracle ();
+
+ const_bitmap equiv_set (tree ssa, basic_block bb) const;
+ void register_equiv (basic_block bb, tree ssa1, tree ssa2);
+
+ void dump (FILE *f, basic_block bb) const;
+ void dump (FILE *f) const;
+
+protected:
+ bitmap_obstack m_bitmaps;
+ struct obstack m_chain_obstack;
+private:
+ bitmap m_equiv_set; // Index by ssa-name. true if an equivalence exists.
+ vec <equiv_chain *> m_equiv; // Index by BB. list of equivalences.
+
+ void limit_check (basic_block bb = NULL);
+ equiv_chain *find_equiv_block (unsigned ssa, int bb) const;
+ equiv_chain *find_equiv_dom (tree name, basic_block bb) const;
+
+ bitmap register_equiv (basic_block bb, unsigned v, equiv_chain *equiv_1);
+ bitmap register_equiv (basic_block bb, equiv_chain *equiv_1,
+ equiv_chain *equiv_2);
+
+};
+
+// Summary block header for relations.
+
+class relation_chain_head
+{
+public:
+ bitmap m_names; // ssa_names with relations in this block.
+ class relation_chain *m_head; // List of relations in block.
+};
+
+// A relation oracle maintains a set of relations between ssa_names using the
+// dominator tree structures. Equivalencies are considered a subset of
+// a general relation and maintained by an equivalence oracle by transparently
+// passing any EQ_EXPR relations to it.
+// Relations are handled at the basic block level. All relations apply to
+// an entire block, and are thus kept in a summary index by block.
+// Similar to the equivalence oracle, edges are handled by applying the
+// relation to the destination block of the edge, but ONLY if that block
+// has a single successor. For now.
+
+class relation_oracle : public equiv_oracle
+{
+public:
+ relation_oracle ();
+ ~relation_oracle ();
+
+ void register_relation (gimple *stmt, relation_kind k, tree op1, tree op2);
+ void register_relation (edge e, relation_kind k, tree op1, tree op2);
+
+ relation_kind query_relation (basic_block bb, tree ssa1, tree ssa2);
+
+ void dump (FILE *f, basic_block bb) const;
+ void dump (FILE *f) const;
+private:
+ bitmap m_tmp;
+ bitmap m_relation_set; // Index by ssa-name. True if a relation exists
+ vec <relation_chain_head> m_relations; // Index by BB, list of relations.
+ relation_kind find_relation_block (unsigned bb, const_bitmap b1,
+ const_bitmap b2);
+ relation_kind find_relation_dom (basic_block bb, const_bitmap b1,
+ const_bitmap b2);
+ relation_kind find_relation_block (int bb, unsigned v1, unsigned v2,
+ relation_chain **obj = NULL);
+ relation_kind find_relation_dom (basic_block bb, unsigned v1, unsigned v2);
+ void register_relation (basic_block bb, relation_kind k, tree op1, tree op2);
+};
+
+#endif /* GCC_VALUE_RELATION_H */
diff --git a/libgcc/config/rs6000/float128-ifunc.c b/libgcc/config/rs6000/float128-ifunc.c
index 57545dd..ef7f731 100644
--- a/libgcc/config/rs6000/float128-ifunc.c
+++ b/libgcc/config/rs6000/float128-ifunc.c
@@ -46,7 +46,9 @@
#endif
#define SW_OR_HW(SW, HW) (__builtin_cpu_supports ("ieee128") ? HW : SW)
+#ifdef FLOAT128_HW_INSNS_ISA3_1
#define SW_OR_HW_ISA3_1(SW, HW) (__builtin_cpu_supports ("arch_3_1") ? HW : SW)
+#endif
/* Resolvers. */
static __typeof__ (__addkf3_sw) *
@@ -97,6 +99,7 @@ __floatdikf_resolve (void)
return SW_OR_HW (__floatdikf_sw, __floatdikf_hw);
}
+#ifdef FLOAT128_HW_INSNS_ISA3_1
static __typeof__ (__floattikf_sw) *
__floattikf_resolve (void)
{
@@ -108,6 +111,7 @@ __floatuntikf_resolve (void)
{
return SW_OR_HW_ISA3_1 (__floatuntikf_sw, __floatuntikf_hw);
}
+#endif
static __typeof__ (__floatunsikf_sw) *
__floatunsikf_resolve (void)
@@ -121,7 +125,7 @@ __floatundikf_resolve (void)
return SW_OR_HW (__floatundikf_sw, __floatundikf_hw);
}
-
+#ifdef FLOAT128_HW_INSNS_ISA3_1
static __typeof__ (__fixkfti_sw) *
__fixkfti_resolve (void)
{
@@ -133,6 +137,7 @@ __fixunskfti_resolve (void)
{
return SW_OR_HW_ISA3_1 (__fixunskfti_sw, __fixunskfti_hw);
}
+#endif
static __typeof__ (__fixkfsi_sw) *
__fixkfsi_resolve (void)
@@ -323,6 +328,7 @@ TFtype __floatsikf (SItype_ppc)
TFtype __floatdikf (DItype_ppc)
__attribute__ ((__ifunc__ ("__floatdikf_resolve")));
+#ifdef FLOAT128_HW_INSNS_ISA3_1
TFtype __floattikf (TItype_ppc)
__attribute__ ((__ifunc__ ("__floattikf_resolve")));
@@ -334,6 +340,7 @@ TItype_ppc __fixkfti (TFtype)
UTItype_ppc __fixunskfti (TFtype)
__attribute__ ((__ifunc__ ("__fixunskfti_resolve")));
+#endif
TFtype __floatunsikf (USItype_ppc)
__attribute__ ((__ifunc__ ("__floatunsikf_resolve")));
diff --git a/libgcc/config/rs6000/t-float128-hw b/libgcc/config/rs6000/t-float128-hw
index c082736..d64ca4d 100644
--- a/libgcc/config/rs6000/t-float128-hw
+++ b/libgcc/config/rs6000/t-float128-hw
@@ -13,13 +13,6 @@ fp128_hw_static_obj = $(addsuffix $(objext),$(fp128_hw_funcs))
fp128_hw_shared_obj = $(addsuffix _s$(objext),$(fp128_hw_funcs))
fp128_hw_obj = $(fp128_hw_static_obj) $(fp128_hw_shared_obj)
-# New functions for ISA 3.1 hardware support
-fp128_3_1_hw_funcs = float128-p10
-fp128_3_1_hw_src = $(srcdir)/config/rs6000/float128-p10.c
-fp128_3_1_hw_static_obj = $(addsuffix $(objext),$(fp128_3_1_hw_funcs))
-fp128_3_1_hw_shared_obj = $(addsuffix _s$(objext),$(fp128_3_1_hw_funcs))
-fp128_3_1_hw_obj = $(fp128_3_1_hw_static_obj) $(fp128_3_1_hw_shared_obj)
-
fp128_ifunc_funcs = float128-ifunc
fp128_ifunc_src = $(srcdir)/config/rs6000/float128-ifunc.c
fp128_ifunc_static_obj = float128-ifunc$(objext)
@@ -37,18 +30,9 @@ FP128_CFLAGS_HW = -Wno-type-limits -mvsx -mfloat128 \
-I$(srcdir)/config/rs6000 \
$(FLOAT128_HW_INSNS)
-FP128_3_1_CFLAGS_HW = -Wno-type-limits -mvsx -mcpu=power10 \
- -mfloat128-hardware -mno-gnu-attribute \
- -I$(srcdir)/soft-fp \
- -I$(srcdir)/config/rs6000 \
- $(FLOAT128_HW_INSNS)
-
$(fp128_hw_obj) : INTERNAL_CFLAGS += $(FP128_CFLAGS_HW)
$(fp128_hw_obj) : $(srcdir)/config/rs6000/t-float128-hw
-$(fp128_3_1_hw_obj) : INTERNAL_CFLAGS += $(FP128_3_1_CFLAGS_HW)
-$(fp128_3_1_hw_obj) : $(srcdir)/config/rs6000/t-float128-p10-hw
-
$(fp128_ifunc_obj) : INTERNAL_CFLAGS += $(FP128_CFLAGS_SW)
$(fp128_ifunc_obj) : $(srcdir)/config/rs6000/t-float128-hw
diff --git a/libgcc/config/rs6000/t-float128-p10-hw b/libgcc/config/rs6000/t-float128-p10-hw
index de36227..edaaee0 100644
--- a/libgcc/config/rs6000/t-float128-p10-hw
+++ b/libgcc/config/rs6000/t-float128-p10-hw
@@ -2,7 +2,7 @@
# Tell the float128 functions that the ISA 3.1 hardware support can
# be compiled it to be selected via IFUNC functions.
-FLOAT128_HW_INSNS = -DFLOAT128_HW_INSNS
+FLOAT128_HW_INSNS += -DFLOAT128_HW_INSNS_ISA3_1
# New functions for hardware support
@@ -14,7 +14,7 @@ fp128_3_1_hw_obj = $(fp128_3_1_hw_static_obj) $(fp128_3_1_hw_shared_obj)
# Build the hardware support functions with appropriate hardware support
FP128_3_1_CFLAGS_HW = -Wno-type-limits -mvsx -mfloat128 \
- -mpower10 \
+ -mcpu=power10 \
-mfloat128-hardware -mno-gnu-attribute \
-I$(srcdir)/soft-fp \
-I$(srcdir)/config/rs6000 \
diff --git a/libgcc/configure b/libgcc/configure
index ce05e0d..4919a56 100755
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -5265,10 +5265,10 @@ $as_echo "$libgcc_cv_powerpc_float128_hw" >&6; }
CFLAGS="$saved_CFLAGS"
saved_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS -mpower10 -mfloat128-hardware"
+ CFLAGS="$CFLAGS -mcpu=power10 -mfloat128-hardware"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PowerPC ISA 3.1 to build hardware __float128 libraries" >&5
$as_echo_n "checking for PowerPC ISA 3.1 to build hardware __float128 libraries... " >&6; }
-if ${libgcc_cv_powerpc_float128_hw+:} false; then :
+if ${libgcc_cv_powerpc_3_1_float128_hw+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -5280,15 +5280,15 @@ else
#ifndef __BUILTIN_CPU_SUPPORTS__
#error "__builtin_cpu_supports is not available"
#endif
- vector unsigned char add (vector unsigned char a, vector unsigned char b)
+ vector unsigned char conv (vector unsigned char qs)
{
vector unsigned char ret;
- __asm__ ("xscvsqqp %0,%1,%2" : "=v" (ret) : "v" (a), "v" (b));
+ __asm__ ("xscvsqqp %0,%1" : "=v" (ret) : "v" (qs));
return ret;
}
- void *add_resolver (void) { return (void *) add; }
- __float128 add_ifunc (__float128, __float128)
- __attribute__ ((__ifunc__ ("add_resolver")));
+ void *conv_resolver (void) { return (void *) conv; }
+ __float128 conv_ifunc (__float128)
+ __attribute__ ((__ifunc__ ("conv_resolver")));
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
libgcc_cv_powerpc_3_1_float128_hw=yes
@@ -5297,8 +5297,8 @@ else
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_powerpc_float128_hw" >&5
- $as_echo "$libgcc_cv_powerpc_float128_hw" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_powerpc_3_1_float128_hw" >&5
+$as_echo "$libgcc_cv_powerpc_3_1_float128_hw" >&6; }
CFLAGS="$saved_CFLAGS"
esac
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index bc315de..13a80b2 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -460,9 +460,9 @@ powerpc*-*-linux*)
CFLAGS="$saved_CFLAGS"
saved_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS -mpower10 -mfloat128-hardware"
+ CFLAGS="$CFLAGS -mcpu=power10 -mfloat128-hardware"
AC_CACHE_CHECK([for PowerPC ISA 3.1 to build hardware __float128 libraries],
- [libgcc_cv_powerpc_float128_hw],
+ [libgcc_cv_powerpc_3_1_float128_hw],
[AC_COMPILE_IFELSE(
[AC_LANG_SOURCE([#include <sys/auxv.h>
#ifndef AT_PLATFORM
@@ -471,15 +471,15 @@ powerpc*-*-linux*)
#ifndef __BUILTIN_CPU_SUPPORTS__
#error "__builtin_cpu_supports is not available"
#endif
- vector unsigned char add (vector unsigned char a, vector unsigned char b)
+ vector unsigned char conv (vector unsigned char qs)
{
vector unsigned char ret;
- __asm__ ("xscvsqqp %0,%1,%2" : "=v" (ret) : "v" (a), "v" (b));
+ __asm__ ("xscvsqqp %0,%1" : "=v" (ret) : "v" (qs));
return ret;
}
- void *add_resolver (void) { return (void *) add; }
- __float128 add_ifunc (__float128, __float128)
- __attribute__ ((__ifunc__ ("add_resolver")));])],
+ void *conv_resolver (void) { return (void *) conv; }
+ __float128 conv_ifunc (__float128)
+ __attribute__ ((__ifunc__ ("conv_resolver")));])],
[libgcc_cv_powerpc_3_1_float128_hw=yes],
[libgcc_cv_powerpc_3_1_float128_hw=no])])
CFLAGS="$saved_CFLAGS"
diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog
index 97bc035..b763a22 100644
--- a/libgfortran/ChangeLog
+++ b/libgfortran/ChangeLog
@@ -1,3 +1,10 @@
+2021-06-22 Sandra Loosemore <sandra@codesourcery.com>
+ Tobias Burnus <tobias@codesourcery.com>
+
+ PR fortran/93524
+ * runtime/ISO_Fortran_binding.c (CFI_allocate): Fix
+ sm computation.
+
2021-06-08 Martin Liska <mliska@suse.cz>
* intrinsics/chmod.c (chmod_internal): Fix typo.
diff --git a/libgfortran/runtime/ISO_Fortran_binding.c b/libgfortran/runtime/ISO_Fortran_binding.c
index 20833ad..0978832 100644
--- a/libgfortran/runtime/ISO_Fortran_binding.c
+++ b/libgfortran/runtime/ISO_Fortran_binding.c
@@ -254,10 +254,7 @@ CFI_allocate (CFI_cdesc_t *dv, const CFI_index_t lower_bounds[],
{
dv->dim[i].lower_bound = lower_bounds[i];
dv->dim[i].extent = upper_bounds[i] - dv->dim[i].lower_bound + 1;
- if (i == 0)
- dv->dim[i].sm = dv->elem_len;
- else
- dv->dim[i].sm = dv->elem_len * dv->dim[i - 1].extent;
+ dv->dim[i].sm = dv->elem_len * arr_len;
arr_len *= dv->dim[i].extent;
}
}
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index f652c4d..c1c04be 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,44 @@
+2021-06-22 Jonathan Wakely <jwakely@redhat.com>
+ Matthias Kretz <m.kretz@gsi.de>
+
+ * include/std/mutex (lock): Replace recursion with iteration
+ when lockables all have the same type.
+ (__detail::__try_lock_impl): Likewise. Pass lockables as
+ parameters, instead of a tuple. Always lock the first one, and
+ recurse for the rest.
+ (__detail::__lock_impl): Adjust call to __try_lock_impl.
+ (__detail::__try_to_lock): Remove.
+ * testsuite/30_threads/lock/3.cc: Check that mutexes are locked.
+ * testsuite/30_threads/lock/4.cc: Also test non-heterogeneous
+ arguments.
+ * testsuite/30_threads/unique_lock/cons/60497.cc: Also check
+ std::try_lock.
+ * testsuite/30_threads/try_lock/5.cc: New test.
+
+2021-06-22 Jonathan Wakely <jwakely@redhat.com>
+
+ * include/std/memory (declare_reachable, undeclare_reachable)
+ (declare_no_pointers, undeclare_no_pointers, get_pointer_safety)
+ (pointer_safety): Only define for C++11 to C++20 inclusive.
+ * testsuite/20_util/pointer_safety/1.cc: Do not run for C++23.
+
+2021-06-22 Jonathan Wakely <jwakely@redhat.com>
+
+ * include/bits/random.h (seed_seq): Constrain initializer-list
+ constructor.
+ * include/bits/random.tcc (seed_seq): Add template parameter.
+ * testsuite/26_numerics/random/seed_seq/cons/default.cc: Check
+ for noexcept.
+ * testsuite/26_numerics/random/seed_seq/cons/initlist.cc: Check
+ constraints.
+
+2021-06-22 Thomas Rodgers <rodgert@appliantology.com>
+
+ PR libstdc++/100806
+ * include/bits/semaphore_base.h (__atomic_semaphore::_M_release):
+ Force _M_release() to wake all waiting threads.
+ * testsuite/30_threads/semaphore/100806.cc: New test.
+
2021-06-21 Jonathan Wakely <jwakely@redhat.com>
* include/std/mutex (__try_to_lock): Move to __detail namespace.
diff --git a/libstdc++-v3/include/bits/random.h b/libstdc++-v3/include/bits/random.h
index 0da013c..ed0d7a8 100644
--- a/libstdc++-v3/include/bits/random.h
+++ b/libstdc++-v3/include/bits/random.h
@@ -6073,7 +6073,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: _M_v()
{ }
- template<typename _IntType>
+ template<typename _IntType, typename = _Require<is_integral<_IntType>>>
seed_seq(std::initializer_list<_IntType> __il);
template<typename _InputIterator>
diff --git a/libstdc++-v3/include/bits/random.tcc b/libstdc++-v3/include/bits/random.tcc
index 1357e18..8e2b702 100644
--- a/libstdc++-v3/include/bits/random.tcc
+++ b/libstdc++-v3/include/bits/random.tcc
@@ -3231,7 +3231,7 @@ namespace __detail
}
- template<typename _IntType>
+ template<typename _IntType, typename>
seed_seq::seed_seq(std::initializer_list<_IntType> __il)
{
for (auto __iter = __il.begin(); __iter != __il.end(); ++__iter)
diff --git a/libstdc++-v3/include/bits/semaphore_base.h b/libstdc++-v3/include/bits/semaphore_base.h
index 9a55978..c4565d7 100644
--- a/libstdc++-v3/include/bits/semaphore_base.h
+++ b/libstdc++-v3/include/bits/semaphore_base.h
@@ -256,7 +256,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__update > 1)
__atomic_notify_address_bare(&_M_counter, true);
else
- __atomic_notify_address_bare(&_M_counter, false);
+ __atomic_notify_address_bare(&_M_counter, true);
+// FIXME - Figure out why this does not wake a waiting thread
+// __atomic_notify_address_bare(&_M_counter, false);
}
private:
diff --git a/libstdc++-v3/include/std/memory b/libstdc++-v3/include/std/memory
index f19de27..da64be2 100644
--- a/libstdc++-v3/include/std/memory
+++ b/libstdc++-v3/include/std/memory
@@ -87,7 +87,7 @@
# include <bits/uses_allocator_args.h>
#endif
-#if __cplusplus >= 201103L
+#if __cplusplus >= 201103L && __cplusplus <= 202002L
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
@@ -132,7 +132,7 @@ get_pointer_safety() noexcept { return pointer_safety::relaxed; }
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
-#endif // C++11
+#endif // C++11 to C++20
#if __cplusplus >= 201703L
// Parallel STL algorithms
diff --git a/libstdc++-v3/include/std/mutex b/libstdc++-v3/include/std/mutex
index 5f2d8f9..c18ca1a 100644
--- a/libstdc++-v3/include/std/mutex
+++ b/libstdc++-v3/include/std/mutex
@@ -514,39 +514,61 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// @cond undocumented
namespace __detail
{
+ // Lock the last lockable, after all previous ones are locked.
template<typename _Lockable>
- inline unique_lock<_Lockable>
- __try_to_lock(_Lockable& __l)
- { return unique_lock<_Lockable>{__l, try_to_lock}; }
-
- // Lock the last element of the tuple, after all previous ones are locked.
- template<int _Idx, typename... _Lockables>
- inline __enable_if_t<_Idx + 1 == sizeof...(_Lockables), int>
- __try_lock_impl(tuple<_Lockables&...>& __lockables)
+ inline int
+ __try_lock_impl(_Lockable& __lockable)
{
- if (auto __lock = __detail::__try_to_lock(std::get<_Idx>(__lockables)))
+ if (unique_lock<_Lockable> __lock{__lockable, try_to_lock})
{
__lock.release();
return -1;
}
else
- return _Idx;
+ return 0;
}
- // Lock tuple elements starting from _Idx.
- template<int _Idx, typename... _Lockables>
- inline __enable_if_t<_Idx + 1 != sizeof...(_Lockables), int>
- __try_lock_impl(tuple<_Lockables&...>& __lockables)
+ // Lock each lockable in turn.
+ // Use iteration if all lockables are the same type, recursion otherwise.
+ template<typename _L0, typename... _Lockables>
+ inline int
+ __try_lock_impl(_L0& __l0, _Lockables&... __lockables)
{
- if (auto __lock = __detail::__try_to_lock(std::get<_Idx>(__lockables)))
+#if __cplusplus >= 201703L
+ if constexpr ((is_same_v<_L0, _Lockables> && ...))
{
- int __idx = __detail::__try_lock_impl<_Idx + 1>(__lockables);
+ constexpr int _Np = 1 + sizeof...(_Lockables);
+ unique_lock<_L0> __locks[_Np] = {
+ {__l0, defer_lock}, {__lockables, defer_lock}...
+ };
+ for (int __i = 0; __i < _Np; ++__i)
+ {
+ if (!__locks[__i].try_lock())
+ {
+ const int __failed = __i;
+ while (__i--)
+ __locks[__i].unlock();
+ return __failed;
+ }
+ }
+ for (auto& __l : __locks)
+ __l.release();
+ return -1;
+ }
+ else
+#endif
+ if (unique_lock<_L0> __lock{__l0, try_to_lock})
+ {
+ int __idx = __detail::__try_lock_impl(__lockables...);
if (__idx == -1)
- __lock.release();
- return __idx;
+ {
+ __lock.release();
+ return -1;
+ }
+ return __idx + 1;
}
else
- return _Idx;
+ return 0;
}
} // namespace __detail
@@ -562,12 +584,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
*
* Sequentially calls try_lock() on each argument.
*/
- template<typename _Lock1, typename _Lock2, typename... _Lock3>
+ template<typename _L1, typename _L2, typename... _L3>
int
- try_lock(_Lock1& __l1, _Lock2& __l2, _Lock3&... __l3)
+ try_lock(_L1& __l1, _L2& __l2, _L3&... __l3)
{
- auto __lockables = std::tie(__l1, __l2, __l3...);
- return __detail::__try_lock_impl<0>(__lockables);
+ return __detail::__try_lock_impl(__l1, __l2, __l3...);
}
/// @cond undocumented
@@ -589,8 +610,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
int __failed = 1; // index that couldn't be locked
{
unique_lock<_L0> __first(__l0);
- auto __rest = std::tie(__l1...);
- __failed += __detail::__try_lock_impl<0>(__rest);
+ __failed += __detail::__try_lock_impl(__l1...);
if (!__failed)
{
__i = -1; // finished
@@ -620,15 +640,45 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
* @post All arguments are locked.
*
* All arguments are locked via a sequence of calls to lock(), try_lock()
- * and unlock(). If the call exits via an exception any locks that were
- * obtained will be released.
+ * and unlock(). If this function exits via an exception any locks that
+ * were obtained will be released.
*/
template<typename _L1, typename _L2, typename... _L3>
void
lock(_L1& __l1, _L2& __l2, _L3&... __l3)
{
- int __i = 0;
- __detail::__lock_impl(__i, 0, __l1, __l2, __l3...);
+#if __cplusplus >= 201703L
+ if constexpr (is_same_v<_L1, _L2> && (is_same_v<_L1, _L3> && ...))
+ {
+ constexpr int _Np = 2 + sizeof...(_L3);
+ unique_lock<_L1> __locks[] = {
+ {__l1, defer_lock}, {__l2, defer_lock}, {__l3, defer_lock}...
+ };
+ int __first = 0;
+ do {
+ __locks[__first].lock();
+ for (int __j = 1; __j < _Np; ++__j)
+ {
+ const int __idx = (__first + __j) % _Np;
+ if (!__locks[__idx].try_lock())
+ {
+ for (int __k = __j; __k != 0; --__k)
+ __locks[(__first + __k - 1) % _Np].unlock();
+ __first = __idx;
+ break;
+ }
+ }
+ } while (!__locks[__first].owns_lock());
+
+ for (auto& __l : __locks)
+ __l.release();
+ }
+ else
+#endif
+ {
+ int __i = 0;
+ __detail::__lock_impl(__i, 0, __l1, __l2, __l3...);
+ }
}
#if __cplusplus >= 201703L
diff --git a/libstdc++-v3/testsuite/20_util/pointer_safety/1.cc b/libstdc++-v3/testsuite/20_util/pointer_safety/1.cc
index 7d9a425..bfacbce 100644
--- a/libstdc++-v3/testsuite/20_util/pointer_safety/1.cc
+++ b/libstdc++-v3/testsuite/20_util/pointer_safety/1.cc
@@ -15,7 +15,7 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-// { dg-do run { target c++11 } }
+// { dg-do run { target { c++11 && { ! c++23 } } } }
#include <memory>
#include <testsuite_hooks.h>
diff --git a/libstdc++-v3/testsuite/26_numerics/random/seed_seq/cons/default.cc b/libstdc++-v3/testsuite/26_numerics/random/seed_seq/cons/default.cc
index 18f55e7..62434a6 100644
--- a/libstdc++-v3/testsuite/26_numerics/random/seed_seq/cons/default.cc
+++ b/libstdc++-v3/testsuite/26_numerics/random/seed_seq/cons/default.cc
@@ -25,6 +25,9 @@
#include <random>
#include <testsuite_hooks.h>
+static_assert( std::is_nothrow_default_constructible<std::seed_seq>::value,
+ "LWG 3422" );
+
void
test01()
{
@@ -34,7 +37,6 @@ test01()
seq.generate(foo.begin(), foo.end());
VERIFY( seq.size() == 0 );
- //VERIFY();
}
int
diff --git a/libstdc++-v3/testsuite/26_numerics/random/seed_seq/cons/initlist.cc b/libstdc++-v3/testsuite/26_numerics/random/seed_seq/cons/initlist.cc
index 44b855e..1ed9eb7 100644
--- a/libstdc++-v3/testsuite/26_numerics/random/seed_seq/cons/initlist.cc
+++ b/libstdc++-v3/testsuite/26_numerics/random/seed_seq/cons/initlist.cc
@@ -36,6 +36,13 @@ test01()
VERIFY( seq.size() == 10 );
}
+void
+lwg3422()
+{
+ int i[32] = { };
+ std::seed_seq ss{i, i+32}; // LWG 3422
+}
+
int main()
{
test01();
diff --git a/libstdc++-v3/testsuite/30_threads/lock/3.cc b/libstdc++-v3/testsuite/30_threads/lock/3.cc
index 5213607..5fa1187 100644
--- a/libstdc++-v3/testsuite/30_threads/lock/3.cc
+++ b/libstdc++-v3/testsuite/30_threads/lock/3.cc
@@ -37,7 +37,7 @@ struct user_lock
is_locked = true;
}
- bool try_lock()
+ bool try_lock()
{ return is_locked ? false : (is_locked = true); }
void unlock()
@@ -62,6 +62,8 @@ int main()
{
//heterogeneous types
std::lock(m1, m2, m3);
+ VERIFY( !m1.try_lock() );
+ VERIFY( !m3.try_lock() );
m1.unlock();
m2.unlock();
m3.unlock();
diff --git a/libstdc++-v3/testsuite/30_threads/lock/4.cc b/libstdc++-v3/testsuite/30_threads/lock/4.cc
index 7ba15cb..130c1f6 100644
--- a/libstdc++-v3/testsuite/30_threads/lock/4.cc
+++ b/libstdc++-v3/testsuite/30_threads/lock/4.cc
@@ -73,6 +73,7 @@ int unreliable_lock::lock_on = -1;
void test01()
{
unreliable_lock l1, l2, l3;
+ std::mutex m1, m2, m3;
try
{
@@ -87,6 +88,60 @@ void test01()
{
VERIFY( false );
}
+
+ // Repeat with non-heterogeneous arguments
+
+ try
+ {
+ unreliable_lock::count = 0;
+ std::lock(l1, l2, l3, m1);
+ VERIFY( unreliable_lock::count == 3 );
+ l1.unlock();
+ l2.unlock();
+ l3.unlock();
+ VERIFY( !m1.try_lock() ); // already locked
+ m1.unlock();
+ }
+ catch (...)
+ {
+ VERIFY( false );
+ }
+
+ try
+ {
+ unreliable_lock::count = 0;
+ std::lock(m1, l1, l2, l3);
+ VERIFY( unreliable_lock::count == 3 );
+ VERIFY( !m1.try_lock() ); // already locked
+ m1.unlock();
+ l1.unlock();
+ l2.unlock();
+ l3.unlock();
+ }
+ catch (...)
+ {
+ VERIFY( false );
+ }
+
+ try
+ {
+ unreliable_lock::count = 0;
+ std::lock(l1, m1, l2, m2, l3, m3);
+ VERIFY( unreliable_lock::count == 3 );
+ l1.unlock();
+ l2.unlock();
+ l3.unlock();
+ VERIFY( !m1.try_lock() ); // already locked
+ VERIFY( !m2.try_lock() ); // already locked
+ VERIFY( !m3.try_lock() ); // already locked
+ m1.unlock();
+ m2.unlock();
+ m3.unlock();
+ }
+ catch (...)
+ {
+ VERIFY( false );
+ }
}
void test02()
@@ -111,6 +166,31 @@ void test02()
{
VERIFY( false );
}
+
+ // Repeat with non-heterogeneous arguments
+
+ try
+ {
+ unreliable_lock::lock_on = 1;
+ while (unreliable_lock::lock_on < 3)
+ {
+ unreliable_lock::count = 0;
+ unreliable_lock l1, l2, l3;
+ std::mutex m1;
+ std::lock(l1, l2, l3, m1);
+ VERIFY( unreliable_lock::count > 3 );
+ l1.unlock();
+ l2.unlock();
+ l3.unlock();
+ VERIFY( !m1.try_lock() ); // already locked
+ m1.unlock();
+ ++unreliable_lock::lock_on;
+ }
+ }
+ catch (...)
+ {
+ VERIFY( false );
+ }
}
void test03()
@@ -133,6 +213,50 @@ void test03()
VERIFY( test );
++unreliable_lock::throw_on;
}
+
+ // Repeat with non-heterogeneous arguments
+
+ unreliable_lock::throw_on = 0;
+ while (unreliable_lock::throw_on < 3)
+ {
+ unreliable_lock::count = 0;
+ unreliable_lock l1, l2, l3;
+ std::mutex m1;
+ bool test = false;
+ try
+ {
+ std::lock(l1, l2, l3, m1);
+ }
+ catch (...)
+ {
+ test = true;
+ }
+ VERIFY( test );
+ VERIFY( m1.try_lock() ); // m1 was not left locked by failed std::lock
+ m1.unlock();
+ ++unreliable_lock::throw_on;
+ }
+
+ unreliable_lock::throw_on = 0;
+ while (unreliable_lock::throw_on < 3)
+ {
+ unreliable_lock::count = 0;
+ unreliable_lock l1, l2, l3;
+ std::mutex m1;
+ bool test = false;
+ try
+ {
+ std::lock(m1, l1, l2, l3);
+ }
+ catch (...)
+ {
+ test = true;
+ }
+ VERIFY( test );
+ VERIFY( m1.try_lock() ); // m1 was not left locked by failed std::lock
+ m1.unlock();
+ ++unreliable_lock::throw_on;
+ }
}
int main()
diff --git a/libstdc++-v3/testsuite/30_threads/semaphore/100806.cc b/libstdc++-v3/testsuite/30_threads/semaphore/100806.cc
new file mode 100644
index 0000000..2fa2628
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/semaphore/100806.cc
@@ -0,0 +1,57 @@
+// { dg-options "-std=gnu++2a -pthread" }
+// { dg-do run { target c++2a } }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+// { dg-add-options libatomic }
+
+#include <iostream>
+#include <sstream>
+
+#include <thread>
+#include <semaphore>
+#include <mutex>
+#include <chrono>
+#include <vector>
+
+std::counting_semaphore<4> semaphore{6};
+
+std::mutex mtx;
+std::vector<std::string> results;
+
+void thread_main(size_t x)
+{
+ semaphore.acquire();
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ semaphore.release();
+ {
+ std::ostringstream stm;
+ stm << "Thread " << x << " finished.";
+ std::lock_guard g{ mtx };
+ results.push_back(stm.str());
+ }
+}
+
+int main()
+{
+ constexpr auto nthreads = 10;
+
+ std::vector<std::thread> threads(nthreads);
+
+ size_t counter{0};
+ for(auto& t : threads)
+ {
+ t = std::thread(thread_main, counter++);
+ }
+
+ for(auto& t : threads)
+ {
+ t.join();
+ {
+ std::lock_guard g{ mtx };
+ for (auto&& r : results)
+ std::cout << r << '\n';
+ std::cout.flush();
+ results.clear();
+ }
+ }
+}
diff --git a/libstdc++-v3/testsuite/30_threads/try_lock/5.cc b/libstdc++-v3/testsuite/30_threads/try_lock/5.cc
new file mode 100644
index 0000000..a5574ff
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/try_lock/5.cc
@@ -0,0 +1,41 @@
+// { dg-do run { target c++11 } }
+
+#include <mutex>
+#include <testsuite_hooks.h>
+
+struct Lockable
+{
+ static int tries;
+
+ void lock() { }
+ void unlock() { }
+ bool try_lock() { return ++tries != 2; }
+};
+
+int Lockable::tries = 0;
+
+void test01()
+{
+ Lockable l1, l2, l3;
+ std::mutex m1, m2;
+
+ VERIFY( std::try_lock(l1, l2, l3) == 1 );
+ VERIFY( Lockable::tries == 2 );
+
+ Lockable::tries = 0;
+ VERIFY( std::try_lock(m1, l1, l2, l3) == 2 );
+ VERIFY( Lockable::tries == 2 );
+
+ Lockable::tries = 0;
+ VERIFY( std::try_lock(l1, l2, l3, m1) == 1 );
+ VERIFY( Lockable::tries == 2 );
+
+ Lockable::tries = 0;
+ VERIFY( std::try_lock(m1, l1, l2, l3, m2) == 2 );
+ VERIFY( Lockable::tries == 2 );
+}
+
+int main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc b/libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc
index 8603e56..08698ce 100644
--- a/libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc
+++ b/libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc
@@ -46,3 +46,9 @@ void test02()
test_type l1, l2, l3;
std::lock(l1, l2, l3);
}
+
+void test03()
+{
+ test_type l1, l2, l3;
+ std::try_lock(l1, l2, l3);
+}