x86-64 is a perfectly acceptable ISA. Strong memory ordering, no architectural optimizations leaking out like branch delay slots or stack windows. Pretty good i-cache efficiency through the use of two-address code and memory operands. Of course, Intel didn't have much to do with it. Most of it is either an accident of history or the work of AMD, who a lot of work regularizing the ISA in the 64-bit transition.
1. Yeah, ARM has one nasty architectural optimization leaking out: the program counter register being 8 bytes ahead of where it should be due to pipelining. Thankfully that got fixed up in AArch64, and if 32-bit mode gets dropped down the line (which is allowed by the architecture) it'll be a thing of the past. x86 has some architectural leaks too, though: the aliasing of the MMX and FP stacks as a hack for compatibility with early versions of Windows comes to mind. This one hasn't been fixed.
2. The REX prefixes are a nightmare: most instructions have one and this tremendously bloats up the instruction stream size. For this reason, the i-cache efficiency is not good compared to actual compressed instruction sets such as Thumb-2 (not that Thumb-2 is wonderful either). Note that if you do extreme hand-optimization of binary size, you can get x86-64 down pretty far, but so few people do that that it doesn't matter in practice.
3. Two address code isn't necessarily a win, especially since it doubles the number of REX prefixes. In AArch64 "and x9,x10,x11" is 4 bytes; in x86-64 "mov r9,r10; and r9,r11" is 6 bytes (and clobbers the condition codes). There's a reason compilers love to emit the three-address LEA...
4. Memory operands are nice, though I think the squeeze on instruction space makes them not worth it in practice. I'd rather use that opcode space for more registers.
5. Immediate encoding on x86-64 is crazy inefficient. "mov rax,1" is a whopping 7 bytes.
Regarding 5, no, it's five bytes (b8 01 00 00 00) for movl $1,%eax. If you actually have a 64-bit immediate, just the immediate itself would be 8 bytes, and the actual instruction is 10 bytes.
Like, implementation details that leak out into the architecture for optimization reasons. Classic example is branch delay slots: https://en.wikipedia.org/wiki/Delay_slot.
> Almost everything that you described is microarchitectural, and not tied to the ISA.
They listed these features 'strong memory ordering', '(no) branch delay slots', '(no) stack windows', 'good i-cache efficiency through the use of two-address code and memory operands'.
Every single one of those is a property of the ISA - the instruction set, its semantics and encoding - not the implementation.
strong memory ordering is a contract. There is nothing intrinsic about the ISA, or its virtues, that dictates the ordering one way or the other. It is entirely guided by what the vendor wants to support. x86's ordering is similar to TSO in SPARC, which uses a RISC like ISA. The ordering is described as a part of the ISA, but any ISA can implement a strong ordering (at the risk of performance losses) if they want to.
i-cache efficiency: Again implementation specific. Efficiency is entirely a result of implementation, isn't it ?
no branch delay slot: Yes, this is a part of the ISA. My point though was that it is uncommon enough that I wouldn't call it a great virtue of x86 per se.