/* * 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.back; import com.android.dx.rop.code.CstInsn; import com.android.dx.rop.cst.CstInteger; import com.android.dx.ssa.NormalSsaInsn; import com.android.dx.ssa.BasicRegisterMapper; import com.android.dx.ssa.RegisterMapper; import com.android.dx.ssa.SsaMethod; import com.android.dx.util.IntSet; import com.android.dx.util.BitIntSet; import java.util.BitSet; import java.util.ArrayList; /** * Allocates registers via a naive n^2 register allocator. * This allocator does not try to co-locate local variables or deal * intelligently with different size register uses. */ public class FirstFitAllocator extends RegisterAllocator { /** * If true, allocator places parameters at the top of the frame * in calling-convention order. */ private static final boolean PRESLOT_PARAMS = true; /** indexed by old reg; the set of old regs we've mapped */ private final BitSet mapped; /** {@inheritDoc} */ public FirstFitAllocator( final SsaMethod ssaMeth, final InterferenceGraph interference) { super(ssaMeth, interference); mapped = new BitSet(ssaMeth.getRegCount()); } /** {@inheritDoc} */ @Override public boolean wantsParamsMovedHigh() { return PRESLOT_PARAMS; } /** {@inheritDoc} */ @Override public RegisterMapper allocateRegisters() { int oldRegCount = ssaMeth.getRegCount(); BasicRegisterMapper mapper = new BasicRegisterMapper(oldRegCount); int nextNewRegister = 0; if (PRESLOT_PARAMS) { /* * Reserve space for the params at the bottom of the register * space. Later, we'll flip the params to the end of the register * space. */ nextNewRegister = ssaMeth.getParamWidth(); } for (int i = 0; i < oldRegCount; i++) { if (mapped.get(i)) { // we already got this one continue; } int maxCategory = getCategoryForSsaReg(i); IntSet current = new BitIntSet(oldRegCount); interference.mergeInterferenceSet(i, current); boolean isPreslotted = false; int newReg = 0; if (PRESLOT_PARAMS && isDefinitionMoveParam(i)) { // Any move-param definition must be a NormalSsaInsn NormalSsaInsn defInsn = (NormalSsaInsn) ssaMeth.getDefinitionForRegister(i); newReg = paramNumberFromMoveParam(defInsn); mapper.addMapping(i, newReg, maxCategory); isPreslotted = true; } else { mapper.addMapping(i, nextNewRegister, maxCategory); newReg = nextNewRegister; } for (int j = i + 1; j < oldRegCount; j++) { if (mapped.get(j) || isDefinitionMoveParam(j)) { continue; } /* * If reg j doesn't interfere with the current mapping. * Also, if this is a pre-slotted method parameter, we * can't use more than the original param width. */ if (!current.has(j) && !(isPreslotted && (maxCategory < getCategoryForSsaReg(j)))) { interference.mergeInterferenceSet(j, current); maxCategory = Math.max(maxCategory, getCategoryForSsaReg(j)); mapper.addMapping(j, newReg, maxCategory); mapped.set(j); } } mapped.set(i); if (!isPreslotted) { nextNewRegister += maxCategory; } } return mapper; } /** * Returns the parameter number that this move-param insn refers to * @param ndefInsn a move-param insn (otherwise, exceptions will be thrown) * @return parameter number (offset in the total parameter width) */ private int paramNumberFromMoveParam(NormalSsaInsn ndefInsn) { CstInsn origInsn = (CstInsn) ndefInsn.getOriginalRopInsn(); return ((CstInteger) origInsn.getConstant()).getValue(); } }