gcc generates bad code in functions with explicit local vars under heavy register pressure

Cesar Eduardo Barros cesarb@web4u.com.br
Wed Apr 5 16:16:00 GMT 2000


When using a function which uses lots of explicit local register vars (with
only two of the seven i386 registers left), gcc sometimes "forget" that a
particular register is tied to a local variable, and clobbers it without saving
to the stack first.

I found the bug in a function I was writing, and isolated one piece of code
which produces the bug, adding optimization barriers
(asm volatile("":::"memory")) to simulate the presence of the surrounding code.
The results weren't identical, but the bug showed anyway.

The offending piece of asm is:
	movb %al,%dl
located between the two barriers. The code is generated from a hairy set of
macros; only a compiler would understand that ;)

The barriers were added so that gcc can't pretend nothing in state has changed
(so it is forced to keep all regs live till they are saved in state again). The
original source had a big loop with a switch within it, so all regs are live in
the full function too.

Version: gcc version 2.95.2 20000313 (Debian GNU/Linux)
Input file:
===cut here===
# 1 "m2000.c"

# 1 "/usr/include/signal.h" 1 3
 

















 









# 1 "/usr/include/features.h" 1 3
 




















 



























































 



















 





 



 







 
# 138 "/usr/include/features.h" 3


 









 





 



























# 196 "/usr/include/features.h" 3


































 



 








 




 

# 1 "/usr/include/sys/cdefs.h" 1 3
 




















 




 





 








 




# 71 "/usr/include/sys/cdefs.h" 3


 







 



# 103 "/usr/include/sys/cdefs.h" 3



 








 















 








 








 









 







# 250 "/usr/include/features.h" 2 3


 








 





 

 








# 1 "/usr/include/gnu/stubs.h" 1 3
 






































# 278 "/usr/include/features.h" 2 3




# 29 "/usr/include/signal.h" 2 3


 

# 1 "/usr/include/bits/sigset.h" 1 3
 





















typedef int __sig_atomic_t;

 


typedef struct
  {
    unsigned long int __val[(1024 / (8 * sizeof (unsigned long int))) ];
  } __sigset_t;




 





# 125 "/usr/include/bits/sigset.h" 3

# 33 "/usr/include/signal.h" 2 3


 





typedef __sig_atomic_t sig_atomic_t;











# 360 "/usr/include/signal.h" 3


 


# 2 "m2000.c" 2




typedef unsigned char reg8_type;
typedef unsigned short reg16_type;

struct maq2000
{
	volatile sig_atomic_t step;
	reg16_type ab, cf, sp, ip;
	unsigned char * mem;
	reg8_type (* in) (void);
	void (* out) (reg8_type x);
};

static void run (struct maq2000 * state)
{
	register unsigned char * mem asm ("%ebx");
	register reg16_type ip asm ("%si");
	register reg16_type ab asm ("%cx");
	register reg16_type cf asm ("%dx");
	register reg16_type sp asm ("%di");

	ab = state->ab;
	cf = state->cf;
	sp = state->sp;
	ip = state->ip;
	mem = state->mem;

	asm volatile ("":::"memory") ;

	({ reg16_type _mem_set8_addr = ((reg16_type)((reg16_type)( ( (((reg16_type)((reg16_type)( (ab) ) & 0xFFFF)) )  ) ) & 0xFFFF)) ; if ((((reg16_type)((reg16_type)( ((reg16_type)((reg16_type)( ( _mem_set8_addr ) ) & 0xFFFF))  & 0xFF00 ) & 0xFFFF)) ) ) asm ("movb %0, (%1, %2)" :   : "q" (((reg8_type)((reg8_type)( (  ((state)->in ())  ) ) & 0xFF)) ), "r" ((mem)), "r" ((unsigned int)_mem_set8_addr) : "memory"); }) ;

	asm volatile ("":::"memory") ;

	state->ab = ab;
	state->cf = cf;
	state->sp = sp;
	state->ip = ip;
}
===cut here===
Command line: gcc -O3 -W -Wall -c -fomit-frame-pointer -save-temps -fkeep-inline-functions -march=k6 -funroll-loops m2000.c -ggdb3
Machine info: Debian unstable Linux 2.2.14 glibc 2.1.3 K6II-350 (i386)
Source changes: Debian patches for gcc 1:2.95.2-8
Assembly output:
===cut here===
	.file	"m2000.c"
	.version	"01.01"
gcc2_compiled.:
	.section	.debug_abbrev
.Ldebug_abbrev0:
	.section	.text
.Ltext0:
	.section	.debug_info
