[comp.sys.mac.programmer] Pascal deficiency?

aberno@questor.wimsey.bc.ca (Anthony Berno) (12/17/90)

I generally prefer Pascal programming, but I have come up against what
seems like a real deficiency in the language. I never really thought
about it before, but there does not seem to be any equivalent to
the ++ or -- operator in Pascal. I was doing some speed checks on
array accessing today, and it occured to me that in doing something
like incrementing an entry by one, the computer was doing rather a
lot of work!

Either there is no way to do a quick increment in Pascal, or I'm missing
something in my knowledge, or I'm wrong about the speed difference between
things like
++(variable) and
(variable):=(variable)+1

Any comments? This is pretty basic, I know, but I never considered it
before. :)  Excuse me while I go get my asbestos suit on.

roy@phri.nyu.edu (Roy Smith) (12/18/90)

aberno@questor.wimsey.bc.ca (Anthony Berno) writes:
> Either there is no way to do a quick increment in Pascal, or I'm missing
> something in my knowledge, or I'm wrong about the speed difference between
> things like ++(variable) and (variable):=(variable)+1

	I've never written a single line of pascal in my life, but in C,
x++ and x = x + 1 are absolutely and completely identical (as is x += 1).
Any decent compiler should generate exactly the same code for all three.
The ++ and -- operators are just syntactic sugar.  I'm not a language
lawyer, so I won't stick my head out about things like

	foo[bar(foo[i])]++

	vs.

	foo[bar(foo[i])] = foo[bar(foo[i])] + 1

but for incrementing simple variables, it makes no difference.  There are
lots of  good reasons not to like Pascal, but this isn't one of them.
--
Roy Smith, Public Health Research Institute
455 First Avenue, New York, NY 10016
roy@alanine.phri.nyu.edu -OR- {att,cmcl2,rutgers,hombre}!phri!roy
"Arcane?  Did you say arcane?  It wouldn't be Unix if it wasn't arcane!"

sec@cs.umn.edu (Stephen E. Collins) (12/18/90)

In <1990Dec17.160242.5095@phri.nyu.edu> roy@phri.nyu.edu (Roy Smith) writes:
>	I've never written a single line of pascal in my life, but in C,
>x++ and x = x + 1 are absolutely and completely identical (as is x += 1).
>Any decent compiler should generate exactly the same code for all three.

Decent is the key word here.  If your compiler does not optimize, you're
likely to get different code for these, and with the number of shoddy
software products on the market these days, you might want to investigate.

To wit, most CPUs have some sort of increment instruction in the hardware,
so a shoddy compiler may generate something like the following code:

x := x+1:    LOAD  X
             ADD   1
             STORE X
 -or-

x++:         INC X


Stephen E. Collins 
University of Minnesota Microcomputer & Workstation Networks Center
sec@boombox.micro.umn.edu | sec@umnacvx.bitnet | FAX: (612)625-6817

keith@Apple.COM (Keith Rollin) (12/18/90)

In article <q72au3w163w@questor.wimsey.bc.ca> aberno@questor.wimsey.bc.ca (Anthony Berno) writes:
>I generally prefer Pascal programming, but I have come up against what
>seems like a real deficiency in the language. I never really thought
>about it before, but there does not seem to be any equivalent to
>the ++ or -- operator in Pascal. I was doing some speed checks on
>array accessing today, and it occured to me that in doing something
>like incrementing an entry by one, the computer was doing rather a
>lot of work!
>
>Either there is no way to do a quick increment in Pascal, or I'm missing
>something in my knowledge, or I'm wrong about the speed difference between
>things like
>++(variable) and
>(variable):=(variable)+1

You could look into the built-in functions PREV and SUCC. However, the
last time I checked them out (which was around 3.0A2 timeframe), using
i := i + 1 actually generated better code. Go figure. I can't. Perhaps
it's because PREV and SUCC also work with general enumerated types
other than bytes, integers, and longints.

-- 
------------------------------------------------------------------------------
Keith Rollin  ---  Apple Computer, Inc.  ---  Developer Technical Support
INTERNET: keith@apple.com
    UUCP: {decwrl, hoptoad, nsc, sun, amdahl}!apple!keith
"Argue for your Apple, and sure enough, it's yours" - Keith Rollin, Contusions

mrn@eplunix.UUCP (Mark R. Nilsen) (12/18/90)

in article <q72au3w163w@questor.wimsey.bc.ca>, aberno@questor.wimsey.bc.ca (Anthony Berno) says:

> I was doing some speed checks on
> array accessing today, and it occured to me that in doing something
> like incrementing an entry by one, the computer was doing rather a
> lot of work!
> 
In Pascal getting to an array element with:
		
		MyArray[i] := Data;

Has the computer taking the address of MyArray and adding (i *
Sizeof(Data)).

In C stepping through an array with:

		MyArray++ = Data; 

Has the computer taking the address of MyArray and incrementing by
Sizeof(Data). 

In C you bypass an integer multiply.  That is one of the nice things
about C.  You can of course still do it the slow way in C   with
MyArray[i] = Data, and the compiler will do the multiply.  Think
Pascal lets you do some pointer calculations but you have to do the
size calculations yourself, in C the compiler will do them for you
(in the case of ++).

--Mark. 

stevewi@hpspdra.HP.COM (Steve Witten) (12/18/90)

You can use the 'succ' and 'pred' operators/functions in Pascal to
accomplish the same function as '++' and '--'.  So:

	integer i,j,k;

	   ...

	j := succ(i);  { same as 'j=i++' }
	k := pred(i);  { same as 'k=i--' }

	   ...

However, you have to remember that '++/--' are positional as well.
You cannot recreate this behavior.  You also cannot recreate the
behavior of 'x++' without an assignment in Pascal.

===============================================================================
Steve Witten                    stevewi%hpspdra@hplabs.hp.com
Intelligent Networks Operation  ...!hplabs!hpspdra!stevewi
Hewlett-Packard Co.             stevewi@hpspdra.spd.hp.com

ewright@convex.com (Edward V. Wright) (12/18/90)

In <1990Dec17.172613.7941@cs.umn.edu> sec@cs.umn.edu (Stephen E. Collins) writes:

>To wit, most CPUs have some sort of increment instruction in the hardware,
>so a shoddy compiler may generate something like the following code:

>x := x+1:    LOAD  X
>             ADD   1
>             STORE X
> -or-

