OSDN Git Service

* gcc.texi: Fixes for makeinfo 4.0 --html.
[pf3gnuchains/gcc-fork.git] / gcc / builtins.c
index f03b70e..f288916 100644 (file)
@@ -96,12 +96,14 @@ static rtx expand_builtin_strcmp    PARAMS ((tree, rtx));
 static rtx expand_builtin_memcpy       PARAMS ((tree));
 static rtx expand_builtin_strcpy       PARAMS ((tree));
 static rtx expand_builtin_memset       PARAMS ((tree));
+static rtx expand_builtin_bzero                PARAMS ((tree));
 static rtx expand_builtin_strlen       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_frame_address        PARAMS ((tree));
 static tree stabilize_va_list          PARAMS ((tree, int));
+static rtx expand_builtin_expect       PARAMS ((tree, rtx));
 
 /* Return the alignment in bits of EXP, a pointer valued expression.
    But don't return more than MAX_ALIGN no matter what.
@@ -134,6 +136,7 @@ get_pointer_alignment (exp, max_align)
          exp = TREE_OPERAND (exp, 0);
          if (TREE_CODE (TREE_TYPE (exp)) != POINTER_TYPE)
            return align;
+
          inner = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)));
          align = MIN (inner, max_align);
          break;
@@ -142,10 +145,10 @@ get_pointer_alignment (exp, max_align)
          /* If sum of pointer + int, restrict our maximum alignment to that
             imposed by the integer.  If not, we can't do any better than
             ALIGN.  */
-         if (TREE_CODE (TREE_OPERAND (exp, 1)) != INTEGER_CST)
+         if (! host_integerp (TREE_OPERAND (exp, 1), 1))
            return align;
 
-         while (((TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)) * BITS_PER_UNIT)
+         while (((tree_low_cst (TREE_OPERAND (exp, 1), 1) * BITS_PER_UNIT)
                  & (max_align - 1))
                 != 0)
            max_align >>= 1;
@@ -376,8 +379,8 @@ expand_builtin_setjmp (buf_addr, target, first_label, next_label)
      calls may traverse the arc back to this label.  */
 
   current_function_has_nonlocal_label = 1;
-  nonlocal_goto_handler_labels =
-    gen_rtx_EXPR_LIST (VOIDmode, lab1, nonlocal_goto_handler_labels);
+  nonlocal_goto_handler_labels
+    gen_rtx_EXPR_LIST (VOIDmode, lab1, nonlocal_goto_handler_labels);
 
   /* Clobber the FP when we get here, so we have to make sure it's
      marked as used by this function.  */
@@ -869,8 +872,6 @@ expand_builtin_apply (function, arguments, argsize)
   /* Create a block where the return registers can be saved.  */
   result = assign_stack_local (BLKmode, apply_result_size (), -1);
 
-  /* ??? The argsize value should be adjusted here.  */
-
   /* Fetch the arg pointer from the ARGUMENTS block.  */
   incoming_args = gen_reg_rtx (Pmode);
   emit_move_insn (incoming_args,
@@ -899,11 +900,10 @@ expand_builtin_apply (function, arguments, argsize)
      haven't figured out how the calling convention macros effect this,
      but it's likely that the source and/or destination addresses in
      the block copy will need updating in machine specific ways.  */
-  dest = allocate_dynamic_stack_space (argsize, 0, 0);
+  dest = allocate_dynamic_stack_space (argsize, 0, BITS_PER_UNIT);
   emit_block_move (gen_rtx_MEM (BLKmode, dest),
                   gen_rtx_MEM (BLKmode, incoming_args),
-                  argsize,
-                  PARM_BOUNDARY / BITS_PER_UNIT);
+                  argsize, PARM_BOUNDARY);
 
   /* Refer to the argument block.  */
   apply_args_size ();
@@ -1389,7 +1389,8 @@ expand_builtin_strlen (exp, target, mode)
 
       /* Now that we are assured of success, expand the source.  */
       start_sequence ();
