tree-complex.c (expand_complex_libcall): New.

* tree-complex.c (expand_complex_libcall): New.
        (expand_complex_multiplication): Use it for c99 compliance.
        (expand_complex_division): Likewise.
        * fold-const.c (fold_complex_add, fold_complex_mult): New.
        (fold): Call them.
        * builtins.c (built_in_names): Remove const.
        * tree.c (build_common_builtin_nodes): Build complex arithmetic
        builtins.
        * tree.h (BUILT_IN_COMPLEX_MUL_MIN, BUILT_IN_COMPLEX_MUL_MAX): New.
        (BUILT_IN_COMPLEX_DIV_MIN, BUILT_IN_COMPLEX_DIV_MAX): New.
        (built_in_names): Remove const.
        * c-common.c (c_common_type_for_mode): Handle complex modes.
        * flags.h, toplev.c (flag_complex_method): Rename from
        flag_complex_divide_method.
        * libgcc2.c (__divsc3, __divdc3, __divxc3, __divtc3,
        __mulsc3, __muldc3, __mulxc3, __multc3): New.
        * libgcc2.h: Declare them.
        * libgcc-std.ver: Export them.
        * mklibgcc.in (lib2funcs): Build them.

From-SVN: r94909
This commit is contained in:
Richard Henderson 2005-02-11 16:26:57 -08:00 committed by Richard Henderson
parent 17e1f1a36f
commit 7e7e470f9b
13 changed files with 568 additions and 12 deletions

View File

@ -1,3 +1,25 @@
2005-02-11 Richard Henderson <rth@redhat.com>
* tree-complex.c (expand_complex_libcall): New.
(expand_complex_multiplication): Use it for c99 compliance.
(expand_complex_division): Likewise.
* fold-const.c (fold_complex_add, fold_complex_mult): New.
(fold): Call them.
* builtins.c (built_in_names): Remove const.
* tree.c (build_common_builtin_nodes): Build complex arithmetic
builtins.
* tree.h (BUILT_IN_COMPLEX_MUL_MIN, BUILT_IN_COMPLEX_MUL_MAX): New.
(BUILT_IN_COMPLEX_DIV_MIN, BUILT_IN_COMPLEX_DIV_MAX): New.
(built_in_names): Remove const.
* c-common.c (c_common_type_for_mode): Handle complex modes.
* flags.h, toplev.c (flag_complex_method): Rename from
flag_complex_divide_method.
* libgcc2.c (__divsc3, __divdc3, __divxc3, __divtc3,
__mulsc3, __muldc3, __mulxc3, __multc3): New.
* libgcc2.h: Declare them.
* libgcc-std.ver: Export them.
* mklibgcc.in (lib2funcs): Build them.
2005-02-11 Steven Bosscher <stevenb@suse.de>
PR tree-optimization/19876

View File

@ -60,7 +60,7 @@ const char *const built_in_class_names[4]
= {"NOT_BUILT_IN", "BUILT_IN_FRONTEND", "BUILT_IN_MD", "BUILT_IN_NORMAL"};
#define DEF_BUILTIN(X, N, C, T, LT, B, F, NA, AT, IM, COND) #X,
const char *const built_in_names[(int) END_BUILTINS] =
const char * built_in_names[(int) END_BUILTINS] =
{
#include "builtins.def"
};

View File

