001/* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013package org.jikesrvm.compilers.opt.controlflow; 014 015import static org.jikesrvm.compilers.opt.ir.Operators.BBEND; 016import static org.jikesrvm.compilers.opt.ir.Operators.LABEL; 017 018import java.util.Enumeration; 019 020import org.jikesrvm.VM; 021import org.jikesrvm.compilers.opt.DefUse; 022import org.jikesrvm.compilers.opt.OptOptions; 023import org.jikesrvm.compilers.opt.driver.CompilerPhase; 024import org.jikesrvm.compilers.opt.ir.BasicBlock; 025import org.jikesrvm.compilers.opt.ir.IR; 026import org.jikesrvm.compilers.opt.ir.Instruction; 027import org.jikesrvm.compilers.opt.ir.Trap; 028import org.jikesrvm.compilers.opt.util.SpaceEffGraphNode; 029 030/** 031 * IR level independent driver for 032 * simple peephole optimizations of branches. 033 */ 034public abstract class BranchOptimizationDriver extends CompilerPhase { 035 036 /** 037 * Optimization level at which phase should be performed. 038 */ 039 private final int level; 040 041 /** 042 * Optimization level at which phase should be performed. 043 */ 044 private final boolean simplify; 045 046 /** 047 * @param level the minimum optimization level at which the branch 048 * optimizations should be performed. 049 * @param simplify perform simplification prior to optimization? 050 */ 051 BranchOptimizationDriver(int level, boolean simplify) { 052 this.level = level; 053 this.simplify = simplify; 054 } 055 056 /** 057 * @param level the minimum optimization level at which the branch 058 * optimizations should be performed. 059 */ 060 BranchOptimizationDriver(int level) { 061 this.level = level; 062 this.simplify = false; 063 } 064 065 /** Interface */ 066 @Override 067 public final boolean shouldPerform(OptOptions options) { 068 return options.getOptLevel() >= level; 069 } 070 071 @Override 072 public final String getName() { 073 return "Branch Optimizations"; 074 } 075 076 @Override 077 public final boolean printingEnabled(OptOptions options, boolean before) { 078 return false; 079 } 080 081 /** 082 * This phase contains no per-compilation instance fields. 083 */ 084 @Override 085 public final CompilerPhase newExecution(IR ir) { 086 return this; 087 } 088 089 /** 090 * Perform peephole branch optimizations. 091 * 092 * @param ir the IR to optimize 093 */ 094 @Override 095 public final void perform(IR ir) { 096 perform(ir, true); 097 } 098 099 public final void perform(IR ir, boolean renumber) { 100 if (simplify) { 101 applySimplify(ir); 102 } 103 104 maximizeBasicBlocks(ir); 105 if (VM.BuildForIA32) { 106 // spans-bb information is used for CMOV insertion 107 DefUse.recomputeSpansBasicBlock(ir); 108 } 109 boolean didSomething = false; 110 boolean didSomethingThisTime = true; 111 while (didSomethingThisTime) { 112 didSomething |= applyPeepholeBranchOpts(ir); 113 didSomethingThisTime = removeUnreachableCode(ir); 114 didSomething |= didSomethingThisTime; 115 } 116 if (didSomething) { 117 maximizeBasicBlocks(ir); 118 } 119 120 ir.cfg.compactNodeNumbering(); 121 122 if (ir.IRStage < IR.MIR) { 123 ir.pruneExceptionalOut(); 124 } 125 } 126 127 /** 128 * Perform branch simplifications. 129 * 130 * @param ir the IR to optimize 131 * @return was something reduced 132 */ 133 private static boolean applySimplify(IR ir) { 134 boolean didSomething = false; 135 for (Enumeration<BasicBlock> e = ir.getBasicBlocks(); e.hasMoreElements();) { 136 BasicBlock bb = e.nextElement(); 137 didSomething |= BranchSimplifier.simplify(bb, ir); 138 } 139 return didSomething; 140 } 141 142 /** 143 * This pass performs peephole branch optimizations. 144 * See Muchnick ~p.590 145 * 146 * @param ir the IR to optimize 147 * @return whether optimizations were applied 148 */ 149 protected boolean applyPeepholeBranchOpts(IR ir) { 150 boolean didSomething = false; 151 for (Enumeration<BasicBlock> e = ir.getBasicBlocks(); e.hasMoreElements();) { 152 BasicBlock bb = e.nextElement(); 153 if (!bb.isEmpty()) { 154 for (Enumeration<Instruction> ie = bb.enumerateBranchInstructions(); ie.hasMoreElements();) { 155 Instruction s = ie.nextElement(); 156 if (optimizeBranchInstruction(ir, s, bb)) { 157 didSomething = true; 158 // hack: we may have modified the instructions; start over 159 ie = bb.enumerateBranchInstructions(); 160 } 161 } 162 } 163 } 164 return didSomething; 165 } 166 167 /** 168 * This method actually does the work of attempting to 169 * peephole optimize a branch instruction. 170 * @param ir the containing IR 171 * @param s the branch instruction to optimize 172 * @param bb the containing basic block 173 * @return true if an optimization was applied, false otherwise 174 */ 175 protected abstract boolean optimizeBranchInstruction(IR ir, Instruction s, BasicBlock bb); 176 177 /** 178 * Remove unreachable code 179 * 180 * @param ir the IR to optimize 181 * @return true if did something, false otherwise 182 */ 183 protected final boolean removeUnreachableCode(IR ir) { 184 boolean result = false; 185 186 // (1) All code in a basic block after an unconditional 187 // trap instruction is dead. 188 for (Instruction s = ir.firstInstructionInCodeOrder(); s != null; s = s.nextInstructionInCodeOrder()) { 189 if (Trap.conforms(s)) { 190 Instruction p = s.nextInstructionInCodeOrder(); 191 if (p.operator() != BBEND) { 192 BasicBlock bb = s.getBasicBlock(); 193 do { 194 Instruction q = p; 195 p = p.nextInstructionInCodeOrder(); 196 q.remove(); 197 } while (p.operator() != BBEND); 198 bb.recomputeNormalOut(ir); 199 result = true; 200 } 201 } 202 } 203 204 // (2) perform a Depth-first search of the control flow graph, 205 // and remove any nodes not reachable from entry. 206 BasicBlock entry = ir.cfg.entry(); 207 ir.cfg.clearDFS(); 208 entry.sortDFS(); 209 for (SpaceEffGraphNode node = entry; node != null;) { 210 // save it now before removeFromCFGAndCodeOrder nulls it out!!! 211 SpaceEffGraphNode nextNode = node.getNext(); 212 if (!node.dfsVisited()) { 213 BasicBlock bb = (BasicBlock) node; 214 ir.cfg.removeFromCFGAndCodeOrder(bb); 215 result = true; 216 } 217 node = nextNode; 218 } 219 return result; 220 } 221 222 /** 223 * Merge adjacent basic blocks 224 * 225 * @param ir the IR to optimize 226 */ 227 protected final void maximizeBasicBlocks(IR ir) { 228 for (BasicBlock currBB = ir.cfg.firstInCodeOrder(); currBB != null;) { 229 if (currBB.mergeFallThrough(ir)) { 230 // don't advance currBB; it may have a new trivial fallthrough to swallow 231 } else { 232 currBB = currBB.nextBasicBlockInCodeOrder(); 233 } 234 } 235 } 236 237 // Helper functions 238 239 protected final Instruction firstLabelFollowing(Instruction s) { 240 for (s = s.nextInstructionInCodeOrder(); s != null; s = s.nextInstructionInCodeOrder()) { 241 if (s.operator() == LABEL) { 242 return s; 243 } 244 } 245 return null; 246 } 247 248 protected final Instruction firstRealInstructionFollowing(Instruction s) { 249 for (s = s.nextInstructionInCodeOrder(); s != null; s = s.nextInstructionInCodeOrder()) { 250 if (s.operator() != LABEL && s.operator() != BBEND) { 251 return s; 252 } 253 } 254 return s; 255 } 256}