• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.back;
18 
19 import com.android.dx.rop.code.RegOps;
20 import com.android.dx.rop.code.RegisterSpec;
21 import com.android.dx.rop.code.PlainInsn;
22 import com.android.dx.rop.code.Rops;
23 import com.android.dx.rop.code.SourcePosition;
24 import com.android.dx.rop.code.RegisterSpecList;
25 import com.android.dx.ssa.NormalSsaInsn;
26 import com.android.dx.ssa.RegisterMapper;
27 import com.android.dx.ssa.SsaInsn;
28 import com.android.dx.ssa.SsaMethod;
29 import com.android.dx.ssa.SsaBasicBlock;
30 import com.android.dx.util.IntSet;
31 import com.android.dx.util.IntIterator;
32 
33 import java.util.BitSet;
34 import java.util.ArrayList;
35 
36 /**
37  * Base class of all register allocators.
38  */
39 public abstract class RegisterAllocator {
40     /** method being processed */
41     protected final SsaMethod ssaMeth;
42 
43     /** interference graph, indexed by register in both dimensions */
44     protected final InterferenceGraph interference;
45 
46     /**
47      * Creates an instance. Call {@code allocateRegisters} to run.
48      * @param ssaMeth method to process.
49      * @param interference Interference graph, indexed by register in both
50      * dimensions.
51      */
RegisterAllocator(SsaMethod ssaMeth, InterferenceGraph interference)52     public RegisterAllocator(SsaMethod ssaMeth,
53             InterferenceGraph interference) {
54         this.ssaMeth = ssaMeth;
55         this.interference = interference;
56     }
57 
58     /**
59      * Indicates whether the method params were allocated at the bottom
60      * of the namespace, and thus should be moved up to the top of the
61      * namespace after phi removal.
62      *
63      * @return {@code true} if params should be moved from low to high
64      */
wantsParamsMovedHigh()65     public abstract boolean wantsParamsMovedHigh();
66 
67     /**
68      * Runs the algorithm.
69      *
70      * @return a register mapper to apply to the {@code SsaMethod}
71      */
allocateRegisters()72     public abstract RegisterMapper allocateRegisters();
73 
74     /**
75      * Returns the category (width) of the definition site of the register.
76      * Returns {@code 1} for undefined registers.
77      *
78      * @param reg register
79      * @return {@code 1..2}
80      */
getCategoryForSsaReg(int reg)81     protected final int getCategoryForSsaReg(int reg) {
82         SsaInsn definition = ssaMeth.getDefinitionForRegister(reg);
83 
84         if (definition == null) {
85             // an undefined reg
86             return 1;
87         } else {
88             return definition.getResult().getCategory();
89         }
90     }
91 
92     /**
93      * Returns the RegisterSpec of the definition of the register.
94      *
95      * @param reg {@code >= 0;} SSA register
96      * @return definition spec of the register or null if it is never defined
97      * (for the case of "version 0" SSA registers)
98      */
getDefinitionSpecForSsaReg(int reg)99     protected final RegisterSpec getDefinitionSpecForSsaReg(int reg) {
100         SsaInsn definition = ssaMeth.getDefinitionForRegister(reg);
101 
102         return definition == null ? null : definition.getResult();
103     }
104 
105     /**
106      * Returns true if the definition site of this register is a
107      * move-param (ie, this is a method parameter).
108      *
109      * @param reg register in question
110      * @return {@code true} if this is a method parameter
111      */
isDefinitionMoveParam(int reg)112     protected boolean isDefinitionMoveParam(int reg) {
113         SsaInsn defInsn = ssaMeth.getDefinitionForRegister(reg);
114 
115         if (defInsn instanceof NormalSsaInsn) {
116             NormalSsaInsn ndefInsn = (NormalSsaInsn) defInsn;
117 
118             return ndefInsn.getOpcode().getOpcode() == RegOps.MOVE_PARAM;
119         }
120 
121         return false;
122     }
123 
124     /**
125      * Inserts a move instruction for a specified SSA register before a
126      * specified instruction, creating a new SSA register and adjusting the
127      * interference graph in the process. The insn currently must be the
128      * last insn in a block.
129      *
130      * @param insn {@code non-null;} insn to insert move before, must
131      * be last insn in block
132      * @param reg {@code non-null;} SSA register to duplicate
133      * @return {@code non-null;} spec of new SSA register created by move
134      */
insertMoveBefore(SsaInsn insn, RegisterSpec reg)135     protected final RegisterSpec insertMoveBefore(SsaInsn insn,
136             RegisterSpec reg) {
137         SsaBasicBlock block = insn.getBlock();
138         ArrayList<SsaInsn> insns = block.getInsns();
139         int insnIndex = insns.indexOf(insn);
140 
141         if (insnIndex < 0) {
142             throw new IllegalArgumentException (
143                     "specified insn is not in this block");
144         }
145 
146         if (insnIndex != insns.size() - 1) {
147             /*
148              * Presently, the interference updater only works when
149              * adding before the last insn, and the last insn must have no
150              * result
151              */
152             throw new IllegalArgumentException(
153                     "Adding move here not supported:" + insn.toHuman());
154         }
155 
156         /*
157          * Get new register and make new move instruction.
158          */
159 
160         // The new result must not have an associated local variable.
161         RegisterSpec newRegSpec = RegisterSpec.make(ssaMeth.makeNewSsaReg(),
162                 reg.getTypeBearer());
163 
164         SsaInsn toAdd = SsaInsn.makeFromRop(
165                 new PlainInsn(Rops.opMove(newRegSpec.getType()),
166                         SourcePosition.NO_INFO, newRegSpec,
167                         RegisterSpecList.make(reg)), block);
168 
169         insns.add(insnIndex, toAdd);
170 
171         int newReg = newRegSpec.getReg();
172 
173         /*
174          * Adjust interference graph based on what's live out of the current
175          * block and what's used by the final instruction.
176          */
177 
178         IntSet liveOut = block.getLiveOutRegs();
179         IntIterator liveOutIter = liveOut.iterator();
180 
181         while (liveOutIter.hasNext()) {
182             interference.add(newReg, liveOutIter.next());
183         }
184 
185         // Everything that's a source in the last insn interferes.
186         RegisterSpecList sources = insn.getSources();
187         int szSources = sources.size();
188 
189         for (int i = 0; i < szSources; i++) {
190             interference.add(newReg, sources.get(i).getReg());
191         }
192 
193         ssaMeth.onInsnsChanged();
194 
195         return newRegSpec;
196     }
197 }
198