[comp.lang.c] Types

franka@mmintl.UUCP (Frank Adams) (01/01/70)

In article <14039@topaz.rutgers.edu> ron@topaz.rutgers.edu (Ron Natalie) writes:
>> I must disagree.  The default compiler settings should cater neither to
>> professionals porting code, nor to professionals doing local development,
>> but to the occasional or novice programmer, who is trying to get his newly
>> written, probably small, program to run.
>
>And I must disagree with you ... The default action for the compiler should
>be to ACT NORMALLY.

In most cases, this is sufficient.  But consider the issue of memory models
for the 8086.  (Yes, I hate the '86, too; but that doesn't make it go away.)
The novice probably wants the small model.  The pro most likely doesn't.  In
this case, the novice should be catered to.

(Anyone doing serious development on an 8086 has to think about segments and
probably make changes to their code to take them into account.  Large model
runs too slowly, and small model isn't big enough.  This is what is wrong
with the 8086 architecture -- high level language programmers shouldn't have
to be concerned about such things.)
------------------------------------------------------------
I am going on vacation.  I am unlikely to see any followups posted to this
message, so please mail me copies of any responses.  Unless they are marked
otherwise, I will assume that any replies to this message are intended for
public consumption.
-- 

Frank Adams                           ihnp4!philabs!pwa-b!mmintl!franka
Ashton-Tate          52 Oakland Ave North         E. Hartford, CT 06108

hrubin@osupyr.UUCP (05/10/87)

In article <734@sdchema.sdchem.UUCP>, tps@sdchem.UUCP (Tom Stockfisch) writes:
> In article <7264@brl-adm.ARPA> lyle@ads.arpa (Lyle Bacon) writes:
> 
> >	C is an evolving language.  I will make a possibly sacrilegious
> >suggestion that the type "complex" be incorporated.
> >	The purest says:" Well, one can just define a structure complex."
> >	...However, the resultant code form using structures and func-
> >tions is much less readable and harder to check....
> >P = complex_mult(A, complex_mult(B, C));
> >
> >P = A * B * C;
> >is more easily read and checked.
> 
> 
> This only solves the problem for the type "complex".  What about vectors
> and matrices and (use your imagination)?

 What we people who can program using the power of the computer really need
to do is convince the X3J11 committee to accept the idea that overloaded
operators, defining of new types (not like C++), defining of operator
symbols corresponding to operations not included in the default language,
forcing inline, substitution of compiler-determined locations in inserted
assembler instructions, and other versatile devices, and in general enabling
the production of good semi-portable code is worthwhile.
-- 
Herman Rubin
Until mid May:
Department of Statistics, Cockins Hall, 1958 Neil Avenue
Ohio State University, Columbus OH43210
hrubin@osupyr or cbosgd!osu-eddie!osupyr!hrubin or ts0474@ohstvma.bitnet
"Permanent":
Department of Statistics, Purdue University, West Lafayette IN47907
hrubin@l.cc.purdue.edu or ihnp4!pur-ee!stat-l!hrubin or hrubin@purccvm.bitnet

guy@gorodish.UUCP (05/12/87)

> > This only solves the problem for the type "complex".  What about vectors
> > and matrices and (use your imagination)?
> 
>  What we people who can program using the power of the computer really need
> to do is convince the X3J11 committee to accept the idea that overloaded
> operators, defining of new types (not like C++), defining of operator
> symbols corresponding to operations not included in the default language,
> forcing inline, substitution of compiler-determined locations in inserted
> assembler instructions, and other versatile devices, and in general enabling
> the production of good semi-portable code is worthwhile.

Good luck.  I suspect you'll need it.

1) Why is it worthwhile to throw all this stuff into C *now*?  One
   thing to note - the more stuff you throw into ANSI C, the longer
   it'll take to see ANSI C implementations, and the longer you'll
   have to wait for all these whizzy features.

2) Why is "defining of new types" followed by "(not like C++)"?

3) Why is "defining of operator symbols corresponding to operations
   not included in the default language" worth the cost of adding
   this?  It is a relatively uncommon feature in programming
   languages, and can complicate the parsing of a language.

4) What does "enabling the production of good semi-portable code"
   mean?  What is the significance of "semi" in "semi-portable"?
   Why do features like overloading of operators "enable the
   production of good semi-portable code", as opposed to the
   production of code in general, or portable code, or whatever?

5) What does "program using the power of the computer" mean?  It
   sounds like a buzzphrase to me.  Plenty of people who don't think C
   should grow without bounds are quite capable of writing efficient
   and portable (and "semi-portable") code.

This looks more like a Christmas list than a practical proposal for
additions to C.  The purpose of a standards effort is *not* to stuff
every feature that somebody thought they needed, or at least wanted,
into the item being standardized.  (To quote Dennis Ritchie - "If you
want PL/I, you know where to find it.")  The language that has every
feature you want doesn't exist, and probably *can't* exist; there are
always tradeoffs, and some features that might seem really nice just
cost too much.

As for "Big changes are needed", well, I shall merely point out that
a LOT of software has been written in C, and is being written in C,
for a host of applications.  I see no reason to believe that this
flow of applications will diminish to a trickle shortly unless this
shopping list of features is added to the language.  (In fact, enough
features added to the language could *itself* diminish the flow of
applications, if it complicates the language or its implementations
to the point that the language is no longer a good choice for the
applications for which it is currently being used.)

leder@ihlpm.UUCP (05/13/87)

In article <18598@sun.uucp>, guy%gorodish@Sun.COM (Guy Harris) writes:
> > 
> >  What we people who can program ... really need
> > to do is convince the X3J11 committee to accept the idea ...
> > the production of good semi-portable code is worthwhile.


I think that your words taken completely out of context provides more
insight that within the context that they were used.

> 1) Why is it worthwhile to throw all this stuff into C...?

If you don't like the language, why not invent a new one?  And that
is what this author procedes to do.  Why don't we have two languages:

	slim C
	
	   and
	
	fat C

With a few exceptions, the committee has done an admiral job of giving
us a very slightly overweight "slim C".

To get to "fat C" we could start with C++ and add ADA, inline FORTH,
with extensions for COBOL and PASCAL, and maybe just a sprinkling of
anything else someone can think of.  In fact the compiler should be
self-modifyable and extenable just in case we left anything out.  This
should ruin any hopes of portability because everyone will be speaking a
different language unless the extensions are built into the source code
or output into a special file that can be moved with the code so that
it becomes a base point for the compiler on the new machine.

It is dangerous when these things start to make sense, so I think I will
stop now.

> This looks more like a Christmas list than a practical proposal...

> The language that has every feature you want doesn't exist ...

> features added ... could ... diminish the flow of applications ...
> to the point that the language is no longer a good choice for the
> applications for which it is currently being used.

This is why 'slim C' is for you and me.


Bob Leder - making a nusiance of myself

henry@utzoo.UUCP (Henry Spencer) (05/14/87)

>  What we people who can program using the power of the computer really need
> to do is convince the X3J11 committee to accept the idea that overloaded
> operators, defining of new types (not like C++), defining of operator
> symbols corresponding to operations not included in the default language,
> forcing inline, substitution of compiler-determined locations in inserted
> assembler instructions, and other versatile devices, and in general enabling
> the production of good semi-portable code is worthwhile.

Hmm, don't want much, do you?  I suspect that you could easily succeed in
convincing X3J11 that these are interesting and useful ideas if done well.
However, I doubt that you could convince them that (a) there is extensive
real experience with these features in C, (b) their implementation is well
understood (defining new symbols is a particular minefield), (c) there is
a crying need for these facilities, or (d) they are not such drastic changes
that they constitute definition of a new language.

If you want to define a new language with all these goodies, go ahead.
But this sure doesn't sound like C, and C is what X3J11 is standardizing.
-- 
"The average nutritional value    Henry Spencer @ U of Toronto Zoology
of promises is roughly zero."     {allegra,ihnp4,decvax,pyramid}!utzoo!henry

stuart@bms-at.UUCP (05/16/87)

The only way new features are going to make 'C' better is if they
are consequences of simplification.

E.g. The 'D' language where all operators are defined at  compile
time.  (A default definition file is included for compatibility.)
This  makes  the  compiler  smaller  (but  slower)  while  adding
overloaded operators and then some (like supporting your favorite
processor  features  not  in  'C').   One  reason  that   current
operators are fixed is to improve compiler performance (you don't
have to interpret the machine templates for  operators  at  every
compile).   With  the  next generation of CPU's, an approach like
this may be practical.  For now, let's not let creeping featurism
turn 'C' into an electronic beaurocracy.

Overloaded operators is better than adding just the complex type,
but  it still doesn't measure up to standards of elegance.  (Mine
anyway.)

We need new concepts, not new features.

NOTE, the best question to ask is not

        "What features can we add"

but,

        "What features are  absolutely  essential  and  what  can
        be  taken away?  Does a feature have a fundamental basis,
        or is it arbitrary and a candidate for user definition?"
-- 
Stuart D. Gathman	<..!seismo!dgis!bms-at!stuart>

gwyn@brl-smoke.ARPA (Doug Gwyn ) (05/17/87)

In article <393@bms-at.UUCP> stuart@bms-at.UUCP (Stuart D. Gathman) writes:
-NOTE, the best question to ask is not
-        "What features can we add"
-but,
-        "What features are  absolutely  essential  and  what  can
-        be  taken away?  Does a feature have a fundamental basis,
-        or is it arbitrary and a candidate for user definition?"

There is a rumor that at one point in the evolution of (Research)
UNIX, nobody was allowed to add a feature to the system without
simultaneously identifying one he could remove.  I don't know if
this is true, but it makes a good story.

cik@l.cc.purdue.edu.UUCP (05/20/87)

In article <8024@utzoo.UUCP>, henry@utzoo.UUCP (Henry Spencer) writes:
> But this sure doesn't sound like C, and C is what X3J11 is standardizing.