@ -1611,7 +1611,27 @@ c_common_type_for_mode (enum machine_mode mode, int unsignedp)
if (mode == TYPE_MODE (build_pointer_type (integer_type_node)))
return unsignedp ? make_unsigned_type (mode) : make_signed_type (mode);
if (VECTOR_MODE_P (mode))
if (COMPLEX_MODE_P (mode))
{
enum machine_mode inner_mode;
tree inner_type;
if (mode == TYPE_MODE (complex_float_type_node))
return complex_float_type_node;
if (mode == TYPE_MODE (complex_double_type_node))
return complex_double_type_node;
if (mode == TYPE_MODE (complex_long_double_type_node))
return complex_long_double_type_node;
if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp)
return complex_integer_type_node;
inner_mode = GET_MODE_INNER (mode);
inner_type = c_common_type_for_mode (inner_mode, unsignedp);
if (inner_type != NULL_TREE)
return build_complex_type (inner_type);
}
else if (VECTOR_MODE_P (mode))
{
enum machine_mode inner_mode = GET_MODE_INNER (mode);
tree inner_type = c_common_type_for_mode (inner_mode, unsignedp);

View File

@ -145,9 +145,9 @@ extern int flag_pcc_struct_return;
/* 0 means straightforward implementation of complex divide acceptable.
1 means wide ranges of inputs must work for complex divide.
2 means C99-like requirements for complex divide (not yet implemented). */
2 means C99-like requirements for complex multiply and divide. */
extern int flag_complex_divide_method;
extern int flag_complex_method;
/* Nonzero means that we don't want inlining by virtue of -fno-inline,
not just because the tree inliner turned us off. */

View File

@ -6306,6 +6306,168 @@ fold_to_nonsharp_ineq_using_bound (tree ineq, tree bound)
return fold (build2 (GE_EXPR, type, a, y));
}
/* Fold complex addition when both components are accessible by parts.
Return non-null if successful. CODE should be PLUS_EXPR for addition,
or MINUS_EXPR for subtraction. */
static tree
fold_complex_add (tree type, tree ac, tree bc, enum tree_code code)
{
tree ar, ai, br, bi, rr, ri, inner_type;
if (TREE_CODE (ac) == COMPLEX_EXPR)
ar = TREE_OPERAND (ac, 0), ai = TREE_OPERAND (ac, 1);
else if (TREE_CODE (ac) == COMPLEX_CST)
ar = TREE_REALPART (ac), ai = TREE_IMAGPART (ac);
else
return NULL;
if (TREE_CODE (bc) == COMPLEX_EXPR)
br = TREE_OPERAND (bc, 0), bi = TREE_OPERAND (bc, 1);
else if (TREE_CODE (bc) == COMPLEX_CST)
br = TREE_REALPART (bc), bi = TREE_IMAGPART (bc);
else
return NULL;
inner_type = TREE_TYPE (type);
rr = fold (build2 (code, inner_type, ar, br));
ri = fold (build2 (code, inner_type, ai, bi));
return fold (build2 (COMPLEX_EXPR, type, rr, ri));
}
/* Perform some simplifications of complex multiplication when one or more
of the components are constants or zeros. Return non-null if successful. */
static tree
fold_complex_mult (tree type, tree ac, tree bc)
{
tree ar, ai, br, bi, rr, ri, inner_type, zero;
bool ar0, ai0, br0, bi0, bi1;
if (TREE_CODE (ac) == COMPLEX_EXPR)
ar = TREE_OPERAND (ac, 0), ai = TREE_OPERAND (ac, 1);
else if (TREE_CODE (ac) == COMPLEX_CST)
ar = TREE_REALPART (ac), ai = TREE_IMAGPART (ac);
else
return NULL;
if (TREE_CODE (bc) == COMPLEX_EXPR)
br = TREE_OPERAND (bc, 0), bi = TREE_OPERAND (bc, 1);
else if (TREE_CODE (bc) == COMPLEX_CST)
br = TREE_REALPART (bc), bi = TREE_IMAGPART (bc);
else
return NULL;
inner_type = TREE_TYPE (type);
zero = NULL;
if (SCALAR_FLOAT_TYPE_P (inner_type))
{
ar0 = ai0 = br0 = bi0 = bi1 = false;
/* We're only interested in +0.0 here, thus we don't use real_zerop. */
if (TREE_CODE (ar) == REAL_CST
&& REAL_VALUES_IDENTICAL (TREE_REAL_CST (ar), dconst0))
ar0 = true, zero = ar;
if (TREE_CODE (ai) == REAL_CST
&& REAL_VALUES_IDENTICAL (TREE_REAL_CST (ai), dconst0))
ai0 = true, zero = ai;
if (TREE_CODE (br) == REAL_CST
&& REAL_VALUES_IDENTICAL (TREE_REAL_CST (br), dconst0))
br0 = true, zero = br;
if (TREE_CODE (bi) == REAL_CST)
{
if (REAL_VALUES_IDENTICAL (TREE_REAL_CST (bi), dconst0))
bi0 = true, zero = bi;
else if (REAL_VALUES_IDENTICAL (TREE_REAL_CST (bi), dconst1))
bi1 = true;
}
}
else
{
ar0 = integer_zerop (ar);
if (ar0)
zero = ar;
ai0 = integer_zerop (ai);
if (ai0)
zero = ai;
br0 = integer_zerop (br);
if (br0)
zero = br;
bi0 = integer_zerop (bi);
if (bi0)
{
zero = bi;
bi1 = false;
}
else
bi1 = integer_onep (bi);
}
/* We won't optimize anything below unless something is zero. */
if (zero == NULL)
return NULL;
if (ai0 && br0 && bi1)
{
rr = zero;
ri = ar;
}
else if (ai0 && bi0)
{
rr = fold (build2 (MULT_EXPR, inner_type, ar, br));
ri = zero;
}
else if (ai0 && br0)
{
rr = zero;
ri = fold (build2 (MULT_EXPR, inner_type, ar, bi));
}
else if (ar0 && bi0)
{
rr = zero;
ri = fold (build2 (MULT_EXPR, inner_type, ai, br));
}
else if (ar0 && br0)
{
rr = fold (build2 (MULT_EXPR, inner_type, ai, br));
rr = fold (build1 (NEGATE_EXPR, inner_type, rr));
ri = zero;
}
else if (bi0)
{
rr = fold (build2 (MULT_EXPR, inner_type, ar, br));
ri = fold (build2 (MULT_EXPR, inner_type, ai, br));
}
else if (ai0)
{
rr = fold (build2 (MULT_EXPR, inner_type, ar, br));
ri = fold (build2 (MULT_EXPR, inner_type, ar, bi));
}
else if (br0)
{
rr = fold (build2 (MULT_EXPR, inner_type, ai, bi));
rr = fold (build1 (NEGATE_EXPR, inner_type, rr));
ri = fold (build2 (MULT_EXPR, inner_type, ar, bi));
}
else if (ar0)
{
rr = fold (build2 (MULT_EXPR, inner_type, ai, bi));
rr = fold (build1 (NEGATE_EXPR, inner_type, rr));
ri = fold (build2 (MULT_EXPR, inner_type, ai, br));
}
else
return NULL;
return fold (build2 (COMPLEX_EXPR, type, rr, ri));
}
/* Perform constant folding and related simplification of EXPR.
The related simplifications include x*1 => x, x*0 => 0, etc.,
and application of the associative law.
@ -6833,6 +6995,14 @@ fold (tree expr)
if (TREE_CODE (arg0) == NEGATE_EXPR
&& reorder_operands_p (TREE_OPERAND (arg0, 0), arg1))
return fold (build2 (MINUS_EXPR, type, arg1, TREE_OPERAND (arg0, 0)));
if (TREE_CODE (type) == COMPLEX_TYPE)
{
tem = fold_complex_add (type, arg0, arg1, PLUS_EXPR);
if (tem)
return tem;
}
if (! FLOAT_TYPE_P (type))
{
if (integer_zerop (arg1))
@ -7264,6 +7434,13 @@ fold (tree expr)
return fold (build2 (MINUS_EXPR, type, negate_expr (arg1),
TREE_OPERAND (arg0, 0)));
if (TREE_CODE (type) == COMPLEX_TYPE)
{
tem = fold_complex_add (type, arg0, arg1, MINUS_EXPR);
if (tem)
return tem;
}
if (! FLOAT_TYPE_P (type))
{
if (! wins && integer_zerop (arg0))
@ -7392,6 +7569,13 @@ fold (tree expr)
negate_expr (arg0),
TREE_OPERAND (arg1, 0)));
if (TREE_CODE (type) == COMPLEX_TYPE)
{
tem = fold_complex_mult (type, arg0, arg1);
if (tem)
return tem;
}
if (! FLOAT_TYPE_P (type))
{
if (integer_zerop (arg1))

View File

@ -241,4 +241,14 @@ GCC_4.0.0 {
__powidf2
__powixf2
__powitf2
}
# c99 compliant complex arithmetic
__divsc3
__divdc3
__divxc3
__divtc3
__mulsc3
__muldc3
__mulxc3
__multc3
}

View File

@ -1501,6 +1501,208 @@ NAME (TYPE x, Wtype m)
#endif
#if defined(L_mulsc3) || defined(L_divsc3) \
|| defined(L_muldc3) || defined(L_divdc3) \
|| (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 80 \
&& (defined(L_mulxc3) || defined(L_divxc3))) \
|| (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128 \
&& (defined(L_multc3) || defined(L_divtc3)))
#undef float
#undef double
#undef long
#if defined(L_mulsc3) || defined(L_divsc3)
# define MTYPE SFtype
# define CTYPE SCtype
# define MODE sc
# define CEXT f
# define NOTRUNC __FLT_EVAL_METHOD__ == 0
#elif defined(L_muldc3) || defined(L_divdc3)
# define MTYPE DFtype
# define CTYPE DCtype
# define MODE dc
# if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 64
# define CEXT l
# define NOTRUNC 1
# else
# define CEXT
# define NOTRUNC __FLT_EVAL_METHOD__ == 0 || __FLT_EVAL_METHOD__ == 1
# endif
#elif defined(L_mulxc3) || defined(L_divxc3)
# define MTYPE XFtype
# define CTYPE XCtype
# define MODE xc
# define CEXT l
# define NOTRUNC 1
#elif defined(L_multc3) || defined(L_divtc3)
# define MTYPE TFtype
# define CTYPE TCtype
# define MODE tc
# define CEXT l
# define NOTRUNC 1
#else
# error
#endif
#define CONCAT3(A,B,C) _CONCAT3(A,B,C)
#define _CONCAT3(A,B,C) A##B##C
#define CONCAT2(A,B) _CONCAT2(A,B)
#define _CONCAT2(A,B) A##B
/* All of these would be present in a full C99 implementation of <math.h>
and <complex.h>. Our problem is that only a few systems have such full
implementations. Further, libgcc_s.so isn't currenly linked against
libm.so, and even for systems that do provide full C99, the extra overhead
of all programs using libgcc having to link against libm. So avoid it. */
#define isnan(x) __builtin_expect ((x) != (x), 0)
#define isfinite(x) __builtin_expect (!isnan((x) - (x)), 1)
#define isinf(x) __builtin_expect (!isnan(x) & !isfinite(x), 0)
#define INFINITY CONCAT2(__builtin_inf, CEXT) ()
#define I 1i
/* Helpers to make the following code slightly less gross. */
#define COPYSIGN CONCAT2(__builtin_copysign, CEXT)
#define FABS CONCAT2(__builtin_fabs, CEXT)
/* Verify that MTYPE matches up with CEXT. */
extern void *compile_type_assert[sizeof(INFINITY) == sizeof(MTYPE) ? 1 : -1];
/* Ensure that we've lost any extra precision. */
#if NOTRUNC
# define TRUNC(x)
#else
# define TRUNC(x) __asm__ ("" : "=m"(x) : "m"(x))
#endif
#if defined(L_mulsc3) || defined(L_muldc3) \
|| defined(L_mulxc3) || defined(L_multc3)
CTYPE
CONCAT3(__mul,MODE,3) (MTYPE a, MTYPE b, MTYPE c, MTYPE d)
{
MTYPE ac, bd, ad, bc, x, y;
ac = a * c;
bd = b * d;
ad = a * d;
bc = b * c;
TRUNC (ac);
TRUNC (bd);
TRUNC (ad);
TRUNC (bc);
x = ac - bd;
y = ad + bc;
if (isnan (x) && isnan (y))
{
/* Recover infinities that computed as NaN + iNaN. */
_Bool recalc = 0;
if (isinf (a) || isinf (b))
{
/* z is infinite. "Box" the infinity and change NaNs in
the other factor to 0. */
a = COPYSIGN (isinf (a) ? 1 : 0, a);
b = COPYSIGN (isinf (b) ? 1 : 0, b);
if (isnan (c)) c = COPYSIGN (0, c);
if (isnan (d)) d = COPYSIGN (0, d);
recalc = 1;
}
if (isinf (c) || isinf (d))
{
/* w is infinite. "Box" the infinity and change NaNs in
the other factor to 0. */
c = COPYSIGN (isinf (c) ? 1 : 0, c);
d = COPYSIGN (isinf (d) ? 1 : 0, d);
if (isnan (a)) a = COPYSIGN (0, a);
if (isnan (b)) b = COPYSIGN (0, b);
recalc = 1;
}
if (!recalc
&& (isinf (ac) || isinf (bd)
|| isinf (ad) || isinf (bc)))
{
/* Recover infinities from overflow by changing NaNs to 0. */
if (isnan (a)) a = COPYSIGN (0, a);
if (isnan (b)) b = COPYSIGN (0, b);
if (isnan (c)) c = COPYSIGN (0, c);
if (isnan (d)) d = COPYSIGN (0, d);
recalc = 1;
}
if (recalc)
{
x = INFINITY * (a * c - b * d);
y = INFINITY * (a * d + b * c);
}
}
return x + I * y;
}
#endif /* complex multiply */
#if defined(L_divsc3) || defined(L_divdc3) \
|| defined(L_divxc3) || defined(L_divtc3)
CTYPE
CONCAT3(__div,MODE,3) (MTYPE a, MTYPE b, MTYPE c, MTYPE d)
{
MTYPE denom, ratio, x, y;
/* ??? We can get better behaviour from logrithmic scaling instead of
the division. But that would mean starting to link libgcc against
libm. We could implement something akin to ldexp/frexp as gcc builtins
fairly easily... */
if (FABS (c) < FABS (d))
{
ratio = c / d;
denom = (c * ratio) + d;
x = ((a * ratio) + b) / denom;
y = ((b * ratio) - a) / denom;
}
else
{
ratio = d / c;
denom = (d * ratio) + c;
x = ((b * ratio) + a) / denom;
y = (b - (a * ratio)) / denom;
}
/* Recover infinities and zeros that computed as NaN+iNaN; the only cases
are non-zero/zero, infinite/finite, and finite/infinite. */
if (isnan (x) && isnan (y))
{
if (denom == 0.0 && (!isnan (a) || !isnan (b)))
{
x = COPYSIGN (INFINITY, c) * a;
y = COPYSIGN (INFINITY, c) * b;
}
else if ((isinf (a) || isinf (b)) && isfinite (c) && isfinite (d))
{
a = COPYSIGN (isinf (a) ? 1 : 0, a);
b = COPYSIGN (isinf (b) ? 1 : 0, b);
x = INFINITY * (a * c + b * d);
y = INFINITY * (b * c - a * d);
}
else if ((isinf (c) || isinf (d)) && isfinite (a) && isfinite (b))
{
c = COPYSIGN (isinf (c) ? 1 : 0, c);
d = COPYSIGN (isinf (d) ? 1 : 0, d);
x = 0.0 * (a * c + b * d);
y = 0.0 * (b * c - a * d);
}
}
return x + I * y;
}
#endif /* complex divide */
#endif /* all complex float routines */
/* From here on down, the routines use normal data types. */
#define SItype bogus_type
@ -1772,4 +1974,3 @@ func_ptr __DTOR_LIST__[2];
#endif
#endif /* no INIT_SECTION_ASM_OP and not CTOR_LISTS_DEFINED_EXTERNALLY */
#endif /* L_ctors */

