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 * ARM 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 */
29static ArmLIR *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
36static ArmLIR *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 */
47static 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, rGLUE, offsetof(InterpState, 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 */
67static 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 */
80static 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, rGLUE, offsetof(InterpState, 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 */
102static 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
112static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc,
113                             RegisterClass opKind)
114{
115    RegisterInfo *pReg;
116    rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false);
117    if (rlSrc.location == kLocDalvikFrame) {
118        loadValueDirect(cUnit, rlSrc, rlSrc.lowReg);
119        rlSrc.location = kLocPhysReg;
120        dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
121    } else if (rlSrc.location == kLocRetval) {
122        loadWordDisp(cUnit, rGLUE, offsetof(InterpState, retval), rlSrc.lowReg);
123        rlSrc.location = kLocPhysReg;
124        dvmCompilerClobber(cUnit, rlSrc.lowReg);
125    }
126    return rlSrc;
127}
128
129static void storeValue(CompilationUnit *cUnit, RegLocation rlDest,
130                       RegLocation rlSrc)
131{
132    RegisterInfo *pRegLo;
133    LIR *defStart;
134    LIR *defEnd;
135    assert(!rlDest.wide);
136    assert(!rlSrc.wide);
137    dvmCompilerKillNullCheckedLoc(cUnit, rlDest);
138    rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
139    rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);
140    if (rlSrc.location == kLocPhysReg) {
141        if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) ||
142            (rlDest.location == kLocPhysReg)) {
143            // Src is live or Dest has assigned reg.
144            rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
145            genRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg);
146        } else {
147            // Just re-assign the registers.  Dest gets Src's regs
148            rlDest.lowReg = rlSrc.lowReg;
149            dvmCompilerClobber(cUnit, rlSrc.lowReg);
150        }
151    } else {
152        // Load Src either into promoted Dest or temps allocated for Dest
153        rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
154        loadValueDirect(cUnit, rlSrc, rlDest.lowReg);
155    }
156
157    // Dest is now live and dirty (until/if we flush it to home location)
158    dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
159    dvmCompilerMarkDirty(cUnit, rlDest.lowReg);
160
161
162    if (rlDest.location == kLocRetval) {
163        storeBaseDisp(cUnit, rGLUE, offsetof(InterpState, retval),
164                      rlDest.lowReg, kWord);
165        dvmCompilerClobber(cUnit, rlDest.lowReg);
166    } else {
167        dvmCompilerResetDefLoc(cUnit, rlDest);
168        if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow)) {
169            defStart = (LIR *)cUnit->lastLIRInsn;
170            int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow);
171            storeBaseDisp(cUnit, rFP, vReg << 2, rlDest.lowReg, kWord);
172            dvmCompilerMarkClean(cUnit, rlDest.lowReg);
173            defEnd = (LIR *)cUnit->lastLIRInsn;
174            dvmCompilerMarkDef(cUnit, rlDest, defStart, defEnd);
175        }
176    }
177}
178
179static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc,
180                                 RegisterClass opKind)
181{
182    RegisterInfo *pRegLo;
183    RegisterInfo *pRegHi;
184    assert(rlSrc.wide);
185    rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false);
186    if (rlSrc.location == kLocDalvikFrame) {
187        loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg);
188        rlSrc.location = kLocPhysReg;
189        dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
190        dvmCompilerMarkLive(cUnit, rlSrc.highReg,
191                            dvmCompilerSRegHi(rlSrc.sRegLow));
192    } else if (rlSrc.location == kLocRetval) {
193        loadBaseDispWide(cUnit, NULL, rGLUE, offsetof(InterpState, retval),
194                         rlSrc.lowReg, rlSrc.highReg, INVALID_SREG);
195        rlSrc.location = kLocPhysReg;
196        dvmCompilerClobber(cUnit, rlSrc.lowReg);
197        dvmCompilerClobber(cUnit, rlSrc.highReg);
198    }
199    return rlSrc;
200}
201
202static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDest,
203                       RegLocation rlSrc)
204{
205    RegisterInfo *pRegLo;
206    RegisterInfo *pRegHi;
207    LIR *defStart;
208    LIR *defEnd;
209    bool srcFP = FPREG(rlSrc.lowReg) && FPREG(rlSrc.highReg);
210    assert(FPREG(rlSrc.lowReg)==FPREG(rlSrc.highReg));
211    assert(rlDest.wide);
212    assert(rlSrc.wide);
213    dvmCompilerKillNullCheckedLoc(cUnit, rlDest);
214    if (rlSrc.location == kLocPhysReg) {
215        if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) ||
216            dvmCompilerIsLive(cUnit, rlSrc.highReg) ||
217            (rlDest.location == kLocPhysReg)) {
218            // Src is live or Dest has assigned reg.
219            rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
220            genRegCopyWide(cUnit, rlDest.lowReg, rlDest.highReg,
221                           rlSrc.lowReg, rlSrc.highReg);
222        } else {
223            // Just re-assign the registers.  Dest gets Src's regs
224            rlDest.lowReg = rlSrc.lowReg;
225            rlDest.highReg = rlSrc.highReg;
226            dvmCompilerClobber(cUnit, rlSrc.lowReg);
227            dvmCompilerClobber(cUnit, rlSrc.highReg);
228        }
229    } else {
230        // Load Src either into promoted Dest or temps allocated for Dest
231        rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
232        loadValueDirectWide(cUnit, rlSrc, rlDest.lowReg,
233                            rlDest.highReg);
234    }
235
236    // Dest is now live and dirty (until/if we flush it to home location)
237    dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
238    dvmCompilerMarkLive(cUnit, rlDest.highReg,
239                        dvmCompilerSRegHi(rlDest.sRegLow));
240    dvmCompilerMarkDirty(cUnit, rlDest.lowReg);
241    dvmCompilerMarkDirty(cUnit, rlDest.highReg);
242    dvmCompilerMarkPair(cUnit, rlDest.lowReg, rlDest.highReg);
243
244
245    if (rlDest.location == kLocRetval) {
246        storeBaseDispWide(cUnit, rGLUE, offsetof(InterpState, retval),
247                          rlDest.lowReg, rlDest.highReg);
248        dvmCompilerClobber(cUnit, rlDest.lowReg);
249        dvmCompilerClobber(cUnit, rlDest.highReg);
250    } else {
251        dvmCompilerResetDefLocWide(cUnit, rlDest);
252        if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow) ||
253            dvmCompilerLiveOut(cUnit, dvmCompilerSRegHi(rlDest.sRegLow))) {
254            defStart = (LIR *)cUnit->lastLIRInsn;
255            int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow);
256            assert((vReg+1) == dvmCompilerS2VReg(cUnit,
257                                     dvmCompilerSRegHi(rlDest.sRegLow)));
258            storeBaseDispWide(cUnit, rFP, vReg << 2, rlDest.lowReg,
259                              rlDest.highReg);
260            dvmCompilerMarkClean(cUnit, rlDest.lowReg);
261            dvmCompilerMarkClean(cUnit, rlDest.highReg);
262            defEnd = (LIR *)cUnit->lastLIRInsn;
263            dvmCompilerMarkDefWide(cUnit, rlDest, defStart, defEnd);
264        }
265    }
266}
267/*
268 * Perform null-check on a register. sReg is the ssa register being checked,
269 * and mReg is the machine register holding the actual value. If internal state
270 * indicates that sReg has been checked before the check request is ignored.
271 */
272static ArmLIR *genNullCheck(CompilationUnit *cUnit, int sReg, int mReg,
273                                int dOffset, ArmLIR *pcrLabel)
274{
275    /* This particular Dalvik register has been null-checked */
276    if (dvmIsBitSet(cUnit->regPool->nullCheckedRegs, sReg)) {
277        return pcrLabel;
278    }
279    dvmSetBit(cUnit->regPool->nullCheckedRegs, sReg);
280    return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel);
281}
282
283
284
285/*
286 * Perform a "reg cmp reg" operation and jump to the PCR region if condition
287 * satisfies.
288 */
289static ArmLIR *genRegRegCheck(CompilationUnit *cUnit,
290                              ArmConditionCode cond,
291                              int reg1, int reg2, int dOffset,
292                              ArmLIR *pcrLabel)
293{
294    ArmLIR *res;
295    res = opRegReg(cUnit, kOpCmp, reg1, reg2);
296    ArmLIR *branch = opCondBranch(cUnit, cond);
297    genCheckCommon(cUnit, dOffset, branch, pcrLabel);
298    return res;
299}
300
301/*
302 * Perform zero-check on a register. Similar to genNullCheck but the value being
303 * checked does not have a corresponding Dalvik register.
304 */
305static ArmLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
306                                int dOffset, ArmLIR *pcrLabel)
307{
308    return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel);
309}
310
311/* Perform bound check on two registers */
312static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
313                                  int rBound, int dOffset, ArmLIR *pcrLabel)
314{
315    return genRegRegCheck(cUnit, kArmCondCs, rIndex, rBound, dOffset,
316                            pcrLabel);
317}
318
319/*
320 * Jump to the out-of-line handler in ARM mode to finish executing the
321 * remaining of more complex instructions.
322 */
323static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode)
324{
325    /*
326     * NOTE - In practice BLX only needs one operand, but since the assembler
327     * may abort itself and retry due to other out-of-range conditions we
328     * cannot really use operand[0] to store the absolute target address since
329     * it may get clobbered by the final relative offset. Therefore,
330     * we fake BLX_1 is a two operand instruction and the absolute target
331     * address is stored in operand[1].
332     */
333    dvmCompilerClobberHandlerRegs(cUnit);
334    newLIR2(cUnit, kThumbBlx1,
335            (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
336            (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
337    newLIR2(cUnit, kThumbBlx2,
338            (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
339            (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
340}
341