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 17package com.android.dx.ssa; 18 19import com.android.dx.rop.code.RegisterSpecList; 20import com.android.dx.rop.code.RegisterSpec; 21import com.android.dx.ssa.back.InterferenceGraph; 22import com.android.dx.util.IntSet; 23import com.android.dx.util.BitIntSet; 24 25import java.util.ArrayList; 26import java.util.BitSet; 27 28/** 29 * A register mapper that keeps track of the accumulated interference 30 * information for the registers in the new namespace. 31 * 32 * Please note that this mapper requires that the old namespace does not 33 * have variable register widths/categories, and the new namespace does. 34 */ 35public class InterferenceRegisterMapper extends BasicRegisterMapper { 36 /** 37 * Array of interference sets. ArrayList is indexed by new namespace 38 * and BitIntSet's are indexed by old namespace. The list expands 39 * as needed and missing items are assumed to interfere with nothing. 40 * 41 * Bit sets are always used here, unlike elsewhere, because the max 42 * size of this matrix will be (countSsaRegs * countRopRegs), which may 43 * grow to hundreds of K but not megabytes. 44 */ 45 private final ArrayList<BitIntSet> newRegInterference; 46 47 /** the interference graph for the old namespace */ 48 private final InterferenceGraph oldRegInterference; 49 50 /** 51 * Constructs an instance 52 * 53 * @param countOldRegisters number of registers in old namespace 54 */ 55 public InterferenceRegisterMapper(InterferenceGraph oldRegInterference, 56 int countOldRegisters) { 57 super(countOldRegisters); 58 59 newRegInterference = new ArrayList<BitIntSet>(); 60 this.oldRegInterference = oldRegInterference; 61 } 62 63 /** {@inheritDoc} */ 64 @Override 65 public void addMapping(int oldReg, int newReg, int category) { 66 super.addMapping(oldReg, newReg, category); 67 68 addInterfence(newReg, oldReg); 69 70 if (category == 2) { 71 addInterfence(newReg + 1, oldReg); 72 } 73 } 74 75 /** 76 * Checks to see if old namespace reg {@code oldReg} interferes 77 * with what currently maps to {@code newReg}. 78 * 79 * @param oldReg old namespace register 80 * @param newReg new namespace register 81 * @param category category of old namespace register 82 * @return true if oldReg will interfere with newReg 83 */ 84 public boolean interferes(int oldReg, int newReg, int category) { 85 if (newReg >= newRegInterference.size()) { 86 return false; 87 } else { 88 IntSet existing = newRegInterference.get(newReg); 89 90 if (existing == null) { 91 return false; 92 } else if (category == 1) { 93 return existing.has(oldReg); 94 } else { 95 return existing.has(oldReg) 96 || (interferes(oldReg, newReg+1, category-1)); 97 } 98 } 99 } 100 101 /** 102 * Checks to see if old namespace reg {@code oldReg} interferes 103 * with what currently maps to {@code newReg}. 104 * 105 * @param oldSpec {@code non-null;} old namespace register 106 * @param newReg new namespace register 107 * @return true if oldReg will interfere with newReg 108 */ 109 public boolean interferes(RegisterSpec oldSpec, int newReg) { 110 return interferes(oldSpec.getReg(), newReg, oldSpec.getCategory()); 111 } 112 113 /** 114 * Adds a register's interference set to the interference list, 115 * growing it if necessary. 116 * 117 * @param newReg register in new namespace 118 * @param oldReg register in old namespace 119 */ 120 private void addInterfence(int newReg, int oldReg) { 121 newRegInterference.ensureCapacity(newReg + 1); 122 123 while (newReg >= newRegInterference.size()) { 124 newRegInterference.add(new BitIntSet(newReg +1)); 125 } 126 127 oldRegInterference.mergeInterferenceSet( 128 oldReg, newRegInterference.get(newReg)); 129 } 130 131 /** 132 * Checks to see if any of a set of old-namespace registers are 133 * pinned to the specified new-namespace reg + category. Takes into 134 * account the category of the old-namespace registers. 135 * 136 * @param oldSpecs {@code non-null;} set of old-namespace regs 137 * @param newReg {@code >= 0;} new-namespace register 138 * @param targetCategory {@code 1..2;} the number of adjacent new-namespace 139 * registers (starting at ropReg) to consider 140 * @return true if any of the old-namespace register have been mapped 141 * to the new-namespace register + category 142 */ 143 public boolean areAnyPinned(RegisterSpecList oldSpecs, 144 int newReg, int targetCategory) { 145 int sz = oldSpecs.size(); 146 147 for (int i = 0; i < sz; i++) { 148 RegisterSpec oldSpec = oldSpecs.get(i); 149 int r = oldToNew(oldSpec.getReg()); 150 151 /* 152 * If oldSpec is a category-2 register, then check both newReg 153 * and newReg - 1. 154 */ 155 if (r == newReg 156 || (oldSpec.getCategory() == 2 && (r + 1) == newReg) 157 || (targetCategory == 2 && (r == newReg + 1))) { 158 return true; 159 } 160 } 161 162 return false; 163 } 164} 165