hd@philtis.UUCP (Henk D. Davids @ PMSN) (06/05/89)
Not trying to start another war, but I'm just looking for the relative merits of PLM versus C for programming our target machines that are based on Intel 80x86 machines. We use VAX/VMS systems for cross-development. I would appreciate any input that will help us to make a decision based on facts, rather than religion ... Thanks, Henk -- ----------------------------------------------------------------- Henk D. Davids @ PHILIPS Medical Systems B.V., Dept. SWE-MTT Building QA-II / PO Box 10000 / 5680 DA Best / The Netherlands UUCP: hd@philtis.cft.philips.nl Voice: +31 40 762255
tneff@bfmny0.UUCP (Tom Neff) (06/06/89)
In article <598@philtis.UUCP> hd@philtis.UUCP (Henk D. Davids @ PMSN) writes: >Not trying to start another war, but I'm just looking for >the relative merits of PLM versus C for programming >our target machines that are based on Intel 80x86 machines. "Just looking for the relative merits" is of course exactly how those wars get started. :-) Both products exist and work well. Intel C is dpANSI conformant (within epsilon, I dunno if it's perfect). Both languages can call each other and other Intel HLL's. C gives you a choice of "fixed" or "variable" parameter passing conventions. If you code in Intel C you can maximize portability to other platforms should the need arise later on. With PL/M on the other hand you can get a little tighter code for some of the classic kinds of systems programming constructs. For instance if you want a CASE driven state machine in a critical interrupt handler, PL/M implements DO CASE as a jump indirect indexed off a short array of offsets, e.g. JMP CASETBL[BX]. C on the other hand does 'switch' as a full if-then/elseif-then/elseif-then... series. So to get to a late case you may have to do a dozen compares and jumps. Unimportant for ordinary application code but possibly critical for, say, an A/D handler. On the other hand if you're bench testing an embedded system using an enhanced development platform, you may find the easy access to C's RTL (printf etc) to be helpful, although you'll have to #if those out before building the embedded target, usually. If your memory model needs are exotic or complex PL/M may be the only way to get it (besides ASMx86). Its extended segmentation models are impressively flexible. Intel C has four basic memory models and a "far" keyword but doesn't support extended segmentation. >We use VAX/VMS systems for cross-development. All the tools are available as VAX cross products I believe. I would >appreciate any input that will help us to make a decision >based on facts, rather than religion ... This presupposes religious arguments are never based on facts. :-) If your shop can afford VAXen there's no sense in not buying BOTH Intel C and PL/M and making your own decision. Whichever you go with for the main project, the other will probably come in handy along the way. The reason arguments like C-vs-PL/M get religious is that only a fanatic would absolutely recommend one over the other! Each product has its strengths and weaknesses and each is usable in a production environment. Your own computing needs are a big part of the answer, so evaluating both is best. -- Tom Neff UUCP: ...!uunet!bfmny0!tneff "Truisms aren't everything." Internet: tneff@bfmny0.UU.NET
peter@ficc.uu.net (Peter da Silva) (06/06/89)
In article <14381@bfmny0.UUCP>, tneff@bfmny0.UUCP (Tom Neff) writes: > CASETBL[BX]. C on the other hand does 'switch' as a full > if-then/elseif-then/elseif-then... series. This must be something specific to intel's C/386, because traditionally 'C' compilers have used a variety of techniques to implement case... including a jump table for dense case tables (such as PL/M DO CASE constructs), lookup tables, if-then-else chains, and a combination of all three. This optimisation existed even in Ritchie's V6 compiler. > If your memory model needs are exotic or complex PL/M may be the only > way to get it (besides ASMx86). Its extended segmentation models are > impressively flexible. Intel C has four basic memory models and > a "far" keyword but doesn't support extended segmentation. At Ensun, we had a complete polled multitasker written entirely in PL/M. If we had done it in C there would have had to be some assembly code to handle the coroutine switching. (Now is this a balanced article or what?) If you're married to intel, go for PL/M by all means. If you don't want to be tied to one processor family, go for C. If you work for the DoD, you didn't read this far because you're using ADA :->. -- Peter da Silva, Xenix Support, Ferranti International Controls Corporation. Business: uunet.uu.net!ficc!peter, peter@ficc.uu.net, +1 713 274 5180. Personal: ...!texbell!sugar!peter, peter@sugar.hackercorp.com.
guy@auspex.auspex.com (Guy Harris) (06/07/89)
>For instance if you want a CASE driven state machine in a critical >interrupt handler, PL/M implements DO CASE as a jump indirect indexed >off a short array of offsets, e.g. JMP CASETBL[BX]. C on the other hand >does 'switch' as a full if-then/elseif-then/elseif-then... series. I sincerely hope Intel's C compiler does not do so for *all* "switch" statements; any competent C compiler can and will turn a "dense" "switch" statement - i.e., one where the cases form a reasonably tight range - into an indexded jump. (The definition of "dense" varies from compiler to compiler.)
tneff@bfmny0.UUCP (Tom Neff) (06/07/89)
In article <1765@auspex.auspex.com> guy@auspex.auspex.com (Guy Harris) writes: > [ I had said: ] >>For instance if you want a CASE driven state machine in a critical >>interrupt handler, PL/M implements DO CASE as a jump indirect indexed >>off a short array of offsets, e.g. JMP CASETBL[BX]. C on the other hand >>does 'switch' as a full if-then/elseif-then/elseif-then... series. > >I sincerely hope Intel's C compiler does not do so for *all* "switch" >statements; any competent C compiler can and will turn a "dense" >"switch" statement - i.e., one where the cases form a reasonably tight >range - into an indexded jump. (The definition of "dense" varies from >compiler to compiler.) Not wanting to make rash statements, I retested it. I'm right. Here's the proof (about 70 lines so hit N if you believe me <grin>): iC-86 COMPILER JUNK 05/27/89 11:23:32 PAGE 1 DOS 3.30 (038-N) iC-86 COMPILER V4.0, COMPILATION OF MODULE JUNK OBJECT MODULE PLACED IN JUNK.OBJ COMPILER INVOKED BY: Z:\L86\IC86.EXE JUNK.C OPTIMIZE(3) CODE PAGEWIDTH(80) line level incl 1 main() 2 { 3 1 int x; 4 1 5 1 switch (x) { 6 2 case 0: foo(x); 7 2 break; 8 2 case 1: fee(x); 9 2 break; 10 2 case 2: fie(x); 11 2 break; 12 2 } 13 1 } iC-86 COMPILER JUNK 05/27/89 11:23:32 PAGE 2 ASSEMBLY LISTING OF OBJECT CODE ; STATEMENT # 2 main PROC NEAR 0000 56 PUSH SI 0001 57 PUSH DI 0002 55 PUSH BP 0003 8BEC MOV BP,SP 0005 51 PUSH CX ; STATEMENT # 5 0006 8B5EFE MOV BX,[BP].x 0009 EB19 JMP @3 @4: ; STATEMENT # 6 000B FF76FE PUSH [BP].x ; 1 000E E80000 CALL foo 0011 EB0E JMP @7 ; STATEMENT # 7 @5: ; STATEMENT # 8 0013 FF76FE PUSH [BP].x ; 1 0016 E80000 CALL fee 0019 EB06 JMP @7 ; STATEMENT # 9 @6: ; STATEMENT # 10 001B FF76FE PUSH [BP].x ; 1 001E E80000 CALL fie @7: 0021 59 POP CX ; 1 ; STATEMENT # 11 0022 EB0F JMP @2 ; STATEMENT # 12 @3: 0024 83FB00 CMP BX,0H 0027 74E2 JZ @4 0029 83FB01 CMP BX,1H 002C 74E5 JZ @5 002E 83FB02 CMP BX,2H 0031 74E8 JZ @6 @2: ; STATEMENT # 13 0033 8BE5 MOV SP,BP 0035 5D POP BP 0036 5F POP DI 0037 5E POP SI 0038 C3 RET main ENDP MODULE INFORMATION: CODE AREA SIZE = 0039H 57D CONSTANT AREA SIZE = 0000H 0D DATA AREA SIZE = 0000H 0D MAXIMUM STACK SIZE = 000CH 12D iC-86 COMPILER JUNK 05/27/89 11:23:32 PAGE 3 ASSEMBLY LISTING OF OBJECT CODE iC-86 COMPILATION COMPLETE. 0 WARNINGS, 0 ERRORS -- You may redistribute this article only to those who may freely do likewise. -- Tom Neff UUCP: ...!uunet!bfmny0!tneff "Truisms aren't everything." Internet: tneff@bfmny0.UU.NET
wht@tridom.uucp (Warren Tucker) (06/08/89)
Having programmed PL/M-86 and -186 for three years and C for five (not concurrently), I give the vote to C with two minor caveats. Pro C: 1. PL/M-x86 is implemented for Intel 80x86 CPUs. If you can imagine you'll EVER want to move the design to another architecture, C is an infinitely better language to put your long hours of design, hacking, debugging and strenuous testing into (medical systems get tested 'strenuously', yes :-) ? ). 2. The tools for C language development abound. The same for PL-M are fewer and harder to find. The same holds for the availability of subroutine libraries and programs to extract code and ideas from. 3. C is a lot less wordy. Having refused to use a macro for the PL/M DECLARE keyword, my fingers are a great deal more tired after finishing a module in PL/M. EVERY function or procedure used in a module not resident in it must be DECLAREd EXTERNALly. This is probably a weaker argument, but it counts. 4. Support. I may be wrong, but I think there is a great deal more C programmers out there than PL/M. Pro PL/M: 5. PL/M is inherently a strongly typed language. It is very hard to screw up the number and type of parameters supplied to a function, etc. This might be a good thing for what you are trying to accomplish. Passing a variable number of arguments to some function like printf is nice, but having the facility all over the language is why function prototyping and lint were invented. 6. I haven't seen any C compiler produce such good code for the Intel CPU. PL/M built-in functions use REP, LOOPxx, MOVSB, etc. in inline code, while C is always calling external routines for such things (like _blmv for structure assignment). Such things are more important for ROM-based MPU-controlled instruments than for, say, a disk-based multi-MIP MRI system. I hope this diatribe has been of some use. -- ------------------------------------------------------------------- Warren Tucker, Tridom Corporation ...!gatech!emory!tridom!wht Sforzando (It., sfohr-tsahn'-doh). A direction to perform the tone or chord with special stress, or marked and sudden emphasis.
peter@ficc.uu.net (Peter da Silva) (06/08/89)
So you're saying that iC86 produces worse code than Ritchie's vintage 1974 or so C compiler... -- Peter da Silva, Xenix Support, Ferranti International Controls Corporation. Business: uunet.uu.net!ficc!peter, peter@ficc.uu.net, +1 713 274 5180. Personal: ...!texbell!sugar!peter, peter@sugar.hackercorp.com.
karl@ficc.uu.net (karl lehenbauer) (06/08/89)
In article <126@tridom.uucp>, wht@tridom.uucp (Warren Tucker) writes: > 5. PL/M is inherently a strongly typed language. It is > very hard to screw up the number and type of parameters > supplied to a function, etc. This might be a good thing for > what you are trying to accomplish. Passing a variable > number of arguments to some function like printf is nice, > but having the facility all over the language is why > function prototyping and lint were invented. True enough, but as I was just commenting over in comp.realtime where we've been discussing this as well, unlike in C, PL/M pointers don't have data types beyond being pointers. (now quoting from <4423@ficc.uu.net>) Thus, a lot of improper use of pointers which would cause warnings (at least) from most C compilers are passed without comment by PL/M and one gets to find the problem by debugging. We do a lot of stuff that has to be FORTRAN-callable, and *all* the parameters for a PL/M routine that's FORTRAN- callable have to be pointers, so a lot of the benefits of data type checking by the compiler are lost to us. -- -- uunet!ficc!karl "Contemptuous lights flashed across the computer's -- karl@ficc.uu.net console." -- Hitchhiker's Guide
tneff@bfmny0.UUCP (Tom Neff) (06/08/89)
In article <126@tridom.uucp> wht@tridom.uucp (Warren Tucker) writes: >2. The tools for C language development abound. The same >for PL-M are fewer and harder to find. The same holds for >the availability of subroutine libraries and programs to >extract code and ideas from. Tool availability unfortunately depends on your choice of platform. If you have the (mis)fortune to be developing on an iRMX box, you don't have a lot of the goodies UNIX or even MS-DOS based folks do. Some you can port yourself, but it's not always trivial to take 200k of BSDish code and shoehorn it into ANSI C on an alien box with only sketchy equivalents for some of the standard UNIX facilities. >3. C is a lot less wordy. Having refused to use a macro >for the PL/M DECLARE keyword, my fingers are a great deal >more tired after finishing a module in PL/M. EVERY function >or procedure used in a module not resident in it must be >DECLAREd EXTERNALly. This is probably a weaker argument, >but it counts. I would like to play devil's advocate here and say that in my experience, the need to spell more things out HELPS program reliability and maintainability rather than hinders it. Writing your first big PL/M source module from scratch can be a bit daunting. Writing the next one can usually be accomplished by boilerplating the structure of the first one wholesale in the editor and replacing the guts with new stuff. That's what I do. On the other hand I have seen my share of write-only C and would not care to have to maintain it for a living. >4. Support. I may be wrong, but I think there is a great >deal more C programmers out there than PL/M. The problem with PL/M programmers is that they don't know each other exist! That's one of the things comp.realtime can help with, also comp.sys.intel although everyone seems to use that group to beg for stepping errata sheets. :-) >5. PL/M is inherently a strongly typed language. It is >very hard to screw up the number and type of parameters >supplied to a function, etc. However see another poster's point that once you pass by ADDRESS, PL/M gives up the ghost, and this can hurt when interfacing with, say, FORTRAN. What that poster didn't point out, though, is that C is no better at interfacing with FORTRAN! Things like LINT only help for C-to-C interfaces. LINK86 is happy to tell you about "type mismatches" of course - and will do so at *book length* if you link C and FORTRAN together with the TYPDEF records still in, even if you did it *right*. >6. I haven't seen any C compiler produce such good code for >the Intel CPU. PL/M built-in functions use REP, LOOPxx, >MOVSB, etc. in inline code, while C is always calling >external routines for such things (like _blmv for structure >assignment). No - as of iCx86 3.0 and later (the ANSI versions, post-Mark Williams atrocity) there is something called <inline.h> which tells the compiler to generate inline code for MOVB type things. There is a #pragma inline (a total kludge) that gets tacked onto the special functions. If you leave out inline.h, it resolves them to the RTL I believe. -- You may redistribute this article only to those who may freely do likewise. -- Tom Neff UUCP: ...!uunet!bfmny0!tneff "Truisms aren't everything." Internet: tneff@bfmny0.UU.NET
tneff@bfmny0.UUCP (Tom Neff) (06/08/89)
In article <4448@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes: >So you're saying that iC86 produces worse code than Ritchie's vintage 1974 >or so C compiler... Actually in response to a mailed suggestion I went back and tried my test program with varying numbers of cases. It turns out that if you have *6 or more* cases, iC-x86 generates a jump table; 5 or fewer, it does it elseif-style. This appears to be more of a space optimization than anything else; my experience with critical realtime code is that speed optimizations are more important for things like interrupt handlers. It would be nice if Intel allowed some programmer control over this behavior for those who *really care* (myself among them). -- You may redistribute this article only to those who may freely do likewise. -- Tom Neff UUCP: ...!uunet!bfmny0!tneff "Truisms aren't everything." Internet: tneff@bfmny0.UU.NET
m5@lynx.uucp (Mike McNally) (06/08/89)
In article <126@tridom.uucp> wht@tridom.uucp (Warren Tucker) writes: >Having programmed PL/M-86 and -186 for three years ... You see a lot of people like this lined up at Lourdes... >6. I haven't seen any C compiler produce such good code for >the Intel CPU. I think that this speaks ill of the Intel C compiler, rather than well of PL/M. Last time I looked at PL/M-86 (admittedly a long long time ago), the code it generated was OK but not spectacular. I feel also that a programmer is much more constrained in terms of source-level optimizations (particularly in the area of manipulation of data structures involving pointers). The claim made that PL/M switch statements are always branch table based is true, but of course that's easy when the case labels are *always* 0 through N. And of course, if the selector is out of range, the results are undefined (no such thing as default:). Structures within structures? Sorry. Two dimensional arrays? Sorry. Macros with arguments? Sorry. My guess is that GCC, well-tuned, would beat the pants off of PL/M. Of course, GCC doesn't generate object files compatible with LINK86. I don't want this to sound like an attack on PL/M; it's been used a lot and it's not all bad. The original request was for opinions, after all. -- Mike McNally Lynx Real-Time Systems uucp: {voder,athsys}!lynx!m5 phone: 408 370 2233 Where equal mind and contest equal, go.
maa@nbires.nbi.com (Mark Armbrust) (06/08/89)
In article <126@tridom.uucp> wht@tridom.uucp (Warren Tucker) writes: > >5. PL/M is inherently a strongly typed language. It is >very hard to screw up the number and type of parameters >supplied to a function, etc. This might be a good thing for >what you are trying to accomplish. Passing a variable >number of arguments to some function like printf is nice, >but having the facility all over the language is why >function prototyping and lint were invented. It's been a while since I've used PL/M, so I may not have the syntax quite right, but you can implement variable arguments by passing pointers: call Printf ("format string", @(arg1, arg2, etc)); The biggest thing I missed in PL/M is the pointer op "->". This op is available in PL/1 and I always wondered why it was dropped from PL/M. I wish I had a dime for every time I wrote: temp = dir$ptr; dir$ptr = some$other$ptr; (do something to dir) dir$ptr = temp; -- Mark Armbrust maa@nbires.nbi.com maa@nbires.UUCP
guy@auspex.auspex.com (Guy Harris) (06/09/89)
>Not wanting to make rash statements, I retested it. I'm right.
SunOS's PCC-based compiler for the 68K does the same for the "case"
statement you gave; however, if I added one more arm to the "switch",
with a "case" value of 3, it generated an indexed jump.
In the worst case, for the if/then/elseif/then... version (i.e., the
value is the last value against which you compare - assuming the value
is within range) of the 3-arm "switch", the indexed jump is better on a
68K. In the best case (i.e., the value is the first value against which
you compare), the indexed jump is *worse* on a 68K (you do one
comparison and one successful conditional jump). If the value is the
one in the middle, the indexed jump is *still* worse.
The numbers may be different for an 80*86, but there may still be a
turn-over point; below some number of comparisions, the
if/then/elseif/then... chain may be better, and above that number an
indexed jump may be better. If so, then if the number of cases in the
"switch" statement is small enough, assuming a reasonably even
distribution of the values "switch"ed on generating an
if/then/elseif/then... chain may be the right thing.
However, if you're switching amongst, say, 64 different values, it's
probably the wrong thing. Given that, I hope Intel's C compiler doesn't
*always* generate an if/then/elseif/then... chain for a "switch"
statement; if the switch statement is dense and has sufficiently many
arms, I would hope it would generate an indexed jump (I find it
difficult to imagine that an indexed jump would *never* be better).
Try a few more arms; if you make it up to, say, 32 arms, and it *still*
generates an if/then/elseif/then... chain, the compiler is probably
being dumb (but check the cycle counts anyway, just for fun...). If
there is an inflection point, check the cycle counts, etc. to see
whether an if/then/elseif/then... chain makes sense for a number of
arms below the inflection point. If so, perhaps the PL/M compiler is
the wrong one....
tneff@bfmny0.UUCP (Tom Neff) (06/09/89)
[Talking about jump tables versus elseif's for dense 'case' constructs.] In article <1782@auspex.auspex.com> guy@auspex.auspex.com (Guy Harris) writes: >Try a few more arms; if you make it up to, say, 32 arms, and it *still* >generates an if/then/elseif/then... chain, the compiler is probably >being dumb (but check the cycle counts anyway, just for fun...). If >there is an inflection point, check the cycle counts, etc. to see >whether an if/then/elseif/then... chain makes sense for a number of >arms below the inflection point. If so, perhaps the PL/M compiler is >the wrong one.... [Side note: in a separate posting I confirm that iC-x86 does change to a jump table at the "inflection point" of 6 or more cases. I had tried 3 and 5 before retesting and just plain missed it.] I would make the claim that in critical realtime code it's more important to have *consistent* code generation for things like 4- and 5- and 6- case state machines than it is to try and shave the extra cycle by using a completely different algorithm below (undocumented) N number of cases. That's the kind of thing that riseth up to smite the harried sysprog at JUST the wrong time, like when the boss screaming at you from an overseas conference room where Something Went Wrong. :-) The thing is, if you want an elseif construct you can always CODE ONE YOURSELF in any language. The whole point of DO CASE (PL/M) or switch (C) for dense case lists should be to use something different, i.e. a jump table. PL/M does this perforce because its DO CASE is like 'switch' without 'case' - each simple or compound statement within the DO CASE scope is assumed to handle the next integer value of the control expression starting at 0 -- thus: DO CASE state; ; /* case 0 - shouldn't happen */ DO; /* case 1 - do something */ masterflags.busy = TRUE; val = get$something(x, y, @status); CALL OUTWORD(that$port, val); state = 2; END; DO; /* case 2 - something else */ val = INWORD(this$port); CALL put$something(val, 0122H, @status); state = 3; END; DO; masterflags.busy = FALSE; state = 1; END; END; /* end case */ Thus in PL/M you have the responsibility for coding your own RANGE CHECKS in an example like the above. Let state = 5 and the above code branches off into never-never land. Unfortunately as you maintain a project and add new states to a machine there is no good automated way to compute MAX_STATE for range check purposes. I tend to put padding cases at the end of my DO CASE structures just in "case": ;;;;;;;;;;; /* insurance */ -- You may redistribute this article only to those who may freely do likewise. -- Tom Neff UUCP: ...!uunet!bfmny0!tneff "Truisms aren't everything." Internet: tneff@bfmny0.UU.NET
tneff@bfmny0.UUCP (Tom Neff) (06/09/89)
In article <4454@ficc.uu.net> karl@ficc.uu.net (karl lehenbauer) writes: > ... We do a lot of stuff that has to be >FORTRAN-callable, and *all* the parameters for a PL/M routine that's FORTRAN- >callable have to be pointers, so a lot of the benefits of data type checking >by the compiler are lost to us. This is not actually true. Intel FORT86 supports the %VAL construct as defined in F77, so you can say SUBROUTINE MYSUB(%VAL(X),%VAL(I),%VAL(J)) REAL*8 X INTEGER I,J ... END ... SUBROUTINE MAIN(RCODE) ... CALL MYSUB(%VAL(OURX),%VAL(2),%VAL(35)) ... and the stuff will get passed by value. If MYSUB or MAIN were in PL/M it would handle its end of the interface with pass-by-value. The one annoyance is LINK86's overzealous TYPDEF frenzy. If you pass %VAL(INTEGER*2) you had better declare your PL/M routine as expecting INTEGER not WORD or you'll get TYPE MISMATCH. For 32 bit quantities there's no escape, except by compiling one or both modules with $NOTYPE. As I point out in comp.realtime (hmm, sometimes crossposting IS a good idea <grin>), *nobody* does a good job of parameter type checking with Intel FORTRAN because it's all done at link time. Only FORTRAN-FORTRAN and C-C and PL/M-PL/M are guaranteed to give meaningful results on the TYPDEF level. (I think PASCAL-FORTRAN did OK the one time I checked. Lotta projects with THAT combo I'll bet! <grin>) So for interfacing with FORTRAN, C is no better a choice than PL/M -- UNLESS you work out an automated way of generating <fortstuff.h> extern declarations from parsing the FORTRAN source code, which seems like a good tool but a lot of work. -- You may redistribute this article only to those who may freely do likewise. -- Tom Neff UUCP: ...!uunet!bfmny0!tneff "Truisms aren't everything." Internet: tneff@bfmny0.UU.NET
tneff@bfmny0.UUCP (Tom Neff) (06/09/89)
In article <409@nbires.nbi.com> maa@nbires.UUCP (Mark Armbrust) writes: >It's been a while since I've used PL/M, so I may not have the syntax >quite right, but you can implement variable arguments by passing pointers: > >call Printf ("format string", @(arg1, arg2, etc)); Uh, no. Strings are passed by @address, and the only legal way to put things in a @(x, y, z...) container is if x and y and z are simple 8-bit constants. If you want to make an array or structure of pointers to various things you can do that, e.g., DECLARE plist (100) POINTER; ... plist(0) = @word1; plist(1) = @realval; plist(2) = @string1; plist(3) = NIL; CALL printf(@('W1 = %d, R1 = %f, S1 = %s', 0DH, 0AH, 0), @plist); you could do it, provided someone wrote a printf-style interpreter that could deal with it (you don't get one with PL/M). Someone put together a PL/M interface with the iC-86 1.0 (== awful Mark Williams C) RTL but it didn't strike me as very usable when I tried it out. -- You may redistribute this article only to those who may freely do likewise. -- Tom Neff UUCP: ...!uunet!bfmny0!tneff "Truisms aren't everything." Internet: tneff@bfmny0.UU.NET
tneff@bfmny0.UUCP (Tom Neff) (06/09/89)
In article <5711@lynx.UUCP> m5@lynx.UUCP (Mike McNally) writes: >The claim made that PL/M switch statements are always branch table >based is true, but of course that's easy when the case labels are >*always* 0 through N. And of course, if the selector is out of range, >the results are undefined (no such thing as default:). Structures >within structures? Sorry. Two dimensional arrays? Sorry. Macros >with arguments? Sorry. Truth Squad Dept.: * The original 'switch' claim had to do with iC, not PL/M, and the claim was that elseif was used when a jump table should have been. PL/M certainly uses jump tables on DO CASE -- this wasn't a claim, it's just a fact. * PL/M doesn't range check DO CASE for you automatically, it's your responsibility. This demands programmer responsibility but allows for extra speed in the case where the o/r *truly* "can't happen". * Structures within structures - available since PL/M 2.7 (1987). * 2-d arrays aren't available in the sense of A(i,j) but you have always been able to do this elegantly with structure arrays: DECLARE table (20) STRUCTURE( col (50) WORD); table(i).col(j) = x+y*5; Now with nested structures (for the last two years) you can generalize this to N-dimensional arrays if the mood strikes. * Macros with arguments are sadly missing from PL/M (all you get is the simple-replacement LITERALLY facility), however one is at liberty to preprocess PL/M source with either MPL86 or (now) the iC-x86 preprocessor before compiling. In fact I suspect the latter will become popular - you can have all the #defines you want and still get valid PL/M to compile. I use MPL86 based "macro PL/M" for a number of projects - it's the best way to automatically generate count precedent string constants, for instance. -- You may redistribute this article only to those who may freely do likewise. -- Tom Neff UUCP: ...!uunet!bfmny0!tneff "Truisms aren't everything." Internet: tneff@bfmny0.UU.NET
peter@ficc.uu.net (Peter da Silva) (06/09/89)
One more point to make before I leave this particular subject. The PL/M do-case construct is a ripe source of bugs: In article <14391@bfmny0.UUCP>, tneff@bfmny0.UUCP (Tom Neff) writes: [explanation of do-case] > I tend to put padding cases at the end of my DO CASE structures just in > "case": > ;;;;;;;;;;; /* insurance */ I rest my case. -- Peter da Silva, Xenix Support, Ferranti International Controls Corporation. Business: uunet.uu.net!ficc!peter, peter@ficc.uu.net, +1 713 274 5180. Personal: ...!texbell!sugar!peter, peter@sugar.hackercorp.com.
vjs@calcite.UUCP (Vernon Schryver) (06/11/89)
In article <5711@lynx.UUCP>, m5@lynx.uucp (Mike McNally) writes: > > ... Last time I looked at PL/M-86 (admittedly a long long > time ago), the code it generated was OK but not spectacular. ... I first saw PL/M-86 as part of MDS-311, in 1978. By 1981, it was ok and reasonably bug free. The current PL/M-386, version 1.3, generates what looks like the same stuff, modified for the 386. Today, it is not comparable to the output of a good C compiler (not pcc). I try to limit looks at the result of '$CODE', because it always makes me want to chuck it and write in ASMx86, regardless of whether it is worthwhile. Current C compilers rarely do that to me. If I had to use BND386 and BLD386, perhaps to use ICE386, I would stick with PL/M. From the manuals, C386 is a new idea at INTEL. There are lots of caveats about C calling sequences, externals vs. common, and so on. Some day, one can expect C386 to be preferred to PL/M. However, unless you work for INTEL, other frontiers look more profitable to pioneer. Recalling my stack of PTR's on early PL/M-86, I took my own advice, and so do not have first hand experience with C386. No one has mentioned INTEL's new policy on their binary format. They treat their relocatable binary format as a top trade secret. In the old 8086 days, it was proprietary, but with enough non-disclosures, they they would tell you about it. This year, I've been told by F.E.'s that even the absolute format is secret, though some of it is documented in the 1.3 manuals. The official policy handed out from the Oregon hotline seems to be that one does not need any PROM programmer, system debugger, or operating system that is not suppied by INTEL. If you do not like that, there is the new HEX386. I guess RMX386 is finally good enough for all possible purposes, and we should look for it to replace AIX as the be all and end all. Vernon Schryver vjs@calcite.uucp
m5@lynx.uucp (Mike McNally) (06/13/89)
In article <14395@bfmny0.UUCP> tneff@bfmny0.UUCP (Tom Neff) writes: >In article <5711@lynx.UUCP> m5@lynx.UUCP (Mike McNally) writes: >> [ things about PL/M, not entirely positive ] > >Truth Squad Dept.: > > [ corrections to some of my claims ] Point taken. I did say that it's been a while since I used PL/M; I know that 2.7 sounds like a kinda big version number. I think a lot of the bad emotional feelings I have about PL/M stem from having to use it on an old System III ("Blue Box") development system with 8" diskette drives. I t w a s v e r y s l o w . I can't say I ever got too fond of ISIS either. If I had PL/M available under UNIX or something, I'd probably not mind using it at all. -- Mike McNally Lynx Real-Time Systems uucp: {voder,athsys}!lynx!m5 phone: 408 370 2233 Where equal mind and contest equal, go.
tneff@bfmny0.UUCP (Tom Neff) (06/14/89)
In article <5732@lynx.UUCP> m5@lynx.UUCP (Mike McNally) writes: >I think a lot of the bad emotional feelings I have about PL/M stem from >having to use it on an old System III ("Blue Box") development system >with 8" diskette drives. I t w a s v e r y s l o w . >I can't say I ever got too fond of ISIS either. If I had PL/M available >under UNIX or something, I'd probably not mind using it at all. ISIS was certainly disgusting. The MDS was a ridiculous tower of iron, but it's brought a lot of embedded controllers to life! PL/M is currently platformed to iRMX I and II, VAX/VMS, MS-DOS and (via the iRMK386 Developers' Kit) to UNIX/386. The latter port requires a kernel hack which was developed for Bell Tech's port and may or may not work with other AT&T derived 386 UNIXen. (Certainly not with Xenix or AIX or whatever.) -- You may redistribute this article only to those who may freely do likewise. -- Tom Neff UUCP: ...!uunet!bfmny0!tneff "Truisms aren't everything." Internet: tneff@bfmny0.UU.NET
peter@ficc.uu.net (Peter da Silva) (06/14/89)
In article <14395@bfmny0.UUCP>, tneff@bfmny0.UUCP (Tom Neff) writes: > * PL/M doesn't range check DO CASE for you automatically, it's your > responsibility. This demands programmer responsibility but allows > for extra speed in the case where the o/r *truly* "can't happen". Come one, Tom. You're usually right on, but it's not fair to tout the PL/M case statement as a benefit over C's switch statement after you've already admitted that PL/M's case statement is badly flawed. -- Peter da Silva, Xenix Support, Ferranti International Controls Corporation. Business: uunet.uu.net!ficc!peter, peter@ficc.uu.net, +1 713 274 5180. Personal: ...!texbell!sugar!peter, peter@sugar.hackercorp.com.
alfred@guardian.UUCP (alfred) (06/15/89)
> It's been a while since I've used PL/M, so I may not have the syntax > quite right, but you can implement variable arguments by passing pointers: > > call Printf ("format string", @(arg1, arg2, etc)); For your information, you no longer need to do that with PL/M-n86 V3.3, under this version, you can call any C-interfaced function with variable parameters (similar to ANSI-C function prototype with ellipses): $interface (C=printf) foo: do; printf: procedure (p) external; declare p pointer; end; proc: procedure (a,b) public; declare (a,b) word; call printf(@('A = %d, B = %d'), a, b); /* LEGAL NOW */ end; end; In this case, type checking will be carried out for the first argument only, extra arguments in the actual call will not be checked. The extreme case will be declaring a C external function with no argument, then you can call that function with any number of parameter.
alfred@guardian.UUCP (alfred) (06/15/89)
> >I sincerely hope Intel's C compiler does not do so for *all* "switch" > >statements; any competent C compiler can and will turn a "dense" > >"switch" statement - i.e., one where the cases form a reasonably tight > >range - into an indexded jump. (The definition of "dense" varies from > >compiler to compiler.) Intel iC-n86 compilers are capable of generating three different kind of code for the "switch" statement. Normally, we generate simple if-then-else code for a dense switch statement with less than six cases, above that an indexed jump will be generated. Moreover, we generate binary search code for those sparsely dense switch statements. And in conformance to ANSI, 32-bit "long" data type can be used as case values.
mac@uvacs.cs.Virginia.EDU (Alex Colvin) (06/20/89)
I had limited experience with PLM on iRMX86. I've used iNtel's old iC86 on iRMX and Turbo C on DOS. PLM does a nice job in the code generation department. A construct such as: call Fred(); do while (UnDone); call Fred(); end; has the branches rearranged into RepeatL: call Fred(); if (UnDone) goto RepeatL; thereby overcoming some if the inexpressiveness of PLM. iC86, by contrast, has a naive code generator. This isn't normally a problem, unless you're really tight on microseconds. Since it's not an ANSI C compiler, it doesn't give you a lot of control over parameter passing (you keep generating code to widen char to int), signed-ness, etc. The libraries are pretty antiquated. I was trying to maintain compatible sources for a network controller across the two systems. The differrence between PC-bus and Multibus was handled by linking in different libraries. The big problems were incompatibilities in C language & (non-)standard libraries. PLM isn't compatible with anything else, so this won't bother you. It's related to PL/I only in syntax. Their implementation of BASED storage ties data structures to a particular pointer, making it hard to write reentrant code. You wind up having to re-declare your structures all over the place, making the code hard to maintain. Macros are a clumsy way to get around this. At least C permits you to re-use a STRUCT declaration. PLM does give you access to selectors (tokens) and other peculiarities of the architecture and OS, where C will require lots of casting. PLM has argument type checking, where iC86 doesn't. PL/M pointers are totally untyped, where iC86 will cast. If the rumor of an ANSI-type C compiler is true, I'd recommend that. The (optional) stronger typing is likely to save you a lot of headaches. You stand a greater chance of stealing code from other applications.
nusip@maccs.McMaster.CA (Mike Borza) (06/21/89)
In article <231@guardian.UUCP> alfred@.UUCP (Alfred Huang) writes: >Intel iC-n86 compilers are capable of generating three different kind of >code for the "switch" statement. Normally, we generate simple if-then-else Great. Was this compiler written by the same bozos who wrote the MS-DOS C cross-compiler for the '196? That one gracefully generates syntax errors for `unsigned int foo();' within function bodies. It fares better for `unsigned int bar;' within a function; it saves its errors for incorrect code generation, conveniently throwing away the desired result of an assignment and saving garbage instead. Beauty, eh? mike borza, Antel Optronics Inc. -- Michael Borza work: <antel!mike@maccs.McMaster.CA> Antel Optronics Inc. home: <boopsy!mike@maccs.McMaster.CA> (416)335-5507 occasionally: <nusip@maccs.McMaster.CA> 3325B Mainway, Burlington, Ont., Canada L7M 1A6
tneff@bfmny0.UUCP (Tom Neff) (06/28/89)
In article <190@uvacs.cs.Virginia.EDU> mac@uvacs.cs.Virginia.EDU (Alex Colvin) writes: >PLM does a nice job in the code generation department... >iC86, by contrast, has a naive code generator. This isn't normally a >problem, unless you're really tight on microseconds. Since it's not an >ANSI C compiler, it doesn't give you a lot of control over parameter >passing (you keep generating code to widen char to int), signed-ness, etc. >The libraries are pretty antiquated. Once again, since a lot of people seem to be unaware of this: The iC86 Alex is talking about is the bad, old Mark Williams-derived unusable atrocity. (Versions 3.1 and earlier.) The shiny, new iC86 4.0, out for well over a year now, is no relation! Intel wrote a dpANS compatible front end and hitched it to the good PL/M code generator Alex alludes to above. The libraries are fine, and available in all memory models. You even have builtins available (optionally) for hardware specific things like OUT and MOVB, so you can use iC86 to write high performance embedded stuff. The code is ROMable and interfaces well with the other Intel languages - PL/M, ASMx86 of course, Pascal, Fortran. Remember, old C bad, new C good. -- You may not redistribute this article for profit without written permission. -- Tom Neff UUCP: ...!uunet!bfmny0!tneff "Truisms aren't everything." Internet: tneff@bfmny0.UU.NET
clay@uci.UUCP (News Administrator) (07/06/89)
I have actually used the latest (as of Fall, '88) version of Intel C with a specific eye towards reasonable code and PL/M compatibility. I was pleased to see both. This is version 3.x (maybe 4.x, I can't remember). This was NOT the original hack job that was too awful for words. With regards to PL/M compatibility, there is no way to say "SELECTOR" in C such that LINK86 will not complain of type mismatches with PL/M modules, but the code works fine. Generated code looks very much like that of PL/M, the default parameter-passing mechanism is "fixed param" which is like MSC "pascal". Interrupt procedures work just like PL/M. Now don't send flames to me if you don't like PL/M's code I'm just saying it looks similar if not identical! The debugger that I Beta -tested looks like Intel licenced it from the same place Microsquishy got Codeview. Seemed to work OK for simple things -- I didn't have a lot of time to work with it, as I was doing an embedded system, not DOS. This work was done when employed by Intercim Corp. in Burnsville, MN. I will forward email to them, as they are not quit on the net yet. -- Clayton Haapala ...!mmm!dicome!uci!clay Unified Communications Inc. "Declare your Point of Entry, Space Wanderer!" 3001 Metro Drive - Suite 500 "Canarsi -- where everyone looks the same." Bloomington, MN 55425 -- zappa
tneff@bfmny0.UUCP (Tom Neff) (07/07/89)
In article <95@uci.UUCP> clay@uci.UUCP (News Administrator) writes: >I have actually used the latest (as of Fall, '88) version of Intel C with >a specific eye towards reasonable code and PL/M compatibility. I was pleased >to see both. This is version 3.x (maybe 4.x, I can't remember). This was NOT >the original hack job that was too awful for words. Definitely 4.0 or 4.1. Anything from Intel marked 3.1 or earlier is the Mark Williams C hack job, which was an atrocity. (Parenthetically (he says, in parentheses (hehe)), I want readers of this newsgroup to know that although I know a lot about Intel products and will defend them against ignorant slanders, I also give Intel unmerciful heat about their shortcomings. Ask any Intel FAE who's had to deal with "Neff" at one time or another. [:-)] ) >With regards to PL/M compatibility, there is no way to say "SELECTOR" in C such >that LINK86 will not complain of type mismatches with PL/M modules, but the >code works fine. This is a case where you have to either compile with NOTYPE or eat the type mismatch with a smile. I might add that LINK86 v2.7 hemorrhages TMM's compared to 2.5. If you have ever delved into the Byzantine workings of OMF-86 and tried to figure out TYPDEF records you will see that there about 850 ways to interpret any pair of candidate PUBDEF/EXTDEF symbols in terms of how they express their applicable types. 2.7 seems stricter, and in the cross language world that's a disaster. I make it a habit to strip TYPDEF's before linking cross language jobs. It just ain't worth it - the few legitimate mismatches you might catch are inundated in the bogus ones. >Generated code looks very much like that of PL/M, the default parameter-passing >mechanism is "fixed param" which is like MSC "pascal". I have my qualms about this decision on Intel's part. They support two parameter passing conventions in iC-x86: "varparams," corresponding to the traditional C implementation on 86 architectures, wherein the caller pushes all arguments onto the stack in reverse order, then a count, then calls the subprogram, then cleans up the stack itself; and "fixparams," corresponding to the way PL/M-86, FORTRAN-86 and Pascal-86 work, wherein the caller pushes all arguments on the stack in forward order, then calls the subprogram which is expected to agree on the number and type of arguments and perform its own stack cleanup on return with the RET <NN> 86 opcode. The latter method is faster for the majority of cases where in fact the caller and callee expect a fixed list of parameters. The former method is slower to deal with but permits variable parameter lists a la "printf". Intel iC-x86 allows functions to be declared/defined with one or another parameter passing convention via a #pragma (functions of either convention may be mixed within a program); so far so good. What I don't like is that Intel has lately selected "fixedparams" as the DEFAULT convention unless you specifically override. That makes me a bit queasy. I doubt Doug Gwyn reads this newsgroup but if he does I bet it would make him a bit queasy too. -- "My God, Thiokol, when do you \\ Tom Neff want me to launch -- next April?" \\ uunet!bfmny0!tneff
peter@guardian.UUCP (peter) (07/11/89)
In article <95@uci.UUCP> clay@uci.UUCP (News Administrator) writes: > >I have actually used the latest (as of Fall, '88) version of Intel C with >a specific eye towards reasonable code and PL/M compatibility. I was pleased >to see both. This is version 3.x (maybe 4.x, I can't remember). This was NOT >the original hack job that was too awful for words. That was iC-86 V4.0. >With regards to PL/M compatibility, there is no way to say "SELECTOR" in C such >that LINK86 will not complain of type mismatches with PL/M modules, but the iC-86 V4.1 includes the "selector" data type, which is compatibile with the PL/M selector. iC-86 V4.1 is available on DOS now, on iRMX(tm) I (aka iRMX-86) in 3-4 weeks. iC-286 V4.1 is also available on DOS now, on iRMX II (aka iRMX 286) in 3-4 weeks. People who suffered through the V3.x compilers on iRMX can upgrade to V4.1 free of charge! >code works fine. > On this matter, I _DO_ speak for Intel! ------------------------------------------------------------------------------- Peter Plamondon, Intel Corp, 5200 NE Elam Young Pkwy, Hillsboro, OR 97124-6497 Internet: peter@langlab1.hf.intel.com +1 503-696-5219 UUNET : uunet!intelhf!langlab1!peter "I speak for myself, as best I can." UUCP : tektronix!psu-cs!foobar!langlab1.hf.intel.com!peter -------------------------------------------------------------------------------
vjs@calcite.UUCP (Vernon Schryver) (07/12/89)
There has been some discussion about PLM386 vs. C in this newsgroup. Some have said that PLM386 does a reasonable job, and so does C. Tonight, I've had occassion to look at the output of PLM386 with optimize(3). It is ugly. If iC386 is as bad, then one would be wise to talk to Motorola, AMD, MIPS, or the SPARK clones. It appears that in the 8 years since I stared closely at large gobs of PL/M86 output, INTEL has not improved the "optimizer". They still do not know the relevance of "peep hole." Because I wish to share my disgust, included below is a small function, and PLM386's best effort. The function is not coded wonderfully, but that is no excuse for the slop the compiler emits. This is a small chunk of a disgustingly large file, from the days when it had to be compiled "large" and multiple files meant extra segment register usage and lots more code, and it had to fit in 2716's The lower case text in the code output are my comments. $code 1192 1 hex$arith: procedure reentrant; 1193 2 declare ptr pointer; 1194 2 call read$char; 1195 2 call get$addr(@ptr,selector(0)); /* takes ptr&selector */ 1196 2 call put$string(@(' = ',0)); /* takes a ptr */ 1197 2 call put$ptr(ptr,0); /* takes ptr */ 1198 2 if selector(ptr)<>data_seg /* a selector */ 1199 2 then do; /* '&&' would be nice */ 1200 3 if not ck$ptr(ptr,1) /* takes ptr & word */ 1201 3 then do; 1202 4 call put$word(flatten(ptr),0); 1203 4 call put$string(@(' base=',0)); 1204 4 call put$word(flatten(build$ptr(selector(ptr),0)),0); 1205 4 call put$string(@(' limit=',0)); 1206 4 call put$word(get$segment$limit(selector(ptr)),0); 1207 4 end; 1208 3 end; 1209 2 end hex$arith; $nocode ; STATEMENT # 1192 HEXARITH PROC NEAR 000028DC 55 PUSH EBP 000028DD 8BEC MOV EBP,ESP 000028DF 51 PUSH ECX ? dense but slow since it 000028E0 51 PUSH ECX ? makes extra memory traffic ? why not ENTER 8 ? ; STATEMENT # 1194 000028E1 E8F6DFFFFF CALL READCHAR ; STATEMENT # 1195 000028E6 8D45FA LEA EAX,[EBP].PTR 000028E9 16 PUSH SS ; 1 000028EA 50 PUSH EAX ; 2 000028EB B800000000 MOV EAX,0H ? what's wrong with XOR EAX,EAX ? 2 bytes instead of 5 000028F0 50 PUSH EAX ; 3 ? what's wrong with PUSH 0? 000028F1 E856E8FFFF CALL GETADDR ; STATEMENT # 1196 000028F6 B8C5020000 MOV EAX,OFFSET(@@LONG$CONSTANT$02C5H) 000028FB 0E PUSH CS ; 1 000028FC 50 PUSH EAX ; 2 000028FD 0E PUSH CS ? what's wrong with long calls? 000028FE E815E2FFFF CALL PUTSTRING ; STATEMENT # 1197 00002903 FF75FE PUSH [EBP].PTR+4H; 1 00002906 FF75FA PUSH [EBP].PTR; 2 00002909 6A00 PUSH 0H !see, it knows about PUSH 0 0000290B E8B4E1FFFF CALL PUTPTR ; STATEMENT # 1198 00002910 668B55FE MOV DX,[EBP].PTR+4H 00002914 8B45FA MOV EAX,[EBP].PTR ?why? Completely dead!? 00002917 662E3B1500000000CMP DX,CS:DATA_SEG ?why not CMP [EBP].PTR.. 0000291F 7467 JZ @284 ; STATEMENT # 1200 00002921 FF75FE PUSH [EBP].PTR+4H; 1 00002924 FF75FA PUSH [EBP].PTR; 2 00002927 6A01 PUSH 1H 00002929 E852E6FFFF CALL CKPTR 0000292E A801 TEST AL,1H 00002930 7556 JNZ @284 ; STATEMENT # 1202 00002932 FF75FE PUSH [EBP].PTR+4H; 1 00002935 FF75FA PUSH [EBP].PTR; 2 00002938 0E PUSH CS ?why not a far call 00002939 E800000000 CALL FLATTEN 0000293E 50 PUSH EAX ; 1 0000293F 6A00 PUSH 0H 00002941 E85EE1FFFF CALL PUTWORD ; STATEMENT # 1203 00002946 B8C9020000 MOV EAX,OFFSET(@@LONG$CONSTANT$02C9H) 0000294B 0E PUSH CS ; 1 0000294C 50 PUSH EAX ; 2 0000294D 0E PUSH CS 0000294E E8C5E1FFFF CALL PUTSTRING ; STATEMENT # 1204 00002953 668B45FE MOV AX,[EBP].PTR+4H ?why not PUSH [EBP].... 00002957 B900000000 MOV ECX,0H ?why not PUSH 0 ? 0000295C 50 PUSH EAX ; 1 0000295D 51 PUSH ECX ; 2 0000295E 0E PUSH CS 0000295F E800000000 CALL FLATTEN 00002964 50 PUSH EAX ; 1 00002965 6A00 PUSH 0H 00002967 E838E1FFFF CALL PUTWORD ; STATEMENT # 1205 0000296C B8D0020000 MOV EAX,OFFSET(@@LONG$CONSTANT$02D0H) 00002971 0E PUSH CS ; 1 00002972 50 PUSH EAX ; 2 00002973 0E PUSH CS 00002974 E89FE1FFFF CALL PUTSTRING ; STATEMENT # 1206 00002979 668B45FE MOV AX,[EBP].PTR+4H 0000297D 0F03C0 LSL EAX,EAX 00002980 50 PUSH EAX ; 1 00002981 6A00 PUSH 0H 00002983 E81CE1FFFF CALL PUTWORD ; STATEMENT # 1208 ; STATEMENT # 1209 @284: 00002988 C9 LEAVE 00002989 C3 RET HEXARITH ENDP Vernon Schryver vjs@calcite.uucp