Example #1
0
        public bool JoinBasicBlocks(List<ILNode> body, ILBasicBlock head, int pos)
        {
            ILLabel nextLabel;
            ILBasicBlock nextBB;
            if (!head.Body.ElementAtOrDefault(head.Body.Count - 2).IsConditionalControlFlow() &&
                head.Body.Last().Match(ILCode.Br, out nextLabel) &&
                labelGlobalRefCount[nextLabel] == 1 &&
                labelToBasicBlock.TryGetValue(nextLabel, out nextBB) &&
                body.Contains(nextBB) &&
                nextBB.Body.First() == nextLabel &&
                !nextBB.Body.OfType<ILTryCatchBlock>().Any()
               )
            {
                var tail = head.Body.RemoveTail(ILCode.Br);
                tail[0].AddSelfAndChildrenRecursiveILRanges(nextBB.ILRanges);
                nextBB.Body[0].AddSelfAndChildrenRecursiveILRanges(nextBB.ILRanges);
                nextBB.Body.RemoveAt(0);  // Remove label
                if (head.Body.Count > 0)
                    head.Body[head.Body.Count - 1].EndILRanges.AddRange(nextBB.ILRanges);
                else
                    head.ILRanges.AddRange(nextBB.ILRanges);
                head.EndILRanges.AddRange(nextBB.EndILRanges);
                head.Body.AddRange(nextBB.Body);

                body.RemoveOrThrow(nextBB);
                return true;
            }
            return false;
        }
Example #2
0
		public bool InlineAllInBasicBlock(ILBasicBlock bb)
		{
			bool modified = false;
			List<ILNode> body = bb.Body;
			for(int i = 0; i < body.Count;) {
				ILVariable locVar;
				ILExpression expr;
				if (body[i].Match(ILCode.Stloc, out locVar, out expr) && InlineOneIfPossible(bb.Body, i, aggressive: false)) {
					modified = true;
					i = Math.Max(0, i - 1); // Go back one step
				} else {
					i++;
				}
			}
			return modified;
		}
Example #3
0
        public bool JoinBasicBlocks(IList <ILNode> body, ILBasicBlock head, int pos)
        {
            ILLabel      nextLabel;
            ILBasicBlock nextBB;

            if (!head.Body.ElementAtOrDefault(head.Body.Count - 2).IsConditionalControlFlow() &&
                head.Body.Last().Match(GMCode.B, out nextLabel) &&
                labelGlobalRefCount[nextLabel] == 1 &&
                labelToBasicBlock.TryGetValue(nextLabel, out nextBB) &&
                body.Contains(nextBB) &&
                nextBB.Body.First() == nextLabel
                )
            {
                head.Body.RemoveTail(GMCode.B);
                nextBB.Body.RemoveAt(0);  // Remove label
                foreach (var a in nextBB.Body)
                {
                    head.Body.Add(a);                            // head.Body.AddRange(nextBB.Body);
                }
                body.RemoveOrThrow(nextBB);
                return(true);
            }
            return(false);
        }
Example #4
0
        // special case.  Since we are modifying the block alot in one go, lets try to do the entire block at once
        public static bool RunOptimizationAndRestart(this ILBasicBlock bb, params Func <IList <ILNode>, ILExpression, int, bool>[] optimizations)
        {
            bool           modified = false;
            IList <ILNode> body     = bb.Body;

            for (int i = bb.Body.Count - 1; i >= 0; i--)
            {
                ILExpression expr = bb.Body.ElementAtOrDefault(i) as ILExpression;
                if (expr != null) // && optimization(bb.Body, expr, i))
                {
                    bool test = false;
                    while (CheckBlockBody(body, expr, i, optimizations))
                    {
                        test = true;
                    }
                    modified |= test;
                    if (test)
                    {
                        i = bb.Body.Count;      // backup
                    }
                }
            }
            return(modified);
        }
Example #5
0
 protected virtual ILBasicBlock VisitBasicBlock(ILBasicBlock basicBlock)
 {
     foreach (var child in basicBlock.GetChildren())
         Visit(child);
     return basicBlock;
 }
Example #6
0
        // This is before the expression is processed, so ILValue's and constants havn't been assigned

        public bool SimplifyTernaryOperator(IList <ILNode> body, ILBasicBlock head, int pos)
        {
            Debug.Assert(body.Contains(head));
            //    Debug.Assert((head.Body[0] as ILLabel).Name != "Block_54");
            //     Debug.Assert((head.Body[0] as ILLabel).Name != "L1257");
            ILExpression condExpr;
            ILLabel      trueLabel;
            ILLabel      falseLabel;

            ILExpression trueExpr;
            ILLabel      trueFall;

            ILExpression falseExpr;
            ILLabel      falseFall;


            ILLabel finalFalseFall;
            ILLabel finalTrueFall;

            if (head.MatchLastAndBr(GMCode.Bt, out trueLabel, out condExpr, out falseLabel) &&
                labelGlobalRefCount[trueLabel] == 1 &&
                labelGlobalRefCount[falseLabel] == 1 &&
                labelToBasicBlock[trueLabel].MatchSingleAndBr(GMCode.Push, out trueExpr, out trueFall) &&
                labelToBasicBlock[falseLabel].MatchSingleAndBr(GMCode.Push, out falseExpr, out falseFall) &&
                trueFall == falseFall &&
                body.Contains(labelToBasicBlock[trueFall])
                // finalFall.Code == GMCode.Pop
                ) // (finalFall == null || finalFall.Code == GMCode.Pop)
            {
                ILBasicBlock trueBlock  = labelToBasicBlock[trueLabel];
                ILBasicBlock falseBlock = labelToBasicBlock[falseLabel];
                ILBasicBlock fallBlock  = labelToBasicBlock[trueFall];
                ILExpression newExpr    = ResolveTernaryExpression(condExpr, trueExpr, falseExpr);

                head.Body.RemoveTail(GMCode.Bt, GMCode.B);
                body.RemoveOrThrow(trueBlock);
                body.RemoveOrThrow(falseBlock);
                IList <ILExpression> finalFall;
                // figure out if its a wierd short or not
                if (fallBlock.MatchSingleAndBr(GMCode.Bt, out finalTrueFall, out finalFall, out finalFalseFall) &&
                    finalFall.Count == 0)
                {
                    head.Body.Add(new ILExpression(GMCode.Bt, finalTrueFall, newExpr));
                    if (labelGlobalRefCount[trueFall] == 2)
                    {
                        body.RemoveOrThrow(fallBlock);
                    }
                }
                else if (fallBlock.Body.Count == 2)  // wierd break,
                {
                    finalFalseFall = fallBlock.GotoLabel();
                    head.Body.Add(new ILExpression(GMCode.Push, null, newExpr)); // we want to push it for next pass
                    if (labelGlobalRefCount[trueFall] == 2)
                    {
                        body.RemoveOrThrow(fallBlock);
                    }
                }
                else if (fallBlock.MatchAt(1, GMCode.Pop))  // generated? wierd instance?
                {
                    finalFalseFall = fallBlock.EntryLabel();
                    error.Info("Wierd Generated Pop here", newExpr);
                    head.Body.Add(new ILExpression(GMCode.Push, null, newExpr));
                    // It should be combined in JoinBasicBlocks function
                    // so don't remove failblock
                }
                else if (fallBlock.MatchAt(1, GMCode.Assign, out finalFall)) // This is an assignment case and unsure what its for
                {
                    finalFall.Add(newExpr);
                    finalFalseFall = fallBlock.EntryLabel();
                }
                if (finalFalseFall == null && fallBlock.MatchLastAt(1, GMCode.Ret))
                {
                    head.Body.Add(new ILExpression(GMCode.Ret, null));
                }
                else
                {
                    Debug.Assert(finalFalseFall != null);
                    head.Body.Add(new ILExpression(GMCode.B, finalFalseFall));
                }
                return(true);
            }
            return(false);
        }
Example #7
0
 public static ILNode First(this ILBasicBlock bb)
 {
     return(bb.Body.First());
 }
