# Difference between delayed branches and out-of-order execution

I have been reading about instruction pipeline and I stumbled upon the term delayed branches. From what I have understood, delayed branches will keep the pipeline busy, by executing instructions, regardless of the outcome of the branch. This will avoid the usages of NOP instructions.

What I do not understand is, how is it it different than Out-of-order execution? In the following example, which I just made up:

1    MOV eax, 5
2    MOV ecx, 6
3    MOV ebx, 2
4    CMP eax, ecx
5    JG label1
6    SUB ecx, ebx
7    CALL someFunc
8 label1:
9    SUB eax, ecx
10    CALL someOtherFunc


if I have understood delayed branches, before the decision is made, whether the jump to label1 will occur, the instructions on line 6 and 7 will be loaded in the pipeline. But isn't this exactly out-of-order execution?

I suppose you could view branch delay slots as a very special sort of out-of-order execution, but this isn't usually what we mean when we talk about out-of-order execution: generally, we're referring to a CPU that has a more general mechanism to detect when instructions can be re-ordered. In addition, usually out-of-order execution takes care to avoid changing the semantics/behavior of the instructions. In contrast, a branch delay slot does change the behavior of the instructions (because it affects whether the instruction after the branch is executed or not).

The "normal" way to execute code goes like this: There is a program counter (PC). The processor executes the instruction pointed to by the program counter. If that instruction is an unconditional branch, or a conditional branch and the condition is true, then the program counter is set to the destination of the branch. Otherwise, the program counter is increased by the length of the instruction.

With out-of-order execution, it seems to the programmer as if everything happened exactly the "normal" way. But internally, the processor can re-order instructions, as long as the observed behaviour is unchanged. An example: You have three instructions: Read X from memory, add X to Y, set Z to 0. Since "Read X from memory" takes a long time, and "add X to Y" must wait until X has been read, the processor executes "set Z = 0" before "add X to Y". But the behaviour that the programmer observes is the same. If they check what the value of Y is, that check is itself an instruction that waits until "add X to Y" is executed, so the value will look fine.

Delayed branches don't work like that. They change the semantics of the code in a defined way. Where I said earlier "if the instruction is a conditional branch and the condition is true, the program counter is set to the destination of the branch", that is not true. Instead, the program counter is set to the destination of the branch after the next instruction has been executed.

With delayed branches, instructions are still executed in order, but the meaning of "in order" has changed. If you have instructions (A, B, C, conditional branch, D, E, F) and the instructions at the destination of the conditional branch are X, Y, Z then instead of the usual order A, B, C, X, Y, Z the order is A, B, C, D, X, Y, Z. And these instructions are executed in order (they might actually be executed out of order, but except for the difference in speed you wouldn't notice).