RFC: Patch to align spills beyond what the stack supports

Steve Ellcey sellcey@imgtec.com
Thu May 7 17:53:00 GMT 2015


I would like to get some feedback on an idea of how to spill registers
that require (or perhaps only prefer for performance reasons) an alignment
greater than that supported by the stack.

If you look at how GCC supports local variables with alignment requirements
greater than the stack supports, there are two methods.  One is to dynamically
realign the stack and the other is to alloca a block of space on the stack
and create a pointer to an aligned address within that space.

The advantage of the first approach is that in addition to aligning local
variables, aligning the stack will align spill slots since they are also
stored on the stack.  The disadvantage with this approach is that it is
complicated, involves a fair amount of target dependent changes, and risks
breaking a targets ABI if not done very carefully.  The x86 target is the
only one that has implemented this approach as far as I can see.

The advantage of the second approach is that it is target independent and
doesn't risk breaking a targets ABI.  The disadvantage is that it doesn't
help with aligning spill slots since it isn't actually changing the stacks
alignment.

After spending some time trying to implement the dynamic stack alignment
method for MIPS, I decided to try the second approach and extend the alloca
method to spills.

My approach was to create a tree pass that tried to guess at how many
aligned spill slots might be needed in a routine and then allocate an
aligned local variable to hold those spills.  This variable would get the
needed alignment via the existing alloca method used for local variables.

This guessing of how many spills we may need is the main drawback to my
approach because we have no way of actually knowing how many (if any) spill
slots we will end up needing.  The advantage of this approach is that
the only real target dependent code I needed to create was to set a hard
register that could point to the spill variable so that the lra-spill code
could use it when needed for spills.   I didn't implement anything for
non-lra register allocation.

I have been thinking that it might be possible to tag the alloca that
allocates the spill area somehow so that lra-spills could increase (or
decrease) it if needed but I haven't investigated that idea in detail yet.

What do people think about this idea?  Attached is a patch I created that
implements this idea for MIPS.  I am still doing some testing, mostly with
MSA vector registers (a MIPS feature not yet checked in).  Reading and writing
these 16 byte registers on a 16 byte boundary is more efficient than an
8 byte boundary but the O32 MIPS ABI only supports 8 byte stack alignment.

Is this an approach that might be approved for checkin with some further
work?

Steve Ellcey
sellcey@imgtec.com



2015-05-07  Steve Ellcey  <sellcey@imgtec.com>

	* Makefile.in (OBJS): Add tree-align-spills.
	* common.opt (Wunaligned-spills): New.
	(falign-spills): New.
	* params.def (PARAM_ALLOCA_SPILL_SLOT_ALIGN): New.
	(PARAM_ALLOCA_SPILL_SLOT_SIZE): New.
	(PARAM_ALLOCA_SPILL_SLOTS): New.
	* passes.def (pass_alloca_spill): New.
	* target.def (get_alloca_spill_regnum): New.
	* timevar.def (TV_TREE_ALLOCA_SPILL): New.
	* tree-pass.h (make_pass_alloca_spill): New.
	* function.h (function): Add new fields.
	* tree-align-spills.c: New.
	* lra-spills.c (assign_mem_slot): Add alignment checks.
	* doc/tm.texi.in (TARGET_GET_ALLOCA_SPILL_REGNUM): New.
	* config/mips/mips.h (AP_REGNUM): New.
	* config/mips/mips.c (mips_conditional_register_usage):
	Reserve AP_REGNUM if needed.
	(mips_get_alloca_spill_regnum): New.
	(TARGET_GET_ALLOCA_SPILL_REGNUM): New.


diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 652b3e71d..9871148 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1400,6 +1400,7 @@ OBJS = \
 	tsan.o \
 	ubsan.o \
 	sanopt.o \
+	tree-align-spills.o \
 	tree-call-cdce.o \
 	tree-cfg.o \
 	tree-cfgcleanup.o \