Example #8
0
        public bool DetectSwitchAndConvertToBranches(IList <ILNode> body, ILBasicBlock head, int pos)
        {
            ILExpression condition;
            ILLabel      trueLabel;
            ILLabel      fallThough;

            // REMEMBER:  The searching goes backwards, so we find the LAST case here, so here is the problem
            // Evey time we run this, we have to search for the first block of the case statement backwards and if
            // the push var is not resolved, we have to drop out... evey single time till the push IS resolved
            // so be sure to run this at the bottom of the decision chain.  Its fine if the push is a simple var
            // but I can bet cash this runs 2-3 times if the push is some kind of expression like 5 + (3 % switch_var))
            // we could change the way the optimizing loop works by going from the start and building a que of things
            // to remove, delete or change hummm...  Take longer but it would make building this functions MUCH simpler
            if (MatchSwitchCase(head, out trueLabel, out fallThough, out condition))  // && head.MatchLastAt(6, GMCode.Push,out switch_expr))
            {
                List <ILBasicBlock> caseBlocks = GetAllCaseBlocks(body, head, pos, out condition, out fallThough);

                foreach (var bb in caseBlocks) // replace the dup statements
                {
                    Debug.Assert(bb.MatchLastAt(5, GMCode.Dup));
                    bb.Body[bb.Body.Count - 5] = new ILExpression(GMCode.Push, null, condition);
                    ILExpression expr = bb.Body[bb.Body.Count - 3] as ILExpression;
                    //   expr.Code = GMCode.Case; // conver the equals to a case
                }
                // search the blocks for ending popz's
                HashSet <ILBasicBlock> blocks_done = new HashSet <ILBasicBlock>();
                Stack <ILBasicBlock>   agenda      = new Stack <ILBasicBlock>(caseBlocks);
                while (agenda.Count > 0)
                {
                    ILBasicBlock bb = agenda.Pop();
                    if (blocks_done.Contains(bb))
                    {
                        continue;                           // already did it
                    }
                    ILExpression popz = bb.Body.OfType <ILExpression>().Where(e => e.Code == GMCode.Popz).SingleOrDefault();
                    if (popz != null)
                    {
                        bb.Body.Remove(popz); // remove it
                        blocks_done.Add(bb);
                    }
                    else
                    {
                        ILLabel exit = bb.OperandLabelLastAt(0);
                        if (exit != null && !blocks_done.Contains(labelToBasicBlock[exit]))
                        {
                            agenda.Push(labelToBasicBlock[exit]);
                        }
                        exit = bb.OperandLabelLastAt(1); // check if we have a bt or something
                        if (exit != null && !blocks_done.Contains(labelToBasicBlock[exit]))
                        {
                            agenda.Push(labelToBasicBlock[exit]);
                        }
                    }
                }


                return(true);
            }


            return(false);
        }
Example #9
0
        public bool MatchRepeatStructure(IList <ILNode> body, ILBasicBlock head, int pos)
        {
            ILExpression rcount;
            ILExpression pushZero;
            int          dupMode = 0;
            ILLabel      fallthough;
            ILLabel      repeatBlock;

            if (head.MatchLastAt(6, GMCode.Push, out rcount) && // header for a repeat, sets it up
                head.MatchLastAt(5, GMCode.Dup, out dupMode) &&
                head.MatchLastAt(4, GMCode.Push, out pushZero) &&
                pushZero.Code == GMCode.Constant && (pushZero.Operand as ILValue).IntValue == 0 &&
                head.MatchLastAt(3, GMCode.Sle) &&
                head.MatchLastAndBr(GMCode.Bt, out fallthough, out repeatBlock))
            {
                // We have to seeperate the head from other bits of the block
                // humm, mabye have to put this in the general build routine like we did with push V:(
                head.Body.RemoveTail(GMCode.Push, GMCode.Dup, GMCode.Push, GMCode.Sle, GMCode.Bt, GMCode.B);

                ILBasicBlock header_block;
                ILLabel      header_label;
                if (head.Body.Count == 1)
                {// The head only has the label, so its safe to use this as the header
                    header_block = head;
                    header_label = head.EntryLabel();
                }
                else
                {
                    header_label = ILLabel.Generate("R");
                    // We have to seperate the head.
                    header_block = new ILBasicBlock();
                    head.Body.Add(new ILExpression(GMCode.B, header_label));
                    header_block.Body.Add(header_label);
                    body.Insert(pos + 1, header_block); // insert before the block so it looks in order
                }

                header_block.Body.Add(new ILExpression(GMCode.Repeat, repeatBlock, rcount));
                header_block.Body.Add(new ILExpression(GMCode.B, fallthough));

                // NOW we got to find the block that matches

                ILExpression subOneConstant;
                ILLabel      footerContinue, footerfallThough;

                /*
                 *
                 *
                 * while (!(start.MatchLastAt(5, GMCode.Push, out subOneConstant) &&
                 *   subOneConstant.Code == GMCode.Constant && (subOneConstant.Operand as ILValue).IntValue == 1 &&
                 *   start.MatchLastAt(4, GMCode.Sub) &&
                 *   start.MatchLastAt(3, GMCode.Dup, out dupMode) && dupMode == 0 &&
                 *  start.MatchLastAndBr(GMCode.Bt, out footerContinue, out footerfallThough)))
                 * {
                 *  ILLabel next = start.GotoLabel();
                 *  start = labelToBasicBlock[next];
                 * }
                 */// ok, on more complicated stuf like an internal loop, this f***s up, so we are going to do a hack
                // The popz fallthough comes RIGHT after the decrment for the repeate loop, so we are going to move up one from that
                // then check it
                ILBasicBlock popzBlock = labelToBasicBlock[fallthough]; //
                Debug.Assert((popzBlock.Body[1] as ILExpression).Code == GMCode.Popz);
                popzBlock.Body.RemoveAt(1);                             // remove the popz
                ILBasicBlock footer = body[body.IndexOf(popzBlock) - 1] as ILBasicBlock;

                if (footer.MatchLastAt(5, GMCode.Push, out subOneConstant) &&
                    subOneConstant.Code == GMCode.Constant && (subOneConstant.Operand as ILValue).IntValue == 1 &&
                    footer.MatchLastAt(4, GMCode.Sub) &&
                    footer.MatchLastAt(3, GMCode.Dup, out dupMode) && dupMode == 0 &&
                    footer.MatchLastAndBr(GMCode.Bt, out footerContinue, out footerfallThough))
                {
                    Debug.Assert(footerfallThough == fallthough && repeatBlock == footerContinue); // sanity check
                    footer.Body.RemoveTail(GMCode.Push, GMCode.Sub, GMCode.Dup, GMCode.Bt, GMCode.B);
                    footer.Body.Add(new ILExpression(GMCode.B, header_block.EntryLabel()));
                }
                else
                {
                    throw new Exception("F**k me");
                }


                // Found!  Some sanity checks thogh

                /* MAJOR BUG UNFINSHED WORK ALERT!
                 * Ok, so this isn't used in undertale, but at some point, somone might want to do a break or continue
                 * Inside of a repeat statment.  I have NO clue why though, use a while?
                 * Anyway, if thats the case then you MUST change the target label of evetyhing going to start, to fallthough, otherwise
                 * the goto cleaner will start screaming at you and do alot of weird stuff
                 * fyi, like the with statments, I am converting this thing into a while loop so I don't have to have
                 * custom loop graph code for these things
                 * So, for now? convert start to loop back to head, head jumps to fallthough, and we remove the popz from the fall though
                 */
                //   ILLabel.Generate("Block_", nextLabelIndex++);



                return(true);
            }
            return(false);
        }
Example #10
0
        /// <summary>
        /// Group input into a set of blocks that can be later arbitraliby schufled.
        /// The method adds necessary branches to make control flow between blocks
        /// explicit and thus order independent.
        /// </summary>
        ///
        public static void SplitToBasicBlocks(ILBlock block, bool reducebranches = false)
        {
            int           nextLabelIndex = 0;
            List <ILNode> basicBlocks    = new List <ILNode>();

            ILLabel      entryLabel = block.Body.FirstOrDefault() as ILLabel ?? ILLabel.Generate("Block_", nextLabelIndex++);
            ILBasicBlock basicBlock = new ILBasicBlock();

            basicBlocks.Add(basicBlock);
            basicBlock.Body.Add(entryLabel);
            block.EntryGoto = new ILExpression(GMCode.B, entryLabel);

            if (block.Body.Count > 0)
            {
                if (block.Body[0] != entryLabel)
                {
                    basicBlock.Body.Add(block.Body[0]);
                }
                for (int i = 1; i < block.Body.Count; i++)
                {
                    ILNode lastNode = block.Body[i - 1];
                    ILNode currNode = block.Body[i];

                    // Start a new basic block if necessary
                    if (currNode is ILLabel ||
                        lastNode.IsConditionalControlFlow() ||
                        lastNode.IsUnconditionalControlFlow())
                    {
                        // Try to reuse the label
                        ILLabel label = currNode as ILLabel ?? ILLabel.Generate("Block_", nextLabelIndex++);

                        // Terminate the last block
                        if (!lastNode.IsUnconditionalControlFlow())
                        {
                            // Explicit branch from one block to other
                            basicBlock.Body.Add(new ILExpression(GMCode.B, label));
                        }

                        // Start the new block
                        basicBlock = new ILBasicBlock();
                        basicBlocks.Add(basicBlock);
                        basicBlock.Body.Add(label);

                        // Add the node to the basic block
                        if (currNode != label)
                        {
                            basicBlock.Body.Add(currNode);
                        }
                    }
                    else
                    {
                        basicBlock.Body.Add(currNode);
                    }
                }
            }

            block.Body = basicBlocks;

            if (reducebranches)
            {
                if (basicBlocks.Count > 0)
                {
                    for (int i = 0; i < block.Body.Count; i++)
                    {
                        ILBasicBlock bb = block.Body[i] as ILBasicBlock;
                        if (bb == null)
                        {
                            continue;
                        }
                        ILLabel trueLabel;
                        ILLabel falseLabel;
                        if (bb.MatchLastAndBr(GMCode.Bf, out falseLabel, out trueLabel))
                        {
                            ILExpression bf = bb.Body[bb.Body.Count - 2] as ILExpression;
                            ILExpression b  = bb.Body[bb.Body.Count - 1] as ILExpression;
                            bf.Code    = GMCode.Bt;
                            b.Operand  = falseLabel;
                            bf.Operand = trueLabel;
                        }
                    }
                }
            }
            return;
        }
