OSDN Git Service

Rename vshuffle/vec_shuffle to vec_perm.
[pf3gnuchains/gcc-fork.git] / gcc / calls.c
index f5592c5..3fa70b5 100644 (file)
@@ -125,7 +125,7 @@ static int stack_arg_under_construction;
 
 static void emit_call_1 (rtx, tree, tree, tree, HOST_WIDE_INT, HOST_WIDE_INT,
                         HOST_WIDE_INT, rtx, rtx, int, rtx, int,
-                        CUMULATIVE_ARGS *);
+                        cumulative_args_t);
 static void precompute_register_parameters (int, struct arg_data *, int *);
 static int store_one_arg (struct arg_data *, rtx, int, int, int);
 static void store_unaligned_arguments_into_pseudos (struct arg_data *, int);
@@ -136,7 +136,7 @@ static int compute_argument_block_size (int, struct args_size *, tree, tree, int
 static void initialize_argument_information (int, struct arg_data *,
                                             struct args_size *, int,
                                             tree, tree,
-                                            tree, tree, CUMULATIVE_ARGS *, int,
+                                            tree, tree, cumulative_args_t, int,
                                             rtx *, int *, int *, int *,
                                             bool *, bool);
 static void compute_argument_addresses (struct arg_data *, rtx, int);
@@ -252,7 +252,7 @@ emit_call_1 (rtx funexp, tree fntree ATTRIBUTE_UNUSED, tree fndecl ATTRIBUTE_UNU
             HOST_WIDE_INT struct_value_size ATTRIBUTE_UNUSED,
             rtx next_arg_reg ATTRIBUTE_UNUSED, rtx valreg,
             int old_inhibit_defer_pop, rtx call_fusage, int ecf_flags,
-            CUMULATIVE_ARGS *args_so_far ATTRIBUTE_UNUSED)
+            cumulative_args_t args_so_far ATTRIBUTE_UNUSED)
 {
   rtx rounded_stack_size_rtx = GEN_INT (rounded_stack_size);
   rtx call_insn, call, funmem;
@@ -261,7 +261,7 @@ emit_call_1 (rtx funexp, tree fntree ATTRIBUTE_UNUSED, tree fndecl ATTRIBUTE_UNU
     = targetm.calls.return_pops_args (fndecl, funtype, stack_size);
 
 #ifdef CALL_POPS_ARGS
-  n_popped += CALL_POPS_ARGS (* args_so_far);
+  n_popped += CALL_POPS_ARGS (*get_cumulative_args (args_so_far));
 #endif
 
   /* Ensure address is valid.  SYMBOL_REF is already valid, so no need,
@@ -434,6 +434,8 @@ emit_call_1 (rtx funexp, tree fntree ATTRIBUTE_UNUSED, tree fndecl ATTRIBUTE_UNU
       rounded_stack_size_rtx = GEN_INT (rounded_stack_size);
       stack_pointer_delta -= n_popped;
 
+      add_reg_note (call_insn, REG_ARGS_SIZE, GEN_INT (stack_pointer_delta));
+
       /* If popup is needed, stack realign must use DRAP  */
       if (SUPPORTS_STACK_ALIGNMENT)
         crtl->need_drap = true;
@@ -567,6 +569,8 @@ special_function_p (const_tree fndecl, int flags)
 int
 setjmp_call_p (const_tree fndecl)
 {
+  if (DECL_IS_RETURNS_TWICE (fndecl))
+    return ECF_RETURNS_TWICE;
   return special_function_p (fndecl, 0) & ECF_RETURNS_TWICE;
 }
 
@@ -700,12 +704,6 @@ precompute_register_parameters (int num_actuals, struct arg_data *args,
            pop_temp_slots ();
          }
 
-       /* If the value is a non-legitimate constant, force it into a
-          pseudo now.  TLS symbols sometimes need a call to resolve.  */
-       if (CONSTANT_P (args[i].value)
-           && !targetm.legitimate_constant_p (args[i].mode, args[i].value))
-         args[i].value = force_reg (args[i].mode, args[i].value);
-
        /* If we are to promote the function arg to a wider mode,
           do it now.  */
 
@@ -715,6 +713,12 @@ precompute_register_parameters (int num_actuals, struct arg_data *args,
                             TYPE_MODE (TREE_TYPE (args[i].tree_value)),
                             args[i].value, args[i].unsignedp);
 
+       /* If the value is a non-legitimate constant, force it into a
+          pseudo now.  TLS symbols sometimes need a call to resolve.  */
+       if (CONSTANT_P (args[i].value)
+           && !targetm.legitimate_constant_p (args[i].mode, args[i].value))
+         args[i].value = force_reg (args[i].mode, args[i].value);
+
        /* If we're going to have to load the value by parts, pull the
           parts into pseudos.  The part extraction process can involve
           non-trivial computation.  */
@@ -738,7 +742,7 @@ precompute_register_parameters (int num_actuals, struct arg_data *args,
                     || (GET_CODE (args[i].value) == SUBREG
                         && REG_P (SUBREG_REG (args[i].value)))))
                 && args[i].mode != BLKmode
-                && rtx_cost (args[i].value, SET, optimize_insn_for_speed_p ())
+                && set_src_cost (args[i].value, optimize_insn_for_speed_p ())
                    > COSTS_N_INSNS (1)
                 && ((*reg_parm_seen
                      && targetm.small_register_classes_for_mode_p (args[i].mode))
@@ -922,8 +926,8 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals)
            emit_move_insn (reg, const0_rtx);
 
            bytes -= bitsize / BITS_PER_UNIT;
-           store_bit_field (reg, bitsize, endian_correction, word_mode,
-                            word);
+           store_bit_field (reg, bitsize, endian_correction, 0, 0,
+                            word_mode, word);
          }
       }
 }
