1. Trying to use gdb on OS X

Argh! I'm trying to figure out how to use gdb to figure out why some integers and bitwise ops aren't being handled correctly in Euphoria 4.05 on OS X. While I understand basic C, and basic machine layout, it can be a bit tough, and I'm very new to gdb debugging.

The worst part is that two times when I set a break point, it altered the execution of the program. The first time, I set a breakpoint in be_runtime.c at binary_op line 2337, with a condition of fn=56 (which is and_bits). When I stepped into the breakpoint, I ended up crashing with an access violation. When I cleard the fn=56 condition and then continued past the breakpoint, I seemed to get stuck in an infinite loop.

And to top it all off, even with the -g3 or -ggdb3 compiler switches, I don't get macro expansion, and this area of the interpreter is riddled with C macros. Then trying to figure out how to properly examine a Euphoria object in the debugger to see what it's doing while manually referring back to the macro definition. I find myself bouncing back and forth between terminal window and gvim source window.

Ah, well, just venting. I'll figure it out. But if anyone has any good gdb tips I'd be glad to hear them. Still, it makes me appreciate the Euphoria debugger, that's for sure! I have a couple ideas and there are still lots of websites to refer to. It's just a learning curve.

new topic     » topic index » view message » categorize

2. Re: Trying to use gdb on OS X

jaygade said...

Then trying to figure out how to properly examine a Euphoria object in the debugger to see what it's doing while manually referring back to the macro definition. I find myself bouncing back and forth between terminal window and gvim source window.

I often do things like:

$ print StdPrint( 1, _some_eu_object_12345, 1 ) 

That's equivalent to "? some_eu_object", so you get something reasonable. For strings, you can do things like "print EPuts(1, _seq_to_print )" (from memory...may not be exactly right).

Matt

new topic     » goto parent     » topic index » view message » categorize

3. Re: Trying to use gdb on OS X

Thanks, I'll try that.

I figure I'm kind of in the "stick the screwdriver into the electrical socket" point of debugging, just trying to understand the tools better and how the source works. It's a lot to digest, even though I've fiddled with bits of the source before.

new topic     » goto parent     » topic index » view message » categorize

4. Re: Trying to use gdb on OS X

So here's where I'm at. For some reason, the computer isn't passing along (-1) or (#FFFFFFFF) correctly in the function call for and_bits() in be_runtime.c. It only seems to fail when combined with a larger integer integer that is promoted to an atom, like #DEADBEE5.

Here's my test program:

include std/convert.e 
include std/math.e 
 
