@@ -145,7 +145,7 @@ static guint16 sri_packedsimd_methods [] = {
145145 SN_get_IsSupported ,
146146};
147147
148- static guint16 packed_simd_alias_methods [] = {
148+ static guint16 packedsimd_alias_methods [] = {
149149 SN_Abs ,
150150 SN_Add ,
151151 SN_AndNot ,
@@ -174,6 +174,19 @@ static guint16 packed_simd_alias_methods [] = {
174174 SN_WidenLower ,
175175 SN_WidenUpper ,
176176 SN_Xor ,
177+ // operators
178+ SN_op_Addition ,
179+ SN_op_BitwiseAnd ,
180+ SN_op_BitwiseOr ,
181+ SN_op_Division ,
182+ SN_op_ExclusiveOr ,
183+ SN_op_LeftShift ,
184+ SN_op_Multiply ,
185+ SN_op_OnesComplement ,
186+ SN_op_RightShift ,
187+ SN_op_Subtraction ,
188+ SN_op_UnaryNegation ,
189+ SN_op_UnsignedRightShift ,
177190};
178191
179192static MonoTypeEnum
@@ -192,8 +205,24 @@ resolve_native_size (MonoTypeEnum type)
192205 return MONO_TYPE_U8 ;
193206#endif
194207 return type ;
208+ }
195209
210+ static const char *
211+ strip_explicit_isimd_prefix (const char * cmethod_name )
212+ {
213+ if (strncmp (cmethod_name , "System.Runtime.Intrinsics.ISimdVector<System." , 45 ) == 0 ) {
214+ // We want explicitly implemented ISimdVector<TSelf, T> APIs to still be expanded where possible
215+ // but, they all prefix the qualified name of the interface first, so we'll check for that and
216+ // skip the prefix before trying to resolve the method.
217+ if (strncmp (cmethod_name + 45 , "Runtime.Intrinsics.Vector128<T>,T>." , 35 ) == 0 ) {
218+ cmethod_name += 80 ;
219+ } else if (strncmp (cmethod_name + 45 , "Numerics.Vector<T>,T>." , 22 ) == 0 ) {
220+ cmethod_name += 67 ;
221+ }
222+ }
223+ return cmethod_name ;
196224}
225+
197226// Returns if opcode was added
198227static gboolean
199228emit_common_simd_operations (TransformData * td , int id , int atype , int vector_size , int arg_size , int scalar_arg , gint16 * simd_opcode , gint16 * simd_intrins )
@@ -475,22 +504,11 @@ emit_vector_create (TransformData *td, MonoMethodSignature *csignature, MonoClas
475504static gboolean
476505emit_sri_vector128 (TransformData * td , MonoMethod * cmethod , MonoMethodSignature * csignature )
477506{
478- const char * cmethod_name = cmethod -> name ;
479-
480- if (strncmp (cmethod_name , "System.Runtime.Intrinsics.ISimdVector<System.Runtime.Intrinsics.Vector" , 70 ) == 0 ) {
481- // We want explicitly implemented ISimdVector<TSelf, T> APIs to still be expanded where possible
482- // but, they all prefix the qualified name of the interface first, so we'll check for that and
483- // skip the prefix before trying to resolve the method.
484-
485- if (strncmp (cmethod_name + 70 , "128<T>,T>." , 10 ) == 0 ) {
486- cmethod_name += 80 ;
487- }
488- }
489-
490507#ifdef HOST_BROWSER
491508 if (emit_sri_packedsimd (td , cmethod , csignature ))
492509 return TRUE;
493510#endif
511+ const char * cmethod_name = strip_explicit_isimd_prefix (cmethod -> name );
494512
495513 int id = lookup_intrins (sri_vector128_methods , sizeof (sri_vector128_methods ), cmethod_name );
496514 if (id == -1 )
@@ -699,19 +717,12 @@ emit_sri_vector128 (TransformData *td, MonoMethod *cmethod, MonoMethodSignature
699717static gboolean
700718emit_sri_vector128_t (TransformData * td , MonoMethod * cmethod , MonoMethodSignature * csignature )
701719{
702- const char * cmethod_name = cmethod -> name ;
703- bool explicitly_implemented = false;
704-
705- if (strncmp (cmethod_name , "System.Runtime.Intrinsics.ISimdVector<System.Runtime.Intrinsics.Vector" , 70 ) == 0 ) {
706- // We want explicitly implemented ISimdVector<TSelf, T> APIs to still be expanded where possible
707- // but, they all prefix the qualified name of the interface first, so we'll check for that and
708- // skip the prefix before trying to resolve the method.
709-
710- if ((strncmp (cmethod_name + 70 , "128<T>,T>." , 10 ) == 0 )) {
711- cmethod_name += 80 ;
712- explicitly_implemented = true;
713- }
714- }
720+ #ifdef HOST_BROWSER
721+ if (emit_sri_packedsimd (td , cmethod , csignature ))
722+ return TRUE;
723+ #endif
724+ const char * cmethod_name = strip_explicit_isimd_prefix (cmethod -> name );
725+ bool explicitly_implemented = cmethod_name != cmethod -> name ;
715726
716727 int id = lookup_intrins (sri_vector128_t_methods , sizeof (sri_vector128_t_methods ), cmethod -> name );
717728 if (id == -1 ) {
@@ -750,17 +761,12 @@ emit_sri_vector128_t (TransformData *td, MonoMethod *cmethod, MonoMethodSignatur
750761static gboolean
751762emit_sn_vector_t (TransformData * td , MonoMethod * cmethod , MonoMethodSignature * csignature , gboolean newobj )
752763{
753- const char * cmethod_name = cmethod -> name ;
754- bool explicitly_implemented = false;
755-
756- if (strncmp (cmethod_name , "System.Runtime.Intrinsics.ISimdVector<System.Numerics.Vector<T>,T>." , 67 ) == 0 ) {
757- // We want explicitly implemented ISimdVector<TSelf, T> APIs to still be expanded where possible
758- // but, they all prefix the qualified name of the interface first, so we'll check for that and
759- // skip the prefix before trying to resolve the method.
760-
761- cmethod_name += 67 ;
762- explicitly_implemented = true;
763- }
764+ #ifdef HOST_BROWSER
765+ if (emit_sri_packedsimd (td , cmethod , csignature ))
766+ return TRUE;
767+ #endif
768+ const char * cmethod_name = strip_explicit_isimd_prefix (cmethod -> name );
769+ bool explicitly_implemented = cmethod_name != cmethod -> name ;
764770
765771 int id = lookup_intrins (sn_vector_t_methods , sizeof (sn_vector_t_methods ), cmethod_name );
766772 if (id == -1 ) {
@@ -1112,10 +1118,23 @@ emit_sri_packedsimd (TransformData *td, MonoMethod *cmethod, MonoMethodSignature
11121118 if (!is_packedsimd ) {
11131119 // transform the method name from the Vector(128|) name to the packed simd name
11141120 // FIXME: This is a hack, but it works for now.
1115- id = lookup_intrins (packed_simd_alias_methods , sizeof (packed_simd_alias_methods ), cmethod_name );
1121+ if (csignature -> hasthis ) {
1122+ return FALSE;
1123+ }
1124+ int scalar_arg = -1 ;
1125+ for (int i = 0 ; i < csignature -> param_count ; i ++ ) {
1126+ if (csignature -> params [i ]-> type != MONO_TYPE_GENERICINST )
1127+ scalar_arg = i ;
1128+ }
1129+ cmethod_name = strip_explicit_isimd_prefix (cmethod_name );
1130+ id = lookup_intrins (packedsimd_alias_methods , sizeof (packedsimd_alias_methods ), cmethod_name );
11161131 gboolean is_unsigned = (atype == MONO_TYPE_U1 || atype == MONO_TYPE_U2 || atype == MONO_TYPE_U4 || atype == MONO_TYPE_U8 || atype == MONO_TYPE_U );
11171132
1118- // cmethod_name = must be a packed simd intrinsic, so we can just use the name directly
1133+ // cmethod_name must match a packed simd intrinsic name, so use an alias when needed.
1134+ // If a match with the aliased name and matching arguments is found, we use it,
1135+ // so be careful not to overmatch if the implementations differ (e.g. Dot.)
1136+ // Failing to find a match is expected in some cases for specific types of T, we simply
1137+ // fall back to the regular intrinsics, then to managed looking for an implementation.
11191138 switch (id ) {
11201139 case SN_LessThan :
11211140 cmethod_name = "CompareLessThan" ;
@@ -1133,23 +1152,61 @@ emit_sri_packedsimd (TransformData *td, MonoMethod *cmethod, MonoMethodSignature
11331152 cmethod_name = "CompareEqual" ;
11341153 break ;
11351154 case SN_BitwiseAnd :
1155+ case SN_op_BitwiseAnd :
11361156 cmethod_name = "And" ;
11371157 break ;
11381158 case SN_BitwiseOr :
1159+ case SN_op_BitwiseOr :
11391160 cmethod_name = "Or" ;
11401161 break ;
11411162 case SN_OnesComplement :
1163+ case SN_op_OnesComplement :
11421164 cmethod_name = "Not" ;
11431165 break ;
1166+ case SN_Load :
1167+ case SN_LoadUnsafe :
1168+ cmethod_name = "LoadVector128" ;
1169+ break ;
11441170 case SN_WidenLower :
11451171 cmethod_name = is_unsigned ? "ZeroExtendWideningLower" : "SignExtendWideningLower" ;
11461172 break ;
11471173 case SN_WidenUpper :
11481174 cmethod_name = is_unsigned ? "ZeroExtendWideningUpper" : "SignExtendWideningUpper" ;
11491175 break ;
1150- case SN_Load :
1151- case SN_LoadUnsafe :
1152- cmethod_name = "LoadVector128" ;
1176+ case SN_op_Addition :
1177+ cmethod_name = "Add" ;
1178+ break ;
1179+ case SN_op_Division :
1180+ if (scalar_arg != -1 )
1181+ return FALSE;
1182+ cmethod_name = "Divide" ;
1183+ break ;
1184+ case SN_op_ExclusiveOr :
1185+ cmethod_name = "Xor" ;
1186+ break ;
1187+ case SN_op_LeftShift :
1188+ if (scalar_arg != 1 )
1189+ return FALSE;
1190+ cmethod_name = "ShiftLeft" ;
1191+ break ;
1192+ case SN_op_Multiply :
1193+ if (scalar_arg != -1 )
1194+ return FALSE;
1195+ cmethod_name = "Multiply" ;
1196+ break ;
1197+ case SN_op_RightShift :
1198+ if (scalar_arg != 1 )
1199+ return FALSE;
1200+ cmethod_name = is_unsigned ? "ShiftRightLogical" : "ShiftRightArithmetic" ;
1201+ break ;
1202+ case SN_op_Subtraction :
1203+ cmethod_name = "Subtract" ;
1204+ break ;
1205+ case SN_op_UnaryNegation :
1206+ cmethod_name = "Negate" ;
1207+ break ;
1208+ case SN_op_UnsignedRightShift :
1209+ cmethod_name = "ShiftRightLogical" ;
11531210 break ;
11541211 case SN_Add :
11551212 case SN_AndNot :
0 commit comments