blob: 0f3f845cb2700e6604768e7685dfb759216c504a [file] [log] [blame]
/*
* 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.jack.dx.ssa;
import com.android.jack.dx.rop.code.RegisterSpec;
import com.android.jack.dx.rop.code.RegisterSpecList;
import com.android.jack.dx.ssa.back.InterferenceGraph;
import com.android.jack.dx.util.BitIntSet;
import com.android.jack.dx.util.IntSet;
import java.util.ArrayList;
/**
* A register mapper that keeps track of the accumulated interference
* information for the registers in the new namespace.
*
* Please note that this mapper requires that the old namespace does not
* have variable register widths/categories, and the new namespace does.
*/
public class InterferenceRegisterMapper extends BasicRegisterMapper {
/**
* Array of interference sets. ArrayList is indexed by new namespace
* and BitIntSet's are indexed by old namespace. The list expands
* as needed and missing items are assumed to interfere with nothing.
*
* Bit sets are always used here, unlike elsewhere, because the max
* size of this matrix will be (countSsaRegs * countRopRegs), which may
* grow to hundreds of K but not megabytes.
*/
private final ArrayList<BitIntSet> newRegInterference;
/** the interference graph for the old namespace */
private final InterferenceGraph oldRegInterference;
/**
* Constructs an instance
*
* @param countOldRegisters number of registers in old namespace
*/
public InterferenceRegisterMapper(InterferenceGraph oldRegInterference, int countOldRegisters) {
super(countOldRegisters);
newRegInterference = new ArrayList<BitIntSet>();
this.oldRegInterference = oldRegInterference;
}
/** {@inheritDoc} */
@Override
public void addMapping(int oldReg, int newReg, int category) {
super.addMapping(oldReg, newReg, category);
addInterfence(newReg, oldReg);
if (category == 2) {
addInterfence(newReg + 1, oldReg);
}
}
/**
* Checks to see if old namespace reg {@code oldReg} interferes
* with what currently maps to {@code newReg}.
*
* @param oldReg old namespace register
* @param newReg new namespace register
* @param category category of old namespace register
* @return true if oldReg will interfere with newReg
*/
public boolean interferes(int oldReg, int newReg, int category) {
if (newReg >= newRegInterference.size()) {
return false;
} else {
IntSet existing = newRegInterference.get(newReg);
if (existing == null) {
return false;
} else if (category == 1) {
return existing.has(oldReg);
} else {
return existing.has(oldReg) || (interferes(oldReg, newReg + 1, category - 1));
}
}
}
/**
* Checks to see if old namespace reg {@code oldReg} interferes
* with what currently maps to {@code newReg}.
*
* @param oldSpec {@code non-null;} old namespace register
* @param newReg new namespace register
* @return true if oldReg will interfere with newReg
*/
public boolean interferes(RegisterSpec oldSpec, int newReg) {
return interferes(oldSpec.getReg(), newReg, oldSpec.getCategory());
}
/**
* Adds a register's interference set to the interference list,
* growing it if necessary.
*
* @param newReg register in new namespace
* @param oldReg register in old namespace
*/
private void addInterfence(int newReg, int oldReg) {
newRegInterference.ensureCapacity(newReg + 1);
while (newReg >= newRegInterference.size()) {
newRegInterference.add(new BitIntSet(newReg + 1));
}
oldRegInterference.mergeInterferenceSet(oldReg, newRegInterference.get(newReg));
}
/**
* Checks to see if any of a set of old-namespace registers are
* pinned to the specified new-namespace reg + category. Takes into
* account the category of the old-namespace registers.
*
* @param oldSpecs {@code non-null;} set of old-namespace regs
* @param newReg {@code >= 0;} new-namespace register
* @param targetCategory {@code 1..2;} the number of adjacent new-namespace
* registers (starting at ropReg) to consider
* @return true if any of the old-namespace register have been mapped
* to the new-namespace register + category
*/
public boolean areAnyPinned(RegisterSpecList oldSpecs, int newReg, int targetCategory) {
int sz = oldSpecs.size();
for (int i = 0; i < sz; i++) {
RegisterSpec oldSpec = oldSpecs.get(i);
int r = oldToNew(oldSpec.getReg());
/*
* If oldSpec is a category-2 register, then check both newReg
* and newReg - 1.
*/
if (r == newReg || (oldSpec.getCategory() == 2 && (r + 1) == newReg)
|| (targetCategory == 2 && (r == newReg + 1))) {
return true;
}
}
return false;
}
}