blob: 70783a4c52aebb2c342391ea168d4d860186331e [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -07001/*
2 * Copyright (C) 2011 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
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080017namespace art {
18
buzbee408ad162012-06-06 16:45:18 -070019bool genArithOpFloat(CompilationUnit* cUnit, Instruction::Code opcode, RegLocation rlDest,
buzbee31a4a6f2012-02-28 15:36:15 -080020 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee67bf8852011-08-17 17:51:35 -070021{
Bill Buzbeea114add2012-05-03 15:00:40 -070022 int op = kThumbBkpt;
23 RegLocation rlResult;
buzbee67bf8852011-08-17 17:51:35 -070024
Bill Buzbeea114add2012-05-03 15:00:40 -070025 /*
26 * Don't attempt to optimize register usage since these opcodes call out to
27 * the handlers.
28 */
buzbee408ad162012-06-06 16:45:18 -070029 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -070030 case Instruction::ADD_FLOAT_2ADDR:
31 case Instruction::ADD_FLOAT:
32 op = kThumb2Vadds;
33 break;
34 case Instruction::SUB_FLOAT_2ADDR:
35 case Instruction::SUB_FLOAT:
36 op = kThumb2Vsubs;
37 break;
38 case Instruction::DIV_FLOAT_2ADDR:
39 case Instruction::DIV_FLOAT:
40 op = kThumb2Vdivs;
41 break;
42 case Instruction::MUL_FLOAT_2ADDR:
43 case Instruction::MUL_FLOAT:
44 op = kThumb2Vmuls;
45 break;
46 case Instruction::REM_FLOAT_2ADDR:
47 case Instruction::REM_FLOAT:
48 case Instruction::NEG_FLOAT: {
buzbee408ad162012-06-06 16:45:18 -070049 return genArithOpFloatPortable(cUnit, opcode, rlDest, rlSrc1, rlSrc2);
buzbee67bf8852011-08-17 17:51:35 -070050 }
Bill Buzbeea114add2012-05-03 15:00:40 -070051 default:
52 return true;
53 }
54 rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
55 rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
56 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
buzbeecbd6d442012-11-17 14:11:25 -080057 newLIR3(cUnit, op, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
Bill Buzbeea114add2012-05-03 15:00:40 -070058 storeValue(cUnit, rlDest, rlResult);
59 return false;
buzbee67bf8852011-08-17 17:51:35 -070060}
61
buzbee408ad162012-06-06 16:45:18 -070062bool genArithOpDouble(CompilationUnit* cUnit, Instruction::Code opcode,
63 RegLocation rlDest, RegLocation rlSrc1, RegLocation rlSrc2)
buzbee67bf8852011-08-17 17:51:35 -070064{
Bill Buzbeea114add2012-05-03 15:00:40 -070065 int op = kThumbBkpt;
66 RegLocation rlResult;
buzbee67bf8852011-08-17 17:51:35 -070067
buzbee408ad162012-06-06 16:45:18 -070068 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -070069 case Instruction::ADD_DOUBLE_2ADDR:
70 case Instruction::ADD_DOUBLE:
71 op = kThumb2Vaddd;
72 break;
73 case Instruction::SUB_DOUBLE_2ADDR:
74 case Instruction::SUB_DOUBLE:
75 op = kThumb2Vsubd;
76 break;
77 case Instruction::DIV_DOUBLE_2ADDR:
78 case Instruction::DIV_DOUBLE:
79 op = kThumb2Vdivd;
80 break;
81 case Instruction::MUL_DOUBLE_2ADDR:
82 case Instruction::MUL_DOUBLE:
83 op = kThumb2Vmuld;
84 break;
85 case Instruction::REM_DOUBLE_2ADDR:
86 case Instruction::REM_DOUBLE:
87 case Instruction::NEG_DOUBLE: {
buzbee408ad162012-06-06 16:45:18 -070088 return genArithOpDoublePortable(cUnit, opcode, rlDest, rlSrc1, rlSrc2);
buzbee67bf8852011-08-17 17:51:35 -070089 }
Bill Buzbeea114add2012-05-03 15:00:40 -070090 default:
91 return true;
92 }
buzbee67bf8852011-08-17 17:51:35 -070093
Bill Buzbeea114add2012-05-03 15:00:40 -070094 rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
95 DCHECK(rlSrc1.wide);
96 rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
97 DCHECK(rlSrc2.wide);
98 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
99 DCHECK(rlDest.wide);
100 DCHECK(rlResult.wide);
buzbeecbd6d442012-11-17 14:11:25 -0800101 newLIR3(cUnit, op, s2d(rlResult.lowReg, rlResult.highReg), s2d(rlSrc1.lowReg, rlSrc1.highReg),
buzbeef0504cd2012-11-13 16:31:10 -0800102 s2d(rlSrc2.lowReg, rlSrc2.highReg));
Bill Buzbeea114add2012-05-03 15:00:40 -0700103 storeValueWide(cUnit, rlDest, rlResult);
104 return false;
buzbee67bf8852011-08-17 17:51:35 -0700105}
106
buzbee408ad162012-06-06 16:45:18 -0700107bool genConversion(CompilationUnit* cUnit, Instruction::Code opcode,
108 RegLocation rlDest, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700109{
Bill Buzbeea114add2012-05-03 15:00:40 -0700110 int op = kThumbBkpt;
Bill Buzbeea114add2012-05-03 15:00:40 -0700111 int srcReg;
Bill Buzbeea114add2012-05-03 15:00:40 -0700112 RegLocation rlResult;
buzbee67bf8852011-08-17 17:51:35 -0700113
Bill Buzbeea114add2012-05-03 15:00:40 -0700114 switch (opcode) {
115 case Instruction::INT_TO_FLOAT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700116 op = kThumb2VcvtIF;
117 break;
118 case Instruction::FLOAT_TO_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700119 op = kThumb2VcvtFI;
120 break;
121 case Instruction::DOUBLE_TO_FLOAT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700122 op = kThumb2VcvtDF;
123 break;
124 case Instruction::FLOAT_TO_DOUBLE:
Bill Buzbeea114add2012-05-03 15:00:40 -0700125 op = kThumb2VcvtFd;
126 break;
127 case Instruction::INT_TO_DOUBLE:
Bill Buzbeea114add2012-05-03 15:00:40 -0700128 op = kThumb2VcvtID;
129 break;
130 case Instruction::DOUBLE_TO_INT:
Bill Buzbeea114add2012-05-03 15:00:40 -0700131 op = kThumb2VcvtDI;
132 break;
133 case Instruction::LONG_TO_DOUBLE:
134 case Instruction::FLOAT_TO_LONG:
135 case Instruction::LONG_TO_FLOAT:
136 case Instruction::DOUBLE_TO_LONG:
buzbee408ad162012-06-06 16:45:18 -0700137 return genConversionPortable(cUnit, opcode, rlDest, rlSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -0700138 default:
139 return true;
140 }
buzbee408ad162012-06-06 16:45:18 -0700141 if (rlSrc.wide) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700142 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
buzbeef0504cd2012-11-13 16:31:10 -0800143 srcReg = s2d(rlSrc.lowReg, rlSrc.highReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700144 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700145 rlSrc = loadValue(cUnit, rlSrc, kFPReg);
146 srcReg = rlSrc.lowReg;
147 }
buzbee408ad162012-06-06 16:45:18 -0700148 if (rlDest.wide) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700149 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
buzbeecbd6d442012-11-17 14:11:25 -0800150 newLIR2(cUnit, op, s2d(rlResult.lowReg, rlResult.highReg), srcReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700151 storeValueWide(cUnit, rlDest, rlResult);
152 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700153 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
buzbeecbd6d442012-11-17 14:11:25 -0800154 newLIR2(cUnit, op, rlResult.lowReg, srcReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700155 storeValue(cUnit, rlDest, rlResult);
156 }
157 return false;
buzbee67bf8852011-08-17 17:51:35 -0700158}
159
buzbee84fd6932012-03-29 16:44:16 -0700160void genFusedFPCmpBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
161 bool gtBias, bool isDouble)
162{
buzbeea1da8a52012-07-09 14:00:21 -0700163 LIR* labelList = cUnit->blockLabelList;
Bill Buzbeea114add2012-05-03 15:00:40 -0700164 LIR* target = &labelList[bb->taken->id];
165 RegLocation rlSrc1;
166 RegLocation rlSrc2;
167 if (isDouble) {
buzbee15bf9802012-06-12 17:49:27 -0700168 rlSrc1 = oatGetSrcWide(cUnit, mir, 0);
169 rlSrc2 = oatGetSrcWide(cUnit, mir, 2);
Bill Buzbeea114add2012-05-03 15:00:40 -0700170 rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
171 rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
buzbeef0504cd2012-11-13 16:31:10 -0800172 newLIR2(cUnit, kThumb2Vcmpd, s2d(rlSrc1.lowReg, rlSrc2.highReg),
173 s2d(rlSrc2.lowReg, rlSrc2.highReg));
Bill Buzbeea114add2012-05-03 15:00:40 -0700174 } else {
175 rlSrc1 = oatGetSrc(cUnit, mir, 0);
176 rlSrc2 = oatGetSrc(cUnit, mir, 1);
177 rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
178 rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
179 newLIR2(cUnit, kThumb2Vcmps, rlSrc1.lowReg, rlSrc2.lowReg);
180 }
181 newLIR0(cUnit, kThumb2Fmstat);
182 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
183 switch(ccode) {
184 case kCondEq:
185 case kCondNe:
186 break;
187 case kCondLt:
188 if (gtBias) {
189 ccode = kCondMi;
190 }
191 break;
192 case kCondLe:
193 if (gtBias) {
194 ccode = kCondLs;
195 }
196 break;
197 case kCondGt:
198 if (gtBias) {
199 ccode = kCondHi;
200 }
201 break;
202 case kCondGe:
203 if (gtBias) {
204 ccode = kCondCs;
205 }
206 break;
207 default:
buzbeecbd6d442012-11-17 14:11:25 -0800208 LOG(FATAL) << "Unexpected ccode: " << ccode;
Bill Buzbeea114add2012-05-03 15:00:40 -0700209 }
210 opCondBranch(cUnit, ccode, target);
buzbee84fd6932012-03-29 16:44:16 -0700211}
212
213
buzbee408ad162012-06-06 16:45:18 -0700214bool genCmpFP(CompilationUnit* cUnit, Instruction::Code opcode, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -0700215 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee67bf8852011-08-17 17:51:35 -0700216{
Bill Buzbeea114add2012-05-03 15:00:40 -0700217 bool isDouble;
218 int defaultResult;
219 RegLocation rlResult;
buzbee67bf8852011-08-17 17:51:35 -0700220
buzbee408ad162012-06-06 16:45:18 -0700221 switch (opcode) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700222 case Instruction::CMPL_FLOAT:
223 isDouble = false;
224 defaultResult = -1;
225 break;
226 case Instruction::CMPG_FLOAT:
227 isDouble = false;
228 defaultResult = 1;
229 break;
230 case Instruction::CMPL_DOUBLE:
231 isDouble = true;
232 defaultResult = -1;
233 break;
234 case Instruction::CMPG_DOUBLE:
235 isDouble = true;
236 defaultResult = 1;
237 break;
238 default:
239 return true;
240 }
241 if (isDouble) {
242 rlSrc1 = loadValueWide(cUnit, rlSrc1, kFPReg);
243 rlSrc2 = loadValueWide(cUnit, rlSrc2, kFPReg);
244 oatClobberSReg(cUnit, rlDest.sRegLow);
245 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
246 loadConstant(cUnit, rlResult.lowReg, defaultResult);
buzbeef0504cd2012-11-13 16:31:10 -0800247 newLIR2(cUnit, kThumb2Vcmpd, s2d(rlSrc1.lowReg, rlSrc2.highReg),
248 s2d(rlSrc2.lowReg, rlSrc2.highReg));
Bill Buzbeea114add2012-05-03 15:00:40 -0700249 } else {
250 rlSrc1 = loadValue(cUnit, rlSrc1, kFPReg);
251 rlSrc2 = loadValue(cUnit, rlSrc2, kFPReg);
252 oatClobberSReg(cUnit, rlDest.sRegLow);
253 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
254 loadConstant(cUnit, rlResult.lowReg, defaultResult);
255 newLIR2(cUnit, kThumb2Vcmps, rlSrc1.lowReg, rlSrc2.lowReg);
256 }
buzbeef0504cd2012-11-13 16:31:10 -0800257 DCHECK(!ARM_FPREG(rlResult.lowReg));
Bill Buzbeea114add2012-05-03 15:00:40 -0700258 newLIR0(cUnit, kThumb2Fmstat);
buzbee67bf8852011-08-17 17:51:35 -0700259
Bill Buzbeea114add2012-05-03 15:00:40 -0700260 opIT(cUnit, (defaultResult == -1) ? kArmCondGt : kArmCondMi, "");
261 newLIR2(cUnit, kThumb2MovImmShift, rlResult.lowReg,
262 modifiedImmediate(-defaultResult)); // Must not alter ccodes
263 genBarrier(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700264
Bill Buzbeea114add2012-05-03 15:00:40 -0700265 opIT(cUnit, kArmCondEq, "");
266 loadConstant(cUnit, rlResult.lowReg, 0);
267 genBarrier(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700268
Bill Buzbeea114add2012-05-03 15:00:40 -0700269 storeValue(cUnit, rlDest, rlResult);
270 return false;
buzbee67bf8852011-08-17 17:51:35 -0700271}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800272
buzbeeefc63692012-11-14 16:31:52 -0800273void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc)
274{
275 RegLocation rlResult;
276 rlSrc = loadValue(cUnit, rlSrc, kFPReg);
277 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
278 newLIR2(cUnit, kThumb2Vnegs, rlResult.lowReg, rlSrc.lowReg);
279 storeValue(cUnit, rlDest, rlResult);
280}
281
282void genNegDouble(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc)
283{
284 RegLocation rlResult;
285 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
286 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
287 newLIR2(cUnit, kThumb2Vnegd, s2d(rlResult.lowReg, rlResult.highReg),
288 s2d(rlSrc.lowReg, rlSrc.highReg));
289 storeValueWide(cUnit, rlDest, rlResult);
290}
291
292bool genInlinedSqrt(CompilationUnit* cUnit, CallInfo* info) {
293 DCHECK_EQ(cUnit->instructionSet, kThumb2);
294 LIR *branch;
295 RegLocation rlSrc = info->args[0];
296 RegLocation rlDest = inlineTargetWide(cUnit, info); // double place for result
297 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
298 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
299 newLIR2(cUnit, kThumb2Vsqrtd, s2d(rlResult.lowReg, rlResult.highReg),
300 s2d(rlSrc.lowReg, rlSrc.highReg));
301 newLIR2(cUnit, kThumb2Vcmpd, s2d(rlResult.lowReg, rlResult.highReg),
302 s2d(rlResult.lowReg, rlResult.highReg));
303 newLIR0(cUnit, kThumb2Fmstat);
304 branch = newLIR2(cUnit, kThumbBCond, 0, kArmCondEq);
305 oatClobberCalleeSave(cUnit);
306 oatLockCallTemps(cUnit); // Using fixed registers
307 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pSqrt));
308 newLIR3(cUnit, kThumb2Fmrrd, r0, r1, s2d(rlSrc.lowReg, rlSrc.highReg));
309 newLIR1(cUnit, kThumbBlxR, rTgt);
310 newLIR3(cUnit, kThumb2Fmdrr, s2d(rlResult.lowReg, rlResult.highReg), r0, r1);
311 branch->target = newLIR0(cUnit, kPseudoTargetLabel);
312 storeValueWide(cUnit, rlDest, rlResult);
313 return true;
314}
315
316
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800317} // namespace art