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 target-independent codegen and support, and is
19 * included by:
20 *
21 *        $(TARGET_ARCH)/Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 * which combines this common code with specific support found in the
24 * applicable directories below this one.
25 *
26 * Prior to including this file, TGT_LIR should be #defined.
27 * For example, for arm:
28 *    #define TGT_LIR ArmLIR
29 * and for x86:
30 *    #define TGT_LIR X86LIR
31 */
32
33
34/* Load a word at base + displacement.  Displacement must be word multiple */
35static TGT_LIR *loadWordDisp(CompilationUnit *cUnit, int rBase,
36                             int displacement, int rDest)
37{
38    return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, kWord,
39                        INVALID_SREG);
40}
41
42static TGT_LIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
43                             int displacement, int rSrc)
44{
45    return storeBaseDisp(cUnit, rBase, displacement, rSrc, kWord);
46}
47
48/*
49 * Load a Dalvik register into a physical register.  Take care when
50 * using this routine, as it doesn't perform any bookkeeping regarding
51 * register liveness.  That is the responsibility of the caller.
52 */
53static void loadValueDirect(CompilationUnit *cUnit, RegLocation rlSrc,
54                            int reg1)
55{
56    rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
57    if (rlSrc.location == kLocPhysReg) {
58        genRegCopy(cUnit, reg1, rlSrc.lowReg);
59    } else  if (rlSrc.location == kLocRetval) {
60        loadWordDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval), reg1);
61    } else {
62        assert(rlSrc.location == kLocDalvikFrame);
63        loadWordDisp(cUnit, rFP, dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2,
64                     reg1);
65    }
66}
67
68/*
69 * Similar to loadValueDirect, but clobbers and allocates the target
70 * register.  Should be used when loading to a fixed register (for example,
71 * loading arguments to an out of line call.
72 */
73static void loadValueDirectFixed(CompilationUnit *cUnit, RegLocation rlSrc,
74                                 int reg1)
75{
76    dvmCompilerClobber(cUnit, reg1);
77    dvmCompilerMarkInUse(cUnit, reg1);
78    loadValueDirect(cUnit, rlSrc, reg1);
79}
80
81/*
82 * Load a Dalvik register pair into a physical register[s].  Take care when
83 * using this routine, as it doesn't perform any bookkeeping regarding
84 * register liveness.  That is the responsibility of the caller.
85 */
86static void loadValueDirectWide(CompilationUnit *cUnit, RegLocation rlSrc,
87                                int regLo, int regHi)
88{
89    rlSrc = dvmCompilerUpdateLocWide(cUnit, rlSrc);
90    if (rlSrc.location == kLocPhysReg) {
91        genRegCopyWide(cUnit, regLo, regHi, rlSrc.lowReg, rlSrc.highReg);
92    } else if (rlSrc.location == kLocRetval) {
93        loadBaseDispWide(cUnit, NULL, rSELF,
94                         offsetof(Thread, interpSave.retval),
95                         regLo, regHi, INVALID_SREG);
96    } else {
97        assert(rlSrc.location == kLocDalvikFrame);
98            loadBaseDispWide(cUnit, NULL, rFP,
99                             dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2,
100                             regLo, regHi, INVALID_SREG);
101    }
102}
103
104/*
105 * Similar to loadValueDirect, but clobbers and allocates the target
106 * registers.  Should be used when loading to a fixed registers (for example,
107 * loading arguments to an out of line call.
108 */
109static void loadValueDirectWideFixed(CompilationUnit *cUnit, RegLocation rlSrc,
110                                     int regLo, int regHi)
111{
112    dvmCompilerClobber(cUnit, regLo);
113    dvmCompilerClobber(cUnit, regHi);
114    dvmCompilerMarkInUse(cUnit, regLo);
115    dvmCompilerMarkInUse(cUnit, regHi);
116    loadValueDirectWide(cUnit, rlSrc, regLo, regHi);
117}
118
119static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc,
120                             RegisterClass opKind)
121{
122    rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false);
123    if (rlSrc.location == kLocDalvikFrame) {
124        loadValueDirect(cUnit, rlSrc, rlSrc.lowReg);
125        rlSrc.location = kLocPhysReg;
126        dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
127    } else if (rlSrc.location == kLocRetval) {
128        loadWordDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval),
129                     rlSrc.lowReg);
130        rlSrc.location = kLocPhysReg;
131        dvmCompilerClobber(cUnit, rlSrc.lowReg);
132    }
133    return rlSrc;
134}
135
136static void storeValue(CompilationUnit *cUnit, RegLocation rlDest,
137                       RegLocation rlSrc)
138{
139    LIR *defStart;
140    LIR *defEnd;
141    assert(!rlDest.wide);
142    assert(!rlSrc.wide);
143    dvmCompilerKillNullCheckedLoc(cUnit, rlDest);
144    rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
145    rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);
146    if (rlSrc.location == kLocPhysReg) {
147        if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) ||
148            (rlDest.location == kLocPhysReg)) {
149            // Src is live or Dest has assigned reg.
150            rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
151            genRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg);
152        } else {
153            // Just re-assign the registers.  Dest gets Src's regs
154            rlDest.lowReg = rlSrc.lowReg;
155            dvmCompilerClobber(cUnit, rlSrc.lowReg);
156        }
157    } else {
158        // Load Src either into promoted Dest or temps allocated for Dest
159        rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
160        loadValueDirect(cUnit, rlSrc, rlDest.lowReg);
161    }
162
163    // Dest is now live and dirty (until/if we flush it to home location)
164    dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
165    dvmCompilerMarkDirty(cUnit, rlDest.lowReg);
166
167
168    if (rlDest.location == kLocRetval) {
169        storeBaseDisp(cUnit, rSELF, offsetof(Thread, interpSave.retval),
170                      rlDest.lowReg, kWord);
171        dvmCompilerClobber(cUnit, rlDest.lowReg);
172    } else {
173        dvmCompilerResetDefLoc(cUnit, rlDest);
174        if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow)) {
175            defStart = (LIR *)cUnit->lastLIRInsn;
176            int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow);
177            storeBaseDisp(cUnit, rFP, vReg << 2, rlDest.lowReg, kWord);
178            dvmCompilerMarkClean(cUnit, rlDest.lowReg);
179            defEnd = (LIR *)cUnit->lastLIRInsn;
180            dvmCompilerMarkDef(cUnit, rlDest, defStart, defEnd);
181        }
182    }
183}
184
185static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc,
186                                 RegisterClass opKind)
187{
188    assert(rlSrc.wide);
189    rlSrc = dvmCompilerEvalLoc(cUnit, rlSrc, opKind, false);
190    if (rlSrc.location == kLocDalvikFrame) {
191        loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg);
192        rlSrc.location = kLocPhysReg;
193        dvmCompilerMarkLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
194        dvmCompilerMarkLive(cUnit, rlSrc.highReg,
195                            dvmCompilerSRegHi(rlSrc.sRegLow));
196    } else if (rlSrc.location == kLocRetval) {
197        loadBaseDispWide(cUnit, NULL, rSELF,
198                         offsetof(Thread, interpSave.retval),
199                         rlSrc.lowReg, rlSrc.highReg, INVALID_SREG);
200        rlSrc.location = kLocPhysReg;
201        dvmCompilerClobber(cUnit, rlSrc.lowReg);
202        dvmCompilerClobber(cUnit, rlSrc.highReg);
203    }
204    return rlSrc;
205}
206
207static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDest,
208                           RegLocation rlSrc)
209{
210    LIR *defStart;
211    LIR *defEnd;
212    assert(FPREG(rlSrc.lowReg)==FPREG(rlSrc.highReg));
213    assert(rlDest.wide);
214    assert(rlSrc.wide);
215    dvmCompilerKillNullCheckedLoc(cUnit, rlDest);
216    if (rlSrc.location == kLocPhysReg) {
217        if (dvmCompilerIsLive(cUnit, rlSrc.lowReg) ||
218            dvmCompilerIsLive(cUnit, rlSrc.highReg) ||
219            (rlDest.location == kLocPhysReg)) {
220            // Src is live or Dest has assigned reg.
221            rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
222            genRegCopyWide(cUnit, rlDest.lowReg, rlDest.highReg,
223                           rlSrc.lowReg, rlSrc.highReg);
224        } else {
225            // Just re-assign the registers.  Dest gets Src's regs
226            rlDest.lowReg = rlSrc.lowReg;
227            rlDest.highReg = rlSrc.highReg;
228            dvmCompilerClobber(cUnit, rlSrc.lowReg);
229            dvmCompilerClobber(cUnit, rlSrc.highReg);
230        }
231    } else {
232        // Load Src either into promoted Dest or temps allocated for Dest
233        rlDest = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, false);
234        loadValueDirectWide(cUnit, rlSrc, rlDest.lowReg,
235                            rlDest.highReg);
236    }
237
238    // Dest is now live and dirty (until/if we flush it to home location)
239    dvmCompilerMarkLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
240    dvmCompilerMarkLive(cUnit, rlDest.highReg,
241                        dvmCompilerSRegHi(rlDest.sRegLow));
242    dvmCompilerMarkDirty(cUnit, rlDest.lowReg);
243    dvmCompilerMarkDirty(cUnit, rlDest.highReg);
244    dvmCompilerMarkPair(cUnit, rlDest.lowReg, rlDest.highReg);
245
246
247    if (rlDest.location == kLocRetval) {
248        storeBaseDispWide(cUnit, rSELF, offsetof(Thread, interpSave.retval),
249                          rlDest.lowReg, rlDest.highReg);
250        dvmCompilerClobber(cUnit, rlDest.lowReg);
251        dvmCompilerClobber(cUnit, rlDest.highReg);
252    } else {
253        dvmCompilerResetDefLocWide(cUnit, rlDest);
254        if (dvmCompilerLiveOut(cUnit, rlDest.sRegLow) ||
255            dvmCompilerLiveOut(cUnit, dvmCompilerSRegHi(rlDest.sRegLow))) {
256            defStart = (LIR *)cUnit->lastLIRInsn;
257            int vReg = dvmCompilerS2VReg(cUnit, rlDest.sRegLow);
258            assert((vReg+1) == dvmCompilerS2VReg(cUnit,
259                                     dvmCompilerSRegHi(rlDest.sRegLow)));
260            storeBaseDispWide(cUnit, rFP, vReg << 2, rlDest.lowReg,
261                              rlDest.highReg);
262            dvmCompilerMarkClean(cUnit, rlDest.lowReg);
263            dvmCompilerMarkClean(cUnit, rlDest.highReg);
264            defEnd = (LIR *)cUnit->lastLIRInsn;
265            dvmCompilerMarkDefWide(cUnit, rlDest, defStart, defEnd);
266        }
267    }
268}
269