/// <summary> /// Generates an assembly code that will decode an integer with a set of InstructionInfo. /// </summary> /// <param name="instructionInfoList"></param> /// <param name="generateCallDelegate"></param> /// <param name="level"></param> public static AstNodeStm GenerateSwitchCode(IEnumerable <InstructionInfo> instructionInfoList, Func <InstructionInfo, AstNodeStm> generateCallDelegate, int level = 0) { //var ILGenerator = SafeILGenerator._UnsafeGetILGenerator(); var instructionInfos = instructionInfoList as InstructionInfo[] ?? instructionInfoList.ToArray(); var commonMask = instructionInfos.Aggregate(0xFFFFFFFF, (Base, instructionInfo) => Base & instructionInfo.Mask); var maskGroups = instructionInfos.GroupBy(instructionInfo => instructionInfo.Value & commonMask); #if false int ShiftOffset = 0; var CommonMaskShifted = CommonMask >> ShiftOffset; uint MinValue = 0; #else var shiftOffset = BitUtils.GetFirstBit1(commonMask); var commonMaskShifted = commonMask >> shiftOffset; var enumerable = maskGroups as IGrouping <uint, InstructionInfo>[] ?? maskGroups.ToArray(); var minValue = enumerable .Select(maskGroup => (maskGroup.First().Value >> shiftOffset) & commonMaskShifted).Min(); #endif //var MaskGroupsCount = MaskGroups.Count(); //Console.WriteLine("[" + Level + "]{0:X}", CommonMask); //var MaskedLocal = SafeILGenerator.DeclareLocal<int>(); return(Ast.Statements( Ast.Switch( Ast.Binary( Ast.Binary(Ast.Binary(Ast.Argument <uint>(0), ">>", shiftOffset), "&", commonMaskShifted), "-", minValue), Ast.Default(generateCallDelegate(null)), enumerable.Select(maskGroup => Ast.Case( ((maskGroup.First().Value >> shiftOffset) & commonMaskShifted) - minValue, (maskGroup.Count() > 1) ? GenerateSwitchCode(maskGroup, generateCallDelegate, level + 1) : generateCallDelegate(maskGroup.First()) ) ).ToArray() ), Ast.Throw(Ast.New <Exception>("Unexpected reach!")) )); }