diff --git a/gcc/common.opt b/gcc/common.opt
index 51833c1..fffd011 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -683,6 +683,10 @@ Wtype-limits
 Common Var(warn_type_limits) Warning EnabledBy(Wextra)
 Warn if a comparison is always true or always false due to the limited range of the data type
 
+Wunaligned-spills
+Common Var(warn_unaligned_spills) Warning
+Warn whenever a variable whose alignment requirement is greater than the stack supports is spilled
+
 Wuninitialized
 Common Var(warn_uninitialized) Warning EnabledBy(Wextra)
 Warn about uninitialized automatic variables
@@ -873,6 +877,10 @@ Align the start of loops
 falign-loops=
 Common RejectNegative Joined UInteger Var(align_loops)
 
+falign-spills
+Common Report Var(flag_align_spills,1) Init(-1)
+Alloca spill space for registers that need alignment greater than the stack.
+
 fargument-alias
 Common Ignore
 Does nothing. Preserved for backward compatibility.
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index bf69850..658818e 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -103,6 +103,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cgraph.h"
 #include "builtins.h"
 #include "rtl-iter.h"
+#include "params.h"
 
 /* True if X is an UNSPEC wrapper around a SYMBOL_REF or LABEL_REF.  */
 #define UNSPEC_ADDRESS_P(X)					\
@@ -17655,6 +17656,12 @@ mips_option_override (void)
       TARGET_MIPS3D = 0;
     }
 
+#if 0
+  /* If TARGET_MSA and flag_align_spills was not explicitly set, set it.  */
+  if (TARGET_MSA && flag_align_spills == -1)
+    flag_align_spills = 1;
+#endif
+
   /* Make sure that -mpaired-single is only used on ISAs that support it.
      We must disable it otherwise since it relies on other ISA properties
      like ISA_HAS_8CC having their normal values.  */
@@ -17928,6 +17935,14 @@ mips_conditional_register_usage (void)
       AND_COMPL_HARD_REG_SET (operand_reg_set,
 			      reg_class_contents[(int) MD_REGS]);
     }
