/// <summary> /// Adds a new section to the Sections list. /// /// If the instruction is a branch instruction, unify the new section with an existing section /// that also branches to the same target. /// </summary> void AddSection(LongSet values, ILInstruction inst) { if (values.IsEmpty) { return; } Block targetBlock; if (inst.MatchBranch(out targetBlock)) { int index; if (targetBlockToSectionIndex.TryGetValue(targetBlock, out index)) { Sections[index] = new KeyValuePair <LongSet, ILInstruction>( Sections[index].Key.UnionWith(values), inst ); } else { targetBlockToSectionIndex.Add(targetBlock, Sections.Count); Sections.Add(new KeyValuePair <LongSet, ILInstruction>(values, inst)); } } else { Sections.Add(new KeyValuePair <LongSet, ILInstruction>(values, inst)); } }
bool ShouldSwapIfTargets(ILInstruction inst1, ILInstruction inst2) { Block block1 = null, block2 = null; if (inst1.MatchBranch(out block1) && inst2.MatchBranch(out block2)) { // prefer arranging stuff in IL order return(block1.ILRange.Start > block2.ILRange.Start); } BlockContainer container1, container2; if (inst1.MatchLeave(out container1) && container1.Parent is TryInstruction) { // 'leave tryBlock' is considered to have a later target than // any branch within the container, and also a later target // than a return instruction. // This is necessary to avoid "goto" statements in the // ExceptionHandling.ConditionalReturnInThrow test. if (!inst2.MatchLeave(out container2)) { container2 = block2?.Parent as BlockContainer; } return(container2 == null || container2.IsDescendantOf(container1)); } if (inst1.MatchBranch(out block1) && inst2.MatchLeave(out container2) && block1.IncomingEdgeCount > 1) { // if (..) goto x; leave c; // Unless x can be inlined, it's better to swap the order if the 'leave' // has a chance to turn into a 'break;' or 'return;' if (container2.Parent is ILFunction) { return(true); // return } if (container2.EntryPoint.IncomingEdgeCount > 1) { // break return(BlockContainer.FindClosestContainer(inst2) == container2); } } return(false); }
/// <summary> /// Analyzes the tail end (last two instructions) of a block. /// </summary> /// <remarks> /// Sets <c>switchVar</c> and <c>defaultInstruction</c> if they are null, /// and adds found sections to <c>sectionLabels</c> and <c>sectionInstructions</c>. /// /// If the function returns false, <c>sectionLabels</c> and <c>sectionInstructions</c> are unmodified. /// </remarks> /// <param name="block">The block to analyze.</param> /// <param name="inputValues">The possible values of the "interesting" variable /// when control flow reaches this block.</param> /// <param name="tailOnly">If true, analyze only the tail (last two instructions). /// If false, analyze the whole block.</param> bool AnalyzeBlock(Block block, LongSet inputValues, bool tailOnly = false) { if (tailOnly) { Debug.Assert(block == rootBlock); if (block.Instructions.Count < 2) { return(false); } } else { Debug.Assert(switchVar != null); // switchVar should always be determined by the top-level call if (block.IncomingEdgeCount != 1 || block == rootBlock) { return(false); // for now, let's only consider if-structures that form a tree } if (block.Instructions.Count != 2) { return(false); } if (block.Parent != rootBlock.Parent) { return(false); // all blocks should belong to the same container } } var inst = block.Instructions[block.Instructions.Count - 2]; ILInstruction condition, trueInst; LongSet trueValues; if (inst.MatchIfInstruction(out condition, out trueInst) && AnalyzeCondition(condition, out trueValues) ) { trueValues = trueValues.IntersectWith(inputValues); Block trueBlock; if (trueInst.MatchBranch(out trueBlock) && AnalyzeBlock(trueBlock, trueValues)) { // OK, true block was further analyzed. InnerBlocks.Add(trueBlock); } else { // Create switch section for trueInst. AddSection(trueValues, trueInst); } } else if (inst.OpCode == OpCode.SwitchInstruction) { if (AnalyzeSwitch((SwitchInstruction)inst, inputValues, out trueValues)) { ContainsILSwitch = true; // OK } else // switch analysis failed (e.g. switchVar mismatch) { return(false); } } else // unknown inst { return(false); } var remainingValues = inputValues.ExceptWith(trueValues); ILInstruction falseInst = block.Instructions.Last(); Block falseBlock; if (falseInst.MatchBranch(out falseBlock) && AnalyzeBlock(falseBlock, remainingValues)) { // OK, false block was further analyzed. InnerBlocks.Add(falseBlock); } else { // Create switch section for falseInst. AddSection(remainingValues, falseInst); } return(true); }