OSDN Git Service

* builtin-types.def (BT_FN_FLOAT_FLOAT_FLOAT): New built-in type.
[pf3gnuchains/gcc-fork.git] / gcc / builtins.c
index 851fc27..e2ad1e8 100644 (file)
@@ -147,7 +147,7 @@ static rtx expand_builtin_strchr    PARAMS ((tree, rtx,
 static rtx expand_builtin_strrchr      PARAMS ((tree, rtx,
                                                 enum machine_mode));
 static rtx expand_builtin_alloca       PARAMS ((tree, rtx));
-static rtx expand_builtin_ffs          PARAMS ((tree, rtx, rtx));
+static rtx expand_builtin_unop         PARAMS ((tree, rtx, rtx, optab));
 static rtx expand_builtin_frame_address        PARAMS ((tree));
 static rtx expand_builtin_fputs                PARAMS ((tree, int, int));
 static tree stabilize_va_list          PARAMS ((tree, int));
@@ -157,6 +157,7 @@ static tree fold_builtin_classify_type      PARAMS ((tree));
 static tree fold_builtin_inf           PARAMS ((tree, int));
 static tree fold_builtin_nan           PARAMS ((tree, tree, int));
 static int validate_arglist            PARAMS ((tree, ...));
+static tree fold_trunc_transparent_mathfn PARAMS ((tree));
 
 /* Return the alignment in bits of EXP, a pointer valued expression.
    But don't return more than MAX_ALIGN no matter what.
@@ -1468,6 +1469,8 @@ expand_builtin_constant_p (exp)
      case is not obvious, so emit (constant_p_rtx (ARGLIST)) and let CSE
      get a chance to see if it can deduce whether ARGLIST is constant.  */
 
+  current_function_calls_constant_p = 1;
+
   tmp = expand_expr (arglist, NULL_RTX, VOIDmode, 0);
   tmp = gen_rtx_CONSTANT_P_RTX (value_mode, tmp);
   return tmp;
@@ -1504,6 +1507,11 @@ mathfn_built_in (type, fn)
       case BUILT_IN_EXPL:
        fcode = BUILT_IN_EXP;
        break;
+      case BUILT_IN_LOG:
+      case BUILT_IN_LOGF:
+      case BUILT_IN_LOGL:
+       fcode = BUILT_IN_LOG;
+       break;
       case BUILT_IN_FLOOR:
       case BUILT_IN_FLOORF:
       case BUILT_IN_FLOORL:
@@ -1555,6 +1563,11 @@ mathfn_built_in (type, fn)
       case BUILT_IN_EXPL:
        fcode = BUILT_IN_EXPF;
        break;
+      case BUILT_IN_LOG:
+      case BUILT_IN_LOGF:
+      case BUILT_IN_LOGL:
+       fcode = BUILT_IN_LOGF;
+       break;
       case BUILT_IN_FLOOR:
       case BUILT_IN_FLOORF:
       case BUILT_IN_FLOORL:
@@ -1606,6 +1619,11 @@ mathfn_built_in (type, fn)
       case BUILT_IN_EXPL:
        fcode = BUILT_IN_EXPL;
        break;
+      case BUILT_IN_LOG:
+      case BUILT_IN_LOGF:
+      case BUILT_IN_LOGL:
+       fcode = BUILT_IN_LOGL;
+       break;
       case BUILT_IN_FLOOR:
       case BUILT_IN_FLOORF:
       case BUILT_IN_FLOORL:
@@ -3578,15 +3596,16 @@ expand_builtin_alloca (arglist, target)
   return result;
 }
 
-/* Expand a call to the ffs builtin.  The arguments are in ARGLIST.
+/* Expand a call to a unary builtin.  The arguments are in ARGLIST.
    Return 0 if a normal call should be emitted rather than expanding the
    function in-line.  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_ffs (arglist, target, subtarget)
+expand_builtin_unop (arglist, target, subtarget, op_optab)
      tree arglist;
      rtx target, subtarget;
+     optab op_optab;
 {
   rtx op0;
   if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
@@ -3594,10 +3613,10 @@ expand_builtin_ffs (arglist, target, subtarget)
 
   /* Compute the argument.  */
   op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0);
-  /* Compute ffs, into TARGET if possible.
+  /* Compute op, into TARGET if possible.
      Set TARGET to wherever the result comes back.  */
   target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))),
-                       ffs_optab, op0, target, 1);
+                       op_optab, op0, target, 1);
   if (target == 0)
     abort ();
   return target;
@@ -3901,6 +3920,15 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       case BUILT_IN_EXP:
       case BUILT_IN_EXPF:
       case BUILT_IN_EXPL:
+      case BUILT_IN_LOG:
+      case BUILT_IN_LOGF:
+      case BUILT_IN_LOGL:
+      case BUILT_IN_POW:
+      case BUILT_IN_POWF:
+      case BUILT_IN_POWL:
+      case BUILT_IN_ATAN2:
+      case BUILT_IN_ATAN2F:
+      case BUILT_IN_ATAN2L:
       case BUILT_IN_MEMSET:
       case BUILT_IN_MEMCPY:
       case BUILT_IN_MEMCMP:
@@ -4096,7 +4124,42 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       break;
 
     case BUILT_IN_FFS:
