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; }
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); }