-      pat = expand_expr (src, src_reg, ptr_mode, EXPAND_SUM);
+      pat = memory_address (BLKmode, 
+               expand_expr (src, src_reg, ptr_mode, EXPAND_SUM));
       if (pat != src_reg)
        emit_move_insn (src_reg, pat);
       pat = gen_sequence ();
@@ -1434,10 +1435,8 @@ expand_builtin_memcpy (arglist)
       tree src = TREE_VALUE (TREE_CHAIN (arglist));
       tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
 
-      int src_align
-       = get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
-      int dest_align
-       = get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
+      int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
+      int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
       rtx dest_mem, src_mem, dest_addr, len_rtx;
 
       /* If either SRC or DEST is not a pointer type, don't do
@@ -1530,8 +1529,7 @@ expand_builtin_memset (exp)
       tree val = TREE_VALUE (TREE_CHAIN (arglist));
       tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
 
-      int dest_align
-       = get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
+      int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
       rtx dest_mem, dest_addr, len_rtx;
 
       /* If DEST is not a pointer type, don't do this 
@@ -1574,6 +1572,40 @@ expand_builtin_memset (exp)
     }
 }
 
+/* Expand expression EXP, which is a call to the bzero builtin.  Return 0
+   if we failed the caller should emit a normal call.  */
+static rtx
+expand_builtin_bzero (exp)
+     tree exp;
+{
+  tree arglist = TREE_OPERAND (exp, 1);
+  tree dest, size, newarglist;
+  rtx result;
+
+  if (arglist == 0
+      /* Arg could be non-pointer if user redeclared this fcn wrong.  */
+      || TREE_CODE (TREE_TYPE (dest = TREE_VALUE (arglist))) != POINTER_TYPE
+      || TREE_CHAIN (arglist) == 0
+      || (TREE_CODE (TREE_TYPE (size = TREE_VALUE (TREE_CHAIN (arglist))))
+         != INTEGER_TYPE))
+    return NULL_RTX;
+
+  /* New argument list transforming bzero(ptr x, int y) to
+     memset(ptr x, int 0, size_t y).  */
+  
+  newarglist = build_tree_list (NULL_TREE, convert (sizetype, size));
+  newarglist = tree_cons (NULL_TREE, integer_zero_node, newarglist);
+  newarglist = tree_cons (NULL_TREE, dest, newarglist);
+
+  TREE_OPERAND (exp, 1) = newarglist;
+  result = expand_builtin_memset(exp);
+      
+  /* Always restore the original arguments.  */
+  TREE_OPERAND (exp, 1) = arglist;
+
+  return result;
+}
+
 #ifdef HAVE_cmpstrsi
 /* Expand expression EXP, which is a call to the memcmp or the strcmp builtin.
    ARGLIST is the argument list for this call.  Return 0 if we failed and the
@@ -1597,15 +1629,15 @@ expand_builtin_memcmp (exp, arglist, target)
       || TREE_CHAIN (TREE_CHAIN (arglist)) == 0
       || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))))) != INTEGER_TYPE)
     return 0;
-  else if (!HAVE_cmpstrsi)
-    return 0;
 
   {
     enum machine_mode mode;
     tree arg1 = TREE_VALUE (arglist);
     tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
     tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+    rtx arg1_rtx, arg2_rtx, arg3_rtx;
     rtx result;
+    rtx insn;
 
     int arg1_align
       = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
@@ -1625,10 +1657,25 @@ expand_builtin_memcmp (exp, arglist, target)
           && REGNO (result) >= FIRST_PSEUDO_REGISTER))
       result = gen_reg_rtx (insn_mode);
 
-    emit_insn (gen_cmpstrsi (result, get_memory_rtx (arg1),
-                            get_memory_rtx (arg2),
-                            expand_expr (len, NULL_RTX, VOIDmode, 0),
-                            GEN_INT (MIN (arg1_align, arg2_align))));
+    arg1_rtx = get_memory_rtx (arg1);
+    arg2_rtx = get_memory_rtx (arg2);
+    arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+    if (!HAVE_cmpstrsi)
+      insn = NULL_RTX;
+    else
+      insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
+                          GEN_INT (MIN (arg1_align, arg2_align)));
+
+    if (insn)
+      emit_insn (insn);
+    else
+      emit_library_call_value (memcmp_libfunc, result, 2,
+                              TYPE_MODE (integer_type_node), 3,
+                              XEXP (arg1_rtx, 0), Pmode,
+                              XEXP (arg2_rtx, 0), Pmode,
+                              convert_to_mode (TYPE_MODE (sizetype), arg3_rtx,
+                                               TREE_UNSIGNED (sizetype)),
+                              TYPE_MODE (sizetype));
 
     /* Return the value in the proper mode for this function.  */
     mode = TYPE_MODE (TREE_TYPE (exp));
