[reload] never-used stack slots?

Cyrille Chepelov cyrille@chepelov.org
Fri Mar 5 20:26:00 GMT 2004


Greetings,

While looking at #3507, I noticed something strange, which happens with
3.3.3/20031206 snapshot, and both mainline and tree-ssa as of last week:

-------------
void foo();

int bar(int a, int b) {
  int c = a - b;
    
  foo();
        
  return c;
}
-------------

This produces with -O2 on i386 the following assembly:

------------
	.file	"test.c"
	.text
	.p2align 4,,15
.globl bar
	.type	bar, @function
bar:
	pushl	%ebp
	movl	%esp, %ebp
	pushl	%ebx
	subl	$4, %esp		;; This
	movl	8(%ebp), %ebx
	call	foo
	movl	12(%ebp), %ecx
	popl	%edx			;; and that 
	subl	%ecx, %ebx
	movl	%ebx, %eax
	popl	%ebx
	popl	%ebp
	ret
	.size	bar, .-bar
	.section	.note.GNU-stack,"",@progbits
	.ident	"GCC: (GNU) 3.5-tree-ssa 20040302 (merged 20040211)"
------------
			(-fnew-ra generates catastrophically worse code)

A few problems: 
	0. Shouldn't %edx (call-clobbered) be preferred over %ebx? (nitpick)
 
	1. There is one stack slot allocated, which is never used. The two
instructions I've annotated above are thus useless.

It looks to me (but only after killing a couple trees and brain cells) that
the problem happens during reload(). I wonder if there shouldn't be some
level of indirection (urk) added to reload's stack slot construction, so
that once the reloads are made, a cleanup pass can happen to notice which
stack slots are actually used and throw out the remaining stack slots
(rearranging the stack slot-related offsets in the newly-created reload
insns as necessary, and subject to alignment requirements)? I certainly
wouldn't dare at this point to even attempt something like that, but if led
gently, maybe I can try to give it a shot.

	2. Notwithstanding the fact that the "subl $4,%esp" is unnecessary,
shouldn't it be replaced with a "pushl %whatever", to save space? I can
understand a reason not to do this, to avoid creating a stall if %whatever
is used just before (so, implementing this would require either a clever
choice of %whatever, or teaching gcc the concept of picking a random
register *after* scheduling, so that it has the least chance of creating a
stall. Urk.)
 	
	3. intuitively, the idea of loading one of the arguments into %ebx
before the call to foo(), performing the computation into %ebx, and finally
moving the result immediately to %eax, looks to me a little less efficient
than doing the computation directly into %eax. At the minimum, we save a
byte of space, perhaps a little more if that allows to avoid
saving/restoring %ebx, doesn't it? OTOH, I have zero clue how a modern CPU
would actually schedule and execute this.

I notice that if I rewrite the code as:

-----------------
void foo();

extern int k; // initialized to 0 somewhere else.

int bar(int a, int b) {
  foo();

  if (k < 0) return k; // this is a stupid basic block barrier. If there's a
		       // smarter way to tell the compiler "split BBs here",
		       // I'd gladly take it
  int c = a - b;

  return c;
}
----------------
and then ignoring in the assembly the consequences of mucking with k, I get
much cleaner code:
bar:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp	;; useless, times 2 (point #1)
	call	foo
	movl	k, %eax		;; ignore (BB barrier)
	testl	%eax, %eax 	;; ignore (BB barrier)
	js	.L1		;; ignore (BB barrier)
	movl	8(%ebp), %eax
	movl	12(%ebp), %edx
	subl	%edx, %eax
.L1:
	leave
	ret
----------------
I wonder if the following shouldn't be done, sometime before lreg or
regmove, if the last BB includes a function call, and that call is not a
tail call:
	The last BB is split after the last call, into BB' and BB".
Everything from BB' that can be moved down to BB" is moved (likely every insn from
BB' that is not depended upon by the arguments to the last function call.

This should reduce the amount of registers live across a function call,
shouldn't it?

OK, lots of whining in this e-mail. A few questions:
	1. Are the powers that be aware of the issues here? (I suspect yes,
		but I haven't found evidence of that in bugzilla)
	2. Are there bits of this e-mail worth recording into the bugzilla?
	3. On the point of cleaning up the stack slot allocation in
		reload(), any comments on the feasability, and perhaps 
		implementation hints?
	4. On the point of splitting the last BB of a function if it
		contains a call, is this stupid, and if it's not, any 
		comments on the feasability and perhaps implementation 
		hints?

Thanks a lot in advance,

	-- Cyrille



More information about the Gcc mailing list