[comp.sys.amiga] manx c

mwm@eris.BERKELEY.EDU (Mike (My watch has windows) Meyer) (01/01/70)

In article <3211@zen.berkeley.edu> waterman@cory.Berkeley.EDU.UUCP (T.S. Alan Waterman) writes:
<     What I don't get is this-- (!ptr) seems more straightforward,
<     you never have to worry about types, and it makes smaller code
<     than (ptr == 0) anyway.  Why use the second expression? (with
<     pointers, at least.)

No, !ptr is *not* more straightforward. I read that as "if ptr is
false". Huh? Pointers aren't booleans - they don't take on true or
false values. On the other hand, !ptr can be read as "if ptr not
valid", which makes some sense. I don't like it, but I'm not dogmatic
about it.

That !ptr generates smaller code on Manx is probably related to Manx
not handling "ptr == 0" correctly. On a compiler that does things
right (4.3BSD pcc), I put in:

	main() {
		char	*x ;
		if (x == 0) ;
		if (!x) ;
		}

and get out (for the important part):

	L15:
		tstl	-4(fp)
		jneq	L16
	L16:
		tstl	-4(fp)
		jneq	L17
	L17:

In other words, you get the exact same code from either case. I expect
Lattice to do the same, and will try to remember to test it when I get
home.

<   I really don't want to turn this into a war, but I have to disagree, at
<least in principle. The comparison operator '==' only applies (and I think
<only should apply) if the objects being compared ARE OF THE SAME TYPE!!!!

You're welcome to disagree. But if you implement a compiler that
enforces that view, please don't call it a C compiler. The standards
quite clearly states that 0 is magic, and turns into a pointer in
expressions involving pointers. A compiler that behaves otherwise is
either buggy, or not a C compiler. The reasons for doing things the
way C does them will be covered below.

<If your 0 happens to be of the same type as your pointer, fine; but, on the
<other hand, if it's not, something's going to get type converted.

The constant 0 is of type int. No questions asked. In expressions
involving poiners, the standards state that it will be converted to a
null pointer. That pointer is not necessarily all 0 bits, it's just
something that no pointer to an object can be. On some architectures,
the pointer with all zero bits can point to a valid object, so you
have to use some other value for the null pointer. 0 gets turned into
that value by the compiler.

<If both arg's are numeric, this wont be a problem, because the 'bigger'
<type will win, and the other one will get converted (try comparing int's
<and reals).  Pointers, though, confuse the poor compiler, because it's not
<sure what you really meant to do. Try comparing a pointer and a floating-point
<real.

But there isn't a floating point value that can be implicitly coerced
into a pointer, so there is no case where doing such a comparison
makes sense. That kind of construct isn't portable. Your argument for
integer comparison is correct, except for the special case of 0.

<   Before you flame, I'll admit that it makes no sense to do that. But then,
<it really doesn't make sense to compare a pointer with a constant of a different
<size, either, becuase the compiler doesn't (but probably should) know
<what to do with it.

But people writing code shouldn't have to know how long pointers on
their machine are! It makes the code less portable. It also creates
nightmares on machines with pointers of different lengths. And pity
the poor person who's writing code on a machine that has a pointer to
some type which is longer than any integral type (yes, such machine
exist).


	<mike
--
Take a magic carpet to the olden days			Mike Meyer
To a mythical land where everybody lays			mwm@berkeley.edu
Around in the clouds in a happy daze			ucbvax!mwm
In Kizmiaz ... Kizmiaz					mwm@ucbjade.BITNET

adamsd@crash.CTS.COM (Adams Douglas) (01/01/70)

I'm not trying to contribute to this back-and-forth which is starting
up, but I personally question the need for using the 'int' type under
Manx. I'm writing a heavily mathematecal application (Planetarium) and
I do not have a single instance of 'int' as a type token anywhere in
my code. Everything is explicitly 'long' or 'short'.

I decided to do this when I read about what Manx does with int's
passed to functions. And I got bit by it with my first piece of test
code, which used 'int'. I also now compile with +L set.

Also, I think 'long' and 'short' keeps you more aware of your memory
usage.


-- 
=======================================================
Adams Douglas	ARPA:crash!adamsd@nosc.mil  AT&T:818-354-3076 <work>
DSN/JPL/NASA	UUCP:{cbosgd | hplabs!hp-sdd | sdcsvax | nosc}!crash!adamsd
		Internet: adamsd@crash.CTS.COM

My opinions! Do you hear? MINE! Not JPL's.

"Do not be angry with me if I tell you the truth." -- Socrates
"Tell the Truth and run."--Yugoslav proverb

stever@videovax.Tek.COM (Steven E. Rice, P.E.) (01/01/70)

