[PATCH] Fix PR29719, ICE on expanding __builtin_lfloor/ceil

Richard Guenther rguenther@suse.de
Sun Nov 5 20:53:00 GMT 2006


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;
+ }



More information about the Gcc-patches mailing list