Skip to content

Commit 8b9c088

Browse files
authored
[mono][interp] implement interp bitcast intrinsics (#115443)
implement interpreter bitcast intrinsics and disable broken mono windows jit bitcast intrinsic
1 parent abc9652 commit 8b9c088

File tree

14 files changed

+91
-114
lines changed

14 files changed

+91
-114
lines changed

src/libraries/System.Private.CoreLib/src/System/Numerics/Plane.Extensions.cs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,6 @@ public static partial class Vector
1111
/// <param name="value">The plane to reinterpret.</param>
1212
/// <returns><paramref name="value" /> reinterpreted as a new <see cref="Vector4" />.</returns>
1313
[Intrinsic]
14-
public static Vector4 AsVector4(this Plane value)
15-
{
16-
#if MONO
17-
return Unsafe.As<Plane, Vector4>(ref value);
18-
#else
19-
return Unsafe.BitCast<Plane, Vector4>(value);
20-
#endif
21-
}
14+
public static Vector4 AsVector4(this Plane value) => Unsafe.BitCast<Plane, Vector4>(value);
2215
}
2316
}

src/libraries/System.Private.CoreLib/src/System/Numerics/Quaternion.Extensions.cs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,6 @@ public static partial class Vector
1111
/// <param name="value">The quaternion to reinterpret.</param>
1212
/// <returns><paramref name="value" /> reinterpreted as a new <see cref="Quaternion" />.</returns>
1313
[Intrinsic]
14-
public static Vector4 AsVector4(this Quaternion value)
15-
{
16-
#if MONO
17-
return Unsafe.As<Quaternion, Vector4>(ref value);
18-
#else
19-
return Unsafe.BitCast<Quaternion, Vector4>(value);
20-
#endif
21-
}
14+
public static Vector4 AsVector4(this Quaternion value) => Unsafe.BitCast<Quaternion, Vector4>(value);
2215
}
2316
}

src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,7 @@ public static Vector<TTo> As<TFrom, TTo>(this Vector<TFrom> vector)
149149
ThrowHelper.ThrowForUnsupportedNumericsVectorBaseType<TFrom>();
150150
ThrowHelper.ThrowForUnsupportedNumericsVectorBaseType<TTo>();
151151

152-
#if MONO
153-
return Unsafe.As<Vector<TFrom>, Vector<TTo>>(ref vector);
154-
#else
155152
return Unsafe.BitCast<Vector<TFrom>, Vector<TTo>>(vector);
156-
#endif
157153
}
158154

159155
/// <summary>Reinterprets a <see cref="Vector{T}" /> as a new <see langword="Vector&lt;Byte&gt;" />.</summary>

src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.Extensions.cs

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,12 @@ public static unsafe partial class Vector
1212
/// <summary>Reinterprets a <see cref="Vector4" /> as a new <see cref="Plane" />.</summary>
1313
/// <param name="value">The vector to reinterpret.</param>
1414
/// <returns><paramref name="value" /> reinterpreted as a new <see cref="Plane" />.</returns>
15-
public static Plane AsPlane(this Vector4 value)
16-
{
17-
#if MONO
18-
return Unsafe.As<Vector4, Plane>(ref value);
19-
#else
20-
return Unsafe.BitCast<Vector4, Plane>(value);
21-
#endif
22-
}
15+
public static Plane AsPlane(this Vector4 value) => Unsafe.BitCast<Vector4, Plane>(value);
2316

2417
/// <summary>Reinterprets a <see cref="Vector4" /> as a new <see cref="Quaternion" />.</summary>
2518
/// <param name="value">The vector to reinterpret.</param>
2619
/// <returns><paramref name="value" /> reinterpreted as a new <see cref="Quaternion" />.</returns>
27-
public static Quaternion AsQuaternion(this Vector4 value)
28-
{
29-
#if MONO
30-
return Unsafe.As<Vector4, Quaternion>(ref value);
31-
#else
32-
return Unsafe.BitCast<Vector4, Quaternion>(value);
33-
#endif
34-
}
20+
public static Quaternion AsQuaternion(this Vector4 value) => Unsafe.BitCast<Vector4, Quaternion>(value);
3521

3622
/// <summary>Reinterprets a <see cref="Vector4" /> as a new <see cref="Vector2" />.</summary>
3723
/// <param name="value">The vector to reinterpret.</param>

src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.Numerics.cs

