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 */
loadValueAddressDirect(CompilationUnit * cUnit,RegLocation rlSrc,int rDest)27 static 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
genInlineSqrt(CompilationUnit * cUnit,MIR * mir)45 static 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 */
genArithOpFloat(CompilationUnit * cUnit,MIR * mir,RegLocation rlDest,RegLocation rlSrc1,RegLocation rlSrc2)64 static 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
genArithOpDouble(CompilationUnit * cUnit,MIR * mir,RegLocation rlDest,RegLocation rlSrc1,RegLocation rlSrc2)110 static 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
genConversion(CompilationUnit * cUnit,MIR * mir)154 static 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
genCmpFP(CompilationUnit * cUnit,MIR * mir,RegLocation rlDest,RegLocation rlSrc1,RegLocation rlSrc2)226 static 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