Normal quotes
This commit is contained in:
parent
5e10794a24
commit
18011c595a
352 changed files with 6040 additions and 6040 deletions
36
12-02.md
36
12-02.md
|
|
@ -18,7 +18,7 @@ calculations take a *minimum* of 5 cycles. On the 486, however, 1 cycle
|
|||
is a big deal because many instructions, including most register-only
|
||||
instructions (**MOV**, **ADD**, **CMP**, and so on) execute in just 1
|
||||
cycle. In particular, **MOV**s to and from memory execute in 1 cycle—if
|
||||
they’re not hampered by something like indexed addressing, in which case
|
||||
they're not hampered by something like indexed addressing, in which case
|
||||
they slow to half speed (or worse, as we will see shortly).
|
||||
|
||||
For example, consider the summing example shown earlier. The version
|
||||
|
|
@ -32,7 +32,7 @@ In a key loop on the 486, 1 cycle can indeed matter.
|
|||
|
||||
#### Calculate Memory Pointers Ahead of Time {#Heading6}
|
||||
|
||||
Rule \#2: Don’t use a register as a memory pointer during the next two
|
||||
Rule \#2: Don't use a register as a memory pointer during the next two
|
||||
cycles after loading it.
|
||||
|
||||
Intel states that if the destination of one instruction is used as the
|
||||
|
|
@ -44,16 +44,16 @@ start of the instruction that will need it, as shown in Figure 12.1;
|
|||
this effectively makes the address calculation time vanish, because it
|
||||
happens while the preceding instruction executes.
|
||||
|
||||
Of course, the 486 *can’t* perform an effective address calculation for
|
||||
Of course, the 486 *can't* perform an effective address calculation for
|
||||
a target instruction ahead of time if one of the address components
|
||||
isn’t known until the instruction starts, and that’s exactly the case
|
||||
when the preceding instruction modifies one of the target instruction’s
|
||||
isn't known until the instruction starts, and that's exactly the case
|
||||
when the preceding instruction modifies one of the target instruction's
|
||||
addressing registers. For example, in the code
|
||||
|
||||
MOV BX,OFFSET MemVar
|
||||
MOV AX,[BX]
|
||||
|
||||
there’s no way that the 486 can calculate the address referenced by
|
||||
there's no way that the 486 can calculate the address referenced by
|
||||
**MOV AX,[BX]** until **MOV BX,OFFSET MemVar** finishes, so pipelining
|
||||
that calculation ahead of time is not possible. A good workaround is
|
||||
rearranging your code so that at least one instruction lies between the
|
||||
|
|
@ -78,7 +78,7 @@ Now that we understand what Intel means by this rule, let me make a very
|
|||
important comment: My observations indicate that for real-mode code, the
|
||||
documentation understates the extent of the penalty for interrupting the
|
||||
address calculation pipeline by loading a memory pointer just before
|
||||
it’s used.
|
||||
it's used.
|
||||
|
||||
------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
 *The truth of the matter appears to be that if a register is the destination of one instruction and is then used by the next instruction to address memory in real mode, not one but two cycles are lost!*
|
||||
|
|
@ -87,17 +87,17 @@ it’s used.
|
|||
In 32-bit protected mode, however, the penalty is, in fact, the 1 cycle
|
||||
that Intel .
|
||||
|
||||
Considering that **MOV** normally takes only one cycle total, that’s
|
||||
Considering that **MOV** normally takes only one cycle total, that's
|
||||
quite a loss. For example, the postdecrement loop shown above is 2 full
|
||||
cycles faster than the preincrement loop, resulting in a 29 percent
|
||||
improvement in the performance of the entire loop. But wait, there’s
|
||||
improvement in the performance of the entire loop. But wait, there's
|
||||
more. If a register is loaded 2 cycles (which generally means 2
|
||||
instructions, but, because some 486 instructions take more than 1 cycle,
|
||||
|
||||
\
|
||||
**Figure 12.1** *One-cycle-ahead address pipelining.*
|
||||
|
||||
the 2 are not always equivalent) before it’s used to point to memory, 1
|
||||
the 2 are not always equivalent) before it's used to point to memory, 1
|
||||
cycle is lost. Therefore, whereas this code
|
||||
|
||||
mov bx,offset MemVar
|
||||
|
|
@ -123,16 +123,16 @@ loses only one cycle, and this code
|
|||
mov ax,[bx]
|
||||
jnz LoopTop
|
||||
|
||||
loses no cycles at all. Apparently, the 486’s addressing calculation
|
||||
loses no cycles at all. Apparently, the 486's addressing calculation
|
||||
pipeline actually starts 2 cycles ahead, as shown in Figure 12.2. (In
|
||||
truth, my best guess at the moment is that the addressing pipeline
|
||||
really does start only 1 cycle ahead; the additional cycle crops up when
|
||||
the addressing pipeline has to wait for a register to be written into
|
||||
the register file before it can read it out for use in addressing
|
||||
calculations. However, I’m guessing here, and the 2-cycle-ahead model in
|
||||
calculations. However, I'm guessing here, and the 2-cycle-ahead model in
|
||||
Figure 12.2 will do just fine for optimization purposes.)
|
||||
|
||||
Clearly, there’s considerable optimization potential in careful
|
||||
Clearly, there's considerable optimization potential in careful
|
||||
rearrangement of 486 code.
|
||||
|
||||
\
|
||||
|
|
@ -140,17 +140,17 @@ rearrangement of 486 code.
|
|||
|
||||
### Caveat Programmor {#Heading7}
|
||||
|
||||
A caution: I’m quite certain that the 2-cycle-ahead addressing pipeline
|
||||
interruption penalty I’ve described exists in the two 486s I’ve tested.
|
||||
However, there’s no guarantee that Intel won’t change this aspect of the
|
||||
A caution: I'm quite certain that the 2-cycle-ahead addressing pipeline
|
||||
interruption penalty I've described exists in the two 486s I've tested.
|
||||
However, there's no guarantee that Intel won't change this aspect of the
|
||||
486 in the future, especially given that the documentation indicates
|
||||
otherwise. Perhaps the 2-cycle penalty is the result of a bug in the
|
||||
initial steps of the 486, and will revert to the documented 1-cycle
|
||||
penalty someday; likewise for the undocumented optimizations I’ll
|
||||
penalty someday; likewise for the undocumented optimizations I'll
|
||||
describe below. Nonetheless, none of the optimizations I suggest would
|
||||
hurt performance even if the undocumented performance characteristics of
|
||||
the 486 were to vanish, and they certainly will help performance on at
|
||||
least some 486s right now, so I feel they’re well worth using.
|
||||
least some 486s right now, so I feel they're well worth using.
|
||||
|
||||
------------------------ --------------------------------- --------------------
|
||||
[Previous](12-01.html) [Table of Contents](index.html) [Next](12-03.html)
|
||||
|
|
|
|||
Loading…
Reference in a new issue