@@ -140,29 +140,33 @@ public unsafe BitArray(bool[] values)
140140
141141 if ( Avx2 . IsSupported )
142142 {
143+ // JIT does not support code hoisting for SIMD yet
144+ Vector256 < byte > zero = Vector256 < byte > . Zero ;
143145 fixed ( bool * ptr = values )
144146 {
145147 for ( ; ( i + Vector256 < byte > . Count ) <= values . Length ; i += ( uint ) Vector256 < byte > . Count )
146148 {
147149 Vector256 < byte > vector = Avx . LoadVector256 ( ( byte * ) ptr + i ) ;
148- Vector256 < byte > isFalse = Avx2 . CompareEqual ( vector , Vector256 < byte > . Zero ) ;
150+ Vector256 < byte > isFalse = Avx2 . CompareEqual ( vector , zero ) ;
149151 int result = Avx2 . MoveMask ( isFalse ) ;
150152 m_array [ i / 32 ] = ~ result ;
151153 }
152154 }
153155 }
154156 else if ( Sse2 . IsSupported )
155157 {
158+ // JIT does not support code hoisting for SIMD yet
159+ Vector128 < byte > zero = Vector128 < byte > . Zero ;
156160 fixed ( bool * ptr = values )
157161 {
158162 for ( ; ( i + Vector128 < byte > . Count * 2 ) <= values . Length ; i += ( uint ) Vector128 < byte > . Count * 2 )
159163 {
160164 Vector128 < byte > lowerVector = Sse2 . LoadVector128 ( ( byte * ) ptr + i ) ;
161- Vector128 < byte > lowerIsFalse = Sse2 . CompareEqual ( lowerVector , Vector128 < byte > . Zero ) ;
165+ Vector128 < byte > lowerIsFalse = Sse2 . CompareEqual ( lowerVector , zero ) ;
162166 int lowerPackedIsFalse = Sse2 . MoveMask ( lowerIsFalse ) ;
163167
164168 Vector128 < byte > upperVector = Sse2 . LoadVector128 ( ( byte * ) ptr + i + Vector128 < byte > . Count ) ;
165- Vector128 < byte > upperIsFalse = Sse2 . CompareEqual ( upperVector , Vector128 < byte > . Zero ) ;
169+ Vector128 < byte > upperIsFalse = Sse2 . CompareEqual ( upperVector , zero ) ;
166170 int upperPackedIsFalse = Sse2 . MoveMask ( upperIsFalse ) ;
167171
168172 m_array [ i / 32 ] = ~ ( ( upperPackedIsFalse << 16 ) | lowerPackedIsFalse ) ;
@@ -171,6 +175,10 @@ public unsafe BitArray(bool[] values)
171175 }
172176 else if ( AdvSimd . Arm64 . IsSupported )
173177 {
178+ // JIT does not support code hoisting for SIMD yet
179+ // However comparison against zero can be replaced to cmeq against zero (vceqzq_s8)
180+ // See dotnet/runtime#33972 for details
181+ Vector128 < byte > zero = Vector128 < byte > . Zero ;
174182 fixed ( bool * ptr = values )
175183 {
176184 for ( ; ( i + Vector128 < byte > . Count * 2 ) <= values . Length ; i += ( uint ) Vector128 < byte > . Count * 2 )
@@ -179,15 +187,15 @@ public unsafe BitArray(bool[] values)
179187 // As a workaround, mask out the relevant bit after comparison
180188 // and combine by ORing all of them together (In this case, adding all of them does the same thing)
181189 Vector128 < byte > lowerVector = AdvSimd . LoadVector128 ( ( byte * ) ptr + i ) ;
182- Vector128 < byte > lowerIsFalse = AdvSimd . CompareEqual ( lowerVector , Vector128 < byte > . Zero ) ;
190+ Vector128 < byte > lowerIsFalse = AdvSimd . CompareEqual ( lowerVector , zero ) ;
183191 Vector128 < byte > bitsExtracted1 = AdvSimd . And ( lowerIsFalse , s_bitMask128 ) ;
184192 bitsExtracted1 = AdvSimd . Arm64 . AddPairwise ( bitsExtracted1 , bitsExtracted1 ) ;
185193 bitsExtracted1 = AdvSimd . Arm64 . AddPairwise ( bitsExtracted1 , bitsExtracted1 ) ;
186194 bitsExtracted1 = AdvSimd . Arm64 . AddPairwise ( bitsExtracted1 , bitsExtracted1 ) ;
187195 Vector128 < short > lowerPackedIsFalse = bitsExtracted1 . AsInt16 ( ) ;
188196
189197 Vector128 < byte > upperVector = AdvSimd . LoadVector128 ( ( byte * ) ptr + i + Vector128 < byte > . Count ) ;
190- Vector128 < byte > upperIsFalse = AdvSimd . CompareEqual ( upperVector , Vector128 < byte > . Zero ) ;
198+ Vector128 < byte > upperIsFalse = AdvSimd . CompareEqual ( upperVector , zero ) ;
191199 Vector128 < byte > bitsExtracted2 = AdvSimd . And ( upperIsFalse , s_bitMask128 ) ;
192200 bitsExtracted2 = AdvSimd . Arm64 . AddPairwise ( bitsExtracted2 , bitsExtracted2 ) ;
193201 bitsExtracted2 = AdvSimd . Arm64 . AddPairwise ( bitsExtracted2 , bitsExtracted2 ) ;
0 commit comments