Пример #1
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);
        }
Пример #2
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;

                    {
                        // Switch
                        IList <ILExpression> cases;
                        ILLabel[]            caseLabels;
                        ILExpression         switchCondition;
                        ILLabel fallLabel;
                        //   IList<ILExpression> cases; out IList<ILExpression> arg, out ILLabel fallLabel)
                        // matches a switch statment, not sure how the hell I am going to do this
                        if (block.MatchLastAndBr(GMCode.Switch, out caseLabels, out cases, out fallLabel))
                        {
                            //    Debug.Assert(fallLabel == endBlock); // this should be true
                            switchCondition = cases[0]; // thats the switch arg
                            cases.RemoveAt(0);          // remove the switch condition

                            // Replace the switch code with ILSwitch
                            ILSwitch ilSwitch = new ILSwitch()
                            {
                                Condition = switchCondition
                            };
                            block.Body.RemoveTail(GMCode.Switch, GMCode.B);
                            block.Body.Add(ilSwitch);
                            block.Body.Add(new ILExpression(GMCode.B, fallLabel));
                            result.Add(block);

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

                            // 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 caseLabels)
                            {
                                ControlFlowNode condTarget = null;
                                labelToCfNode.TryGetValue(condLabel, out condTarget);
                                if (condTarget != null)
                                {
                                    frontiers.UnionWith(condTarget.DominanceFrontier.Except(new[] { condTarget }));
                                }
                            }

                            for (int i = 0; i < caseLabels.Length; i++)
                            {
                                ILLabel condLabel = caseLabels[i];

                                // Find or create new case block
                                ILSwitch.CaseBlock caseBlock = ilSwitch.CaseBlocks.FirstOrDefault(b => b.EntryGoto.Operand == condLabel);
                                if (caseBlock == null)
                                {
                                    caseBlock = new ILSwitch.CaseBlock()
                                    {
                                        Values    = new List <ILExpression>(),
                                        EntryGoto = new ILExpression(GMCode.B, condLabel)
                                    };
                                    ilSwitch.CaseBlocks.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 =
                                            {
                                                new ILLabel()
                                                {
                                                    Name = "SwitchBreak_" + (nextLabelIndex++)
                                                },
                                                new ILExpression(GMCode.LoopOrSwitchBreak, null)
                                            }
                                        });
                                    }
                                }
                                if (cases[i].Code != GMCode.DefaultCase)
                                {
                                    caseBlock.Values.Add(cases[i].Arguments[0]);
                                }
                                else
                                {
                                    caseBlock.Values.Add(new ILExpression(GMCode.DefaultCase, null));
                                }
                            }

                            // 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.CaseBlock()
                                    {
                                        EntryGoto = new ILExpression(GMCode.B, fallLabel)
                                    };
                                    ilSwitch.CaseBlocks.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 =
                                        {
                                            new ILLabel()
                                            {
                                                Name = "SwitchBreak_" + (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.Bf, out falseLabel, out condExprs, out trueLabel) &&
                            condExprs[0].Code != GMCode.Pop)     // 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,
                                TrueBlock = new ILBlock()
                                {
                                    EntryGoto = new ILExpression(GMCode.B, trueLabel)
                                },
                                FalseBlock = new ILBlock()
                                {
                                    EntryGoto = new ILExpression(GMCode.B, falseLabel)
                                }
                            };
                            block.Body.RemoveTail(GMCode.Bf, 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);
        }
