[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Lousy code generation (Re: MoriaGS 5.3.1 coming...)



In article <1qg65mINNsm6@gap.caltech.edu> nathan@cco.caltech.edu (Nathan Mates) writes:
> In article <jpenne.734744316@ee.ualberta.ca> jpenne@ee.ualberta.ca (Jerry Penner) writes:
> >
> >Subtracting two numbers takes just as long (or short) as comparing
> >them.  I think you'll need to come up with a better example than that.
> >What else about MPW C's generated code is bloated?
>
>     Sorry to disagree with you. As the chart that came with my ORCA/M 1.1
> assembler says, the sbc #xxxx and cmp #xxxx operands both take the same amount
> of time. That I'll give you. But, look at what's necessary before subtraction
> as opposed to comparing the numbers: a sec instruction. 2 measley cycles.
> That's it...

[stuff deleted]

> 
> 720A: lda F0              (4+)
> 720C: sec                 (2)
> 720D: sbc #0003           (3)
> 7210: bvs 7215 {+03}      (2,3)
> 7212: eor #8000           (3)
> 7215: bmi 7230 {+19}      (2,3)
> 7217: lda xxxx
>    some other random code...
> 7230: lda yyyy

There's a very good reason for doing all of the strange code: the
value loaded from location F0 is a _signed_ integer.  The CMP
instruction only deals with unsigned values, so you have to use SBC if
you want to compare a signed integer.

Determining the relationship between signed integers after doing the
SBC involves examining the N, V and possibly Z flags.

The following table gives the relationships.  A is the accumulator, B
is the value in memory that was subtracted.

N V Z   Relationship
0 0 0   A > B
0 0 1   A = B
0 1 0   A < B
0 1 1   not possible
1 0 0   A < B
1 0 1   not possible
1 1 0   A > B
1 1 1   not possible

Most processors have special signed branch instructions which test the
various combinations of N, V and Z.  The 6502 and 65816 don't have any
such instructions, so the program has to simulate their operation.

The tests are as follows:

Branch if greater than:          Z = 0 and N = V
Branch if less than or equal:    Z = 1 or N <> V
Branch if less than:             N <> V
Branch if greater than or equal: N = V


The code you quoted is the fastest way to synthesize a "signed branch
if greater than or equal" operation on the 65816.


What this all boils down to is the original code: since the program
declared the variable as an int (signed), the compiler must use signed
comparison to work out if the variable is greater than or equal to 3.
If the program declared the variable as an unsigned int, then the
compiler could use unsigned comparison (the CMP instruction), which
would be much faster.  For this reason, if you're writing code in C on
a 6502-based computer, it is always best to use unsigned variables
whenever possible.

For your information: ORCA/C, ORCA/Pascal, MPW Pascal, TML Pascal and
all the other IIgs native C and Pascal compilers would have generated
exactly the same code for the comparison.

>    If you can point out something that I've missed in this, go ahead. The
> code works, I'll give it that, but it's rather wasteful of memory and
> processor time. I was half thinking of writing an optimization program to
> go through the code, scanning for things like this, and replacing it with
> the shorter code, but now that moria's coming out, why bother?

If the variable really can become negative, then "optimizing" this
code would introduce a bug into the program.  It would be a better
idea to get the source code and change the variables to unsigned where
appropriate.
-- 
David Empson                                                               
dempson@swell.actrix.gen.nz    <--- Note my new E-Mail address!            
Snail mail: P.O. Box 27-103, Wellington, New Zealand