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,11 +10,11 @@ chapter: '13'
pages: 254-256
---
On the 386, **ROR** was the only way to split a 32-bit register into two
16-bit registers. On the 486, however, **BSWAP** can not only do the
job, but can do it better, because **BSWAP** executes in just one cycle.
**BSWAP** has the added benefit of not affecting any flags, unlike
**ROR**. With **BSWAP**-based code like that in Listing 13.6, the upper
On the 386, `ROR` was the only way to split a 32-bit register into two
16-bit registers. On the 486, however, `BSWAP` can not only do the
job, but can do it better, because `BSWAP` executes in just one cycle.
`BSWAP` has the added benefit of not affecting any flags, unlike
`ROR`. With `BSWAP`-based code like that in Listing 13.6, the upper
16 bits of a register can be accessed with only 2 cycles of overhead and
without altering any flags, making the technique of packing two 16-bit
registers into one 32-bit register much more useful.
@ -37,8 +37,8 @@ looptop:
### Pushing and Popping Memory {#Heading5}
Pushing or popping a memory location, as in **PUSH WORD PTR [BX]** or
**POP [MemVar]**, is a compact, easy way to get a value onto or off of
Pushing or popping a memory location, as in `PUSH WORD PTR [BX]` or
`POP [MemVar]`, is a compact, easy way to get a value onto or off of
the stack, especially when pushing parameters for calling a C-compatible
function. However, on a 486, these are unattractive instructions from a
performance perspective. Pushing a memory location takes four cycles; by
@ -70,23 +70,23 @@ is so slow? The rule on the 486 is that simple operations, which can be
executed in a single cycle by the 486's RISC core, are fast; whereas
complex operations, which must be carried out in microcode just as they
were on the 386, are almost all relatively slow. Slow, complex
operations include all the string instructions except **REP MOVS,** as
well as **XLAT, LOOP,** and, of course, **PUSH *mem*** and **POP
*mem.***
operations include all the string instructions except `REP MOVS`, as
well as `XLAT`, `LOOP`, and, of course, `PUSH *mem*` and `POP
*mem*`.
> ![](images/i.jpg)
> Whenever possible, try to use the 486's 1-cycle instructions, including
> **MOV, ADD, SUB, CMP, ADC, SBB, XOR, AND, OR, TEST, LEA**, and **PUSH
> reg** and **POP reg**. These instructions have an added benefit in that
> it's often possible to rearrange them for maximum pipeline efficiency,
> as is the case with Terje's optimization described earlier in this
> chapter.
> `MOV`, `ADD`, `SUB`, `CMP`, `ADC`, `SBB`, `XOR`, `AND`, `OR`, `TEST`,
> `LEA`, and `PUSH reg` and `POP reg`. These instructions have an added
> benefit in that it's often possible to rearrange them for maximum
> pipeline efficiency, as is the case with Terje's optimization described
> earlier in this chapter.
### Optimal 1-Bit Shifts and Rotates {#Heading6}
On a 486, the n-bit forms of the shift and rotate instructions—as in
**ROR AX,2** and **SHL BX,9**—are 2-cycle instructions, but the 1-bit
forms—as in **ROR AX,1** and **SHL BX,1—**are *3-cycle* instructions. Go
`ROR AX,2` and `SHL BX,9`—are 2-cycle instructions, but the 1-bit
forms—as in `ROR AX,1` and `SHL BX,1`-are *3-cycle* instructions. Go
figure.
Assemblers default to the 1-bit instruction for 1-bit shifts and
@ -96,12 +96,12 @@ the n-bit form doesn't even exist on an 8088. In a really critical loop,
however, it might be worth hand-assembling the n-bit form of a
single-bit shift or rotate in order to save that cycle. The easiest way
to do this is to assemble a 2-bit form of the desired instruction, as in
**SHL AX,2,** then look at the hex codes that the assembler generates
and use **DB** to insert them in your program code, with the value two
replaced with the value one. For example, you could determine that **SHL
AX,2** assembles to the bytes 0C1H 0E0H 002H, either by looking at the
`SHL AX,2`, then look at the hex codes that the assembler generates
and use `DB` to insert them in your program code, with the value two
replaced with the value one. For example, you could determine that `SHL
AX,2` assembles to the bytes 0C1H 0E0H 002H, either by looking at the
disassembly in a debugger or by having the assembler generate a listing
file. You could then insert the n-bit version of **SHL AX,1** in your
file. You could then insert the n-bit version of `SHL AX,1` in your
code as follows:
```nasm
@ -111,12 +111,12 @@ mov dx,ax
```
At the end of this sequence, DX will contain 2, and the fast n-bit
version of **SHL AX,1** will have executed. If you use this approach,
version of `SHL AX,1` will have executed. If you use this approach,
I'd recommend using a macro, rather than sticking DBs in the middle of
your code.
Again, this technique is advantageous *only* on a 486. It also doesn't
apply to **RCL** and **RCR,** where you definitely want to use the 1-bit
apply to `RCL` and `RCR`, where you definitely want to use the 1-bit
versions whenever you can, because the n-bit versions are horrendously
slow. But if you're optimizing for the 486, these tidbits can save a few
critical cycles—and Lord knows that if you're optimizing for the