View File

@ -92,12 +92,16 @@ typedef unsigned int UTItype __attribute__ ((mode (TI)));
typedef float SFtype __attribute__ ((mode (SF)));
typedef float DFtype __attribute__ ((mode (DF)));
typedef _Complex float SCtype __attribute__ ((mode (SC)));
typedef _Complex float DCtype __attribute__ ((mode (DC)));
#if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 80
typedef float XFtype __attribute__ ((mode (XF)));
typedef _Complex float XCtype __attribute__ ((mode (XC)));
#endif
#if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128
typedef float TFtype __attribute__ ((mode (TF)));
typedef _Complex float TCtype __attribute__ ((mode (TC)));
#endif
#else /* BITS_PER_UNIT != 8 */
@ -308,12 +312,19 @@ extern DWtype __fixunssfDI (SFtype);
extern SFtype __powisf2 (SFtype, Wtype);
extern DFtype __powidf2 (DFtype, Wtype);
extern SCtype __divsc3 (SFtype, SFtype, SFtype, SFtype);
extern SCtype __mulsc3 (SFtype, SFtype, SFtype, SFtype);
extern DCtype __divdc3 (DFtype, DFtype, DFtype, DFtype);
extern DCtype __muldc3 (DFtype, DFtype, DFtype, DFtype);
#if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 80
extern DWtype __fixxfdi (XFtype);
extern DWtype __fixunsxfDI (XFtype);
extern XFtype __floatdixf (DWtype);
extern UWtype __fixunsxfSI (XFtype);
extern XFtype __powixf2 (XFtype, Wtype);
extern XCtype __divxc3 (XFtype, XFtype, XFtype, XFtype);
extern XCtype __mulxc3 (XFtype, XFtype, XFtype, XFtype);
#endif
#if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128
@ -321,6 +332,8 @@ extern DWtype __fixunstfDI (TFtype);
extern DWtype __fixtfdi (TFtype);
extern TFtype __floatditf (DWtype);
extern TFtype __powitf2 (TFtype, Wtype);
extern TCtype __divtc3 (TFtype, TFtype, TFtype, TFtype);
extern TCtype __multc3 (TFtype, TFtype, TFtype, TFtype);
#endif
#endif /* BITS_PER_UNIT == 8 */

