Ejemplo n.º 1
0
        public static void Optimize(StructuredProgramContext context)
        {
            AstBlock mainBlock = context.CurrentFunction.MainBlock;

            // When debug mode is enabled, we disable expression propagation
            // (this makes comparison with the disassembly easier).
            if ((context.Config.Options.Flags & TranslationFlags.DebugMode) == 0)
            {
                AstBlockVisitor visitor = new AstBlockVisitor(mainBlock);

                foreach (IAstNode node in visitor.Visit())
                {
                    if (node is AstAssignment assignment && assignment.Destination is AstOperand propVar)
                    {
                        bool isWorthPropagating = propVar.Uses.Count == 1 || IsWorthPropagating(assignment.Source);

                        if (propVar.Defs.Count == 1 && isWorthPropagating)
                        {
                            PropagateExpression(propVar, assignment.Source);
                        }

                        if (propVar.Type == OperandType.LocalVariable && propVar.Uses.Count == 0)
                        {
                            visitor.Block.Remove(assignment);

                            context.CurrentFunction.Locals.Remove(propVar);
                        }
                    }
                }
            }

            RemoveEmptyBlocks(mainBlock);
        }
Ejemplo n.º 2
0
        private static void Lift(GotoStatement stmt)
        {
            AstBlock block = ParentBlock(stmt.Goto);

            AstBlock[] path = BackwardsPath(block, ParentBlock(stmt.Label));

            AstBlock loopFirstStmt = path[path.Length - 1];

            if (loopFirstStmt.Type == AstBlockType.Else)
            {
                loopFirstStmt = Previous(loopFirstStmt) as AstBlock;

                if (loopFirstStmt == null || loopFirstStmt.Type != AstBlockType.If)
                {
                    throw new InvalidOperationException("Found an else without a matching if.");
                }
            }

            AstBlock newBlock = EncloseDoWhile(stmt, block, loopFirstStmt);

            block.Remove(stmt.Goto);

            newBlock.AddFirst(stmt.Goto);

            stmt.IsLoop = false;
        }
Ejemplo n.º 3
0
        public static void Optimize(StructuredProgramInfo info)
        {
            AstBlock mainBlock = info.MainBlock;

            AstBlockVisitor visitor = new AstBlockVisitor(mainBlock);

            foreach (IAstNode node in visitor.Visit())
            {
                if (node is AstAssignment assignment && assignment.Destination is AstOperand propVar)
                {
                    bool isWorthPropagating = propVar.Uses.Count == 1 || IsWorthPropagating(assignment.Source);

                    if (propVar.Defs.Count == 1 && isWorthPropagating)
                    {
                        PropagateExpression(propVar, assignment.Source);
                    }

                    if (propVar.Type == OperandType.LocalVariable && propVar.Uses.Count == 0)
                    {
                        visitor.Block.Remove(assignment);

                        info.Locals.Remove(propVar);
                    }
                }
            }

            RemoveEmptyBlocks(mainBlock);
        }
Ejemplo n.º 4
0
        private static void EncloseSingleInst(GotoStatement stmt, Instruction inst)
        {
            AstBlock block = ParentBlock(stmt.Goto);

            AstBlock newBlock = new AstBlock(AstBlockType.If, stmt.Condition);

            block.AddAfter(stmt.Goto, newBlock);

            newBlock.AddFirst(new AstOperation(inst));
        }
Ejemplo n.º 5
0
        public StructuredProgramInfo(AstBlock mainBlock)
        {
            MainBlock = mainBlock;

            Locals = new HashSet <AstOperand>();

            CBuffers = new HashSet <int>();

            IAttributes = new HashSet <int>();
            OAttributes = new HashSet <int>();

            Samplers = new HashSet <AstTextureOperation>();
        }
Ejemplo n.º 6
0
        private static AstBlock[] BackwardsPath(AstBlock top, AstBlock bottom)
        {
            AstBlock block = bottom;

            List <AstBlock> path = new List <AstBlock>();

            while (block != top)
            {
                path.Add(block);

                block = block.Parent;
            }

            return(path.ToArray());
        }
