More seriously, yup: if you read the architecture manual this instruction can take a long time. It's also a pain for a OoO (not superscalar!) cpu to keep track of all the dependencies.
It made complete sense back in the early 80s when the instruction set was designed, but like universal condition code dependent instruction execution it was dropped from ARM64 for good reasons.
Why would it be harder for OoO to keep track of this than N mov/load instructions? It is just that the dependency tracker is working in instruction space?
As mentioned before these were microcoded anyways so it may end up "compiling" down to N loads which should track just as well.
Why couldn't you just not undo it, and have it read/write twice? This wouldn't be a problem if you're accessing normal ram, like the prologue and epilogue of a function. Add a comment to the manual saying to not use this instruction when reading/writing hardware registers where accessing it changes state.
Not all instructions are re-startable. ldm/stm that writes back to the base register is only re-startable if the write-back and the update to PC are last.
The microcontroller-scale cores have a few extra bits in the control/status register that govern restart of an interrupted ldm/stm or IT (if-then, a form of hammock predication).
> Imagine you hit a bus error on the last memory access of LDM. You already updated 15 registers, so now you need to undo all of that.
Irrelevant. "Undo all of that" is just a matter of using an older version of the register alias table. The retirement process has do to that for any and all faults anyway.
My point was that undoing multiple writes is not as easy as undoing one write. Your register file (really, reorder buffer) either needs to add more write ports to it, or you need a state machine to complete that clean-up over multiple cycles.
Without that instruction, your hardware design could have assumed that reverting state can always be done in one cycle. That makes the hardware implementation easier.
Your point is based on a fundamental mis-understanding of what the reorder buffer (ROB) is doing.
Any time there is a fault, it is detected by the retirement stage as it inspects the ROB. There are already hundreds of state changes that must be rolled back: all of the succeeding entries in the ROB. So the work performed by the recovery mechanism isn't changed by the amount of clobbered state because it is completely clobbered! The ROB must rewind it all.
The register file doesn't need any additional ports, because the fault recovery mechanism doesn't touch the physical registers. It only updates the register alias table (RAT) to point to the appropriate registers. But that machine must be capable of restoring 100% of the register pointers very quickly no matter what. Whether the faulting instruction touched one, two, or 16 registers doesn't matter. The 100+ updates following it are enough state that the answer must be: "Everything".
You are correct for complex CPUs with actual ROB with hundreds of entries. For those micro-architecture, LDM is not particularly stressful. I was focused on the micro-controller case, with much simpler pipelines. LDM is one of the instructions causing the pipeline a lot more headaches than it's worth.
Microcontrollers don't need additional ports either. Take a look a the ARMv7-M status/control register. It has a few bits of state to allow ldm, stm, and if-then to be resumed in-place.
At that scale, those mechanisms aren't micro-coded, they are state-machined. You just have to restore the state machine.
If anyone is interested why R15 is special cased here a bit, it's because R15 is the program counter and that extra cycle is the interlock where they'd otherwise have to put a delay slot.
> Are instructions typically variable in the number of cycles it takes?
Very much so, either due to memory latency or just inherent complexity. For example, a single division instruction can easily take the same time as ten adds.