static void SetResult(ILExpression expr, ILExpression n) { // IL ranges from removed nodes are assigned to the new operator expression var removednodes = expr.GetSelfAndChildrenRecursive <ILExpression>().Except(n.GetSelfAndChildrenRecursive <ILExpression>()); n.ILRanges.AddRange(removednodes.SelectMany(el => el.ILRanges)); // the new expression is wrapped in a container so that negations aren't pushed through lifted comparison operations expr.Code = ILCode.Wrap; expr.Arguments.Clear(); expr.Arguments.Add(n); expr.ILRanges.Clear(); expr.InferredType = n.InferredType; }
/// <summary> /// Determines whether it is safe to move 'expressionBeingMoved' past 'expr' /// </summary> bool IsSafeForInlineOver(ILExpression expr, ILExpression expressionBeingMoved) { switch (expr.Code) { case ILCode.Ldloc: ILVariable loadedVar = (ILVariable)expr.Operand; if (numLdloca.GetOrDefault(loadedVar) != 0) { // abort, inlining is not possible return(false); } foreach (ILExpression potentialStore in expressionBeingMoved.GetSelfAndChildrenRecursive <ILExpression>()) { if (potentialStore.Code == ILCode.Stloc && potentialStore.Operand == loadedVar) { return(false); } } // the expression is loading a non-forbidden variable return(true); case ILCode.Ldloca: case ILCode.Ldflda: case ILCode.Ldsflda: case ILCode.Ldelema: case ILCode.AddressOf: case ILCode.ValueOf: case ILCode.NullableOf: // address-loading instructions are safe if their arguments are safe foreach (ILExpression arg in expr.Arguments) { if (!IsSafeForInlineOver(arg, expressionBeingMoved)) { return(false); } } return(true); default: // instructions with no side-effects are safe (except for Ldloc and Ldloca which are handled separately) return(expr.HasNoSideEffects()); } }