|
6 | 6 | using System.Diagnostics;
|
7 | 7 | using System.Numerics;
|
8 | 8 | using System.Runtime.CompilerServices;
|
9 |
| -using System.Runtime.Intrinsics.X86; |
10 | 9 | using Internal.Runtime.CompilerServices;
|
11 | 10 |
|
12 | 11 | namespace System.Text.Unicode
|
@@ -61,47 +60,27 @@ private static uint ExtractCharFromFirstTwoByteSequence(uint value)
|
61 | 60 | }
|
62 | 61 |
|
63 | 62 | /// <summary>
|
64 |
| - /// Given a machine-endian DWORD which four bytes of UTF-8 data, interprets the input as a |
| 63 | + /// Given a machine-endian DWORD which represents four bytes of UTF-8 data, interprets the input as a |
65 | 64 | /// four-byte UTF-8 sequence and returns the machine-endian DWORD of the UTF-16 representation.
|
66 | 65 | /// </summary>
|
67 | 66 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
68 | 67 | private static uint ExtractCharsFromFourByteSequence(uint value)
|
69 | 68 | {
|
70 | 69 | if (BitConverter.IsLittleEndian)
|
71 | 70 | {
|
72 |
| - if (Bmi2.IsSupported) |
73 |
| - { |
74 |
| - // need to reverse endianness for bit manipulation to work correctly |
75 |
| - value = BinaryPrimitives.ReverseEndianness(value); |
76 |
| - |
77 |
| - // value = [ 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx ] |
78 |
| - // want to return [ 110110wwwwxxxxxx 110111xxxxxxxxxx ] |
79 |
| - // where wwww = uuuuu - 1 |
80 |
| - |
81 |
| - uint highSurrogateChar = Bmi2.ParallelBitExtract(value, 0b00000111_00111111_00110000_00000000u); |
82 |
| - uint lowSurrogateChar = Bmi2.ParallelBitExtract(value, 0b00000000_00000000_00001111_00111111u); |
83 |
| - |
84 |
| - uint combined = (lowSurrogateChar << 16) + highSurrogateChar; |
85 |
| - combined -= 0x40u; // wwww = uuuuu - 1 |
86 |
| - combined += 0xDC00_D800u; // add surrogate markers |
87 |
| - return combined; |
88 |
| - } |
89 |
| - else |
90 |
| - { |
91 |
| - // input is UTF8 [ 10xxxxxx 10yyyyyy 10uuzzzz 11110uuu ] = scalar 000uuuuu zzzzyyyy yyxxxxxx |
92 |
| - // want to return UTF16 scalar 000uuuuuzzzzyyyyyyxxxxxx = [ 110111yy yyxxxxxx 110110ww wwzzzzyy ] |
93 |
| - // where wwww = uuuuu - 1 |
94 |
| - uint retVal = (uint)(byte)value << 8; // retVal = [ 00000000 00000000 11110uuu 00000000 ] |
95 |
| - retVal |= (value & 0x0000_3F00u) >> 6; // retVal = [ 00000000 00000000 11110uuu uuzzzz00 ] |
96 |
| - retVal |= (value & 0x0030_0000u) >> 20; // retVal = [ 00000000 00000000 11110uuu uuzzzzyy ] |
97 |
| - retVal |= (value & 0x3F00_0000u) >> 8; // retVal = [ 00000000 00xxxxxx 11110uuu uuzzzzyy ] |
98 |
| - retVal |= (value & 0x000F_0000u) << 6; // retVal = [ 000000yy yyxxxxxx 11110uuu uuzzzzyy ] |
99 |
| - retVal -= 0x0000_0040u; // retVal = [ 000000yy yyxxxxxx 111100ww wwzzzzyy ] |
100 |
| - retVal -= 0x0000_2000u; // retVal = [ 000000yy yyxxxxxx 110100ww wwzzzzyy ] |
101 |
| - retVal += 0x0000_0800u; // retVal = [ 000000yy yyxxxxxx 110110ww wwzzzzyy ] |
102 |
| - retVal += 0xDC00_0000u; // retVal = [ 110111yy yyxxxxxx 110110ww wwzzzzyy ] |
103 |
| - return retVal; |
104 |
| - } |
| 71 | + // input is UTF8 [ 10xxxxxx 10yyyyyy 10uuzzzz 11110uuu ] = scalar 000uuuuu zzzzyyyy yyxxxxxx |
| 72 | + // want to return UTF16 scalar 000uuuuuzzzzyyyyyyxxxxxx = [ 110111yy yyxxxxxx 110110ww wwzzzzyy ] |
| 73 | + // where wwww = uuuuu - 1 |
| 74 | + uint retVal = (uint)(byte)value << 8; // retVal = [ 00000000 00000000 11110uuu 00000000 ] |
| 75 | + retVal |= (value & 0x0000_3F00u) >> 6; // retVal = [ 00000000 00000000 11110uuu uuzzzz00 ] |
| 76 | + retVal |= (value & 0x0030_0000u) >> 20; // retVal = [ 00000000 00000000 11110uuu uuzzzzyy ] |
| 77 | + retVal |= (value & 0x3F00_0000u) >> 8; // retVal = [ 00000000 00xxxxxx 11110uuu uuzzzzyy ] |
| 78 | + retVal |= (value & 0x000F_0000u) << 6; // retVal = [ 000000yy yyxxxxxx 11110uuu uuzzzzyy ] |
| 79 | + retVal -= 0x0000_0040u; // retVal = [ 000000yy yyxxxxxx 111100ww wwzzzzyy ] |
| 80 | + retVal -= 0x0000_2000u; // retVal = [ 000000yy yyxxxxxx 110100ww wwzzzzyy ] |
| 81 | + retVal += 0x0000_0800u; // retVal = [ 000000yy yyxxxxxx 110110ww wwzzzzyy ] |
| 82 | + retVal += 0xDC00_0000u; // retVal = [ 110111yy yyxxxxxx 110110ww wwzzzzyy ] |
| 83 | + return retVal; |
105 | 84 | }
|
106 | 85 | else
|
107 | 86 | {
|
@@ -135,37 +114,19 @@ private static uint ExtractFourUtf8BytesFromSurrogatePair(uint value)
|
135 | 114 | // input = [ 110111yyyyxxxxxx 110110wwwwzzzzyy ] = scalar (000uuuuu zzzzyyyy yyxxxxxx)
|
136 | 115 | // must return [ 10xxxxxx 10yyyyyy 10uuzzzz 11110uuu ], where wwww = uuuuu - 1
|
137 | 116 |
|
138 |
| - if (Bmi2.IsSupported) |
139 |
| - { |
140 |
| - // Since pdep and pext have high latencies and can only be dispatched to a single execution port, we want |
141 |
| - // to use them conservatively. Here, we'll build up the scalar value (this would normally be pext) via simple |
142 |
| - // logical and arithmetic operations, and use only pdep for the expensive step of exploding the scalar across |
143 |
| - // all four output bytes. |
144 |
| - |
145 |
| - uint unmaskedScalar = (value << 10) + (value >> 16) + ((0x40u) << 10) /* uuuuu = wwww + 1 */ - 0xDC00u /* remove low surrogate marker */; |
146 |
| - |
147 |
| - // Now, unmaskedScalar = [ xxxxxx11 011uuuuu zzzzyyyy yyxxxxxx ]. There's a bit of unneeded junk at the beginning |
148 |
| - // that should normally be masked out via an and, but we'll just direct pdep to ignore it. |
| 117 | + value += 0x0000_0040u; // = [ 110111yyyyxxxxxx 11011uuuuuzzzzyy ] |
149 | 118 |
|
150 |
| - uint exploded = Bmi2.ParallelBitDeposit(unmaskedScalar, 0b00000111_00111111_00111111_00111111u); // = [ 00000uuu 00uuzzzz 00yyyyyy 00xxxxxx ] |
151 |
| - return BinaryPrimitives.ReverseEndianness(exploded + 0xF080_8080u); // = [ 10xxxxxx 10yyyyyy 10uuzzzz 11110uuu ] |
152 |
| - } |
153 |
| - else |
154 |
| - { |
155 |
| - value += 0x0000_0040u; // = [ 110111yyyyxxxxxx 11011uuuuuzzzzyy ] |
| 119 | + uint tempA = BinaryPrimitives.ReverseEndianness(value & 0x003F_0700u); // = [ 00000000 00000uuu 00xxxxxx 00000000 ] |
| 120 | + tempA = BitOperations.RotateLeft(tempA, 16); // = [ 00xxxxxx 00000000 00000000 00000uuu ] |
156 | 121 |
|
157 |
| - uint tempA = BinaryPrimitives.ReverseEndianness(value & 0x003F_0700u); // = [ 00000000 00000uuu 00xxxxxx 00000000 ] |
158 |
| - tempA = BitOperations.RotateLeft(tempA, 16); // = [ 00xxxxxx 00000000 00000000 00000uuu ] |
| 122 | + uint tempB = (value & 0x00FCu) << 6; // = [ 00000000 00000000 00uuzzzz 00000000 ] |
| 123 | + uint tempC = (value >> 6) & 0x000F_0000u; // = [ 00000000 0000yyyy 00000000 00000000 ] |
| 124 | + tempC |= tempB; |
159 | 125 |
|
160 |
| - uint tempB = (value & 0x00FCu) << 6; // = [ 00000000 00000000 00uuzzzz 00000000 ] |
161 |
| - uint tempC = (value >> 6) & 0x000F_0000u; // = [ 00000000 0000yyyy 00000000 00000000 ] |
162 |
| - tempC |= tempB; |
| 126 | + uint tempD = (value & 0x03u) << 20; // = [ 00000000 00yy0000 00000000 00000000 ] |
| 127 | + tempD |= 0x8080_80F0u; |
163 | 128 |
|
164 |
| - uint tempD = (value & 0x03u) << 20; // = [ 00000000 00yy0000 00000000 00000000 ] |
165 |
| - tempD |= 0x8080_80F0u; |
166 |
| - |
167 |
| - return (tempD | tempA | tempC); // = [ 10xxxxxx 10yyyyyy 10uuzzzz 11110uuu ] |
168 |
| - } |
| 129 | + return (tempD | tempA | tempC); // = [ 10xxxxxx 10yyyyyy 10uuzzzz 11110uuu ] |
169 | 130 | }
|
170 | 131 | else
|
171 | 132 | {
|
@@ -756,43 +717,6 @@ private static bool UInt32ThirdByteIsAscii(uint value)
|
756 | 717 | || (!BitConverter.IsLittleEndian && ((value & 0x8000u) == 0));
|
757 | 718 | }
|
758 | 719 |
|
759 |
| - /// <summary> |
760 |
| - /// Given a DWORD which represents a buffer of 4 ASCII bytes, widen each byte to a 16-bit WORD |
761 |
| - /// and writes the resulting QWORD into the destination with machine endianness. |
762 |
| - /// </summary> |
763 |
| - [MethodImpl(MethodImplOptions.AggressiveInlining)] |
764 |
| - private static void Widen4AsciiBytesToCharsAndWrite(ref char outputBuffer, uint value) |
765 |
| - { |
766 |
| - if (Bmi2.X64.IsSupported) |
767 |
| - { |
768 |
| - // BMI2 will work regardless of the processor's endianness. |
769 |
| - Unsafe.WriteUnaligned(ref Unsafe.As<char, byte>(ref outputBuffer), Bmi2.X64.ParallelBitDeposit(value, 0x00FF00FF_00FF00FFul)); |
770 |
| - } |
771 |
| - else |
772 |
| - { |
773 |
| - if (BitConverter.IsLittleEndian) |
774 |
| - { |
775 |
| - outputBuffer = (char)(byte)value; |
776 |
| - value >>= 8; |
777 |
| - Unsafe.Add(ref outputBuffer, 1) = (char)(byte)value; |
778 |
| - value >>= 8; |
779 |
| - Unsafe.Add(ref outputBuffer, 2) = (char)(byte)value; |
780 |
| - value >>= 8; |
781 |
| - Unsafe.Add(ref outputBuffer, 3) = (char)value; |
782 |
| - } |
783 |
| - else |
784 |
| - { |
785 |
| - Unsafe.Add(ref outputBuffer, 3) = (char)(byte)value; |
786 |
| - value >>= 8; |
787 |
| - Unsafe.Add(ref outputBuffer, 2) = (char)(byte)value; |
788 |
| - value >>= 8; |
789 |
| - Unsafe.Add(ref outputBuffer, 1) = (char)(byte)value; |
790 |
| - value >>= 8; |
791 |
| - outputBuffer = (char)value; |
792 |
| - } |
793 |
| - } |
794 |
| - } |
795 |
| - |
796 | 720 | /// <summary>
|
797 | 721 | /// Given a DWORD which represents a buffer of 2 packed UTF-16 values in machine endianess,
|
798 | 722 | /// converts those scalar values to their 3-byte UTF-8 representation and writes the
|
|
0 commit comments