Normal quotes

This commit is contained in:
James Gregory 2013-12-30 18:34:31 +11:00
commit 18011c595a
352 changed files with 6040 additions and 6040 deletions

View file

@ -5,7 +5,7 @@
#### Rotating and Shifting with Tables {#Heading8}
As another example of local optimization, consider the matter of
rotating or shifting a mask into position. First, let’s look at the
rotating or shifting a mask into position. First, let's look at the
simple task of setting bit N of AX to 1.
The obvious way to do this is to place N in CL, rotate the bit into
@ -18,7 +18,7 @@ position, and OR it with AX, as follows:
This solution is obvious because it takes good advantage of the special
ability of the x86 family to shift or rotate by the variable number of
bits specified by CL. However, it takes an average of about 45 cycles on
an 8088. It’s actually far faster to precalculate the results, pass the
an 8088. It's actually far faster to precalculate the results, pass the
bit number in BX, and look the shifted bit up, as shown in Listing 7.3.
**LISTING 7.3 L7-3.ASM**
@ -40,7 +40,7 @@ instructions, but by selecting the fastest *sequence* of instructions.
In the particular example above, we once again run into the difficulty
of optimizing across the x86 family. The table lookup is faster on the
8088 and 286, but it’s slightly slower on the 386 and no faster on the
8088 and 286, but it's slightly slower on the 386 and no faster on the
486. However, 386/486-specific code could use enhanced addressing to
accomplish the whole job in just one instruction, along the lines of the
code snippet in Listing 7.4.
@ -63,34 +63,34 @@ code snippet in Listing 7.4.
#### NOT Flips Bits—Not Flags {#Heading9}
The **NOT** instruction flips all the bits in the operand, from 0 to 1
or from 1 to 0. That’s as simple as could be, but **NOT** nonetheless
has a minor but interesting talent: It doesn’t affect the flags. That
or from 1 to 0. That's as simple as could be, but **NOT** nonetheless
has a minor but interesting talent: It doesn't affect the flags. That
can be irritating; I once spent a good hour tracking down a bug caused
by my unconscious assumption that **NOT** does set the flags. After all,
every other arithmetic and logical instruction sets the flags; why not
**NOT**? Probably because **NOT** isn’t considered to be an arithmetic
or logical instruction at all; rather, it’s a data manipulation
**NOT**? Probably because **NOT** isn't considered to be an arithmetic
or logical instruction at all; rather, it's a data manipulation
instruction, like **MOV** and the various rotates. (These are **RCR,
RCL, ROR,** and **ROL,** which affect only the Carry and Overflow
flags.) NOT is often used for tasks, such as flipping masks, where
there’s no reason to test the state of the result, and in that context
there's no reason to test the state of the result, and in that context
it can be handy to keep the flags unmodified for later testing.
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
![](images/i.jpg) *Besides, if you want to **NOT** an operand and set the flags in the process, you can just **XOR** it with -1. Put another way, the only functional difference between **NOT AX** and **XOR AX,0FFFFH** is that **XOR** modifies the flags and **NOT** doesn’t.*
![](images/i.jpg) *Besides, if you want to **NOT** an operand and set the flags in the process, you can just **XOR** it with -1. Put another way, the only functional difference between **NOT AX** and **XOR AX,0FFFFH** is that **XOR** modifies the flags and **NOT** doesn't.*
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
The x86 instruction set offers many ways to accomplish almost any task.
Understanding the subtle distinctions between the instructions—whether
and which flags are set, for example—can be critical when you’re trying
to optimize a code sequence and you’re running out of registers, or when
you’re trying to minimize branching.
and which flags are set, for example—can be critical when you're trying
to optimize a code sequence and you're running out of registers, or when
you're trying to minimize branching.
#### Incrementing with and without Carry {#Heading10}
Another case in which there are two slightly different ways to perform a
task involves adding 1 to an operand. You can do this with **INC,** as
in **INC AX,** or you can do it with **ADD,** as in **ADD AX,1.** What’s
in **INC AX,** or you can do it with **ADD,** as in **ADD AX,1.** What's
the difference? The obvious difference is that **INC** is usually a byte
or two shorter (the exception being **ADD AL,1,** which at two bytes is
the same length as **INC AL**), and is faster on some processors. Less
@ -130,15 +130,15 @@ additions, with code along the lines shown in Listing 7.6.
SAHF ;restore the carry flag
LOOP LOOP_TOP
It’s not that the Listing 7.6 approach is necessarily better or worse;
It's not that the Listing 7.6 approach is necessarily better or worse;
that depends on the processor and the situation. The Listing 7.6
approach is *different,* and if you understand the differences, you’ll
approach is *different,* and if you understand the differences, you'll
be able to choose the best approach for whatever code you happen to
write. (**DEC** has the same property of preserving the Carry flag, by
the way.)
There are a couple of interesting aspects to the last example. First,
note that **LOOP** doesn’t affect any flags at all; this allows the
note that **LOOP** doesn't affect any flags at all; this allows the
Carry flag to remain unchanged from one addition to the next. Not
altering the arithmetic flags is a common characteristic of program
control instructions (as opposed to arithmetic and logical instructions
@ -149,12 +149,12 @@ like **SUB** and **AND,** which do alter the flags).
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Not only do **LOOP** and **JCXZ** not alter the flags, but **REP MOVS**,
which counts down CX to 0, doesn’t affect the flags either.
which counts down CX to 0, doesn't affect the flags either.
The other interesting point about the last example is the use of
**LAHF** and **SAHF,** which transfer the low byte of the FLAGS register
to and from AH, respectively. These instructions were created to help
provide compatibility with the 8080’s (that’s *8080*, not *8088*)
provide compatibility with the 8080's (that's *8080*, not *8088*)
**PUSH** **PSW** and **POP PSW** instructions, but turn out to be
compact (one byte) instructions for saving and restoring the arithmetic
flags. A word of caution, however: **SAHF** restores the Carry, Zero,
@ -163,13 +163,13 @@ which resides in the high byte of the FLAGS register. Also, be aware
that **LAHF** and **SAHF** provide a fast way to preserve the flags on
an 8088 but are relatively slow instructions on the 486 and Pentium.
There are times when it’s a clear liability that **INC** doesn’t set the
There are times when it's a clear liability that **INC** doesn't set the
Carry flag. For instance
INC AX
ADC DX,0
does *not* increment the 32-bit value in DX:AX. To do that, you’d need
does *not* increment the 32-bit value in DX:AX. To do that, you'd need
the following:
ADD AX,1