This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] RTL optimize sqrt on targets without a sqrt insn
- From: Roger Sayle <roger at eyesopen dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sun, 20 Jul 2003 07:22:29 -0600 (MDT)
- Subject: [PATCH] RTL optimize sqrt on targets without a sqrt insn
The following patch fixes the failure of builtins-18.c on numerous
targets without hardware support for a FP sqrt instruction. An
example of the problem can be seen in the code below:
double foo()
{
double x;
x = 4.0;
return sqrt(x);
}
The problem is that the constant 4.0 isn't propagated into the sqrt
call until the RTL optimizers. Unfortunately, on targets without a
sqrt insn, the middle-end expands the sqrt call to an anonymous libcall
which looses the "SQRT" semantics, and hence the RTL simplifiers don't
know what to do once they determine the argument is a compile-time
constant.
The patch below fixes this by attaching a REG_EQUAL note containing
a SQRT rtx to the REG_RETVAL insn of the libcall, replacing its EXPR_LIST
of pure/const arguments. This keeps the semantics of the sqrt, with the
libcall, and the RTL optimizers then do the right thing. In theory, we
could apply this to more math builtins, if they were given their own RTL
operators.
The following patch has been tested on both i686-pc-linux-gnu and
powerpc-ibm-aix5.2.0.0 with a full "make bootstrap", all languages
except treelang (on both) and Ada (on AIX), and regression tested
with a top-level "make -k check" with no new failures. As reported
above, this resolves builtins-18.c on AIX, and I've also tested that
we now optimize the small example above on x86 with the command line
options "-O2 -ffast-math -mno-fancy-math-387".
Ok for mainline?
[Also I'd really appreciate it if someone could approve Dave Anglin's
http://gcc.gnu.org/ml/gcc-patches/2003-07/msg00247.html, this both
fixes a serious bootstrap problem, and documents the current behaviour
of REG_EQUAL notes in GCC. REG_EQUAL notes are treated consistently
everywhere except load_mems in loop.c, which happens to be the last
place in the compiler where we redirect a branch by substituting the
label_ref ourselves rather than using the correct routines such as
redirect_jump and potentially preserve the CFG. Whilst I appreciate
it's a noble goal to make loop.c CFG-aware (its being replaced by
Zdenek's rewrite anyway), I think its unfair for Dave to have to
suffer from PR middle-end/11414 in the mean-time, especially when
he's posted a perfectly reasonable solution IMHO]
2003-07-20 Roger Sayle <roger@eyesopen.com>
* builtins.c (expand_builtin_mathfn): Rearrange so that we only
return 0 for invalid argument types. Instead drop through to a
call of expand_call at the bottom of function. If op is SQRT,
try attaching a SQRT rtx as the REQ_EQUAL note of the libcall.
Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.232
diff -c -3 -p -r1.232 builtins.c
*** builtins.c 11 Jul 2003 21:04:53 -0000 1.232
--- builtins.c 20 Jul 2003 01:12:26 -0000
*************** static rtx
*** 1723,1729 ****
expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
{
optab builtin_optab;
! rtx op0, insns;
tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
tree arglist = TREE_OPERAND (exp, 1);
enum machine_mode mode;
--- 1723,1729 ----
expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
{
optab builtin_optab;
! rtx op0, insns, before_call;
tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
tree arglist = TREE_OPERAND (exp, 1);
enum machine_mode mode;
*************** expand_builtin_mathfn (tree exp, rtx tar
*** 1794,1842 ****
/* Make a suitable register to place result in. */
mode = TYPE_MODE (TREE_TYPE (exp));
- /* Before working hard, check whether the instruction is available. */
- if (builtin_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing)
- return 0;
- target = gen_reg_rtx (mode);
-
if (! flag_errno_math || ! HONOR_NANS (mode))
errno_set = false;
! /* 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 = save_expr (arg);
! if (narg != arg)
{
! arglist = build_tree_list (NULL_TREE, arg);
! exp = build_function_call_expr (fndecl, arglist);
}
! op0 = expand_expr (arg, subtarget, VOIDmode, 0);
! emit_queue ();
! start_sequence ();
! /* Compute into TARGET.
! Set TARGET to wherever the result comes back. */
! target = expand_unop (mode, builtin_optab, op0, target, 0);
!
! /* If we were unable to expand via the builtin, stop the sequence
! (without outputting the insns) and call to the library function
! with the stabilized argument list. */
! if (target == 0)
{
! end_sequence ();
! return expand_call (exp, target, target == const0_rtx);
}
-
- if (errno_set)
- expand_errno_check (exp, target);
-
- /* Output the entire sequence. */
- insns = get_insns ();
- end_sequence ();
- emit_insn (insns);
return target;
}
--- 1794,1886 ----
/* Make a suitable register to place result in. */
mode = TYPE_MODE (TREE_TYPE (exp));
if (! flag_errno_math || ! HONOR_NANS (mode))
errno_set = false;
! /* Before working hard, check whether the instruction is available. */
! if (builtin_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
! target = gen_reg_rtx (mode);
!
! /* 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 = save_expr (arg);
! if (narg != arg)
! {
! arglist = build_tree_list (NULL_TREE, arg);
! exp = build_function_call_expr (fndecl, arglist);
! }
!
! op0 = expand_expr (arg, subtarget, VOIDmode, 0);
!
! emit_queue ();
! start_sequence ();
!
! /* Compute into TARGET.
! Set TARGET to wherever the result comes back. */
! target = expand_unop (mode, builtin_optab, op0, target, 0);
!
! if (target != 0)
! {
! if (errno_set)
! expand_errno_check (exp, target);
!
! /* Output the entire sequence. */
! insns = get_insns ();
! end_sequence ();
! emit_insn (insns);
! return target;
! }
!
! /* If we were unable to expand via the builtin, stop the sequence
! (without outputting the insns) and call to the library function
! with the stabilized argument list. */
! end_sequence ();
}
! before_call = get_last_insn ();
! target = expand_call (exp, target, target == const0_rtx);
! /* If this is a sqrt operation and we don't care about errno, try to
! attach a REG_EQUAL note with a SQRT rtx to the emitted libcall.
! This allows the semantics of the libcall to be visible to the RTL
! optimizers. */
! if (builtin_optab == sqrt_optab && !errno_set)
{
! /* Search backwards through the insns emitted by expand_call looking
! for the instruction with the REG_RETVAL note. */
! rtx last = get_last_insn ();
! while (last != before_call)
! {
! if (find_reg_note (last, REG_RETVAL, NULL))
! {
! rtx note = find_reg_note (last, REG_EQUAL, NULL);
! /* Check that the REQ_EQUAL note is an EXPR_LIST with
! two elements, i.e. symbol_ref(sqrt) and the operand. */
! if (note
! && GET_CODE (note) == EXPR_LIST
! && GET_CODE (XEXP (note, 0)) == EXPR_LIST
! && XEXP (XEXP (note, 0), 1) != NULL_RTX
! && XEXP (XEXP (XEXP (note, 0), 1), 1) == NULL_RTX)
! {
! rtx operand = XEXP (XEXP (XEXP (note, 0), 1), 0);
! /* Check operand is a register with expected mode. */
! if (operand
! && GET_CODE (operand) == REG
! && GET_MODE (operand) == mode)
! {
! /* Replace the REG_EQUAL note with a SQRT rtx. */
! rtx equiv = gen_rtx_SQRT (mode, operand);
! set_unique_reg_note (last, REG_EQUAL, equiv);
! }
! }
! break;
! }
! last = PREV_INSN (last);
! }
}
return target;
}
Roger
--
Roger Sayle, E-mail: roger@eyesopen.com
OpenEye Scientific Software, WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road, Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507. Fax: (+1) 505-473-0833