AMD Software optimization Guide for AMD Family 10h Processors. [rev.3.09].[2008-11] Datasheet

Page 1
Advanced Micro Devices
Software Optimization
Guide
for
AMD Family 10h
Processors
Page 2
Trademarks
© 2006–2008 Advanced Micro Devices, Inc. All rights reserved.
The contents of this document are provided in connection with Advanced Micro Devices, Inc. (“AMD”) products. AMD makes no representations or warranties with respect to the accuracy or completeness of the contents of this publication and reserves the right to make changes to specifications and product descriptions at any time without notice. The infor­mation contained herein may be of a preliminary or advance nature and is subject to change without notice. No license, whether express, implied, arising by estoppel or other­wise, to any intellectual property rights is granted by this publication. Except as set forth in AMD’s Standard Terms and Conditions of Sale, AMD assumes no liability whatsoever, and disclaims any express or implied warranty, relating to its products including, but not limited to, the implied warranty of merchantability, fitness for a particular purpose, or infringement of any intellectual property right.
AMD’s products are not designed, intended, authorized or warranted for use as compo­nents in systems intended for surgical implant into the body, or in other applications intended to support or sustain life, or in any other application in which the failure of AMD’s product could create a situation where personal injury, death, or severe property or environmental damage may occur. AMD reserves the right to discontinue or make changes to its products at any time without notice.
AMD, the AMD Arrow logo, and combinations thereof, 3DNow!, AMD Virtualization and AMD-V are trademarks of Advanced Micro Devices, Inc.
HyperTransport is a licensed trademark of th
Linux is a registered trademark o
Microsoft and Windows are registered trademarks
MMX is a trademark of Intel Corporation.
PCI-X and PCI Express are registered trademarks of the PCI-Special Interest Group (PCI-SIG).
Solaris is a registered trademar
Other product names used in this publication are for iden
f Linus Torvald.
k of Sun Microsystems, Inc.
e HyperTransport Technology Consortium.
of Microsoft Corporation.
tification purposes only and may be trademarks of their respective companies.
Page 3
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors

Contents

Revision History. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xvii
Chapter 1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1
1.1 Intended Audience . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1
1.2 Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1
1.3 Using This Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2
1.3.1 Special Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3
1.3.2 Numbering Systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3
1.3.3 Typographic Notation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4
1.4 Important New Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4
1.4.1 Multi-Core Processors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4
1.4.2 Primitive Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4
1.4.3 Internal Instruction Formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4
1.4.4 Types of Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5
1.5 Key Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .6
1.5.1 Implementation Guideline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .6
1.6 What’s New on AMD Family 10h Processors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .6
1.6.1 AMD Instruction Set Enhancements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .7
1.6.2 Floating-Point Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .7
1.6.3 Load-Execute Instructions for Unaligned Data . . . . . . . . . . . . . . . . . . . . . . . .8
1.6.4 Instruction Fetching Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .8
1.6.5 Instruction Decode and Floating-Point Pipe Improvements . . . . . . . . . . . . . . .9
1.6.6 Notable Performance Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .9
1.6.7 Large Page Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .11
1.6.8 AMD Virtualization™ Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .11
Chapter 2 C and C++ Source-Level Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13
2.1 Declarations of Floating-Point Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14
2.2 Using Arrays and Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14
Contents iii
Page 4
Software Optimization Guide for AMD Family 10h Processors
2.3 Unrolling Small Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .17
2.4 Arrange Boolean Operands for Quick Expression Evaluation . . . . . . . . . . . . . . . . . .18
2.5 Expression Order in Compound Branch Conditions . . . . . . . . . . . . . . . . . . . . . . . . .19
2.6 Long Logical Expressions in If Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .20
2.7 Dynamic Memory Allocation Consideration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .21
2.8 Unnecessary Store-to-Load Dependencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .21
2.9 Matching Store and Load Size . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .23
2.10 Use of Function Prototypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .25
2.11 Use of const Type Qualifier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .26
2.12 Generic Loop Hoisting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .26
2.13 Local Static Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .28
2.14 Explicit Parallelism in Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .29
40546 Rev. 3.09 November 2008
2.15 Extracting Common Subexpressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .30
2.16 Sorting and Padding C and C++ Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .31
2.17 Replacing Integer Division with Multiplication . . . . . . . . . . . . . . . . . . . . . . . . . . . . .32
2.18 Frequently Dereferenced Pointer Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .33
2.19 32-Bit Integral Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .34
2.20 Sign of Integer Operands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .35
2.21 Accelerating Floating-Point Division and Square Root . . . . . . . . . . . . . . . . . . . . . . .36
2.22 Speeding Up Branches Based on Comparisons Between Floats . . . . . . . . . . . . . . . .38
®
2.23 Improving Performance in Linux
Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .40
2.24 Aligning Matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .41
Chapter 3 General 64-Bit Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .43
3.1 64-Bit Registers and Integer Arithmetic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .43
3.2 Using 64-bit Arithmetic for Large-Integer Multiplication . . . . . . . . . . . . . . . . . . . . .45
3.3 128-Bit Media Instructions and Floating-Point Operations . . . . . . . . . . . . . . . . . . . .49
3.4 32-Bit Legacy GPRs and Small Unsigned Integers . . . . . . . . . . . . . . . . . . . . . . . . . .49
Chapter 4 Instruction-Decoding Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .51
4.1 DirectPath Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .52
4.2 Load-Execute Instructions for Floating-Point or Integer Operands . . . . . . . . . . . . . .53
iv Contents
Page 5
40546 Rev. 3.09 November 2008
4.2.1 Load-Execute Integer Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .53
4.2.2 Load-Execute SSE/SSE2/SSE3 Instructions with Floating-Point
or Integer Operands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .54
4.2.3 Load-Execute x87 Instructions with Integer Operands . . . . . . . . . . . . . . . . .55
4.3 Loop Iteration Boundaries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .56
4.4 32/64-Bit vs. 16-Bit Forms of the LEA Instruction . . . . . . . . . . . . . . . . . . . . . . . . . .56
4.5 Take Advantage of x86 and AMD64 Complex Addressing Modes . . . . . . . . . . . . . .57
4.6 Short Instruction Encodings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .58
4.7 Stack Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .59
4.8 Partial-Register Writes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .60
4.9 Using LEAVE for Function Epilogues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .64
4.10 Alternatives to SHLD Instruction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .66
Software Optimization Guide for AMD Family 10h Processors
4.11 8-Bit Sign-Extended Immediate Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .67
4.12 8-Bit Sign-Extended Displacements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .67
4.13 Code Padding with Operand-Size Override and Multibyte NOP . . . . . . . . . . . . . . . .68
Chapter 5 Cache and Memory Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .71
5.1 Memory-Size Mismatches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .71
5.2 Natural Alignment of Data Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .73
5.3 Store-to-Load Forwarding Restrictions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .74
5.4 Good Practices for Avoiding False Store-to-Load Forwarding . . . . . . . . . . . . . . . . .80
5.5 Prefetch and Streaming Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .81
5.6 Write-Combining . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .89
5.7 L1 Data Cache Bank Conflicts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .90
5.8 Placing Code and Data in the Same 64-Byte Cache Line . . . . . . . . . . . . . . . . . . . . . .91
5.9 Memory and String Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .92
5.10 Stack Considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .94
5.11 Cache Issues When Writing Instruction Bytes to Memory . . . . . . . . . . . . . . . . . . . .95
5.12 Interleave Loads and Stores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .96
5.13 Using 1-Gbyte Virtual Memory Pages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .96
Chapter 6 Branch Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .99
Contents v
Page 6
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
6.1 Branch Alignment and Density . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .99
6.2 Three-Byte Return-Immediate RET Instruction . . . . . . . . . . . . . . . . . . . . . . . . . . . .100
6.3 Branches That Depend on Random Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .101
6.4 Pairing CALL and RETURN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .103
6.5 Nonzero Code-Segment Base Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .104
6.6 Replacing Branches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .104
6.7 Avoiding the LOOP Instruction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .106
6.8 Far Control-Transfer Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .106
6.9 Branches Not-Taken Preferable to Branches Taken . . . . . . . . . . . . . . . . . . . . . . . .107
Chapter 7 Scheduling Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .109
7.1 Instruction Scheduling by Latency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .109
7.2 Loop Unrolling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .110
7.3 Inline Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .113
7.4 Address-Generation Interlocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .115
7.5 MOVZX and MOVSX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .116
7.6 Pointer Arithmetic in Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .116
7.7 Pushing Memory Data Directly onto the Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . .118
Chapter 8 Integer Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .119
8.1 Replacing Division with Multiplication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .119
8.2 Alternative Code for Multiplying by a Constant . . . . . . . . . . . . . . . . . . . . . . . . . . .123
8.3 Repeated String Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .126
8.4 Using XOR to Clear Integer Registers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .127
8.5 Efficient 64-Bit Integer Arithmetic in 32-Bit Mode . . . . . . . . . . . . . . . . . . . . . . . . .128
8.6 Derivation of Algorithm, Multiplier, and Shift Factor for Integer Division
by Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .135
8.7 Optimizing Integer Division . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .141
8.8 Efficient Implementation of Population Count and Leading-Zero Count . . . . . . . .142
Chapter 9 Optimizing with SIMD Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .143
9.1 Ensure All Packed Floating-Point Data are Aligned . . . . . . . . . . . . . . . . . . . . . . . .144
9.2 Explicit Load Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .144
vi Contents
Page 7
40546 Rev. 3.09 November 2008
9.3 Unaligned and Aligned Data Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .145
9.4 Moving Data Between General-Purpose and MMX™ or XMM Registers . . . . . . .145
9.5 Use SSE Instructions to Construct Fast Block-Copy Routines in 32-Bit
Mode or 64-bit Mode. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .146
9.6 EMMS Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .147
9.7 Using SIMD Instructions for Fast Square Roots and Divisions . . . . . . . . . . . . . . . .148
9.8 Use XOR Operations to Negate Operands of SSEx Instructions . . . . . . . . . . . . . . .150
9.9 Clearing MMX™ and XMM Registers with XOR Instructions . . . . . . . . . . . . . . . .151
9.10 Finding the Floating-Point Absolute Value of Operands of SSE and
SSE2 Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .152
9.11 Accumulating Single-Precision Floating-Point Numbers Using SSE and
SSE2 Instructions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .153
9.12 Complex-Number Arithmetic Using SSE, SSE2, and SSE3 Instructions . . . . . . . .154
Software Optimization Guide for AMD Family 10h Processors
9.13 Optimized 4 X 4 Matrix Multiplication on 4 X 1 Column Vector Routines . . . . . .160
9.14 Floating-Point-to-Integer Conversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .163
9.15 Reuse of Dead Registers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .163
9.16 Floating-Point Scalar Conversions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .164
Chapter 10 x87 Floating-Point Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .167
10.1 Using Multiplication Rather Than Division . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .167
10.2 Achieving Two Floating-Point Operations per Clock Cycle . . . . . . . . . . . . . . . . . .168
10.3 Floating-Point Compare Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .172
10.4 Using the FXCH Instruction Rather Than FST/FLD Pairs . . . . . . . . . . . . . . . . . . . .172
10.5 Floating-Point Subexpression Elimination . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .173
10.6 Accumulating Precision-Sensitive Quantities in x87 Registers . . . . . . . . . . . . . . . .174
10.7 Avoiding Extended-Precision Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .175
Chapter 11 Multiprocessor Considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .177
11.1 ccNUMA Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .177
11.2 Writing Instruction Bytes to Memory on Multiprocessor Systems . . . . . . . . . . . . .187
11.3 Multithreading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .188
11.4 Memory Barrier Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .194
11.5 Optimizing Inter-Core Data Transfer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .197
Contents vii
Page 8
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
Chapter 12 Optimizing Secure Virtual Machines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .203
12.1 Use Nested Paging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .204
12.2 VMCB.G_PAT Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .205
12.3 State Swapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .205
12.4 Economizing Interceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .206
12.5 Nested Page Size . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .207
12.6 Shadow Page Size . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .208
12.7 Setting VMCB.TLB_Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .208
12.8 TLB Flushes in Shadow Paging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .209
12.9 Use of Virtual Interrupt VMCB Field . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .210
12.10 Avoid Instruction Fetch for Intercepted (REP) OUTS Instructions . . . . . . . . . . . . .211
12.11 Share IOIO and MSR Protection Maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .213
12.12 Obey CPUID Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .213
12.13 Using Time Sources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .214
12.14 Paravirtualized Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .215
Appendix A Microarchitecture of AMD Family 10h Processors . . . . . . . . . . . . . . . . . . . . . . .217
A.1 Key Microarchitecture Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .218
A.2 Microarchitecture of AMD Family 10h Processors . . . . . . . . . . . . . . . . . . . . . . . . .218
A.3 Superscalar Processor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .219
A.4 Processor Block Diagram . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .219
A.5 AMD Family 10h Processor Cache Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . .220
A.5.1 L1 Instruction Cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .221
A.5.2 L1 Data Cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .221
A.5.3 L2 Cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .221
A.5.4 L3 Cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .221
A.6 Branch-Prediction Table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .222
A.7 Fetch-Decode Unit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .222
A.8 Sideband Stack Optimizer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .223
A.9 Instruction Control Unit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .223
A.10 Translation-Lookaside Buffer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .223
viii Contents
Page 9
40546 Rev. 3.09 November 2008
A.10.1 L1 Instruction TLB Specifications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .223
A.10.2 L1 Data TLB Specifications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .223
A.10.3 L2 Instruction TLB Specifications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .223
A.10.4 L2 Data TLB Specifications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .224
A.11 Integer Unit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .224
A.11.1 Integer Scheduler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .224
A.11.2 Integer Execution Unit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .224
A.12 Floating-Point Unit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .225
A.12.1 Floating-Point Scheduler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .225
A.12.2 Floating-Point Execution Unit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .226
A.13 Load-Store Unit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .227
A.14 Write Combining . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .228
Software Optimization Guide for AMD Family 10h Processors
A.15 Integrated Memory Controller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .228
A.16 HyperTransport™ Technology Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .228
Appendix B Implementation of Write-Combining . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .231
B.1 Write-Combining Definitions and Abbreviations . . . . . . . . . . . . . . . . . . . . . . . . . . .231
B.2 Programming Details . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .232
B.3 Write-Combining Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .232
B.4 Sending Write-Buffer Data to the System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .233
B.5 Write Combining to MMI/O Devices that Support Write Chaining . . . . . . . . . . . .233
Appendix C Instruction Latencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .235
C.1 Understanding Instruction Entries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .236
C.2 General Purpose and Integer Instruction Latencies . . . . . . . . . . . . . . . . . . . . . . . . .240
C.3 System Instruction Latencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .250
C.4 128-Bit Media Instruction Latencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .254
C.5 64-Bit Media Instruction Latencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .268
C.6 x87 Floating-Point Instruction Latencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .273
Appendix D Tools and APIs for
AMD Family 10h ccNUMA Multiprocessor Systems. . . . . . . . . . . . . . . . . . . . . .277
D.1.1 Support Under Linux® . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .277
Contents ix
Page 10
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
D.1.2 Support under Solaris™ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .278
D.1.3 Support under Microsoft® Windows® . . . . . . . . . . . . . . . . . . . . . . . . . . . . .279
D.2 Tools and APIs for Node Interleaving . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .279
D.2.1 Support under Linux® . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .279
D.2.2 Support under Solaris™ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .279
D.2.3 Support under Microsoft® Windows® . . . . . . . . . . . . . . . . . . . . . . . . . . . . .280
D.2.4 Node Interleaving Configuration in the BIOS . . . . . . . . . . . . . . . . . . . . . . .280
Appendix E NUMA Optimizations for I/O Devices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .281
E.1 AMD64 System Topologies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .281
E.2 Key Optimizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .281
E.3 Determining Number Of Nodes in AMD Family 10h Processor Systems
in User-Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .282
E.4 Allocating I/O Device Buffers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .283
E.5 I/O Thread Scheduling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .284
E.6 Using Write-Only Buffers for Device Consumption . . . . . . . . . . . . . . . . . . . . . . . .284
E.7 Access of PCI Configuration Register . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .285
E.8 Determine the Nodes that Have Noncoherent HyperTransport™ I/O Links . . . . . .287
E.9 Using Interrupt Affinity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .292
Appendix F Remarks on the RDTSC(P) Instruction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .293
Appendix G Guide to Instruction-Based Sampling on AMD Family 10h Processors . . . . . .295
G.1 Background . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .295
G.2 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .296
G.3 IBS fetch sampling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .297
G.3.1 Taking an IBS fetch sample . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .297
G.3.2 Interpreting IBS fetch data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .298
G.4 IBS op sampling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .300
G.4.1 Taking an IBS op sample . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .300
G.4.2 Interpreting IBS op data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .300
G.4.3 Interpreting IBS branch/return/resync op data . . . . . . . . . . . . . . . . . . . . . . .302
G.4.4 Interpreting IBS Load/Store Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .303
x Contents
Page 11
40546 Rev. 3.09 November 2008
G.4.5 Interpreting IBS load/store Northbridge data . . . . . . . . . . . . . . . . . . . . . . . .304
G.5 Software-based analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .306
G.5.1 Derived events and post-processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .307
G.5.2 Derived events for IBS fetch data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .309
G.5.3 Derived Events for all Ops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .310
G.5.4 Derived events for IBS branch/return/resync ops . . . . . . . . . . . . . . . . . . . . .310
G.5.5 Derived events for IBS load/store operations . . . . . . . . . . . . . . . . . . . . . . . .311
G.6 Derived Events for Northbridge Activity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .312
Software Optimization Guide for AMD Family 10h Processors
Contents xi
Page 12
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
xii Contents
Page 13
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors

