Beispiel #1
0
        static Leave CombineExits(Block block)
        {
            if (!(block.Instructions.SecondToLastOrDefault() is IfInstruction ifInst && block.Instructions.LastOrDefault() is Leave leaveElse))
            {
                return(null);
            }
            if (!ifInst.FalseInst.MatchNop())
            {
                return(null);
            }
            // try to unwrap true branch to single instruction:
            var trueInstruction = Block.Unwrap(ifInst.TrueInst);

            // if the true branch is a block with multiple instructions:
            // try to apply the combine exits transform to the nested block
            // and then continue on that transformed block.
            // Example:
            // if (cond) {
            //   if (cond2) {
            //     leave (value)
            //   }
            //   leave (value2)
            // }
            // leave (value3)
            // =>
            // leave (if (cond) value else if (cond2) value2 else value3)
            if (trueInstruction is Block nestedBlock && nestedBlock.Instructions.Count == 2)
            {
                trueInstruction = CombineExits(nestedBlock);
            }
            if (!(trueInstruction is Leave leave))
            {
                return(null);
            }
            if (!(leave.IsLeavingFunction && leaveElse.IsLeavingFunction))
            {
                return(null);
            }
            if (leave.Value.MatchNop() || leaveElse.Value.MatchNop())
            {
                return(null);
            }
            // if (cond) {
            //   leave (value)
            // }
            // leave (elseValue)
            // =>
            // leave (if (cond) value else elseValue)
            IfInstruction value = new IfInstruction(ifInst.Condition, leave.Value, leaveElse.Value);

            value.AddILRange(ifInst);
            Leave combinedLeave = new Leave(leave.TargetContainer, value);

            combinedLeave.AddILRange(leaveElse);
            combinedLeave.AddILRange(leave);
            ifInst.ReplaceWith(combinedLeave);
            block.Instructions.RemoveAt(combinedLeave.ChildIndex + 1);
            return(combinedLeave);
        }