Ejemplo n.º 7
0
        public StructuredFunction(
            AstBlock mainBlock,
            string name,
            VariableType returnType,
            VariableType[] inArguments,
            VariableType[] outArguments)
        {
            MainBlock    = mainBlock;
            Name         = name;
            ReturnType   = returnType;
            InArguments  = inArguments;
            OutArguments = outArguments;

            Locals = new HashSet <AstOperand>();
        }
        public StructuredProgramInfo(AstBlock mainBlock)
        {
            MainBlock = mainBlock;

            Locals = new HashSet <AstOperand>();

            CBuffers = new HashSet <int>();
            SBuffers = new HashSet <int>();

            IAttributes = new HashSet <int>();
            OAttributes = new HashSet <int>();

            InterpolationQualifiers = new InterpolationQualifier[32];

            Samplers = new HashSet <AstTextureOperation>();
            Images   = new HashSet <AstTextureOperation>();
        }
Ejemplo n.º 9
0
        private static void MoveInward(GotoStatement stmt)
        {
            AstBlock block = ParentBlock(stmt.Goto);

            AstBlock[] path = BackwardsPath(block, ParentBlock(stmt.Label));

            for (int index = path.Length - 1; index >= 0; index--)
            {
                AstBlock child = path[index];
                AstBlock last  = child;

                if (child.Type == AstBlockType.If)
                {
                    // Modify the if condition to allow it to be entered by the goto.
                    if (!ContainsCondComb(child.Condition, Instruction.LogicalOr, stmt.Condition))
                    {
                        child.OrCondition(stmt.Condition);
                    }
                }
                else if (child.Type == AstBlockType.Else)
                {
                    // Modify the matching if condition to force the else to be entered by the goto.
                    if (!(Previous(child) is AstBlock ifBlock) || ifBlock.Type != AstBlockType.If)
                    {
                        throw new InvalidOperationException("Found an else without a matching if.");
                    }

                    IAstNode cond = InverseCond(stmt.Condition);

                    if (!ContainsCondComb(ifBlock.Condition, Instruction.LogicalAnd, cond))
                    {
                        ifBlock.AndCondition(cond);
                    }

                    last = ifBlock;
                }

                Enclose(block, AstBlockType.If, stmt.Condition, Next(stmt.Goto), last);

                block.Remove(stmt.Goto);

                child.AddFirst(stmt.Goto);

                block = child;
            }
        }
Ejemplo n.º 10
0
        private static AstBlock Enclose(
            AstBlock block,
            AstBlockType type,
            IAstNode cond,
            IAstNode first,
            IAstNode last = null)
        {
            if (first == last)
            {
                return(null);
            }

            if (type == AstBlockType.If)
            {
                cond = InverseCond(cond);
            }

            // Do a quick check, if we are enclosing a single block,
            // and the block type/condition matches the one we're going
            // to create, then we don't need a new block, we can just
            // return the old one.
            bool hasSingleNode = Next(first) == last;

            if (hasSingleNode && BlockMatches(first, type, cond))
            {
                return(first as AstBlock);
            }

            AstBlock newBlock = new AstBlock(type, cond);

            block.AddBefore(first, newBlock);

            while (first != last)
            {
                IAstNode next = Next(first);

                block.Remove(first);

                newBlock.Add(first);

                first = next;
            }

            return(newBlock);
        }
Ejemplo n.º 11
0
        private static bool DirectlyRelated(AstBlock lBlock, AstBlock rBlock, int lLevel, int rLevel)
        {
            // If the levels are equal, they can be either siblings or indirectly related.
            if (lLevel == rLevel)
            {
                return(false);
            }

            IAstNode block;
            IAstNode other;

            int blockLvl, otherLvl;

            if (lLevel > rLevel)
            {
                block    = lBlock;
                blockLvl = lLevel;
                other    = rBlock;
                otherLvl = rLevel;
            }
            else /* if (rLevel > lLevel) */
            {
                block    = rBlock;
                blockLvl = rLevel;
                other    = lBlock;
                otherLvl = lLevel;
            }

            while (blockLvl >= otherLvl)
            {
                if (block == other)
                {
                    return(true);
                }

                block = block.Parent;

                blockLvl--;
            }

            return(false);
        }