>x++:         INC X


Actually, this would have to be

>x++:         LOAD  X
>             INC   X
>             STORE X

Unless you have an instruction to increment variables in memory!

peirce@outpost.UUCP (Michael Peirce) (12/18/90)

In article <q72au3w163w@questor.wimsey.bc.ca>, aberno@questor.wimsey.bc.ca (Anthony Berno) writes:
> 
> I generally prefer Pascal programming, but I have come up against what
> seems like a real deficiency in the language. I never really thought
> about it before, but there does not seem to be any equivalent to
> the ++ or -- operator in Pascal. I was doing some speed checks on
> array accessing today, and it occured to me that in doing something
> like incrementing an entry by one, the computer was doing rather a
> lot of work!
> 
> Either there is no way to do a quick increment in Pascal, or I'm missing
> something in my knowledge, or I'm wrong about the speed difference between
> things like
> ++(variable) and
> (variable):=(variable)+1
> 
> Any comments? This is pretty basic, I know, but I never considered it
> before. :)  Excuse me while I go get my asbestos suit on.

Using X := X + 1; rather than the c style X++; is more a matter of style 
than substance.  Just to make sure I Iooked at the code generated from a 
"X := X + 1;" statement (using DUMPOBJ in MPW) and found the use of 

"ADDQ.W  #$1,-2(A6)".  

The same instruction was generated by C for both "X++;" and "X = X + 1;" too.

Don't worry, be happy.  Pascal does a pretty good job for you.

-- michael


--  Michael Peirce         --   {apple,decwrl}!claris!outpost!peirce
--  Peirce Software        --   Suite 301, 719 Hibiscus Place
--  Macintosh Programming  --   San Jose, California 95117
--           & Consulting  --   (408) 244-6554, AppleLink: PEIRCE

roy@phri.nyu.edu (Roy Smith) (12/18/90)

I asserted that:
> in C, x++ and x=x+1 are absolutely and completely identical (as is x+=1).
> Any decent compiler should generate exactly the same code for all three.

sec@cs.umn.edu (Stephen E. Collins) replied:
> Decent is the key word here.  If your compiler does not optimize, you're
> likely to get different code for these, and with the number of shoddy
> software products on the market these days, you might want to investigate.

	My first impression of Stephen's posting was "well, any compiler
that's so bad it can't generate code for x=x+1 as good as it does for x++
must really be the pits".  So, I tried an experiment.  I compiled:

	a () { int x; x = 1; x = x + 1; }
	b () { int x; x = 1; x++; }

on my SunOS-3.5.2 system using the stock C compiler, with and without -O and
compared the code generated with -S.  I'll confess to never having learned
the m68k instruction set, but it sure looks like in both cases, b() generated
more efficient code than a().  Stripping away the function entry and exit
code, basically you have:

           without -O flag                with -O flag

a()     movl    #0x1,a6@(-0x4)           moveq   #1,d0
        movl    a6@(-0x4),d0             movl    d0,a6@(-4)
        addql   #0x1,d0                  addql   #1,d0
        movl    d0,a6@(-0x4)             movl    d0,a6@(-4)
                                 
b()     movl    #0x1,a6@(-0x4)           moveq   #1,d1
        addql   #0x1,a6@(-0x4)           movl    d1,a6@(-4)
                                         addql   #1,a6@(-4)

	Clearly, either I was out of line making my original assertion or the
stock SunOS-3.5.2 C compiler really is the pits!  Maybe a little of both?
Anyway, I'll still stand by my original assertion, that the -- and ++
operators are just syntactic sugar and the lack of them does not, by itself,
make Pascal a worse language.  It's not fair to heap the sins of poor
compiler implementations on the language itself (unless there is something
inherent in the language that makes it hard to write good compilers).

	As an afterthought, I would hope that the C compiler Sun is now
unbundling and charging real money for would generate better code than the
stock one they used to ship.
--
Roy Smith, Public Health Research Institute
455 First Avenue, New York, NY 10016
roy@alanine.phri.nyu.edu -OR- {att,cmcl2,rutgers,hombre}!phri!roy
"Arcane?  Did you say arcane?  It wouldn't be Unix if it wasn't arcane!"

minich@d.cs.okstate.edu (Robert Minich) (12/18/90)

by stevewi@hpspdra.HP.COM (Steve Witten):
| You can use the 'succ' and 'pred' operators/functions in Pascal to
| accomplish the same function as '++' and '--'.  So:
| 
| 	integer i,j,k;
| 
| 	   ...
| 
| 	j := succ(i);  { same as 'j=i++' }
| 	k := pred(i);  { same as 'k=i--' }
| 
| 	   ...
| 
| However, you have to remember that '++/--' are positional as well.
| You cannot recreate this behavior.  You also cannot recreate the
| behavior of 'x++' without an assignment in Pascal.

  Do you not use C very often or are you VERY tired? The above Pascal
statements are equivalent to

	j := i + 1;
	k := i - 1;

whereas the C translates to Pascal as

j = i++;         | j := j + i;
                 | i := i + 1;
k = i--;         | k := i - 1;
                 | i := i - 1;

The pred() and succ() functions are really used to get increment ordinal
types whereas C doesn't care too much about types and will increment,
say, a char by 1 without blinking.

  Someone has already posted MPW C's output so I thought I'd see what
THINK C 4.0.2 does with the following:

	alpha() { int x;   x = 1; x = x + 1; }
	beta () { int x;   x = 1; x++; }
	main () { alpha(); beta(); }

  ALPHA
     +0000  LINK       A6,#$FFFE
     +0004  MOVEQ      #$01,D0           | tmp = 1;
     +0006  MOVE.W     D0,-$0002(A6)     | x   = tmp;     <== ick
     +000A  MOVE.W     -$0002(A6),D0     | tmp = x;       <==
     +000E  ADDQ.W     #$1,D0            | tmp = tmp + 1;
     +0010  MOVE.W     D0,-$0002(A6)     | x   = tmp;
     +0014  UNLK       A6
     +0016  RTS
  BETA
     +0000  LINK       A6,#$FFFE
     +0004  MOVEQ      #$01,D0           | tmp = 1;
     +0006  MOVE.W     D0,-$0002(A6)     | x   = tmp;
     +000A  ADDQ.W     #$1,-$0002(A6)    | x   = x + 1;
     +000E  UNLK       A6
     +0010  RTS

  I also tried {x += 1;} and it produced identical asm to BETA, which is
