Skip to content

Conversation

@anthonycanino
Copy link
Owner

Overview

This PR demonstrates a few things which I think are useful for learnings (and optimize several cases below that ARM typically had optimized and beat us in micros):

  1. The creation of a table driven intrinsic, e.g., NI_AVX512DQ_VL_ConvertToDouble128, which allows to map a lowering between a method (though in this case, there are no frontend APIs added) and an argument type (for example, Vector128<long>) to a specific hardware instruction vcvtps2udq.

  2. The mapping of a vector method to a named intrinsic, for example, Vector128.ConvertToDouble(Vector128<ulong> v) to NI_AVX512DQ_VL_ConvertToDouble128.

  3. The mapping of a variable length vector method to a named intrinsic, for example Vector.ConvertToDouble(Vector<ulong> v) to NI_AVX512DQ_VL_ConvertToDouble128.

  4. The addition of several new AVX512 instructions to the instruction tables.

Not all intrinsics must map to a single instruction --- several will actually lower to a series of instructions, which we'd probably call it "codegen" versus a hardware intrinsic, though those terms are loosely defined.

Optimized Cases

Cases that have been optimized to use one of the single AVX512VL instructions...

        // -----------------------------------------
	// Cases are Vector long => double, ulong => double
	// -----------------------------------------

	// VCVTUQQ2PD
	[MethodImpl(MethodImplOptions.NoInlining)]
	public static Vector128<double> VLongToDouble(long i)
	{
		Vector128<long> v1 = Vector128.Create(i);
		return Vector128.ConvertToDouble(v1);
	}

	// VCVTQQ2PD
	[MethodImpl(MethodImplOptions.NoInlining)]
	public static Vector128<double> VUlongToDouble(ulong i)
	{
		Vector128<ulong> v1 = Vector128.Create(i);
		return Vector128.ConvertToDouble(v1);
	}

	// VCVTUQQ2PD
	[MethodImpl(MethodImplOptions.NoInlining)]
	public static Vector<double> VLongToDoubleVT(long i)
	{
		Vector<long> v1 = new Vector<long>(i);
		return Vector.ConvertToDouble(v1);
	}

	// VCVTQQ2PD
	[MethodImpl(MethodImplOptions.NoInlining)]
	public static Vector<double> VUlongToDoubleVT(ulong i)
	{
		Vector<ulong> v1 = new Vector<ulong>(i);
		return Vector.ConvertToDouble(v1);
	}

	// -----------------------------------------
	// Cases are Vector double => long
	// -----------------------------------------

	[MethodImpl(MethodImplOptions.NoInlining)]
	public static Vector128<long> VDoubleToLong(double i)
	{
		Vector128<double> v1 = Vector128.Create(i);
		return Vector128.ConvertToInt64(v1);
	}

	// VCVTUQQ2PD
	[MethodImpl(MethodImplOptions.NoInlining)]
	public static Vector<long> VDoubleToLongVT(double i)
	{
		Vector<double> v1 = new Vector<double>(i);
		return Vector.ConvertToInt64(v1);
	}

	// -----------------------------------------
	// Cases are Vector double => ulong
	// -----------------------------------------

	[MethodImpl(MethodImplOptions.NoInlining)]
	public static Vector128<ulong> VDoubleToUlong(double i)
	{
		Vector128<double> v1 = Vector128.Create(i);
		return Vector128.ConvertToUInt64(v1);
	}

	// VCVTUQQ2PD
	[MethodImpl(MethodImplOptions.NoInlining)]
	public static Vector<ulong> VDoubleToUlongVT(double i)
	{
		Vector<double> v1 = new Vector<double>(i);
		return Vector.ConvertToUInt64(v1);
	}

	// -----------------------------------------
	// Cases are Vector float => uint
	// -----------------------------------------

	[MethodImpl(MethodImplOptions.NoInlining)]
	public static Vector128<uint> VFloatToUint(float i)
	{
		Vector128<float> v1 = Vector128.Create(i);
		return Vector128.ConvertToUInt32(v1);
	}

	[MethodImpl(MethodImplOptions.NoInlining)]
	public static Vector<uint> VFloatToUintVT(float i)
	{
		Vector<float> v1 = new Vector<float>(i);
		return Vector.ConvertToUInt32(v1);
	}

	[MethodImpl(MethodImplOptions.NoInlining)]
	public static Vector128<float> VUintToFloat(uint i)
	{
		Vector128<uint> v1 = Vector128.Create(i);
		return Vector128.ConvertToSingle(v1);
	}

	[MethodImpl(MethodImplOptions.NoInlining)]
	public static Vector<float> VUintToFloatVT(uint i)
	{
		Vector<uint> v1 = new Vector<uint>(i);
		return Vector.ConvertToSingle(v1);
	}