In article <3211@zen.berkeley.edu>, waterman@cory.Berkeley.EDU.UUCP (T.S. Alan Waterman) writes:

> In article <17827@amdcad.AMD.COM> tim@amdcad.UUCP (Tim Olson) writes:

[ quite a bit deleted ]

>        There are many kinds of '0' (short, long, pointer, floating-point..)
>        and saying "equal to 0" leaves things open to Manx's type conversion.
>        Manx has a bug in that it likes to leave constants as untouched as
>        possible.
>        [argument mine] 
>> 
>> 	From the X3J11 ANSI C Draft, section 3.2.2.3 (Pointers):
>> 
>> 	"... An integral constant expression with the value 0, or such an
> 		^^^^^^^^  but how big is an integer?? (we've been through
> 			  this before!!)

Way back when, shortly after the dawn of time (but not much), I was an
eager college student programming on an IBM 1620.  [The 1620 was one of
the few really *digital* computers ever built (in our case, it had 60,000
*digits* of core, each of which could hold a single decimal *digit* --
0 to 9; none of this *binary* nonsense. . .).]  Our 1620 had a FORTRAN
compiler (big step forward -- previous machines had assembly language
only).

In IBM 1620 FORTRAN one saw numerous constructs of the form (remember
the IJKLMN rule -- anything starting with those letters is an integer;
anything else is real):

      A = 2.0
      B = FLOAT(I)/3.0
      C = 2.0*B

This was because the 1620 FORTRAN compiler was very narrow-minded.  If
a number doesn't have a decimal point (or an exponent), then it *must*
be an integer, right?

Mercifully, compilers have improved along with computer speeds.  One
concept that has been added is called "type coercion" -- expressions
are scanned and values are converted to the "highest" type present
in the expression.

Since the type of any expression is known at compile time, constants
can be "coerced" to the appropriate type, without creating compiler
hysteria or user frustration.  As the type of the expression in
question ("ptr == 0") is clearly known in advance -- "ptr" has been
declared to be a pointer -- there is no good reason not to coerce the
zero to the correct type!

>      What I don't get is this-- (!ptr) seems more straightforward,
>      you never have to worry about types, and it makes smaller code
>      than (ptr == 0) anyway.  Why use the second expression? (with
>      pointers, at least.)

There is no reason (other than incomplete optimization) that (ptr == 0)
should be any larger than (!ptr) -- at least on the 68000 family!  If we
ignore the limited arithmetic allowable on pointers, the general strategy
for an equality test would be (using long words, because of the pointer
arithmetic):

                 movea.l   <source>,Ax
                 cmpa.l    #<constant>,Ax
                 bne       not_equal

                 [ code to be executed if the two are equal ]

                 bra       around

    not_equal    [ code to be executed if the two are not equal ]

    around       [ next statement ]

But, when the optimizer (or for that matter, the compiler) sees it is
generating a "movea.l  <source>,Ax" / "cmp.l  #0,Ax" sequence, it can
immediately delete the "cmp" instruction, because the 68000 sets the
condition codes when the register is loaded.

For a (!ptr) construct, a "tst.l <source>" might be generated, but this
is neither smaller nor faster than the "movea.l" instruction.  Further,
with a pointer it is probable the pointer will be used if it is non-zero,
so the register load is likely to be both faster and smaller overall.

					Steve Rice

-----------------------------------------------------------------------------
new: stever@videovax.tv.Tek.com
old: {decvax | hplabs | ihnp4 | uw-beaver | cae780}!tektronix!videovax!stever

bobb@tekfdi.TEK.COM (Robert Bales) (01/01/70)

In article <3211@zen.berkeley.edu> waterman@cory.Berkeley.EDU.UUCP (T.S. Alan
Waterman) writes:

>     What I don't get is this-- (!ptr) seems more straightforward,
>     you never have to worry about types, and it makes smaller code
>     than (ptr == 0) anyway.  Why use the second expression? (with
>     pointers, at least.)

Speaking just for myself: :)

What does "if (!ptr)" mean? (rhetorical question) As we all know, it means the
same as "if (ptr == 0)" However, interpreting the first form requires
knowledge that the C "if" statement compares against 0, while the second form
makes the desired test explicit and is, therefore -- I feel -- clearer.

   Bob Bales
   Tektronix, Inc.

I help Tektronix make their instruments. They don't help me make my opinions.

derek@speedy.WISC.EDU (Derek Zahn) (07/31/87)

Mike, I wonder if you don't somehow have an old version of the Manx stuff;
when did you buy it?  I bought mine in February and my manual
does not have the discrepancies yours does; neither have I noticed any
bugs in the compiler.  By the way, the default is small code and small
data; +C and +D use the large models.