OK. What I don't understand is what the heck is going on around what I
marked "ick." Surely such a minute optimisation as not reading back what
you just wrote is not too difficult to code. (Of course, I don't write
compilers, either. :-) However, I think the ideal would be to replace
ALPHA's

     +0004  MOVEQ      #$01,D0           | tmp = 1;
     +0006  MOVE.W     D0,-$0002(A6)     | x   = tmp;     <== ick
     +000A  MOVE.W     -$0002(A6),D0     | tmp = x;       <==
     +000E  ADDQ.W     #$1,D0            | tmp = tmp + 1;
     +0010  MOVE.W     D0,-$0002(A6)     | x   = tmp;

with

            MOVEQ.W    #$1,-$0002(A6)    | x = 1;
            ADDQ.W     #$1,-$0002(A6)    | x = x + 1;

and be done with it. BETA is almost that ideal but Th C insists on using
a register temp for x=1. I guess I can live with it if only because I
don't like modifying asm by hand on a regular basis. :-) Now a really
fancy optimizer would figure out that x always ends up as 2 or even that
x is never used outside this scope and so forget about the calling ALPHA
altogether. 

  For the heck of it, I looked at what THINK Pascal 2.02 generated for
the program below. It looks like the old Th Pascal betters the current
Th C...

program Test;
 procedure alpha;
  var i: integer;
 begin
  i := 1;
  i := i + 1;
 end;
begin
 alpha;
end.

  ALPHA
     +0000  2840EA     LINK       A6,#$FFEE
     +0004  2840EE     MOVE.L     D7,-(A7)  push(D7)
     +0006  2840F0     MOVEQ      #$01,D7   i := 1;
     +0008  2840F2     ADDQ.W     #$1,D7    i := i + 1;
     +000A  2840F4     MOVE.L     (A7)+,D7  pop(D7)
     +000C  2840F6     UNLK       A6
     +000E  2840F8     RTS

  Here, I don't understand what the deal is with saving D7 before use
but I also don't remember Pascal calling conventions, so this may be
proper. If anyone would like to add Th Pascal 3.0 output, that would be
great, too. (I decided Pascal was getting on my nerves and the 3.0
upgrade was way too expensive for "just to have it around.")
-- 
|_    /| | Robert Minich            |
|\'o.O'  | Oklahoma State University| "I'm a newcomer here, but does the
|=(___)= | minich@d.cs.okstate.edu  |  net ever lay any argument to rest?"
|   U    | - Ackphtth               |                    -- dan herrick

sandy@snoopy.cs.umass.edu (& Wise) (12/18/90)

> Either there is no way to do a quick increment in Pascal ...

Pascal does not have an increment operator.  Wirth acknowledged this
problem with the design of Modula-2 when he added the forms:
  INC ( variable );
  DEC ( variable );
However, I think Pascal will let you can use the successor function.
This doesn't eliminate the assignment, but does explicitly request the
increment:
  variable := SUCC ( variable );

> ... or I'm missing something in my knowledge, or I'm wrong about the
>speed difference between things like
> ++(variable) and
> (variable):=(variable)+1

The speed difference between the two depends on the quality of the
optimizations, and context (e.g., in a FOR loop, Pascal's implicit
increment can usually be done as part of the test and branch 
instruction, while in C the increment is an explicit statement, and
the optimizer must catch it).
--
Alexander Erskine Wise /\/\/\/\/\/\/\/\/\/\/\/\ Software Development Laboratory
/\/\/\/\/\/\/\/\/\/\/\/\/\/\ WISE@CS.UMASS.EDU /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
\/\/\ This situation calls for large amounts of unadulterated CHOCOLATE! /\/\/\

hodas@saul.cis.upenn.edu (Josh Hodas) (12/18/90)

In article <1990Dec18.042748.6765@d.cs.okstate.edu> minich@d.cs.okstate.edu (Robert Minich) writes:
>by stevewi@hpspdra.HP.COM (Steve Witten):
>| You can use the 'succ' and 'pred' operators/functions in Pascal to
>| accomplish the same function as '++' and '--'.  So:
>| 
>| 	integer i,j,k;
>| 
>| 	   ...
>| 
>| 	j := succ(i);  { same as 'j=i++' }
>| 	k := pred(i);  { same as 'k=i--' }
>| 
>| 	   ...
>| 
>| However, you have to remember that '++/--' are positional as well.
>| You cannot recreate this behavior.  You also cannot recreate the
>| behavior of 'x++' without an assignment in Pascal.
>
>  Do you not use C very often or are you VERY tired? The above Pascal
>statements are equivalent to
>
>	j := i + 1;
>	k := i - 1;
>
>whereas the C translates to Pascal as
>
>j = i++;         | j := j + i;
>                 | i := i + 1;
>k = i--;         | k := i - 1;
>                 | i := i - 1;
>


Robert,



  Do you not use C very often or are you VERY tired? 


Sorry, I couldn't resist.



j = i++		=>	j := i;
			i := i + 1;


K = i--		=>	K := i;
			i := i - 1;


and, for completeness:


j = ++i		=>	i := i + 1;
			j := i;
			

K = i--		=>	i := i - 1;
			k := i;


Josh
----------------------------------------------------------------------------
Josh Hodas    		Home Phone:	     (215) 222-7112   
4223 Pine Street	School Office Phone: (215) 898-9514
Philadelphia, PA 19104	New E-Mail Address:  hodas@saul.cis.upenn.edu

n67786@lehtori.tut.fi (Nieminen Tero) (12/19/90)

     I also tried {x += 1;} and it produced identical asm to BETA, which is
   OK. What I don't understand is what the heck is going on around what I
   marked "ick." Surely such a minute optimisation as not reading back what
   you just wrote is not too difficult to code. (Of course, I don't write
   compilers, either. :-) However, I think the ideal would be to replace
   ALPHA's

	+0004  MOVEQ      #$01,D0           | tmp = 1;
	+0006  MOVE.W     D0,-$0002(A6)     | x   = tmp;     <== ick
	+000A  MOVE.W     -$0002(A6),D0     | tmp = x;       <==
	+000E  ADDQ.W     #$1,D0            | tmp = tmp + 1;
	+0010  MOVE.W     D0,-$0002(A6)     | x   = tmp;

   with

	       MOVEQ.W    #$1,-$0002(A6)    | x = 1;
	       ADDQ.W     #$1,-$0002(A6)    | x = x + 1;

   and be done with it.

