private bool OptimizeBranches(ControlFlowGraph2 cfg)
        {
            bool hasChanges = false;

            foreach (var bb in cfg.BasicBlocks)
            {
                var ins = bb.Exit;

                if (ins.Registers.Count > 0 && ins.Registers[0].PreventOptimization)
                {
                    continue;
                }

                if (IsComparisonToRegister(ins.Code))
                {
                    hasChanges = OptimizeComparisonToConstZero(ins, bb) || hasChanges;
                }

                if (ins.Code.IsComparisonBranch() && ins.Next.Code == RCode.Goto)
                {
                    hasChanges = OptimizeBranchFollowedByGoto(ins, cfg) || hasChanges;
                }

                // Eliminate Predictable branches
                if (ins.Code.IsComparisonBranch() || ins.Code == RCode.Goto)
                {
                    hasChanges = OptimizePredictableBranch(ins, bb, cfg) || hasChanges;
                }
            }
            return(hasChanges);
        }
        private static bool OptimizeBranchFollowedByGoto(Instruction ins, ControlFlowGraph2 cfg)
        {
            // Redirect branches immediately followed by a goto
            // If they jump just after the goto, and we are the only
            // instruction reaching the goto.

            var branchTarget = (Instruction)ins.Operand;

            if (branchTarget != ins.Next.NextOrDefault)
            {
                return(false);
            }

            var gotoBlock = cfg.GetBlockFromEntry(ins.Next);

            // if there are other instructions reaching the goto, don't do anything.
            if (gotoBlock.EntryBlocks.Count() != 1)
            {
                return(false);
            }

            // invert the comparison and eliminate the goto
            ins.Code = ReverseComparison(ins.Code);
            cfg.RerouteBranch(ins, (Instruction)ins.Next.Operand);
            ins.Next.ConvertToNop();
            return(true);
        }
        private bool OptimizeBranches(ControlFlowGraph2 cfg)
        {
            bool hasChanges = false;

            foreach (var bb in cfg.BasicBlocks)
            {
                var ins = bb.Exit;

                if (ins.Registers.Count > 0 && ins.Registers[0].PreventOptimization)
                    continue;

                if (IsComparisonToRegister(ins.Code))
                    hasChanges = OptimizeComparisonToConstZero(ins, bb) || hasChanges;

                if (ins.Code.IsComparisonBranch() && ins.Next.Code == RCode.Goto)
                    hasChanges = OptimizeBranchFollowedByGoto(ins, cfg) || hasChanges;

                // Eliminate Predictable branches
                if (ins.Code.IsComparisonBranch() || ins.Code == RCode.Goto)
                {
                    hasChanges = OptimizePredictableBranch(ins, bb, cfg) || hasChanges;
                }
            }
            return hasChanges;
        }
        public bool Transform(Dex target, MethodBody body)
        {
            bool hasChanges = false;

            var graph = new ControlFlowGraph2(body);
            var registerUsage = new RegisterUsageMap2(graph);

            hasChanges = EliminateRegisterAssigments(registerUsage);
            
            return hasChanges;
        }
