]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/config/riscv/riscv.c
RISC-V: Add sifive-7 pipeline description.
[thirdparty/gcc.git] / gcc / config / riscv / riscv.c
index d8446f82b9622d054e2fcffe0fb118a1ea703758..9aa0fd2fb71deb1177cbebc2bb9f7f0f843e2521 100644 (file)
@@ -226,6 +226,9 @@ struct riscv_cpu_info {
   /* This CPU's canonical name.  */
   const char *name;
 
+  /* Which automaton to use for tuning.  */
+  enum riscv_microarchitecture_type microarchitecture;
+
   /* Tuning parameters for this CPU.  */
   const struct riscv_tune_info *tune_info;
 };
@@ -246,6 +249,9 @@ static int epilogue_cfa_sp_offset;
 /* Which tuning parameters to use.  */
 static const struct riscv_tune_info *tune_info;
 
+/* Which automaton to use for tuning.  */
+enum riscv_microarchitecture_type riscv_microarchitecture;
+
 /* Index R is the smallest register class that contains register R.  */
 const enum reg_class riscv_regno_to_class[FIRST_PSEUDO_REGISTER] = {
   GR_REGS,     GR_REGS,        GR_REGS,        GR_REGS,
@@ -280,6 +286,19 @@ static const struct riscv_tune_info rocket_tune_info = {
   true,                                                /* slow_unaligned_access */
 };
 
+/* Costs to use when optimizing for Sifive 7 Series.  */
+static const struct riscv_tune_info sifive_7_tune_info = {
+  {COSTS_N_INSNS (4), COSTS_N_INSNS (5)},      /* fp_add */
+  {COSTS_N_INSNS (4), COSTS_N_INSNS (5)},      /* fp_mul */
+  {COSTS_N_INSNS (20), COSTS_N_INSNS (20)},    /* fp_div */
+  {COSTS_N_INSNS (4), COSTS_N_INSNS (4)},      /* int_mul */
+  {COSTS_N_INSNS (6), COSTS_N_INSNS (6)},      /* int_div */
+  2,                                           /* issue_rate */
+  4,                                           /* branch_cost */
+  3,                                           /* memory_cost */
+  true,                                                /* slow_unaligned_access */
+};
+
 /* Costs to use when optimizing for size.  */
 static const struct riscv_tune_info optimize_size_tune_info = {
   {COSTS_N_INSNS (1), COSTS_N_INSNS (1)},      /* fp_add */
@@ -316,8 +335,11 @@ static const struct attribute_spec riscv_attribute_table[] =
 
 /* A table describing all the processors GCC knows about.  */
 static const struct riscv_cpu_info riscv_cpu_info_table[] = {
-  { "rocket", &rocket_tune_info },
-  { "size", &optimize_size_tune_info },
+  { "rocket", generic, &rocket_tune_info },
+  { "sifive-3-series", generic, &rocket_tune_info },
+  { "sifive-5-series", generic, &rocket_tune_info },
+  { "sifive-7-series", sifive_7, &sifive_7_tune_info },
+  { "size", generic, &optimize_size_tune_info },
 };
 
 /* Return the riscv_cpu_info entry for the given name string.  */
@@ -4094,6 +4116,93 @@ riscv_can_use_return_insn (void)
          && ! cfun->machine->interrupt_handler_p);
 }
 
+/* Given that there exists at least one variable that is set (produced)
+   by OUT_INSN and read (consumed) by IN_INSN, return true iff
+   IN_INSN represents one or more memory store operations and none of
+   the variables set by OUT_INSN is used by IN_INSN as the address of a
+   store operation.  If either IN_INSN or OUT_INSN does not represent
+   a "single" RTL SET expression (as loosely defined by the
+   implementation of the single_set function) or a PARALLEL with only
+   SETs, CLOBBERs, and USEs inside, this function returns false.
+
+   Borrowed from rs6000, riscv_store_data_bypass_p checks for certain
+   conditions that result in assertion failures in the generic
+   store_data_bypass_p function and returns FALSE in such cases.
+
+   This is required to make -msave-restore work with the sifive-7
+   pipeline description.  */
+
+bool
+riscv_store_data_bypass_p (rtx_insn *out_insn, rtx_insn *in_insn)
+{
+  rtx out_set, in_set;
+  rtx out_pat, in_pat;
+  rtx out_exp, in_exp;
+  int i, j;
+
+  in_set = single_set (in_insn);
+  if (in_set)
+    {
+      if (MEM_P (SET_DEST (in_set)))
+       {
+         out_set = single_set (out_insn);
+         if (!out_set)
+           {
+             out_pat = PATTERN (out_insn);
+             if (GET_CODE (out_pat) == PARALLEL)
+               {
+                 for (i = 0; i < XVECLEN (out_pat, 0); i++)
+                   {
+                     out_exp = XVECEXP (out_pat, 0, i);
+                     if ((GET_CODE (out_exp) == CLOBBER)
+                         || (GET_CODE (out_exp) == USE))
+                       continue;
+                     else if (GET_CODE (out_exp) != SET)
+                       return false;
+                   }
+               }
+           }
+       }
+    }
+  else
+    {
+      in_pat = PATTERN (in_insn);
+      if (GET_CODE (in_pat) != PARALLEL)
+       return false;
+
+      for (i = 0; i < XVECLEN (in_pat, 0); i++)
+       {
+         in_exp = XVECEXP (in_pat, 0, i);
+         if ((GET_CODE (in_exp) == CLOBBER) || (GET_CODE (in_exp) == USE))
+           continue;
+         else if (GET_CODE (in_exp) != SET)
+           return false;
+
+         if (MEM_P (SET_DEST (in_exp)))
+           {
+             out_set = single_set (out_insn);
+             if (!out_set)
+               {
+                 out_pat = PATTERN (out_insn);
+                 if (GET_CODE (out_pat) != PARALLEL)
+                   return false;
+                 for (j = 0; j < XVECLEN (out_pat, 0); j++)
+                   {
+                     out_exp = XVECEXP (out_pat, 0, j);
+                     if ((GET_CODE (out_exp) == CLOBBER)
+                         || (GET_CODE (out_exp) == USE))
+                       continue;
+                     else if (GET_CODE (out_exp) != SET)
+                       return false;
+                   }
+               }
+           }
+       }
+    }
+
+  return store_data_bypass_p (out_insn, in_insn);
+}
+
 /* Implement TARGET_SECONDARY_MEMORY_NEEDED.
 
    When floating-point registers are wider than integer ones, moves between
@@ -4358,6 +4467,7 @@ riscv_option_override (void)
   /* Handle -mtune.  */
   cpu = riscv_parse_cpu (riscv_tune_string ? riscv_tune_string :
                         RISCV_TUNE_STRING_DEFAULT);
+  riscv_microarchitecture = cpu->microarchitecture;
   tune_info = optimize_size ? &optimize_size_tune_info : cpu->tune_info;
 
   /* Use -mtune's setting for slow_unaligned_access, even when optimizing