.Ldebug_info0:
	.section	.debug_line
.Ldebug_line0:
.text
	.align 4
	.type	 run,@function
run:
.LFB1:
.LM1:

.LBB2:
.LBB3:
	subl $28,%esp
.LCFI0:
	pushl %ebp
.LCFI1:
	pushl %edi
.LCFI2:
	pushl %esi
.LCFI3:
	pushl %ebx
.LCFI4:
	movl 48(%esp),%ebp
.LM2:

	movzwl 4(%ebp),%ecx
.LM3:

	movzwl 6(%ebp),%edx
.LM4:

	movzwl 8(%ebp),%edi
.LM5:

	movzwl 10(%ebp),%esi
.LM6:

	movl 12(%ebp),%ebx
.LM7:

#APP
#NO_APP
.LM8:

	movw %cx,30(%esp)
	testb $255,%ch
	je .L3
	movl 16(%ebp),%eax
	call *%eax
	movb %al,%dl
	movzwl 30(%esp),%eax
#APP
	movb %dl, (%ebx, %eax)
#NO_APP
.L3:
.LBE3:
.LM9:

#APP
#NO_APP
.LM10:

	movw %cx,4(%ebp)
.LM11:

	movw %dx,6(%ebp)
.LM12:

	movw %di,8(%ebp)
.LM13:

	movw %si,10(%ebp)
	popl %ebx
	popl %esi
	popl %edi
	popl %ebp
	addl $28,%esp
.LCFI5:
	ret
.LM14:

.LBE2:
.LFE1:
.Lfe1:
	.size	 run,.Lfe1-run

.section	.eh_frame,"aw",@progbits
__FRAME_BEGIN__:
	.4byte	.LLCIE1
.LSCIE1:
	.4byte	0x0
	.byte	0x1
	.byte	0x0
	.byte	0x1
	.byte	0x7c
	.byte	0x8
	.byte	0xc
	.byte	0x4
	.byte	0x4
	.byte	0x88
	.byte	0x1
	.align 4
.LECIE1:
	.set	.LLCIE1,.LECIE1-.LSCIE1
	.4byte	.LLFDE1
.LSFDE1:
	.4byte	.LSFDE1-__FRAME_BEGIN__
	.4byte	.LFB1
	.4byte	.LFE1-.LFB1
	.byte	0x4
	.4byte	.LCFI0-.LFB1
	.byte	0xe
	.byte	0x20
	.byte	0x4
	.4byte	.LCFI1-.LCFI0
	.byte	0xe
	.byte	0x24
	.byte	0x85
	.byte	0x9
	.byte	0x4
	.4byte	.LCFI2-.LCFI1
	.byte	0xe
	.byte	0x28
	.byte	0x87
	.byte	0xa
	.byte	0x4
	.4byte	.LCFI3-.LCFI2
	.byte	0xe
	.byte	0x2c
	.byte	0x86
	.byte	0xb
	.byte	0x4
	.4byte	.LCFI4-.LCFI3
	.byte	0xe
	.byte	0x30
	.byte	0x83
	.byte	0xc
	.byte	0x4
	.4byte	.LCFI5-.LCFI4
	.byte	0xe
	.byte	0x14
	.align 4
.LEFDE1:
	.set	.LLFDE1,.LEFDE1-.LSFDE1

	.section	.text
