--- /dev/null
+// { dg-do compile { target c++20 } }
+// { dg-options "-O2 -Wall" }
+
+// Make sure we don't get a -Wnonnull warning here.
+
+#include <compare>
+
+ template<typename Tp>
+ constexpr auto
+ min_cmp(Tp x, Tp y)
+ {
+ struct Res {
+ Tp M_min;
+ decltype(x <=> y) M_cmp;
+ };
+ auto c = x <=> y;
+ if (c > 0)
+ return Res{y, c};
+ return Res{x, c};
+ }
+
+
+ template<typename InputIter1, typename InputIter2>
+ auto
+ lexicographical_compare_three_way(InputIter1 first1,
+ InputIter1 last1,
+ InputIter2 first2,
+ InputIter2 last2)
+ -> decltype(*first1 <=> *first2)
+ {
+ const auto [len, lencmp] =
+ min_cmp(last1 - first1, last2 - first2);
+ if (len)
+ {
+ const auto blen = len * sizeof(*first1);
+ const auto c
+ = __builtin_memcmp(&*first1, &*first2, blen) <=> 0;
+ if (c != 0)
+ return c;
+ }
+ return lencmp;
+ }
+
+auto
+test03()
+{
+ unsigned char a[2] = { 1, 2 };
+ unsigned char* p = nullptr;
+ return lexicographical_compare_three_way(p, p, a, a+2);
+}
return true;
}
-/* Return the single store in BB with VDEF or NULL if there are
- other stores in the BB or loads following the store. VPHI is
- where the only use of the vdef should be. */
+/* Return the last store in BB with VDEF or NULL if there are
+ loads following the store. VPHI is where the only use of the
+ vdef should be. If ONLYONESTORE is true, then the store is
+ the only store in the BB. */
static gimple *
-single_trailing_store_in_bb (basic_block bb, tree vdef, gphi *vphi)
+trailing_store_in_bb (basic_block bb, tree vdef, gphi *vphi, bool onlyonestore)
{
if (SSA_NAME_IS_DEFAULT_DEF (vdef))
return NULL;
|| gimple_code (store) == GIMPLE_PHI)
return NULL;
- /* Verify there is no other store in this BB. */
- if (!SSA_NAME_IS_DEFAULT_DEF (gimple_vuse (store))
+ /* Verify there is no other store in this BB if requested. */
+ if (onlyonestore
+ && !SSA_NAME_IS_DEFAULT_DEF (gimple_vuse (store))
&& gimple_bb (SSA_NAME_DEF_STMT (gimple_vuse (store))) == bb
&& gimple_code (SSA_NAME_DEF_STMT (gimple_vuse (store))) != GIMPLE_PHI)
return NULL;
+
/* Verify there is no load or store after the store, the vdef of the store
should only be used by the vphi joining the 2 bbs. */
use_operand_p use_p;
if (cond) goto THEN_BB; else goto ELSE_BB (edge E1)
THEN_BB:
...
- ONLY_STORE = Y;
+ STORE = Y;
...
goto JOIN_BB;
ELSE_BB:
...
- ONLY_STORE = Z;
+ STORE = Z;
...
fallthrough (edge E0)
JOIN_BB:
some more
- Handles only the case with single store in THEN_BB and ELSE_BB. That is
+ Handles only the case with store in THEN_BB and ELSE_BB. That is
cheap enough due to in phiopt and not worry about heurstics. Moving the store
- out might provide an opportunity for a phiopt to happen. */
+ out might provide an opportunity for a phiopt to happen.
+ At -O1 (!flag_expensive_optimizations), this only handles the only store in
+ the BBs. */
static bool
cond_if_else_store_replacement_limited (basic_block then_bb, basic_block else_bb,
return false;
tree then_vdef = PHI_ARG_DEF_FROM_EDGE (vphi, single_succ_edge (then_bb));
- gimple *then_assign = single_trailing_store_in_bb (then_bb, then_vdef, vphi);
+ gimple *then_assign = trailing_store_in_bb (then_bb, then_vdef, vphi,
+ !flag_expensive_optimizations);
if (!then_assign)
return false;
tree else_vdef = PHI_ARG_DEF_FROM_EDGE (vphi, single_succ_edge (else_bb));
- gimple *else_assign = single_trailing_store_in_bb (else_bb, else_vdef, vphi);
+ gimple *else_assign = trailing_store_in_bb (else_bb, else_vdef, vphi,
+ !flag_expensive_optimizations);
if (!else_assign)
return false;
bool found, ok = false, res;
tree then_lhs, else_lhs;
basic_block blocks[3];
-
- /* Handle the case with single store in THEN_BB and ELSE_BB. That is
- cheap enough to always handle as it allows us to elide dependence
- checking. */
gphi *vphi = get_virtual_phi (join_bb);
if (!vphi)
return false;
- tree then_vdef = PHI_ARG_DEF_FROM_EDGE (vphi, single_succ_edge (then_bb));
- gimple *then_assign = single_trailing_store_in_bb (then_bb, then_vdef, vphi);
- if (then_assign)
- {
- tree else_vdef = PHI_ARG_DEF_FROM_EDGE (vphi, single_succ_edge (else_bb));
- gimple *else_assign = single_trailing_store_in_bb (else_bb, else_vdef,
- vphi);
- if (else_assign)
- return cond_if_else_store_replacement_1 (then_bb, else_bb, join_bb,
- then_assign, else_assign,
- vphi);
- }
+
+ /* Handle the case with trailing stores in THEN_BB and ELSE_BB. That is
+ cheap enough to always handle as it allows us to elide dependence
+ checking. */
+ while (cond_if_else_store_replacement_limited (then_bb, else_bb, join_bb))
+ ;
/* If either vectorization or if-conversion is disabled then do
not sink any stores. */
&& !predictable_edge_p (EDGE_SUCC (bb, 1)))
hoist_adjacent_loads (bb, bb1, bb2, bb3);
- /* Try to see if there are only one store in each side of the if
+ /* Try to see if there are only store in each side of the if
and try to remove that. */
if (EDGE_COUNT (bb3->preds) == 2)
- cond_if_else_store_replacement_limited (bb1, bb2, bb3);
+ while (cond_if_else_store_replacement_limited (bb1, bb2, bb3))
+ ;
}
gimple_stmt_iterator gsi;