Sure, this is what makes it good for mispredictable branches - data decompression for instance. If you can't speculate ahead, it's a waste of space in the branch prediction buffer to do it.
But I definitely wish it was a builtin function instead of the compiler generating it, because none of them can guess when to use it.
So, literally exactly the same state that conditional branch instructions depend on? Aside from implementation details (like >Intel refuses to speculate loads in them<, which, to be fair, might be its own problem), "cmovz D S" is just "jnz skip ; mov D S ; skip:" without the useless branch overhead.
There is hope that it doesn't squat a precious branch-prediction slot, hope that it doesn't incur a branch misprediction pipeline stall if it's taken, or not taken, hope that fewer instructions translates to fewer clock cycles, hope that what looks like a copy really just does a register-renaming accounting trick, ...
Or do you mean that the problem is having 3 instead of 2 source operands?
Or that one of the operands is the flag register on x86-like architecture? (but you can just use a normal register being nonzero)
The issue with CMOV is primarily that it's a three operand instruction. If it was a two-instruction operation, it would just be arithmetic, and nobody would care.
A minor, secondary issue is that conditional moves have a data dependency on both of the source operands, unlike conditional branch and move, which means that they are often slower than a predictable branch and move on a fast processor. However, this doesn't matter all that much, because they're optional, so just don't use them when they aren't a good fit.
Intel and AMD make it work by throwing another 10,000 or 100,000 transistors at it.
It is better to let macro-op fusion hardware identify opportunities to convert a branch-over-move sequence, all by itself. RISC-V is supposed to be all about powerful macro-op fusion.
Clang is really aggressive about generating cmovs. On Gcc you can still use (x & -c) expressions to get nicely pipelined conditional expressions, but Clang stomps them all to cmovs.
Cmov is one of the methods to mitigate Spectre because Intel refuses to speculate loads in them. So, cmov from memory pessimizes your code in cases where you aren't worried what might be sharing your cache.