Exemplo n.º 1
0
        IfInstruction HandleConditionalOperator(IfInstruction inst)
        {
            // if (cond) stloc (A, V1) else stloc (A, V2) --> stloc (A, if (cond) V1 else V2)
            Block trueInst = inst.TrueInst as Block;

            if (trueInst == null || trueInst.Instructions.Count != 1)
            {
                return(inst);
            }
            Block falseInst = inst.FalseInst as Block;

            if (falseInst == null || falseInst.Instructions.Count != 1)
            {
                return(inst);
            }
            ILVariable    v;
            ILInstruction value1, value2;

            if (trueInst.Instructions[0].MatchStLoc(out v, out value1) && falseInst.Instructions[0].MatchStLoc(v, out value2))
            {
                context.Step("conditional operator", inst);
                var newIf = new IfInstruction(Comp.LogicNot(inst.Condition), value2, value1);
                newIf.AddILRange(inst);
                inst.ReplaceWith(new StLoc(v, newIf));
                context.RequestRerun();                  // trigger potential inlining of the newly created StLoc
                return(newIf);
            }
            return(inst);
        }
Exemplo n.º 2
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);
        }