• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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 /*
18  * This file contains codegen and support common to all supported
19  * Mips variants.  It is included by:
20  *
21  *        Codegen-$(TARGET_ARCH_VARIANT).c
22  *
23  * which combines this common code with specific support found in the
24  * applicable directory below this one.
25  */
26 
27 
28 /* Load a word at base + displacement.  Displacement must be word multiple */
loadWordDisp(CompilationUnit * cUnit,int rBase,int displacement,int rDest)29 static MipsLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
30                             int rDest)
31 {
32     return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, kWord,
33                         INVALID_SREG);
34 }
35 
storeWordDisp(CompilationUnit * cUnit,int rBase,int displacement,int rSrc)36 static MipsLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
37                              int displacement, int rSrc)
38 {
39     return storeBaseDisp(cUnit, rBase, displacement, rSrc, kWord);
40 }
41 
42 /*
43  * Load a Dalvik register into a physical register.  Take care when
44  * using this routine, as it doesn't perform any bookkeeping regarding
45  * register liveness.  That is the responsibility of the caller.
46  */
loadValueDirect(CompilationUnit * cUnit,RegLocation rlSrc,int reg1)47 static void loadValueDirect(CompilationUnit *cUnit, RegLocation rlSrc,
48                                 int reg1)
49 {
50     rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
51     if (rlSrc.location == kLocPhysReg) {
52         genRegCopy(cUnit, reg1, rlSrc.lowReg);
53     } else  if (rlSrc.location == kLocRetval) {
54         loadWordDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval), reg1);
55     } else {
56         assert(rlSrc.location == kLocDalvikFrame);
57         loadWordDisp(cUnit, rFP, dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2,
58                      reg1);
59     }
60 }
61 
62 /*
63  * Similar to loadValueDirect, but clobbers and allocates the target
64  * register.  Should be used when loading to a fixed register (for example,
65  * loading arguments to an out of line call.
66  */
loadValueDirectFixed(CompilationUnit * cUnit,RegLocation rlSrc,int reg1)67 static void loadValueDirectFixed(CompilationUnit *cUnit, RegLocation rlSrc,
68                                  int reg1)
69 {
70     dvmCompilerClobber(cUnit, reg1);
71     dvmCompilerMarkInUse(cUnit, reg1);
72     loadValueDirect(cUnit, rlSrc, reg1);
73 }
74 
75 /*
76  * Load a Dalvik register pair into a physical register[s].  Take care when
77  * using this routine, as it doesn't perform any bookkeeping regarding
78  * register liveness.  That is the responsibility of the caller.
79  */
loadValueDirectWide(CompilationUnit * cUnit,RegLocation rlSrc,int regLo,int regHi)80 static void loadValueDirectWide(CompilationUnit *cUnit, RegLocation rlSrc,
81                                 int regLo, int regHi)
82 {
83     rlSrc = dvmCompilerUpdateLocWide(cUnit, rlSrc);
84     if (rlSrc.location == kLocPhysReg) {
85         genRegCopyWide(cUnit, regLo, regHi, rlSrc.lowReg, rlSrc.highReg);
86     } else if (rlSrc.location == kLocRetval) {
87         loadBaseDispWide(cUnit, NULL, rSELF, offsetof(Thread, interpSave.retval),
88                          regLo, regHi, INVALID_SREG);
89     } else {
90         assert(rlSrc.location == kLocDalvikFrame);
91             loadBaseDispWide(cUnit, NULL, rFP,
92                              dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2,
93                              regLo, regHi, INVALID_SREG);
94     }
95 }
96 
97 /*
98  * Similar to loadValueDirect, but clobbers and allocates the target
99  * registers.  Should be used when loading to a fixed registers (for example,
100  * loading arguments to an out of line call.
101  */
loadValueDirectWideFixed(CompilationUnit * cUnit,RegLocation rlSrc,int regLo,int regHi)102 static void loadValueDirectWideFixed(CompilationUnit *cUnit, RegLocation rlSrc,
103                                      int regLo, int regHi)
104 {
105     dvmCompilerClobber(cUnit, regLo);
106     dvmCompilerClobber(cUnit, regHi);
107     dvmCompilerMarkInUse(cUnit, regLo);
108     dvmCompilerMarkInUse(cUnit, regHi);
109     loadValueDirectWide(cUnit, rlSrc, regLo, regHi);
110 }
111 
loadValue(CompilationUnit * cUnit,RegLocation rlSrc,RegisterClass opKind)112 static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc,
113                              RegisterClass opKind)
114 {
115     rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false);
116     if (rlSrc.location == kLocDalvikFrame) {
117         loadValueDirect(cUnit, rlSrc, rlSrc.lowReg);
118         rlSrc.location = kLocPhysReg;
119         dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
120     } else if (rlSrc.location == kLocRetval) {
121         loadWordDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval), rlSrc.lowReg);
122         rlSrc.location = kLocPhysReg;
123         dvmCompilerClobber(cUnit, rlSrc.lowReg);
124     }
125     return rlSrc;
126 }
127 
storeValue(CompilationUnit * cUnit,RegLocation rlDest,RegLocation rlSrc)128 static void storeValue(CompilationUnit *cUnit, RegLocation rlDest,
129                        RegLocation rlSrc)
130 {
131     LIR *defStart;
132     LIR *defEnd;
133     assert(!rlDest.wide);
134     assert(!rlSrc.wide);
135     dvmCompilerKillNullCheckedLoc(cUnit, rlDest);
136     rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
137     rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);
138     if (rlSrc.location == kLocPhysReg) {
139         if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) ||
140             (rlDest.location == kLocPhysReg)) {
141             // Src is live or Dest has assigned reg.
142             rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
143             genRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg);
144         } else {
145             // Just re-assign the registers.  Dest gets Src's regs
146             rlDest.lowReg = rlSrc.lowReg;
147             dvmCompilerClobber(cUnit, rlSrc.lowReg);
148         }
149     } else {
150         // Load Src either into promoted Dest or temps allocated for Dest
151         rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
152         loadValueDirect(cUnit, rlSrc, rlDest.lowReg);
153     }
154 
155     // Dest is now live and dirty (until/if we flush it to home location)
156     dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
157     dvmCompilerMarkDirty(cUnit, rlDest.lowReg);
158 
159 
160     if (rlDest.location == kLocRetval) {
161         storeBaseDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval),
162                       rlDest.lowReg, kWord);
163         dvmCompilerClobber(cUnit, rlDest.lowReg);
164     } else {
165         dvmCompilerResetDefLoc(cUnit, rlDest);
166         if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow)) {
167             defStart = (LIR *)cUnit->lastLIRInsn;
168             int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow);
169             storeBaseDisp(cUnit, rFP, vReg << 2, rlDest.lowReg, kWord);
170             dvmCompilerMarkClean(cUnit, rlDest.lowReg);
171             defEnd = (LIR *)cUnit->lastLIRInsn;
172             dvmCompilerMarkDef(cUnit, rlDest, defStart, defEnd);
173         }
174     }
175 }
176 
loadValueWide(CompilationUnit * cUnit,RegLocation rlSrc,RegisterClass opKind)177 static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc,
178                                  RegisterClass opKind)
179 {
180     assert(rlSrc.wide);
181     rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false);
182     if (rlSrc.location == kLocDalvikFrame) {
183         loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg);
184         rlSrc.location = kLocPhysReg;
185         dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
186         dvmCompilerMarkLive(cUnit, rlSrc.highReg,
187                             dvmCompilerSRegHi(rlSrc.sRegLow));
188     } else if (rlSrc.location == kLocRetval) {
189         loadBaseDispWide(cUnit, NULL, rSELF, offsetof(Thread, interpSave.retval),
190                          rlSrc.lowReg, rlSrc.highReg, INVALID_SREG);
191         rlSrc.location = kLocPhysReg;
192         dvmCompilerClobber(cUnit, rlSrc.lowReg);
193         dvmCompilerClobber(cUnit, rlSrc.highReg);
194     }
195     return rlSrc;
196 }
197 
storeValueWide(CompilationUnit * cUnit,RegLocation rlDest,RegLocation rlSrc)198 static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDest,
199                        RegLocation rlSrc)
200 {
201     LIR *defStart;
202     LIR *defEnd;
203     assert(FPREG(rlSrc.lowReg)==FPREG(rlSrc.highReg));
204     assert(rlDest.wide);
205     assert(rlSrc.wide);
206     dvmCompilerKillNullCheckedLoc(cUnit, rlDest);
207     if (rlSrc.location == kLocPhysReg) {
208         if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) ||
209             dvmCompilerIsLive(cUnit, rlSrc.highReg) ||
210             (rlDest.location == kLocPhysReg)) {
211             // Src is live or Dest has assigned reg.
212             rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
213             genRegCopyWide(cUnit, rlDest.lowReg, rlDest.highReg,
214                            rlSrc.lowReg, rlSrc.highReg);
215         } else {
216             // Just re-assign the registers.  Dest gets Src's regs
217             rlDest.lowReg = rlSrc.lowReg;
218             rlDest.highReg = rlSrc.highReg;
219             dvmCompilerClobber(cUnit, rlSrc.lowReg);
220             dvmCompilerClobber(cUnit, rlSrc.highReg);
221         }
222     } else {
223         // Load Src either into promoted Dest or temps allocated for Dest
224         rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
225         loadValueDirectWide(cUnit, rlSrc, rlDest.lowReg,
226                             rlDest.highReg);
227     }
228 
229     // Dest is now live and dirty (until/if we flush it to home location)
230     dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
231     dvmCompilerMarkLive(cUnit, rlDest.highReg,
232                         dvmCompilerSRegHi(rlDest.sRegLow));
233     dvmCompilerMarkDirty(cUnit, rlDest.lowReg);
234     dvmCompilerMarkDirty(cUnit, rlDest.highReg);
235     dvmCompilerMarkPair(cUnit, rlDest.lowReg, rlDest.highReg);
236 
237 
238     if (rlDest.location == kLocRetval) {
239         storeBaseDispWide(cUnit, rSELF, offsetof(Thread, interpSave.retval),
240                           rlDest.lowReg, rlDest.highReg);
241         dvmCompilerClobber(cUnit, rlDest.lowReg);
242         dvmCompilerClobber(cUnit, rlDest.highReg);
243     } else {
244         dvmCompilerResetDefLocWide(cUnit, rlDest);
245         if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow) ||
246             dvmCompilerLiveOut(cUnit, dvmCompilerSRegHi(rlDest.sRegLow))) {
247             defStart = (LIR *)cUnit->lastLIRInsn;
248             int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow);
249             assert((vReg+1) == dvmCompilerS2VReg(cUnit,
250                                      dvmCompilerSRegHi(rlDest.sRegLow)));
251             storeBaseDispWide(cUnit, rFP, vReg << 2, rlDest.lowReg,
252                               rlDest.highReg);
253             dvmCompilerMarkClean(cUnit, rlDest.lowReg);
254             dvmCompilerMarkClean(cUnit, rlDest.highReg);
255             defEnd = (LIR *)cUnit->lastLIRInsn;
256             dvmCompilerMarkDefWide(cUnit, rlDest, defStart, defEnd);
257         }
258     }
259 }
260 /*
261  * Perform null-check on a register. sReg is the ssa register being checked,
262  * and mReg is the machine register holding the actual value. If internal state
263  * indicates that sReg has been checked before the check request is ignored.
264  */
genNullCheck(CompilationUnit * cUnit,int sReg,int mReg,int dOffset,MipsLIR * pcrLabel)265 static MipsLIR *genNullCheck(CompilationUnit *cUnit, int sReg, int mReg,
266                                 int dOffset, MipsLIR *pcrLabel)
267 {
268     /* This particular Dalvik register has been null-checked */
269     if (dvmIsBitSet(cUnit->regPool->nullCheckedRegs, sReg)) {
270         return pcrLabel;
271     }
272     dvmSetBit(cUnit->regPool->nullCheckedRegs, sReg);
273     return genRegImmCheck(cUnit, kMipsCondEq, mReg, 0, dOffset, pcrLabel);
274 }
275 
276 
277 
278 /*
279  * Perform a "reg cmp reg" operation and jump to the PCR region if condition
280  * satisfies.
281  */
genRegRegCheck(CompilationUnit * cUnit,MipsConditionCode cond,int reg1,int reg2,int dOffset,MipsLIR * pcrLabel)282 static MipsLIR *genRegRegCheck(CompilationUnit *cUnit,
283                               MipsConditionCode cond,
284                               int reg1, int reg2, int dOffset,
285                               MipsLIR *pcrLabel)
286 {
287     MipsLIR *res = NULL;
288     if (cond == kMipsCondGe) { /* signed >= case */
289         int tReg = dvmCompilerAllocTemp(cUnit);
290         res = newLIR3(cUnit, kMipsSlt, tReg, reg1, reg2);
291         MipsLIR *branch = opCompareBranch(cUnit, kMipsBeqz, tReg, -1);
292         genCheckCommon(cUnit, dOffset, branch, pcrLabel);
293     } else if (cond == kMipsCondCs) {  /* unsigned >= case */
294         int tReg = dvmCompilerAllocTemp(cUnit);
295         res = newLIR3(cUnit, kMipsSltu, tReg, reg1, reg2);
296         MipsLIR *branch = opCompareBranch(cUnit, kMipsBeqz, tReg, -1);
297         genCheckCommon(cUnit, dOffset, branch, pcrLabel);
298     } else {
299         ALOGE("Unexpected condition in genRegRegCheck: %d\n", (int) cond);
300         dvmAbort();
301     }
302     return res;
303 }
304 
305 /*
306  * Perform zero-check on a register. Similar to genNullCheck but the value being
307  * checked does not have a corresponding Dalvik register.
308  */
genZeroCheck(CompilationUnit * cUnit,int mReg,int dOffset,MipsLIR * pcrLabel)309 static MipsLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
310                                 int dOffset, MipsLIR *pcrLabel)
311 {
312     return genRegImmCheck(cUnit, kMipsCondEq, mReg, 0, dOffset, pcrLabel);
313 }
314 
315 /* Perform bound check on two registers */
genBoundsCheck(CompilationUnit * cUnit,int rIndex,int rBound,int dOffset,MipsLIR * pcrLabel)316 static MipsLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
317                                   int rBound, int dOffset, MipsLIR *pcrLabel)
318 {
319     return genRegRegCheck(cUnit, kMipsCondCs, rIndex, rBound, dOffset,
320                             pcrLabel);
321 }
322 
323 /*
324  * Jump to the out-of-line handler to finish executing the
325  * remaining of more complex instructions.
326  */
genDispatchToHandler(CompilationUnit * cUnit,TemplateOpcode opCode)327 static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpcode opCode)
328 {
329     /*
330      * We're jumping from a trace to a template. Using jal is preferable to jalr,
331      * but we need to ensure source and target addresses allow the use of jal.
332      * This should almost always be the case, but if source and target are in
333      * different 256mb regions then use jalr.  The test below is very conservative
334      * since we don't have a source address yet, but this is ok for now given that
335      * we expect this case to be very rare. The test can be made less conservative
336      * as needed in the future in coordination with address assignment during
337      * the assembly process.
338      */
339     dvmCompilerClobberHandlerRegs(cUnit);
340     int targetAddr = (int) gDvmJit.codeCache + templateEntryOffsets[opCode];
341     int maxSourceAddr = (int) gDvmJit.codeCache + gDvmJit.codeCacheSize;
342 
343     if ((targetAddr & 0xF0000000) == (maxSourceAddr & 0xF0000000)) {
344         newLIR1(cUnit, kMipsJal, targetAddr);
345     } else {
346         loadConstant(cUnit, r_T9, targetAddr);
347         newLIR2(cUnit, kMipsJalr, r_RA, r_T9);
348     }
349 }
350