mirror of
https://github.com/Smaug123/WoofWare.PawPrint
synced 2025-10-08 23:48:39 +00:00
365 lines
7.5 KiB
C#
365 lines
7.5 KiB
C#
using System;
|
|
|
|
unsafe class LdindTest
|
|
{
|
|
static int Main(string[] args)
|
|
{
|
|
var failures = 0;
|
|
// Test Ldind.i1 (signed byte)
|
|
failures += TestLdindI1();
|
|
|
|
// Test Ldind.u1 (unsigned byte)
|
|
failures += TestLdindU1();
|
|
|
|
// Test Ldind.i2 (signed short)
|
|
failures += TestLdindI2();
|
|
|
|
// Test Ldind.u2 (unsigned short)
|
|
failures += TestLdindU2();
|
|
|
|
// Test Ldind.i4 (signed int)
|
|
failures += TestLdindI4();
|
|
|
|
// Test Ldind.u4 (unsigned int)
|
|
failures += TestLdindU4();
|
|
|
|
// Test Ldind.i8 (signed long)
|
|
failures += TestLdindI8();
|
|
|
|
// Test Ldind.i8 via u8 (there's no Ldind.u8)
|
|
failures += TestLdindI8ViaU8();
|
|
|
|
// Test Ldind.r4 (float)
|
|
failures += TestLdindR4();
|
|
|
|
// Test Ldind.r8 (double)
|
|
failures += TestLdindR8();
|
|
|
|
// Test truncation behavior
|
|
failures += TestTruncation();
|
|
|
|
// Test with managed pointers (ref)
|
|
failures += TestManagedPointers();
|
|
|
|
// Test Ldind.i (native int)
|
|
failures += TestLdindI();
|
|
|
|
return failures;
|
|
}
|
|
|
|
static int TestLdindI1()
|
|
{
|
|
sbyte value = -128;
|
|
sbyte* ptr = &value;
|
|
sbyte loaded = *ptr; // This generates ldind.i1
|
|
if (value != loaded)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
value = 127;
|
|
loaded = *ptr;
|
|
if (value != loaded)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int TestLdindU1()
|
|
{
|
|
byte value = 255;
|
|
byte* ptr = &value;
|
|
byte loaded = *ptr; // This generates ldind.u1
|
|
if (value != loaded)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
value = 0;
|
|
loaded = *ptr;
|
|
if (value != loaded)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int TestLdindI2()
|
|
{
|
|
short value = -32768;
|
|
short* ptr = &value;
|
|
short loaded = *ptr; // This generates ldind.i2
|
|
if (value != loaded)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
value = 32767;
|
|
loaded = *ptr;
|
|
if (value != loaded)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int TestLdindU2()
|
|
{
|
|
ushort value = 65535;
|
|
ushort* ptr = &value;
|
|
ushort loaded = *ptr; // This generates ldind.u2
|
|
if (value != loaded)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
value = 0;
|
|
loaded = *ptr;
|
|
if (value != loaded)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int TestLdindI4()
|
|
{
|
|
int value = int.MinValue;
|
|
int* ptr = &value;
|
|
int loaded = *ptr; // This generates ldind.i4
|
|
if (value != loaded)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
value = int.MaxValue;
|
|
loaded = *ptr;
|
|
if (value != loaded)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int TestLdindU4()
|
|
{
|
|
uint value = uint.MaxValue;
|
|
uint* ptr = &value;
|
|
uint loaded = *ptr; // This generates ldind.u4
|
|
if (value != loaded)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
value = 0;
|
|
loaded = *ptr;
|
|
if (value != loaded)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int TestLdindI8()
|
|
{
|
|
long value = long.MinValue;
|
|
long* ptr = &value;
|
|
long loaded = *ptr; // This generates ldind.i8
|
|
if (value != loaded)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
value = long.MaxValue;
|
|
loaded = *ptr;
|
|
if (value != loaded)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int TestLdindI8ViaU8()
|
|
{
|
|
ulong value = ulong.MaxValue;
|
|
ulong* ptr = &value;
|
|
ulong loaded = *ptr; // This generates ldind.i8 again, because there's no ldind.u8
|
|
if (value != loaded)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
value = 0;
|
|
loaded = *ptr;
|
|
if (value != loaded)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int TestLdindR4()
|
|
{
|
|
float value = float.MinValue;
|
|
float* ptr = &value;
|
|
float loaded = *ptr; // This generates ldind.r4
|
|
if (BitConverter.SingleToInt32Bits(value) != BitConverter.SingleToInt32Bits(loaded))
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
value = float.MaxValue;
|
|
loaded = *ptr;
|
|
if (BitConverter.SingleToInt32Bits(value) != BitConverter.SingleToInt32Bits(loaded))
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
value = float.NaN;
|
|
loaded = *ptr;
|
|
if (BitConverter.SingleToInt32Bits(value) != BitConverter.SingleToInt32Bits(loaded))
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int TestLdindR8()
|
|
{
|
|
double value = double.MinValue;
|
|
double* ptr = &value;
|
|
double loaded = *ptr; // This generates ldind.r8
|
|
if (BitConverter.DoubleToInt64Bits(value) != BitConverter.DoubleToInt64Bits(loaded))
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
value = double.MaxValue;
|
|
loaded = *ptr;
|
|
if (BitConverter.DoubleToInt64Bits(value) != BitConverter.DoubleToInt64Bits(loaded))
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
value = double.NaN;
|
|
loaded = *ptr;
|
|
if (BitConverter.DoubleToInt64Bits(value) != BitConverter.DoubleToInt64Bits(loaded))
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int TestLdindI()
|
|
{
|
|
IntPtr value = new IntPtr(42);
|
|
IntPtr* ptr = &value;
|
|
IntPtr loaded = *ptr; // This generates ldind.i
|
|
if (value != loaded)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
value = IntPtr.Zero;
|
|
loaded = *ptr;
|
|
if (value != loaded)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int TestTruncation()
|
|
{
|
|
// Store a larger value and load as smaller type
|
|
int largeValue = 0x1234ABCD;
|
|
void* ptr = &largeValue;
|
|
|
|
byte byteValue = *(byte*)ptr; // Should truncate to 0xCD
|
|
if (byteValue != 0xCD)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
short shortValue = *(short*)ptr; // Should truncate to 0xABCD
|
|
if (shortValue != -21555)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
// Test sign extension
|
|
sbyte signedByte = *(sbyte*)ptr; // 0xCD as signed byte is -51
|
|
if (signedByte != -51)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int TestManagedPointers()
|
|
{
|
|
int value = 42;
|
|
ref int refValue = ref value;
|
|
var expected42 = TestRefParameter(ref refValue);
|
|
if (expected42 != 42)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
if (refValue != 84)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
// Test with array element
|
|
int[] array = new int[3];
|
|
array[0] = 10;
|
|
array[1] = 20;
|
|
array[2] = 30;
|
|
ref int element = ref array[1];
|
|
if (element != 20)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
// Test with local variable
|
|
int local = 100;
|
|
var expected100 = TestRefLocal(ref local);
|
|
if (expected100 != 100)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int TestRefParameter(ref int param)
|
|
{
|
|
var result = 0;
|
|
// This will use ldind instructions when accessing param
|
|
result += param;
|
|
param = 84;
|
|
return result;
|
|
}
|
|
|
|
static int TestRefLocal(ref int local)
|
|
{
|
|
// Create a ref local
|
|
ref int refLocal = ref local;
|
|
return refLocal;
|
|
}
|
|
}
|