Bug using unsigned char return values in if statements?

First off:
bash-3.1$ pgcc -V

pgcc 6.0-8 32-bit target on x86 Windows


Ok, Matlab defines some functions returning type bool which is typedef’d to unsigned char. I test these a lot in if statements. It looks like from comparing pgcc’s assembly to gcc’s assembly that the problem comes from the register testing. Using pgcc there’s junk left in the upper part of eax and thus the result is always true. Using gcc testing only the lower 8 bits (register AL) results in the correct answer. So, is this a pgcc bug (should only be testing AL), a Matlab bug (the mxIsEmpty function should initialize eax=0), or something I’ve missed?

Here is the assembly code produced from pgcc followed by the gcc assembly code, and lastly by snippets of the preprocessed C source code.


PGCC ASSEMBLY


.file “test.c”

PGC 6.0 -opt 1

PGC 06/15/2006 16:25:32

pgcc test.c -S -Ic:/matlab/r2006a/extern/include -Lc:/matlab/r2006a/bin/win32 -lmex -lmx

c:\PROGRA~1\PGI/nt86/6.0/bin/pgc.EXE test.c -opt 1 -terse 1 -inform warn

-x 19 0x400000 -x 119 0x40610400 -x 119 0x100000 -x 119 0x1000 -x 120 0x80

-x 122 0x40 -x 123 0x1000 -x 127 4 -x 80 0x300 -y 80 0x1000 -x 80 0x40000000

-x 119 0x1000000 -astype 1 -stdinc c:\PROGRA~1\PGI/nt86/6.0/include;c:\PROGRA~1\PGI/nt86/6.0/mingw/include;c:\PROGRA~1\PGI/nt86/6.0/mingw/mingw32/include;c:\PROGRA~1\PGI/nt86/6.0/mingw/lib/gcc-lib/mingw32/2.95.3-5/include

-def POSIX -def __POSIX -def POSIX -def WIN32 -def _WIN32 -def __WIN32

-def WIN32 -def WINNT -def __WINNT -def WINNT -def X86=1 -def MINGW32=1.0

-def MSVCRT -def __i386 -def i386 -def i386 -def nt86 -def unix

-predicate #machine(i386) #lint(off) #system(unix) #system(winnt) #cpu(i386)

-idir c:/matlab/r2006a/extern/include -cmdline +pgcc test.c -S -Ic:/matlab/r2006a/extern/include -Lc:/matlab/r2006a/bin/win32 -lmex -lmx

-asm test.s

lineno: 6

.text
.align 4
.long …EN1-_mexFunction+0xc8000000
.align 16
.globl _mexFunction
.def _mexFunction; .scl 2; .type 0x20; .endef
_mexFunction:
pushl %ebp
movl %esp,%ebp
subl $8,%esp
…EN1:

lineno: 7

movl 20(%ebp),%eax
movl (%eax),%edx
movl %edx,(%esp)
call _mxIsEmpty
testl %eax,%eax
je .LB635
movl $.S00636,%ecx
movl %ecx,(%esp)
call _mexPrintf
jmp .LB638
.LB635:

lineno: 10

movl $.S00639,%eax
movl %eax,(%esp)
call _mexPrintf
.LB638:

lineno: 11

movl %ebp,%esp
popl %ebp
ret
.data
.align 1
.S00639:

“!empty\n”

.byte 0x21,0x65,0x6d,0x70,0x74,0x79,0x0a,0x00
.S00636:

“empty\n”

.byte 0x65,0x6d,0x70,0x74,0x79,0x0a,0x00
.data


GCC ASSEMBLY


.file “test_gcc.c”
.section .rdata,“dr”
LC0:
.ascii “empty\12\0”
LC1:
.ascii “!empty\12\0”
.text
.globl _mexFunction
.def _mexFunction; .scl 2; .type 32; .endef
_mexFunction:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl 20(%ebp), %eax
movl (%eax), %eax
movl %eax, (%esp)
call _mxIsEmpty
testb %al, %al
je L2
movl $LC0, (%esp)
call _mexPrintf
jmp L1
L2:
movl $LC1, (%esp)
call _mexPrintf
L1:
leave
ret
.def _mexPrintf; .scl 3; .type 32; .endef
.def _mxIsEmpty; .scl 3; .type 32; .endef

\


C Source code


typedef unsigned char boolean_T ;

typedef boolean_T bool ;

[snip]

extern bool mxIsEmpty (
const mxArray * pa
) ;

[snip]

void mexFunction (
int nlhs ,
mxArray * plhs ,
int nrhs ,
const mxArray * prhs
) ;

[snip]

void mexFunction ( int nlhs , mxArray * plhs , int nrhs , const mxArray * prhs )
{
if ( mxIsEmpty ( prhs [ 0 ] ) )
mexPrintf ( “empty\n” ) ;
else
mexPrintf ( “!empty\n” ) ;
}

Hi Chris,

Sorry for the delay in answering. I did some research on this and the best I can tell is that it’s a compatibility issue rather than a bug. Integer and Char values should be returned in the %eax register with unsigned char’s being zero extended. For performance reasons, PGCC auto-promotes Chars to Integers and is why PGCC uses ‘testl’ instead of ‘testb’. PGCC can do this so long as eax has been zero extended. I hesitate to call it a bug in the Matlab either since I don’t know how it was compiled nor what assumptions were made. Rather, I’ve let our Win32 engineers know about the compatibilty issue and hopefully they can resolve the problem with the 6.2 release.

As a work around, I’d like you to try to first compile with “-Msignextend”. If that doesn’t work, try explicitly casting the return value to “int” (i.e. put a “int ( foo )”) around each of the matlab functions or mask the return value (i.e. "if 0x0F & foo() ) ").

Thanks,
Mat

I’ll try the signextend flag. My workaround was to just use the following for each function func that returned bool.

#define func(a) (func(a) & 0x01)

As I stated in the post, I wasn’t sure whether it was a PGI bug, matlab bug, or just something inbetween. I’m going to submit it to Matlab for review.