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
28
07-02.md
28
07-02.md
|
|
@ -10,7 +10,7 @@ chapter: '07'
|
|||
pages: 139-141
|
||||
---
|
||||
|
||||
By the way, don't fall victim to the lures of **JCXZ** and do something
|
||||
By the way, don't fall victim to the lures of `JCXZ` and do something
|
||||
like this:
|
||||
|
||||
```nasm
|
||||
|
|
@ -18,19 +18,19 @@ and cx,ofh ;Isolate the desired field
|
|||
jcxz SkipLoop ;If field is 0, don't bother
|
||||
```
|
||||
|
||||
The **AND** instruction has already set the Zero flag, so this
|
||||
The `AND` instruction has already set the Zero flag, so this
|
||||
|
||||
```nasm
|
||||
and cx,0fh ;Isolate the desired field
|
||||
jz SkipLoop ;If field is 0, don't bother
|
||||
```
|
||||
|
||||
will do just fine and is faster on all processors. Use **JCXZ** only
|
||||
will do just fine and is faster on all processors. Use `JCXZ` only
|
||||
when the Zero flag isn't already set to reflect the status of CX.
|
||||
|
||||
### The Lessons of LOOP and JCXZ {#Heading4}
|
||||
|
||||
What can we learn from **LOOP** and **JCXZ?** First, that a single
|
||||
What can we learn from `LOOP` and `JCXZ`? First, that a single
|
||||
instruction that is intended to do a complex task is not necessarily
|
||||
faster than several instructions that together do the same thing.
|
||||
Second, that the relative merits of instructions and optimization rules
|
||||
|
|
@ -39,11 +39,11 @@ vary to a surprisingly large degree across the x86 family.
|
|||
In particular, if you're going to write 386 protected mode code, which
|
||||
will run only on the 386, 486, and Pentium, you'd be well advised to
|
||||
rethink your use of the more esoteric members of the x86 instruction
|
||||
set. **LOOP, JCXZ,** the various accumulator-specific instructions, and
|
||||
set. `LOOP, JCXZ`, the various accumulator-specific instructions, and
|
||||
even the string instructions in many circumstances no longer offer the
|
||||
advantages they did on the 8088. Sometimes they're just not any faster
|
||||
than more general instructions, so they're not worth going out of your
|
||||
way to use; sometimes, as with **LOOP,** they're actually slower, and
|
||||
way to use; sometimes, as with `LOOP`, they're actually slower, and
|
||||
you'd do well to avoid them altogether in the 386/486 world. Reviewing
|
||||
the instruction cycle times in the MASM or TASM manuals, or looking over
|
||||
the cycle times in Intel's literature, is a good place to start;
|
||||
|
|
@ -53,8 +53,8 @@ relative performance levels of x86 instructions.
|
|||
|
||||
#### Avoiding LOOPS of Any Stripe {#Heading5}
|
||||
|
||||
Cycle counting and directly substituting instructions (**DEC CX/JNZ**
|
||||
for **LOOP,** for example) are techniques that belong at the lowest
|
||||
Cycle counting and directly substituting instructions (`DEC CX/JNZ`
|
||||
for `LOOP`, for example) are techniques that belong at the lowest
|
||||
level of optimization. It's an important level, but it's fairly
|
||||
mechanical; once you've learned the capabilities and relative
|
||||
performance levels of the various instructions, you should be able to
|
||||
|
|
@ -74,16 +74,16 @@ characteristics. Your job is to sequence those blocks so that they
|
|||
perform well. It doesn't matter what the instructions are intended to do
|
||||
or what their names are; all that matters is what they *do.*
|
||||
|
||||
Our discussion of **LOOP** versus **DEC/JNZ** is an excellent example of
|
||||
Our discussion of `LOOP` versus `DEC/JNZ` is an excellent example of
|
||||
optimization by cycle counting. It's worth knowing, but once you've
|
||||
learned it, you just routinely use **DEC/JNZ** at the bottom of loops in
|
||||
learned it, you just routinely use `DEC/JNZ` at the bottom of loops in
|
||||
386/486-specific code, and that's that. Besides, you'll save at most a
|
||||
few cycles each time, and while that helps a little, it's not going to
|
||||
make all *that* much difference.
|
||||
|
||||
Now let's step back for a moment, and with no preconceptions consider
|
||||
what the x86 instruction set can do for us. The bulk of the time with
|
||||
both **LOOP** and **DEC/JNZ** is taken up by branching, which just
|
||||
both `LOOP` and `DEC/JNZ` is taken up by branching, which just
|
||||
happens to be one of the slowest aspects of every processor in the x86
|
||||
family, and the rest is taken up by decrementing the count register and
|
||||
checking whether it's zero. There may be ways to perform those tasks a
|
||||
|
|
@ -101,17 +101,17 @@ Consider Listing 7.1, which searches a buffer until either the specified
|
|||
byte is found, a zero byte is found, or the specified number of
|
||||
characters have been checked. Such a function would be useful for
|
||||
scanning up to a maximum number of characters in a zero-terminated
|
||||
buffer. Listing 7.1, which uses **LOOP** in the main loop, performs a
|
||||
buffer. Listing 7.1, which uses `LOOP` in the main loop, performs a
|
||||
search of the sample string for a period (‘.') in 170 µs on a 20 MHz
|
||||
cached 386.
|
||||
|
||||
When the **LOOP** in Listing 7.1 is replaced with **DEC CX/JNZ,**
|
||||
When the `LOOP` in Listing 7.1 is replaced with `DEC CX/JNZ`,
|
||||
performance improves to 168 µs, less than 2 percent faster than Listing
|
||||
7.1. Actually, instruction fetching, instruction alignment, cache
|
||||
characteristics, or something similar is affecting these results; I'd
|
||||
expect a slightly larger improvement—around 7 percent—but that's the
|
||||
most that counting cycles could buy us in this case. (All right,
|
||||
already; **LOOPNZ** could be used at the bottom of the loop, and other
|
||||
already; `LOOPNZ` could be used at the bottom of the loop, and other
|
||||
optimizations are surely possible, but all that won't add up to anywhere
|
||||
near the benefits we're about to see from local optimization, and that's
|
||||
the whole point.)
|
||||
Loading…
Reference in a new issue