[comp.lang.misc] using

cik@l.cc.purdue.edu (Herman Rubin) (08/03/88)

In article <11699@steinmetz.ge.com>, davidsen@steinmetz.ge.com (William E. Davidsen Jr) writes:
> In article <37406@linus.UUCP> munck@faron.UUCP (Robert Munck) writes:

> | Mixing languages is not a terrific idea if your program is to be
> | maintained and enhanced over the years.  Languages change, too, and
> | trying to keep up with diverging languages...
  
>   A few words on that... One way to preserve portability is to get the
> whole program working in C, and identify the problem areas. Then the
> assembler output of C can be massaged by hand for efficiency. By always
> starting with compiler output you avoid having the C source and the
> assembler source out of phase to the point where the C won't work
> anymore.
> 
>   I know this is clumsy, that's why I recommend it. It will make you
> think before spending a lot of time trying to make small gains in
> performance, as opposed to rethinking the whole algorithm.

But what do you recommend if your languages (C, FORTRAN, etc.) are
incapable of doing even a remotely reasonable job with the program?
I can provide relatively simple examples of programs which can be
handled in a reasonably portable manner, but for which C does not 
have the concepts needed at all.  These are not esoteric concepts;
anyone who understands that machine words are composed of bits in
a structured manner, and that the bits of a structure can be used in
any manner compatible with the structure, can understand them.

Another problem is the fact that what one can do with a single instruction
on one machine takes many on another.  An example is to round a double 
precision number to the nearest integer.  If you think this is unimportant,
every trigonometric and exponential subroutine, or a subroutine computing
elliptic functions, etc., uses this or something similar.  On some machines,
this should be a moderately lengthy series of instructions.  On others, there
is a machine instruction which does precisely this.  Now many (all that I have
seen, but I have been told that there are ones which do not have this problem)
C compilers will not allow asm instructions to use the compiler's knowledge of
which registers are assigned to which variables.

C cannot do the job.  The present assemblers have the disadvantage that they
are atrociously difficult to read and write.  This is not necessary; COMPASS
for the CDC6x00 and its descendents were easier, but not easy enough, and CAL
on the CRAY easier still, but more can be done.  I wonder how difficult it 
would be to use an overloaded operator weakly typed assembler.  Some think that
C is this; maybe it was intended as a replacement for such an object, but it
fails badly.

-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hrubin@l.cc.purdue.edu (Internet, bitnet, UUCP)