OK. Would someone out there with a Motorola 68000/020/030 (or most
notably 040 manual) check which one uses the leas clock sycles. Don't be
that easily fooled by the number of lines of code produced if speed is
what you are after. Operations on registers (ie. the move-to-reg
add-to-reg) tend to be a lot faster in Motorola processors (especially
040) than operations on memory locations.
  Just my 0.02 worth.
--
   Tero Nieminen                    Tampere University of Technology
   n67786@cc.tut.fi                 Tampere, Finland, Europe

minich@d.cs.okstate.edu (Robert Minich) (12/19/90)

by hodas@saul.cis.upenn.edu (Josh Hodas):
>minich@d.cs.okstate.edu (Robert Minich) writes:

>#by stevewi@hpspdra.HP.COM (Steve Witten):
># 
># [...]
>#
>#
>#  Do you not use C very often or are you VERY tired? The above Pascal
>#statements are equivalent to
> 
>   Do you not use C very often or are you VERY tired? 

I guess I shouldn't post at 2am without a Jolt break. :-)
 
> Sorry, I couldn't resist.

Understandably... seeing as I couldn't resist the first mistake,
myself!

Exec summary: Thanks Josh. I goofed but so did Steve. Got it?
-- 
|_    /| | Robert Minich            |
|\'o.O'  | Oklahoma State University| "I'm a newcomer here, but does the
|=(___)= | minich@d.cs.okstate.edu  |  net ever lay any argument to rest?"
|   U    | - Ackphtth               |                    -- dan herrick

n67786@lehtori.tut.fi (Nieminen Tero) (12/19/90)

In article <16650@imag.imag.fr> gourdol@imag.imag.fr (Gourdol Arnaud) writes:

   Writing optimisation for Pascal IS more difficult than for C, in the
   sens that in C, when we use the ++ operator you say to the compiler
   "Hey, stupid, don't forget to use the INC operator that exist
    in assembly language!"
   When you do i := i + 1; in Pascal, the compiler must detect that
   it can (and should) use the inc operator. Much more difficult
   when the expression is a bit complicated (like a[i]).

If the C compilers optimization is any good it WILL notice such cases
too. But this kind of optimization is not in any way illegal in Pascal
and it's the compilers defect not to catch it (be that C or Pascal
compiler, or any other for that matter).

I would rather say that since C language is so much closer to machine
level, you might be tempted to consider programmers decisions better
optimization than what the compiler could produce. It hasbeen proven
many times that in non trivial cases Fortran compilers produce better
code for accessing elements of array than equivalent C compiler even
though the Fortran code uses indexes in stead of pointers (at least in
source code level). What exactly the compiler output is is entirely up
to the compiler (like it should be in my opinion). In the era of
pipelined processor architecture it is especially wise to leave the
optimization for the compiler. And the less the language has to do with
the hardware the easier it should be to make the compiler optimizing
optimal (since it doesn't need to watch out for any bad decisions made
by the programmer).

   There is still no good compiler on the Mac (except GCC maybe ?)
   either in C or Pascal.

True enough. Or for any other language for that matter.

   (Of course, LSP and LSC are REAL love for programming and debugging
   as compared to cc, dbx and adb on Sun !!!)

   Arnaud.  
--
   Tero Nieminen                    Tampere University of Technology
   n67786@cc.tut.fi                 Tampere, Finland, Europe

gourdol@imag.imag.fr (Gourdol Arnaud) (12/19/90)

LSP and LSC are both not very good compilers, I mean for the code
the build being not "good" code. BTW MPW C3.0 is not a good compiler
either.
I had the chance to write a compiler and so have been involved
in comparing different compilers performance, bot on the Mac and 
on Sun. Sun C compiler IS very good. There are many levels of
optimisation (4 in fact) which can be actived with -O1 to -O4.
With -O4 if you write a program like :
main()
{ int i,j;
  i = 0;
  j = 1;
  i = j++ + 1;
};

the compiler will produce... nothing. (Hey ! this code does
nothing, does it ?)

Writing optimisation for Pascal IS more difficult than for C, in the
sens that in C, when we use the ++ operator you say to the compiler
"Hey, stupid, don't forget to use the INC operator that exist
 in assembly language!"
When you do i := i + 1; in Pascal, the compiler must detect that
it can (and should) use the inc operator. Much more difficult
when the expression is a bit complicated (like a[i]).

There is still no good compiler on the Mac (except GCC maybe ?)
either in C or Pascal.

(Of course, LSP and LSC are REAL love for programming and debugging
as compared to cc, dbx and adb on Sun !!!)

Arnaud.  

philip@pescadero.Stanford.EDU (Philip Machanick) (12/19/90)

In article <SANDY.90Dec18095930@snoopy.cs.umass.edu>, sandy@snoopy.cs.umass.edu (& Wise) writes:
|> The speed difference between the two depends on the quality of the
|> optimizations, and context (e.g., in a FOR loop, Pascal's implicit
|> increment can usually be done as part of the test and branch 
|> instruction, while in C the increment is an explicit statement, and
|> the optimizer must catch it).

Since we are in reading compiler output mode, would someone care to compare
the code produced by the following Pascal:

program test;
  var i:integer;
begin
  for i:=1 to 10 do {something}
end.

and C:

main()
{ int i;
  for (i=1; i<= 10; i++) /* do something */
  ;
}

As with the ++ examples, there is no reason a _good_ compiler should do
better or worse with either, but the C case is slightly more difficult,
as noted above.
-- 
Philip Machanick
philip@pescadero.stanford.edu

peirce@outpost.UUCP (Michael Peirce) (12/19/90)

In article <1990Dec18.215406.29735@Neon.Stanford.EDU>, philip@pescadero.Stanford.EDU (Philip Machanick) writes:
> 
> In article <SANDY.90Dec18095930@snoopy.cs.umass.edu>, sandy@snoopy.cs.umass.edu (& Wise) writes:
> |> The speed difference between the two depends on the quality of the
> |> optimizations, and context (e.g., in a FOR loop, Pascal's implicit
> |> increment can usually be done as part of the test and branch 
> |> instruction, while in C the increment is an explicit statement, and
> |> the optimizer must catch it).
> 
> Since we are in reading compiler output mode, would someone care to compare
> the code produced by the following Pascal:
> 
> program test;
>   var i:integer;
> begin
>   for i:=1 to 10 do {something}
> end.
> 
> and C:
> 
> main()
> { int i;
>   for (i=1; i<= 10; i++) /* do something */
>   ;
> }

