internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { var stack = context.Stack; if (stack.Count < 1) { throw new StackTooSmallException(OpCode.Int64CountTrailingZeroes, 1, stack.Count); } var type = stack.Peek(); //Assuming validation passes, the remaining type will be this. if (type != ValueType.Int64) { throw new StackTypeInvalidException(OpCode.Int64CountTrailingZeroes, ValueType.Int64, type); } context.Emit(IKVM.Reflection.Emit.OpCodes.Call, context[HelperMethod.Int64CountTrailingZeroes, (helper, c) => { Assert(c != null); var result = context.ExportsBuilder.DefineMethod( "☣ Int64CountTrailingZeroes", IKVMCompilationContext.HelperMethodAttributes, universe.Import(typeof(long)), new[] { universe.Import(typeof(ulong)) }); //All modern CPUs have a fast instruction specifically for this process, but there's no way to use it from .NET. //Based on the algorithm found here: http://aggregate.org/MAGIC/#Trailing%20Zero%20Count var il = result.GetILGenerator(); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Neg); il.Emit(IKVM.Reflection.Emit.OpCodes.And); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_1); il.Emit(IKVM.Reflection.Emit.OpCodes.Conv_I8); il.Emit(IKVM.Reflection.Emit.OpCodes.Sub); il.Emit(IKVM.Reflection.Emit.OpCodes.Call, Int64CountOneBits.IKVMCreateHelper(HelperMethod.Int64CountOneBits, context, universe)); il.Emit(IKVM.Reflection.Emit.OpCodes.Ret); return(result); } ]); }
internal sealed override void CompileIKVM(IKVMCompilationContext context, IKVM.Reflection.Universe universe) { var stack = context.Stack; if (stack.Count < 1) { throw new StackTooSmallException(OpCode.Int64CountLeadingZeroes, 1, stack.Count); } var type = stack.Peek(); //Assuming validation passes, the remaining type will be this. if (type != ValueType.Int64) { throw new StackTypeInvalidException(OpCode.Int64CountLeadingZeroes, ValueType.Int64, type); } context.Emit(IKVM.Reflection.Emit.OpCodes.Call, context[HelperMethod.Int64CountLeadingZeroes, (helper, c) => { Assert(c != null); var result = context.ExportsBuilder.DefineMethod( "☣ Int64CountLeadingZeroes", IKVMCompilationContext.HelperMethodAttributes, universe.Import(typeof(ulong)), new[] { universe.Import(typeof(ulong)) }); //All modern CPUs have a fast instruction specifically for this process, but there's no way to use it from .NET. //This algorithm is extended from https://stackoverflow.com/questions/10439242/count-leading-zeroes-in-an-int32 var il = result.GetILGenerator(); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_1); il.Emit(IKVM.Reflection.Emit.OpCodes.Shr_Un); il.Emit(IKVM.Reflection.Emit.OpCodes.Or); il.Emit(IKVM.Reflection.Emit.OpCodes.Starg_S, 0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_2); il.Emit(IKVM.Reflection.Emit.OpCodes.Shr_Un); il.Emit(IKVM.Reflection.Emit.OpCodes.Or); il.Emit(IKVM.Reflection.Emit.OpCodes.Starg_S, 0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_4); il.Emit(IKVM.Reflection.Emit.OpCodes.Shr_Un); il.Emit(IKVM.Reflection.Emit.OpCodes.Or); il.Emit(IKVM.Reflection.Emit.OpCodes.Starg_S, 0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_8); il.Emit(IKVM.Reflection.Emit.OpCodes.Shr_Un); il.Emit(IKVM.Reflection.Emit.OpCodes.Or); il.Emit(IKVM.Reflection.Emit.OpCodes.Starg_S, 0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_S, 16); il.Emit(IKVM.Reflection.Emit.OpCodes.Shr_Un); il.Emit(IKVM.Reflection.Emit.OpCodes.Or); il.Emit(IKVM.Reflection.Emit.OpCodes.Starg_S, 0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_S, 32); il.Emit(IKVM.Reflection.Emit.OpCodes.Shr_Un); il.Emit(IKVM.Reflection.Emit.OpCodes.Or); il.Emit(IKVM.Reflection.Emit.OpCodes.Starg_S, 0); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldc_I4_S, 64); il.Emit(IKVM.Reflection.Emit.OpCodes.Ldarg_0); il.Emit(IKVM.Reflection.Emit.OpCodes.Call, Int64CountOneBits.IKVMCreateHelper(HelperMethod.Int64CountOneBits, context, universe)); il.Emit(IKVM.Reflection.Emit.OpCodes.Sub); il.Emit(IKVM.Reflection.Emit.OpCodes.Ret); return(result); } ]); }