summaryrefslogtreecommitdiff
path: root/dx/src/com/android/dx/ssa/SsaConverter.java
diff options
context:
space:
mode:
Diffstat (limited to 'dx/src/com/android/dx/ssa/SsaConverter.java')
-rw-r--r--dx/src/com/android/dx/ssa/SsaConverter.java391
1 files changed, 391 insertions, 0 deletions
diff --git a/dx/src/com/android/dx/ssa/SsaConverter.java b/dx/src/com/android/dx/ssa/SsaConverter.java
new file mode 100644
index 0000000..5cd8b6f
--- /dev/null
+++ b/dx/src/com/android/dx/ssa/SsaConverter.java
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dx.ssa;
+
+import com.android.dx.rop.code.RegisterSpec;
+import com.android.dx.rop.code.RopMethod;
+import com.android.dx.util.IntIterator;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+
+/**
+ * Converts ROP methods to SSA Methods
+ */
+public class SsaConverter {
+ public static final boolean DEBUG = false;
+
+ /**
+ * Returns an SSA representation, edge-split and with phi
+ * functions placed.
+ *
+ * @param rmeth input
+ * @param paramWidth the total width, in register-units, of the method's
+ * parameters
+ * @param isStatic {@code true} if this method has no {@code this}
+ * pointer argument
+ * @return output in SSA form
+ */
+ public static SsaMethod convertToSsaMethod(RopMethod rmeth,
+ int paramWidth, boolean isStatic) {
+ SsaMethod result
+ = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic);
+
+ edgeSplit(result);
+
+ LocalVariableInfo localInfo = LocalVariableExtractor.extract(result);
+
+ placePhiFunctions(result, localInfo, 0);
+ new SsaRenamer(result).run();
+
+ /*
+ * The exit block, added here, is not considered for edge splitting
+ * or phi placement since no actual control flows to it.
+ */
+ result.makeExitBlock();
+
+ return result;
+ }
+
+ /**
+ * Updates an SSA representation, placing phi functions and renaming all
+ * registers above a certain threshold number.
+ *
+ * @param ssaMeth input
+ * @param threshold registers below this number are unchanged
+ */
+ public static void updateSsaMethod(SsaMethod ssaMeth, int threshold) {
+ LocalVariableInfo localInfo = LocalVariableExtractor.extract(ssaMeth);
+ placePhiFunctions(ssaMeth, localInfo, threshold);
+ new SsaRenamer(ssaMeth, threshold).run();
+ }
+
+ /**
+ * Returns an SSA represention with only the edge-splitter run.
+ *
+ * @param rmeth method to process
+ * @param paramWidth width of all arguments in the method
+ * @param isStatic {@code true} if this method has no {@code this}
+ * pointer argument
+ * @return an SSA represention with only the edge-splitter run
+ */
+ public static SsaMethod testEdgeSplit (RopMethod rmeth, int paramWidth,
+ boolean isStatic) {
+ SsaMethod result;
+
+ result = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic);
+
+ edgeSplit(result);
+ return result;
+ }
+
+ /**
+ * Returns an SSA represention with only the steps through the
+ * phi placement run.
+ *
+ * @param rmeth method to process
+ * @param paramWidth width of all arguments in the method
+ * @param isStatic {@code true} if this method has no {@code this}
+ * pointer argument
+ * @return an SSA represention with only the edge-splitter run
+ */
+ public static SsaMethod testPhiPlacement (RopMethod rmeth, int paramWidth,
+ boolean isStatic) {
+ SsaMethod result;
+
+ result = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic);
+
+ edgeSplit(result);
+
+ LocalVariableInfo localInfo = LocalVariableExtractor.extract(result);
+
+ placePhiFunctions(result, localInfo, 0);
+ return result;
+ }
+
+ /**
+ * See Appel section 19.1:
+ *
+ * Converts CFG into "edge-split" form, such that each node either a
+ * unique successor or unique predecessor.<p>
+ *
+ * In addition, the SSA form we use enforces a further constraint,
+ * requiring each block with a final instruction that returns a
+ * value to have a primary successor that has no other
+ * predecessor. This ensures move statements can always be
+ * inserted correctly when phi statements are removed.
+ *
+ * @param result method to process
+ */
+ private static void edgeSplit(SsaMethod result) {
+ edgeSplitPredecessors(result);
+ edgeSplitMoveExceptionsAndResults(result);
+ edgeSplitSuccessors(result);
+ }
+
+ /**
+ * Inserts Z nodes as new predecessors for every node that has multiple
+ * successors and multiple predecessors.
+ *
+ * @param result {@code non-null;} method to process
+ */
+ private static void edgeSplitPredecessors(SsaMethod result) {
+ ArrayList<SsaBasicBlock> blocks = result.getBlocks();
+
+ /*
+ * New blocks are added to the end of the block list during
+ * this iteration.
+ */
+ for (int i = blocks.size() - 1; i >= 0; i-- ) {
+ SsaBasicBlock block = blocks.get(i);
+ if (nodeNeedsUniquePredecessor(block)) {
+ block.insertNewPredecessor();
+ }
+ }
+ }
+
+ /**
+ * @param block {@code non-null;} block in question
+ * @return {@code true} if this node needs to have a unique
+ * predecessor created for it
+ */
+ private static boolean nodeNeedsUniquePredecessor(SsaBasicBlock block) {
+ /*
+ * Any block with that has both multiple successors and multiple
+ * predecessors needs a new predecessor node.
+ */
+
+ int countPredecessors = block.getPredecessors().cardinality();
+ int countSuccessors = block.getSuccessors().cardinality();
+
+ return (countPredecessors > 1 && countSuccessors > 1);
+ }
+
+ /**
+ * In ROP form, move-exception must occur as the first insn in a block
+ * immediately succeeding the insn that could thrown an exception.
+ * We may need room to insert move insns later, so make sure to split
+ * any block that starts with a move-exception such that there is a
+ * unique move-exception block for each predecessor.
+ *
+ * @param ssaMeth method to process
+ */
+ private static void edgeSplitMoveExceptionsAndResults(SsaMethod ssaMeth) {
+ ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
+
+ /*
+ * New blocks are added to the end of the block list during
+ * this iteration.
+ */
+ for (int i = blocks.size() - 1; i >= 0; i-- ) {
+ SsaBasicBlock block = blocks.get(i);
+
+ /*
+ * Any block that starts with a move-exception and has more than
+ * one predecessor...
+ */
+ if (!block.isExitBlock()
+ && block.getPredecessors().cardinality() > 1
+ && block.getInsns().get(0).isMoveException()) {
+
+ // block.getPredecessors() is changed in the loop below.
+ BitSet preds = (BitSet)block.getPredecessors().clone();
+ for (int j = preds.nextSetBit(0); j >= 0;
+ j = preds.nextSetBit(j + 1)) {
+ SsaBasicBlock predecessor = blocks.get(j);
+ SsaBasicBlock zNode
+ = predecessor.insertNewSuccessor(block);
+
+ /*
+ * Make sure to place the move-exception as the
+ * first insn.
+ */
+ zNode.getInsns().add(0, block.getInsns().get(0).clone());
+ }
+
+ // Remove the move-exception from the original block.
+ block.getInsns().remove(0);
+ }
+ }
+ }
+
+ /**
+ * Inserts Z nodes for every node that needs a new
+ * successor.
+ *
+ * @param result {@code non-null;} method to process
+ */
+ private static void edgeSplitSuccessors(SsaMethod result) {
+ ArrayList<SsaBasicBlock> blocks = result.getBlocks();
+
+ /*
+ * New blocks are added to the end of the block list during
+ * this iteration.
+ */
+ for (int i = blocks.size() - 1; i >= 0; i-- ) {
+ SsaBasicBlock block = blocks.get(i);
+
+ // Successors list is modified in loop below.
+ BitSet successors = (BitSet)block.getSuccessors().clone();
+ for (int j = successors.nextSetBit(0);
+ j >= 0; j = successors.nextSetBit(j+1)) {
+
+ SsaBasicBlock succ = blocks.get(j);
+
+ if (needsNewSuccessor(block, succ)) {
+ block.insertNewSuccessor(succ);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns {@code true} if block and successor need a Z-node
+ * between them. Presently, this is {@code true} if the final
+ * instruction has any sources or results and the current
+ * successor block has more than one predecessor.
+ *
+ * @param block predecessor node
+ * @param succ successor node
+ * @return {@code true} if a Z node is needed
+ */
+ private static boolean needsNewSuccessor(SsaBasicBlock block,
+ SsaBasicBlock succ) {
+ ArrayList<SsaInsn> insns = block.getInsns();
+ SsaInsn lastInsn = insns.get(insns.size() - 1);
+
+ return ((lastInsn.getResult() != null)
+ || (lastInsn.getSources().size() > 0))
+ && succ.getPredecessors().cardinality() > 1;
+ }
+
+ /**
+ * See Appel algorithm 19.6:
+ *
+ * Place Phi functions in appropriate locations.
+ *
+ * @param ssaMeth {@code non-null;} method to process.
+ * Modifications are made in-place.
+ * @param localInfo {@code non-null;} local variable info, used
+ * when placing phis
+ * @param threshold registers below this number are ignored
+ */
+ private static void placePhiFunctions (SsaMethod ssaMeth,
+ LocalVariableInfo localInfo, int threshold) {
+ ArrayList<SsaBasicBlock> ssaBlocks;
+ int regCount;
+ int blockCount;
+
+ ssaBlocks = ssaMeth.getBlocks();
+ blockCount = ssaBlocks.size();
+ regCount = ssaMeth.getRegCount() - threshold;
+
+ DomFront df = new DomFront(ssaMeth);
+ DomFront.DomInfo[] domInfos = df.run();
+
+ // Bit set of registers vs block index "definition sites"
+ BitSet[] defsites = new BitSet[regCount];
+
+ // Bit set of registers vs block index "phi placement sites"
+ BitSet[] phisites = new BitSet[regCount];
+
+ for (int i = 0; i < regCount; i++) {
+ defsites[i] = new BitSet(blockCount);
+ phisites[i] = new BitSet(blockCount);
+ }
+
+ /*
+ * For each register, build a set of all basic blocks where
+ * containing an assignment to that register.
+ */
+ for (int bi = 0, s = ssaBlocks.size(); bi < s; bi++) {
+ SsaBasicBlock b = ssaBlocks.get(bi);
+
+ for (SsaInsn insn : b.getInsns()) {
+ RegisterSpec rs = insn.getResult();
+
+ if (rs != null && rs.getReg() - threshold >= 0) {
+ defsites[rs.getReg() - threshold].set(bi);
+ }
+ }
+ }
+
+ if (DEBUG) {
+ System.out.println("defsites");
+
+ for (int i = 0; i < regCount; i++) {
+ StringBuilder sb = new StringBuilder();
+ sb.append('v').append(i).append(": ");
+ sb.append(defsites[i].toString());
+ System.out.println(sb);
+ }
+ }
+
+ BitSet worklist;
+
+ /*
+ * For each register, compute all locations for phi placement
+ * based on dominance-frontier algorithm.
+ */
+ for (int reg = 0, s = regCount; reg < s; reg++) {
+ int workBlockIndex;
+
+ /* Worklist set starts out with each node where reg is assigned. */
+
+ worklist = (BitSet) (defsites[reg].clone());
+
+ while (0 <= (workBlockIndex = worklist.nextSetBit(0))) {
+ worklist.clear(workBlockIndex);
+ IntIterator dfIterator
+ = domInfos[workBlockIndex].dominanceFrontiers.iterator();
+
+ while (dfIterator.hasNext()) {
+ int dfBlockIndex = dfIterator.next();
+
+ if (!phisites[reg].get(dfBlockIndex)) {
+ phisites[reg].set(dfBlockIndex);
+
+ int tReg = reg + threshold;
+ RegisterSpec rs
+ = localInfo.getStarts(dfBlockIndex).get(tReg);
+
+ if (rs == null) {
+ ssaBlocks.get(dfBlockIndex).addPhiInsnForReg(tReg);
+ } else {
+ ssaBlocks.get(dfBlockIndex).addPhiInsnForReg(rs);
+ }
+
+ if (!defsites[reg].get(dfBlockIndex)) {
+ worklist.set(dfBlockIndex);
+ }
+ }
+ }
+ }
+ }
+
+ if (DEBUG) {
+ System.out.println("phisites");
+
+ for (int i = 0; i < regCount; i++) {
+ StringBuilder sb = new StringBuilder();
+ sb.append('v').append(i).append(": ");
+ sb.append(phisites[i].toString());
+ System.out.println(sb);
+ }
+ }
+ }
+}