[net.lang] structured assembler vs. C

rb@ccivax.UUCP (rex ballard) (02/13/86)

The previous article suggests that we write the 'first draft' in C and
then rewrite it in assembler.  In support of this, the author claims:
A: the rewrite in assembler will be faster/more efficient.
B: the assembler will be more maintainable.

On point B:, studies have shown that the number of errors or changes is
exponentially related to the number of lines of code.  One study indicates
that the average is one error per 1000 lines.  Another indicates 1 change
(as a result of error or enhancement) per 25 lines.  Both studies indicate
that this is requardless of language.  The second study indicates exponential
increases in errors per module.  There are also few 'static verification
tests' available in assembler.  Lint on the other hand, provides such
capabilities even to the 'heuristic level'.  Had lint not been written,
C would probably not be as popular as it is.  Perhaps providing lint
with all compilers would reduce resistance to it in such arenas as
personal computers.

While it is true that assemblers may reduce time, the most common savings
are in the form of argument passing through registers rather than the stack.
This could be remedied through the compiler, frame oriented hardware
(such as CCI's 6/32), or other 'Automated approaches'.  An assembler routine
which expects certain values in certain registers tends to imply higher
maintenence costs, since it is not always convenient or practical to
reserve/assign those registers explicitly.  Transfers and alignment
of registers may actually offset the time saved using the assembler
module in the first place.

On point A:, ideally, all software should be written twice.  Reality
seems to prevent that.  If it is possible to rewrite, doing so in
the same language provides similar benifits, without adding the
possibility of mis-interpretation and new errors in translation.

Profilers can identify 'hot spots' where excessive time is being
spent.  These are viable candidates for assembler or 'fast but no morals'
C code.

Certain problems like 'context switches' which involve explicit use of
specific registers (like the stack pointer), or 'jump tables' are
not practical in C, and have to be written in assembler anyway.

Calling a C routine from assembler is relatively easy, calling assembler
routines is harder but possible and practical for those 'really tight loops'.

Of course the same is true for any other 'high level language' of the
3rd generation type (Fortran, C, Cobol, PLM... compiled languages).
C just gives the programmer control at a much deeper level (pointers
with negative indexes...).  About the only thing C doesn't do that
assembler provides is absolute addresses of variables (typically
port addresses, trap vectors, and registers).  Perhaps these are
worth considering as improvements for C, but not for replacing the
compiler with a human being.

Fourth generation languages (Forth, SmallTalk, Neon...) may find
better ways of solving these problems, but this is still a new field
where good standards have yet to evolve.  Eventually, we will see
a 'fourth generation' equivelent to C, or even Ratfor, which will
replace C the same way assembler replaced machine code and Fortran and
C replaced assemblers.

As to programmer time being more important than user time:  To a point,
I would agree, but when looking at all the PC compatibles and seeing
how "XYZ software crashes on ABC's computer" because of 'fast assembler
routines' that weren't "vectored in", I wonder if the speed is really
worth all the lost business.  Also, even though 'system response time'
may not be optimal, the interface, interactive nature of the work, and
the 'presentation level' interface are much more significant factors.
Dvorak keyboards, Mice, number of disk accesses required to complete a
search/grep and other hardware and software design issues have more to
do with the effecient use of 'User time' than the execution time of
the code (which represents less than 1% of the actual time on most systems).

In vertical market situations, where the customers needs change weekly,
the quicker you can get those changes made, the better.  Is looking
through 100,000 lines of assembler quicker than looking through
5000 lines of C?

herndon@umn-cs.UUCP (02/17/86)

<** Pet Flame On **>
  Actually, it didn't hasn't always been impossible to construct
jump tables in C.  In the Good ol' Days before 0 AL (After Lint),
the "goto" statement would take any operand as a destination.
A label simply had a machine address as a value, and "goto" simply
jumped there.  Thus one could do things like:

foo() {
a:
	bar(a);
}

bar (x)
{
	goto x;
}

and blow one's stack out of the water.  All kinds of unsavory things
were possible, and generally undesirable.  Unfortunately, with the
coming of "strong typing" (and its concomitant weak ideas), the
type label got lost.  One cannot type coerce a label to anything else,
nor anything else to a label.  Very discouraging to those of us who
occasionally like to jump to arrays full of machine code (say, for
direct interpreters, etc.).  Admittedly, these kinds of applications
are generally pretty rare, but doing it now requires an array of
procedure addresses, and one often has to use an enormous stack
if each procedure calls the next.  This is may not be desirable if
there is no reason to return to the caller, as in tail recursion.
It's not optimized in C compilers like it often is in lisp.
  Having a type "label" for type coercions, like the type "void",
would be very useful to me in occasional, rare applications.
  Oops!  Don't get me wrong -- I like strong type typing in practice.
It has saved me countless bugs which would have had me stymied for
days.  However, the "theory" of strong typing as it exists seems
very weak.  Maybe someday, it will get better, but since it appears
closely related to semantic issues, I doubt it.
<** Pet Flame Over **>


				Robert Herndon
				...!ihnp4!umn-cs!herndon