ok@quintus.uucp (Richard A. O'Keefe) (08/04/88)

In article <856@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
>Another problem is the fact that what one can do with a single instruction
>on one machine takes many on another.  An example is to round a double 
>precision number to the nearest integer.  If you think this is unimportant,
>every trigonometric and exponential subroutine, or a subroutine computing
>elliptic functions, etc., uses this or something similar.  On some machines,
>this should be a moderately lengthy series of instructions.  On others, there
>is a machine instruction which does precisely this.  Now many (all that I have
>seen, but I have been told that there are ones which do not have this problem)
>C compilers will not allow asm instructions to use the compiler's knowledge of
>which registers are assigned to which variables.

I am sympathetic to Rubin's position, but I can't quite tell which side
he is arguing on here.  Let's replace his example by a still humbler one:
integer multiplication.  I have to include the operation of integer
multiplication in assembly code generated by a "smart" macro processor.
MUL doesn't quite take the non-portability prize; I think DIV does that.
But even MUL is a subroutine call on some machines (not always obeying
the protocol used elsewhere), an instruction on some, a sequence of 20-40
instructions on others.  It is a relief to turn to C (pathetic though a
language which doesn't report overflows may be) and not have to worry
about that[*].  The situation with floating-point is worse.  Once you start
porting generated assembly code between machines with 32/16/11/8 general
registers and varying numbers and arrangements of floating-point registers,
it pretty soon occurs to you that it doesn't matter whether the compiler
will "allow asm instructions to use the compiler's knowledge of which
registers are assigned to which variables" or not, it's not going to port
_nohow_.

If you want to mingle small chunks of assembly code with C code, I'm
convinced that asm("..") is obsolete: /usr/lib/inline is so much better
(e.g. you can switch from C implementations of such functions to inline
assembly code without changing your source, and better still, change _back_).
A trap for asm("...") users: some C compilers switch off optimisation in a
function if you use asm(), even if all you did was plant a label or comment.

[*] I have seriously considered writing C routines to do integer *, /, %,
and calling them from the generated assembly code.  What was that about using
assembly code to get access to machine instructions?

smryan@garth.UUCP (Steven Ryan) (08/05/88)

>                                                 I wonder how difficult it 
>would be to use an overloaded operator weakly typed assembler.  Some think that
>C is this; maybe it was intended as a replacement for such an object, but it
>fails badly.

Compass macros can implement something akin to overloaded operators and typed
operands, although the 8-character limitation is difficult.

On the 205 assembler, Meta, our project had procs (=macros) to do things like

          WHILE      P,EQ,TRUE                    while p do
          IF         [T_EXP,L,EXP_OPCD],EQ,O_RADD   if t_exp[l].exp_opcd=o_rad
          THEN                                       then
          GFIELD     T_EXP,L,EXP_OP1,L                l:=t_exp[l].exp_opcd
          ELSE                                       else
          CALL       XYZ,[L,IN],[P,OUT]               xyz(l in,p out)
          IFEND                                     ifend
          WHILEND                                  whileend

daveb@geac.UUCP (David Collier-Brown) (08/05/88)

From article <856@l.cc.purdue.edu>, by cik@l.cc.purdue.edu (Herman Rubin):
> But what do you recommend if your languages (C, FORTRAN, etc.) are
> incapable of doing even a remotely reasonable job with the program?

>...   Now many (all that I have
> seen, but I have been told that there are ones which do not have this problem)
> C compilers will not allow asm instructions to use the compiler's knowledge of
> which registers are assigned to which variables.

  There are two problems here: expressive power of the language and
quality of the compiler/embedded-assembler interface.

Problem 1: Language.
  Get a better language.  No smileys here, its a serious suggestion.
C may be my favorite language, but I won't claim it is either modern
or consistently well-implemented.  Use FORTRAN for numerical
problems if C gets in the way, C for structure-shuffling if FORTRAN
gets in the way.  Use Ada or C++ if the non-extensibility of either
gets in the way.  

Problem 2: Compilers.
  Get a good one, for whatever language you buy.  Make sure it will
use the machine's standard[1] call interface if one exists, so you can
mix languages.  

   An anecdote: I once used an Ada[2] cross-compiler, back when Ada
was **real** new and implementations tended to be weak.  When I had
to generate an in-line trap, I discovered I could state it all in
the HLL.  One declaration of a bit pattern (which was the
instruction), one package definition to define the interface to it
and umpty-dozen pragmas to say 
	put it in-line
	parameter A must be in register An and An+1
	parameter B must be in register R1
   Net result? It generated almost "perfect" code for the trap,
without any register-moves or call-return linkages.  This is
extensible to modeling almost any machine instruction[3], and one can
always re-write the package to turn it into a different instruction
(or sequence of instructions) if you have to port it.


  --OR--
  You can try to invalidate the problem, and make the compiler
generate optimal code.  Yes, I said MAKE.

  Another anecdote: last year, I had to speed up a critical inner
loop in a very large system written in Pascal.  The compiler **would
not** accept a declaration for the construct that was needed (a
pointer to an array greater than its normal maximum size).  It was
initially done by allocating the array in the non-pascal startup
code and using inline assembler to access it.  It was ***slow***.
  When I looked at the code generated, inlining had only saved me
the call-return instruction pair, not the required register/stack
setup for the call.
  So I wrote out the addressing expression in Pascal, as arithmetic.
The code it generate was one instruction "poorer" than the optimum,
because it moved the result from the general registers to the
address registers at the end.  This was 6 instructions better than
the inline assembler, and 8 better than out-of line instructions.
(The move occurred as a result of my using an explicit union: if the
language understood casts, it might have disappeared too).
  Result?  We got our speedup, even though Pascal "knew" it wasn't
supposed to be that helpful.

  So don't dispair, you can get out of almost any problem in
Confuser Science: you just have to go back to first principles and
attack the meta-problem.

--dave (no cute statement today) c-b
[1] Including de-facto ones, if the hardware one is yucky...
[2] Ada is a trademark of the U.S. Gov't (Ada Joint Project Office)
[3] This is generally a super-non-portable idea, though.
-- 
 David Collier-Brown.  |{yunexus,utgpu}!geac!daveb
 Geac Computers Ltd.,  |  Computer science loses its
 350 Steelcase Road,   |  memory, if not its mind,
 Markham, Ontario.     |  every six months.