Example #11
0
        List <ILNode> FindConditions(HashSet <ControlFlowNode> scope, ControlFlowNode entryNode)
        {
            List <ILNode> result = new List <ILNode>();

            // Do not modify entry data
            scope = new HashSet <ControlFlowNode>(scope);

            Stack <ControlFlowNode> agenda = new Stack <ControlFlowNode>();

            agenda.Push(entryNode);
            while (agenda.Count > 0)
            {
                ControlFlowNode node = agenda.Pop();

                // Find a block that represents a simple condition
                if (scope.Contains(node))
                {
                    ILBasicBlock block = (ILBasicBlock)node.UserData;

                    {
                        IList <ILExpression> conditions;
                        ILLabel fallLabel;
                        // Switch
                        FakeSwitch fswitch;
                        if (block.MatchLastAndBr(GMCode.Switch, out fswitch, out conditions, out fallLabel))
                        {
                            ILSwitch ilSwitch = new ILSwitch()
                            {
                                Condition = fswitch.SwitchExpression
                            };
                            block.Body[block.Body.Count - 2] = ilSwitch; // replace it, nothing else needs to be done!
                            result.Add(block);                           // except add it to the result, DOLT

                            scope.RemoveOrThrow(node);                   // Remove the item so that it is not picked up as content

                            // Pull in code of cases
                            ControlFlowNode fallTarget = null;
                            labelToCfNode.TryGetValue(fallLabel, out fallTarget);

                            HashSet <ControlFlowNode> frontiers = new HashSet <ControlFlowNode>();
                            if (fallTarget != null)
                            {
                                frontiers.UnionWith(fallTarget.DominanceFrontier.Except(new[] { fallTarget }));
                            }

                            foreach (ILLabel condLabel in fswitch.CaseExpressions.Select(x => x.Value))
                            {
                                ControlFlowNode condTarget = null;
                                labelToCfNode.TryGetValue(condLabel, out condTarget);
                                if (condTarget != null)
                                {
                                    frontiers.UnionWith(condTarget.DominanceFrontier.Except(new[] { condTarget }));
                                }
                            }
                            for (int i = 0; i < fswitch.CaseExpressions.Count; i++)
                            {
                                ILLabel condLabel = fswitch.CaseExpressions[i].Value;

                                // Find or create new case block
                                ILSwitch.ILCase caseBlock = ilSwitch.Cases.FirstOrDefault(b => b.EntryGoto.Operand == condLabel);
                                if (caseBlock == null)
                                {
                                    caseBlock = new ILSwitch.ILCase()
                                    {
                                        Values    = new List <ILExpression>(),
                                        EntryGoto = new ILExpression(GMCode.B, condLabel)
                                    };
                                    ilSwitch.Cases.Add(caseBlock);

                                    ControlFlowNode condTarget = null;
                                    labelToCfNode.TryGetValue(condLabel, out condTarget);
                                    if (condTarget != null && !frontiers.Contains(condTarget))
                                    {
                                        HashSet <ControlFlowNode> content = FindDominatedNodes(scope, condTarget);
                                        scope.ExceptWith(content);
                                        foreach (var con in FindConditions(content, condTarget))
                                        {
                                            caseBlock.Body.Add(con);
                                        }
                                        //   caseBlock.Body.AddRange(FindConditions(content, condTarget));
                                        // Add explicit break which should not be used by default, but the goto removal might decide to use it
                                        caseBlock.Body.Add(new ILBasicBlock()
                                        {
                                            Body =
                                            {
                                                ILLabel.Generate("SwitchBreak",            (int)nextLabelIndex++),
                                                new ILExpression(GMCode.LoopOrSwitchBreak, null)
                                            }
                                        });
                                    }
                                }
                                caseBlock.Values.Add(fswitch.CaseExpressions[i].Key);
                            }

                            // Heuristis to determine if we want to use fallthough as default case
                            if (fallTarget != null && !frontiers.Contains(fallTarget))
                            {
                                HashSet <ControlFlowNode> content = FindDominatedNodes(scope, fallTarget);
                                if (content.Any())
                                {
                                    var caseBlock = new ILSwitch.ILCase()
                                    {
                                        EntryGoto = new ILExpression(GMCode.B, fallLabel)
                                    };
                                    ilSwitch.Cases.Add(caseBlock);
                                    block.Body.RemoveTail(GMCode.B);

                                    scope.ExceptWith(content);
                                    foreach (var con in FindConditions(content, fallTarget))
                                    {
                                        caseBlock.Body.Add(con);
                                    }

                                    // Add explicit break which should not be used by default, but the goto removal might decide to use it
                                    caseBlock.Body.Add(new ILBasicBlock()
                                    {
                                        Body =
                                        {
                                            ILLabel.Generate("SwitchBreak",            (int)nextLabelIndex++),
                                            new ILExpression(GMCode.LoopOrSwitchBreak, null)
                                        }
                                    });
                                }
                            }
                        }
                        //   Debug.Assert((block.Body.First() as ILLabel).Name != "L1938");
                        // Two-way branch
                        ILLabel trueLabel;
                        ILLabel falseLabel;
                        IList <ILExpression> condExprs;
                        if (block.MatchLastAndBr(GMCode.Bt, out trueLabel, out condExprs, out falseLabel) && // be sure to invert this condition
                            condExprs.Count > 0)     // its resolved
                        {
                            ILExpression   condExpr = condExprs[0];
                            IList <ILNode> body     = block.Body;
                            // this is a simple condition, skip anything short curiket for now
                            // Match a condition patern
                            // Convert the brtrue to ILCondition
                            ILCondition ilCond = new ILCondition()
                            {
                                Condition = condExpr, //code == GMCode.Bf ? condExpr : condExpr.NegateCondition(),
                                TrueBlock = new ILBlock()
                                {
                                    EntryGoto = new ILExpression(GMCode.B, trueLabel)
                                },
                                FalseBlock = new ILBlock()
                                {
                                    EntryGoto = new ILExpression(GMCode.B, falseLabel)
                                }
                            };
                            block.Body.RemoveTail(GMCode.Bt, GMCode.B);
                            block.Body.Add(ilCond);
                            result.Add(block);

                            // Remove the item immediately so that it is not picked up as content
                            scope.RemoveOrThrow(node);

                            ControlFlowNode trueTarget = null;
                            labelToCfNode.TryGetValue(trueLabel, out trueTarget);
                            ControlFlowNode falseTarget = null;
                            labelToCfNode.TryGetValue(falseLabel, out falseTarget);

                            // Pull in the conditional code
                            if (trueTarget != null && HasSingleEdgeEnteringBlock(trueTarget))
                            {
                                HashSet <ControlFlowNode> content = FindDominatedNodes(scope, trueTarget);
                                scope.ExceptWith(content);
                                foreach (var con in FindConditions(content, trueTarget))
                                {
                                    ilCond.TrueBlock.Body.Add(con);
                                }
                            }
                            if (falseTarget != null && HasSingleEdgeEnteringBlock(falseTarget))
                            {
                                HashSet <ControlFlowNode> content = FindDominatedNodes(scope, falseTarget);
                                scope.ExceptWith(content);
                                foreach (var con in FindConditions(content, falseTarget))
                                {
                                    ilCond.FalseBlock.Body.Add(con);
                                }
                            }
                        }
                    }

                    // Add the node now so that we have good ordering
                    if (scope.Contains(node))
                    {
                        result.Add((ILNode)node.UserData);
                        scope.Remove(node);
                    }
                }

                // depth-first traversal of dominator tree
                for (int i = node.DominatorTreeChildren.Count - 1; i >= 0; i--)
                {
                    agenda.Push(node.DominatorTreeChildren[i]);
                }
            }

            // Add whatever is left
            foreach (var node in scope)
            {
                result.Add((ILNode)node.UserData);
            }

            return(result);
        }