OK, but I made one change: since MPW C uses 32-bit ints and MPW Pascal
integers are 16-bit, I changed the pascal example to use LongInts
as they are 32-bits.  

Here are the two sources:

The Pascal Source -

UNIT Test;

INTERFACE

PROCEDURE testit(x:LONGINT);

IMPLEMENTATION

PROCEDURE SomeThing(a,b: LONGINT); EXTERNAL;

PROCEDURE Testit(x:LONGINT);
VAR
	i : LONGINT;
BEGIN
	FOR i := 1 to 10 DO BEGIN
		SomeThing(i,x);
	END;
END;

END.

And the MPW C source -

void SomeThing(int a, int b); external;

void test(int x)
{
	int i;

	for (i=1;i<= 10;i++) {
		SomeThing(i,x);
	}
};

And now the results from the MPW DUMPOBJ tool:

For Pascal -

-- Enter the routine
00000000: 4E56 FFFC      'NV..'            LINK       A6,#$FFFC
00000004: 2F07           '/.'              MOVE.L     D7,-(A7)

-- set for the FOR loop
00000006: 7E01           '~.'              MOVEQ      #$01,D7
00000008: 600C           '`.'              BRA.S      *+$000E             ; 00000016

-- do the subroutine call
0000000A: 2F07           '/.'              MOVE.L     D7,-(A7)
0000000C: 2F2E 0008      '/...'            MOVE.L     $0008(A6),-(A7)
00000010: 4EBA 0000      'N...'            JSR        SOMETHING           ; id: 3

-- process the FOR loop
00000014: 5287           'R.'              ADDQ.L     #$1,D7
00000016: 700A           'p.'              MOVEQ      #$0A,D0
00000018: B087           '..'              CMP.L      D7,D0
0000001A: 6CEE           'l.'              BGE.S      *-$0010             ; 0000000A

-- exit the routine
0000001C: 2E1F           '..'              MOVE.L     (A7)+,D7
0000001E: 4E5E           'N^'              UNLK       A6
00000020: 2E9F           '..'              MOVE.L     (A7)+,(A7)
00000022: 4E75           'Nu'              RTS        

And the C -

-- Enter the routine
00000000: 4E56 0000      'NV..'            LINK       A6,#$0000
00000004: 48E7 1300      'H...'            MOVEM.L    D3/D6/D7,-(A7)

-- set for the FOR loop
00000008: 2C2E 0008      ',...'            MOVE.L     $0008(A6),D6
0000000C: 7E01           '~.'              MOVEQ      #$01,D7

-- do the subroutine call
0000000E: 2F06           '/.'              MOVE.L     D6,-(A7)
00000010: 2F07           '/.'              MOVE.L     D7,-(A7)
00000012: 4EBA 0000      'N...'            JSR        SomeThing           ; id: 3
00000016: 508F           'P.'              ADDQ.L     #$8,A7

-- process the FOR loop
00000018: 2007           ' .'              MOVE.L     D7,D0
0000001A: 5287           'R.'              ADDQ.L     #$1,D7
0000001C: 700A           'p.'              MOVEQ      #$0A,D0
0000001E: B087           '..'              CMP.L      D7,D0
00000020: 6CEC           'l.'              BGE.S      *-$0012             ; 0000000E

-- exit the routine
00000022: 4CEE 00C8 FFF4 'L.....'          MOVEM.L    -$000C(A6),D3/D6/D7
00000028: 4E5E           'N^'              UNLK       A6
0000002A: 4E75           'Nu'              RTS        


Pascal generates a few less instruction.  I'm not sure which is faster
- I was too lazy to count cycles.  But again this shows that they're
both pretty close.  

Declaring the C routines to be Pascal, i.e. Pascal style calling conventions
didn't change the byte count.

-- michael


--  Michael Peirce         --   {apple,decwrl}!claris!outpost!peirce
--  Peirce Software        --   Suite 301, 719 Hibiscus Place
--  Macintosh Programming  --   San Jose, California 95117
--           & Consulting  --   (408) 244-6554, AppleLink: PEIRCE

Lawson.English@p88.f15.n300.z1.fidonet.org (Lawson English) (12/19/90)

Anthony Berno writes in a message to All

AB> Either there is no way to do a quick increment in Pascal, or 
AB> I'm missing something in my knowledge, or I'm wrong about the 
AB> speed difference between things like ++(variable) and 
(variable):=(variable)+1-
AB> 

If your compiler is bad at optimization (and all Apple compilers are 
notoriously
bad), then it won't recognize the special case of inc x for x := x+1;  Of 
course,
as most Apple products are slowed down by the trap dispatcher, thrid-party 
optimization
is pretty much a waste unless a substantial amount of time is spent in 
arithmatic
or searching/sorting.

Consider: the average graphics program on a Plus spends 20% of its time in the
 
