[v4] x86: Rewrite ix86_find_max_used_stack_alignment

Message ID CAMe9rOpioAjEe1Y-5MRm1vjaGW0DLKUpasj4_XfGb8u8-7Vc1A@mail.gmail.com
State New
Headers
Series [v4] x86: Rewrite ix86_find_max_used_stack_alignment |

Commit Message

H.J. Lu April 7, 2026, 9:57 p.m. UTC
  On Wed, Apr 8, 2026 at 2:00 AM Richard Biener
<richard.guenther@gmail.com> wrote:
>
> On Tue, Apr 7, 2026 at 5:18 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> >
...
> > How about something like this:
> >
> > /* Update the maximum stack slot alignment from memory alignment if
> >    OP is stack memory.  */
> >
> > static void
> > ix86_update_stack_alignment_2 (const_rtx op, unsigned int &alignment)
> > {
> >   /* Skip if OP is a memory operand with SYMBOLIC_CONST.  */
> >   rtx x = XEXP (op, 0);
> >   if (SYMBOLIC_CONST (x))
> >     return;
> >
> >   unsigned int mem_align = MEM_ALIGN (op);
> >   tree mem_expr = MEM_EXPR (op);
> >   if (!mem_expr)
> >     {
> >       /* If MEM_EXPR is NULL, assume that OP is a memory operand.  */
> > check_alignment:
> >       if (mem_align > alignment)
> > alignment = mem_align;
> >       return;
> >     }
> >
> >   tree var = get_base_address (mem_expr);
> >
> >   /* Skip if OP references an argument passed on stack.  */
> >   if (TREE_CODE (var) == PARM_DECL)
> >     return;
> >
> >   if (TREE_CODE (var) == MEM_REF || TREE_CODE (var) == TARGET_MEM_REF)
> >     {
> >       var = TREE_OPERAND (var, 0);
> >       /* Skip if OP is a memory operand from SSA_NAME.  */
> >       if (TREE_CODE (var) == SSA_NAME)
> > return;
> >       goto check_alignment;
> >     }
> >
> >   if (!VAR_P (var) || !DECL_RTL_SET_P (var))
> >     goto check_alignment;
> >
> >   x = DECL_RTL (var);
> >   if (!MEM_P (x))
> >     goto check_alignment;
> >
> >   x = XEXP (x, 0);
> >   if (SYMBOLIC_CONST (x))
> >     return;
> >
> >   goto check_alignment;
> > }
> >
> > /* Update the maximum stack slot alignment from memory alignment if
> >    SET references stack memory.  */
> >
> > static void
> > ix86_update_stack_alignment_1 (rtx set, unsigned int &alignment)
> > {
> >   rtx dest = SET_DEST (set);
> >
> >   if (MEM_P (dest))
> >     return ix86_update_stack_alignment_2 (dest, alignment);
> >
> >   const_rtx src = SET_SRC (set);
> >
> >   subrtx_iterator::array_type array;
> >   FOR_EACH_SUBRTX (iter, array, src, ALL)
> >     {
> >       auto op = *iter;
> >
> >       if (MEM_P (op))
> > return ix86_update_stack_alignment_2 (op, alignment);
> >     }
> > }
> >
> > /* Update the maximum stack slot alignment from memory alignment if
> >    INSN references stack memory.  */
> >
> > static void
> > ix86_update_stack_alignment (rtx_insn *insn, unsigned int &alignment)
> > {
> >   rtx set = single_set (insn);
> >   if (set)
> >     return ix86_update_stack_alignment_1 (set, alignment);
> >
> >   rtx pat = PATTERN (insn);
> >   if (GET_CODE (pat) != PARALLEL)
> >     return;
> >
> >   for (int i = 0; i < XVECLEN (pat, 0); i++)
> >     {
> >       rtx exp = XVECEXP (pat, 0, i);
> >
> >       if (GET_CODE (exp) == SET)
> > ix86_update_stack_alignment_1 (exp, alignment);
> >     }
> > }
> >
> > /* Set stack_frame_required to false if stack frame isn't required.
> >    Update STACK_ALIGNMENT to the largest alignment, in bits, of stack
> >    slot used if stack frame is required and CHECK_STACK_SLOT is true.  */
> >
> > static void
> > ix86_find_max_used_stack_alignment (unsigned int &stack_alignment,
> >     bool check_stack_slot)
> > {
> >   HARD_REG_SET set_up_by_prologue, prologue_used;
> >   basic_block bb;
> >
> >   CLEAR_HARD_REG_SET (prologue_used);
> >   CLEAR_HARD_REG_SET (set_up_by_prologue);
> >   add_to_hard_reg_set (&set_up_by_prologue, Pmode, STACK_POINTER_REGNUM);
> >   add_to_hard_reg_set (&set_up_by_prologue, Pmode, ARG_POINTER_REGNUM);
> >   add_to_hard_reg_set (&set_up_by_prologue, Pmode,
> >        HARD_FRAME_POINTER_REGNUM);
> >
> >   bool require_stack_frame = false;
> >
> >   /* The preferred stack alignment is the minimum stack alignment.  */
> >   if (check_stack_slot
> >       && stack_alignment > crtl->preferred_stack_boundary)
> >     stack_alignment = crtl->preferred_stack_boundary;
> >
> >   FOR_EACH_BB_FN (bb, cfun)
> >     {
> >       rtx_insn *insn;
> >       FOR_BB_INSNS (bb, insn)
> > if (NONDEBUG_INSN_P (insn))
> >   {
> >     if (!require_stack_frame
> > && requires_stack_frame_p (insn, prologue_used,
> >    set_up_by_prologue))
> >       {
> > require_stack_frame = true;
> >
> > /* Stop if we don't need to check stack slot.  */
> > if (!check_stack_slot)
> >   break;
> >       }
> >
> >     if (!check_stack_slot || !NONJUMP_INSN_P (insn))
> >       continue;
> >
> >     ix86_update_stack_alignment (insn, stack_alignment);
> >   }
> >     }
> >
> >   cfun->machine->stack_frame_required = require_stack_frame;
> > }
>
> AFAICS this considers almost all MEMs to be stack accesses and thus
> should be conservative.  The tracking of which regs point to the stack
> is gone?

Yes.

> FOR_EACH_BB_FN visits block in no particular order, init_alias_analysis
> properly iterates to compute what a reg points to, but with multiple defs
> I belive it gives up.  But it is probably most closely equivalent to what
> your current code does (just more correct and faster).
>

Here is the patch to rewrite ix86_find_max_used_stack_alignment.
There are no regressions.

OK for master?
  

Comments

Richard Biener April 8, 2026, 11:46 a.m. UTC | #1
On Wed, 8 Apr 2026, H.J. Lu wrote:

