Change bold code snippets to inline code blocks

This commit is contained in:
James Gregory 2013-12-31 17:12:29 +11:00
commit 3c76d884ef
185 changed files with 1772 additions and 1772 deletions

View file

@ -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.)