JZ, JE - Jump if Zero, Jump if Equal
JNZ, JNE - Jump if Not Zero, Jump if Not Equal
JC - Jump if Carry
JNC - Jump if No Carry
JO - Jump if Overflow
JNO - Jump if No Overflow
JS - Jump if Signed (Negative)
JNS - Jump if Not Signed (Positive or Zero)
JP, JPE - Jump if Parity, Jump if Parity is Even
JNP, JPO - Jump if Not Parity, Jump if Parity is OddSay in Rust:
let foo = if bar { 1 } else { 2 };
And
let mut foo; if bar { foo = 1; } else { foo = 2; }
Despite they looked the same, functions the same and effectively the same, but the first one is the conditional move, and the second one would be a jump initially (until further compiler optimization kick in)
You will notice that for conditional move, you "get" a predictable expression for the result, but with branched jump, it's like you "get" a bunch of arbitrary statements, that writes to the expression. It may end up folding so both will essentially be compiled to cmov, but the way to representation of the assignment is different. You can be certain with conditional instructions, but you can't be certain with branched jump, otherwise we don't need branch prediction.
In fact, the way conditional instructions work is due to Church encoding, that you created a lambda function that calls the left or right function depending on the input evaluation, which can be seen as implicitly embedding the branch.