trap dispatcher. The average '020 machine spends 60% of its time there. I 
don't
know how much time is spent there in the 030 machines but I would not be 
surprised
if as much as 75-80% of the time is spent there. This assumes that SANE is 
being
used instead of the '881/882. Regions are another area where graphics slows
to a crawl: if you are sure that your program will never write outside of the
screen (you're doing a copybits for instance), set your clip region to a 
rectangle,
rather than let the cute rounded corners of the screen be used. This can speed
 
up full-screen drawing by quite a bit.

My first programming job on the Mac was providing the software 
background/support
for software optimization of the accellerator/graphics board. Some 0f the 
stuff
in the 128k ROMS was pretty scary we found.

Lawson
 

 

--  
Uucp: ...{gatech,ames,rutgers}!ncar!asuvax!stjhmc!300!15.88!Lawson.English
Internet: Lawson.English@p88.f15.n300.z1.fidonet.org

alexr@apple.com (Alex Rosenberg) (12/20/90)

In article <0B010004.o0u3z7@outpost.UUCP> peirce@outpost.UUCP (Michael 
Peirce) writes:
> Here are the two sources:
> 
> The Pascal Source -
> 
> UNIT Test;
> 
> INTERFACE
> 
> PROCEDURE testit(x:LONGINT);
> 
> IMPLEMENTATION
> 
> PROCEDURE SomeThing(a,b: LONGINT); EXTERNAL;
> 
> PROCEDURE Testit(x:LONGINT);
> VAR
>         i : LONGINT;
> BEGIN
>         FOR i := 1 to 10 DO BEGIN
>                 SomeThing(i,x);
>         END;
> END;
> 
> END.
> 
> And the MPW C source -
> 
> void SomeThing(int a, int b); external;
> 
> void test(int x)
> {
>         int i;
> 
>         for (i=1;i<= 10;i++) {
>                 SomeThing(i,x);
>         }
> };

The MPW C case can be optimized like:

 void test(int x)
 {
         int i;
 
         for (i=10; i; --i) {
                 SomeThing(i,x);
        }
 };

MPW C should end up using a DBRA loop for this, which uses less 
instructions. Note the predecriment, as in MPW C, prefix operations on 
register-based variables (as "i" should is) are tighter than postfix.

(Note that while I think that the Pascal compiler can generate DBRA loops,
I'm not sure it will in this case.)

By far, the handiest tool for this sort of investigation is UltraSlimFast. 
This MPW tool can be found on the System 7.0 Beta CD. It prints object 
code next to the source code, matching lines up as much as possible.

---------------------------------------------------------------------------
-  Alexander M. Rosenberg  - INTERNET: alexr@apple.com      - Yoyodyne    -
-  330 1/2 Waverley St.    - UUCP:ucbvax!apple!alexr        - Propulsion  -
-  Palo Alto, CA 94301     -                                - Systems     -
-  (415) 329-8463          - Nobody is my employer so       - :-)         -
-  (408) 974-3110          - nobody cares what I say.       -             -

jmunkki@hila.hut.fi (Juri Munkki) (12/20/90)

n67786@lehtori.tut.fi (Nieminen Tero) writes:
>   OK. What I don't understand is what the heck is going on around what I
>   marked "ick." Surely such a minute optimisation as not reading back what
>   you just wrote is not too difficult to code. (Of course, I don't write
>   compilers, either. :-) However, I think the ideal would be to replace
>   ALPHA's
>
>	+0004  MOVEQ      #$01,D0           | tmp = 1;
>	+0006  MOVE.W     D0,-$0002(A6)     | x   = tmp;     <== ick
>	+000A  MOVE.W     -$0002(A6),D0     | tmp = x;       <==
>	+000E  ADDQ.W     #$1,D0            | tmp = tmp + 1;
>	+0010  MOVE.W     D0,-$0002(A6)     | x   = tmp;

One thing to remember about the Think C compiler is that it doesn't
automatically allocate register variables. The Think Pascal examples
that we have seen here allocated a register variable and used that.
That's why they saved the register in the stack first and then
initialized it.

If you really want to write something as stupid as the subroutine
that has been discussed here, write it like this in Think C:
void	dotest()
{
	register int	i=1;
	
	i++;
}

This produces:
	move.l	D7,-(sp)
	moveq.l	#1,D7
	addq.w	#1,D7
	move.l	(sp)+,D7
	rts

Looks good to me. Of course Think C is not an optimizing compiler in the
strict sense of the word. IMHO, C is just a fancy assembler that produces
portable code...

Also, Think C 4.02 produces the following code, if I omit the register
allocation:

	link	A6,-2
	moveq.l	#1,D0
	move.w	D0,-2(A6)
	addq.l	#1,-2(A6)
	unlk	A6
	rts

Changing the initializer to something like 1024 will change the code
so that we have:

	link	A6,-2
	move.w	#1024,-2(A6)
	addq.l	#1,-2(A6)
	unlk	A6
	rts

To be honest, I don't find this thread useful. The best way to learn
about these things is to read a basic text on compilers or take a course
on compiler design. The reason why C doesn't produce all that good code
with i=i+1 is because it has i++ available, so programmers use that and
there is no need to waste time trying to optimize i=i+1, since it doesn't
usually occur in normal code. Pascal compilers run into i:=i+1 all the time,
so they have to watch for it.

   ____________________________________________________________________________
  / Juri Munkki	    /  Helsinki University of Technology   /  Wind  / Project /
 / jmunkki@hut.fi  /  Computing Center Macintosh Support  /  Surf  /  STORM  /
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

hawley@adobe.COM (Steve Hawley) (12/20/90)

Although this has less to do with Mac programming than programming in general,
I remember reading an article about optimization when I was in a compiler
class.  The gist of the article was that benchmarks the author had done
revealed that the code generated by available Pascal compilers was really
slow in comparison to that of FORTRAN compilers.  The reasoning was that
programmers had been using FORTRAN (at that time) for computationally intensive
tasks, and out of need, the compilers were tweaked to optimize the living
daylights out of the code, whereas nobody bothered using Pascal for "real"
tasks, so nobody bothered optimizing the compiler.  Vicious circle.  It's not
completely the case that the language is defficient, but the optimizers were
lousy (or non-existent).

Of course there are some things the language won't let you do, and the structure
of Pascal doesn't help the compiler writer optimize.

Autoincrement and autodecrement were not added to C merely as syntactic sugar.
They were added in as a concession to the fact that addition and subtraction
of small constants are commonplace in programming, and as such we can
accomplish several things:
	1) Reduce the amount of typing the programmer needs to do.
	2) Factor out the special case from the optimizer into the parser.
	3) Provide a closer tie to the target machine.
	4) Complicate the parser.

For example, if I write a routine to copy a string, in C I would do this

strcpy(dst, src)
char *dst, *src;
{
	while ((*dst++ = *src++) != '\0');
}

in Pascal (assuming the same null terminated strings):

procedure strcpy(dst, src: ^char);
{ 'scuse my Pascal, I haven't had to code in it actively for several years }
begin
	while (src^ <> CHR(0)) do begin
		dst^ := src^;
		dst := SUCC(dst)
		src := SUCC(src);
	end;
	dst^ := src^ { copy the NULL }
end;

So what's my point?  I don't know, I've kind of lost it.  Oh right, I was
defending Pascal.  Both functions are abstractions of what you want to do:
copy data from point a to point b using a sentinel.

On a processor with relatively few capabilities, the C version might generate
something like this:

L0:	move src, a0
	move (a0), d0	get char
	add  #$1, a0	assuming we can do arithmetic on address registers
	move a0, src
	move dst, a0
	move d0, (a0)	copy char
	add  #$1, a0
	move a0, dst
	cmp  #$0, d0	sentinel test
	bne  L0

