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