View File

@ -62,7 +62,8 @@ lib2funcs='_muldi3 _negdi2 _lshrdi3 _ashldi3 _ashrdi3
_addvdi3 _subvsi3 _subvdi3 _mulvsi3 _mulvdi3 _negvsi2 _negvdi2 _ctors
_ffssi2 _ffsdi2 _clz _clzsi2 _clzdi2 _ctzsi2 _ctzdi2 _popcount_tab
_popcountsi2 _popcountdi2 _paritysi2 _paritydi2 _powisf2 _powidf2
_powixf2 _powitf2'
_powixf2 _powitf2 _mulsc3 _muldc3 _mulxc3 _multc3 _divsc3 _divdc3
_divxc3 _divtc3'
# Disable SHLIB_LINK if shared libgcc not enabled.
if [ "@enable_shared@" = "no" ]; then

View File

@ -267,9 +267,9 @@ int flag_pcc_struct_return = DEFAULT_PCC_STRUCT_RETURN;
/* 0 means straightforward implementation of complex divide acceptable.
1 means wide ranges of inputs must work for complex divide.
2 means C99-like requirements for complex divide (not yet implemented). */
2 means C99-like requirements for complex multiply and divide. */
int flag_complex_divide_method = 0;
int flag_complex_method = 0;
/* Nonzero means that we don't want inlining by virtue of -fno-inline,
not just because the tree inliner turned us off. */