Okay, let me stick to nasty problems with C.

	1.  Have the compiler substitute locations in -asm- statements.
	Other than editing the assembler output, I do not believe there
	is any way to insert asm statements which can be expected to
	survive a change from one compiler to another.

	2.  Require that the compiler honor, whenever possible, assignments
	to registers.				      ^^^^^^^^

	3.  Allow the programmer to force non-promotion of floating to double,
	whenever the programmer feels there is a good reason to do this.
	I know when there is no point in using double; the compiler cannot.
	Also, on some machines, one cannot print out a floating number in hex.
	(Okay, I can finagle it.  But I had an occasion where this would have
	been a problem.  I edited the assembler code, as the easiest option.)

	4.  Allow floating point numbers to be given in hex.  Try putting in
	2^-32 as a floating point or double constant.  Why should one have to
	risk computer roundoff when it is totally unnecessary?

	5.  Require that the compiler honor parentheses.  When I want a   
	subroutine to return (x - y - k*c) + f(y), I most emphatically do
	not want the compiler to do the "obvious" rearrangement to combine
	the two terms with y; this can be a major loss of accuracy.  To set
	a variable equal to the parenthetical expression is a significant
	loss of time.
-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hrubin@l.cc.purdue.edu or pur-ee!stat-l!cik or hrubin@purccvm.bitnet

guy%gorodish@Sun.COM (Guy Harris) (05/22/87)

> 	1.  Have the compiler substitute locations in -asm- statements.
> 	Other than editing the assembler output, I do not believe there
> 	is any way to insert asm statements which can be expected to
> 	survive a change from one compiler to another.

This isn't a C language *specification* issue.  This is a C
*implementation* issue.  Some implementations, such as the AT&T WE32K
series implementation, support this.  It's not clear that a language
specification can include something like this, since the specifiers
generally can't predict in advance what sort of machines the language
will be implemented on.

> 	3.  Allow the programmer to force non-promotion of floating to double,
> 	whenever the programmer feels there is a good reason to do this.

Go read the ANSI C draft standard; it no longer requires floating
point arithmetic to be done in double precision.

> 	4.  Allow floating point numbers to be given in hex.  Try putting in
> 	2^-32 as a floating point or double constant.  Why should one have to
> 	risk computer roundoff when it is totally unnecessary?

If you really must do this, you can do it with a union.  (Yes, this
may be inconvenient.  Life is full of little inconveniences.)

> 	5.  Require that the compiler honor parentheses.  When I want a   
> 	subroutine to return (x - y - k*c) + f(y), I most emphatically do
> 	not want the compiler to do the "obvious" rearrangement to combine
> 	the two terms with y; this can be a major loss of accuracy.

No!  When a system programmer writes some expression involving
several macros, all of which perform arithmetic on their arguments,
and some subset of those arguments are constant, they most
emphatically want the compiler to do as much of the computation at
compile time as possible, even if this means rearranging the
expression.

Perhaps the rules for rearrangement should be different for integral
and floating-point operations, but it would be a serious mistake to
change C for the benefit of people doing heavy floating-point
computation if that makes it handle integer and pointer arithmetic
less efficiently.
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com

edw@ius2.cs.cmu.edu (Eddie Wyatt) (05/22/87)

In article <533@l.cc.purdue.edu>, cik@l.cc.purdue.edu (Herman Rubin) writes:
> In article <8024@utzoo.UUCP>, henry@utzoo.UUCP (Henry Spencer) writes:
> > But this sure doesn't sound like C, and C is what X3J11 is standardizing.
> 
> Okay, let me stick to nasty problems with C.
> 
> 	1.  Have the compiler substitute locations in -asm- statements.
> 	Other than editing the assembler output, I do not believe there
> 	is any way to insert asm statements which can be expected to
> 	survive a change from one compiler to another.

	I have no idea what you are talking about.  The asm statement
	allows you to insert assemble code into your C program, what
	is the problem you are having with this?
> 
> 	2.  Require that the compiler honor, whenever possible, assignments
> 	to registers.				      ^^^^^^^^

	Is this really a problem?  Maybe I've been luckly, but when I ask
	for a register I get it provided I haven't used them all yet.
> 
> 	3.  Allow the programmer to force non-promotion of floating to double,
> 	whenever the programmer feels there is a good reason to do this.
> 	I know when there is no point in using double; the compiler cannot.
> 	Also, on some machines, one cannot print out a floating number in hex.
> 	(Okay, I can finagle it.  But I had an occasion where this would have
> 	been a problem.  I edited the assembler code, as the easiest option.)

	But heres the problem - floatfunc(3.0),  should 3.0 be pass as
	a float or a double?  To complicate matters, say floatfunc is
	external. Function prototypes may take care of this though.

	How about this to solve your problem.

		typedef union 
			{
			float fnum;
			int inum;
			} floatint;

		floatint num;

		num.fnum = 4.5;
		printf("%x\n",num.inum);

	which brings up - guess my bug:

		static void BBfwrite (val)
    		    float   val;
    		    {
    		    write_out_msg_buffer((char *) &val,sizeof(float));
    		    }

	The problem here  is fixed now.

> 
> 	4.  Allow floating point numbers to be given in hex.  Try putting in
> 	2^-32 as a floating point or double constant.  Why should one have to
> 	risk computer roundoff when it is totally unnecessary?

	Some people have noted that this might be a niece feature, I forget
	what if any problems there are with this.

> 
> 	5.  Require that the compiler honor parentheses.  When I want a   
> 	subroutine to return (x - y - k*c) + f(y), I most emphatically do
> 	not want the compiler to do the "obvious" rearrangement to combine
> 	the two terms with y; this can be a major loss of accuracy.  To set
> 	a variable equal to the parenthetical expression is a significant
> 	loss of time.

	What two terms with y?  I hope my C compiler doesn't think y can
	be factor out of that expression to form (f-1)(y) :-).
	To address your real complaint, the ANSI standard plans on supporting
	parenthesis honoring through the use of the unary +. +(x - y) + y
	will be evaluated as it appears.  If you don't like the unary
	+ put it into a define statement say:

		#define HONOR(x)	+(x)	

	Please lets not get into a long philosophic debate over this
	we have seen it all before.  If you don't like it, use another
	language.
> -- 
> Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
> Phone: (317)494-6054
> hrubin@l.cc.purdue.edu or pur-ee!stat-l!cik or hrubin@purccvm.bitnet

-- 
					Eddie Wyatt

e-mail: edw@ius2.cs.cmu.edu

henry@utzoo.UUCP (Henry Spencer) (05/24/87)

> 	1.  Have the compiler substitute locations in -asm- statements.
> 	Other than editing the assembler output, I do not believe there
> 	is any way to insert asm statements which can be expected to
> 	survive a change from one compiler to another.

You are almost right:  there is *no* way to insert asm statements which
can be expected to cross compiler boundaries.  Note that compilers are not
required to (a) implement asm statements at all, or (b) generate assembler
output at all.

More generally, there is a problem in that the legal ways of using a
C variable in assembler are highly variable, a function of the compiler
as well as the machine.  For example, on many RISC machines the only
memory-reference instructions are Load and Store.  This means that the
extent to which the compiler puts variables into registers will *greatly*
influence how you write code with asm.  Whether a given variable is a
legal operand for a particular instruction will be very compiler-dependent.
This problem simply has no general solution.  Such a requirement would
degenerate to a motherhood like "the compiler should be as helpful as
possible to assembler programmers", which is (a) useless and (b) not an
obviously desirable statement.

Note that asm is not in X3J11 C at all, except for a mention in the
"Common Extensions" appendix.

>	2.  Require that the compiler honor, whenever possible, assignments
>	to registers.				      ^^^^^^^^

Please define "whenever possible".  Most programmers would applaud a
compiler that made the code run faster at the cost of sometimes disregarding
"register" directives.

>	3.  Allow the programmer to force non-promotion of floating to double,
>	whenever the programmer feels there is a good reason to do this.

X3J11 already makes this an option for compilers.  Some mandatory way of
doing it might be useful, but it's a secondary issue:  compiler implementors
whose customers are concerned about numerical issues will do it as a matter
of course.

>	4.  Allow floating point numbers to be given in hex...

This can already be done, albeit clumsily and in somewhat machine-dependent
ways.  However, since those adverbs also apply to doing it in hex, I see
no reason for action on this.

>	5.  Require that the compiler honor parentheses...

This is somewhat defensible in floating-point arithmetic, but a major loss
otherwise.  "If you want Fortran, you know where to find it."
-- 
"The average nutritional value    Henry Spencer @ U of Toronto Zoology
of promises is roughly zero."     {allegra,ihnp4,decvax,pyramid}!utzoo!henry

drw@cullvax.UUCP (05/27/87)

hrubin@osupyr.UUCP (Herman Rubin) writes:
>  What we people who can program using the power of the computer really need
> to do is convince the X3J11 committee to accept the idea that overloaded
> operators, defining of new types (not like C++), defining of operator
> symbols corresponding to operations not included in the default language,
> forcing inline, substitution of compiler-determined locations in inserted
> assembler instructions, and other versatile devices, and in general enabling
> the production of good semi-portable code is worthwhile.

One problem is that ANSI is only into standardizing existing practice.
In several parts of their rationale they note that there is
"insufficient experience" with a particular concept, and thus, they
won't include it in the standard.  (This hasn't stopped them from
adding a few totally new features, though.  But they are features that
are despirately needed.)  What we need is for someone to add these
features into a respected compiler and distribute it, so we can see
how these ideas work in practice.  Unfortunately, the commercial
outfits aren't interested in advancing the state of the art.  "He who
is out in front gets shot in the back."

Dale
-- 
Dale Worley		Cullinet Software
UUCP: ...!seismo!harvard!mit-eddie!cullvax!drw
ARPA: cullvax!drw@eddie.mit.edu
Un*x (a generic name for a class of OS's) != Unix (AT&T's brand of such)

