This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix PR29719, ICE on expanding __builtin_lfloor/ceil
- From: Richard Guenther <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sun, 5 Nov 2006 21:55:16 +0100 (CET)
- Subject: [PATCH] Fix PR29719, ICE on expanding __builtin_lfloor/ceil
This fixes our inability to expand calls to __builtin_lfloorf on non-C99
targets. Even if the middle-end does not create calls to
__builtin_lfloorf in non-C99 mode, the user is still exposed to the
builtin function.
This fixes expansion in case the target doesn't provide an optab expansion
for lfloor/lceil by open-coding the operation using expand_fix and
expand_real and compensation code.
Bootstrapped and tested on x86_64-unknown-linux-gnu,
ok for mainline? (I'd appreciate some testing on more weird targets
to see if we always can expand_fix/expand_real there)
Thanks,
Richard.
:ADDPATCH middle-end:
2006-11-05 Richard Guenther <rguenther@suse.de>
PR middle-end/29719
* builtins.c (expand_builtin_int_roundingfn): Fall back to
open-coding lfloor and lceil in case no optab is available.
* gcc.dg/builtins-59.c: New testcase.
Index: builtins.c
===================================================================
*** builtins.c (revision 118505)
--- builtins.c (working copy)
*************** static rtx
*** 2226,2256 ****
expand_builtin_int_roundingfn (tree exp, rtx target, rtx subtarget)
{
convert_optab builtin_optab;
! rtx op0, insns, tmp;
tree fndecl = get_callee_fndecl (exp);
tree arglist = TREE_OPERAND (exp, 1);
- enum built_in_function fallback_fn;
- tree fallback_fndecl;
enum machine_mode mode;
! tree arg, narg;
if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
gcc_unreachable ();
arg = TREE_VALUE (arglist);
switch (DECL_FUNCTION_CODE (fndecl))
{
CASE_FLT_FN (BUILT_IN_LCEIL):
CASE_FLT_FN (BUILT_IN_LLCEIL):
builtin_optab = lceil_optab;
! fallback_fn = BUILT_IN_CEIL;
break;
CASE_FLT_FN (BUILT_IN_LFLOOR):
CASE_FLT_FN (BUILT_IN_LLFLOOR):
builtin_optab = lfloor_optab;
! fallback_fn = BUILT_IN_FLOOR;
break;
default:
--- 2226,2257 ----
expand_builtin_int_roundingfn (tree exp, rtx target, rtx subtarget)
{
convert_optab builtin_optab;
! rtx op0, insns;
tree fndecl = get_callee_fndecl (exp);
tree arglist = TREE_OPERAND (exp, 1);
enum machine_mode mode;
! tree arg, narg, fixed;
! tree itype = TREE_TYPE (exp), ftype;
! bool do_floor;
if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
gcc_unreachable ();
arg = TREE_VALUE (arglist);
+ ftype = TREE_TYPE (arg);
switch (DECL_FUNCTION_CODE (fndecl))
{
CASE_FLT_FN (BUILT_IN_LCEIL):
CASE_FLT_FN (BUILT_IN_LLCEIL):
builtin_optab = lceil_optab;
! do_floor = false;
break;
CASE_FLT_FN (BUILT_IN_LFLOOR):
CASE_FLT_FN (BUILT_IN_LLFLOOR):
builtin_optab = lfloor_optab;
! do_floor = true;
break;
default:
*************** expand_builtin_int_roundingfn (tree exp,
*** 2266,2277 ****
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);
--- 2267,2272 ----
*************** expand_builtin_int_roundingfn (tree exp,
*** 2291,2311 ****
(without outputting the insns). */
end_sequence ();
! /* Fall back to floating point rounding optab. */
! fallback_fndecl = mathfn_built_in (TREE_TYPE (arg), fallback_fn);
! /* We shouldn't get here on targets without TARGET_C99_FUNCTIONS.
! ??? Perhaps convert (int)floorf(x) into (int)floor((double)x). */
! gcc_assert (fallback_fndecl != NULL_TREE);
! exp = build_function_call_expr (fallback_fndecl, arglist);
! tmp = expand_normal (exp);
!
! /* Truncate the result of floating point optab to integer
! via expand_fix (). */
target = gen_reg_rtx (mode);
! expand_fix (target, tmp, 0);
! return target;
}
/* Expand a call to one of the builtin math functions doing integer
--- 2286,2315 ----
(without outputting the insns). */
end_sequence ();
! /* We need to fall back to either calling one of the C99 ceil
! or floor functions and then truncating the result or open-code
! the operation (which will also do libcalls for the fix/float
! operations if they are not available). */
! /* Truncate the operand to the final integer mode and build a decl
! to refer to this intermediate result. */
target = gen_reg_rtx (mode);
! expand_fix (target, op0, 0);
! fixed = build_decl (VAR_DECL, NULL_TREE, itype);
! set_decl_rtl (fixed, target);
!
! /* Expand the lfloor operation to
! (double)fixed > op0 ? fixed - 1 : fixed
! and the lceil operation to
! (double)fixed < op0 ? fixed + 1 : fixed */
! exp = build3 (COND_EXPR, itype,
! build2 (do_floor ? GT_EXPR : LT_EXPR, boolean_type_node,
! build1 (FLOAT_EXPR, ftype, fixed), narg),
! build2 (do_floor ? MINUS_EXPR : PLUS_EXPR,
! itype, fixed, build_int_cst (itype, 1)),
! fixed);
! return expand_normal (exp);
}
/* Expand a call to one of the builtin math functions doing integer
Index: testsuite/gcc.dg/builtins-59.c
===================================================================
*** testsuite/gcc.dg/builtins-59.c (revision 0)
--- testsuite/gcc.dg/builtins-59.c (revision 0)
***************
*** 0 ****
--- 1,27 ----
+ /* { dg-do link } */
+ /* { dg-options "-std=c89" } */
+
+ long test1 (float x)
+ {
+ return __builtin_lfloorf (x);
+ }
+
+ long test2 (float x)
+ {
+ return __builtin_lceilf (x);
+ }
+
+ long test3 (double x)
+ {
+ return __builtin_lfloor (x);
+ }
+
+ long test4 (double x)
+ {
+ return __builtin_lceil (x);
+ }
+
+ int main()
+ {
+ return 0;
+ }