franka@mmintl.UUCP (Frank Adams) (01/01/70)
In article <14039@topaz.rutgers.edu> ron@topaz.rutgers.edu (Ron Natalie) writes: >> I must disagree. The default compiler settings should cater neither to >> professionals porting code, nor to professionals doing local development, >> but to the occasional or novice programmer, who is trying to get his newly >> written, probably small, program to run. > >And I must disagree with you ... The default action for the compiler should >be to ACT NORMALLY. In most cases, this is sufficient. But consider the issue of memory models for the 8086. (Yes, I hate the '86, too; but that doesn't make it go away.) The novice probably wants the small model. The pro most likely doesn't. In this case, the novice should be catered to. (Anyone doing serious development on an 8086 has to think about segments and probably make changes to their code to take them into account. Large model runs too slowly, and small model isn't big enough. This is what is wrong with the 8086 architecture -- high level language programmers shouldn't have to be concerned about such things.) ------------------------------------------------------------ I am going on vacation. I am unlikely to see any followups posted to this message, so please mail me copies of any responses. Unless they are marked otherwise, I will assume that any replies to this message are intended for public consumption. -- Frank Adams ihnp4!philabs!pwa-b!mmintl!franka Ashton-Tate 52 Oakland Ave North E. Hartford, CT 06108
hrubin@osupyr.UUCP (05/10/87)
In article <734@sdchema.sdchem.UUCP>, tps@sdchem.UUCP (Tom Stockfisch) writes: > In article <7264@brl-adm.ARPA> lyle@ads.arpa (Lyle Bacon) writes: > > > C is an evolving language. I will make a possibly sacrilegious > >suggestion that the type "complex" be incorporated. > > The purest says:" Well, one can just define a structure complex." > > ...However, the resultant code form using structures and func- > >tions is much less readable and harder to check.... > >P = complex_mult(A, complex_mult(B, C)); > > > >P = A * B * C; > >is more easily read and checked. > > > This only solves the problem for the type "complex". What about vectors > and matrices and (use your imagination)? What we people who can program using the power of the computer really need to do is convince the X3J11 committee to accept the idea that overloaded operators, defining of new types (not like C++), defining of operator symbols corresponding to operations not included in the default language, forcing inline, substitution of compiler-determined locations in inserted assembler instructions, and other versatile devices, and in general enabling the production of good semi-portable code is worthwhile. -- Herman Rubin Until mid May: Department of Statistics, Cockins Hall, 1958 Neil Avenue Ohio State University, Columbus OH43210 hrubin@osupyr or cbosgd!osu-eddie!osupyr!hrubin or ts0474@ohstvma.bitnet "Permanent": Department of Statistics, Purdue University, West Lafayette IN47907 hrubin@l.cc.purdue.edu or ihnp4!pur-ee!stat-l!hrubin or hrubin@purccvm.bitnet
guy@gorodish.UUCP (05/12/87)
> > This only solves the problem for the type "complex". What about vectors > > and matrices and (use your imagination)? > > What we people who can program using the power of the computer really need > to do is convince the X3J11 committee to accept the idea that overloaded > operators, defining of new types (not like C++), defining of operator > symbols corresponding to operations not included in the default language, > forcing inline, substitution of compiler-determined locations in inserted > assembler instructions, and other versatile devices, and in general enabling > the production of good semi-portable code is worthwhile. Good luck. I suspect you'll need it. 1) Why is it worthwhile to throw all this stuff into C *now*? One thing to note - the more stuff you throw into ANSI C, the longer it'll take to see ANSI C implementations, and the longer you'll have to wait for all these whizzy features. 2) Why is "defining of new types" followed by "(not like C++)"? 3) Why is "defining of operator symbols corresponding to operations not included in the default language" worth the cost of adding this? It is a relatively uncommon feature in programming languages, and can complicate the parsing of a language. 4) What does "enabling the production of good semi-portable code" mean? What is the significance of "semi" in "semi-portable"? Why do features like overloading of operators "enable the production of good semi-portable code", as opposed to the production of code in general, or portable code, or whatever? 5) What does "program using the power of the computer" mean? It sounds like a buzzphrase to me. Plenty of people who don't think C should grow without bounds are quite capable of writing efficient and portable (and "semi-portable") code. This looks more like a Christmas list than a practical proposal for additions to C. The purpose of a standards effort is *not* to stuff every feature that somebody thought they needed, or at least wanted, into the item being standardized. (To quote Dennis Ritchie - "If you want PL/I, you know where to find it.") The language that has every feature you want doesn't exist, and probably *can't* exist; there are always tradeoffs, and some features that might seem really nice just cost too much. As for "Big changes are needed", well, I shall merely point out that a LOT of software has been written in C, and is being written in C, for a host of applications. I see no reason to believe that this flow of applications will diminish to a trickle shortly unless this shopping list of features is added to the language. (In fact, enough features added to the language could *itself* diminish the flow of applications, if it complicates the language or its implementations to the point that the language is no longer a good choice for the applications for which it is currently being used.)
leder@ihlpm.UUCP (05/13/87)
In article <18598@sun.uucp>, guy%gorodish@Sun.COM (Guy Harris) writes: > > > > What we people who can program ... really need > > to do is convince the X3J11 committee to accept the idea ... > > the production of good semi-portable code is worthwhile. I think that your words taken completely out of context provides more insight that within the context that they were used. > 1) Why is it worthwhile to throw all this stuff into C...? If you don't like the language, why not invent a new one? And that is what this author procedes to do. Why don't we have two languages: slim C and fat C With a few exceptions, the committee has done an admiral job of giving us a very slightly overweight "slim C". To get to "fat C" we could start with C++ and add ADA, inline FORTH, with extensions for COBOL and PASCAL, and maybe just a sprinkling of anything else someone can think of. In fact the compiler should be self-modifyable and extenable just in case we left anything out. This should ruin any hopes of portability because everyone will be speaking a different language unless the extensions are built into the source code or output into a special file that can be moved with the code so that it becomes a base point for the compiler on the new machine. It is dangerous when these things start to make sense, so I think I will stop now. > This looks more like a Christmas list than a practical proposal... > The language that has every feature you want doesn't exist ... > features added ... could ... diminish the flow of applications ... > to the point that the language is no longer a good choice for the > applications for which it is currently being used. This is why 'slim C' is for you and me. Bob Leder - making a nusiance of myself
henry@utzoo.UUCP (Henry Spencer) (05/14/87)
> What we people who can program using the power of the computer really need > to do is convince the X3J11 committee to accept the idea that overloaded > operators, defining of new types (not like C++), defining of operator > symbols corresponding to operations not included in the default language, > forcing inline, substitution of compiler-determined locations in inserted > assembler instructions, and other versatile devices, and in general enabling > the production of good semi-portable code is worthwhile. Hmm, don't want much, do you? I suspect that you could easily succeed in convincing X3J11 that these are interesting and useful ideas if done well. However, I doubt that you could convince them that (a) there is extensive real experience with these features in C, (b) their implementation is well understood (defining new symbols is a particular minefield), (c) there is a crying need for these facilities, or (d) they are not such drastic changes that they constitute definition of a new language. If you want to define a new language with all these goodies, go ahead. But this sure doesn't sound like C, and C is what X3J11 is standardizing. -- "The average nutritional value Henry Spencer @ U of Toronto Zoology of promises is roughly zero." {allegra,ihnp4,decvax,pyramid}!utzoo!henry
stuart@bms-at.UUCP (05/16/87)
The only way new features are going to make 'C' better is if they are consequences of simplification. E.g. The 'D' language where all operators are defined at compile time. (A default definition file is included for compatibility.) This makes the compiler smaller (but slower) while adding overloaded operators and then some (like supporting your favorite processor features not in 'C'). One reason that current operators are fixed is to improve compiler performance (you don't have to interpret the machine templates for operators at every compile). With the next generation of CPU's, an approach like this may be practical. For now, let's not let creeping featurism turn 'C' into an electronic beaurocracy. Overloaded operators is better than adding just the complex type, but it still doesn't measure up to standards of elegance. (Mine anyway.) We need new concepts, not new features. NOTE, the best question to ask is not "What features can we add" but, "What features are absolutely essential and what can be taken away? Does a feature have a fundamental basis, or is it arbitrary and a candidate for user definition?" -- Stuart D. Gathman <..!seismo!dgis!bms-at!stuart>
gwyn@brl-smoke.ARPA (Doug Gwyn ) (05/17/87)
In article <393@bms-at.UUCP> stuart@bms-at.UUCP (Stuart D. Gathman) writes:
-NOTE, the best question to ask is not
- "What features can we add"
-but,
- "What features are absolutely essential and what can
- be taken away? Does a feature have a fundamental basis,
- or is it arbitrary and a candidate for user definition?"
There is a rumor that at one point in the evolution of (Research)
UNIX, nobody was allowed to add a feature to the system without
simultaneously identifying one he could remove. I don't know if
this is true, but it makes a good story.
cik@l.cc.purdue.edu.UUCP (05/20/87)
In article <8024@utzoo.UUCP>, henry@utzoo.UUCP (Henry Spencer) writes: > But this sure doesn't sound like C, and C is what X3J11 is standardizing. Okay, let me stick to nasty problems with C. 1. Have the compiler substitute locations in -asm- statements. Other than editing the assembler output, I do not believe there is any way to insert asm statements which can be expected to survive a change from one compiler to another. 2. Require that the compiler honor, whenever possible, assignments to registers. ^^^^^^^^ 3. Allow the programmer to force non-promotion of floating to double, whenever the programmer feels there is a good reason to do this. I know when there is no point in using double; the compiler cannot. Also, on some machines, one cannot print out a floating number in hex. (Okay, I can finagle it. But I had an occasion where this would have been a problem. I edited the assembler code, as the easiest option.) 4. Allow floating point numbers to be given in hex. Try putting in 2^-32 as a floating point or double constant. Why should one have to risk computer roundoff when it is totally unnecessary? 5. Require that the compiler honor parentheses. When I want a subroutine to return (x - y - k*c) + f(y), I most emphatically do not want the compiler to do the "obvious" rearrangement to combine the two terms with y; this can be a major loss of accuracy. To set a variable equal to the parenthetical expression is a significant loss of time. -- Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907 Phone: (317)494-6054 hrubin@l.cc.purdue.edu or pur-ee!stat-l!cik or hrubin@purccvm.bitnet
guy%gorodish@Sun.COM (Guy Harris) (05/22/87)
> 1. Have the compiler substitute locations in -asm- statements. > Other than editing the assembler output, I do not believe there > is any way to insert asm statements which can be expected to > survive a change from one compiler to another. This isn't a C language *specification* issue. This is a C *implementation* issue. Some implementations, such as the AT&T WE32K series implementation, support this. It's not clear that a language specification can include something like this, since the specifiers generally can't predict in advance what sort of machines the language will be implemented on. > 3. Allow the programmer to force non-promotion of floating to double, > whenever the programmer feels there is a good reason to do this. Go read the ANSI C draft standard; it no longer requires floating point arithmetic to be done in double precision. > 4. Allow floating point numbers to be given in hex. Try putting in > 2^-32 as a floating point or double constant. Why should one have to > risk computer roundoff when it is totally unnecessary? If you really must do this, you can do it with a union. (Yes, this may be inconvenient. Life is full of little inconveniences.) > 5. Require that the compiler honor parentheses. When I want a > subroutine to return (x - y - k*c) + f(y), I most emphatically do > not want the compiler to do the "obvious" rearrangement to combine > the two terms with y; this can be a major loss of accuracy. No! When a system programmer writes some expression involving several macros, all of which perform arithmetic on their arguments, and some subset of those arguments are constant, they most emphatically want the compiler to do as much of the computation at compile time as possible, even if this means rearranging the expression. Perhaps the rules for rearrangement should be different for integral and floating-point operations, but it would be a serious mistake to change C for the benefit of people doing heavy floating-point computation if that makes it handle integer and pointer arithmetic less efficiently. Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com
edw@ius2.cs.cmu.edu (Eddie Wyatt) (05/22/87)
In article <533@l.cc.purdue.edu>, cik@l.cc.purdue.edu (Herman Rubin) writes: > In article <8024@utzoo.UUCP>, henry@utzoo.UUCP (Henry Spencer) writes: > > But this sure doesn't sound like C, and C is what X3J11 is standardizing. > > Okay, let me stick to nasty problems with C. > > 1. Have the compiler substitute locations in -asm- statements. > Other than editing the assembler output, I do not believe there > is any way to insert asm statements which can be expected to > survive a change from one compiler to another. I have no idea what you are talking about. The asm statement allows you to insert assemble code into your C program, what is the problem you are having with this? > > 2. Require that the compiler honor, whenever possible, assignments > to registers. ^^^^^^^^ Is this really a problem? Maybe I've been luckly, but when I ask for a register I get it provided I haven't used them all yet. > > 3. Allow the programmer to force non-promotion of floating to double, > whenever the programmer feels there is a good reason to do this. > I know when there is no point in using double; the compiler cannot. > Also, on some machines, one cannot print out a floating number in hex. > (Okay, I can finagle it. But I had an occasion where this would have > been a problem. I edited the assembler code, as the easiest option.) But heres the problem - floatfunc(3.0), should 3.0 be pass as a float or a double? To complicate matters, say floatfunc is external. Function prototypes may take care of this though. How about this to solve your problem. typedef union { float fnum; int inum; } floatint; floatint num; num.fnum = 4.5; printf("%x\n",num.inum); which brings up - guess my bug: static void BBfwrite (val) float val; { write_out_msg_buffer((char *) &val,sizeof(float)); } The problem here is fixed now. > > 4. Allow floating point numbers to be given in hex. Try putting in > 2^-32 as a floating point or double constant. Why should one have to > risk computer roundoff when it is totally unnecessary? Some people have noted that this might be a niece feature, I forget what if any problems there are with this. > > 5. Require that the compiler honor parentheses. When I want a > subroutine to return (x - y - k*c) + f(y), I most emphatically do > not want the compiler to do the "obvious" rearrangement to combine > the two terms with y; this can be a major loss of accuracy. To set > a variable equal to the parenthetical expression is a significant > loss of time. What two terms with y? I hope my C compiler doesn't think y can be factor out of that expression to form (f-1)(y) :-). To address your real complaint, the ANSI standard plans on supporting parenthesis honoring through the use of the unary +. +(x - y) + y will be evaluated as it appears. If you don't like the unary + put it into a define statement say: #define HONOR(x) +(x) Please lets not get into a long philosophic debate over this we have seen it all before. If you don't like it, use another language. > -- > Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907 > Phone: (317)494-6054 > hrubin@l.cc.purdue.edu or pur-ee!stat-l!cik or hrubin@purccvm.bitnet -- Eddie Wyatt e-mail: edw@ius2.cs.cmu.edu
henry@utzoo.UUCP (Henry Spencer) (05/24/87)
> 1. Have the compiler substitute locations in -asm- statements. > Other than editing the assembler output, I do not believe there > is any way to insert asm statements which can be expected to > survive a change from one compiler to another. You are almost right: there is *no* way to insert asm statements which can be expected to cross compiler boundaries. Note that compilers are not required to (a) implement asm statements at all, or (b) generate assembler output at all. More generally, there is a problem in that the legal ways of using a C variable in assembler are highly variable, a function of the compiler as well as the machine. For example, on many RISC machines the only memory-reference instructions are Load and Store. This means that the extent to which the compiler puts variables into registers will *greatly* influence how you write code with asm. Whether a given variable is a legal operand for a particular instruction will be very compiler-dependent. This problem simply has no general solution. Such a requirement would degenerate to a motherhood like "the compiler should be as helpful as possible to assembler programmers", which is (a) useless and (b) not an obviously desirable statement. Note that asm is not in X3J11 C at all, except for a mention in the "Common Extensions" appendix. > 2. Require that the compiler honor, whenever possible, assignments > to registers. ^^^^^^^^ Please define "whenever possible". Most programmers would applaud a compiler that made the code run faster at the cost of sometimes disregarding "register" directives. > 3. Allow the programmer to force non-promotion of floating to double, > whenever the programmer feels there is a good reason to do this. X3J11 already makes this an option for compilers. Some mandatory way of doing it might be useful, but it's a secondary issue: compiler implementors whose customers are concerned about numerical issues will do it as a matter of course. > 4. Allow floating point numbers to be given in hex... This can already be done, albeit clumsily and in somewhat machine-dependent ways. However, since those adverbs also apply to doing it in hex, I see no reason for action on this. > 5. Require that the compiler honor parentheses... This is somewhat defensible in floating-point arithmetic, but a major loss otherwise. "If you want Fortran, you know where to find it." -- "The average nutritional value Henry Spencer @ U of Toronto Zoology of promises is roughly zero." {allegra,ihnp4,decvax,pyramid}!utzoo!henry
drw@cullvax.UUCP (05/27/87)
hrubin@osupyr.UUCP (Herman Rubin) writes: > What we people who can program using the power of the computer really need > to do is convince the X3J11 committee to accept the idea that overloaded > operators, defining of new types (not like C++), defining of operator > symbols corresponding to operations not included in the default language, > forcing inline, substitution of compiler-determined locations in inserted > assembler instructions, and other versatile devices, and in general enabling > the production of good semi-portable code is worthwhile. One problem is that ANSI is only into standardizing existing practice. In several parts of their rationale they note that there is "insufficient experience" with a particular concept, and thus, they won't include it in the standard. (This hasn't stopped them from adding a few totally new features, though. But they are features that are despirately needed.) What we need is for someone to add these features into a respected compiler and distribute it, so we can see how these ideas work in practice. Unfortunately, the commercial outfits aren't interested in advancing the state of the art. "He who is out in front gets shot in the back." Dale -- Dale Worley Cullinet Software UUCP: ...!seismo!harvard!mit-eddie!cullvax!drw ARPA: cullvax!drw@eddie.mit.edu Un*x (a generic name for a class of OS's) != Unix (AT&T's brand of such)
cik@l.cc.purdue.edu.UUCP (06/10/87)
# In article <533@l.cc.purdue.edu>, cik@l.cc.purdue.edu (Herman Rubin) writes: # > In article <8024@utzoo.UUCP>, henry@utzoo.UUCP (Henry Spencer) writes: # > > But this sure doesn't sound like C, and C is what X3J11 is standardizing. # > # > Okay, let me stick to nasty problems with C. # > # > 1. Have the compiler substitute locations in -asm- statements. # > Other than editing the assembler output, I do not believe there # > is any way to insert asm statements which can be expected to # > survive a change from one compiler to another. # # I have no idea what you are talking about. The asm statement # allows you to insert assemble code into your C program, what # is the problem you are having with this? For example, suppose that the variable j has just been computed, and I want to transfer on overflow to loc. On the VAX, in C this is asm(" jov xxx,LLL"); wher xxx is the location of j that the compiler has assigned and LLL is the compiler's symbol for loc. Sometimes, but not always, I can figure out where the compiler has put j, but definitely not loc. The only way I have been able to do this is to put in something for xxx and LLL, get the assembler listing, and then edit it. # > 2. Require that the compiler honor, whenever possible, assignments # > to registers. ^^^^^^^^ # # Is this really a problem? Maybe I've been luckly, but when I ask # for a register I get it provided I haven't used them all yet. On the VAX, the compiler only lets me use half of the registers, and in cases in which I wish to specify that a variable be in a specific register, it refuses completely. It refuses to put floating and double variables in registers. Also, using C compilers for both the VAX and the PYRAMID, I have been unable to get the compiler to put a one-word union in a register. # > # > 3. Allow the programmer to force non-promotion of floating to double, # > whenever the programmer feels there is a good reason to do this. # > I know when there is no point in using double; the compiler cannot. # > Also, on some machines, one cannot print out a floating number in hex. # > (Okay, I can finagle it. But I had an occasion where this would have # > been a problem. I edited the assembler code, as the easiest option.) # # But heres the problem - floatfunc(3.0), should 3.0 be pass as # a float or a double? To complicate matters, say floatfunc is # external. Function prototypes may take care of this though. # # How about this to solve your problem. # # typedef union # { # float fnum; # int inum; # } floatint; # I agree that your solution would work, and I would have used this method if I had foreseen the problem. However, if a variable is typed float, it should be possible to pass it unpromoted in C without having to work. # > 4. Allow floating point numbers to be given in hex. Try putting in # > 2^-32 as a floating point or double constant. Why should one have to # > risk computer roundoff when it is totally unnecessary? # # Some people have noted that this might be a niece feature, I forget # what if any problems there are with this. # There are no problems with this, but I do not know of any notation that has been suggested to do this. # > # > 5. Require that the compiler honor parentheses. When I want a # > subroutine to return (x - y - k*c) + f(y), I most emphatically do # > not want the compiler to do the "obvious" rearrangement to combine # > the two terms with y; this can be a major loss of accuracy. To set # > a variable equal to the parenthetical expression is a significant # > loss of time. # # What two terms with y? I hope my C compiler doesn't think y can # be factor out of that expression to form (f-1)(y) :-). The two terms are -y and f(y). # To address your real complaint, the ANSI standard plans on supporting # parenthesis honoring through the use of the unary +. +(x - y) + y # will be evaluated as it appears. # I have no objection to the unary +, but many of the commentators in this news group seem to. # Please lets not get into a long philosophic debate over this # we have seen it all before. If you don't like it, use another # language. If there were another appropriate language, I would. None of the other languages I know (except PL/1, which is unnecessarily clumsy) do any better. # Eddie Wyatt # # e-mail: edw@ius2.cs.cmu.edu -- Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907 Phone: (317)494-6054 hrubin@l.cc.purdue.edu or pur-ee!stat-l!cik or hrubin@purccvm.bitnet
karl@haddock.UUCP (06/12/87)
In article <541@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes: >>>1. Have the compiler substitute locations in -asm- statements. >>>Other than editing the assembler output, I do not believe there >>>is any way to insert asm statements which can be expected to >>>survive a change from one compiler to another. > >For example, suppose that the variable j has just been computed, and I want >to transfer on overflow to loc. On the VAX, in C this is > asm(" jov xxx,LLL"); >[where xxx and LLL are the assembler's names for j and loc]. The only way I >have been able to do this is to put in something for xxx and LLL, get the >assembler listing, and then edit it. If you're arguing that vendors should implement such a feature, I agree; it makes asm() much more useful. But there is no way this could be standardized. ANY use of asm() is both machine- and compiler-dependent. X3J11 does not require that an implementation support asm() (it's a "Common Extension") or even that it have an assembly pass. >>>2. Require that the compiler honor, whenever possible, assignments >>>to registers. This is meaningless. The standard says nothing about machine registers; it knows nothing about the underlying hardware. (Even the rule that integers are stored in binary is covered by the as-if rule.) Whether a compiler is conforming depends only upon the output of programs compiled by it. >On the VAX, the compiler only lets me use half of the registers, and in cases >in which I wish to specify that a variable be in a specific register, it >refuses completely. It refuses to put floating and double variables in >registers. Also, using C compilers for both the VAX and the PYRAMID, >I have been unable to get the compiler to put a one-word union in a register. Complain to the vendor, not the standards committee. >>>3. Allow the programmer to force non-promotion of floating to double, Compilers are now free to use single-precision for float-only arithmetic. Function arguments are promoted from float to double only in the absence of a prototype. >[Eddie Wyatt writes:] >> But heres the problem - floatfunc(3.0), should 3.0 be pass as >> a float or a double? To complicate matters, say floatfunc is >> external. Function prototypes may take care of this though. They do. Also, "3.0" is a double whereas "3.0F" is a float. (This doesn't affect your example, which should treat "3.0" and "3.0F" identically.) >>>Also, on some machines, one cannot print out a floating number in hex. If you want to pass an unpromoted float to printf("%x"), you'll have to use something nonportable no matter what -- enclosing the float in a union, as suggested by Eddie, is probably best. Note that the number of "%x"'s is also machine dependent. >>>4. Allow floating point numbers to be given in hex. Try putting in >>>2^-32 as a floating point or double constant. Why should one have to >>>risk computer roundoff when it is totally unnecessary? If you mean you want to specify the bit-pattern of the floating-point number, you can use a union or a pointer-cast. (And I have no sympathy if your program fails to port.) I'll assume you just want base-16 scientific notation. One solution is to evaluate 2^-32 by some other means (e.g. "dc") and type in the decimal digits. When I give the compiler a decimal representation of a floating-point number, I expect it to generate the nearest possible number. If it didn't, I'd complain to the compiler vendor. Alternately, you could write an expression such as 1.0/1024.0/1024.0/4.0; any decent compiler will do the arithmetic at compile-time. >>>5. Require that the compiler honor parentheses. When I want a >>>subroutine to return (x - y - k*c) + f(y), I most emphatically do >>>not want the compiler to do the "obvious" rearrangement to combine >>>the two terms with y; this can be a major loss of accuracy. To set >>>a variable equal to the parenthetical expression is a significant >>>loss of time. Unless I specify otherwise (with unary plus), I most emphatically *do* want the compiler to rearrange such an expression if that makes it more efficient. (Btw, even assigning to a kludge variable (the pre-ANSI way to do this) need not be a "significant loss of time" -- the optimizer should be able to note that the variable is dead, and not bother to store it anywhere.) Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
am@cl.cam.ac.uk (Alan Mycroft) (06/17/87)
In article <546@haddock.UUCP> karl@haddock.ISC.COM.UUCP (Karl Heuer) writes: >ANY use of asm() is both machine- and compiler-dependent. X3J11 does not >require that an implementation support asm() (it's a "Common Extension") or >even that it have an assembly pass. > My understanding of the X3J11 OCtober 86 public review draft is that a C compiler which treats f() { asm("ret"); } as anything other than a call to the C function asm() with a pointer to 4 bytes of initialised storage is broken. (Of course, if you include a non-ansi header, or use a #pragma then all bets are off as the program behaviour is unspecified. However the above use IS deprecated in asm() has not been declared previously). I believe that the appendix listing of 'asm' is intended as a warning to users who wish to write code which also works on older 'C's and who might otherwise get burnt.
mouse@mcgill-vision.UUCP (der Mouse) (06/23/87)
In article <541@l.cc.purdue.edu>, cik@l.cc.purdue.edu (Herman Rubin) writes: [various stuff about problems with C] >>> 2. Require that the compiler honor, whenever possible, assignments >>> to registers. ^^^^^^^^ >> Is this really a problem? Maybe I've been luckly, but when I ask >> for a register I get it provided I haven't used them all yet. > On the VAX, the compiler only lets me use half of the registers, and > [other "problems"] Sorry. For the compilers you were using, it's not possible. If you want full control over allocation of all the machine's registers (or even any control over any of them), you don't want standard C. >>> 3. [...] Also, on some machines, one cannot print out a floating >>> number in hex. >>> 4. Allow floating point numbers to be given in hex. Try putting >>> in 2^-32 as a floating point or double constant. Why should one >>> have to risk computer roundoff when it is totally unnecessary? >> Some people have noted that this might be a niece feature, I forget >> what if any problems there are with this. > There are no problems with this, but I do not know of any notation > that has been suggested to do this. There is a problem with both of those: suppose floating-point is not stored in a binary format - say it uses floating-point ternary? Suppose the machine uses packed decimal? Suppose you figure out your hex constant for your VAX and then have to port to your Sun? Then to your 80x86? Then to your IBM mainframe? Then to that packed decimal machine I mentioned? Yech. Just write 1/65536.0/65536.0 and let the compiler figure it out. >>> 5. Require that the compiler honor parentheses. Not this again, just when we thought it had been beaten to death.... >>> [...] (x - y - k*c) + f(y), I most emphatically do not want the >>> compiler to do the "obvious" rearrangement to combine the two terms >>> with y; >> What two terms with y? I hope my C compiler doesn't think y can be >> factor out of that expression to form (f-1)(y) :-). > The two terms are -y and f(y). What would you think the "obvious" rearrangement would merge -y and f(y) to form? I fear the "obvious" rearrangement isn't obvious to me. The only thing that looks anything like reasonable was the >> suggestion of (f-1)(y), and even that is pretty silly. Or do you mean you don't want it to generate (x-k*c)+(f(y)-y)? Sorry, again, you don't want standard C (though ANSI has unary +, which could be used to "solve" this particular "problem"). der Mouse (mouse@mcgill-vision.uucp)
jack@swlabs.UUCP (Jack Bonn) (06/26/87)
In article <820@mcgill-vision.UUCP>, mouse@mcgill-vision.UUCP (der Mouse) writes: > >>> 4. Allow floating point numbers to be given in hex. Try putting > >>> in 2^-32 as a floating point or double constant. Why should one > >>> have to risk computer roundoff when it is totally unnecessary? > > There is a problem with both of those: suppose floating-point is not > stored in a binary format - say it uses floating-point ternary? > Suppose the machine uses packed decimal? Suppose you figure out your > hex constant for your VAX and then have to port to your Sun? Then to > your 80x86? Then to your IBM mainframe? Then to that packed decimal > machine I mentioned? Yech. Just write 1/65536.0/65536.0 and let the > compiler figure it out. Why not just allow 0x0.00000001? I don't think the suggestion is to encode the hexadecimal in the _internal_ format for the machine, just to be able to express the constant in a base other that 10. Certainly, if the machine was a decimal machine, round-off would still occur. But the majority of implementations (are there any decimal-only c's?) would not encounter it. But the pressing question is: Must the dot then be referred to as the "hexa-decimal point"? :-) -- Jack Bonn, <> Software Labs, Ltd, Box 451, Easton CT 06612 seismo!uunet!swlabs!jack
daniels@cae780.TEK.COM (Scott Daniels) (06/26/87)
In article <820@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse) writes: >In article <541@l.cc.purdue.edu>, cik@l.cc.purdue.edu (Herman Rubin) writes: >>>> 4. Allow floating point numbers to be given in hex. Try putting >>>> in 2^-32 as a floating point or double constant. Why should one >>>> have to risk computer roundoff when it is totally unnecessary? >>> Some people have noted that this might be a niece feature, I forget >>> what if any problems there are with this. >> There are no problems with this, but I do not know of any notation >> that has been suggested to do this. > >There is a problem with both of those: suppose floating-point is not >stored in a binary format - say it uses floating-point ternary? >Suppose the machine uses packed decimal? Suppose you figure out your >hex constant for your VAX and then have to port to your Sun? Then to >your 80x86? Then to your IBM mainframe? Then to that packed decimal >machine I mentioned? Yech. Just write 1/65536.0/65536.0 and let the >compiler figure it out. > The problem being pointed out is that there are no binary formats provided. We have done quite well with providing decimal formats where the underlying machine has no decimal floating point, why not have a similar notation for binary (or base N if you can agree on a nice notation). Given such a format, it is possible to produce a terse binary text string which represented the exact value that your machine calculated, but would be readable on another machine with the closest approximation of which that machine is capable. The kind of notation desired is like: 0.5 == 0x0.8, 0.625 == 0x0.A, 128.5 == 0x80.8, 128.5 == 0x8.08@4 Hard to resolve issues are things like: base of expression of exponent, is the exponent a power of two or the base (should the last be 0x8.08@1), How do you represent Nans (or do you). It certainly seems to me that such a notation is greatly to be desired (we can agree that the floating point on most machines is closer to binary than decimal). What we do not have is enough practical experience with a notation to be sure we know a solution. That is why Ansi-C should not have such a format. FROM: Scott Daniels, Tektronix CAE 5302 Betsy Ross Drive, Santa Clara, CA 95054 UUCP: tektronix!teklds!cae780!daniels {ihnp4, decvax!decwrl}!amdcad!cae780!daniels {nsc, hplabs, resonex, qubix, leadsv}!cae780!daniels
peter@sugar.UUCP (Peter DaSilva) (07/06/87)
Or for those of us with broken compilers with CPP part of CC, #asm? I have always thought asm() looked hokey. #pragma asm PDP-11 mov (IP)+,WP ; anybody recognise this jmp @(WP)+ ; piece of code? #pragma C -- -- Peter da Silva `-_-' ...!seismo!soma!uhnix1!sugar!peter (I said, NO PHOTOS!)
karl@haddock.UUCP (Karl Heuer) (07/07/87)
In article <727@jenny.cl.cam.ac.uk> am@cl.cam.ac.uk (Alan Mycroft) writes: >My understanding of [Oct86 dpANS] is that a C compiler which treats > f() { asm("ret"); } >as anything other than a call to [an ordinary function named "asm"] is broken >[Since builtin asm is not part of the standard.] "Broken" is a bit strong. Such compilers (which will likely continue to exist in the ANSI world) will simply be "not strictly conforming". Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
ron@topaz.rutgers.edu.UUCP (07/08/87)
Excuse me, but doesn't the compiler standard make provision for functions being built-in? I seem to remember provision having to be made to make sure one could defeat built in compiler treatment of certain math functions that were turned into inline code and allowing the user to make them true function calls (presumably because the programmer wanted to make his own version of the function). What makes asm("string") any different than someones version of log(x) that might get turned into a call to the machines log instruction, unless it was explicitly turned off? -Ron
karl@haddock.UUCP (07/10/87)
In article <13220@topaz.rutgers.edu> ron@topaz.rutgers.edu (Ron Natalie) writes: >Excuse me, but doesn't the compiler standard make provision for functions >being built-in? I seem to remember provision having to be made to make >sure one could defeat built in compiler treatment of certain math functions >that were turned into inline code and allowing the user to make them true >function calls Yes. This can be done with "#undef", or by enclosing the name in parens. >(presumably because the programmer wanted to make his own version of the >function). No, such a substitution yields undefined behavior, even if the user function has identical semantics. >What makes asm("string") any different than someones version of log(x) that >might get turned into a call to the machines log instruction, unless it was >explicitly turned off? "log" is part of the standard, "asm" is not. Thus, a strictly conforming implementation must assume by default that "asm" refers to a user function. However, the builtin could be named "__asm"; then the user could explicitly enable it with "#define asm __asm". Alternately, the feature could be enabled via "#pragma". Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
am@cl.cam.ac.uk (Alan Mycroft) (07/22/87)
In article <684@haddock.UUCP> karl@haddock.ISC.COM (Karl Heuer) writes: >>My understanding of [Oct86 dpANS] is that a C compiler which treats >> f() { asm("ret"); } >>as anything other than a call to [an ordinary function named "asm"] is broken >"Broken" is a bit strong. Such compilers (which will likely continue to >exist in the ANSI world) will simply be "not strictly conforming". > My dpANS gives no such notion as a "strictly conforming compiler". (strictly conforming PROGRAM, yes). It says: "A conforming hosted implementation shall accept any strictly conforming program.", and thus (assuming that by 'accept', ANSI means 'and gives the correct answer') we see that if f() does not call asm() then the compiler is not a "conforming hosted implementation". I.e. not ANSI C.
steve@nuchat.UUCP (Steve Nuchia) (08/04/87)
In article <847@haddock.ISC.COM>, karl@haddock.ISC.COM (Karl Heuer) writes: > You are right; I got the terms confused. In fact A.6.5 says that certain > common extensions, e.g. nonstandard keywords, will render an implementation > nonconforming. > > I still think "broken" is too strong a word. But if I were a compiler vendor > I'd be certain to have a switch that disabled all extensions to yield a "pure" > implementation. Please: If anyone reading this is ever in a position to affect a decision on this point, make the silly flags default to the portable, standard configuration. I worked on a project that had a major commercial product running on something like 30 different unix boxes, which at one time spanned the gamut from v7-based xenix to sys5.2. There were three serious time sinks in the porting group, and dealing with the feature differences among the unix versions wasn't one of them. Actually getting the code from the base machine to all the targets (usually over serial lines) consumed a lot of clock time, but was not too demanding on the people. Incompatible bugs consumed the largest amount of time, taken across both the porting staff and the development group. If everyone had the same bugs life would be grand. Right behind bugs was compiler/linker/make flags. Figuring out the silly magic required to get company X's compiler to behave like a unix C compiler took an amazing amount of time. Particularly if company X was in the intel camp, but it happened with other processors too. The stories I could tell. Anyway, It is a serious presumption on the part of the compiler vendors to place the burden of groping through the manual (or disassembling the compiler) on the occasional user, the application porter. The guy doing development on the box can more reasonably be expected to become intimate with its compiler. does any of this make sense? Steve Nuchia {{soma,academ}!uhnix1,sun!housun}!nuchat!steve
peter@sugar.UUCP (Peter da Silva) (08/06/87)
>My dpANS gives no such notion as a "strictly conforming compiler". (strictly >conforming PROGRAM, yes). It says: "A conforming hosted implementation >shall accept any strictly conforming program.", and thus [an asm-extended >compiler] is not a "conforming hosted implementation". I.e. not ANSI C. Let "A Conforming Hosted Implementation" be A Let "Accepts a Strictly Conforming Program" be B Let "Accepts a Non-conforming Program" be C Your first statement now becomes A => B. This allows you to state !B => !A, that is, if it doesn't accept a strictly conforming program, it's not a conforming hosted implementatio. It doesn't say anything about C. You can't say C => !A, nor !C => !A. You're confusing "accepts a non-conforming program" with "doesn't accept a conforming program". Or else you didn't include all the relevent facts in your article. -- -- Peter da Silva `-_-' ...!seismo!soma!uhnix1!sugar!peter (I said, NO PHOTOS!)
franka@mmintl.UUCP (Frank Adams) (08/15/87)
In article <279@nuchat.UUCP> steve@nuchat.UUCP (Steve Nuchia) writes: >Anyway, It is a serious presumption on the part of the compiler vendors to >place the burden of groping through the manual (or disassembling the >compiler) on the occasional user, the application porter. The guy doing >development on the box can more reasonably be expected to become intimate >with its compiler. I must disagree. The default compiler settings should cater neither to professionals porting code, nor to professionals doing local development, but to the occasional or novice programmer, who is trying to get his newly written, probably small, program to run. Professionals should expect to do the work necessary to learn how to use their tools to perform the functions they want them to perform. The tools should cater to the novices, without putting an excessive burden on the pro. -- Frank Adams ihnp4!philabs!pwa-b!mmintl!franka Ashton-Tate 52 Oakland Ave North E. Hartford, CT 06108
msf@amelia.UUCP (08/18/87)
In article <2311@mmintl.UUCP> franka@mmintl.UUCP (Frank Adams) writes: > The default compiler settings should cater neither to >professionals porting code, nor to professionals doing local development, >but to the occasional or novice programmer, who is trying to get his newly >written, probably small, program to run. I must disagree with Mr. Adams. C is *not* a beginner's language. I would agree with his comments were they refering to Pascal or BASIC (two languages that were designed for programming novices, although many complex professional programs have been written in them); or FORTRAN (since it is so commonly used by people who have little or no interest in having to `figure out' the computer). C is a powerful language that offers lots of rope for the novice to hang himself. THIS IS NOT A BUG, IT IS A FEATURE! That same flexibility allows the professional experienced programmer the freedom to do what they want to do. C should not cater to novices, there are plenty of double checking languages out there. Let the C compiler default to the most used options by the professionals (which I would hope were the maximum portability options) and let the novices acquire experience using Pascal. >Professionals should expect to do the work necessary to learn how to use >their tools to perform the functions they want them to perform. The tools >should cater to the novices, without putting an excessive burden on the pro. This might be true for a $20 drill, but I doubt a $200K milling machine is optimized for a high school shop class. That IS an excessive burden. mike Michael Fischbein msf@prandtl.nas.nasa.gov ...!seismo!decuac!csmunix!icase!msf These are my opinions and not necessarily official views of any organization.
ron@topaz.rutgers.edu.UUCP (08/18/87)
> I must disagree. The default compiler settings should cater neither to > professionals porting code, nor to professionals doing local development, > but to the occasional or novice programmer, who is trying to get his newly > written, probably small, program to run. And I must disagree with you, if we follow this discussion back to the beginning. The default action for the compiler should be to ACT NORMALLY. ACTING NORMALLY means complying with whatever standards might be there. Making non-standard changes the default neither helps the naive nor the professional programmer at all. A naive programmer new to C is probably working with a C text that is references NORMAL C, even if he is not, you are doing him a disservice teaching him broken C. A naive programmer, not new to C, but new to this compiler, would really expect the C compiler to work like all the other ones. A professional programmer knows what the C standards are and codes to them, clearly identifying nonstandard and probably nonportable constracts that he uses. The operational rule here is the oft quoted "Principle of Least Astonishment." For example many novice K&R readers and long term C hands were screwed by Lattice C defaults. -Ron
root@hobbes.UUCP (John Plocher) (08/24/87)
+---- Frank Adams writes the following in article <2322@mmintl.UUCP> ---- | | (Anyone doing serious development on an 8086 has to think about segments and | probably make changes to their code to take them into account. Large model | runs too slowly, and small model isn't big enough. This is what is wrong | with the 8086 architecture -- high level language programmers shouldn't have | to be concerned about such things.) | | Frank Adams ihnp4!philabs!pwa-b!mmintl!franka | Ashton-Tate 52 Oakland Ave North E. Hartford, CT 06108 +---- One thing that has bothered me for a long time about the 808x compilers is the following: When I was learning PDP-11 assembler we found out that the compilers could use branch instructions iff the target was less than +/- 128 bytes away. If not, a jump instruction would be used. Branches were short and fast, jumps were big and slow. Obvious. Along came the 808x and I find that there were 2 modes for addresses: short and fast -vs- big and slow; these addresses could be used for code and data. Obviously the compiler/linker/loader should be the one to determine which to use, right? I mean, if a data object is within 64K of someplace then "near" pointers could be used; if it is too far, use "far" pointers. Boy was I pissed when I found out that things didn't work that way! AAAArrrrrgggghhhh! All that needs to done is to have each library routine avaliable in each combo of models, and a smart linker which can use them. -- John Plocher uwvax!geowhiz!uwspan!plocher plocher%uwspan.UUCP@uwvax.CS.WISC.EDU
tim@amdcad.AMD.COM (Tim Olson) (08/24/87)
In article <193@hobbes.UUCP> root@hobbes.UUCP (John Plocher) writes: +----- |One thing that has bothered me for a long time about the 808x compilers |is the following: | When I was learning PDP-11 assembler we found out that the compilers |could use branch instructions iff the target was less than +/- 128 bytes |away. If not, a jump instruction would be used. Branches were short and |fast, jumps were big and slow. Obvious. | Along came the 808x and I find that there were 2 modes for addresses: |short and fast -vs- big and slow; these addresses could be used for code |and data. Obviously the compiler/linker/loader should be the one to determine |which to use, right? I mean, if a data object is within 64K of someplace |then "near" pointers could be used; if it is too far, use "far" pointers. | Boy was I pissed when I found out that things didn't work that way! | | AAAArrrrrgggghhhh! | |All that needs to done is to have each library routine avaliable in each |combo of models, and a smart linker which can use them. +----- That has to be a pretty smart linker, as far as linkers go. It is an N-P complete problem to "optimally" change "far" references to "near" references (and compact the code) at link time. Here's the problem: During pass1, the linker builds the symbol table of externally defined addresses. During pass2, it discovers that a "far" reference is really "near". It then changes the code at that location to be a near reference (which usually reduces the size of the code at that point). It then has to fill the unused space with "nops" (dubious benifit) or "compact" the code. After compacting, *all* labels following the compacted reference have been changed by the size of the code reduction (even local, "static" labels, which don't normally get passed to the linker!). Worse yet, the compaction may have brought a label into "near" range that was determined to be far, before. So pass2 must be run over again. There is research going on in this area, because it would benifit a great many architectures. A good paper to read on the subject is one written by David Wall of DEC -- sorry, I can't find the paper so I can't give a complete reference -- those that are interested can email me; I should be able to find the reference for you. -- Tim Olson Advanced Micro Devices (tim@amdcad.amd.com)
schung@cory.Berkeley.EDU (Stephen the Greatest) (08/24/87)
>All that needs to done is to have each library routine avaliable in each >combo of models, and a smart linker which can use them. >-- >John Plocher uwvax!geowhiz!uwspan!plocher plocher%uwspan.UUCP@uwvax.CS.WISC.EDU And now something completely different... What about an object file format that does not distinguish between near/far pointer usage? Have the (real smart) linker generate the right code from these object files. This will put more work to the linker, but make sure that only one version of each library routine must be written. - Stephen
root@hobbes.UUCP (08/27/87)
+---- Tim Olson writes in <18042@amdcad.AMD.COM> ---- | +---- John Plocher ( that's *me* ) wrote ---- | | Along came the 808x and I find that there were 2 modes for addresses: | |short and fast -vs- big and slow; these addresses could be used for code | |and data. Obviously the compiler/linker/loader should be the one to | |determine which to use, right? | +----- | | That has to be a pretty smart linker, as far as linkers go. It is an | N-P complete problem to "optimally" change "far" references to "near" | references (and compact the code) at link time. +---- Why couldn't this be done in the compiler when everything is still in 3-address form IN THE COMPILER? Don't wait to do this until after the code has been generated! Start off assuming that everything is "far", and go thru marking things that can be proved "near". At this point, labels are still symbolic, and since we have an arbitrary data structure for the 3-address code there is no need for compaction or filling with 'nops'. This would (obviously?) mean that there needs to be more or different info stored in ".obj" files - the linker might even need to include the traditional "code generator" found in today's compilers. Off the top of my head I'd think that a "P-code" object file with the needed symbol table info could be a place to start. If the "super-linker" uses a few heuristics like: The total size of this program is < 64K so all code pointers can be "near" The total static/Global/BSS... data is < 64K, ... Aliasing is detected; assume "far" pointers for this ... it could do a passable job. There are cases where things get very rough - I've done a lot of what is now being called "mixed model" programming; using printf() when you have both "near" and "far" strings is not for the masses! I just think that the computer should be able to do this sort of mundaine thing for me. Right now, I have to determine that my code is > 64K and add the -Ml flag to my compiles. At the very least, the compiler should be able to do this! -- John Plocher uwvax!geowhiz!uwspan!plocher plocher%uwspan.UUCP@uwvax.CS.WISC.EDU
jack@swlabs.UUCP (Jack Bonn) (08/28/87)
In article <200@hobbes.UUCP>, root@hobbes.UUCP (John Plocher) writes: > Why couldn't this be done in the compiler when everything is still in > 3-address form IN THE COMPILER? Don't wait to do this until after the code > has been generated! Start off assuming that everything is "far", and go > thru marking things that can be proved "near". At this point, labels are > still symbolic, and since we have an arbitrary data structure for the > 3-address code there is no need for compaction or filling with 'nops'. Why not generate source assembler that doesn't indicate whether the target is near or far. Then let the assembler choose the long or short form of the jump depending on the worst case distance from the target. I think I remember an assembler that did just the job that you are looking for. If I remember correctly, it was a three pass assembler that worked like this for branch addresses: 1) Pass over the source and compute the range of address that each symbol can have. The instruction location counter would actually be a pair of values, ilc.min and ilc.max. Whenever an instruction is read, increment these values appropriately. For jumps, this would mean adding different values to ilc.min and ilc.max. 2) Make what is normally a pass 1 over the input. The exception here is that whenever a jump instruction is read, compute the WORST CASE distance to the target. Mark that jump instruction for pass 2 and update the ilc appropriately. 3) Do what is normally pass 2. Of course there are cases where this is too pessimistic, since the "real" solution is exponential (np-complete?). But in real cases, this yields results very close to optimum. -- Jack Bonn, <> Software Labs, Ltd, Box 451, Easton CT 06612 seismo!uunet!swlabs!jack
fnf@mcdsun.UUCP (08/31/87)
In article <296@swlabs.UUCP> jack@swlabs.UUCP (Jack Bonn) writes: >Why not generate source assembler that doesn't indicate whether the target >is near or far. Ok so far... > Then let the assembler choose the long or short form of >the jump depending on the worst case distance from the target. This only works for jumps to local symbols within the same assembly module, and GREATLY complicates the work of a linker which optimizes both local and global references (since it must now cope with relocation done by the assembler when it inserts or deletes code between the definition and reference of a local symbol). Again, I believe the assembler has no business whatsoever doing relocation and current implementations only do so for historical reasons (the assembler writer knew that assemblers have "always" done this). Relocation is the linker's job. If anyone has a counter argument please post! >Of course there are cases where this is too pessimistic, since the "real" >solution is exponential (np-complete?). But in real cases, this yields >results very close to optimum. Gosh, I'm glad this discussion didn't come up several months ago when I was in the midst of writing a new linker from scratch. The code to implement near/far relocation optimizations might have taken more than the three days or so that it actually took, if I'd have known how difficult a problem it was to solve efficiently... :-) :-) :-) :-) -Fred -- = Drug tests; just say *NO*! = Fred Fish Motorola Computer Division, 3013 S 52nd St, Tempe, Az 85282 USA = seismo!noao!mcdsun!fnf (602) 438-3614
jack@swlabs.UUCP (09/01/87)
In article <364@mcdsun.UUCP>, fnf@mcdsun.UUCP (Fred Fish) writes: > In article <296@swlabs.UUCP> jack@swlabs.UUCP I wrote: > > Then let the assembler choose the long or short form of > >the jump depending on the worst case distance from the target. > > This only works for jumps to local symbols within the same assembly module, > and GREATLY complicates the work of a linker which optimizes both local > and global references (since it must now cope with relocation done by > the assembler when it inserts or deletes code between the definition and > reference of a local symbol). The algorithm presented requires no such optimization by the linker. The assembler described yields object code with the correct long/short jumps and no additional relocation/fixup information. There is nothing for the linker to fixup. -- Jack Bonn, <> Software Labs, Ltd, Box 451, Easton CT 06612 seismo!uunet!swlabs!jack
peter@sugar.UUCP (Peter da Silva) (09/02/87)
> [ description of how to make an assembler that handles long/short branches ]
But that doesn't resolve the problem of how to deal with near and far
cals to seperately compiled code. If the calling sequence of the 8086
was a little more logical, you could have 2 entry points for the routine:
near and far. The near would just push the segment and fall through to
the far. Unfortunately, segment is not the top of the stack in a far
call. See Kernighan's April column in Computer Language.
--
-- Peter da Silva `-_-' ...!seismo!soma!uhnix1!sugar!peter
-- U <--- not a copyrighted cartoon :->
fnf@mcdsun.UUCP (09/02/87)
In article <320@swlabs.UUCP> jack@swlabs.UUCP (Jack Bonn) writes: >In article <364@mcdsun.UUCP>, fnf@mcdsun.UUCP (Fred Fish) writes: >> This only works for jumps to local symbols within the same assembly module, >> and GREATLY complicates the work of a linker which optimizes both local >> and global references (since it must now cope with relocation done by >> the assembler when it inserts or deletes code between the definition and >> reference of a local symbol). > >The algorithm presented requires no such optimization by the linker. The >assembler described yields object code with the correct long/short jumps and >no additional relocation/fixup information. > >There is nothing for the linker to fixup. Sigh, guess we are going to have to go into the gory details. Assume a hypothetical machine with two forms of a jump instruction. One is is 32 bits and is evenly split with 16 bits being the instruction op code and the other 16 bits being a PC relative offset. The other jump instruction is two long words, each 32 bits, with the first being a different 16 bit opcode with the other 16 bits unused, and the second being a 32 bit PC relative offset. I.E.: jump.near <16 bit opcode><16 bit offset> jump.far <16 bit opcode>< unused > < 32 bit offset > Now assume some assembly code such as the following (note the lack of near/far specifications): . . 0x00000100 jump L1 #L1 is local . . 0x00000200 jump _strcpy #_strcpy is defined elsewhere . . 0x00000300 L1 jump _exit #_exit is defined elsewhere . . ^ | Offset from start of module The assembler assumes all jumps are near jumps and simply emits object code that looks something like: . 0x00000100 <jump.near opcode><16 bits of 0> . . 0x00000200 <jump.near opcode><16 bits of 0> . . 0x00000300 L1 <jump.near opcode><16 bits of 0> Now along comes the linker. It gathers up our object module, finds the reference to external routine _strcpy, and loads the module from the C library that defines _strcpy (along with lots of other stuff at the same time). Assume the definition of _strcpy in another module is located in the executable 0x00100000 bytes from the jump instruction above that uses it (heh, this is GNU Emacs :-). Now obviously 0x00100000 won't fit in 16 bits, so the linker must modify the object code to look something like: . 0x00001100 <jump.near opcode><16 bits of 0> . . 0x00001200 <jump.far opcode><16 bits of 0> #modified opcode 0x00001204 < 32 bit offset > #inserted field . . 0x00001304 L1 <16 bit opcode><16 bits of 0> . . 0x00101200 <begin code for _strcpy> ^ | Offset from start of executable module After relocation resolution, the final object code looks like: 0x00001100 <jump.near opcode><0x0204> . . 0x00001200 <jump.far opcode><0x0000> #modified opcode 0x00001204 < 0x00100000 > #inserted field . . 0x00001304 L1 <jump.near opcode><0x1234> . . 0x00101200 <begin code for _strcpy> If the assembler had decided that since the jump to L1 was a local jump of "known" offset 0x200, stuck 0x200 in the offset field, and thrown away the relocation information, the linker would not have been able to go back and fix up the 0x200 to 0x204 without scanning all the executable code looking for references that spanned the insertion point (at 0x1200-0x1204). This would have essentially required you to disassemble the entire load module EVERY TIME you promoted a jump.near instruction to a jump.far instruction! Hope this helps to clarify why the assembler SHOULD NOT do any relocation. -Fred -- = Drug tests; just say *NO*! = Fred Fish Motorola Computer Division, 3013 S 52nd St, Tempe, Az 85282 USA = seismo!noao!mcdsun!fnf (602) 438-3614
jack@swlabs.UUCP (Jack Bonn) (09/03/87)
In article <366@mcdsun.UUCP>, fnf@mcdsun.UUCP (Fred Fish) writes: > In article <320@swlabs.UUCP> jack@swlabs.UUCP (Jack Bonn) writes: > >In article <364@mcdsun.UUCP>, fnf@mcdsun.UUCP (Fred Fish) writes: > >> This only works for jumps to local symbols within the same assembly module, > >> and GREATLY complicates the work of a linker which optimizes both local > >> and global references (since it must now cope with relocation done by > >> the assembler when it inserts or deletes code between the definition and > >> reference of a local symbol). > > > >The algorithm presented requires no such optimization by the linker. The > >assembler described yields object code with the correct long/short jumps and > >no additional relocation/fixup information. > > > >There is nothing for the linker to fixup. > > Sigh, guess we are going to have to go into the gory details. <gory details omitted> If I understand you correctly, the method I described makes it more difficult for an optimizing linker to do its job. Of course, we had no such optimizing linker (or source thereof), or the assembler optimization would have been unnecessary. But I guess I am troubled by this linker optimization and maybe those in net-land can clarify: 1) Are there many of these optimizing linkers out there? 2) Is it true that to debug in assembler, the listing must be generated after the link is done? I think that this would be necessary since the addresses within the module are changed after the assembly is complete. (Does anyone else use assembler anymore?) 3) What are the consequences on unit testing code that may not match that which is part of the final product. How do we get this past Q/A? (or do we even tell them :-) ) 4) Won't it be true that two identical links may not even be the same length since the orderings in the libraries may change. Won't this make real-time analysis difficult, since the number of bytes of instructions may change from link to link. 5) Has there been any attempt to adjust the ordering of the modules to improve the overall optimization? It seems that this is an analogous situation to that encountered in VLSI placement/layout. Of course this is very computationally intensive for a complex die. But it would make sense to cluster "connected" modules together. Maybe an option to ld is called for, one that pulls object modules from the library _in order_ before trying to resolve unresolved references. At least then, this could be specified manually. Am I the only one who is troubled by all of this? I really like the potential for a automatic mixed model for a "brain-damaged" machine like the one I am posting from (at least for JMPs, calls are trickier). And I am sure there are many things that can be improved by optimizations like this (like the kernel) even for architectures that mix models much more easily than the Intel "family". But I also think that if all tool developers are going to go off and implement an improvement that takes "3 days or so" we might want to take some time and think about the consequences before doing so. -- Jack Bonn, <> Software Labs, Ltd, Box 451, Easton CT 06612 seismo!uunet!swlabs!jack
markb@sdcrdcf.UUCP (Mark Biggar) (09/03/87)
In article <613@sugar.UUCP> peter@sugar.UUCP (Peter da Silva) writes: >> [ description of how to make an assembler that handles long/short branches ] >But that doesn't resolve the problem of how to deal with near and far >cals to seperately compiled code. If the calling sequence of the 8086 >was a little more logical, you could have 2 entry points for the routine: >near and far. The near would just push the segment and fall through to >the far. Unfortunately, segment is not the top of the stack in a far >call. See Kernighan's April column in Computer Language. No the offest is on the top of the stack, so you can do the following: When generating the op for a near or far sub call the compiler inserts a nop before the call if necessary so that a far call always pushes an odd offset onto the stack and a near call always pushes an even offset. now the subroutine looks something like: label ... ... mov ax,(sp) and ax,1 jz label1 retfar label1 retnear This scheme was developed during a discussion with Robert Dewar of NYU at the last SIGAda meeting the was held in San Diego (3 yrs ago?), about how to compile Ada packages for an 86. Mark Biggar {allegra,burdvax,cbosgd,hplabs,ihnp4,akgua,sdcsvax}!sdcrdcf!markb
fnf@mcdsun.UUCP (Fred Fish) (09/04/87)
In article <333@swlabs.UUCP> jack@swlabs.UUCP (Jack Bonn) writes: >1) Are there many of these optimizing linkers out there? Not to my knowledge. But I would be VERY interested in any references anyone might be able to provide on either existing implementations or proposed implementations. >2) Is it true that to debug in assembler, the listing must be > generated after the link is done? I think that this would be Yes, I suppose this is true. Since the linker has total freedom to change the code in anyway it sees fit, up to and including moving instructions around and inserting or deleting instructions of its own devising. This also has obvious ramifications for people that write self-modifying code and for symbolic debuggers. Of course there is a "do-what-I-wrote" mode that just does a "dumb" link, but that doesn't help you much when your bug is fatal to the optimized version but innocuous in the "dumb" version. >4) Won't it be true that two identical links may not even be the same > length since the orderings in the libraries may change. Won't this > make real-time analysis difficult, since the number of bytes of > instructions may change from link to link. True again, which brings you to item 5 as you noted below. BTW I'm not sure what you mean by "make real-time analysis difficult". Are you refering to analysis of real-time systems or analysis in real-time or something else? >5) Has there been any attempt to adjust the ordering of the modules to > improve the overall optimization? It seems that this is an analogous Yes. :-) -Fred -- = Drug tests; just say *NO*! = Fred Fish Motorola Computer Division, 3013 S 52nd St, Tempe, Az 85282 USA = seismo!noao!mcdsun!fnf (602) 438-3614
wayne@ames.arpa (09/05/87)
Carol: Thanx much for the select poop; VERY thorough for something you "just slapped together"! However (isn't there always one?), I've still got one question (and a comment or two). First, the question: in your write-up, exactly what do you do to "terminate select" in the selwakeup routine? If I understand things, what you want to do is wake up the one sleeping process given by db->db_sel (now p); how do you wakeup a single process without waking everybody else that's sleeping on selwait? (By the way, my understanding is that if only one process is sleeping, then you wake only him; otherwise, you wakeup everybody in the whole system who is waiting for selects on any device, most of whom will go right back to sleep. Trade-off of infrequent inefficiency for simplicity. Correct?) Now a couple of comments on the write-up, mostly for feedback and to see if I really do understand. First, xxselect is called with "ds" as param but actually wants "db"; the call should be something like xxselqueue(ds.db), right? (Assuming the device buffer is an element of the device structure.) Also, at the top of - 3 -, the sentence "The key is that more than one process can try to select for the same event on the same process" should end with "device" rather than "process," no? Finally, in the code for selwakeup, why bother testing for SSEL before resetting it? And also a comment on the stuff being added to the driver-writing manual. It contains the sentence "The process number of the current process is in u.u_procp" which really isn't true (at least if you think of "process number" as synonymous with "process id"); shouldn't it be "A pointer to the current process's proc table entry ..."? Finally, a philosophical item. How does the xxselect routine know whether the user is in fact going to sleep? I mean, to quote your note, "On a poll, the driver xxselect routine is called just once from the kernel select routine." It seems to me the procedures you outlined will set db->db_sel in the poll case as well, although admittedly the test in selwakeup for (caddr_t)&selwait will prevent anything weird happening. Of course, if there's no way xxselect knows whether the user is polling or not, then ... Anyway, thanx again. Help with "terminate select" please? wayne
mouse@mcgill-vision.UUCP (09/22/87)
In article <366@mcdsun.UUCP>, fnf@mcdsun.UUCP (Fred Fish) writes: > In article <320@swlabs.UUCP> jack@swlabs.UUCP (Jack Bonn) writes: >> In article <364@mcdsun.UUCP>, fnf@mcdsun.UUCP (Fred Fish) writes: [> through >>> about short/long branches] [>>> (Fred Fish) says this complicates the linker] [>> (Jack Bonn) says no] [> (Fred Fish) says] > Sigh, guess we are going to have to go into the gory details. > [Example: machine with two jump instructions > jump.near <16 bit opcode><16 bit offset> > jump.far <16 bit opcode>< unused > <32 bit offset> > ] > Now assume some assembly code such as the following (note the lack of > near/far specifications): [intervening dots edited out -dM] > 0x00000100 jump L1 #L1 is local > 0x00000200 jump _strcpy #_strcpy is defined elsewhere > 0x00000300 L1 jump _exit #_exit is defined elsewhere > The assembler assumes all jumps are near jumps But that is exactly what it mustn't do. I would expect the assembler to produce a near jump for the first one, since it knows that one is near. For the other two, it must produce far jumps, or at least reserve enough space for a far jump. Then the linker can either cop out and use a far jump when the offset would have fit in 16 bits or it can replace it with a near jump. If it replaces it, it either has to fill 32 bits with some sort of no-op or else it has to move stuff. If you choose to shrink things, the assembler will have to tell the loader about the first jump as well (the offset will need changing). In its complete form, the above solution is no better than the other way (promoting near jumps to far jumps). However, the above will produce minimal code in almost all cases (one program out of five thousand maybe will have a non-optimal jump?). This is plenty good enough for most people. The other three can pay the price of a little extra cpu time and get it optimal. All you need is for the assembler to tell the loader about each such instruction, so the loader can fix up whatever it has to without having to scan the entire load module looking for jumps that cross the area it's patching. UNIX currently has something reminiscent of this: the assembler chooses branch instructions in near/far variants and fixes the instruction type at assemble time, pessimizing for undefined symbols. The loader merely fills in the offsets, even if a shorter instruction sequence would have been possible had it been known that the target was as close as it is. der Mouse (mouse@mcgill-vision.uucp)
fnf@mcdsun.UUCP (Fred Fish) (10/07/87)
In article <899@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse) writes: [stuff deleted... fnf] >> Sigh, guess we are going to have to go into the gory details. [stuff deleted... fnf] >> The assembler assumes all jumps are near jumps > >But that is exactly what it mustn't do. I would expect the assembler >to produce a near jump for the first one, since it knows that one is >near. For the other two, it must produce far jumps, or at least >reserve enough space for a far jump. Then the linker can either cop >out and use a far jump when the offset would have fit in 16 bits or it >can replace it with a near jump. If it replaces it, it either has to >fill 32 bits with some sort of no-op or else it has to move stuff. If >you choose to shrink things, the assembler will have to tell the loader >about the first jump as well (the offset will need changing). Gee, its been a while since this topic came around the first time, so lots of people will probably be totally in the dark about the original issues. Speaking strictly for those that remember the discussion, let me reiterate the major points: 1. The assembler *does not* do any relocation, computation of offsets, or whatever you want to call it. When it sees a symbol, either local or global, it just stuffs it into the symbol table to be passed on to the linker and creates a relocation entry for the current offset. I'm really puzzled by people's persistent belief that the assembler should do anything else (other than conditioning from current released implementations for most CISC processors). 2. The assembler has to emit either a "near" jump for a "far" jump bit pattern in the object code (I guess it could emit a third "insert appropriate jump instruction here" code, but why bother). If you default to "near" jumps, you have the linker fix up all the jumps that are really "far" jumps to be "far" jumps. If you default to "far" jumps, you have the linker fix up all the jumps that are really "near" jumps to be "near" jumps. In either case, you either grow or shrink the code as appropriate, in the linker. What could be easier? In either case, you end up with exactly the same executable object code. No nops, no "non-optimal" jumps, the *same* *optimal* *code*. 3. Now the only choice is to decide which default you want. For my implementation, it was obvious that near jumps were the correct default. For another situation, the reverse might be true. I don't claim that either is somehow theoretically "better". (Someone else might care to claim so though, don't let me stop you... :-) >UNIX currently has something reminiscent of this: the assembler chooses >branch instructions in near/far variants and fixes the instruction type >at assemble time, pessimizing for undefined symbols. The loader merely >fills in the offsets, even if a shorter instruction sequence would have >been possible had it been known that the target was as close as it is. Don't let existing sub-optimal solutions cloud your vision. -Fred -- # Fred Fish hao!noao!mcdsun!fnf (602) 438-3614 # Motorola Computer Division, 2900 S. Diablo Way, Tempe, Az 85282 USA
rwhite@nusdhub.UUCP (Robert C. White Jr.) (10/09/87)
In article <384@mcdsun.UUCP>, fnf@mcdsun.UUCP (Fred Fish) writes: > the linker fix up all the jumps that are really "near" jumps > to be "near" jumps. In either case, you either grow or > shrink the code as appropriate, in the linker. What could > be easier? In either case, you end up with exactly the same > executable object code. No nops, no "non-optimal" jumps, the > *same* *optimal* *code*. First, a linker is a "linking loader" and it's only REAL purpose is to resolve refrences and setup dynamic relocation information. ALL "short" jumps [add/subtract value from the instruction pointer directly] are compleetly generated and closed in the assembler. If there were to be an alteration in the size of a block of code-text, the linker would have to "reassemble" the code block to make up for the altered "short" jumps and such. In order for the linker to do this it would either need the source code, or it would have to take a stab at disassembeling the object code and hope not to get it wrong. The assembler is designed to AUTOMATICALLY determine the "near"ness or "far"ness of a refrence. This works beautfuly as long as you act like a pascal programmer and only use backward refrences. For the forward refrences you must use a keyword like "near" or "far" or else take what you get, and hope what you get is close enough to work. It should be obvious that the assemblers job is to assemble and the linkers job is to link. MR FRED: At one point you said "what could be simpler" [deleted from this text for brevity]. If it is so simple, I would love to see your compleeted disassembling-assebeling-optomizing-editing-linking-loader on the market. [For a PC or 3B2 prefreable, as these are the machines I have avalible to test it on.] Discalmer: YES! I used x86 refrences, I did this because I like to stick to topics and machines I know, so _PLEASE_, no "there are other machines in existance, you introverted slob..." type flames. And, yes, I am woking on my spelling, but if I waited till my dislexic brain could do it perfectly, nobody would ever see my deathless prose. Rob ("So who asked you anyway?") white.
franka@mmintl.UUCP (Frank Adams) (10/09/87)
In article <384@mcdsun.UUCP> fnf@mcdsun.UUCP (Fred Fish) writes: >3. Now the only choice is to decide which default you want. > For my implementation, it was obvious that near jumps were > the correct default. For another situation, the reverse > might be true. I don't claim that either is somehow > theoretically "better". (Someone else might care to claim > so though, don't let me stop you... :-) It seems like the near jumps are the correct choice, since they take less space. This is not a fantastically important consideration, but I don't see any other considerations whatsoever. It does not seem like an accidental property of the architecture that the near jumps are shorter than the far ones; if they aren't shorter, why have them? -- Frank Adams ihnp4!philabs!pwa-b!mmintl!franka Ashton-Tate 52 Oakland Ave North E. Hartford, CT 06108
henry@utzoo.UUCP (Henry Spencer) (10/11/87)
> ... If you default to "near" jumps, you have the > linker fix up all the jumps that are really "far" jumps ... > [vice versa for defaulting to "far" jumps] > ... In either case, you either grow or > shrink the code as appropriate, in the linker. What could > be easier? In either case, you end up with exactly the same > executable object code. No nops, no "non-optimal" jumps, the > *same* *optimal* *code*. ...I don't claim that either is somehow > theoretically "better"... Hah, caught you, Fred! Not (quite) true unless the linker is fairly sophisticated. There are interdependent situations in which the spans of several jumps depend on each other's size: they can all be "near", but the linker will discover this only if it looks at making them *all* "near" at the same time. A simple one-at-a-time approach with a "far" default will leave them all "far". The level of sophistication needed to spot this amounts to simulating a "near" default, so one might as well just use that default in the first place. Such situations are admittedly not all that common, but it does supply a reason for picking "near" over "far" if nothing else interferes. -- "Mir" means "peace", as in | Henry Spencer @ U of Toronto Zoology "the war is over; we've won". | {allegra,ihnp4,decvax,utai}!utzoo!henry
fnf@mcdsun.UUCP (Fred Fish) (10/14/87)
>In article <384@mcdsun.UUCP>, fnf@mcdsun.UUCP (Fred Fish) writes: > the linker fix up all the jumps that are really "near" jumps > to be "near" jumps. In either case, you either grow or > shrink the code as appropriate, in the linker. What could > be easier? In either case, you end up with exactly the same > executable object code. No nops, no "non-optimal" jumps, the > *same* *optimal* *code*. Since posting this, I have received some mail from Dean Inada at Peregrine Systems that provided an example where shrinking the code is not really possible without considering more than one candidate jump at a time, something that my current implementation doesn't do. Thus growing the code is the correct choice for my situation. The example Dean provided was essentially: foo: farjump bar ["X" bytes of stuff] farjump foo bar: Where X is just that right size such that neither jump, considered by itself, can be shortened to near, but if we had started with near jumps neither would have been required to be lengthened to far jumps. "X" depends upon the size of your near/far jump sequences. Thus in order to make my original statement true, it is necessary to consider more than one candidate jump simultaneously (LOTS more work). Thus "near" as the default is even more obviously the correct choice for my implementation. In article <117@nusdhub.UUCP> rwhite@nusdhub.UUCP (Robert C. White Jr.) writes: > ALL "short" jumps [add/subtract value from the >instruction pointer directly] are compleetly generated and closed >in the assembler. If there were to be an alteration in the size >of a block of code-text, the linker would have to "reassemble" the >code block to make up for the altered "short" jumps and such. In >order for the linker to do this it would either need the source >code, or it would have to take a stab at disassembeling the object >code and hope not to get it wrong. The assembler is designed to >AUTOMATICALLY determine the "near"ness or "far"ness of a refrence. The only reason that the linker would need to "reassemble" the code block is if the assembler decided to try doing part of the linker's job to begin with. My assembler doesn't, thus my linker doesn't have to go through the pain you described above. > It should be obvious that the assemblers job is to assemble >and the linkers job is to link. I couldn't agree more... >MR FRED: At one point you said "what could be simpler" [deleted from this text >for brevity]. If it is so simple, I would love to see your compleeted >disassembling-assebeling-optomizing-editing-linking-loader on the >market. [For a PC or 3B2 prefreable, as these are the machines >I have avalible to test it on.] You very likely will see it some day, though I doubt it will run on the PC or 3B2 except possibly as part of a cross development environment. -Fred -- # Fred Fish hao!noao!mcdsun!fnf (602) 438-3614 # Motorola Computer Division, 2900 S. Diablo Way, Tempe, Az 85282 USA