1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.dx.ssa; 18 19 import com.android.dx.rop.code.RegisterSpec; 20 import com.android.dx.rop.code.RopMethod; 21 import com.android.dx.util.IntIterator; 22 import java.util.ArrayList; 23 import java.util.BitSet; 24 25 /** 26 * Converts ROP methods to SSA Methods 27 */ 28 public class SsaConverter { 29 public static final boolean DEBUG = false; 30 31 /** 32 * Returns an SSA representation, edge-split and with phi 33 * functions placed. 34 * 35 * @param rmeth input 36 * @param paramWidth the total width, in register-units, of the method's 37 * parameters 38 * @param isStatic {@code true} if this method has no {@code this} 39 * pointer argument 40 * @return output in SSA form 41 */ convertToSsaMethod(RopMethod rmeth, int paramWidth, boolean isStatic)42 public static SsaMethod convertToSsaMethod(RopMethod rmeth, 43 int paramWidth, boolean isStatic) { 44 SsaMethod result 45 = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic); 46 47 edgeSplit(result); 48 49 LocalVariableInfo localInfo = LocalVariableExtractor.extract(result); 50 51 placePhiFunctions(result, localInfo, 0); 52 new SsaRenamer(result).run(); 53 54 /* 55 * The exit block, added here, is not considered for edge splitting 56 * or phi placement since no actual control flows to it. 57 */ 58 result.makeExitBlock(); 59 60 return result; 61 } 62 63 /** 64 * Updates an SSA representation, placing phi functions and renaming all 65 * registers above a certain threshold number. 66 * 67 * @param ssaMeth input 68 * @param threshold registers below this number are unchanged 69 */ updateSsaMethod(SsaMethod ssaMeth, int threshold)70 public static void updateSsaMethod(SsaMethod ssaMeth, int threshold) { 71 LocalVariableInfo localInfo = LocalVariableExtractor.extract(ssaMeth); 72 placePhiFunctions(ssaMeth, localInfo, threshold); 73 new SsaRenamer(ssaMeth, threshold).run(); 74 } 75 76 /** 77 * Returns an SSA represention with only the edge-splitter run. 78 * 79 * @param rmeth method to process 80 * @param paramWidth width of all arguments in the method 81 * @param isStatic {@code true} if this method has no {@code this} 82 * pointer argument 83 * @return an SSA represention with only the edge-splitter run 84 */ testEdgeSplit(RopMethod rmeth, int paramWidth, boolean isStatic)85 public static SsaMethod testEdgeSplit (RopMethod rmeth, int paramWidth, 86 boolean isStatic) { 87 SsaMethod result; 88 89 result = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic); 90 91 edgeSplit(result); 92 return result; 93 } 94 95 /** 96 * Returns an SSA represention with only the steps through the 97 * phi placement run. 98 * 99 * @param rmeth method to process 100 * @param paramWidth width of all arguments in the method 101 * @param isStatic {@code true} if this method has no {@code this} 102 * pointer argument 103 * @return an SSA represention with only the edge-splitter run 104 */ testPhiPlacement(RopMethod rmeth, int paramWidth, boolean isStatic)105 public static SsaMethod testPhiPlacement (RopMethod rmeth, int paramWidth, 106 boolean isStatic) { 107 SsaMethod result; 108 109 result = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic); 110 111 edgeSplit(result); 112 113 LocalVariableInfo localInfo = LocalVariableExtractor.extract(result); 114 115 placePhiFunctions(result, localInfo, 0); 116 return result; 117 } 118 119 /** 120 * See Appel section 19.1: 121 * 122 * Converts CFG into "edge-split" form, such that each node either a 123 * unique successor or unique predecessor.<p> 124 * 125 * In addition, the SSA form we use enforces a further constraint, 126 * requiring each block with a final instruction that returns a 127 * value to have a primary successor that has no other 128 * predecessor. This ensures move statements can always be 129 * inserted correctly when phi statements are removed. 130 * 131 * @param result method to process 132 */ edgeSplit(SsaMethod result)133 private static void edgeSplit(SsaMethod result) { 134 edgeSplitPredecessors(result); 135 edgeSplitMoveExceptionsAndResults(result); 136 edgeSplitSuccessors(result); 137 } 138 139 /** 140 * Inserts Z nodes as new predecessors for every node that has multiple 141 * successors and multiple predecessors. 142 * 143 * @param result {@code non-null;} method to process 144 */ edgeSplitPredecessors(SsaMethod result)145 private static void edgeSplitPredecessors(SsaMethod result) { 146 ArrayList<SsaBasicBlock> blocks = result.getBlocks(); 147 148 /* 149 * New blocks are added to the end of the block list during 150 * this iteration. 151 */ 152 for (int i = blocks.size() - 1; i >= 0; i-- ) { 153 SsaBasicBlock block = blocks.get(i); 154 if (nodeNeedsUniquePredecessor(block)) { 155 block.insertNewPredecessor(); 156 } 157 } 158 } 159 160 /** 161 * @param block {@code non-null;} block in question 162 * @return {@code true} if this node needs to have a unique 163 * predecessor created for it 164 */ nodeNeedsUniquePredecessor(SsaBasicBlock block)165 private static boolean nodeNeedsUniquePredecessor(SsaBasicBlock block) { 166 /* 167 * Any block with that has both multiple successors and multiple 168 * predecessors needs a new predecessor node. 169 */ 170 171 int countPredecessors = block.getPredecessors().cardinality(); 172 int countSuccessors = block.getSuccessors().cardinality(); 173 174 return (countPredecessors > 1 && countSuccessors > 1); 175 } 176 177 /** 178 * In ROP form, move-exception must occur as the first insn in a block 179 * immediately succeeding the insn that could thrown an exception. 180 * We may need room to insert move insns later, so make sure to split 181 * any block that starts with a move-exception such that there is a 182 * unique move-exception block for each predecessor. 183 * 184 * @param ssaMeth method to process 185 */ edgeSplitMoveExceptionsAndResults(SsaMethod ssaMeth)186 private static void edgeSplitMoveExceptionsAndResults(SsaMethod ssaMeth) { 187 ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks(); 188 189 /* 190 * New blocks are added to the end of the block list during 191 * this iteration. 192 */ 193 for (int i = blocks.size() - 1; i >= 0; i-- ) { 194 SsaBasicBlock block = blocks.get(i); 195 196 /* 197 * Any block that starts with a move-exception and has more than 198 * one predecessor... 199 */ 200 if (!block.isExitBlock() 201 && block.getPredecessors().cardinality() > 1 202 && block.getInsns().get(0).isMoveException()) { 203 204 // block.getPredecessors() is changed in the loop below. 205 BitSet preds = (BitSet)block.getPredecessors().clone(); 206 for (int j = preds.nextSetBit(0); j >= 0; 207 j = preds.nextSetBit(j + 1)) { 208 SsaBasicBlock predecessor = blocks.get(j); 209 SsaBasicBlock zNode 210 = predecessor.insertNewSuccessor(block); 211 212 /* 213 * Make sure to place the move-exception as the 214 * first insn. 215 */ 216 zNode.getInsns().add(0, block.getInsns().get(0).clone()); 217 } 218 219 // Remove the move-exception from the original block. 220 block.getInsns().remove(0); 221 } 222 } 223 } 224 225 /** 226 * Inserts Z nodes for every node that needs a new 227 * successor. 228 * 229 * @param result {@code non-null;} method to process 230 */ edgeSplitSuccessors(SsaMethod result)231 private static void edgeSplitSuccessors(SsaMethod result) { 232 ArrayList<SsaBasicBlock> blocks = result.getBlocks(); 233 234 /* 235 * New blocks are added to the end of the block list during 236 * this iteration. 237 */ 238 for (int i = blocks.size() - 1; i >= 0; i-- ) { 239 SsaBasicBlock block = blocks.get(i); 240 241 // Successors list is modified in loop below. 242 BitSet successors = (BitSet)block.getSuccessors().clone(); 243 for (int j = successors.nextSetBit(0); 244 j >= 0; j = successors.nextSetBit(j+1)) { 245 246 SsaBasicBlock succ = blocks.get(j); 247 248 if (needsNewSuccessor(block, succ)) { 249 block.insertNewSuccessor(succ); 250 } 251 } 252 } 253 } 254 255 /** 256 * Returns {@code true} if block and successor need a Z-node 257 * between them. Presently, this is {@code true} if the final 258 * instruction has any sources or results and the current 259 * successor block has more than one predecessor. 260 * 261 * @param block predecessor node 262 * @param succ successor node 263 * @return {@code true} if a Z node is needed 264 */ needsNewSuccessor(SsaBasicBlock block, SsaBasicBlock succ)265 private static boolean needsNewSuccessor(SsaBasicBlock block, 266 SsaBasicBlock succ) { 267 ArrayList<SsaInsn> insns = block.getInsns(); 268 SsaInsn lastInsn = insns.get(insns.size() - 1); 269 270 return ((lastInsn.getResult() != null) 271 || (lastInsn.getSources().size() > 0)) 272 && succ.getPredecessors().cardinality() > 1; 273 } 274 275 /** 276 * See Appel algorithm 19.6: 277 * 278 * Place Phi functions in appropriate locations. 279 * 280 * @param ssaMeth {@code non-null;} method to process. 281 * Modifications are made in-place. 282 * @param localInfo {@code non-null;} local variable info, used 283 * when placing phis 284 * @param threshold registers below this number are ignored 285 */ placePhiFunctions(SsaMethod ssaMeth, LocalVariableInfo localInfo, int threshold)286 private static void placePhiFunctions (SsaMethod ssaMeth, 287 LocalVariableInfo localInfo, int threshold) { 288 ArrayList<SsaBasicBlock> ssaBlocks; 289 int regCount; 290 int blockCount; 291 292 ssaBlocks = ssaMeth.getBlocks(); 293 blockCount = ssaBlocks.size(); 294 regCount = ssaMeth.getRegCount() - threshold; 295 296 DomFront df = new DomFront(ssaMeth); 297 DomFront.DomInfo[] domInfos = df.run(); 298 299 // Bit set of registers vs block index "definition sites" 300 BitSet[] defsites = new BitSet[regCount]; 301 302 // Bit set of registers vs block index "phi placement sites" 303 BitSet[] phisites = new BitSet[regCount]; 304 305 for (int i = 0; i < regCount; i++) { 306 defsites[i] = new BitSet(blockCount); 307 phisites[i] = new BitSet(blockCount); 308 } 309 310 /* 311 * For each register, build a set of all basic blocks where 312 * containing an assignment to that register. 313 */ 314 for (int bi = 0, s = ssaBlocks.size(); bi < s; bi++) { 315 SsaBasicBlock b = ssaBlocks.get(bi); 316 317 for (SsaInsn insn : b.getInsns()) { 318 RegisterSpec rs = insn.getResult(); 319 320 if (rs != null && rs.getReg() - threshold >= 0) { 321 defsites[rs.getReg() - threshold].set(bi); 322 } 323 } 324 } 325 326 if (DEBUG) { 327 System.out.println("defsites"); 328 329 for (int i = 0; i < regCount; i++) { 330 StringBuilder sb = new StringBuilder(); 331 sb.append('v').append(i).append(": "); 332 sb.append(defsites[i].toString()); 333 System.out.println(sb); 334 } 335 } 336 337 BitSet worklist; 338 339 /* 340 * For each register, compute all locations for phi placement 341 * based on dominance-frontier algorithm. 342 */ 343 for (int reg = 0, s = regCount; reg < s; reg++) { 344 int workBlockIndex; 345 346 /* Worklist set starts out with each node where reg is assigned. */ 347 348 worklist = (BitSet) (defsites[reg].clone()); 349 350 while (0 <= (workBlockIndex = worklist.nextSetBit(0))) { 351 worklist.clear(workBlockIndex); 352 IntIterator dfIterator 353 = domInfos[workBlockIndex].dominanceFrontiers.iterator(); 354 355 while (dfIterator.hasNext()) { 356 int dfBlockIndex = dfIterator.next(); 357 358 if (!phisites[reg].get(dfBlockIndex)) { 359 phisites[reg].set(dfBlockIndex); 360 361 int tReg = reg + threshold; 362 RegisterSpec rs 363 = localInfo.getStarts(dfBlockIndex).get(tReg); 364 365 if (rs == null) { 366 ssaBlocks.get(dfBlockIndex).addPhiInsnForReg(tReg); 367 } else { 368 ssaBlocks.get(dfBlockIndex).addPhiInsnForReg(rs); 369 } 370 371 if (!defsites[reg].get(dfBlockIndex)) { 372 worklist.set(dfBlockIndex); 373 } 374 } 375 } 376 } 377 } 378 379 if (DEBUG) { 380 System.out.println("phisites"); 381 382 for (int i = 0; i < regCount; i++) { 383 StringBuilder sb = new StringBuilder(); 384 sb.append('v').append(i).append(": "); 385 sb.append(phisites[i].toString()); 386 System.out.println(sb); 387 } 388 } 389 } 390 } 391