Beispiel #1
0
 // somewhere, so bug, is leaving an empty block, I think because of switches
 public bool RemoveRedundentBlocks(IList <ILNode> body, ILBasicBlock head, int pos)
 {
     if (!labelGlobalRefCount.ContainsKey(head.EntryLabel()) && body.Contains(head))
     {
         if (head.Body.Count != 2)
         {
             // we have an empty block that has data in it? throw it as an error.
             // Might just be extra code like after an exit that was never used or a programer error but lets record it anyway
             error.Warning("BasicBlock with data removed, not linked to anything so should be safe", head);
         }
         body.RemoveOrThrow(head);
         return(true);
     }
     return(false);
 }
Beispiel #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);
        }
Beispiel #3
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);
        }
Beispiel #4
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);
        }