I agree that the manual at times can be a pain, and I do wish that Manx
had function prototyping (gone are the carefree days of anarchic hacking;
I guess we all get old).

derek

Derek Zahn @ Wisconsin

USENET:         ...!{allegra,heurikon,ihnp4,seismo,ucbvax}!uwvax!derek
BITNET:         derek at wiscvm
ARPA INTERNET:  derek@cs.wisc.edu

"It's much much much too hot in here."

mwm@eris.UUCP (07/31/87)

In article <4028@spool.WISC.EDU> derek@speedy.WISC.EDU (Derek Zahn) writes:
<Mike, I wonder if you don't somehow have an old version of the Manx stuff;
<when did you buy it? 

I didn't buy it. A company I'm doing some work for said "Oh, could you
do it with Manx. Here's a copy." When I asked about legality, they
said "We've got a site license."

They have since changed their mind (I detect a power struggle). I'm
going to check on the status of the site license and see if I can keep
using it (the Manx make looks nicer than the PD one I'm running now).
If not, it all goes back to the company.

Have you checked the specific references I posted last night?

BTW, I've been told that the code generation bug I tripped over is
fixed in 3.40b.

	<mike
--
But I'll survive, no you won't catch me,		Mike Meyer
I'll resist the urge that is tempting me,		ucbvax!mwm
I'll avert my eyes, keep you off my knee,		mwm@berkeley.edu
But it feels so good when you talk to me.		mwm@ucbjade.BITNET

cjp@vax135.UUCP (Charles Poirier) (08/04/87)

This has been posted before but it may need to be said again.
The problem Mike Meyer mentioned, about Manx C claiming illegal
pointer-to-int comparison in

if (ptr == NULL)

can be fixed by redefining NULL.  As in:

#undef NULL
#define NULL ((void *) 0L)

The cast of "pointer to void" tells the compiler to "ignore pointer type".
You might want to go and change the include file which (mis)defined NULL
in the first place.  I misrecall which file that is, sorry.

-- 
	Charles Poirier   (decvax,ucbvax,ihnp4,attmail)!vax135!cjp

   "Docking complete...       Docking complete...       Docking complete..."

mwm@eris.BERKELEY.EDU (Mike (My watch has windows) Meyer) (08/05/87)

In article <1836@vax135.UUCP> cjp@vax135.UUCP (Charles Poirier) writes:
<This has been posted before but it may need to be said again.
<The problem Mike Meyer mentioned, about Manx C claiming illegal
<pointer-to-int comparison in
<
<if (ptr == NULL)
<
<can be fixed by redefining NULL.  As in:
<
<#undef NULL
<#define NULL ((void *) 0L)
<
<The cast of "pointer to void" tells the compiler to "ignore pointer type".
<You might want to go and change the include file which (mis)defined NULL
<in the first place.  I misrecall which file that is, sorry.

Uh, when you start talking about "misdefining NULL", you're walking on
very thin ice. K & R are noticably silent, except to say that
"assigning a constant 0 to a pointer will produce a null pointer
distinguished from a pointer to any object."

dpANS says that NULL must be defined, and must be either "0" or
"((void *) 0))". *Not* "0L". Making it 0L creates a whole different
set of headaches.

So I'd claim that you're misdefining NULL to cover for a bug in the
compiler.

Of course, "if (ptr == 0)" is as valid as "if (ptr == NULL)", and
probably isn't fixed by that change. That the identical "if (!ptr)"
doesn't produce an error message may indicate that "if (ptr == 0)"
won't, either.

	<mike
--
ICUROK2C, ICUROK2.				Mike Meyer
ICUROK2C, ICWR2.				mwm@berkeley.edu
URAQT, I WANT U2.				ucbvax!mwm
OO2EZ, I WANT U2.				mwm@ucbjade.BITNET

waterman@cory.Berkeley.EDU (T.S. Alan Waterman) (08/06/87)

>Of course, "if (ptr == 0)" is as valid as "if (ptr == NULL)", and
>probably isn't fixed by that change. That the identical "if (!ptr)"
>doesn't produce an error message may indicate that "if (ptr == 0)"
>won't, either.
>
>	<mike

Mike, the deal with this problem is this:

  if (ptr == 0)  compares the pointer with an INT, which is gonna be 16 bits.
    That is, is hacks ptr in half and compares the bottom half with 0 (16 bits).
    If you don't expect your pointer to end up on such a huge page-boundary,
    this'll work, but I wouldn't trust it....

  if (!ptr) loads the thing into a register (all 32 bits of it) and checks
    the zero flag. It doesn't run a cmp instruction.


In short, the error message is correct. You are being rightly warned the the
compiler is about to do exactly what you told it to, and not really what
you wanted to do. Oh, BTW, defining anything as a ((void *) x) makes a long-
word (32 bit) value, whether x is long or not.


TS Waterman

'psionic code, the only way to fly'	waterman@cory.Berkeley.Edu
"I am my employer, and these are not his opinions"

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

In article <3199@zen.berkeley.edu> waterman@cory.Berkeley.EDU.UUCP (T.S. Alan Waterman) writes:
+-----
| >Of course, "if (ptr == 0)" is as valid as "if (ptr == NULL)", and
| >probably isn't fixed by that change. That the identical "if (!ptr)"
| >doesn't produce an error message may indicate that "if (ptr == 0)"
| >won't, either.
| >
| >	<mike
| 
| Mike, the deal with this problem is this:
| 
|   if (ptr == 0)  compares the pointer with an INT, which is gonna be 16 bits.
|     That is, is hacks ptr in half and compares the bottom half with 0 (16 bits).
|     If you don't expect your pointer to end up on such a huge page-boundary,
|     this'll work, but I wouldn't trust it....
+-----
No.  Mike is right.  From K&R, section 7.7 (Equality Operators):

	"... A pointer to which 0 has been assigned is guaranteed not to
	point to any object, *and will appear to be equal to 0*; in
	conventional usage, such a pointer is considered to be null."
	[emphasis mine]

	From the X3J11 ANSI C Draft, section 3.2.2.3 (Pointers):

	"... An integral constant expression with the value 0, or such an
	expression cast to type void, is called a null pointer constant. 
	If a null pointer constant is assigned to or compared for
	equality to a pointer, the constant is converted to a pointer of
	that type.  Such a pointer, called a *null pointer*, is
	guaranteed not to point to any object or function."

Any C compiler which doesn't perform in this manner is broken.

+-----
|   if (!ptr) loads the thing into a register (all 32 bits of it) and checks
|     the zero flag. It doesn't run a cmp instruction.
+-----
No. !ptr is *exactly* equivalent to ptr==0.  K&R, section 7.2:

	"... The result of the logical negation operator ! is 1 if the
	value of its operand is 0, 0 if the value of its operand is
	non-zero.  ...  It is applicable to any arithmetic type *or to
	pointers*."
	[emphasis mine]

	From the X3J11 ANSI C Draft, section 3.3.3.3 (Unary Operators)

	"... The result of the logical negation operator ! is 0 if the
	value of its operand is nonzero, 1 if the value of its operand
	is 0.  ...  The expression !E is equivalent to (0==E)."

Sorry for the diatribe, but us C police want to eradicate any
disinformation as soon as possible so that it doesn't corrupt young
minds ;-) ;-) ;-)

	-- Tim Olson
	(tim@amdcad.amd.com)

	"C-Police 'R' Us"