Пример #3
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;
                    ILLabel      trueLabel;
                    ILLabel      falseLabel;
                    // It has to be just brtrue - any preceding code would introduce goto
                    if (basicBlock.MatchSingleAndBr(GMCode.Bf, out falseLabel, out condExpr, out trueLabel) ||
                        //  basicBlock.MatchSingleAndBr(GMCode.Bt, out trueLabel, out condExpr, out falseLabel) ||
                        basicBlock.MatchSingleAndBr(GMCode.Pushenv, out falseLabel, out condExpr, out trueLabel)) // built it the same way
                    {
                        bool            ispushEnv = (basicBlock.Body.ElementAt(basicBlock.Body.Count - 2) as ILExpression).Code == GMCode.Pushenv;
                        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);

                            // If false means enter the loop
                            if (loopContents.Contains(falseTarget) || falseTarget == node)
                            {
                                // Negate the condition
                                condExpr = new ILExpression(GMCode.Not, null, condExpr);
                                ILLabel tmp = trueLabel;
                                trueLabel  = falseLabel;
                                falseLabel = tmp;
                            }

                            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);
                            }
                            if (ispushEnv)
                            {
                                // Use loop to implement the brtrue
                                basicBlock.Body.RemoveTail(GMCode.Pushenv, GMCode.B);
                                basicBlock.Body.Add(new ILWithStatement()
                                {
                                    Enviroment = condExpr,
                                    Body       = new ILBlock()
                                    {
                                        EntryGoto = new ILExpression(GMCode.B, trueLabel),
                                        Body      = FindLoops(loopContents, node, false)
                                    }
                                });
                            }
                            else
                            {
                                // Use loop to implement the brtrue
                                basicBlock.Body.RemoveTail(GMCode.Bf, GMCode.B);
                                basicBlock.Body.Add(new ILWhileLoop()
                                {
                                    Condition = condExpr,
                                    BodyBlock = new ILBlock()
                                    {
                                        EntryGoto = new ILExpression(GMCode.B, trueLabel),
                                        Body      = FindLoops(loopContents, node, false)
                                    }
                                });
                            }

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

                            scope.ExceptWith(loopContents);
                        }
                    }

                    // Fallback method: while(true)
                    if (scope.Contains(node))
                    {
                        result.Add(new ILBasicBlock()
                        {
                            Body = new List <ILNode>()
                            {
                                new ILLabel()
                                {
                                    Name = "Loop_" + (nextLabelIndex++)
                                },
                                new ILWhileLoop()
                                {
                                    BodyBlock = 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);
        }
Пример #4
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)
        {
            int           nextLabelIndex = 0;
            List <ILNode> basicBlocks    = new List <ILNode>();

            ILLabel entryLabel = block.Body.FirstOrDefault() as ILLabel ?? new ILLabel()
            {
                Name = "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 ?? new ILLabel()
                        {
                            Name = "Block_" + (nextLabelIndex++).ToString()
                        };

                        // 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;
            return;
        }
Пример #5
0
        // This is before the expression is processed, so ILValue's and constants havn't been assigned



        public bool SimplifyTernaryOperator(List <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;

            ILExpression finalFall;
            ILLabel      finalFalseFall;
            ILLabel      finalTrueFall;

            if ((head.MatchLastAndBr(GMCode.Bt, out trueLabel, out condExpr, out falseLabel) ||
                 head.MatchLastAndBr(GMCode.Bf, out falseLabel, out condExpr, out trueLabel)) &&
                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[trueLabel]) &&
                labelToBasicBlock[trueFall].MatchLastAndBr(GMCode.Bf, out finalFalseFall, out finalFall, out finalTrueFall) &&
                finalFall.Code == GMCode.Pop
                ) // (finalFall == null || finalFall.Code == GMCode.Pop)
            {
                Debug.Assert(finalFall.Arguments.Count != 2);
                ILValue falseLocVar = falseExpr.Code == GMCode.Constant ? falseExpr.Operand as ILValue : null;
                ILValue trueLocVar  = trueExpr.Code == GMCode.Constant ? trueExpr.Operand as ILValue : null;
                Debug.Assert(falseLocVar != null || trueLocVar != null);
                ILExpression newExpr = null;
                // 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 (trueLocVar != null && trueLocVar.Type == GM_Type.Short && (trueLocVar == 0 || trueLocVar == 1))
                {
                    // It can be expressed as logical expression
                    if (trueLocVar != 0)
                    {
                        newExpr = MakeLeftAssociativeShortCircuit(GMCode.LogicOr, condExpr, falseExpr);
                    }
                    else
                    {
                        newExpr = MakeLeftAssociativeShortCircuit(GMCode.LogicAnd, new ILExpression(GMCode.Not, null, condExpr), falseExpr);
                    }
                }
                else if (falseLocVar != null && falseLocVar.Type == GM_Type.Short && (falseLocVar == 0 || falseLocVar == 1))
                {
                    // It can be expressed as logical expression
                    if (falseLocVar != 0)
                    {
                        newExpr = MakeLeftAssociativeShortCircuit(GMCode.LogicOr, new ILExpression(GMCode.Not, null, condExpr), trueExpr);
                    }
                    else
                    {
                        newExpr = MakeLeftAssociativeShortCircuit(GMCode.LogicAnd, condExpr, trueExpr);
                    }
                }
                Debug.Assert(newExpr != null);
                // head.Body.RemoveTail(ILCode.Brtrue, ILCode.Br);
                head.Body.RemoveRange(head.Body.Count - 2, 2);
                head.Body.Add(new ILExpression(GMCode.Bf, finalFalseFall, newExpr));
                head.Body.Add(new ILExpression(GMCode.B, finalTrueFall));

                // Remove the inlined branch from scope
                // body.RemoveOrThrow(nextBasicBlock);
                // Remove the old basic blocks
                body.RemoveOrThrow(labelToBasicBlock[trueLabel]);
                body.RemoveOrThrow(labelToBasicBlock[falseLabel]);
                body.RemoveOrThrow(labelToBasicBlock[trueFall]);
                return(true);
            }
            return(false);
        }
Пример #6
0
        public bool SimplifyShortCircuit(IList <ILNode> body, ILBasicBlock head, int pos)
        {
            Debug.Assert(body.Contains(head));
            // Debug.Assert((head.Body[0] as ILLabel).Name != "Block_54");
            ILExpression condExpr;
            ILLabel      trueLabel;
            ILLabel      falseLabel;

            // Ok, since we have not changed out all the Bf's to Bt like in ILSpy, we have to do them seperately
            // as I am getting bugs in my wahhoo about it
            if ((head.MatchLastAndBr(GMCode.Bf, out falseLabel, out condExpr, out trueLabel) ||
                 head.MatchLastAndBr(GMCode.Bt, out trueLabel, out condExpr, out falseLabel)) &&
                condExpr.Code != GMCode.Pop // its a terrtery so ignore it?
                )                           // I saw this too
            {
                GMCode code = (head.Body[head.Body.Count - 2] as ILExpression).Code;
                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);
                    negate = GMCode.Bt == code ? !negate : negate;
                    ILBasicBlock nextBasicBlock = labelToBasicBlock[nextLabel];
                    ILExpression nextCondExpr;
                    ILLabel      nextTrueLablel;
                    ILLabel      nextFalseLabel;
                    if (body.Contains(nextBasicBlock) &&
                        nextBasicBlock != head &&
                        labelGlobalRefCount[(ILLabel)nextBasicBlock.Body.First()] == 1 &&
                        (nextBasicBlock.MatchSingleAndBr(GMCode.Bf, out nextFalseLabel, out nextCondExpr, out nextTrueLablel) ||
                         nextBasicBlock.MatchSingleAndBr(GMCode.Bt, out nextTrueLablel, out nextCondExpr, out nextFalseLabel)) &&
                        nextCondExpr.Code != GMCode.Pop && // ugh
                        (otherLablel == nextFalseLabel || otherLablel == nextTrueLablel))
                    {
                        //     Debug.Assert(nextCondExpr.Arguments.Count != 2);
                        // Create short cicuit branch
                        ILExpression logicExpr;
                        if (otherLablel == nextFalseLabel)
                        {
                            logicExpr = MakeLeftAssociativeShortCircuit(GMCode.LogicAnd, negate ? new ILExpression(GMCode.Not, null, condExpr) : condExpr, nextCondExpr);
                        }
                        else
                        {
                            logicExpr = MakeLeftAssociativeShortCircuit(GMCode.LogicOr, negate ? condExpr : new ILExpression(GMCode.Not, null, condExpr), nextCondExpr);
                        }
                        //   head.Body.RemoveTail(GMCode.Bf, GMCode.B);
                        head.Body.RemoveRange(head.Body.Count - 2, 2);
                        head.Body.Add(new ILExpression(GMCode.Bf, nextFalseLabel, logicExpr));
                        head.Body.Add(new ILExpression(GMCode.B, nextTrueLablel));

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

                        return(true);
                    }
                }
            }

            return(false);
        }