Example #5
0
        public bool Transform(Dex target, MethodBody body)
        {
            bool hasChanges = false;

            var graph         = new ControlFlowGraph2(body);
            var registerUsage = new RegisterUsageMap2(graph);

            hasChanges = EliminateRegisterAssigments(registerUsage);

            return(hasChanges);
        }
        /// <summary>
        /// This will eliminate or shortcut:
        ///     (1) zero-comparisons to a just set const
        ///     (2) branch to a branch when the second branch zero-compares to a
        ///         just set const before the first branch.
        //      (3) branch to a const immediatly followed by a zero-comparison
        //          to that same const.
        /// </summary>
        private bool OptimizePredictableBranch(Instruction ins, BasicBlock block, ControlFlowGraph2 cfg)
        {
            // (1) zero-comparisons to a just set const
            if (ins != block.Entry &&
                IsComparisonWithZero(ins.Code) && ins.Previous.Code == RCode.Const &&
                IsSameRegister(ins.Registers, ins.Previous.Registers))
            {
                if (WillTakeBranch(ins.Code, Convert.ToInt32(ins.Previous.Operand)))
                {
                    ins.Registers.Clear();
                    ins.Code = RCode.Goto;
                    return(true);
                }
                else
                {
                    ins.ConvertToNop();
                    return(true);
                }
            }

            // (2)  branch to a branch when the second branch zero-compares to a
            //      just set const before the first branch.
            var target = (Instruction)ins.Operand;

            if (ins != block.Entry &&
                IsComparisonWithZero(target.Code) && ins.Previous.Code == RCode.Const &&
                IsSameRegister(target.Registers, ins.Previous.Registers))
            {
                if (WillTakeBranch(target.Code, Convert.ToInt32(ins.Previous.Operand)))
                {
                    cfg.RerouteBranch(ins, (Instruction)target.Operand);
                }
                else
                {
                    cfg.RerouteBranch(ins, target.Next);
                }
                return(true);
            }

            // (3) branch to a const immediatly followed by a zero-comparison to that same const.
            //     We can only shortcut if the register is not read again after the branch.
            if (target.Code == RCode.Const && IsComparisonWithZero(target.Next.Code) &&
                IsSameRegister(target.Registers, target.Next.Registers))
            {
                var secondBranch = target.Next;
                var secondBlock  = cfg.GetBlockFromExit(secondBranch);

                var visited = new HashSet <BasicBlock> {
                    secondBlock
                };
                // we know the second block contains only two instructions.
                if (!IsRegisterReadAgain(target.Registers[0], secondBlock.ExitBlocks, visited))
                {
                    if (WillTakeBranch(secondBranch.Code, Convert.ToInt32(target.Operand)))
                    {
                        cfg.RerouteBranch(ins, (Instruction)target.Next.Operand);
                    }
                    else
                    {
                        cfg.RerouteBranch(ins, target.Next.Next);
                    }
                    return(true);
                }
            }

            return(false);
        }
        public bool Transform(Dex target, MethodBody body)
        {
            var cfg = new ControlFlowGraph2(body);

            return(OptimizeBranches(cfg));
        }
        /// <summary>
        /// This will eliminate or shortcut: 
        ///     (1) zero-comparisons to a just set const
        ///     (2) branch to a branch when the second branch zero-compares to a 
        ///         just set const before the first branch.
        //      (3) branch to a const immediatly followed by a zero-comparison
        //          to that same const.
        /// </summary>
        private bool OptimizePredictableBranch(Instruction ins, BasicBlock block, ControlFlowGraph2 cfg)
        {
            // (1) zero-comparisons to a just set const
            if (ins != block.Entry 
                && IsComparisonWithZero(ins.Code) && ins.Previous.Code == RCode.Const 
                && IsSameRegister(ins.Registers, ins.Previous.Registers))
            {
                if (WillTakeBranch(ins.Code, Convert.ToInt32(ins.Previous.Operand)))
                {
                    ins.Registers.Clear();
                    ins.Code = RCode.Goto;
                    return true;
                }
                else
                {
                    ins.ConvertToNop();
                    return true;
                }
            }

            // (2)  branch to a branch when the second branch zero-compares to a 
            //      just set const before the first branch.
            var target = (Instruction)ins.Operand;
            if (ins != block.Entry 
                && IsComparisonWithZero(target.Code) && ins.Previous.Code == RCode.Const 
                && IsSameRegister(target.Registers, ins.Previous.Registers))
            {
                if (WillTakeBranch(target.Code, Convert.ToInt32(ins.Previous.Operand)))
                    cfg.RerouteBranch(ins, (Instruction)target.Operand);
                else
                    cfg.RerouteBranch(ins, target.Next);
                return true;
            }

            // (3) branch to a const immediatly followed by a zero-comparison to that same const.
            //     We can only shortcut if the register is not read again after the branch.
            if (target.Code == RCode.Const && IsComparisonWithZero(target.Next.Code)
                && IsSameRegister(target.Registers, target.Next.Registers))
            {
                var secondBranch = target.Next;
                var secondBlock = cfg.GetBlockFromExit(secondBranch);

                var visited = new HashSet<BasicBlock> {secondBlock};
                    // we know the second block contains only two instructions. 
                if (!IsRegisterReadAgain(target.Registers[0], secondBlock.ExitBlocks, visited))
                {
                    if (WillTakeBranch(secondBranch.Code, Convert.ToInt32(target.Operand)))
                        cfg.RerouteBranch(ins, (Instruction)target.Next.Operand);
                    else
                        cfg.RerouteBranch(ins, target.Next.Next);
                    return true;
                }
            }

            return false;
        }
        private static bool OptimizeBranchFollowedByGoto(Instruction ins, ControlFlowGraph2 cfg)
        {
            // Redirect branches immediately followed by a goto
            // If they jump just after the goto, and we are the only
            // instruction reaching the goto.
            
            var branchTarget = (Instruction) ins.Operand;
            if (branchTarget != ins.Next.NextOrDefault) 
                return false;

            var gotoBlock = cfg.GetBlockFromEntry(ins.Next);

            // if there are other instructions reaching the goto, don't do anything.
            if (gotoBlock.EntryBlocks.Count() != 1) 
                return false;

            // invert the comparison and eliminate the goto
            ins.Code = ReverseComparison(ins.Code);
            cfg.RerouteBranch(ins, (Instruction)ins.Next.Operand);
            ins.Next.ConvertToNop();
            return true;
        }
 public bool Transform(Dex target, MethodBody body)
 {
     var cfg = new ControlFlowGraph2(body);
     return OptimizeBranches(cfg);
 }