rokicki@rocky.STANFORD.EDU (Tomas Rokicki) (08/06/87)

About the `faster' Lattice---if anyone verifies this, let me know.
I don't believe benchmarks in ads.  But Lattice does have compilers
which do true data-flow based code optimization; maybe they've
moved some of those smarts onto the Amiga.  That would be a win.
That, and good automatic register allocation.

If a faster Lattice does exist, I can see a lot of people
recompiling a lot of old code for that speed-up . . .

-tom

fnf@mcdsun.UUCP (Fred Fish) (08/06/87)

In article <3199@zen.berkeley.edu> waterman@cory.Berkeley.EDU.UUCP (T.S. Alan Waterman) writes:
>Mike, the deal with this problem is this:
>
>  if (ptr == 0)  compares the pointer with an INT, which is gonna be 16 bits.
>    That is, is hacks ptr in half and compares the bottom half with 0 (16 bits).

No, Mike was right.  Bear in mind that I haven't actually tried the example
given to see what the generated code is, but if it is as you described
above then it is broken.

From draft proposed Ansi C standard, 3.2.2.3:

	"An integral constant expression with the value 0, or such an 
	expression cast to type void *, is called a null pointer constant.
	If a null pointer constant is assigned to or compared for
	equality to a pointer, the constant is converted to a pointer
	of that type.  ..."

In other words, the 16 bit int is widened to 32 bits, not the other
way around.  Now granted, Manx C is hardly "Ansi C", but the above
rule is not something new with Ansi C.

>
>In short, the error message is correct. You are being rightly warned the the
>compiler is about to do exactly what you told it to, and not really what
>you wanted to do. Oh, BTW, defining anything as a ((void *) x) makes a long-
>word (32 bit) value, whether x is long or not.

If it behaves as you believe, the compiler is rightly warning that it
it doing whatever it feels like, not what you told it to, or what it should
be doing.  :-)

-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

waterman@cory.Berkeley.EDU (T.S. Alan Waterman) (08/06/87)

In article <17827@amdcad.AMD.COM> tim@amdcad.UUCP (Tim Olson) writes:
>+-----
>No.  Mike is right.  From K&R, section 7.7 (Equality Operators):
>
>	"... A pointer to which 0 has been assigned is guaranteed not to
>	point to any object, *and will appear to be equal to 0*; in
>	conventional usage, such a pointer is considered to be null."
>	[emphasis mine]

       There are many kinds of '0' (short, long, pointer, floating-point..)
       and saying "equal to 0" leaves things open to Manx's type conversion.
       Manx has a bug in that it likes to leave constants as untouched as
       possible.
       [argument mine] 
>
>	From the X3J11 ANSI C Draft, section 3.2.2.3 (Pointers):
>
>	"... An integral constant expression with the value 0, or such an
		^^^^^^^^  but how big is an integer?? (we've been through
			  this before!!)

>	expression cast to type void, is called a null pointer constant. 
>	If a null pointer constant is assigned to or compared for
>	equality to a pointer, the constant is converted to a pointer of
>	that type.  Such a pointer, called a *null pointer*, is
>	guaranteed not to point to any object or function."
>
>Any C compiler which doesn't perform in this manner is broken.

     You're right--it's broken, but now we all know that Manx shortens
     the pointer instead of extending the constant, so we have two choices:
     1)  live with it,   or
     2) live with it for now, and hope Goodnow fixes it soon!

     What I don't get is this-- (!ptr) seems more straightforward,
     you never have to worry about types, and it makes smaller code
     than (ptr == 0) anyway.  Why use the second expression? (with
     pointers, at least.)
>
>[...] !ptr is *exactly* equivalent to ptr==0.  K&R, section 7.2:
>
>	"... The result of the logical negation operator ! is 1 if the
>	value of its operand is 0, 0 if the value of its operand is
>	non-zero.  ...  It is applicable to any arithmetic type *or to
>	pointers*."
>	[emphasis mine]

     This is very true, but "!ptr is *exactly* equivalent to ptr==0" is
     misleading. (ptr == 0) does type checking and conversion,
     (!ptr) doesn't.

>
>	From the X3J11 ANSI C Draft, section 3.3.3.3 (Unary Operators)
>
>	"... The result of the logical negation operator ! is 0 if the
>	value of its operand is nonzero, 1 if the value of its operand
>	is 0.  ...  The expression !E is equivalent to (0==E)."
>
>Sorry for the diatribe, but us C police want to eradicate any
>disinformation as soon as possible so that it doesn't corrupt young
>minds ;-) ;-) ;-)
>
>	-- Tim Olson
>	(tim@amdcad.amd.com)
>
>	"C-Police 'R' Us"

   I really don't want to turn this into a war, but I have to disagree, at
least in principle. The comparison operator '==' only applies (and I think
only should apply) if the objects being compared ARE OF THE SAME TYPE!!!!

If your 0 happens to be of the same type as your pointer, fine; but, on the
other hand, if it's not, something's going to get type converted.
If both arg's are numeric, this wont be a problem, because the 'bigger'
type will win, and the other one will get converted (try comparing int's
and reals).  Pointers, though, confuse the poor compiler, because it's not
sure what you really meant to do. Try comparing a pointer and a floating-point
real.
   Before you flame, I'll admit that it makes no sense to do that. But then,
it really doesn't make sense to compare a pointer with a constant of a different
size, either, becuase the compiler doesn't (but probably should) know
what to do with it.
   It's awfully inconvienient (maybe that's putting it REAL mildly) to go
redefine NULL, or go around comparing to 0L if you don't want to use
the ! operator. But the compiler is slightly in that it munches
the pointer instead of the int.  (Or, if you want to be a purist about
it and not have have to worry, use Lettuce C, where ALL the ints are
32 bits :^)
   Type comparisons are always a pain in the rear, but they get especially
bad with constants (like 0), beacause (this) compiler assumes you knew what
you meant when you typed 0 (and not 0L). Use a NULL that's the same size
as your pointer.


     Big Brother's been sleeping--careful not to wake him up...

     --TS  (sorry to be so long-winded -- it's a bad habit)

mwm@eris.BERKELEY.EDU (Mike (My watch has windows) Meyer) (08/06/87)

In article <468@rocky.STANFORD.EDU> rokicki@rocky.STANFORD.EDU (Tomas Rokicki) writes:
<About the `faster' Lattice---if anyone verifies this, let me know.