> On Wed, Apr 8, 2026 at 2:00 AM Richard Biener
> <richard.guenther@gmail.com> wrote:
> >
> > On Tue, Apr 7, 2026 at 5:18 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> > >
> ...
> > > How about something like this:
> > >
> > > /* Update the maximum stack slot alignment from memory alignment if
> > >    OP is stack memory.  */
> > >
> > > static void
> > > ix86_update_stack_alignment_2 (const_rtx op, unsigned int &alignment)
> > > {
> > >   /* Skip if OP is a memory operand with SYMBOLIC_CONST.  */
> > >   rtx x = XEXP (op, 0);
> > >   if (SYMBOLIC_CONST (x))
> > >     return;
> > >
> > >   unsigned int mem_align = MEM_ALIGN (op);
> > >   tree mem_expr = MEM_EXPR (op);
> > >   if (!mem_expr)
> > >     {
> > >       /* If MEM_EXPR is NULL, assume that OP is a memory operand.  */
> > > check_alignment:
> > >       if (mem_align > alignment)
> > > alignment = mem_align;
> > >       return;
> > >     }
> > >
> > >   tree var = get_base_address (mem_expr);
> > >
> > >   /* Skip if OP references an argument passed on stack.  */
> > >   if (TREE_CODE (var) == PARM_DECL)
> > >     return;
> > >
> > >   if (TREE_CODE (var) == MEM_REF || TREE_CODE (var) == TARGET_MEM_REF)
> > >     {
> > >       var = TREE_OPERAND (var, 0);
> > >       /* Skip if OP is a memory operand from SSA_NAME.  */
> > >       if (TREE_CODE (var) == SSA_NAME)
> > > return;
> > >       goto check_alignment;
> > >     }
> > >
> > >   if (!VAR_P (var) || !DECL_RTL_SET_P (var))
> > >     goto check_alignment;
> > >
> > >   x = DECL_RTL (var);
> > >   if (!MEM_P (x))
> > >     goto check_alignment;
> > >
> > >   x = XEXP (x, 0);
> > >   if (SYMBOLIC_CONST (x))
> > >     return;
> > >
> > >   goto check_alignment;
> > > }
> > >
> > > /* Update the maximum stack slot alignment from memory alignment if
> > >    SET references stack memory.  */
> > >
> > > static void
> > > ix86_update_stack_alignment_1 (rtx set, unsigned int &alignment)
> > > {
> > >   rtx dest = SET_DEST (set);
> > >
> > >   if (MEM_P (dest))
> > >     return ix86_update_stack_alignment_2 (dest, alignment);
> > >
> > >   const_rtx src = SET_SRC (set);
> > >
> > >   subrtx_iterator::array_type array;
> > >   FOR_EACH_SUBRTX (iter, array, src, ALL)
> > >     {
> > >       auto op = *iter;
> > >
> > >       if (MEM_P (op))
> > > return ix86_update_stack_alignment_2 (op, alignment);
> > >     }
> > > }
> > >
> > > /* Update the maximum stack slot alignment from memory alignment if
> > >    INSN references stack memory.  */
> > >
> > > static void
> > > ix86_update_stack_alignment (rtx_insn *insn, unsigned int &alignment)
> > > {
> > >   rtx set = single_set (insn);
> > >   if (set)
> > >     return ix86_update_stack_alignment_1 (set, alignment);
> > >
> > >   rtx pat = PATTERN (insn);
> > >   if (GET_CODE (pat) != PARALLEL)
> > >     return;
> > >
> > >   for (int i = 0; i < XVECLEN (pat, 0); i++)
> > >     {
> > >       rtx exp = XVECEXP (pat, 0, i);
> > >
> > >       if (GET_CODE (exp) == SET)
> > > ix86_update_stack_alignment_1 (exp, alignment);
> > >     }
> > > }
> > >
> > > /* Set stack_frame_required to false if stack frame isn't required.
> > >    Update STACK_ALIGNMENT to the largest alignment, in bits, of stack
> > >    slot used if stack frame is required and CHECK_STACK_SLOT is true.  */
> > >
> > > static void
> > > ix86_find_max_used_stack_alignment (unsigned int &stack_alignment,
> > >     bool check_stack_slot)
> > > {
> > >   HARD_REG_SET set_up_by_prologue, prologue_used;
> > >   basic_block bb;
> > >
> > >   CLEAR_HARD_REG_SET (prologue_used);
> > >   CLEAR_HARD_REG_SET (set_up_by_prologue);
> > >   add_to_hard_reg_set (&set_up_by_prologue, Pmode, STACK_POINTER_REGNUM);
> > >   add_to_hard_reg_set (&set_up_by_prologue, Pmode, ARG_POINTER_REGNUM);
> > >   add_to_hard_reg_set (&set_up_by_prologue, Pmode,
> > >        HARD_FRAME_POINTER_REGNUM);
> > >
> > >   bool require_stack_frame = false;
> > >
> > >   /* The preferred stack alignment is the minimum stack alignment.  */
> > >   if (check_stack_slot
> > >       && stack_alignment > crtl->preferred_stack_boundary)
> > >     stack_alignment = crtl->preferred_stack_boundary;
> > >
> > >   FOR_EACH_BB_FN (bb, cfun)
> > >     {
> > >       rtx_insn *insn;
> > >       FOR_BB_INSNS (bb, insn)
> > > if (NONDEBUG_INSN_P (insn))
> > >   {
> > >     if (!require_stack_frame
> > > && requires_stack_frame_p (insn, prologue_used,
> > >    set_up_by_prologue))
> > >       {
> > > require_stack_frame = true;
> > >
> > > /* Stop if we don't need to check stack slot.  */
> > > if (!check_stack_slot)
> > >   break;
> > >       }
> > >
> > >     if (!check_stack_slot || !NONJUMP_INSN_P (insn))
> > >       continue;
> > >
> > >     ix86_update_stack_alignment (insn, stack_alignment);
> > >   }
> > >     }
> > >
> > >   cfun->machine->stack_frame_required = require_stack_frame;
> > > }
> >
> > AFAICS this considers almost all MEMs to be stack accesses and thus
> > should be conservative.  The tracking of which regs point to the stack
> > is gone?
> 
> Yes.
> 
> > FOR_EACH_BB_FN visits block in no particular order, init_alias_analysis
> > properly iterates to compute what a reg points to, but with multiple defs
> > I belive it gives up.  But it is probably most closely equivalent to what
> > your current code does (just more correct and faster).
> >
> 
> Here is the patch to rewrite ix86_find_max_used_stack_alignment.
> There are no regressions.
> 
> OK for master?

  if (TREE_CODE (var) == MEM_REF || TREE_CODE (var) == TARGET_MEM_REF)
    {
      var = TREE_OPERAND (var, 0);
      /* Skip if OP is a memory operand from SSA_NAME.  */
      if (TREE_CODE (var) == SSA_NAME)
        return;

So this seems wrong, we ignore all indirect memory accesses as
not belonging to the stack here.

The "else" should be unreachable due to how get_base_address
works.

      goto check_alignment;
    }

  if (!VAR_P (var) || !DECL_RTL_SET_P (var))
    goto check_alignment;

