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