I hit the lattice BBS last night after seeing that article. Wanted to
order a copy of the thing!

The current versions list shows the AmigaDOS C compiler at 3.10, and
the MS-DOS C compiler at 3.20. No mention of 4.0 at all.

I'm going to wait till I see the ad with my own eyes, then call them
and try and order the upgrade.

	<mike

--
Round about, round about, in a fair ring-a.		Mike Meyer
Thus we dance, thus we dance, and thus we sing-a.	mwm@berkeley.edu
Trip and go, to and fro, over this green-a.		ucbvax!mwm
All about, in and out, over this green-a.		mwm@ucbjade.BITNET

nw@palladium.UUCP (Neil Webber) (08/08/87)

In article <3199@zen.berkeley.edu>, waterman@cory.Berkeley.EDU (T.S. Alan Waterman) writes:
> 
>   if (ptr == 0)  compares the pointer with an INT, which is gonna be 16 bits.
>     That is, is hacks ptr in half and compares the bottom half with 0 (16 bits).
>     If you don't expect your pointer to end up on such a huge page-boundary,
>     this'll work, but I wouldn't trust it....
> 
>   if (!ptr) loads the thing into a register (all 32 bits of it) and checks
>     the zero flag. It doesn't run a cmp instruction.
> 
> In short, the error message is correct. You are being rightly warned the the
> compiler is about to do exactly what you told it to, and not really what
> you wanted to do.
> 
Sorry, but the Manx compiler is dead wrong here.  In certain contexts, the
symbol "0" DOES NOT MEAN INTEGER ZERO.  It means "null pointer".  The contexts
that exhibit this property are exactly those contexts where the compiler
knows that a pointer comparison or assignment is being performed.