+
+  if (flag_align_spills)
+    {
+      global_regs[AP_REGNUM] = 1;
+      fixed_regs[AP_REGNUM] = 1;
+      call_used_regs[AP_REGNUM] = 1;
+    }
+
   /* $f20-$f23 are call-clobbered for n64.  */
   if (mips_abi == ABI_64)
     {
@@ -19364,7 +19379,17 @@ mips_lra_p (void)
 {
   return mips_lra_flag;
 }
-
+
+/* Return alloca spill register number, this register points to alloca
+   space used for registers whose alignment requirement is greater than
+   the stack supports.  */
+
+static
+int mips_get_alloca_spill_regnum (void)
+{
+  return AP_REGNUM;
+}
+
 /* Initialize the GCC target structure.  */
 #undef TARGET_ASM_ALIGNED_HI_OP
 #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
@@ -19621,6 +19646,9 @@ mips_lra_p (void)
 #undef TARGET_LRA_P
 #define TARGET_LRA_P mips_lra_p
 
+#undef TARGET_GET_ALLOCA_SPILL_REGNUM
+#define TARGET_GET_ALLOCA_SPILL_REGNUM mips_get_alloca_spill_regnum
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-mips.h"
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index 4bd83f5..8e7d9bc 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -1898,6 +1898,9 @@ FP_ASM_SPEC "\
 /* Register in which static-chain is passed to a function.  */
 #define STATIC_CHAIN_REGNUM (GP_REG_FIRST + 15)
 
+/* Argument pointer register if needed (due to stack realignment).  */
+#define AP_REGNUM (GP_REG_FIRST + 16)
+
 /* Registers used as temporaries in prologue/epilogue code:
 
    - If a MIPS16 PIC function needs access to _gp, it first loads
diff --git a/gcc/config/mips/t-mti-linux b/gcc/config/mips/t-mti-linux
index c0dcbf0..adf1dae 100644
--- a/gcc/config/mips/t-mti-linux
+++ b/gcc/config/mips/t-mti-linux
@@ -19,8 +19,8 @@
 # The default build is mips32r2, hard-float big-endian.  Add mips32,
 # soft-float, and little-endian variations.
 
-MULTILIB_OPTIONS = mips32/mips64/mips64r2 mips16/mmicromips mabi=64 EL msoft-float mnan=2008
-MULTILIB_DIRNAMES = mips32 mips64 mips64r2 mips16 micromips 64 el sof nan2008
+MULTILIB_OPTIONS = mips64r2 mabi=64 EL mnan=2008
+MULTILIB_DIRNAMES = mips64r2 64 el nan2008
 MULTILIB_MATCHES = EL=mel EB=meb mips32r2=mips32r3 mips32r2=mips32r5 mips64r2=mips64r3 mips64r2=mips64r5
 
 # The 64 bit ABI is not supported on the mips32 architecture.
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index dd1fd22..00590a8 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -9564,6 +9564,10 @@ following it should not be run.  Usually true only for virtual assembler
 targets.
 @end deftypevr
 
+@deftypefn {Target Hook} int TARGET_GET_ALLOCA_SPILL_REGNUM (void)
+Hard register number used to access memory for highly aligned spills (more than MAX_STACK_ALIGNMENT).
+@end deftypefn
+
 @defmac ASM_OUTPUT_DWARF_DELTA (@var{stream}, @var{size}, @var{label1}, @var{label2})
 A C statement to issue assembly directives that create a difference
 @var{lab1} minus @var{lab2}, using an integer of the given @var{size}.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 8680967..0a8271d 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -7011,6 +7011,8 @@ tables, and hence is desirable if it works.
 
 @hook TARGET_NO_REGISTER_ALLOCATION
 
+@hook TARGET_GET_ALLOCA_SPILL_REGNUM
+
 @defmac ASM_OUTPUT_DWARF_DELTA (@var{stream}, @var{size}, @var{label1}, @var{label2})
 A C statement to issue assembly directives that create a difference
 @var{lab1} minus @var{lab2}, using an integer of the given @var{size}.
diff --git a/gcc/function.h b/gcc/function.h
index 81d76bf..4484713 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -589,6 +589,12 @@ struct GTY(()) function {
   /* Last assigned dependence info clique.  */
   unsigned short last_clique;
 
+  /* Highly aligned spill slot information.  */
+  unsigned int spill_slot_alignment;
+  unsigned int spill_slot_size;
+  unsigned int spill_slots;
+  unsigned int used_spill_slots;
+
   /* Collected bit flags.  */
 
   /* Number of units of general registers that need saving in stdarg
diff --git a/gcc/lra-spills.c b/gcc/lra-spills.c
index ed678d5..9298727 100644
--- a/gcc/lra-spills.c
+++ b/gcc/lra-spills.c
@@ -101,6 +101,8 @@ along with GCC; see the file COPYING3.	If not see
 #include "lra-int.h"
 #include "ira.h"
 #include "df.h"
+#include "diagnostic-core.h"
+#include "params.h"
 
 
 /* Max regno at the start of the pass.	*/
@@ -180,10 +182,36 @@ assign_mem_slot (int i)
      which refer to the pseudo reg in wider modes.  We allocate a new
      slot, making sure that it has enough inherent space and total
      space.  */
+  else if ((flag_align_spills > 0) && (inherent_align > STACK_BOUNDARY))
+    {
+	rtx spill_reg, addr;
+	int spill_offset;
+
+	gcc_assert (targetm.get_alloca_spill_regnum);
+	gcc_assert (cfun->spill_slot_size > 0);
+	gcc_assert (cfun->spill_slot_alignment > 0);
+	gcc_assert (cfun->spill_slots > 0);
+	gcc_assert (((cfun->spill_slot_size * 8)
+		     % cfun->spill_slot_alignment) == 0);
+	if (cfun->used_spill_slots >= cfun->spill_slots)
+	  error ("ran out of spill slots for registers with alignment greater than stack alignment");
+
+	spill_reg = gen_raw_REG (Pmode, targetm.get_alloca_spill_regnum ());
+	spill_offset = cfun->used_spill_slots * cfun->spill_slot_size;
+	addr = plus_constant (Pmode, spill_reg, spill_offset);
+	cfun->used_spill_slots++;
+	x = gen_rtx_MEM (mode, addr);
+	slots[pseudo_slots[i].slot_num].mem = x;
+	set_mem_attrs_for_spill (x);
+	pseudo_slots[i].mem = x;
+    }
   else
     {
       rtx stack_slot;
 
+      if (warn_unaligned_spills && (inherent_align > STACK_BOUNDARY))
+	warning (OPT_Wunaligned_spills, "A psuedo-register is being spilled to the stack with isufficient alignment");
+
       /* No known place to spill from => no slot to reuse.  */
       x = assign_stack_local (mode, total_size,
 			      min_align > inherent_align
diff --git a/gcc/params.def b/gcc/params.def
index 48b39a2..a3ae79c 100644
--- a/gcc/params.def
+++ b/gcc/params.def
@@ -1177,6 +1177,21 @@ DEFPARAM (PARAM_MAX_FSM_THREAD_PATHS,
 	  "max-fsm-thread-paths",
 	  "Maximum number of new jump thread paths to create for a finite state automaton",
 	  50, 1, 999999)
+
+DEFPARAM (PARAM_ALLOCA_SPILL_SLOT_ALIGN,
+	  "alloca-spill-slot-align",
+	  "Number of bytes to allocate for highly aligned spills",
+	  -1, 0, 999999)
+
+DEFPARAM (PARAM_ALLOCA_SPILL_SLOT_SIZE,
+	  "alloca-spill-slot-size",
+	  "Number of bytes to allocate for highly aligned spills",
+	  -1, 0, 999999)
+
+DEFPARAM (PARAM_ALLOCA_SPILL_SLOTS,
+	  "alloca-spill-slots",
+	  "Number of bytes to allocate for highly aligned spills",
+	  -1, 0, 999999)
 /*
 
 Local variables:
diff --git a/gcc/passes.def b/gcc/passes.def
index 32213e8..72cb44b 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -346,6 +346,7 @@ along with GCC; see the file COPYING3.  If not see
   NEXT_PASS (pass_lower_vaarg);
   NEXT_PASS (pass_lower_vector);
   NEXT_PASS (pass_lower_complex_O0);
+  NEXT_PASS (pass_alloca_spill);
   NEXT_PASS (pass_asan_O0);
   NEXT_PASS (pass_tsan_O0);
   NEXT_PASS (pass_sanopt);
diff --git a/gcc/target.def b/gcc/target.def
index 329ea04..732ca87 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -5826,6 +5826,11 @@ following it should not be run.  Usually true only for virtual assembler\n\
 targets.",
 bool, false)
 
+DEFHOOK
+(get_alloca_spill_regnum,
+ "Hard register number used to access memory for highly aligned spills (more than MAX_STACK_ALIGNMENT).",
+ int, (void), NULL)
+
 /* Leave the boolean fields at the end.  */
 
 /* Functions related to mode switching.  */
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 711bbed..a79c741 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -268,6 +268,7 @@ DEFTIMEVAR (TV_PLUGIN_RUN            , "plugin execution")
 DEFTIMEVAR (TV_GIMPLE_SLSR           , "straight-line strength reduction")
 DEFTIMEVAR (TV_VTABLE_VERIFICATION   , "vtable verification")
 DEFTIMEVAR (TV_TREE_UBSAN            , "tree ubsan")
+DEFTIMEVAR (TV_TREE_ALLOCA_SPILL     , "tree alloca spill")
 
 /* Everything else in rest_of_compilation not included above.  */
 DEFTIMEVAR (TV_EARLY_LOCAL	     , "early local passes")
diff --git a/gcc/tree-align-spills.c b/gcc/tree-align-spills.c
new file mode 100644
index 0000000..635d8af
--- /dev/null
+++ b/gcc/tree-align-spills.c
@@ -0,0 +1,221 @@
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "vec.h"
+#include "double-int.h"
+#include "input.h"
+#include "alias.h"
+#include "symtab.h"
+#include "wide-int.h"
+#include "inchash.h"
+#include "tree.h"
+#include "fold-const.h"
+#include "hard-reg-set.h"
+#include "input.h"
+#include "function.h"
+#include "predict.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "basic-block.h"
+#include "tree-pretty-print.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-expr.h"
+#include "is-a.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
+#include "gimple-walk.h"
+#include "gimple-ssa.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
+#include "tree-pass.h"
+#include "langhooks.h"
+#include "rtl.h"
+#include "expr.h"
+#include "flags.h"
+#include "print-tree.h"
+#include "target.h"
+#include "common/common-target.h"
+#include "targhooks.h"
+#include "stor-layout.h"
+#include "ipa-ref.h"
+#include "plugin-api.h"
+#include "cgraph.h"
+#include "params.h"
+
+/* static vec<tree> op_list; */
+
+static tree
+check_alignment (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data)
+{
+  struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
+  vec<tree> *op_list = (vec<tree> *) wi->info;
+  bool found;
+  unsigned int i;
+  tree t;
+
+  if (((TREE_CODE (*tp) == SSA_NAME)
+	|| (TREE_CODE (*tp) == VAR_DECL)
+	|| (TREE_CODE (*tp) == VECTOR_CST))
+      && VECTOR_TYPE_P (TREE_TYPE (*tp))
+      && GET_MODE_ALIGNMENT (vector_type_mode (TREE_TYPE (*tp)))
+	 > STACK_BOUNDARY)
+    {
+      found = false;
+      FOR_EACH_VEC_ELT (*op_list, i, t)
+	{
+	  if (t == *tp)
+	    {
+	      found = true;
+	      break;
+	    }
+	}
+      if (!found)
+        op_list->safe_push (*tp);
+    }
+  return NULL_TREE;
+}
+
+static void
+set_spill_info (function *fun)
+{
+  basic_block bb;
+  gimple_stmt_iterator gsi;
+  tree t;
+  size_t align, size;
+  size_t max_align, max_size, spill_slots;
+  unsigned int i;
+  machine_mode mode;
+  vec<tree> op_list = vNULL;
+
+  op_list = vNULL;
+
+  FOR_ALL_BB_FN (bb, fun)
+    for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+      {
+	gimple stmt = gsi_stmt (gsi);
+	struct walk_stmt_info wi;
+	memset (&wi, 0, sizeof (wi));
+	wi.info = &op_list;
+	walk_gimple_op (stmt, check_alignment, &wi);
+      }
+
+  max_align = 0;
+  max_size = 0;
+  spill_slots = 0;
+  FOR_EACH_VEC_ELT (op_list, i, t)
+    {
+      mode = vector_type_mode (TREE_TYPE (t));
+      align = GET_MODE_ALIGNMENT (mode);
+      size = GET_MODE_SIZE (mode);
+      if (align > max_align)
+	max_align = align;
+      if (size > max_size)
+	max_size = size;      
+      spill_slots++;
+    }
+
+  if (PARAM_VALUE (PARAM_ALLOCA_SPILL_SLOT_ALIGN) > 0)
+    fun->spill_slot_alignment = PARAM_VALUE (PARAM_ALLOCA_SPILL_SLOT_ALIGN);
+  else
+    fun->spill_slot_alignment = max_align;
+
+  if (PARAM_VALUE (PARAM_ALLOCA_SPILL_SLOT_SIZE) > 0)
+    fun->spill_slot_size = PARAM_VALUE (PARAM_ALLOCA_SPILL_SLOT_SIZE);
+  else
+    fun->spill_slot_size = max_size;
+
+  if (PARAM_VALUE (PARAM_ALLOCA_SPILL_SLOTS) > 0)
+    fun->spill_slots = PARAM_VALUE (PARAM_ALLOCA_SPILL_SLOTS);
+  else
+    fun->spill_slots = spill_slots;
+
+  fun->used_spill_slots = 0;
+}
+
+static void
+allocate_aligned_spill (function *fun)
+{
+  tree array_type, array_var, ptr_type, ptr_var, id;
+  gassign *stmt;
+  edge e;
+  int n;
+  char spill_reg_name[20];
+  size_t alloc_size;
+
+  alloc_size = fun->spill_slots * fun->spill_slot_size;
+  array_type = build_array_type_nelts (char_type_node, alloc_size);
+  TYPE_ALIGN (array_type) = fun->spill_slot_alignment;
+  array_var = create_tmp_var (array_type, "spill");
+
+  ptr_type = build_pointer_type (char_type_node);
+  spill_reg_name[0] = '*';
+  n = targetm.get_alloca_spill_regnum ();
+  strcpy (&spill_reg_name[1], reg_names[n]);
+  id = get_identifier (spill_reg_name);
+  ptr_var = build_decl (UNKNOWN_LOCATION, VAR_DECL, id, ptr_type);
+  TREE_PUBLIC (ptr_var) = 1;
+  DECL_EXTERNAL (ptr_var) = 1;
+  DECL_REGISTER (ptr_var) = 1;
+  DECL_HARD_REGISTER (ptr_var) = 1;
+  SET_DECL_ASSEMBLER_NAME (ptr_var, id);
+  varpool_node::finalize_decl (ptr_var);
+
+  fun->has_local_explicit_reg_vars = true;
+
+  stmt = gimple_build_assign (ptr_var, build_fold_addr_expr (array_var));
+  TREE_SIDE_EFFECTS (gimple_assign_lhs (stmt)) = 1;
+  e = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (fun));
+  gsi_insert_on_edge_immediate (e, stmt);
+}
+
+namespace {
+
+const pass_data pass_data_alloca_spill =
+{
+  GIMPLE_PASS, /* type */
+  "alloca_spill", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_TREE_ALLOCA_SPILL, /* tv_id */
+  ( PROP_ssa | PROP_cfg ), /* properties_required */
+  PROP_cfg, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  ( TODO_cleanup_cfg | TODO_update_ssa), /* todo_flags_finish */
+};
+
+class pass_alloca_spill : public gimple_opt_pass
+{
+public:
+  pass_alloca_spill (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_alloca_spill, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *) { return (flag_align_spills > 0); }
+
+  virtual unsigned int execute (function *);
+
+}; // class pass_realign_stack
+
+unsigned int
+pass_alloca_spill::execute (function *fun)
+{
+  set_spill_info (fun);
+
+  if (fun->spill_slots > 0)
+    allocate_aligned_spill (fun);
+
+  return 0;
+}
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_alloca_spill (gcc::context *ctxt)
+{
+  return new pass_alloca_spill (ctxt);
+}
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 172bd82..a259b7c 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -452,6 +452,7 @@ extern gimple_opt_pass *make_pass_strength_reduction (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_vtable_verify (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_ubsan (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_sanopt (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_alloca_spill (gcc::context *ctxt);
 
 /* IPA Passes */
 extern simple_ipa_opt_pass *make_pass_ipa_lower_emutls (gcc::context *ctxt);



More information about the Gcc-patches mailing list