cik@l.cc.purdue.edu.UUCP (06/10/87)

# In article <533@l.cc.purdue.edu>, cik@l.cc.purdue.edu (Herman Rubin) writes:
# > In article <8024@utzoo.UUCP>, henry@utzoo.UUCP (Henry Spencer) writes:
# > > But this sure doesn't sound like C, and C is what X3J11 is standardizing.
# > 
# > Okay, let me stick to nasty problems with C.
# > 
# > 	1.  Have the compiler substitute locations in -asm- statements.
# > 	Other than editing the assembler output, I do not believe there
# > 	is any way to insert asm statements which can be expected to
# > 	survive a change from one compiler to another.
# 
# 	I have no idea what you are talking about.  The asm statement
# 	allows you to insert assemble code into your C program, what
# 	is the problem you are having with this?

For example, suppose that the variable j has just been computed, and I want
to transfer on overflow to loc.  On the VAX, in C this is

	asm("	jov	xxx,LLL");

wher xxx is the location of j that the compiler has assigned and LLL is the
compiler's symbol for loc.  Sometimes, but not always, I can figure out where
the compiler has put j, but definitely not loc.  The only way I have been able
to do this is to put in something for xxx and LLL, get the assembler listing,
and then edit it.

# > 	2.  Require that the compiler honor, whenever possible, assignments
# > 	to registers.				      ^^^^^^^^
# 
# 	Is this really a problem?  Maybe I've been luckly, but when I ask
# 	for a register I get it provided I haven't used them all yet.

On the VAX, the compiler only lets me use half of the registers, and in cases
in which I wish to specify that a variable be in a specific register, it
refuses completely.  It refuses to put floating and double variables in
registers.  Also, using C compilers for both the VAX and the PYRAMID,
I have been unable to get the compiler to put a one-word union in a register.
# > 
# > 	3.  Allow the programmer to force non-promotion of floating to double,
# > 	whenever the programmer feels there is a good reason to do this.
# > 	I know when there is no point in using double; the compiler cannot.
# > 	Also, on some machines, one cannot print out a floating number in hex.
# > 	(Okay, I can finagle it.  But I had an occasion where this would have
# > 	been a problem.  I edited the assembler code, as the easiest option.)
# 
# 	But heres the problem - floatfunc(3.0),  should 3.0 be pass as
# 	a float or a double?  To complicate matters, say floatfunc is
# 	external. Function prototypes may take care of this though.
# 
# 	How about this to solve your problem.
# 
# 		typedef union 
# 			{
# 			float fnum;
# 			int inum;
# 			} floatint;
# 
I agree that your solution would work, and I would have used this method
if I had foreseen the problem.  However, if a variable is typed float, it
should be possible to pass it unpromoted in C without having to work.

# > 	4.  Allow floating point numbers to be given in hex.  Try putting in
# > 	2^-32 as a floating point or double constant.  Why should one have to
# > 	risk computer roundoff when it is totally unnecessary?
# 
# 	Some people have noted that this might be a niece feature, I forget
# 	what if any problems there are with this.
# 
There are no problems with this, but I do not know of any notation that has
been suggested to do this.
# > 
# > 	5.  Require that the compiler honor parentheses.  When I want a   
# > 	subroutine to return (x - y - k*c) + f(y), I most emphatically do
# > 	not want the compiler to do the "obvious" rearrangement to combine
# > 	the two terms with y; this can be a major loss of accuracy.  To set
# > 	a variable equal to the parenthetical expression is a significant
# > 	loss of time.
# 
# 	What two terms with y?  I hope my C compiler doesn't think y can
# 	be factor out of that expression to form (f-1)(y) :-).

The two terms are -y and f(y).

# 	To address your real complaint, the ANSI standard plans on supporting
# 	parenthesis honoring through the use of the unary +. +(x - y) + y
# 	will be evaluated as it appears.
# 
I have no objection to the unary +, but many of the commentators in this
news group seem to.

# 	Please lets not get into a long philosophic debate over this
# 	we have seen it all before.  If you don't like it, use another
# 	language.

If there were another appropriate language, I would.  None of the other
languages I know (except PL/1, which is unnecessarily clumsy) do any better.

# 					Eddie Wyatt
# 
# e-mail: edw@ius2.cs.cmu.edu


-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hrubin@l.cc.purdue.edu or pur-ee!stat-l!cik or hrubin@purccvm.bitnet

karl@haddock.UUCP (06/12/87)

In article <541@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
>>>1.  Have the compiler substitute locations in -asm- statements.
>>>Other than editing the assembler output, I do not believe there
>>>is any way to insert asm statements which can be expected to
>>>survive a change from one compiler to another.
>
>For example, suppose that the variable j has just been computed, and I want
>to transfer on overflow to loc.  On the VAX, in C this is
>	asm("	jov	xxx,LLL");
>[where xxx and LLL are the assembler's names for j and loc].  The only way I
>have been able to do this is to put in something for xxx and LLL, get the
>assembler listing, and then edit it.

If you're arguing that vendors should implement such a feature, I agree; it
makes asm() much more useful.  But there is no way this could be standardized.
ANY use of asm() is both machine- and compiler-dependent.  X3J11 does not
require that an implementation support asm() (it's a "Common Extension") or
even that it have an assembly pass.

>>>2.  Require that the compiler honor, whenever possible, assignments
>>>to registers.

This is meaningless.  The standard says nothing about machine registers; it
knows nothing about the underlying hardware.  (Even the rule that integers are
stored in binary is covered by the as-if rule.)  Whether a compiler is
conforming depends only upon the output of programs compiled by it.

>On the VAX, the compiler only lets me use half of the registers, and in cases
>in which I wish to specify that a variable be in a specific register, it
>refuses completely.  It refuses to put floating and double variables in
>registers.  Also, using C compilers for both the VAX and the PYRAMID,
>I have been unable to get the compiler to put a one-word union in a register.

Complain to the vendor, not the standards committee.

>>>3.  Allow the programmer to force non-promotion of floating to double,

Compilers are now free to use single-precision for float-only arithmetic.
Function arguments are promoted from float to double only in the absence of a
prototype.

>[Eddie Wyatt writes:]
>>	But heres the problem - floatfunc(3.0),  should 3.0 be pass as
>>	a float or a double?  To complicate matters, say floatfunc is
>>	external. Function prototypes may take care of this though.

They do.  Also, "3.0" is a double whereas "3.0F" is a float.  (This doesn't
affect your example, which should treat "3.0" and "3.0F" identically.)

>>>Also, on some machines, one cannot print out a floating number in hex.

If you want to pass an unpromoted float to printf("%x"), you'll have to use
something nonportable no matter what -- enclosing the float in a union, as
suggested by Eddie, is probably best.  Note that the number of "%x"'s is also
machine dependent.

>>>4.  Allow floating point numbers to be given in hex.  Try putting in
>>>2^-32 as a floating point or double constant.  Why should one have to
>>>risk computer roundoff when it is totally unnecessary?

If you mean you want to specify the bit-pattern of the floating-point number,
you can use a union or a pointer-cast.  (And I have no sympathy if your
program fails to port.)  I'll assume you just want base-16 scientific
notation.

One solution is to evaluate 2^-32 by some other means (e.g. "dc") and type in
the decimal digits.  When I give the compiler a decimal representation of a
floating-point number, I expect it to generate the nearest possible number.
If it didn't, I'd complain to the compiler vendor.

Alternately, you could write an expression such as 1.0/1024.0/1024.0/4.0; any
decent compiler will do the arithmetic at compile-time.

>>>5.  Require that the compiler honor parentheses.  When I want a
>>>subroutine to return (x - y - k*c) + f(y), I most emphatically do
>>>not want the compiler to do the "obvious" rearrangement to combine
>>>the two terms with y; this can be a major loss of accuracy.  To set
>>>a variable equal to the parenthetical expression is a significant
>>>loss of time.

Unless I specify otherwise (with unary plus), I most emphatically *do* want
the compiler to rearrange such an expression if that makes it more efficient.
(Btw, even assigning to a kludge variable (the pre-ANSI way to do this) need
not be a "significant loss of time" -- the optimizer should be able to note
that the variable is dead, and not bother to store it anywhere.)

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

am@cl.cam.ac.uk (Alan Mycroft) (06/17/87)

In article <546@haddock.UUCP> karl@haddock.ISC.COM.UUCP (Karl Heuer) writes:
>ANY use of asm() is both machine- and compiler-dependent.  X3J11 does not
>require that an implementation support asm() (it's a "Common Extension") or
>even that it have an assembly pass.
>
My understanding of the X3J11 OCtober 86 public review draft is
that a C compiler which treats
   f() { asm("ret"); }
as anything other than a call to the C function asm() with a pointer
to 4 bytes of initialised storage is broken.
(Of course, if you include a non-ansi header, or use a #pragma then
all bets are off as the program behaviour is unspecified.  However
the above use IS deprecated in asm() has not been declared previously).

I believe that the appendix listing of 'asm' is intended as a warning
to users who wish to write code which also works on older 'C's and
who might otherwise get burnt.

mouse@mcgill-vision.UUCP (der Mouse) (06/23/87)

In article <541@l.cc.purdue.edu>, cik@l.cc.purdue.edu (Herman Rubin) writes:
[various stuff about problems with C]
>>> 2.  Require that the compiler honor, whenever possible, assignments
>>> to registers.                                 ^^^^^^^^
>> Is this really a problem?  Maybe I've been luckly, but when I ask
>> for a register I get it provided I haven't used them all yet.
> On the VAX, the compiler only lets me use half of the registers, and
> [other "problems"]

Sorry.  For the compilers you were using, it's not possible.  If you
want full control over allocation of all the machine's registers (or
even any control over any of them), you don't want standard C.

>>> 3.  [...] Also, on some machines, one cannot print out a floating
>>> number in hex.

>>> 4.  Allow floating point numbers to be given in hex.  Try putting
>>> in 2^-32 as a floating point or double constant.  Why should one
>>> have to risk computer roundoff when it is totally unnecessary?
>> Some people have noted that this might be a niece feature, I forget
>> what if any problems there are with this.
> There are no problems with this, but I do not know of any notation
> that has been suggested to do this.

There is a problem with both of those: suppose floating-point is not
stored in a binary format - say it uses floating-point ternary?
Suppose the machine uses packed decimal?  Suppose you figure out your
hex constant for your VAX and then have to port to your Sun?  Then to
your 80x86?  Then to your IBM mainframe?  Then to that packed decimal
machine I mentioned?  Yech.  Just write 1/65536.0/65536.0 and let the
compiler figure it out.

>>> 5.  Require that the compiler honor parentheses.

Not this again, just when we thought it had been beaten to death....

>>> [...] (x - y - k*c) + f(y), I most emphatically do not want the
>>> compiler to do the "obvious" rearrangement to combine the two terms
>>> with y;
>> What two terms with y?  I hope my C compiler doesn't think y can be
>> factor out of that expression to form (f-1)(y) :-).
> The two terms are -y and f(y).

What would you think the "obvious" rearrangement would merge -y and
f(y) to form?  I fear the "obvious" rearrangement isn't obvious to me.
The only thing that looks anything like reasonable was the >>
suggestion of (f-1)(y), and even that is pretty silly.  Or do you mean
you don't want it to generate (x-k*c)+(f(y)-y)?  Sorry, again, you
don't want standard C (though ANSI has unary +, which could be used to
"solve" this particular "problem").

					der Mouse

				(mouse@mcgill-vision.uucp)

