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); }
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); }