Example #12
0
        List <ILNode> FindLoops(HashSet <ControlFlowNode> scope, ControlFlowNode entryPoint, bool excludeEntryPoint)
        {
            List <ILNode> result = new List <ILNode>();

            // Do not modify entry data
            scope = new HashSet <ControlFlowNode>(scope);

            Queue <ControlFlowNode> agenda = new Queue <ControlFlowNode>();

            agenda.Enqueue(entryPoint);
            while (agenda.Count > 0)
            {
                ControlFlowNode node = agenda.Dequeue();

                // If the node is a loop header
                if (scope.Contains(node) &&
                    node.DominanceFrontier.Contains(node) &&
                    (node != entryPoint || !excludeEntryPoint))
                {
                    HashSet <ControlFlowNode> loopContents = FindLoopContent(scope, node);

                    // If the first expression is a loop condition
                    ILBasicBlock basicBlock = (ILBasicBlock)node.UserData;
                    ILExpression condExpr   = null;
                    ILLabel      trueLabel;
                    ILLabel      falseLabel;
                    // It has to be just brtrue - any preceding code would introduce goto
                    error.Assert(!basicBlock.MatchLastAndBr(GMCode.Bt, out trueLabel, out condExpr, out falseLabel),
                                 "Unrolled loop");
                    if (basicBlock.MatchLastAndBr(GMCode.Bt, out trueLabel, out condExpr, out falseLabel) ||
                        basicBlock.MatchLastAndBr(GMCode.Pushenv, out falseLabel, out condExpr, out trueLabel) || // built it the same way from the dissasembler, this needs inverted
                        basicBlock.MatchLastAndBr(GMCode.Repeat, out trueLabel, out condExpr, out falseLabel))    // repeate loop is built like a while
                    {
                        GMCode          loopType = (basicBlock.Body.ElementAt(basicBlock.Body.Count - 2) as ILExpression).Code;
                        ControlFlowNode trueTarget;
                        labelToCfNode.TryGetValue(trueLabel, out trueTarget);
                        ControlFlowNode falseTarget;
                        labelToCfNode.TryGetValue(falseLabel, out falseTarget);

                        // If one point inside the loop and the other outside
                        if ((!loopContents.Contains(trueTarget) && loopContents.Contains(falseTarget)) ||
                            (loopContents.Contains(trueTarget) && !loopContents.Contains(falseTarget)))
                        {
                            loopContents.RemoveOrThrow(node);
                            scope.RemoveOrThrow(node);

                            bool mustNegate = false;
                            if (loopContents.Contains(falseTarget) || falseTarget == node)
                            {
                                // Negate the condition
                                mustNegate = true;
                                //  condExpr = new ILExpression(GMCode.Not, null, condExpr);
                                ILLabel tmp = trueLabel;
                                trueLabel  = falseLabel;
                                falseLabel = tmp;
                            }
                            // HACK

                            ControlFlowNode postLoopTarget;
                            labelToCfNode.TryGetValue(falseLabel, out postLoopTarget);
                            if (postLoopTarget != null)
                            {
                                // Pull more nodes into the loop
                                HashSet <ControlFlowNode> postLoopContents = FindDominatedNodes(scope, postLoopTarget);
                                var pullIn = scope.Except(postLoopContents).Where(n => node.Dominates(n));
                                loopContents.UnionWith(pullIn);
                            }


                            //Debug.Assert(false);
                            Debug.Assert(condExpr != null);
                            switch (loopType)
                            {
                            case GMCode.Pushenv:
                                basicBlock.Body.RemoveTail(GMCode.Pushenv, GMCode.B);
                                basicBlock.Body.Add(new ILWithStatement()
                                {
                                    Condition = condExpr,     // we never negate
                                    Body      = new ILBlock()
                                    {
                                        EntryGoto = new ILExpression(GMCode.B, trueLabel),
                                        Body      = FindLoops(loopContents, node, false)
                                    }
                                });
                                break;

                            case GMCode.Bt:
                                basicBlock.Body.RemoveTail(GMCode.Bt, GMCode.B);
                                basicBlock.Body.Add(new ILWhileLoop()
                                {
                                    Condition = mustNegate ? condExpr.NegateCondition() : condExpr,
                                    Body      = new ILBlock()
                                    {
                                        EntryGoto = new ILExpression(GMCode.B, trueLabel),
                                        Body      = FindLoops(loopContents, node, false)
                                    }
                                });

                                break;

                            case GMCode.Repeat:
                                basicBlock.Body.RemoveTail(GMCode.Repeat, GMCode.B);
                                basicBlock.Body.Add(new ILRepeat()
                                {
                                    Condition = condExpr,     // we never negate
                                    Body      = new ILBlock()
                                    {
                                        EntryGoto = new ILExpression(GMCode.B, trueLabel),
                                        Body      = FindLoops(loopContents, node, false)
                                    }
                                });

                                break;
                            }
                            basicBlock.Body.Add(new ILExpression(GMCode.B, falseLabel));


                            result.Add(basicBlock);

                            scope.ExceptWith(loopContents);
                        }
                    }

                    // Fallback method: while(true)
                    if (scope.Contains(node))
                    {
                        Debug.Assert(false);
                        result.Add(new ILBasicBlock()
                        {
                            Body = new List <ILNode>()
                            {
                                ILLabel.Generate("Loop"),
                                new ILWhileLoop()
                                {
                                    Condition = new ILExpression(GMCode.Constant, new ILValue(true)),
                                    Body      = new ILBlock()
                                    {
                                        EntryGoto = new ILExpression(GMCode.B, (ILLabel)basicBlock.Body.First()),
                                        Body      = FindLoops(loopContents, node, true)
                                    }
                                },
                            },
                        });

                        scope.ExceptWith(loopContents);
                    }
                }

                // Using the dominator tree should ensure we find the the widest loop first
                foreach (var child in node.DominatorTreeChildren)
                {
                    agenda.Enqueue(child);
                }
            }

            // Add whatever is left
            foreach (var node in scope)
            {
                result.Add((ILNode)node.UserData);
            }
            scope.Clear();

            return(result);
        }
Example #13
0
        // scope is modified if successful
        bool TrySimplifyShortCircuit(List<ILNode> scope, ILBasicBlock head)
        {
            Debug.Assert(scope.Contains(head));

            ILExpression branchExpr = null;
            ILLabel trueLabel = null;
            ILLabel falseLabel = null;
            if(IsConditionalBranch(head, ref branchExpr, ref trueLabel, ref falseLabel)) {
                for (int pass = 0; pass < 2; pass++) {

                    // On the second pass, swap labels and negate expression of the first branch
                    // It is slightly ugly, but much better then copy-pasting this whole block
                    ILLabel nextLabel   = (pass == 0) ? trueLabel  : falseLabel;
                    ILLabel otherLablel = (pass == 0) ? falseLabel : trueLabel;
                    bool    negate      = (pass == 1);

                    ILBasicBlock nextBasicBlock = labelToBasicBlock[nextLabel];
                    ILExpression nextBranchExpr = null;
                    ILLabel nextTrueLablel = null;
                    ILLabel nextFalseLabel = null;
                    if (scope.Contains(nextBasicBlock) &&
                        nextBasicBlock != head &&
                        labelGlobalRefCount[nextBasicBlock.EntryLabel] == 1 &&
                        IsConditionalBranch(nextBasicBlock, ref nextBranchExpr, ref nextTrueLablel, ref nextFalseLabel) &&
                        (otherLablel == nextFalseLabel || otherLablel == nextTrueLablel))
                    {
                        // We are using the branches as expressions now, so do not keep their labels alive
                        branchExpr.Operand = null;
                        nextBranchExpr.Operand = null;

                        // Create short cicuit branch
                        if (otherLablel == nextFalseLabel) {
                            head.Body[0] = new ILExpression(ILCode.BrLogicAnd, nextTrueLablel, negate ? new ILExpression(ILCode.LogicNot, null, branchExpr) : branchExpr, nextBranchExpr);
                        } else {
                            head.Body[0] = new ILExpression(ILCode.BrLogicOr, nextTrueLablel, negate ? branchExpr : new ILExpression(ILCode.LogicNot, null, branchExpr), nextBranchExpr);
                        }
                        head.FallthoughGoto = new ILExpression(ILCode.Br, nextFalseLabel);

                        // Remove the inlined branch from scope
                        labelGlobalRefCount[nextBasicBlock.EntryLabel] = 0;
                        if (!scope.Remove(nextBasicBlock))
                            throw new Exception("Element not found");

                        return true;
                    }
                }
            }
            return false;
        }
Example #14
0
 bool IsConditionalBranch(ILBasicBlock bb, ref ILExpression branchExpr, ref ILLabel trueLabel, ref ILLabel falseLabel)
 {
     if (bb.Body.Count == 1) {
         branchExpr = bb.Body[0] as ILExpression;
         if (branchExpr != null && branchExpr.Operand is ILLabel && branchExpr.Arguments.Count > 0) {
             trueLabel  = (ILLabel)branchExpr.Operand;
             falseLabel = (ILLabel)((ILExpression)bb.FallthoughGoto).Operand;
             return true;
         }
     }
     return false;
 }
