From: rrt@mpd.tandem.com (Robert Teisberg)
Newsgroups: alt.folklore.computers
Subject: Re: The need for an assembler (was: Favorite CPU)
Date: 21 Aug 92 00:40:17 GMT
Reply-To: rrt@amadeus.UUCP (Robert Teisberg)
Organization: /etc/organization

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.

True enough, but the best existing compilers do a better job than you
give them credit for.

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

Your compiler experience appears to be limited.  Check out MIPS cc
with -O3 sometime.

>- 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 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. 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. 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. How do you
>  express these minute differences to your C compiler ?

You don't if you're smart.  If your compiler can't tell that a value
is no longer needed, you need a new compiler.  If you're using a
processor for which it's hard for the compiler to choose the best
instruction sequence, you need a new processor (this is what the RISC
revolution is all about).  What do you do with your assembly language
program when you discover six revisions later that after all you DO
need the saved contents of the register 40 lines later?  Better yet,
if you change a program that once needed to save the value in such a
way that you can now safely discard it, do you recode the bit-test to
make it faster, or do you leave it alone to avoid the risk of
injecting a bug?  What if some future Z80 superset processor can do
bit-tests faster than ANDs or rotates?  What do you do when you need
to port your code to a 68000?  These are weighty issues if the program
is written in assembler, but except for the last no one even thinks
about them if it is coded in a HLL.

>- 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. No problem from within assembler. 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.

Let me express this a little differently.  If you are dependent on a
run-time library which was designed to be used by assembly language
programs, it is easier to use the library if you code in assembly
language.  Why am I not surprised by this?  Most tools are easiest to
use when they are used in the way in which they are designed.  

As I said earlier about compilers, if your run-time library is
horrible, you need a new run-time library.

>- 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 vaguely remember doing
>  that for HOURS to get a tape reading program to work exactly right.
>  How do you do this in C ?

You "just sit down with the CPU manual", etc.  That sounds easy.  So
how come you spent "HOURS" getting it right?

What do you do when you port your code to a faster processor?  Have
you ever had to code a timing loop in the face of cache effects?  The
ideal solution to the problem of tight delay loops is a
sub-microsecond granularity hardware clock that you can read repeatedly
until it contains the value you are waiting for.  It is
processor-independent, clock-speed independent, and
language-independent.  Nowadays, you can often get one for free as
part of your CPU chip.

Actually I'll grant you this one in part.  Sometimes you are stuck
with hardware that forces sub-optimal software design on you.  This is
one of the places where I too use assembler.  But I don't therefore
proclaim the virtues of assembly language; I just breathe a sigh of
relief that I can solve the problem without going back and fighting
the engineer over adding a $2.00 part to the board (then when I have
to do the job over again with a new processor or a higher clock speed
or faster code memory or an instruction cache or ... I curse the
engineer once again for not getting it right the first time).

Now that I look back, I see that most of your justifications for
assembly language are based on the premise that you can't change the
hardware or the tools, which is sadly often the case.  And when it is
true, I make the same choice.  I also point out to management that
they are choosing to pay my salary for a longer period than otherwise
necessary in order to reduce the recurring cost of hardware.  This is
sometimes the right solution, but not always, and without proper
accounting for non-recurring engineering expense, the choice is almost
inevitably to minimize the expense that can be measured and ignore the
one that cannot :-(.
 
>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.

Well, there are a few things.  There are also those who would argue
that the problem with C is that it is a LOW-level language.  A
high-level language would let you say what you mean rather than what
you want the processor to do, and the compiler could choose the best
implementation for whatever bizarre combination of hardware you care to
to put it on.

>Note: I am not advocating writing everything in assembler. That's
>crazy. But good hand-coded assembler still has its place, in
>particular in the tight spots of device drivers and realtime systems
>(where every clock cycle counts). Therefore I agree that assembler is
>RARELY neccessary.

Actually I agree with nearly every word of this paragraph.  However, I
would point out that real-time programming is coming less-and-less to
mean squeezing every clock cycle out of the code and more-and-more to
mean making execution speed predictable (interestingly, the fastest
systems available today are poorly suited to real-time applications
because their performance is unpredictable).  What I'd really like is a
high-level language that lets me express real-time constraints in a
form that offers hints to the compiler about the appropriateness of
trading off space for time and allows the compiler to tell me whether
the constraints can be met.


-- 
Bob Teisberg @ Tandem Computers, Inc. | rrt@mpd.tandem.com
14231 Tandem Blvd.                    | (512) 244-8119
Austin, Texas  78728                  |
Jimmy and I have a deal.  Jimmy doesn't hack code; I don't speak for Tandem.
Newsgroups: alt.folklore.computers,comp.edu,comp.human-factors,comp.misc,comp.programming