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