jack@swlabs.UUCP (Jack Bonn) (06/26/87)

In article <820@mcgill-vision.UUCP>, mouse@mcgill-vision.UUCP (der Mouse) writes:
> >>> 4.  Allow floating point numbers to be given in hex.  Try putting
> >>> in 2^-32 as a floating point or double constant.  Why should one
> >>> have to risk computer roundoff when it is totally unnecessary?
> 
> There is a problem with both of those: suppose floating-point is not
> stored in a binary format - say it uses floating-point ternary?
> Suppose the machine uses packed decimal?  Suppose you figure out your
> hex constant for your VAX and then have to port to your Sun?  Then to
> your 80x86?  Then to your IBM mainframe?  Then to that packed decimal
> machine I mentioned?  Yech.  Just write 1/65536.0/65536.0 and let the
> compiler figure it out.

Why not just allow 0x0.00000001?  I don't think the suggestion is to 
encode the hexadecimal in the _internal_ format for the machine, just 
to be able to express the constant in a base other that 10.  Certainly,
if the machine was a decimal machine, round-off would still occur.  But
the majority of implementations (are there any decimal-only c's?) would
not encounter it.

But the pressing question is: Must the dot then be referred to as the 
"hexa-decimal point"?  :-)
-- 
Jack Bonn, <> Software Labs, Ltd, Box 451, Easton CT  06612
seismo!uunet!swlabs!jack

daniels@cae780.TEK.COM (Scott Daniels) (06/26/87)

In article <820@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse) writes:
>In article <541@l.cc.purdue.edu>, cik@l.cc.purdue.edu (Herman Rubin) writes:
>>>> 4.  Allow floating point numbers to be given in hex.  Try putting
>>>> in 2^-32 as a floating point or double constant.  Why should one
>>>> have to risk computer roundoff when it is totally unnecessary?
>>> Some people have noted that this might be a niece feature, I forget
>>> what if any problems there are with this.
>> There are no problems with this, but I do not know of any notation
>> that has been suggested to do this.
>
>There is a problem with both of those: suppose floating-point is not
>stored in a binary format - say it uses floating-point ternary?
>Suppose the machine uses packed decimal?  Suppose you figure out your
>hex constant for your VAX and then have to port to your Sun?  Then to
>your 80x86?  Then to your IBM mainframe?  Then to that packed decimal
>machine I mentioned?  Yech.  Just write 1/65536.0/65536.0 and let the
>compiler figure it out.
>

The problem being pointed out is that there are no binary formats provided.
We have done quite well with providing decimal formats where the underlying
machine has no decimal floating point, why not have a similar notation for 
binary (or base N if you can agree on a nice notation).  Given such a format,
it is possible to produce a terse binary text string which represented the 
exact value that your machine calculated, but would be readable on another
machine with the closest approximation of which that machine is capable.

The kind of notation desired is like:
    0.5 == 0x0.8,  0.625 == 0x0.A,  128.5 == 0x80.8,  128.5 == 0x8.08@4
Hard to resolve issues are things like: base of expression of exponent,
is the exponent a power of two or the base (should the last be 0x8.08@1),
How do you represent Nans (or do you).  It certainly seems to me that such
a notation is greatly to be desired (we can agree that the floating point 
on most machines is  closer to binary than decimal).  What we do not have 
is enough practical experience with a notation to be sure we know a solution.
That is why Ansi-C should not have such a format.

FROM:   Scott Daniels, Tektronix CAE
	5302 Betsy Ross Drive, Santa Clara, CA  95054
UUCP:   tektronix!teklds!cae780!daniels
	{ihnp4, decvax!decwrl}!amdcad!cae780!daniels 
        {nsc, hplabs, resonex, qubix, leadsv}!cae780!daniels 

peter@sugar.UUCP (Peter DaSilva) (07/06/87)

Or for those of us with broken compilers with CPP part of CC, #asm? I have
always thought asm() looked hokey.

#pragma asm PDP-11
	mov	(IP)+,WP	; anybody recognise this
	jmp	@(WP)+		; piece of code?
#pragma C
-- 
-- Peter da Silva `-_-' ...!seismo!soma!uhnix1!sugar!peter (I said, NO PHOTOS!)

karl@haddock.UUCP (Karl Heuer) (07/07/87)

In article <727@jenny.cl.cam.ac.uk> am@cl.cam.ac.uk (Alan Mycroft) writes:
>My understanding of [Oct86 dpANS] is that a C compiler which treats
>   f() { asm("ret"); }
>as anything other than a call to [an ordinary function named "asm"] is broken
>[Since builtin asm is not part of the standard.]

"Broken" is a bit strong.  Such compilers (which will likely continue to
exist in the ANSI world) will simply be "not strictly conforming".

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

ron@topaz.rutgers.edu.UUCP (07/08/87)

Excuse me, but doesn't the compiler standard make provision for functions
being built-in?  I seem to remember provision having to be made to make
sure one could defeat built in compiler treatment of certain math functions
that were turned into inline code and allowing the user to make them true
function calls (presumably because the programmer wanted to make his own
version of the function).  What makes asm("string") any different than
someones version of log(x) that might get turned into a call to the machines
log instruction, unless it was explicitly turned off?

-Ron

karl@haddock.UUCP (07/10/87)

In article <13220@topaz.rutgers.edu> ron@topaz.rutgers.edu (Ron Natalie) writes:
>Excuse me, but doesn't the compiler standard make provision for functions
>being built-in?  I seem to remember provision having to be made to make
>sure one could defeat built in compiler treatment of certain math functions
>that were turned into inline code and allowing the user to make them true
>function calls

Yes.  This can be done with "#undef", or by enclosing the name in parens.

>(presumably because the programmer wanted to make his own version of the
>function).

No, such a substitution yields undefined behavior, even if the user function
has identical semantics.

>What makes asm("string") any different than someones version of log(x) that
>might get turned into a call to the machines log instruction, unless it was
>explicitly turned off?

"log" is part of the standard, "asm" is not.  Thus, a strictly conforming
implementation must assume by default that "asm" refers to a user function.
However, the builtin could be named "__asm"; then the user could explicitly
enable it with "#define asm __asm".  Alternately, the feature could be enabled
via "#pragma".

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

am@cl.cam.ac.uk (Alan Mycroft) (07/22/87)

In article <684@haddock.UUCP> karl@haddock.ISC.COM (Karl Heuer) writes:
>>My understanding of [Oct86 dpANS] is that a C compiler which treats
>>   f() { asm("ret"); }
>>as anything other than a call to [an ordinary function named "asm"] is broken
>"Broken" is a bit strong.  Such compilers (which will likely continue to
>exist in the ANSI world) will simply be "not strictly conforming".
>
My dpANS gives no such notion as a "strictly conforming compiler".
(strictly conforming PROGRAM, yes).  It says:  "A conforming hosted
implementation shall accept any strictly conforming program.", and
thus (assuming that by 'accept', ANSI means 'and gives the correct answer')
we see that if f() does not call asm() then the compiler is not
a "conforming hosted implementation".  I.e. not ANSI C.

steve@nuchat.UUCP (Steve Nuchia) (08/04/87)

In article <847@haddock.ISC.COM>, karl@haddock.ISC.COM (Karl Heuer) writes:
> You are right; I got the terms confused.  In fact A.6.5 says that certain
> common extensions, e.g. nonstandard keywords, will render an implementation
> nonconforming.
> 
> I still think "broken" is too strong a word.  But if I were a compiler vendor
> I'd be certain to have a switch that disabled all extensions to yield a "pure"
> implementation.

Please:

If anyone reading this is ever in a position to affect a decision on
this point, make the silly flags default to the portable, standard
configuration.  I worked on a project that had a major commercial
product running on something like 30 different unix boxes, which at
one time spanned the gamut from v7-based xenix to sys5.2.  There were
three serious time sinks in the porting group, and dealing with the
feature differences among the unix versions wasn't one of them.

Actually getting the code from the base machine to all the targets
(usually over serial lines) consumed a lot of clock time, but was
not too demanding on the people.  Incompatible bugs consumed the
largest amount of time, taken across both the porting staff and
the development group.  If everyone had the same bugs life would
be grand.  Right behind bugs was compiler/linker/make flags.
Figuring out the silly magic required to get company X's compiler
to behave like a unix C compiler took an amazing amount of time.
Particularly if company X was in the intel camp, but it happened
with other processors too.

The stories I could tell.  Anyway, It is a serious presumption
on the part of the compiler vendors to place the burden of groping
through the manual (or disassembling the compiler) on the occasional
user, the application porter.  The guy doing development on the
box can more reasonably be expected to become intimate with its
compiler.

	does any of this make sense?
	Steve Nuchia
	{{soma,academ}!uhnix1,sun!housun}!nuchat!steve

peter@sugar.UUCP (Peter da Silva) (08/06/87)

>My dpANS gives no such notion as a "strictly conforming compiler".  (strictly
>conforming PROGRAM, yes).  It says:  "A conforming hosted implementation
>shall accept any strictly conforming program.", and thus [an asm-extended
>compiler] is not a "conforming hosted implementation".  I.e. not ANSI C.

Let "A Conforming Hosted Implementation" be A
Let "Accepts a Strictly Conforming Program" be B
Let "Accepts a Non-conforming Program" be C

Your first statement now becomes A => B.

This allows you to state !B => !A, that is, if it doesn't accept a strictly
conforming program, it's not a conforming hosted implementatio.

It doesn't say anything about C. You can't say C => !A, nor !C => !A.

You're confusing "accepts a non-conforming program" with "doesn't accept
a conforming program".

Or else you didn't include all the relevent facts in your article.
-- 
-- Peter da Silva `-_-' ...!seismo!soma!uhnix1!sugar!peter (I said, NO PHOTOS!)

