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
54
19-03.md
54
19-03.md
|
|
@ -15,21 +15,21 @@ pages: 375-377
|
|||
I'll spend the rest of this chapter covering a variety of Pentium
|
||||
optimization tips. For starters, effective address calculations (that
|
||||
is, the addition and scaling required to calculate a memory operand's
|
||||
address, as for example in **MOV EAX,[EBX+ECX\*2+4]**) never take any
|
||||
address, as for example in `MOV EAX,[EBX+ECX*2+4]`) never take any
|
||||
extra cycles on the Pentium (other than possibly an AGI cycle), even for
|
||||
the use of base+index addressing (as in **MOV [ESI+EDI],EAX**) or
|
||||
scaling (\*2, \*4, or \*8, as in **INC ARRAY[ESI\*4]**). On the 486,
|
||||
the use of base+index addressing (as in `MOV [ESI+EDI],EAX`) or
|
||||
scaling (\*2, \*4, or \*8, as in `INC ARRAY[ESI*4]`). On the 486,
|
||||
both of the latter cases cause a 1-cycle penalty. The faster effective
|
||||
address calculations have the side effect of making **LEA** very
|
||||
attractive as an arithmetic instruction. **LEA** can add any two
|
||||
address calculations have the side effect of making `LEA` very
|
||||
attractive as an arithmetic instruction. `LEA` can add any two
|
||||
registers, one of which can be multiplied by one, two, four, or eight,
|
||||
plus a constant value, and can store the result in any register—all in
|
||||
one cycle, apart from AGIs. Not only that, but as we'll see in the next
|
||||
chapter, **LEA** can go through either pipe, whereas **SHL** can only go
|
||||
through the U-pipe, so **LEA** is often a superior choice for
|
||||
multiplication by three, four, five, eight, or nine. (**ADD** is the
|
||||
best choice for multiplication by two.) If you use **LEA** for
|
||||
arithmetic, do remember that unlike **ADD** and **SHL**, it doesn't
|
||||
chapter, `LEA` can go through either pipe, whereas `SHL` can only go
|
||||
through the U-pipe, so `LEA` is often a superior choice for
|
||||
multiplication by three, four, five, eight, or nine. (`ADD` is the
|
||||
best choice for multiplication by two.) If you use `LEA` for
|
||||
arithmetic, do remember that unlike `ADD` and `SHL`, it doesn't
|
||||
modify any flags.
|
||||
|
||||
As on the 486, memory operands should not cross any more alignment
|
||||
|
|
@ -61,8 +61,8 @@ bigger overall.
|
|||
|
||||
Instruction prefixes are awfully expensive; avoid them if you can.
|
||||
(These include size and addressing prefixes, segment overrides,
|
||||
**LOCK**, and the 0FH prefixes that extend the instruction set with
|
||||
instructions such as **MOVSX**. The exceptions are conditional jumps, a
|
||||
`LOCK`, and the 0FH prefixes that extend the instruction set with
|
||||
instructions such as `MOVSX`. The exceptions are conditional jumps, a
|
||||
fast special case.) At a minimum, a prefix byte generally takes an extra
|
||||
cycle and shuts down the V-pipe for that cycle, effectively costing as
|
||||
much as two normal instructions (although prefix cycles can overlap with
|
||||
|
|
@ -81,34 +81,34 @@ variables to longs when performing calculations.) Likewise, you should
|
|||
if possible avoid putting data in the code segment and referring to it
|
||||
with a CS: prefix, or otherwise using segment overrides.
|
||||
|
||||
**LOCK** is a particularly costly instruction, especially on
|
||||
`LOCK` is a particularly costly instruction, especially on
|
||||
multiprocessor machines, because it locks the bus and requires that the
|
||||
hardware be brought into a synchronized state. The cost varies depending
|
||||
on the processor and system, but **LOCK** can make an **INC [*mem*]**
|
||||
on the processor and system, but `LOCK` can make an `INC [*mem*]`
|
||||
instruction (which normally takes 3 cycles) 5, 10, or more cycles
|
||||
slower. Most programmers will never use **LOCK** on purpose—it's
|
||||
slower. Most programmers will never use `LOCK` on purpose—it's
|
||||
primarily an operating system instruction—but there's a hidden gotcha
|
||||
here because the **XCHG** instruction always locks the bus when used
|
||||
here because the `XCHG` instruction always locks the bus when used
|
||||
with a memory operand.
|
||||
|
||||
> 
|
||||
> **XCHG** is a tempting instruction that's often used in assembly
|
||||
> `XCHG` is a tempting instruction that's often used in assembly
|
||||
> language; for example, exchanging with video memory is a popular way to
|
||||
> read and write VGA memory in a single instruction—but it's now a bad
|
||||
> idea. As it happens, on the 486 and Pentium, using **MOV**s to read and
|
||||
> idea. As it happens, on the 486 and Pentium, using `MOV`s to read and
|
||||
> write memory is faster, anyway; and even on the 486, my measurements
|
||||
> indicate a five-cycle tax for **LOCK** in general, and a nine-cycle
|
||||
> execution time for **XCHG** with memory. Avoid **XCHG** with memory if
|
||||
> indicate a five-cycle tax for `LOCK` in general, and a nine-cycle
|
||||
> execution time for `XCHG` with memory. Avoid `XCHG` with memory if
|
||||
> you possibly can.
|
||||
|
||||
As with the 486, don't use **ENTER** or **LEAVE**, which are slower than
|
||||
the equivalent discrete instructions. Also, start using **TEST
|
||||
*reg,reg*** instead of **AND *reg,reg*** or **OR *reg,reg*** to test
|
||||
As with the 486, don't use `ENTER` or `LEAVE`, which are slower than
|
||||
the equivalent discrete instructions. Also, start using `TEST
|
||||
*reg,reg*` instead of `AND *reg,reg*` or `OR *reg,reg*` to test
|
||||
whether a register is zero. The reason, as we'll see in Chapter 21, is
|
||||
that **TEST**, unlike **AND** and **OR**, never modifies the target
|
||||
register. Although in this particular case **AND** and **OR** don't
|
||||
that `TEST`, unlike `AND` and `OR`, never modifies the target
|
||||
register. Although in this particular case `AND` and `OR` don't
|
||||
modify the target register either, the Pentium has no way of knowing
|
||||
that ahead of time, so if **AND** or **OR** goes through the U-pipe, the
|
||||
that ahead of time, so if `AND` or `OR` goes through the U-pipe, the
|
||||
Pentium may have to shut down the V-pipe for a cycle to avoid potential
|
||||
dependencies on the result of the **AND** or **OR**. **TEST** suffers
|
||||
dependencies on the result of the `AND` or `OR`. `TEST` suffers
|
||||
from no such potential dependencies.
|
||||
|
|
|
|||
Loading…
Reference in a new issue