Example #15
0
        public bool SimplifyShortCircuit(List<ILNode> body, ILBasicBlock head, int pos)
        {
            Debug.Assert(body.Contains(head));

            ILExpression condExpr;
            ILLabel trueLabel;
            ILLabel falseLabel;
            if(head.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) {
                for (int pass = 0; pass < 2; pass++) {

                    // On the second pass, swap labels and negate expression of the first branch
                    // It is slightly ugly, but much better then copy-pasting this whole block
                    ILLabel nextLabel   = (pass == 0) ? trueLabel  : falseLabel;
                    ILLabel otherLablel = (pass == 0) ? falseLabel : trueLabel;
                    bool    negate      = (pass == 1);

                    ILBasicBlock nextBasicBlock = labelToBasicBlock[nextLabel];
                    ILExpression nextCondExpr;
                    ILLabel nextTrueLablel;
                    ILLabel nextFalseLabel;
                    if (body.Contains(nextBasicBlock) &&
                        nextBasicBlock != head &&
                        labelGlobalRefCount[(ILLabel)nextBasicBlock.Body.First()] == 1 &&
                        nextBasicBlock.MatchSingleAndBr(ILCode.Brtrue, out nextTrueLablel, out nextCondExpr, out nextFalseLabel) &&
                        (otherLablel == nextFalseLabel || otherLablel == nextTrueLablel))
                    {
                        // Create short cicuit branch
                        ILExpression logicExpr;
                        if (otherLablel == nextFalseLabel) {
                            logicExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, negate ? new ILExpression(ILCode.LogicNot, null, condExpr) : condExpr, nextCondExpr);
                        } else {
                            logicExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, negate ? condExpr : new ILExpression(ILCode.LogicNot, null, condExpr), nextCondExpr);
                        }
                        var tail = head.Body.RemoveTail(ILCode.Brtrue, ILCode.Br);
                        nextCondExpr.ILRanges.AddRange(tail[0].ILRanges);	// brtrue
                        nextCondExpr.ILRanges.AddRange(nextBasicBlock.ILRanges);
                        nextBasicBlock.Body[0].AddSelfAndChildrenRecursiveILRanges(nextCondExpr.ILRanges);	// label
                        nextCondExpr.ILRanges.AddRange(nextBasicBlock.Body[1].ILRanges);	// brtrue

                        head.Body.Add(new ILExpression(ILCode.Brtrue, nextTrueLablel, logicExpr));
                        ILExpression brFalseLbl;
                        head.Body.Add(brFalseLbl = new ILExpression(ILCode.Br, nextFalseLabel));
                        nextBasicBlock.Body[2].AddSelfAndChildrenRecursiveILRanges(brFalseLbl.ILRanges);	// br
                        brFalseLbl.ILRanges.AddRange(nextBasicBlock.EndILRanges);
                        tail[1].AddSelfAndChildrenRecursiveILRanges(brFalseLbl.ILRanges); // br

                        // Remove the inlined branch from scope
                        body.RemoveOrThrow(nextBasicBlock);

                        return true;
                    }
                }
            }
            return false;
        }
Example #16
0
        public bool SimplifyTernaryOperator(List<ILNode> body, ILBasicBlock head, int pos)
        {
            Debug.Assert(body.Contains(head));

            ILExpression condExpr;
            ILLabel trueLabel;
            ILLabel falseLabel;
            ILVariable trueLocVar = null;
            ILExpression trueExpr;
            ILLabel trueFall;
            ILVariable falseLocVar = null;
            ILExpression falseExpr;
            ILLabel falseFall;
            object unused;

            if (head.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel) &&
                labelGlobalRefCount[trueLabel] == 1 &&
                labelGlobalRefCount[falseLabel] == 1 &&
                ((labelToBasicBlock[trueLabel].MatchSingleAndBr(ILCode.Stloc, out trueLocVar, out trueExpr, out trueFall) &&
                  labelToBasicBlock[falseLabel].MatchSingleAndBr(ILCode.Stloc, out falseLocVar, out falseExpr, out falseFall) &&
                  trueLocVar == falseLocVar && trueFall == falseFall) ||
                 (labelToBasicBlock[trueLabel].MatchSingle(ILCode.Ret, out unused, out trueExpr) &&
                  labelToBasicBlock[falseLabel].MatchSingle(ILCode.Ret, out unused, out falseExpr))) &&
                body.Contains(labelToBasicBlock[trueLabel]) &&
                body.Contains(labelToBasicBlock[falseLabel])
               )
            {
                bool isStloc = trueLocVar != null;
                ILCode opCode = isStloc ? ILCode.Stloc : ILCode.Ret;
                TypeSig retType = isStloc ? trueLocVar.Type : this.context.CurrentMethod.ReturnType;
                bool retTypeIsBoolean = retType.GetElementType() == ElementType.Boolean;
                int leftBoolVal;
                int rightBoolVal;
                ILExpression newExpr;
                // a ? true:false  is equivalent to  a
                // a ? false:true  is equivalent to  !a
                // a ? true : b    is equivalent to  a || b
                // a ? b : true    is equivalent to  !a || b
                // a ? b : false   is equivalent to  a && b
                // a ? false : b   is equivalent to  !a && b
                if (retTypeIsBoolean &&
                    trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal) &&
                    falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal) &&
                    ((leftBoolVal != 0 && rightBoolVal == 0) || (leftBoolVal == 0 && rightBoolVal != 0))
                   )
                {
                    // It can be expressed as trivilal expression
                    if (leftBoolVal != 0) {
                        newExpr = condExpr;
                    } else {
                        newExpr = new ILExpression(ILCode.LogicNot, null, condExpr) { InferredType = corLib.Boolean };
                    }
                } else if ((retTypeIsBoolean || falseExpr.InferredType.GetElementType() == ElementType.Boolean) && trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal) && (leftBoolVal == 0 || leftBoolVal == 1)) {
                    // It can be expressed as logical expression
                    if (leftBoolVal != 0) {
                        newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, condExpr, falseExpr);
                    } else {
                        newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, new ILExpression(ILCode.LogicNot, null, condExpr), falseExpr);
                    }
                } else if ((retTypeIsBoolean || trueExpr.InferredType.GetElementType() == ElementType.Boolean) && falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal) && (rightBoolVal == 0 || rightBoolVal == 1)) {
                    // It can be expressed as logical expression
                    if (rightBoolVal != 0) {
                        newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, new ILExpression(ILCode.LogicNot, null, condExpr), trueExpr);
                    } else {
                        newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, condExpr, trueExpr);
                    }
                } else {
                    // Ternary operator tends to create long complicated return statements
                    if (opCode == ILCode.Ret)
                        return false;

                    // Only simplify generated variables
                    if (opCode == ILCode.Stloc && !trueLocVar.GeneratedByDecompiler)
                        return false;

                    // Create ternary expression
                    newExpr = new ILExpression(ILCode.TernaryOp, null, condExpr, trueExpr, falseExpr);
                }

                var tail = head.Body.RemoveTail(ILCode.Brtrue, ILCode.Br);
                var listNodes = new List<ILNode>();
                var newExprNodes = newExpr.GetSelfAndChildrenRecursive<ILNode>(listNodes).ToArray();
                foreach (var node in labelToBasicBlock[trueLabel].GetSelfAndChildrenRecursive<ILNode>(listNodes).Except(newExprNodes))
                    newExpr.ILRanges.AddRange(node.AllILRanges);
                foreach (var node in labelToBasicBlock[falseLabel].GetSelfAndChildrenRecursive<ILNode>(listNodes).Except(newExprNodes))
                    newExpr.ILRanges.AddRange(node.AllILRanges);
                newExpr.ILRanges.AddRange(tail[0].ILRanges);
                tail[1].AddSelfAndChildrenRecursiveILRanges(newExpr.ILRanges);

                head.Body.Add(new ILExpression(opCode, trueLocVar, newExpr));
                if (isStloc)
                    head.Body.Add(new ILExpression(ILCode.Br, trueFall));

                // Remove the old basic blocks
                body.RemoveOrThrow(labelToBasicBlock[trueLabel]);
                body.RemoveOrThrow(labelToBasicBlock[falseLabel]);

                return true;
            }
            return false;
        }
Example #17
0
        public static bool MatchSingleAndBr(this ILBasicBlock bb, GMCode code, out ILExpression arg, out ILLabel brLabel)
        {
            object filler;

            return(bb.MatchSingleAndBr <object>(code, out filler, out arg, out brLabel));
        }
Example #18
0
 public static void RemoveAtLast(this ILBasicBlock bb, int i)
 {
     bb.Body.RemoveAtLast(i);
 }
Example #19
0
        /// <summary>
        /// Group input into a set of blocks that can be later arbitraliby schufled.
        /// The method adds necessary branches to make control flow between blocks
        /// explicit and thus order independent.
        /// </summary>
        void SplitToBasicBlocks(ILBlock block)
        {
            // Remve no-ops
            // TODO: Assign the no-op range to someting
            block.Body = block.Body.Where(n => !(n is ILExpression && ((ILExpression)n).Code == ILCode.Nop)).ToList();

            List<ILNode> basicBlocks = new List<ILNode>();

            ILBasicBlock basicBlock = new ILBasicBlock() {
                EntryLabel = new ILLabel() { Name = "Block_" + (nextBlockIndex++) }
            };
            basicBlocks.Add(basicBlock);
            block.EntryGoto = new ILExpression(ILCode.Br, basicBlock.EntryLabel);

            if (block.Body.Count > 0) {
                basicBlock.Body.Add(block.Body[0]);

                for (int i = 1; i < block.Body.Count; i++) {
                    ILNode lastNode = block.Body[i - 1];
                    ILNode currNode = block.Body[i];

                    bool added = false;

                    // Insert split
                    if (currNode is ILLabel ||
                        lastNode is ILTryCatchBlock ||
                        currNode is ILTryCatchBlock ||
                        (lastNode is ILExpression) && ((ILExpression)lastNode).IsBranch() ||
                        (currNode is ILExpression) && (((ILExpression)currNode).IsBranch() && basicBlock.Body.Count > 0))
                    {
                        ILBasicBlock lastBlock = basicBlock;
                        basicBlock = new ILBasicBlock();
                        basicBlocks.Add(basicBlock);
                        if (currNode is ILLabel) {
                            // Reuse the first label
                            basicBlock.EntryLabel = (ILLabel)currNode;
                            added = true;
                        } else {
                            basicBlock.EntryLabel = new ILLabel() { Name = "Block_" + (nextBlockIndex++) };
                        }

                        // Explicit branch from one block to other
                        // (unless the last expression was unconditional branch)
                        if (!(lastNode is ILExpression) || ((ILExpression)lastNode).Code.CanFallThough()) {
                            lastBlock.FallthoughGoto = new ILExpression(ILCode.Br, basicBlock.EntryLabel);
                        }
                    }

                    if (!added)
                        basicBlock.Body.Add(currNode);
                }
            }

            block.Body = basicBlocks;
            return;
        }
