// устранение переходов через переходы (пример из презентации Opt5.pdf слайд 32) public static (bool wasChanged, IReadOnlyList <Instruction> instructions) RemoveGotoThroughGoto(IReadOnlyList <Instruction> instructions) { if (instructions is null) { throw new ArgumentNullException(nameof(instructions), "instructions is null"); } var wasChanged = false; var newInstructions = new List <Instruction>(); for (var i = 0; i < instructions.Count; ++i) { if (instructions[i].Operation == "ifgoto" && 4 <= (instructions.Count - i)) { var com0 = instructions[i]; var com1 = instructions[i + 1]; var com2 = instructions[i + 2]; var com3 = instructions[i + 3]; // только одна операция if (com1.Operation == "goto" && com1.Label == "" && com2.Operation != "noop" && com0.Argument2 == com2.Label && com1.Argument1 == com3.Label) { var tmpName = ThreeAddressCodeTmp.GenTmpName(); newInstructions.Add(new Instruction(com0.Label, "NOT", com0.Argument1, "", tmpName)); newInstructions.Add(new Instruction("", "ifgoto", tmpName, com3.Label, "")); var label = com2.Label.StartsWith("L", StringComparison.Ordinal) && uint.TryParse(com2.Label[1..], out _) ? "" : com2.Label;
/// <summary> /// Протянуть if с метками /// </summary> /// <param name="findInstruction">Инструкция, которую мы ищем</param> /// <param name="instructions">Набор наших инструкций</param> /// <returns> /// Вернёт изменённые инструкции, если меток if не более двух /// </returns> private static List <Instruction> PropagateIfWithLabel(Instruction findInstruction, List <Instruction> instructions) { var findIndexIf = instructions.IndexOf(findInstruction); if (findIndexIf == -1 || instructions.Where(x => instructions[findIndexIf].Label == x.Argument1 && x.Operation == "goto" && x.ToString() != instructions[findIndexIf].ToString()).Count() > 1) { return(instructions); } var findItem = instructions.Where(x => instructions[findIndexIf].Label == x.Argument1 && x.Operation == "goto").Any() ? instructions.Where(x => instructions[findIndexIf].Label == x.Argument1 && x.Operation == "goto").ElementAt(0) : new Instruction("", "", "", "", ""); var findIndexGoto = instructions.IndexOf(findItem); if (findIndexGoto == -1) { return(instructions); } wasChanged = true; instructions[findIndexGoto] = new Instruction("", instructions[findIndexIf].Operation, instructions[findIndexIf].Argument1, instructions[findIndexIf].Argument2, instructions[findIndexIf].Result); instructions.RemoveAt(findIndexIf); if (instructions[findIndexIf].Label == "") { instructions[findIndexIf].Label = ThreeAddressCodeTmp.GenTmpLabel(); } instructions.Insert(findIndexGoto + 1, new Instruction("", "goto", instructions[findIndexIf].Label, "", "")); return(instructions); }