On the 68000:

        char *ptr;

        ptr = 0;                /* 32 bit assignment of zeros to ptr */
        if (ptr == 0)           /* 32 bit comparison, Manx notwithstanding */

The size of an integer has nothing to do with it.  The symbol "0" is special.
Perhaps things would have been more clear if K & R had chosen some keyword, such
as "nil", but they didn't.

This is all spelled out quite well in K&R, H&S, as well as dpANS.  If the
Manx compiler insists on interpreting the meaning of those statements
differently, it's a bug.  I certainly don't plan to litter my code with
junk like

        if (ptr == 0L)

just because of a bug in Manx.

-- 
Neil Webber / Palladium Data Systems / (No longer confused with Jordan Marsh)
               Marlboro MA, 01752  {linus!alliant, harvard!cfisun}!palladium!nw

rokicki@rocky.STANFORD.EDU (Tomas Rokicki) (08/08/87)

> I'm not trying to contribute to this back-and-forth which is starting
> up, but I personally question the need for using the 'int' type under
> Manx.

There are plenty of reasons to use int.  First, int is defined as the
most `natural' size of a word.  For most values, this gives you speed.
For instance, if you use a 16-bit value when the int size is 32, in
each expression, that value will be expanded to a 32-bit value.  Those
additional instructions add up.  A 32-bit value where a 16-bit value
is more appropriate takes longer to fetch.  The less you mix word
lengths in expressions, usually, the more efficient your code is.

Secondly, scanf and printf use %d for ints, and %ld for longs.  Here
you *must* use ints, or do your own formatting, or do some fancy
#ifdef'ing to select the appropriate string (if your code is to be
portable.)  I use the stdio library regularly; it's portable, fairly
efficient, and pretty powerful.

Thirdly, all arguments to functions are coerced to at least ints if
they are smaller.  This is another case where using an int can avoid
some type coercions.

Now, typedefs have there place, certainly, and for arrays and the like,
they are invaluable.  But judicious use of int's can help your C
compiler do a good job.  For instance, the VAX 4.3bsd C compiler won't
put a short in a register.  The same compiler, and hcc on an IBM RT,
have a rather serious bug when comparing an unsigned short to an int.

And, then, of course, you have the standard functions, which typically
expect int's.  Here, at least, passing a short is safe, since it will
be expanded to an int on compilers which use 32-bit ints, but passing
a long will break on 16-bit C compilers.

I never use the +L option in Manx.  It's worth the additional speed.
And it's not that hard to write code that is portable to 16-bit int
machines and 32-bit int machines.

-tom

stever@videovax.Tek.COM (Steven E. Rice, P.E.) (08/10/87)

In article <4524@videovax.Tek.COM>, I wrote:

[ a bunch deleted ]

> There is no reason (other than incomplete optimization) that (ptr == 0)
> should be any larger than (!ptr) -- at least on the 68000 family!  If we
> ignore the limited arithmetic allowable on pointers, the general strategy
> for an equality test would be (using long words, because of the pointer
> arithmetic):
> 
>                  movea.l   <source>,Ax
>                  cmpa.l    #<constant>,Ax
>                  bne       not_equal
> 
>                  [ code to be executed if the two are equal ]
> 
>                  bra       around
> 
>     not_equal    [ code to be executed if the two are not equal ]
> 
>     around       [ next statement ]

So far, so good.  However, I then stick my foot into my mouth:
 
> But, when the optimizer (or for that matter, the compiler) sees it is
> generating a "movea.l  <source>,Ax" / "cmp.l  #0,Ax" sequence, it can
> immediately delete the "cmp" instruction, because the 68000 sets the
> condition codes when the register is loaded.

Thomas M. Breuel (<tmb@prep.ai.mit.edu>) wrote to point out that it is
true the condition codes are set -- but only when loading the data
registers!  Thus, while the full sequence would work, the shortened one
would not.

A reasonable alternative is to load the pointer value into a data register
(where the condition codes *are* set), and then branch:

                 move.l    <source>,Dx
                 bne       not_equal

                 etc.

Then, code in the leg executed when the pointer is non-zero can transfer
the pointer value to an address register, or use it directly as an index
value.

Thanks to Tom for pointing out my error.

					Steve Rice

-----------------------------------------------------------------------------
new: stever@videovax.tv.Tek.com
old: {decvax | hplabs | ihnp4 | uw-beaver | cae780}!tektronix!videovax!stever

keithd@cadovax.UUCP (08/10/87)

In article <344@palladium.UUCP> nw@palladium.UUCP (Neil Webber) writes:
>I certainly don't plan to litter my code with
>junk like
>
>        if (ptr == 0L)
>
>just because of a bug in Manx.

Or worse:

		if (ptr == (char *)0)

			and

		ptr = (struct foobar *)0;

Keith

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

> And, then, of course, you have the standard functions, which typically
> expect int's.  Here, at least, passing a short is safe, since it will
> be expanded to an int on compilers which use 32-bit ints, but passing
> a long will break on 16-bit C compilers.

last time I looked all the standard functions on the Amiga expect 32 bit
integers. Have you got some variant of Wait(), AllocMem(), and so on that
work differently?

So, for that matter, do all the standard Aztec functions in the 32 bit
integer library.

I use +P. I don't see any point to using anything but until you have a
known performance problem. After all, Aztec +P is still faster than Lattice.

Most of my programs spend most of their time Wait()ing anyway.
-- 
-- Peter da Silva `-_-' ...!seismo!soma!uhnix1!sugar!peter (I said, NO PHOTOS!)

