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
genArithOpFloat(CompilationUnit * cUnit,MIR * mir,RegLocation rlDest,RegLocation rlSrc1,RegLocation rlSrc2)17 static bool genArithOpFloat(CompilationUnit *cUnit, MIR *mir,
18 RegLocation rlDest, RegLocation rlSrc1,
19 RegLocation rlSrc2)
20 {
21 int op = kThumbBkpt;
22 RegLocation rlResult;
23
24 /*
25 * Don't attempt to optimize register usage since these opcodes call out to
26 * the handlers.
27 */
28 switch (mir->dalvikInsn.opcode) {
29 case OP_ADD_FLOAT_2ADDR:
30 case OP_ADD_FLOAT:
31 op = kThumb2Vadds;
32 break;
33 case OP_SUB_FLOAT_2ADDR:
34 case OP_SUB_FLOAT:
35 op = kThumb2Vsubs;
36 break;
37 case OP_DIV_FLOAT_2ADDR:
38 case OP_DIV_FLOAT:
39 op = kThumb2Vdivs;
40 break;
41 case OP_MUL_FLOAT_2ADDR:
42 case OP_MUL_FLOAT:
43 op = kThumb2Vmuls;
44 break;
45 case OP_REM_FLOAT_2ADDR:
46 case OP_REM_FLOAT:
47 case OP_NEG_FLOAT: {
48 return genArithOpFloatPortable(cUnit, mir, rlDest, rlSrc1,
49 rlSrc2);
50 }
51 default:
52 return true;
53 }
54 rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
55 rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
56 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
57 newLIR3(cUnit, (ArmOpcode)op, rlResult.lowReg, rlSrc1.lowReg,
58 rlSrc2.lowReg);
59 storeValue(cUnit, rlDest, rlResult);
60 return false;
61 }
62
genArithOpDouble(CompilationUnit * cUnit,MIR * mir,RegLocation rlDest,RegLocation rlSrc1,RegLocation rlSrc2)63 static bool genArithOpDouble(CompilationUnit *cUnit, MIR *mir,
64 RegLocation rlDest, RegLocation rlSrc1,
65 RegLocation rlSrc2)
66 {
67 int op = kThumbBkpt;
68 RegLocation rlResult;
69
70 switch (mir->dalvikInsn.opcode) {
71 case OP_ADD_DOUBLE_2ADDR:
72 case OP_ADD_DOUBLE:
73 op = kThumb2Vaddd;
74 break;
75 case OP_SUB_DOUBLE_2ADDR:
76 case OP_SUB_DOUBLE:
77 op = kThumb2Vsubd;
78 break;
79 case OP_DIV_DOUBLE_2ADDR:
80 case OP_DIV_DOUBLE:
81 op = kThumb2Vdivd;
82 break;
83 case OP_MUL_DOUBLE_2ADDR:
84 case OP_MUL_DOUBLE:
85 op = kThumb2Vmuld;
86 break;
87 case OP_REM_DOUBLE_2ADDR:
88 case OP_REM_DOUBLE:
89 case OP_NEG_DOUBLE: {
90 return genArithOpDoublePortable(cUnit, mir, rlDest, rlSrc1,
91 rlSrc2);
92 }
93 default:
94 return true;
95 }
96
97 rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
98 assert(rlSrc1.wide);
99 rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
100 assert(rlSrc2.wide);
101 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
102 assert(rlDest.wide);
103 assert(rlResult.wide);
104 newLIR3(cUnit, (ArmOpcode)op, S2D(rlResult.lowReg, rlResult.highReg),
105 S2D(rlSrc1.lowReg, rlSrc1.highReg),
106 S2D(rlSrc2.lowReg, rlSrc2.highReg));
107 storeValueWide(cUnit, rlDest, rlResult);
108 return false;
109 }
110
genConversion(CompilationUnit * cUnit,MIR * mir)111 static bool genConversion(CompilationUnit *cUnit, MIR *mir)
112 {
113 Opcode opcode = mir->dalvikInsn.opcode;
114 int op = kThumbBkpt;
115 bool longSrc = false;
116 bool longDest = false;
117 int srcReg;
118 RegLocation rlSrc;
119 RegLocation rlDest;
120 RegLocation rlResult;
121
122 switch (opcode) {
123 case OP_INT_TO_FLOAT:
124 longSrc = false;
125 longDest = false;
126 op = kThumb2VcvtIF;
127 break;
128 case OP_FLOAT_TO_INT:
129 longSrc = false;
130 longDest = false;
131 op = kThumb2VcvtFI;
132 break;
133 case OP_DOUBLE_TO_FLOAT:
134 longSrc = true;
135 longDest = false;
136 op = kThumb2VcvtDF;
137 break;
138 case OP_FLOAT_TO_DOUBLE:
139 longSrc = false;
140 longDest = true;
141 op = kThumb2VcvtFd;
142 break;
143 case OP_INT_TO_DOUBLE:
144 longSrc = false;
145 longDest = true;
146 op = kThumb2VcvtID;
147 break;
148 case OP_DOUBLE_TO_INT:
149 longSrc = true;
150 longDest = false;
151 op = kThumb2VcvtDI;
152 break;
153 case OP_LONG_TO_DOUBLE:
154 case OP_FLOAT_TO_LONG:
155 case OP_LONG_TO_FLOAT:
156 case OP_DOUBLE_TO_LONG:
157 return genConversionPortable(cUnit, mir);
158 default:
159 return true;
160 }
161 if (longSrc) {
162 rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
163 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
164 srcReg = S2D(rlSrc.lowReg, rlSrc.highReg);
165 } else {
166 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
167 rlSrc = loadValue(cUnit, rlSrc, kFPReg);
168 srcReg = rlSrc.lowReg;
169 }
170 if (longDest) {
171 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
172 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
173 newLIR2(cUnit, (ArmOpcode)op, S2D(rlResult.lowReg, rlResult.highReg),
174 srcReg);
175 storeValueWide(cUnit, rlDest, rlResult);
176 } else {
177 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
178 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
179 newLIR2(cUnit, (ArmOpcode)op, rlResult.lowReg, srcReg);
180 storeValue(cUnit, rlDest, rlResult);
181 }
182 return false;
183 }
184
genInlineSqrt(CompilationUnit * cUnit,MIR * mir)185 static bool genInlineSqrt(CompilationUnit *cUnit, MIR *mir)
186 {
187 ArmLIR *branch;
188 RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
189 RegLocation rlDest = inlinedTargetWide(cUnit, mir, true);
190 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
191 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kFPReg, true);
192 newLIR2(cUnit, kThumb2Vsqrtd, S2D(rlResult.lowReg, rlResult.highReg),
193 S2D(rlSrc.lowReg, rlSrc.highReg));
194 newLIR2(cUnit, kThumb2Vcmpd, S2D(rlResult.lowReg, rlResult.highReg),
195 S2D(rlResult.lowReg, rlResult.highReg));
196 newLIR0(cUnit, kThumb2Fmstat);
197 branch = newLIR2(cUnit, kThumbBCond, 0, kArmCondEq);
198 dvmCompilerClobberCallRegs(cUnit);
199 LOAD_FUNC_ADDR(cUnit, r2, (int) (double (*)(double)) sqrt);
200 newLIR3(cUnit, kThumb2Fmrrd, r0, r1, S2D(rlSrc.lowReg, rlSrc.highReg));
201 newLIR1(cUnit, kThumbBlxR, r2);
202 newLIR3(cUnit, kThumb2Fmdrr, S2D(rlResult.lowReg, rlResult.highReg),
203 r0, r1);
204 ArmLIR *label = newLIR0(cUnit, kArmPseudoTargetLabel);
205 label->defMask = ENCODE_ALL;
206 branch->generic.target = (LIR *)label;
207 storeValueWide(cUnit, rlDest, rlResult);
208 return false;
209 }
210
genCmpFP(CompilationUnit * cUnit,MIR * mir,RegLocation rlDest,RegLocation rlSrc1,RegLocation rlSrc2)211 static bool genCmpFP(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
212 RegLocation rlSrc1, RegLocation rlSrc2)
213 {
214 bool isDouble;
215 int defaultResult;
216 RegLocation rlResult;
217
218 switch(mir->dalvikInsn.opcode) {
219 case OP_CMPL_FLOAT:
220 isDouble = false;
221 defaultResult = -1;
222 break;
223 case OP_CMPG_FLOAT:
224 isDouble = false;
225 defaultResult = 1;
226 break;
227 case OP_CMPL_DOUBLE:
228 isDouble = true;
229 defaultResult = -1;
230 break;
231 case OP_CMPG_DOUBLE:
232 isDouble = true;
233 defaultResult = 1;
234 break;
235 default:
236 return true;
237 }
238 if (isDouble) {
239 rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
240 rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
241 dvmCompilerClobberSReg(cUnit, rlDest.sRegLow);
242 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
243 loadConstant(cUnit, rlResult.lowReg, defaultResult);
244 newLIR2(cUnit, kThumb2Vcmpd, S2D(rlSrc1.lowReg, r1Src2.highReg),
245 S2D(rlSrc2.lowReg, rlSrc2.highReg));
246 } else {
247 rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
248 rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
249 dvmCompilerClobberSReg(cUnit, rlDest.sRegLow);
250 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
251 loadConstant(cUnit, rlResult.lowReg, defaultResult);
252 newLIR2(cUnit, kThumb2Vcmps, rlSrc1.lowReg, rlSrc2.lowReg);
253 }
254 assert(!FPREG(rlResult.lowReg));
255 newLIR0(cUnit, kThumb2Fmstat);
256
257 genIT(cUnit, (defaultResult == -1) ? kArmCondGt : kArmCondMi, "");
258 newLIR2(cUnit, kThumb2MovImmShift, rlResult.lowReg,
259 modifiedImmediate(-defaultResult)); // Must not alter ccodes
260 genBarrier(cUnit);
261
262 genIT(cUnit, kArmCondEq, "");
263 loadConstant(cUnit, rlResult.lowReg, 0);
264 genBarrier(cUnit);
265
266 storeValue(cUnit, rlDest, rlResult);
267 return false;
268 }
269