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