View File

@ -105,6 +105,40 @@ expand_complex_addition (block_stmt_iterator *bsi, tree inner_type,
update_complex_assignment (bsi, rr, ri);
}
/* Expand a complex multiplication or division to a libcall to the c99
compliant routines. */
static void
expand_complex_libcall (block_stmt_iterator *bsi, tree ar, tree ai,
tree br, tree bi, enum tree_code code)
{
enum machine_mode mode;
enum built_in_function bcode;
tree args, fn, stmt, type;
args = tree_cons (NULL, bi, NULL);
args = tree_cons (NULL, br, args);
args = tree_cons (NULL, ai, args);
args = tree_cons (NULL, ar, args);
stmt = bsi_stmt (*bsi);
type = TREE_TYPE (TREE_OPERAND (stmt, 1));
mode = TYPE_MODE (type);
gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
if (code == MULT_EXPR)
bcode = BUILT_IN_COMPLEX_MUL_MIN + mode - MIN_MODE_COMPLEX_FLOAT;
else if (code == RDIV_EXPR)
bcode = BUILT_IN_COMPLEX_DIV_MIN + mode - MIN_MODE_COMPLEX_FLOAT;
else
gcc_unreachable ();
fn = built_in_decls[bcode];
TREE_OPERAND (stmt, 1)
= build3 (CALL_EXPR, type, build_fold_addr_expr (fn), args, NULL);
modify_stmt (stmt);
}
/* Expand complex multiplication to scalars:
a * b = (ar*br - ai*bi) + i(ar*bi + br*ai)
*/
@ -115,6 +149,12 @@ expand_complex_multiplication (block_stmt_iterator *bsi, tree inner_type,
{
tree t1, t2, t3, t4, rr, ri;
if (flag_complex_method == 2 && SCALAR_FLOAT_TYPE_P (inner_type))
{
expand_complex_libcall (bsi, ar, ai, br, bi, MULT_EXPR);
return;
}
t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ar, br);
t2 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ai, bi);
t3 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ar, bi);
@ -311,18 +351,27 @@ expand_complex_division (block_stmt_iterator *bsi, tree inner_type,
tree ar, tree ai, tree br, tree bi,
enum tree_code code)
{
switch (flag_complex_divide_method)
switch (flag_complex_method)
{
case 0:
/* straightforward implementation of complex divide acceptable. */
expand_complex_div_straight (bsi, inner_type, ar, ai, br, bi, code);
break;
case 2:
if (SCALAR_FLOAT_TYPE_P (inner_type))
{
expand_complex_libcall (bsi, ar, ai, br, bi, code);
return;
}
/* FALLTHRU */
case 1:
/* wide ranges of inputs must work for complex divide. */
expand_complex_div_wide (bsi, inner_type, ar, ai, br, bi, code);
break;
default:
/* C99-like requirements for complex divide (not yet implemented). */
gcc_unreachable ();
}
}