Example #20
0
        ILBasicBlock FindEndOfSwitch(ILBasicBlock start)
        {
            ILLabel callTo;

            return(FindEndOfSwitch(start, out callTo));
        }
Example #21
0
		public bool SimplifyNullCoalescing(List<ILNode> body, ILBasicBlock head, int pos)
		{
			// ...
			// v = ldloc(leftVar)
			// brtrue(endBBLabel, ldloc(leftVar))
			// br(rightBBLabel)
			//
			// rightBBLabel:
			// v = rightExpr
			// br(endBBLabel)
			// ...
			// =>
			// ...
			// v = NullCoalescing(ldloc(leftVar), rightExpr)
			// br(endBBLabel)
				
			ILVariable v, v2;
			ILExpression leftExpr, leftExpr2;
			ILVariable leftVar;
			ILLabel endBBLabel, endBBLabel2;
			ILLabel rightBBLabel;
			ILBasicBlock rightBB;
			ILExpression rightExpr;
			if (head.Body.Count >= 3 &&
				head.Body[head.Body.Count - 3].Match(ILCode.Stloc, out v, out leftExpr) &&
			    leftExpr.Match(ILCode.Ldloc, out leftVar) &&
			    head.MatchLastAndBr(ILCode.Brtrue, out endBBLabel, out leftExpr2, out rightBBLabel) &&
			    leftExpr2.MatchLdloc(leftVar) &&
			    labelToBasicBlock.TryGetValue(rightBBLabel, out rightBB) &&
			    rightBB.MatchSingleAndBr(ILCode.Stloc, out v2, out rightExpr, out endBBLabel2) &&
			    v == v2 &&
			    endBBLabel == endBBLabel2 &&
			    labelGlobalRefCount.GetOrDefault(rightBBLabel) == 1 &&
			    body.Contains(rightBB)
			   )
			{
				head.Body.RemoveTail(ILCode.Stloc, ILCode.Brtrue, ILCode.Br);
				head.Body.Add(new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.NullCoalescing, null, leftExpr, rightExpr)));
				head.Body.Add(new ILExpression(ILCode.Br, endBBLabel));
				
				body.RemoveOrThrow(labelToBasicBlock[rightBBLabel]);
				return true;
			}
			return false;
		}
Example #22
0
        public bool DetectSwitch_GenerateSwitch(IList <ILNode> body, ILBasicBlock head, int pos)
        {
            ILExpression condition;
            ILLabel      trueLabel;
            ILLabel      fallThough;

            // REMEMBER:  The searching goes backwards, so we find the FIRST case here, so here is the problem
            // Evey time we run this, we have to search for the first block of the case statement backwards and if
            // the push var is not resolved, we have to drop out... evey single time till the push IS resolved
            // so be sure to run this at the bottom of the decision chain.  Its fine if the push is a simple var
            // but I can bet cash this runs 2-3 times if the push is some kind of expression like 5 + (3 % switch_var))
            // we could change the way the optimizing loop works by going from the start and building a que of things
            // to remove, delete or change hummm...  Take longer but it would make building this functions MUCH simpler
            if (MatchSwitchCase(head, out trueLabel, out fallThough, out condition) &&
                !MatchSwitchCase(body.ElementAtOrDefault(pos - 1) as ILBasicBlock, out trueLabel, out fallThough, out condition)
                )  // && head.MatchLastAt(6, GMCode.Push,out switch_expr))
            {
                List <ILBasicBlock> caseBlocks = GetAllCaseBlocks(body, head, pos, out condition, out fallThough);
                if (caseBlocks == null)
                {
                    return(false);
                }
                ILExpression fswitch = new ILExpression(GMCode.Switch, null);
                FakeSwitch   args    = new FakeSwitch();
                args.SwitchExpression = condition;
                args.CaseExpressions  = caseBlocks.Select(bb =>
                                                          new KeyValuePair <ILExpression, ILLabel>((bb.ElementAtLast(3) as ILExpression).Arguments[0], (bb.ElementAtLast(1) as ILExpression).Operand as ILLabel)
                                                          ).ToList();

                fswitch.Operand = args;
                // search the blocks for ending popz's and remove the popz
                HashSet <ILBasicBlock> blocks_done = new HashSet <ILBasicBlock>();
                Stack <ILBasicBlock>   agenda      = new Stack <ILBasicBlock>(caseBlocks);
                while (agenda.Count > 0)
                {
                    ILBasicBlock bb = agenda.Pop();
                    if (blocks_done.Contains(bb))
                    {
                        continue;                           // already did it
                    }
                    ILExpression popz = bb.Body.OfType <ILExpression>().Where(e => e.Code == GMCode.Popz).SingleOrDefault();
                    if (popz != null)
                    {
                        bb.Body.Remove(popz); // remove it
                    }
                    else
                    {
                        ILLabel exit = bb.OperandLabelLastAt(0);
                        if (exit != null && !blocks_done.Contains(labelToBasicBlock[exit]))
                        {
                            agenda.Push(labelToBasicBlock[exit]);
                        }
                        exit = bb.OperandLabelLastAt(1); // check if we have a bt or something
                        if (exit != null && !blocks_done.Contains(labelToBasicBlock[exit]))
                        {
                            agenda.Push(labelToBasicBlock[exit]);
                        }
                    }
                    blocks_done.Add(bb);
                }
                ILBasicBlock startOfAllCases = caseBlocks.First();
                caseBlocks.Remove(startOfAllCases);
                startOfAllCases.Body.RemoveTail(GMCode.Dup, GMCode.Push, GMCode.Seq, GMCode.Bt, GMCode.B);
                startOfAllCases.Body.Add(fswitch);
                startOfAllCases.Body.Add(new ILExpression(GMCode.B, fallThough)); //  end_of_switch.EntryLabel()));
                body.RemoveAll(caseBlocks);

                return(true);
            }


            return(false);
        }
Example #23
0
		public bool SimplifyTernaryOperator(List<ILNode> body, ILBasicBlock head, int pos)
		{
			Debug.Assert(body.Contains(head));
			
			ILExpression condExpr;
			ILLabel trueLabel;
			ILLabel falseLabel;
			ILVariable trueLocVar = null;
			ILExpression trueExpr;
			ILLabel trueFall;
			ILVariable falseLocVar = null;
			ILExpression falseExpr;
			ILLabel falseFall;
			object unused;
			
			if (head.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel) &&
			    labelGlobalRefCount[trueLabel] == 1 &&
			    labelGlobalRefCount[falseLabel] == 1 &&
			    ((labelToBasicBlock[trueLabel].MatchSingleAndBr(ILCode.Stloc, out trueLocVar, out trueExpr, out trueFall) &&
			      labelToBasicBlock[falseLabel].MatchSingleAndBr(ILCode.Stloc, out falseLocVar, out falseExpr, out falseFall) &&
			      trueLocVar == falseLocVar && trueFall == falseFall) ||
			     (labelToBasicBlock[trueLabel].MatchSingle(ILCode.Ret, out unused, out trueExpr) &&
			      labelToBasicBlock[falseLabel].MatchSingle(ILCode.Ret, out unused, out falseExpr))) &&
			    body.Contains(labelToBasicBlock[trueLabel]) &&
			    body.Contains(labelToBasicBlock[falseLabel])
			   )
			{
				bool isStloc = trueLocVar != null;
				ILCode opCode = isStloc ? ILCode.Stloc : ILCode.Ret;
				TypeReference retType = isStloc ? trueLocVar.Type : this.context.CurrentMethod.ReturnType;
				bool retTypeIsBoolean = TypeAnalysis.IsBoolean(retType);
				int leftBoolVal;
				int rightBoolVal;
				ILExpression newExpr;
				// a ? true:false  is equivalent to  a
				// a ? false:true  is equivalent to  !a
				// a ? true : b    is equivalent to  a || b
				// a ? b : true    is equivalent to  !a || b
				// a ? b : false   is equivalent to  a && b
				// a ? false : b   is equivalent to  !a && b
				if (retTypeIsBoolean &&
				    trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal) &&
				    falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal) &&
				    ((leftBoolVal != 0 && rightBoolVal == 0) || (leftBoolVal == 0 && rightBoolVal != 0))
				   )
				{
					// It can be expressed as trivilal expression
					if (leftBoolVal != 0) {
						newExpr = condExpr;
					} else {
						newExpr = new ILExpression(ILCode.LogicNot, null, condExpr);
					}
				} else if (retTypeIsBoolean && trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal)) {
					// It can be expressed as logical expression
					if (leftBoolVal != 0) {
						newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, condExpr, falseExpr);
					} else {
						newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, new ILExpression(ILCode.LogicNot, null, condExpr), falseExpr);
					}
				} else if (retTypeIsBoolean && falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal)) {
					// It can be expressed as logical expression
					if (rightBoolVal != 0) {
						newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, new ILExpression(ILCode.LogicNot, null, condExpr), trueExpr);
					} else {
						newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, condExpr, trueExpr);
					}
				} else {
					// Ternary operator tends to create long complicated return statements					
					if (opCode == ILCode.Ret)
						return false;
					
					// Only simplify generated variables
					if (opCode == ILCode.Stloc && !trueLocVar.IsGenerated)
						return false;
					
					// Create ternary expression
					newExpr = new ILExpression(ILCode.TernaryOp, null, condExpr, trueExpr, falseExpr);
				}
				
				head.Body.RemoveTail(ILCode.Brtrue, ILCode.Br);
				head.Body.Add(new ILExpression(opCode, trueLocVar, newExpr));
				if (isStloc)
					head.Body.Add(new ILExpression(ILCode.Br, trueFall));
				
				// Remove the old basic blocks
				body.RemoveOrThrow(labelToBasicBlock[trueLabel]);
				body.RemoveOrThrow(labelToBasicBlock[falseLabel]);
				
				return true;
			}
			return false;
		}