Ejemplo n.º 12
0
        private static AstBlock EncloseDoWhile(GotoStatement stmt, AstBlock block, IAstNode first)
        {
            if (block.Type == AstBlockType.DoWhile && first == block.First)
            {
                // We only need to insert the continue if we're not at the end of the loop,
                // or if our condition is different from the loop condition.
                if (Next(stmt.Goto) != null || block.Condition != stmt.Condition)
                {
                    EncloseSingleInst(stmt, Instruction.LoopContinue);
                }

                // Modify the do-while condition to allow it to continue.
                if (!ContainsCondComb(block.Condition, Instruction.LogicalOr, stmt.Condition))
                {
                    block.OrCondition(stmt.Condition);
                }

                return(block);
            }

            return(Enclose(block, AstBlockType.DoWhile, stmt.Condition, first, stmt.Goto));
        }
Ejemplo n.º 13
0
        public IEnumerable <IAstNode> Visit()
        {
            IAstNode node = Block.First;

            while (node != null)
            {
                //We reached a child block, visit the nodes inside.
                while (node is AstBlock childBlock)
                {
                    Block = childBlock;

                    node = childBlock.First;

                    BlockEntered?.Invoke(this, new BlockVisitationEventArgs(Block));
                }

                //Node may be null, if the block is empty.
                if (node != null)
                {
                    IAstNode next = Next(node);

                    yield return(node);

                    node = next;
                }

                //We reached the end of the list, go up on tree to the parent blocks.
                while (node == null && Block.Type != AstBlockType.Main)
                {
                    BlockLeft?.Invoke(this, new BlockVisitationEventArgs(Block));

                    node = Next(Block);

                    Block = Block.Parent;
                }
            }
        }
Ejemplo n.º 14
0
        private static void RemoveEmptyBlocks(AstBlock mainBlock)
        {
            Queue <AstBlock> pending = new Queue <AstBlock>();

            pending.Enqueue(mainBlock);

            while (pending.TryDequeue(out AstBlock block))
            {
                foreach (IAstNode node in block)
                {
                    if (node is AstBlock childBlock)
                    {
                        pending.Enqueue(childBlock);
                    }
                }

                AstBlock parent = block.Parent;

                if (parent == null)
                {
                    continue;
                }

                AstBlock nextBlock = Next(block) as AstBlock;

                bool hasElse = nextBlock != null && nextBlock.Type == AstBlockType.Else;

                bool isIf = block.Type == AstBlockType.If;

                if (block.Count == 0)
                {
                    if (isIf)
                    {
                        if (hasElse)
                        {
                            nextBlock.TurnIntoIf(InverseCond(block.Condition));
                        }

                        parent.Remove(block);
                    }
                    else if (block.Type == AstBlockType.Else)
                    {
                        parent.Remove(block);
                    }
                }
                else if (isIf && parent.Type == AstBlockType.Else && parent.Count == (hasElse ? 2 : 1))
                {
                    AstBlock parentOfParent = parent.Parent;

                    parent.Remove(block);

                    parentOfParent.AddAfter(parent, block);

                    if (hasElse)
                    {
                        parent.Remove(nextBlock);

                        parentOfParent.AddAfter(block, nextBlock);
                    }

                    parentOfParent.Remove(parent);

                    block.TurnIntoElseIf();
                }
            }
        }
