This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

IA32 redundant stack adjusts


I decided to look into why we get so many redundant adds/subs of the
stack pointer on ia32.

This code:

int add(int b, int c)
{
   return b + c;
}

int main(void)
{
   printf("%d\n", add(2, 4));
   return 0;
}

when compiled with -O2 -fomit-frame-pointer by current CVS, produces
this output:

	.file	"st.c"
	.version	"01.01"
gcc2_compiled.:
.text
	.align 16
.globl add
	.type	 add,@function
add:
	movl	8(%esp), %eax
	movl	4(%esp), %edx
	addl	%edx, %eax
	ret
.Lfe1:
	.size	 add,.Lfe1-add
		.section	.rodata
.LC0:
	.string	"%d\n"
.text
	.align 16
.globl main
	.type	 main,@function
main:
	subl	$12, %esp
	subl	$8, %esp
	subl	$8, %esp
	pushl	$4
	pushl	$2
	call	add
	pushl	%eax
	pushl	$.LC0
	call	printf
	addl	$32, %esp
	xorl	%eax, %eax
	addl	$12, %esp
	ret
.Lfe2:
	.size	 main,.Lfe2-main
	.ident	"GCC: (GNU) 2.96 20000114 (experimental)"

Notice there are _three_ successive subs to %esp at the beginning of
main, and two successive adds (scheduled apart) at the end.  The
adjust by $12 at beginning and end comes from the prologue/epilogue,
but the two successive sub $8 insns are present in the initial RTL.
The .flow dump has

(insn 9 38 11 (parallel[ 
            (set (reg:SI 7 esp)
                (plus:SI (reg:SI 7 esp)
                    (const_int -8 [0xfffffff8])))
            (clobber (reg:CC 17 flags))
        ] ) 174 {*addsi_1} (nil)
    (expr_list:REG_UNUSED (reg:CC 17 flags)
        (nil)))

(insn 11 9 13 (parallel[ 
            (set (reg:SI 7 esp)
                (plus:SI (reg:SI 7 esp)
                    (const_int -8 [0xfffffff8])))
            (clobber (reg:CC 17 flags))
        ] ) 174 {*addsi_1} (nil)
    (expr_list:REG_UNUSED (reg:CC 17 flags)
        (nil)))

What's wrong with this picture?  The LOG_LINKS list of insn 11 is
nil.  That is because flow.c has a general policy of not generating
data flow info for the stack pointer.  The commentary says over and
over "we don't need this" but never explains why.  Anyway, it's easy
to cut it all out, and then you get

(insn 9 38 11 (parallel[ 
            (set (reg:SI 7 esp)
                (plus:SI (reg:SI 7 esp)
                    (const_int -8 [0xfffffff8])))
            (clobber (reg:CC 17 flags))
        ] ) 174 {*addsi_1} (nil)
    (expr_list:REG_UNUSED (reg:CC 17 flags)
        (nil)))

(insn 11 9 13 (parallel[ 
            (set (reg:SI 7 esp)
                (plus:SI (reg:SI 7 esp)
                    (const_int -8 [0xfffffff8])))
            (clobber (reg:CC 17 flags))
        ] ) 174 {*addsi_1} (insn_list 9 (nil))
    (expr_list:REG_UNUSED (reg:CC 17 flags)
        (nil)))


and then you discover that combine.c explicitly refuses to combine
stack pointer operations.

  /* Don't eliminate a store in the stack pointer.  */
  if (dest == stack_pointer_rtx
      /* ... */ )
    return 0;

[from combine.c:can_combine_p]

If you cut that out too, combine finally does its job.

(note 9 38 11 "" NOTE_INSN_DELETED)

(insn 11 9 13 (parallel[ 
            (set (reg:SI 7 esp)
                (plus:SI (reg:SI 7 esp)
                    (const_int -16 [0xfffffff0])))
            (clobber (reg:CC 17 flags))
        ] ) 174 {*addsi_1} (nil)
    (expr_list:REG_UNUSED (reg:CC 17 flags)
        (nil)))

We are still stuck with the mergeable adjusts in the prologue and
epilogue.  I tried running the combiner again after flow2, but it blew
up horribly, which is not really a surprise.  I may see if we can use
a peephole here.  Anyway, before submitting a patch, I'd like to know
if anyone remembers why flow doesn't generate info for the stack
pointer and why combine refuses to merge insns that touch it.

zw


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]