public static bool Compare(this InstructionCollection source, InstructionCollection n, Func<Instruction, Instruction, bool> checkitem) { return Compare<Instruction>(source,n,checkitem); }
private void AddOrderToRun(int orderId, int runId) { CustomPrincipal customPrincipal = (Entities.CustomPrincipal)Page.User; string userName = customPrincipal.UserName; Facade.IJob facJob = new Facade.Job(); Entities.Job job = new Orchestrator.Entities.Job(); job = facJob.GetJob(runId, true, true); Entities.InstructionCollection collections = new Orchestrator.Entities.InstructionCollection(); Entities.Instruction collectionInstruction = null; Entities.CollectDrop cd; Entities.InstructionCollection deliveries = new Orchestrator.Entities.InstructionCollection(); Entities.Instruction deliveryInstruction = null; Facade.IPoint facPoint = new Facade.Point(); Facade.IOrder facOrder = new Facade.Order(); Entities.Point point; Entities.Order order = facOrder.GetForOrderID(orderId); int pointID = order.CollectionPointID; DateTime bookedDateTime = order.CollectionDateTime; bool collectionIsAnyTime = order.CollectionIsAnytime; // if this setting is true then we want to create a new instruction for the order. if (Globals.Configuration.OneDropAndLoadInstructionPerOrder) { collectionInstruction = null; } else { collectionInstruction = job.Instructions.GetForInstructionTypeAndPointID(eInstructionType.Load, pointID, bookedDateTime, collectionIsAnyTime); } if (collectionInstruction == null) { collectionInstruction = new Orchestrator.Entities.Instruction(); collectionInstruction.InstructionTypeId = (int)eInstructionType.Load; collectionInstruction.BookedDateTime = bookedDateTime; if (collectionIsAnyTime) { collectionInstruction.IsAnyTime = true; } point = facPoint.GetPointForPointId(pointID); collectionInstruction.PointID = pointID; collectionInstruction.Point = point; collectionInstruction.ClientsCustomerIdentityID = point.IdentityId; collectionInstruction.CollectDrops = new Orchestrator.Entities.CollectDropCollection(); collectionInstruction.InstructionOrder = 0; } cd = new Orchestrator.Entities.CollectDrop(); cd.PalletTypeID = order.PalletTypeID; cd.NoPallets = order.NoPallets; cd.NoCases = order.Cases; cd.GoodsTypeId = order.GoodsTypeID; cd.OrderID = order.OrderID; cd.OrderAction = eOrderAction.Default; cd.Weight = order.Weight; cd.ClientsCustomerReference = order.DeliveryOrderNumber; cd.Docket = order.OrderID.ToString(); collectionInstruction.CollectDrops.Add(cd); collections.Add(collectionInstruction); eOrderAction orderAction = eOrderAction.Default; int deliveryPointID = order.DeliveryPointID; DateTime deliveryDateTime = order.DeliveryDateTime; bool deliveryIsAnyTime = order.DeliveryIsAnytime; // if this setting is true then we want to create a new instruction for the order. if (Globals.Configuration.OneDropAndLoadInstructionPerOrder) { deliveryInstruction = null; } else { deliveryInstruction = job.Instructions.GetForInstructionTypeAndPointID(eInstructionType.Drop, deliveryPointID, deliveryDateTime, deliveryIsAnyTime); } if (deliveryInstruction == null) { deliveryInstruction = new Orchestrator.Entities.Instruction(); deliveryInstruction.InstructionTypeId = (int)eInstructionType.Drop; deliveryInstruction.BookedDateTime = deliveryDateTime; if (deliveryIsAnyTime) { deliveryInstruction.IsAnyTime = true; } point = facPoint.GetPointForPointId(deliveryPointID); deliveryInstruction.ClientsCustomerIdentityID = point.IdentityId; deliveryInstruction.PointID = deliveryPointID; deliveryInstruction.Point = point; deliveryInstruction.CollectDrops = new Orchestrator.Entities.CollectDropCollection(); deliveryInstruction.InstructionOrder = 0; } cd = new Orchestrator.Entities.CollectDrop(); cd.PalletTypeID = order.PalletTypeID; cd.NoPallets = order.NoPallets; cd.NoCases = order.Cases; cd.GoodsTypeId = order.GoodsTypeID; cd.OrderID = order.OrderID; cd.Weight = order.Weight; cd.ClientsCustomerReference = order.DeliveryOrderNumber; cd.Docket = order.OrderID.ToString(); cd.OrderAction = orderAction; deliveryInstruction.CollectDrops.Add(cd); deliveries.Add(deliveryInstruction); facOrder.UpdateForCollectionRun(cd.OrderID, deliveryInstruction.PointID, deliveryInstruction.BookedDateTime, deliveryInstruction.IsAnyTime, cd.OrderAction, userName); List <Instruction> instructions = new List <Instruction>(); Entities.CollectDropCollection orderedCollectDrops = new CollectDropCollection(); for (int i = 0; i < collections.Count; i++) { orderedCollectDrops = new CollectDropCollection(); int pos = 0; foreach (Entities.CollectDrop orderedCD in collections[i].CollectDrops) { if (orderedCollectDrops.Count == 0) { orderedCollectDrops.Add(orderedCD); } else { for (int x = 0; x < orderedCollectDrops.Count; x++) { if (orderedCD.OrderID > orderedCollectDrops[x].OrderID) { pos = x + 1; } } orderedCollectDrops.Insert(pos, orderedCD); } } collections[i].CollectDrops = orderedCollectDrops; instructions.Add(collections[i]); } Entities.InstructionCollection orderedInstructions = new InstructionCollection(); for (int i = 0; i < deliveries.Count; i++) { int pos = 0; if (orderedInstructions.Count == 0) { orderedInstructions.Add(deliveries[i]); } else { for (int y = 0; y < orderedInstructions.Count; y++) { if (deliveries[i].CollectDrops[0].OrderID > orderedInstructions[y].CollectDrops[0].OrderID) { pos = y + 1; } } orderedInstructions.Insert(pos, deliveries[i]); } } foreach (Entities.Instruction ins in orderedInstructions) { instructions.Add(ins); } facJob.AmendInstructions(job, instructions, eLegTimeAlterationMode.Minimal, userName); }
public static bool Compare(this InstructionCollection source, InstructionCollection n) { return Compare<Instruction>(source,n); }
GetCustomInstructionListFromInstructionCollection(InstructionCollection instructions) { if (instructions == null) throw new ArgumentNullException("instructions", "instructions cannot be null."); IList<CustomInstruction> instructionList = new List<CustomInstruction>(); foreach (Instruction fxCopInstruction in instructions) { var currentInstruction = new CustomInstruction(); currentInstruction.Offset = fxCopInstruction.Offset; currentInstruction.OpCode = fxCopInstruction.OpCode; var localValue = fxCopInstruction.Value as Local; if (localValue == null) { currentInstruction.Value = fxCopInstruction.Value; } else { currentInstruction.Value = new CustomLocal() { Name = localValue.Name.Name }; } instructionList.Add(currentInstruction); } return instructionList; }
public virtual IInstructionCollection TransformInstructionCollection(IInstructionCollection value) { IInstruction[] array = new IInstruction[value.Count]; for (int i = 0; i < value.Count; i++) { array[i] = this.TransformInstruction(value[i]); } IInstructionCollection target = new InstructionCollection(); target.AddRange(array); return target; }
public InstructionCollection CreateInstructions() { this.ResetUseCount(false); var instructions = new InstructionCollection(this.BaseGems); if (this.Gem != null) { this.Gem.UseCount = 1; } this.BuildGem(this.Gem, instructions, true); if (instructions.SlotsRequired > SlotLimit) { instructions = this.CondenseSlots(new List<Gem>(this.BaseGems), true); instructions.WasCondensed = true; } else { instructions.WasCondensed = false; } return instructions; }
/// <summary>Attempts to create individual gems in the tree from the base gem, then combines them into the larger one. This allows combining larger gems that won't fit into 36 slots all at once, at the cost of increasing the number of instructions necessary to do so.</summary> /// <param name="gemsToIgnore">A list of gems that are already slotted from previous runs. The base call to CondenseSlots should pass the base gems only.</param> /// <param name="lastRun">Indicates whether or not this is the last node in the tree. The base call to CondenseSlots should always pass true. Internally, this is always passed as false for the first node of a gem, and passed as the parent value for the second node. Thus, it will be true only for the second node of the second node of the second node...etc.</param> /// <returns>The list of instructions to create the costliest possible gem in the number of slots allowed.</returns> private InstructionCollection CondenseSlots(ICollection<Gem> gemsToIgnore, bool lastRun) { var combine1 = new Combiner(this.Gem.Component1, this.gems, false); combine1.Gem.UseCount++; var instructions1 = new InstructionCollection(gemsToIgnore); combine1.BuildGem(combine1.Gem, instructions1, true); combine1.Gem.UseCount--; if (gemsToIgnore.Count >= SlotLimit) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "You cannot build this gem with {0} slots.", SlotLimit)); } if (instructions1.SlotsRequired > SlotLimit) { instructions1 = combine1.CondenseSlots(gemsToIgnore, false); } gemsToIgnore.Add(combine1.Gem); var combine2 = new Combiner(this.Gem.Component2, this.gems, lastRun); combine2.Gem.UseCount++; var instructions2 = new InstructionCollection(gemsToIgnore); combine2.BuildGem(combine2.Gem, instructions2, lastRun); combine2.Gem.UseCount--; if (gemsToIgnore.Count >= SlotLimit) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "You cannot build this gem with {0} slots.", SlotLimit)); } if (instructions2.SlotsRequired > SlotLimit) { instructions2 = combine2.CondenseSlots(gemsToIgnore, lastRun); } gemsToIgnore.Remove(combine1.Gem); return new InstructionCollection(instructions1, instructions2, this.Gem); }
public static bool Compare(this InstructionCollection source, InstructionCollection n, Func <Instruction, Instruction, bool> checkitem) { return(Compare <Instruction>(source, n, checkitem)); }
public static bool Compare(this InstructionCollection source, InstructionCollection n, Func <Instruction, Instruction, Action <string, string>, bool> checkitem, Action <string, string> errAct) { return(Compare <Instruction>(source, n, checkitem, errAct)); }
private void Awake() { PI = (InstructionCollection)FindObjectOfType(typeof(InstructionCollection)); InstUIs = new List <InstructionUI>(GetComponentsInChildren <InstructionUI>()); PI.OnRefreshItems += PI_OnRefreshUI; }
public static bool Compare(this InstructionCollection source, InstructionCollection n) { return(Compare <Instruction>(source, n)); }
bool IsPartOfInitializer(InstructionCollection <ILInstruction> instructions, int pos, ILVariable target, IType rootType, ref BlockType blockType, Dictionary <ILVariable, (int Index, ILInstruction Value)> possibleIndexVariables)
public override void Initialize(PieceTable pieceTable, InstructionCollection switches) { base.Initialize(pieceTable, switches); chart.Initialize(switches); }
public override void VisitInstructionCollection(InstructionCollection instructions) { foreach (Instruction instr in instructions) { CheckExceptionHandlers(instr); m_writer.Write("{0}: {1}", Label(instr), instr.OpCode.Name); switch (instr.OpCode.OperandType) { case OperandType.InlineNone: break; case OperandType.InlineSwitch: m_writer.WriteLine("("); m_writer.Indent(); Instruction [] targets = (Instruction [])instr.Operand; for (int i = 0; i < targets.Length; i++) { m_writer.Write(Label(targets [i])); m_writer.WriteLine(i < targets.Length - 1 ? "," : string.Empty); } m_writer.Unindent(); m_writer.Write(")"); break; case OperandType.ShortInlineBrTarget: case OperandType.InlineBrTarget: m_writer.WriteLine(Label((Instruction)instr.Operand)); break; case OperandType.ShortInlineVar: case OperandType.InlineVar: VariableDefinition var = (VariableDefinition)instr.Operand; if (var.Name != null && var.Name.Length > 0) { m_writer.Write(var.Name); } else { m_writer.Write(instructions.Container.Variables.IndexOf(var)); } break; case OperandType.ShortInlineParam: case OperandType.InlineParam: ParameterDefinition param = (ParameterDefinition)instr.Operand; if (param.Name != null && param.Name.Length > 0) { m_writer.Write(Formater.Escape(param.Name)); } else { m_writer.Write(instructions.Container.Method.Parameters.IndexOf(param)); } break; case OperandType.InlineI: case OperandType.InlineI8: case OperandType.InlineR: case OperandType.ShortInlineI: case OperandType.ShortInlineR: m_writer.Write(instr.Operand.ToString()); break; case OperandType.InlineString: //FIXME: Handle unicode strings with non zero high byte StringBuilder sb = new StringBuilder(instr.Operand.ToString()); //FIXME: extract to a method sb.Replace("\"", "\\\""); sb.Replace("\t", "\\t"); sb.Replace("\r", "\\r"); sb.Replace("\n", "\\n"); m_writer.Write(String.Concat( "\"", sb.ToString(), "\"")); break; case OperandType.InlineType: m_writer.Write(Formater.Signature((TypeReference)instr.Operand)); break; case OperandType.InlineMethod: case OperandType.InlineField: VisitMemberReference(instr.Operand as MemberReference); break; case OperandType.InlineTok: if (instr.Operand is TypeReference) { m_writer.Write(Formater.Signature((TypeReference)instr.Operand, true)); } else if (instr.Operand is MemberReference) { if (instr.Operand is FieldReference) { m_writer.Write("field"); } //FIXME: method VisitMemberReference((MemberReference)instr.Operand); } break; } m_writer.WriteLine(); } }
public static bool Compare(this InstructionCollection source, InstructionCollection n, Func<Instruction, Instruction, Action<string, string>, bool> checkitem, Action<string, string> errAct) { return Compare<Instruction>(source,n,checkitem,errAct); }
private void Awake() { OC = GetComponentInParent <InstructionCollection>(); destroyButton = GetComponentInChildren <Button>(); destroyButton.onClick.AddListener(() => OnDestroyButtonClicked(Selection)); }
public virtual void VisitInstructionCollection(InstructionCollection instructions) { }
/// <summary> /// Fill jumps /// </summary> /// <param name="bag">Bag</param> /// <param name="ins">Instruction</param> /// <param name="offsetToIndexCache">Cache</param> public override void ProcessInstruction(InstructionCollection bag, Instruction ins, OffsetRelationCache offsetToIndexCache) { if (ins.OpCode == null) { return; } switch (ins.OpCode.Name) { // Detect bad property optimization case nameof(NeoOpCode.DROP): { /* * 0x03C5 PUSH0 Method 0x03C5 [R4S] * 0x03C6 NEWARRAY * 0x03C7 TOALTSTACK * That is the only valid > 0x03C8 PUSHBYTES3 0x523453 R4S * 0x03CC NOP * 0x03CD FROMALTSTACK * > 0x03CE DROP */ int y = 1; for (int x = (int)ins.Location.Index - 1; x >= 0 && y <= 6; x--, y++) { Instruction i = bag[x]; if (i == null || i.OpCode == null) { return; } switch (y) { case 1: { if (i.OpCode.Name != nameof(NeoOpCode.FROMALTSTACK)) { // Detect Push / Drop if (i.OpCode.Name.StartsWith("PUSH")) { ins.Flags = InstructionFlag.UnusableCode; ins.ApplyColorForFlags(); i.Flags = InstructionFlag.UnusableCode; i.ApplyColorForFlags(); } return; } break; } case 2: { if (i.OpCode.Name != nameof(NeoOpCode.NOP)) { return; } break; } case 3: { if (!i.OpCode.Name.StartsWith("PUSH")) { return; } break; } case 4: { if (i.OpCode.Name != nameof(NeoOpCode.TOALTSTACK)) { return; } break; } case 5: { if (i.OpCode.Name != nameof(NeoOpCode.NEWARRAY)) { return; } break; } case 6: { if (i.OpCode.Name != nameof(NeoOpCode.PUSH0)) { return; } break; } } } if (y == 7) { ins.Flags = InstructionFlag.UnusableCode; ins.ApplyColorForFlags(); y = 1; for (int x = (int)ins.Location.Index - 1, m = x - 6; x > m; x--, y++) { if (y == 3) { continue; } Instruction i = bag[x]; i.Flags = InstructionFlag.UnusableCode; i.ApplyColorForFlags(); } } break; } // Detect NOP case nameof(NeoOpCode.NOP): { ins.Flags = InstructionFlag.UnusableCode; ins.ApplyColorForFlags(); break; } // Detect To/From ALTSTACK case nameof(NeoOpCode.FROMALTSTACK): { if (ins.Location.Index != 0) { Instruction prev = bag[ins.Location.Index - 1]; if (prev != null && prev.OpCode != null && prev.OpCode.Name == nameof(NeoOpCode.TOALTSTACK)) { prev.Flags = InstructionFlag.UnusableCode; ins.Flags = InstructionFlag.UnusableCode; prev.ApplyColorForFlags(); ins.ApplyColorForFlags(); } } break; } case nameof(NeoOpCode.RET): { ins.Jump = new Jump(new OnJumpDelegate( (d, i) => { if (d == null || d.CurrentInstructionIndex != i.Location.Index || !(d is NeoDebugger neodebug)) { return(null); } try { return((uint)neodebug.Engine.InvocationStack.Peek().InstructionPointer); } catch { } return(null); }) ); break; } case nameof(NeoOpCode.CALL): case nameof(NeoOpCode.JMP): { if (!(ins.Argument is OpCodeShortArgument a)) { return; } uint offset = (uint)a.Value; if (offset == 3) { // Detect JMP to next line ins.Flags = InstructionFlag.UnusableCode; ins.ApplyColorForFlags(); } offset = ins.Location.Offset + offset; if (offsetToIndexCache.TryGetValue(offset, out uint ix, OffsetIndexRelation.OffsetToIndex)) { ins.Jump = new Jump(offset, ix); }
private void BuildGem(Gem gem, InstructionCollection instructions, bool doPostScan) { if (gem == null || !gem.IsNeeded || instructions.SlotsRequired > SlotLimit) { return; } var gem1 = gem.Component1; var gem2 = gem.Component2; this.BuildGem(gem1, instructions, true); this.BuildGem(gem2, instructions, true); // Re-check if gem is needed in case gem was already built during optimization routine for component gems. if (gem.IsNeeded && instructions.SlotsRequired <= SlotLimit) { gem1.UseCount--; gem2.UseCount--; doPostScan &= gem.IsUpgrade ? instructions.Upgrade(gem) : instructions.Combine(gem); while (doPostScan && instructions.SlotsRequired <= SlotLimit) { doPostScan = this.OptimizeLastGems(instructions) || this.OptimizeSingleUseGems(instructions); } } }
/// <summary> /// Matches Roslyn C# switch on nullable. /// </summary> bool MatchRoslynSwitchOnNullable(InstructionCollection <ILInstruction> instructions, int i, out SwitchInstruction newSwitch) { newSwitch = null; // match first block: // if (logic.not(call get_HasValue(target))) br nullCaseBlock // br switchBlock if (!instructions[i].MatchIfInstruction(out var condition, out var trueInst)) { return(false); } if (!instructions[i + 1].MatchBranch(out var switchBlock) || !trueInst.MatchBranch(out var nullCaseBlock)) { return(false); } if (!condition.MatchLogicNot(out var getHasValue) || !NullableLiftingTransform.MatchHasValueCall(getHasValue, out ILInstruction target) || !SemanticHelper.IsPure(target.Flags)) { return(false); } // match second block: switchBlock // note: I have seen cases where switchVar is inlined into the switch. // stloc switchVar(call GetValueOrDefault(ldloca tmp)) // switch (ldloc switchVar) { // case [0..1): br caseBlock1 // ... more cases ... // case [long.MinValue..0),[1..5),[6..10),[11..long.MaxValue]: br defaultBlock // } if (switchBlock.IncomingEdgeCount != 1) { return(false); } SwitchInstruction switchInst; switch (switchBlock.Instructions.Count) { case 2: { // this is the normal case described by the pattern above if (!switchBlock.Instructions[0].MatchStLoc(out var switchVar, out var getValueOrDefault)) { return(false); } if (!switchVar.IsSingleDefinition || switchVar.LoadCount != 1) { return(false); } if (!(NullableLiftingTransform.MatchGetValueOrDefault(getValueOrDefault, out ILInstruction target2) && target2.Match(target).Success)) { return(false); } if (!(switchBlock.Instructions[1] is SwitchInstruction si)) { return(false); } switchInst = si; break; } case 1: { // this is the special case where `call GetValueOrDefault(ldloca tmp)` is inlined into the switch. if (!(switchBlock.Instructions[0] is SwitchInstruction si)) { return(false); } if (!(NullableLiftingTransform.MatchGetValueOrDefault(si.Value, out ILInstruction target2) && target2.Match(target).Success)) { return(false); } switchInst = si; break; } default: { return(false); } } ILInstruction switchValue; if (target.MatchLdLoca(out var v)) { switchValue = new LdLoc(v).WithILRange(target); } else { switchValue = new LdObj(target, ((CallInstruction)getHasValue).Method.DeclaringType); } newSwitch = BuildLiftedSwitch(nullCaseBlock, switchInst, switchValue); return(true); }
private bool OptimizeSingleUseGems(InstructionCollection instructions) { var optimized = false; foreach (var gem in this.gems) { if (gem.IsNeeded && gem.Component1.Slot != Combiner.NotSlotted && gem.Component2.Slot != Combiner.NotSlotted && (gem.Component1.UseCount == 1 || gem.Component2.UseCount == 1)) { optimized = true; this.BuildGem(gem, instructions, false); } } return optimized; }
/// <summary> /// Matches legacy C# switch on nullable. /// </summary> bool MatchSwitchOnNullable(InstructionCollection <ILInstruction> instructions, int i, out SwitchInstruction newSwitch) { newSwitch = null; // match first block: // stloc tmp(ldloca switchValueVar) // stloc switchVariable(call GetValueOrDefault(ldloc tmp)) // if (logic.not(call get_HasValue(ldloc tmp))) br nullCaseBlock // br switchBlock if (i < 2) { return(false); } if (!instructions[i - 2].MatchStLoc(out var tmp, out var ldloca) || !instructions[i - 1].MatchStLoc(out var switchVariable, out var getValueOrDefault) || !instructions[i].MatchIfInstruction(out var condition, out var trueInst)) { return(false); } if (!tmp.IsSingleDefinition || tmp.LoadCount != 2) { return(false); } if (!switchVariable.IsSingleDefinition || switchVariable.LoadCount != 1) { return(false); } if (!instructions[i + 1].MatchBranch(out var switchBlock) || !trueInst.MatchBranch(out var nullCaseBlock)) { return(false); } if (!ldloca.MatchLdLoca(out var switchValueVar)) { return(false); } if (!condition.MatchLogicNot(out var getHasValue)) { return(false); } if (!NullableLiftingTransform.MatchGetValueOrDefault(getValueOrDefault, out ILInstruction getValueOrDefaultArg)) { return(false); } if (!NullableLiftingTransform.MatchHasValueCall(getHasValue, out ILInstruction getHasValueArg)) { return(false); } if (!(getHasValueArg.MatchLdLoc(tmp) && getValueOrDefaultArg.MatchLdLoc(tmp))) { return(false); } // match second block: switchBlock // switch (ldloc switchVariable) { // case [0..1): br caseBlock1 // ... more cases ... // case [long.MinValue..0),[1..5),[6..10),[11..long.MaxValue]: br defaultBlock // } if (switchBlock.Instructions.Count != 1 || switchBlock.IncomingEdgeCount != 1) { return(false); } if (!(switchBlock.Instructions[0] is SwitchInstruction switchInst)) { return(false); } newSwitch = BuildLiftedSwitch(nullCaseBlock, switchInst, new LdLoc(switchValueVar)); return(true); }
public virtual void VisitInstructionCollection (InstructionCollection instructions) { }
/// <summary> /// Matches Roslyn C# switch on nullable. /// </summary> bool MatchRoslynSwitchOnNullable(InstructionCollection <ILInstruction> instructions, int i, out SwitchInstruction newSwitch) { newSwitch = null; // match first block: // stloc tmp(ldloc switchValueVar) // if (logic.not(call get_HasValue(ldloca tmp))) br nullCaseBlock // br switchBlock if (i < 1) { return(false); } if (!instructions[i - 1].MatchStLoc(out var tmp, out var switchValue) || !instructions[i].MatchIfInstruction(out var condition, out var trueInst)) { return(false); } if (tmp.StoreCount != 1 || tmp.AddressCount != 2 || tmp.LoadCount != 0) { return(false); } if (!instructions[i + 1].MatchBranch(out var switchBlock) || !trueInst.MatchBranch(out var nullCaseBlock)) { return(false); } if (!condition.MatchLogicNot(out var getHasValue) || !NullableLiftingTransform.MatchHasValueCall(getHasValue, out ILVariable target1) || target1 != tmp) { return(false); } // match second block: switchBlock // note: I have seen cases where switchVar is inlined into the switch. // stloc switchVar(call GetValueOrDefault(ldloca tmp)) // switch (ldloc switchVar) { // case [0..1): br caseBlock1 // ... more cases ... // case [long.MinValue..0),[1..5),[6..10),[11..long.MaxValue]: br defaultBlock // } if (switchBlock.IncomingEdgeCount != 1) { return(false); } SwitchInstruction switchInst; switch (switchBlock.Instructions.Count) { case 2: { // this is the normal case described by the pattern above if (!switchBlock.Instructions[0].MatchStLoc(out var switchVar, out var getValueOrDefault)) { return(false); } if (!switchVar.IsSingleDefinition || switchVar.LoadCount != 1) { return(false); } if (!NullableLiftingTransform.MatchGetValueOrDefault(getValueOrDefault, tmp)) { return(false); } if (!(switchBlock.Instructions[1] is SwitchInstruction si)) { return(false); } switchInst = si; break; } case 1: { // this is the special case where `call GetValueOrDefault(ldloca tmp)` is inlined into the switch. if (!(switchBlock.Instructions[0] is SwitchInstruction si)) { return(false); } if (!NullableLiftingTransform.MatchGetValueOrDefault(si.Value, tmp)) { return(false); } switchInst = si; break; } default: { return(false); } } newSwitch = BuildLiftedSwitch(nullCaseBlock, switchInst, switchValue); return(true); }