printf(1, "1. and_bits(#3EADBEE5, -1): Exp: %x | Res: %x\n", {#3EADBEE5, and_bits(#3EADBEE5, -1)}) 
printf(1, "2. and_bits(#DEADBEE5, -1): Exp: %x | Res: %x\n", {#DEADBEE5, and_bits(#DEADBEE5, -1)}) 
printf(1, "3. and_bits(-1, #DEADBEE5): Exp: %x | Res: %x\n", {#DEADBEE5, and_bits(-1, #DEADBEE5)}) 
printf(1, "4. and_bits(-1, -1): Exp: %x | Res: %x\n", {-1, and_bits(-1, -1)}) 
printf(1, "5. and_bits(-1, #FFFFFFFF): Exp: %x | Res: %x\n", {-1, and_bits(-1, #FFFFFFFF)}) 
printf(1, "6. and_bits(#FFFFFFFF, #FFFFFFFF): Exp: %x | Res: %x\n", {#FFFFFFFF, and_bits(#FFFFFFFF, #FFFFFFFF)}) 
printf(1, "7. and_bits(3735928549, -1): Exp: %x | Res: %x\n", {3735928549, and_bits(3735928549, -1)}) 
printf(1, "8. and_bits(3735928549, #DEADBEE5): Exp: %x | Res: %x\n", {3735928549, and_bits(3735928549, #DEADBEE5)}) 
 
-- Fails tests 2, 3, 5, 7 

1. and_bits(#3EADBEE5, -1): Exp: 3EADBEE5 | Res: 3EADBEE5 
2. and_bits(#DEADBEE5, -1): Exp: DEADBEE5 | Res: 0 
3. and_bits(-1, #DEADBEE5): Exp: DEADBEE5 | Res: 0 
4. and_bits(-1, -1): Exp: FFFFFFFF | Res: FFFFFFFF 
5. and_bits(-1, #FFFFFFFF): Exp: FFFFFFFF | Res: 0 
6. and_bits(#FFFFFFFF, #FFFFFFFF): Exp: FFFFFFFF | Res: FFFFFFFF 
7. and_bits(3735928549, -1): Exp: DEADBEE5 | Res: 0 
8. and_bits(3735928549, #DEADBEE5): Exp: DEADBEE5 | Res: DEADBEE5 

Using gdb, I've traced the program to be_runtime.c line 1761.

Dand_bits (a=0x804e20, b=0xbfffe220) at be_runtime.c:1761 
1761		return and_bits( (unsigned long)(a->dbl), (unsigned long)(b->dbl)); 

At this point, a->dbl and b->dbl have the correct values (but in double format). The cast should take care of that and put both values on the stack for the and_bits() call.

(gdb) p/x (unsigned long)(a->dbl)  
$58 = 0xdeadbee5 
(gdb) p/x (unsigned long)(b->dbl) 
$59 = 0xffffffff 

I can tell gdb to return at that point and it works correctly, so the asm code must be being generated incorrectly. Now, my understanding of x86 assembler is even worse than my understanding of C, and my understanding of floating point and vector instructions is non-existent.

Here's the disassembly for line 1761:

0x002c1498 <Dand_bits+13>:	mov    0xc(%ebp),%eax 
0x002c149b <Dand_bits+16>:	movsd  (%eax),%xmm0 
0x002c149f <Dand_bits+20>:	movapd %xmm0,%xmm1 
0x002c14a3 <Dand_bits+24>:	lea    0x26de9(%ebx),%eax 
0x002c14a9 <Dand_bits+30>:	movapd (%eax),%xmm0 
0x002c14ad <Dand_bits+34>:	movapd %xmm0,%xmm2 
0x002c14b1 <Dand_bits+38>:	cmplesd %xmm1,%xmm2 
0x002c14b6 <Dand_bits+43>:	lea    0x26df9(%ebx),%eax 
0x002c14bc <Dand_bits+49>:	movapd (%eax),%xmm0 
0x002c14c0 <Dand_bits+53>:	minsd  %xmm0,%xmm1 
0x002c14c4 <Dand_bits+57>:	xorpd  %xmm0,%xmm0 
0x002c14c8 <Dand_bits+61>:	maxsd  %xmm0,%xmm1 
0x002c14cc <Dand_bits+65>:	lea    0x26de9(%ebx),%eax 
0x002c14d2 <Dand_bits+71>:	movapd (%eax),%xmm0 
0x002c14d6 <Dand_bits+75>:	andpd  %xmm2,%xmm0 
0x002c14da <Dand_bits+79>:	subpd  %xmm0,%xmm1 
0x002c14de <Dand_bits+83>:	cvttpd2dq %xmm1,%xmm1 
0x002c14e2 <Dand_bits+87>:	movdqa %xmm2,%xmm0 
0x002c14e6 <Dand_bits+91>:	psllq  $0x1f,%xmm0 
0x002c14eb <Dand_bits+96>:	pxor   %xmm0,%xmm1 
0x002c14ef <Dand_bits+100>:	movd   %xmm1,%edx 
0x002c14f3 <Dand_bits+104>:	mov    0x8(%ebp),%eax 
0x002c14f6 <Dand_bits+107>:	movsd  (%eax),%xmm0 
0x002c14fa <Dand_bits+111>:	movapd %xmm0,%xmm1 
0x002c14fe <Dand_bits+115>:	lea    0x26de9(%ebx),%eax 
0x002c1504 <Dand_bits+121>:	movapd (%eax),%xmm0 
0x002c1508 <Dand_bits+125>:	movapd %xmm0,%xmm2 
0x002c150c <Dand_bits+129>:	cmplesd %xmm1,%xmm2 
0x002c1511 <Dand_bits+134>:	lea    0x26df9(%ebx),%eax 
0x002c1517 <Dand_bits+140>:	movapd (%eax),%xmm0 
0x002c151b <Dand_bits+144>:	minsd  %xmm0,%xmm1 
0x002c151f <Dand_bits+148>:	xorpd  %xmm0,%xmm0 
0x002c1523 <Dand_bits+152>:	maxsd  %xmm0,%xmm1 
0x002c1527 <Dand_bits+156>:	lea    0x26de9(%ebx),%eax 
0x002c152d <Dand_bits+162>:	movapd (%eax),%xmm0 
0x002c1531 <Dand_bits+166>:	andpd  %xmm2,%xmm0 
0x002c1535 <Dand_bits+170>:	subpd  %xmm0,%xmm1 
0x002c1539 <Dand_bits+174>:	cvttpd2dq %xmm1,%xmm1 
0x002c153d <Dand_bits+178>:	movdqa %xmm2,%xmm0 
0x002c1541 <Dand_bits+182>:	psllq  $0x1f,%xmm0 
0x002c1546 <Dand_bits+187>:	pxor   %xmm0,%xmm1 
0x002c154a <Dand_bits+191>:	movd   %xmm1,%eax 
0x002c154e <Dand_bits+195>:	mov    %edx,0x4(%esp) 
0x002c1552 <Dand_bits+199>:	mov    %eax,(%esp) 
0x002c1555 <Dand_bits+202>:	call   0x2c1423 <and_bits> 

By the time that and_bits() gets called,

Breakpoint 4, and_bits (a=3735928549, b=0) at be_runtime.c:1754 
1754		a = a & b; 

b is equal to 0 when it should be 0xFFFFFFFF.

gcc --version 
i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (dot 3) 

I may try to remove the --ffast-math option and see what happens. I should also take a closer look at test 4 and figure out why it it passing.

new topic     » goto parent     » topic index » view message » categorize

5. Re: Trying to use gdb on OS X

Okay, I changed the code of Dand_bits() in be_runtime.c to this and it works:

object Dand_bits(d_ptr a, d_ptr b) 
/* double a AND b */ 
{ 
/*	return and_bits( (unsigned long)(a->dbl), (unsigned long)(b->dbl));*/ 
	unsigned long long i1, i2; 
	i1 = (unsigned long long)(a->dbl); 
	i2 = (unsigned long long)(b->dbl); 
	return and_bits((unsigned long)(i1), (unsigned long)(i2)); 
} 

I'm not sure why the cast to long long is necessary, just that the conversion was failing somewhere. Even though I'm compiling to 32 bits, the OS is 32/64 hybrid. I do remember seeing a 64-bit representation of -1 in gdb (0xffffffffffffffff) in my initial investigations, I just don't remember exactly how I got it.

jason$ file build/eui 
build/eui: Mach-O executable i386 
 
jason$ uname -a 
Darwin 10.8.0 Darwin Kernel Version 10.8.0: Tue Jun  7 16:33:36 PDT 2011; root:xnu-1504.15.3~1/RELEASE_I386 i386 

new topic     » goto parent     » topic index » view message » categorize

6. Re: Trying to use gdb on OS X

jaygade said...

Okay, I changed the code of Dand_bits() in be_runtime.c to this and it works:

I'm not sure why the cast to long long is necessary, just that the conversion was failing somewhere. Even though I'm compiling to 32 bits, the OS is 32/64 hybrid. I do remember seeing a 64-bit representation of -1 in gdb (0xffffffffffffffff) in my initial investigations, I just don't remember exactly how I got it.

This seems similiar to the and_bits() issue that was seen in ARM a few months back.

http://openeuphoria.org/forum/m/120902.wc

http://openeuphoria.org/forum/m/120910.wc

Considering that, unlike ARM, OSX runs on identical hardware to the x86/x64 version (and using the same compiler suite to boot!), even if the results are suppose to be formally undefined/implementation dependent, I'm not sure why we'd get different results. But that appears to be what is happening here.

new topic     » goto parent     » topic index » view message » categorize

7. Re: Trying to use gdb on OS X

It's funny because the cast worked in gdb, just not in the code generated by gcc.

Okay, I'll undo my code and try to add a #ifdef EOSX to the existing #ifdef ARM or something and try that.

Wait a minute -- can't we cast to long and then to unsigned long? It's the cast of (-1) to unsigned long which is implementation defined right?

Idea which might be portable: in Dand_bits, cast to long, then in and_bits cast to unsigned long.

new topic     » goto parent     » topic index » view message » categorize

8. Re: Trying to use gdb on OS X

jaygade said...

It's funny because the cast worked in gdb, just not in the code generated by gcc.

That is odd.

jaygade said...

Okay, I'll undo my code and try to add a #ifdef EOSX to the existing #ifdef ARM or something and try that.

Well, we know that your code works. Maybe the right thing to do is to add your code around an #ifdef EOSX.

jaygade said...

Wait a minute -- can't we cast to long and then to unsigned long? It's the cast of (-1) to unsigned long which is implementation defined right?

Idea which might be portable: in Dand_bits, cast to long, then in and_bits cast to unsigned long.

Perhaps, but so is any bitwise operation involving more than 32bits according to the other thread.

new topic     » goto parent     » topic index » view message » categorize

9. Re: Trying to use gdb on OS X

jimcbrown said...
jaygade said...

Okay, I'll undo my code and try to add a #ifdef EOSX to the existing #ifdef ARM or something and try that.

Well, we know that your code works. Maybe the right thing to do is to add your code around an #ifdef EOSX.

Well, the better goal would be to make something that is completely portable without an #ifdef if possible. Second would probably be to define a macro that converts dbl to int reliably and wrap that in #ifdef if necessary.

jimcbrown said...
jaygade said...

Wait a minute -- can't we cast to long and then to unsigned long? It's the cast of (-1) to unsigned long which is implementation defined right?

Idea which might be portable: in Dand_bits, cast to long, then in and_bits cast to unsigned long.

Perhaps, but so is any bitwise operation involving more than 32bits according to the other thread.

Right, I meant to include all of the D*_bits() functions.

Unfortunately, casting to long first still doesn't work because I can't get just the bits of 0xDEADBEE5 from the double into a 32-bit number. It works for 0xFFFFFFFF. I have to cast to long long and then to unsigned long.

Can we guarantee that long long is 64 bits on all platforms, or use int64_t or something? If so, then I think that's a good portable solution which could fix ARM and OSX and still work on Windows/Linux because conversion from long long to unsigned long is defined to work properly.

Regardless, I'll continue testing.

new topic     » goto parent     » topic index » view message » categorize

10. Re: Trying to use gdb on OS X

jaygade said...
jimcbrown said...
jaygade said...

Okay, I'll undo my code and try to add a #ifdef EOSX to the existing #ifdef ARM or something and try that.

Well, we know that your code works. Maybe the right thing to do is to add your code around an #ifdef EOSX.

Well, the better goal would be to make something that is completely portable without an #ifdef if possible.

Well, speed is an issue here. Doing these casts unnecessarily on x86 might slow it down (but then gain it might not).

jaygade said...

Second would probably be to define a macro that converts dbl to int reliably and wrap that in #ifdef if necessary.

I can't see a downside to that.

jaygade said...
jimcbrown said...
jaygade said...

Wait a minute -- can't we cast to long and then to unsigned long? It's the cast of (-1) to unsigned long which is implementation defined right?

Idea which might be portable: in Dand_bits, cast to long, then in and_bits cast to unsigned long.

Perhaps, but so is any bitwise operation involving more than 32bits according to the other thread.

Right, I meant to include all of the D*_bits() functions.

Unfortunately, casting to long first still doesn't work because I can't get just the bits of 0xDEADBEE5 from the double into a 32-bit number. It works for 0xFFFFFFFF. I have to cast to long long and then to unsigned long.

Ouch.

jaygade said...

Can we guarantee that long long is 64 bits on all platforms, or use int64_t or something? If so, then I think that's a good portable solution which could fix ARM and OSX and still work on Windows/Linux because conversion from long long to unsigned long is defined to work properly.

Regardless, I'll continue testing.

I'd say we should use int64_t, as that's standardized, while 'long long' is really a GNU extension.

Thankfully we no longer have to worry about Watcom. (IIRC it doesn't support either, we'd have to use __int64 or something there if we needed a 64bit integer type for some reason.)

new topic     » goto parent     » topic index » view message » categorize

11. Re: Trying to use gdb on OS X

long long is in C99; isn't it reasonable to expect it to be present? We compile on gcc 99% of the time on all platforms so we can almost assume it. I don't mind changing it to int64_t, though, but if so then we may want to follow suit throughout the whole source.

Right now, I have edited some macros and comments in execute.h, and the D*_bits functions in be_runtime.c. Some of the changes to execute.h may be controversial since it's such an old file used in so many places, but I don't think I broke anything. Especially since I didn't #ifdef them.

As far as performance is concerned, I thought about that but I thought that wrapping more decisions around the casts would probably be worse in the long run than just performing the casts only when necessary. Most of them are performed by hardware anyway. It would probably have to be measured for sure. I doubt the cast to long long takes much longer than the cast to unsigned long, however. I didn't really add any new casting. Regardless, compiler optimizations should count for that too.

As for submitting my changes, I would like them reviewed and tested by others before actually committing them into the mainline 4.0 branch. I especially want to make sure they run on other platforms as I expect them to. Should I just commit to 4.0, or should I make a new tag or branch, or what? I'll post diffs to the forum if I need to.

Regardless, I'll make some new eubins for OS X which hopefully someone can test.

Changes made: execute.h

  • I changed the order of the #defines so they could reference each other.
  • I reordered the object representation comment into numeric order and added hex values.
  • I redefined INT_VAL and MAKE_INT to cast to long long, and then to long in order to preserve bits during conversion from double.
  • I redefined MAKE_UINT to work in terms of INT_VAL and MAXINT macros.

be_runtime.c

  • I added INT_VAL macro in place of manual casts in all D*_bits() functions.

Edit: Oh, I think that OpenWatcom 1.2 supports long long. http://www.openwatcom.org/index.php/C99_Compliance

new topic     » goto parent     » topic index » view message » categorize

12. Re: Trying to use gdb on OS X

jaygade said...

long long is in C99; isn't it reasonable to expect it to be present? We compile on gcc 99% of the time on all platforms so we can almost assume it. I don't mind changing it to int64_t, though, but if so then we may want to follow suit throughout the whole source.

Hmm, that's a good point. I guess one day in the far future, there might be a platform that gcc supports with 256 sized ints where long long isn't 64bits ... but that's probably not worrying about right now.

jaygade said...

but if so then we may want to follow suit throughout the whole source.

I felt that we should do this anyways, considering that only int64_t et al guarantee a particular size in bits. This is a huge job though.

jaygade said...

As far as performance is concerned, I thought about that but I thought that wrapping more decisions around the casts would probably be worse in the long run than just performing the casts only when necessary.

Well, #ifdefs take no runtime performance hit at all. Just saying.

jaygade said...

Most of them are performed by hardware anyway. It would probably have to be measured for sure. I doubt the cast to long long takes much longer than the cast to unsigned long, however. I didn't really add any new casting. Regardless, compiler optimizations should count for that too.

Thinking it over, you're probably right. It's not like hardware is getting any slower, anyways.

jaygade said...

As for submitting my changes, I would like them reviewed and tested by others before actually committing them into the mainline 4.0 branch. I especially want to make sure they run on other platforms as I expect them to. Should I just commit to 4.0, or should I make a new tag or branch, or what? I'll post diffs to the forum if I need to.

A new branch is probably best... I don't think it's a big deal if you commit straight to 4.0 though. Someone needs to test on ARM and the other platforms to make sure nothing breaks anyways...

jaygade said...

Edit: Oh, I think that OpenWatcom 1.2 supports long long. http://www.openwatcom.org/index.php/C99_Compliance

Hmm. Maybe I was thinking of MSVC...

new topic     » goto parent     » topic index » view message » categorize

13. Re: Trying to use gdb on OS X

Continuing on.

Test results summary: 
    FAIL: t_callc.e 
    FAIL: t_filesys.e 
    FAIL: t_io.e 
    FAIL: t_locale.e 
    FAIL: t_net_http.e 
    FAIL: t_socket.e 
Files (run: 147) (failed: 6) (96% success) 

First eutest failure is for t_callc.e

interpreting t_callc.e: 
CMD 'eui   -d UNITTEST -batch t_callc.e ' 
  failed: can open lib818.dll, expected: TRUE but got: FALSE 
 
/Users/jason/Dropbox/src/openeuphoria/stable/osx/include/std/unittest.e:454 in procedure assert()  
can open lib818.dll  
 
... called from /Users/jason/Dropbox/src/openeuphoria/stable/osx/tests/t_callc.e:148  
 
--> See ex.err  
  failed: unittesting crashed, expected: TRUE but got: FALSE 
  13 tests run, 11 passed, 2 failed, 85% success 
FAILURE: t_callc.e EUPHORIA error with status 256 
 
Test results summary: 
    FAIL: t_callc.e 
Files (run: 1) (failed: 1) (0% success) 

Looking through the history, this was a 4.1 thing? There is no lib818.dll or lib818.c included with the 4.0 branch.

t_filesys.e fails. It looks like it has something to do with wildcard expansion.

interpreting t_filesys.e: 
CMD '/Users/jason/bin/eui   -d UNITTEST -batch t_filesys.e ' 
  failed: dir() #5, expected: "anything but '-1'" but got: -1 
  137 tests run, 136 passed, 1 failed, 99% success 
FAILURE: t_filesys.e program died with status 256 

t_io.e fails. It looks like seek doesn't work on OS X like it does on other BSDs.

interpreting t_io.e: 
CMD '/Users/jason/bin/eui   -d UNITTEST -batch t_io.e ' 
  failed: Seek STDIN, expected: 1 but got: 0 
  failed: Seek STDOUT, expected: 1 but got: 0 
  failed: Seek STDERR, expected: 1 but got: 0 
  71 tests run, 68 passed, 3 failed, 96% success 
FAILURE: t_io.e program died with status 256 

More to come. Time to quit for tonight.

new topic     » goto parent     » topic index » view message » categorize

14. Re: Trying to use gdb on OS X

jimcbrown said...

I'd say we should use int64_t, as that's standardized, while 'long long' is really a GNU extension.

Thankfully we no longer have to worry about Watcom. (IIRC it doesn't support either, we'd have to use __int64 or something there if we needed a 64bit integer type for some reason.)

Yes, we do this on 4.1, but he's trying to get 4.0 working under OSX. This is very disappointing. Could you try the following program?

#include <stdio.h> 
 
void convert_double( double d ){ 
	long l = (long) d; 
	unsigned long u = (unsigned long) d; 
	printf("%g -> %lx %lx\n", d, l, u ); 
} 
 
int main(){ 
	convert_double( (double) -1 ); 
	convert_double( (double) 0xdeadbeef ); 
	return 0; 
} 
 

I tried this two different ways:

$ gcc -m32 test.c -o test && ./test 
-1 -> ffffffff ffffffff 
3.73593e+09 -> 80000000 deadbeef 
 
gcc -m64 test.c -o test && ./test 
-1 -> ffffffffffffffff ffffffffffffffff 
3.73593e+09 -> deadbeef deadbeef 

Matt

new topic     » goto parent     » topic index » view message » categorize

15. Re: Trying to use gdb on OS X

mattlewis said...

he's trying to get 4.0 working under OSX. This is very disappointing.

Now that you mention it, it is very strange ... how did this break? None of this code was changed in the 4.0 branch since 4.0.0 was released (and that was back when we had an OSX dev and a few OSX testers).

new topic     » goto parent     » topic index » view message » categorize

16. Re: Trying to use gdb on OS X

I can't try the test until tonight (after 4:30pm PDT), although I'm sure I'll get similar results since that was what I was seeing in gdb from the compiled code. However when typing the casts directly into gdb they worked correctly.

I don't know how/why it broke. My OS X has an older GCC (I think I posted the version number up thread).

It now seems odd to me that the casting has always worked and was never broken in other versions; you would expect to see some odd errors whenever a pointer got stored as a double and then cast back into an int.

Whoever wrote the t_math.e bit tests and used a number that was sure to be cast as a double did a good job of catching this.

new topic     » goto parent     » topic index » view message » categorize

17. Re: Trying to use gdb on OS X

I might be overthinking this a bit. I need to write this out to wrap my head around it:

1. double contains a positive value in the integer range (0x00000000 - 0xFFFFFFFF). Conversion to unsigned long should be converted correctly. Conversion to signed long should fail if the double is greater than 0x7FFFFFFF.

2. double contains a negative value in the integer range (0x80000000 - 0xFFFFFFFF). Conversion to unsigned long should fail (implementation defined - I was getting 0 when testing above). Conversion to signed long should be okay.

When going to unsigned (which we generally want for bit and address manipulation) the key difference is the sign of the double is handled.

Looking at Matt's example up above, it looks like test 1 holds true. Test 2 converts to both unsigned and signed correctly in Matt's example (for -1), but I think on OS X it will fail.

new topic     » goto parent     » topic index » view message » categorize

18. Re: Trying to use gdb on OS X

jaygade said...

I might be overthinking this a bit. I need to write this out to wrap my head around it:

1. double contains a positive value in the integer range (0x00000000 - 0xFFFFFFFF). Conversion to unsigned long should be converted correctly. Conversion to signed long should fail if the double is greater than 0x7FFFFFFF.

The basic problem is that the behavior is undefined from the perspective of the C specs, so it's very possible that the version of gcc on OSX started doing something different, pre-empting the normal x86 behavior.

You might want to look into the function we added for these casts for ARM in the default branch. I don't know if that's a better solution than using a 64-bit integer or not.

Matt

new topic     » goto parent     » topic index » view message » categorize

19. Re: Trying to use gdb on OS X

Whichever method turns out to be better -- casting doubles to 64-bit int or wrapping some platform targets in an #ifdef() and adding a function, I will have learned things which will help me when I move on to --screwing up-- messing around with the 4.1 source.

And hopefully we'll have a more robust 4.06 release that people can continue to use.

new topic     » goto parent     » topic index » view message » categorize

20. Re: Trying to use gdb on OS X

mattlewis said...

Could you try the following program?

#include <stdio.h> 
 
void convert_double( double d ){ 
	long l = (long) d; 
	unsigned long u = (unsigned long) d; 
	printf("%g -> %lx %lx\n", d, l, u ); 
} 
 
int main(){ 
	convert_double( (double) -1 ); 
	convert_double( (double) 0xdeadbeef ); 
	return 0; 
} 
 

I tried this two different ways:

$ gcc -m32 test.c -o test && ./test 
-1 -> ffffffff ffffffff 
3.73593e+09 -> 80000000 deadbeef 
 
gcc -m64 test.c -o test && ./test 
-1 -> ffffffffffffffff ffffffffffffffff 
3.73593e+09 -> deadbeef deadbeef 

Matt


OS X results:

jason$ ./test-dbl32 
-1 -> ffffffff 0 
3.73593e+09 -> 80000000 deadbeef 
 
jason$ ./test-dbl64 
-1 -> ffffffffffffffff ffffffffffffffff 
3.73593e+09 -> deadbeef deadbeef 

new topic     » goto parent     » topic index » view message » categorize

21. Re: Trying to use gdb on OS X

I think I can guarantee the reason is because the compiler is using SSE* instructions for the conversion.

When I compile and run this the program size is the same, but the instructions are different -- it uses the normal 387 math instructions for the conversion:

/* test-dbl-ll32.c */ 
#include <stdio.h>  
  
void convert_double( double d ){  
	long l = (long) (long long) d;  
	unsigned long u = (unsigned long) (long long) d;  
	printf("%g -> %lx %lx\n", d, l, u );  
}  
  
int main(){  
	convert_double( (double) -1 );  
	convert_double( (double) 0xdeadbeef );  
	return 0;  
}  

Results:

jason$ ./test-dbl-ll32 
-1 -> ffffffff ffffffff 
3.73593e+09 -> deadbeef deadbeef 

When I compile Matt's original code with either -march=i386 or -mfpmath=387:

jason$ ./test-dbl 
-1 -> ffffffff ffffffff 
3.73593e+09 -> 80000000 deadbeef 

Interesting: with -march-i386, the code uses only 387 instructions. With -mfpmath=387, I still see some SSE* instructions in the disassembly.

I'm going to post this now, but out of curiosity I will try compiling test-dbl-ll32 with -mfpmath=sse2.

Edit: the -msse and -msse2 code are identical, and they both use 387 instructions. smile Both are identical to the version with only -m32.

Edit2: Compiling Matt's original code with -mnosse works, but is subtly different from -march=i386.

While this should be tested on ARM to make sure, I am still currently of the opinion that casting double to long long (or int64_t) prior to casting to unsigned long (or whatever portable type) is the correct thing to do for all platforms, and that eliminating an #ifdef and eliminating a separate function to convert doubles to int is the best solution.

new topic     » goto parent     » topic index » view message » categorize

22. Re: Trying to use gdb on OS X

jaygade said...

While this should be tested on ARM to make sure, I am still currently of the opinion that casting double to long long (or int64_t) prior to casting to unsigned long (or whatever portable type) is the correct thing to do for all platforms, and that eliminating an #ifdef and eliminating a separate function to convert doubles to int is the best solution.

In cases where that's big enough, yes it will work. The problem comes when you have a value that's too large for the target type. I hadn't even considered stuff like SSE instructions.

Matt

new topic     » goto parent     » topic index » view message » categorize

23. Re: Trying to use gdb on OS X

mattlewis said...

In cases where that's big enough, yes it will work. The problem comes when you have a value that's too large for the target type. I hadn't even considered stuff like SSE instructions.

Matt

How do you mean?

I don't mean to convert all doubles to integers, only doubles capable of representing Euphoria integers and C pointers. I expect us to be in 64-bit land for quite some time to come, but if we do move to 128-bit systems, <stdint.h> has intmax_t instead of int64_t. Do any 32-bit targets not support some kind of int64_t?

Regardless, I was thinking about this more this morning. Since 4.0 should be relatively stable, it will probably be better for me to change configure so that OSX doesn't use sse (or maybe so that no x86 uses sse?) instead of making the larger change to the Euphoria source itself (except for commenting the behavior).

For 4.1 I'm not sure. Will 4.1 support both 32- and 64-bit platforms?

new topic     » goto parent     » topic index » view message » categorize

24. Re: Trying to use gdb on OS X

jaygade said...

For 4.1 I'm not sure. Will 4.1 support both 32- and 64-bit platforms?

Yes. The prealphas already have for some time.

jaygade said...
mattlewis said...

In cases where that's big enough, yes it will work. The problem comes when you have a value that's too large for the target type. I hadn't even considered stuff like SSE instructions.

Matt

How do you mean?

I don't mean to convert all doubles to integers, only doubles capable of representing Euphoria integers and C pointers. I expect us to be in 64-bit land for quite some time to come, but if we do move to 128-bit systems, <stdint.h> has intmax_t instead of int64_t.

It's already a problem on 64bit, since we have long doubles (or extended floating points) that could in theory hold larger integer values than a 64bit int. We need a way to do bitwise ops on these superlarge values...

jaygade said...

Do any 32-bit targets not support some kind of int64_t?

Nothing modern that I can think of. Win32s maybe? Or really old 32bit DOS systems?

new topic     » goto parent     » topic index » view message » categorize

25. Re: Trying to use gdb on OS X

jaygade said...
mattlewis said...

In cases where that's big enough, yes it will work. The problem comes when you have a value that's too large for the target type. I hadn't even considered stuff like SSE instructions.

How do you mean?

I don't mean to convert all doubles to integers, only doubles capable of representing Euphoria integers and C pointers.

The question becomes, what do we do with input that is beyond that? It's very possible to get values too big for a 64-bit integer coming out of a euphoria atom that has some of its lowest 32 bits set. It's not really a common or particularly useful thing to do, but someone will do it and we should figure out how we're going to handle it. We could simply throw an error, or just say behavior is undefined when the value is too big.

Matt

new topic     » goto parent     » topic index » view message » categorize

26. Re: Trying to use gdb on OS X

jimcbrown said...

It's already a problem on 64bit, since we have long doubles (or extended floating points) that could in theory hold larger integer values than a 64bit int. We need a way to do bitwise ops on these superlarge values...

Does Euphoria use long doubles or extended floats internally now?

Right now, a normal double can hold an integer with 52 bits of precision, and those 52 bits will fit into a 64-bit type. So what I'm doing is taking that double with 52 bits, converting it to a 64 bit integer, and keeping lowest 32 bits. Then we can perform bitwise operations on the number. Remember, this is all internal to the C backend routines -- no double in these cases should be outside the range of a 32-bit integer because that is how the backend is written. (Although I don't think there are any explicit checks for this.)

Going forward maybe we need explicit routines to handle real<-->integer conversions for users regardless of the underlying type or size. I see that the library has to_integer() which returns either 0 or a default value if the number is out of bounds of a Euphoria 29-bit integer.

jimcbrown said...
jaygade said...

Do any 32-bit targets not support some kind of int64_t?

Nothing modern that I can think of. Win32s maybe? Or really old 32bit DOS systems?

I think it's really a compiler function; the compiler knows enough about the underlying machine to know whether it can be done in the processor or with a routine (like the old pre-387 days). I was looking into it and I saw that djgpp supports long long. I guess it depends on how old of machines we want to support with new code, or else suggest users use existing older software with older machines.

If and when we work with more embedded architectures, we'll have to solve whatever other problems crop up then.

mattlewis said...

The question becomes, what do we do with input that is beyond that? It's very possible to get values too big for a 64-bit integer coming out of a euphoria atom that has some of its lowest 32 bits set. It's not really a common or particularly useful thing to do, but someone will do it and we should figure out how we're going to handle it. We could simply throw an error, or just say behavior is undefined when the value is too big.

Matt

How does Euphoria handle converting doubles too large for a Euphoria integer now? (Tested on Windows with 4.05...) It fails with a type check error. Should this behavior change?


Remember, this is all for internal conversions between an integral atom stored as a C double and one stored as a C integer used either as an integer (for bitwise ops) or as a pointer. Not for user type conversions between arbitrary doubles and integers (at this point).

I created the change because I compiled 4.0 on OS X, found that I was failing the *bits() routines in t_math.e, and tried to figure out why. I found that certain doubles were not being converted to unsigned longs correctly. Although I didn't realize it at the time, the same problem seems to be related to the ARM port failing the same tests, only I came up with a different solution.

Converting between (larger) doubles and (larger) integers and performing bitwise operations on them is certainly a worthwhile goal, but it wasn't the main thrust of my bugfixing.

I realize that this only applies to 32-bit versions of Euphoria, not necessarily to 64-bit versions, but it will have to be accounted for if there is one codebase which can be compiled to both.

new topic     » goto parent     » topic index » view message » categorize

27. Re: Trying to use gdb on OS X

jaygade said...
jimcbrown said...

It's already a problem on 64bit, since we have long doubles (or extended floating points) that could in theory hold larger integer values than a 64bit int. We need a way to do bitwise ops on these superlarge values...

Does Euphoria use long doubles or extended floats internally now?

64-bit euphoria does.

jaygade said...

Right now, a normal double can hold an integer with 52 bits of precision, and those 52 bits will fit into a 64-bit type. So what I'm doing is taking that double with 52 bits, converting it to a 64 bit integer, and keeping lowest 32 bits. Then we can perform bitwise operations on the number. Remember, this is all internal to the C backend routines -- no double in these cases should be outside the range of a 32-bit integer because that is how the backend is written. (Although I don't think there are any explicit checks for this.)

The number stored in a double doesn't necessarily fit into a 64-bit integer. Remember, part of the double precision floating point value is an exponent.

jaygade said...
mattlewis said...

The question becomes, what do we do with input that is beyond that? It's very possible to get values too big for a 64-bit integer coming out of a euphoria atom that has some of its lowest 32 bits set. It's not really a common or particularly useful thing to do, but someone will do it and we should figure out how we're going to handle it. We could simply throw an error, or just say behavior is undefined when the value is too big.

How does Euphoria handle converting doubles too large for a Euphoria integer now? (Tested on Windows with 4.05...) It fails with a type check error. Should this behavior change?

Remember, this is all for internal conversions between an integral atom stored as a C double and one stored as a C integer used either as an integer (for bitwise ops) or as a pointer. Not for user type conversions between arbitrary doubles and integers (at this point).

I'm not sure...but I don't feel like spending a whole lot of time figuring it out right now. smile As I said, it's kind of a weird situation that most people aren't going to encounter unless they're trying to break things. A type check error is probably appropriate, since it's probably a bug in their code that caused the problem in the first place.

jaygade said...

I created the change because I compiled 4.0 on OS X, found that I was failing the *bits() routines in t_math.e, and tried to figure out why. I found that certain doubles were not being converted to unsigned longs correctly. Although I didn't realize it at the time, the same problem seems to be related to the ARM port failing the same tests, only I came up with a different solution.

Converting between (larger) doubles and (larger) integers and performing bitwise operations on them is certainly a worthwhile goal, but it wasn't the main thrust of my bugfixing.

I realize that this only applies to 32-bit versions of Euphoria, not necessarily to 64-bit versions, but it will have to be accounted for if there is one codebase which can be compiled to both.

Yes. In general, my approach for this sort of thing is to write some tests that fail and then try to figure out how to fix it. That way the issue is less likely to be forgotten, especially if I'm not sure how to get it fixed.

Matt

new topic     » goto parent     » topic index » view message » categorize

28. Re: Trying to use gdb on OS X

Should I create a ticket? I don't want this issue to get lost either.

mattlewis said...

The number stored in a double doesn't necessarily fit into a 64-bit integer. Remember, part of the double precision floating point value is an exponent.

Yes, I know this, and I thought that I had addressed it a couple of times unless I'm missing some other point.

Currently 32-bit Euphoria has 29-bit integers, and it can perform bitwise operations on integers up to 32 bits in size. Bitwise operations on integers larger than 32 bits produce incorrect results.

Integers which are between 30 and 32 bits in size are stored as doubles. In order to preserve all 32 bits, the C backend has to cast the double to a C integer (long or unsigned long), perform the operation, and then store it back to a double.

The C standard says that casting a double to a long that is too big to fit into the long is undefined, and that casting double that is too big or is negative to an unsigned long is undefined.

There was a bug in the Euphoria C backend which relied upon this undefined behavior working a certain way. The fact that it worked until now is why it wasn't caught until we started moving into ARM and OS X platforms. The bug manifested itself as incorrect results from bitwise operations when the arguments were negative or were larger than 29 bits.

At this point I am not trying to address other behavior or larger values, although some very good points have been raised. Changing the D*bits() functions to work on the full range of integers that can be accurately represented is an interesting, but separate, problem.

new topic     » goto parent     » topic index » view message » categorize

29. Re: Trying to use gdb on OS X

jaygade said...
mattlewis said...

The number stored in a double doesn't necessarily fit into a 64-bit integer. Remember, part of the double precision floating point value is an exponent.

Yes, I know this, and I thought that I had addressed it a couple of times unless I'm missing some other point.

Currently 32-bit Euphoria has 29-bit integers, and it can perform bitwise operations on integers up to 32 bits in size. Bitwise operations on integers larger than 32 bits produce incorrect results.

Integers which are between 30 and 32 bits in size are stored as doubles.

It's 31-bit. (Actually, it's 4 separate integer types, each which holds 29-bit values, but which when counted together map up to a full 31 unique bits. Roughly speaking, it's like we have one integer type to represent all positive integers and another to represent all negative integers, or something.)

Only 32bit values should need to be stored as doubles.

new topic     » goto parent     » topic index » view message » categorize

30. Re: Trying to use gdb on OS X

jimcbrown said...
jaygade said...
mattlewis said...

The number stored in a double doesn't necessarily fit into a 64-bit integer. Remember, part of the double precision floating point value is an exponent.

Yes, I know this, and I thought that I had addressed it a couple of times unless I'm missing some other point.

Currently 32-bit Euphoria has 29-bit integers, and it can perform bitwise operations on integers up to 32 bits in size. Bitwise operations on integers larger than 32 bits produce incorrect results.

Integers which are between 30 and 32 bits in size are stored as doubles.

It's 31-bit. (Actually, it's 4 separate integer types, each which holds 29-bit values, but which when counted together map up to a full 31 unique bits. Roughly speaking, it's like we have one integer type to represent all positive integers and another to represent all negative integers, or something.)

Only 32bit values should need to be stored as doubles.

Okay -- I should know that. smh.

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu