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/*
23 * Take the address of a Dalvik register and store it into rDest.
24 * Clobber any live values associated either with the Dalvik value
25 * or the target register and lock the target fixed register.
26 */
27static void loadValueAddressDirect(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             dvmCompilerFlushRegWide(cUnit, rlSrc.lowReg, rlSrc.highReg);
35         } else {
36             dvmCompilerFlushReg(cUnit, rlSrc.lowReg);
37         }
38     }
39     dvmCompilerClobber(cUnit, rDest);
40     dvmCompilerLockTemp(cUnit, rDest);
41     opRegRegImm(cUnit, kOpAdd, rDest, r5FP,
42                 dvmCompilerS2VReg(cUnit, rlSrc.sRegLow) << 2);
43}
44
45static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
46{
47    RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
48    RegLocation rlResult = LOC_C_RETURN_WIDE;
49    RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
50    loadValueAddressDirect(cUnit, rlSrc, r2);
51    genDispatchToHandler(cUnit, TEMPLATE_SQRT_DOUBLE_VFP);
52    storeValueWide(cUnit, rlDest, rlResult);
53    return false;
54}
55
56/*
57 * TUNING: On some implementations, it is quicker to pass addresses
58 * to the handlers rather than load the operands into core registers
59 * and then move the values to FP regs in the handlers.  Other implementations
60 * may prefer passing data in registers (and the latter approach would
61 * yield cleaner register handling - avoiding the requirement that operands
62 * be flushed to memory prior to the call).
63 */
64static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir,
65                            RegLocation rlDest, RegLocation rlSrc1,
66                            RegLocation rlSrc2)
67{
68    TemplateOpcode opcode;
69
70    /*
71     * Don't attempt to optimize register usage since these opcodes call out to
72     * the handlers.
73     */
74    switch (mir->dalvikInsn.opcode) {
75        case OP_ADD_FLOAT_2ADDR:
76        case OP_ADD_FLOAT:
77            opcode = TEMPLATE_ADD_FLOAT_VFP;
78            break;
79        case OP_SUB_FLOAT_2ADDR:
80        case OP_SUB_FLOAT:
81            opcode = TEMPLATE_SUB_FLOAT_VFP;
82            break;
83        case OP_DIV_FLOAT_2ADDR:
84        case OP_DIV_FLOAT:
85            opcode = TEMPLATE_DIV_FLOAT_VFP;
86            break;
87        case OP_MUL_FLOAT_2ADDR:
88        case OP_MUL_FLOAT:
89            opcode = TEMPLATE_MUL_FLOAT_VFP;
90            break;
91        case OP_REM_FLOAT_2ADDR:
92        case OP_REM_FLOAT:
93        case OP_NEG_FLOAT: {
94            return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1, rlSrc2);
95        }
96        default:
97            return true;
98    }
99    loadValueAddressDirect(cUnit, rlDest, r0);
100    loadValueAddressDirect(cUnit, rlSrc1, r1);
101    loadValueAddressDirect(cUnit, rlSrc2, r2);
102    genDispatchToHandler(cUnit, opcode);
103    rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);
104    if (rlDest.location == kLocPhysReg) {
105        dvmCompilerClobber(cUnit, rlDest.lowReg);
106    }
107    return false;
108}
109
110static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir,
111                             RegLocation rlDest, RegLocation rlSrc1,
112                             RegLocation rlSrc2)
113{
114    TemplateOpcode opcode;
115
116    switch (mir->dalvikInsn.opcode) {
117        case OP_ADD_DOUBLE_2ADDR:
118        case OP_ADD_DOUBLE:
119            opcode = TEMPLATE_ADD_DOUBLE_VFP;
120            break;
121        case OP_SUB_DOUBLE_2ADDR:
122        case OP_SUB_DOUBLE:
123            opcode = TEMPLATE_SUB_DOUBLE_VFP;
124            break;
125        case OP_DIV_DOUBLE_2ADDR:
126        case OP_DIV_DOUBLE:
127            opcode = TEMPLATE_DIV_DOUBLE_VFP;
128            break;
129        case OP_MUL_DOUBLE_2ADDR:
130        case OP_MUL_DOUBLE:
131            opcode = TEMPLATE_MUL_DOUBLE_VFP;
132            break;
133        case OP_REM_DOUBLE_2ADDR:
134        case OP_REM_DOUBLE:
135        case OP_NEG_DOUBLE: {
136            return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1,
137                                               rlSrc2);
138        }
139        default:
140            return true;
141    }
142    loadValueAddressDirect(cUnit, rlDest, r0);
143    loadValueAddressDirect(cUnit, rlSrc1, r1);
144    loadValueAddressDirect(cUnit, rlSrc2, r2);
145    genDispatchToHandler(cUnit, opcode);
146    rlDest = dvmCompilerUpdateLocWide(cUnit, rlDest);
147    if (rlDest.location == kLocPhysReg) {
148        dvmCompilerClobber(cUnit, rlDest.lowReg);
149        dvmCompilerClobber(cUnit, rlDest.highReg);
150    }
151    return false;
152}
153
154static bool genConversion(CompilationUnit *cUnit, MIR *mir)
155{
156    Opcode opcode = mir->dalvikInsn.opcode;
157    bool longSrc = false;
158    bool longDest = false;
159    RegLocation rlSrc;
160    RegLocation rlDest;
161    TemplateOpcode templateOpcode;
162    switch (opcode) {
163        case OP_INT_TO_FLOAT:
164            longSrc = false;
165            longDest = false;
166            templateOpcode = TEMPLATE_INT_TO_FLOAT_VFP;
167            break;
168        case OP_FLOAT_TO_INT:
169            longSrc = false;
170            longDest = false;
171            templateOpcode = TEMPLATE_FLOAT_TO_INT_VFP;
172            break;
173        case OP_DOUBLE_TO_FLOAT:
174            longSrc = true;
175            longDest = false;
176            templateOpcode = TEMPLATE_DOUBLE_TO_FLOAT_VFP;
177            break;
178        case OP_FLOAT_TO_DOUBLE:
179            longSrc = false;
180            longDest = true;
181            templateOpcode = TEMPLATE_FLOAT_TO_DOUBLE_VFP;
182            break;
183        case OP_INT_TO_DOUBLE:
184            longSrc = false;
185            longDest = true;
186            templateOpcode = TEMPLATE_INT_TO_DOUBLE_VFP;
187            break;
188        case OP_DOUBLE_TO_INT:
189            longSrc = true;
190            longDest = false;
191            templateOpcode = TEMPLATE_DOUBLE_TO_INT_VFP;
192            break;
193        case OP_LONG_TO_DOUBLE:
194        case OP_FLOAT_TO_LONG:
195        case OP_LONG_TO_FLOAT:
196        case OP_DOUBLE_TO_LONG:
197            return genConversionPortable(cUnit, mir);
198        default:
199            return true;
200    }
201
202    if (longSrc) {
203        rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
204    } else {
205        rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
206    }
207
208    if (longDest) {
209        rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
210    } else {
211        rlDest = dvmCompilerGetDest(cUnit, mir, 0);
212    }
213    loadValueAddressDirect(cUnit, rlDest, r0);
214    loadValueAddressDirect(cUnit, rlSrc, r1);
215    genDispatchToHandler(cUnit, templateOpcode);
216    if (rlDest.wide) {
217        rlDest = dvmCompilerUpdateLocWide(cUnit, rlDest);
218        dvmCompilerClobber(cUnit, rlDest.highReg);
219    } else {
220        rlDest = dvmCompilerUpdateLoc(cUnit, rlDest);
221    }
222    dvmCompilerClobber(cUnit, rlDest.lowReg);
223    return false;
224}
225
226static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
227                     RegLocation rlSrc1, RegLocation rlSrc2)
228{
229    TemplateOpcode templateOpcode;
230    RegLocation rlResult = dvmCompilerGetReturn(cUnit);
231    bool wide = true;
232
233    switch(mir->dalvikInsn.opcode) {
234        case OP_CMPL_FLOAT:
235            templateOpcode = TEMPLATE_CMPL_FLOAT_VFP;
236            wide = false;
237            break;
238        case OP_CMPG_FLOAT:
239            templateOpcode = TEMPLATE_CMPG_FLOAT_VFP;
240            wide = false;
241            break;
242        case OP_CMPL_DOUBLE:
243            templateOpcode = TEMPLATE_CMPL_DOUBLE_VFP;
244            break;
245        case OP_CMPG_DOUBLE:
246            templateOpcode = TEMPLATE_CMPG_DOUBLE_VFP;
247            break;
248        default:
249            return true;
250    }
251    loadValueAddressDirect(cUnit, rlSrc1, r0);
252    loadValueAddressDirect(cUnit, rlSrc2, r1);
253    genDispatchToHandler(cUnit, templateOpcode);
254    storeValue(cUnit, rlDest, rlResult);
255    return false;
256}
257