]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/config/sh/sh.c
Update copyright years.
[thirdparty/gcc.git] / gcc / config / sh / sh.c
index bcd82cb75989474356485f8b63a1871d1cb3b6fa..1564109c9425752f7ceb8e6c7d67910a9d3f8b8b 100644 (file)
@@ -1,5 +1,5 @@
 /* Output routines for GCC for Renesas / SuperH SH.
-   Copyright (C) 1993-2019 Free Software Foundation, Inc.
+   Copyright (C) 1993-2021 Free Software Foundation, Inc.
    Contributed by Steve Chamberlain (sac@cygnus.com).
    Improved by Jim Wilson (wilson@cygnus.com).
 
@@ -249,7 +249,7 @@ static void sh_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
                                HOST_WIDE_INT, tree);
 static void sh_file_start (void);
 static bool sh_assemble_integer (rtx, unsigned int, int);
-static bool flow_dependent_p (rtx, rtx);
+static bool flow_dependent_p (rtx_insn *, rtx_insn *);
 static void flow_dependent_p_1 (rtx, const_rtx, void *);
 static int shiftcosts (rtx);
 static int and_xor_ior_costs (rtx, int);
@@ -296,13 +296,11 @@ static machine_mode sh_promote_function_mode (const_tree type,
                                                   int for_return);
 static bool sh_pass_by_reference (cumulative_args_t,
                                  const function_arg_info &);
-static bool sh_callee_copies (cumulative_args_t, machine_mode,
-                             const_tree, bool);
+static bool sh_callee_copies (cumulative_args_t, const function_arg_info &);
 static int sh_arg_partial_bytes (cumulative_args_t, const function_arg_info &);
-static void sh_function_arg_advance (cumulative_args_t, machine_mode,
-                                    const_tree, bool);
-static rtx sh_function_arg (cumulative_args_t, machine_mode,
-                           const_tree, bool);
+static void sh_function_arg_advance (cumulative_args_t,
+                                    const function_arg_info &);
+static rtx sh_function_arg (cumulative_args_t, const function_arg_info &);
 static int sh_dwarf_calling_convention (const_tree);
 static void sh_encode_section_info (tree, rtx, int);
 static bool sh2a_function_vector_p (tree);
@@ -663,6 +661,9 @@ static const struct attribute_spec sh_attribute_table[] =
 #undef TARGET_CONSTANT_ALIGNMENT
 #define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
 
+#undef  TARGET_HAVE_SPECULATION_SAFE_VALUE
+#define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 
@@ -736,7 +737,7 @@ got_mode_name:;
     {
       if (tokens[i] == "strict")
        ret.strict = true;
-      else if (tokens[i].find ("gbr-offset=") == 0)
+      else if (!tokens[i].compare (0, strlen ("gbr-offset="), "gbr-offset="))
        {
          std::string offset_str = tokens[i].substr (strlen ("gbr-offset="));
          ret.tcb_gbr_offset = integral_argument (offset_str.c_str ());
@@ -799,7 +800,7 @@ register_sh_passes (void)
   /* Run sh_treg_combine pass after register allocation and basic block
      reordering as this sometimes creates new opportunities.  */
   register_pass (make_pass_sh_treg_combine (g, true, "sh_treg_combine3"),
-                PASS_POS_INSERT_AFTER, "split4", 1);
+                PASS_POS_INSERT_AFTER, "split3", 1);
 
   /* Optimize sett and clrt insns, by e.g. removing them if the T bit value
      is known after a conditional branch.
@@ -957,11 +958,13 @@ sh_option_override (void)
   if (flag_unsafe_math_optimizations)
     {
       /* Enable fsca insn for SH4A if not otherwise specified by the user.  */
-      if (global_options_set.x_TARGET_FSCA == 0 && TARGET_SH4A_FP)
+      if (global_options_set.x_TARGET_FSCA == 0
+         && (TARGET_SH4A_FP || TARGET_FPU_SH4_300))
        TARGET_FSCA = 1;
 
       /* Enable fsrra insn for SH4A if not otherwise specified by the user.  */
-      if (global_options_set.x_TARGET_FSRRA == 0 && TARGET_SH4A_FP)
+      if (global_options_set.x_TARGET_FSRRA == 0
+         && (TARGET_SH4A_FP || TARGET_FPU_SH4_300))
        TARGET_FSRRA = 1;
     }
 
