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