I think you meant "MOVC(a, b, c) returns c if a is bitwise zero and b otherwise." above.
Ah, yes...
Alternatively:
"MOVC(x, y, z) evaluates to `z' when `x' is bitwise zero and to `y' otherwise."
I deliberately avoided using `x`, `y` and `z` because they easily confuse with swizzle letters. Of course `a` and `b` are used for swizzles too, but the fact that `c` and `d` are not arguably makes it harder to fall for it.
At the risk of rehashing a discussion we've been over before, this does suggest that "MOVC" is perhaps not the most appropriate name for operation; this sounds like what some other languages might call "if". (I.e., "MOVC(x, y, z)" is essentially "(if x y z)".)
Both `MOVC` and `TERNARY` are a form of `if`, so `if` looks precisely like the thing you'd want to avoid to name either of them. They just differ by a technicality in how they evaluate trueness. The names still make some sense, given the context: `MOVC` is designed to reproduce the raw behavior of, well, the `MOVC` operator in TPF, while `TERNARY` is designed to reproduce the behavior of the ternary operator in C.
Are both "y" and "z" always evaluated, or is that conditional on "x" as well?
From my point of view the HLSL IR doesn't have a concept of evaluating nodes. Nodes purely forward a value and have no side effects.
So "TERNARY(a, b, c)" is equivalent to "MOVC(EQUAL(a, 0), b, c)", right?
Rather `MOVC(NEQUAL(a, 0), b, c)`, unless I am missing something, where `0` is assumed to be of the same type as `a`. As the comment notices, they only differ for `a == -0.0`: `MOVC(-0.0, b, c) == b`, while `TERNARY(-0.0, b, c) == c`.