Singularity/Library/PackageCache/com.unity.burst@1.8.4/Tests/Runtime/Shared/031-Pointers.cs
2024-05-06 11:45:45 -07:00

929 lines
27 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;
}
[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)]
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_MethodNotSupported)]
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
[TestCompiler]
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;
}
[TestCompiler]
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#)
}
}
}