You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
327 lines
14 KiB
327 lines
14 KiB
using System; |
|
|
|
namespace Unity.Burst.Intrinsics |
|
{ |
|
/// <summary> |
|
/// Common intrinsics that are exposed across all Burst targets. |
|
/// </summary> |
|
public static class Common |
|
{ |
|
/// <summary> |
|
/// Hint that the current thread should pause. |
|
/// |
|
/// In Burst compiled code this will map to platform specific |
|
/// ways to hint that the current thread should be paused as |
|
/// it is performing a calculation that would benefit from |
|
/// not contending with other threads. Atomic operations in |
|
/// tight loops (like spin-locks) can benefit from use of this |
|
/// intrinsic. |
|
/// |
|
/// - On x86 systems this maps to the `pause` instruction. |
|
/// - On ARM systems this maps to the `yield` instruction. |
|
/// |
|
/// Note that this is not an operating system level thread yield, |
|
/// it only provides a hint to the CPU that the current thread can |
|
/// afford to pause its execution temporarily. |
|
/// </summary> |
|
public static void Pause() { } |
|
|
|
#if UNITY_BURST_EXPERIMENTAL_PREFETCH_INTRINSIC |
|
public enum ReadWrite : int |
|
{ |
|
Read = 0, |
|
Write = 1, |
|
} |
|
|
|
public enum Locality : int |
|
{ |
|
NoTemporalLocality = 0, |
|
LowTemporalLocality = 1, |
|
ModerateTemporalLocality = 2, |
|
HighTemporalLocality = 3, |
|
} |
|
|
|
/// <summary> |
|
/// Prefetch a pointer. |
|
/// </summary> |
|
/// <param name="v">The pointer to prefetch.</param> |
|
/// <param name="rw">Whether the pointer will be used for reading or writing.</param> |
|
/// <param name="locality">The cache locality of the pointer.</param> |
|
public static unsafe void Prefetch(void* v, ReadWrite rw, Locality locality = Locality.HighTemporalLocality) { } |
|
#endif |
|
|
|
/// <summary> |
|
/// Return the low half of the multiplication of two numbers, and the high part as an out parameter. |
|
/// </summary> |
|
/// <param name="x">A value to multiply.</param> |
|
/// <param name="y">A value to multiply.</param> |
|
/// <param name="high">The high-half of the multiplication result.</param> |
|
/// <returns>The low-half of the multiplication result.</returns> |
|
public static ulong umul128(ulong x, ulong y, out ulong high) |
|
{ |
|
// Provide a software fallback for the cases Burst isn't being used. |
|
|
|
// Split the inputs into high/low sections. |
|
ulong xLo = (uint)x; |
|
ulong xHi = x >> 32; |
|
ulong yLo = (uint)y; |
|
ulong yHi = y >> 32; |
|
|
|
// We have to use 4 multiples to compute the full range of the result. |
|
ulong hi = xHi * yHi; |
|
ulong m1 = xHi * yLo; |
|
ulong m2 = yHi * xLo; |
|
ulong lo = xLo * yLo; |
|
|
|
ulong m1Lo = (uint)m1; |
|
ulong loHi = lo >> 32; |
|
ulong m1Hi = m1 >> 32; |
|
|
|
high = hi + m1Hi + ((loHi + m1Lo + m2) >> 32); |
|
return x * y; |
|
} |
|
|
|
#if UNITY_BURST_EXPERIMENTAL_ATOMIC_INTRINSICS |
|
/// <summary> |
|
/// Bitwise and as an atomic operation. |
|
/// </summary> |
|
/// <param name="location">Where to atomically and the result into.</param> |
|
/// <param name="value">The value to be combined.</param> |
|
/// <returns>The original value in <paramref name="location" />.</returns> |
|
/// <remarks>Using the return value of this intrinsic may result in worse code-generation on some platforms (a compare-exchange loop), rather than a single atomic instruction being generated.</remarks> |
|
/// <seealso cref="https://docs.microsoft.com/en-us/dotnet/api/system.threading.interlocked.and"/> |
|
public static int InterlockedAnd(ref int location, int value) |
|
{ |
|
// Provide a software fallback for the cases Burst isn't being used. |
|
|
|
var currentValue = System.Threading.Interlocked.Add(ref location, 0); |
|
|
|
while (true) |
|
{ |
|
var updatedValue = currentValue & value; |
|
|
|
// If nothing would change by and'ing in our thing, bail out early. |
|
if (updatedValue == currentValue) |
|
{ |
|
return currentValue; |
|
} |
|
|
|
var newValue = System.Threading.Interlocked.CompareExchange(ref location, updatedValue, currentValue); |
|
|
|
// If the original value was the same as the what we just got back from the compare exchange, it means our update succeeded. |
|
if (newValue == currentValue) |
|
{ |
|
return currentValue; |
|
} |
|
|
|
// Lastly update the last known good value of location and try again! |
|
currentValue = newValue; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Bitwise and as an atomic operation. |
|
/// </summary> |
|
/// <param name="location">Where to atomically and the result into.</param> |
|
/// <param name="value">The value to be combined.</param> |
|
/// <returns>The original value in <paramref name="location" />.</returns> |
|
/// <remarks>Using the return value of this intrinsic may result in worse code-generation on some platforms (a compare-exchange loop), rather than a single atomic instruction being generated.</remarks> |
|
/// <seealso cref="https://docs.microsoft.com/en-us/dotnet/api/system.threading.interlocked.and"/> |
|
public static uint InterlockedAnd(ref uint location, uint value) |
|
{ |
|
unsafe |
|
{ |
|
ref int locationAsInt = ref Unsafe.AsRef<int>(Unsafe.AsPointer(ref location)); |
|
int valueAsInt = (int)value; |
|
|
|
return (uint)InterlockedAnd(ref locationAsInt, valueAsInt); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Bitwise and as an atomic operation. |
|
/// </summary> |
|
/// <param name="location">Where to atomically and the result into.</param> |
|
/// <param name="value">The value to be combined.</param> |
|
/// <returns>The original value in <paramref name="location" />.</returns> |
|
/// <remarks>Using the return value of this intrinsic may result in worse code-generation on some platforms (a compare-exchange loop), rather than a single atomic instruction being generated.</remarks> |
|
/// <seealso cref="https://docs.microsoft.com/en-us/dotnet/api/system.threading.interlocked.and"/> |
|
public static long InterlockedAnd(ref long location, long value) |
|
{ |
|
// Provide a software fallback for the cases Burst isn't being used. |
|
|
|
var currentValue = System.Threading.Interlocked.Read(ref location); |
|
|
|
while (true) |
|
{ |
|
var updatedValue = currentValue & value; |
|
|
|
// If nothing would change by and'ing in our thing, bail out early. |
|
if (updatedValue == currentValue) |
|
{ |
|
return currentValue; |
|
} |
|
|
|
var newValue = System.Threading.Interlocked.CompareExchange(ref location, updatedValue, currentValue); |
|
|
|
// If the original value was the same as the what we just got back from the compare exchange, it means our update succeeded. |
|
if (newValue == currentValue) |
|
{ |
|
return currentValue; |
|
} |
|
|
|
// Lastly update the last known good value of location and try again! |
|
currentValue = newValue; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Bitwise and as an atomic operation. |
|
/// </summary> |
|
/// <param name="location">Where to atomically and the result into.</param> |
|
/// <param name="value">The value to be combined.</param> |
|
/// <returns>The original value in <paramref name="location" />.</returns> |
|
/// <remarks>Using the return value of this intrinsic may result in worse code-generation on some platforms (a compare-exchange loop), rather than a single atomic instruction being generated.</remarks> |
|
/// <seealso cref="https://docs.microsoft.com/en-us/dotnet/api/system.threading.interlocked.and"/> |
|
public static ulong InterlockedAnd(ref ulong location, ulong value) |
|
{ |
|
unsafe |
|
{ |
|
ref long locationAsInt = ref Unsafe.AsRef<long>(Unsafe.AsPointer(ref location)); |
|
long valueAsInt = (long)value; |
|
|
|
return (ulong)InterlockedAnd(ref locationAsInt, valueAsInt); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Bitwise or as an atomic operation. |
|
/// </summary> |
|
/// <param name="location">Where to atomically or the result into.</param> |
|
/// <param name="value">The value to be combined.</param> |
|
/// <returns>The original value in <paramref name="location" />.</returns> |
|
/// <remarks>Using the return value of this intrinsic may result in worse code-generation on some platforms (a compare-exchange loop), rather than a single atomic instruction being generated.</remarks> |
|
/// <seealso cref="https://docs.microsoft.com/en-us/dotnet/api/system.threading.interlocked.or"/> |
|
public static int InterlockedOr(ref int location, int value) |
|
{ |
|
// Provide a software fallback for the cases Burst isn't being used. |
|
|
|
var currentValue = System.Threading.Interlocked.Add(ref location, 0); |
|
|
|
while (true) |
|
{ |
|
var updatedValue = currentValue | value; |
|
|
|
// If nothing would change by or'ing in our thing, bail out early. |
|
if (updatedValue == currentValue) |
|
{ |
|
return currentValue; |
|
} |
|
|
|
var newValue = System.Threading.Interlocked.CompareExchange(ref location, updatedValue, currentValue); |
|
|
|
// If the original value was the same as the what we just got back from the compare exchange, it means our update succeeded. |
|
if (newValue == currentValue) |
|
{ |
|
return currentValue; |
|
} |
|
|
|
// Lastly update the last known good value of location and try again! |
|
currentValue = newValue; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Bitwise or as an atomic operation. |
|
/// </summary> |
|
/// <param name="location">Where to atomically or the result into.</param> |
|
/// <param name="value">The value to be combined.</param> |
|
/// <returns>The original value in <paramref name="location" />.</returns> |
|
/// <remarks>Using the return value of this intrinsic may result in worse code-generation on some platforms (a compare-exchange loop), rather than a single atomic instruction being generated.</remarks> |
|
/// <seealso cref="https://docs.microsoft.com/en-us/dotnet/api/system.threading.interlocked.or"/> |
|
public static uint InterlockedOr(ref uint location, uint value) |
|
{ |
|
unsafe |
|
{ |
|
ref int locationAsInt = ref Unsafe.AsRef<int>(Unsafe.AsPointer(ref location)); |
|
int valueAsInt = (int)value; |
|
|
|
return (uint)InterlockedOr(ref locationAsInt, valueAsInt); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Bitwise or as an atomic operation. |
|
/// </summary> |
|
/// <param name="location">Where to atomically or the result into.</param> |
|
/// <param name="value">The value to be combined.</param> |
|
/// <returns>The original value in <paramref name="location" />.</returns> |
|
/// <remarks>Using the return value of this intrinsic may result in worse code-generation on some platforms (a compare-exchange loop), rather than a single atomic instruction being generated.</remarks> |
|
/// <seealso cref="https://docs.microsoft.com/en-us/dotnet/api/system.threading.interlocked.or"/> |
|
public static long InterlockedOr(ref long location, long value) |
|
{ |
|
// Provide a software fallback for the cases Burst isn't being used. |
|
|
|
var currentValue = System.Threading.Interlocked.Read(ref location); |
|
|
|
while (true) |
|
{ |
|
var updatedValue = currentValue | value; |
|
|
|
// If nothing would change by or'ing in our thing, bail out early. |
|
if (updatedValue == currentValue) |
|
{ |
|
return currentValue; |
|
} |
|
|
|
var newValue = System.Threading.Interlocked.CompareExchange(ref location, updatedValue, currentValue); |
|
|
|
// If the original value was the same as the what we just got back from the compare exchange, it means our update succeeded. |
|
if (newValue == currentValue) |
|
{ |
|
return currentValue; |
|
} |
|
|
|
// Lastly update the last known good value of location and try again! |
|
currentValue = newValue; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Bitwise or as an atomic operation. |
|
/// </summary> |
|
/// <param name="location">Where to atomically or the result into.</param> |
|
/// <param name="value">The value to be combined.</param> |
|
/// <returns>The original value in <paramref name="location" />.</returns> |
|
/// <remarks>Using the return value of this intrinsic may result in worse code-generation on some platforms (a compare-exchange loop), rather than a single atomic instruction being generated.</remarks> |
|
/// <seealso cref="https://docs.microsoft.com/en-us/dotnet/api/system.threading.interlocked.or"/> |
|
public static ulong InterlockedOr(ref ulong location, ulong value) |
|
{ |
|
unsafe |
|
{ |
|
ref long locationAsInt = ref Unsafe.AsRef<long>(Unsafe.AsPointer(ref location)); |
|
long valueAsInt = (long)value; |
|
|
|
return (ulong)InterlockedOr(ref locationAsInt, valueAsInt); |
|
} |
|
} |
|
#endif |
|
} |
|
|
|
[AttributeUsage(AttributeTargets.Method, Inherited = false)] |
|
// expose the type to btests via Unity.Burst.dll |
|
#if BURST_INTERNAL |
|
public |
|
#else |
|
internal |
|
#endif |
|
sealed class BurstTargetCpuAttribute : Attribute |
|
{ |
|
public BurstTargetCpuAttribute(BurstTargetCpu TargetCpu) |
|
{ |
|
this.TargetCpu = TargetCpu; |
|
} |
|
|
|
public readonly BurstTargetCpu TargetCpu; |
|
} |
|
}
|
|
|