anthonycanino pushed a commit that referenced this pull request Jul 6, 2023
…tnet#87189)

This fixes a startup crash on Big Sur:

> error: * Assertion at /Users/runner/work/1/s/src/mono/mono/utils/mono-hwcap-arm64.c:35, condition `res == 0' not met

Because sysctl can't find some of these options:

    $ sysctl hw.optional.armv8_crc32
    hw.optional.armv8_crc32: 1
    $ sysctl hw.optional.arm.FEAT_RDM
    sysctl: unknown oid 'hw.optional.arm.FEAT_RDM'
    $ sysctl hw.optional.arm.FEAT_DotProd
    sysctl: unknown oid 'hw.optional.arm.FEAT_DotProd'
    $ sysctl hw.optional.arm.FEAT_SHA1
    sysctl: unknown oid 'hw.optional.arm.FEAT_SHA1'
    $ sysctl hw.optional.arm.FEAT_SHA256
    sysctl: unknown oid 'hw.optional.arm.FEAT_SHA256'
    $ sysctl hw.optional.arm.FEAT_AES
    sysctl: unknown oid 'hw.optional.arm.FEAT_AES'

Full stack trace:

* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
  * frame #0: 0x0000010ef37560 libmonosgen-2.0.dylib`monoeg_assertion_message
    frame #1: 0x0000010ef375cc libmonosgen-2.0.dylib`mono_assertion_message + 32
    frame #2: 0x0000010ef40d6c libmonosgen-2.0.dylib`mono_hwcap_arch_init + 544
    frame #3: 0x0000010ef54bd8 libmonosgen-2.0.dylib`mono_hwcap_init + 72
    frame #4: 0x0000010ee14dc0 libmonosgen-2.0.dylib`parse_optimizations + 52
    frame #5: 0x0000010edbed48 libmonosgen-2.0.dylib`mono_init
    frame #6: 0x0000010ee18968 libmonosgen-2.0.dylib`mono_jit_init_version
    frame #7: 0x0000010f48a300 libxamarin-dotnet-debug.dylib`xamarin_bridge_initialize + 216
    frame #8: 0x0000010f4900a4 libxamarin-dotnet-debug.dylib`xamarin_main + 376
anthonycanino pushed a commit that referenced this pull request Dec 18, 2024
* bug #1: don't allow for values out of the SerializationRecordType enum range

* bug #2: throw SerializationException rather than KeyNotFoundException when the referenced record is missing or it points to a record of different type

* bug #3: throw SerializationException rather than FormatException when it's being thrown by BinaryReader (or sth else that we use)

* bug #4: document the fact that IOException can be thrown

* bug #5: throw SerializationException rather than OverflowException when parsing the decimal fails

* bug #6: 0 and 17 are illegal values for PrimitiveType enum

* bug #7: throw SerializationException when a surrogate character is read (so far an ArgumentException was thrown)
anthonycanino pushed a commit that referenced this pull request Oct 23, 2025
Currently, offsets are incorrectly treated as indices which is
leading to incorrect code being emitted.

e.g., `ScatterWithByteOffsets<long>` emits
`ST1D Zdata.D, Pg, [Xbase, Zoffsets.D, lsl #3]`
instead of,
`ST1D Zdata.D, Pg, [Xbase, Zoffsets.D]`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants