From: feedable <[email protected]>

All of GCC's RTL machinery currently expects no instruction to exceed
MAX_RECOG_OPERANDS (which is 30). This is fine for most targets, since
they don't usually have more than 30 things of note anyway, and there
are not many ways to run out of operands in an asm stmt. However, it may
still happen, and there are targets now that will want an arbitrary
amount of operands (e.g. wasm's call family of insns).

For that reason, this patch seeks to remove this limit, primarily by
replacing instances of static C arrays of bound MAX_RECOG_OPERANDS by
small vectors of the same bound, but which can allocate more if there
are more operands.

This patch currently does not provide a way to actually define insn
patterns with an arbitrary number of operands, nor does it touch the
machine description infrastructure, so the only observable effect is
asm_operands now having an arbitrary amount of operands.

Many functions take in a pair of pointer+size to pass an array, this
patch replaces that by array_slice parameters.

LRA also makes use of -1-terminated arrays, mostly because it's more
convenient than maintaining a separate array of sizes for its arrays
of arrays. This is mostly redundant now, since the arrays-of-arrays
are now handled by vectors-of-vectors. The relevant functions now
accept array_slice parameters instead.

IRA has a global bitmap for all insns and operands to mark scratches,
and it relies on a fixed number of operands to avoid overlap. There
isn't an easy way to convert that to support an arbitrary operand
count, so a supplemental one is added to handle operands over the
limit.

gcc/ChangeLog:

        * cfgexpand.cc (expand_asm_stmt): Remove the asm operand limit
        * cse.cc (qty_table): Turn into a vector.
        (new_basic_block): Handle vectors instead of arrays.
        (make_new_qty): Likewise.
        (cse_extended_basic_block): Likewise.
        (cse_main): Remove the upper bound.
        * emit-rtl.cc (copy_insn_scratch): Replace arrays by
        operand_vec.
        (copy_insn_1): Use as operand_vec.
        (copy_insn): Likewise.
        (rtx_expander::rtx_expander): Use bitmaps.
        (rtx_expander::get_unshared_operand): Likewise.
        * final.cc (output_asm_operand_names): Use array_slice.
        (get_insn_template): Adjust for operand_vec.
        (final_scan_insn_1): Adjust for array_slice.
        (output_asm_insn): Remove MAX_RECOG_OPERANDS, replace arrays by
        operand_vec.
        * genattrtab.cc (write_header): Convert of vector to C array.
        * haifa-sched.cc (model_recompute): Replace arrays by
        operand_vec.
        * ira-conflicts.cc (process_reg_shuffles): Use array_slice.
        (add_insn_allocno_copies):Replace arrays by operand_vec.
        * ira-costs.cc (op_costs_nops): Describe the number of
        elements in op_costs and this_op_costs.
        (ira_ensure_cost_capacity): Utility fn to resize op_costs.
        (record_reg_classes): Replace arrays by
        operand_vec, use array_slice.
        (record_operand_costs): Likewise.
        (scan_one_insn):Handle op_costs being dynamic.
        (ira_init_costs_once): Likewise.
        (target_ira_int::free_ira_costs): Likewise.
        (ira_init_costs): Likewise.
        * ira-int.h: Likewsie.
        * ira.cc (ira_former_scratch_operand_p): Introduce storage for
        additional operands.
        (ira_register_new_scratch_op): Likewise.
        (remove_scratches): Likewise.
        (ira_restore_scratches): Likewise.
        * ira.h (ira_former_scratch_operand_p): Use unsigned for opno.
        (ira_register_new_scratch_op): Likewise.
        * loop-invariant.cc (regs_set[): Turn into a vector.
        (mark_reg_store): Handle vector.
        (calculate_loop_reg_pressure): Handle vector.
        * lra-constraints.cc (init_curr_operand_mode): Replace
        arrays by operand_vec, use array_slice.
        (get_reload_reg): Likewise.
        (check_conflict_input_operands): Likewise.
        (match_reload): Likewise.
        (check_and_process_move): Likewise.
        (process_alt_operands): Likewise.
        (curr_insn_transform): Likewsie.
        (MAX_RELOAD_INSNS_PER_OPERAND_NUMBER): Add per-operand limit.
        (combine_reload_insn): Use vectors.
        (lra_constraints): Compute max reload count exactly.
        (add_to_inherit): Handle vector.
        (inherit_in_ebb): Likewise.
        * lra-eliminations.cc (eliminate_regs_in_insn): Use vectors.
        * lra-int.h (lra_update_dups): Use array_slice.
        * lra.cc (lra_update_dups): Likewise.
        (lra_set_insn_recog_data): Likewise.
        (lra_update_insn_recog_data): Likewise.
        * postreload.cc (reload_cse_simplify_operands): Likewise.
        * recog.cc (check_asm_operands): Replace arrays by
        operand_vec, use array_slice.
        (decode_asm_operands): Likewise.
        (asm_operand_ok): Likewise.
        (extract_insn): Likewise.
        (preprocess_constraints): Likewise.
        (constrain_operands): Likewise.
        * recog.h (asm_operand_ok): Likewise.
        (struct recog_data_d): Use the new types.
        * regrename.cc (hide_operands): Replace arrays by operand_vec,
        use array_slice.
        (restore_operands): Likewise.
        (build_def_use): Likewise.
        * reload.cc (struct reload): Likewise.
        * rtl.h (decode_asm_operands): Replace arrays by operand_vec,
        use array_slice.
        * varasm.cc (assemble_asm): Likewise.

gcc/testsuite/ChangeLog:

        * gcc.dg/pr61692.c: Mark >30 ops as allowed.
---
 gcc/cfgexpand.cc               |  21 +--
 gcc/cse.cc                     |  44 ++---
 gcc/emit-rtl.cc                |  28 ++-
 gcc/final.cc                   |  74 ++++----
 gcc/genattrtab.cc              |   2 +-
 gcc/haifa-sched.cc             |  18 +-
 gcc/ira-conflicts.cc           |   4 +-
 gcc/ira-costs.cc               |  77 +++++---
 gcc/ira-int.h                  |   6 +-
 gcc/ira.cc                     |  39 +++-
 gcc/ira.h                      |   5 +-
 gcc/loop-invariant.cc          |  13 +-
 gcc/lra-constraints.cc         | 315 ++++++++++++++++-----------------
 gcc/lra-eliminations.cc        |   4 +-
 gcc/lra-int.h                  |   5 +-
 gcc/lra.cc                     |  46 ++---
 gcc/postreload.cc              |  10 +-
 gcc/recog.cc                   |  86 ++++-----
 gcc/recog.h                    |  40 ++++-
 gcc/regrename.cc               |  30 ++--
 gcc/reload.cc                  |   4 +-
 gcc/rtl.h                      |   7 +-
 gcc/testsuite/gcc.dg/pr61692.c |  10 +-
 gcc/varasm.cc                  |   8 +-
 24 files changed, 466 insertions(+), 430 deletions(-)

diff --git a/gcc/cfgexpand.cc b/gcc/cfgexpand.cc
index 128cfc77684be..bb5e52a54741b 100644
--- a/gcc/cfgexpand.cc
+++ b/gcc/cfgexpand.cc
@@ -3445,16 +3445,9 @@ expand_asm_stmt (gasm *stmt)
   unsigned i;
   bool error_seen = false;
 
-  /* ??? Diagnose during gimplification?  */
-  if (ninputs + noutputs + nlabels > MAX_RECOG_OPERANDS)
-    {
-      error_at (locus, "more than %d operands in %<asm%>", MAX_RECOG_OPERANDS);
-      return;
-    }
-
-  auto_vec<tree, MAX_RECOG_OPERANDS> output_tvec;
-  auto_vec<tree, MAX_RECOG_OPERANDS> input_tvec;
-  auto_vec<const char *, MAX_RECOG_OPERANDS> constraints;
+  operand_vec<tree> output_tvec;
+  operand_vec<tree> input_tvec;
+  operand_vec<const char *> constraints;
 
   /* Copy the gimple vectors into new vectors that we can manipulate.  */
 
@@ -3644,8 +3637,8 @@ expand_asm_stmt (gasm *stmt)
   int old_generating_concat_p = generating_concat_p;
 
   /* Vector of RTX's of evaluated output operands.  */
-  auto_vec<rtx, MAX_RECOG_OPERANDS> output_rvec;
-  auto_vec<int, MAX_RECOG_OPERANDS> inout_opnum;
+  operand_vec<rtx> output_rvec;
+  operand_vec<int> inout_opnum;
   rtx_insn *after_rtl_seq = NULL, *after_rtl_end = NULL;
 
   output_rvec.safe_grow (noutputs, true);
@@ -3745,8 +3738,8 @@ expand_asm_stmt (gasm *stmt)
       str = "";
     }
 
-  auto_vec<rtx, MAX_RECOG_OPERANDS> input_rvec;
-  auto_vec<machine_mode, MAX_RECOG_OPERANDS> input_mode;
+  operand_vec<rtx> input_rvec;
+  operand_vec<machine_mode> input_mode;
 
   input_rvec.safe_grow (ninputs, true);
   input_mode.safe_grow (ninputs, true);
diff --git a/gcc/cse.cc b/gcc/cse.cc
index f573c54744cb5..e18d21f7b1620 100644
--- a/gcc/cse.cc
+++ b/gcc/cse.cc
@@ -207,16 +207,6 @@ Related expressions:
    so that it is possible to find out if there exists any
    register equivalent to an expression related to a given expression.  */
 
-/* Length of qty_table vector.  We know in advance we will not need
-   a quantity number this big.  */
-
-static int max_qty;
-
-/* Next quantity number to be allocated.
-   This is 1 + the largest number needed so far.  */
-
-static int next_qty;
-
 /* Per-qty information tracking.
 
    `first_reg' and `last_reg' track the head and tail of the
@@ -254,7 +244,7 @@ struct qty_table_elem
 };
 
 /* The table of all qtys, indexed by qty number.  */
-static struct qty_table_elem *qty_table;
+static auto_vec<qty_table_elem, MAX_RECOG_OPERANDS * 100> qty_table;
 
 /* Insn being scanned.  */
 
@@ -843,7 +833,7 @@ new_basic_block (void)
 {
   int i;
 
-  next_qty = 0;
+  qty_table.truncate (0);
 
   /* Invalidate cse_reg_info_table.  */
   cse_reg_info_timestamp++;
@@ -883,19 +873,16 @@ new_basic_block (void)
 static void
 make_new_qty (unsigned int reg, machine_mode mode)
 {
-  int q;
-  struct qty_table_elem *ent;
   struct reg_eqv_elem *eqv;
 
-  gcc_assert (next_qty < max_qty);
-
-  q = REG_QTY (reg) = next_qty++;
-  ent = &qty_table[q];
-  ent->first_reg = reg;
-  ent->last_reg = reg;
-  ent->mode = mode;
-  ent->const_rtx = ent->const_insn = NULL;
-  ent->comparison_code = UNKNOWN;
+  REG_QTY (reg) = qty_table.length ();
+  struct qty_table_elem ent;
+  ent.first_reg = reg;
+  ent.last_reg = reg;
+  ent.mode = mode;
+  ent.const_rtx = ent.const_insn = NULL;
+  ent.comparison_code = UNKNOWN;
+  qty_table.safe_push (ent);
 
   eqv = &reg_eqv_table[reg];
   eqv->next = eqv->prev = -1;
@@ -6722,7 +6709,7 @@ cse_extended_basic_block (struct cse_basic_block_data 
*ebb_data)
   int num_insns = 0;
 
   /* Allocate the space needed by qty_table.  */
-  qty_table = XNEWVEC (struct qty_table_elem, max_qty);
+  qty_table.truncate (0);
 
   new_basic_block ();
   cse_ebb_live_in = df_get_live_in (ebb_data->path[0].bb);
@@ -6847,9 +6834,7 @@ cse_extended_basic_block (struct cse_basic_block_data 
*ebb_data)
        }
     }
 
-  gcc_assert (next_qty <= max_qty);
-
-  free (qty_table);
+  qty_table.truncate (0);
 }
 
 
@@ -7033,11 +7018,6 @@ cse_main (rtx_insn *f ATTRIBUTE_UNUSED, int nregs)
              df_insn_rescan (match.widest_insn);
        }
 
-         /* Get a reasonable estimate for the maximum number of qty's
-            needed for this path.  For this, we take the number of sets
-            and multiply that by MAX_RECOG_OPERANDS.  */
-         max_qty = ebb_data.nsets * MAX_RECOG_OPERANDS;
-
          /* Dump the path we're about to process.  */
          if (dump_file)
            cse_dump_path (&ebb_data, ebb_data.nsets, dump_file);
diff --git a/gcc/emit-rtl.cc b/gcc/emit-rtl.cc
index 4a23eaefe0246..7747d3e0402a1 100644
--- a/gcc/emit-rtl.cc
+++ b/gcc/emit-rtl.cc
@@ -5795,9 +5795,7 @@ init_virtual_regs (void)
 
 
 /* Used by copy_insn_1 to avoid copying SCRATCHes more than once.  */
-static rtx copy_insn_scratch_in[MAX_RECOG_OPERANDS];
-static rtx copy_insn_scratch_out[MAX_RECOG_OPERANDS];
-static int copy_insn_n_scratches;
+static operand_vec<std::pair<rtx, rtx>> copy_insn_scratch;
 
 /* When an insn is being copied by copy_insn_1, this is nonzero if we have
    copied an ASM_OPERANDS.
@@ -5856,9 +5854,9 @@ copy_insn_1 (rtx orig)
       break;
 
     case SCRATCH:
-      for (i = 0; i < copy_insn_n_scratches; i++)
-       if (copy_insn_scratch_in[i] == orig)
-         return copy_insn_scratch_out[i];
+      for (auto &scratch: copy_insn_scratch)
+       if (scratch.first == orig)
+         return scratch.second;
       break;
 
     case CONST:
@@ -5930,12 +5928,7 @@ copy_insn_1 (rtx orig)
       }
 
   if (code == SCRATCH)
-    {
-      i = copy_insn_n_scratches++;
-      gcc_assert (i < MAX_RECOG_OPERANDS);
-      copy_insn_scratch_in[i] = orig;
-      copy_insn_scratch_out[i] = copy;
-    }
+    copy_insn_scratch.safe_push ({orig, copy});
   else if (code == ASM_OPERANDS)
     {
       orig_asm_operands_vector = ASM_OPERANDS_INPUT_VEC (orig);
@@ -5955,7 +5948,7 @@ copy_insn_1 (rtx orig)
 rtx
 copy_insn (rtx insn)
 {
-  copy_insn_n_scratches = 0;
+  copy_insn_scratch.truncate (0);
   orig_asm_operands_vector = 0;
   orig_asm_constraints_vector = 0;
   copy_asm_operands_vector = 0;
@@ -6834,12 +6827,12 @@ protected:
      MATCH_OPERAND or MATCH_DUP.  In order to ensure correct sharing,
      further replacements need to use a copy of the operand, rather than
      the original rtx.  */
