Change bold code snippets to inline code blocks
This commit is contained in:
parent
f658bfbb40
commit
3c76d884ef
185 changed files with 1772 additions and 1772 deletions
50
09-02.md
50
09-02.md
|
|
@ -11,17 +11,17 @@ pages: 172-175
|
|||
---
|
||||
|
||||
However, it generally is. Sure, if the length is odd, John's approach
|
||||
incurs a penalty approximately equal to the **REP** startup time for
|
||||
**MOVSB**. However, if the length is even, John's approach doesn't
|
||||
incurs a penalty approximately equal to the `REP` startup time for
|
||||
`MOVSB`. However, if the length is even, John's approach doesn't
|
||||
branch, saving cycles and not emptying the prefetch queue. If copy
|
||||
lengths are evenly distributed between even and odd, John's approach is
|
||||
faster in most x86 systems. (Not on the 486, though.)
|
||||
|
||||
John also points out that on the 386, multiple **LEA**s can be combined
|
||||
to perform multiplications that can't be handled by a single **LEA**,
|
||||
John also points out that on the 386, multiple `LEA`s can be combined
|
||||
to perform multiplications that can't be handled by a single `LEA`,
|
||||
much as multiple shifts and adds can be used for multiplication, only
|
||||
faster. **LEA** can be used to multiply in a single instruction on the
|
||||
386, but only by the values 2, 3, 4, 5, 8, and 9; several **LEA**s
|
||||
faster. `LEA` can be used to multiply in a single instruction on the
|
||||
386, but only by the values 2, 3, 4, 5, 8, and 9; several `LEA`s
|
||||
strung together can handle a much wider range of values. For example,
|
||||
video programmers are undoubtedly familiar with the following code to
|
||||
multiply AX times 80 (the width in bytes of the bitmap in most PC
|
||||
|
|
@ -38,7 +38,7 @@ SH LAX,1 ;*64
|
|||
ADD AX,BX ;*80
|
||||
```
|
||||
|
||||
Using **LEA** on the 386, the above could be reduced to
|
||||
Using `LEA` on the 386, the above could be reduced to
|
||||
|
||||
```nasm
|
||||
LEA EAX,[EAX*2] ;*2
|
||||
|
|
@ -68,12 +68,12 @@ ADD AX,BX ;*80
|
|||
|
||||
That brings us to multiplication, one of the slowest of x86 operations
|
||||
and one that allows for considerable optimization. One way to speed up
|
||||
multiplication is to use shift and add, **LEA**, or a lookup table to
|
||||
multiplication is to use shift and add, `LEA`, or a lookup table to
|
||||
hard-code a multiplication operation for a fixed multiplier, as shown
|
||||
above. Another is to take advantage of the early-out feature of the 386
|
||||
(and the 486, but in the interests of brevity I'll just say "386" from
|
||||
now on) by arranging your operands so that the multiplier (always the
|
||||
rightmost operand following **MUL** or **IMUL**) is no larger than the
|
||||
rightmost operand following `MUL` or `IMUL`) is no larger than the
|
||||
other operand.
|
||||
|
||||
> 
|
||||
|
|
@ -97,17 +97,17 @@ regularly indicate that multiplication takes 3 to 4 cycles longer than
|
|||
the specs indicate, but the cycle-per-bit advantage of smaller
|
||||
multipliers holds true nonetheless.)
|
||||
|
||||
This highlights another interesting point: **MUL** and **IMUL** on the
|
||||
This highlights another interesting point: `MUL` and `IMUL` on the
|
||||
386 are so fast that alternative multiplication approaches, while
|
||||
generally still faster, are worthwhile only in truly time-critical code.
|
||||
|
||||
> 
|
||||
> On 386SXs and uncached 386s, where code size can significantly affect
|
||||
> performance due to instruction prefetching, the compact **MUL** and
|
||||
> **IMUL** instructions can approach and in some cases even outperform the
|
||||
> performance due to instruction prefetching, the compact `MUL` and
|
||||
> `IMUL` instructions can approach and in some cases even outperform the
|
||||
> "optimized" alternatives.
|
||||
|
||||
All in all, **MUL** and **IMUL** are reasonable performers on the 386,
|
||||
All in all, `MUL` and `IMUL` are reasonable performers on the 386,
|
||||
no longer to be avoided in most cases—and you can help that along by
|
||||
arranging your code to make the smaller operand the multiplier whenever
|
||||
you know which operand is smaller.
|
||||
|
|
@ -121,33 +121,33 @@ scale value is the logical choice for the multiplier.
|
|||
|
||||
#### Optimizing Optimized Searching {#Heading6}
|
||||
|
||||
Rob Williams writes with a wonderful optimization to the **REPNZ
|
||||
SCASB-**based optimized searching routine I discussed in Chapter 5. As a
|
||||
Rob Williams writes with a wonderful optimization to the `REPNZ
|
||||
SCASB`-based optimized searching routine I discussed in Chapter 5. As a
|
||||
quick refresher, I described searching a buffer for a text string as
|
||||
follows: Scan for the first byte of the text string with **REPNZ
|
||||
SCASB**, then use **REPZ CMPS** to check for a full match whenever
|
||||
**REPNZ SCASB** finds a match for the first character, as shown in
|
||||
follows: Scan for the first byte of the text string with `REPNZ
|
||||
SCASB`, then use `REPZ CMPS` to check for a full match whenever
|
||||
`REPNZ SCASB` finds a match for the first character, as shown in
|
||||
Figure 9.1. The principle is that most buffer characters won't match the
|
||||
first character of any given string, so **REPNZ SCASB**, by far the
|
||||
first character of any given string, so `REPNZ SCASB`, by far the
|
||||
fastest way to search on the PC, can be used to eliminate most potential
|
||||
matches; each remaining potential match can then be checked in its
|
||||
entirety with **REPZ CMPS**.
|
||||
entirety with `REPZ CMPS`.
|
||||
|
||||

|
||||
|
||||
Rob's revelation, which he credits without explanation to Edgar Allen
|
||||
Poe (search nevermore?), was that by far the slowest part of the whole
|
||||
deal is handling **REPNZ SCASB** matches, which require checking the
|
||||
remainder of the string with **REPZ CMPS** and restarting **REPNZ
|
||||
SCASB** if no match is found.
|
||||
deal is handling `REPNZ SCASB` matches, which require checking the
|
||||
remainder of the string with `REPZ CMPS` and restarting `REPNZ
|
||||
SCASB` if no match is found.
|
||||
|
||||
> 
|
||||
> Rob points out that the number of **REPNZ SCASB** matches can easily be
|
||||
> Rob points out that the number of `REPNZ SCASB` matches can easily be
|
||||
> reduced simply by scanning for the character in the searched-for string
|
||||
> that appears least often in the buffer being searched.
|
||||
|
||||
Imagine, if you will, that you're searching for the string "EQUAL." By
|
||||
my approach, you'd use **REPNZ SCASB** to scan for each occurrence of
|
||||
my approach, you'd use `REPNZ SCASB` to scan for each occurrence of
|
||||
"E," which crops up quite often in normal text. Rob points out that it
|
||||
would make more sense to scan for "Q," then back up one character and
|
||||
check the whole string when a "Q" is found, as shown in Figure 9.2. "Q"
|
||||
|
|
|
|||
Loading…
Reference in a new issue