franka@mmintl.UUCP (Frank Adams) (08/15/87)

In article <279@nuchat.UUCP> steve@nuchat.UUCP (Steve Nuchia) writes:
>Anyway, It is a serious presumption on the part of the compiler vendors to
>place the burden of groping through the manual (or disassembling the
>compiler) on the occasional user, the application porter.  The guy doing
>development on the box can more reasonably be expected to become intimate
>with its compiler.

I must disagree.  The default compiler settings should cater neither to
professionals porting code, nor to professionals doing local development,
but to the occasional or novice programmer, who is trying to get his newly
written, probably small, program to run.

Professionals should expect to do the work necessary to learn how to use
their tools to perform the functions they want them to perform.  The tools
should cater to the novices, without putting an excessive burden on the pro.
-- 

Frank Adams                           ihnp4!philabs!pwa-b!mmintl!franka
Ashton-Tate          52 Oakland Ave North         E. Hartford, CT 06108

msf@amelia.UUCP (08/18/87)

In article <2311@mmintl.UUCP> franka@mmintl.UUCP (Frank Adams) writes:
>  The default compiler settings should cater neither to
>professionals porting code, nor to professionals doing local development,
>but to the occasional or novice programmer, who is trying to get his newly
>written, probably small, program to run.

I must disagree with Mr. Adams.  C is *not* a beginner's language.  I would
agree with his comments were they refering to Pascal or BASIC (two languages
that were designed for programming novices, although many complex professional
programs have been written in them); or FORTRAN (since it is so commonly
used by people who have little or no interest in having to `figure out' the
computer).  C is a powerful language that offers lots of rope for the novice
to hang himself.  THIS IS NOT A BUG, IT IS A FEATURE!  That same flexibility
allows the professional experienced programmer the freedom to do what they
want to do.  C should not cater to novices, there are plenty of double
checking languages out there.  Let the C compiler default to the most
used options by the professionals (which I would hope were the maximum
portability options) and let the novices acquire experience using Pascal.
 
>Professionals should expect to do the work necessary to learn how to use
>their tools to perform the functions they want them to perform.  The tools
>should cater to the novices, without putting an excessive burden on the pro.

This might be true for a $20 drill, but I doubt a $200K milling machine
is optimized for a high school shop class.  That IS an excessive burden.

	mike
Michael Fischbein                 msf@prandtl.nas.nasa.gov
                                  ...!seismo!decuac!csmunix!icase!msf
These are my opinions and not necessarily official views of any
organization.

ron@topaz.rutgers.edu.UUCP (08/18/87)

> I must disagree.  The default compiler settings should cater neither to
> professionals porting code, nor to professionals doing local development,
> but to the occasional or novice programmer, who is trying to get his newly
> written, probably small, program to run.

And I must disagree with you, if we follow this discussion back to the
beginning.

The default action for the compiler should be to ACT NORMALLY.  ACTING
NORMALLY means complying with whatever standards might be there.  Making
non-standard changes the default neither helps the naive nor the professional
programmer at all.  A naive programmer new to C is probably working with
a C text that is references NORMAL C, even if he is not, you are doing
him a disservice teaching him broken C.  A naive programmer, not new to
C, but new to this compiler, would really expect the C compiler to work
like all the other ones.  A professional programmer knows what the C
standards are and codes to them, clearly identifying nonstandard and
probably nonportable constracts that he uses.

The operational rule here is the oft quoted "Principle of Least Astonishment."
For example many novice K&R readers and long term C hands were screwed by
Lattice C defaults.

-Ron

root@hobbes.UUCP (John Plocher) (08/24/87)

+---- Frank Adams writes the following in article <2322@mmintl.UUCP> ----
| 
| (Anyone doing serious development on an 8086 has to think about segments and
| probably make changes to their code to take them into account.  Large model
| runs too slowly, and small model isn't big enough.  This is what is wrong
| with the 8086 architecture -- high level language programmers shouldn't have
| to be concerned about such things.)
| 
| Frank Adams                           ihnp4!philabs!pwa-b!mmintl!franka
| Ashton-Tate          52 Oakland Ave North         E. Hartford, CT 06108
+----

One thing that has bothered me for a long time about the 808x compilers
is the following:
    When I was learning PDP-11 assembler we found out that the compilers
could use branch instructions iff the target was less than +/- 128 bytes
away.  If not, a jump instruction would be used.  Branches were short and
fast, jumps were big and slow.  Obvious.
    Along came the 808x and I find that there were 2 modes for addresses:
short and fast -vs- big and slow; these addresses could be used for code
and data.  Obviously the compiler/linker/loader should be the one to determine
which to use, right?  I mean, if a data object is within 64K of someplace
then "near" pointers could be used; if it is too far, use "far" pointers.
  Boy was I pissed when I found out that things didn't work that way!

		    AAAArrrrrgggghhhh!

All that needs to done is to have each library routine avaliable in each
combo of models, and a smart linker which can use them.



-- 
John Plocher uwvax!geowhiz!uwspan!plocher  plocher%uwspan.UUCP@uwvax.CS.WISC.EDU

tim@amdcad.AMD.COM (Tim Olson) (08/24/87)

In article <193@hobbes.UUCP> root@hobbes.UUCP (John Plocher) writes:
+-----
|One thing that has bothered me for a long time about the 808x compilers
|is the following:
|    When I was learning PDP-11 assembler we found out that the compilers
|could use branch instructions iff the target was less than +/- 128 bytes
|away.  If not, a jump instruction would be used.  Branches were short and
|fast, jumps were big and slow.  Obvious.
|    Along came the 808x and I find that there were 2 modes for addresses:
|short and fast -vs- big and slow; these addresses could be used for code
|and data.  Obviously the compiler/linker/loader should be the one to determine
|which to use, right?  I mean, if a data object is within 64K of someplace
|then "near" pointers could be used; if it is too far, use "far" pointers.
|  Boy was I pissed when I found out that things didn't work that way!
|
|		    AAAArrrrrgggghhhh!
|
|All that needs to done is to have each library routine avaliable in each
|combo of models, and a smart linker which can use them.
+-----

That has to be a pretty smart linker, as far as linkers go.  It is an
N-P complete problem to "optimally" change "far" references to "near"
references (and compact the code) at link time.

Here's the problem:

During pass1, the linker builds the symbol table of externally defined
addresses.  During pass2, it discovers that a "far" reference is really
"near".  It then changes the code at that location to be a near
reference (which usually reduces the size of the code at that point). 
It then has to fill the unused space with "nops" (dubious benifit) or
"compact" the code.

After compacting, *all* labels following the compacted reference have
been changed by the size of the code reduction (even local, "static"
labels, which don't normally get passed to the linker!).  Worse yet, the
compaction may have brought a label into "near" range that was
determined to be far, before.  So pass2 must be run over again.

There is research going on in this area, because it would benifit a
great many architectures.  A good paper to read on the subject is one
written by David Wall of DEC -- sorry, I can't find the paper so I can't
give a complete reference -- those that are interested can email me; I
should be able to find the reference for you.


	-- Tim Olson
	Advanced Micro Devices
	(tim@amdcad.amd.com)

schung@cory.Berkeley.EDU (Stephen the Greatest) (08/24/87)

>All that needs to done is to have each library routine avaliable in each
>combo of models, and a smart linker which can use them.
>-- 
>John Plocher uwvax!geowhiz!uwspan!plocher  plocher%uwspan.UUCP@uwvax.CS.WISC.EDU


	And now something completely different...

	What about an object file format that does not distinguish between
	near/far pointer usage?  Have the (real smart) linker generate the
	right code from these object files.  This will put more work to the
	linker, but make sure that only one version of each library routine
	must be written.

					- Stephen

root@hobbes.UUCP (08/27/87)

+---- Tim Olson writes in <18042@amdcad.AMD.COM> ----
| +---- John Plocher ( that's *me* ) wrote ----
| |    Along came the 808x and I find that there were 2 modes for addresses:
| |short and fast -vs- big and slow; these addresses could be used for code
| |and data.  Obviously the compiler/linker/loader should be the one to
| |determine which to use, right?
| +-----
| 
| That has to be a pretty smart linker, as far as linkers go.  It is an
| N-P complete problem to "optimally" change "far" references to "near"
| references (and compact the code) at link time.
+----

Why couldn't this be done in the compiler when everything is still in
3-address form IN THE COMPILER?  Don't wait to do this until after the code
has been generated!  Start off assuming that everything is "far", and go
thru marking things that can be proved "near".  At this point, labels are
still symbolic, and since we have an arbitrary data structure for the
3-address code there is no need for compaction or filling with 'nops'.

This would (obviously?) mean that there needs to be more or different info
stored in ".obj" files - the linker might even need to include the
traditional "code generator" found in today's compilers.

Off the top of my head I'd think that a "P-code" object file with the
needed symbol table info could be a place to start.  If the "super-linker"
uses a few heuristics like:

    The total size of this program is < 64K so all code pointers can be "near"
    The total static/Global/BSS... data is < 64K, ...
    Aliasing is detected; assume "far" pointers for this
    ...
it could do a passable job.

There are cases where things get very rough - I've done a lot of what is
now being called "mixed model" programming; using printf() when you have
both "near" and "far" strings is not for the masses!  I just think that the
computer should be able to do this sort of mundaine thing for me.  Right
now, I have to determine that my code is > 64K and add the -Ml flag to my
compiles.  At the very least, the compiler should be able to do this!

-- 
John Plocher uwvax!geowhiz!uwspan!plocher  plocher%uwspan.UUCP@uwvax.CS.WISC.EDU

jack@swlabs.UUCP (Jack Bonn) (08/28/87)

In article <200@hobbes.UUCP>, root@hobbes.UUCP (John Plocher) writes:
> Why couldn't this be done in the compiler when everything is still in
> 3-address form IN THE COMPILER?  Don't wait to do this until after the code
> has been generated!  Start off assuming that everything is "far", and go
> thru marking things that can be proved "near".  At this point, labels are
> still symbolic, and since we have an arbitrary data structure for the
> 3-address code there is no need for compaction or filling with 'nops'.

Why not generate source assembler that doesn't indicate whether the target
is near or far.  Then let the assembler choose the long or short form of
the jump depending on the worst case distance from the target.

I think I remember an assembler that did just the job that you are looking
for.  If I remember correctly, it was a three pass assembler that worked
like this for branch addresses:

1) Pass over the source and compute the range of address that each symbol
   can have.  The instruction location counter would actually be a pair
   of values, ilc.min and ilc.max.  Whenever an instruction is read, 
   increment these values appropriately.  For jumps, this would mean adding
   different values to ilc.min and ilc.max.

2) Make what is normally a pass 1 over the input.  The exception here is
   that whenever a jump instruction is read, compute the WORST CASE distance
   to the target.  Mark that jump instruction for pass 2 and update the ilc
   appropriately.

3) Do what is normally pass 2.

Of course there are cases where this is too pessimistic, since the "real"
solution is exponential (np-complete?).  But in real cases, this yields
results very close to optimum.

-- 
Jack Bonn, <> Software Labs, Ltd, Box 451, Easton CT  06612
seismo!uunet!swlabs!jack

fnf@mcdsun.UUCP (08/31/87)

In article <296@swlabs.UUCP> jack@swlabs.UUCP (Jack Bonn) writes:
>Why not generate source assembler that doesn't indicate whether the target
>is near or far.

Ok so far...

>		  Then let the assembler choose the long or short form of
>the jump depending on the worst case distance from the target.

This only works for jumps to local symbols within the same assembly module,
and GREATLY complicates the work of a linker which optimizes both local
and global references (since it must now cope with relocation done by
the assembler when it inserts or deletes code between the definition and
reference of a local symbol).  Again, I believe the assembler has no
business whatsoever doing relocation and current implementations only
do so for historical reasons (the assembler writer knew that assemblers
have "always" done this).  Relocation is the linker's job.  If anyone
has a counter argument please post!

>Of course there are cases where this is too pessimistic, since the "real"
>solution is exponential (np-complete?).  But in real cases, this yields
>results very close to optimum.

Gosh, I'm glad this discussion didn't come up several months ago when
I was in the midst of writing a new linker from scratch.  The code to
implement near/far relocation optimizations might have taken more than
the three days or so that it actually took, if I'd have known how
difficult a problem it was to solve efficiently...   :-) :-) :-) :-)

-Fred
-- 
= Drug tests; just say *NO*!
= Fred Fish  Motorola Computer Division, 3013 S 52nd St, Tempe, Az 85282  USA
= seismo!noao!mcdsun!fnf    (602) 438-3614

jack@swlabs.UUCP (09/01/87)

In article <364@mcdsun.UUCP>, fnf@mcdsun.UUCP (Fred Fish) writes:
> In article <296@swlabs.UUCP> jack@swlabs.UUCP I wrote: 
> >		  Then let the assembler choose the long or short form of
> >the jump depending on the worst case distance from the target.
> 
> This only works for jumps to local symbols within the same assembly module,
> and GREATLY complicates the work of a linker which optimizes both local
> and global references (since it must now cope with relocation done by
> the assembler when it inserts or deletes code between the definition and
> reference of a local symbol).  


The algorithm presented requires no such optimization by the linker.  The
assembler described yields object code with the correct long/short jumps and
no additional relocation/fixup information.  

There is nothing for the linker to fixup.

-- 
Jack Bonn, <> Software Labs, Ltd, Box 451, Easton CT  06612
seismo!uunet!swlabs!jack

peter@sugar.UUCP (Peter da Silva) (09/02/87)

> [ description of how to make an assembler that handles long/short branches ]

But that doesn't resolve the problem of how to deal with near and far
cals to seperately compiled code. If the calling sequence of the 8086
was a little more logical, you could have 2 entry points for the routine:
near and far. The near would just push the segment and fall through to
the far. Unfortunately, segment is not the top of the stack in a far
call. See Kernighan's April column in Computer Language.
-- 
-- Peter da Silva `-_-' ...!seismo!soma!uhnix1!sugar!peter
--                  U   <--- not a copyrighted cartoon :->

fnf@mcdsun.UUCP (09/02/87)

In article <320@swlabs.UUCP> jack@swlabs.UUCP (Jack Bonn) writes:
>In article <364@mcdsun.UUCP>, fnf@mcdsun.UUCP (Fred Fish) writes:
>> This only works for jumps to local symbols within the same assembly module,
>> and GREATLY complicates the work of a linker which optimizes both local
>> and global references (since it must now cope with relocation done by
>> the assembler when it inserts or deletes code between the definition and
>> reference of a local symbol).  
>
>The algorithm presented requires no such optimization by the linker.  The
>assembler described yields object code with the correct long/short jumps and
>no additional relocation/fixup information.  
>
>There is nothing for the linker to fixup.

Sigh, guess we are going to have to go into the gory details.  Assume
a hypothetical machine with two forms of a jump instruction.  One is
is 32 bits and is evenly split with 16 bits being the instruction op
code and the other 16 bits being a PC relative offset.  The other
jump instruction is two long words, each 32 bits, with the first being
a different 16 bit opcode with the other 16 bits unused, and the second
being a 32 bit PC relative offset.  I.E.:

	jump.near	<16 bit opcode><16 bit offset>

	jump.far	<16 bit opcode><   unused    >
			<       32 bit offset        >

Now assume some assembly code such as the following (note the lack
of near/far specifications):

			.
			.
	0x00000100	jump	L1		#L1 is local
			.
			.
	0x00000200	jump	_strcpy		#_strcpy is defined elsewhere
			.
			.
	0x00000300  L1	jump	_exit		#_exit is defined elsewhere
			.
			.
	^
	|

	Offset from start of module
	 

The assembler assumes all jumps are near jumps and simply emits object
code that looks something like:

			.
	0x00000100	<jump.near opcode><16 bits of 0>
			.
			.
	0x00000200	<jump.near opcode><16 bits of 0>
			.
			.
	0x00000300  L1	<jump.near opcode><16 bits of 0>

Now along comes the linker.  It gathers up our object module, finds the
reference to external routine _strcpy, and loads the module from the C
library that defines _strcpy (along with lots of other stuff at the same
time).  Assume the definition of _strcpy in another module is located in
the executable 0x00100000 bytes from the jump instruction above that uses
it (heh, this is GNU Emacs :-).  Now obviously 0x00100000 won't fit in
16 bits, so the linker must modify the object code to look something like:

			.
	0x00001100	<jump.near opcode><16 bits of 0>
			.
			.
	0x00001200	<jump.far  opcode><16 bits of 0>  #modified opcode
	0x00001204	<         32 bit offset        >  #inserted field
			.
			.
	0x00001304  L1	<16 bit opcode><16 bits of 0>
			.
			.
	0x00101200	<begin code for _strcpy>

	^
	|
	Offset from start of executable module

After relocation resolution, the final object code looks like:

	0x00001100	<jump.near opcode><0x0204>
			.
			.
	0x00001200	<jump.far  opcode><0x0000>	#modified opcode
	0x00001204	<       0x00100000    >		#inserted field
			.
			.
	0x00001304  L1	<jump.near opcode><0x1234>
			.
			.
	0x00101200	<begin code for _strcpy>

If the assembler had decided that since the jump to L1 was a local
jump of "known" offset 0x200, stuck 0x200 in the offset field, and
thrown away the relocation information, the linker would not have been
able to go back and fix up the 0x200 to 0x204 without scanning all the
executable code looking for references that spanned the insertion
point (at 0x1200-0x1204).  This would have essentially required you
to disassemble the entire load module EVERY TIME you promoted a
jump.near instruction to a jump.far instruction!

Hope this helps to clarify why the assembler SHOULD NOT do any
relocation.

-Fred

-- 
= Drug tests; just say *NO*!
= Fred Fish  Motorola Computer Division, 3013 S 52nd St, Tempe, Az 85282  USA
= seismo!noao!mcdsun!fnf    (602) 438-3614

jack@swlabs.UUCP (Jack Bonn) (09/03/87)

In article <366@mcdsun.UUCP>, fnf@mcdsun.UUCP (Fred Fish) writes:
> In article <320@swlabs.UUCP> jack@swlabs.UUCP (Jack Bonn) writes:
> >In article <364@mcdsun.UUCP>, fnf@mcdsun.UUCP (Fred Fish) writes:
> >> This only works for jumps to local symbols within the same assembly module,
> >> and GREATLY complicates the work of a linker which optimizes both local
> >> and global references (since it must now cope with relocation done by
> >> the assembler when it inserts or deletes code between the definition and
> >> reference of a local symbol).  
> >
> >The algorithm presented requires no such optimization by the linker.  The
> >assembler described yields object code with the correct long/short jumps and
> >no additional relocation/fixup information.  
> >
> >There is nothing for the linker to fixup.
> 
> Sigh, guess we are going to have to go into the gory details.  

	<gory details omitted>

If I understand you correctly, the method I described makes it more
difficult for an optimizing linker to do its job.  Of course, we had
no such optimizing linker (or source thereof), or the assembler optimization
would have been unnecessary.  But I guess I am troubled by this linker 
optimization and maybe those in net-land can clarify:

1) Are there many of these optimizing linkers out there?