The Pascal code may generate this:

	move src, a0
L0:	move (a0), d0
	cmp  #$0, d0
	beq  L1
	move dst, a0
	move d0, (a0)
	add  #$1, (a0)
	move a0, dst
	move src, a0
	add  #$1, a0
	move a0, src
	jump L0
L1	move dst, a0
	move d0, a0

and lo and behold, the C is a 10 instruction loop, the Pascal an 11 instruction
loop.  Of course, this isn't a real instruction set and I've purposely limited
its capabilities, but how far is it from a RISC processor?  Not far.  Not far
at all.  The RISC processor would do most of the work in registers and
eliminate a lot of the memory juggling.

Of course, withthe Pascal, you must pray that your optimizer has the sense to
do good work for you.

With a 68000 target processor, there's no reason to get the following assembly
language from the C code:

	move.l src, a0
	move.l dst, a1
L0:	move.b (a0)+,(a1)+
	bne L0

Which you won't get from Think C, by the way, unless you declare your variables
to be registers...

Whatever.
Steve Hawley
hawley@adobe.com
-- 
"I'm sick and tired of being told that ordinary decent people are fed up with
being sick and tired.  I know I'm certainly not, and I'm sick and tired of
begin told that I am." -Monty Python

minich@d.cs.okstate.edu (Robert Minich) (12/20/90)

by alexr@apple.com (Alex Rosenberg):
| By far, the handiest tool for this sort of investigation is UltraSlimFast. 
| This MPW tool can be found on the System 7.0 Beta CD. It prints object 
| code next to the source code, matching lines up as much as possible.

  How about a tool to calculate cycle counts for given chunks of code
for various cpus (68000, 010, 020, 030, 040) and differing wait states?
That would make these micro-optimisations much easier. :-)
-- 
|_    /| | Robert Minich            |
|\'o.O'  | Oklahoma State University| "I'm a newcomer here, but does the
|=(___)= | minich@d.cs.okstate.edu  |  net ever lay any argument to rest?"
|   U    | - Ackphtth               |                    -- dan herrick

jfr@locus.com (Jon Rosen) (12/21/90)

In article <q72au3w163w@questor.wimsey.bc.ca> aberno@questor.wimsey.bc.ca (Anthony Berno) writes:
>I generally prefer Pascal programming, but I have come up against what
>seems like a real deficiency in the language. I never really thought
>about it before, but there does not seem to be any equivalent to
>the ++ or -- operator in Pascal. I was doing some speed checks on
>array accessing today, and it occured to me that in doing something
>like incrementing an entry by one, the computer was doing rather a
>lot of work!
>
>Either there is no way to do a quick increment in Pascal, or I'm missing
>something in my knowledge, or I'm wrong about the speed difference between
>things like
>++(variable) and
>(variable):=(variable)+1
>

Your observation is a good one... However, it is not a quality of
the language itself that causes the suboptimal performance, but
rather the quality of the optimizer...
 
A good Pascal compiler will recognize the construct X := X+1;
and perform the appropriate machine code in the best way
possible to increment the variable X by 1... Depending on
the machine that is being used, this may be a direct register
or memory increment instruction or it may end up the same
as the assignment statement X := X+2; with a different value
being added... In C, X = X+1; and X++; may also be implemented
differently depending on the machine or identically... The
IBM 370 mainframe, for instance, has no increment/decrement
instructions (well, BCTR might be used here, for decrementing)
so the C version of these statements is indentical...
 
An example of where a Pascal compiler can be more optimal
than a suboptimal C compiler is the WITH statement.  Within
the domain of a WITH record statement, most good Pascal
compilers will attempt to hold a pointer to the record in
aworking register... In C compilers, since all structure
usages require explicit pointing (struct.field), the
compiler that does not do good optimization of the use 
of a set of structure references might throw constantly
reload the register with the pointer to struct...
 
So language makes it easier for compilers to do certain
things, but the compiler itself still has to take advantage
and the underlying machine architecture has to be able
to provide the tools for taking advantage... Otherwise,
it really doesn't matter...
 
Jon R.

Lawson.English@p88.f15.n300.z1.fidonet.org (Lawson English) (12/22/90)

Nieminen Tero writes in a message to All

NT> There is still no good compiler on the Mac (except GCC maybe 
NT> ?)  either in C or Pascal. 
NT> True enough. Or for any other language for that matter. 
NT>  (Of course, LSP and LSC are REAL love for programming and debugging 
NT>  as compared to cc, dbx and adb on Sun !!!) 

Obviously you never tested HyperC on the Mac. That little gem (non-supported
for the last few years) would compile smaller code than any other Mac compiler
 
(usually 40-60% smaller). Its problems were myriad; however, if anyone wants
to get the source code, it's still available.

Lawson
 

 

--  
Uucp: ...{gatech,ames,rutgers}!ncar!asuvax!stjhmc!300!15.88!Lawson.English
Internet: Lawson.English@p88.f15.n300.z1.fidonet.org

Lawson.English@p88.f15.n300.z1.fidonet.org (Lawson English) (12/22/90)

Edward V. Wright writes in a message to All

EVW> 
>x++:         LOAD  X
>             INC   X
>             STORE X
EVW>  Unless you have an instruction to increment variables in memory! 

As I recall, MC68xxx DOES have an increment of an indexed memory location. The
 
'020 has a direct memory inc (I think).

Lawson
 

 

--  
Uucp: ...{gatech,ames,rutgers}!ncar!asuvax!stjhmc!300!15.88!Lawson.English
Internet: Lawson.English@p88.f15.n300.z1.fidonet.org

Chris.Gehlker@p12.f56.n114.z1.fidonet.org (Chris Gehlker) (12/24/90)

SEC> Decent is the key word here. If your compiler does not optimize, 
SEC> you're likely to get different code for these, and with the number 
SEC> of shoddy software products on the market these days, you might 
SEC> want to investigate.

I've disassembled enough C and Pascal, both THINK and MPW, to know that they
all generate and Addq.x   #1,dx for this instruction no matter how you write
it.

j := j + 1;
j := Succ(j);

j = j + 1;
j++;
++j;
j += 1;
all generate exactly the same code. 
 

--  
Uucp: ...{gatech,ames,rutgers}!ncar!asuvax!stjhmc!56.12!Chris.Gehlker
Internet: Chris.Gehlker@p12.f56.n114.z1.fidonet.org