Пример #7
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));
        }
Пример #8
0
        void TestAndFixWierdLoop(List <ILNode> body, ILBasicBlock head, int pos)
        {
            object       uvalue1;
            ILValue      value2;
            ILLabel      endLoop;
            ILLabel      startLoop;
            ILExpression filler;
            //Debug.Assert((head.Body[0] as ILLabel).Name != "L36");
            // Wierd one here.  I ran accross this a few times and I think this is generated code
            // for events.  Basicly, it pushes a constant on the stack and uses a repeat loop
            // however since I am not doing ANY kind of real stack/temporary analysis.  I would have
            // to rewrite and add a bunch of code to get that to work and right now its only a few functions
            // Its easyer to build a while loop out of it and let the decompiler handle it rather than
            // build a more robust stack anilizer
            // ugh have to make a new block for it too, meh
            int headLen = head.Body.Count;

            if (head.MatchAt(headLen - 6, GMCode.Push, out uvalue1) &&
                head.MatchAt(headLen - 5, GMCode.Dup) &&
                head.MatchAt(headLen - 4, GMCode.Push, out value2) &&

                head.MatchAt(headLen - 3, GMCode.Sle) &&
                head.MatchLastAndBr(GMCode.Bt, out endLoop, out filler, out startLoop))
            {
                // ok, lets rewrite the head so it makes sence
                ILLabel       newLoopStart = NewJunkLoop();
                ILVariable    genVar       = NewGeneratedVar();
                List <ILNode> newHead      = new List <ILNode>();
                for (int ii = 0; ii <= headLen - 7; ii++)
                {
                    newHead.Add(head.Body[ii]);                                       // add the front of it including the sub part
                }
                newHead.Add(new ILExpression(GMCode.Push, uvalue1));
                newHead.Add(new ILExpression(GMCode.Pop, genVar));
                newHead.Add(new ILExpression(GMCode.B, newLoopStart));
                ILBasicBlock newLoopBlock = new ILBasicBlock();
                newLoopBlock.Body.Add(newLoopStart);
                newLoopBlock.Body.Add(new ILExpression(GMCode.Push, genVar));
                newLoopBlock.Body.Add(new ILExpression(GMCode.Push, new ILValue(0)));

                newLoopBlock.Body.Add(new ILExpression(GMCode.Sgt, null));
                newLoopBlock.Body.Add(new ILExpression(GMCode.Bf, endLoop, new ILExpression(GMCode.Pop, null)));
                newLoopBlock.Body.Add(new ILExpression(GMCode.B, startLoop));
                head.Body = newHead;
                body.Add(newLoopBlock);
                // Now the hard part, we have to find the end bit
                for (int j = pos; j < body.Count; j++)
                {
                    ILBasicBlock bj = body[j] as ILBasicBlock;
                    ILLabel      testEnd, testStart;
                    ILValue      subPart;
                    int          len = bj.Body.Count;
                    //    Debug.Assert((bj.Body[0] as ILLabel).Name != "L114");
                    if (bj.MatchLastAndBr(GMCode.Bt, out testStart, out filler, out testEnd) &&
                        testEnd == endLoop && testStart == startLoop &&
                        bj.MatchAt(len - 3, GMCode.Dup) &&
                        bj.MatchAt(len - 4, GMCode.Sub) &&
                        bj.MatchAt(len - 5, GMCode.Push, out subPart)
                        )
                    {
                        List <ILNode> list2 = new List <ILNode>();
                        for (int ii = 0; ii <= len - 6; ii++)
                        {
                            list2.Add(bj.Body[ii]);                                   // add the front of it including the sub part
                        }
                        list2.Add(new ILExpression(GMCode.Push, genVar));
                        list2.Add(bj.Body[len - 5]);                         // add the sub part
                        list2.Add(bj.Body[len - 4]);                         // add the sub part
                        list2.Add(new ILExpression(GMCode.Pop, genVar));     // assign it
                        list2.Add(new ILExpression(GMCode.B, newLoopStart)); // branch back to the start
                        bj.Body = list2;                                     // replace
                        break;                                               // all done, let it continue
                    }
                }
                //  Debug.Assert(false); // coudln't find the end block
            }
        }
