--- /dev/null
+/* { dg-do compile { target sqrt_insn } } */
+/* { dg-options "-Ofast -fdump-tree-cplxlower1" } */
+/* { dg-add-options sqrt_insn } */
+
+
+double f(_Complex double a)
+{
+ a+= 1.0f;
+ return __builtin_cabs(a);
+}
+
+/* Check that cabs is expanded during complex lowering. */
+/* { dg-final { scan-tree-dump-not "__builtin_cabs " "cplxlower1" } } */
+/* { dg-final { scan-tree-dump "__builtin_sqrt " "cplxlower1" } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-cplxlower1" } */
+
+
+double f(_Complex double a)
+{
+ a+= 1.0f;
+ return __builtin_cabs(a);
+}
+
+/* Check that cabs is not expanded during complex lowering. */
+/* { dg-final { scan-tree-dump "__builtin_cabs " "cplxlower1" } } */
+/* { dg-final { scan-tree-dump-not "__builtin_sqrt " "cplxlower1" } } */
--- /dev/null
+! { dg-do compile }
+! { dg-additional-options "-Ofast" }
+! { dg-require-effective-target vect_float }
+! { dg-require-effective-target vect_call_sqrtf }
+
+! { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } }
+! CABS expansion should allow for the vectorization to happen.
+
+subroutine foo(a,b,n)
+ complex(kind(1.0))::a(*)
+ real(kind(1.0))::b(*)
+ integer::i,n
+
+ do i=1,n
+ b(i)=abs(a(i))**2
+ end do
+
+end subroutine foo
#include "system.h"
#include "coretypes.h"
#include "backend.h"
+#include "target.h"
#include "rtl.h"
#include "tree.h"
#include "gimple.h"
#include "cfganal.h"
#include "gimple-fold.h"
#include "diagnostic-core.h"
-
+#include "case-cfn-macros.h"
+#include "builtins.h"
+#include "optabs-tree.h"
/* For each complex ssa name, a lattice value. We're interested in finding
out whether a complex number is degenerate in some way, having only real
{
case GIMPLE_CALL:
if (gimple_call_lhs (stmt))
- sim_again_p = is_complex_reg (gimple_call_lhs (stmt));
+ {
+ sim_again_p = is_complex_reg (gimple_call_lhs (stmt));
+ switch (gimple_call_combined_fn (stmt))
+ {
+ CASE_CFN_CABS:
+ /* Expand cabs only if unsafe math and optimizing. */
+ if (optimize && flag_unsafe_math_optimizations)
+ saw_a_complex_op = true;
+ break;
+ default:;
+ }
+ }
break;
case GIMPLE_ASSIGN:
}
}
+
+/* ARG is the argument to a cabs builtin call in GSI with location info
+ LOC. Create a sequence of statements prior to GSI that calculates
+ sqrt(R*R + I*I), where R and I are the real and imaginary components
+ of ARG, respectively. */
+
+static void
+gimple_expand_builtin_cabs (gimple_stmt_iterator *gsi, gimple *old_stmt)
+{
+ tree real_part, imag_part, addend1, addend2, sum;
+ tree arg = gimple_call_arg (old_stmt, 0);
+ tree type = TREE_TYPE (TREE_TYPE (arg));
+ tree sqrtfn = mathfn_built_in (type, BUILT_IN_SQRT);
+ machine_mode mode = TYPE_MODE (type);
+ gimple *new_stmt;
+
+ if (!flag_unsafe_math_optimizations
+ || !optimize_bb_for_speed_p (gimple_bb (old_stmt))
+ || !sqrtfn
+ || optab_handler (sqrt_optab, mode) == CODE_FOR_nothing)
+ return;
+
+ real_part = extract_component (gsi, arg, false, true);
+ imag_part = extract_component (gsi, arg, true, true);
+ location_t loc = gimple_location (old_stmt);
+
+ gimple_seq stmts = NULL;
+ addend1 = gimple_build (&stmts, loc, MULT_EXPR, type, real_part, real_part);
+ addend2 = gimple_build (&stmts, loc, MULT_EXPR, type, imag_part, imag_part);
+ sum = gimple_build (&stmts, loc, PLUS_EXPR, type, addend1, addend2);
+ gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+
+ /* Build the sqrt call. */
+ new_stmt = gimple_build_call (sqrtfn, 1, sum);
+ gimple_set_location (new_stmt, loc);
+ tree lhs = gimple_call_lhs (old_stmt);
+ gimple_call_set_lhs (new_stmt, lhs);
+ gsi_replace (gsi, new_stmt, true);
+}
+
/* Process one statement. If we identify a complex operation, expand it. */
static void
tree ac, ar, ai, bc, br, bi;
complex_lattice_t al, bl;
enum tree_code code;
+ if (gimple_code (stmt) == GIMPLE_CALL)
+ {
+ switch (gimple_call_combined_fn (stmt))
+ {
+ CASE_CFN_CABS:
+ gimple_expand_builtin_cabs (gsi, stmt);
+ return;
+ default:;
+ }
+ }
if (gimple_code (stmt) == GIMPLE_ASM)
{
return result;
}
-/* Build a gimple reference operation with the given CODE and argument
- ARG, assigning the result to a new SSA name of TYPE with NAME.
- Insert the statement prior to GSI's current position, and return
- the fresh SSA name. */
-
-static inline tree
-build_and_insert_ref (gimple_stmt_iterator *gsi, location_t loc, tree type,
- const char *name, enum tree_code code, tree arg0)
-{
- tree result = make_temp_ssa_name (type, NULL, name);
- gimple *stmt = gimple_build_assign (result, build1 (code, type, arg0));
- gimple_set_location (stmt, loc);
- gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
- return result;
-}
-
/* Build a gimple assignment to cast VAL to TYPE. Insert the statement
prior to GSI's current position, and return the fresh SSA name. */
return NULL_TREE;
}
-/* ARG is the argument to a cabs builtin call in GSI with location info
- LOC. Create a sequence of statements prior to GSI that calculates
- sqrt(R*R + I*I), where R and I are the real and imaginary components
- of ARG, respectively. Return an expression holding the result. */
-
-static tree
-gimple_expand_builtin_cabs (gimple_stmt_iterator *gsi, location_t loc, tree arg)
-{
- tree real_part, imag_part, addend1, addend2, sum, result;
- tree type = TREE_TYPE (TREE_TYPE (arg));
- tree sqrtfn = mathfn_built_in (type, BUILT_IN_SQRT);
- machine_mode mode = TYPE_MODE (type);
-
- if (!flag_unsafe_math_optimizations
- || !optimize_bb_for_speed_p (gimple_bb (gsi_stmt (*gsi)))
- || !sqrtfn
- || optab_handler (sqrt_optab, mode) == CODE_FOR_nothing)
- return NULL_TREE;
-
- real_part = build_and_insert_ref (gsi, loc, type, "cabs",
- REALPART_EXPR, arg);
- addend1 = build_and_insert_binop (gsi, loc, "cabs", MULT_EXPR,
- real_part, real_part);
- imag_part = build_and_insert_ref (gsi, loc, type, "cabs",
- IMAGPART_EXPR, arg);
- addend2 = build_and_insert_binop (gsi, loc, "cabs", MULT_EXPR,
- imag_part, imag_part);
- sum = build_and_insert_binop (gsi, loc, "cabs", PLUS_EXPR, addend1, addend2);
- result = build_and_insert_call (gsi, loc, sqrtfn, sum);
-
- return result;
-}
-
/* Go through all calls to sin, cos and cexpi and call execute_cse_sincos_1
on the SSA_NAME argument of each of them. */
}
/* Expand powi(x,n) into an optimal number of multiplies, when n is a constant.
- Also expand CABS. */
+ Note the name is powcabs but cabs expansion was moved to the lower complex
+ pass. */
namespace {
const pass_data pass_data_expand_powcabs =
}
break;
- CASE_CFN_CABS:
- arg0 = gimple_call_arg (stmt, 0);
- loc = gimple_location (stmt);
- result = gimple_expand_builtin_cabs (&gsi, loc, arg0);
-
- if (result)
- {
- tree lhs = gimple_get_lhs (stmt);
- gassign *new_stmt = gimple_build_assign (lhs, result);
- gimple_set_location (new_stmt, loc);
- unlink_stmt_vdef (stmt);
- gsi_replace (&gsi, new_stmt, true);
- cleanup_eh = true;
- if (gimple_vdef (stmt))
- release_ssa_name (gimple_vdef (stmt));
- }
- break;
-
default:;
}
}