Ejemplo n.º 15
0
        // This is a modified version of the algorithm presented on the paper
        // "Taming Control Flow: A Structured Approach to Eliminating Goto Statements".
        public static void Eliminate(GotoStatement[] gotos)
        {
            for (int index = gotos.Length - 1; index >= 0; index--)
            {
                GotoStatement stmt = gotos[index];

                AstBlock gBlock = ParentBlock(stmt.Goto);
                AstBlock lBlock = ParentBlock(stmt.Label);

                int gLevel = Level(gBlock);
                int lLevel = Level(lBlock);

                if (IndirectlyRelated(gBlock, lBlock, gLevel, lLevel))
                {
                    AstBlock drBlock = gBlock;

                    int drLevel = gLevel;

                    do
                    {
                        drBlock = drBlock.Parent;

                        drLevel--;
                    }while (!DirectlyRelated(drBlock, lBlock, drLevel, lLevel));

                    MoveOutward(stmt, gLevel, drLevel);

                    gBlock = drBlock;
                    gLevel = drLevel;

                    if (Previous(stmt.Goto) is AstBlock elseBlock && elseBlock.Type == AstBlockType.Else)
                    {
                        // It's possible that the label was enclosed inside an else block,
                        // in this case we need to update the block and level.
                        // We also need to set the IsLoop for the case when the label is
                        // now before the goto, due to the newly introduced else block.
                        lBlock = ParentBlock(stmt.Label);

                        lLevel = Level(lBlock);

                        if (!IndirectlyRelated(elseBlock, lBlock, gLevel + 1, lLevel))
                        {
                            stmt.IsLoop = true;
                        }
                    }
                }

                if (DirectlyRelated(gBlock, lBlock, gLevel, lLevel))
                {
                    if (gLevel > lLevel)
                    {
                        MoveOutward(stmt, gLevel, lLevel);
                    }
                    else
                    {
                        if (stmt.IsLoop)
                        {
                            Lift(stmt);
                        }

                        MoveInward(stmt);
                    }
                }

                gBlock = ParentBlock(stmt.Goto);

                if (stmt.IsLoop)
                {
                    EncloseDoWhile(stmt, gBlock, stmt.Label);
                }
                else
                {
                    Enclose(gBlock, AstBlockType.If, stmt.Condition, Next(stmt.Goto), stmt.Label);
                }

                gBlock.Remove(stmt.Goto);
            }
        }
Ejemplo n.º 16
0
 public AstBlockVisitor(AstBlock mainBlock)
 {
     Block = mainBlock;
 }
Ejemplo n.º 17
0
 public BlockVisitationEventArgs(AstBlock block)
 {
     Block = block;
 }
Ejemplo n.º 18
0
        private static void MoveOutward(GotoStatement stmt, int gLevel, int lLevel)
        {
            AstBlock origin = ParentBlock(stmt.Goto);

            AstBlock block = origin;

            // Check if a loop is enclosing the goto, and the block that is
            // directly related to the label is above the loop block.
            // In that case, we need to introduce a break to get out of the loop.
            AstBlock loopBlock = origin;

            int loopLevel = gLevel;

            while (loopLevel > lLevel)
            {
                AstBlock child = loopBlock;

                loopBlock = loopBlock.Parent;

                loopLevel--;

                if (child.Type == AstBlockType.DoWhile)
                {
                    EncloseSingleInst(stmt, Instruction.LoopBreak);

                    block.Remove(stmt.Goto);

                    loopBlock.AddAfter(child, stmt.Goto);

                    block  = loopBlock;
                    gLevel = loopLevel;
                }
            }

            // Insert ifs to skip the parts that shouldn't be executed due to the goto.
            bool tryInsertElse = stmt.IsUnconditional && origin.Type == AstBlockType.If;

            while (gLevel > lLevel)
            {
                Enclose(block, AstBlockType.If, stmt.Condition, Next(stmt.Goto));

                block.Remove(stmt.Goto);

                AstBlock child = block;

                // We can't move the goto in the middle of a if and a else block, in
                // this case we need to move it after the else.
                // IsLoop may need to be updated if the label is inside the else, as
                // introducing a loop is the only way to ensure the else will be executed.
                if (Next(child) is AstBlock elseBlock && elseBlock.Type == AstBlockType.Else)
                {
                    child = elseBlock;
                }

                block = block.Parent;

                block.AddAfter(child, stmt.Goto);

                gLevel--;

                if (tryInsertElse && child == origin)
                {
                    AstBlock lBlock = ParentBlock(stmt.Label);

                    IAstNode last = block == lBlock && !stmt.IsLoop ? stmt.Label : null;

                    AstBlock newBlock = Enclose(block, AstBlockType.Else, null, Next(stmt.Goto), last);

                    if (newBlock != null)
                    {
                        block.Remove(stmt.Goto);

                        block.AddAfter(newBlock, stmt.Goto);
                    }
                }
            }
        }
Ejemplo n.º 19
0
 private static bool IndirectlyRelated(AstBlock lBlock, AstBlock rBlock, int lLevel, int rlevel)
 {
     return(!(lBlock == rBlock || DirectlyRelated(lBlock, rBlock, lLevel, rlevel)));
 }