View File

@ -5903,6 +5903,48 @@ build_common_builtin_nodes (void)
BUILT_IN_PROFILE_FUNC_ENTER, "profile_func_enter", 0);
local_define_builtin ("__builtin_profile_func_exit", ftype,
BUILT_IN_PROFILE_FUNC_EXIT, "profile_func_exit", 0);
/* Complex multiplication and division. These are handled as builtins
rather than optabs because emit_library_call_value doesn't support
complex. Further, we can do slightly better with folding these
beasties if the real and complex parts of the arguments are separate. */
{
enum machine_mode mode;
for (mode = MIN_MODE_COMPLEX_FLOAT; mode <= MAX_MODE_COMPLEX_FLOAT; ++mode)
{
char mode_name_buf[4], *q;
const char *p;
enum built_in_function mcode, dcode;
tree type, inner_type;
type = lang_hooks.types.type_for_mode (mode, 0);
if (type == NULL)
continue;
inner_type = TREE_TYPE (type);
tmp = tree_cons (NULL_TREE, inner_type, void_list_node);
tmp = tree_cons (NULL_TREE, inner_type, tmp);
tmp = tree_cons (NULL_TREE, inner_type, tmp);
tmp = tree_cons (NULL_TREE, inner_type, tmp);
ftype = build_function_type (type, tmp);
mcode = BUILT_IN_COMPLEX_MUL_MIN + mode - MIN_MODE_COMPLEX_FLOAT;
dcode = BUILT_IN_COMPLEX_DIV_MIN + mode - MIN_MODE_COMPLEX_FLOAT;
for (p = GET_MODE_NAME (mode), q = mode_name_buf; *p; p++, q++)
*q = TOLOWER (*p);
*q = '\0';
built_in_names[mcode] = concat ("__mul", mode_name_buf, "3", NULL);
local_define_builtin (built_in_names[mcode], ftype, mcode,
built_in_names[mcode], ECF_CONST | ECF_NOTHROW);
built_in_names[dcode] = concat ("__div", mode_name_buf, "3", NULL);
local_define_builtin (built_in_names[dcode], ftype, dcode,
built_in_names[dcode], ECF_CONST | ECF_NOTHROW);
}
}
}
/* HACK. GROSS. This is absolutely disgusting. I wish there was a

View File

@ -187,13 +187,27 @@ enum built_in_function
{
#include "builtins.def"
/* Complex division routines in libgcc. These are done via builtins
because emit_library_call_value can't handle complex values. */
BUILT_IN_COMPLEX_MUL_MIN,
BUILT_IN_COMPLEX_MUL_MAX
= BUILT_IN_COMPLEX_MUL_MIN
+ MAX_MODE_COMPLEX_FLOAT
- MIN_MODE_COMPLEX_FLOAT,
BUILT_IN_COMPLEX_DIV_MIN,
BUILT_IN_COMPLEX_DIV_MAX
= BUILT_IN_COMPLEX_DIV_MIN
+ MAX_MODE_COMPLEX_FLOAT
- MIN_MODE_COMPLEX_FLOAT,
/* Upper bound on non-language-specific builtins. */
END_BUILTINS
};
#undef DEF_BUILTIN
/* Names for the above. */
extern const char *const built_in_names[(int) END_BUILTINS];
extern const char * built_in_names[(int) END_BUILTINS];
/* Helper macros for math builtins. */