123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- #if BURST_INTERNAL || UNITY_BURST_EXPERIMENTAL_NEON_INTRINSICS
- using System.Runtime.CompilerServices;
- using System.Runtime.InteropServices;
- using static Unity.Burst.Intrinsics.Arm.Neon;
- using static Unity.Burst.Intrinsics.X86.F16C;
-
- namespace Unity.Burst.Intrinsics
- {
- /// <summary>
- /// Represents a 16-bit floating point value (half precision)
- /// Warning: this type may not be natively supported by your hardware, or its usage may be suboptimal
- /// </summary>
- public readonly struct f16 : System.IEquatable<f16>
- {
- /// <summary>
- /// The container for the actual 16-bit half precision floating point value
- /// </summary>
- private readonly ushort value;
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static uint f32tof16(float x)
- {
- if (IsF16CSupported)
- {
- var v = new v128();
- v.Float0 = x;
- var result = cvtps_ph(v, (int)X86.RoundingMode.FROUND_TRUNC_NOEXC);
- return result.UShort0;
- }
- else if (IsNeonHalfFPSupported)
- {
- var v = new v128();
- v.Float0 = x;
- var result = vcvt_f16_f32(v);
- return result.UShort0;
- }
- // Managed fallback
- const int infinity_32 = 255 << 23;
- const uint msk = 0x7FFFF000u;
-
- uint ux = asuint(x);
- uint uux = ux & msk;
- uint h = (uint)(asuint(min(asfloat(uux) * 1.92592994e-34f, 260042752.0f)) + 0x1000) >> 13; // Clamp to signed infinity if overflowed
- h = select(h,
- select(0x7c00u, 0x7e00u, (int)uux > infinity_32),
- (int)uux >= infinity_32); // NaN->qNaN and Inf->Inf
- return h | (ux & ~msk) >> 16;
- }
-
- /// <summary>Returns the bit pattern of a float as a uint.</summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static uint asuint(float x) { return (uint)asint(x); }
-
- /// <summary>Returns the minimum of two float values.</summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static float min(float x, float y) { return float.IsNaN(y) || x < y ? x : y; }
-
- /// <summary>Returns b if c is true, a otherwise.</summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static uint select(uint a, uint b, bool c) { return c ? b : a; }
-
- /// <summary>Returns the bit pattern of a uint as a float.</summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static float asfloat(uint x) { return asfloat((int)x); }
-
- [StructLayout(LayoutKind.Explicit)]
- private struct IntFloatUnion
- {
- [FieldOffset(0)]
- public int intValue;
- [FieldOffset(0)]
- public float floatValue;
- }
-
- /// <summary>Returns the bit pattern of an int as a float.</summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static float asfloat(int x)
- {
- IntFloatUnion u;
- u.floatValue = 0;
- u.intValue = x;
-
- return u.floatValue;
- }
-
- /// <summary>Returns the bit pattern of a float as an int.</summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static int asint(float x)
- {
- IntFloatUnion u;
- u.intValue = 0;
- u.floatValue = x;
- return u.intValue;
- }
-
- /// <summary>Constructs a half value from a half value.</summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public f16(f16 x)
- {
- value = x.value;
- }
-
- /// <summary>Constructs a half value from a float value.</summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public f16(float v)
- {
- value = (ushort)f32tof16(v);
- }
-
- /// <summary>Returns whether two f16 values are equal.</summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool operator ==(f16 lhs, f16 rhs)
- {
- return lhs.value == rhs.value;
- }
-
- /// <summary>Returns whether two f16 values are different.</summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool operator !=(f16 lhs, f16 rhs)
- {
- return lhs.value != rhs.value;
- }
-
- /// <summary>Returns true if the f16 is equal to a given f16, false otherwise.</summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool Equals(f16 rhs)
- {
- return value == rhs.value;
- }
-
- /// <summary>Returns true if the half is equal to a given half, false otherwise.</summary>
- public override bool Equals(object o) { return Equals((f16)o); }
-
- /// <summary>Returns a hash code for the half.</summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public override int GetHashCode() { return (int)value; }
-
- }
- }
- #endif // BURST_INTERNAL || UNITY_BURST_EXPERIMENTAL_NEON_INTRINSICS
|