2) Is it true that to debug in assembler, the listing must be
   generated after the link is done?  I think that this would be
   necessary since the addresses within the module are changed after the
   assembly is complete.  (Does anyone else use assembler anymore?)

3) What are the consequences on unit testing code that may not 
   match that which is part of the final product.  How do we get this
   past Q/A?  (or do we even tell them :-) )

4) Won't it be true that two identical links may not even be the same
   length since the orderings in the libraries may change.  Won't this
   make real-time analysis difficult, since the number of bytes of
   instructions may change from link to link.

5) Has there been any attempt to adjust the ordering of the modules to
   improve the overall optimization?  It seems that this is an analogous
   situation to that encountered in VLSI placement/layout.  Of course
   this is very computationally intensive for a complex die.  But it
   would make sense to cluster "connected" modules together.  Maybe an
   option to ld is called for, one that pulls object modules from the
   library _in order_ before trying to resolve unresolved references.
   At least then, this could be specified manually.

Am I the only one who is troubled by all of this?  I really like the
potential for a automatic mixed model for a "brain-damaged" machine like
the one I am posting from (at least for JMPs, calls are trickier).  And I 
am sure there are many things that can be improved by optimizations like 
this (like the kernel) even for architectures that mix models much more 
easily than the Intel "family".  But I also think that if all tool 
developers are going to go off and implement an improvement that takes 
"3 days or so" we might want to take some time and think about the 
consequences before doing so.
-- 
Jack Bonn, <> Software Labs, Ltd, Box 451, Easton CT  06612
seismo!uunet!swlabs!jack

