using System; namespace Unity.Burst.Intrinsics { /// /// Common intrinsics that are exposed across all Burst targets. /// public static class Common { /// /// 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. /// 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, } /// /// Prefetch a pointer. /// /// The pointer to prefetch. /// Whether the pointer will be used for reading or writing. /// The cache locality of the pointer. public static unsafe void Prefetch(void* v, ReadWrite rw, Locality locality = Locality.HighTemporalLocality) { } #endif /// /// Return the low half of the multiplication of two numbers, and the high part as an out parameter. /// /// A value to multiply. /// A value to multiply. /// The high-half of the multiplication result. /// The low-half of the multiplication result. 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 /// /// Bitwise and as an atomic operation. /// /// Where to atomically and the result into. /// The value to be combined. /// The original value in . /// 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. /// 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; } } /// /// Bitwise and as an atomic operation. /// /// Where to atomically and the result into. /// The value to be combined. /// The original value in . /// 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. /// public static uint InterlockedAnd(ref uint location, uint value) { unsafe { ref int locationAsInt = ref Unsafe.AsRef(Unsafe.AsPointer(ref location)); int valueAsInt = (int)value; return (uint)InterlockedAnd(ref locationAsInt, valueAsInt); } } /// /// Bitwise and as an atomic operation. /// /// Where to atomically and the result into. /// The value to be combined. /// The original value in . /// 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. /// 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; } } /// /// Bitwise and as an atomic operation. /// /// Where to atomically and the result into. /// The value to be combined. /// The original value in . /// 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. /// public static ulong InterlockedAnd(ref ulong location, ulong value) { unsafe { ref long locationAsInt = ref Unsafe.AsRef(Unsafe.AsPointer(ref location)); long valueAsInt = (long)value; return (ulong)InterlockedAnd(ref locationAsInt, valueAsInt); } } /// /// Bitwise or as an atomic operation. /// /// Where to atomically or the result into. /// The value to be combined. /// The original value in . /// 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. /// 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; } } /// /// Bitwise or as an atomic operation. /// /// Where to atomically or the result into. /// The value to be combined. /// The original value in . /// 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. /// public static uint InterlockedOr(ref uint location, uint value) { unsafe { ref int locationAsInt = ref Unsafe.AsRef(Unsafe.AsPointer(ref location)); int valueAsInt = (int)value; return (uint)InterlockedOr(ref locationAsInt, valueAsInt); } } /// /// Bitwise or as an atomic operation. /// /// Where to atomically or the result into. /// The value to be combined. /// The original value in . /// 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. /// 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; } } /// /// Bitwise or as an atomic operation. /// /// Where to atomically or the result into. /// The value to be combined. /// The original value in . /// 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. /// public static ulong InterlockedOr(ref ulong location, ulong value) { unsafe { ref long locationAsInt = ref Unsafe.AsRef(Unsafe.AsPointer(ref location)); long valueAsInt = (long)value; return (ulong)InterlockedOr(ref locationAsInt, valueAsInt); } } #endif } [AttributeUsage(AttributeTargets.Method, Inherited = false)] [BurstRuntime.Preserve] // 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; } }