@@ -1866,66 +1913,44 @@ expand_builtin_next_arg (arglist)
    from multiple evaluations.  */
 
 static tree
-stabilize_va_list (valist, was_ptr)
+stabilize_va_list (valist, needs_lvalue)
      tree valist;
-     int was_ptr;
+     int needs_lvalue;
 {
   if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
     {
-      /* If stdarg.h took the address of an array-type valist that was passed
-         as a parameter, we'll have taken the address of the parameter itself
-         rather than the array as we'd intended.  Undo this mistake.  */
+      if (TREE_SIDE_EFFECTS (valist))
+       valist = save_expr (valist);
 
-      if (was_ptr)
+      /* For this case, the backends will be expecting a pointer to
+        TREE_TYPE (va_list_type_node), but it's possible we've
+        actually been given an array (an actual va_list_type_node).
+        So fix it.  */
+      if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
        {
-         STRIP_NOPS (valist);
-
-         /* Two cases: either &array, which decomposed to 
-               <ptr <array <record> valist>>
-            or &ptr, which turned into
-               <ptr <ptr <record>>>
-            In the first case we'll need to put the ADDR_EXPR back
-            after frobbing the types as if &array[0].  */
-
-         if (TREE_CODE (valist) != ADDR_EXPR)
-           abort ();
-         valist = TREE_OPERAND (valist, 0);
-       }
+         tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
+         tree p2 = build_pointer_type (va_list_type_node);
 
-      if (TYPE_MAIN_VARIANT (TREE_TYPE (valist))
-         == TYPE_MAIN_VARIANT (va_list_type_node))
-       {
-         tree pt = build_pointer_type (TREE_TYPE (va_list_type_node));
-         valist = build1 (ADDR_EXPR, pt, valist);
-         TREE_SIDE_EFFECTS (valist)
-           = TREE_SIDE_EFFECTS (TREE_OPERAND (valist, 0));
-       }
-      else
-       {
-         if (! POINTER_TYPE_P (TREE_TYPE (valist))
-             || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (valist)))
-                 != TYPE_MAIN_VARIANT (TREE_TYPE (va_list_type_node))))
-           abort ();
+         valist = build1 (ADDR_EXPR, p2, valist);
+         valist = fold (build1 (NOP_EXPR, p1, valist));
        }
-
-      if (TREE_SIDE_EFFECTS (valist))
-       valist = save_expr (valist);
     }
   else
     {
-      if (! was_ptr)
-       {
-         tree pt;
+      tree pt;
 
+      if (! needs_lvalue)
+       {
          if (! TREE_SIDE_EFFECTS (valist))
            return valist;
-
+         
          pt = build_pointer_type (va_list_type_node);
-          valist = fold (build1 (ADDR_EXPR, pt, valist));
+         valist = fold (build1 (ADDR_EXPR, pt, valist));
          TREE_SIDE_EFFECTS (valist) = 1;
        }
+
       if (TREE_SIDE_EFFECTS (valist))
-        valist = save_expr (valist);
+       valist = save_expr (valist);
       valist = fold (build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)),
                             valist));
     }
@@ -2178,8 +2203,7 @@ expand_builtin_va_copy (arglist)
       MEM_ALIAS_SET (srcb) = get_alias_set (TREE_TYPE (TREE_TYPE (src)));
 
       /* Copy.  */