-  bbitmap<MAX_RECOG_OPERANDS> m_used;
+  bitmap m_used;
 };
 }
 
 rtx_expander::rtx_expander (const uint8_t *seq, rtx *operands)
-  : m_seq (seq), m_operands (operands), m_used ()
+  : m_seq (seq), m_operands (operands), m_used (bitmap_gc_alloc ())
 {}
 
 /* Read and return the next encoded "BEB128" integer.  */
@@ -6873,11 +6866,10 @@ rtx
 rtx_expander::get_unshared_operand ()
 {
   auto opno = get_uint ();
-  auto mask = m_used.from_index (opno);
-  if (m_used & mask)
+  if (bitmap_bit_p (m_used, opno))
     return copy_rtx (m_operands[opno]);
 
-  m_used |= mask;
+  bitmap_set_bit (m_used, opno);
   return m_operands[opno];
 }
 
diff --git a/gcc/final.cc b/gcc/final.cc
index 0152be59fc85a..847d1e6ce543b 100644
--- a/gcc/final.cc
+++ b/gcc/final.cc
@@ -197,7 +197,7 @@ static rtx walk_alter_subreg (rtx *, bool *);
 static void output_asm_name (void);
 static void output_alternate_entry_point (FILE *, rtx_insn *);
 static tree get_mem_expr_from_op (rtx, int *);
-static void output_asm_operand_names (rtx *, int *, int);
+static void output_asm_operand_names (rtx *, array_slice<int>);
 #ifdef LEAF_REGISTERS
 static void leaf_renumber_regs (rtx_insn *);
 #endif
@@ -2031,7 +2031,8 @@ get_insn_template (int code, rtx_insn *insn)
       return insn_data[code].output.multi[which_alternative];
     case INSN_OUTPUT_FORMAT_FUNCTION:
       gcc_assert (insn);
-      return (*insn_data[code].output.function) (recog_data.operand, insn);
+      return (*insn_data[code].output.function) (recog_data.operand.address (),
+             insn);
 
     default:
       gcc_unreachable ();