Figures

Figure 1. Memory-Limited Code ...................................................................................................87
Figure 2. Processor-Limited Code .................................................................................................88
Figure 3. Simple SMP Block Diagram.........................................................................................180
Figure 4. AMD Family 10h 2P System........................................................................................181
Figure 5. Dual Quad-Core AMD Family 10h Processor Configuration ......................................181
Figure 6. Block Diagram of a ccNUMA AMD Family 10h Quad-Core Multiprocessor
System...........................................................................................................................182
Figure 7. Internal Resources Associated with a Multiprocessor Node ........................................183
Figure 8. AMD Family 10h Processors Block Diagram ..............................................................218
Figure 9. Integer Execution Pipeline............................................................................................223
Figure 10. Floating-Point Unit .......................................................................................................225
Figure 11. Load-Store Unit ............................................................................................................226
Figure 12. Configuration Address Register (0CF8h) .....................................................................283
Figure 13. Configuration Data Register (0CFCh) ..........................................................................283
Figure 14. Link Type Registers F0x[F8, D8, B8, 98] ....................................................................286
Figure 15. MMIO Base Address Registers F1x(B8h, B0h, A8h, A0h, 98h, 90h, 88h, 80h) .........287
Figure 16. MMIO Limit Address Registers F1x[BC, B4, AC, A4, 9C, 94, 8C, 84]......................287
Figure 17. Configuration Map Registers F1x[E0h, E4h, E8h, ECh] .............................................289
Figure 18. Histogram for the IBS Fetch Completed Derived Event ..............................................307
Figures xiii
Page 14
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
xiv Figures
Page 15
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors

Tables

Table 1. Instructions, Macro-ops and Micro-ops ............................................................................5
Table 2. Optimizations by Rank......................................................................................................6
Table 3. Comparisons Against Zero..............................................................................................39
Table 4. Comparisons Against Positive Constant .........................................................................39
Table 5. Comparisons Among Two Floats....................................................................................39
Table 6. Prefetching Guidelines ....................................................................................................83
Table 7. DIV/IDIV Latencies......................................................................................................142
Table 8. Single-Precision Floating-Point Scalar Conversion......................................................164
Table 9. Double-Precision Floating-Point Scalar Conversion ....................................................165
Table 10. Write-Combining Completion Events...........................................................................232
Table 11. Latency Formats............................................................................................................239
Table 12. General Purpose and Integer Instruction Latencies ......................................................240
Table 13. System Instruction Latencies ........................................................................................250
Table 14. 128-Bit Media Instruction Latencies.............................................................................254
Table 15. 64-Bit Media Instruction Latencies...............................................................................269
Table 16. x87 Floating-Point Instruction Latencies......................................................................274
Table 17. Size of Base Address Register ......................................................................................289
Table 18. IBS Hardware Event Flags............................................................................................298
Table 19. Event Flag Combinations..............................................................................................299
Table 20. IbsOpData MSR Event Flags and Counts.....................................................................302
Table 21. Execution Status Indicated by IbsOpBrnMisp and IbsOpBrnTaken Flags...................302
Table 22. Execution Status Indicated by IbsOpReturn and IbsOpMispReturn Flags...................303
Table 23. IbsOpData3 Register Information.................................................................................304
Table 24. IbsOpData2 Register Fields ..........................................................................................305
Table 25. Northbridge Request Data Source Field .......................................................................306
Table 26. IBS Northbridge Event Data .........................................................................................306
Table 27. An IBS Fetch Sample....................................................................................................307
Table 28. 2-D Table of IBS Fetch Samples ..................................................................................307
Table 29. New Events Derived from Combined Event Flags.......................................................309
Table 30. Derived Events for All Ops...........................................................................................310
Table 31. Derived Events to Measure Branch, Return and Resync Ops.......................................310
Table 32. Derived Events for Ops That Perform Load and/or Store Operations ..........................311
Table 33. IBS Northbridge Derived Events ..................................................................................312
Tables xv
Page 16
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
xvi Tables
Page 17
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors

Revision History

Date Rev. Description
November 2008 3.09 Corrected the document title.
October 2008 3.08 Corrected assemby code examples in section 4.5, ’Take Advantage of x86 and
AMD64 Complex Addressing Modes’ on page 57.
Made minor clarifications in 4.10, ’Alternatives to SHLD Instruction’ on page 66.
Clarified latency information in 6.7, ’Avoiding the LOOP Instruction’ on page 106.
Corrected assembly language statements in 7.2, ’Loop Unrolling’ on page 110.
Clarified latency discrepancies between processor revisions in ’Changes in Latency’ on page 239.
April 2008 3.06 Revised section 4.13, on page ’Code Padding with Operand-Size Override and
Multibyte NOP’ on page 68.
Revised section 9.16, ’Floating-Point Scalar Conversions’ on page 166.
Revised the ‘Tag-to-retire Count’ and ’Completion-to-retire count’ on page 304. Clarified the use of the IbsDcStBnkCon and IbsDcLdBnkCon fields in IbsOpData3 register, clarified the description concerning data cache miss latency in ’Interpreting IBS Load/Store Data’ on page 305.
December 2007 3.05 Added Appendix E, ’NUMA Optimizations for I/O Devices’ on page 283. Added
Appendix F, ’Remarks on the RDTSC(P) Instruction’ on page 295
September 2007 3.04 Updated ’Memory and String Routines’ on page 92; updated ’Code Padding with
Operand-Size Override and Multibyte NOP’ on page 68; updated Appendix C, ’Instruction Latencies’ on page 237; Added Appendix G, ’Guide to Instruction­Based Sampling on AMD Family 10h Processors’ on page 297.
June 2007 3.03 Made several minor corrections.
May 2007 3.02 Corrected several AMD-V™ related typos.
May 2007 3.01 Corrected the specified value for the MXCSR misaligned exception mask bit.
April 2007 3.00 Initial release.
Revision History xvii
Page 18
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
xviii Revision History
Page 19
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors

Chapter 1 Introduction

This guide provides optimization information and recommendations for AMD Family 10h processors. These optimizations are designed to yield software code that is fast, compact, and efficient. Toward this end, the optimizations in each of the following chapters are listed in order of importance.
This chapter covers the following topics:
Topic Page
Intended Audience 1
Getting Started 1
Using This Guide 2
Important New Terms 4
Key Optimizations 6
What’s New on AMD Family 10h Processors 6

1.1 Intended Audience

This book is intended for compiler and assembler designers, as well as C, C++, and assembly­language programmers writing performance-sensitive code sequences. This guide assumes that you are familiar with the AMD64 instruction set and the AMD64 architecture (registers and programming modes). For complete information on the AMD64 architecture and instruction set, see the multivolume AMD64 Architecture Programmer’s Manual available from AMD.com. Individual volumes and their order numbers are provided below.
Title Order Number
Volume 1, Application Programming 24592
Volume 2, System Programming 24593
Volume 3, General-Purpose and System Instructions 24594
Volume 4, 128-Bit Media Instructions 26568
Volume 5, 64-Bit Media and x87 Floating-Point Instructions 26569
AMD64 Architecture Programmer’s Manual Documentation Updates 33633

1.2 Getting Started

More experienced readers may skip to “Key Optimizations” on page 6, which identifies the most important optimizations, and to “What’s New on AMD Family 10h Processors” on page 6 for a quick review of key new performance enhancement features introduced with AMD Family 10h processors.
Chapter 1 Introduction 1
Page 20
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008

1.3 Using This Guide

Each of the remaining chapters in this document focuses on a particular general area of relevance to software optimization on AMD Family 10h processors. Each chapter is organized into a set of one or more recommended related optimizations pertaining to a particular issue. These sections are divided into three sections:
• Optimization—Specifies the recommended action required for achieving the optimization under
consideration.
• Application—Specifies the type of software for which the particular optimization is relevant (i.e.,
to 32-bit software or 64-bit software or to both).
• Rationale—Provides additional explanatory technical information regarding the particular
optimization. This section usually provides illustrative C, C++, or assembly code examples as well.
The chapters that follow cover the following topics:
• Chapter 2, “C and C++ Source-Level Optimizations,” describes techniques that you can use to
optimize your C and C++ source code.
• Chapter 3, “General 64-Bit Optimizations,” presents general assembly-language optimizations
that can improve the performance of software designed to run in 64-bit mode. The optimizations in this chapter apply only to 64-bit software.
• Chapter 4, “Instruction-Decoding Optimizations,” discusses optimizations designed to maximize
the number of instructions that the processor can decode at one time.
• Chapter 5, “Cache and Memory Optimizations,” discusses how to take advantage of the large L1
caches and high-bandwidth buses.
• Chapter 6, “Branch Optimizations,” discusses improving branch prediction and minimizing
branch penalties.
• Chapter 7, “Scheduling Optimizations.” discusses improving instruction scheduling in the
processor.
• Chapter 8, “Integer Optimizations,” discusses integer performance.
• Chapter 9, “Optimizing with SIMD Instructions,” discusses the 64-bit and 128-bit SIMD
instructions (SSE, SSE2, SSE3, SSE4a) used to encode floating-point and integer operations.
• Chapter 10, “x87 Floating-Point Optimizations,” discusses optimizations using the x87 assembly
instructions.
• Chapter 11, “Multiprocessor Considerations,” discusses processor/core selection and related
issues for applications running on multiprocessor/multicore cache coherent non-uniform memory access (ccNUMA) configurations.
• Chapter 12, “Optimizing Secure Systems,” discusses ways to minimize the performance overhead
imposed by the virtualization of a guest.
2 Introduction Chapter 1
Page 21
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
• Appendix A, “Microarchitecture of AMD Family 10h Processors,” discusses the internal design,
or microarchitecture, of the AMD Family 10h processor and provides information about translation-lookaside buffers and other functional units that, while not part of the main processor, are integrated on the chip.
• Appendix B, “Implementation of Write-Combining,” describes how AMD Family 10h processors
perform memory write-combining.
• Appendix C, “Instruction Latencies,” provides a complete listing of all AMD64 instructions with
each instruction’s decode type, execution latency, and—where applicable—the pipes and throughput used in the floating-point unit.
• Appendix D, “Tools and APIs for AMD Family 10h ccNUMA Multiprocessor Systems” provides
information on tools for programming in NUMA environments.
• Appendix E, “NUMA Optimizations for I/O Devices” provides information on the association of
particular I/O devices with a specific nodes in a NUMA system.
• Appendix F, “Remarks on the RDTSC(P) Instruction” provides information on using the RDTSC
and RDTSCP instructions to load the value of the time stamp counter (TSC).
• Appendix G, “Guide to Instruction-Based Sampling on AMD Family 10h Processors” describes
the use of intruction-based sampling to monitor software performance.
1.3.1 Special Information
Special information in this guide is marked as follows:
This symbol appears next to the most important, or key, optimizations.
1.3.2 Numbering Systems
The following suffixes identify different numbering systems:
This suffix Identifies a
b Binary number. For example, the binary equivalent of the number 5 is written 101b.
d Decimal number. Decimal numbers are followed by this suffix only when the possibility of
confusion exists. In general, decimal numbers are shown without a suffix.
h Hexadecimal number. For example, the hexadecimal equivalent of the number 60 is
written 3Ch.
Chapter 1 Introduction 3
Page 22
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
1.3.3 Typographic Notation
This guide uses the following typographic notations for certain types of information:
This type of text Identifies
italic Placeholders that represent information you must provide. Italicized text is also used
for the titles of publications and for emphasis.
monowidth Program statements and function names.

1.4 Important New Terms

This section defines several important terms and concepts used in this guide.
1.4.1 Multi-Core Processors
The AMD Family 10h family of processors have multiple cores. A multi-core processor contains two to four identical cores that share the processor’s L3 cache and Northbridge (see Appendix A). Within a processor, each core can simultaneously run independent threads.
1.4.2 Primitive Operations
AMD Family 10h processors perform four types of primitive operations:
• Integer (arithmetic or logic)
• Floating-point (arithmetic)
• Load
• Store
1.4.3 Internal Instruction Formats
The AMD64 instruction set is complex. Instructions have variable-length encoding and many perform multiple primitive operations. AMD directly, but, instead, decode them internally into simpler fixed-length instructions called macro-ops. Processor schedulers subsequently break down macro-ops into sequences of even simpler instructions called micro-ops, each of which specifies a single primitive operation.
A macro-op is a fixed-length instruction that:
• Expresses, at most, one integer or floating-point operation and one load and/or store operation.
• Is the primary unit of work managed (that is, dispatched and retired) by the processor.
Family 10h processors do not execute these complex instructions
A micro-op is a fixed-length instruction that:
• Expresses one and only one of the primitive operations that the processor can perform (for
example, a load).
4 Introduction Chapter 1
Page 23
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
• Is executed by the processor’s execution units.
Table 1 on page 5 summarizes the differences between AMD64 instructions, macro-ops, and micro­ops.
Table 1. Instructions, Macro-ops and Micro-ops
Comparing AMD64 instructions Macro-ops Micro-ops
Complexity Complex
A single instruction may specify one or more of each of the following operations:
• Integer or floating-point
• Load
•Store
Encoded length Variable (instructions are
different lengths)
Regularized instruction fields
No (field locations and definitions vary among instructions)
Average
A single macro-op may specify—at most—one integer or floating-point operation and one of the following operations:
• Load
•Store
• Load and store to the same address
Fixed (all macro-ops are the same length)
Yes (field locations and definitions are the same for all macro-ops)
Simple
A single micro-op specifies only one of the following primitive operations:
• Integer or floating-point
• Load
•Store
Fixed (all micro-ops are the same length)
Yes (field locations and definitions are the same for all micro-ops)
1.4.4 Types of Instructions
Instructions are classified according to how they are decoded by the processor. There are three types of instructions:
Instruction Type Description
DirectPath Single Decodes directly into one macro-op in microprocessor hardware.
DirectPath Double Decodes directly into two macro-ops in microprocessor hardware.
VectorPath Decodes into one or more (usually three or more) macro-ops using the on-chip
microcode-engine ROM (MROM).
Chapter 1 Introduction 5
Page 24
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008

1.5 Key Optimizations

While all of the optimizations in this guide help improve software performance, some of them have more impact than others. Optimizations that offer the most improvement are called key optimizations.
This symbol appears next to the most important (key) optimizations.
1.5.1 Implementation Guideline
Concentrate your efforts on implementing key optimizations before moving on to other optimizations.
Table 2 lists the key optimizations. These optimizations are discussed in detail in later sections of this book.
Table 2. Optimizations by Rank
Rank Optimization
1 Load-Execute Instructions for Floating-Point or Integer Operands (See
section 4.2 on page 53.)
2 Write-Combining (See section 5.6 on page 89.)
3 Branches That Depend on Random Data (See section 6.3 on page 101.)
4 Loop Unrolling (See section 7.2 on page 110.)
5 Pointer Arithmetic in Loops (See section 7.6 on page 116.)
6 Explicit Load Instructions (See section 9.2 on page 146.)
7 Reuse of Dead Registers (See section 9.15 on page 165.)
8 ccNUMA Optimizations (See section 11.1 on page 179.)
9 Multithreading (See section 11.3 on page 190.)
10 Prefetch and Streaming Instructions (See section 5.5 on page 81.)
11 Memory and String Routines (See section 5.9 on page 92.)
12 Loop Iteration Boundaries (See section 4.3 on page 56.)
13 Floating-Point Scalar Conversions (See sections 9.16 on page 166.)

1.6 What’s New on AMD Family 10h Processors