.Letext0:

	.section	.debug_line
	.4byte	0xd2
	.2byte	0x2
	.4byte	0x52
	.byte	0x4
	.byte	0x1
	.byte	-10
	.byte	245
	.byte	10
	.byte	0x0
	.byte	0x1
	.byte	0x1
	.byte	0x1
	.byte	0x1
	.byte	0x0
	.byte	0x0
	.byte	0x0
	.byte	0x1
	.byte	0x0
	.string	"m2000.c"

	.byte	0x0
	.byte	0x0
	.byte	0x0
	.string	"/usr/include/bits/sigset.h"

	.byte	0x0
	.byte	0x0
	.byte	0x0
	.string	"/usr/include/signal.h"

	.byte	0x0
	.byte	0x0
	.byte	0x0
	.byte	0x0
	.byte	0x0
	.byte	0x5
	.byte	0x2
	.4byte	.LM1
	.byte	0x26
	.byte	0x0
	.byte	0x5
	.byte	0x2
	.4byte	.LM2
	.byte	0x1b
	.byte	0x0
	.byte	0x5
	.byte	0x2
	.4byte	.LM3
	.byte	0x15
	.byte	0x0
	.byte	0x5
	.byte	0x2
	.4byte	.LM4
	.byte	0x15
	.byte	0x0
	.byte	0x5
	.byte	0x2
	.4byte	.LM5
	.byte	0x15
	.byte	0x0
	.byte	0x5
	.byte	0x2
	.4byte	.LM6
	.byte	0x15
	.byte	0x0
	.byte	0x5
	.byte	0x2
	.4byte	.LM7
	.byte	0x16
	.byte	0x0
	.byte	0x5
	.byte	0x2
	.4byte	.LM8
	.byte	0x16
	.byte	0x0
	.byte	0x5
	.byte	0x2
	.4byte	.LM9
	.byte	0x16
	.byte	0x0
	.byte	0x5
	.byte	0x2
	.4byte	.LM10
	.byte	0x16
	.byte	0x0
	.byte	0x5
	.byte	0x2
	.4byte	.LM11
	.byte	0x15
	.byte	0x0
	.byte	0x5
	.byte	0x2
	.4byte	.LM12
	.byte	0x15
	.byte	0x0
	.byte	0x5
	.byte	0x2
	.4byte	.LM13
	.byte	0x15
	.byte	0x0
	.byte	0x5
	.byte	0x2
	.4byte	.LM14
	.byte	0x15
	.byte	0x0
	.byte	0x5
	.byte	0x2
	.4byte	.Letext0
	.byte	0x0
	.byte	0x1
	.byte	0x1

	.section	.debug_abbrev
	.byte	0x1
	.byte	0x11
	.byte	0x1
	.byte	0x3
	.byte	0x8
	.byte	0x1b
	.byte	0x8
	.byte	0x25
	.byte	0x8
	.byte	0x13
	.byte	0xb
	.byte	0x11
	.byte	0x1
	.byte	0x12
	.byte	0x1
	.byte	0x10
	.byte	0x6
	.byte	0,0
	.byte	0x2
	.byte	0x2e
	.byte	0x1
	.byte	0x1
	.byte	0x13
	.byte	0x3
	.byte	0x8
	.byte	0x3a
	.byte	0xb
	.byte	0x3b
	.byte	0xb
	.byte	0x27
	.byte	0xc
	.byte	0x20
	.byte	0xb
	.byte	0,0
	.byte	0x3
	.byte	0x5
	.byte	0x0
	.byte	0x3
	.byte	0x8
	.byte	0x3a
	.byte	0xb
	.byte	0x3b
	.byte	0xb
	.byte	0x49
	.byte	0x13
	.byte	0,0
	.byte	0x4
	.byte	0x34
	.byte	0x0
	.byte	0x3
	.byte	0x8
	.byte	0x3a
	.byte	0xb
	.byte	0x3b
	.byte	0xb
	.byte	0x49
	.byte	0x13
	.byte	0,0
	.byte	0x5
	.byte	0xb
	.byte	0x1
	.byte	0x1
	.byte	0x13
	.byte	0,0
	.byte	0x6
	.byte	0x13
	.byte	0x1
	.byte	0x1
	.byte	0x13
	.byte	0x3
	.byte	0x8
	.byte	0xb
	.byte	0xb
	.byte	0x3a
	.byte	0xb
	.byte	0x3b
	.byte	0xb
	.byte	0,0
	.byte	0x7
	.byte	0xd
	.byte	0x0
	.byte	0x3
	.byte	0x8
	.byte	0x3a
	.byte	0xb
	.byte	0x3b
	.byte	0xb
	.byte	0x49
	.byte	0x13
	.byte	0x38
	.byte	0xa
	.byte	0,0
	.byte	0x8
	.byte	0xf
	.byte	0x0
	.byte	0xb
	.byte	0xb
	.byte	0x49
	.byte	0x13
	.byte	0,0
	.byte	0x9
	.byte	0x24
	.byte	0x0
	.byte	0x3
	.byte	0x8
	.byte	0xb
	.byte	0xb
	.byte	0x3e
	.byte	0xb
	.byte	0,0
	.byte	0xa
	.byte	0x35
	.byte	0x0
	.byte	0x49
	.byte	0x13
	.byte	0,0
	.byte	0xb
	.byte	0x15
	.byte	0x0
	.byte	0x27
	.byte	0xc
	.byte	0x49
	.byte	0x13
	.byte	0,0
	.byte	0xc
	.byte	0x15
	.byte	0x1
	.byte	0x1
	.byte	0x13
	.byte	0x27
	.byte	0xc
	.byte	0,0
	.byte	0xd
	.byte	0x5
	.byte	0x0
	.byte	0x49
	.byte	0x13
	.byte	0,0
	.byte	0xe
	.byte	0x2e
	.byte	0x1
	.byte	0x1
	.byte	0x13
	.byte	0x31
	.byte	0x13
	.byte	0x11
	.byte	0x1
	.byte	0x12
	.byte	0x1
	.byte	0x40
	.byte	0xa
	.byte	0,0
	.byte	0xf
	.byte	0x5
	.byte	0x0
	.byte	0x31
	.byte	0x13
	.byte	0x2
	.byte	0xa
	.byte	0,0
	.byte	0x10
	.byte	0x34
	.byte	0x0
	.byte	0x31
	.byte	0x13
	.byte	0x2
	.byte	0xa
	.byte	0,0
	.byte	0x11
	.byte	0xb
	.byte	0x1
	.byte	0x1
	.byte	0x13
	.byte	0x11
	.byte	0x1
	.byte	0x12
	.byte	0x1
	.byte	0,0
	.byte	0x12
	.byte	0x16
	.byte	0x0
	.byte	0x3
	.byte	0x8
	.byte	0x3a
	.byte	0xb
	.byte	0x3b
	.byte	0xb
	.byte	0x49
	.byte	0x13
	.byte	0,0
	.byte	0x13
	.byte	0x13
	.byte	0x1
	.byte	0x1
	.byte	0x13
	.byte	0xb
	.byte	0xb
	.byte	0x3a
	.byte	0xb
	.byte	0x3b
	.byte	0xb
	.byte	0,0
	.byte	0x14
	.byte	0x1
	.byte	0x1
	.byte	0x1
	.byte	0x13
	.byte	0x49
	.byte	0x13
	.byte	0,0
	.byte	0x15
	.byte	0x21
	.byte	0x0
	.byte	0x2f
	.byte	0xb
	.byte	0,0
	.byte	0

	.section	.debug_info
	.4byte	0x2c8
	.2byte	0x2
	.4byte	.Ldebug_abbrev0
	.byte	0x4
	.byte	0x1
	.string	"m2000.c"

	.string	"/home/cesarb/tmp/tmp/20000327/bugs/2"

	.string	"GNU C 2.95.2 20000313 (Debian GNU/Linux)"

	.byte	0x1
	.4byte	.Ltext0
	.4byte	.Letext0
	.4byte	.Ldebug_line0
	.byte	0x2
	.4byte	0xd9
	.string	"run"

	.byte	0x1
	.byte	0x13
	.byte	0x1
	.byte	0x3
	.byte	0x3
	.string	"state"

	.byte	0x1
	.byte	0x12
	.4byte	0x156
	.byte	0x4
	.string	"mem"

	.byte	0x1
	.byte	0x14
	.4byte	0x15c
	.byte	0x4
	.string	"ip"

	.byte	0x1
	.byte	0x15
	.4byte	0x173
	.byte	0x4
	.string	"ab"

	.byte	0x1
	.byte	0x16
	.4byte	0x173
	.byte	0x4
	.string	"cf"

	.byte	0x1
	.byte	0x17
	.4byte	0x173
	.byte	0x4
	.string	"sp"

	.byte	0x1
	.byte	0x18
	.4byte	0x173
	.byte	0x5
	.4byte	0xd8
	.byte	0x4
	.string	"_mem_set8_addr"

	.byte	0x1
	.byte	0x22
	.4byte	0x173
	.byte	0x0
	.byte	0x0
	.byte	0x6
	.4byte	0x156
	.string	"maq2000"

	.byte	0x18
	.byte	0x1
	.byte	0xa
	.byte	0x7
	.string	"step"

	.byte	0x1
	.byte	0xb
	.4byte	0x181
	.byte	0x2
	.byte	0x23
	.byte	0x0
	.byte	0x7
	.string	"ab"

	.byte	0x1
	.byte	0xc
	.4byte	0x173
	.byte	0x2
	.byte	0x23
	.byte	0x4
	.byte	0x7
	.string	"cf"

	.byte	0x1
	.byte	0xc
	.4byte	0x173
	.byte	0x2
	.byte	0x23
	.byte	0x6
	.byte	0x7
	.string	"sp"

	.byte	0x1
	.byte	0xc
	.4byte	0x173
	.byte	0x2
	.byte	0x23
	.byte	0x8
	.byte	0x7
	.string	"ip"

	.byte	0x1
	.byte	0xc
	.4byte	0x173
	.byte	0x2
	.byte	0x23
	.byte	0xa
	.byte	0x7
	.string	"mem"

	.byte	0x1
	.byte	0xd
	.4byte	0x15c
	.byte	0x2
	.byte	0x23
	.byte	0xc
	.byte	0x7
	.string	"in"

	.byte	0x1
	.byte	0xe
	.4byte	0x1a9
	.byte	0x2
	.byte	0x23
	.byte	0x10
	.byte	0x7
	.string	"out"

	.byte	0x1
	.byte	0xf
	.4byte	0x1bb
	.byte	0x2
	.byte	0x23
	.byte	0x14
	.byte	0x0
	.byte	0x8
	.byte	0x4
	.4byte	0xd9
	.byte	0x8
	.byte	0x4
	.4byte	0x162
	.byte	0x9
	.string	"unsigned char"

	.byte	0x1
	.byte	0x8
	.byte	0x9
	.string	"reg16_type"

	.byte	0x2
	.byte	0x7
	.byte	0xa
	.4byte	0x186
	.byte	0x9
	.string	"sig_atomic_t"

	.byte	0x4
	.byte	0x5
	.byte	0xb
	.byte	0x1
	.4byte	0x19c
	.byte	0x9
	.string	"reg8_type"

	.byte	0x1
	.byte	0x7
	.byte	0x8
	.byte	0x4
	.4byte	0x196
	.byte	0xc
	.4byte	0x1bb
	.byte	0x1
	.byte	0xd
	.4byte	0x19c
	.byte	0x0
	.byte	0x8
	.byte	0x4
	.4byte	0x1af
	.byte	0xe
	.4byte	0x215
	.4byte	0x6f
	.4byte	.LFB1
	.4byte	.LFE1
	.byte	0x1
	.byte	0x54
	.byte	0xf
	.4byte	0x7c
	.byte	0x1
	.byte	0x55
	.byte	0x10
	.4byte	0x89
	.byte	0x1
	.byte	0x53
	.byte	0x10
	.4byte	0x94
	.byte	0x1
	.byte	0x56
	.byte	0x10
	.4byte	0x9e
	.byte	0x1
	.byte	0x51
	.byte	0x10
	.4byte	0xa8
	.byte	0x1
	.byte	0x52
	.byte	0x10
	.4byte	0xb2
	.byte	0x1
	.byte	0x57
	.byte	0x11
	.4byte	0x214
	.4byte	.LBB3
	.4byte	.LBE3
	.byte	0x10
	.4byte	0xc1
	.byte	0x2
	.byte	0x91
	.byte	0x1e
	.byte	0x0
	.byte	0x0
	.byte	0x12
	.string	"__sig_atomic_t"

	.byte	0x2
	.byte	0x17
	.4byte	0x22b
	.byte	0x9
	.string	"int"

	.byte	0x4
	.byte	0x5
	.byte	0x13
	.4byte	0x24b
	.byte	0x80
	.byte	0x2
	.byte	0x1f
	.byte	0x7
	.string	"__val"

	.byte	0x2
	.byte	0x1e
	.4byte	0x24b
	.byte	0x2
	.byte	0x23
	.byte	0x0
	.byte	0x0
	.byte	0x14
	.4byte	0x257
	.4byte	0x257
	.byte	0x15
	.byte	0x1f
	.byte	0x0
	.byte	0x9
	.string	"long unsigned int"

	.byte	0x4
	.byte	0x7
	.byte	0x12
	.string	"__sigset_t"

	.byte	0x2
	.byte	0x1f
	.4byte	0x232
	.byte	0x12
	.string	"sig_atomic_t"

	.byte	0x3
	.byte	0x29
	.4byte	0x215
	.byte	0x12
	.string	"reg8_type"

	.byte	0x1
	.byte	0x6
	.4byte	0x162
	.byte	0x12
	.string	"reg16_type"

	.byte	0x1
	.byte	0x7
	.4byte	0x2b5
	.byte	0x9
	.string	"short unsigned int"

	.byte	0x2
	.byte	0x7
	.byte	0x0

	.section	.debug_aranges
	.4byte	0x1c
	.2byte	0x2
	.4byte	.Ldebug_info0
	.byte	0x4
	.byte	0x0
	.4byte	0x4
	.4byte	.Ltext0
	.4byte	.Letext0-.Ltext0
	.4byte	0x0
	.4byte	0x0
	.ident	"GCC: (GNU) 2.95.2 20000313 (Debian GNU/Linux)"
===cut here===

-- 
Cesar Eduardo Barros
cesarb@web4u.com.br
cesarb@dcc.ufrj.br


More information about the Gcc-bugs mailing list