Пример #9
0
        void CreateSwitchExpresion(ILNode condition, List <ILNode> list, List <ILNode> body, ILBasicBlock head, int pos)
        {
            // we are in a case block, check if its the first block

            List <ILBasicBlock> caseBlocks       = new List <ILBasicBlock>();
            List <ILLabel>      caseLabels       = new List <ILLabel>();
            ILExpression        switchExpression = new ILExpression(GMCode.Switch, null);

            switchExpression.Arguments.Add(NodeToExpresion(condition)); // pop the switch condition
            ILBasicBlock current = head;
            ILLabel      nextCase;
            ILLabel      caseTrue;
            ILExpression fakeArgument;

            while (current.MatchLastAndBr(GMCode.Bt, out caseTrue, out fakeArgument, out nextCase))
            {
                ILNode operand;
                if (!current.MatchAt(current.Body.Count - 4, GMCode.Push, out operand))
                {
                    throw new Exception("fix");
                }
                if (!(operand is ILValue))
                {
                    throw new Exception("Can only handle constants right now");
                }
                switchExpression.Arguments.Add(new ILExpression(GMCode.Case, caseTrue, NodeToExpresion(operand)));
                caseLabels.Add(caseTrue);
                body.Remove(current);
                current = labelToBasicBlock[nextCase];
            }
            body.Insert(pos, head);

            var lastBlock = current;


            ILLabel fallLabel;

            if (!lastBlock.MatchSingle(GMCode.B, out fallLabel))
            {
                throw new Exception("fix");
            }
            current = labelToBasicBlock[fallLabel];
            if (!current.MatchAt(1, GMCode.Popz))
            { // has a default case
              // Side note, the LoopAndConditions figures out if we have a default case by checking
              // if the ending branch is linked to all the other case branches
              // so we don't need to do anything here
              // All this code is JUST for finding that popz that pops the condition out of the switch
              // if you don't care about it, you could just search though all the expresions and remove any and all
              // popz's  I am beggining to think this is the right way to do it as I don't see any other uses
              // of popz's
              //  Debug.Assert(false);
                BuildNextBlockData(); // build block chain, we need this for default and mabye case lookups
                                      // ok, this is why we DON'T want to remove redundent code as there is this empty
                                      // useless goto RIGHt after this that has the link to the finale case
                ILLabel nextBlockLabel = lastBlock.Body.First() as ILLabel;
                var     uselessBlock   = this.labelToNextBlock[nextBlockLabel];
                ILLabel newFallLabel;
                if (!uselessBlock.MatchSingle(GMCode.B, out newFallLabel))
                {
                    throw new Exception("fix");
                }
                current = labelToBasicBlock[newFallLabel];

                if (!current.MatchAt(1, GMCode.Popz))
                {
                    throw new Exception("I have no idea where the popz is for this switch");
                }
            }
            current.Body.RemoveAt(1);
            ILLabel lastBlockLabel = lastBlock.Body.First() as ILLabel;

            if (this.labelGlobalRefCount[lastBlockLabel] == 1)
            {
                body.Remove(lastBlockLabel);
            }
            switchExpression.Operand = caseLabels.ToArray();

            list.Add(switchExpression);
            list.Add(new ILExpression(GMCode.B, fallLabel));
        }
