diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 90c826f5a05..cc300099d60 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2007-01-30 Uros Bizjak + + * builtins.c (expand_builtin_int_interclass_roundingfn): New function + to handle optabs that operate on floating point input argument and + output to integer output. + (expand_builtin_mathfn) [BUILT_IN_ILOGB]: Move from here ... + (expand_builtin_interclass_mathfn) [BUILT_IN_ILOGB]: ... to here. + (expand_builtin): Expand BUILT_IN_ILOGB{,F,L} using + expand_builtin_interclass_mathfn (). + * config/i386/i386.md (fxtractxf3_i387): Rename from *fxtractxf3_i387. + (ilogbsi2): Remove. + (ilogbxf2, ilogb2): New expanders to implement ilogb, ilogbf and + ilogbl built-in functions as x87 intrinsics. + 2007-01-30 Richard Guenther PR middle-end/27657 diff --git a/gcc/builtins.c b/gcc/builtins.c index a2f540a416f..5ba1eae5eb6 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -95,6 +95,7 @@ static void expand_errno_check (tree, rtx); static rtx expand_builtin_mathfn (tree, rtx, rtx); static rtx expand_builtin_mathfn_2 (tree, rtx, rtx); static rtx expand_builtin_mathfn_3 (tree, rtx, rtx); +static rtx expand_builtin_interclass_mathfn (tree, rtx, rtx); static rtx expand_builtin_sincos (tree); static rtx expand_builtin_cexpi (tree, rtx, rtx); static rtx expand_builtin_int_roundingfn (tree, rtx, rtx); @@ -1814,8 +1815,6 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget) errno_set = true; builtin_optab = expm1_optab; break; CASE_FLT_FN (BUILT_IN_LOGB): errno_set = true; builtin_optab = logb_optab; break; - CASE_FLT_FN (BUILT_IN_ILOGB): - errno_set = true; builtin_optab = ilogb_optab; break; CASE_FLT_FN (BUILT_IN_LOG): errno_set = true; builtin_optab = log_optab; break; CASE_FLT_FN (BUILT_IN_LOG10): @@ -2170,6 +2169,86 @@ expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget) return target; } +/* Expand a call to one of the builtin math functions that operate on + floating point argument and output an integer result (ilogb, isinf, + isnan, etc). + Return 0 if a normal call should be emitted rather than expanding the + function in-line. EXP is the expression that is a call to the builtin + function; if convenient, the result should be placed in TARGET. + SUBTARGET may be used as the target for computing one of EXP's operands. */ + +static rtx +expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget) +{ + optab builtin_optab; + enum insn_code icode; + rtx op0; + tree fndecl = get_callee_fndecl (exp); + tree arglist = TREE_OPERAND (exp, 1); + enum machine_mode mode; + bool errno_set = false; + tree arg, narg; + + if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) + return 0; + + arg = TREE_VALUE (arglist); + + switch (DECL_FUNCTION_CODE (fndecl)) + { + CASE_FLT_FN (BUILT_IN_ILOGB): + errno_set = true; builtin_optab = ilogb_optab; break; + default: + gcc_unreachable (); + } + + /* There's no easy way to detect the case we need to set EDOM. */ + if (flag_errno_math && errno_set) + return NULL_RTX; + + /* Optab mode depends on the mode of the input argument. */ + mode = TYPE_MODE (TREE_TYPE (arg)); + + icode = builtin_optab->handlers[(int) mode].insn_code; + + /* Before working hard, check whether the instruction is available. */ + if (icode != CODE_FOR_nothing) + { + /* Make a suitable register to place result in. */ + if (!target + || GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp))) + target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp))); + + gcc_assert (insn_data[icode].operand[0].predicate + (target, GET_MODE (target))); + + /* Wrap the computation of the argument in a SAVE_EXPR, as we may + need to expand the argument again. This way, we will not perform + side-effects more the once. */ + narg = builtin_save_expr (arg); + if (narg != arg) + { + arg = narg; + arglist = build_tree_list (NULL_TREE, arg); + exp = build_function_call_expr (fndecl, arglist); + } + + op0 = expand_expr (arg, subtarget, VOIDmode, 0); + + if (mode != GET_MODE (op0)) + op0 = convert_to_mode (mode, op0, 0); + + /* Compute into TARGET. + Set TARGET to wherever the result comes back. */ + emit_unop_insn (icode, target, op0, UNKNOWN); + return target; + } + + target = expand_call (exp, target, target == const0_rtx); + + return target; +} + /* Expand a call to the builtin sincos math function. Return 0 if a normal call should be emitted rather than expanding the function in-line. EXP is the expression that is a call to the builtin @@ -5817,7 +5896,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, CASE_FLT_FN (BUILT_IN_EXP2): CASE_FLT_FN (BUILT_IN_EXPM1): CASE_FLT_FN (BUILT_IN_LOGB): - CASE_FLT_FN (BUILT_IN_ILOGB): CASE_FLT_FN (BUILT_IN_LOG): CASE_FLT_FN (BUILT_IN_LOG10): CASE_FLT_FN (BUILT_IN_LOG2): @@ -5842,6 +5920,14 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, return target; break; + CASE_FLT_FN (BUILT_IN_ILOGB): + if (! flag_unsafe_math_optimizations) + break; + target = expand_builtin_interclass_mathfn (exp, target, subtarget); + if (target) + return target; + break; + CASE_FLT_FN (BUILT_IN_LCEIL): CASE_FLT_FN (BUILT_IN_LLCEIL): CASE_FLT_FN (BUILT_IN_LFLOOR): diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 21d1c2b0092..a9620e2242b 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -16261,7 +16261,7 @@ DONE; }) -(define_insn "*fxtractxf3_i387" +(define_insn "fxtractxf3_i387" [(set (match_operand:XF 0 "register_operand" "=f") (unspec:XF [(match_operand:XF 2 "register_operand" "0")] UNSPEC_XTRACT_FRACT)) @@ -16316,21 +16316,34 @@ DONE; }) -(define_expand "ilogbsi2" - [(parallel [(set (match_dup 2) - (unspec:XF [(match_operand:XF 1 "register_operand" "")] - UNSPEC_XTRACT_FRACT)) - (set (match_dup 3) - (unspec:XF [(match_dup 1)] UNSPEC_XTRACT_EXP))]) - (parallel [(set (match_operand:SI 0 "register_operand" "") - (fix:SI (match_dup 3))) - (clobber (reg:CC FLAGS_REG))])] +(define_expand "ilogbxf2" + [(use (match_operand:SI 0 "register_operand" "")) + (use (match_operand:XF 1 "register_operand" ""))] "TARGET_USE_FANCY_MATH_387 - && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387) && flag_unsafe_math_optimizations && !optimize_size" { - operands[2] = gen_reg_rtx (XFmode); - operands[3] = gen_reg_rtx (XFmode); + rtx op0 = gen_reg_rtx (XFmode); + rtx op1 = gen_reg_rtx (XFmode); + + emit_insn (gen_fxtractxf3_i387 (op0, op1, operands[1])); + emit_insn (gen_fix_truncxfsi2 (operands[0], op1)); + DONE; +}) + +(define_expand "ilogb2" + [(use (match_operand:SI 0 "register_operand" "")) + (use (match_operand:X87MODEF12 1 "register_operand" ""))] + "TARGET_USE_FANCY_MATH_387 + && (!(SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH) + || TARGET_MIX_SSE_I387) + && flag_unsafe_math_optimizations && !optimize_size" +{ + rtx op0 = gen_reg_rtx (XFmode); + rtx op1 = gen_reg_rtx (XFmode); + + emit_insn (gen_fxtract_extendxf3_i387 (op0, op1, operands[1])); + emit_insn (gen_fix_truncxfsi2 (operands[0], op1)); + DONE; }) (define_insn "*f2xm1xf2_i387"