The gotos are ugly, some else if / nesting should get rid of
them with duplicating the check_alignment out at the end.

I do wonder whether the above would be more precise written as

static void
ix86_update_stack_alignment_2 (const_rtx op, unsigned int &alignment)
{
  rtx base = find_base_term (XEXP (op, 0));

  /* Skip if OP references an argument slot.  */
  if (base == static_reg_base_value[ARG_POINTER_REGNUM])
    return;

  if (!base
      || base == static_reg_base_value[STACK_POINTER_REGNUM]
      || base == static_reg_base_value[FRAME_POINTER_REGNUM])
    alignment = MAX (MEM_ALIGN (op), alignment);
}

using RTL points-to.  I belive that is what your ix86_find_all_reg_uses
attempted to compute.

Note find_base_term and friends are not exported from alias.cc so
the predicate part would need to be split out into a new predicate
there, alongside the existing may_be_sp_based_p ().  As said you'll
need to call init_alias_analysis from the pass the above is
ultimatively called from.

Otherwise this seems like an improvement.

Richard.
  
H.J. Lu April 8, 2026, 9:46 p.m. UTC | #2
On Wed, Apr 8, 2026 at 7:46 PM Richard Biener <rguenther@suse.de> wrote:
>
> On Wed, 8 Apr 2026, H.J. Lu wrote:
>
> > On Wed, Apr 8, 2026 at 2:00 AM Richard Biener
> > <richard.guenther@gmail.com> wrote:
> > >
> > > On Tue, Apr 7, 2026 at 5:18 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> > > >
> > ...
> > > > How about something like this:
> > > >
> > > > /* Update the maximum stack slot alignment from memory alignment if
> > > >    OP is stack memory.  */
> > > >
> > > > static void
> > > > ix86_update_stack_alignment_2 (const_rtx op, unsigned int &alignment)
> > > > {
> > > >   /* Skip if OP is a memory operand with SYMBOLIC_CONST.  */
> > > >   rtx x = XEXP (op, 0);
> > > >   if (SYMBOLIC_CONST (x))
> > > >     return;
> > > >
> > > >   unsigned int mem_align = MEM_ALIGN (op);
> > > >   tree mem_expr = MEM_EXPR (op);
> > > >   if (!mem_expr)
> > > >     {
> > > >       /* If MEM_EXPR is NULL, assume that OP is a memory operand.  */
> > > > check_alignment:
> > > >       if (mem_align > alignment)
> > > > alignment = mem_align;
> > > >       return;
> > > >     }
> > > >
> > > >   tree var = get_base_address (mem_expr);
> > > >
> > > >   /* Skip if OP references an argument passed on stack.  */
> > > >   if (TREE_CODE (var) == PARM_DECL)
> > > >     return;
> > > >
> > > >   if (TREE_CODE (var) == MEM_REF || TREE_CODE (var) == TARGET_MEM_REF)
> > > >     {
> > > >       var = TREE_OPERAND (var, 0);
> > > >       /* Skip if OP is a memory operand from SSA_NAME.  */
> > > >       if (TREE_CODE (var) == SSA_NAME)
> > > > return;
> > > >       goto check_alignment;
> > > >     }
> > > >
> > > >   if (!VAR_P (var) || !DECL_RTL_SET_P (var))
> > > >     goto check_alignment;
> > > >
> > > >   x = DECL_RTL (var);
> > > >   if (!MEM_P (x))
> > > >     goto check_alignment;
> > > >
> > > >   x = XEXP (x, 0);
> > > >   if (SYMBOLIC_CONST (x))
> > > >     return;
> > > >
> > > >   goto check_alignment;
> > > > }
> > > >
> > > > /* Update the maximum stack slot alignment from memory alignment if
> > > >    SET references stack memory.  */
> > > >
> > > > static void
> > > > ix86_update_stack_alignment_1 (rtx set, unsigned int &alignment)
> > > > {
> > > >   rtx dest = SET_DEST (set);
> > > >
> > > >   if (MEM_P (dest))
> > > >     return ix86_update_stack_alignment_2 (dest, alignment);
> > > >
> > > >   const_rtx src = SET_SRC (set);
> > > >
> > > >   subrtx_iterator::array_type array;
> > > >   FOR_EACH_SUBRTX (iter, array, src, ALL)
> > > >     {
> > > >       auto op = *iter;
> > > >
> > > >       if (MEM_P (op))
> > > > return ix86_update_stack_alignment_2 (op, alignment);
> > > >     }
> > > > }
> > > >
> > > > /* Update the maximum stack slot alignment from memory alignment if
> > > >    INSN references stack memory.  */
> > > >
> > > > static void
> > > > ix86_update_stack_alignment (rtx_insn *insn, unsigned int &alignment)
> > > > {
> > > >   rtx set = single_set (insn);
> > > >   if (set)
> > > >     return ix86_update_stack_alignment_1 (set, alignment);
> > > >
> > > >   rtx pat = PATTERN (insn);
> > > >   if (GET_CODE (pat) != PARALLEL)
> > > >     return;
> > > >
> > > >   for (int i = 0; i < XVECLEN (pat, 0); i++)
> > > >     {
> > > >       rtx exp = XVECEXP (pat, 0, i);
> > > >
> > > >       if (GET_CODE (exp) == SET)
> > > > ix86_update_stack_alignment_1 (exp, alignment);
> > > >     }
> > > > }
> > > >
> > > > /* Set stack_frame_required to false if stack frame isn't required.
> > > >    Update STACK_ALIGNMENT to the largest alignment, in bits, of stack
> > > >    slot used if stack frame is required and CHECK_STACK_SLOT is true.  */
> > > >
> > > > static void
> > > > ix86_find_max_used_stack_alignment (unsigned int &stack_alignment,
> > > >     bool check_stack_slot)
> > > > {
> > > >   HARD_REG_SET set_up_by_prologue, prologue_used;
> > > >   basic_block bb;
> > > >
> > > >   CLEAR_HARD_REG_SET (prologue_used);
> > > >   CLEAR_HARD_REG_SET (set_up_by_prologue);
> > > >   add_to_hard_reg_set (&set_up_by_prologue, Pmode, STACK_POINTER_REGNUM);
> > > >   add_to_hard_reg_set (&set_up_by_prologue, Pmode, ARG_POINTER_REGNUM);
> > > >   add_to_hard_reg_set (&set_up_by_prologue, Pmode,
> > > >        HARD_FRAME_POINTER_REGNUM);
> > > >
> > > >   bool require_stack_frame = false;
> > > >
> > > >   /* The preferred stack alignment is the minimum stack alignment.  */
> > > >   if (check_stack_slot
> > > >       && stack_alignment > crtl->preferred_stack_boundary)
> > > >     stack_alignment = crtl->preferred_stack_boundary;
> > > >
> > > >   FOR_EACH_BB_FN (bb, cfun)
> > > >     {
> > > >       rtx_insn *insn;
> > > >       FOR_BB_INSNS (bb, insn)
> > > > if (NONDEBUG_INSN_P (insn))
> > > >   {
> > > >     if (!require_stack_frame
> > > > && requires_stack_frame_p (insn, prologue_used,
> > > >    set_up_by_prologue))
> > > >       {
> > > > require_stack_frame = true;
> > > >
> > > > /* Stop if we don't need to check stack slot.  */
> > > > if (!check_stack_slot)
> > > >   break;
> > > >       }
> > > >
> > > >     if (!check_stack_slot || !NONJUMP_INSN_P (insn))
> > > >       continue;
> > > >
> > > >     ix86_update_stack_alignment (insn, stack_alignment);
> > > >   }
> > > >     }
> > > >
> > > >   cfun->machine->stack_frame_required = require_stack_frame;
> > > > }
> > >
> > > AFAICS this considers almost all MEMs to be stack accesses and thus
> > > should be conservative.  The tracking of which regs point to the stack
> > > is gone?
> >
> > Yes.
> >
> > > FOR_EACH_BB_FN visits block in no particular order, init_alias_analysis
> > > properly iterates to compute what a reg points to, but with multiple defs
> > > I belive it gives up.  But it is probably most closely equivalent to what
> > > your current code does (just more correct and faster).
> > >
> >
> > Here is the patch to rewrite ix86_find_max_used_stack_alignment.
> > There are no regressions.
> >
> > OK for master?
>
>   if (TREE_CODE (var) == MEM_REF || TREE_CODE (var) == TARGET_MEM_REF)
>     {
>       var = TREE_OPERAND (var, 0);
>       /* Skip if OP is a memory operand from SSA_NAME.  */
>       if (TREE_CODE (var) == SSA_NAME)
>         return;
>
> So this seems wrong, we ignore all indirect memory accesses as
> not belonging to the stack here.
>
> The "else" should be unreachable due to how get_base_address
> works.
>
>       goto check_alignment;
>     }
>
>   if (!VAR_P (var) || !DECL_RTL_SET_P (var))
>     goto check_alignment;
>
> The gotos are ugly, some else if / nesting should get rid of
> them with duplicating the check_alignment out at the end.
>
> I do wonder whether the above would be more precise written as
>
> static void
> ix86_update_stack_alignment_2 (const_rtx op, unsigned int &alignment)
> {
>   rtx base = find_base_term (XEXP (op, 0));
>
>   /* Skip if OP references an argument slot.  */
>   if (base == static_reg_base_value[ARG_POINTER_REGNUM])
>     return;
>
>   if (!base
^^^^^^^^^^^^^^^

For

char c, d;
_BitInt(2048) b;

void
foo (__int128, _BitInt(1024) a)
{
  b *= 0;
  c %= (char)(a ?: d);
}

we got

(gdb) call debug (insn)
(insn 14 12 65 3 (set (mem:V4DI (reg:DI 0 ax [orig:112 ivtmp.23 ]
[112]) [1 MEM <vector(4) unsigned long> [(_BitInt(2048) *)_34]+0 S32
A256])
        (reg:V4DI 20 xmm0 [117])) "x.c":7:5 discrim 33280 2461
{movv4di_internal}
     (nil))
(gdb)

and

(gdb) call debug (op)
(mem:V4DI (reg:DI 0 ax [orig:112 ivtmp.23 ] [112]) [1 MEM <vector(4)
unsigned long> [(_BitInt(2048) *)_34]+0 S32 A256])
(gdb) next
8607   if (base != static_reg_base_value[ARG_POINTER_REGNUM]
(gdb) p base
$4 = (rtx) 0x0
(gdb)

if base is 0, we can't assume that it accesses stack.

>       || base == static_reg_base_value[STACK_POINTER_REGNUM]
>       || base == static_reg_base_value[FRAME_POINTER_REGNUM])
>     alignment = MAX (MEM_ALIGN (op), alignment);
> }
>
> using RTL points-to.  I belive that is what your ix86_find_all_reg_uses
> attempted to compute.
>
> Note find_base_term and friends are not exported from alias.cc so
> the predicate part would need to be split out into a new predicate
> there, alongside the existing may_be_sp_based_p ().  As said you'll
> need to call init_alias_analysis from the pass the above is

Isn't init_alias_analysis called from backend_init_target?
Why should it be called again?


> ultimatively called from.
>
> Otherwise this seems like an improvement.
>
> Richard.
  
Richard Biener April 9, 2026, 9:13 a.m. UTC | #3
On Thu, 9 Apr 2026, H.J. Lu wrote:

> On Wed, Apr 8, 2026 at 7:46 PM Richard Biener <rguenther@suse.de> wrote:
> >
> > On Wed, 8 Apr 2026, H.J. Lu wrote:
> >
> > > On Wed, Apr 8, 2026 at 2:00 AM Richard Biener
> > > <richard.guenther@gmail.com> wrote:
> > > >
> > > > On Tue, Apr 7, 2026 at 5:18 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> > > > >
> > > ...
> > > > > How about something like this:
> > > > >
> > > > > /* Update the maximum stack slot alignment from memory alignment if
> > > > >    OP is stack memory.  */
> > > > >
> > > > > static void
> > > > > ix86_update_stack_alignment_2 (const_rtx op, unsigned int &alignment)
> > > > > {
> > > > >   /* Skip if OP is a memory operand with SYMBOLIC_CONST.  */
> > > > >   rtx x = XEXP (op, 0);
> > > > >   if (SYMBOLIC_CONST (x))
> > > > >     return;
> > > > >
> > > > >   unsigned int mem_align = MEM_ALIGN (op);
> > > > >   tree mem_expr = MEM_EXPR (op);
> > > > >   if (!mem_expr)
> > > > >     {
> > > > >       /* If MEM_EXPR is NULL, assume that OP is a memory operand.  */
> > > > > check_alignment:
> > > > >       if (mem_align > alignment)
> > > > > alignment = mem_align;
> > > > >       return;
> > > > >     }
> > > > >
> > > > >   tree var = get_base_address (mem_expr);
> > > > >
> > > > >   /* Skip if OP references an argument passed on stack.  */
> > > > >   if (TREE_CODE (var) == PARM_DECL)
> > > > >     return;
> > > > >
> > > > >   if (TREE_CODE (var) == MEM_REF || TREE_CODE (var) == TARGET_MEM_REF)
> > > > >     {
> > > > >       var = TREE_OPERAND (var, 0);
> > > > >       /* Skip if OP is a memory operand from SSA_NAME.  */
> > > > >       if (TREE_CODE (var) == SSA_NAME)
> > > > > return;
> > > > >       goto check_alignment;
> > > > >     }
> > > > >
> > > > >   if (!VAR_P (var) || !DECL_RTL_SET_P (var))
> > > > >     goto check_alignment;
> > > > >
> > > > >   x = DECL_RTL (var);
> > > > >   if (!MEM_P (x))
> > > > >     goto check_alignment;
> > > > >
> > > > >   x = XEXP (x, 0);
> > > > >   if (SYMBOLIC_CONST (x))
> > > > >     return;
> > > > >
> > > > >   goto check_alignment;
> > > > > }
> > > > >
> > > > > /* Update the maximum stack slot alignment from memory alignment if
> > > > >    SET references stack memory.  */
> > > > >
> > > > > static void
> > > > > ix86_update_stack_alignment_1 (rtx set, unsigned int &alignment)
> > > > > {
> > > > >   rtx dest = SET_DEST (set);
> > > > >
> > > > >   if (MEM_P (dest))
> > > > >     return ix86_update_stack_alignment_2 (dest, alignment);
> > > > >
> > > > >   const_rtx src = SET_SRC (set);
> > > > >
> > > > >   subrtx_iterator::array_type array;
> > > > >   FOR_EACH_SUBRTX (iter, array, src, ALL)
> > > > >     {
> > > > >       auto op = *iter;
> > > > >
> > > > >       if (MEM_P (op))
> > > > > return ix86_update_stack_alignment_2 (op, alignment);
> > > > >     }
> > > > > }
> > > > >
> > > > > /* Update the maximum stack slot alignment from memory alignment if
> > > > >    INSN references stack memory.  */
> > > > >
> > > > > static void
> > > > > ix86_update_stack_alignment (rtx_insn *insn, unsigned int &alignment)
> > > > > {
> > > > >   rtx set = single_set (insn);
> > > > >   if (set)
> > > > >     return ix86_update_stack_alignment_1 (set, alignment);
> > > > >
> > > > >   rtx pat = PATTERN (insn);
> > > > >   if (GET_CODE (pat) != PARALLEL)
> > > > >     return;
> > > > >
> > > > >   for (int i = 0; i < XVECLEN (pat, 0); i++)
> > > > >     {
> > > > >       rtx exp = XVECEXP (pat, 0, i);
> > > > >
> > > > >       if (GET_CODE (exp) == SET)
> > > > > ix86_update_stack_alignment_1 (exp, alignment);
> > > > >     }
> > > > > }
> > > > >
> > > > > /* Set stack_frame_required to false if stack frame isn't required.
> > > > >    Update STACK_ALIGNMENT to the largest alignment, in bits, of stack
> > > > >    slot used if stack frame is required and CHECK_STACK_SLOT is true.  */
> > > > >
> > > > > static void
> > > > > ix86_find_max_used_stack_alignment (unsigned int &stack_alignment,
> > > > >     bool check_stack_slot)
> > > > > {
> > > > >   HARD_REG_SET set_up_by_prologue, prologue_used;
> > > > >   basic_block bb;
> > > > >
> > > > >   CLEAR_HARD_REG_SET (prologue_used);
> > > > >   CLEAR_HARD_REG_SET (set_up_by_prologue);
> > > > >   add_to_hard_reg_set (&set_up_by_prologue, Pmode, STACK_POINTER_REGNUM);
> > > > >   add_to_hard_reg_set (&set_up_by_prologue, Pmode, ARG_POINTER_REGNUM);
> > > > >   add_to_hard_reg_set (&set_up_by_prologue, Pmode,
> > > > >        HARD_FRAME_POINTER_REGNUM);
> > > > >
> > > > >   bool require_stack_frame = false;
> > > > >
> > > > >   /* The preferred stack alignment is the minimum stack alignment.  */
> > > > >   if (check_stack_slot
> > > > >       && stack_alignment > crtl->preferred_stack_boundary)
> > > > >     stack_alignment = crtl->preferred_stack_boundary;
> > > > >
> > > > >   FOR_EACH_BB_FN (bb, cfun)
> > > > >     {
> > > > >       rtx_insn *insn;
> > > > >       FOR_BB_INSNS (bb, insn)
> > > > > if (NONDEBUG_INSN_P (insn))
> > > > >   {
> > > > >     if (!require_stack_frame
> > > > > && requires_stack_frame_p (insn, prologue_used,
> > > > >    set_up_by_prologue))
> > > > >       {
> > > > > require_stack_frame = true;
> > > > >
> > > > > /* Stop if we don't need to check stack slot.  */
> > > > > if (!check_stack_slot)
> > > > >   break;
> > > > >       }
> > > > >
> > > > >     if (!check_stack_slot || !NONJUMP_INSN_P (insn))
> > > > >       continue;
> > > > >
> > > > >     ix86_update_stack_alignment (insn, stack_alignment);
> > > > >   }
> > > > >     }
> > > > >
> > > > >   cfun->machine->stack_frame_required = require_stack_frame;
> > > > > }
> > > >
> > > > AFAICS this considers almost all MEMs to be stack accesses and thus
> > > > should be conservative.  The tracking of which regs point to the stack
> > > > is gone?
> > >
> > > Yes.
> > >
> > > > FOR_EACH_BB_FN visits block in no particular order, init_alias_analysis
> > > > properly iterates to compute what a reg points to, but with multiple defs
> > > > I belive it gives up.  But it is probably most closely equivalent to what
> > > > your current code does (just more correct and faster).
> > > >
> > >
> > > Here is the patch to rewrite ix86_find_max_used_stack_alignment.
> > > There are no regressions.
> > >
> > > OK for master?
> >
> >   if (TREE_CODE (var) == MEM_REF || TREE_CODE (var) == TARGET_MEM_REF)
> >     {
> >       var = TREE_OPERAND (var, 0);
> >       /* Skip if OP is a memory operand from SSA_NAME.  */
> >       if (TREE_CODE (var) == SSA_NAME)
> >         return;
> >
> > So this seems wrong, we ignore all indirect memory accesses as
> > not belonging to the stack here.
> >
> > The "else" should be unreachable due to how get_base_address
> > works.
> >
> >       goto check_alignment;
> >     }
> >
> >   if (!VAR_P (var) || !DECL_RTL_SET_P (var))
> >     goto check_alignment;
> >
> > The gotos are ugly, some else if / nesting should get rid of
> > them with duplicating the check_alignment out at the end.
> >
> > I do wonder whether the above would be more precise written as
> >
> > static void
> > ix86_update_stack_alignment_2 (const_rtx op, unsigned int &alignment)
> > {
> >   rtx base = find_base_term (XEXP (op, 0));
> >
> >   /* Skip if OP references an argument slot.  */
> >   if (base == static_reg_base_value[ARG_POINTER_REGNUM])
> >     return;
> >
> >   if (!base
> ^^^^^^^^^^^^^^^
> 
> For
> 
> char c, d;
> _BitInt(2048) b;
> 
> void
> foo (__int128, _BitInt(1024) a)
> {
>   b *= 0;
>   c %= (char)(a ?: d);
> }
> 
> we got
> 
> (gdb) call debug (insn)
> (insn 14 12 65 3 (set (mem:V4DI (reg:DI 0 ax [orig:112 ivtmp.23 ]
> [112]) [1 MEM <vector(4) unsigned long> [(_BitInt(2048) *)_34]+0 S32
> A256])
>         (reg:V4DI 20 xmm0 [117])) "x.c":7:5 discrim 33280 2461
> {movv4di_internal}
>      (nil))
> (gdb)
> 
> and
> 
> (gdb) call debug (op)
> (mem:V4DI (reg:DI 0 ax [orig:112 ivtmp.23 ] [112]) [1 MEM <vector(4)
> unsigned long> [(_BitInt(2048) *)_34]+0 S32 A256])
> (gdb) next
> 8607   if (base != static_reg_base_value[ARG_POINTER_REGNUM]
> (gdb) p base
> $4 = (rtx) 0x0
> (gdb)
> 
> if base is 0, we can't assume that it accesses stack.

Well, base == 0 means "don't know", so we have to conservatively
_assume_ it accesses the stack, no?  Similar to your
SSA_NAME early out I commented on.

But sure, RTL points-to analysis leaves a lot to be desired.

> >       || base == static_reg_base_value[STACK_POINTER_REGNUM]
> >       || base == static_reg_base_value[FRAME_POINTER_REGNUM])
> >     alignment = MAX (MEM_ALIGN (op), alignment);
> > }
> >
> > using RTL points-to.  I belive that is what your ix86_find_all_reg_uses
> > attempted to compute.
> >
> > Note find_base_term and friends are not exported from alias.cc so
> > the predicate part would need to be split out into a new predicate
> > there, alongside the existing may_be_sp_based_p ().  As said you'll
> > need to call init_alias_analysis from the pass the above is
> 
> Isn't init_alias_analysis called from backend_init_target?
> Why should it be called again?

Because the RTL IL changes and reg_base_value[] needs to be computed
to get accurate (and correct) info.

Richard.
  

Patch

From 86dc761742cf29b5ce563a5f3c80faec04a28492 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Tue, 7 Apr 2026 23:16:38 +0800
Subject: [PATCH v4] x86: Rewrite ix86_find_max_used_stack_alignment

Revert changes in ix86_find_max_used_stack_alignment

f511bf93f94 x86: Call ix86_access_stack_p only for larger alignment
a7cce1afee8 x86: Call ix86_access_stack_p only with symbolic constant load
b54533a2863 x86: Update stack alignment only if stack is used
b9ea3b2ef98 x86: Properly find the maximum stack slot alignment

and rewrite ix86_find_max_used_stack_alignment based on

7b39d7b3b84 Correct x86: Call ix86_access_stack_p only for larger alignment

Update the maximum stack slot alignment from memory alignment only if

1. The memory operand isn't SYMBOLIC_CONST.
2. Its MEM_EXPR is NULL.
3. The memory operand isn't an argument passed on stack.
4. The memory operand isn't an SSA_NAME.
5. The memory operand isn't an VAR_DECL or its DECL_RTL_SET_P is false.
6. Its DECL_RTL isn't SYMBOLIC_CONST.

The compile times of PR target/124165 and PR target/124684 test are
unchanged.

	PR target/109780
	PR target/109093
	PR target/124098
	PR target/124165
	PR target/124684
	PR target/124759
	PR target/124789
	* config/i386/i386.cc (stack_access_data): Removed.
	(ix86_update_stack_alignment): Removed.
	(ix86_find_all_reg_uses_1): Likewise.
	(ix86_find_all_reg_uses): Likewise.
	(ix86_access_stack_p): Likewise.
	(ix86_need_alignment_p_2): Changed to ...
	(ix86_update_stack_alignment_2): This.  Update the maximum stack
	slot alignment from memory alignment only if the memory operand
	may access stack.
	(ix86_need_alignment_p_1): Changed to ...
	(ix86_update_stack_alignment_1): This.
	(ix86_need_alignment_p): Changed to ...
	(ix86_update_stack_alignment): This.
	(ix86_find_max_used_stack_alignment): If check_stack_slot is
	true, call ix86_update_stack_alignment on each INSN.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
 gcc/config/i386/i386.cc | 353 ++++++++--------------------------------
 1 file changed, 65 insertions(+), 288 deletions(-)

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 9d1a2af7064..2d53af5c0c2 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -8598,221 +8598,67 @@  output_probe_stack_range (rtx reg, rtx end)
   return "";
 }
 
-/* Data passed to ix86_update_stack_alignment.  */
-struct stack_access_data
-{
-  /* The stack access register.  */
-  const_rtx reg;
-  /* Pointer to stack alignment.  */
-  unsigned int *stack_alignment;
-};
-
-/* Return true if OP references an argument passed on stack.  */
-
-static bool
-ix86_argument_passed_on_stack_p (const_rtx op)
-{
-  tree mem_expr = MEM_EXPR (op);
-  if (mem_expr)
-    {
-      tree var = get_base_address (mem_expr);
-      return TREE_CODE (var) == PARM_DECL;
-    }
-  return false;
-}
-
-/* Update the maximum stack slot alignment from memory alignment in PAT.  */
+/* Update the maximum stack slot alignment from memory alignment if
+   OP is stack memory.  */
 
 static void
-ix86_update_stack_alignment (rtx, const_rtx pat, void *data)
+ix86_update_stack_alignment_2 (const_rtx op, unsigned int &alignment)
 {
-  /* This insn may reference stack slot.  Update the maximum stack slot
-     alignment if the memory is referenced by the stack access register. */
-  stack_access_data *p = (stack_access_data *) data;
+  /* Skip if OP is a memory operand with SYMBOLIC_CONST.  */
+  rtx x = XEXP (op, 0);
+  if (SYMBOLIC_CONST (x))
+    return;
 
-  subrtx_iterator::array_type array;
-  FOR_EACH_SUBRTX (iter, array, pat, ALL)
+  unsigned int mem_align = MEM_ALIGN (op);
+  tree mem_expr = MEM_EXPR (op);
+  if (!mem_expr)
     {
-      auto op = *iter;
-      if (MEM_P (op))
-	{
-	  /* NB: Ignore arguments passed on stack since caller is
-	     responsible to align the outgoing stack for arguments
-	     passed on stack.  */
-	  if (reg_mentioned_p (p->reg, XEXP (op, 0))
-	      && !ix86_argument_passed_on_stack_p (op))
-	    {
-	      unsigned int alignment = MEM_ALIGN (op);
-
-	      if (alignment > *p->stack_alignment)
-		*p->stack_alignment = alignment;
-	      break;
-	    }
-	  else
-	    iter.skip_subrtxes ();
-	}
+      /* If MEM_EXPR is NULL, assume that OP is a memory operand.  */
+check_alignment:
+      if (mem_align > alignment)
+	alignment = mem_align;
+      return;
     }
-}
 
-/* Helper function for ix86_find_all_reg_uses.  */
-
-static void
-ix86_find_all_reg_uses_1 (HARD_REG_SET &regset,
-			  rtx set, unsigned int regno,
-			  auto_bitmap &worklist)
-{
-  rtx dest = SET_DEST (set);
-
-  if (!REG_P (dest))
-    return;
-
-  /* Reject non-Pmode modes.  */
-  if (GET_MODE (dest) != Pmode)
-    return;
-
-  unsigned int dst_regno = REGNO (dest);
+  tree var = get_base_address (mem_expr);
 
-  if (TEST_HARD_REG_BIT (regset, dst_regno))
+  /* Skip if OP references an argument passed on stack.  */
+  if (TREE_CODE (var) == PARM_DECL)
     return;
 
-  const_rtx src = SET_SRC (set);
-
-  subrtx_iterator::array_type array;
-  FOR_EACH_SUBRTX (iter, array, src, ALL)
+  if (TREE_CODE (var) == MEM_REF || TREE_CODE (var) == TARGET_MEM_REF)
     {
-      auto op = *iter;
-
-      if (MEM_P (op))
-	iter.skip_subrtxes ();
-
-      if (REG_P (op) && REGNO (op) == regno)
-	{
-	  /* Add this register to register set.  */
-	  add_to_hard_reg_set (&regset, Pmode, dst_regno);
-	  bitmap_set_bit (worklist, dst_regno);
-	  break;
-	}
-    }
-}
-
-/* Find all registers defined with register REGNO.  */
-
-static void
-ix86_find_all_reg_uses (HARD_REG_SET &regset,
-			unsigned int regno, auto_bitmap &worklist)
-{
-  for (df_ref ref = DF_REG_USE_CHAIN (regno);
-       ref != NULL;
-       ref = DF_REF_NEXT_REG (ref))
-    {
-      if (DF_REF_IS_ARTIFICIAL (ref))
-	continue;
-
-      rtx_insn *insn = DF_REF_INSN (ref);
-
-      if (!NONJUMP_INSN_P (insn))
-	continue;
-
-      unsigned int ref_regno = DF_REF_REGNO (ref);
-
-      rtx set = single_set (insn);
-      if (set)
-	{
-	  ix86_find_all_reg_uses_1 (regset, set,
-				    ref_regno, worklist);
-	  continue;
-	}
-
-      rtx pat = PATTERN (insn);
-      if (GET_CODE (pat) != PARALLEL)
-	continue;
-
-      for (int i = 0; i < XVECLEN (pat, 0); i++)
-	{
-	  rtx exp = XVECEXP (pat, 0, i);
-
-	  if (GET_CODE (exp) == SET)
-	    ix86_find_all_reg_uses_1 (regset, exp,
-				      ref_regno, worklist);
-	}
+      var = TREE_OPERAND (var, 0);
+      /* Skip if OP is a memory operand from SSA_NAME.  */
+      if (TREE_CODE (var) == SSA_NAME)
+	return;
+      goto check_alignment;
     }
-}
 
-/* Return true if the hard register REGNO used for a stack access is
-   defined in a basic block that dominates the block where it is used.  */
-
-static bool
-ix86_access_stack_p (unsigned int regno, basic_block bb,
-		     HARD_REG_SET &set_up_by_prologue,
-		     HARD_REG_SET &prologue_used,
-		     auto_bitmap reg_dominate_bbs_known[],
-		     auto_bitmap reg_dominate_bbs[])
-{
-  if (bitmap_bit_p (reg_dominate_bbs_known[regno], bb->index))
-    return bitmap_bit_p (reg_dominate_bbs[regno], bb->index);
-
-  bitmap_set_bit (reg_dominate_bbs_known[regno], bb->index);
-
-  /* Get all BBs which set REGNO and dominate the current BB from all
-     DEFs of REGNO.  */
-  for (df_ref def = DF_REG_DEF_CHAIN (regno);
-       def;
-       def = DF_REF_NEXT_REG (def))
-    if (!DF_REF_IS_ARTIFICIAL (def)
-	&& !DF_REF_FLAGS_IS_SET (def, DF_REF_MAY_CLOBBER)
-	&& !DF_REF_FLAGS_IS_SET (def, DF_REF_MUST_CLOBBER))
-      {
-	basic_block set_bb = DF_REF_BB (def);
-	if (dominated_by_p (CDI_DOMINATORS, bb, set_bb))
-	  {
-	    rtx_insn *insn = DF_REF_INSN (def);
-	    /* Return true if INSN requires stack.  */
-	    if (requires_stack_frame_p (insn, prologue_used,
-					set_up_by_prologue))
-	      {
-		bitmap_set_bit (reg_dominate_bbs[regno], bb->index);
-		return true;
-	      }
-	  }
-      }
-
-  /* When we get here, REGNO used in the current BB doesn't access
-     stack.  */
-  return false;
-}
-
-/* Return true if OP isn't a memory operand with SYMBOLIC_CONST and
-   needs alignment > ALIGNMENT.  */
-
-static bool
-ix86_need_alignment_p_2 (const_rtx op, unsigned int alignment)
-{
-  bool need_alignment = MEM_ALIGN (op) > alignment;
-  tree mem_expr = MEM_EXPR (op);
-  if (!mem_expr)
-    return need_alignment;
-
-  tree var = get_base_address (mem_expr);
   if (!VAR_P (var) || !DECL_RTL_SET_P (var))
-    return need_alignment;
+    goto check_alignment;
 
-  rtx x = DECL_RTL (var);
+  x = DECL_RTL (var);
   if (!MEM_P (x))
-    return need_alignment;
+    goto check_alignment;
 
   x = XEXP (x, 0);
-  return !SYMBOLIC_CONST (x) && need_alignment;
+  if (SYMBOLIC_CONST (x))
+    return;
+
+  goto check_alignment;
 }
 
-/* Return true if SET needs alignment > ALIGNMENT.  */
+/* Update the maximum stack slot alignment from memory alignment if
+   SET references stack memory.  */
 
-static bool
-ix86_need_alignment_p_1 (rtx set, unsigned int alignment)
+static void
+ix86_update_stack_alignment_1 (rtx set, unsigned int &alignment)
 {
   rtx dest = SET_DEST (set);
 
   if (MEM_P (dest))
-    return ix86_need_alignment_p_2 (dest, alignment);
+    return ix86_update_stack_alignment_2 (dest, alignment);
 
   const_rtx src = SET_SRC (set);
 
@@ -8822,35 +8668,31 @@  ix86_need_alignment_p_1 (rtx set, unsigned int alignment)
       auto op = *iter;
 
       if (MEM_P (op))
-	return ix86_need_alignment_p_2 (op, alignment);
+	return ix86_update_stack_alignment_2 (op, alignment);
     }
-
-  return false;
 }
 