@@ -2632,7 +2633,8 @@ final_scan_insn_1 (rtx_insn *insn, FILE *file, int 
optimize_p ATTRIBUTE_UNUSED,
            CC_STATUS_INIT;
 
            /* Get out the operand values.  */
-           string = decode_asm_operands (body, ops, NULL, NULL, NULL, &loc);
+           string = decode_asm_operands (body, {ops, noperands},
+                                         NULL, NULL, NULL, &loc);
            /* Inhibit dying on what would otherwise be compiler bugs.  */
            insn_noperands = noperands;
            this_is_asm_operands = insn;
@@ -2776,7 +2778,8 @@ final_scan_insn_1 (rtx_insn *insn, FILE *file, int 
optimize_p ATTRIBUTE_UNUSED,
           it is output.  */
 
 #ifdef FINAL_PRESCAN_INSN
-       FINAL_PRESCAN_INSN (insn, recog_data.operand, recog_data.n_operands);
+       FINAL_PRESCAN_INSN (insn, recog_data.operand.address (),
+                           recog_data.n_operands);
 #endif
 
        if (targetm.have_conditional_execution ()
@@ -2853,12 +2856,13 @@ final_scan_insn_1 (rtx_insn *insn, FILE *file, int 
optimize_p ATTRIBUTE_UNUSED,
          }
 
        /* Output assembler code from the template.  */
-       output_asm_insn (templ, recog_data.operand);
+       output_asm_insn (templ, recog_data.operand.address ());
 
        /* Some target machines need to postscan each insn after
           it is output.  */
        if (targetm.asm_out.final_postscan_insn)
-         targetm.asm_out.final_postscan_insn (file, insn, recog_data.operand,
+         targetm.asm_out.final_postscan_insn (file, insn,
+                                              recog_data.operand.address (),
                                               recog_data.n_operands);
 
        if (!targetm.asm_out.unwind_emit_before_insn
@@ -3287,17 +3291,15 @@ get_mem_expr_from_op (rtx op, int *paddressp)
    is the number of operands to write.  */
 
 static void
-output_asm_operand_names (rtx *operands, int *oporder, int nops)
+output_asm_operand_names (rtx *operands, array_slice<int> oporder)
 {
   int wrote = 0;
-  int i;
 
-  for (i = 0; i < nops; i++)
+  for (int opnum : oporder)
     {
       int addressp;
-      int opnum = oporder[i];
       /* Skip invalid ops. */
-      if (opnum == MAX_RECOG_OPERANDS)
+      if (opnum == -1)
        continue;
       rtx op = operands[opnum];
       tree expr = get_mem_expr_from_op (op, &addressp);
@@ -3432,16 +3434,26 @@ output_asm_insn (const char *templ, rtx *operands)
 #ifdef ASSEMBLER_DIALECT
   int dialect = 0;
 #endif
-  int oporder[MAX_RECOG_OPERANDS+1];
-  char opoutput[MAX_RECOG_OPERANDS+1];
-  int ops = 0;
+
+  operand_vec<int> oporder;
+  operand_vec<int> opoutput;
+  auto record_operand = [&](long idx)
+    {
+      if (idx < 0)
+       return;
+      if (opoutput.length () <= idx)
+       opoutput.safe_grow_cleared (idx + 1);
+      bool res = opoutput[idx];
+      opoutput[idx] = 1;
+      if (!res)
+       oporder.safe_push (idx);
+    };
 
   /* An insn may return a null string template
      in a case where no assembler code is needed.  */
   if (*templ == 0)
     return;
 
-  memset (opoutput, 0, sizeof opoutput);
   p = templ;
   putc ('\t', asm_out_file);
 
@@ -3454,12 +3466,12 @@ output_asm_insn (const char *templ, rtx *operands)
       {
       case '\n':
        if (flag_verbose_asm)
-         output_asm_operand_names (operands, oporder, ops);
+         output_asm_operand_names (operands, oporder);
        if (flag_print_asm_name)
          output_asm_name ();
 
-       ops = 0;
-       memset (opoutput, 0, sizeof opoutput);
+       oporder.truncate (0);
+       opoutput.truncate (0);
 
        putc (c, asm_out_file);
 #ifdef ASM_OUTPUT_OPCODE
@@ -3509,7 +3521,7 @@ output_asm_insn (const char *templ, rtx *operands)
        else if (ISALPHA (*p))
          {
            int letter = *p++;
-           unsigned long opnum;
+           long opnum;
            char *endptr;
            int letter2 = 0;
 
@@ -3518,12 +3530,16 @@ output_asm_insn (const char *templ, rtx *operands)
            opnum = strtoul (p, &endptr, 10);
 
            if (endptr == p)
-             output_operand_lossage ("operand number missing "
-                                     "after %%-letter");
+             {
+               /* Force the opnum in bounds to a bogus location.  */
+               opnum = -1;
+               output_operand_lossage ("operand number missing "
+                                       "after %%-letter");
+             }
            else if (this_is_asm_operands && opnum >= insn_noperands)
              {
-               /* Force the opnum in bounds to a bogus location. */
-               opnum = MAX_RECOG_OPERANDS;
+               /* Force the opnum in bounds to a bogus location.  */
+               opnum = -1;
                output_operand_lossage ("operand number out of range");
              }
            else if (letter == 'l')
@@ -3551,9 +3567,7 @@ output_asm_insn (const char *templ, rtx *operands)
            else
              output_operand (operands[opnum], letter);
 
-           if (!opoutput[opnum])
-             oporder[ops++] = opnum;
-           opoutput[opnum] = 1;
+           record_operand (opnum);
 
            p = endptr;
            c = *p;
@@ -3568,15 +3582,13 @@ output_asm_insn (const char *templ, rtx *operands)
            if (this_is_asm_operands && opnum >= insn_noperands)
              {
                /* Force the opnum in bounds to a bogus location. */
-               opnum = MAX_RECOG_OPERANDS;
+               opnum = -1;
                output_operand_lossage ("operand number out of range");
              }
            else
              output_operand (operands[opnum], 0);
 
-           if (!opoutput[opnum])
-             oporder[ops++] = opnum;
-           opoutput[opnum] = 1;
+           record_operand (opnum);
 
            p = endptr;
            c = *p;
@@ -3600,7 +3612,7 @@ output_asm_insn (const char *templ, rtx *operands)
 
   /* Write out the variable names for operands, if we know them.  */
   if (flag_verbose_asm)
-    output_asm_operand_names (operands, oporder, ops);
+    output_asm_operand_names (operands, oporder);
   if (flag_print_asm_name)
     output_asm_name ();
 
diff --git a/gcc/genattrtab.cc b/gcc/genattrtab.cc
index a2cf08d530583..1dc0515cb6c4a 100644
--- a/gcc/genattrtab.cc
+++ b/gcc/genattrtab.cc
@@ -5203,7 +5203,7 @@ write_header (FILE *outf)
   fprintf (outf, "#include \"flags.h\"\n");
   fprintf (outf, "#include \"emit-rtl.h\"\n");
   fprintf (outf, "\n");
-  fprintf (outf, "#define operands recog_data.operand\n\n");
+  fprintf (outf, "#define operands (recog_data.operand.address ())\n\n");
 }
 
 static FILE *
diff --git a/gcc/haifa-sched.cc b/gcc/haifa-sched.cc
index 879749e9785d1..28d20bdc55999 100644
--- a/gcc/haifa-sched.cc
+++ b/gcc/haifa-sched.cc
@@ -2116,15 +2116,16 @@ model_update_pressure (struct model_pressure_group 
*group,
 static void
 model_recompute (rtx_insn *insn)
 {
-  struct {
+  struct uses_t {
     int last_use;
     int regno;
-  } uses[FIRST_PSEUDO_REGISTER + MAX_RECOG_OPERANDS];
+  };
+  auto_vec<uses_t, FIRST_PSEUDO_REGISTER + MAX_RECOG_OPERANDS> uses;
   struct reg_use_data *use;
   struct reg_pressure_data *reg_pressure;
   int delta[N_REG_CLASSES];
   int pci, point, mix, new_last, cl, ref_pressure, queue;
-  unsigned int i, num_uses, num_pending_births;
+  unsigned int i, num_pending_births;
   bool print_p;
 
   /* The destinations of INSN were previously live from POINT onwards, but are
@@ -2141,7 +2142,6 @@ model_recompute (rtx_insn *insn)
      before POINT.  Adjust DELTA so that it represents the effect of
      this change after POINT - 1.  Set NUM_PENDING_BIRTHS to the number of
      registers that will be born in the range [model_curr_point, POINT).  */
-  num_uses = 0;
   num_pending_births = 0;
   bitmap_clear (tmp_bitmap);
   for (use = INSN_REG_USE_LIST (insn); use != NULL; use = use->next_insn_use)
@@ -2155,12 +2155,9 @@ model_recompute (rtx_insn *insn)
             currently assumed to be live.  */
          && bitmap_bit_p (curr_reg_live, use->regno))
        {
-         gcc_assert (num_uses < ARRAY_SIZE (uses));
-         uses[num_uses].last_use = new_last;
-         uses[num_uses].regno = use->regno;
+         uses.safe_push ({new_last, use->regno});
          /* This register is no longer live after POINT - 1.  */
          mark_regno_birth_or_death (NULL, delta, use->regno, false);
-         num_uses++;
          if (new_last >= 0)
            num_pending_births++;
        }
@@ -2190,7 +2187,7 @@ model_recompute (rtx_insn *insn)
               after POINT.  Make it describe the effect on the pressure
               before POINT.  */
            i = 0;
-           while (i < num_uses)
+           while (i < uses.length ())
              {
                if (uses[i].last_use == point)
                  {
@@ -2199,8 +2196,7 @@ model_recompute (rtx_insn *insn)
                                               uses[i].regno, true);
 
                    /* Remove this use from the array.  */
-                   uses[i] = uses[num_uses - 1];
-                   num_uses--;
+                   uses.unordered_remove (i);
                    num_pending_births--;
                  }
                else
diff --git a/gcc/ira-conflicts.cc b/gcc/ira-conflicts.cc
index b5152ffaeceea..24d6231d01b92 100644
--- a/gcc/ira-conflicts.cc
+++ b/gcc/ira-conflicts.cc
@@ -465,7 +465,7 @@ can_use_same_reg_p (rtx_insn *insn, int output, int input)
    them with frequency FREQ.  */
 static void
 process_reg_shuffles (rtx_insn *insn, rtx reg, int op_num, int freq,
-                     bool *bound_p)
+                     array_slice<bool> bound_p)
 {
   int i;
   rtx another_reg;
@@ -497,7 +497,6 @@ static void
 add_insn_allocno_copies (rtx_insn *insn)
 {
   rtx set = single_set (insn), operand, dup;
-  bool bound_p[MAX_RECOG_OPERANDS];
   int i, n, freq;
   alternative_mask alts;
 
@@ -529,6 +528,7 @@ add_insn_allocno_copies (rtx_insn *insn)
   if (! find_reg_note (insn, REG_DEAD, NULL_RTX))
     return;
   alts = ira_setup_alts (insn);
+  operand_vec<bool> bound_p (recog_data.n_operands, {});
   for (i = 0; i < recog_data.n_operands; i++)
     bound_p[i] = false;
   for (i = 0; i < recog_data.n_operands; i++)
diff --git a/gcc/ira-costs.cc b/gcc/ira-costs.cc
index 65cb75895b846..ce0f5a73717e8 100644
--- a/gcc/ira-costs.cc
+++ b/gcc/ira-costs.cc
@@ -64,11 +64,16 @@ struct costs
   (this_target_ira_int->x_init_cost)
 #define temp_costs \
   (this_target_ira_int->x_temp_costs)
+#define op_costs_nops \
+  (this_target_ira_int->x_op_costs_nops)
 #define op_costs \
   (this_target_ira_int->x_op_costs)
 #define this_op_costs \
   (this_target_ira_int->x_this_op_costs)
 
+
+static void ira_ensure_cost_capacity (size_t size);
+
 /* Costs of each class for each allocno or pseudo.  */
 static struct costs *costs;
 
@@ -496,13 +501,14 @@ copy_cost (rtx x, machine_mode mode, reg_class_t rclass, 
bool to_p,
    The cost of each class for this insn is its lowest cost among all
    the alternatives.  */
 static void
-record_reg_classes (int n_alts, int n_ops, rtx *ops,
-                   machine_mode *modes, const char **constraints,
+record_reg_classes (int n_alts, int n_ops, array_slice<rtx> ops,
+                   array_slice<machine_mode> modes,
+                   array_slice<const char *> constraints,
                    rtx_insn *insn, enum reg_class *pref)
 {
   int alt;
   int i, j, k;
-  int insn_allows_mem[MAX_RECOG_OPERANDS];
+  operand_vec<int> insn_allows_mem (n_ops, 0);
   move_table *move_in_cost, *move_out_cost;
   short (*mem_cost)[2];
   const char *p;
@@ -518,16 +524,14 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
       dump_insn_slim (ira_dump_file, insn);
   }
 
-  for (i = 0; i < n_ops; i++)
-    insn_allows_mem[i] = 0;
-
   /* Process each alternative, each time minimizing an operand's cost
      with the cost for each operand in that alternative.  */
   alternative_mask preferred = get_preferred_alternatives (insn);
   for (alt = 0; alt < n_alts; alt++)
     {
-      enum reg_class classes[MAX_RECOG_OPERANDS];
-      int allows_mem[MAX_RECOG_OPERANDS];
+      /* Initially show we know nothing about the register class.  */
+      operand_vec<reg_class> classes (n_ops, NO_REGS);
+      operand_vec<int> allows_mem (n_ops, 0);
       enum reg_class rclass;
       int alt_fail = 0;
       int alt_cost = 0, op_cost_add;
@@ -555,6 +559,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
          fprintf (ira_dump_file, "\n");
        }
 
+      ira_ensure_cost_capacity (n_ops);
       for (i = 0; i < n_ops; i++)
        {
          unsigned char c;
@@ -564,10 +569,6 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
          int allows_addr = 0;
          int win = 0;
 
-         /* Initially show we know nothing about the register class.  */
-         classes[i] = NO_REGS;
-         allows_mem[i] = 0;
-
          /* If this operand has no constraints at all, we can
             conclude nothing about it since anything is valid.  */
          if (*p == 0)
@@ -1357,11 +1358,12 @@ record_address_regs (machine_mode mode, addr_space_t 
as, rtx x,
 static void
 record_operand_costs (rtx_insn *insn, enum reg_class *pref)
 {
-  const char *constraints[MAX_RECOG_OPERANDS];
-  machine_mode modes[MAX_RECOG_OPERANDS];
+  operand_vec<const char *> constraints (recog_data.n_operands, nullptr);
+  operand_vec<machine_mode> modes (recog_data.n_operands, VOIDmode);
   rtx set;
   int i;
 
+  ira_ensure_cost_capacity (recog_data.n_operands);
   if ((set = single_set (insn)) != NULL_RTX
       /* In rare cases the single set insn might have less 2 operands
         as the source can be a fixed special reg.  */
@@ -1505,7 +1507,7 @@ record_operand_costs (rtx_insn *insn, enum reg_class 
*pref)
   for (i = 0; i < (int) recog_data.n_operands - 1; i++)
     if (constraints[i][0] == '%')
       {
-       const char *xconstraints[MAX_RECOG_OPERANDS];
+       operand_vec<const char *> xconstraints (recog_data.n_operands, nullptr);
        int j;
 
        /* Handle commutative operands by swapping the
@@ -1629,6 +1631,7 @@ scan_one_insn (rtx_insn *insn)
 
   /* Now add the cost for each operand to the total costs for its
      allocno.  */
+  ira_ensure_cost_capacity (recog_data.n_operands);
   for (i = 0; i < recog_data.n_operands; i++)
     {
       rtx op = recog_data.operand[i];
@@ -2559,35 +2562,55 @@ setup_allocno_class_and_costs (void)
 void
 ira_init_costs_once (void)
 {
-  int i;
-
   init_cost = NULL;
-  for (i = 0; i < MAX_RECOG_OPERANDS; i++)
-    {
-      op_costs[i] = NULL;
-      this_op_costs[i] = NULL;
-    }
   temp_costs = NULL;
+  op_costs_nops = 0;
+  op_costs = 0;
+  this_op_costs = 0;
 }
 
 /* Free allocated temporary cost vectors.  */
 void
 target_ira_int::free_ira_costs ()
 {
-  int i;
+  size_t i;
 
   free (x_init_cost);
   x_init_cost = NULL;
-  for (i = 0; i < MAX_RECOG_OPERANDS; i++)
+  for (i = 0; i < x_op_costs_nops; i++)
     {
       free (x_op_costs[i]);
       free (x_this_op_costs[i]);
       x_op_costs[i] = x_this_op_costs[i] = NULL;
     }
+  x_op_costs_nops = 0;
+  free (x_op_costs);
+  free (x_this_op_costs);
+  x_op_costs = 0;
+  x_this_op_costs = 0;
   free (x_temp_costs);
   x_temp_costs = NULL;
 }
 
+static void
+ira_ensure_cost_capacity (size_t size)
+{
+  if (size <= op_costs_nops)
+    return;
+
+  op_costs = (struct costs **) xrealloc (op_costs,
+                                        size * sizeof (struct costs *));
+  this_op_costs = (struct costs **) xrealloc (this_op_costs,
+                                             size * sizeof (struct costs *));
+
+  for (size_t i = op_costs_nops; i < size; i++)
+    {
+      op_costs[i] = (struct costs *) xmalloc (max_struct_costs_size);
+      this_op_costs[i] = (struct costs *) xmalloc (max_struct_costs_size);
+    }
+  op_costs_nops = size;
+}
+
 /* This is called each time register related information is
    changed.  */
 void
@@ -2604,11 +2627,7 @@ ira_init_costs (void)
   init_cost->mem_cost = 1000000;
   for (i = 0; i < ira_important_classes_num; i++)
     init_cost->cost[i] = 1000000;
-  for (i = 0; i < MAX_RECOG_OPERANDS; i++)
-    {
-      op_costs[i] = (struct costs *) xmalloc (max_struct_costs_size);
-      this_op_costs[i] = (struct costs *) xmalloc (max_struct_costs_size);
-    }
+  ira_ensure_cost_capacity (MAX_RECOG_OPERANDS);
   temp_costs = (struct costs *) xmalloc (max_struct_costs_size);
 }
 
diff --git a/gcc/ira-int.h b/gcc/ira-int.h
index 710801bd65cd6..56a38daa1e49a 100644
--- a/gcc/ira-int.h
+++ b/gcc/ira-int.h
@@ -842,9 +842,11 @@ public:
   /* Allocated once, and used for temporary purposes.  */
   struct costs *x_temp_costs;
 
+  /* Element count in the following arrays.  */
+  size_t x_op_costs_nops;
   /* Allocated once, and used for the cost calculation.  */
-  struct costs *x_op_costs[MAX_RECOG_OPERANDS];
-  struct costs *x_this_op_costs[MAX_RECOG_OPERANDS];
+  struct costs **x_op_costs;
+  struct costs **x_this_op_costs;
 
   /* Hard registers that cannot be used for the register allocator for
      all functions of the current compilation unit.  */
diff --git a/gcc/ira.cc b/gcc/ira.cc
index 798a7f01c5da7..ab289beff0fac 100644
--- a/gcc/ira.cc
+++ b/gcc/ira.cc
@@ -5416,6 +5416,8 @@ static bitmap_head scratch_bitmap;
 
 /* Bitmap of scratch operands. */
 static bitmap_head scratch_operand_bitmap;
+static hash_map<int_hash<size_t, -1, -2>, auto_vec<HOST_WIDE_INT, 1>>
+  additional_scratch_operand_bitmap;
 
 /* Return true if pseudo REGNO is made of SCRATCH.  */
 bool
@@ -5426,16 +5428,26 @@ ira_former_scratch_p (int regno)
 
 /* Return true if the operand NOP of INSN is a former scratch. */
 bool
-ira_former_scratch_operand_p (rtx_insn *insn, int nop)
+ira_former_scratch_operand_p (rtx_insn *insn, unsigned nop)
 {
-  return bitmap_bit_p (&scratch_operand_bitmap,
-                      INSN_UID (insn) * MAX_RECOG_OPERANDS + nop) != 0;
+  if (nop < MAX_RECOG_OPERANDS)
+    return bitmap_bit_p (&scratch_operand_bitmap,
+                        INSN_UID (insn) * MAX_RECOG_OPERANDS + nop) != 0;
+  nop -= MAX_RECOG_OPERANDS;
+  bool old;
+  auto &ops = additional_scratch_operand_bitmap
+             .get_or_insert (INSN_UID (insn), &old);
+  unsigned nop_high = nop / HOST_BITS_PER_WIDE_INT;
+  unsigned nop_low = nop % HOST_BITS_PER_WIDE_INT;
+  if (ops.length () <= nop_high)
+    return false;
+  return ops[nop_high] & (HOST_WIDE_INT_1U << nop_low);
 }
 
 /* Register operand NOP in INSN as a former scratch.  It will be
    changed to scratch back, if it is necessary, at the LRA end.  */
 void
-ira_register_new_scratch_op (rtx_insn *insn, int nop, int icode)
+ira_register_new_scratch_op (rtx_insn *insn, unsigned nop, int icode)
 {
   rtx op = *recog_data.operand_loc[nop];
   sloc_t loc = XNEW (struct sloc);
@@ -5446,9 +5458,22 @@ ira_register_new_scratch_op (rtx_insn *insn, int nop, 
int icode)
   loc->icode = icode;
   scratches.safe_push (loc);
   bitmap_set_bit (&scratch_bitmap, REGNO (op));
-  bitmap_set_bit (&scratch_operand_bitmap,
-                 INSN_UID (insn) * MAX_RECOG_OPERANDS + nop);
   add_reg_note (insn, REG_UNUSED, op);
+  if (nop < MAX_RECOG_OPERANDS)
+    {
+      bitmap_set_bit (&scratch_operand_bitmap,
+                     INSN_UID (insn) * MAX_RECOG_OPERANDS + nop);
+      return;
+    }
+  nop -= MAX_RECOG_OPERANDS;
+  bool old;
+  auto &ops = additional_scratch_operand_bitmap
+             .get_or_insert (INSN_UID (insn), &old);
+  unsigned nop_high = nop / HOST_BITS_PER_WIDE_INT;
+  unsigned nop_low = nop % HOST_BITS_PER_WIDE_INT;
+  if (ops.length () <= nop_high)
+    ops.safe_grow_cleared (nop_high + 1);
+  ops[nop_high] |= 1 << nop_low;
 }
 
 /* Return true if string STR contains constraint 'X'.  */
@@ -5516,6 +5541,7 @@ remove_scratches (void)
   scratches.create (get_max_uid ());
   bitmap_initialize (&scratch_bitmap, &reg_obstack);
   bitmap_initialize (&scratch_operand_bitmap, &reg_obstack);
+  additional_scratch_operand_bitmap.empty ();
   FOR_EACH_BB_FN (bb, cfun)
     FOR_BB_INSNS (bb, insn)
     if (INSN_P (insn)
@@ -5572,6 +5598,7 @@ ira_restore_scratches (FILE *dump_file)
   scratches.release ();
   bitmap_clear (&scratch_bitmap);
   bitmap_clear (&scratch_operand_bitmap);
+  additional_scratch_operand_bitmap.empty ();
 }
 
 
diff --git a/gcc/ira.h b/gcc/ira.h
index 138729924e09a..92fdfd57de4aa 100644
--- a/gcc/ira.h
+++ b/gcc/ira.h
@@ -218,8 +218,9 @@ extern bool ira_bad_reload_regno (int, rtx, rtx);
 extern void ira_adjust_equiv_reg_cost (unsigned, int);
 
 extern bool ira_former_scratch_p (int regno);
-extern bool ira_former_scratch_operand_p (rtx_insn *insn, int nop);
-extern void ira_register_new_scratch_op (rtx_insn *insn, int nop, int icode);
+extern bool ira_former_scratch_operand_p (rtx_insn *insn, unsigned nop);
+extern void ira_register_new_scratch_op (rtx_insn *insn, unsigned nop,
+                                        int icode);
 extern bool ira_remove_insn_scratches (rtx_insn *insn, bool all_p, FILE 
*dump_file,
                                       rtx (*get_reg) (rtx original));
 extern void ira_restore_scratches (FILE *dump_file);
diff --git a/gcc/loop-invariant.cc b/gcc/loop-invariant.cc
index 8b82cdfbd7c97..4cc587e58211f 100644
--- a/gcc/loop-invariant.cc
+++ b/gcc/loop-invariant.cc
@@ -2006,10 +2006,7 @@ static int curr_reg_pressure[N_REG_CLASSES];
 /* Record all regs that are set in any one insn.  Communication from
    mark_reg_{store,clobber} and global_conflicts.  Asm can refer to
    all hard-registers.  */
-static rtx regs_set[(FIRST_PSEUDO_REGISTER > MAX_RECOG_OPERANDS
-                    ? FIRST_PSEUDO_REGISTER : MAX_RECOG_OPERANDS) * 2];
-/* Number of regs stored in the previous array.  */
-static int n_regs_set;
+static operand_vec<rtx> regs_set;
 
 /* Return pressure class and number of needed hard registers (through
    *NREGS) of register REGNO.  */
@@ -2095,7 +2092,7 @@ mark_reg_store (rtx reg, const_rtx setter 
ATTRIBUTE_UNUSED,
   if (! REG_P (reg))
     return;
 
-  regs_set[n_regs_set++] = reg;
+  regs_set.safe_push (reg);
 
   unsigned int end_regno = END_REGNO (reg);
   for (unsigned int regno = REGNO (reg); regno < end_regno; ++regno)
@@ -2199,7 +2196,7 @@ calculate_loop_reg_pressure (void)
            continue;
 
          mark_ref_regs (PATTERN (insn));
-         n_regs_set = 0;
+         regs_set.truncate (0);
          note_stores (insn, mark_reg_clobber, NULL);
 
          /* Mark any registers dead after INSN as dead now.  */
@@ -2220,10 +2217,10 @@ calculate_loop_reg_pressure (void)
              if (REG_NOTE_KIND (link) == REG_INC)
                mark_reg_store (XEXP (link, 0), NULL_RTX, NULL);
 
-         while (n_regs_set-- > 0)
+         for (int i = regs_set.length (); i; --i)
            {
              rtx note = find_regno_note (insn, REG_UNUSED,
-                                         REGNO (regs_set[n_regs_set]));
+                                         REGNO (regs_set[i - 1]));
              if (! note)
                continue;
 
diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc
index 2d95758a5b73b..d4a4f66cee056 100644
--- a/gcc/lra-constraints.cc
+++ b/gcc/lra-constraints.cc
@@ -150,11 +150,11 @@ static rtx curr_insn_set;
 static basic_block curr_bb;
 static lra_insn_recog_data_t curr_id;
 static struct lra_static_insn_data *curr_static_id;
-static machine_mode curr_operand_mode[MAX_RECOG_OPERANDS];
+static operand_vec<machine_mode> curr_operand_mode;
 /* Mode of the register substituted by its equivalence with VOIDmode
    (e.g. constant) and whose subreg is given operand of the current
    insn.  VOIDmode in all other cases.  */
-static machine_mode original_subreg_reg_mode[MAX_RECOG_OPERANDS];
+static operand_vec<machine_mode> original_subreg_reg_mode;
 /* The first call insn after curr_insn within the EBB during inherit_in_ebb
    or NULL outside of that function.  */
 static rtx_insn *first_call_insn;
@@ -613,6 +613,8 @@ static void
 init_curr_operand_mode (void)
 {
   int nop = curr_static_id->n_operands;
+  curr_operand_mode.truncate (0);
+  curr_operand_mode.safe_grow_cleared (nop);
   for (int i = 0; i < nop; i++)
     {
       machine_mode mode = GET_MODE (*curr_id->operand_loc[i]);
@@ -646,18 +648,16 @@ struct input_reload
   rtx reg;
 };
 
-/* The number of elements in the following array.  */
-static int curr_insn_input_reloads_num;
 /* Array containing info about input reloads.  It is used to find the
    same input reload and reuse the reload pseudo in this case. */
-static struct input_reload curr_insn_input_reloads[LRA_MAX_INSN_RELOADS];
+static reload_vec<input_reload> curr_insn_input_reloads;
 
 /* Initiate data concerning reuse of input reloads for the current
    insn.  */
 static void
 init_curr_insn_input_reloads (void)
 {
-  curr_insn_input_reloads_num = 0;
+  curr_insn_input_reloads.truncate (0);
 }
 
 /* The canonical form of an rtx inside a MEM is not necessarily the same as the
@@ -721,9 +721,6 @@ get_reload_reg (enum op_type type, machine_mode mode, rtx 
original,
                bool in_subreg_p, bool early_clobber_p,
                const char *title, rtx *result_reg)
 {
-  int i, regno;
-  enum reg_class new_class;
-
   if (type == OP_OUT)
     {
       /* Output reload registers tend to start out with a conservative
@@ -737,6 +734,7 @@ get_reload_reg (enum op_type type, machine_mode mode, rtx 
original,
         of register class rather than create a second reload register.
         This also helps to avoid cycling for registers that are only
         used by reload instructions.  */
+      enum reg_class new_class;
       if (REG_P (original)
          && (int) REGNO (original) >= new_regno_start
          && (INSN_UID (curr_insn) >= new_insn_uid_start
@@ -773,15 +771,16 @@ get_reload_reg (enum op_type type, machine_mode mode, rtx 
original,
   /* Prevent reuse value of expression with side effects,
      e.g. volatile memory.  */
   if (! side_effects_p (original))
-    for (i = 0; i < curr_insn_input_reloads_num; i++)
+    for (auto &reload: curr_insn_input_reloads)
       {
-       if (! curr_insn_input_reloads[i].match_p
-           && ! curr_insn_input_reloads[i].early_clobber_p
-           && rtx_equal_p (curr_insn_input_reloads[i].input, original)
-           && in_class_p (curr_insn_input_reloads[i].reg, rclass, &new_class))
+       enum reg_class new_class;
+       if (! reload.match_p
+           && ! reload.early_clobber_p
+           && rtx_equal_p (reload.input, original)
+           && in_class_p (reload.reg, rclass, &new_class))
          {
-           rtx reg = curr_insn_input_reloads[i].reg;
-           regno = REGNO (reg);
+           rtx reg = reload.reg;
+           int regno = REGNO (reg);
            /* If input is equal to original and both are VOIDmode,
               GET_MODE (reg) might be still different from mode.
               Ensure we don't return *result_reg with wrong mode.  */
@@ -823,22 +822,22 @@ get_reload_reg (enum op_type type, machine_mode mode, rtx 
original,
        /* If we have an input reload with a different mode, make sure it
           will get a different hard reg.  */
        else if (REG_P (original)
-                && REG_P (curr_insn_input_reloads[i].input)
-                && REGNO (original) == REGNO (curr_insn_input_reloads[i].input)
+                && REG_P (reload.input)
+                && REGNO (original) == REGNO (reload.input)
                 && (GET_MODE (original)
-                    != GET_MODE (curr_insn_input_reloads[i].input)))
+                    != GET_MODE (reload.input)))
          unique_p = true;
       }
   *result_reg = (unique_p
                 ? lra_create_new_reg_with_unique_value
                 : lra_create_new_reg) (mode, original, rclass,
                                        exclude_start_hard_regs, title);
-  lra_assert (curr_insn_input_reloads_num < LRA_MAX_INSN_RELOADS);
-  curr_insn_input_reloads[curr_insn_input_reloads_num].input = original;
-  curr_insn_input_reloads[curr_insn_input_reloads_num].match_p = false;
-  curr_insn_input_reloads[curr_insn_input_reloads_num].early_clobber_p
-    = early_clobber_p;
-  curr_insn_input_reloads[curr_insn_input_reloads_num++].reg = *result_reg;
+  input_reload new_reload;
+  new_reload.input = original;
+  new_reload.match_p = false;
+  new_reload.early_clobber_p = early_clobber_p;
+  new_reload.reg = *result_reg;
+  curr_insn_input_reloads.safe_push (new_reload);
   return true;
 }
 
@@ -1072,19 +1071,15 @@ regno_val_use_in (unsigned int regno, rtx x)
    has a negaitve end marker) do not use pseudos with the same value
    as REGNO.  */
 static bool
-check_conflict_input_operands (int regno, signed char *ins)
+check_conflict_input_operands (int regno, array_slice<int> ins)
 {
-  int in;
   int n_operands = curr_static_id->n_operands;
 
   for (int nop = 0; nop < n_operands; nop++)
     if (! curr_static_id->operand[nop].is_operator
        && curr_static_id->operand[nop].type != OP_OUT)
       {
-       for (int i = 0; (in = ins[i]) >= 0; i++)
-         if (in == nop)
-           break;
-       if (in < 0
+       if (! ins.contains (nop)
            && regno_val_use_in (regno, *curr_id->operand_loc[nop]) != NULL_RTX)
          return false;
       }
@@ -1099,12 +1094,11 @@ check_conflict_input_operands (int regno, signed char 
*ins)
    input reloads for matched input operands INS.  EARLY_CLOBBER_P is a flag
    that the output operand is early clobbered for chosen alternative.  */
 static void
-match_reload (signed char out, signed char *ins, signed char *outs,
+match_reload (int out, array_slice<int> ins, array_slice<int> outs,
              enum reg_class goal_class, HARD_REG_SET *exclude_start_hard_regs,
              rtx_insn **before, rtx_insn **after, bool early_clobber_p)
 {
   bool out_conflict;
-  int i, in;
   rtx new_in_reg, new_out_reg, reg;
   machine_mode inmode, outmode;
   rtx in_rtx = *curr_id->operand_loc[ins[0]];
@@ -1230,10 +1224,10 @@ match_reload (signed char out, signed char *ins, signed 
char *outs,
       out_conflict = false;
       if (REG_P (in_rtx))
        {
-         for (i = 0; outs[i] >= 0; i++)
+         for (int out_op: outs)
            {
-             rtx other_out_rtx = *curr_id->operand_loc[outs[i]];
-             if (outs[i] != out && REG_P (other_out_rtx)
+             rtx other_out_rtx = *curr_id->operand_loc[out_op];
+             if (out_op != out && REG_P (other_out_rtx)
                  && (regno_val_use_in (REGNO (in_rtx), other_out_rtx)
                      != NULL_RTX))
                {
@@ -1244,7 +1238,7 @@ match_reload (signed char out, signed char *ins, signed 
char *outs,
        }
 
       new_in_reg = new_out_reg
-       = (! early_clobber_p && ins[1] < 0 && REG_P (in_rtx)
+       = (! early_clobber_p && ins.size () == 1 && REG_P (in_rtx)
           && (int) REGNO (in_rtx) < lra_new_regno_start
           && find_regno_note (curr_insn, REG_DEAD, REGNO (in_rtx))
           && (out < 0
@@ -1267,12 +1261,14 @@ match_reload (signed char out, signed char *ins, signed 
char *outs,
   *before = end_sequence ();
   /* Add the new pseudo to consider values of subsequent input reload
      pseudos.  */
-  lra_assert (curr_insn_input_reloads_num < LRA_MAX_INSN_RELOADS);
-  curr_insn_input_reloads[curr_insn_input_reloads_num].input = in_rtx;
-  curr_insn_input_reloads[curr_insn_input_reloads_num].match_p = true;
-  curr_insn_input_reloads[curr_insn_input_reloads_num].early_clobber_p = false;
-  curr_insn_input_reloads[curr_insn_input_reloads_num++].reg = new_in_reg;
-  for (i = 0; (in = ins[i]) >= 0; i++)
+  input_reload new_reload;
+  new_reload.input = in_rtx;
+  new_reload.match_p = true;
+  new_reload.early_clobber_p = false;
+  new_reload.reg = new_in_reg;
+  curr_insn_input_reloads.safe_push (new_reload);
+
+  for (int in: ins)
     if (GET_MODE (*curr_id->operand_loc[in]) == VOIDmode
        || GET_MODE (new_in_reg) == GET_MODE (*curr_id->operand_loc[in]))
       *curr_id->operand_loc[in] = new_in_reg;
@@ -1530,23 +1526,21 @@ check_and_process_move (bool *change_p, bool *sec_mem_p 
ATTRIBUTE_UNUSED)
 
 /* The chosen reg classes which should be used for the corresponding
    operands.  */
-static enum reg_class goal_alt[MAX_RECOG_OPERANDS];
+static operand_vec<reg_class> goal_alt;
 /* Hard registers which cannot be a start hard register for the corresponding
    operands.  */
-static HARD_REG_SET goal_alt_exclude_start_hard_regs[MAX_RECOG_OPERANDS];
+static operand_vec<HARD_REG_SET> goal_alt_exclude_start_hard_regs;
 /* True if the operand should be the same as another operand and that
    other operand does not need a reload.  */
-static bool goal_alt_match_win[MAX_RECOG_OPERANDS];
+static operand_vec<bool> goal_alt_match_win;
 /* True if the operand does not need a reload. */
-static bool goal_alt_win[MAX_RECOG_OPERANDS];
+static operand_vec<bool> goal_alt_win;
 /* True if the operand can be offsetable memory.  */
-static bool goal_alt_offmemok[MAX_RECOG_OPERANDS];
+static operand_vec<bool> goal_alt_offmemok;
 /* The number of an operand to which given operand can be matched to.  */
-static int goal_alt_matches[MAX_RECOG_OPERANDS];
-/* The number of elements in the following array.  */
-static int goal_alt_dont_inherit_ops_num;
+static operand_vec<int> goal_alt_matches;
 /* Numbers of operands whose reload pseudos should not be inherited.  */
-static int goal_alt_dont_inherit_ops[MAX_RECOG_OPERANDS];
+static operand_vec<int> goal_alt_dont_inherit_ops;
 /* True if we should try only this alternative for the next constraint sub-pass
    to speed up the sub-pass.  */
 static bool goal_reuse_alt_p;
@@ -1559,7 +1553,7 @@ static bool goal_alt_out_sp_reload_p;
 
 /* True if the corresponding operand is the result of an equivalence
    substitution.  */
-static bool equiv_substition_p[MAX_RECOG_OPERANDS];
+static operand_vec<bool> equiv_substition_p;
 
 /* The following five variables are used to choose the best insn
    alternative.         They reflect final characteristics of the best
@@ -2457,20 +2451,18 @@ process_alt_operands (int only_alternative)
   /* The number of elements in the following array.  */
   int early_clobbered_regs_num;
   /* Numbers of operands which are early clobber registers.  */
-  int early_clobbered_nops[MAX_RECOG_OPERANDS];
-  enum reg_class curr_alt[MAX_RECOG_OPERANDS];
   enum reg_class all_this_alternative;
   int all_used_nregs, all_reload_nregs;
-  HARD_REG_SET curr_alt_set[MAX_RECOG_OPERANDS];
-  HARD_REG_SET curr_alt_exclude_start_hard_regs[MAX_RECOG_OPERANDS];
-  bool curr_alt_match_win[MAX_RECOG_OPERANDS];
-  bool curr_alt_win[MAX_RECOG_OPERANDS];
-  bool curr_alt_offmemok[MAX_RECOG_OPERANDS];
-  int curr_alt_matches[MAX_RECOG_OPERANDS];
-  /* The number of elements in the following array.  */
-  int curr_alt_dont_inherit_ops_num;
+  operand_vec<int> early_clobbered_nops (n_operands, -1);
+  operand_vec<reg_class> curr_alt (n_operands, NO_REGS);
+  operand_vec<HARD_REG_SET> curr_alt_set (n_operands, {});
+  operand_vec<HARD_REG_SET> curr_alt_exclude_start_hard_regs (n_operands, {});
+  operand_vec<bool> curr_alt_match_win (n_operands, false);
+  operand_vec<bool> curr_alt_win (n_operands, false);
+  operand_vec<bool> curr_alt_offmemok (n_operands, false);
+  operand_vec<int> curr_alt_matches (n_operands, -1);
   /* Numbers of operands whose reload pseudos should not be inherited. */
-  int curr_alt_dont_inherit_ops[MAX_RECOG_OPERANDS];
+  operand_vec<int> curr_alt_dont_inherit_ops;
   bool curr_reuse_alt_p;
   /* True if output stack pointer reload should be generated for the current
      alternative.  */
@@ -2479,17 +2471,24 @@ process_alt_operands (int only_alternative)
   rtx op;
   /* The register when the operand is a subreg of register, otherwise the
      operand itself.  */
-  rtx no_subreg_reg_operand[MAX_RECOG_OPERANDS];
+  operand_vec<rtx> no_subreg_reg_operand (n_operands, NULL_RTX);
   /* The register if the operand is a register or subreg of register,
      otherwise NULL.  */
-  rtx operand_reg[MAX_RECOG_OPERANDS];
-  int hard_regno[MAX_RECOG_OPERANDS];
-  machine_mode biggest_mode[MAX_RECOG_OPERANDS];
+  operand_vec<rtx> operand_reg (n_operands, NULL_RTX);
+  operand_vec<int> hard_regno (n_operands, -1);
+  operand_vec<machine_mode> biggest_mode (n_operands, VOIDmode);
   int reload_nregs, reload_sum;
   bool costly_p;
   enum reg_class cl;
   const HARD_REG_SET *cl_filter;
   HARD_REG_SET hard_reg_constraint;
+  if (n_operands > curr_operand_mode.length ())
+    curr_operand_mode.safe_grow_cleared (n_operands);
+  if (n_operands > original_subreg_reg_mode.length ())
+    {
+      original_subreg_reg_mode.safe_grow_cleared (n_operands);
+      equiv_substition_p.safe_grow_cleared (n_operands);
+    }
 
   /* Calculate some data common for all alternatives to speed up the
      function. */
@@ -2547,7 +2546,7 @@ process_alt_operands (int only_alternative)
          fprintf (lra_dump_file, "\n");
        }
 
-      bool matching_early_clobber[MAX_RECOG_OPERANDS];
+      operand_vec<bool> matching_early_clobber (n_operands, false);
       curr_small_class_check++;
       overall = losers = addr_losers = 0;
       static_reject = reject = reload_nregs = reload_sum = 0;
@@ -3681,7 +3680,7 @@ process_alt_operands (int only_alternative)
            }
        }
       ok_p = true;
-      curr_alt_dont_inherit_ops_num = 0;
+      curr_alt_dont_inherit_ops.truncate (0);
       for (nop = 0; nop < early_clobbered_regs_num; nop++)
        {
          int i, j, clobbered_hard_regno, first_conflict_j, last_conflict_j;
@@ -3743,8 +3742,7 @@ process_alt_operands (int only_alternative)
                  && !HARD_REGISTER_P (operand_reg[last_conflict_j])))
            {
              curr_alt_win[last_conflict_j] = false;
-             curr_alt_dont_inherit_ops[curr_alt_dont_inherit_ops_num++]
-               = last_conflict_j;
+             curr_alt_dont_inherit_ops.safe_push (last_conflict_j);
              losers++;
              if (lra_dump_file != NULL)
                fprintf
@@ -3770,7 +3768,7 @@ process_alt_operands (int only_alternative)
                    overall += LRA_LOSER_COST_FACTOR;
                  }
              if (! curr_alt_match_win[i])
-               curr_alt_dont_inherit_ops[curr_alt_dont_inherit_ops_num++] = i;
+               curr_alt_dont_inherit_ops.safe_push (i);
              else
                {
                  /* Remember pseudos used for match reloads are never
@@ -3817,20 +3815,14 @@ process_alt_operands (int only_alternative)
                                  || (best_reload_sum == reload_sum
                                      && nalt < goal_alt_number))))))))
        {
-         for (nop = 0; nop < n_operands; nop++)
-           {
-             goal_alt_win[nop] = curr_alt_win[nop];
-             goal_alt_match_win[nop] = curr_alt_match_win[nop];
-             goal_alt_matches[nop] = curr_alt_matches[nop];
-             goal_alt[nop] = curr_alt[nop];
-             goal_alt_exclude_start_hard_regs[nop]
-               = curr_alt_exclude_start_hard_regs[nop];
-             goal_alt_offmemok[nop] = curr_alt_offmemok[nop];
-           }
-         goal_alt_dont_inherit_ops_num = curr_alt_dont_inherit_ops_num;
+         goal_alt_win = curr_alt_win;
+         goal_alt_match_win = curr_alt_match_win;
+         goal_alt_matches = curr_alt_matches;
+         goal_alt = curr_alt;
+         goal_alt_exclude_start_hard_regs = curr_alt_exclude_start_hard_regs;
+         goal_alt_offmemok = curr_alt_offmemok;
          goal_reuse_alt_p = curr_reuse_alt_p;
-         for (nop = 0; nop < curr_alt_dont_inherit_ops_num; nop++)
-           goal_alt_dont_inherit_ops[nop] = curr_alt_dont_inherit_ops[nop];
+         goal_alt_dont_inherit_ops = curr_alt_dont_inherit_ops;
          goal_alt_swapped = curr_swapped;
          goal_alt_out_sp_reload_p = curr_alt_out_sp_reload_p;
          best_overall = overall;
@@ -4641,14 +4633,10 @@ reload_section_anchor_p (int nop)
 static bool
 curr_insn_transform (bool check_only_p)
 {
-  int i, j, k;
+  int i, j;
   int n_operands;
   int n_alternatives;
-  int n_outputs;
   int commutative;
-  signed char goal_alt_matched[MAX_RECOG_OPERANDS][MAX_RECOG_OPERANDS];
-  signed char match_inputs[MAX_RECOG_OPERANDS + 1];
-  signed char outputs[MAX_RECOG_OPERANDS + 1];
   rtx_insn *before, *after;
   bool alt_p = false;
   /* Flag that the insn has been changed through a transformation.  */
@@ -4679,6 +4667,9 @@ curr_insn_transform (bool check_only_p)
   n_operands = curr_static_id->n_operands;
   n_alternatives = curr_static_id->n_alternatives;
 
+  operand_vec<operand_vec<int>> goal_alt_matched (n_operands, {});
+  operand_vec<int> match_inputs;
+  operand_vec<int> outputs;
   /* Just return "no reloads" if insn has no operands with
      constraints.  */
   if (n_operands == 0 || n_alternatives == 0)
@@ -4686,11 +4677,10 @@ curr_insn_transform (bool check_only_p)
 
   max_regno_before = max_reg_num ();
 
-  for (i = 0; i < n_operands; i++)
-    {
-      goal_alt_matched[i][0] = -1;
-      goal_alt_matches[i] = -1;
-    }
+  goal_alt_matches.truncate (0);
+  goal_alt_matches.safe_grow (n_operands);
+  for (int &op: goal_alt_matches)
+    op = -1;
 
   commutative = curr_static_id->commutative;
 
@@ -4704,6 +4694,13 @@ curr_insn_transform (bool check_only_p)
   curr_swapped = false;
   goal_alt_swapped = false;
 
+  if (! check_only_p)
+    {
+      equiv_substition_p.truncate (0);
+      equiv_substition_p.safe_grow_cleared (n_operands);
+      original_subreg_reg_mode.truncate (0);
+      original_subreg_reg_mode.safe_grow_cleared (n_operands);
+    }
   if (! check_only_p)
     /* Make equivalence substitution and memory subreg elimination
        before address processing because an address legitimacy can
@@ -4720,8 +4717,6 @@ curr_insn_transform (bool check_only_p)
        if (GET_CODE (old) == SUBREG)
          old = SUBREG_REG (old);
        subst = get_equiv_with_elimination (old, curr_insn);
-       original_subreg_reg_mode[i] = VOIDmode;
-       equiv_substition_p[i] = false;
 
        if (subst != old
            /* We don't want to change an out operand by constant or invariant
@@ -4792,7 +4787,8 @@ curr_insn_transform (bool check_only_p)
 
  try_swapped:
 
-  reused_alternative_num = check_only_p ? LRA_UNKNOWN_ALT : 
curr_id->used_insn_alternative;
+  reused_alternative_num = check_only_p ? LRA_UNKNOWN_ALT
+                                       : curr_id->used_insn_alternative;
   if (lra_dump_file != NULL && reused_alternative_num >= 0)
     fprintf (lra_dump_file, "Reusing alternative %d for insn #%u\n",
             reused_alternative_num, INSN_UID (curr_insn));
@@ -4979,17 +4975,14 @@ curr_insn_transform (bool check_only_p)
   for (i = 0; i < n_operands; i++)
     if ((j = goal_alt_matches[i]) >= 0)
       {
-       for (k = 0; goal_alt_matched[j][k] >= 0; k++)
-         ;
+       auto &curr = goal_alt_matched[j];
        /* We allow matching one output operand and several input
           operands.  */
-       lra_assert (k == 0
+       lra_assert (curr.is_empty ()
                    || (curr_static_id->operand[j].type == OP_OUT
                        && curr_static_id->operand[i].type == OP_IN
-                       && (curr_static_id->operand
-                           [goal_alt_matched[j][0]].type == OP_IN)));
-       goal_alt_matched[j][k] = i;
-       goal_alt_matched[j][k + 1] = -1;
+                       && curr_static_id->operand[curr[0]].type == OP_IN));
+       curr.safe_push (i);
       }
 
   for (i = 0; i < n_operands; i++)
@@ -5073,11 +5066,9 @@ curr_insn_transform (bool check_only_p)
          }
       }
 
-  n_outputs = 0;
   for (i = 0; i < n_operands; i++)
     if (curr_static_id->operand[i].type == OP_OUT)
-      outputs[n_outputs++] = i;
-  outputs[n_outputs] = -1;
+      outputs.safe_push (i);
   for (i = 0; i < n_operands; i++)
     {
       int regno;
@@ -5126,20 +5117,20 @@ curr_insn_transform (bool check_only_p)
                           || MEM_P (SET_DEST (curr_insn_set))
                           || GET_CODE (SET_DEST (curr_insn_set)) == SUBREG))))
            optional_p = true;
-         else if (goal_alt_matched[i][0] != -1
+         else if (!goal_alt_matched[i].is_empty ()
                   && curr_static_id->operand[i].type == OP_OUT
                   && (curr_static_id->operand_alternative
                       [goal_alt_number * n_operands + i].earlyclobber)
                   && REG_P (op))
            {
-             for (j = 0; goal_alt_matched[i][j] != -1; j++)
-               {
-                 rtx op2 = *curr_id->operand_loc[goal_alt_matched[i][j]];
 
-                 if (REG_P (op2) && REGNO (op) != REGNO (op2))
-                   break;
-               }
-             if (goal_alt_matched[i][j] != -1)
+             array_slice<int> alt_ref {goal_alt_matched[i]};
+             bool found = alt_ref.find ([&] (int opalt)
+               {
+                 rtx op2 = *curr_id->operand_loc[opalt];
+                 return REG_P (op2) && REGNO (op) != REGNO (op2);
+               });
+             if (found)
                {
                  /* Generate reloads for different output and matched
                     input registers.  This is the easiest way to avoid
@@ -5178,7 +5169,7 @@ curr_insn_transform (bool check_only_p)
         appearing where an offsettable address will do.  It also may
         be a case when the address should be special in other words
         not a general one (e.g. it needs no index reg).  */
-      if (goal_alt_matched[i][0] == -1 && goal_alt_offmemok[i] && MEM_P (op))
+      if (goal_alt_matched[i].is_empty () && goal_alt_offmemok[i] && MEM_P 
(op))
        {
          enum reg_class rclass;
          rtx *loc = &XEXP (op, 0);
@@ -5231,13 +5222,14 @@ curr_insn_transform (bool check_only_p)
 
              lra_emit_move (new_reg, addr);
              if (align_p)
-               emit_move_insn (new_reg, gen_rtx_AND (GET_MODE (new_reg), 
new_reg, XEXP (*loc, 1)));
+               emit_move_insn (new_reg, gen_rtx_AND (GET_MODE (new_reg),
+                                                     new_reg, XEXP (*loc, 1)));
            }
          before = end_sequence ();
          *loc = new_reg;
          lra_update_dup (curr_id, i);
        }
-      else if (goal_alt_matched[i][0] == -1)
+      else if (goal_alt_matched[i].is_empty ())
        {
          machine_mode mode;
          rtx reg, *loc;
@@ -5323,12 +5315,8 @@ curr_insn_transform (bool check_only_p)
              after = end_sequence ();
              *loc = new_reg;
            }
-         for (j = 0; j < goal_alt_dont_inherit_ops_num; j++)
-           if (goal_alt_dont_inherit_ops[j] == i)
-             {
-               lra_set_regno_unique_value (REGNO (new_reg));
-               break;
-             }
+         if (goal_alt_dont_inherit_ops.contains (i))
+           lra_set_regno_unique_value (REGNO (new_reg));
          lra_update_dup (curr_id, i);
        }
       else if (curr_static_id->operand[i].type == OP_IN
@@ -5342,8 +5330,8 @@ curr_insn_transform (bool check_only_p)
                            -1)))))
        {
          /* generate reloads for input and matched outputs.  */
-         match_inputs[0] = i;
-         match_inputs[1] = -1;
+         match_inputs.truncate (0);
+         match_inputs.safe_push (i);
          match_reload (goal_alt_matched[i][0], match_inputs, outputs,
                        goal_alt[i], &goal_alt_exclude_start_hard_regs[i],
                        &before, &after,
@@ -5369,10 +5357,10 @@ curr_insn_transform (bool check_only_p)
                   == OP_IN))
        {
          /* Generate reloads for matched inputs.  */
-         match_inputs[0] = i;
-         for (j = 0; (k = goal_alt_matched[i][j]) >= 0; j++)
-           match_inputs[j + 1] = k;
-         match_inputs[j + 1] = -1;
+         match_inputs.truncate (0);
+         match_inputs.safe_push (i);
+         for (int opalt: goal_alt_matched[i])
+           match_inputs.safe_push (opalt);
          match_reload (-1, match_inputs, outputs, goal_alt[i],
                        &goal_alt_exclude_start_hard_regs[i],
                        &before, &after, false);
@@ -5641,6 +5629,9 @@ loc_equivalence_callback (rtx loc, const_rtx, void *data)
    preventing this pass cycling in a bug case. */
 #define MAX_RELOAD_INSNS_NUMBER LRA_MAX_INSN_RELOADS
 
+/* Same as above but per an insn operand.  */
+#define MAX_RELOAD_INSNS_PER_OPERAND_NUMBER 3
+
 /* The current iteration number of this LRA pass.  */
 int lra_constraint_iter;
 
@@ -5784,8 +5775,8 @@ combine_reload_insn (rtx_insn *from, rtx_insn *to)
   rtx_insn *saved_insn;
   rtx set, from_reg, to_reg, op;
   enum reg_class to_class, from_class;
-  int n, nop;
-  signed char changed_nops[MAX_RECOG_OPERANDS + 1];
+  int nop;
+  operand_vec<int> changed_nops;
 
   /* Check conditions for second memory reload and original insn:  */
   if ((targetm.secondary_memory_needed
@@ -5812,7 +5803,7 @@ combine_reload_insn (rtx_insn *from, rtx_insn *to)
   /* Check that reload insn is a load:  */
   if (to_class != NO_REGS || from_class == NO_REGS)
     return false;
-  for (n = nop = 0; nop < static_id->n_operands; nop++)
+  for (nop = 0; nop < static_id->n_operands; nop++)
     {
       if (static_id->operand[nop].type != OP_IN)
        continue;
@@ -5820,9 +5811,8 @@ combine_reload_insn (rtx_insn *from, rtx_insn *to)
       if (!REG_P (op) || REGNO (op) != REGNO (from_reg))
        continue;
       *id->operand_loc[nop] = to_reg;
-      changed_nops[n++] = nop;
+      changed_nops.safe_push (nop);
     }
-  changed_nops[n] = -1;
   lra_update_dups (id, changed_nops);
   lra_update_insn_regno_info (to);
   ok_p = recog_memoized (to) >= 0;
@@ -5870,11 +5860,8 @@ combine_reload_insn (rtx_insn *from, rtx_insn *to)
       fprintf (lra_dump_file, "    Failed combined insn:\n");
       dump_insn_slim (lra_dump_file, to);
     }
-  for (int i = 0; i < n; i++)
-    {
-      nop = changed_nops[i];
-      *id->operand_loc[nop] = from_reg;
-    }
+  for (int change: changed_nops)
+    *id->operand_loc[change] = from_reg;
   lra_update_dups (id, changed_nops);
   lra_update_insn_regno_info (to);
   if (lra_dump_file != NULL)
@@ -6062,6 +6049,7 @@ lra_constraints (bool first_p)
     lra_push_insn_by_uid (uid);
   min_len = lra_insn_stack_length ();
   new_insns_num = 0;
+  int reload_limit = 0;
   last_bb = NULL;
   changed_p = false;
   original_insn = NULL;
@@ -6080,15 +6068,22 @@ lra_constraints (bool first_p)
          min_len = new_min_len;
          new_insns_num = 0;
          original_insn = curr_insn;
+         reload_limit
+           = lra_get_insn_recog_data (curr_insn)->insn_static_data->n_operands;
+         reload_limit *= MAX_RELOAD_INSNS_PER_OPERAND_NUMBER;
+         /* Allow at least as many reloads as were allowed historically to
+            prevent regressions.  */
+         if (reload_limit < MAX_RELOAD_INSNS_NUMBER)
+           reload_limit = MAX_RELOAD_INSNS_NUMBER;
        }
       else if (combine_reload_insn (curr_insn, original_insn))
        {
          continue;
         }
-      if (new_insns_num > MAX_RELOAD_INSNS_NUMBER)
+      if (new_insns_num > reload_limit)
        internal_error
          ("maximum number of generated reload insns per insn achieved (%d)",
-          MAX_RELOAD_INSNS_NUMBER);
+          reload_limit);
       new_insns_num++;
       if (DEBUG_INSN_P (curr_insn))
        {
@@ -7378,24 +7373,17 @@ struct to_inherit
 
 /* Array containing all info for doing inheritance from the current
    insn.  */
-static struct to_inherit to_inherit[LRA_MAX_INSN_RELOADS];
-
-/* Number elements in the previous array.  */
-static int to_inherit_num;
+static reload_vec<to_inherit> to_inherit;
 
 /* Add inheritance info REGNO and INSNS. Their meaning is described in
    structure to_inherit.  */
 static void
 add_to_inherit (int regno, rtx insns)
 {
-  int i;
-
-  for (i = 0; i < to_inherit_num; i++)
-    if (to_inherit[i].regno == regno)
+  for (auto &v: to_inherit)
+    if (v.regno == regno)
       return;
-  lra_assert (to_inherit_num < LRA_MAX_INSN_RELOADS);
-  to_inherit[to_inherit_num].regno = regno;
-  to_inherit[to_inherit_num++].insns = insns;
+  to_inherit.safe_push ({regno, insns});
 }
 
 /* Return the last non-debug insn in basic block BB, or the block begin
@@ -7604,7 +7592,7 @@ inherit_in_ebb (rtx_insn *head, rtx_insn *tail)
 
          curr_id = lra_get_insn_recog_data (curr_insn);
          curr_static_id = curr_id->insn_static_data;
-         to_inherit_num = 0;
+         to_inherit.truncate (0);
          /* Process insn definitions.  */
          for (iter = 0; iter < 2; iter++)
            for (reg = iter == 0 ? curr_id->regs : curr_static_id->hard_regs;
@@ -7683,10 +7671,9 @@ inherit_in_ebb (rtx_insn *head, rtx_insn *tail)
                usage_insns[dst_regno - FIRST_PSEUDO_REGISTER].check
                  = -(int) INSN_UID (curr_insn);
          if (! JUMP_P (curr_insn))
-           for (i = 0; i < to_inherit_num; i++)
-             if (inherit_reload_reg (true, to_inherit[i].regno,
-                                     ALL_REGS, curr_insn,
-                                     to_inherit[i].insns))
+           for (auto &v: to_inherit)
+             if (inherit_reload_reg (true, v.regno, ALL_REGS, curr_insn,
+                                     v.insns))
              change_p = true;
          if (CALL_P (curr_insn))
            {
@@ -7738,7 +7725,7 @@ inherit_in_ebb (rtx_insn *head, rtx_insn *tail)
                    }
                }
            }
-         to_inherit_num = 0;
+         to_inherit.truncate (0);
          /* Process insn usages.  */
          for (iter = 0; iter < 2; iter++)
            for (reg = iter == 0 ? curr_id->regs : curr_static_id->hard_regs;
@@ -7812,11 +7799,11 @@ inherit_in_ebb (rtx_insn *head, rtx_insn *tail)
                   SET_HARD_REG_BIT (live_hard_regs, src_regno);
                   add_next_usage_insn (src_regno, curr_insn, reloads_num);
                }
-         for (i = 0; i < to_inherit_num; i++)
+         for (auto &v: to_inherit)
            {
-             src_regno = to_inherit[i].regno;
+             src_regno = v.regno;
              if (inherit_reload_reg (false, src_regno, ALL_REGS,
-                                     curr_insn, to_inherit[i].insns))
+                                     curr_insn, v.insns))
                change_p = true;
              else
                setup_next_usage_insn (src_regno, curr_insn, reloads_num, 
false);
diff --git a/gcc/lra-eliminations.cc b/gcc/lra-eliminations.cc
index 2aa83e2aa427b..6eec08da26f38 100644
--- a/gcc/lra-eliminations.cc
+++ b/gcc/lra-eliminations.cc
@@ -935,8 +935,6 @@ eliminate_regs_in_insn (rtx_insn *insn, bool replace_p, 
bool first_p,
   rtx set, old_set = single_set (insn);
   bool validate_p;
   int i;
-  rtx substed_operand[MAX_RECOG_OPERANDS];
-  rtx orig_operand[MAX_RECOG_OPERANDS];
   class lra_elim_table *ep;
   rtx plus_src, plus_cst_src;
   lra_insn_recog_data_t id;
@@ -1053,6 +1051,8 @@ eliminate_regs_in_insn (rtx_insn *insn, bool replace_p, 
bool first_p,
   id = lra_get_insn_recog_data (insn);
   static_id = id->insn_static_data;
   validate_p = false;
+  operand_vec<rtx> substed_operand (static_id->n_operands, NULL_RTX);
+  operand_vec<rtx> orig_operand (static_id->n_operands, NULL_RTX);
   for (i = 0; i < static_id->n_operands; i++)
     {
       orig_operand[i] = *id->operand_loc[i];
diff --git a/gcc/lra-int.h b/gcc/lra-int.h
index 8b50c60c13295..a6420e6b7da38 100644
--- a/gcc/lra-int.h
+++ b/gcc/lra-int.h
@@ -28,6 +28,9 @@ along with GCC; see the file COPYING3.        If not see
    base and index registers might require a reload too.         */
 #define LRA_MAX_INSN_RELOADS (MAX_RECOG_OPERANDS * 3)
 
+template<class T>
+using reload_vec = auto_vec<T, LRA_MAX_INSN_RELOADS>;
+
 typedef struct lra_live_range *lra_live_range_t;
 
 struct dependent_filter
@@ -344,7 +347,7 @@ extern void lra_set_insn_deleted (rtx_insn *);
 extern void lra_delete_dead_insn (rtx_insn *);
 extern void lra_emit_add (rtx, rtx, rtx);
 extern void lra_emit_move (rtx, rtx);
-extern void lra_update_dups (lra_insn_recog_data_t, signed char *);
+extern void lra_update_dups (lra_insn_recog_data_t, array_slice<int>);
 extern void lra_asm_insn_error (rtx_insn *insn);
 
 extern void lra_dump_insns (FILE *f);
diff --git a/gcc/lra.cc b/gcc/lra.cc
index e25710dc7d754..8d3fb758f4b07 100644
--- a/gcc/lra.cc
+++ b/gcc/lra.cc
@@ -533,16 +533,16 @@ lra_emit_move (rtx x, rtx y)
 }
 
 /* Update insn operands which are duplication of operands whose
-   numbers are in array of NOPS (with end marker -1).  The insn is
-   represented by its LRA internal representation ID.  */
+   numbers are in array of NOPS.  The insn is represented by its
+   LRA internal representation ID.  */
 void
-lra_update_dups (lra_insn_recog_data_t id, signed char *nops)
+lra_update_dups (lra_insn_recog_data_t id, array_slice<int> nops)
 {
-  int i, j, nop;
+  int i;
   struct lra_static_insn_data *static_id = id->insn_static_data;
 
   for (i = 0; i < static_id->n_dups; i++)
-    for (j = 0; (nop = nops[j]) >= 0; j++)
+    for (int nop: nops)
       if (static_id->dup_num[i] == nop)
        *id->dup_loc[i] = *id->operand_loc[nop];
 }
@@ -1031,10 +1031,11 @@ lra_set_insn_recog_data (rtx_insn *insn)
   if (icode < 0)
     {
       int nop, nalt;
-      machine_mode operand_mode[MAX_RECOG_OPERANDS];
-      const char *constraints[MAX_RECOG_OPERANDS];
-
       nop = asm_noperands (PATTERN (insn));
+      int nop2 = nop < 0 ? 0 : nop;
+      operand_vec <machine_mode> operand_mode (nop2, VOIDmode);
+      operand_vec <const char *> constraints (nop2, nullptr);
+
       data->operand_loc = data->dup_loc = NULL;
       nalt = 1;
       if (nop < 0)
@@ -1052,14 +1053,14 @@ lra_set_insn_recog_data (rtx_insn *insn)
        {
          /* expand_asm_operands makes sure there aren't too many
             operands.  */
-         lra_assert (nop <= MAX_RECOG_OPERANDS);
          if (nop != 0)
            data->operand_loc = XNEWVEC (rtx *, nop);
          /* Now get the operand values and constraints out of the
             insn.  */
          decode_asm_operands (PATTERN (insn), NULL,
-                              data->operand_loc,
-                              constraints, operand_mode, NULL);
+                              {data->operand_loc, (unsigned)nop},
+                              constraints,
+                              operand_mode, NULL);
          if (nop > 0)
            for (const char *p =constraints[0]; *p; p++)
              nalt += *p == ',';
@@ -1084,7 +1085,7 @@ lra_set_insn_recog_data (rtx_insn *insn)
        {
          operand_alternative *op_alt = XCNEWVEC (operand_alternative,
                                                  nalt * nop);
-         preprocess_constraints (nop, nalt, constraints, op_alt,
+         preprocess_constraints (nop, nalt, constraints.address (), op_alt,
                                  data->operand_loc);
          setup_operand_alternative (data, op_alt);
        }
@@ -1102,7 +1103,7 @@ lra_set_insn_recog_data (rtx_insn *insn)
       else
        {
          locs = XNEWVEC (rtx *, n);
-         memcpy (locs, recog_data.operand_loc, n * sizeof (rtx *));
+         memcpy (locs, recog_data.operand_loc.address (), n * sizeof (rtx *));
        }
       data->operand_loc = locs;
       n = insn_static_data->n_dups;
@@ -1111,7 +1112,7 @@ lra_set_insn_recog_data (rtx_insn *insn)
       else
        {
          locs = XNEWVEC (rtx *, n);
-         memcpy (locs, recog_data.dup_loc, n * sizeof (rtx *));
+         memcpy (locs, recog_data.dup_loc.address (), n * sizeof (rtx *));
        }
       data->dup_loc = locs;
       data->preferred_alternatives = get_preferred_alternatives (insn);
@@ -1260,18 +1261,19 @@ lra_update_insn_recog_data (rtx_insn *insn)
   if (data->icode < 0)
     {
       int nop;
-      machine_mode operand_mode[MAX_RECOG_OPERANDS];
-      const char *constraints[MAX_RECOG_OPERANDS];
-
       nop = asm_noperands (PATTERN (insn));
+      operand_vec<machine_mode> operand_mode (std::max (nop, 0), VOIDmode);
+      operand_vec<const char *> constraints (std::max (nop, 0), nullptr);
+
       if (nop >= 0)
        {
          lra_assert (nop == data->insn_static_data->n_operands);
          /* Now get the operand values and constraints out of the
             insn.  */
          decode_asm_operands (PATTERN (insn), NULL,
-                              data->operand_loc,
-                              constraints, operand_mode, NULL);
+                              {data->operand_loc, (unsigned)nop},
+                              constraints,
+                              operand_mode, NULL);
 
          if (flag_checking)
            for (int i = 0; i < nop; i++)
@@ -1294,10 +1296,12 @@ lra_update_insn_recog_data (rtx_insn *insn)
       insn_extract (insn);
       n = insn_static_data->n_operands;
       if (n != 0)
-       memcpy (data->operand_loc, recog_data.operand_loc, n * sizeof (rtx *));
+       memcpy (data->operand_loc, recog_data.operand_loc.address (),
+               n * sizeof (rtx *));
       n = insn_static_data->n_dups;
       if (n != 0)
-       memcpy (data->dup_loc, recog_data.dup_loc, n * sizeof (rtx *));
+       memcpy (data->dup_loc, recog_data.dup_loc.address (),
+               n * sizeof (rtx *));
       lra_assert (check_bool_attrs (insn));
     }
   return data;
diff --git a/gcc/postreload.cc b/gcc/postreload.cc
index 576456c79d560..7fbbc359a8ab5 100644
--- a/gcc/postreload.cc
+++ b/gcc/postreload.cc
@@ -471,10 +471,12 @@ reload_cse_simplify_operands (rtx_insn *insn, rtx testreg)
 {
   int i, j;
 
+  extract_constrain_insn (insn);
+
   /* For each operand, all registers that are equivalent to it.  */
-  HARD_REG_SET equiv_regs[MAX_RECOG_OPERANDS];
+  operand_vec<HARD_REG_SET> equiv_regs (recog_data.n_operands, {});
 
-  const char *constraints[MAX_RECOG_OPERANDS];
+  operand_vec<const char *> constraints (recog_data.n_operands, {});
 
   /* Vector recording how bad an alternative is.  */
   int *alternative_reject;
@@ -484,12 +486,10 @@ reload_cse_simplify_operands (rtx_insn *insn, rtx testreg)
   /* Array of vectors recording, for each operand and each alternative,
      which hard register to substitute, or -1 if the operand should be
      left as it is.  */
-  int *op_alt_regno[MAX_RECOG_OPERANDS];
+  operand_vec<int *> op_alt_regno (recog_data.n_operands, {});
   /* Array of alternatives, sorted in order of decreasing desirability.  */
   int *alternative_order;
 
-  extract_constrain_insn (insn);
-
   if (recog_data.n_alternatives == 0 || recog_data.n_operands == 0)
     return 0;
 
diff --git a/gcc/recog.cc b/gcc/recog.cc
index f9cff68e45737..70bc5bbe42296 100644
--- a/gcc/recog.cc
+++ b/gcc/recog.cc
@@ -79,8 +79,8 @@ struct recog_data_d recog_data;
 const operand_alternative *recog_op_alt;
 
 /* Used to provide recog_op_alt for asms.  */
-static operand_alternative asm_op_alt[MAX_RECOG_OPERANDS
-                                     * MAX_RECOG_ALTERNATIVES];
+static auto_vec<operand_alternative,
+               MAX_RECOG_OPERANDS * MAX_RECOG_ALTERNATIVES> asm_op_alt;
 
 /* On return from `constrain_operands', indicate which alternative
    was satisfied.  */
@@ -144,8 +144,8 @@ bool
 check_asm_operands (rtx x)
 {
   int noperands;
-  rtx *operands;
-  const char **constraints;
+  array_slice<rtx> operands;
+  array_slice<const char *> constraints;
   int i;
 
   if (!asm_labels_ok (x))
@@ -167,8 +167,8 @@ check_asm_operands (rtx x)
   if (noperands == 0)
     return true;
 
-  operands = XALLOCAVEC (rtx, noperands);
-  constraints = XALLOCAVEC (const char *, noperands);
+  operands = {XALLOCAVEC (rtx, noperands), (unsigned)noperands};
+  constraints = {XALLOCAVEC (const char *, noperands), (unsigned)noperands};
 
   decode_asm_operands (x, operands, NULL, constraints, NULL, NULL);
 
@@ -2127,8 +2127,10 @@ asm_noperands (const_rtx body)
    we don't store that info.  */
 
 const char *
-decode_asm_operands (rtx body, rtx *operands, rtx **operand_locs,
-                    const char **constraints, machine_mode *modes,
+decode_asm_operands (rtx body, array_slice<rtx> operands,
+                    array_slice<rtx *> operand_locs,
+                    array_slice<const char *> constraints,
+                    array_slice<machine_mode> modes,
                     location_t *loc)
 {
   int nbase = 0, n, i;
@@ -2147,13 +2149,13 @@ decode_asm_operands (rtx body, rtx *operands, rtx 
**operand_locs,
 
       /* The output is in the SET.
         Its constraint is in the ASM_OPERANDS itself.  */
-      if (operands)
+      if (operands.is_valid ())
        operands[0] = SET_DEST (body);
-      if (operand_locs)
+      if (operand_locs.is_valid ())
        operand_locs[0] = &SET_DEST (body);
-      if (constraints)
+      if (constraints.is_valid ())
        constraints[0] = ASM_OPERANDS_OUTPUT_CONSTRAINT (asmop);
-      if (modes)
+      if (modes.is_valid ())
        modes[0] = GET_MODE (SET_DEST (body));
       nbase = 1;
       break;
@@ -2175,13 +2177,13 @@ decode_asm_operands (rtx body, rtx *operands, rtx 
**operand_locs,
                    || GET_CODE (XVECEXP (body, 0, i)) == CLOBBER)
                  break;                /* Past last SET */
                gcc_assert (GET_CODE (XVECEXP (body, 0, i)) == SET);
-               if (operands)
+               if (operands.is_valid ())
                  operands[i] = SET_DEST (XVECEXP (body, 0, i));
-               if (operand_locs)
+               if (operand_locs.is_valid ())
                  operand_locs[i] = &SET_DEST (XVECEXP (body, 0, i));
-               if (constraints)
+               if (constraints.is_valid ())
                  constraints[i] = XSTR (SET_SRC (XVECEXP (body, 0, i)), 1);
-               if (modes)
+               if (modes.is_valid ())
                  modes[i] = GET_MODE (SET_DEST (XVECEXP (body, 0, i)));
              }
            nbase = i;
@@ -2202,13 +2204,13 @@ decode_asm_operands (rtx body, rtx *operands, rtx 
**operand_locs,
   n = ASM_OPERANDS_INPUT_LENGTH (asmop);
   for (i = 0; i < n; i++)
     {
-      if (operand_locs)
+      if (operand_locs.is_valid ())
        operand_locs[nbase + i] = &ASM_OPERANDS_INPUT (asmop, i);
-      if (operands)
+      if (operands.is_valid ())
        operands[nbase + i] = ASM_OPERANDS_INPUT (asmop, i);
-      if (constraints)
+      if (constraints.is_valid ())
        constraints[nbase + i] = ASM_OPERANDS_INPUT_CONSTRAINT (asmop, i);
-      if (modes)
+      if (modes.is_valid ())
        modes[nbase + i] = ASM_OPERANDS_INPUT_MODE (asmop, i);
     }
   nbase += n;
@@ -2216,13 +2218,13 @@ decode_asm_operands (rtx body, rtx *operands, rtx 
**operand_locs,
   n = ASM_OPERANDS_LABEL_LENGTH (asmop);
   for (i = 0; i < n; i++)
     {
-      if (operand_locs)
+      if (operand_locs.is_valid ())
        operand_locs[nbase + i] = &ASM_OPERANDS_LABEL (asmop, i);
-      if (operands)
+      if (operands.is_valid ())
        operands[nbase + i] = ASM_OPERANDS_LABEL (asmop, i);
-      if (constraints)
+      if (constraints.is_valid ())
        constraints[nbase + i] = "";
-      if (modes)
+      if (modes.is_valid ())
        modes[nbase + i] = Pmode;
     }
 
@@ -2280,7 +2282,8 @@ get_referenced_operands (const char *string, bool *used,
    Return > 0 if ok, = 0 if bad, < 0 if inconclusive.  */
 
 int
-asm_operand_ok (rtx op, const char *constraint, const char **constraints)
+asm_operand_ok (rtx op, const char *constraint,
+               array_slice<const char *> constraints)
 {
   int result = 0;
   bool incdec_ok = false;
@@ -2312,7 +2315,7 @@ asm_operand_ok (rtx op, const char *constraint, const 
char **constraints)
             given us the proper matching constraint, but we can't
             actually fail the check if they didn't.  Indicate that
             results are inconclusive.  */
-         if (constraints)
+         if (constraints.is_valid ())
            {
              char *end;
              unsigned long match;
@@ -2827,9 +2830,8 @@ extract_insn (rtx_insn *insn)
   int noperands;
   rtx body = PATTERN (insn);
 
-  recog_data.n_operands = 0;
+  recog_data.init (0, 0);
   recog_data.n_alternatives = 0;
-  recog_data.n_dups = 0;
   recog_data.is_asm = false;
 
   switch (GET_CODE (body))
@@ -2858,20 +2860,18 @@ extract_insn (rtx_insn *insn)
        goto normal_insn;
     case ASM_OPERANDS:
     asm_insn:
-      recog_data.n_operands = noperands = asm_noperands (body);
+      recog_data.init (noperands = asm_noperands (body), 0);
       if (noperands >= 0)
        {
          /* This insn is an `asm' with operands.  */
 
-         /* expand_asm_operands makes sure there aren't too many operands.  */
-         gcc_assert (noperands <= MAX_RECOG_OPERANDS);
-
          /* Now get the operand values and constraints out of the insn.  */
          decode_asm_operands (body, recog_data.operand,
                               recog_data.operand_loc,
                               recog_data.constraints,
                               recog_data.operand_mode, NULL);
-         memset (recog_data.is_operator, 0, sizeof recog_data.is_operator);
+         for (char &x : recog_data.is_operator)
+           x = 0;
          if (noperands > 0)
            {
              const char *p =  recog_data.constraints[0];
@@ -2893,9 +2893,9 @@ extract_insn (rtx_insn *insn)
       if (icode < 0)
        fatal_insn_not_found (insn);
 
-      recog_data.n_operands = noperands = insn_data[icode].n_operands;
+      recog_data.init (noperands = insn_data[icode].n_operands,
+                      insn_data[icode].n_dups);
       recog_data.n_alternatives = insn_data[icode].n_alternatives;
-      recog_data.n_dups = insn_data[icode].n_dups;
 
       insn_extract (insn);
 
@@ -3101,11 +3101,13 @@ preprocess_constraints (rtx_insn *insn)
       int n_operands = recog_data.n_operands;
       int n_alternatives = recog_data.n_alternatives;
       int n_entries = n_operands * n_alternatives;
-      memset (asm_op_alt, 0, n_entries * sizeof (operand_alternative));
+      asm_op_alt.truncate (0);
+      asm_op_alt.safe_grow_cleared (n_entries);
       preprocess_constraints (n_operands, n_alternatives,
-                             recog_data.constraints, asm_op_alt,
+                             recog_data.constraints.address (),
+                             asm_op_alt.address (),
                              NULL);
-      recog_op_alt = asm_op_alt;
+      recog_op_alt = asm_op_alt.address ();
     }
 }
 
@@ -3168,12 +3170,12 @@ test_dependent_filter (constraint_num cn, rtx op, int 
offset,
 bool
 constrain_operands (int strict, alternative_mask alternatives)
 {
-  const char *constraints[MAX_RECOG_OPERANDS];
-  int matching_operands[MAX_RECOG_OPERANDS];
-  int earlyclobber[MAX_RECOG_OPERANDS];
+  operand_vec<const char *> constraints (recog_data.n_operands, NULL);
+  operand_vec<int> matching_operands (recog_data.n_operands, 0);
+  operand_vec<int> earlyclobber (recog_data.n_operands, 0);
   int c;
 
-  struct funny_match funny_match[MAX_RECOG_OPERANDS];
+  operand_vec<funny_match> funny_match (recog_data.n_operands, {});
   int funny_match_index;
 
   which_alternative = 0;
diff --git a/gcc/recog.h b/gcc/recog.h
index d7c816a6097d4..0eb0a99db1d77 100644
--- a/gcc/recog.h
+++ b/gcc/recog.h
@@ -250,7 +250,7 @@ private:
 extern void init_recog (void);
 extern void init_recog_no_volatile (void);
 extern bool check_asm_operands (rtx);
-extern int asm_operand_ok (rtx, const char *, const char **);
+extern int asm_operand_ok (rtx, const char *, array_slice<const char *>);
 extern bool validate_change (rtx, rtx *, rtx, bool);
 extern bool validate_unshare_change (rtx, rtx *, rtx, bool);
 extern bool validate_change_xveclen (rtx, rtx *, int, bool);
@@ -381,10 +381,32 @@ extern int which_alternative;
 /* True for inline asm operands with - constraint modifier.  */
 extern bool raw_constraint_p;
 
+/* Convenience wrapper for operand-related data storage.  */
+template<typename T>
+using operand_vec = auto_vec<T, MAX_RECOG_OPERANDS>;
+
 /* The following vectors hold the results from insn_extract.  */
 
 struct recog_data_d
 {
+  void init (size_t noperands, size_t ndups)
+  {
+    auto resize = [](auto &vec, size_t n)
+      {
+       vec.truncate (0);
+       vec.safe_grow_cleared (n);
+      };
+    n_operands = noperands;
+    n_dups = ndups;
+    resize (operand, noperands);
+    resize (operand_loc, noperands);
+    resize (constraints, noperands);
+    resize (is_operator, noperands);
+    resize (operand_mode, noperands);
+    resize (operand_type, noperands);
+    resize (dup_loc, ndups);
+    resize (dup_num, ndups);
+  }
   /* It is very tempting to make the 5 operand related arrays into a
      structure and index on that.  However, to be source compatible
      with all of the existing md file insn constraints and output
@@ -392,30 +414,30 @@ struct recog_data_d
      member, making an array for the rest seems pointless.  */
 
   /* Gives value of operand N.  */
-  rtx operand[MAX_RECOG_OPERANDS];
+  operand_vec<rtx> operand;
 
   /* Gives location where operand N was found.  */
-  rtx *operand_loc[MAX_RECOG_OPERANDS];
+  operand_vec<rtx *> operand_loc;
 
   /* Gives the constraint string for operand N.  */
-  const char *constraints[MAX_RECOG_OPERANDS];
+  operand_vec<const char *> constraints;
 
   /* Nonzero if operand N is a match_operator or a match_parallel.  */
-  char is_operator[MAX_RECOG_OPERANDS];
+  operand_vec<char> is_operator;
 
   /* Gives the mode of operand N.  */
-  machine_mode operand_mode[MAX_RECOG_OPERANDS];
+  operand_vec<machine_mode> operand_mode;
 
   /* Gives the type (in, out, inout) for operand N.  */
-  enum op_type operand_type[MAX_RECOG_OPERANDS];
+  operand_vec<enum op_type> operand_type;
 
   /* Gives location where the Nth duplicate-appearance of an operand
      was found.  This is something that matched MATCH_DUP.  */
-  rtx *dup_loc[MAX_DUP_OPERANDS];
+  operand_vec<rtx *> dup_loc;
 
   /* Gives the operand number that was duplicated in the Nth
      duplicate-appearance of an operand.  */
-  char dup_num[MAX_DUP_OPERANDS];
+  operand_vec<char> dup_num;
 
   /* ??? Note that these are `char' instead of `unsigned char' to (try to)
      avoid certain lossage from K&R C, wherein `unsigned char' default
diff --git a/gcc/regrename.cc b/gcc/regrename.cc
index 07c3659f8a8c5..ee925385ed610 100644
--- a/gcc/regrename.cc
+++ b/gcc/regrename.cc
@@ -1575,8 +1575,9 @@ scan_rtx (rtx_insn *insn, rtx *loc, enum reg_class cl, 
enum scan_actions action,
    and earlyclobbers.  */
 
 static void
-hide_operands (int n_ops, rtx *old_operands, rtx *old_dups,
-              unsigned HOST_WIDE_INT do_not_hide, bool inout_and_ec_only)
+hide_operands (int n_ops, array_slice<rtx> old_operands,
+              array_slice<rtx> old_dups, const_bitmap do_not_hide,
+              bool inout_and_ec_only)
 {
   int i;
   const operand_alternative *op_alt = which_op_alt ();
@@ -1588,7 +1589,7 @@ hide_operands (int n_ops, rtx *old_operands, rtx 
*old_dups,
         reachable by proper operands.  */
       if (recog_data.constraints[i][0] == '\0')
        continue;
-      if (do_not_hide & (1 << i))
+      if (bitmap_bit_p (do_not_hide, i))
        continue;
       if (!inout_and_ec_only || recog_data.operand_type[i] == OP_INOUT
          || op_alt[i].earlyclobber)
@@ -1598,7 +1599,7 @@ hide_operands (int n_ops, rtx *old_operands, rtx 
*old_dups,
     {
       int opn = recog_data.dup_num[i];
       old_dups[i] = *recog_data.dup_loc[i];
-      if (do_not_hide & (1 << opn))
+      if (bitmap_bit_p (do_not_hide, opn))
        continue;
       if (!inout_and_ec_only || recog_data.operand_type[opn] == OP_INOUT
          || op_alt[opn].earlyclobber)
@@ -1610,7 +1611,8 @@ hide_operands (int n_ops, rtx *old_operands, rtx 
*old_dups,
    are processing; the arguments are the same as in hide_operands.  */
 
 static void
-restore_operands (rtx_insn *insn, int n_ops, rtx *old_operands, rtx *old_dups)
+restore_operands (rtx_insn *insn, int n_ops, array_slice<rtx> old_operands,
+                 array_slice<rtx> old_dups)
 {
   int i;
   for (i = 0; i < recog_data.n_dups; i++)
@@ -1680,7 +1682,7 @@ static bool
 build_def_use (basic_block bb)
 {
   rtx_insn *insn;
-  unsigned HOST_WIDE_INT untracked_operands;
+  auto_bitmap untracked_operands;
 
   fail_current_block = false;
 
@@ -1690,8 +1692,6 @@ build_def_use (basic_block bb)
        {
          int n_ops;
          rtx note;
-         rtx old_operands[MAX_RECOG_OPERANDS];
-         rtx old_dups[MAX_DUP_OPERANDS];
          int i;
          int predicated;
          enum rtx_code set_code = SET;
@@ -1726,9 +1726,11 @@ build_def_use (basic_block bb)
 
          extract_constrain_insn (insn);
          preprocess_constraints (insn);
+         operand_vec<rtx> old_operands (recog_data.n_operands, NULL_RTX);
+         operand_vec<rtx> old_dups (recog_data.n_dups, NULL_RTX);
          const operand_alternative *op_alt = which_op_alt ();
          n_ops = recog_data.n_operands;
-         untracked_operands = 0;
+         bitmap_clear (untracked_operands);
 
          if (insn_rr.exists ())
            {
@@ -1768,8 +1770,8 @@ build_def_use (basic_block bb)
                                    GET_MODE_SIZE (matches_mode))
                          && !verify_reg_in_set (op, &live_in_chains))
                        {
-                         untracked_operands |= 1 << i;
-                         untracked_operands |= 1 << matches;
+                         bitmap_set_bit (untracked_operands, i);
+                         bitmap_set_bit (untracked_operands, matches);
                        }
                    }
                }
@@ -1777,12 +1779,12 @@ build_def_use (basic_block bb)
              if (regstack_completed
                  && REG_P (op)
                  && IN_RANGE (REGNO (op), FIRST_STACK_REG, LAST_STACK_REG))
-               untracked_operands |= 1 << i;
+               bitmap_set_bit (untracked_operands, i);
 #endif
              /* If there's an in-out operand with a register that is not
                 being tracked at all yet, open a chain.  */
              if (recog_data.operand_type[i] == OP_INOUT
-                 && !(untracked_operands & (1 << i))
+                 && !bitmap_bit_p (untracked_operands, i)
                  && REG_P (op)
                  && !verify_reg_tracked (op))
                create_new_chain (REGNO (op), REG_NREGS (op), NULL, NULL,
@@ -1847,7 +1849,7 @@ build_def_use (basic_block bb)
                 information to pass down.  Any operands that we could
                 substitute in will be represented elsewhere.  */
              if (recog_data.constraints[opn][0] == '\0'
-                 || untracked_operands & (1 << opn))
+                 || bitmap_bit_p (untracked_operands, opn))
                continue;
 
              if (insn_info)
diff --git a/gcc/reload.cc b/gcc/reload.cc
index 7917cc94a9d0b..e9afa966ae21a 100644
--- a/gcc/reload.cc
+++ b/gcc/reload.cc
@@ -2728,9 +2728,9 @@ find_reloads (rtx_insn *insn, int replace, int 
ind_levels, int live_known,
   insn_code_number = INSN_CODE (insn);
   this_insn_is_asm = insn_code_number < 0;
 
-  memcpy (operand_mode, recog_data.operand_mode,
+  memcpy (operand_mode, recog_data.operand_mode.address (),
          noperands * sizeof (machine_mode));
-  memcpy (constraints, recog_data.constraints,
+  memcpy (constraints, recog_data.constraints.address (),
          noperands * sizeof (const char *));
 
   commutative = -1;
diff --git a/gcc/rtl.h b/gcc/rtl.h
index aa0b4c77a3951..465431b8c4586 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -3865,8 +3865,11 @@ extern void reginfo_cc_finalize (void);
 /* recog.cc */
 extern rtx extract_asm_operands (rtx);
 extern int asm_noperands (const_rtx);
-extern const char *decode_asm_operands (rtx, rtx *, rtx **, const char **,
-                                       machine_mode *, location_t *);
+extern const char *decode_asm_operands (rtx, array_slice<rtx>,
+                                       array_slice<rtx *>,
+                                       array_slice<const char *>,
+                                       array_slice<machine_mode>,
+                                       location_t *);
 extern void get_referenced_operands (const char *, bool *, unsigned int);
 
 extern enum reg_class reg_preferred_class (int);
diff --git a/gcc/testsuite/gcc.dg/pr61692.c b/gcc/testsuite/gcc.dg/pr61692.c
index 1b619bd753555..67873b80daa48 100644
--- a/gcc/testsuite/gcc.dg/pr61692.c
+++ b/gcc/testsuite/gcc.dg/pr61692.c
@@ -25,7 +25,7 @@ int Labels()
           label21, label22, label23, label24, label25, 
           label26, label27, label28, label29, label30);
 
-    __asm__ goto ("" /* { dg-error "more than 30 operands" } */
+    __asm__ goto ("" /* Works. */
         : /* no outputs */ 
         : /* no inputs */ 
         : /* no clobbers */
@@ -71,7 +71,7 @@ int Labels_and_Inputs()
       : /* no clobbers */
       : label01);
 
-    __asm__ goto ("" /* { dg-error "more than 30 operands" } */
+    __asm__ goto ("" /* Works. */
       : /* no outputs */
       : "m" (b01), "m" (b02), "m" (b03), "m" (b04), "m" (b05), 
         "m" (b06), "m" (b07), "m" (b08), "m" (b09), "m" (b10), 
@@ -101,7 +101,7 @@ int Outputs()
            "=m" (b21),  "=m" (b22),  "=m" (b23),  "=m" (b24), "=m" (b25),
            "=m" (b26),  "=m" (b27),  "=m" (b28),  "=m" (b29), "=m" (b30));
 
-    __asm__ volatile ("" /* { dg-error "more than 30 operands" } */
+    __asm__ volatile ("" /* Works. */
          : "=m" (b01),  "=m" (b02),  "=m" (b03),  "=m" (b04), "=m" (b05),
            "=m" (b06),  "=m" (b07),  "=m" (b08),  "=m" (b09), "=m" (b10),
            "=m" (b11),  "=m" (b12),  "=m" (b13),  "=m" (b14), "=m" (b15),
@@ -134,7 +134,7 @@ int Inputs()
         "m" (b21), "m" (b22), "m" (b23), "m" (b24), "m" (b25),
         "m" (b26), "m" (b27), "m" (b28), "m" (b29), "m" (b30));
 
-    __asm__ volatile ("" /* { dg-error "more than 30 operands" } */
+    __asm__ volatile ("" /* Works. */
       : /* no outputs */
       : "m" (b01), "m" (b02), "m" (b03), "m" (b04), "m" (b05), 
         "m" (b06), "m" (b07), "m" (b08), "m" (b09), "m" (b10), 
@@ -164,7 +164,7 @@ int Input_Output()
            "+m" (b06),  "+m" (b07),  "+m" (b08),  "+m" (b09), "+m" (b10),
            "+m" (b11),  "+m" (b12),  "+m" (b13),  "+m" (b14), "+m" (b15));
 
-    __asm__ volatile ("" /* { dg-error "more than 30 operands" } */
+    __asm__ volatile ("" /* Works. */
          : "+m" (b01),  "+m" (b02),  "+m" (b03),  "+m" (b04), "+m" (b05),
            "+m" (b06),  "+m" (b07),  "+m" (b08),  "+m" (b09), "+m" (b10),
            "+m" (b11),  "+m" (b12),  "+m" (b13),  "+m" (b14), "+m" (b15),
diff --git a/gcc/varasm.cc b/gcc/varasm.cc
index 0dbc35d926a34..a4f4b849f184c 100644
--- a/gcc/varasm.cc
+++ b/gcc/varasm.cc
@@ -1745,15 +1745,9 @@ assemble_asm (tree asm_str)
       tree tail;
       bool allows_mem, allows_reg, is_inout;
       rtx *ops = NULL;
-      if (noutputs + ninputs > MAX_RECOG_OPERANDS)
-       {
-         error ("more than %d operands in %<asm%>", MAX_RECOG_OPERANDS);
-         goto done;
-       }
       constraints = XALLOCAVEC (const char *, noutputs + ninputs);
       ops = XALLOCAVEC (rtx, noutputs + ninputs);
-      memset (&recog_data, 0, sizeof (recog_data));
-      recog_data.n_operands = ninputs + noutputs;
+      recog_data.init (ninputs + noutputs, 0);
       recog_data.is_asm = true;
       reload_completed = 0;
       cse_not_expected = 1;
-- 
2.54.0

Reply via email to