jdg@elmgate.UUCP (08/16/87)

In article <4524@videovax.Tek.COM> stever@videovax.Tek.COM (Steven E. Rice, P.E.) writes:

[ ALL SORTS OF TEXT DELETED ]
>
>But, when the optimizer (or for that matter, the compiler) sees it is
>generating a "movea.l  <source>,Ax" / "cmp.l  #0,Ax" sequence, it can
>immediately delete the "cmp" instruction, because the 68000 sets the
                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^
>condition codes when the register is loaded.
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>					Steve Rice
>
>-----------------------------------------------------------------------------
>new: stever@videovax.tv.Tek.com
>old: {decvax | hplabs | ihnp4 | uw-beaver | cae780}!tektronix!videovax!stever

I'm sure many will point this out, but technically your wrong:

Page 115 Of the "MC68000 16/32 Bit Microprocessor Prgrammers R
Reference Manual Fourth edition", shows the MOVEA <ea>,An instruction
does not effect the condition codes.

No big deal of course, use a data register instead:
	MOVE.L _ptr, <FREE DATAREGISTER>
	BEQ Somelabel

Also having spent a bit of time looking into optimizing C compilers, the
data flow section must determine if it is wiser to generate the move
to the data register or to do the cmp instruction.  If the data register
has to be spilled to accomodate the faster test for zero  the *OVERALL*
effect may slow the code down <store Dn; do the testing; recover Dn later>. 
This assumes that optimizer has already determined what's in Dn
"DESERVES" a data register all it's own, or it could be that it has delayed
it's storage.  Sorry for ramblin' but I find the subject of true 
optimizing compilers interesting for reasons I won't go into.....


-- 
Jeff Gortatowsky       {seismo,allegra}!rochester!kodak!elmgate!jdg
Eastman Kodak Company  
These comments are mine alone and not Eastman Kodak's. How's that for a
simple and complete disclaimer? 

scotty@l5comp.UUCP (Scott Turner) (08/17/87)

Yes, movea.{w,l} ea,a{0..7} doesn't modify the condition codes.

But deciding "Hey I can fix that by shoving it in a data register" doesn't
always work out well in an optimizing compiler either. Consider that what
you have done is place the value in question into TWO registers, thus using
twice the number of registers needed. Registers are valuable to say the least.

