OSDN Git Service

Dalvik fast interpreter support and JIT implementation
[android-x86/dalvik.git] / vm / compiler / codegen / mips / FP / MipsFP.cpp
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 is included by Codegen-armv5te-vfp.c, and implements architecture
19  * variant-specific code.
20  */
21
22 extern void dvmCompilerFlushRegWideForV5TEVFP(CompilationUnit *cUnit,
23                                               int reg1, int reg2);
24 extern void dvmCompilerFlushRegForV5TEVFP(CompilationUnit *cUnit, int reg);
25
26 /* First, flush any registers associated with this value */
27 static void loadValueAddress(CompilationUnit *cUnit, RegLocation rlSrc,
28                              int rDest)
29 {
30      rlSrc = rlSrc.wide ? dvmCompilerUpdateLocWide(cUnit, rlSrc) :
31                           dvmCompilerUpdateLoc(cUnit, rlSrc);
32      if (rlSrc.location == kLocPhysReg) {
33          if (rlSrc.wide) {
34              dvmCompilerFlushRegWideForV5TEVFP(cUnit, rlSrc.lowReg,
35                                                rlSrc.highReg);
36          } else {
37              dvmCompilerFlushRegForV5TEVFP(cUnit, rlSrc.lowReg);
38          }
39      }
40      opRegRegImm(cUnit, kOpAdd, rDest, rFP,
41                  dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2);
42 }
43
44 static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
45 {
46     RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
47 #ifdef __mips_hard_float
48     RegLocation rlResult = LOC_C_RETURN_WIDE_ALT;
49 #else
50     RegLocation rlResult = LOC_C_RETURN_WIDE;
51 #endif
52     RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
53     loadValueAddress(cUnit, rlSrc, r_A2);
54     genDispatchToHandler(cUnit, TEMPLATE_SQRT_DOUBLE_VFP);
55     storeValueWide(cUnit, rlDest, rlResult);
56     return false;
57 }
58
59 /*
60  * TUNING: On some implementations, it is quicker to pass addresses
61  * to the handlers rather than load the operands into core registers
62  * and then move the values to FP regs in the handlers.  Other implementations
63  * may prefer passing data in registers (and the latter approach would
64  * yeild cleaner register handling - avoiding the requirement that operands
65  * be flushed to memory prior to the call).
66  */
67 static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir,
68                             RegLocation rlDest, RegLocation rlSrc1,
69                             RegLocation rlSrc2)
70 {
71 #ifdef __mips_hard_float
72     int op = kMipsNop;
73     RegLocation rlResult;
74
75     /*
76      * Don't attempt to optimize register usage since these opcodes call out to
77      * the handlers.
78      */
79     switch (mir->dalvikInsn.opcode) {
80         case OP_ADD_FLOAT_2ADDR:
81         case OP_ADD_FLOAT:
82             op = kMipsFadds;
83             break;
84         case OP_SUB_FLOAT_2ADDR:
85         case OP_SUB_FLOAT:
86             op = kMipsFsubs;
87             break;
88         case OP_DIV_FLOAT_2ADDR:
89         case OP_DIV_FLOAT:
90             op = kMipsFdivs;
91             break;
92         case OP_MUL_FLOAT_2ADDR:
93         case OP_MUL_FLOAT:
94             op = kMipsFmuls;
95             break;
96         case OP_REM_FLOAT_2ADDR:
97         case OP_REM_FLOAT:
98         case OP_NEG_FLOAT: {
99             return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
100         }
101         default:
102             return true;
103     }
104     rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
105     rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
106     rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
107     newLIR3(cUnit, (MipsOpCode)op, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
108     storeValue(cUnit, rlDest, rlResult);
109
110     return false;
111 #else
112     TemplateOpcode opcode;
113
114     /*
115      * Don't attempt to optimize register usage since these opcodes call out to
116      * the handlers.
117      */
118     switch (mir->dalvikInsn.opcode) {
119         case OP_ADD_FLOAT_2ADDR:
120         case OP_ADD_FLOAT:
121             opcode = TEMPLATE_ADD_FLOAT_VFP;
122             break;
123         case OP_SUB_FLOAT_2ADDR:
124         case OP_SUB_FLOAT:
125             opcode = TEMPLATE_SUB_FLOAT_VFP;
126             break;
127         case OP_DIV_FLOAT_2ADDR:
128         case OP_DIV_FLOAT:
129             opcode = TEMPLATE_DIV_FLOAT_VFP;
130             break;
131         case OP_MUL_FLOAT_2ADDR:
132         case OP_MUL_FLOAT:
133             opcode = TEMPLATE_MUL_FLOAT_VFP;
134             break;
135         case OP_REM_FLOAT_2ADDR:
136         case OP_REM_FLOAT:
137         case OP_NEG_FLOAT: {
138             return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
139         }
140         default:
141             return true;
142     }
143     loadValueAddress(cUnit, rlDest, r_A0);
144     dvmCompilerClobber(cUnit, r_A0);
145     loadValueAddress(cUnit, rlSrc1, r_A1);
146     dvmCompilerClobber(cUnit, r_A1);
147     loadValueAddress(cUnit, rlSrc2, r_A2);
148     genDispatchToHandler(cUnit, opcode);
149     rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);
150     if (rlDest.location == kLocPhysReg) {
151         dvmCompilerClobber(cUnit, rlDest.lowReg);
152     }
153     return false;
154 #endif
155 }
156
157 static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir,
158                              RegLocation rlDest, RegLocation rlSrc1,
159                              RegLocation rlSrc2)
160 {
161 #ifdef __mips_hard_float
162     int op = kMipsNop;
163     RegLocation rlResult;
164
165     switch (mir->dalvikInsn.opcode) {
166         case OP_ADD_DOUBLE_2ADDR:
167         case OP_ADD_DOUBLE:
168             op = kMipsFaddd;
169             break;
170         case OP_SUB_DOUBLE_2ADDR:
171         case OP_SUB_DOUBLE:
172             op = kMipsFsubd;
173             break;
174         case OP_DIV_DOUBLE_2ADDR:
175         case OP_DIV_DOUBLE:
176             op = kMipsFdivd;
177             break;
178         case OP_MUL_DOUBLE_2ADDR:
179         case OP_MUL_DOUBLE:
180             op = kMipsFmuld;
181             break;
182         case OP_REM_DOUBLE_2ADDR:
183         case OP_REM_DOUBLE:
184         case OP_NEG_DOUBLE: {
185             return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
186         }
187         default:
188             return true;
189     }
190     rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
191     assert(rlSrc1.wide);
192     rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
193     assert(rlSrc2.wide);
194     rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
195     assert(rlDest.wide);
196     assert(rlResult.wide);
197     newLIR3(cUnit, (MipsOpCode)op, S2D(rlResult.lowReg, rlResult.highReg),
198             S2D(rlSrc1.lowReg, rlSrc1.highReg),
199             S2D(rlSrc2.lowReg, rlSrc2.highReg));
200     storeValueWide(cUnit, rlDest, rlResult);
201     return false;
202 #else
203     TemplateOpcode opcode;
204
205     switch (mir->dalvikInsn.opcode) {
206         case OP_ADD_DOUBLE_2ADDR:
207         case OP_ADD_DOUBLE:
208             opcode = TEMPLATE_ADD_DOUBLE_VFP;
209             break;
210         case OP_SUB_DOUBLE_2ADDR:
211         case OP_SUB_DOUBLE:
212             opcode = TEMPLATE_SUB_DOUBLE_VFP;
213             break;
214         case OP_DIV_DOUBLE_2ADDR:
215         case OP_DIV_DOUBLE:
216             opcode = TEMPLATE_DIV_DOUBLE_VFP;
217             break;
218         case OP_MUL_DOUBLE_2ADDR:
219         case OP_MUL_DOUBLE:
220             opcode = TEMPLATE_MUL_DOUBLE_VFP;
221             break;
222         case OP_REM_DOUBLE_2ADDR:
223         case OP_REM_DOUBLE:
224         case OP_NEG_DOUBLE: {
225             return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1,
226                                                rlSrc2);
227         }
228         default:
229             return true;
230     }
231     loadValueAddress(cUnit, rlDest, r_A0);
232     dvmCompilerClobber(cUnit, r_A0);
233     loadValueAddress(cUnit, rlSrc1, r_A1);
234     dvmCompilerClobber(cUnit, r_A1);
235     loadValueAddress(cUnit, rlSrc2, r_A2);
236     genDispatchToHandler(cUnit, opcode);
237     rlDest = dvmCompilerUpdateLocWide(cUnit, rlDest);
238     if (rlDest.location == kLocPhysReg) {
239         dvmCompilerClobber(cUnit, rlDest.lowReg);
240         dvmCompilerClobber(cUnit, rlDest.highReg);
241     }
242     return false;
243 #endif
244 }
245
246 static bool genConversion(CompilationUnit *cUnit, MIR *mir)
247 {
248     Opcode opcode = mir->dalvikInsn.opcode;
249     bool longSrc = false;
250     bool longDest = false;
251     RegLocation rlSrc;
252     RegLocation rlDest;
253 #ifdef __mips_hard_float
254     int op = kMipsNop;
255     int srcReg;
256     RegLocation rlResult;
257
258     switch (opcode) {
259         case OP_INT_TO_FLOAT:
260             longSrc = false;
261             longDest = false;
262             op = kMipsFcvtsw;
263             break;
264         case OP_DOUBLE_TO_FLOAT:
265             longSrc = true;
266             longDest = false;
267             op = kMipsFcvtsd;
268             break;
269         case OP_FLOAT_TO_DOUBLE:
270             longSrc = false;
271             longDest = true;
272             op = kMipsFcvtds;
273             break;
274         case OP_INT_TO_DOUBLE:
275             longSrc = false;
276             longDest = true;
277             op = kMipsFcvtdw;
278             break;
279         case OP_FLOAT_TO_INT:
280         case OP_DOUBLE_TO_INT:
281         case OP_LONG_TO_DOUBLE:
282         case OP_FLOAT_TO_LONG:
283         case OP_LONG_TO_FLOAT:
284         case OP_DOUBLE_TO_LONG:
285             return genConversionPortable(cUnit, mir);
286         default:
287             return true;
288     }
289     if (longSrc) {
290         rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
291         rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
292         srcReg = S2D(rlSrc.lowReg, rlSrc.highReg);
293     } else {
294         rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
295         rlSrc = loadValue(cUnit, rlSrc, kFPReg);
296         srcReg = rlSrc.lowReg;
297     }
298     if (longDest) {
299         rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
300         rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
301         newLIR2(cUnit, (MipsOpCode)op, S2D(rlResult.lowReg, rlResult.highReg), srcReg);
302         storeValueWide(cUnit, rlDest, rlResult);
303     } else {
304         rlDest = dvmCompilerGetDest(cUnit, mir, 0);
305         rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
306         newLIR2(cUnit, (MipsOpCode)op, rlResult.lowReg, srcReg);
307         storeValue(cUnit, rlDest, rlResult);
308     }
309     return false;
310 #else
311     TemplateOpcode templateOpcode;
312     switch (opcode) {
313         case OP_INT_TO_FLOAT:
314             longSrc = false;
315             longDest = false;
316             templateOpcode = TEMPLATE_INT_TO_FLOAT_VFP;
317             break;
318         case OP_FLOAT_TO_INT:
319             longSrc = false;
320             longDest = false;
321             templateOpcode = TEMPLATE_FLOAT_TO_INT_VFP;
322             break;
323         case OP_DOUBLE_TO_FLOAT:
324             longSrc = true;
325             longDest = false;
326             templateOpcode = TEMPLATE_DOUBLE_TO_FLOAT_VFP;
327             break;
328         case OP_FLOAT_TO_DOUBLE:
329             longSrc = false;
330             longDest = true;
331             templateOpcode = TEMPLATE_FLOAT_TO_DOUBLE_VFP;
332             break;
333         case OP_INT_TO_DOUBLE:
334             longSrc = false;
335             longDest = true;
336             templateOpcode = TEMPLATE_INT_TO_DOUBLE_VFP;
337             break;
338         case OP_DOUBLE_TO_INT:
339             longSrc = true;
340             longDest = false;
341             templateOpcode = TEMPLATE_DOUBLE_TO_INT_VFP;
342             break;
343         case OP_LONG_TO_DOUBLE:
344         case OP_FLOAT_TO_LONG:
345         case OP_LONG_TO_FLOAT:
346         case OP_DOUBLE_TO_LONG:
347             return genConversionPortable(cUnit, mir);
348         default:
349             return true;
350     }
351
352     if (longSrc) {
353         rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
354     } else {
355         rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
356     }
357
358     if (longDest) {
359         rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
360     } else {
361         rlDest = dvmCompilerGetDest(cUnit, mir, 0);
362     }
363     loadValueAddress(cUnit, rlDest, r_A0);
364     dvmCompilerClobber(cUnit, r_A0);
365     loadValueAddress(cUnit, rlSrc, r_A1);
366     genDispatchToHandler(cUnit, templateOpcode);
367     if (rlDest.wide) {
368         rlDest = dvmCompilerUpdateLocWide(cUnit, rlDest);
369         dvmCompilerClobber(cUnit, rlDest.highReg);
370     } else {
371         rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);
372     }
373     dvmCompilerClobber(cUnit, rlDest.lowReg);
374     return false;
375 #endif
376 }
377
378 static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
379                      RegLocation rlSrc1, RegLocation rlSrc2)
380 {
381     TemplateOpcode templateOpcode;
382     RegLocation rlResult = dvmCompilerGetReturn(cUnit);
383     bool wide = true;
384
385     switch(mir->dalvikInsn.opcode) {
386         case OP_CMPL_FLOAT:
387             templateOpcode = TEMPLATE_CMPL_FLOAT_VFP;
388             wide = false;
389             break;
390         case OP_CMPG_FLOAT:
391             templateOpcode = TEMPLATE_CMPG_FLOAT_VFP;
392             wide = false;
393             break;
394         case OP_CMPL_DOUBLE:
395             templateOpcode = TEMPLATE_CMPL_DOUBLE_VFP;
396             break;
397         case OP_CMPG_DOUBLE:
398             templateOpcode = TEMPLATE_CMPG_DOUBLE_VFP;
399             break;
400         default:
401             return true;
402     }
403     loadValueAddress(cUnit, rlSrc1, r_A0);
404     dvmCompilerClobber(cUnit, r_A0);
405     loadValueAddress(cUnit, rlSrc2, r_A1);
406     genDispatchToHandler(cUnit, templateOpcode);
407     storeValue(cUnit, rlDest, rlResult);
408     return false;
409 }