-/* Return true if INSN needs alignment > ALIGNMENT.  */
+/* Update the maximum stack slot alignment from memory alignment if
+   INSN references stack memory.  */
 
-static bool
-ix86_need_alignment_p (rtx_insn *insn, unsigned int alignment)
+static void
+ix86_update_stack_alignment (rtx_insn *insn, unsigned int &alignment)
 {
   rtx set = single_set (insn);
   if (set)
-    return ix86_need_alignment_p_1 (set, alignment);
+    return ix86_update_stack_alignment_1 (set, alignment);
 
   rtx pat = PATTERN (insn);
   if (GET_CODE (pat) != PARALLEL)
-    return false;
+    return;
 
   for (int i = 0; i < XVECLEN (pat, 0); i++)
     {
       rtx exp = XVECEXP (pat, 0, i);
 
-      if (GET_CODE (exp) == SET
-	  && ix86_need_alignment_p_1 (exp, alignment))
-	return true;
+      if (GET_CODE (exp) == SET)
+	ix86_update_stack_alignment_1 (exp, alignment);
     }
-
-  return false;
 }
 
 /* Set stack_frame_required to false if stack frame isn't required.
@@ -8873,101 +8715,36 @@  ix86_find_max_used_stack_alignment (unsigned int &stack_alignment,
 
   bool require_stack_frame = false;
 
+  /* The preferred stack alignment is the minimum stack alignment.  */
+  if (check_stack_slot
+      && stack_alignment > crtl->preferred_stack_boundary)
+    stack_alignment = crtl->preferred_stack_boundary;
+
   FOR_EACH_BB_FN (bb, cfun)
     {
       rtx_insn *insn;
       FOR_BB_INSNS (bb, insn)
-	if (NONDEBUG_INSN_P (insn)
-	    && requires_stack_frame_p (insn, prologue_used,
-				       set_up_by_prologue))
+	if (NONDEBUG_INSN_P (insn))
 	  {
-	    require_stack_frame = true;
-	    break;
-	  }
-    }
-
-  cfun->machine->stack_frame_required = require_stack_frame;
-
-  /* Stop if we don't need to check stack slot.  */
-  if (!check_stack_slot)
-    return;
-
-  /* The preferred stack alignment is the minimum stack alignment.  */
-  if (stack_alignment > crtl->preferred_stack_boundary)
-    stack_alignment = crtl->preferred_stack_boundary;
-
-  HARD_REG_SET stack_slot_access;
-  CLEAR_HARD_REG_SET (stack_slot_access);
-
-  /* Stack slot can be accessed by stack pointer, frame pointer or
-     registers defined by stack pointer or frame pointer.  */
-  auto_bitmap worklist;
-
-  add_to_hard_reg_set (&stack_slot_access, Pmode, STACK_POINTER_REGNUM);
-  bitmap_set_bit (worklist, STACK_POINTER_REGNUM);
-
-  if (frame_pointer_needed)
-    {
-      add_to_hard_reg_set (&stack_slot_access, Pmode,
-			   HARD_FRAME_POINTER_REGNUM);
-      bitmap_set_bit (worklist, HARD_FRAME_POINTER_REGNUM);
-    }
-
-  /* Registers on HARD_STACK_SLOT_ACCESS always access stack.  */
-  HARD_REG_SET hard_stack_slot_access = stack_slot_access;
-
-  calculate_dominance_info (CDI_DOMINATORS);
-
-  unsigned int regno;
-
-  do
-    {
-      regno = bitmap_clear_first_set_bit (worklist);
-      ix86_find_all_reg_uses (stack_slot_access, regno, worklist);
-    }
-  while (!bitmap_empty_p (worklist));
-
-  hard_reg_set_iterator hrsi;
-  stack_access_data data;
-
-  auto_bitmap reg_dominate_bbs_known[FIRST_PSEUDO_REGISTER];
-  auto_bitmap reg_dominate_bbs[FIRST_PSEUDO_REGISTER];
-
-  data.stack_alignment = &stack_alignment;
-
-  EXECUTE_IF_SET_IN_HARD_REG_SET (stack_slot_access, 0, regno, hrsi)
-    {
-      for (df_ref ref = DF_REG_USE_CHAIN (regno);
-	   ref != NULL;
-	   ref = DF_REF_NEXT_REG (ref))
-	{
-	  if (DF_REF_IS_ARTIFICIAL (ref))
-	    continue;
+	    if (!require_stack_frame
+		&& requires_stack_frame_p (insn, prologue_used,
+					   set_up_by_prologue))
+	      {
+		require_stack_frame = true;
 
-	  rtx_insn *insn = DF_REF_INSN (ref);
+		/* Stop if we don't need to check stack slot.  */
+		if (!check_stack_slot)
+		  break;
+	      }
 
-	  if (!NONJUMP_INSN_P (insn))
-	    continue;
+	    if (!check_stack_slot || !NONJUMP_INSN_P (insn))
+	      continue;
 
-	  /* Call ix86_access_stack_p only if INSN needs alignment >
-	     STACK_ALIGNMENT.  */
-	  if (ix86_need_alignment_p (insn, stack_alignment)
-	      && (TEST_HARD_REG_BIT (hard_stack_slot_access, regno)
-		  || ix86_access_stack_p (regno, BLOCK_FOR_INSN (insn),
-					  set_up_by_prologue,
-					  prologue_used,
-					  reg_dominate_bbs_known,
-					  reg_dominate_bbs)))
-	    {
-	      /* Update stack alignment if REGNO is used for stack
-		 access.  */
-	      data.reg = DF_REF_REG (ref);
-	      note_stores (insn, ix86_update_stack_alignment, &data);
-	    }
-	}
+	    ix86_update_stack_alignment (insn, stack_alignment);
+	  }
     }
 
-  free_dominance_info (CDI_DOMINATORS);
+  cfun->machine->stack_frame_required = require_stack_frame;
 }
 
 /* Finalize stack_realign_needed and frame_pointer_needed flags, which
-- 
2.53.0