Problem description
When we compare unsigned integer and signed integer, as an example, Slang currently casts unsigned integer to signed integer.
But this is opposite to how other languages do such as C/C++, GLSL and HLSL.
In C, when unsigned integer is used with a signed integer, the signed integer is promoted to unsigned integer.
C99 defines the rule as following, called "usual arithmetic conversion":
One type between T1 and T2 is an signed integer type S, the
other type is an unsigned integer type U. Apply the following rules:
If the integer conversion rank of U is greater than or equal to the integer conversion rank of S, C is U.
Otherwise, if S can represent all of the values of U, C is S.
We should print a warning when binary operators are used with different sign-ness of integer types.
And we should also follow the "usual arithmetic conversion".
The reason why Slang converts from unsigned to sign is because it follows the "ConversionCost" rule.
But we should apply a different rule for the binary operators.
Following lines show the Conversion costs for the sign-ness cost.
// Conversions that are lossless, but change "kind"
kConversionCost_UnsignedToSignedPromotion = 200,
// Conversion from signed->unsigned integer of same or greater size
kConversionCost_SignedToUnsignedConversion = 300,
Note that the cost of "uint -> int" is lower than "int -> uint".
The binary operators subject to this issue are following:
operator+
operator-
operator*
operator/
operator%
operator<
operator<=
operator>
operator>=
Goal
We should print a warning when binary operators are used with different sign-ness of integer types.
And we should also follow the "usual arithmetic conversion".
Repro step
Following test case can generate the HLSL/GLSL source code for the operator<(int,uint) case.
When the cast to "int" is removed, SPIR-V asm looks different.
// With cast to int,
// outputBuffer_0._data[0U] = int(i32Input_0._data[0U] < int(u32Input_0._data[1U]));
%27 = OpLoad %uint %26
%28 = OpBitcast %int %27
%30 = OpSLessThan %bool %18 %28
// Without cast to int
// outputBuffer_0._data[0U] = int(i32Input_0._data[0U] < u32Input_0._data[1U]);
%28 = OpLoad %uint %27
%30 = OpULessThan %bool %20 %28
Note
I suspected that the ConversionCost might be set incorrectly.
But it doesn't seem that is the case.
When there are overloading with "int" and 'uint", DXC prefers "int" over "uint".
The following example shows the different DXIL between two cases where the first case defines only "USE_INT" and another case defines only "USE_UINT".
When both "USE_INT" and "USE_UINT" are defined, the resulting DXIL was same to the case that defined only "USE_INT".
Problem description When we compare unsigned integer and signed integer, as an example, Slang currently casts unsigned integer to signed integer. But this is opposite to how other languages do such as C/C++, GLSL and HLSL.
In C, when unsigned integer is used with a signed integer, the signed integer is promoted to unsigned integer. C99 defines the rule as following, called "usual arithmetic conversion":
We should print a warning when binary operators are used with different sign-ness of integer types. And we should also follow the "usual arithmetic conversion".
The reason why Slang converts from unsigned to sign is because it follows the "ConversionCost" rule. But we should apply a different rule for the binary operators. Following lines show the Conversion costs for the sign-ness cost.
Note that the cost of "uint -> int" is lower than "int -> uint".
The binary operators subject to this issue are following:
Goal We should print a warning when binary operators are used with different sign-ness of integer types. And we should also follow the "usual arithmetic conversion".
Repro step Following test case can generate the HLSL/GLSL source code for the
operator<(int,uint)
case.Slang generates HLSL as following,
In order to inspect the DXIL, you can copy the code above and put it in the Shader Playground When the cast to "int" is removed, DXIL looks different.
Similarly, Slang generates GLSL as following,
When the cast to "int" is removed, SPIR-V asm looks different.
Note I suspected that the
ConversionCost
might be set incorrectly. But it doesn't seem that is the case.When there are overloading with "int" and 'uint", DXC prefers "int" over "uint". The following example shows the different DXIL between two cases where the first case defines only "USE_INT" and another case defines only "USE_UINT". When both "USE_INT" and "USE_UINT" are defined, the resulting DXIL was same to the case that defined only "USE_INT".