This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
IA32 redundant stack adjusts
- To: gcc at gcc dot gnu dot org
- Subject: IA32 redundant stack adjusts
- From: Zack Weinberg <zack at wolery dot cumb dot org>
- Date: Fri, 14 Jan 2000 12:31:26 -0800
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