gstein@oracle.com (Greg Stein) (02/14/90)
> From: jln@acns.nwu.edu (John Norstad) > In article <1046@watserv1.waterloo.edu> bmwrkshp@watserv1.waterloo.edu ( > Wrkshp Id - Sys Design ) writes: > > But I'm sure THINK C is still an order of magnitude > > faster. Don't know what that linker is doing. Sure takes its own > > sweet time even on Mac II's. > > As I understand it, one of the reasons is that MPW's linker is much > smarter. For example, it lets you direct individual routines within a > single module to different segments, and it eliminates dead code. I'm not > sure about all this, though. > > > I would probably use MPW 99% of the time if it weren't for the fact > > that the C compiler is broken. Even the updated C compiler > > included with the C++ package still has bugs. > > I've heard this from other places too (e.g., the guys at Wolfram). But > I'm up to 16,000 lines of pretty hairy C code in Disinfectant now, and > I've yet to encounter a single compiler bug. Maybe because I'm a reformed > Pascal fanatic, I don't write as ugly code as the rest of you guys :-) > > John Norstad > Northwestern University > jln@acns.nwu.edu > I have a nice bug from V3.1b3e19 of MPW C. Type in this little code fragment, compile it, and look at its output: int main() { char *a, *b = 0L; int c = 0L; /* assignment to prevent warnings */ if (a = &b[c]) return(1); return(2); } The relevant part is this: ... LEA $00(A3,D7.L),A4 ; all vars are in registers BEQ.S @1 ... Note that a conditional branch is performed without any testing being done. (Yes, the bug has been reported to Apple) Don't ask me how I found the bug, but it is repeatable. Things like this make me wonder just how stable the compiler is. I realize that I have a Beta version and that the line of code above is sheer idiocy for most purposes, but still... John, I will agree with you, though, about the Linker. Think C includes code a whole file at a time -- it won't pick out individual routines from a file. MPW C will do this. What I don't get is why Think C hasn't changed this by now -- they've had a few versions to do it. Heck, in high school when I wrote the Rascal compiler for the Mac, I wrote a linker that did dead code analysis and picked out a routine at a time. Surely, Mike Kahl could do it. Well, John, I don't know whether you write ugly code or not, but Disinfectant 1.6 is a very nice piece of work. Thanx. Greg Stein -- This posting bears no relation to my employer Arpa: gstein%oracle.uucp@apple.com UUCP: ..!{uunet,apple}!oracle!gstein
amanda@mermaid.intercon.com (Amanda Walker) (02/15/90)
In article <1990Feb14.004350.14475@oracle.com>, gstein@oracle.com (Greg Stein) writes: > Things like this make me wonder just how stable the compiler is. It seems pretty good for "most" code. In particular, all of the bugs we've found have been code generation bugs where the condition codes are not tracked properly. Well, that and scribbling on the SCSI driver :-)... -- Amanda Walker InterCon Systems Corporation "Many of the truths we cling to depend greatly upon our own point of view." --Obi-Wan Kenobi in "Return of the Jedi"
anders@penguin (Anders Wallgren) (02/15/90)
Also, try the following: #include <stdio.h> enum test_enum { enum_1 = 1, enum_2 = 2, enum_3 = 3, enum_4 = 4, }; typedef struct { int val_int; unsigned char *val_string; } TEST_STRUCT; void main(void) { enum test_enum type; TEST_STRUCT uval,*uvalp; int val; type = enum_4 uval.val_int = 1; uvalp = &uval; val = 1; type = (enum test_enum)(uval.val_int); printf("struct and cast: type is %d (this should be 1)\n", type); type = enum_4 type = uval.val_int; printf("struct, no cast: type is %d (this should be 1)\n", type); type = enum_4; type = (enum test_enum)(uvalp->val_int); printf("struct and cast through pointer: type is %d (this should be 1)\n", type); type = enum_4; type = uvalp->val_int; printf("struct, no cast, through pointer: type is %d (this should be 1)\n", type); type = enum_4; } This won't work in 3.1b1 or 3.1 final.
billkatt@mondo.engin.umich.edu (billkatt) (02/15/90)
In article <1990Feb14.004350.14475@oracle.com> you write: >> From: jln@acns.nwu.edu (John Norstad) >> In article <1046@watserv1.waterloo.edu> bmwrkshp@watserv1.waterloo.edu ( >> Wrkshp Id - Sys Design ) writes: >> > But I'm sure THINK C is still an order of magnitude >> > faster. Don't know what that linker is doing. Sure takes its own >> > sweet time even on Mac II's. >> >> As I understand it, one of the reasons is that MPW's linker is much >> smarter. For example, it lets you direct individual routines within a >> single module to different segments, and it eliminates dead code. I'm not >> sure about all this, though. >> >John, I will agree with you, though, about the Linker. Think C >includes code a whole file at a time -- it won't pick out individual >routines from a file. MPW C will do this. What I don't get is why >Think C hasn't changed this by now -- they've had a few versions to do >it. Heck, in high school when I wrote the Rascal compiler for the >Mac, I wrote a linker that did dead code analysis and picked out a >routine at a time. Surely, Mike Kahl could do it. Think C DOES indeed remove dead code, ever since version 3.0. It doesn't seem to do quite as good a job as MPW 3.0, but a good job none the less. To remove dead code, just check the 'Smart Link' check box when you build your app/DA/whatever. You can go out and prove it to yourself by writing a program which uses one small routine from the ANSI library, and building it to disk. Whereas the ANSI library is 27K long, your program will come out to about 5 or 6K. -Steve Bollinger billkatt@mondo.engin.umich.edu
anders@penguin (Anders Wallgren) (02/16/90)
Of course we shouldn't forget that MPW C and C++ are not compatible. CFront does not optimize enums, whereas the C compiler does, which causes a lot of problems. According to Apple there is no way to get around this: "When CFront compiles your code, although it uses the same C compiler, it has already tokenized its input and performed its own version of optimization at that level. ...it would be a good idea if all C compilers on that same platform produced interchangeable optimized code but this is unfortunately not the case here... You will not be able to mix code between CFront and MPW C at this time without adding glue code to fix up the differences. Your comments will, however, be brought to the attention of the compilers group and, hopefully, this incompatibility will not always be true." 1. Perhaps it should be suggested to Apple's compiler group that they should spend more time testing their compilers and less time inventing infantile error messages. 2. Better yet, perhaps they should provide switches to turn off these optimizations so that we can get around bugs and 'incompatibilities.' 3. The thing that really steams me is that there's a switch to CFront to turn off the optimization that it never does, but no switch to the MPW C compiler to turn off the optimization that it always does. Anders
gstein@oracle.com (02/16/90)
Steve Bollinger writes: >Greg Stein writes: >John, I will agree with you, though, about the Linker. Think C >>includes code a whole file at a time -- it won't pick out individual >>routines from a file. MPW C will do this. What I don't get is why >>Think C hasn't changed this by now -- they've had a few versions to do >>it. Heck, in high school when I wrote the Rascal compiler for the >>Mac, I wrote a linker that did dead code analysis and picked out a >>routine at a time. Surely, Mike Kahl could do it. > >Think C DOES indeed remove dead code, ever since version 3.0. It doesn't seem >to do quite as good a job as MPW 3.0, but a good job none the less. To >remove dead code, just check the 'Smart Link' check box when you build your >app/DA/whatever. You can go out and prove it to yourself by writing a >program which uses one small routine from the ANSI library, and building it to >disk. Whereas the ANSI library is 27K long, your program will come out to >about 5 or 6K. > Hmm... I had thought that Think C works on a file by file basis. If you include a routine from a file, the WHOLE file is pulled in. Note, though, that this doesn't count for projects/libraries: in these it picks the file out of the project. As for the ANSI library, Think has split up the source into a bunch of tiny files. Since you use one routine, you get one (little) file. I know that using "Run..." doesn't do any dead code analysis and you pick up whole libraries/ projects (e.g. MacTraps), but building is different. Maybe I'm brain dead and they've fixed this. Unfortunately, I have to wait until I get home to check cuz we don't use Think C here at work :-( Happy hacking... Greg Stein -- This posting bears no relation to my employer Arpa: gstein%oracle.uucp@apple.com UUCP: ..!{uunet,apple}!oracle!gstein
ph@cci632.UUCP (Pete Hoch) (02/17/90)
In article <10898@zodiac.ADS.COM>, anders@penguin (Anders Wallgren) writes: > Of course we shouldn't forget that MPW C and C++ are not compatible. > > You will not be > able to mix code between CFront and MPW C at this time without adding > glue code to fix up the differences. What do you mean? What are the differences? I am currently linking C with C++, assembler and Pascal. There are no link errors and no run time errors. (That I have traced to the compilers :-) So what is it that is not compatible? Thanks, Pete Hoch
CXT105@psuvm.psu.edu (Christopher Tate) (02/17/90)
In article <1990Feb16.012322.19895@oracle.com>, gstein@oracle.com says: >Hmm... > >I had thought that Think C works on a file by file basis. If you >include a routine from a file, the WHOLE file is pulled in. Note, >though, that this doesn't count for projects/libraries: in these it >picks the file out of the project. As for the ANSI library, Think has >split up the source into a bunch of tiny files. Since you use one >routine, you get one (little) file. I know that using "Run..." >doesn't do any dead code analysis and you pick up whole libraries/ >projects (e.g. MacTraps), but building is different. I'm not sure about this, but I think that THINK C does its dead-code removal on a SEGMENT-basis. If you have several routines in the same segment in your project (which you are including as a library), and you use any one of them, you'll wind up with all of them in your final build. But, you won't have any code from other segments of the same included project. Note that this applies to *projects* which are included in other projects, not to actual "libraries." ------- Christopher Tate | "And as I watch the drops of rain | Weave their weary paths and die, cxt105@psuvm.psu.edu | I know that I am like the rain; {...}!psuvax1!psuvm.bitnet!cxt105 | There but for the grace of you go I." cxt105@psuvm.bitnet | -- Simon & Garfunkle
minich@a.cs.okstate.edu (MINICH ROBERT JOHN) (02/17/90)
From article <1990Feb16.012322.19895@oracle.com>, by gstein@oracle.com: > Hmm... > > I had thought that Think C works on a file by file basis. If you > include a routine from a file, the WHOLE file is pulled in. Note, > though, that this doesn't count for projects/libraries: in these it > picks the file out of the project. As for the ANSI library, Think has > split up the source into a bunch of tiny files. Since you use one > routine, you get one (little) file. I know that using "Run..." > doesn't do any dead code analysis and you pick up whole libraries/ > projects (e.g. MacTraps), but building is different. > > Maybe I'm brain dead and they've fixed this. Unfortunately, I have to > wait until I get home to check cuz we don't use Think C here at work :-( > Greg Stein I am not sure about THINK C, but I know the way THINK Pascal works, it does include entire files when you're debugging, but when you "Build..." and check "Smart Linking", it does go routine by routine. I've had a couple occasions where I picked out a couple routines out of each of many seperate files. The total of all the files wouldn't fit into one segment unless I did the Build.. with Smart Linking. Oc course, I went and deleted the majority of the source, which I didn't happen to be using, so I could debug the darn thing! Robert Minich minich@a.cs.okstate.edu
anders@penguin (Anders Wallgren) (02/18/90)
The MPW C compiler optimizes the size of enums depending on what values they take on - if it only has ten values, all of which are less than the maximum value that a data size can hold, then it will make the enum that size. There is no way to turn this off. When CFront compiles your code, it makes all your enums int's, irregardless of what values they hold. Apparently Apple wanted it to optimize enums like their C compiler does, because there is a flag to CFront (-z6, I think) to tell it to NOT optimize enum, but this is in fact what it does all the time. This causes BIG PROBLEMS. For example, if you have a struct with a member that is an enum, and then try to write code in C _and_ C++ that know about this struct, they won't agree on the size of it, and will overwrite each other. Of course there is no warning from either compiler, since they both think they know what they are doing, and no warning from the linker since you're just passing pointers to structs, and not the structs themselves. The following three-file test program will demonstrate this pretty clearly: test.h ------ enum type { type1, type2, type3 }; typedef struct foo { enum type t; short s; long l; } FOO; int kernel(FOO *f); test.c ------ #include "test.h" int kernel(f) FOO *f; { int i = sizeof(FOO); f->t = type2; f->s = 0x0101; f->l = 0x69696969; return i; } test.cp ------- #include <stdio.h> extern "C" { #include "test.h" } main(void) { char c[256]; FOO f; char d[256]; int i = sizeof(f); int j = kernel(&f); printf("sizeof foo (c++): %d\n", i); printf("sizeof foo (c): %d\n", j); printf("foo.t (2): %d, foo.s (x0101): %x, foo.l (x69696969): %x\n", f.t, f.s, f.l); }
rmh@apple.com (Rick Holzgrafe) (02/20/90)
In article <10936@zodiac.ADS.COM> anders@penguin (Anders Wallgren) writes: > The MPW C compiler optimizes the size of enums depending on what > values they take on - if it only has ten values, all of which are less > than the maximum value that a data size can hold, then it will make > the enum that size. There is no way to turn this off. > > When CFront compiles your code, it makes all your enums int's, > irregardless of what values they hold. Apparently Apple wanted it to > optimize enums like their C compiler does, because there is a flag to > CFront (-z6, I think) to tell it to NOT optimize enum, but this is in > fact what it does all the time. I *know* it's ugly and offensive, but could you do something like: enum type { type1, type2, type3, typeDummy=0x7fffffff }; to force MPW C to use 32-bit values for enums? If so, #define FORCE_LONG_ENUMS ,typeDummy=0x7fffffff enum type { type1, type2, type3 FORCE_LONG_ENUMS}; could be used for the duration, then easily compiled out when the compilers get their acts together. ========================================================================== Rick Holzgrafe | {sun,voder,nsc,mtxinu,dual}!apple!rmh Software Engineer | AppleLink HOLZGRAFE1 rmh@apple.com Apple Computer, Inc. | "All opinions expressed are mine, and do 20525 Mariani Ave. MS: 67-B | not necessarily represent those of my Cupertino, CA 95014 | employer, Apple Computer Inc."
anders@penguin (Anders Wallgren) (02/21/90)
In article <6792@internal.Apple.COM>, rmh@apple (Rick Holzgrafe) writes: >I *know* it's ugly and offensive, but could you do something like: > enum type { type1, type2, type3, typeDummy=0x7fffffff }; >to force MPW C to use 32-bit values for enums? If so, > #define FORCE_LONG_ENUMS ,typeDummy=0x7fffffff > enum type { type1, type2, type3 FORCE_LONG_ENUMS}; >could be used for the duration, then easily compiled out when the >compilers get their acts together. Yeah, we did something like: typedef enum { foo, bar, } ENUM_DEF(FOO_BAR); using a macro which was conditionally defined based on what platform we compiled the code on: #ifdef MACOS #define ENUM_DEF(name) _ ## name; typedef short name #else #define ENUM_DEF(name) name #endif This way we didn't have to modify the member of the enums, and could rely on enums being a certain size. Anders