4 ms·
Indeed, and this is where the usenet post linked in a sibling comment is really informative: In my opinion, the most common reasonable reason for including
by NobodyNada 4y ago
Indeed, and this is where the usenet post linked in a sibling comment is really informative:
In my opinion, the most common reasonable reason for including some
instructions is:
a) There is a datatype deemed worth supporting, i.e., whose use
burns an interesting number of cycles, either because:
1) It gets used often enough, OR
2) It is used less often, but is really expensive.
b) There is a reasonable hardware cost to support the datatype.
c) Simulating the use of the datatype with the existing instructions
is noticably expensive.
In practice, b)+c) usually mean that the datatype operations can obtain
useful parallelism in hardware, that cannot be gotten at by sequences of
the existing instructions. IF it is difficult to beat sequences of
existing instructions in speed, then only if those sequences are really
frequent would one add new instrucions, i.e.e., for code density.
Adding a little adder and shifter to the memory access unit meets all these conditions -- it's an operation that is effectively free in hardware, but would cost extra cycles & bytes to implement in software.
So the "problem" with x86 isn't that such a complex addressing mode exists. It's that the ADD instruction has such a complex addressing mode, as does nearly every other instruction in the ISA. An 'ADD mem, reg' instruction is really a load, an add, and a store, and there's no hardware magic you can do to accelerate that -- it's just as fast to write "load, add, store" in software, so this fails tests b) and c).
A RISC will typically have, let's say a dozen load/store instructions to support a variety of addressing modes (probably more if you account for atomics and vectors and non-temporals and whatnot). Then you only need one ADD instruction, one SUB instruction, one XOR instruction, maybe one FJCVTZS instruction, etc. But on x86, you get sort of a combinatoric explosion between possible combinations of instructions, addressing modes, and prefix bytes, which means your decoder has to support a dozen ADDs, a dozen SUBs, a dozen XORs, a dozen FJCVTZSes, and whatever.
- akira2501 4y ago> which means your decoder has to support a dozen ADDs, a dozen SUBs, a dozen XORs Does it? The way I've always internalized it is the SIB and MOD/RM are just adding AGU options to the instruction. They're there in the underlying microcode set, and x86 just happens to give me direct access to them through opcode extensions. Is that not how it's actually implemented?
- NobodyNada 4y agoI have no idea how it's implemented under-the-hood, I don't even know what any of those acronyms stand for :) Regardless of how it's implemented, I don't believe it changes my point that an 'ADD mem, reg' really is at least 3 separate operations, and code density is the only potential benefit to expressing them as a single instruction (on a modern architecture). If you have suggestions as to how I should reword my comment, I'm happy to make edits.
- rep_lodsb 4y agoYes, the address unit handles the shift+add (both on x86 and ARM). That everything is translated into RISC-like "microcode" is a bit of a meme, it was only really true for the first generation 8086/8088 (from 1978). Those early chips actually had microcode subroutines to compute for example BX+DI and move the result into an internal address register. But every following x86 generation did it in hardware. Modern CPUs with out-of-order execution do break read/modify/write instructions into separate micro-ops however.
- jsnell 4y ago> it's just as fast to write "load, add, store" in software Not really, since you then need an extra register, which in x86 would be a very expensive cross-cutting change.
- NobodyNada 4y agoAnd that's why RISC processors expose more architectural registers than CISC processors. (A read-modify-write instruction on a CISC processor will still implicitly need a temporary physical register; RISC processors simply expose a larger set of logical registers since a lot of these implicit temporary registers become explicit.)