Example #24
0
        public bool DetectSwitch_GenerateBranches(IList <ILNode> body, ILBasicBlock head, int pos)
        {
            bool         modified = false;
            ILExpression condition;
            ILLabel      trueLabel;
            ILLabel      falseLabel;
            ILLabel      fallThough;

            //    Debug.Assert(head.EntryLabel().Name != "Block_473");
            if (MatchSwitchCase(head, out trueLabel, out fallThough, out condition))   // we ignore this first match, but remember the position
            {
                List <ILExpression> cases        = new List <ILExpression>();
                List <ILNode>       caseBlocks   = new List <ILNode>();
                ILLabel             prev         = head.EntryLabel();
                ILBasicBlock        startOfCases = head;
                cases.Add(PreSetUpCaseBlock(startOfCases, condition));
                caseBlocks.Add(startOfCases);

                for (int i = pos - 1; i >= 0; i--)
                {
                    ILBasicBlock bb = body[i] as ILBasicBlock;
                    if (MatchSwitchCase(bb, out trueLabel, out falseLabel, out condition))
                    {
                        caseBlocks.Add(bb);
                        cases.Add(PreSetUpCaseBlock(bb, condition));

                        Debug.Assert(falseLabel == prev);
                        prev         = bb.EntryLabel();
                        startOfCases = bb;
                    }
                    else
                    {
                        break;
                    }
                }
                // we have all the cases
                // head is at the "head" of the cases
                ILExpression left;
                if (startOfCases.Body[startOfCases.Body.Count - 3].Match(GMCode.Push, out left))
                {
                    startOfCases.Body.RemoveAt(startOfCases.Body.Count - 3);
                    foreach (var e in cases)
                    {
                        e.Arguments.Insert(0, new ILExpression(left));                     // add the expression to all the branches
                    }
                }
                else
                {
                    throw new Exception("switch failure");
                }
                // It seems GM makes a default case that just jumps to the end of the switch but I cannot
                // rely on it always being there
                ILBasicBlock default_case = body[pos + 1] as ILBasicBlock;
                Debug.Assert(default_case.EntryLabel() == head.GotoLabel());
                ILBasicBlock end_of_switch = labelToBasicBlock[default_case.GotoLabel()];
                if ((end_of_switch.Body[1] as ILExpression).Code == GMCode.Popz)
                {
                    end_of_switch.Body.RemoveAt(1); // yeaa!
                }
                else // booo
                { // We have a default case so now we have to find where the popz ends,
                    // this could be bad if we had a wierd generated for loop, but we are just doing stupid search
                    ILBasicBlock test1 = FindEndOfSwitch(end_of_switch);
                    // we take a sample from one of the cases to make sure we do end up at the same place
                    ILBasicBlock test2 = FindEndOfSwitch(head);
                    if (test1 == test2)
                    {                           // two matches are good enough for me
                        test1.Body.RemoveAt(1); // yeaa!
                    }
                    else
                    {
                        error.Error("Cannot find end of switch", end_of_switch); // booo
                    }
                }
                // tricky part, finding that damn popz

                // Ok, we have all the case blocks, they are all fixed, and its like a big chain of ifs now.
                // But for anything OTHER than lua that has switch statments, we want to mark this for latter

                modified |= true;
            }
            return(modified);
        }
Example #25
0
        public bool SimplifyCustomShortCircuit(List<ILNode> body, ILBasicBlock head, int pos)
        {
            Debug.Assert(body.Contains(head));

            // --- looking for the following pattern ---
            // stloc(targetVar, leftVar)
            // brtrue(exitLabel, call(op_False, leftVar)
            // br(followingBlock)
            //
            // FollowingBlock:
            // stloc(targetVar, call(op_BitwiseAnd, leftVar, rightExpression))
            // br(exitLabel)
            // ---

            if (head.Body.Count < 3)
                return false;

            // looking for:
            // stloc(targetVar, leftVar)
            ILVariable targetVar;
            ILExpression targetVarInitExpr;
            if (!head.Body[head.Body.Count - 3].Match(ILCode.Stloc, out targetVar, out targetVarInitExpr))
                return false;

            ILVariable leftVar;
            if (!targetVarInitExpr.Match(ILCode.Ldloc, out leftVar))
                return false;

            // looking for:
            // brtrue(exitLabel, call(op_False, leftVar)
            // br(followingBlock)
            ILExpression callExpr;
            ILLabel exitLabel;
            ILLabel followingBlock;
            if(!head.MatchLastAndBr(ILCode.Brtrue, out exitLabel, out callExpr, out followingBlock))
                return false;

            if (labelGlobalRefCount[followingBlock] > 1)
                return false;

            IMethod opFalse;
            ILExpression opFalseArg;
            if (!callExpr.Match(ILCode.Call, out opFalse, out opFalseArg))
                return false;

            // ignore operators other than op_False and op_True
            if (opFalse.Name != "op_False" && opFalse.Name != "op_True")
                return false;

            if (!opFalseArg.MatchLdloc(leftVar))
                return false;

            ILBasicBlock followingBasicBlock = labelToBasicBlock[followingBlock];

            // FollowingBlock:
            // stloc(targetVar, call(op_BitwiseAnd, leftVar, rightExpression))
            // br(exitLabel)
            ILVariable _targetVar;
            ILExpression opBitwiseCallExpr;
            ILLabel _exitLabel;
            if (!followingBasicBlock.MatchSingleAndBr(ILCode.Stloc, out _targetVar, out opBitwiseCallExpr, out _exitLabel))
                return false;

            if (_targetVar != targetVar || exitLabel != _exitLabel)
                return false;

            IMethod opBitwise;
            ILExpression leftVarExpression;
            ILExpression rightExpression;
            if (!opBitwiseCallExpr.Match(ILCode.Call, out opBitwise, out leftVarExpression, out rightExpression))
                return false;

            if (!leftVarExpression.MatchLdloc(leftVar))
                return false;

            // ignore operators other than op_BitwiseAnd and op_BitwiseOr
            if (opBitwise.Name != "op_BitwiseAnd" && opBitwise.Name != "op_BitwiseOr")
                return false;

            // insert:
            // stloc(targetVar, LogicAnd(C::op_BitwiseAnd, leftVar, rightExpression)
            // br(exitLabel)
            ILCode op = opBitwise.Name == "op_BitwiseAnd" ? ILCode.LogicAnd : ILCode.LogicOr;

            if (op == ILCode.LogicAnd && opFalse.Name != "op_False")
                return false;

            if (op == ILCode.LogicOr && opFalse.Name != "op_True")
                return false;

            ILExpression shortCircuitExpr = MakeLeftAssociativeShortCircuit(op, opFalseArg, rightExpression);
            shortCircuitExpr.Operand = opBitwise;

            var tail = head.Body.RemoveTail(ILCode.Stloc, ILCode.Brtrue, ILCode.Br);
            //TODO: Keep tail's ILRanges
            //TODO: Keep ILRanges of other things that are removed by this method
            head.Body.Add(new ILExpression(ILCode.Stloc, targetVar, shortCircuitExpr));
            head.Body.Add(new ILExpression(ILCode.Br, exitLabel));
            body.Remove(followingBasicBlock);

            return true;
        }
Example #26
0
 public static ILNode ElementAtOrDefault(this ILBasicBlock bb, int i)
 {
     return(bb.Body.ElementAtOrDefault(i));
 }
