forked from BilalY/Rasagar
949 lines
28 KiB
C#
949 lines
28 KiB
C#
|
using System;
|
||
|
using System.Diagnostics;
|
||
|
using System.Runtime.CompilerServices;
|
||
|
using System.Runtime.InteropServices;
|
||
|
using Unity.Burst;
|
||
|
using Unity.Collections;
|
||
|
using Unity.Collections.LowLevel.Unsafe;
|
||
|
using Unity.Jobs;
|
||
|
using Unity.Mathematics;
|
||
|
using UnityBenchShared;
|
||
|
|
||
|
namespace Burst.Compiler.IL.Tests
|
||
|
{
|
||
|
internal class Pointers
|
||
|
{
|
||
|
[TestCompiler(1)]
|
||
|
[TestCompiler(4)]
|
||
|
[TestCompiler(5)]
|
||
|
public static int CheckAddressOf(int a)
|
||
|
{
|
||
|
var value = new MyIntValue(a);
|
||
|
ref int intValue = ref value.GetValuePtr();
|
||
|
return intValue * 10 + 1;
|
||
|
}
|
||
|
|
||
|
public struct MyIntValue
|
||
|
{
|
||
|
public MyIntValue(int value)
|
||
|
{
|
||
|
Value = value;
|
||
|
}
|
||
|
|
||
|
public int Value;
|
||
|
|
||
|
public unsafe ref int GetValuePtr()
|
||
|
{
|
||
|
fixed (void* ptr = &this)
|
||
|
{
|
||
|
return ref *(int*) ptr;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0, MyCastEnum.Value2)]
|
||
|
[TestCompiler(1, MyCastEnum.Value0)]
|
||
|
[TestCompiler(2, MyCastEnum.Value3)]
|
||
|
public static unsafe MyCastEnum PointerCastEnum(int value, MyCastEnum newValue)
|
||
|
{
|
||
|
var ptvalue = new IntPtr(&value);
|
||
|
var pEnum = (MyCastEnum*) ptvalue;
|
||
|
*pEnum = newValue;
|
||
|
return *pEnum;
|
||
|
}
|
||
|
|
||
|
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_0_OR_GREATER
|
||
|
[TestCompiler(50, 50)]
|
||
|
public static unsafe bool PointerIEquatable(IntPtr a, IntPtr b)
|
||
|
{
|
||
|
return a.Equals(b); // This
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
[TestCompiler(0, 0)]
|
||
|
[TestCompiler(0, 1)]
|
||
|
[TestCompiler(1, 0)]
|
||
|
public static unsafe bool PointerCompare(IntPtr a, IntPtr b)
|
||
|
{
|
||
|
return a == b;
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0)]
|
||
|
[TestCompiler(1)]
|
||
|
[TestCompiler(2)]
|
||
|
public static unsafe bool RawPointerCompare(IntPtr value)
|
||
|
{
|
||
|
return (void*)value == (void*)1;
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0)]
|
||
|
[TestCompiler(1)]
|
||
|
[TestCompiler(42424242)]
|
||
|
[TestCompiler(0xC0FFEE4DEADBEEF)]
|
||
|
public static unsafe int PointerHash(IntPtr value)
|
||
|
{
|
||
|
return value.GetHashCode();
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0)]
|
||
|
[TestCompiler(1)]
|
||
|
[TestCompiler(42424242)]
|
||
|
public static unsafe IntPtr PointerToPointer(IntPtr value)
|
||
|
{
|
||
|
return new IntPtr(value.ToPointer());
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0, ExpectCompilerException = true, ExpectedDiagnosticId = DiagnosticId.ERR_CallingManagedMethodNotSupported)]
|
||
|
public static unsafe int PointerToString(IntPtr value)
|
||
|
{
|
||
|
return value.ToString().Length;
|
||
|
}
|
||
|
|
||
|
[TestCompiler(1)]
|
||
|
[TestCompiler(255)]
|
||
|
[TestCompiler(12351235)]
|
||
|
public static unsafe int PointerAdd(int a)
|
||
|
{
|
||
|
var pA = (byte*)&a;
|
||
|
var pDest = pA + 3;
|
||
|
*pDest = (byte)a;
|
||
|
return a;
|
||
|
}
|
||
|
|
||
|
[TestCompiler(1)]
|
||
|
[TestCompiler(255)]
|
||
|
[TestCompiler(12351235)]
|
||
|
public static unsafe int PointerSub(int a)
|
||
|
{
|
||
|
var pA = (byte*)&a;
|
||
|
var pDest = pA + 3;
|
||
|
*(pDest - 1) = (byte)a;
|
||
|
return a;
|
||
|
}
|
||
|
|
||
|
[TestCompiler]
|
||
|
public static unsafe int PointerPointerSub()
|
||
|
{
|
||
|
var value = new StructForPointerPointerSub();
|
||
|
int* pa = &value.A;
|
||
|
int* pb = &value.B;
|
||
|
var auto = (pb - pa);
|
||
|
return (int)auto;
|
||
|
}
|
||
|
|
||
|
[TestCompiler]
|
||
|
public static unsafe int WhileWithPointer()
|
||
|
{
|
||
|
var check = new CheckPointers { X = 1, Y = 2, Z = 3, W = 4 };
|
||
|
int* pstart = &check.X;
|
||
|
int* pend = &check.W;
|
||
|
int result = 0;
|
||
|
while (pstart <= pend)
|
||
|
{
|
||
|
result += *pstart;
|
||
|
pstart++;
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
struct StructForPointerPointerSub
|
||
|
{
|
||
|
public int A;
|
||
|
public int B;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
[TestCompiler(1)]
|
||
|
[TestCompiler(255)]
|
||
|
[TestCompiler(12351235)]
|
||
|
public static IntPtr IntPtrConstructor(int a)
|
||
|
{
|
||
|
return new IntPtr(a);
|
||
|
}
|
||
|
|
||
|
[TestCompiler(1U)]
|
||
|
[TestCompiler(255U)]
|
||
|
[TestCompiler(12351235U)]
|
||
|
public static UIntPtr UIntPtrConstructor(uint a)
|
||
|
{
|
||
|
return new UIntPtr(a);
|
||
|
}
|
||
|
|
||
|
[TestCompiler(1)]
|
||
|
[TestCompiler(255)]
|
||
|
[TestCompiler(12351235)]
|
||
|
public static int IntPtrToInt32(int a)
|
||
|
{
|
||
|
return new IntPtr(a).ToInt32();
|
||
|
}
|
||
|
|
||
|
[TestCompiler(1)]
|
||
|
[TestCompiler(255)]
|
||
|
[TestCompiler(12351235)]
|
||
|
public static long IntPtrToInt64(int a)
|
||
|
{
|
||
|
return new IntPtr(a).ToInt64();
|
||
|
}
|
||
|
|
||
|
[TestCompiler(OverrideOn32BitNative = 4)]
|
||
|
public static int IntPtrSize()
|
||
|
{
|
||
|
return IntPtr.Size;
|
||
|
}
|
||
|
|
||
|
// asserted in IntPtrProcessor
|
||
|
[TestCompiler(OverrideOn32BitNative = true)]
|
||
|
public static bool IntPtrSizeCompared()
|
||
|
{
|
||
|
return IntPtr.Size == 4;
|
||
|
}
|
||
|
|
||
|
[TestCompiler]
|
||
|
public static IntPtr IntPtrZero()
|
||
|
{
|
||
|
return IntPtr.Zero;
|
||
|
}
|
||
|
|
||
|
[TestCompiler(1)]
|
||
|
[TestCompiler(5)]
|
||
|
public static IntPtr IntPtrAdd(IntPtr a)
|
||
|
{
|
||
|
return IntPtr.Add(a, 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
[TestCompiler(1)]
|
||
|
[TestCompiler(5)]
|
||
|
public static IntPtr IntPtrAdd2(IntPtr a)
|
||
|
{
|
||
|
return a + 1;
|
||
|
}
|
||
|
|
||
|
[TestCompiler(1)]
|
||
|
[TestCompiler(5)]
|
||
|
public static IntPtr IntPtrSub(IntPtr a)
|
||
|
{
|
||
|
return IntPtr.Subtract(a, 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
[TestCompiler(1)]
|
||
|
[TestCompiler(5)]
|
||
|
public static IntPtr IntPtrSub2(IntPtr a)
|
||
|
{
|
||
|
return a - 1;
|
||
|
}
|
||
|
|
||
|
[TestCompiler]
|
||
|
public static UIntPtr UIntPtrZero()
|
||
|
{
|
||
|
return UIntPtr.Zero;
|
||
|
}
|
||
|
|
||
|
[TestCompiler(1U)]
|
||
|
[TestCompiler(5U)]
|
||
|
public static UIntPtr UIntPtrAdd(UIntPtr a)
|
||
|
{
|
||
|
return UIntPtr.Add(a, 1);
|
||
|
}
|
||
|
|
||
|
[TestCompiler(1U)]
|
||
|
[TestCompiler(5U)]
|
||
|
public static UIntPtr UIntPtrSubstract(UIntPtr a)
|
||
|
{
|
||
|
return UIntPtr.Subtract(a, 1);
|
||
|
}
|
||
|
|
||
|
[TestCompiler(1)]
|
||
|
public static unsafe int PointerAccess(int a)
|
||
|
{
|
||
|
var value = a;
|
||
|
var pValue = &value;
|
||
|
pValue[0] = a + 5;
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0)] // Keep it at 0 only!
|
||
|
public static unsafe int PointerAccess2(int a)
|
||
|
{
|
||
|
int value = 15;
|
||
|
var pValue = &value;
|
||
|
pValue[a] = value + 5;
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0)] // Keep it at 0 only!
|
||
|
public static unsafe float PointerAccess3(int a)
|
||
|
{
|
||
|
float value = 15.0f;
|
||
|
var pValue = &value;
|
||
|
pValue[a] = value + 5.0f;
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0)]
|
||
|
public static unsafe int PointerCompareViaInt(int a)
|
||
|
{
|
||
|
int b;
|
||
|
if (&a == &b)
|
||
|
return 1;
|
||
|
else
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0)]
|
||
|
public static unsafe int IntPtrCompare(int a)
|
||
|
{
|
||
|
int b;
|
||
|
IntPtr aPtr = (IntPtr)(&a);
|
||
|
IntPtr bPtr = (IntPtr)(&b);
|
||
|
if (aPtr == bPtr)
|
||
|
return 1;
|
||
|
else
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
[TestCompiler(typeof(IntPtrZeroProvider), 1)]
|
||
|
[TestCompiler(typeof(IntPtrOneProvider), 2)]
|
||
|
public static unsafe int UnsafeCompare(int* a, int b)
|
||
|
{
|
||
|
if (a == null)
|
||
|
{
|
||
|
return 1 + b;
|
||
|
}
|
||
|
|
||
|
return 2 + b;
|
||
|
}
|
||
|
|
||
|
unsafe struct NativeQueueBlockHeader
|
||
|
{
|
||
|
#pragma warning disable 0649
|
||
|
public byte* nextBlock;
|
||
|
public int itemsInBlock;
|
||
|
#pragma warning restore 0649
|
||
|
}
|
||
|
|
||
|
[TestCompiler]
|
||
|
public static unsafe void PointerCastWithStruct()
|
||
|
{
|
||
|
|
||
|
byte* currentWriteBlock = null;
|
||
|
if (currentWriteBlock != null && ((NativeQueueBlockHeader*) currentWriteBlock)->itemsInBlock == 100)
|
||
|
{
|
||
|
((NativeQueueBlockHeader*) currentWriteBlock)->itemsInBlock = 5;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private class IntPtrZeroProvider : IArgumentProvider
|
||
|
{
|
||
|
public object Value => IntPtr.Zero;
|
||
|
}
|
||
|
|
||
|
private class IntPtrOneProvider : IArgumentProvider
|
||
|
{
|
||
|
public object Value => new IntPtr(1);
|
||
|
}
|
||
|
|
||
|
[TestCompiler]
|
||
|
public static unsafe int FixedField()
|
||
|
{
|
||
|
var fixedStruct = new MyStructWithFixed();
|
||
|
fixedStruct.Values[0] = 1;
|
||
|
fixedStruct.Values[1] = 2;
|
||
|
fixedStruct.Values[2] = 3;
|
||
|
fixedStruct.Values[9] = 9;
|
||
|
|
||
|
int result = 0;
|
||
|
for (int i = 0; i < 10; i++)
|
||
|
{
|
||
|
result += fixedStruct.Values[i];
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
[TestCompiler(typeof(MyStructWithFixedProvider), 1)]
|
||
|
//[TestCompiler(typeof(MyStructWithFixedProvider), 2)]
|
||
|
public static unsafe int FixedFieldViaPointer(ref MyStructWithFixed fixedStruct, int i)
|
||
|
{
|
||
|
fixed (MyStructWithFixed* check = &fixedStruct)
|
||
|
{
|
||
|
int* data = check->Values;
|
||
|
return data[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[TestCompiler(typeof(MyStructWithFixedProvider))]
|
||
|
public static unsafe int FixedInt32AndRefInt32(ref MyStructWithFixed fixedStruct)
|
||
|
{
|
||
|
fixed (int* data = &fixedStruct.Value)
|
||
|
{
|
||
|
// We do a call to ProcessInt after with a ref int
|
||
|
// to check that we don't collide with the PinnedType introduced by the previous
|
||
|
// fixed statement
|
||
|
ProcessInt(ref *data);
|
||
|
}
|
||
|
|
||
|
return fixedStruct.Value;
|
||
|
}
|
||
|
|
||
|
private static void ProcessInt(ref int value)
|
||
|
{
|
||
|
value += 5;
|
||
|
}
|
||
|
|
||
|
public unsafe struct ConditionalTestStruct
|
||
|
{
|
||
|
public void* a;
|
||
|
public void* b;
|
||
|
}
|
||
|
|
||
|
public unsafe struct PointerConditional : IJob, IDisposable
|
||
|
{
|
||
|
public ConditionalTestStruct* t;
|
||
|
|
||
|
public void Execute()
|
||
|
{
|
||
|
t->b = t->a != null ? t->a : null;
|
||
|
}
|
||
|
|
||
|
|
||
|
public struct Provider : IArgumentProvider
|
||
|
{
|
||
|
public object Value
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
var value = new PointerConditional();
|
||
|
value.t = (ConditionalTestStruct*)UnsafeUtility.Malloc(UnsafeUtility.SizeOf<ConditionalTestStruct>(), 4, Allocator.Persistent);
|
||
|
value.t->a = (void*)0x12345678;
|
||
|
value.t->b = null;
|
||
|
return value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void Dispose()
|
||
|
{
|
||
|
UnsafeUtility.Free(t, Allocator.Persistent);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[TestCompiler(typeof(PointerConditional.Provider))]
|
||
|
public static unsafe bool TestConditionalPointer([NoAlias] ref PointerConditional job)
|
||
|
{
|
||
|
job.Execute();
|
||
|
return job.t->a == job.t->b;
|
||
|
}
|
||
|
|
||
|
#if BURST_TESTS_ONLY
|
||
|
// Disabled on .Net 7 due to Unsafe.ByteOffset
|
||
|
[TestCompiler(IgnoreOnNetCore = true)]
|
||
|
public static int TestFieldOffset()
|
||
|
{
|
||
|
var t = default(StructWithFields);
|
||
|
return (int)Unsafe.ByteOffset(ref Unsafe.As<int, bool>(ref t.a), ref t.d);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
public struct StructWithFields
|
||
|
{
|
||
|
public int a;
|
||
|
public int b;
|
||
|
public bool c;
|
||
|
public bool d;
|
||
|
public bool e;
|
||
|
public bool f;
|
||
|
}
|
||
|
|
||
|
public unsafe struct MyStructWithFixed
|
||
|
{
|
||
|
public fixed int Values[10];
|
||
|
public int Value;
|
||
|
}
|
||
|
|
||
|
private struct MyStructWithFixedProvider : IArgumentProvider
|
||
|
{
|
||
|
public unsafe object Value
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
var field = new MyStructWithFixed();
|
||
|
for (int i = 0; i < 10; i++)
|
||
|
{
|
||
|
field.Values[i] = (i + 1) * 5;
|
||
|
}
|
||
|
|
||
|
field.Value = 1235;
|
||
|
|
||
|
return field;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0)]
|
||
|
public static unsafe void TestCellVisibleInternal(int length)
|
||
|
{
|
||
|
int3* cellVisibleRequest = (int3*)0;
|
||
|
bool*cellVisibleResult = (bool*)0;
|
||
|
int3* visibleCells = (int3*)0;
|
||
|
IsCellVisibleInternal(cellVisibleRequest, cellVisibleResult, visibleCells, length, length);
|
||
|
}
|
||
|
|
||
|
static unsafe void IsCellVisibleInternal(int3* cellVisibleRequest, bool* cellVisibleResult, int3* visibleCells, int requestLength, int visibleCellsLength)
|
||
|
{
|
||
|
for (int r = 0; r < requestLength; r++)
|
||
|
{
|
||
|
cellVisibleResult[r] = false;
|
||
|
for (int i = 0; i < visibleCellsLength; i++)
|
||
|
{
|
||
|
if (visibleCells[i].x == cellVisibleRequest[r].x && visibleCells[i].y == cellVisibleRequest[r].y && visibleCells[i].z == cellVisibleRequest[r].z)
|
||
|
{
|
||
|
cellVisibleResult[r] = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public enum MyCastEnum
|
||
|
{
|
||
|
Value0 = 0,
|
||
|
Value1 = 1,
|
||
|
Value2 = 2,
|
||
|
Value3 = 3,
|
||
|
}
|
||
|
|
||
|
public struct CheckPointers
|
||
|
{
|
||
|
public int X;
|
||
|
public int Y;
|
||
|
public int Z;
|
||
|
public int W;
|
||
|
}
|
||
|
|
||
|
// From https://github.com/Unity-Technologies/ECSJobDemos/issues/244
|
||
|
[TestCompiler]
|
||
|
public static unsafe int InitialiseViaCastedPointer()
|
||
|
{
|
||
|
int value = 0;
|
||
|
|
||
|
void* ptr = &value;
|
||
|
|
||
|
byte* asBytePtr = (byte*)ptr;
|
||
|
|
||
|
((int*)asBytePtr)[0] = -1;
|
||
|
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
[TestCompiler(1)]
|
||
|
public static unsafe int PointerWriteArg(int a)
|
||
|
{
|
||
|
return (int)TestPointerAndGeneric<float>((int*) a);
|
||
|
}
|
||
|
|
||
|
private static unsafe int* TestPointerAndGeneric<T>(int* p) where T : struct
|
||
|
{
|
||
|
p = (int*)(IntPtr)26;
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
|
||
|
[TestCompiler(ExpectedDiagnosticId = DiagnosticId.WRN_ExceptionThrownInNonSafetyCheckGuardedFunction)]
|
||
|
public static void TestBlobAssetReferenceData()
|
||
|
{
|
||
|
var blob = new BlobAssetReferenceData(IntPtr.Zero);
|
||
|
blob.Validate();
|
||
|
}
|
||
|
|
||
|
|
||
|
[StructLayout(LayoutKind.Explicit, Size = 16)]
|
||
|
internal unsafe struct BlobAssetHeader
|
||
|
{
|
||
|
[FieldOffset(0)] public void* ValidationPtr;
|
||
|
[FieldOffset(8)] public int Length;
|
||
|
[FieldOffset(12)] public Allocator Allocator;
|
||
|
}
|
||
|
|
||
|
internal unsafe struct BlobAssetReferenceData
|
||
|
{
|
||
|
[NativeDisableUnsafePtrRestriction]
|
||
|
public byte* _ptr;
|
||
|
|
||
|
public BlobAssetReferenceData(IntPtr zero)
|
||
|
{
|
||
|
_ptr = (byte*)zero;
|
||
|
}
|
||
|
|
||
|
internal BlobAssetHeader* Header => ((BlobAssetHeader*)_ptr) - 1;
|
||
|
|
||
|
public void Validate()
|
||
|
{
|
||
|
if (_ptr != null)
|
||
|
if (Header->ValidationPtr != _ptr)
|
||
|
throw new InvalidOperationException("The BlobAssetReference is not valid. Likely it has already been unloaded or released");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal unsafe struct StackAllocCheck
|
||
|
{
|
||
|
public int* ptr;
|
||
|
|
||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||
|
public void AddToPtr(int* otherPtr)
|
||
|
{
|
||
|
*otherPtr = 42;
|
||
|
*ptr += 1;
|
||
|
*ptr += *otherPtr;
|
||
|
}
|
||
|
|
||
|
public class Provider : IArgumentProvider
|
||
|
{
|
||
|
public object Value => new StackAllocCheck();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[TestCompiler(typeof(StackAllocCheck.Provider))]
|
||
|
public static unsafe bool StackAllocAliasCheck([NoAlias] ref StackAllocCheck stackAllocCheck)
|
||
|
{
|
||
|
int* ptr = stackalloc int[1];
|
||
|
*ptr = 13;
|
||
|
|
||
|
stackAllocCheck.ptr = ptr;
|
||
|
|
||
|
stackAllocCheck.AddToPtr(ptr);
|
||
|
|
||
|
if (*ptr != 86)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
*stackAllocCheck.ptr = -4;
|
||
|
*ptr += 1;
|
||
|
*ptr += *stackAllocCheck.ptr;
|
||
|
|
||
|
if (*ptr != -6)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
[TestCompiler(1)]
|
||
|
public static unsafe int NativeIntAddCheck(int a)
|
||
|
{
|
||
|
return (int)(&a + 1) - (int)&a;
|
||
|
}
|
||
|
|
||
|
public unsafe struct PointerArithmetic : IJob, IDisposable
|
||
|
{
|
||
|
[NativeDisableUnsafePtrRestriction] public int** pointers;
|
||
|
|
||
|
public void Execute()
|
||
|
{
|
||
|
pointers[10] = pointers[10] + +1;
|
||
|
pointers[20] = pointers[20] - +1;
|
||
|
pointers[30] = pointers[30] - -1;
|
||
|
pointers[40] = pointers[40] + -1;
|
||
|
}
|
||
|
|
||
|
public struct Provider : IArgumentProvider
|
||
|
{
|
||
|
public object Value
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
var value = new PointerArithmetic();
|
||
|
value.pointers = (int**)UnsafeUtility.Malloc(1000*sizeof(int*), 8, Allocator.Persistent);
|
||
|
UnsafeUtility.MemClear(value.pointers, 1000 * sizeof(int*));
|
||
|
return value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void Dispose()
|
||
|
{
|
||
|
UnsafeUtility.Free(pointers, Allocator.Persistent);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// The arithmetic test has been split to make it easier to see the mismatched value (rather than true!=false)
|
||
|
// According to : https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/unsafe-code#pointer-types
|
||
|
// Conversion between pointers and integrals is "Implementation Defined".
|
||
|
|
||
|
|
||
|
[TestCompiler(typeof(PointerArithmetic.Provider))]
|
||
|
public static unsafe Int64 TestArithmeticPointerA(ref PointerArithmetic job)
|
||
|
{
|
||
|
job.Execute();
|
||
|
if (sizeof(int*) == 4)
|
||
|
return (Int64)(UInt32)(job.pointers[10]); // Workaround IL2CPP 32bit Bug : https://fogbugz.unity3d.com/f/cases/1254635/
|
||
|
return (Int64)job.pointers[10];
|
||
|
}
|
||
|
|
||
|
[TestCompiler(typeof(PointerArithmetic.Provider))]
|
||
|
public static unsafe Int64 TestArithmeticPointerB(ref PointerArithmetic job)
|
||
|
{
|
||
|
job.Execute();
|
||
|
if (sizeof(int*) == 4)
|
||
|
return (Int64)(UInt32)(job.pointers[20]); // Workaround IL2CPP 32bit Bug : https://fogbugz.unity3d.com/f/cases/1254635/
|
||
|
return (Int64)job.pointers[20];
|
||
|
}
|
||
|
|
||
|
[TestCompiler(typeof(PointerArithmetic.Provider))]
|
||
|
public static unsafe Int64 TestArithmeticPointerC(ref PointerArithmetic job)
|
||
|
{
|
||
|
job.Execute();
|
||
|
if (sizeof(int*) == 4)
|
||
|
return (Int64)(UInt32)(job.pointers[30]); // Workaround IL2CPP 32bit Bug : https://fogbugz.unity3d.com/f/cases/1254635/
|
||
|
return (Int64)job.pointers[30];
|
||
|
}
|
||
|
|
||
|
[TestCompiler(typeof(PointerArithmetic.Provider))]
|
||
|
public static unsafe Int64 TestArithmeticPointerD(ref PointerArithmetic job)
|
||
|
{
|
||
|
job.Execute();
|
||
|
if (sizeof(int*) == 4)
|
||
|
return (Int64)(UInt32)(job.pointers[40]); // Workaround IL2CPP 32bit Bug : https://fogbugz.unity3d.com/f/cases/1254635/
|
||
|
return (Int64)job.pointers[40];
|
||
|
}
|
||
|
|
||
|
private struct TestData
|
||
|
{
|
||
|
public int3 Min;
|
||
|
public int Size;
|
||
|
}
|
||
|
|
||
|
[TestCompiler]
|
||
|
public static unsafe int TestPointerWithIn()
|
||
|
{
|
||
|
var foo = stackalloc TestData[1];
|
||
|
|
||
|
*foo = new TestData { Min = new int3(0, 1, 2), Size = 3 };
|
||
|
|
||
|
return SubFunctionWithInPointer(in foo);
|
||
|
}
|
||
|
|
||
|
private static unsafe int SubFunctionWithInPointer(in TestData* node)
|
||
|
{
|
||
|
int3 data = node->Min;
|
||
|
|
||
|
return node->Size + data.x + data.y + data.z;
|
||
|
}
|
||
|
|
||
|
/* System.Buffer::Memmove - Disabled on .Net 7 due to :
|
||
|
|
||
|
Framework
|
||
|
IL_000e: conv.ovf.u8 args(IL_000d(ldarg.3))
|
||
|
IL_000f: call System.Void System.Buffer::Memmove(System.Byte*,System.Byte*,System.UInt64) args(IL_000b(ldarg.1), IL_000c(ldarg.0), IL_000e(conv.ovf.u8))
|
||
|
|
||
|
.Net 7 (note reference no pointer...)
|
||
|
IL_000e: conv.ovf.u args(IL_000d(ldarg.3))
|
||
|
IL_000f: call System.Void System.Buffer::Memmove(System.Byte&,System.Byte&,System.UIntPtr) args(IL_000b(ldarg.1), IL_000c(ldarg.0), IL_000e(conv.ovf.u))
|
||
|
*/
|
||
|
[TestCompiler(IgnoreOnNetCore = true)]
|
||
|
public static unsafe int TestSystemBufferMemoryCopy()
|
||
|
{
|
||
|
var a = stackalloc int[2];
|
||
|
a[0] = 42;
|
||
|
System.Buffer.MemoryCopy(a + 0, a + 1, UnsafeUtility.SizeOf<int>(), UnsafeUtility.SizeOf<int>());
|
||
|
return a[1];
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, byte.MinValue)]
|
||
|
[TestCompiler(0ul, byte.MaxValue)]
|
||
|
public static unsafe IntPtr PointerMathAddPNTypesByte(UInt64 p,byte a)
|
||
|
{
|
||
|
var pointer = (byte*)p;
|
||
|
return new IntPtr(pointer + a); // Pointer LHS
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, byte.MinValue)]
|
||
|
[TestCompiler(0ul, byte.MaxValue)]
|
||
|
public static unsafe IntPtr PointerMathAddNPTypesByte(UInt64 p,byte a)
|
||
|
{
|
||
|
var pointer = (byte*)p;
|
||
|
return new IntPtr(a + pointer); // Pointer RHS
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, byte.MinValue)]
|
||
|
[TestCompiler(0ul, byte.MaxValue)]
|
||
|
public static unsafe IntPtr PointerMathSubPNTypesByte(UInt64 p,byte a)
|
||
|
{
|
||
|
var pointer = (byte*)p;
|
||
|
return new IntPtr(pointer - a); // Pointer LHS (no RHS since not legal in C#)
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, sbyte.MinValue)]
|
||
|
[TestCompiler(0ul, sbyte.MaxValue)]
|
||
|
public static unsafe IntPtr PointerMathAddPNTypesSByte(UInt64 p,sbyte a)
|
||
|
{
|
||
|
var pointer = (sbyte*)p;
|
||
|
return new IntPtr(pointer + a); // Pointer LHS
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, sbyte.MinValue)]
|
||
|
[TestCompiler(0ul, sbyte.MaxValue)]
|
||
|
public static unsafe IntPtr PointerMathAddNPTypesSByte(UInt64 p,sbyte a)
|
||
|
{
|
||
|
var pointer = (sbyte*)p;
|
||
|
return new IntPtr(a + pointer); // Pointer RHS
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, sbyte.MinValue)]
|
||
|
[TestCompiler(0ul, sbyte.MaxValue)]
|
||
|
public static unsafe IntPtr PointerMathSubPNTypesSByte(UInt64 p,sbyte a)
|
||
|
{
|
||
|
var pointer = (sbyte*)p;
|
||
|
return new IntPtr(pointer - a); // Pointer LHS (no RHS since not legal in C#)
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, short.MinValue)]
|
||
|
[TestCompiler(0ul, short.MaxValue)]
|
||
|
public static unsafe IntPtr PointerMathAddPNTypesShort(UInt64 p,short a)
|
||
|
{
|
||
|
var pointer = (short*)p;
|
||
|
return new IntPtr(pointer + a); // Pointer LHS
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, short.MinValue)]
|
||
|
[TestCompiler(0ul, short.MaxValue)]
|
||
|
public static unsafe IntPtr PointerMathAddNPTypesShort(UInt64 p,short a)
|
||
|
{
|
||
|
var pointer = (short*)p;
|
||
|
return new IntPtr(a + pointer); // Pointer RHS
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, short.MinValue)]
|
||
|
[TestCompiler(0ul, short.MaxValue)]
|
||
|
public static unsafe IntPtr PointerMathSubPNTypesShort(UInt64 p,short a)
|
||
|
{
|
||
|
var pointer = (short*)p;
|
||
|
return new IntPtr(pointer - a); // Pointer LHS (no RHS since not legal in C#)
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, ushort.MinValue)]
|
||
|
[TestCompiler(0ul, ushort.MaxValue)]
|
||
|
public static unsafe IntPtr PointerMathAddPNTypesUShort(UInt64 p,ushort a)
|
||
|
{
|
||
|
var pointer = (ushort*)p;
|
||
|
return new IntPtr(pointer + a); // Pointer LHS
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, ushort.MinValue)]
|
||
|
[TestCompiler(0ul, ushort.MaxValue)]
|
||
|
public static unsafe IntPtr PointerMathAddNPTypesUShort(UInt64 p,ushort a)
|
||
|
{
|
||
|
var pointer = (ushort*)p;
|
||
|
return new IntPtr(a + pointer); // Pointer RHS
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, ushort.MinValue)]
|
||
|
[TestCompiler(0ul, ushort.MaxValue)]
|
||
|
public static unsafe IntPtr PointerMathSubPNTypesUShort(UInt64 p,ushort a)
|
||
|
{
|
||
|
var pointer = (ushort*)p;
|
||
|
return new IntPtr(pointer - a); // Pointer LHS (no RHS since not legal in C#)
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, int.MinValue)]
|
||
|
[TestCompiler(0ul, int.MaxValue)]
|
||
|
public static unsafe IntPtr PointerMathAddPNTypesInt(UInt64 p,int a)
|
||
|
{
|
||
|
var pointer = (int*)p;
|
||
|
return new IntPtr(pointer + a); // Pointer LHS
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, int.MinValue)]
|
||
|
[TestCompiler(0ul, int.MaxValue)]
|
||
|
public static unsafe IntPtr PointerMathAddNPTypesInt(UInt64 p,int a)
|
||
|
{
|
||
|
var pointer = (int*)p;
|
||
|
return new IntPtr(a + pointer); // Pointer RHS
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, int.MinValue)]
|
||
|
[TestCompiler(0ul, int.MaxValue)]
|
||
|
public static unsafe IntPtr PointerMathSubPNTypesInt(UInt64 p,int a)
|
||
|
{
|
||
|
var pointer = (int*)p;
|
||
|
return new IntPtr(pointer - a); // Pointer LHS (no RHS since not legal in C#)
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, uint.MinValue)]
|
||
|
[TestCompiler(0ul, uint.MaxValue)]
|
||
|
public static unsafe IntPtr PointerMathAddPNTypesUInt(UInt64 p,uint a)
|
||
|
{
|
||
|
var pointer = (uint*)p;
|
||
|
return new IntPtr(pointer + a); // Pointer LHS
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, uint.MinValue)]
|
||
|
[TestCompiler(0ul, uint.MaxValue)]
|
||
|
public static unsafe IntPtr PointerMathAddNPTypesUInt(UInt64 p,uint a)
|
||
|
{
|
||
|
var pointer = (uint*)p;
|
||
|
return new IntPtr(a + pointer); // Pointer RHS
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, uint.MinValue)]
|
||
|
[TestCompiler(0ul, uint.MaxValue)]
|
||
|
public static unsafe IntPtr PointerMathSubPNTypesUInt(UInt64 p,uint a)
|
||
|
{
|
||
|
var pointer = (uint*)p;
|
||
|
return new IntPtr(pointer - a); // Pointer LHS (no RHS since not legal in C#)
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, long.MinValue)]
|
||
|
[TestCompiler(0ul, long.MaxValue)]
|
||
|
public static unsafe IntPtr PolongerMathAddPNTypesLong(UInt64 p,long a)
|
||
|
{
|
||
|
var polonger = (long*)p;
|
||
|
return new IntPtr(polonger + a); // Polonger LHS
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, long.MinValue)]
|
||
|
[TestCompiler(0ul, long.MaxValue)]
|
||
|
public static unsafe IntPtr PolongerMathAddNPTypesLong(UInt64 p,long a)
|
||
|
{
|
||
|
var polonger = (long*)p;
|
||
|
return new IntPtr(a + polonger); // Polonger RHS
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, long.MinValue)]
|
||
|
[TestCompiler(0ul, long.MaxValue)]
|
||
|
public static unsafe IntPtr PolongerMathSubPNTypesLong(UInt64 p,long a)
|
||
|
{
|
||
|
var polonger = (long*)p;
|
||
|
return new IntPtr(polonger - a); // Polonger LHS (no RHS since not legal in C#)
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, ulong.MinValue)]
|
||
|
[TestCompiler(0ul, ulong.MaxValue)]
|
||
|
public static unsafe IntPtr PolongerMathAddPNTypesULong(UInt64 p,ulong a)
|
||
|
{
|
||
|
var polonger = (ulong*)p;
|
||
|
return new IntPtr(polonger + a); // Polonger LHS
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, ulong.MinValue)]
|
||
|
[TestCompiler(0ul, ulong.MaxValue)]
|
||
|
public static unsafe IntPtr PolongerMathAddNPTypesULong(UInt64 p,ulong a)
|
||
|
{
|
||
|
var polonger = (ulong*)p;
|
||
|
return new IntPtr(a + polonger); // Polonger RHS
|
||
|
}
|
||
|
|
||
|
[TestCompiler(0ul, ulong.MinValue)]
|
||
|
[TestCompiler(0ul, ulong.MaxValue)]
|
||
|
public static unsafe IntPtr PolongerMathSubPNTypesULong(UInt64 p,ulong a)
|
||
|
{
|
||
|
var polonger = (ulong*)p;
|
||
|
return new IntPtr(polonger - a); // Polonger LHS (no RHS since not legal in C#)
|
||
|
}
|
||
|
}
|
||
|
}
|