AMD Family 10h processors introduce several new features that can significantly enhance software performance when compared to the previous AMD64 microprocessors. The following section provides compiler/assembler designers and C/C++/assembly language programmers with a summary of these performance improvements. Throughout this discussion, it is assumed that readers are familiar with the software optimization guide for the previous AMD64 processors and the terminology used there.
6 Introduction Chapter 1
Page 25
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
1.6.1 AMD Instruction Set Enhancements
The AMD Family 10h processor has been enhanced with the following new instructions:
• LZCNT, POPCNT—Advanced Bit Manipulation (ABM) instructions operate on general purpose registers.
• MOVNTSS, MOVNTSD, EXTRQ, INSERTQ—SSE4a instructions operate on XMM registers.
Support for these instructions is implementation dependent. See the CPUID Specification, order# 25481, and the AMD64 Architecture Programmer’s Manual Updates Application Note, order# 33633, for additional information.
1.6.2 Floating-Point Improvements
Previous AMD64 processors supported 64-bit floating-point execution units. The new AMD Family 10h processors add support for 128-bit floating-point execution units. As a result, the throughput of both single-precision and double-precision floating-point SSEx vector operations has improved by 2X over the previous generation of AMD processors.
Performance Guidelines for Vectorized Floating-Point SSEx Code
While 128-bit floating-point execution units imply better performance for vectorized floating-point SSEx code, it is necessary to adhere to several performance guidelines to realize their full potential:
• Avoid writing less than 128 bits of an XMM register when using certain initializing and non­initializing operations.
A floating-point XMM register is viewed as one 128-bit register internally by the processor. Writing to a 64-bit half of a 128-bit XMM register results in a merge dependency on the other 64­bit half. Therefore the following replacements are advised on AMD Family 10h processors:
– Replace MOVLPX/MOVHPX reg, mem pairs with MOVUPX reg, mem, irrespective of the
alignment of the data. On AMD
Family 10h processors, the MOVUPX instruction is just as efficient as MOVAPX for when data is aligned. Hence it is advised to use MOVUPX regardless of the alignment.
– Replace MOVLPD reg, mem with MOVSD reg, mem.
– Replace MOVSD reg, reg with MOVAPD reg, reg.
However, there are also several instructions that initialize the lower 64 or 32 bits of an XMM register and zero out the upper 64 or 96 bits and, thus, do not suffer from such merge dependencies. Consider, for example, the following instructions:
MOVSD xmm, [mem64] MOVSS xmm, [mem32]
When writing to a register during the course of a non-initializing operation on the register, there is usually no additional performance loss due to partial register reads and writes. This is because in
Chapter 1 Introduction 7
Page 26
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
the typical case, the partial register that is being written is also a source to the operation. For example, addsd xmm1, xmm2 does not suffer from merge dependencies.
There are often cases of non-initializing operations on a register, in which the partial register being written by the operation is not a source for the operation. In these cases also, it is preferable to avoid partial register writes. If it is not possible to avoid writing to a part of that register, then you should schedule any prior operation on any part of that register well ahead of the point where the partial write occurs.
Examples of non-initializing instructions that result in merge dependencies are SQRTSD, CVTPI2PS, CVTSI2SD, CVTSS2SD, MOVLHPS, MOVHLPS, UNPCKLPD and PUNPCKLQDQ.
For additional details on this optimization see “Partial-Register Writes” on page 60, “Explicit Load Instructions” on page 146, “Unaligned and Aligned Data Access” on page 147, and “Reuse of Dead Registers” on page 165.
• In the event of a load following a previous store to a given address for aligned floating-point vector data, use 128-bit stores and 128-bit loads instead of MOVLPX/MOVHPX pairs for storing and loading the data. This allows store-to-load forwarding to occur. Using MOVLPX/MOVHPX pairs is still recommended for storing unaligned floating-point vector data. Additional details on these restrictions can be obtained in “Store-to-Load Forwarding Restrictions” on page 74.
• To make use of the doubled throughput of both single-precision and double-precision floating­point SSEx vector operations, a compiler or an application developer can consider either increasing the unrolling factor of loops that include such vector operations and/or performing other code transformations to keep the floating-point pipeline fully utilized.
1.6.3 Load-Execute Instructions for Unaligned Data
Use load-execute instructions instead of discrete load and execute instructions when performing SSE floating-point/SSE integer/x87 computations on floating-point source operands. This is recommended regardless of the alignment of packed data on AMD
Family 10h processors. (The use of load-execute instructions under these circumstances was only recommended for aligned packed data on the previous AMD64 processors.) This replacement is only possible if the misaligned exception mask (MM) is set. See the AMD CPUID Specification, order# 25481, and the AMD64 Architecture Programmer’s Manual Updates Application Note, order# 33633,for additional information on SSE misaligned access support. This optimization can be especially useful in vectorized SSEx loops and may eliminate the need for loop peeling due to nonalignment. (See “Load­Execute Instructions for Floating-Point or Integer Operands” on page 53.)
1.6.4 Instruction Fetching Improvements
The fetch window has changed from 16 bytes on previous AMD64 processors to 32 bytes on AMD Family 10h processors. The 32-byte fetch, when combined with the 128-bit floating-point execution unit, allows the processor to sustain a fetch/dispatch/retire sequence of three large instructions per cycle.
8 Introduction Chapter 1
Page 27
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
Assembly language programmers can now group large instructions together without worrying about an instruction possibly spanning the fetch window. In this regard, it is also advisable to align hot loops to 32 bytes instead of 16 bytes, especially in the case of loops for large SSE instructions.
For additional details, readers can refer to “Loop Iteration Boundaries” on page 56.
1.6.5 Instruction Decode and Floating-Point Pipe Improvements
Several integer and floating-point instructions have improved latencies and decode types on AMD Family 10h processors. Furthermore, the FPU pipes utilized by several floating-point instructions have changed. These changes can influence instruction choice and scheduling for compilers and hand-written assembly code. A comprehensive listing of all AMD64 instructions with their decode types, decode type changes from previous families of AMD processors, and execution latencies and FPU pipe utilization data are available in Appendix C.
1.6.6 Notable Performance Improvements
Several enhancements to the AMD64 architecture have resulted in significant performance improvements in AMD Family 10h processors, including:
• Improved performance of shuffle instructions
• Improved data transfer between floating-point registers and general purpose registers
• Improved floating-point register to floating-point register moves
• Optimization of repeated move instructions
• More efficient PUSH/POP stack operations
• 1-Gbyte paging
These are discussed in the following paragraphs and elsewhere in this document.
Improved Bandwidth Decode Type for Shuffle Instructions
The floating-point logic in AMD Family 10h processors uses three separate execution positions or pipes called FADD, FMUL and FSTORE. This is illustrated in
Figure 8 on page 222 in Appendix A. Current AMD Family 10h processors support two SSE logical/shuffle units, one in the FMUL pipe and another in the FADD pipe, while previous AMD64 processors have only one SSE logical/shuffle unit in the FMUL pipe. As a result, the SSE/SSE2 shuffle instructions can be processed at twice the previous bandwidth on AMD Family 10h processors. Furthermore, the PSHUFD and SHUFPx shuffle instructions are now DirectPath instructions instead of VectorPath instructions on AMD
Family 10h processors and take advantage of the 128-bit floating point execution units. Hence, these instructions get a further 2X boost in bandwidth, resulting in an overall improvement of 4X in bandwidth compared to the previous generation of AMD processors.
It’s more efficient to use SHUFPx and PSHUFD instructions over combinations of more than one MOVLHPS/MOVHLPS/UNPCKx/PUNPCKx instructions to do shuffle operations.
Chapter 1 Introduction 9
Page 28
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
Data Transfer Between Floating-Point Registers and General Purpose Integer Registers
We recommend using the MOVD instruction when moving data from an MMX™ or XMM register to a GPR. However, when moving data from a GPR to an MMX or XMM floating-point register, it is advisable to use separate store and load instructions to move the data from the source register to a temporary location in memory and then from memory into the destination register, taking the memory latency into account when scheduling them.
The performance of the CVTSS2SI, CVTTSS2SI, CVTSD2SI, CVTTSD2SI instructions that are used to convert floating-point data to integer data has improved. For additional details see “Floating­Point-to-Integer Conversion” on page 165.
Floating-Point Register-to-Register Moves
On previous AMD processors, floating-point register-to-register moves could only go through the FADD and FMUL pipes. On AMD Family 10h processors, floating-point register-to-register moves can also go through the FSTORE pipe, thereby improving overall throughput.
Repeated String Instructions
REP instructions have been optimized on AMD Family 10h processors. See “Repeated String Instructions” on page 126 for details on how to take advantage of these optimizations.
Faster PUSH/POP with the Sideband Stack Optimizer
AMD Family 10h processors have added a sideband stack optimizer (SSO). This special circuitry removes the dependency that arises during chains of PUSH and POP operations on the rSP register and, thereby, improves the efficiency of the PUSH and POP instructions.
The SSO also improves the performance of CALL and RET instructions, among others. (See “Stack Operations” on page 59.)
10 Introduction Chapter 1
Page 29
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
1.6.7 Large Page Support
AMD Family 10h processors now have better large page support, having incorporated new 1GB paging and 2MB and 4KB paging improvements.
The L1 data TLB and L2 data TLB now support 1GB pages, a benefit to applications making large data-set random accesses.
The L1 instruction TLB, L1 data TLB and L2 data TLB have increased the number of entries for 2MB pages. This improves the performance of software that uses 2MB code or data or code mixed with data virtual pages.
The L1 data TLB has also increased the number of entries for 4KB pages.
For additional details on the actual number of TLB entries, see section A.10, “Translation-Lookaside Buffer” on page 225.
For more information on 1-Gbyte pages see “Using 1-Gbyte Virtual Memory Pages” on page 96.
1.6.8 AMD Virtualization™ Optimizations
Chapter 12, “Optimizing Secure Virtual Machines” covers optimizations that minimize the performance overhead imposed by the virtualization of a guest in AMD Virtualization™ technology (AMD-V™). Topics include:
• The advantages of using nested paging instead of shadow paging
• Guest page attribute table (PAT) configuration
• State swapping
• Economizing Interceptions
• Nested page and shadow page size
• TLB control and flushing in shadow pages
• Instruction Fetch for Intercepted (REP) INS instructions
• Sharing IOIO and MSR protection masks
•CPUID
• Time resources
• Paravirtualized resources
Chapter 1 Introduction 11
Page 30
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
12 Introduction Chapter 1
Page 31
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
Chapter 2 C and C++ Source-Level
Optimizations
Although C and C++ compilers can often produce very efficient object code from naive source code, careful attention to coding details can lead to even better object code and therefore to improved performance. Many optimizations take advantage of the underlying mechanisms used by C and C++ compilers to translate source code into sequences of AMD64 instructions. This chapter includes guidelines for writing C and C++ source code that yields an approximation to the most highly efficient optimization.
This chapter covers the following topics:
Topic Page
Declarations of Floating-Point Values 14
Using Arrays and Pointers 14
Unrolling Small Loops 17
Arrange Boolean Operands for Quick Expression Evaluation 18
Expression Order in Compound Branch Conditions 19
Long Logical Expressions in If Statements 20
Dynamic Memory Allocation Consideration 21
Unnecessary Store-to-Load Dependencies 21
Matching Store and Load Size 23
Use of Function Prototypes 25
Use of const Type Qualifier 26
Generic Loop Hoisting 26
Local Static Functions 28
Explicit Parallelism in Code 29
Extracting Common Subexpressions 30
Sorting and Padding C and C++ Structures 31
Replacing Integer Division with Multiplication 32
Frequently Dereferenced Pointer Arguments 33
32-Bit Integral Data Types 34
Sign of Integer Operands 35
Accelerating Floating-Point Division and Square Root 36
Speeding Up Branches Based on Comparisons Between Floats 38
Improving Performance in Linux
Aligning Matrices 41
®
Libraries
40
Chapter 2 C and C++ Source-Level Optimizations 13
Page 32
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008

2.1 Declarations of Floating-Point Values

Optimization
When working with single precision (float) values:
• Use the f or F suffix (for example, 3.14f) to specify a constant value of type float.
• Use function prototypes for all functions that accept arguments of type float.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
C and C++ compilers treat floating-point constants and arguments as double precision (double) unless you specify otherwise. However, single precision floating-point values occupy half the memory space as double precision values and can often provide the precision necessary for a given computational problem.
This optimization also results in more efficient use of the XMM Streaming SIMD registers: four single precision values can be packed into a single XMM register, compared to two double precision values.

2.2 Using Arrays and Pointers

Optimization
Use array notation instead of pointer notation when working with arrays.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
C allows the use of either the array operator ([]) or pointers to access the elements of an array. However, the use of pointers in C makes work difficult for optimizers in C compilers. Without
14 C and C++ Source-Level Optimizations Chapter 2
Page 33
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
detailed and aggressive pointer analysis, the compiler has to assume that writes through a pointer can write to any location in memory, including storage allocated to other variables. (For example, *p and
*q can refer to the same memory location, while x[0] and x[2] cannot.) Pointers make it difficult for
compilers to detect the presence or absence of aliasing—with possible ambiguous access to a block of memory. The compiler sometimes must assume aliasing in the presence of pointers, which limits the opportunities for optimization. Array notation makes the task of the optimizer easier by reducing possible aliasing.
Example
Avoid code, such as the following, which uses pointer notation:
typedef struct { float x, y, z, w; } VERTEX;
typedef struct { float m[4][4]; } MATRIX;
void XForm(float *res, const float *v, const float *m, int numverts) {
float dp; int i; const VERTEX* vv = (VERTEX *)v;
for (i = 0; i < numverts; i++) { dp = vv->x * *m++; dp += vv->y * *m++; dp += vv->z * *m++; dp += vv->w * *m++;
*res++ = dp; // Write transformed x.
dp = vv->x * *m++; dp += vv->y * *m++; dp += vv->z * *m++; dp += vv->w * *m++;
*res++ = dp; // Write transformed y.
dp = vv->x * *m++; dp += vv->y * *m++; dp += vv->z * *m++; dp += vv->w * *m++;
*res++ = dp; // Write transformed z.
dp = vv->x * *m++; dp += vv->y * *m++; dp += vv->z * *m++; dp += vv->w * *m++;
Chapter 2 C and C++ Source-Level Optimizations 15
Page 34
Software Optimization Guide for AMD Family 10h Processors
*res++ = dp; // Write transformed w.
++vv; // Next input vertex m -= 16; // Reset to start of transform matrix. } }
40546 Rev. 3.09 November 2008
Instead, use the equivalent array notation:
typedef struct { float x, y, z, w; } VERTEX;
typedef struct { float m[4][4]; } MATRIX;
void XForm(float *res, const float *v, const float *m, int numverts) { int i; const VERTEX* vv = (VERTEX *)v; const MATRIX* mm = (MATRIX *)m; VERTEX* rr = (VERTEX *)res; for (i = 0; i < numverts; i++) { rr[i].x = vv[i].x * mm->m[0][0] + vv[i].y * mm->m[0][1] + vv[i].z * mm->m[0][2] + vv[i].w * mm->m[0][3]; rr[i].y = vv[i].x * mm->m[1][0] + vv[i].y * mm->m[1][1] + vv[i].z * mm->m[1][2] + vv[i].w * mm->m[1][3]; rr[i].z = vv[i].x * mm->m[2][0] + vv[i].y * mm->m[2][1] + vv[i].z * mm->m[2][2] + vv[i].w * mm->m[2][3]; rr[i].w = vv[i].x * mm->m[3][0] + vv[i].y * mm->m[3][1] + vv[i].z * mm->m[3][2] + vv[i].w * mm->m[3][3]; } }
Additional Considerations
Source-code transformations interact with a compiler’s code generator, making it difficult to control the generated machine code from the source level. It is even possible that source-code transformations aimed at improving performance may conflict with compiler optimizations. Depending on the compiler and the specific source code, it is possible for pointer-style code to compile into machine code that is faster than that generated from equivalent array-style code. Compare the performance of your code after implementing a source-code transformation with the performance of the original code to be sure that there is an improvement.
Some compilers provide proprietary declaration keywords that further allow the compiler to reduce possible aliasing. See Compiler Usage Guidelines for 64-Bit Operating Systems on AMD64 Platforms Application Note, order# 32035, for details.
16 C and C++ Source-Level Optimizations Chapter 2
Page 35
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors

2.3 Unrolling Small Loops

Optimization
Completely unroll loops that have a small fixed loop count and a small loop body.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
Many compilers do not aggressively unroll loops. Manually unrolling loops can benefit performance, especially if the loop body is small, making the loop overhead significant.
Unrolling loops increases the code size, which may decrease performance in rare cases.
Example
Avoid a small loop like this:
// 3D-transform: Multiply vector V by 4x4 transform matrix M. for (i = 0; i < 4; i++) { r[i] = 0; for (j = 0; j < 4; j++) { r[i] += m[j][i] * v[j]; } }
Instead, replace it with its completely unrolled equivalent, as shown here:
r[0] = m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2] + m[3][0] * v[3]; r[1] = m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2] + m[3][1] * v[3]; r[2] = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2] * v[3]; r[3] = m[0][3] * v[0] + m[1][3] * v[1] + m[2][3] * v[2] + m[3][3] * v[3];
Related Information
For information on loop unrolling at the assembly-language level, see “Loop Unrolling” on page 110.
Chapter 2 C and C++ Source-Level Optimizations 17
Page 36
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
2.4 Arrange Boolean Operands for Quick Expression
Evaluation
Optimization
In expressions that use the logical AND (&&) or logical OR (||) operator, arrange the operands for quick evaluation of the expression:
If the expression uses this operator
&& (logical AND) False || (logical OR) True
Then arrange the operands from left to right in decreasing probability of being
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
C and C++ compilers guarantee short-circuit evaluation of the boolean operators && and ||. In an expression that uses &&, the first operand to evaluate to false terminates the evaluation; subsequent operands are not evaluated. In an expression that uses ||, the first operand to evaluate to true terminates the evaluation.
When used to control program flow, expressions involving && and || are translated into a series of conditional branches. This optimization minimizes the total number of conditions evaluated and branches executed.
Example 1
In the following code, the operands of && are not arranged for quick expression evaluation because the first operand is not the condition case most likely to be false (it is far less likely for an animal name to begin with a ‘y’ than for it to have fewer than four characters):
char animalname[30]; char *p;
p = animalname;
if ((strlen(p) > 4) && (*p == 'y')) { ... }
Because the odds that the animal name begins with a ‘y’ are comparatively low, it is better to put that operand first:
18 C and C++ Source-Level Optimizations Chapter 2
Page 37
40546 Rev. 3.09 November 2008
if ((*p == 'y') && (strlen(p) > 4)) { ... }
Software Optimization Guide for AMD Family 10h Processors
Example 2
In the following code (assuming a uniform random distribution of i), the operands of || are not arranged for quick expression evaluation because the first operand is not the condition most likely to be true:
unsigned int i;
if ((i < 4) || (i & 1)) { ... }
Because it is more likely for the least-significant bit of i to be 1, it is better to put that operand first:
if ((i & 1) || (i < 4)) { ... }
2.5 Expression Order in Compound Branch
Conditions
Optimization
In the most active areas of a program, order the expressions in compound branch conditions to take advantage of short circuiting of compound conditional expressions.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
Branch conditions in C programs often consist of compound conditions consisting of multiple boolean expressions joined by the logical AND (&&) or logical OR (||) operators. C compilers guarantee short-circuit evaluation of these operators. In a compound logical OR expression, the first operand to evaluate to true terminates the evaluation, and subsequent operands are not evaluated at all. Similarly, in a logical AND expression, the first operand to evaluate to false terminates the evaluation. Hence, it is not always possible to swap the operands of logical OR and logical AND. This is especially true when the evaluation of one of the operands causes a side effect. In most cases the order of operands in such expressions is irrelevant.
When used to control conditional branches, expressions involving logical OR or logical AND are translated into a series of conditional branches. The ordering of the conditional branches is a function of the ordering of the expressions in the compound condition and can have a significant impact on
Chapter 2 C and C++ Source-Level Optimizations 19
Page 38
Software Optimization Guide for AMD Family 10h Processors
performance. It is impossible to give an easy, closed-form formula on how to order the conditions. Overall performance is a function of the following factors:
• Probability of a branch misprediction for each of the branches generated
• Additional latency incurred due to a branch misprediction
• Cost of evaluating the conditions controlling each of the branches generated
• Amount of parallelism that can be extracted in evaluating the branch conditions
• Data stream consumed by an application (mostly due to the dependence of misprediction
probabilities on the nature of the incoming data in data-dependent branches)
It is recommended to experiment with the ordering of expressions in compound branch conditions in the most active areas of a program (“hot spots,” consuming a great amount of execution time). Such hot spots can be found through the use of profiling by feeding a typical data stream to the program while doing the experiments.
40546 Rev. 3.09 November 2008