Dr. Wirth in his recent (well kinda recent :) paper on the subject of compiler
code generation vs modern CPU's makes the same mistake that alot of people
make in studying code generation. They look at distinct pieces of code with
nothing in front of them and nothing after them. In the real world this happens
very very very rarely.

Let's take for example that lovely if (!=ptr) example:
>>                  movea.l   <source>,Ax
>>                  cmpa.l    #<constant>,Ax
>>                  bne       not_equal
This is what brought on the discussion about slam dancing a data register to
set the condition codes.

What's  wrong with this code?

First, <source> may ALREADY BE IN Ax! If the compiler is truely doing a
good job of optimization then there is indeed a very real probability that
Ax is already loaded with <source>. Reloading it would be a waste.

Second, the BEST optimizations often come from careful analysis of the
manual for the CPU. This is because CPU designers often slide in little
things to help out in code generation. In this case <constant> is 0. Most
compilers take a look at the right hand side and say "Whoa! That's an
Address register, dem only comes in 32 bits." However, upon careful
analysis of what Motorola really has to say we find that on a cmpa.w
#<constant>,A{0..7} <constant> is sign extended to 32 bits BEFORE it is
compared to the 32 bits in A{0..7}. Thus for <constant>'s of range 0..32767
cmpa.w can be used rather than cmpa.l. You'd be amazed how many compilers
don't use the cmpa.w in these cases.

Third, in a highly optimizing compiler there is always a continous running
record kept of WHAT is in each register. It may be that there is a 0
already loaded up in a register just waiting to be used to check out our
address register. Also, many of these compilers go one step further and
keep track of the use of immediate values. They will often then review this
list in order to load the most often used immediate values into registers.

Sure even a cmpa.{w,l} D{0..7},A{0..7} takes two cycles longer than the
movea.l D{0..7},A{0..7} which is the eqv opcode for timing comparisons
against the "Slam dance a Dreg" mode. BUT, two cycles is pretty cheap
compared to how many cycles it takes to load that poor Dreg after it gets
danced on.

Scott Turner
-- 
UUCP-stick: stride!l5comp!scotty | If you want to injure my goldfish just make
UUCP-auto: scotty@l5comp.UUCP    | sure I don't run up a vet bill.
GEnie: JST			 | "The bombs drop in 5 minutes" R. Reagan
		"Pirated software? Just say *NO*!" S. Turner

bennete@romana.cs.orst.edu (Erik J. Bennett) (11/15/88)

Is there any way to calloc more than 65535 bytes in manx 3.6a?
-Erik
bennete@romana.cs.orst.edu

dillon@POSTGRES.BERKELEY.EDU (Matt Dillon) (11/16/88)

>Is there any way to calloc more than 65535 bytes in manx 3.6a?
>-Erik
>bennete@romana.cs.orst.edu

	With 16 bit ints you cannot.  If you use 32 bit ints (+L option),
you can.

	However, at least in 3.6, there is an 'lmalloc' call which takes a
long (for those of you who use 16 bit ints).  Since this doesn't automatically
zero the memory, you still have to do that yourself.

						-Matt

phils@tekigm2.TEK.COM (Philip E Staub) (11/22/88)

In article <8811160401.AA24804@postgres.Berkeley.EDU> dillon@POSTGRES.BERKELEY.EDU (Matt Dillon) writes:
... question about large allocations via calloc ...
>
>	However, at least in 3.6, there is an 'lmalloc' call which takes a
>long (for those of you who use 16 bit ints).  Since this doesn't automatically
>zero the memory, you still have to do that yourself.
>
>						-Matt

The lmalloc() has been around for a long time in the Manx compiler. I'm
quite sure I had it when I bought the 3.20a compiler over 2 years ago. In
addition, even then, malloc() was implemented as follows:

The Manx malloc() call merely extracts the size argument into a long
variable and calls lmalloc(). The size argument is treated as unsigned.
When using 16 bit ints, this means you get no more than 65535 bytes. When 
using 32 bit ints, the same thing happens, meaning that a call on malloc() 
is equivalent to a call on lmalloc(), with the exception that you have an
extra level of subroutine call.

What you may have to be careful about is indexing the pointer you get from 
lmalloc() by a number larger than 65k. I haven't been able to reproduce this
with the 3.6 compiler, but I know that earlier versions had problems doing
this, since the compiler treated the index as an 'int' rather than a long,
even if you used a 'long' variable as the index. Caveat Emptor.

Yes, you still have to clear the memory yourself.

Phil
-- 
------------------------------------------------------------------------------
Phil Staub        
Tektronix, Inc., Vancouver, Washington 98668
phils@tekigm2.MEN.TEK.COM