Reputation: 1232
In x86 Assembler, given that you have
why do you need Indexed and Base Pointer addressing modes? Each could be replaced by a loop as far as I know.
Also Indirect mode doesn't seem to be overly useful either, since you can simply use Direct mode instead to reference the memory address. What is the purpose of first accessing a register which then contains a pointer to a memory address?
In short, which addressing modes are really necessary?
Upvotes: 3
Views: 2696
Reputation: 364458
You only need one memory addressing mode, and that's what many classic RISC machines do in practice, such as MIPS, SPARC, RISC-V. They choose immediate($register)
because there's room for an immediate in fixed-width instructions. (Some like PowerPC have separate instructions for indexed addressing, otherwise you have to do math in registers to compute the address you want.)
x86 can't do much without registers, so I don't think you can get rid of the register "addressing mode". Some very different architectures might not use registers, and just have a stack or memory,memory instructions. IDK how they implement pointers; maybe such architectures can do memory[memory]
(C array notation).
Immediate isn't needed for computation to be possible. You can construct any value, using multiple registers. Start with a zero (xor eax, eax
), inc
it to get a 1, left-shift it to whatever position you want, inc
that to set the low bit, left-shift that, etc. So it takes at worst 2*popcount(N)
instructions to get N
into a register. Note that immediate shift counts won't be available, though, so the obvious method of repeated shifting by one (shl eax
, yes there is a separate encoding for shift-by-one, or just use add eax, eax
) will just depend on the position of the highest set bit. So log2(N) + popcount(N)
for the obvious shift and inc.
Absolute (what you call direct) memory addressing is not the most useful addressing mode. We can emulate it by constructing addresses with a sequence of instructions (see above), and using [register]
. If we're trying to cut down, we want to ditch it. As Jester pointed out, keeping absolute addressing as our only form would be terribly inconvenient (or maybe impossible?) to use.
Index is obviously available for performance, not necessity: you can shift and add with separate instructions.
Displacements are also just for performance, so we can get rid of them and force code to add any displacement manually. See the Immediate paragraph for how.
I believe x86 would still be arbitrarily programmable with just register
and [register]
addressing modes.
With register
, [register]
, and immediate
, performance shouldn't be dramatically worse than full x86, although register pressure would be worse since you'd need spare regs to compute addresses more often. As well as of course needing more instructions.
If you were going to have only one memory addressing mode, a more useful choice than [reg]
is [reg+disp]
like RISCs use. That would sometimes save instructions (and spare registers) by not having to compute an address in another register, and still allow LEA to copy-and-add a constant, although not its current ability to shift-and-add two regs.
For x86's current machine-code format, that takes an extra byte (or 4 bytes) of machine code. Signalling reg
direct vs. [reg]
-indirect (mem) vs. [reg+disp8]
vs. [reg+disp32]
uses 2 bits in the ModRM byte.
If implicit access to memory doesn't count as an addressing mode, you can of course emulate [register]
with lodsd
and stosd
, but you wouldn't be able to do atomic read-modify-write operations. That feels like a cheat, though.
There's also the stack (push/pop
): I don't know if a stack+registers machine is Turing-complete, but it certainly isn't programmable in the usual sense. Of course, if you modify e/rsp
, you can again emulate [register]
, but with less choice of operand-size than lodsb/w/d/q
/ stosb/w/d/q
.
x86 has quite a lot of space to store things in registers if you include the 16 ymm registers. Although I can't think of a way to move data between integer registers and the high 128b of a ymm without using either memory or immediate operands (for vextractf128
), so in practice you have more like sixteen 16B vector-register slots for stashing local state other than the stack. Still, it's limited size, which probably means that 8 GP registers in the 32bit 386 ISA vs. all the integer/mmx/ymm registers in the 64bit AVX2 ISA isn't relevant for whether the machine is turing-complete with only push/pop, registers, and no modification of the stack pointer other than by push/pop.
Upvotes: 1
Reputation: 6145
Although in theory 'addressing mode' can be used to refer to the operand type, it's a bit confusing since it doesn't involve an address. The Intel manual uses 'addressing mode' to refer to memory addressing, and I will use this definition.
In assembly, an operand can be :
In the x86 architecture, the "addressing mode" is only for the last type of operands : memory operands (addresses), and refers to the methods available to calculate the addresses. The addressing modes can be summarized in a single configurable addressing mode :
address = REG_base + REG_index*n + offset
REG_base
, REG_index
, n
and offset
are all configurable, and can all be omitted (but you need at least one, obviously).
address = offset
is called immediate, direct or absolute addressing.
address = REG_base
is called register indirect addressing.
address = REG_base + REG_index
is called base plus index addressing.
Similarly, you can add an offset (offset
) and a scale (n
).
Strictly speaking, you only need one mode to do everything : register indirect addressing (address = REG
). With that, if you need to access memory, you can calculate any address you want in a register, and use it to do the access.
It can also replace direct register operands by using memory instead, and immediate operands by constructing values with arithmetic. However, for a practical instruction set, you would still immediate operands to load addresses effectively, and register operands are needed if you don't want pointer-only registers.
All the other addressing modes beside register indirect are here for convenience, and they are indeed really convenient :
int
) arrays with no additional registers or calculations.These addressing modes don't need much calculations from the CPU : only additions and shifts. Considering x86 can do a multiplication every cycle, those operations are trivial but still very convenient.
Upvotes: 8