2.6 Long Logical Expressions in If Statements

Optimization
In if statements, avoid long logical expressions that can generate dense conditional branches that violate the guideline described in “Branch Alignment and Density” on page 99. When long logical expressions are unavoidable, try to arrange them so that most of the implicit branches are not be taken.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
High branch density can lead to some branches not being identified by the branch predictor (as described in section “Branch Alignment and Density” on page 99). If these unpredicted branches are not taken, they will not cause a misprediction penalty.
Preferred for Data that Falls Mostly Within the Range
if (a <= max && a >= min && b <= max && b >= min)
If most of the data falls within the range, the branches will not be taken, so the above code is preferred. Otherwise, the following code is preferred.
20 C and C++ Source-Level Optimizations Chapter 2
Page 39
40546 Rev. 3.09 November 2008
Preferred for Data that Does Not Fall Mostly Within the Range
if (a > max || a < min || b > max || b < min)
Software Optimization Guide for AMD Family 10h Processors

2.7 Dynamic Memory Allocation Consideration

Optimization
Where this aligned pointer cannot be guaranteed, use the technique shown in the following code to make the pointer 16-byte aligned, if needed.
Application
This optimization applies to:
• 32-bit software
Examples
Dynamic memory allocation—accomplished through the use of the malloc library function in C— should always return a pointer that is suitably aligned for the largest base type (16-byte alignment). However, this may not always be the case. In this example, after memory allocation, use np instead of
p to access the data. The pointer p is still needed in order to deallocate the storage later.
double *p; double *np;
p = (double *)malloc(sizeof(double) * number_of_doubles + 15); np = (double *)((((ptrdiff_t)(p)) + 15L) & (-16L));

2.8 Unnecessary Store-to-Load Dependencies

Optimization
Avoid store-to-load dependencies.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
A store-to-load dependency exists when data is stored to memory, only to be read back shortly thereafter. For details, see
Chapter 2 C and C++ Source-Level Optimizations 21
“Store-to-Load Forwarding Restrictions” on page 74. The
Page 40
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
AMD Family 10h processor contains hardware to accelerate such store-to-load dependencies, allowing the load to obtain the store data before it has been written to memory. However, avoiding such dependencies and keeping the data in an internal register results in faster code.
It is especially important to avoid store-to-load dependencies if they are part of a long dependency chain, as may occur in a recurrence computation. If the dependency occurs while operating on arrays, many compilers are unable to optimize the code in a way that avoids the store-to-load dependency. In some instances the language definition may prohibit the compiler from using code transformations that would remove the store-to-load dependency. Therefore, it is recommended that the programmer remove the dependency manually, for example, by introducing a temporary variable that can be kept in a register. This can result in a significant performance increase.
Examples
Avoid
double x[VECLEN], y[VECLEN], z[VECLEN]; unsigned int k;
for (k = 1; k < VECLEN; k++) { x[k] = x[k-1] + y[k]; }
for (k = 1; k < VECLEN; k++) { x[k] = z[k] * (y[k] - x[k-1]); }
Preferred
double x[VECLEN], y[VECLEN], z[VECLEN]; unsigned int k; double t;
t = x[0]; for (k = 1; k < VECLEN; k++) { t = t + y[k]; x[k] = t; }
t = x[0]; for (k = 1; k < VECLEN; k++) { t = z[k] * (y[k] - t); x[k] = t; }
22 C and C++ Source-Level Optimizations Chapter 2
Page 41
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors

2.9 Matching Store and Load Size

Optimization
Align memory accesses and match addresses and sizes of stores and dependent loads.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
The AMD Family 10h processor contains a load-store buffer to speed up the forwarding of store data to dependent loads. However, this store-to-load forwarding (STLF) inside the load-store buffer occurs, in general, only when the addresses and sizes of the store and the dependent load match, and when both memory accesses are aligned. For details, see “Store-to-Load Forwarding Restrictions” on page 74.
It is impossible to control load and store activity at the source level in such a way as to avoid all cases that violate restrictions placed on store-to-load-forwarding. In some instances it is possible to spot such cases in the source code. Size mismatches can easily occur when different-size data items are joined in a union. Address mismatches could be the result of pointer manipulation.
The following examples show a situation involving a union of different-size data items. The examples show a user-defined unsigned 16.16 fixed-point type and two operations defined on this type. Function fixed_add adds two fixed-point numbers, and function fixed_int extracts the integer portion of a fixed-point number.
Listing shows an inappropriate implementation of fixed_int, which, when used on the result of fixed_add, causes misalignment, address mismatch, or size mismatch between memory operands, such that no store-to-load forwarding in the load-store buffer takes place. The following examples shows how to properly implement
fixed_int in order to allow
store-to-load forwarding in the load-store buffer.
Examples
Avoid
typedef union { unsigned int whole; struct { unsigned short frac; /* Lower 16 bits are fraction. */ unsigned short intg; /* Upper 16 bits are integer. */ } parts; } FIXED_U_16_16;
Chapter 2 C and C++ Source-Level Optimizations 23
Page 42
Software Optimization Guide for AMD Family 10h Processors
__inline FIXED_U_16_16 fixed_add(FIXED_U_16_16 x, FIXED_U_16_16 y) { FIXED_U_16_16 z; z.whole = x.whole + y.whole; return (z); }
__inline unsigned int fixed_int(FIXED_U_16_16 x) { return((unsigned int)(x.parts.intg)); } ... FIXED_U_16_16 y, z; unsigned int q; ... label1: y = fixed_add (y, z); q = fixed_int (y);
label2: ...
40546 Rev. 3.09 November 2008
The object code generated for the source code between label1 and label2 typically follows one of these two variants:
; Variant 1 mov edx, DWORD PTR [z] mov eax, DWORD PTR [y] ; -+ add eax, edx ; | mov DWORD PTR [y], eax ; | mov EAX, DWORD PTR [y+2] ; <+ Address mismatch--no forwarding in LSU and EAX, 0FFFFh mov DWORD PTR [q], eax
; Variant 2 mov edx, DWORD PTR [z] mov eax, DWORD PTR [y] ; -+ add eax, edx ; | mov DWORD PTR [y], eax ; | movzx eax, WORD PTR [y+2] ; <+ Size and address mismatch--no forwarding in LSU mov DWORD PTR [q], eax
Some more sophisticated compilers may generate optimal machine code even for the previous example. These compilers provide various optional levels and types of optimizations that are controlled by compiler program flags. When compiled at a moderate level of optimization, such compilers may generate perfectly acceptable code from C++ code such as that listed above. For more information, see Compiler Usage Guidelines for 64-Bit Operating Systems on AMD64 Platforms
Application Note, order# 32035.
Preferred
typedef union { unsigned int whole; struct { unsigned short frac; /* Lower 16 bits are fraction. */ unsigned short intg; /* Upper 16 bits are integer. */
24 C and C++ Source-Level Optimizations Chapter 2
Page 43
40546 Rev. 3.09 November 2008
} parts; } FIXED_U_16_16;
__inline FIXED_U_16_16 fixed_add(FIXED_U_16_16 x, FIXED_U_16_16 y) { FIXED_U_16_16 z; z.whole = x.whole + y.whole; return(z); }
__inline unsigned int fixed_int(FIXED_U_16_16 x) { return (x.whole >> 16); } ... FIXED_U_16_16 y, z; unsigned int q; ... label1: y = fixed_add (y, z); q = fixed_int (y);
label2: ...
Software Optimization Guide for AMD Family 10h Processors
The object code generated for the source code between label1 and label2 typically looks like this:
mov edx, DWORD PTR [z] mov eax, DWORD PTR [y] add eax, edx mov DWORD PTR [y], eax ; -+ mov eax, DWORD PTR [y] ; <+ Aligned (size/address match)--forwarding in LSU shr eax, 16 mov DWORD PTR [q], eax

2.10 Use of Function Prototypes

Optimization
In general, use prototypes for all functions.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
Prototypes can convey additional information to the compiler that might enable more aggressive optimizations.
Chapter 2 C and C++ Source-Level Optimizations 25
Page 44
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008

2.11 Use of const Type Qualifier

Optimization
For objects whose values will not be changed, use the const type qualifier.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
Using the const type qualifier makes code more robust and may enable the compiler to generate higher-performance code. For example, under the C standard, a compiler is not required to allocate storage for an object that is declared const, if its address is never used.

2.12 Generic Loop Hoisting

