Instruction
MOVSD
Moves the low double between XMM registers or to and from memory; a load zeroes the upper half, a register move keeps it.
- Extensions
- Forms
- 4 (4 Legacy)
- Data
- Intel XED v2026.08.23
MOVSD moves one double, the low 64 bits of an XMM register. It is SSE2’s scalar move, and it shares its name with the doubleword form of the string instruction MOVS; assemblers tell the two apart by their operands. What it does to the rest of the register depends on where the double comes from:
- From memory it fills the whole XMM register: the double goes to bits 63:0 and bits 127:64 become zero. Zen 5’s recorded load did so and left bits 511:128 as they were, as every legacy SSE instruction does.
- To memory it writes eight bytes and nothing else; the recorded store left the bytes after them alone.
- Between registers it replaces only bits 63:0 of the destination
and keeps bits 127:64, so the old destination is an input. There are
two encodings for this, 0F 10 and 0F 11, which GNU as picks with its
{load}and{store}prefixes; both recorded cases kept the high double.
No form converts or rounds anything, so MXCSR plays no part, and the memory operand need not be aligned. MOVSS is the same instruction for singles, MOVQ the move that clears the high half even from a register, and VMOVSD the VEX and EVEX form, which merges with a second source rather than with the destination.
In compiled code
In our builds at -O2, GCC 14 and Clang 23 load and store double values
with it. A plain copy of a double between registers uses another
instruction: GCC uses MOVAPD and Clang MOVAPS, which
write the whole register. Intel’s optimization guide recommends that
choice, since a register-to-register move waits for whatever last wrote
its destination, while a load from memory breaks that dependence
(Sections 3.5.2.4 and 3.5.2.6). The register form appears when merging
is the point, for _mm_move_sd or storing into element 0 of a
__m128d; with -march=x86-64-v2, Clang writes those as
BLENDPS with an immediate of 3, and GCC keeps the
merging move. For _mm_load_sd, GCC loads with MOVQ and Clang with this
instruction, to the same result.
In the optimization guide
What the optimization guide says about MOVSD, a line per claim. Each links to the claim in the guide, with its sources and where they differ.
Out of order
- Partial register and flag writes: Scalar SSE instructions that write only the low element of an XMM register keep the rest of it, and so wait for its last writer:
movssandmovsdbetween registers,movlpdandmovhpdfrom memory, and conversions and square roots such ascvtsi2sdandsqrtss.
Forms
Data flow
Where the elements of the sources go, element 0 on the right; results that depend on a control value are drawn for an example. How to read.
MOVSD xmm, m64Result doubles 1 to 0: 0, a0.
MOVSD m64, xmmm64 receives double 0 of xmm2: a0.
Result doubles 1 to 0: unchanged, a0.
Operation
What the forms do, in pseudocode that our tests run against results recorded on real processors. How to read.
MOVSD xmm, m64xmm1.write(mem.q[0]) # bits 127:64 zeroed
# bits 128 and up of the register are unchangedRun on AMD Zen 5 (EPYC 9645): 1 case.
MOVSD m64, xmmmem.q[0] = xmm2.q[0]Run on AMD Zen 5 (EPYC 9645): 1 case.
xmm1.q[0] = xmm2.q[0] # the others keep their values
# bits 128 and up of the register are unchangedRun on AMD Zen 5 (EPYC 9645): 2 cases.
Operands
| Operand | Kind | Action |
|---|---|---|
MOVSD xmm, xmm/m64 | ||
xmm | explicit | write |
xmm/m64 | explicit | read |
MOVSD xmm/m64, xmm | ||
xmm/m64 | explicit | write |
xmm | explicit | read |
Flags
None: XED records no flag that the forms test or change.
Exceptions
The exception class is XED's name for the set of exception conditions that a form follows. How to read.
- All forms
SSE_TYPE_5
Intrinsics
The C intrinsics of Clang 23.1.2 that compile to MOVSD, each with the form it compiles to and the Clang options it needs. The forms come from compiling every intrinsic and decoding the result with Intel XED; all intrinsics A–Z explains the method.
| Intrinsic | Compiles to |
|---|---|
_mm_load_sd
__m128d _mm_load_sd(const double *__dp) |
|
CPUID and processors
Each form belongs to an XED ISA set. A form can be used when the processor reports every CPUID bit of one of its ISA set's alternatives.
| ISA set | CPUID | Processors |
|---|---|---|
SSE2 | SSE2 | Every x86-64 processor in XED’s model and Zen 3 to Zen 6 |
More SSE2 instructions
Sources
- Intel XED v2026.08.23 (commit
0bcb6237345c): forms, encodings, operands, flags, exception classes, attributes, ISA sets, CPUID bits and chip model. - The CPU data of x86-64.net: Zen 3 to Zen 6, from GCC’s
-marchfeature sets and AMD’s Processor Programming References, which the page of each processor cites. - Clang's x86 intrinsic headers, LLVM 23.1.2 (commit
85ac56026243): the intrinsics, their signatures and doc comments, and the Clang of that release, which compiled each of them. - Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 2 (325383-093, September 2026): Volume 2B, page 4-108 (MOVSD)
- Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 1 (253665-093, September 2026)
- AMD64 Architecture Programmer's Manual, Volume 4: 128-Bit and 256-Bit Media Instructions (26568, rev. 3.25, November 2021), Wayback Machine copy of AMD's PDF
- Intel 64 and IA-32 Architectures Optimization Reference Manual, Volume 1 (248966-051, October 2026)
The tables are derived from Intel XED, Copyright Intel Corporation, licensed under the Apache License 2.0; x86-64.net converted and reformatted them. The intrinsics and their signatures come from Clang, part of the LLVM Project, licensed under the Apache License 2.0 with LLVM Exceptions. The text is our own.