// устранение переходов через переходы (пример из презентации 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);
        }