@@ -965,12 +969,13 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
                                 int n_named_args ATTRIBUTE_UNUSED,
                                 tree exp, tree struct_value_addr_value,
                                 tree fndecl, tree fntype,
-                                CUMULATIVE_ARGS *args_so_far,
+                                cumulative_args_t args_so_far,
                                 int reg_parm_stack_space,
                                 rtx *old_stack_level, int *old_pending_adj,
                                 int *must_preallocate, int *ecf_flags,
                                 bool *may_tailcall, bool call_from_thunk_p)
 {
+  CUMULATIVE_ARGS *args_so_far_pnt = get_cumulative_args (args_so_far);
   location_t loc = EXPR_LOCATION (exp);
   /* 1 if scanning parms front to back, -1 if scanning back to front.  */
   int inc;
@@ -1062,14 +1067,14 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
         with those made by function.c.  */
 
       /* See if this argument should be passed by invisible reference.  */
-      if (pass_by_reference (args_so_far, TYPE_MODE (type),
+      if (pass_by_reference (args_so_far_pnt, TYPE_MODE (type),
                             type, argpos < n_named_args))
        {
          bool callee_copies;
          tree base;
 
          callee_copies
-           = reference_callee_copied (args_so_far, TYPE_MODE (type),
+           = reference_callee_copied (args_so_far_pnt, TYPE_MODE (type),
                                       type, argpos < n_named_args);
 
          /* If we're compiling a thunk, pass through invisible references
@@ -1081,6 +1086,8 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
                  && TREE_CODE (base) != SSA_NAME
                  && (!DECL_P (base) || MEM_P (DECL_RTL (base)))))
            {
+             mark_addressable (args[i].tree_value);
+
              /* We can't use sibcalls if a callee-copied argument is
                 stored in the current function's frame.  */
              if (!call_from_thunk_p && DECL_P (base) && !TREE_STATIC (base))
@@ -1476,7 +1483,7 @@ compute_argument_addresses (struct arg_data *args, rtx argblock, int num_actuals
              partial_mode = mode_for_size (units_on_stack * BITS_PER_UNIT,
                                            MODE_INT, 1);
              args[i].stack = gen_rtx_MEM (partial_mode, addr);
-             set_mem_size (args[i].stack, GEN_INT (units_on_stack));
+             set_mem_size (args[i].stack, units_on_stack);
            }
          else
            {
@@ -1508,7 +1515,7 @@ compute_argument_addresses (struct arg_data *args, rtx argblock, int num_actuals
                 Generate a simple memory reference of the correct size.
               */
              args[i].stack_slot = gen_rtx_MEM (partial_mode, addr);
-             set_mem_size (args[i].stack_slot, GEN_INT (units_on_stack));
+             set_mem_size (args[i].stack_slot, units_on_stack);
            }
          else
            {
@@ -1586,6 +1593,10 @@ mem_overlaps_already_clobbered_arg_p (rtx addr, unsigned HOST_WIDE_INT size)
           && (XEXP (addr, 0) == crtl->args.internal_arg_pointer
               || XEXP (addr, 1) == crtl->args.internal_arg_pointer))
     return true;
+  /* If the address comes in a register, we have no idea of its origin so
+     give up and conservatively return true.  */
+  else if (REG_P(addr))
+    return true;
   else
     return false;
 
@@ -1745,7 +1756,8 @@ load_register_parameters (struct arg_data *args, int num_actuals,
          if (GET_CODE (reg) == PARALLEL)
            use_group_regs (call_fusage, reg);
          else if (nregs == -1)
-           use_reg (call_fusage, reg);
+           use_reg_mode (call_fusage, reg,
+                         TYPE_MODE (TREE_TYPE (args[i].tree_value)));
          else if (nregs > 0)
            use_regs (call_fusage, REGNO (reg), nregs);
        }
@@ -1826,6 +1838,10 @@ check_sibcall_argument_overlap_1 (rtx x)
 
   code = GET_CODE (x);
 
+  /* We need not check the operands of the CALL expression itself.  */
+  if (code == CALL)
+    return 0;
+
   if (code == MEM)
     return mem_overlaps_already_clobbered_arg_p (XEXP (x, 0),
                                                 GET_MODE_SIZE (GET_MODE (x)));
@@ -2003,7 +2019,8 @@ expand_call (tree exp, rtx target, int ignore)
   /* Size of arguments before any adjustments (such as rounding).  */
   int unadjusted_args_size;
   /* Data on reg parms scanned so far.  */
-  CUMULATIVE_ARGS args_so_far;
+  CUMULATIVE_ARGS args_so_far_v;
+  cumulative_args_t args_so_far;
   /* Nonzero if a reg parm has been scanned.  */
   int reg_parm_seen;
   /* Nonzero if this is an indirect function call.  */
@@ -2241,7 +2258,8 @@ expand_call (tree exp, rtx target, int ignore)
      calling convention than normal calls.  The fourth argument in
      INIT_CUMULATIVE_ARGS tells the backend if this is an indirect call
      or not.  */
-  INIT_CUMULATIVE_ARGS (args_so_far, funtype, NULL_RTX, fndecl, n_named_args);
+  INIT_CUMULATIVE_ARGS (args_so_far_v, funtype, NULL_RTX, fndecl, n_named_args);
+  args_so_far = pack_cumulative_args (&args_so_far_v);
 
   /* Now possibly adjust the number of named args.
      Normally, don't include the last named arg if anonymous args follow.
@@ -2262,10 +2280,10 @@ expand_call (tree exp, rtx target, int ignore)
      registers, so we must force them into memory.  */
 
   if (type_arg_types != 0
-      && targetm.calls.strict_argument_naming (&args_so_far))
+      && targetm.calls.strict_argument_naming (args_so_far))
     ;
   else if (type_arg_types != 0
-          && ! targetm.calls.pretend_outgoing_varargs_named (&args_so_far))
+          && ! targetm.calls.pretend_outgoing_varargs_named (args_so_far))
     /* Don't include the last named arg.  */
     --n_named_args;
   else
@@ -2281,7 +2299,7 @@ expand_call (tree exp, rtx target, int ignore)
   initialize_argument_information (num_actuals, args, &args_size,
                                   n_named_args, exp,
                                   structure_value_addr_value, fndecl, fntype,
-                                  &args_so_far, reg_parm_stack_space,
+                                  args_so_far, reg_parm_stack_space,
                                   &old_stack_level, &old_pending_adj,
                                   &must_preallocate, &flags,
                                   &try_tail_call, CALL_FROM_THUNK_P (exp));
@@ -2798,10 +2816,10 @@ expand_call (tree exp, rtx target, int ignore)
              }
 
          if (args[i].stack)
-           call_fusage = gen_rtx_EXPR_LIST (VOIDmode,
-                                            gen_rtx_USE (VOIDmode,
-                                                         args[i].stack),
-                                            call_fusage);
+           call_fusage
+             = gen_rtx_EXPR_LIST (TYPE_MODE (TREE_TYPE (args[i].tree_value)),
+                                  gen_rtx_USE (VOIDmode, args[i].stack),
+                                  call_fusage);
        }
 
       /* If we have a parm that is passed in registers but not in memory
@@ -2871,12 +2889,12 @@ expand_call (tree exp, rtx target, int ignore)
       /* Set up next argument register.  For sibling calls on machines
         with register windows this should be the incoming register.  */
       if (pass == 0)
-       next_arg_reg = targetm.calls.function_incoming_arg (&args_so_far,
+       next_arg_reg = targetm.calls.function_incoming_arg (args_so_far,
                                                            VOIDmode,
                                                            void_type_node,
                                                            true);
       else
-       next_arg_reg = targetm.calls.function_arg (&args_so_far,
+       next_arg_reg = targetm.calls.function_arg (args_so_far,
                                                   VOIDmode, void_type_node,
                                                   true);
 
@@ -2891,7 +2909,7 @@ expand_call (tree exp, rtx target, int ignore)
       emit_call_1 (funexp, exp, fndecl, funtype, unadjusted_args_size,
                   adjusted_args_size.constant, struct_value_size,
                   next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage,
-                  flags, args_so_far);
+                  flags, args_so_far);
 
       /* If the call setup or the call itself overlaps with anything
         of the argument setup we probably clobbered our call address.
@@ -3111,8 +3129,13 @@ expand_call (tree exp, rtx target, int ignore)
 
       if (old_stack_level)
        {
+         rtx prev = get_last_insn ();
+
          emit_stack_restore (SAVE_BLOCK, old_stack_level);
          stack_pointer_delta = old_stack_pointer_delta;
+
+         fixup_args_size_notes (prev, get_last_insn (), stack_pointer_delta);
+
          pending_stack_adjust = old_pending_adj;
          old_stack_allocated = stack_pointer_delta - pending_stack_adjust;
          stack_arg_under_construction = old_stack_arg_under_construction;
@@ -3322,7 +3345,8 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
   int inc;
   int count;
   rtx argblock = 0;
-  CUMULATIVE_ARGS args_so_far;
+  CUMULATIVE_ARGS args_so_far_v;
+  cumulative_args_t args_so_far;
   struct arg
   {
     rtx value;
@@ -3434,10 +3458,11 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
   memset (argvec, 0, (nargs + 1) * sizeof (struct arg));
 
 #ifdef INIT_CUMULATIVE_LIBCALL_ARGS
-  INIT_CUMULATIVE_LIBCALL_ARGS (args_so_far, outmode, fun);
+  INIT_CUMULATIVE_LIBCALL_ARGS (args_so_far_v, outmode, fun);
 #else
-  INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, fun, 0, nargs);
+  INIT_CUMULATIVE_ARGS (args_so_far_v, NULL_TREE, fun, 0, nargs);
 #endif
+  args_so_far = pack_cumulative_args (&args_so_far_v);
 
   args_size.constant = 0;
   args_size.var = 0;
@@ -3464,9 +3489,9 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
       argvec[count].mode = Pmode;
       argvec[count].partial = 0;
 
-      argvec[count].reg = targetm.calls.function_arg (&args_so_far,
+      argvec[count].reg = targetm.calls.function_arg (args_so_far,
                                                      Pmode, NULL_TREE, true);
-      gcc_assert (targetm.calls.arg_partial_bytes (&args_so_far, Pmode,
+      gcc_assert (targetm.calls.arg_partial_bytes (args_so_far, Pmode,
                                                   NULL_TREE, 1) == 0);
 
       locate_and_pad_parm (Pmode, NULL_TREE,
@@ -3481,7 +3506,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
          || reg_parm_stack_space > 0)
        args_size.constant += argvec[count].locate.size.constant;
 
-      targetm.calls.function_arg_advance (&args_so_far, Pmode, (tree) 0, true);
+      targetm.calls.function_arg_advance (args_so_far, Pmode, (tree) 0, true);
 
       count++;
     }
@@ -3502,11 +3527,11 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
          && !(CONSTANT_P (val) && targetm.legitimate_constant_p (mode, val)))
        val = force_operand (val, NULL_RTX);
 
-      if (pass_by_reference (&args_so_far, mode, NULL_TREE, 1))
+      if (pass_by_reference (&args_so_far_v, mode, NULL_TREE, 1))
        {
          rtx slot;
          int must_copy
-           = !reference_callee_copied (&args_so_far, mode, NULL_TREE, 1);
+           = !reference_callee_copied (&args_so_far_v, mode, NULL_TREE, 1);
 
          /* If this was a CONST function, it is now PURE since it now
             reads memory.  */
@@ -3517,7 +3542,12 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
            }
 
          if (MEM_P (val) && !must_copy)
-           slot = val;
+           {
+             tree val_expr = MEM_EXPR (val);
+             if (val_expr)
+               mark_addressable (val_expr);
+             slot = val;
+           }
          else
            {
              slot = assign_temp (lang_hooks.types.type_for_mode (mode, 0),
@@ -3541,28 +3571,37 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
       mode = promote_function_mode (NULL_TREE, mode, &unsigned_p, NULL_TREE, 0);
       argvec[count].mode = mode;
       argvec[count].value = convert_modes (mode, GET_MODE (val), val, unsigned_p);
-      argvec[count].reg = targetm.calls.function_arg (&args_so_far, mode,
+      argvec[count].reg = targetm.calls.function_arg (args_so_far, mode,
                                                      NULL_TREE, true);
 
       argvec[count].partial
-       = targetm.calls.arg_partial_bytes (&args_so_far, mode, NULL_TREE, 1);
+       = targetm.calls.arg_partial_bytes (args_so_far, mode, NULL_TREE, 1);
 
-      locate_and_pad_parm (mode, NULL_TREE,
+      if (argvec[count].reg == 0
+         || argvec[count].partial != 0
+         || reg_parm_stack_space > 0)
+       {
+         locate_and_pad_parm (mode, NULL_TREE,
 #ifdef STACK_PARMS_IN_REG_PARM_AREA
-                          1,
+                              1,
 #else
-                          argvec[count].reg != 0,
+                              argvec[count].reg != 0,
+#endif
+                              argvec[count].partial,
+                              NULL_TREE, &args_size, &argvec[count].locate);
+         args_size.constant += argvec[count].locate.size.constant;
+         gcc_assert (!argvec[count].locate.size.var);
+       }
+#ifdef BLOCK_REG_PADDING
+      else
+       /* The argument is passed entirely in registers.  See at which
+          end it should be padded.  */
+       argvec[count].locate.where_pad =
+         BLOCK_REG_PADDING (mode, NULL_TREE,
+                            GET_MODE_SIZE (mode) <= UNITS_PER_WORD);
 #endif
-                          argvec[count].partial,
-                          NULL_TREE, &args_size, &argvec[count].locate);
-
-      gcc_assert (!argvec[count].locate.size.var);
-
-      if (argvec[count].reg == 0 || argvec[count].partial != 0
-         || reg_parm_stack_space > 0)
-       args_size.constant += argvec[count].locate.size.constant;
 
-      targetm.calls.function_arg_advance (&args_so_far, mode, (tree) 0, true);
+      targetm.calls.function_arg_advance (args_so_far, mode, (tree) 0, true);
     }
 
   /* If this machine requires an external definition for library
@@ -3807,13 +3846,43 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
       rtx val = argvec[argnum].value;
       rtx reg = argvec[argnum].reg;
       int partial = argvec[argnum].partial;
-
+#ifdef BLOCK_REG_PADDING
+      int size = 0;
+#endif
+      
       /* Handle calls that pass values in multiple non-contiguous
         locations.  The PA64 has examples of this for library calls.  */
       if (reg != 0 && GET_CODE (reg) == PARALLEL)
        emit_group_load (reg, val, NULL_TREE, GET_MODE_SIZE (mode));
       else if (reg != 0 && partial == 0)
-       emit_move_insn (reg, val);
+        {
+         emit_move_insn (reg, val);
+#ifdef BLOCK_REG_PADDING
+         size = GET_MODE_SIZE (argvec[argnum].mode);
+
+         /* Copied from load_register_parameters.  */
+
+         /* Handle case where we have a value that needs shifting
+            up to the msb.  eg. a QImode value and we're padding
+            upward on a BYTES_BIG_ENDIAN machine.  */
+         if (size < UNITS_PER_WORD
+             && (argvec[argnum].locate.where_pad
+                 == (BYTES_BIG_ENDIAN ? upward : downward)))
+           {
+             rtx x;
+             int shift = (UNITS_PER_WORD - size) * BITS_PER_UNIT;
+
+             /* Assigning REG here rather than a temp makes CALL_FUSAGE
+                report the whole reg as used.  Strictly speaking, the
+                call only uses SIZE bytes at the msb end, but it doesn't
+                seem worth generating rtl to say that.  */
+             reg = gen_rtx_REG (word_mode, REGNO (reg));
+             x = expand_shift (LSHIFT_EXPR, word_mode, reg, shift, reg, 1);
+             if (x != reg)
+               emit_move_insn (reg, x);
+           }
+#endif
+       }
 
       NO_DEFER_POP;
     }
@@ -3874,10 +3943,19 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
               build_function_type (tfom, NULL_TREE),
               original_args_size.constant, args_size.constant,
               struct_value_size,
-              targetm.calls.function_arg (&args_so_far,
+              targetm.calls.function_arg (args_so_far,
                                           VOIDmode, void_type_node, true),
               valreg,
-              old_inhibit_defer_pop + 1, call_fusage, flags, & args_so_far);
+              old_inhibit_defer_pop + 1, call_fusage, flags, args_so_far);
+
+  /* Right-shift returned value if necessary.  */
+  if (!pcc_struct_value
+      && TYPE_MODE (tfom) != BLKmode
+      && targetm.calls.return_in_msb (tfom))
+    {
+      shift_return_value (TYPE_MODE (tfom), false, valreg);
+      valreg = gen_rtx_REG (TYPE_MODE (tfom), REGNO (valreg));
+    }
 
   /* For calls to `setjmp', etc., inform function.c:setjmp_warnings
      that it should complain if nonvolatile values are live.  For