WIP: HLSL: hlsl register class iomapping

Adds --hlsl-iomap option to perform IO mapping in HLSL register space.

--shift-cbuffer-binding is now a synonym for --shift-ubo-binding.

The idea way to do this seems to be passing in a dedicated IO resolver, but
that would require more intrusive restructuring, so maybe best for its
own PR.

The TDefaultHlslIoResolver class and the former TDefaultIoResolver class
share quite a bit of mechanism in a common base class.

TODO: tbuffers are landing in the wrong register class, which needs some
investigation.  They're either wrong upstream, or the detection in the
resolver is wrong.
diff --git a/Test/hlsl.automap.frag b/Test/hlsl.automap.frag
new file mode 100644
index 0000000..fbb4545
--- /dev/null
+++ b/Test/hlsl.automap.frag
@@ -0,0 +1,57 @@
+// Test register class offsets for different resource types
+
+SamplerState       s1 : register(s1);
+SamplerComparisonState s2 : register(s2);
+
+Texture1D <float4> t1 : register(t1);
+Texture2D <float4> t2 : register(t2);
+Texture3D <float4> t3 : register(t3);
+StructuredBuffer<float4> t4 : register(t4);
+ByteAddressBuffer t5 : register(t5);
+Buffer<float4> t6 : register(t6);
+
+RWTexture1D <float4> u1 : register(u1);
+RWTexture2D <float4> u2 : register(u2);
+RWTexture3D <float4> u3 : register(u3);
+
+RWBuffer <float> u4 : register(u4);
+RWByteAddressBuffer u5 : register(u5);
+RWStructuredBuffer<float> u6 : register(u6);
+AppendStructuredBuffer<float> u7 : register(u7);
+ConsumeStructuredBuffer<float> u8 : register(u8);
+
+cbuffer cb : register(b1) {
+    int cb1;
+};
+
+// tbuffer tb : register(t7) {
+//     int tb1;
+// };
+
+float4 main() : SV_Target0
+{
+    t1;
+    t2;
+    t3;
+    t4[0];
+    t5.Load(0);
+    t6;
+
+    s1;
+    s2;
+
+    u1;
+    u2;
+    u3;
+
+    u4[0];
+    u5.Load(0);
+    u6[0];
+    u7[0];
+    u8[0];
+
+    cb1;
+    // tb1; TODO: wrong type?
+
+    return 0;
+}