/// <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").Count() > 0 ? 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); }
/// <summary> /// Протянуть if с метками /// </summary> /// <param name="findInstruction">Инструкция которую мы ищем</param> /// <param name="instructions">Набор наших инструкций</param> /// <returns> /// Вернет измененные инструкции если меткок if не более двух /// </returns> private static List <Instruction> StretchIFWithLabel(Instruction findInstruction, List <Instruction> instructions) { int 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); } int findIndexGoto = instructions.IndexOf(instructions.Where(x => instructions[findIndexIf].Label == x.Argument1 && x.Operation == "goto").ElementAt(0)); wasChanged = true; if (instructions[findIndexIf + 1].Label == "") { instructions[findIndexGoto] = new Instruction("", instructions[findIndexIf].Operation, instructions[findIndexIf].Argument1, instructions[findIndexIf].Argument2, instructions[findIndexIf].Result); var tmp = ThreeAddressCodeTmp.GenTmpLabel(); instructions[findIndexIf] = new Instruction(tmp, "noop", "", "", ""); instructions.Insert(findIndexGoto + 1, new Instruction("", "goto", tmp, "", "")); } else { instructions[findIndexGoto] = new Instruction("", instructions[findIndexIf].Operation, instructions[findIndexIf].Argument1, instructions[findIndexIf].Argument2, instructions[findIndexIf].Result); var tmp = instructions[findIndexIf + 1].Label; instructions[findIndexIf] = new Instruction("", "noop", "", "", ""); instructions.Insert(findIndexGoto + 1, new Instruction("", "goto", tmp, "", "")); } return(instructions); }
// устранение переходов через переходы (пример из презентации Opt5.pdf слайд 32) public static (bool wasChanged, IReadOnlyList <Instruction> instructions) RemoveGotoThroughGoto(IReadOnlyList <Instruction> instructions) { if (instructions is null) { throw new ArgumentNullException("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") && uint.TryParse(com2.Label.Substring(1), out _) ? "" : com2.Label; newInstructions.Add(new Instruction(label, com2.Operation, com2.Argument1, com2.Argument2, com2.Result)); newInstructions.Add(com3.Copy()); wasChanged = true; i += 3; continue; } } newInstructions.Add(instructions[i].Copy()); } return(wasChanged, newInstructions); }
// устранение переходов через переходы (experimental) #region /*public static Tuple<bool, List<Instruction>> RemoveGotoThroughGoto(List<Instruction> instructions) * { * if (instructions is null) * throw new ArgumentNullException("instructions is null"); * * bool isChange = false; * var newInstructions = new List<Instruction>(); * * for (int i = 0; i < instructions.Count; ++i) * { * var com0 = instructions[i]; * if (instructions[i].Operation == "ifgoto" && 4 <= (instructions.Count - i)) * { * var com1 = instructions[i + 1]; * var com2 = instructions[i + 2]; * * // * if (com1.Operation == "goto" && com1.Label == "" && com2.Operation != "noop" && com0.Argument2 == com2.Label) * { * // search end label with "noop" operation * var endLabelIndex = FindLabelIndex(instructions, i + 2, com1.Argument1); * if (0 < endLabelIndex || endLabelIndex < instructions.Count || instructions[endLabelIndex].Operation == "noop") * { * // * string tmpName = ThreeAddressCodeTmp.GenTmpName(); * newInstructions.Add(new Instruction(com0.Label, "EQUAL", "False", com0.Argument1, tmpName)); // операция отрицания через EQUAL * newInstructions.Add(new Instruction("", "ifgoto", tmpName, com1.Argument1, "")); * * // copy instructions for true branch * newInstructions.Add(new Instruction("", com2.Operation, com2.Argument1, com2.Argument2, com2.Result)); * for (int k = i + 3; k < endLabelIndex; ++k) * { * var bla = instructions[k]; * newInstructions.Add(new Instruction(bla.Label, bla.Operation, bla.Argument1, bla.Argument2, bla.Result)); * } * * var endLabel = instructions[endLabelIndex]; * newInstructions.Add(new Instruction(endLabel.Label, endLabel.Operation, endLabel.Argument1, endLabel.Argument2, endLabel.Result)); * i = endLabelIndex; * isChange = true; * continue; * } * } * } * * newInstructions.Add(new Instruction(com0.Label, com0.Operation, com0.Argument1, com0.Argument2, com0.Result)); * } * * return Tuple.Create(isChange, newInstructions); * }*/ #endregion // устранение переходов через переходы (пример из презентации Opt5.pdf слайд 32) public static Tuple <bool, List <Instruction> > RemoveGotoThroughGoto(List <Instruction> instructions) { if (instructions is null) { throw new ArgumentNullException("instructions is null"); } bool isChange = false; var newInstructions = new List <Instruction>(); for (int 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) { string tmpName = ThreeAddressCodeTmp.GenTmpName(); newInstructions.Add(new Instruction(com0.Label, "NOT", com0.Argument1, "", tmpName)); newInstructions.Add(new Instruction("", "ifgoto", tmpName, com3.Label, "")); newInstructions.Add(new Instruction("", com2.Operation, com2.Argument1, com2.Argument2, com2.Result)); newInstructions.Add(new Instruction(com3.Label, com3.Operation, com3.Argument1, com3.Argument2, com3.Result)); isChange = true; i += 3; continue; } } newInstructions.Add(new Instruction(instructions[i].Label, instructions[i].Operation, instructions[i].Argument1, instructions[i].Argument2, instructions[i].Result)); } return(Tuple.Create(isChange, newInstructions)); }