markb@sdcrdcf.UUCP (Mark Biggar) (09/03/87)

In article <613@sugar.UUCP> peter@sugar.UUCP (Peter da Silva) writes:
>> [ description of how to make an assembler that handles long/short branches ]
>But that doesn't resolve the problem of how to deal with near and far
>cals to seperately compiled code. If the calling sequence of the 8086
>was a little more logical, you could have 2 entry points for the routine:
>near and far. The near would just push the segment and fall through to
>the far. Unfortunately, segment is not the top of the stack in a far
>call. See Kernighan's April column in Computer Language.

No the offest is on the top of the stack, so you can do the following:

When generating the op for a near or far sub call the compiler inserts
a nop before the call if necessary so that a far call always pushes an odd
offset onto the stack and a near call always pushes an even offset.
now the subroutine looks something like:

label   ...
	...
	mov     ax,(sp)
	and     ax,1
	jz      label1
	retfar
label1  retnear

This scheme was developed during a discussion with Robert Dewar of NYU
at the last SIGAda meeting the was held in San Diego (3 yrs ago?),
about how to compile Ada packages for an 86.

Mark Biggar
{allegra,burdvax,cbosgd,hplabs,ihnp4,akgua,sdcsvax}!sdcrdcf!markb

fnf@mcdsun.UUCP (Fred Fish) (09/04/87)

In article <333@swlabs.UUCP> jack@swlabs.UUCP (Jack Bonn) writes:
>1) Are there many of these optimizing linkers out there?

Not to my knowledge.  But I would be VERY interested in any references
anyone might be able to provide on either existing implementations or
proposed implementations.

>2) Is it true that to debug in assembler, the listing must be
>   generated after the link is done?  I think that this would be

Yes, I suppose this is true.  Since the linker has total freedom to
change the code in anyway it sees fit, up to and including moving
instructions around and inserting or deleting instructions of its own
devising.  This also has obvious ramifications for people that write 
self-modifying code and for symbolic debuggers.  Of course there is a
"do-what-I-wrote" mode that just does a "dumb" link, but that doesn't
help you much when your bug is fatal to the optimized version but innocuous
in the "dumb" version.

>4) Won't it be true that two identical links may not even be the same
>   length since the orderings in the libraries may change.  Won't this
>   make real-time analysis difficult, since the number of bytes of
>   instructions may change from link to link.

True again, which brings you to item 5 as you noted below.  BTW I'm not
sure what you mean by "make real-time analysis difficult".  Are you
refering to analysis of real-time systems or analysis in real-time or 
something else?

>5) Has there been any attempt to adjust the ordering of the modules to
>   improve the overall optimization?  It seems that this is an analogous

Yes.  :-)

-Fred
-- 
= Drug tests; just say *NO*!
= Fred Fish  Motorola Computer Division, 3013 S 52nd St, Tempe, Az 85282  USA
= seismo!noao!mcdsun!fnf    (602) 438-3614

wayne@ames.arpa (09/05/87)

Carol:

Thanx much for the select poop; VERY thorough for something you "just
slapped together"!  However (isn't there always one?), I've still got
one question (and a comment or two).

First, the question: in your write-up, exactly what do you do to
"terminate select" in the selwakeup routine?  If I understand things,
what you want to do is wake up the one sleeping process given by
db->db_sel (now p); how do you wakeup a single process without waking
everybody else that's sleeping on selwait?  (By the way, my
understanding is that if only one process is sleeping, then you wake
only him; otherwise, you wakeup everybody in the whole system who is
waiting for selects on any device, most of whom will go right back to
sleep.  Trade-off of infrequent inefficiency for simplicity.
Correct?)

Now a couple of comments on the write-up, mostly for feedback and to
see if I really do understand.  First, xxselect is called with "ds" as
param but actually wants "db"; the call should be something like
xxselqueue(ds.db), right?  (Assuming the device buffer is an element
of the device structure.)  Also, at the top of - 3 -, the sentence
"The key is that more than one process can try to select for the same
event on the same process" should end with "device" rather than
"process," no?  Finally, in the code for selwakeup, why bother testing
for SSEL before resetting it?

And also a comment on the stuff being added to the driver-writing
manual.  It contains the sentence "The process number of the current
process is in u.u_procp" which really isn't true (at least if you
think of "process number" as synonymous with "process id"); shouldn't
it be "A pointer to the current process's proc table entry ..."?

Finally, a philosophical item.  How does the xxselect routine know
whether the user is in fact going to sleep?  I mean, to quote your
note, "On a poll, the driver xxselect routine is called just once from
the kernel select routine."  It seems to me the procedures you
outlined will set db->db_sel in the poll case as well, although
admittedly the test in selwakeup for (caddr_t)&selwait will prevent
anything weird happening.  Of course, if there's no way xxselect knows
whether the user is polling or not, then ...

Anyway, thanx again.  Help with "terminate select" please?

wayne

mouse@mcgill-vision.UUCP (09/22/87)

In article <366@mcdsun.UUCP>, fnf@mcdsun.UUCP (Fred Fish) writes:
> In article <320@swlabs.UUCP> jack@swlabs.UUCP (Jack Bonn) writes:
>> In article <364@mcdsun.UUCP>, fnf@mcdsun.UUCP (Fred Fish) writes:
[> through >>> about short/long branches]
[>>> (Fred Fish) says this complicates the linker]
[>> (Jack Bonn) says no]
[> (Fred Fish) says]

> Sigh, guess we are going to have to go into the gory details.

> [Example: machine with two jump instructions
> jump.near	<16 bit opcode><16 bit offset>
> jump.far	<16 bit opcode><   unused    >	<32 bit offset>
> ]

> Now assume some assembly code such as the following (note the lack of
> near/far specifications):
[intervening dots edited out -dM]
> 	0x00000100	jump	L1		#L1 is local
> 	0x00000200	jump	_strcpy		#_strcpy is defined elsewhere
> 	0x00000300  L1	jump	_exit		#_exit is defined elsewhere

> The assembler assumes all jumps are near jumps

But that is exactly what it mustn't do.  I would expect the assembler
to produce a near jump for the first one, since it knows that one is
near.  For the other two, it must produce far jumps, or at least
reserve enough space for a far jump.  Then the linker can either cop
out and use a far jump when the offset would have fit in 16 bits or it
can replace it with a near jump.  If it replaces it, it either has to
fill 32 bits with some sort of no-op or else it has to move stuff.  If
you choose to shrink things, the assembler will have to tell the loader
about the first jump as well (the offset will need changing).

In its complete form, the above solution is no better than the other
way (promoting near jumps to far jumps).  However, the above will
produce minimal code in almost all cases (one program out of five
thousand maybe will have a non-optimal jump?).  This is plenty good
enough for most people.  The other three can pay the price of a little
extra cpu time and get it optimal.

All you need is for the assembler to tell the loader about each such
instruction, so the loader can fix up whatever it has to without having
to scan the entire load module looking for jumps that cross the area
it's patching.

UNIX currently has something reminiscent of this: the assembler chooses
branch instructions in near/far variants and fixes the instruction type
at assemble time, pessimizing for undefined symbols.  The loader merely
fills in the offsets, even if a shorter instruction sequence would have
been possible had it been known that the target was as close as it is.

					der Mouse

				(mouse@mcgill-vision.uucp)

