What should optimized compiled code for copying 3 bytes from one place to another, say, using `memcpy(,,3)` look like, in terms of assembly instructions?

Consider the following program:

```
#include <string.h>
int main() {
  int* p = (int*) 0x10;
  int x = 0;
  memcpy(&x, p, 4);
  x = x * (x > 1 ? 2 : 3);
  memcpy(p, &x, 4);  
  return 0;
}

```

it's a bit contrived a will cause a segmentation violation, but I need those instructions so that compiling with `-O3` doesn't make all of it go away. When I [compile this](https://godbolt.org/g/SNY4Ro) (GodBolt, GCC 6.3 -O3), I get:

```
main:
        mov     edx, DWORD PTR ds:16
        xor     eax, eax
        cmp     edx, 1
        setle   al
        add     eax, 2
        imul    eax, edx
        mov     DWORD PTR ds:16, eax
        xor     eax, eax
        ret

```

great - a single `mov` of a DWORD (= 4 bytes) from memory to a register. Nice and optimized. Now let's change the `memcpy(&x, p1, 4)` into `memcpy(&x, p1, 3)`? The compilation result becomes:

```
main:
        mov     DWORD PTR [rsp-4], 0
        movzx   eax, WORD PTR ds:16
        mov     WORD PTR [rsp-4], ax
        movzx   eax, BYTE PTR ds:18
        mov     BYTE PTR [rsp-2], al
        mov     edx, DWORD PTR [rsp-4]
        xor     eax, eax
        cmp     edx, 1
        setle   al
        add     eax, 2
        imul    eax, edx
        mov     DWORD PTR ds:16, eax
        xor     eax, eax
        ret

```

I'm not much of an exprt on Intel X86\_64 assembly (read: I can't even read it properly when it's complicated), so - I don't quite get this. I mean, I get what's happening in the first 6 instructions and why so many of them are necessary. Why aren't two moves sufficient? A `mov WORD PTR` int `al` and a `mov BYTE PTR` into `ah`? 

... so, I came here to ask. As I was writing the question I noticed GodBolt also has clang as an option. Well, clang (3.9.0 -O3) does this:

```
main:                                   # @main
        movzx   eax, byte ptr [18]
        shl     eax, 16
        movzx   ecx, word ptr [16]
        or      ecx, eax
        cmp     ecx, 2
        sbb     eax, eax
        and     eax, 1
        or      eax, 2
        imul    eax, ecx
        mov     dword ptr [16], eax
        xor     eax, eax
        ret

```

which looks more like what I expected. What explains the difference?

**Notes:**

* It's the same behavior essentially if I don't initialize `x = 0`.
* Other GCC versions do about the same thing as GCC 6.3, but GCC 7 is down to 5 instead of 6 `mov`'s.
* Other versions of clang (starting from 3.4) do about the same thing.
* The behavior is similar if we forego memcpy'ing for the following:

```
#include <string.h>

typedef struct {
  unsigned char data[3];
}  uint24_t;

int main() {
  uint24_t* p = (uint24_t*) 0x30;
  int x = 0;
  *((uint24_t*) &x) = *p;
  x = x * (x > 1 ? 2 : 3);
  *p = *((uint24_t*) &x);
  return 0;
} 

```
* If you want to contrast with what happens when the relevant code is in a function, have a look at [this](https://godbolt.org/g/5EDSvC) or [the uint24\_t struct version](https://godbolt.org/g/lDJSRm) (GodBolt). Then have a look at [what happens for 4-byte values](https://godbolt.org/g/EkV5KE).