-      emit_block_move (dstb, srcb, size, 
-                      TYPE_ALIGN (va_list_type_node) / BITS_PER_UNIT);
+      emit_block_move (dstb, srcb, size, TYPE_ALIGN (va_list_type_node));
     }
 
   return const0_rtx;
@@ -2283,6 +2307,48 @@ expand_builtin_ffs (arglist, target, subtarget)
     abort ();
   return target;
 }
+
+/* Expand a call to __builtin_expect.  We return our argument and
+   emit a NOTE_INSN_EXPECTED_VALUE note.  */
+
+static rtx
+expand_builtin_expect (arglist, target)
+     tree arglist;
+     rtx target;
+{
+  tree exp, c;
+  rtx note, rtx_c;
+
+  if (arglist == NULL_TREE
+      || TREE_CHAIN (arglist) == NULL_TREE)
+    return const0_rtx;
+  exp = TREE_VALUE (arglist);
+  c = TREE_VALUE (TREE_CHAIN (arglist));
+
+  if (TREE_CODE (c) != INTEGER_CST)
+    {
+      error ("second arg to `__builtin_expect' must be a constant");
+      c = integer_zero_node;
+    }
+
+  target = expand_expr (exp, target, VOIDmode, EXPAND_NORMAL);
+
+  /* Don't bother with expected value notes for integral constants.  */
+  if (GET_CODE (target) != CONST_INT)
+    {
+      /* We do need to force this into a register so that we can be
+        moderately sure to be able to correctly interpret the branch
+        condition later.  */
+      target = force_reg (GET_MODE (target), target);
+  
+      rtx_c = expand_expr (c, NULL_RTX, GET_MODE (target), EXPAND_NORMAL);
+
+      note = emit_note (NULL, NOTE_INSN_EXPECTED_VALUE);
+      NOTE_EXPECTED_VALUE (note) = gen_rtx_EQ (VOIDmode, target, rtx_c);
+    }
+
+  return target;
+}
 \f
 /* Expand an expression EXP that calls a built-in function,
    with result going to TARGET if that's convenient
@@ -2313,6 +2379,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       && (fcode == BUILT_IN_SIN || fcode == BUILT_IN_COS
          || fcode == BUILT_IN_FSQRT || fcode == BUILT_IN_MEMSET
          || fcode == BUILT_IN_MEMCPY || fcode == BUILT_IN_MEMCMP
+         || fcode == BUILT_IN_BCMP || fcode == BUILT_IN_BZERO
          || fcode == BUILT_IN_STRLEN || fcode == BUILT_IN_STRCPY
          || fcode == BUILT_IN_STRCMP || fcode == BUILT_IN_FFS))
     return expand_call (exp, target, ignore);
@@ -2450,6 +2517,12 @@ expand_builtin (exp, target, subtarget, mode, ignore)
        return target;
       break;
 
+    case BUILT_IN_BZERO:
+      target = expand_builtin_bzero (exp);
+      if (target)
+       return target;
+      break;
+
 /* These comparison functions need an instruction that returns an actual
    index.  An ordinary compare that just sets the condition codes
    is not enough.  */
@@ -2460,6 +2533,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
        return target;
       break;
 
+    case BUILT_IN_BCMP:
     case BUILT_IN_MEMCMP:
       target = expand_builtin_memcmp (exp, arglist, target);
       if (target)
@@ -2467,6 +2541,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       break;
 #else
     case BUILT_IN_STRCMP:
+    case BUILT_IN_BCMP:
     case BUILT_IN_MEMCMP:
       break;
 #endif
@@ -2549,6 +2624,8 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       return expand_builtin_va_end (arglist);
     case BUILT_IN_VA_COPY:
       return expand_builtin_va_copy (arglist);
+    case BUILT_IN_EXPECT:
+      return expand_builtin_expect (arglist, target);
 
     default:                   /* just do library call, if unknown builtin */
       error ("built-in function `%s' not currently supported",