82 lines
7.9 KiB
HTML
82 lines
7.9 KiB
HTML
<HTML>
|
|
<HEAD>
|
|
<META name=vsisbn content="1576101746">
|
|
<META name=vstitle content="Michael Abrash's Graphics Programming Black Book, Special Edition">
|
|
<META name=vsauthor content="Michael Abrash">
|
|
<META name=vspublisher content="The Coriolis Group">
|
|
<META name=vspubdate content="07/01/97">
|
|
<META name=vscategory content="Web and Software Development: Game Development,Web and Software Development: Graphics and Multimedia Development">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<TITLE>Michael Abrash's Graphics Programming Black Book Special Edition: Pentium: Not the Same Old Song</TITLE>
|
|
|
|
<!-- HEADER -->
|
|
<!-- Empty Reference Subhead -->
|
|
|
|
<!--ISBN=1576101746//-->
|
|
<!--TITLE=Michael Abrash's Graphics Programming Black Book Special Edition//-->
|
|
<!--AUTHOR=Michael Abrash//-->
|
|
<!--PUBLISHER=The Coriolis Group, Inc.//-->
|
|
<!--CHAPTER=19//-->
|
|
<!--PAGES=375-377//-->
|
|
<!--UNASSIGNED1//-->
|
|
<!--UNASSIGNED2//--></HEAD><BODY LINK=#0000FF ALINK=#000099 VLINK=#0000FF BGCOLOR=#FFFFFF>
|
|
|
|
<CENTER>
|
|
<TABLE BORDER>
|
|
<TR>
|
|
<TD><A HREF="19-02.html">Previous</A></TD>
|
|
<TD><A HREF="index.html">Table of Contents</A></TD>
|
|
<TD><A HREF="19-04.html">Next</A></TD>
|
|
</TR>
|
|
</TABLE>
|
|
</CENTER>
|
|
<P><BR></P>
|
|
<H3><A NAME="Heading7"></A><FONT COLOR="#000077">Faster Addressing and More</FONT></H3>
|
|
<P>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 <B>MOV EAX,[EBX+ECX*2+4]</B>) never take any extra cycles on the Pentium (other than possibly an AGI cycle), even for the use of base+index addressing (as in <B>MOV [ESI+EDI],EAX</B>) or scaling (*2, *4, or *8, as in <B>INC ARRAY[ESI*4]</B>). On the 486, both of the latter cases cause a 1-cycle penalty. The faster effective address calculations have the side effect of making <B>LEA</B> very attractive as an arithmetic instruction. <B>LEA</B> 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, <B>LEA</B> can go through either pipe, whereas <B>SHL</B> can only go through the U-pipe, so <B>LEA</B> is often a superior choice for multiplication by three, four, five, eight, or nine. (<B>ADD</B> is the best choice for multiplication by two.) If you use <B>LEA</B> for arithmetic, do remember that unlike <B>ADD</B> and <B>SHL</B>, it doesn’t modify any flags.</P>
|
|
<P>As on the 486, memory operands should not cross any more alignment boundaries than absolutely necessary. Word operands should be word-aligned, dword operands should be dword-aligned, and qword operands (double-precision variables) should be qword-aligned. Spanning a dword boundary, as in</P>
|
|
<!-- CODE SNIP //-->
|
|
<PRE>
|
|
mov ebx,3
|
|
:
|
|
mov eax,[ebx]
|
|
</PRE>
|
|
<!-- END CODE SNIP //-->
|
|
<P>costs three cycles. On the other hand, as noted above, branch targets can now span cache lines with impunity, so on the Pentium there’s no good argument for the paragraph (that is, 16-byte) alignment that Intel recommends for 486 jump targets. The 32-byte alignment might make for slightly more efficient Pentium cache usage, but would make code much bigger overall.
|
|
</P>
|
|
<TABLE WIDTH="100%"><TD VALIGN="TOP" ALIGN="LEFT" WIDTH="5%"><IMG SRC="images/19-03i.jpg"><TD VALIGN="TOP" ALIGN="LEFT" WIDTH="95%"><SMALL><I>In fact, given that most jump targets aren’t in performance-critical code, it’s hard to make a compelling argument for aligning branch targets even on the 486. I’d say that no alignment (except possibly where you know a branch target lies in a key loop), or at most dword alignment (for the 386) is plenty, and can shrink code size considerably.</I></SMALL>
|
|
</TABLE>
|
|
<P>Instruction prefixes are awfully expensive; avoid them if you can. (These include size and addressing prefixes, segment overrides, <B>LOCK</B>, and the 0FH prefixes that extend the instruction set with instructions such as <B>MOVSX</B>. 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 previous multicycle instructions, or AGIs, as on the 486). This means that using 32-bit addressing or 32-bit operands in a 16-bit segment, or vice versa, makes for bigger code that’s significantly slower. So, for example, you should generally avoid 16-bit variables (shorts, in C) in 32-bit code, although if using 32-bit variables where they’re not needed makes your data space get a lot bigger, you may want to stick with shorts, especially since longs use the cache less efficiently than shorts. The trade-off depends on the amount of data and the number of instructions that reference that data. (eight-bit variables, such as chars, have no extra overhead and can be used freely, although they may be less desirable than longs for compilers that tend to promote 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.</P>
|
|
<P><B>LOCK</B> 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 <B>LOCK</B> can make an <B>INC [<I>mem</I>]</B> instruction (which normally takes 3 cycles) 5, 10, or more cycles slower. Most programmers will never use <B>LOCK</B> on purpose—it’s primarily an operating system instruction—but there’s a hidden gotcha here because the <B>XCHG</B> instruction always locks the bus when used with a memory operand.</P>
|
|
<TABLE WIDTH="100%"><TD VALIGN="TOP" ALIGN="LEFT" WIDTH="5%"><IMG SRC="images/19-04i.jpg"><TD VALIGN="TOP" ALIGN="LEFT" WIDTH="95%"><SMALL><I><B>XCHG</B> 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 <B>MOV</B>s to read and write memory is faster, anyway; and even on the 486, my measurements indicate a five-cycle tax for <B>LOCK</B> in general, and a nine-cycle execution time for <B>XCHG</B> with memory. Avoid <B>XCHG</B> with memory if you possibly can.</I></SMALL>
|
|
</TABLE>
|
|
<P>As with the 486, don’t use <B>ENTER</B> or <B>LEAVE</B>, which are slower than the equivalent discrete instructions. Also, start using <B>TEST <I>reg,reg</I></B> instead of <B>AND <I>reg,reg</I></B> or <B>OR <I>reg,reg</I></B> to test whether a register is zero. The reason, as we’ll see in Chapter 21, is that <B>TEST</B>, unlike <B>AND</B> and <B>OR</B>, never modifies the target register. Although in this particular case <B>AND</B> and <B>OR</B> don’t modify the target register either, the Pentium has no way of knowing that ahead of time, so if <B>AND</B> or <B>OR</B> 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 <B>AND</B> or <B>OR</B>. <B>TEST</B> suffers from no such potential dependencies.</P><P><BR></P>
|
|
<CENTER>
|
|
<TABLE BORDER>
|
|
<TR>
|
|
<TD><A HREF="19-02.html">Previous</A></TD>
|
|
<TD><A HREF="index.html">Table of Contents</A></TD>
|
|
<TD><A HREF="19-04.html">Next</A></TD>
|
|
</TR>
|
|
</TABLE>
|
|
</CENTER>
|
|
|
|
<hr width="90%" size="1" noshade>
|
|
<div align="center">
|
|
<font face="Verdana,sans-serif" size="1">Graphics Programming Black Book © 2001 Michael Abrash</font>
|
|
</div>
|
|
<!-- all of the reference materials (books) have the footer and subfoot reveresed -->
|
|
<!-- reference_subfoot = footer -->
|
|
<!-- reference_footer = subfoot -->
|
|
|
|
<!-- BEGIN SUB FOOTER -->
|
|
</BODY>
|
|
</HTML>
|
|
|
|
<!-- END FOOTER -->
|
|
|
|
|