Two issues:
- It is not easy for the compiler to always fill up a single delay slot. Filling dozen of them (as required for a deeply pipelined modern processor) would be significantly harder.
- The number of delay slots would depend on the depth of the cpu pipeline. If you do not want to expose microarchitectural details in your ISA, you need either JIT or install time specialization. edit: or stick with a potentially suboptimal number.
There's no way you could cover all variable latency scenarios with fixed delay slots, unless you have a highly specific scenario like a GPU where you control all the internals.
Notably, branching on a flag f on the GPU was so slow that most of the time it was faster to (manually) compute both branches b1 and b2 and then calculate the result as r = f * b1 + (1-f) * b2 (where f is either 0 or 1).
You trade it off with increased code size which might spill the cache but for small tight loops not exceeding the cache line/ size it would still be a good win.
sub eax, 1
(several non-flags-touching instructions)
jmpne loop_start
I would expect that a branch predictor wouldn't be needed as the jump only needs the flags register to figure out where the branch is going to go.This is not specific of OoO cpus. In order cpus work the same way, assuming they have a predictor of course.
edit: to be more precise, jumps are not not resolved at the fetch stage, but in one of the early stages, in fact there is often a bubble for taken branches as the fetcher will fetch the next instruction in the stream by default.
Considering the complex predictors on current PCs, we would save quite a lot of circuitry. But that circuitry is there because it is the most effective place to increase the CPU speed, if you used it for something else, speed would go down, not up (but power consumption would improve).
Also, actual clock speed isn't really relevant and has a complex relation to CPU speed. That circuitry isn't affecting clock speed, so it wouldn't change.
Power consumption per second might go down, but overall may go up, depending on how many more seconds the computation takes.
The rule of thumb you learned is useful for optimizing PC software, but has no place in CPU architecture discussions.
Also, "usually" leaves a lot of important cases out.
What if we had a modern, pipelined CPU architecture with no branch predictor, which instead unconditionally executed the X instructions immediately following every branch before (possibly) proceeding with the branch's target instruction?
Would compilers and programmers be able to find most of the efficiencies that we currently rely on the branch predictor to find? What would be the common cases where it would be hard to do that?
How much circuitry would we save by leaving out the predictor? Enough to allow a measurable speedup in the CPU clock speed?