/// <summary> /// Group input into a set of blocks that can be later arbitraliby schufled. /// The method adds necessary branches to make control flow between blocks /// explicit and thus order independent. /// </summary> /// public static void SplitToBasicBlocks(ILBlock block, bool reducebranches = false) { int nextLabelIndex = 0; List <ILNode> basicBlocks = new List <ILNode>(); ILLabel entryLabel = block.Body.FirstOrDefault() as ILLabel ?? ILLabel.Generate("Block_", nextLabelIndex++); ILBasicBlock basicBlock = new ILBasicBlock(); basicBlocks.Add(basicBlock); basicBlock.Body.Add(entryLabel); block.EntryGoto = new ILExpression(GMCode.B, entryLabel); if (block.Body.Count > 0) { if (block.Body[0] != entryLabel) { basicBlock.Body.Add(block.Body[0]); } for (int i = 1; i < block.Body.Count; i++) { ILNode lastNode = block.Body[i - 1]; ILNode currNode = block.Body[i]; // Start a new basic block if necessary if (currNode is ILLabel || lastNode.IsConditionalControlFlow() || lastNode.IsUnconditionalControlFlow()) { // Try to reuse the label ILLabel label = currNode as ILLabel ?? ILLabel.Generate("Block_", nextLabelIndex++); // Terminate the last block if (!lastNode.IsUnconditionalControlFlow()) { // Explicit branch from one block to other basicBlock.Body.Add(new ILExpression(GMCode.B, label)); } // Start the new block basicBlock = new ILBasicBlock(); basicBlocks.Add(basicBlock); basicBlock.Body.Add(label); // Add the node to the basic block if (currNode != label) { basicBlock.Body.Add(currNode); } } else { basicBlock.Body.Add(currNode); } } } block.Body = basicBlocks; if (reducebranches) { if (basicBlocks.Count > 0) { for (int i = 0; i < block.Body.Count; i++) { ILBasicBlock bb = block.Body[i] as ILBasicBlock; if (bb == null) { continue; } ILLabel trueLabel; ILLabel falseLabel; if (bb.MatchLastAndBr(GMCode.Bf, out falseLabel, out trueLabel)) { ILExpression bf = bb.Body[bb.Body.Count - 2] as ILExpression; ILExpression b = bb.Body[bb.Body.Count - 1] as ILExpression; bf.Code = GMCode.Bt; b.Operand = falseLabel; bf.Operand = trueLabel; } } } } return; }