Skip to content

Commit

Permalink
Recognize the Vector128/256.AsVector* methods as intrinsic (#1280)
Browse files Browse the repository at this point in the history
* Recognize the `Vector128/256.AsVector*` methods as intrinsic

* Ensure we normalize the struct handle for S.Numerics to S.R.Intrinsic vector conversions

* Marking the Vector128/256.As* methods as intrinsic

* Don't handle AsVector2 or AsVector3 as intrinsic right now
  • Loading branch information
tannergooding committed Jan 24, 2020
1 parent baaab1f commit cec14a8
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/coreclr/src/jit/hwintrinsiclistxarch.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ HARDWARE_INTRINSIC(Vector128_AsSingle, "AsSingle",
HARDWARE_INTRINSIC(Vector128_AsUInt16, "AsUInt16", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(Vector128_AsUInt32, "AsUInt32", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(Vector128_AsUInt64, "AsUInt64", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(Vector128_AsVector, "AsVector", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(Vector128_AsVector2, "AsVector2", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(Vector128_AsVector3, "AsVector3", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(Vector128_AsVector4, "AsVector4", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(Vector128_AsVector128, "AsVector128", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(Vector128_Count, "get_Count", Vector128, -1, 16, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(Vector128_CreateScalarUnsafe, "CreateScalarUnsafe", Vector128, -1, 16, 1, {INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_movss, INS_movsdsse2}, HW_Category_SIMDScalar, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(Vector128_GetElement, "GetElement", Vector128, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg)
Expand All @@ -63,6 +68,8 @@ HARDWARE_INTRINSIC(Vector256_AsSingle, "AsSingle",
HARDWARE_INTRINSIC(Vector256_AsUInt16, "AsUInt16", Vector256, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(Vector256_AsUInt32, "AsUInt32", Vector256, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(Vector256_AsUInt64, "AsUInt64", Vector256, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(Vector256_AsVector, "AsVector", Vector256, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(Vector256_AsVector256, "AsVector256", Vector256, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(Vector256_Count, "get_Count", Vector256, -1, 32, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(Vector256_CreateScalarUnsafe, "CreateScalarUnsafe", Vector256, -1, 32, 1, {INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_movss, INS_movsdsse2}, HW_Category_SIMDScalar, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics)
HARDWARE_INTRINSIC(Vector256_GetElement, "GetElement", Vector256, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_BaseTypeFromFirstArg)
Expand Down
126 changes: 126 additions & 0 deletions src/coreclr/src/jit/hwintrinsicxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,132 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic,
break;
}

case NI_Vector128_AsVector:
{
assert(sig->numArgs == 1);

if (getSIMDVectorRegisterByteLength() == YMM_REGSIZE_BYTES)
{
// Vector<T> is TYP_SIMD32, so we should treat this as a call to Vector128.ToVector256
return impBaseIntrinsic(NI_Vector128_ToVector256, clsHnd, method, sig, mustExpand);
}

assert(getSIMDVectorRegisterByteLength() == XMM_REGSIZE_BYTES);

// We fold away the cast here, as it only exists to satisfy
// the type system. It is safe to do this here since the retNode type
// and the signature return type are both the same TYP_SIMD.

retNode = impSIMDPopStack(retType, /* expectAddr: */ false, sig->retTypeClass);
SetOpLclRelatedToSIMDIntrinsic(retNode);
assert(retNode->gtType == getSIMDTypeForSize(getSIMDTypeSizeInBytes(sig->retTypeSigClass)));

break;
}

case NI_Vector128_AsVector2:
case NI_Vector128_AsVector3:
{
// TYP_SIMD8 and TYP_SIMD12 currently only expose "safe" versions
// which zero the upper elements and so are implemented in managed.
unreached();
}

case NI_Vector128_AsVector4:
{
// We fold away the cast here, as it only exists to satisfy
// the type system. It is safe to do this here since the retNode type
// and the signature return type are both the same TYP_SIMD or the
// return type is a smaller TYP_SIMD that shares the same register.

retNode = impSIMDPopStack(retType, /* expectAddr: */ false, sig->retTypeClass);
SetOpLclRelatedToSIMDIntrinsic(retNode);
assert(retNode->gtType == getSIMDTypeForSize(getSIMDTypeSizeInBytes(sig->retTypeSigClass)));

break;
}

case NI_Vector128_AsVector128:
{
assert(sig->numArgs == 1);

switch (getSIMDTypeForSize(simdSize))
{
case TYP_SIMD8:
case TYP_SIMD12:
{
// TYP_SIMD8 and TYP_SIMD12 currently only expose "safe" versions
// which zero the upper elements and so are implemented in managed.
unreached();
}

case TYP_SIMD16:
{
// We fold away the cast here, as it only exists to satisfy
// the type system. It is safe to do this here since the retNode type
// and the signature return type are both the same TYP_SIMD.

retNode = impSIMDPopStack(retType, /* expectAddr: */ false, sig->retTypeClass);
SetOpLclRelatedToSIMDIntrinsic(retNode);
assert(retNode->gtType == getSIMDTypeForSize(getSIMDTypeSizeInBytes(sig->retTypeSigClass)));

break;
}

case TYP_SIMD32:
{
// Vector<T> is TYP_SIMD32, so we should treat this as a call to Vector256.GetLower
return impBaseIntrinsic(NI_Vector256_GetLower, clsHnd, method, sig, mustExpand);
}

default:
{
unreached();
}
}

break;
}

case NI_Vector256_AsVector:
case NI_Vector256_AsVector256:
{
assert(sig->numArgs == 1);

if (getSIMDVectorRegisterByteLength() == YMM_REGSIZE_BYTES)
{
// We fold away the cast here, as it only exists to satisfy
// the type system. It is safe to do this here since the retNode type
// and the signature return type are both the same TYP_SIMD.

retNode = impSIMDPopStack(retType, /* expectAddr: */ false, sig->retTypeClass);
SetOpLclRelatedToSIMDIntrinsic(retNode);
assert(retNode->gtType == getSIMDTypeForSize(getSIMDTypeSizeInBytes(sig->retTypeSigClass)));

break;
}

assert(getSIMDVectorRegisterByteLength() == XMM_REGSIZE_BYTES);

if (compSupports(InstructionSet_AVX))
{
// We support Vector256 but Vector<T> is only 16-bytes, so we should
// treat this method as a call to Vector256.GetLower or Vector128.ToVector256

if (intrinsic == NI_Vector256_AsVector)
{
return impBaseIntrinsic(NI_Vector256_GetLower, clsHnd, method, sig, mustExpand);
}
else
{
assert(intrinsic == NI_Vector256_AsVector256);
return impBaseIntrinsic(NI_Vector128_ToVector256, clsHnd, method, sig, mustExpand);
}
}

break;
}

case NI_Vector128_Count:
case NI_Vector256_Count:
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ public static Vector128<float> AsVector128(this Vector3 value)
/// <summary>Reinterprets a <see cref="Vector4" /> as a new <see cref="Vector128{Single}" />.</summary>
/// <param name="value">The vector to reinterpret.</param>
/// <returns><paramref name="value" /> reinterpreted as a new <see cref="Vector128{Single}" />.</returns>
[Intrinsic]
public static Vector128<float> AsVector128(this Vector4 value)
{
return Unsafe.As<Vector4, Vector128<float>>(ref value);
Expand All @@ -202,6 +203,7 @@ public static Vector128<float> AsVector128(this Vector4 value)
/// <param name="value">The vector to reinterpret.</param>
/// <returns><paramref name="value" /> reinterpreted as a new <see cref="Vector128{T}" />.</returns>
/// <exception cref="NotSupportedException">The type of <paramref name="value" /> (<typeparamref name="T" />) is not supported.</exception>
[Intrinsic]
public static Vector128<T> AsVector128<T>(this Vector<T> value)
where T : struct
{
Expand Down Expand Up @@ -229,6 +231,7 @@ public static Vector3 AsVector3(this Vector128<float> value)
/// <summary>Reinterprets a <see cref="Vector128{Single}" /> as a new <see cref="Vector4" />.</summary>
/// <param name="value">The vector to reinterpret.</param>
/// <returns><paramref name="value" /> reinterpreted as a new <see cref="Vector4" />.</returns>
[Intrinsic]
public static Vector4 AsVector4(this Vector128<float> value)
{
return Unsafe.As<Vector128<float>, Vector4>(ref value);
Expand All @@ -239,6 +242,7 @@ public static Vector4 AsVector4(this Vector128<float> value)
/// <param name="value">The vector to reinterpret.</param>
/// <returns><paramref name="value" /> reinterpreted as a new <see cref="Vector{T}" />.</returns>
/// <exception cref="NotSupportedException">The type of <paramref name="value" /> (<typeparamref name="T" />) is not supported.</exception>
[Intrinsic]
public static Vector<T> AsVector<T>(this Vector128<T> value)
where T : struct
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ public static Vector256<ulong> AsUInt64<T>(this Vector256<T> vector)
/// <param name="value">The vector to reinterpret.</param>
/// <returns><paramref name="value" /> reinterpreted as a new <see cref="Vector256{T}" />.</returns>
/// <exception cref="NotSupportedException">The type of <paramref name="value" /> (<typeparamref name="T" />) is not supported.</exception>
[Intrinsic]
public static Vector256<T> AsVector256<T>(this Vector<T> value)
where T : struct
{
Expand All @@ -194,6 +195,7 @@ public static Vector256<T> AsVector256<T>(this Vector<T> value)
/// <param name="value">The vector to reinterpret.</param>
/// <returns><paramref name="value" /> reinterpreted as a new <see cref="Vector{T}" />.</returns>
/// <exception cref="NotSupportedException">The type of <paramref name="value" /> (<typeparamref name="T" />) is not supported.</exception>
[Intrinsic]
public static Vector<T> AsVector<T>(this Vector256<T> value)
where T : struct
{
Expand Down

0 comments on commit cec14a8

Please sign in to comment.