Example #27
0
        public bool SimplifyNullCoalescing(List<ILNode> body, ILBasicBlock head, int pos)
        {
            // ...
            // v = ldloc(leftVar)
            // brtrue(endBBLabel, ldloc(leftVar))
            // br(rightBBLabel)
            //
            // rightBBLabel:
            // v = rightExpr
            // br(endBBLabel)
            // ...
            // =>
            // ...
            // v = NullCoalescing(ldloc(leftVar), rightExpr)
            // br(endBBLabel)

            ILVariable v, v2;
            ILExpression leftExpr, leftExpr2;
            ILVariable leftVar;
            ILLabel endBBLabel, endBBLabel2;
            ILLabel rightBBLabel;
            ILBasicBlock rightBB;
            ILExpression rightExpr;
            if (head.Body.Count >= 3 &&
                head.Body[head.Body.Count - 3].Match(ILCode.Stloc, out v, out leftExpr) &&
                leftExpr.Match(ILCode.Ldloc, out leftVar) &&
                head.MatchLastAndBr(ILCode.Brtrue, out endBBLabel, out leftExpr2, out rightBBLabel) &&
                leftExpr2.MatchLdloc(leftVar) &&
                labelToBasicBlock.TryGetValue(rightBBLabel, out rightBB) &&
                rightBB.MatchSingleAndBr(ILCode.Stloc, out v2, out rightExpr, out endBBLabel2) &&
                v == v2 &&
                endBBLabel == endBBLabel2 &&
                labelGlobalRefCount.GetOrDefault(rightBBLabel) == 1 &&
                body.Contains(rightBB)
               )
            {
                var tail = head.Body.RemoveTail(ILCode.Stloc, ILCode.Brtrue, ILCode.Br);
                ILExpression nullCoal, stloc;
                head.Body.Add(stloc = new ILExpression(ILCode.Stloc, v, nullCoal = new ILExpression(ILCode.NullCoalescing, null, leftExpr, rightExpr)));
                head.Body.Add(new ILExpression(ILCode.Br, endBBLabel));
                tail[0].AddSelfAndChildrenRecursiveILRanges(stloc.ILRanges);
                tail[1].AddSelfAndChildrenRecursiveILRanges(nullCoal.ILRanges);
                tail[2].AddSelfAndChildrenRecursiveILRanges(rightExpr.ILRanges);	// br (to rightBB)
                rightExpr.ILRanges.AddRange(rightBB.AllILRanges);
                rightBB.Body[0].AddSelfAndChildrenRecursiveILRanges(rightExpr.ILRanges);	// label
                rightExpr.ILRanges.AddRange(rightBB.Body[1].ILRanges);      // stloc: no recursive add
                rightBB.Body[2].AddSelfAndChildrenRecursiveILRanges(rightExpr.ILRanges);	// br

                body.RemoveOrThrow(labelToBasicBlock[rightBBLabel]);
                return true;
            }
            return false;
        }
Example #28
0
 public static T ElementAtOrDefault <T>(this ILBasicBlock bb, int i) where T : ILNode
 {
     return(bb.Body.ElementAtOrDefault(i) as T);
 }
Example #29
0
        private void ProcessMethodDecencies(InterMethod method, ILNode node, List <InterGenericArgument> genericArgs)
        {
            if (node is ILBlock)
            {
                ILBlock block = node as ILBlock;

                foreach (ILNode n in block.Body)
                {
                    ProcessMethodDecencies(method, n, genericArgs);
                }
            }
            else if (node is ILBasicBlock)
            {
                ILBasicBlock block = node as ILBasicBlock;

                foreach (ILNode n in block.Body)
                {
                    ProcessMethodDecencies(method, n, genericArgs);
                }
            }
            else if (node is ILTryCatchBlock)
            {
                ILTryCatchBlock block = node as ILTryCatchBlock;

                foreach (ILNode n in block.TryBlock.Body)
                {
                    ProcessMethodDecencies(method, n, genericArgs);
                }
                if (block.FaultBlock != null)
                {
                    foreach (ILNode n in block.FaultBlock.Body)
                    {
                        ProcessMethodDecencies(method, n, genericArgs);
                    }
                }
                if (block.FinallyBlock != null)
                {
                    foreach (ILNode n in block.FinallyBlock.Body)
                    {
                        ProcessMethodDecencies(method, n, genericArgs);
                    }
                }
                foreach (var catchBlock in block.CatchBlocks)
                {
                    ((IResolver)this).Resolve(catchBlock.ExceptionType, genericArgs);
                    ProcessMethodDecencies(method, catchBlock, genericArgs);
                }
            }
            else if (node is ILExpression)
            {
                ILExpression e = node as ILExpression;

                foreach (var n in e.Arguments)
                {
                    ProcessMethodDecencies(method, n, genericArgs);
                }

                if ((e.Code == ILCode.Mkrefany) || (e.Code == ILCode.Refanyval))
                {
                    ((IResolver)this).Resolve(ClassNames.SystemTypedReference.ClassName);
                }

                if (e.Code == ILCode.Refanytype)
                {
                    ((IResolver)this).Resolve(ClassNames.SystemTypedReference.ClassName);
                    ((IResolver)this).Resolve(ClassNames.SystemRuntimeTypeHandle.ClassName);
                }

                if (e.Code == ILCode.Arglist)
                {
                    ((IResolver)this).Resolve(ClassNames.SystemRuntimeArgumentHandle.ClassName);
                }

                if (e.Code.IsExternalRealization())
                {
                    ((IResolver)this).Resolve(ClassNames.CIL2JavaVESInstructions.ClassName);
                }

                if (e.Code == ILCode.Ldc_Decimal)
                {
                    ((IResolver)this).Resolve(ClassNames.SystemDecimal.ClassNames);
                }

                if (e.Code == ILCode.Ldtoken)
                {
                    if (e.Operand is TypeReference)
                    {
                        ((IResolver)this).Resolve(ClassNames.SystemRuntimeTypeHandle.ClassName);
                    }
                    else if (e.Operand is FieldReference)
                    {
                        ((IResolver)this).Resolve(ClassNames.SystemRuntimeFieldHandle.ClassName);
                    }
                    else if (e.Operand is MethodReference)
                    {
                        ((IResolver)this).Resolve(ClassNames.SystemRuntimeMethodHandle.ClassName);
                    }
                }

                if (e.Operand is ILVariable)
                {
                    ((IResolver)this).Resolve(((ILVariable)e.Operand).Type, genericArgs);
                }
                if (e.Operand is TypeReference)
                {
                    ((IResolver)this).Resolve((TypeReference)e.Operand, genericArgs);
                }
                if (e.Operand is MethodReference)
                {
                    ((IResolver)this).Resolve((MethodReference)e.Operand, genericArgs);
                }
                if (e.Operand is FieldReference)
                {
                    InterField fld          = ((IResolver)this).Resolve((FieldReference)e.Operand, genericArgs);
                    bool       needAccessor = false;

                    if ((fld.IsPrivate) && (fld.DeclaringType != method.DeclaringType))
                    {
                        needAccessor = true;
                    }
                    else if ((fld.IsProtected) && (fld.DeclaringType != method.DeclaringType) &&
                             (!method.DeclaringType.IsSuper(fld.DeclaringType)))
                    {
                        needAccessor = true;
                    }

                    if (needAccessor)
                    {
                        switch (e.Code)
                        {
                        case ILCode.Ldflda:
                        case ILCode.Ldsflda:
                            if (fld.FieldType.IsValueType)
                            {
                                fld.DeclaringType.AddFieldAccessor(new FieldAccessor(FieldAccessorType.Getter, fld));
                            }
                            break;

                        case ILCode.Ldfld:
                        case ILCode.Ldsfld:
                            fld.DeclaringType.AddFieldAccessor(new FieldAccessor(FieldAccessorType.Getter, fld));
                            break;

                        case ILCode.Stfld:
                        case ILCode.Stsfld:
                            fld.DeclaringType.AddFieldAccessor(new FieldAccessor(FieldAccessorType.Setter, fld));
                            break;
                        }
                    }
                }

                InterType expected = null;
                InterType inferred = null;

                if (e.ExpectedType != null)
                {
                    expected = ((IResolver)this).Resolve(e.ExpectedType, genericArgs);
                }
                if (e.InferredType != null)
                {
                    inferred = ((IResolver)this).Resolve(e.InferredType, genericArgs);
                }

                if ((expected != null) && (expected.IsInterface) && (inferred != null) && (inferred.IsArray))
                {
                    ((IResolver)this).Resolve(ClassNames.ArraysInterfaceAdapterTypeName,
                                              new List <InterGenericArgument>()
                    {
                        new InterGenericArgument(GenericArgumentOwnerType.Type, 0, inferred.ElementType)
                    });
                }
            }
            else if (node is ILWhileLoop)
            {
                ILWhileLoop loop = node as ILWhileLoop;
                ProcessMethodDecencies(method, loop.Condition, genericArgs);
                ProcessMethodDecencies(method, loop.BodyBlock, genericArgs);
            }
            else if (node is ILCondition)
            {
                ILCondition cond = node as ILCondition;
                ProcessMethodDecencies(method, cond.Condition, genericArgs);
                ProcessMethodDecencies(method, cond.TrueBlock, genericArgs);
                ProcessMethodDecencies(method, cond.FalseBlock, genericArgs);
            }
            else if (node is ILSwitch)
            {
                ILSwitch sw = node as ILSwitch;
                ProcessMethodDecencies(method, sw.Condition, genericArgs);
                foreach (var c in sw.CaseBlocks)
                {
                    ProcessMethodDecencies(method, c, genericArgs);
                }
            }
            else if (node is ILFixedStatement)
            {
                ILFixedStatement fs = node as ILFixedStatement;
                foreach (var n in fs.Initializers)
                {
                    ProcessMethodDecencies(method, n, genericArgs);
                }
                ProcessMethodDecencies(method, fs.BodyBlock, genericArgs);
            }
        }