Optimize Enum.HasFlag () implementation and recognize it in the JIT.
authorAlex Rønne Petersen <alexrp@xamarin.com>
Thu, 29 Jan 2015 00:17:14 +0000 (01:17 +0100)
committerAlex Rønne Petersen <alexrp@xamarin.com>
Thu, 29 Jan 2015 18:06:33 +0000 (19:06 +0100)
commit8221afc2bc0cd55ed7820252869e4decbeb4042c
treee01a3014e18bd3f95cba70de9badcc2e91ce015f
parent32db079545c12380d66952328c05c6f4a70284d8
Optimize Enum.HasFlag () implementation and recognize it in the JIT.

The previous implementation did a ton of reflection and boxing making
it about 4x slower than it should be. This new (native) implementation
simply memcpy ()s the values out of the Enum objects and then does the
bitwise AND.

In addition, the JIT now recognizes this common IL pattern:

<push int or long ptr>
<push int or long>
box MyFlagsEnum
constrained. MyFlagsEnum
callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)

This is generated from C# code such as:

MyFlagsEnum a = ..., b = ...;
a.HasFlag (b);

When the operand types of the `box` and `constrained.` instructions are
the same, we can skip all the slow stuff that HasFlag () normally does
and simply turn the whole thing into this IR:

<this> = loadi4_membase <this_ptr>
<temp> = int_and <this> <flag>
icompare <temp> <flag>
<result> = int_ceq

This is about 60x faster than the old HasFlag () without any JIT support
and about 15x faster than the new HasFlag () native implementation.

Also, added missing argument checks to HasFlag ().
mcs/class/corlib/System/Enum.cs
mcs/class/corlib/Test/System/EnumTest.cs
mono/metadata/icall-def.h
mono/metadata/icall.c
mono/mini/method-to-ir.c
mono/tests/Makefile.am
mono/tests/enum-intrins.cs [new file with mode: 0644]