Lines changed: 6 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -53,53 +53,25 @@ public static partial class Vector128
5353
/// <param name="value">The vector to reinterpret.</param>
5454
/// <returns><paramref name="value" /> reinterpreted as a new <see cref="Plane" />.</returns>
5555
[Intrinsic]
56-
public static Plane AsPlane(this Vector128<float> value)
57-
{
58-
#if MONO
59-
return Unsafe.As<Vector128<float>, Plane>(ref value);
60-
#else
61-
return Unsafe.BitCast<Vector128<float>, Plane>(value);
62-
#endif
63-
}
56+
public static Plane AsPlane(this Vector128<float> value) => Unsafe.BitCast<Vector128<float>, Plane>(value);
6457

6558
/// <summary>Reinterprets a <see langword="Vector128&lt;Single&gt;" /> as a new <see cref="Quaternion" />.</summary>
6659
/// <param name="value">The vector to reinterpret.</param>
6760
/// <returns><paramref name="value" /> reinterpreted as a new <see cref="Quaternion" />.</returns>
6861
[Intrinsic]
69-
public static Quaternion AsQuaternion(this Vector128<float> value)
70-
{
71-
#if MONO
72-
return Unsafe.As<Vector128<float>, Quaternion>(ref value);
73-
#else
74-
return Unsafe.BitCast<Vector128<float>, Quaternion>(value);
75-
#endif
76-
}
62+
public static Quaternion AsQuaternion(this Vector128<float> value) => Unsafe.BitCast<Vector128<float>, Quaternion>(value);
7763

7864
/// <summary>Reinterprets a <see cref="Plane" /> as a new <see langword="Vector128&lt;Single&gt;" />.</summary>
7965
/// <param name="value">The plane to reinterpret.</param>
8066
/// <returns><paramref name="value" /> reinterpreted as a new <see langword="Vector128&lt;Single&gt;" />.</returns>
8167
[Intrinsic]
82-
public static Vector128<float> AsVector128(this Plane value)
83-
{
84-
#if MONO
85-
return Unsafe.As<Plane, Vector128<float>>(ref value);
86-
#else
87-
return Unsafe.BitCast<Plane, Vector128<float>>(value);
88-
#endif
89-
}
68+
public static Vector128<float> AsVector128(this Plane value) => Unsafe.BitCast<Plane, Vector128<float>>(value);
9069

9170
/// <summary>Reinterprets a <see cref="Quaternion" /> as a new <see langword="Vector128&lt;Single&gt;" />.</summary>
9271
/// <param name="value">The quaternion to reinterpret.</param>
9372
/// <returns><paramref name="value" /> reinterpreted as a new <see langword="Vector128&lt;Single&gt;" />.</returns>
9473
[Intrinsic]
95-
public static Vector128<float> AsVector128(this Quaternion value)
96-
{
97-
#if MONO
98-
return Unsafe.As<Quaternion, Vector128<float>>(ref value);
99-
#else
100-
return Unsafe.BitCast<Quaternion, Vector128<float>>(value);
101-
#endif
102-
}
74+
public static Vector128<float> AsVector128(this Quaternion value) => Unsafe.BitCast<Quaternion, Vector128<float>>(value);
10375

10476
/// <summary>Reinterprets a <see langword="Vector2" /> as a new <see cref="Vector128&lt;Single&gt;" /> with the new elements zeroed.</summary>
10577
/// <param name="value">The vector to reinterpret.</param>
@@ -117,14 +89,7 @@ public static Vector128<float> AsVector128(this Quaternion value)
11789
/// <param name="value">The vector to reinterpret.</param>
11890
/// <returns><paramref name="value" /> reinterpreted as a new <see langword="Vector128&lt;Single&gt;" />.</returns>
11991
[Intrinsic]
120-
public static Vector128<float> AsVector128(this Vector4 value)
121-
{
122-
#if MONO
123-
return Unsafe.As<Vector4, Vector128<float>>(ref value);
124-
#else
125-
return Unsafe.BitCast<Vector4, Vector128<float>>(value);
126-
#endif
127-
}
92+
public static Vector128<float> AsVector128(this Vector4 value) => Unsafe.BitCast<Vector4, Vector128<float>>(value);
12893

12994
/// <summary>Reinterprets a <see cref="Vector{T}" /> as a new <see cref="Vector128{T}" />.</summary>
13095
/// <typeparam name="T">The type of the elements in the vector.</typeparam>
@@ -196,14 +161,7 @@ public static Vector3 AsVector3(this Vector128<float> value)
196161
/// <param name="value">The vector to reinterpret.</param>
197162
/// <returns><paramref name="value" /> reinterpreted as a new <see cref="Vector4" />.</returns>
198163
[Intrinsic]
199-
public static Vector4 AsVector4(this Vector128<float> value)
200-
{
201-
#if MONO
202-
return Unsafe.As<Vector128<float>, Vector4>(ref value);
203-
#else
204-
return Unsafe.BitCast<Vector128<float>, Vector4>(value);
205-
#endif
206-
}
164+
public static Vector4 AsVector4(this Vector128<float> value) => Unsafe.BitCast<Vector128<float>, Vector4>(value);
207165

208166
/// <summary>Reinterprets a <see cref="Vector128{T}" /> as a new <see cref="Vector{T}" />.</summary>
209167
/// <typeparam name="T">The type of the elements in the vector.</typeparam>

src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,7 @@ public static Vector128<TTo> As<TFrom, TTo>(this Vector128<TFrom> vector)
177177
ThrowHelper.ThrowForUnsupportedIntrinsicsVector128BaseType<TFrom>();
178178
ThrowHelper.ThrowForUnsupportedIntrinsicsVector128BaseType<TTo>();
179179

180-
#if MONO
181-
return Unsafe.As<Vector128<TFrom>, Vector128<TTo>>(ref vector);
182-
#else
183180
return Unsafe.BitCast<Vector128<TFrom>, Vector128<TTo>>(vector);
184-
#endif
185181
}
186182

187183
/// <summary>Reinterprets a <see cref="Vector128{T}" /> as a new <see langword="Vector128&lt;Byte&gt;" />.</summary>

src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -171,11 +171,7 @@ public static Vector256<TTo> As<TFrom, TTo>(this Vector256<TFrom> vector)
171171
ThrowHelper.ThrowForUnsupportedIntrinsicsVector256BaseType<TFrom>();
172172
ThrowHelper.ThrowForUnsupportedIntrinsicsVector256BaseType<TTo>();
173173

174-
#if MONO
175-
return Unsafe.As<Vector256<TFrom>, Vector256<TTo>>(ref vector);
176-
#else
177174
return Unsafe.BitCast<Vector256<TFrom>, Vector256<TTo>>(vector);
178-
#endif
179175
}
180176

181177
/// <summary>Reinterprets a <see cref="Vector256{T}" /> as a new <see langword="Vector256&lt;Byte&gt;" />.</summary>

src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,7 @@ public static Vector512<TTo> As<TFrom, TTo>(this Vector512<TFrom> vector)
170170
ThrowHelper.ThrowForUnsupportedIntrinsicsVector512BaseType<TFrom>();
171171
ThrowHelper.ThrowForUnsupportedIntrinsicsVector512BaseType<TTo>();
172172

173-
#if MONO
174-
return Unsafe.As<Vector512<TFrom>, Vector512<TTo>>(ref vector);
175-
#else
176173
return Unsafe.BitCast<Vector512<TFrom>, Vector512<TTo>>(vector);
177-
#endif
178174
}
179175

180176
/// <summary>Reinterprets a <see cref="Vector512{T}" /> as a new <see langword="Vector512&lt;Byte&gt;" />.</summary>

src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,7 @@ public static Vector64<TTo> As<TFrom, TTo>(this Vector64<TFrom> vector)
170170
ThrowHelper.ThrowForUnsupportedIntrinsicsVector64BaseType<TFrom>();
171171
ThrowHelper.ThrowForUnsupportedIntrinsicsVector64BaseType<TTo>();
172172

173-
#if MONO
174-
return Unsafe.As<Vector64<TFrom>, Vector64<TTo>>(ref vector);
175-
#else
176173
return Unsafe.BitCast<Vector64<TFrom>, Vector64<TTo>>(vector);
177-
#endif
178174
}
179175

180176
/// <summary>Reinterprets a <see cref="Vector64{T}" /> as a new <see langword="Vector64&lt;Byte&gt;" />.</summary>

src/mono/mono/mini/interp/transform.c

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2139,6 +2139,16 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas
21392139
return TRUE;
21402140
}
21412141
}
2142+
} else if (in_corlib && !strcmp (klass_name_space, "System") && (!strcmp (klass_name, "BitConverter"))) {
2143+
if (!strcmp (tm, "DoubleToInt64Bits") || !strcmp (tm, "DoubleToUInt64Bits")) {
2144+
*op = MINT_MOV_8;
2145+
} else if (!strcmp (tm, "Int32BitsToSingle") || !strcmp (tm, "UInt32BitsToSingle")) {
2146+
*op = MINT_MOV_4;
2147+
} else if (!strcmp (tm, "Int64BitsToDouble") || !strcmp (tm, "UInt64BitsToDouble")) {
2148+
*op = MINT_MOV_8;
2149+
} else if (!strcmp (tm, "SingleToInt32Bits") || !strcmp (tm, "SingleToUInt32Bits")) {
2150+
*op = MINT_MOV_4;
2151+
}
21422152
} else if (in_corlib && !strcmp (klass_name_space, "System.Runtime.CompilerServices") && !strcmp (klass_name, "Unsafe")) {
21432153
if (!strcmp (tm, "AddByteOffset"))
21442154
#if SIZEOF_VOID_P == 4
@@ -2156,6 +2166,72 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas
21562166
return TRUE;
21572167
} else if (!strcmp (tm, "AreSame")) {
21582168
*op = MINT_CEQ_P;
2169+
} else if (!strcmp (tm, "BitCast")) {
2170+
MonoGenericContext *ctx = mono_method_get_context (target_method);
2171+
g_assert (ctx);
2172+
g_assert (ctx->method_inst);
2173+
g_assert (ctx->method_inst->type_argc == 2);
2174+
g_assert (csignature->param_count == 1);
2175+
2176+
// We explicitly do not handle gsharedvt as it is meant as a slow fallback strategy
2177+
// instead we fallback to the managed implementation which will do the right things
2178+
2179+
MonoType *tfrom = ctx->method_inst->type_argv [0];
2180+
MonoType *tto = ctx->method_inst->type_argv [1];
2181+
tfrom = mini_get_underlying_type (tfrom);
2182+
tto = mini_get_underlying_type (tto);
2183+
2184+
// The underlying API always throws for reference type inputs, so we
2185+
// fallback to the managed implementation to let that handling occur
2186+
2187+
if (MONO_TYPE_IS_REFERENCE (tfrom) || MONO_TYPE_IS_REFERENCE (tto)) {
2188+
return FALSE;
2189+
}
2190+
2191+
MonoClass *tto_klass = mono_class_from_mono_type_internal (tto);
2192+
2193+
// The same applies for when the type sizes do not match, as this will always throw
2194+
// and so its not an expected case and we can fallback to the managed implementation
2195+
2196+
int tfrom_align, tto_align;
2197+
gint32 size = mono_type_size (tfrom, &tfrom_align);
2198+
if (size != mono_type_size (tto, &tto_align)) {
2199+
return FALSE;
2200+
}
2201+
g_assert (size < G_MAXUINT16);
2202+
2203+
// We have several different move opcodes to handle the data depending on the
2204+
// source and target types, so detect and optimize the most common ones falling
2205+
// back to what is effectively `ReadUnaligned<TTo>(ref As<TFrom, byte>(ref source))`
2206+
// for anything that can't be special cased as potentially zero-cost move.
2207+
2208+
if (m_class_is_enumtype (tto_klass)) {
2209+
tto = mono_class_enum_basetype_internal (tto_klass);
2210+
}
2211+
2212+
int mov_op = interp_get_mov_for_type (mono_mint_type (tto), TRUE);
2213+
2214+
if (mov_op == MINT_MOV_VT ) {
2215+
if (size <= 4) {
2216+
*op = MINT_MOV_4;
2217+
} else if (size <= 8) {
2218+
*op = MINT_MOV_8;
2219+
} else {
2220+
td->sp--;
2221+
interp_add_ins (td, MINT_MOV_VT);
2222+
interp_ins_set_sreg (td->last_ins, td->sp [0].var);
2223+
push_type_vt (td, tto_klass, size);
2224+
interp_ins_set_dreg (td->last_ins, td->sp [-1].var);
2225+
td->last_ins->data [0] = GINT32_TO_UINT16 (size);
2226+
td->ip += 5;
2227+
return TRUE;
2228+
}
2229+
} else {
2230+
if (size < 4)
2231+
return FALSE;
2232+
2233+
*op = mov_op;
2234+
}
21592235
} else if (!strcmp (tm, "ByteOffset")) {
21602236
#if SIZEOF_VOID_P == 4
21612237
interp_add_ins (td, MINT_SUB_I4);

0 commit comments

Comments
 (0)