12

After reading the question I'm still not sure how CPU does branching.

I understand that we have an instruction counter which points to the current instruction. And after performing conditional jump it either stays the same (increments as usual) or increases (jumps) and points to another branch, that's clear.

The problem: to define conditional jump we need a conditional jump? I mean in order to evaluate an IF the processor has to evaluate condition and IF it's true, then jump, otherwise not. It's an endless recursion.

So how does the conditional jump work on the lowest level?

LNK
  • 239
  • 2
  • 5
  • 1
    The processor performs the comparison, and if it succeeds, it updates the instruction pointer with the new value. No recursion there. – Yuval Filmus Apr 06 '21 at 09:38
  • @YuvalFilmus, you said "and if it succeeds". So we have another "if" here and that's the question. To check if it succeeds we need another comparison and check if it succeeds? But to check that we need another one... And so on. You can't use "if" while you're defining "if". – LNK Apr 06 '21 at 11:14
  • No. First, there is a comparison, say "compare register A and register B". That instruction sets condition code flags. For example if A contained 50 and B contained 20 then the "Greater" flag is set and the "Equal" flag is cleared. A conditional jump is a separate instruction. "Jump if greater or equal" will not compare anything, it just checks that either the "Greater" or the "Equal" flag is set. No comparison needed. – gnasher729 Apr 06 '21 at 14:13
  • 1
    Presuming you are not asking about things like branch prediction, etc? Because that adds a whole other level of complexity... – J... Apr 06 '21 at 17:56
  • 1
    Interesting question -- it reminds me a little of Carroll's Paradox about logical implication. – John Coleman Apr 06 '21 at 22:56
  • 4
  • This is a place where looking at assembly language would be a very good idea. If you know what the concrete CPU instructions are, it becomes pretty clear from there. Or go play MHRD -- a "game" of CPU hardware design -- to make it even clearer. – Charles Duffy Apr 07 '21 at 22:33
  • @CharlesDuffy, no, looking at assembly did not help -- the question arose aftern looking at je command, for instance. Thanks for recommending the MHRD! – LNK Apr 08 '21 at 09:18

2 Answers2

29

The problem: to define conditional jump we need a conditional jump? I mean in order to evaluate an IF the processor has to evaluate condition and IF it's true, then jump, otherwise not. It's an endless recursion.

Processors have some level of code that is directly executed, by hardware circuits. That might not be the same level that they expose as their ISA, processors may translate ISA-level instructions into some other form before really executing them or even treat ISA-level instructions as small subroutines that are implemented in micro-code, but there is still some level is not interpreted in terms of something else and built into the physical structure of the hardware.

Below is a diagram of a simple processor. The "if" in the logic of "if we need to branch then take PC+offset as next PC, otherwise take PC+4" is implemented by the top left multiplexer (labeled Mux). A multiplexer does not actually "do one thing or the other", it combines two signals and a control signal via the formula: (~condition & a) | (condition & b). That's just a boolean formula that can be implemented easily as a physical circuit.

diagram

harold
  • 2,053
  • 14
  • 14
  • 1
    Think of the multiplexer as a two-in one-out switch. Kinda like a mechanical switch that connects the output to either of the inputs. And instead of the switch being pushed physically by a human, it is "pushed" by a control line. So first the expression of the condition is evaluated and returns true or false (or rather high or low). And high will correspond to one input setting, while low corresponds to the other input setting. – Dakkaron Apr 07 '21 at 12:02
  • 1
    At a higher level, the C-like equivalent of this would be: mask = condition - 1; instructionCounter = (jumpTargetIf & ~mask) | (jumpTargetElse & mask); (Assuming 2s complement and condition is either 1 or 0). – Levi Apr 08 '21 at 09:44
6

The problem: to define conditional jump we need a conditional jump? I mean in order to evaluate an IF the processor has to evaluate condition and IF it's true, then jump, otherwise not. It's an endless recursion.

We can define a conditional jump in terms of a conditional move. For example, a conditional jump can be:

  1. Increment the program counter to point to the next instruction.
  2. Test the condition.
  3. Conditionally load the program counter with the jump target if the condition tested true in step 2.
  4. Go to the instruction the program counter refers to.

Notice that step 3 is executed unconditionally. It is a conditional move, but we always execute the conditional move. No jump capability of any kind is required here.

So conditional jumps are built out of conditional moves which are not implemented using any kind of jump at all. The conditional move always takes place, it just doesn't always have the semantic affect of moving anything.

It is important to understand that conditional moves can be built out of unconditional moves. If we do some math that results in the value we unconditionally move being the same as the previous value we are moving on top of, the effect is the same as if the move never occurred. So we can build the semantic effect of a conditional move entirely out of unconditional code.

Here's an example of a way to implement a conditional move that doesn't involve any conditions:

  1. Multiply the current value of the program counter by the condition.
  2. Invert the condition.
  3. Multiply the current value of the jump target by the condition.
  4. Add the result of step 3 to the program counter.

You can see that this leaves the value of the program counter unchanged if the condition is zero and loads the program counter with the jump target if the condition is one. This code is a straight-through flow with no conditional code at all.

Because a conditional move can easily be built out of unconditional operations, reducing a conditional branch to a conditional move is sufficient to implement conditional branches.

David Schwartz
  • 201
  • 1
  • 5