#include "tree-eh.h"
#include "targhooks.h"
#include "domwalk.h"
+#include "tree-ssa-math-opts.h"
/* This structure represents one basic block that either computes a
division, or is a common dominator for basic block that compute a
/* Convert ARG0**N to a tree of multiplications of ARG0 with itself.
This function needs to be kept in sync with powi_cost above. */
-static tree
+tree
powi_as_mults (gimple_stmt_iterator *gsi, location_t loc,
tree arg0, HOST_WIDE_INT n)
{
tree target;
if (n == 0)
- return build_real (type, dconst1);
+ return build_one_cst (type);
- memset (cache, 0, sizeof (cache));
+ memset (cache, 0, sizeof (cache));
cache[1] = arg0;
result = powi_as_mults_1 (gsi, loc, type, (n < 0) ? -n : n, cache);
--- /dev/null
+/* Global, SSA-based optimizations using mathematical identities.
+ Copyright (C) 2021 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 COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_TREE_SSA_MATH_OPTS_H
+#define GCC_TREE_SSA_MATH_OPTS_H
+
+extern tree powi_as_mults (gimple_stmt_iterator *, location_t,
+ tree, HOST_WIDE_INT);
+
+#endif /* GCC_TREE_SSA_MATH_OPTS_H */
#include "gimplify.h"
#include "case-cfn-macros.h"
#include "tree-ssa-reassoc.h"
+#include "tree-ssa-math-opts.h"
/* This is a simple global reassociation pass. It is, in part, based
on the LLVM pass of the same name (They do some things more/less
gimple *mul_stmt, *pow_stmt;
/* Nothing to do if BUILT_IN_POWI doesn't exist for this type and
- target. */
- if (!powi_fndecl)
+ target, unless type is integral. */
+ if (!powi_fndecl && !INTEGRAL_TYPE_P (type))
return NULL_TREE;
/* Allocate the repeated factor vector. */
}
else
{
- iter_result = make_temp_ssa_name (type, NULL, "reassocpow");
- pow_stmt = gimple_build_call (powi_fndecl, 2, rf1->repr,
- build_int_cst (integer_type_node,
- power));
- gimple_call_set_lhs (pow_stmt, iter_result);
- gimple_set_location (pow_stmt, gimple_location (stmt));
- gimple_set_uid (pow_stmt, gimple_uid (stmt));
- gsi_insert_before (&gsi, pow_stmt, GSI_SAME_STMT);
+ if (INTEGRAL_TYPE_P (type))
+ {
+ gcc_assert (power > 1);
+ gimple_stmt_iterator gsip = gsi;
+ gsi_prev (&gsip);
+ iter_result = powi_as_mults (&gsi, gimple_location (stmt),
+ rf1->repr, power);
+ gimple_stmt_iterator gsic = gsi;
+ while (gsi_stmt (gsic) != gsi_stmt (gsip))
+ {
+ gimple_set_uid (gsi_stmt (gsic), gimple_uid (stmt));
+ gimple_set_visited (gsi_stmt (gsic), true);
+ gsi_prev (&gsic);
+ }
+ }
+ else
+ {
+ iter_result = make_temp_ssa_name (type, NULL, "reassocpow");
+ pow_stmt
+ = gimple_build_call (powi_fndecl, 2, rf1->repr,
+ build_int_cst (integer_type_node,
+ power));
+ gimple_call_set_lhs (pow_stmt, iter_result);
+ gimple_set_location (pow_stmt, gimple_location (stmt));
+ gimple_set_uid (pow_stmt, gimple_uid (stmt));
+ gsi_insert_before (&gsi, pow_stmt, GSI_SAME_STMT);
+ }
if (dump_file && (dump_flags & TDF_DETAILS))
{
/* Form a call to __builtin_powi for the maximum product
just formed, raised to the power obtained earlier. */
rf1 = &repeat_factor_vec[j];
- iter_result = make_temp_ssa_name (type, NULL, "reassocpow");
- pow_stmt = gimple_build_call (powi_fndecl, 2, rf1->repr,
- build_int_cst (integer_type_node,
- power));
- gimple_call_set_lhs (pow_stmt, iter_result);
- gimple_set_location (pow_stmt, gimple_location (stmt));
- gimple_set_uid (pow_stmt, gimple_uid (stmt));
- gsi_insert_before (&gsi, pow_stmt, GSI_SAME_STMT);
+ if (INTEGRAL_TYPE_P (type))
+ {
+ gcc_assert (power > 1);
+ gimple_stmt_iterator gsip = gsi;
+ gsi_prev (&gsip);
+ iter_result = powi_as_mults (&gsi, gimple_location (stmt),
+ rf1->repr, power);
+ gimple_stmt_iterator gsic = gsi;
+ while (gsi_stmt (gsic) != gsi_stmt (gsip))
+ {
+ gimple_set_uid (gsi_stmt (gsic), gimple_uid (stmt));
+ gimple_set_visited (gsi_stmt (gsic), true);
+ gsi_prev (&gsic);
+ }
+ }
+ else
+ {
+ iter_result = make_temp_ssa_name (type, NULL, "reassocpow");
+ pow_stmt = gimple_build_call (powi_fndecl, 2, rf1->repr,
+ build_int_cst (integer_type_node,
+ power));
+ gimple_call_set_lhs (pow_stmt, iter_result);
+ gimple_set_location (pow_stmt, gimple_location (stmt));
+ gimple_set_uid (pow_stmt, gimple_uid (stmt));
+ gsi_insert_before (&gsi, pow_stmt, GSI_SAME_STMT);
+ }
}
/* If we previously formed at least one other builtin_powi call,
attempt_builtin_copysign (&ops);
if (reassoc_insert_powi_p
- && flag_unsafe_math_optimizations)
+ && (flag_unsafe_math_optimizations
+ || (INTEGRAL_TYPE_P (TREE_TYPE (lhs)))))
powi_result = attempt_builtin_powi (stmt, &ops);
}