Optimization
To improve the performance of inner loops, reduce redundant constant calculations (that is, loop­invariant calculations). This idea can also be extended to invariant control structures.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale and Examples
The following example demonstrates the use of an invariant condition in an if statement in a for loop. The second listing shows the preferred optimization.
Avoid
for (i...) { if (CONSTANT0) { DoWork0(i); // Does not affect CONSTANT0. } else {
26 C and C++ Source-Level Optimizations Chapter 2
Page 45
40546 Rev. 3.09 November 2008
DoWork1(i); // Does not affect CONSTANT0. } }
Software Optimization Guide for AMD Family 10h Processors
Preferred
if (CONSTANT0) { for (i...) { DoWork0(i); } } else { for (i...) { DoWork1(i); } }
The preferred optimization in the preceding example tightens the inner loops by avoiding repetitious evaluation of a known if control structure. Although the branch would be easily predicted, the extra instructions and decode limitations imposed by branching are eliminated.
To generalize the preceding example further for multiple-constant control code, more work may be needed to create the proper outer loop. Enumeration of the constant cases reduces this to a simple
switch statement.
Avoid
for (i...) { if (CONSTANT0) { DoWork0(i); // Does not affect CONSTANT0 or CONSTANT1. } else { DoWork1(i); // Does not affect CONSTANT0 or CONSTANT1. }
if (CONSTANT1) { DoWork2(i); // Does not affect CONSTANT0 or CONSTANT1. } else { DoWork3(i); // Does not affect CONSTANT0 or CONSTANT1. } }
Transform the loop in the preceding example (by using the switch statement) into:
Preferred
#define combine(c1, c2) (((c1) << 1) + (c2)) switch (combine(CONSTANT0 != 0, CONSTANT1 != 0)) { case combine(0, 0): for(i...) { DoWork0(i); DoWork2(i); }
Chapter 2 C and C++ Source-Level Optimizations 27
Page 46
Software Optimization Guide for AMD Family 10h Processors
break; case combine(1, 0): for(i...) { DoWork1(i); DoWork2(i); } break; case combine(0, 1): for(i...) { DoWork0(i); DoWork3(i); } break; case combine( 1, 1 ): for(i...) { DoWork1(i); DoWork3(i); } break; default: break; }
40546 Rev. 3.09 November 2008
Some introductory code is necessary to generate all the combinations for the switch constant and the total amount of code has doubled. However, the inner loops are now free of if statements. In ideal cases where the DoWorkn functions are inlined, the successive functions have greater overlap, leading to greater parallelism than possible in the presence of intervening if statements.
The same idea can be applied to constant switch statements or to combinations of switch statements and if statements inside of for loops. The method used to combine the input constants becomes more complicated but benefits performance.
However, the number of inner loops can also substantially increase. If the number of inner loops is prohibitively high, then only the most common cases must be dealt with directly, and the remaining cases can fall back to the old code in the default clause of the switch statement. This situation is typical of run-time generated code. While the performance of run-time generated code can be improved by means similar to those presented here, it is much harder to maintain and developers must do their own code-generation optimizations without the help of an available compiler.

2.13 Local Static Functions

Optimization
Declare as static functions that are not used outside the file where they are defined.
Application
This optimization applies to:
• 32-bit software
28 C and C++ Source-Level Optimizations Chapter 2
Page 47
40546 Rev. 3.09 November 2008
• 64-bit software
Software Optimization Guide for AMD Family 10h Processors
Rationale
Declaring a function as static forces internal linkage. Functions that are not declared as static default to external linkage, which may inhibit certain optimizations—for example, aggressive inlining—with some compilers. In C++, programmers can declare functions inside an anonymous namespace to achieve the same local scoping effect.

2.14 Explicit Parallelism in Code

Optimization
Where possible, break long dependency chains into several independent chains that can be executed in parallel to take advantage of the execution units in each pipeline.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
It is especially important to break long x87, SSE, or SSE2 dependency chains into smaller executing units in floating-point code, because of the longer latency of floating-point operations. Most languages (including ANSI C) are bound by the guarantee that floating-point expressions can not be reordered; compilers cannot usually perform such optimizations unless they offer a switch to allow noncompliant reordering of floating-point expressions according to algebraic rules.
Reordered code that is algebraically identical to the original code does not necessarily produce identical computational results due to the lack of associativity of floating-point operations. There are well-known numerical considerations in applying these optimizations (consult a book on numerical analysis). In some cases, reordered floating-point code may lead to unexpected results, but in the vast majority of cases, the final result differs only in the least-significant bits.
Examples
Avoid
double a[100], sum; int i;
sum = 0.0f;
Chapter 2 C and C++ Source-Level Optimizations 29
Page 48
Software Optimization Guide for AMD Family 10h Processors
for (i = 0; i < 100; i++) { sum += a[i]; }
40546 Rev. 3.09 November 2008
Preferred
double a[100], sum1, sum2, sum3, sum4, sum; int i;
sum1 = 0.0; sum2 = 0.0; sum3 = 0.0; sum4 = 0.0; for (i = 0; i < 100; i + 4) { sum1 += a[i]; sum2 += a[i+1]; sum3 += a[i+2]; sum4 += a[i+3]; } sum = (sum4 + sum3) + (sum1 + sum2);
Notice that the four-way unrolling is chosen to exploit the four-stage fully pipelined floating-point adder. Each stage of the floating-point adder is occupied on every clock cycle, ensuring maximum sustained utilization.

2.15 Extracting Common Subexpressions

Optimization
Manually extract common subexpressions from floating-point expressions, where C compilers may be unable to extract them due to the rules against reordering of floating-point expressions in the ANSI standard.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
Specifically, the compiler cannot rearrange the computation according to algebraic equivalencies before extracting common subexpressions. Rearranging the expression may give different computational results due to the lack of associativity of floating-point operations, but the results usually differ in only the least-significant bits. However, since errors in the least significant bits can be magnified by later operations to the extent that they completely invalidate the calculation, the programmer should proceed with caution when implementing this sort of computation.
30 C and C++ Source-Level Optimizations Chapter 2
Page 49
40546 Rev. 3.09 November 2008
Examples
Avoid
double a, b, c, d, e, f;
e = b * c / d; f = b / d * a;
Preferred
double a, b, c, d, e, f, t;
t = b / d; e = c * t; f = a * t;
Avoid
double a, b, c, e, f;
Software Optimization Guide for AMD Family 10h Processors
e = a / c; f = b / c;
Preferred
double a, b, c, e, f, t;
t = 1 / c; e = a * t f = b * t;

2.16 Sorting and Padding C and C++ Structures

Optimization
Sort and pad C and C++ structures to achieve natural alignment.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Chapter 2 C and C++ Source-Level Optimizations 31
Page 50
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
Rationale
In order to achieve better alignment for structures, many compilers have options that allow padding of structures to make their sizes multiples of words, doublewords, or quadwords. In addition, to improve the alignment of structure members, some compilers may allocate structure elements in an order that differs from the order in which they are declared. Unfortunately, some compilers may not offer any of these features, or their implementations might not work properly in all situations.
By sorting and padding structures at the source-code level, if the first member of a structure is naturally aligned, then all other members are naturally aligned as well. This allows, for example, arrays of structures to be perfectly aligned.
Sorting and Padding C and C++ Structures
To sort and pad a C or C++ structure, follow these steps:
1. Sort the structure members according to their type sizes, declaring members with larger type sizes
ahead of members with smaller type sizes.
2. Pad the structure so the size of the structure is a multiple of the largest member’s type size.
Examples
Avoid structure declarations in which the members are not declared in order of their type sizes and the size of the structure is not a multiple of the size of the largest member’s type:
struct { char a[5]; \\ Smallest type size (1 byte * 5) long k; \\ 4 bytes in this example double x; \\ Largest type size (8 bytes) } baz;
Instead, declare the members according to their type sizes (largest to smallest) and add padding to ensure that the size of the structure is a multiple of the largest member’s type size:
struct { double x; \\ Largest type size (8 bytes) long k; \\ 4 bytes in this example char a[5]; \\ Smallest type size (1 byte * 5) char pad[7]; \\ Make structure size a multiple of 8. } baz;

2.17 Replacing Integer Division with Multiplication

Optimization
Replace integer division with multiplication when there are multiple divisions in an expression. (This is possible only if no overflow will occur during the computation of the product. The possibility of an overflow can be determined by considering the possible ranges of the divisors.)
32 C and C++ Source-Level Optimizations Chapter 2
Page 51
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
Integer division is the slowest of all integer arithmetic operations.
Examples
Avoid code that uses two integer divisions:
int i, j, k, m;
m = i / j / k;
Instead, replace one of the integer divisions with the appropriate multiplication:
m = i / (j * k);

2.18 Frequently Dereferenced Pointer Arguments

Optimization
Avoid dereferenced pointer arguments inside a function.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
Because the compiler has no knowledge of aliasing between pointers, such dereferencing cannot be “optimized away.” Since data may not be maintained in registers, memory traffic can significantly increase.
Many compilers have an “assume no aliasing” optimization switch. This allows the compiler to assume that two different pointers always have disjoint contents and does not require copying of pointer arguments to local variables. If your compiler does not have this type of optimization, then copy the data referenced by the pointer arguments to local variables at the start of the function and if necessary copy them back at the end of the function. (Some compilers also provide keywords to
Chapter 2 C and C++ Source-Level Optimizations 33
Page 52
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
provide the same aliasing information to the compiler. For details, see Compiler Usage Guidelines for 64-Bit Operating Systems on AMD64 Platforms Application Note, order# 32035.)
Examples
Avoid
// Assumes pointers are different and q != r. void isqrt(unsigned long a, unsigned long *q, unsigned long *r) {
*q = a; if (a > 0) { while (*q > (*r = a / *q)) { *q = (*q + *r) >> 1; } } *r = a - *q * *q; }
Preferred
// Assumes pointers are different and q != r. void isqrt(unsigned long a, unsigned long *q, unsigned long *r) {
unsigned long qq, rr; qq = a; if (a > 0) { while (qq > (rr = a / qq)) { qq = (qq + rr) >> 1; } } rr = a - qq * qq; *q = qq; *r = rr; }

2.19 32-Bit Integral Data Types

Optimization
Use 32-bit integers instead of smaller sized integers (16-bit or 8-bit).
Application
This optimization applies to:
• 32-bit software
• 64-bit software
34 C and C++ Source-Level Optimizations Chapter 2
Page 53
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
Rationale
When choosing between 32-bit, 16-bit and 8-bit data types in cases where memory footprint is not a concern, using 32-bit integer types in 32-bit software (32-bit or 64-bit integer types in 64-bit software) avoids possible register-merging false dependencies due to partial register writes. See section 4.8, "Partial-Register Writes" on page 60 for details.

2.20 Sign of Integer Operands

Optimization
Where there is a choice of using either a signed or an unsigned type, take into consideration that some operations are faster with unsigned types while others are faster for signed types.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
In many cases, the type of data to be stored in an integer variable determines whether a signed or an unsigned integer type is appropriate. For example, to record the weight of a person in pounds, no negative numbers are required, so an unsigned type is appropriate. However, recording temperatures in degrees Celsius may require both positive and negative numbers, so a signed type is needed.
Integer-to-floating-point conversion using integers larger than 16 bits is faster with signed types, as the AMD64 architecture provides instructions for converting signed integers to floating-point but has no instructions for converting unsigned integers. In a typical case, a 32-bit integer is converted by a compiler to assembly as follows:
Examples
Avoid
double x; ====> mov [temp+4], 0 unsigned int i; mov eax, i mov [temp], eax x = i; fild QWORD PTR [temp] fstp QWORD PTR [x]
The preceding code is slow not only because of the number of instructions, but also because a size mismatch prevents store-to-load forwarding to the FILD instruction. Instead, use the following code:
Chapter 2 C and C++ Source-Level Optimizations 35
Page 54
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
Preferred
double x; ====> fild DWORD PTR [i] int i; fstp QWORD PTR [x]
x = i;
Computing quotients and remainders in integer division by constants is faster when performed on unsigned types. The following typical case is the compiler output for a 32-bit integer divided by 4:
Avoid
int i; ====> mov eax, i cdq i = i / 4; and edx, 3 add eax, edx sar eax, 2 mov i, eax
Preferred
unsigned int i; ====> shr i, 2
i = i / 4;
In summary, use unsigned types for:
• Division and remainders
• Loop counters
• Array indexing
Use signed types for:
• Integer-to-floating-point conversion
2.21 Accelerating Floating-Point Division and Square
Root
Optimization
In applications employing the heavy use of single precision division and square root operations, in which the compiler maps floating-point operations to x87 instructions, the x87 FPU control word register precision control specification bits (PC) can be set to single precision to improve performance. (The processor defaults to double-extended precision. See AMD64 Architecture Programmer’s Manual, Volume 1, order# 24592, for details on the FPU control register.)
36 C and C++ Source-Level Optimizations Chapter 2
Page 55
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
Note: For hotspots that can be recoded in assembly language or SSE intrinsics, refer to section
9.7“Using SIMD Instructions for Fast Square Roots and Divisions” on page 150 for coding suggestions.
Application
This optimization applies to any compiler that maps floating-point operations to x87 instructions. This is generally true only for 32-bit compilers.
Rationale
Division and square root have a much longer latency than other floating-point operations, even though the AMD Family 10h processors provide significant acceleration of these two operations. In some application programs, these operations occur so often that they seriously impair performance. If the code has hot spots that use single precision arithmetic only (that is, all computation involves data of type float) and for some reason cannot be ported to SSE, SSE2, or SSE3 code, the following technique may be used to improve performance.
The x87 FPU has a precision-control field as part of the FPU control word. The precision-control setting determines rounding precision of instruction results and affects the basic arithmetic operations, including division and the extraction of square root. Division and square root on the AMD Family 10h processors are only computed to the number of bits necessary for the currently selected precision. Setting precision control to single precision (versus the default of double-extended precision) lowers the latency of those operations.
For example, the 32-bit version Microsoft® Visual C environment provides functions to manipulate the FPU control word and, thus, the precision control bits. Note that these functions are not very fast, so insert changes of precision control where doing so creates little overhead, such as outside of computation-intensive loops. Otherwise, the overhead created by the function calls outweighs the benefit of reducing the latencies of divide and square-root operations. The following example shows how to set the precision control to single precision and later restore the original settings in the Microsoft Visual C environment.
Examples
/* Prototype for _controlfp_s function */ #include <float.h>
unsigned int cw, orig_cw; int err;
/* Get original FP control word and save it. */
err = _controlfp_s(&orig_cw, 0, 0); if ( err ) /* handle error here */;
/* Set precision in FPU control word to single precision. This reduces the latency of divide and square-root operations. */
Chapter 2 C and C++ Source-Level Optimizations 37
Page 56
Software Optimization Guide for AMD Family 10h Processors
err = _controlfp_s(&cw, _PC_24, MCW_PC); if ( err ) /* handle error here */;
/* Restore original FPU control word */
err = _controlfp_s(&cw, orig_cw, MCW_PC); if ( err ) /* handle error here */;
40546 Rev. 3.09 November 2008
2.22 Speeding Up Branches Based on Comparisons
Between Floats
Optimization
Store operands of type float into a memory location and use integer comparison with the memory location to perform fast branches in cases where compilers do not support fast floating-point comparison instructions.
Application
This optimization applies to 32-bit software.
Rationale
Branches based on floating-point comparisons are often slow. AMD Family 10h processors support the FCOMI, FUCOMI, FCOMIP, and FUCOMIP instructions that allow implementation of fast branches based on comparisons between operands of type double or type float. However, some compilers do not support generating these instructions.
Some compilers only implement branches based on floating-point comparisons by using FCOM or FCOMP to compare the floating-point operands, followed by FSTSW AX in order to transfer the x87 condition-code flags into EAX. The subsequent branch is then based on the contents of the EAX register. Although the AMD FSTSW instruction, this process is still fairly slow.
Branches Dependent on Integer Comparisons Are Fast
One alternative for branches dependent upon the outcome of the comparison of operands of type
float is to store the operand(s) into a memory location and then perform an integer comparison with
that memory location. Branches dependent on integer comparisons are very fast. The replacement code uses a load dependent on an immediately prior store. If the store is not doubleword-aligned, no store-to-load-forwarding takes place, and the branch is still slow. Also, if there is a lot of activity in the load-store queue, forwarding of the store data may be somewhat delayed, thus negating some of the advantages of using the replacement code. It is recommended that you experiment with the replacement code to test whether it actually provides a performance increase in the code at hand.
Family 10h processors have acceleration hardware to speed up the
38 C and C++ Source-Level Optimizations Chapter 2
Page 57
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
The replacement code works well for comparisons against zero, including correct behavior when encountering a negative zero as allowed by the IEEE-754 standard. It also works well for comparing to positive constants. In that case, the user must first determine the integer representation of that floating-point constant. This can be accomplished with the following C code snippet:
float x; scanf("%g", &x); printf("%08X\n", (*((int *)(&x))));
The replacement code is IEEE-754 compliant for all classes of floating-point operands except NaNs.
Examples
Initial definitions:
#define FLOAT2INTCAST(f) (*((int *)(&f))) #define FLOAT2UINTCAST(f) (*((unsigned int *)(&f)))
Table 3. Comparisons Against Zero
Use this … Instead of this.
if (FLOAT2UINTCAST(f) > 0x80000000U) if (f < 0.0f) if (FLOAT2INCAST(f) <= 0) if (f <= 0.0f) if (FLOAT2INTCAST(f) > 0) if (f > 0.0f) if (FLOAT2UINTCAST(f) <= 0x80000000U) if (f >= 0.0f)
Table 4. Comparisons Against Positive Constant
Use this … Instead of this.
if (FLOAT2INTCAST(f) < 0x40400000) if (f < 3.0f) if (FLOAT2INTCAST(f) <= 0x40400000) if (f <= 3.0f) if (FLOAT2INTCAST(f) > 0x40400000) if (f > 3.0f) if (FLOAT2INTCAST(f) >= 0x40400000) if (f >= 3.0f)
Table 5. Comparisons Among Two Floats
Use this … Instead of this.
float t = f1 - f2;
if (FLOAT2UINTCAST(t) > 0x80000000U) float t = f1 - f2;
if (FLOAT2INTCAST(t) <= 0) float t = f1 - f2;
if (FLOAT2INTCAST(t) > 0) float t = f1 - f2;
f (FLOAT2UINTCAST(f) <= 0x80000000U)
if (f1 < f2)
if (f1 <= f2)
if (f1 > f2)
if (f1 >= f2)
Chapter 2 C and C++ Source-Level Optimizations 39
Page 58
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008

2.23 Improving Performance in Linux® Libraries

Optimization
If symbol interposition is not important to a particular application, then you should control the visibility of the symbols in a shared object in such a way as to optimize internal references to other symbols in the library and minimize the symbol export table size.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
Dynamically loadable libraries are a versatile feature of the Linux® operating system. These allow one or more symbols in one library to override an identical symbol in another library. Known as interposition, this ability makes customizations and probing seamless. Interposition is implemented by means of a procedure linkage table (PLT). The PLT is so flexible that even references to an overridden symbol inside its own library end up referencing the overriding symbol. However, the PLT imposes a performance penalty by requiring all function calls to public global routines to go through an extra step that increases the chances of cache misses and branch mispredictions. This is particularly severe for C++ classes whose methods refer to other methods in the same class.
When using ld to link a shared object, include the command line option -Bsymbolic.
If using a version of gcc prior to 4.0 to link a shared object, add the option -Wl,-Bsymbolic to the command-line. If using gcc 4.0 or later, add the option line.
If finer control is desired, then it is possible to specify -fvisibility=hidden to gcc 4.0 or later and then add __attribute__ ((visibility ("default"))) to each symbol that should be exported. When building C++ shared objects, also consider using the -fvisibility-inlines-hidden option.
40 C and C++ Source-Level Optimizations Chapter 2
-fvisibility=protected to the command-
Page 59
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors

2.24 Aligning Matrices

Optimization
When using multi-dimensional arrays or matrices, make sure that each row or 2nd-order dimension starts at a 16-byte boundary.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
Instead of creating matrices with arbitrary dimensions, make sure that the size in bytes of the low­order dimension is a multiple of 16 and that it starts at a 16-byte boundary. By doing so, when iterating over the elements of the matrix the compiler is presented with data properly aligned for low­cost vectorization.
For example, in:
double a [10][11], b [10][11]; int i, j;
for (j = 0; j < 10; j++) for (i = 0; i < 11; i++) b [j][i] = a [j][i] * M_1_PI;
Declare the matrices in this way:
__declspec (align (16)) double a [10][ ((11 * sizeof (double) + 15) / 16) * 16 / sizeof (double)], b [10][ ((11 * sizeof (double) + 15) / 16) * 16 / sizeof (double)]; int i, j;
for (j = 0; j < 10; j++) for (i = 0; i < 11; i++) b [j][i] = a [j][i] * M_1_PI;
However, be aware of cache-bank conflicts for best performance. For more information, see section
5.7, "L1 Data Cache Bank Conflicts" on page 90.
Chapter 2 C and C++ Source-Level Optimizations 41
Page 60
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
42 C and C++ Source-Level Optimizations Chapter 2
Page 61
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors

Chapter 3 General 64-Bit Optimizations

The AMD64 architecture provides a compatibility mode, which allows a 64-bit operating system to run existing 16-bit and 32-bit applications, and a 64-bit mode, which provides 64-bit addressing and expanded register resources to improve performance for recompiled 64-bit programs. This chapter presents general optimizations to improve the performance of software designed to run in 64-bit mode.
This chapter covers the following topics:
Topic Page
64-Bit Registers and Integer Arithmetic 43
Using 64-bit Arithmetic for Large-Integer Multiplication 45
128-Bit Media Instructions and Floating-Point Operations 49
32-Bit Legacy GPRs and Small Unsigned Integers 49

3.1 64-Bit Registers and Integer Arithmetic

Optimization
Use 64-bit registers for 64-bit integer arithmetic.
Rationale
Using 64-bit registers instead of their 32-bit equivalents can dramatically reduce the amount of code necessary to perform 64-bit integer arithmetic.
Example 1
This code performs 64-bit addition using 32-bit registers:
; Add ECX:EBX to EDX:EAX, and place sum in EDX:EAX. 00000000 03 C3 add eax, ebx 00000002 13 D1 adc edx, ecx
Using 64-bit registers, the previous code can be replaced by one simple instruction (assuming that RAX and RBX contain the 64-bit integer values to add):
00000000 48 03 C3 add rax, rbx
Although the preceding instruction requires one additional byte for the REX prefix, it is still one byte shorter than the original code. More importantly, this instruction still has a latency of only one cycle, uses two fewer registers, and occupies only one decode slot.
Chapter 3 General 64-Bit Optimizations 43
Page 62
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
Example 2
To perform the low-order half of the product of two 64-bit integers using 32-bit registers, a procedure such as the following is necessary:
; In: [ESP+8]:[ESP+4] = multiplicand ; [ESP+16]:[ESP+12] = multiplier ; Out: EDX:EAX = (multiplicand * multiplier) % 2^64 ; Modifies: EAX, ECX, EDX, EFlags
llmul PROC mov edx, [esp+8] ; multiplicand_hi mov ecx, [esp+16] ; multiplier_hi or edx, ecx ; One operand >= 2^32? mov edx, [esp+12] ; multiplier_lo mov eax, [esp+4] ; multiplicand_lo jnz twomul ; Yes, need two multiplies. mul edx ; multiplicand_lo * multiplier_lo ret ; Done, return to caller.
twomul: imul edx, [esp+8] ; p3_lo = multiplicand_hi * multiplier_lo imul ecx, eax ; p2_lo = multiplier_hi * multiplicand_lo add ecx, edx ; p2_lo + p3_lo mul dword ptr [esp+12] ; p1 = multiplicand_lo * multiplier_lo add edx, ecx ; p1 + p2_lo + p3_lo = result in EDX:EAX ret ; Done, return to caller.
llmul ENDP
Using 64-bit registers, the entire product can be produced with only one instruction:
; Multiply RAX by RBX. The 128-bit product is stored in RDX:RAX. 00000000 48 F7 EB imul rbx
Related Information
For more examples of 64-bit arithmetic using only 32-bit registers, see the example on page 47 and “Efficient 64-Bit Integer Arithmetic in 32-Bit Mode” on page 129.
44 General 64-Bit Optimizations Chapter 3
Page 63
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
3.2 Using 64-bit Arithmetic for Large-Integer
Multiplication
Optimization
Use 64-bit arithmetic for integer multiplication that produces 128-bit or larger products.
Background
Large integer multiplications (those involving 128-bit or larger products) are utilized in a variety of applications, such as cryptography software, which figure prominently in e-commerce applications and secure transactions on the Internet. Processors cannot perform large-number multiplication natively; they must break the operation into chunks that are permitted by their architecture (32-bit or 64-bit additions and multiplications).
Rationale
Using 64-bit rather than 32-bit integer operations dramatically reduces the number of additions and multiplications required to compute large products. For example, computing a 1024-bit product using 64-bit arithmetic requires fewer than one quarter the number of instructions required when using 32-bit operations:
Comparing... 32-bit arithmetic 64-bit arithmetic
Number of multiplications 256 64
Number of additions with carry 509 125
Number of additions 255 63
In addition, the processor performs 64-bit additions just as fast as it performs 32-bit additions, and the latency of 64-bit multiplications is only slightly higher than for 32-bit multiplications. (The processor is capable of performing three independent 64-bit additions each clock cycle and a 64-bit multiplication every other clock cycle.)
Example
Consider the multiplication of two unsigned 64-bit numbers a and b, represented in terms of 32-bit components a1:a0 and b1:b0.
a = a1 * 232 + a0
b = b1 * 232 + b0
The product of a and b, calculated using the FOIL method of the polynomials above, can be expressed in terms of products of the 32-bit components, as follows:
Chapter 3 General 64-Bit Optimizations 45
Page 64
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
Formula 3.1
c = (a1 * b1) * 264 + (a1 * b0 + a0 * b1) * 232 + (a0 * b0)
Each of the products of the components of a and b (for example, a1 * b1) is composed of 64 bits—an upper 32 bits and a lower 32 bits. It is convenient to represent these individual products as d, e, f, and
g, as follows:
a0 * b0 = d1:d0 = d1 * 232 + d0
a1 * b0 = e1:e0 = e1 * 232 + e0
a0 * b1 = f1:f0 = f1 * 232 + f0
a1 * b1 = g1:g0 = g1 * 232 + g0
Substitution into Formula 3.1 above yields the following equation:
Formula 3.2
c = (g1 * 232 + g0) * 264 + (e1 * 232 + e0 + f1 * 232 + f0) * 232 + (d1 * 232 + d0)
Simplifying yields this equation:
Formula 3.3
c = g1 * 296 + (e1 + f1 + g0) * 264 + (d1 + e0 + f0) * 232 + d0
It is convenient to represent the terms that are multiplied by each power of 2 as c3, c2, c1, and c0, as follows:
g1 = c3
e1 + f1 + g0 = c2
d1 + e0 + f0 = c1
d0 = c0
Substituting again yields:
Formula 3.4
c = c3 * 296 + c2 * 264 + c1 * 232 + c0
46 General 64-Bit Optimizations Chapter 3
Page 65
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
The following procedure performs 64-bit unsigned integer multiplication, as previously illustrated using 32-bit integer operations:
; 32bitalu_64x64(int *a, int *b, int *c); ; ; TO ASSEMBLE INTO *.obj DO THE FOLLOWING: ; ml.exe -coff -c 32bitalu_64x64.asm ; .586 .K3D .XMM _DATA SEGMENT tempESP dd 0 _DATA ENDS _TEXT SEGMENT ASSUME DS:_DATA PUBLIC _32bitalu_64x64 _32bitalu_64x64 PROC NEAR ;============================================================================== ; Save the register state. Registers EAX, ECX, and EDX are considered volatile ; and assumed to be changed, while the registers below must be preserved. push ebp mov ebp, esp ;============================================================================== ; Parameters passed into routine: ; [ebp+8] = ->a ; [ebp+12] = ->b ; [ebp+16] = ->c ;============================================================================== push ebx push esi push edi ;============================================================================== mov esi,[ebp+8] ; ESI = ->a mov edi,[ebp+12] ; EDI = ->b mov ecx,[ebp+16] ; ECX = ->c push ebp mov [tempESP], esp ;============================================================================== ; Multiply 64-bit numbers a and b, each of which is composed of two 32-bit ; components: ; a = a1 * 2^32 + a0 ; b = b1 * 2^32 + b0 mov eax,[esi] ; EAX = a0 mov edx,[edi] ; EDX = b0 mul edx ; EDX:EAX = a0*b0 = d1:d0 mov ebx,edx ; EDX = d1 mov [ecx],eax ; c0 = EAX xor esp,esp ; ESP = 0 xor ebp,ebp ; EBP = 0 mov eax,[esi+4] ; EAX = a1 mov edx,[edi] ; EDX = b0 mul edx ; EDX:EAX = a1*b0 = e1:e0 add ebx,eax ; EBX = d1 + e0 adc ebp,edx ; EBP = e1 + possible carry from d1+e0 adc esp,0 ; Collect possible carry into c3.
Chapter 3 General 64-Bit Optimizations 47
Page 66
Software Optimization Guide for AMD Family 10h Processors
mov eax,[esi] ; EAX = a0 mov edx,[edx+4] ; EDX = b1 mul edx ; EDX:EAX = a0*b1 = f1:f0 add ebx,eax ; EBX = d1 + e0 + f0 adc ebp,edx ; EBP = e1 + f1 + carry adc esp,0 ; Collect possible carry into c3. mov [ecx+4],ebx ; c1 = d1 + e0 + f0
mov eax,[esi+4] ; EAX = a1 mov edx,[edi+4] ; EDX = b1 mul edx ; EDX:EAX = a1*b1 = g1:g0 add ebp,eax ; EBP = e1 + f1 + g0 + carry adc esp,edx ; ESP = g1 + carry mov [ecx+8],ebp ; c2 = e1 + f1 + g0 + carry mov [ecx+12],esp ; c3 = g1 + carry ;============================================================================== ; Restore the register state. mov esp, [tempESP] pop ebp pop edi pop esi pop ebx mov esp, ebp pop ebp ;============================================================================== ret _32bitalu_64x64 ENDP _TEXT ENDS END
40546 Rev. 3.09 November 2008
To improve performance and substantially reduce code size, the following procedure performs the same 64-bit integer multiplication using 64-bit instead of 32-bit operations:
; 64bitalu_64x64(int *a, int *b, int *c); ; ; TO ASSEMBLE INTO *.obj DO THE FOLLOWING: ; ml64.exe -c 64bitalu_64x64.asm ; _TEXT SEGMENT 64bitalu_64x64 PROC NEAR ;============================================================================== ; Parameters passed into routine: ; rcx = ->a ; rdx = ->b ; r8 = ->c ;============================================================================== mov rax, [rcx] ; RAX = [a0] mul [rdx] ; Multiply [a0] by [b0] such that ; RDX:RAX = [c1]:[c0]. mov [r8], rax ; Store 128-bit product of a and b. mov [r8+8], rdx ;============================================================================== ret 64bitalu_64x64 ENDP END
48 General 64-Bit Optimizations Chapter 3
Page 67
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
3.3 128-Bit Media Instructions and Floating-Point
Operations
Optimization
Use 128-bit media (SSE, SSE2, SSE3, and SSE4a) instructions instead of x87 or 64-bit media instructions for floating-point operations.
Rationale
In 64-bit mode, the processor provides eight additional XMM registers (XMM8–XMM15) for a total of 16. These extra registers can substantially reduce register pressure in floating-point code written using 128-bit media instructions.
Although the processor fully supports the x87 and 64-bit media instructions, there are only eight registers available to these instructions (ST(0)–ST(7) or MMX0–MMX7, respectively). Additionally, the x87 and 64-bit media instructions require cumbersome register manipulation and mode switches, unlike SSE, SSE2, SSE3 and SSE4a.
For further information, see Chapter 9, “Optimizing with SIMD Instructions” on page 145.

3.4 32-Bit Legacy GPRs and Small Unsigned Integers

Optimization
Use the 32-bit legacy general-purpose registers (EAX through ESI) instead of their 64-bit extensions to store unsigned integer values whose range never requires more than 32 bits, even if subsequent statements use the 32-bit value in a 64-bit operation. (For example, use ECX instead of RCX until you need to perform a 64-bit operation; then use RCX.)
Rationale
In 64-bit mode, the machine-language representation of many instructions that operate on unsigned 64-bit register operands requires a REX prefix byte, which increases the size of the code. However, instructions that operate on a 32-bit legacy register operand do not require the prefix and have the desirable side-effect of clearing the upper 32 bits of the extended register to zero. For example, using the AND instruction on ECX clears the upper half of RCX.
Caution
Because the assembler also uses a REX prefix byte to encode the 32-bit sizes of the eight new 64-bit general-purpose registers (R8D–R15D), you should only use one of the original eight general­purpose registers (EAX through ESI) to implement this technique.
Chapter 3 General 64-Bit Optimizations 49
Page 68
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
Example
The following example illustrates the unnecessary use of 64-bit registers to calculate the number of bytes remaining to be copied by an aligned block-copy routine after copying the first few bytes having addresses not meeting the routine’s 8-byte-alignment requirements. The first two statements, after the program comments, use the 64-bit R10 register—presumably, because this value is later used to adjust a 64-bit value in R8—even though it requires no more than four bits to represent the range of values stored in R10. Using R10 instead of a smaller register requires a REX prefix byte (in this case,
49), which increases the size of the machine-language code.
; Input: ; R10 = source address (src) ; R8 = number of bytes to copy (count) 49 F7 DA neg r10 ; Subtract the source address from 2^64. 49 83 E2 07 and r10, 7 ; Determine how many bytes were copied separately. 4D 2B C2 sub r8, r10 ; Subtract the number of bytes already copied from ; the number of bytes to copy.
To improve code density, the following rewritten code uses ECX until it is absolutely necessary to use RCX, eliminating two REX prefix bytes:
F7 D9 neg ecx ; Subtract the source address from 2^32 (the processor ; clears the high 32 bits of RCX). 83 E1 07 and ecx, 7 ; Determine how many bytes were copied separately. 4C 2B C1 sub r8, rcx ; Subtract the number of bytes already copied from ; the number of bytes to copy.
50 General 64-Bit Optimizations Chapter 3
Page 69
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
Chapter 4 Instruction-Decoding
Optimizations
The optimizations in this chapter are designed to help maximize the number of instructions that the processor can decode at one time.
The AMD Family 10h processor instruction fetcher reads 32-byte packets from the L1 instruction cache. These packets are 32-byte aligned. The instruction bytes are then merged into a 32-byte pick window. On each cycle, the in-order front-end engine selects up to three AMD64 instructions to decode from the pick window.
This chapter covers the following topics:
Topic Page
DirectPath Instructions 52
Load-Execute Instructions for Floating-Point or Integer Operands 53
Loop Iteration Boundaries 56
32/64-Bit vs. 16-Bit Forms of the LEA Instruction 56
Take Advantage of x86 and AMD64 Complex Addressing Modes 57
Short Instruction Encodings 56
Stack Operations 59
Partial-Register Writes 60
Using LEAVE for Function Epilogues 64
Alternatives to SHLD Instruction 66
8-Bit Sign-Extended Immediate Values 67
8-Bit Sign-Extended Displacements 68
Code Padding with Operand-Size Override and Multibyte NOP 68
Chapter 4 Instruction-Decoding Optimizations 51
Page 70
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008

4.1 DirectPath Instructions

Optimization
Use DirectPath instructions rather than VectorPath instructions. To determine the type of an
instruction—either DirectPath or VectorPath—see Appendix C, “Instruction Latencies.”
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
DirectPath instructions minimize the number of operations per AMD64 instruction, thus providing for optimally efficient decode and execution. Up to three DirectPath Single instructions, or one and a half DirectPath Double instructions, can be decoded per cycle. VectorPath instructions block the decoding of DirectPath instructions.
The AMD Family 10h processor has been designed to execute the instructions most frequently generated by compilers as DirectPath Single or DirectPath Double instructions. However, assembly writers must still take into consideration the use of DirectPath versus VectorPath instructions.
Examples
The following example shows code for swapping two memory values. Although the second case uses an extra instruction, it is preferred because it avoids VectorPath instructions.
Avoid code such as the following which uses a V
movzx eax, BYTE PTR [memA] xchg [memB], al ; xchg mem8, reg8 is a VectorPath instruction mov [memA], al
Instead, use an equivalent instruction sequence such as the following using DirectPath instructions.
;; All of the following are DirectPath instructions movzx eax, BYTE PTR [memA] movzx ebx, BYTE PTR [memB] mov [memB], al mov [memA], bl
ectorPath instruction.
52 Instruction-Decoding Optimizations Chapter 4
Page 71
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
4.2 Load-Execute Instructions for Floating-Point or
Integer Operands
A load-execute instruction is an instruction that loads a value from memory into a register and then performs an operation on that value. Many general purpose instructions, such as ADD, SUB, AND, etc., have load-execute forms:
ADD rax, QWORD PTR [foo]
This instruction loads the value foo from memory and then adds it to the value in the RAX register.
The work performed by a load-execute instruction can also be accomplished by using two discrete instructions—a load instruction followed by an execute instruction. The following example employs discrete load and execute stages:
MOV rbx, QWORD PTR [foo] ADD rax, rbx
The first statement loads the value foo from memory into the RBX register. The second statement adds the value in RBX to the value in RAX.
The following optimizations govern the use of load-execute instructions:
• Load-Execute Integer Instructions on page 53.
• Load-Execute SSE/SSE2/SSE3 Instructions with Floating-Point or Integer Operands on page 54.
• Load-Execute x87 Instructions with Integer Operands on page 55.
4.2.1 Load-Execute Integer Instructions
Optimization
When performing integer computations, use load-execute instructions instead of discrete load
and execute instructions. Use discrete load and execute instructions only under one or more of the
wing circumstances:
follo
• to explicitly schedule load and execute operations
• to avoid scheduler stalls for longer e
• if the load target will be used multiple times in different instructions
xecuting instructions
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Chapter 4 Instruction-Decoding Optimizations 53
Page 72
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
Rationale
Most load-execute integer instructions are DirectPath decodable and can be decoded at the rate of three per cycle. Splitting a load-execute integer instruction into two separate instructions reduces decoding bandwidth and increases register pressure, which results in lower performance.
4.2.2 Load-Execute SSE/SSE2/SSE3 Instructions with Floating-Point
or Integer Operands
Optimization
When performing floating-point computation using floating-point or integer source operands,
use load-execute instructions instead of discrete load and execute instructions.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
Using load-execute floating-point instructions that take floating-point or integer operands improves performance for the following reasons:
• Denser code allows more work to be held in the instruction cache.
• Denser code generates fewer internal macro-ops, allowing the floating-point scheduler to hold
more work, which increases the chances of extracting parallelism from the code.
The use of load-execute packed SSE instructions instead of distinct load and e
xecute instructions improves performance in cases in which data might not be aligned on a 16-byte boundary. However, this requires setting the misaligned exception mask (MXCSR[17]). Setting this bit disables general protection exceptions for unaligned loads in SSE load-execute instructions. See also “Unaligned and Aligned Data Access” on page 147.
Example
Avoid code such as the following, which uses discrete load and execute SSE instructions:
movss xmm0, [float_var1] movss xmm12, [float_var2] mulss xmm0, xmm12
Instead, use code such as the following, which uses a load-execute SSE floating-point instruction:
movss xmm0, [float_var1] mulss xmm0, [float_var2]
54 Instruction-Decoding Optimizations Chapter 4
Page 73
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
4.2.3 Load-Execute x87 Instructions with Integer Operands
Optimization
Avoid x87 load-execute floating-point instructions that take integer operands (FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FIMUL, FISUB, and FISUBR). When performing floating-point computations using integer source operands, use discrete load (FILD) and execute instructions instead.
However, when performing floating-point computations using floating point operands, use load­execute instructions instead of discrete load and execute instructions.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
The load-execute floating-point instructions that take integer operands take longer to execute than an FILD followed by the same register-execute arithmetic instruction. In some situations, this optimization can also reduce execution time, if FILD can be scheduled several instructions ahead of the arithmetic instruction to cover the FILD latency.
Example
Avoid code such as the following, which uses load-execute floating-point instructions that take integer operands:
fld QWORD PTR [foo] ; Push foo onto FP stack [ST(0) = foo]. fimul DWORD PTR [bar] ; Multiply bar by ST(0) [ST(0) = bar * foo]. fiadd DWORD PTR [baz] ; Add baz to ST(0) [ST(0) = baz + (bar * foo)].
Instead, use code such as the following, which uses discrete load and execute instructions:
fild DWORD PTR [bar] ; Push bar onto FP stack. fild DWORD PTR [baz] ; Push baz onto FP stack. fld QWORD PTR [foo] ; Push foo onto FP stack. fmulp st(2), st ; Multiply and pop [ST(1) = foo * bar, ST(0) = baz]. faddp st(1), st ; Add and pop [ST(0) = baz + (foo * bar)].
Chapter 4 Instruction-Decoding Optimizations 55
Page 74
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008

4.3 Loop Iteration Boundaries

Optimization
Fit an entire loop iteration into the smallest number of 32-byte-aligned blocks. In program “hot spots” (as determined by either profiling or loop-nesting analysis), loop iteration boundaries should be placed at or near the beginning of code windows that are 32-byte aligned. The smaller the basic block, the more beneficial this optimization will be.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
AMD Family 10h processors can fetch 32 bytes of instruction data per cycle, but will not fetch across a 32-byte-aligned boundary. Aligning branch targets maximizes the number of instructions in the pick window and preserves instruction-cache space in branch-intensive code outside such hot spots.

4.4 32/64-Bit vs. 16-Bit Forms of the LEA Instruction

Optimization
Use the 32-bit or 64-bit forms of the Load Effective Address (LEA) instruction rather than the 16-bit form.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
The 32-bit and 64-bit LEA instructions are implemented as DirectPath operations with an execution latency of only two cycles. The 16-bit LEA instruction, however, is a VectorPath instruction, which lowers the decode bandwidth and has a longer execution latency.
56 Instruction-Decoding Optimizations Chapter 4
Page 75
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
4.5 Take Advantage of x86 and AMD64 Complex
Addressing Modes
Optimization
When porting from other architectures, remember that the x86 architecture provides many complex addressing modes. By building the effective address in one instruction, the instruction count can sometimes be reduced, leading to better code density and greater decode bandwidth. Refer to the section on effective addresses in the AMD64 Architecture Programmer's Manual, Volume 1: Application Programming, order# 24592 for more detailed information on how effective addresses are formed.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
Building the effective address sometimes seems to require numerous instructions when there is a base address (such as the base of an array), an index and a displacement (if applicable). However, the x86 architecture can often handle all of this information in one instruction. This can reduce code size and results in fewer instructions to decode. As always, attention should be paid to total instruction length, latencies and whether or not the instruction choices are DirectPath (fastest) or VectorPath (slower).
Example
The first instruction sequence of five instructions having a total latency of 8 can be replaced by one instruction.
Number of Bytes Latency Instruction
31 mov r11d, r10d 82 lea rcx, 68E35h 31 add r11, rcx 53 mov cl, BYTE PTR [r11+r13] 21 cmp cl, al
The following instruction replaces the functionality of the above sequence.
Number of Bytes Latency Instruction
84 cmp BYTE PTR [r10+r13+68E35h], al
Chapter 4 Instruction-Decoding Optimizations 57
Page 76
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
Example
These two instructions:
mov r11, QWORD PTR ds:0x4c65a mov r11, QWORD PTR [r11+r8*8]
can be replaced by one instruction:
mov r11, QWORD PTR [r8*8+0x4c65a]

4.6 Short Instruction Encodings

Optimization
Use instruction forms with shorter encodings rather than those with longer encodings. For example, use 8-bit displacements instead of 32-bit displacements, and use the single-byte form of simple integer instructions instead of the 2-byte opcode-ModR/M form.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
Using shorter instructions increases the number of instructions that can fit into the L1 instruction cache and increases the average decode rate.
Example
Avoid the use of instructions having longer encodings, such as the following:
81 C0 78 56 34 12 add eax, 12345678h ; 2-byte opcode form (with ModRM) 81 C3 FB FF FF FF add ebx, -5 ; 32-bit immediate value 0F 84 05 00 00 00 jz label1 ; 2-byte opcode, 32-bit immediate value
Instead, choose instructions having shorter encodings, such as:
05 78 56 34 12 add eax, 12345678h ; 1-byte opcode form 83 C3 FB add ebx, -5 ; 8-bit sign-extended immediate value 74 05 jz label1 ; 1-byte opcode, 8-bit immediate value
58 Instruction-Decoding Optimizations Chapter 4
Page 77
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors

4.7 Stack Operations

Optimization
When saving or restoring registers in function prologues or epilogues, or when passing arguments through the stack, use PUSH or POP instructions to improve performance and to reduce code size.
When deallocating stack space at function exit, use RET imm to improve performance and to reduce code size.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
In spite of the implicit dependency between several successive PUSH or POP instructions on the stack-pointer (which PUSH and POP modify), special circuitry (the Sideband Stack Optimizer) tracks the value that the stack-pointer assumes, allowing parallel execution of more than one PUSH or POP. This is also true of instructions that reference the stack-pointer, either implicitly or explicitly, including:
• Near CALL
• Near RET
• LEAVE
• Instructions that specify the stack-pointer as a source register.
• Instructions that specify the stack-pointer in the addressing mode of a memory operand without
an index register.
However, the Sideband Stack Optimizer cannot break the dependency between the aforementioned instructions and other instructions that refer either implicitly or explicitly to the stack-pointer, including:
• LEA instructions that specify the stack-pointer.
• Instructions that specify the stack-pointer as a destination register.
• Instructions that specify the stack-pointer in the addressing mode of a memory operand with an
index register.
• VectorPath instructions that specify the stack-pointer.
Chapter 4 Instruction-Decoding Optimizations 59
Page 78
Software Optimization Guide for AMD Family 10h Processors
Examples
Avoid
sub esp, 20 mov [esp + 16], edi mov [esp + 12], esi ... mov [esp], eax call ... ... mov esi, [esp + 12] mov edi, [esp + 16] add esp, 20 ret
Preferred
sub esp, 8 push edi push esi ... push eax call ... ... pop esi pop edi add esp, 8 ret
40546 Rev. 3.09 November 2008

4.8 Partial-Register Writes

Optimization
When writing to a register for the purpose of initialization, avoid instructions that
• write less than 32 bits of a general purpose integer register.
• write less than 128 bits of an XMM register.
When writing to a register during the course of a non-initializing operation on the register,
• avoid partial register writes.
• schedule any prior operations on the target register well ahead of the point in the code where the
partial write is to occur.
Application
This optimization applies to:
• 32-bit software
60 Instruction-Decoding Optimizations Chapter 4
Page 79
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
• 64-bit software
Rationale
In order to handle partial register writes, the processor’s execution core implements a data merging scheme. In the execution unit, an instruction that writes part of a register merges the modified portion with the current state of the other part of the register. This creates a false dependency on the most recent instruction that writes to any part of the register.
When writing to a register for the purpose of register initialization, it is usually possible to avoid false dependencies by careful instruction selection. For example, rather than initializing a part of a floating­point 128-bit XMM register, initialize the whole 128-bit register.
When writing to a register during the course of a non-initializing operation on the register, there is usually no additional performance loss due to partial register reads and writes. This is because, in the typical case, the partial register being written to is also a source operand to the operation.
For example, the following instruction does not suffer from merge dependencies:
addsd, xmm1, xmm2
However, in some cases of non-initializing operations on a register, it is preferable to avoid partial register writes and replace them with more efficient operations. In these cases, the partial register being written by the operation is not a source for the operation. Examples are provided below.
If it is not possible to avoid writing to a part of that register, you should schedule any such prior operation on any part of the register well ahead of the point where the partial write occurs. Such cases are also listed in the examples.
A general purpose integer register is viewed as a 64-bit register internal to the processor. A floating­point XMM register is viewed as one 128-bit register internal to the processor.
Current generation processors cannot write a 64-bit half of a 128-bit XMM register without having a merge dependency on the other 64-bit half. Additionally, current generation processors cannot write a 32-bit portion of a 128-bit XMM register without having a merge dependency on other bits of that register.
However, there are several instructions that initialize the lower 64 bits or 32 bits of an XMM register that also zero out the upper 64 or 96 bits and, thus, do not suffer from merge dependencies. For example, the following instructions do not have merge dependencies:
movsd xmm, [mem64] movss xmm, [mem32]
Integer operations that write to the lower 32 bits of a general purpose integer register do not have a false merge dependency because they zero out the upper 32 bits. But operations that write to portions of a general purpose integer register narrower than 32 bits should be avoided.
Chapter 4 Instruction-Decoding Optimizations 61
Page 80
Software Optimization Guide for AMD Family 10h Processors
Example 1
Avoid
MOV al, bl
Preferred
MOVZX eax, bl
Example 2
Avoid
MOV al, [ebx]
Preferred
MOVZX eax, byte ptr [ebx]
40546 Rev. 3.09 November 2008
Example 3
Avoid
MOV al, 01h
Preferred
MOV eax, 00000001h
Example 4
The following recommendation only applies when both instruction operands of the MOVSS instruction are registers.
Avoid
MOVSS xmm1, xmm2
Preferred
MOVAPS xmm1, xmm2
62 Instruction-Decoding Optimizations Chapter 4
Page 81
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
Example 5
While this example uses instructions with double-precision data type, the principle also applies to instructions with single-precision data types.
Avoid
MOVLPD xmm1, QWORD PTR[eax] ; ; Address may or may not be ; 16-byte aligned. MOVHPD xmm1, QWORD PTR[eax+8];
Preferred
MOVUPD xmm1, XMMWORD PTR[eax] ;
Example 6
Avoid
MOVLPD xmm1, QWORD PTR [eax]
MOVHPD xmm1, QWORD PTR [eax] ; Same memory location as used for MOVLPD.
Preferred
MOVDDUP xmm1, QWORD PTR [eax];
Example 7
The following recommendation only applies when both operands of the MOVSD instruction are registers. If the source operand of the MOVSD instruction is a memory operand, the high-order 64 bits of the destination register are zeroed out, thereby avoiding any merge dependency on the destination register.
Avoid
MOVSD xmm1, xmm2
Preferred
MOVAPD xmm1, xmm2
Chapter 4 Instruction-Decoding Optimizations 63
Page 82
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
Example 8
When the source operand of the MOVSD instruction is a memory operand, the high-order 64 bits of the destination register are zeroed out, thereby avoiding any merge dependency on the destination register.
Avoid
MOVLPD xmm1, mem64
Preferred
MOVSD xmm1, mem64
Example 9
The SQRTSD instruction writes only the lower 64 bits of xmm1 and so should be moved well below the write from the MULPD. In addition to SQRTSD, this example also applies for other instructions such as CVTPI2PS, CVTSI2SD, CVTSS2SD, UNPCKLPD, PUNPCKLQDQ, MOVLHPS and MOVHLPS.
Avoid
MULPD xmm1, xmm3 SQRTSD xmm1, xmm2
Preferred
MULPD xmm1, xmm3
.....schedule some other unrelated instructions here
SQRTSD xmm1, xmm2

4.9 Using LEAVE for Function Epilogues

Optimization
The recommended optimization for function epilogues depends on whether the function allocates local variables.
If the function Then
Allocates local variables. Replace the traditional function epilogue with the LEAVE instruction.
Does not allocate local variables or does not have a frame-pointer.
Do not use function prologues or epilogues. Access function arguments and local variables through rSP.
64 Instruction-Decoding Optimizations Chapter 4
Page 83
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
Functions That Allocate Local Variables
The LEAVE instruction is a single-byte instruction and saves 2 bytes of code space over the traditional epilogue. Replacing the traditional sequence with LEAVE also preserves decode bandwidth.
Functions That Do Not Allocate Local Variables
Accessing function arguments and local variables directly through ESP frees EBP for use as a general-purpose register.
Background
The function arguments and local variables inside a function are referenced through a so-called frame pointer. In AMD64 code, the base pointer register (rBP) is customarily used as a frame pointer. You set up the frame pointer at the beginning of the function using a function prologue:
push ebp ; Save old frame pointer. mov ebp, esp ; Initialize new frame pointer. sub esp, n ; Allocate space for local variables (only if the ; function allocates local variables).
Function arguments on the stack can now be accessed at positive offsets relative to rBP, and local variables are accessible at negative offsets relative to rBP.
Example
The traditional function epilogue looks like this:
mov esp, ebp ; Deallocate local variables (only if space was allocated). pop ebp ; Restore old frame pointer.
Replace the traditional function epilogue with a single LEAVE instruction:
leave
Chapter 4 Instruction-Decoding Optimizations 65
Page 84
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008

4.10 Alternatives to SHLD Instruction

Optimization
Where register pressure is low, replace the SHLD instruction with alternative code using ADD and ADC, or SHR and LEA.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
Using alternative code in place of SHLD achieves lower overall latency and requires fewer execution resources. The 32-bit and 64-bit forms of ADD, ADC, SHR, and LEA (except 16-bit form) are DirectPath instructions, while SHLD is a VectorPath instruction. Use of the replacement code optimizes decode bandwidth because it potentially enables the simultaneous decoding of a third DirectPath instruction. However, the replacement code may increase register pressure because it destroys the contents of one register (reg2 in the following examples) whereas the register is preserved by SHLD.
Example 1
Replace this instruction:
shld reg32a, reg32b, 1 ; Operands are 32-bit registers.
with this code sequence:
add reg32b, reg32b ; Operands are 32-bit registers adc reg32a, reg32a
Example 2
Replace this instruction:
shld reg1, reg2, 2
with this code sequence:
shr reg2, 30 lea reg1, [reg1*4+reg2]
66 Instruction-Decoding Optimizations Chapter 4
Page 85
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
Example 3
Replace this instruction:
shld reg1, reg2, 3
with this code sequence:
shr reg2, 29 lea reg1, [reg1*8+reg2]

4.11 8-Bit Sign-Extended Immediate Values

Optimization
Use 8-bit sign-extended immediate values instead of larger-size values.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
Using 8-bit sign-extended immediate values improves code density with no negative effects on the processor.
Example
Consider this instruction:
add bx, -5
Avoid encoding it as:
81 C3 FF FB
Instead, encode it as:
83 C3 FB
Chapter 4 Instruction-Decoding Optimizations 67
Page 86
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008

4.12 8-Bit Sign-Extended Displacements

Optimization
Use 8-bit sign-extended displacements for conditional branches.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
Using short, 8-bit sign-extended displacements for conditional branches improves code density with no negative effects on the processor. See “Branch Alignment and Density” on page 99 for more details on optimizing branches.
4.13 Code Padding with Operand-Size Override and
Multibyte NOP
Optimization
Use the multibyte NOP instruction (0F 1Fh) to align code and space out branches..
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
Occasionally it is necessary to insert neutral code fillers into the code stream (for example, for code­alignment purposes or to space out branches). Because this filler code is executable, it should take up as few execution resources as possible, should not diminish decode density, and should not modify any processor state other than to advance the instruction pointer (rIP). Although there are several possible multibyte NOP-equivalent instructions that do not change the processor state (other than rIP), combinations of the operand-size override and the multibyte NOP instruction are more efficient. These NOP instructions are only available on AMD Athlon™ and later processors. For processors older than Athlon, use the standard NOP (opcode 090h) in combination with up to three operand size
68 Instruction-Decoding Optimizations Chapter 4
Page 87
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
override prefixes (opcode 66h). The use of more than three legacy prefixes limits decoder performance.
Chapter 4 Instruction-Decoding Optimizations 69
Page 88
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
Example
Assign code-padding sequences like these and use them to align code and space out branches. These sequences are suitable for both 32-bit and 64-bit code, and you can use them on the AMD Family 10h processors:
NOP1_OVERRIDE_NOP TEXTEQU <DB 090h> NOP2_OVERRIDE_NOP TEXTEQU <DB 066h, 090h> NOP3_OVERRIDE_NOP TEXTEQU <DB 00fh, 01fh, 000h> NOP4_OVERRIDE_NOP TEXTEQU <DB 00fh, 01fh, 040h, 000h> NOP5_OVERRIDE_NOP TEXTEQU <DB 00fh, 01fh, 044h, 000h, 000h> NOP6_OVERRIDE_NOP TEXTEQU <DB 066h, 00fh, 01fh, 044h, 000h, 000h> NOP7_OVERRIDE_NOP TEXTEQU <DB 00fh, 01fh, 080h, 000h, 000h, 000h, 000h> NOP8_OVERRIDE_NOP TEXTEQU <DB 00fh, 01fh, 084h, 000h, 000h, 000h, 000h, 000h> NOP9_OVERRIDE_NOP TEXTEQU <DB 066h, 00fh, 01fh, 084h, 000h, 000h, 000h, 000h, 000h> NOP10_OVERRIDE_NOP TEXTEQU <DB 066h, 066h, 00fh, 01fh, 084h, 000h, 000h, 000h, 000h, 000h> NOP11_OVERRIDE_NOP TEXTEQU <DB 066h, 066h, 066h, 00fh, 01fh, 084h, 000h, 000h, 000h, 000h, 000h>
In certain rare situations, padding of up to 31 bytes can improve performance by aligning “hot” branch targets. For example, run-time profile information may reveal that a forward branch is very often taken. In these cases, generate padding by combining a minimum number of the large NOP instructions used in the above code-padding sequences.
For x87 floating-point instructions, a better single-byte padding exists. See “Align and Pack DirectPath x87 Instructions” on page 173. For aligning loop tops, see “Loop Iteration Boundaries” on page 56.
70 Instruction-Decoding Optimizations Chapter 4
Page 89
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors

Chapter 5 Cache and Memory Optimizations

The optimizations in this chapter take advantage of the large L1 caches and high-bandwidth buses of AMD Family 10h processors.
This chapter covers the following topics:
Topic Page
Memory-Size Mismatches 71
Natural Alignment of Data Objects 73
Store-to-Load Forwarding Restrictions 74
Prefetch and Streaming Instructions 81
Write-Combining 89
L1 Data Cache Bank Conflicts 90
Placing Code and Data in the Same 64-Byte Cache Line 91
Memory and String Routines 92
Stack Considerations 94
Cache Issues When Writing Instruction Bytes to Memory 95
Interleave Loads and Stores 96
Using 1-Gbyte Virtual Memory Pages 96

5.1 Memory-Size Mismatches

Optimization
Avoid memory-size mismatches when different instructions operate on the same data. When one instruction stores and another instruction subsequently loads the same data, align instruction operands an
d keep the loads/stores of each operand the same size.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Examples—Store-to-Load-Forwarding Stalls
The following code examples result in a store-to-load-forwarding stall:
Chapter 5 Cache and Memory Optimizations 71
Page 90
Software Optimization Guide for AMD Family 10h Processors
Avoid (64-bit)
foo DQ ? ; Assume foo is 8-byte aligned. ... mov DWORD PTR foo, eax ; Store a DWORD to foo. mov DWORD PTR foo+4, ebx ; Now store to foo+4. mov rcx, QWORD PTR foo ; Load a QWORD from foo.
Avoid (32-bit)
foo DQ ? ; Assume foo is 4-byte aligned. ... mov DWORD PTR foo, eax ; Store a DWORD in foo. mov DWORD PTR foo+4, edx ; Store a DWORD in foo+4. fld QWORD PTR foo ; Load a QWORD from foo.
Avoid
mov foo, eax mov foo+4, edx ... movq mm0, foo
40546 Rev. 3.09 November 2008
Preferred
mov foo, eax mov foo+4, edx ... movd mm0, foo punpckldq mm0, foo+4
Preferred If Stores Are Close to the Load
movd mm0, eax mov foo+4, edx punpckldq mm0, foo+4
Examples—Large-to-Small Mismatches
Avoid large-to-small mismatches, as shown in the following code:
Avoid (64-bit)
foo DQ ? ; Assume foo is 8-byte aligned. ... mov QWORD PTR foo, rax ; Store a QWORD to foo. mov eax, DWORD PTR foo ; Load a DWORD from foo. mov edx, DWORD PTR foo+4 ; Load a DWORD from foo+4.
Avoid (32-bit)
foo DQ ? ; Assume foo is 4-byte aligned.
72 Cache and Memory Optimizations Chapter 5
Page 91
40546 Rev. 3.09 November 2008
... fst QWORD PTR foo ; Store a QWORD in foo. mov eax, DWORD PTR foo ; Load a DWORD from foo. mov edx, DWORD PTR foo+4 ; Load a DWORD from foo+4.
Software Optimization Guide for AMD Family 10h Processors
Avoid
movq foo, mm0 ... mov eax, foo mov edx, foo+4
Preferred
movd foo, mm0 pswapd mm0, mm0 movd foo+4, mm0 pswapd mm0, mm0 ... mov eax, foo mov edx, foo+4
Preferred If the Contents of MM0 are No Longer Needed
movd foo, mm0 punpckhdq mm0, mm0 movd foo+4, mm0 ... mov eax, foo mov edx, foo+4
Preferred If the Stores and Loads are Close Together, Option 1
movd eax, mm0 pswapd mm0, mm0 movd edx, mm0 pswapd mm0, mm0
Preferred If the Stores and Loads are Close Together, Option 2
movd eax, mm0 punpckhdq mm0, mm0 movd edx, mm0

5.2 Natural Alignment of Data Objects

Optimization
Make sure data objects are naturally aligned. An object is naturally aligned if it is located at an address that is a multiple of its size.
Chapter 5 Cache and Memory Optimizations 73
Page 92
Software Optimization Guide for AMD Family 10h Processors
Locate this type of object At an address evenly divisible by
Word 2
Doubleword 4
Quadword 8
Ten-byte (for example, TBYTE or REAL10) 8 (instead of 10)
Double quadword 16
40546 Rev. 3.09 November 2008
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
A misaligned store or load operation suffers a minimum one-cycle penalty in the processor’s load­store pipeline. Also, using misaligned loads and stores increase the likelihood of encountering a store­to-load forwarding pitfall, especially when operating in long mode (64-bit software). (For a more detailed discussion of store-to-load forwarding issues, see “Store-to-Load Forwarding Restrictions” on page 74.)
In addition, if the Alignment Mask bit is set in Control Register 0 (CR0), an unaligned memory reference may cause an alignment check exception. For more information on this topic, see the AMD64 Architecture Programmer’s Manual, Volume 2, order# 24593.

5.3 Store-to-Load Forwarding Restrictions

Optimization
Maintain consistent operand sizes across all loads and stores. Preferably use doubleword, quadword, or 128-bit operand sizes. Avoid store-to-load forwarding pitfalls, such as
• narrow-to-wide forwarding cases.
• mismatched addresses for stores and loads.
• misaligned data references.
• loading data from anywhere in the same doubleword of memory other than the identical start
addresses of the stores when using word or byte stores
74 Cache and Memory Optimizations Chapter 5
Page 93
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
Store-to-load forwarding refers to the process of a load reading (forwarding) data from the store buffer. Where this is possible, it can lead to a performance improvement because the load does not have to wait for the recently written (stored) data to be written to cache and then read back out again.
There are circumstances under which AMD Family 10h processor load-store (LS) architecture does not allow data to be read from a store in the store buffer. In these cases, it is impossible to load the needed data into a register until the store has retired out of the store buffer and written to the data cache. A store-buffer entry cannot retire and write to the data cache until every instruction before the store has completed and retired from the reorder buffer. The implication of this restriction is that all instructions in the reorder buffer, up to and including the store, must complete and retire out of the reorder buffer before the load can complete. Effectively, the load has a false dependency on every instruction up to the store.
Due to the significant depth of the LS buffer of AMD Family 10h processors, any load that is dependent on a store that cannot bypass data through the LS buffer may experience significant delays of up to tens of clock cycles, where the exact delay is a function of pipeline conditions.
The following sections describe store-to-load forwarding examples.
Store-to-Load Forwarding Pitfalls—True Dependencies
A load is not allowed to read data from the store-buffer entry if any of the following conditions occur:
• The start address of the load does not match the start address of the store.
• The load operand size is greater than the store operand size.
• Either the load or the store is misaligned. See “Natural Alignment of Data Objects” on page 73 for
additional information on alignment recommendations.
• A high byte (or word) store and a low byte (or word) store in the same aligned doubleword are
followed by either a low or high byte (or word) load.
The following sections describe common-case scenarios to avoid. In these scenarios, a load has a true dependency on an LS2-buffered store, but cannot read (forward) data from a store-buffer entry.
Load Operand Size Greater than the Store Operand Size
If the following conditions are present, there is a narrow-to-wide store-buffer data-forwarding restriction:
Chapter 5 Cache and Memory Optimizations 75
Page 94
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
• The operand size of the store data is smaller than the operand size of the load data.
• The range of addresses spanned by the store data covers some subrange of the addresses spanned
by the load data.
Examples
Avoid
mov eax, 10h mov WORD PTR [eax], bx ; Word store ... mov ecx, DWORD PTR [eax] ; Doubleword load--cannot forward upper byte ; from store buffer
Avoid
MOV eax, 10h MOV BYTE PTR [eax+3], bl ; Byte store ... MOV ecx, DWORD PTR [eax] ; Doubleword load--cannot forward upper byte ; from store buffer
Avoid
MOV eax, 10h MOVSD QWORD PTR [eax], xmm0 ; Quadword store MOVSD QWORD PTR [eax+8], xmm1 ; Quadword store
...
MOVAPD xmm2, XMMWORD PTR [eax] ; Octal Word load--cannot forward upper and ; lower Quadwords from store buffer.
Preferred
MOV eax, 10h
MOVAPD xmm3, xmm0 ; Assumes XMM3 is available and will not be detrimental ; to register pressure
SHUFPD xmm3, xmm1, 0
MOVAPD XMMWORD PTR [eax], xmm3
....
MOVAPD xmm2, XMMWORD PTR [eax] ; Octal Word load--can forward from ; Octal word store from store buffer
76 Cache and Memory Optimizations Chapter 5
Page 95
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
Mismatched Store and Load Addresses
A data-forwarding restriction exists if the start address of the store data does not match the start address of the load data.
In general, wide stores can forward data to narrow loads if the start address of the load matches that of the store and neither store nor load is misaligned. However, store-to-load forwarding cannot occur if the start addresses of the load and store do not match, with the exception that stores to an aligned 128­bit location can forward to loads of 64 bits or less, starting at its upper 64-bit quadword.
Examples
Avoid
movq [foo], mm1 ; Store upper and lower half. ... add eax, [foo] ; Fine add edx, [foo+4] ; Not good!
Preferred
movd [foo], mm1 ; Store lower half. punpckhdq mm1, mm1 ; Copy upper half into lower half. movd [foo+4], mm1 ; Store lower half. ... add eax, [foo] ; Fine add edx, [foo+4] ; Fine
Acceptable
mov eax, 10h movapd XMMWORD PTR [eax], xmm0 ; Store upper and lower half.
...
movsd xmm1, QWORD PTR [eax] ; Fine movsd xmm2, QWORD PTR [eax+8] ; Load of upper 64 bits, OK.
Misaligned Store-Buffer Data-Forwarding Restriction
If the following condition is present, there is a misaligned store-buffer data-forwarding restriction:
• The store or load address is misaligned. For example, a quadword store is not aligned to a
quadword boundary.
A common case of misaligned store-data forwarding involves the passing of misaligned quadword floating-point data on the doubleword-aligned integer stack. Avoid the type of code shown in the following example:
mov esp, 24h fstp QWORD PTR [esp] ; ESP = 24
Chapter 5 Cache and Memory Optimizations 77
Page 96
Software Optimization Guide for AMD Family 10h Processors
... ; Store occurs to quadword misaligned address. fld QWORD PTR [esp] ; Quadword load cannot forward from quadword ; misaligned ‘FSTP[ESP]’ store operation.
40546 Rev. 3.09 November 2008
Forwarding Restriction from Distinct Stores on Distinct Bytes (or Words) to a Subsequent Load on One of the Same Bytes (or Words) Within the Same Aligned Doubleword Location
When there are two or more distinct stores to distinct bytes (or words) inside the same aligned doubleword memory location, it may not be possible to forward the data from the stores to a subsequent load from one of the same byte (or word) locations. Therefore, it is recommended to use doubleword, quad word or 128-bit operand sizes to allow store-to-load forwarding.
However, when there is only a single store and a single load to a byte (or word) inside an aligned doubleword location, store-to-load forwarding is allowed to occur as long as all of the other conditions listed previously in this section for store-to-load forwarding are satisfied.
Examples
In all of the examples below, the operations in between the store and the load indicated by the ... are assumed not to write to any part of the aligned doubleword under consideration.
Allowed
mov eax, 10h mov BYTE PTR [eax], bl ; Low-byte store to an aligned doubleword ... mov dl, BYTE PTR[eax] ; low byte load CAN forward from low byte store
Allowed
mov eax, 10h mov WORD PTR [eax], bx ; Low-word store to an aligned doubleword ...
mov dl, BYTE PTR[eax] ; low byte load CAN forward from low word store
Allowed
mov eax, 10h mov DWORD PTR [eax], ebx ; doubleword store to an aligned doubleword ... mov dx, WORD PTR[eax] ; low word load CAN forward from doubleword store
Avoid
mov eax, 10h mov BYTE PTR[eax], bl ; Low-byte store to an aligned doubleword mov BYTE PTR[eax+1], bh ; High-byte store to an aligned doubleword
78 Cache and Memory Optimizations Chapter 5
Page 97
40546 Rev. 3.09 November 2008
... mov dl, BYTE PTR [eax] ; low byte load cannot forward from low byte store
Software Optimization Guide for AMD Family 10h Processors
Preferred
mov eax, 10h mov WORD PTR [eax], bx ; ... mov dl, BYTE PTR [eax] ;
Avoid
mov eax, 10h mov BYTE PTR[eax], bl ; Low-byte store to an aligned doubleword mov BYTE PTR[eax+1], bh ; High-byte store to an aligned doubleword ... mov dl, BYTE PTR [eax] ; low byte load cannot forward from low byte store mov dh, BYTE PTR [eax+1]; high byte load CAN forward from high byte store
Preferred
mov eax, 10h mov WORD PTR [eax], bx ; ... mov dx, WORD PTR [eax] ;
Summary of Store-to-Load-Forwarding Pitfalls to Avoid
The following list summarizes the situations that require care to handle store-to-load forwarding cases:
• Avoid narrow-to-wide forwarding cases.
• Avoid mismatched addresses for stores and loads.
• Avoid misaligned data references.
• When using word or byte stores, avoid having two or more distinct stores to distinct bytes (or
words) inside the same aligned doubleword memory location followed by a subsequent load from one of the same byte (or word) locations.
• Maintain consistent operand sizes across all loads and stores. Preferably use doubleword,
quadword, or 128-bit operand sizes.
Chapter 5 Cache and Memory Optimizations 79
Page 98
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
5.4 Good Practices for Avoiding False Store-to-Load
Forwarding
Optimization
Choose linear addresses for the source and destination operands of REP MOVS/CMPS that are not an exact multiple of 4K pages away from each other.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
As mentioned in the previous section, store-to-load forwarding occurs when the store address matches the load address. This address match is split into two stages. In the first stage, bits 4:11 of the store and the load addresses are matched. In addition the double word mask of the store and load addresses is matched. The double word mask indicates whether the load/store pair is accessing the same double word in a 16-byte bank. If both these parameters match, then a store-to-load forward is initiated. In the second stage the remaining bits 12:47 of the store and load addresses is matched. If the remaining bits match, then the STLF is considered as a true STLF and is allowed to proceed. Otherwise it is considered as a false STLF and the load is cancelled and retried.
The previous section deals with true STLF and describes the practices to follow to promote it. This section deals with the cases of false STLF and what the developer needs to do to avoid these from occurring in the first place, thereby avoiding the later penalty of STLF cancellation.
Example
For REP MOVS/CMPS, choose linear addresses that avoid conflicts.
REP stands for the repeat function. This function repeats or iterates its associated string instruction as many times as specified in the counter register (rCX) and terminates the repetition when the value in rCX reaches 0. For example, REP MOVS moves a string from a source address to a destination address a specified number of times. In the event that bits 4:11 of the linear address of the store address in the first iteration match the load address in the second iteration, a store-to-load forward may be initiated.
When the destination address of an iteration is located at an exact multiple of 4K pages away from the source address of the next iteration, an STLF will be initiated. When the remaining address bits are found to be mismatched later, the STLF is cancelled and the load has to be retried. This results in a significant penalty of wasted DC bandwidth due to having to retry loads multiple times.
80 Cache and Memory Optimizations Chapter 5
Page 99
40546 Rev. 3.09 November 2008
Software Optimization Guide for AMD Family 10h Processors
For example, a REP MOVS instruction suffers from these inefficiencies if RSI is 0x1ffeee000000 and RDI is 0x1ffeee401000.

5.5 Prefetch and Streaming Instructions

Optimization
Where appropriate, use one of the prefetch instructions to increase the effective bandwidth of AMD Family 10h processors.
Application
This optimization applies to:
• 32-bit software
• 64-bit software
Rationale
Prefetch instructions take advantage of the high bus bandwidth of AMD Family 10h processors to hide latencies when fetching data from system memory. A prefetch instruction initiates a read request of a specified address and reads the entire cache line that contains that address.
AMD Family 10h processors perform three types of prefetches:
Prefetch type Description
Load Reads the data into the L1 data cache; the data is later evicted to the L2 cache. The
following instructions perform load prefetches: PREFETCH, PREFETCHT0, PREFETCHT1, and PREFETCHT2.
Store Reads the data into the L1 data cache and marks the data as modified; the data is
later evicted to the L2 cache. The PREFETCHW instruction performs a store prefetch.
Nontemporal The PREFETCHNTA instruction performs a nontemporal prefetch. The data is read
into the L1 data cache; to avoid cache pollution, when a PREFETCHNTA misses in the L2 cache and reads from memory, the data is never evicted to the L2 cache. When a PREFETCHNTA hits in the L2 cache, the data is evicted back to the L2 cache.
The prefetch instructions can be used anywhere, in any type of code. The use of prefetch instructions is not affected by the values of Control Register 0 (CR0) bits, such as CR0.EM and CR0.TS.
Prefetching versus Preloading
In code that makes irregular memory accesses rather than seq
uential accesses, an ordinary MOV instruction is the best way to load data. But in situations where sequential addresses are read, prefetch instructions can improve performance. Prefetch instructions only update the L1 data cache and do not update an architectural register.
Chapter 5 Cache and Memory Optimizations 81
Page 100
Software Optimization Guide for AMD Family 10h Processors
40546 Rev. 3.09 November 2008
Unit-Stride Access
Large data sets typically require unit-stride access to ensure that all data pulled in by a prefetch instruction are actually used. Large data sets make use of all data that are read from memory, rather than using only a sparse subset of the memory. If necessary, you should reorganize algorithms or data structures to allow unit-stride access. For a definition of unit-stride access, see “Definitions” on page 88.
Hardware Prefetcher Optimizations
Previous AMD64 processors prefetched data into the L2 cache. In AMD Family 10h processors, the data hardware prefetcher loads data into the L1 cache. This hides the L2 cache access latency and offers significant performance improvement. However, this slightly increases the risk of thrashing and cache pollution, as discussed later in Section 5.5.
The hardware prefetcher in AMD Family 10h processors is a unit-stride prefetcher which trains on L1 cache misses and propagates on L1 cache accesses (hits and misses). Any two consecutive cache line misses can train a hardware prefetch stream, and this generates a preset number of initial prefetch requests. Any subsequent unit-stride accesses propagate the stream, causing more cache lines to be prefetched. For example, if the preset value is 3 and there are L1 misses to lines I and I+1, the prefetcher issues prefetch requests for lines I+2, I+3, and I+4. Subsequently, if a hit or miss to line I+2 is seen, a prefetch request for I+5 is issued, and so on.
Adaptive Prefetching
In AMD Family 10h processors, a hardware optimization called adaptive prefetching is implemented to improve the timeliness of the prefetches. This mechanism basically kicks in if the demand stream catches up with the prefetch stream, and it adjusts the prefetch distance dynamically to maintain a good prefetch distance. Here, a good prefetch distance is defined as the number of cachelines the prefetch stream needs to stay ahead, such that the demand stream hits on prefetched lines in the L1 cache. Again, the hardware has a preset maximum fetch-ahead distance that controls this dynamic scheme. As part of this adaptive scheme, the hardware prefetcher in AMD Family 10h processors maintains pending prefetch request counters and adjustable distance counters. This helps the prefetcher to scale with different memory technologies.
Note that in AMD Family 10h processors, the hardware prefetcher trains on software prefetch requests (including the NTA type).
Contraindications for Prefetching
There are situations in which careless software prefetching can hurt performance.
• Thrashing—This is potentially the worst scenario. Thrashing occurs if more than two arrays are
prefetched in parallel and the addresses are separated by whole multiples of 32K bytes (the L1 cache size divided by the associativity). When this occurs, some of the prefetched data evicts other prefetched data before it can be used. This is inefficient even without prefetching—which simply makes the situation worse. Thrashing can be particularly bad if PREFETCHNTA is used.
82 Cache and Memory Optimizations Chapter 5
Loading...