Пример #10
0
        Status ProcessExpression(List <ILNode> list, ILBasicBlock head, int pos, Stack <ILNode> stack)
        {
            ILExpression e = head.Body[pos] as ILExpression;

            if (e == null)
            {
                list.Add(head.Body[pos]);
                return(Status.NoChangeAdded);
            }
            ILValue    tempValue;
            ILVariable tempVar;

            switch (e.Code)
            {
            case GMCode.Push:
                tempValue = e.Operand as ILValue;
                tempVar   = e.Operand as ILVariable;
                if (tempValue != null)
                {
                    stack.Push(tempValue);
                }
                else if (tempVar != null)
                {
                    ProcessVar(tempVar, stack);
                    stack.Push(tempVar);
                }
                else
                {     // block comes back as a push expression
                    Debug.Assert(e.Arguments.Count > 0);
                    stack.Push(e.Arguments[0]);
                }
                return(Status.AddedToStack);

            case GMCode.Pop:     // convert to an assign
            {
                tempVar = e.Operand as ILVariable;
                Debug.Assert(tempVar != null);
                ILExpression expr = null;
                if (Dup1Seen)
                {
                    expr = NodeToExpresion(stack.Pop());                   // have to swap the assignment if a dup 1 was done
                }
                ProcessVar(tempVar, stack);
                e.Code    = GMCode.Assign;
                e.Operand = null;
                e.Arguments.Add(NodeToExpresion(tempVar));
                if (!Dup1Seen)
                {
                    expr = NodeToExpresion(stack.Pop());
                }
                e.Arguments.Add(expr);


                list.Add(e);
                return(Status.ChangedAdded);
            }

            case GMCode.Call:
            {
                if (e.Extra == -1)
                {
                    list.Add(e);
                    return(Status.NoChangeAdded);
                }         // its already resolved
                          //ILExpression call = new ILExpression(GMCode.Call, )
                          //ILCall call = new ILCall() { Name = e.Operand as string };
                          //for (int j = 0; j < e.Extra; j++) call.Arguments.Add(stack.Pop());
                if (e.Extra > 0)
                {
                    for (int j = 0; j < e.Extra; j++)
                    {
                        e.Arguments.Add(NodeToExpresion(stack.Pop()));
                    }
                }
                e.Extra = -1;
                stack.Push(e);
            }
                return(Status.AddedToStack);

            case GMCode.Popz:
            {
                if (stack.Count == 0)
                {
                    list.Add(e);
                    //  Debug.Assert(false);
                    return(Status.ChangedAdded);
                }
                else
                {
                    ILExpression call = stack.Peek() as ILExpression;
                    if (call != null && call.Code == GMCode.Call)
                    {
                        stack.Pop();
                        list.Add(call);
                        return(Status.ChangedAdded);
                    }
                    else
                    {
                        throw new Exception("popz on a non call?");          // return e; // else, ignore for switch
                    }
                }
            }

            case GMCode.Bf:
            case GMCode.Bt:
            case GMCode.Ret:
                if (stack.Count > 0)
                {
                    // Debug.Assert(stack.Count == 1);
                    e.Arguments[0] = NodeToExpresion(stack.Pop());
                    if (stack.Count > 0)
                    {
                        foreach (var n in stack)
                        {
                            list.Add(new ILExpression(GMCode.Push, null, NodeToExpresion(n)));
                        }
                    }
                    list.Add(e);
                    return(Status.ChangedAdded);
                }
                else
                {
                    list.Add(e);
                    return(Status.NoChangeAdded);
                }

            case GMCode.B:
            case GMCode.Exit:
                if (stack.Count > 0)
                {
                    foreach (var n in stack)
                    {
                        list.Add(new ILExpression(GMCode.Push, null, NodeToExpresion(n)));
                    }
                }
                list.Add(e);
                return(Status.ChangedAdded);

            case GMCode.Dup:
                if ((int)e.Operand == 0)
                {
                    stack.Push(stack.Peek());     // simple case
                    return(Status.DupStack0);
                }
                else
                {
                    // this is usally on an expression that uses a var multipual times so the instance and index is copyed
                    // HOWEVER the stack may need to be swaped
                    foreach (var n in stack.Reverse().ToArray())
                    {
                        stack.Push(n);   // copy the entire stack
                    }
                    Dup1Seen = true;     // usally this is on an assignment += -= of an array or such
                    return(Status.DupStack1);
                }

            default:     // ok we handle an expression
                if (e.Code.isExpression())
                {
                    for (int j = 0; j < e.Code.GetPopDelta(); j++)
                    {
                        if (stack.Count > 0)
                        {
                            e.Arguments.Add(NodeToExpresion(stack.Pop()));
                        }
                        else
                        {
                            e.Arguments.Add(new ILExpression(GMCode.Pop, null));
                        }
                    }

                    e.Arguments.Reverse(); // till I fix it latter, sigh
                    stack.Push(e);         // push expressions back
                    return(Status.AddedToStack);
                }
                else
                {
                    list.Add(e);
                    return(Status.NoChangeAdded);
                }
            }
            throw new Exception("Shouldn't get here?");
        }