Chris.Gehlker@p12.f56.n114.z1.fidonet.org (Chris Gehlker) (12/24/90)

AB> I generally prefer Pascal programming, but I have come up against 
AB> what seems like a real deficiency in the language. I never really 
AB> thought about it before, but there does not seem to be any equivalent 
AB> to the ++ or -- operator in Pascal. I was doing some speed checks 
AB> on array accessing today, and it occured to me that in doing 
AB> something like incrementing an entry by one, the computer was 
AB> doing rather a lot of work! 
AB> Either there is no way to do a quick increment in Pascal, or 
AB> I'm missing something in my knowledge, or I'm wrong about the 
AB> speed difference between things like ++(variable) and 
(variable):=(variable)+1

You are right about the loss of efficiency in accessing arrays but wrong about
 
the source of the inefficiency. Variable := Variable +1 or Variable := 
Succ(variable)
will generate exactly the same code as variable++, namely a addq.x  #1,Dx. 
Where Pascal falls down is in address arthmetic:
for i := 1 to rows do
     for j := 1 to columns do
          thearray[i,j] := something;
will generate a run time multiply to each time through the inner loop to 
figure
out the offset from the start of the array.  On the Mac you can work around
this by writing something like:
Type elementPtr = ^integer;

var
     theElement, arrayStart:longint;

...
arrayStart := longint(@thearray[1,1]);
theElement := 0
while theElement <= longint(@theArray[rows,columns]) do
begin
     elementPtr(arrayStart + theElement)^ := something;
     theElement := theElement + sizeof(integer)
end;
This gives a big speedup at the cost of clarity and portability. 
 

--  
Uucp: ...{gatech,ames,rutgers}!ncar!asuvax!stjhmc!56.12!Chris.Gehlker
Internet: Chris.Gehlker@p12.f56.n114.z1.fidonet.org

Chris.Gehlker@p12.f56.n114.z1.fidonet.org (Chris Gehlker) (12/24/90)

RM>  Here, I don't understand what the deal is with saving D7 before 
RM> use but I also don't remember Pascal calling conventions, so 
RM> this may be proper. If anyone would like to add Th Pascal 3.0 
RM> output, that would be great, too. (I decided Pascal was getting 
RM> on my nerves and the 3.0 upgrade was way too expensive for "just 
RM> to have it around.")

THINK Pascal 3.0.1 generated code identical to your 2.02 example whether I 
wrote
it as i := i + 1; or i := succ(i);  As for the C, guys from Symantic have said
 
here quite a bit that their philosophy is that if the programmer wants a 
variable
to be register, she should declare it register.  This is diametrically opposit
 
tp the MPW philsophy. 
 

--  
Uucp: ...{gatech,ames,rutgers}!ncar!asuvax!stjhmc!56.12!Chris.Gehlker
Internet: Chris.Gehlker@p12.f56.n114.z1.fidonet.org

sampson@cod.NOSC.MIL (Charles H. Sampson) (01/08/91)

In article <33176.27759EC3@stjhmc.fidonet.org> Chris.Gehlker@p12.f56.n114.z1.fidonet.org (Chris Gehlker) writes:
>Where Pascal falls down is in address arthmetic:
>for i := 1 to rows do
>     for j := 1 to columns do
>          thearray[i,j] := something;
>will generate a run time multiply to each time through the inner loop to 
>figure
>out the offset from the start of the array.  On the Mac you can work around
>this by writing something like: ...

     I've just picked up this thread, so I hope my comment hasn't been made
already.  The above complaint appears to be against the Pascal language for
not doing a good job on array accesses.  The fault is not the language, it's
the compiler.  There is an ancient code optimization technique called
strength-reduction that will remove all the multiplies in favor of setting
up an initial address outside the loop and then calculating the next address
inside the loop by addition, just like the deleted example did.  This tech-
nique is so old and understood so well that many don't even consider it an
optimization any more -- just a standard code-generation technique.  As to
why your favorite compiler isn't doing it, you'll have to ask the vendor.

                              Charlie

Chris.Gehlker@p12.f56.n114.z1.fidonet.org (Chris Gehlker) (01/09/91)

CHS> I've just picked up this thread, so I hope my comment hasn't 
CHS> been made already. The above complaint appears to be against 
CHS> the Pascal language for not doing a good job on array accesses. 
CHS> The fault is not the language, it's the compiler.

I'm just getting back here after being off line for awhile and I've missed the
intervening posts but your point is well taken.  The example I had in mind,
as opposed to the example I posted, was more complicated.  I was thinking of
a simulation where each cell had to learn the status of it's neighbors. The
pointer arithmetic was a little harrier than simpliy initiallizing an array.

I don't think either MPW Pascal or LSP do any stress reduction.  In fact I've
disassembled eneough LSP to be sure that it doesn't.  I'll have to check MPW.
 
--  
Uucp: ...{gatech,ames,rutgers}!ncar!asuvax!stjhmc!56.12!Chris.Gehlker
Internet: Chris.Gehlker@p12.f56.n114.z1.fidonet.org

siegel@endor.uucp (Rich Siegel) (01/11/91)

In article <34587.278C73DB@stjhmc.fidonet.org> Chris.Gehlker@p12.f56.n114.z1.fidonet.org (Chris Gehlker) writes:
>
>I don't think either MPW Pascal or LSP do any stress reduction.  In fact I've
>disassembled eneough LSP to be sure that it doesn't.  I'll have to check MPW.

	Actually, THINK Pascal does do stress reduction, because it compiles
so fast. You get work done, so you stay on schedule, and that reduces the
stress level of yourself, and consequently of those around you. ;-)

R.



 Rich Siegel	Symantec Languages Group  Internet: siegel@endor.harvard.edu

"...she's dressed in yellow, she says 'Hello, come sit next to me, you
fine fellow..."

Bruce.Hoult@bbs.actrix.gen.nz (01/14/91)

Chris Gehlker writes:
>I don't think either MPW Pascal or LSP do any stress reduction.
 
They don't do much strength reduction either :-)
-- 
Bruce.Hoult@bbs.actrix.gen.nz   Twisted pair: +64 4 772 116
BIX: brucehoult                 Last Resort:  PO Box 4145 Wellington, NZ
"...a plan so cunning, you could pin a tail on it and call it a weasel..."