From: wollman@sal.emba.uvm.edu (Garrett Wollman)
Subject: Re: The need for an assembler (was: Favorite CPU)
Organization: University of Vermont, EMBA Computer Facility
Date: Fri, 21 Aug 1992 01:13:17 GMT

In article <5242@unixhub.SLAC.Stanford.EDU> ralph@falcon.SLAC.Stanford.EDU (Ralph Becker-Szendy) writes:
>Nonsense. There are many (efficient!) things you can do in assembler
>but not in C. And I'm sure even the best optimizing compilers don't
>know all the tricks you can pull in assembler.

>- If I call any subroutine or function in C, a large set of registers
>  will be saved in some fashion, often unneccesarily.

If you have a compiler that does mega-IPA (like MIPS), on a machine
with a reasonably sized register file (like MIPS), or almost any
compiler on a machine with register windows (SPARC), then subroutines
may use entirely disjoint sets of registers.

>- When I want to test a particular bit in assembly language, I have
>  several ways of doing it (in the Z80 for example I can rotate if it
>  was the first or the last bit, I can mask and test, or I can do a bit
>  test instruction).

In C, you simply use the `and' (&) operator, and the compiler will
pick whichever is fastest for your operation.

>  In some situations, some of these ways may be
>  better than others. Example: I just read the status register from a
>  device.  If I don't need the register any longer, I just mask the bit
>  I want with an AND and check the result for zero/nonzero; this is the
>  fastest method.

On a three-operand machine, it's extremely easy to do this, and any
RISC compiler worth its salt will do it:

   ; status value in %r2
   load %r1,#mask
   and %r1,%r2,%r0 
   bCC label
   nop			; fill delay slot

(In most RISC machines, r0 is a source of zeros and a sink for
anything.  In some machines, however, arithmetic instructions do not
set the condition codes, and an explicit comparison must be made.)

>  If I care about the whole content, but need a quick
>  look at the top or bottom bit, I rotate the registers so the desired
>  bit walks into the carry flag and test that.

On modern architectures, this doesn't buy you anything.  Most
reasonable instruction sets will branch on any condition you may
happen to like.  Some machines don't even *have* a rotate instruction!

>  Only if I really need the
>  whole status register unmodified do I have to do a slow bit-test
>  operation, or waste another register on saving/testing.

When registers come a dime a dozen, this isn't something you really
need to worry about.

>  How do you
>  express these minute differences to your C compiler ?

You don't.  Your C compiler is quite capable of reading your code to
determine if a particular variable is dead at a particular point, and
it can do many other things with a greater reliability than most human
programmers (for example, loop-strength reduction).

>- If there is a useful routine (like output a character) which is
>  provided with a strange calling sequence (the character has to be in
>  register X and a function code in register Y), I can not use it from
>  within C, because there is no general way to express all possible
>  calling conventions.

So don't use that routine.  Or use a modern architecture where there
is only ONE calling convention.  (Sadly, however, there are still
possible differences where large aggregates are passed around, some by
reference, some by value, and some by even uglier means.)

>  If I even touch
>  putc or printf I am deep in the mess of a horrible run-time-library,
>  which is liable to be a lot less efficient.

If your run-time library is horrible, get a new one.  If your putc
isn't defined as an inline, get a new one.  (Here's a good example:

static inline int __sputc(int _c, FILE *_p) {
        if (--_p->_w >= 0 || (_p->_w >= _p->_lbfsize && (char)_c != '\n'))
                return (*_p->_p++ = _c);
        else
                return (__swbuf(_c, _p));
}


>- If I need a really tight timing delay loop (say a microsecond), I
>  just sit down with the CPU manual, count clock cycles, and do the
>  correct number and type of instructions (pick the correct instructions
>  to get the right number of clock cycles).

I hope I never have to maintain any code like this.  The speed of
modern microprocessors is increasing every month, and such a delay
loop will be obsolete in less than two years.  (Of course, if you're
still working on 1970s technology microprocessors, like the Z80, then
you don't have to worry about this.  But then, the only excuse for
using such a processor is as an embedded controller, where it is
reasonable to use assembly and you don't have to worry about someone
changing the CPU speed out from under you.

>  I vaguely remember doing
>  that for HOURS to get a tape reading program to work exactly right.
>  How do you do this in C ?

You don't.

>So, C is not the answer to all questions. There are LOADS AND LOADS of
>things which can not be expressed in C; and there are some thing which
>any HLL compiler will do less efficiently than handcoded assembly.

Depends on your definition of `efficient'.  Sure, it is possible for
hand coded assembly to run faster than compiler output, but it's not
very efficient if you take eighteen months to laboriously hand-code a
product, and your competition can use modern techniques to get a
product out in six; unless you're IBM, they'll be wiping your guts all
over the floor...

-GAWollman

-- 
   Garrett A. Wollman  = wollman@emba.uvm.edu = UVM is welcome to my opinions
                       =    uvm-gen!wollman   =
   That's what being alive is all about.  No deity, no higher goal
   exists, than to bring joy to another person.    - Elf Sternberg
Newsgroups: alt.folklore.computers