If we don't add a register count to vkd3d_shader_signature_element then API users can't specify SM 6 signatures with it, because they contain a register count ('row count' in the docs but it amounts to the same).
Patch 1 contains only what's required to resolve multiple fork/join phases into one. I see no intermediate changes which can be made.
I can probably split off a few small changes from patch 3: merging split I/O registers, separating the relative address from the register index for register relative indexing, inserting the control point count or id in reg.idx where it's missing, and creating a partial default control point phase in the IR. For the remainder, the problem is once the signatures are normalised then all the changes are necessary for it to work.
It may be feasible to normalise only input signatures, then add outputs later, or vice-versa, bearing in mind sometimes the patch constants are inputs.
The location for the normalisation is debatable. Henri and I agreed spirv.c is probably the best place because these changes are intended to make emitting SPIR-V easier. It can also be argued that since the SM 6 parser naturally emits in this form, except for one or two fixups, it's not all that related to SPIR-V.