-      target = expand_builtin_ffs (arglist, target, subtarget);
+    case BUILT_IN_FFSL:
+    case BUILT_IN_FFSLL:
+      target = expand_builtin_unop (arglist, target, subtarget, ffs_optab);
+      if (target)
+       return target;
+      break;
+
+    case BUILT_IN_CLZ:
+    case BUILT_IN_CLZL:
+    case BUILT_IN_CLZLL:
+      target = expand_builtin_unop (arglist, target, subtarget, clz_optab);
+      if (target)
+       return target;
+      break;
+
+    case BUILT_IN_CTZ:
+    case BUILT_IN_CTZL:
+    case BUILT_IN_CTZLL:
+      target = expand_builtin_unop (arglist, target, subtarget, ctz_optab);
+      if (target)
+       return target;
+      break;
+
+    case BUILT_IN_POPCOUNT:
+    case BUILT_IN_POPCOUNTL:
+    case BUILT_IN_POPCOUNTLL:
+      target = expand_builtin_unop (arglist, target, subtarget,
+                                   popcount_optab);
+      if (target)
+       return target;
+      break;
+
+    case BUILT_IN_PARITY:
+    case BUILT_IN_PARITYL:
+    case BUILT_IN_PARITYLL:
+      target = expand_builtin_unop (arglist, target, subtarget, parity_optab);
       if (target)
        return target;
       break;
@@ -4423,6 +4486,36 @@ fold_builtin_nan (arglist, type, quiet)
   return build_real (type, real);
 }
 
+/* EXP is assumed to me builtin call where truncation can be propagated
+   across (for instance floor((double)f) == (double)floorf (f).
+   Do the transformation.  */
+static tree
+fold_trunc_transparent_mathfn (exp)
+     tree exp;
+{
+  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+  tree arglist = TREE_OPERAND (exp, 1);
+  enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
+
+  if (optimize && validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+    {
+      tree arg0 = strip_float_extensions (TREE_VALUE (arglist));
+      tree ftype = TREE_TYPE (exp);
+      tree newtype = TREE_TYPE (arg0);
+      tree decl;
+
+      if (TYPE_PRECISION (newtype) < TYPE_PRECISION (ftype)
+         && (decl = mathfn_built_in (newtype, fcode)))
+       {
+         arglist =
+           build_tree_list (NULL_TREE, fold (convert (newtype, arg0)));
+         return convert (ftype,
+                         build_function_call_expr (decl, arglist));
+       }
+    }
+  return 0;
+}
+
 /* Used by constant folding to eliminate some builtin calls early.  EXP is
    the CALL_EXPR of a call to a builtin function.  */
 
@@ -4574,6 +4667,23 @@ fold_builtin (exp)
     case BUILT_IN_NANSL:
       return fold_builtin_nan (arglist, TREE_TYPE (TREE_TYPE (fndecl)), false);
 
+    case BUILT_IN_FLOOR:
+    case BUILT_IN_FLOORF:
+    case BUILT_IN_FLOORL:
+    case BUILT_IN_CEIL:
+    case BUILT_IN_CEILF:
+    case BUILT_IN_CEILL:
+    case BUILT_IN_TRUNC:
+    case BUILT_IN_TRUNCF:
+    case BUILT_IN_TRUNCL:
+    case BUILT_IN_ROUND:
+    case BUILT_IN_ROUNDF:
+    case BUILT_IN_ROUNDL:
+    case BUILT_IN_NEARBYINT:
+    case BUILT_IN_NEARBYINTF:
+    case BUILT_IN_NEARBYINTL:
+      return fold_trunc_transparent_mathfn (exp);
+
     default:
       break;
     }
@@ -4670,26 +4780,20 @@ default_expand_builtin (exp, target, subtarget, mode, ignore)
 void
 purge_builtin_constant_p ()
 {
-  rtx insn, done, set;
-  rtx arg, new, note;
-  basic_block bb;
+  rtx insn, set, arg, new, note;
 
-  FOR_EACH_BB (bb)
-    {
-      done = NEXT_INSN (bb->end);
-      for (insn = bb->head; insn != done; insn = NEXT_INSN (insn))
-       if (INSN_P (insn)
-           && (set = single_set (insn)) != NULL_RTX
-           && GET_CODE (SET_SRC (set)) == CONSTANT_P_RTX)
-         {
-           arg = XEXP (SET_SRC (set), 0);
-           new = CONSTANT_P (arg) ? const1_rtx : const0_rtx;
-           validate_change (insn, &SET_SRC (set), new, 0);
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    if (INSN_P (insn)
+       && (set = single_set (insn)) != NULL_RTX
+       && GET_CODE (SET_SRC (set)) == CONSTANT_P_RTX)
+      {
+       arg = XEXP (SET_SRC (set), 0);
+       new = CONSTANT_P (arg) ? const1_rtx : const0_rtx;
+       validate_change (insn, &SET_SRC (set), new, 0);
 
-           /* Remove the REG_EQUAL note from the insn.  */
-           if ((note = find_reg_note (insn, REG_EQUAL, NULL_RTX)) != 0)
-             remove_note (insn, note);
-         }
-    }
+       /* Remove the REG_EQUAL note from the insn.  */
+       if ((note = find_reg_note (insn, REG_EQUAL, NULL_RTX)) != 0)
+         remove_note (insn, note);
+      }
 }