cik@l.cc.purdue.edu (Herman Rubin) (07/31/90)
This appeared in an article posted to comp.lang.fortran, and I believe it illustrates a point about the weaknesses of HLLs (The poster was referring to C at this point) and compilers. In article <4922@munnari.oz.au>, ok@mudla.cs.mu.OZ (Richard O'Keefe) writes: > double nint(double x) > { > return ceil(x + 0.5) - (fmod(x*0.5 + 0.25, 1.0) != 0); > } > > is all it takes.] I have not checked the code, but this points out what is wrong with the present HLLs and that compilers cannot be expected to overcome the problem. If this #define were used, then this block of code would be inserted wherever this is wanted, even if there is a machine instruction which does the job. I do not see how a compiler can recognize that the complicated body of code can be replaced by a single instruction and make that substitution. One could put that one in, but another will arise, and another. And these will continue to crop up as long as the language primitives are restricted as they now are. -- Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907 Phone: (317)494-6054 hrubin@l.cc.purdue.edu (Internet, bitnet) {purdue,pur-ee}!l.cc!cik(UUCP) -- Send compilers articles to compilers@esegue.segue.boston.ma.us {spdcc | ima | lotus| world}!esegue. Meta-mail to compilers-request@esegue.
gl8f@astsun7.astro.Virginia.EDU (Greg Lindahl) (07/31/90)
In article <1990Jul30.180439.26627@esegue.segue.boston.ma.us> cik@l.cc.purdue.edu (Herman Rubin) writes: >This appeared in an article posted to comp.lang.fortran, and I believe it >illustrates a point about the weaknesses of HLLs (The poster was referring >to C at this point) and compilers. Actually, this "weakness" can be solved by a smart linker. >In article <4922@munnari.oz.au>, ok@mudla.cs.mu.OZ (Richard O'Keefe) writes: > >> double nint(double x) >> { >> return ceil(x + 0.5) - (fmod(x*0.5 + 0.25, 1.0) != 0); >> } >> >> is all it takes.] > >I have not checked the code, but this points out what is wrong with the >present HLLs and that compilers cannot be expected to overcome the problem. >If this #define were used, then this block of code would be inserted wherever >this is wanted, even if there is a machine instruction which does the job. Right. It's a bit silly to expect the compiler author to support any possible hardware instruction and any possible piece of convoluted code that might use that instruction. However, if you have a list of things you want done fast, then write a set of HLL subroutines that accomplish these things. (NINT() is a Fortran intrinsic already, for example.) This is your portable library. Then for each architecture with a smart linker, write the necessary inline assembly files and link appropriately. (For NINT(), the vendor's Fortran should do it for you.) I note that the MIPS linker, Sun's linker, and gcc all have no problems doing this efficiently. The subroutine linkage gets optimized away and you are left with only the single, efficient instruction. >I do not see how a compiler can recognize that the complicated body of code >can be replaced by a single instruction and make that substitution. One >could put that one in, but another will arise, and another. And these will >continue to crop up as long as the language primitives are restricted as >they now are. You have to have list of these primitives somewhere, because your language is going to need either operators or functions which accomplish your tasks. That is, unless you want a mind-reading compiler that is a wizard with instruction sets. Your little portable routines define "Herman's Lovely Language", and things can run everywhere at top speed. So, in summary, this is how you do what you want, today, with today's HLLs. Doing it this way is much easier than designing your own HLL, which you have declined to do. -- "In fact you should not be involved in IRC." -- Phil Howard
ok@goanna.cs.rmit.OZ.AU (Richard A. O'Keefe) (08/01/90)
In article <1990Jul30.180439.26627@esegue.segue.boston.ma.us>, cik@l.cc.purdue.edu (Herman Rubin) writes: > In article <4922@munnari.oz.au>, ok@mudla.cs.mu.OZ (Richard O'Keefe) writes: > > double nint(double x) > > { > > return ceil(x + 0.5) - (fmod(x*0.5 + 0.25, 1.0) != 0); > > } > I have not checked the code, but this points out what is wrong with the > present HLLs and that compilers cannot be expected to overcome the problem. > If this #define were used, then this block of code would be inserted wherever > this is wanted, even if there is a machine instruction which does the job. Er, that's a FUNCTION, sir, not a macro (#define). When a compiler sees a call to nint(), it will generate a procedure call. (Yes, in C++ and gcc I could say "inline double nint(...) but I *didn't*.) > I do not see how a compiler can recognize that the complicated body of code > can be replaced by a single instruction and make that substitution. Nobody else is _expecting_ the compiler to do that. To start with, the only reason that I gave C code for nint() at all is that some C compilers ALREADY have it as a built-in math function but some haven't; I said "here is what you can do if you haven't already got it". I have commented before on the ".il" facility provided by the Sun compilers. I would like to point out once again that they provide a comparatively clean way of getting at any instruction you like from within C. Here's what we do in this case. Suppose we have a machine running SunOS on which the way of rounding a double precision float to integer format is cvtdir <source>,<destination> (supposing this saves me looking up manuals to find out what the instruction is really called on a 68881) and suppose that the machine is otherwise like a 680x0. I would write a .il file # This file defines nint() using a hardware instruction .inline _nint,8 cvtird sp@+,r0 .end Then I would write in my C source code #ifdef imaginary_sun_model extern double nint(); #else double nint(x) double x; { extern double ceil(), fmod(); return ceil(x + 0.5) - (fmod(x*0.5 + 0.25, 1.0) != 0); } #endif Compiling this on the right kind of Sun machine, I'd do cc -O myprog.c nint.il Compiling it on any other kind of machine, I'd do cc -O myprog.c and I would have a program which exploited the 'cvtdir' instruction IF THAT INSTRUCTION EXISTS but which ran just fine on a machine which had no such instruction, without needing any assembly code hacking on the latter machine. The .il approach *WOULD* substitute exactly the right single instruction in the right places (the .il expansion pass is smart enough to combine movd _foo,sp@- cvtdir sp@+,r0 to cvtdir _foo,r0 so I do mean a single instruction). Surely this is a good approach? We use abstraction to hide the machine- dependent details. We have an operation which makes sense on its own however it is implemented; the rest of the program uses it _as if_ it were a call to a C function, and it may be implemented by a call to C code, a call to assembly code, inline expansion of C code, or inline expansion of assembly code. The V.3/386 C compiler has a similar feature, although there the assembly definitions are included in the C source code (asm functions). This idea can of course be applied to Pascal or Modula-2 or Fortran just as well as it can to C, and assembly code inserts are already part of standard Ada. -- ok@goanna.cs.rmit.oz.au -- Send compilers articles to compilers@esegue.segue.boston.ma.us {spdcc | ima | lotus| world}!esegue. Meta-mail to compilers-request@esegue.
bart@videovax.tv.tek.com (Bart Massey) (08/01/90)
In article <1990Jul30.180439.26627@esegue.segue.boston.ma.us> cik@l.cc.purdue.edu (Herman Rubin) writes: > This appeared in an article posted to comp.lang.fortran, and I believe it > illustrates a point about the weaknesses of HLLs (The poster was referring > to C at this point) and compilers. > > In article <4922@munnari.oz.au>, ok@mudla.cs.mu.OZ (Richard O'Keefe) writes: > > > double nint(double x) > > { > > return ceil(x + 0.5) - (fmod(x*0.5 + 0.25, 1.0) != 0); > > } > > > > is all it takes.] ... > I do not see how a compiler can recognize that the complicated body of code > can be replaced by a single instruction and make that substitution. ... I tend to like the GCC approach to all this a great deal. For the above program, the nint() primitive above might be coded something like inline double const nint(double const x) { #ifdef frobozzco double result; asm("\tfrobozz_nint\t%1,%0":"=f"(result):"f"(x)); return result; #elif foobarco double result; asm("\tfoobar_nint\t%0,%1":"=f"(result):"f"(x)); return result; #else return ceil(x + 0.5) - (fmod(x*0.5 + 0.25, 1.0) != 0); #endif } Note that the above code generates a single inline machine instruction on machines which support it, and otherwise generates the best sequence of inline machine instructions it can. This is as close as I've ever seen to a "user-extensible code generator", and it seems to solve a large class of such problems very well, at least IMHO, by shifting the burden of code generation in specialized applications from the compiler designer to the application programmer, the latter presumably having a better idea of what he/she wants or needs. Note also that in G++, one can even declare the standard C operators to be implemented by such inline asm functions, and thus get, for example, maximum efficiency from a C++ complex number package on a machine which supports complex numbers directly in the FPU. I've seen Mr. Rubin post on this topic before, and I would humbly suggest that, if he would be so generous, he could benefit the computing community greatly by generating a GCC-compatible header file containing a bunch of these inline asm functions for the complicated numerical operations he feels are important to optimize well, and for a number of common CPUs. I know that I, for one, would be very interested in the results of such an exercise. For a similar exercise in complex FPU insn utilization, at least for a single processor, see Matthew Self's "math-68881.h", distributed with GCC. I look at GCC's "inline asm function" feature as a way to extend the semantic primitives of the language, in a syntactically compatible way. So far, it seems to me to have worked pretty well. Bart Massey ..tektronix!videovax.tv.tek.com!bart ..tektronix!reed.bitnet!bart -- Send compilers articles to compilers@esegue.segue.boston.ma.us {spdcc | ima | lotus| world}!esegue. Meta-mail to compilers-request@esegue.
cik@l.cc.purdue.edu (Herman Rubin) (08/19/90)
In article <13071@mentor.cc.purdue.edu>, ags@seaman.cc.purdue.edu (Dave Seaman) writes: > In article <60344@lanl.gov> jlg@lanl.gov (Jim Giles) writes: > >From article <13035@mentor.cc.purdue.edu>, by ags@seaman.cc.purdue.edu (Dave Seaman): > >> So what do you do if the target machine has more than one Fortran > >> implementation and the different versions are not even compatible with each > >> other? > >I'm not interested in whether the Fortrans (or Cs, Pascals, Modulas, > >etc.) are compatible with each other, I only want them to be _callable_ > >from each other on a way which appears consistent from the HLL point of > >view. If this means that several different bridges to Fortran have to > >be present on the low-level for different Fortrans, that tough. Of > >course, implementors who avoid use of industry (or vendor) standard > >calling sequence conventions are shooting themselves in the foot by > >making their produce harder to use from within existing environments. > The two examples I gave of incompatible Fortrans were both cases of > vendor-supplied Fortrans that ran on the same machines and were reasonably > compatible at the source language level (though with slightly different > extensions), but which were fundamentally incompatible at the object code > level. They are definitely not callable from each other. > An implementor of some other language (Pascal, say) does not need to support > every incompatible version of Fortran on the machine. It's more cost-effective > to pick just one Fortran to support. There is a not too expensive alternative to this problem, and other interface problems. That is, to put the necessary software to handle various call and return procedures in the various compilers. Each compiler expects its input arguments in a clearly defined manner, and also its register saving procedures, and there is no good reason why this information could not be incorporated into another compiler. This could even be used for machine language calls. I did not say that there were no costs, in particular efficiency costs, involved. But it provides a kludge which is easy to implement. It also gets around the problems of name changes by the compiler in many cases. In the UNIX systems I have seen, in general a Fortran program cannot call a C program because of the name problem. It may be necessary to produce these interfaces in assembler, but this will be a small cost compared to the alternatives of language translation or recompilation. Many algorithme at Purdue were not callable from one Fortran to another, and this could have been handled. -- Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907 Phone: (317)494-6054 hrubin@l.cc.purdue.edu (Internet, bitnet) {purdue,pur-ee}!l.cc!cik(UUCP)