fnf@mcdsun.UUCP (Fred Fish) (10/07/87)

In article <899@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse) writes:
[stuff deleted... fnf]
>> Sigh, guess we are going to have to go into the gory details.
[stuff deleted... fnf]
>> The assembler assumes all jumps are near jumps
>
>But that is exactly what it mustn't do.  I would expect the assembler
>to produce a near jump for the first one, since it knows that one is
>near.  For the other two, it must produce far jumps, or at least
>reserve enough space for a far jump.  Then the linker can either cop
>out and use a far jump when the offset would have fit in 16 bits or it
>can replace it with a near jump.  If it replaces it, it either has to
>fill 32 bits with some sort of no-op or else it has to move stuff.  If
>you choose to shrink things, the assembler will have to tell the loader
>about the first jump as well (the offset will need changing).

Gee, its been a while since this topic came around the first time, so
lots of people will probably be totally in the dark about the original
issues.  Speaking strictly for those that remember the discussion,
let me reiterate the major points:

1.	The assembler *does not* do any relocation, computation
	of offsets, or whatever you want to call it.  When it
	sees a symbol, either local or global, it just stuffs it
	into the symbol table to be passed on to the linker and
	creates a relocation entry for the current offset.  I'm really
	puzzled by people's persistent belief that the assembler should
	do anything else (other than conditioning from current released
	implementations for most CISC processors).

2.	The assembler has to emit either a "near" jump for a "far"
	jump bit pattern in the object code (I guess it could emit
	a third "insert appropriate jump instruction here" code, but
	why bother).  If you default to "near" jumps, you have the
	linker fix up all the jumps that are really "far" jumps to
	be "far" jumps.  If you default to "far" jumps, you have
	the linker fix up all the jumps that are really "near" jumps
	to be "near" jumps.  In either case, you either grow or
	shrink the code as appropriate, in the linker.  What could
	be easier?  In either case, you end up with exactly the same
	executable object code.  No nops, no "non-optimal" jumps, the
	*same* *optimal* *code*.

3.	Now the only choice is to decide which default you want.
	For my implementation, it was obvious that near jumps were
	the correct default.  For another situation, the reverse
	might be true.  I don't claim that either is somehow
	theoretically "better".  (Someone else might care to claim
	so though, don't let me stop you... :-)


>UNIX currently has something reminiscent of this: the assembler chooses
>branch instructions in near/far variants and fixes the instruction type
>at assemble time, pessimizing for undefined symbols.  The loader merely
>fills in the offsets, even if a shorter instruction sequence would have
>been possible had it been known that the target was as close as it is.

Don't let existing sub-optimal solutions cloud your vision.

-Fred
-- 
# Fred Fish    hao!noao!mcdsun!fnf    (602) 438-3614
# Motorola Computer Division, 2900 S. Diablo Way, Tempe, Az 85282  USA

rwhite@nusdhub.UUCP (Robert C. White Jr.) (10/09/87)

In article <384@mcdsun.UUCP>, fnf@mcdsun.UUCP (Fred Fish) writes:
> 	the linker fix up all the jumps that are really "near" jumps
> 	to be "near" jumps.  In either case, you either grow or
> 	shrink the code as appropriate, in the linker.  What could
> 	be easier?  In either case, you end up with exactly the same
> 	executable object code.  No nops, no "non-optimal" jumps, the
> 	*same* *optimal* *code*.

	First, a linker is a "linking loader" and it's only REAL
purpose is to resolve refrences and setup dynamic relocation
information.  ALL "short" jumps [add/subtract value from the
instruction pointer directly] are compleetly generated and closed
in the assembler.  If there were to be an alteration in the size
of a block of code-text, the linker would have to "reassemble" the
code block to make up for the altered "short" jumps and such.  In
order for the linker to do this it would either need the source
code, or it would have to take a stab at disassembeling the object
code and hope not to get it wrong.
	The assembler is designed to AUTOMATICALLY determine the
"near"ness or "far"ness of a refrence.  This works beautfuly as
long as you act like a pascal programmer and only use backward
refrences.  For the forward refrences you must use a keyword like
"near" or "far" or else take what you get, and hope what you get
is close enough to work.
	It should be obvious that the assemblers job is to assemble
and the linkers job is to link.

MR FRED:  At one point you said "what could be simpler" [deleted from this text
for brevity].  If it is so simple, I would love to see your compleeted
disassembling-assebeling-optomizing-editing-linking-loader on the
market.  [For a PC or 3B2 prefreable, as these are the machines
I have avalible to test it on.]

Discalmer:  YES! I used x86 refrences, I did this because I like to
stick to topics and machines I know, so _PLEASE_, no "there are other
machines in existance, you introverted slob..." type flames.  And, yes,
I am woking on my spelling, but if I waited till my dislexic brain
could do it perfectly, nobody would ever see my deathless prose.

Rob ("So who asked you anyway?") white.

franka@mmintl.UUCP (Frank Adams) (10/09/87)

In article <384@mcdsun.UUCP> fnf@mcdsun.UUCP (Fred Fish) writes:
>3.	Now the only choice is to decide which default you want.
>	For my implementation, it was obvious that near jumps were
>	the correct default.  For another situation, the reverse
>	might be true.  I don't claim that either is somehow
>	theoretically "better".  (Someone else might care to claim
>	so though, don't let me stop you... :-)

It seems like the near jumps are the correct choice, since they take less
space.  This is not a fantastically important consideration, but I don't see
any other considerations whatsoever.

It does not seem like an accidental property of the architecture that the
near jumps are shorter than the far ones; if they aren't shorter, why have
them?
-- 

Frank Adams                           ihnp4!philabs!pwa-b!mmintl!franka
Ashton-Tate          52 Oakland Ave North         E. Hartford, CT 06108

henry@utzoo.UUCP (Henry Spencer) (10/11/87)

>	... If you default to "near" jumps, you have the
>	linker fix up all the jumps that are really "far" jumps ...
>	[vice versa for defaulting to "far" jumps]
>	... In either case, you either grow or
>	shrink the code as appropriate, in the linker.  What could
>	be easier?  In either case, you end up with exactly the same
>	executable object code.  No nops, no "non-optimal" jumps, the
>	*same* *optimal* *code*. ...I don't claim that either is somehow
>	theoretically "better"...

Hah, caught you, Fred!  Not (quite) true unless the linker is fairly
sophisticated.  There are interdependent situations in which the spans of
several jumps depend on each other's size:  they can all be "near", but the
linker will discover this only if it looks at making them *all* "near" at
the same time.  A simple one-at-a-time approach with a "far" default will
leave them all "far".  The level of sophistication needed to spot this
amounts to simulating a "near" default, so one might as well just use that
default in the first place.

Such situations are admittedly not all that common, but it does supply a
reason for picking "near" over "far" if nothing else interferes.
-- 
"Mir" means "peace", as in           |  Henry Spencer @ U of Toronto Zoology
"the war is over; we've won".        | {allegra,ihnp4,decvax,utai}!utzoo!henry

fnf@mcdsun.UUCP (Fred Fish) (10/14/87)

>In article <384@mcdsun.UUCP>, fnf@mcdsun.UUCP (Fred Fish) writes:
> 	the linker fix up all the jumps that are really "near" jumps
> 	to be "near" jumps.  In either case, you either grow or
> 	shrink the code as appropriate, in the linker.  What could
> 	be easier?  In either case, you end up with exactly the same
> 	executable object code.  No nops, no "non-optimal" jumps, the
> 	*same* *optimal* *code*.

Since posting this, I have received some mail from Dean Inada at Peregrine
Systems that provided an example where shrinking the code is not really
possible without considering more than one candidate jump at a time, something
that my current implementation doesn't do.  Thus growing the code is the
correct choice for my situation.

The example Dean provided was essentially:

	foo:
		farjump	bar
		["X" bytes of stuff]
		farjump	foo
	bar:

Where X is just that right size such that neither jump, considered by
itself, can be shortened to near, but if we had started with near jumps
neither would have been required to be lengthened to far jumps.  "X" 
depends upon the size of your near/far jump sequences.  Thus in order to
make my original statement true, it is necessary to consider more than
one candidate jump simultaneously (LOTS more work).  Thus "near" as the
default is even more obviously the correct choice for my implementation.

In article <117@nusdhub.UUCP> rwhite@nusdhub.UUCP (Robert C. White Jr.) writes:
>    ALL "short" jumps [add/subtract value from the
>instruction pointer directly] are compleetly generated and closed
>in the assembler.  If there were to be an alteration in the size
>of a block of code-text, the linker would have to "reassemble" the
>code block to make up for the altered "short" jumps and such.  In
>order for the linker to do this it would either need the source
>code, or it would have to take a stab at disassembeling the object
>code and hope not to get it wrong. The assembler is designed to
>AUTOMATICALLY determine the "near"ness or "far"ness of a refrence. 

The only reason that the linker would need to "reassemble" the code
block is if the assembler decided to try doing part of the linker's
job to begin with.  My assembler doesn't, thus my linker doesn't have
to go through the pain you described above.

>	It should be obvious that the assemblers job is to assemble
>and the linkers job is to link.

I couldn't agree more...

>MR FRED: At one point you said "what could be simpler" [deleted from this text
>for brevity].  If it is so simple, I would love to see your compleeted
>disassembling-assebeling-optomizing-editing-linking-loader on the
>market.  [For a PC or 3B2 prefreable, as these are the machines
>I have avalible to test it on.]

You very likely will see it some day, though I doubt it will run on the
PC or 3B2 except possibly as part of a cross development environment.

-Fred
-- 
# Fred Fish    hao!noao!mcdsun!fnf    (602) 438-3614
# Motorola Computer Division, 2900 S. Diablo Way, Tempe, Az 85282  USA