@@ -2105,7 +2108,7 @@ expand_cbranchdi4 (rtx *operands, enum rtx_code comparison)
       lsw_taken = EQ;
       if (prob.initialized_p ())
        {
-         /* FIXME: This is not optimal.  We do not really know the probablity
+         /* FIXME: This is not optimal.  We do not really know the probability
             that values differ by MCW only, but we should probably distribute
             probabilities more evenly.  */
          msw_skip_prob = rev_prob;
@@ -6705,13 +6708,13 @@ output_stack_adjust (int size, rtx reg, int epilogue_p,
             to handle this case, so just die when we see it.  */
          if (epilogue_p < 0
              || current_function_interrupt
-             || ! call_really_used_regs[temp] || fixed_regs[temp])
+             || ! call_used_regs[temp] || fixed_regs[temp])
            temp = -1;
          if (temp < 0 && ! current_function_interrupt && epilogue_p >= 0)
            {
-             HARD_REG_SET temps;
-             COPY_HARD_REG_SET (temps, call_used_reg_set);
-             AND_COMPL_HARD_REG_SET (temps, call_fixed_reg_set);
+             HARD_REG_SET temps = (regs_invalidated_by_call
+                                   & ~fixed_reg_set
+                                   & savable_regs);
              if (epilogue_p > 0)
                {
                  int nreg = 0;
@@ -6745,7 +6748,7 @@ output_stack_adjust (int size, rtx reg, int epilogue_p,
            {
              HARD_REG_SET temps;
 
-             COPY_HARD_REG_SET (temps, *live_regs_mask);
+             temps = *live_regs_mask;
              CLEAR_HARD_REG_BIT (temps, REGNO (reg));
              temp = scavenge_reg (&temps);
            }
@@ -6910,11 +6913,8 @@ push_regs (HARD_REG_SET *mask, bool interrupt_handler)
       if (i == FIRST_FP_REG && interrupt_handler && TARGET_FMOVD
          && hard_reg_set_intersect_p (*mask, reg_class_contents[DF_REGS]))
        {
-         HARD_REG_SET unsaved;
-
          push (FPSCR_REG);
-         COMPL_HARD_REG_SET (unsaved, *mask);
-         fpscr_set_from_mem (NORMAL_MODE (FP_MODE), unsaved);
+         fpscr_set_from_mem (NORMAL_MODE (FP_MODE), ~*mask);
          skip_fpscr = true;
        }
       if (i != PR_REG
@@ -7014,7 +7014,7 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
   else if (TARGET_FPU_DOUBLE && TARGET_FMOVD && TARGET_FPU_SINGLE)
     for (int count = 0, reg = FIRST_FP_REG; reg <= LAST_FP_REG; reg += 2)
       if (df_regs_ever_live_p (reg) && df_regs_ever_live_p (reg+1)
-         && (! call_really_used_regs[reg]
+         && (! call_used_regs[reg]
              || interrupt_handler)
          && ++count > 2)
        {
@@ -7045,7 +7045,7 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
          : interrupt_handler
          ? (/* Need to save all the regs ever live.  */
             (df_regs_ever_live_p (reg)
-             || (call_really_used_regs[reg]
+             || (call_used_regs[reg]
                  && (! fixed_regs[reg] || reg == MACH_REG || reg == MACL_REG
                      || reg == PIC_OFFSET_TABLE_REGNUM)
                  && has_call))
@@ -7058,9 +7058,10 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
          : (/* Only push those regs which are used and need to be saved.  */
             (false)
             || (df_regs_ever_live_p (reg)
-                && ((!call_really_used_regs[reg]
+                && ((!call_used_regs[reg]
                      && !(reg != PIC_OFFSET_TABLE_REGNUM
-                          && fixed_regs[reg] && call_used_regs[reg]))
+                          && fixed_regs[reg]
+                          && call_used_or_fixed_reg_p (reg)))
                     || (trapa_handler && reg == FPSCR_REG && TARGET_FPU_ANY)))
             || (crtl->calls_eh_return
                 && (reg == EH_RETURN_DATA_REGNO (0)
@@ -7903,7 +7904,7 @@ sh_pass_by_reference (cumulative_args_t cum_v, const function_arg_info &arg)
 {
   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
 
-  if (targetm.calls.must_pass_in_stack (arg.mode, arg.type))
+  if (targetm.calls.must_pass_in_stack (arg))
     return true;
 
   /* ??? std_gimplify_va_arg_expr passes NULL for cum.  That function
@@ -7916,14 +7917,15 @@ sh_pass_by_reference (cumulative_args_t cum_v, const function_arg_info &arg)
 }
 
 static bool
-sh_callee_copies (cumulative_args_t cum, machine_mode mode,
-                 const_tree type, bool named ATTRIBUTE_UNUSED)
+sh_callee_copies (cumulative_args_t cum, const function_arg_info &arg)
 {
   /* ??? How can it possibly be correct to return true only on the
      caller side of the equation?  Is there someplace else in the
      sh backend that's magically producing the copies?  */
   return (get_cumulative_args (cum)->outgoing
-         && ((mode == BLKmode ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode))
+         && ((arg.mode == BLKmode
+              ? TYPE_ALIGN (arg.type)
+              : GET_MODE_ALIGNMENT (arg.mode))
              % SH_MIN_ALIGN_FOR_CALLEE_COPY == 0));
 }
 
@@ -8010,30 +8012,25 @@ sh_arg_partial_bytes (cumulative_args_t cum_v, const function_arg_info &arg)
    Value is zero to push the argument on the stack,
    or a hard register in which to store the argument.
 
-   MODE is the argument's machine mode.
-   TYPE is the data type of the argument (as a tree).
-    This is null for libcalls where that information may
-    not be available.
    CUM is a variable of type CUMULATIVE_ARGS which gives info about
     the preceding args and about the function being called.
-   NAMED is nonzero if this argument is a named parameter
-    (otherwise it is an extra parameter matching an ellipsis).
+   ARG is a description of the argument.
 
    On SH the first args are normally in registers
    and the rest are pushed.  Any arg that starts within the first
    NPARM_REGS words is at least partially passed in a register unless
    its data type forbids.  */
 static rtx
-sh_function_arg (cumulative_args_t ca_v, machine_mode mode,
-                const_tree type, bool named)
+sh_function_arg (cumulative_args_t ca_v, const function_arg_info &arg)
 {
   CUMULATIVE_ARGS *ca = get_cumulative_args (ca_v);
+  machine_mode mode = arg.mode;
 
-  if (mode == VOIDmode)
+  if (arg.end_marker_p ())
     return ca->renesas_abi ? const1_rtx : const0_rtx;
 
-  if (sh_pass_in_reg_p (*ca, mode, type)
-      && (named || ! (TARGET_HITACHI || ca->renesas_abi)))
+  if (sh_pass_in_reg_p (*ca, mode, arg.type)
+      && (arg.named || ! (TARGET_HITACHI || ca->renesas_abi)))
     {
       int regno;
 
@@ -8072,13 +8069,10 @@ sh_function_arg (cumulative_args_t ca_v, machine_mode mode,
   return NULL_RTX;
 }
 
-/* Update the data in CUM to advance over an argument
-   of mode MODE and data type TYPE.
-   (TYPE is null for libcalls where that information may not be
-   available.)  */
+/* Update the data in CUM to advance over argument ARG.  */
 static void
-sh_function_arg_advance (cumulative_args_t ca_v, machine_mode mode,
-                        const_tree type, bool named ATTRIBUTE_UNUSED)
+sh_function_arg_advance (cumulative_args_t ca_v,
+                        const function_arg_info &arg)
 {
   CUMULATIVE_ARGS *ca = get_cumulative_args (ca_v);
 
@@ -8088,7 +8082,7 @@ sh_function_arg_advance (cumulative_args_t ca_v, machine_mode mode,
   if ((TARGET_HITACHI || ca->renesas_abi) && TARGET_FPU_DOUBLE)
     {
       /* Note that we've used the skipped register.  */
-      if (mode == SFmode && ca->free_single_fp_reg)
+      if (arg.mode == SFmode && ca->free_single_fp_reg)
        {
          ca->free_single_fp_reg = 0;
          return;
@@ -8097,21 +8091,19 @@ sh_function_arg_advance (cumulative_args_t ca_v, machine_mode mode,
         skipped in order to align the DF value.  We note this skipped
         register, because the next SF value will use it, and not the
         SF that follows the DF.  */
-      if (mode == DFmode
+      if (arg.mode == DFmode
          && sh_round_reg (*ca, DFmode) != sh_round_reg (*ca, SFmode))
        {
          ca->free_single_fp_reg = (sh_round_reg (*ca, SFmode)
-                                   + BASE_ARG_REG (mode));
+                                   + BASE_ARG_REG (arg.mode));
        }
     }
 
   if (! ((TARGET_SH4 || TARGET_SH2A) || ca->renesas_abi)
-      || sh_pass_in_reg_p (*ca, mode, type))
-    (ca->arg_count[(int) get_sh_arg_class (mode)]
-     = (sh_round_reg (*ca, mode)
-       + (mode == BLKmode
-          ? CEIL (int_size_in_bytes (type), UNITS_PER_WORD)
-          : CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD))));
+      || sh_pass_in_reg_p (*ca, arg.mode, arg.type))
+    (ca->arg_count[(int) get_sh_arg_class (arg.mode)]
+     = (sh_round_reg (*ca, arg.mode)
+       + CEIL (arg.promoted_size_in_bytes (), UNITS_PER_WORD)));
 }
 
 /* The Renesas calling convention doesn't quite fit into this scheme since
@@ -8302,7 +8294,7 @@ sh_fix_range (const char *const_str)
        }
 
       for (int i = first; i <= last; ++i)
-       fixed_regs[i] = call_used_regs[i] = 1;
+       fixed_regs[i] = 1;
 
       if (!comma)
        break;
@@ -8822,7 +8814,7 @@ reg_unused_after (rtx reg, rtx_insn *insn)
       if (set == NULL && reg_overlap_mentioned_p (reg, PATTERN (insn)))
        return false;
 
-      if (code == CALL_INSN && call_really_used_regs[REGNO (reg)])
+      if (code == CALL_INSN && call_used_regs[REGNO (reg)])
        return true;
     }
   return true;
@@ -9644,11 +9636,11 @@ sh_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn, int cost,
 /* Check if INSN is flow-dependent on DEP_INSN.  Can also be used to check
    if DEP_INSN is anti-flow dependent on INSN.  */
 static bool
-flow_dependent_p (rtx insn, rtx dep_insn)
+flow_dependent_p (rtx_insn *insn, rtx_insn *dep_insn)
 {
   rtx tmp = PATTERN (insn);
 
-  note_stores (PATTERN (dep_insn), flow_dependent_p_1, &tmp);
+  note_stores (dep_insn, flow_dependent_p_1, &tmp);
   return tmp == NULL_RTX;
 }
 
@@ -10647,7 +10639,7 @@ sh_hard_regno_caller_save_mode (unsigned int regno, unsigned int nregs,
              && ((regno - FIRST_FP_REG) & 1) == 0)))
     return mode;
 
-  return choose_hard_reg_mode (regno, nregs, false);
+  return choose_hard_reg_mode (regno, nregs, NULL);
 }
 
 /* Implement TARGET_CAN_CHANGE_MODE_CLASS.  */
@@ -10817,10 +10809,11 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
     {
       tree ptype = build_pointer_type (TREE_TYPE (funtype));
 
-      sh_function_arg_advance (pack_cumulative_args (&cum), Pmode, ptype, true);
+      function_arg_info ptr_arg (ptype, Pmode, /*named=*/true);
+      sh_function_arg_advance (pack_cumulative_args (&cum), ptr_arg);
     }
-  this_rtx
-    = sh_function_arg (pack_cumulative_args (&cum), Pmode, ptr_type_node, true);
+  function_arg_info ptr_arg (ptr_type_node, Pmode, /*named=*/true);
+  this_rtx = sh_function_arg (pack_cumulative_args (&cum), ptr_arg);
 
   /* For SHcompact, we only have r0 for a scratch register: r1 is the
      static chain pointer (even if you can't have nested virtual functions
@@ -10828,16 +10821,16 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
      registers are used for argument passing, are callee-saved, or reserved.  */
   /* We need to check call_used_regs / fixed_regs in case -fcall_saved-reg /
      -ffixed-reg has been used.  */
-  if (! call_used_regs[0] || fixed_regs[0])
+  if (! call_used_or_fixed_reg_p (0) || fixed_regs[0])
     error ("r0 needs to be available as a call-clobbered register");
   scratch0 = scratch1 = scratch2 = gen_rtx_REG (Pmode, 0);
 
     {
-      if (call_used_regs[1] && ! fixed_regs[1])
+      if (call_used_or_fixed_reg_p (1) && ! fixed_regs[1])
        scratch1 = gen_rtx_REG (ptr_mode, 1);
       /* N.B., if not TARGET_HITACHI, register 2 is used to pass the pointer
         pointing where to return struct values.  */
-      if (call_used_regs[3] && ! fixed_regs[3])
+      if (call_used_or_fixed_reg_p (3) && ! fixed_regs[3])
        scratch2 = gen_rtx_REG (Pmode, 3);
     }
 
@@ -11459,32 +11452,28 @@ sh_conditional_register_usage (void)
 {
   for (int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno ++)
     if (! VALID_REGISTER_P (regno))
-      fixed_regs[regno] = call_used_regs[regno] = 1;
+      fixed_regs[regno] = 1;
   /* R8 and R9 are call-clobbered on SH5, but not on earlier SH ABIs.  */
   if (flag_pic)
-    {
-      fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
-      call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
-    }
+    fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
   if (TARGET_FDPIC)
     {
       fixed_regs[PIC_REG] = 1;
       call_used_regs[PIC_REG] = 1;
-      call_really_used_regs[PIC_REG] = 1;
     }
   /* Renesas saves and restores mac registers on call.  */
   if (TARGET_HITACHI && ! TARGET_NOMACSAVE)
     {
-      call_really_used_regs[MACH_REG] = 0;
-      call_really_used_regs[MACL_REG] = 0;
+      call_used_regs[MACH_REG] = 0;
+      call_used_regs[MACL_REG] = 0;
     }
 
   for (int regno = FIRST_GENERAL_REG; regno <= LAST_GENERAL_REG; regno++)
-    if (! fixed_regs[regno] && call_really_used_regs[regno])
+    if (! fixed_regs[regno] && call_used_regs[regno])
       SET_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS], regno);
 
-  call_really_used_regs[FPSCR_MODES_REG] = 0;
-  call_really_used_regs[FPSCR_STAT_REG] = 0;
+  call_used_regs[FPSCR_MODES_REG] = 0;
+  call_used_regs[FPSCR_STAT_REG] = 0;
 }
 
 /* Implement TARGET_LEGITIMATE_CONSTANT_P
@@ -11710,7 +11699,7 @@ sh_find_equiv_gbr_addr (rtx_insn* insn, rtx mem)
        {
          if (CALL_P (DF_REF_INSN (d)))
            {
-             if (REGNO_REG_SET_P (regs_invalidated_by_call_regset, GBR_REG))
+             if (TEST_HARD_REG_BIT (regs_invalidated_by_call, GBR_REG))
                return NULL_RTX;
              else
                continue;
@@ -12081,9 +12070,11 @@ sh_extending_set_of_reg::use_as_extended_reg (rtx_insn* use_at_insn) const
        rtx r = gen_reg_rtx (SImode);
        rtx_insn* i0;
        if (from_mode == QImode)
-         i0 = emit_insn_after (gen_extendqisi2 (r, set_src), insn);
+         i0 = sh_check_add_incdec_notes (
+                       emit_insn_after (gen_extendqisi2 (r, set_src), insn));
        else if (from_mode == HImode)
-         i0 = emit_insn_after (gen_extendhisi2 (r, set_src), insn);
+         i0 = sh_check_add_incdec_notes (
+                       emit_insn_after (gen_extendhisi2 (r, set_src), insn));
        else
          gcc_unreachable ();
 
@@ -12501,7 +12492,7 @@ static void
 sh_emit_mode_set (int entity ATTRIBUTE_UNUSED, int mode,
                  int prev_mode, HARD_REG_SET regs_live ATTRIBUTE_UNUSED)
 {
-  if ((TARGET_SH4A_FP || TARGET_SH4_300)
+  if ((TARGET_SH4A_FP || TARGET_FPU_SH4_300)
       && prev_mode != FP_MODE_NONE && prev_mode != mode)
     {
       emit_insn (gen_toggle_pr ());