blob: 2b2592d5dbdccf66fe3d68332d606b2ff2812868 [file] [log] [blame]
Brian Carlstrom7940e442013-07-12 13:46:57 -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
17#include "arm_lir.h"
18#include "codegen_arm.h"
19#include "dex/quick/mir_to_lir-inl.h"
20
21namespace art {
22
23void ArmMir2Lir::GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070024 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070025 int op = kThumbBkpt;
26 RegLocation rl_result;
27
28 /*
29 * Don't attempt to optimize register usage since these opcodes call out to
30 * the handlers.
31 */
32 switch (opcode) {
33 case Instruction::ADD_FLOAT_2ADDR:
34 case Instruction::ADD_FLOAT:
35 op = kThumb2Vadds;
36 break;
37 case Instruction::SUB_FLOAT_2ADDR:
38 case Instruction::SUB_FLOAT:
39 op = kThumb2Vsubs;
40 break;
41 case Instruction::DIV_FLOAT_2ADDR:
42 case Instruction::DIV_FLOAT:
43 op = kThumb2Vdivs;
44 break;
45 case Instruction::MUL_FLOAT_2ADDR:
46 case Instruction::MUL_FLOAT:
47 op = kThumb2Vmuls;
48 break;
49 case Instruction::REM_FLOAT_2ADDR:
50 case Instruction::REM_FLOAT:
51 FlushAllRegs(); // Send everything to home location
Andreas Gampe98430592014-07-27 19:44:50 -070052 CallRuntimeHelperRegLocationRegLocation(kQuickFmodf, rl_src1, rl_src2, false);
buzbeea0cd2d72014-06-01 09:33:49 -070053 rl_result = GetReturn(kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -070054 StoreValue(rl_dest, rl_result);
55 return;
56 case Instruction::NEG_FLOAT:
57 GenNegFloat(rl_dest, rl_src1);
58 return;
59 default:
60 LOG(FATAL) << "Unexpected opcode: " << opcode;
61 }
62 rl_src1 = LoadValue(rl_src1, kFPReg);
63 rl_src2 = LoadValue(rl_src2, kFPReg);
64 rl_result = EvalLoc(rl_dest, kFPReg, true);
Bill Buzbee00e1ec62014-02-27 23:44:13 +000065 NewLIR3(op, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -070066 StoreValue(rl_dest, rl_result);
67}
68
69void ArmMir2Lir::GenArithOpDouble(Instruction::Code opcode,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070070 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070071 int op = kThumbBkpt;
72 RegLocation rl_result;
73
74 switch (opcode) {
75 case Instruction::ADD_DOUBLE_2ADDR:
76 case Instruction::ADD_DOUBLE:
77 op = kThumb2Vaddd;
78 break;
79 case Instruction::SUB_DOUBLE_2ADDR:
80 case Instruction::SUB_DOUBLE:
81 op = kThumb2Vsubd;
82 break;
83 case Instruction::DIV_DOUBLE_2ADDR:
84 case Instruction::DIV_DOUBLE:
85 op = kThumb2Vdivd;
86 break;
87 case Instruction::MUL_DOUBLE_2ADDR:
88 case Instruction::MUL_DOUBLE:
89 op = kThumb2Vmuld;
90 break;
91 case Instruction::REM_DOUBLE_2ADDR:
92 case Instruction::REM_DOUBLE:
93 FlushAllRegs(); // Send everything to home location
Andreas Gampe98430592014-07-27 19:44:50 -070094 CallRuntimeHelperRegLocationRegLocation(kQuickFmod, rl_src1, rl_src2, false);
buzbeea0cd2d72014-06-01 09:33:49 -070095 rl_result = GetReturnWide(kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -070096 StoreValueWide(rl_dest, rl_result);
97 return;
98 case Instruction::NEG_DOUBLE:
99 GenNegDouble(rl_dest, rl_src1);
100 return;
101 default:
102 LOG(FATAL) << "Unexpected opcode: " << opcode;
103 }
104
105 rl_src1 = LoadValueWide(rl_src1, kFPReg);
106 DCHECK(rl_src1.wide);
107 rl_src2 = LoadValueWide(rl_src2, kFPReg);
108 DCHECK(rl_src2.wide);
109 rl_result = EvalLoc(rl_dest, kFPReg, true);
110 DCHECK(rl_dest.wide);
111 DCHECK(rl_result.wide);
buzbee091cc402014-03-31 10:14:40 -0700112 NewLIR3(op, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700113 StoreValueWide(rl_dest, rl_result);
114}
115
Ningsheng Jian675e09b2014-10-23 13:48:36 +0800116void ArmMir2Lir::GenMultiplyByConstantFloat(RegLocation rl_dest, RegLocation rl_src1,
117 int32_t constant) {
118 RegLocation rl_result;
119 RegStorage r_tmp = AllocTempSingle();
120 LoadConstantNoClobber(r_tmp, constant);
121 rl_src1 = LoadValue(rl_src1, kFPReg);
122 rl_result = EvalLoc(rl_dest, kFPReg, true);
123 NewLIR3(kThumb2Vmuls, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), r_tmp.GetReg());
124 StoreValue(rl_dest, rl_result);
125}
126
127void ArmMir2Lir::GenMultiplyByConstantDouble(RegLocation rl_dest, RegLocation rl_src1,
128 int64_t constant) {
129 RegLocation rl_result;
130 RegStorage r_tmp = AllocTempDouble();
131 DCHECK(r_tmp.IsDouble());
132 LoadConstantWide(r_tmp, constant);
133 rl_src1 = LoadValueWide(rl_src1, kFPReg);
134 DCHECK(rl_src1.wide);
135 rl_result = EvalLocWide(rl_dest, kFPReg, true);
136 DCHECK(rl_dest.wide);
137 DCHECK(rl_result.wide);
138 NewLIR3(kThumb2Vmuld, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), r_tmp.GetReg());
139 StoreValueWide(rl_dest, rl_result);
140}
141
buzbee091cc402014-03-31 10:14:40 -0700142void ArmMir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700143 int op = kThumbBkpt;
144 int src_reg;
145 RegLocation rl_result;
146
147 switch (opcode) {
148 case Instruction::INT_TO_FLOAT:
149 op = kThumb2VcvtIF;
150 break;
151 case Instruction::FLOAT_TO_INT:
152 op = kThumb2VcvtFI;
153 break;
154 case Instruction::DOUBLE_TO_FLOAT:
155 op = kThumb2VcvtDF;
156 break;
157 case Instruction::FLOAT_TO_DOUBLE:
158 op = kThumb2VcvtFd;
159 break;
160 case Instruction::INT_TO_DOUBLE:
Zheng Xue19649a2014-02-27 13:30:55 +0000161 op = kThumb2VcvtF64S32;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700162 break;
163 case Instruction::DOUBLE_TO_INT:
164 op = kThumb2VcvtDI;
165 break;
Ian Rogersef6a7762013-12-19 17:58:05 -0800166 case Instruction::LONG_TO_DOUBLE: {
167 rl_src = LoadValueWide(rl_src, kFPReg);
buzbee85089dd2014-05-25 15:10:52 -0700168 RegisterInfo* info = GetRegInfo(rl_src.reg);
169 RegStorage src_low = info->FindMatchingView(RegisterInfo::kLowSingleStorageMask)->GetReg();
170 DCHECK(src_low.Valid());
171 RegStorage src_high = info->FindMatchingView(RegisterInfo::kHighSingleStorageMask)->GetReg();
172 DCHECK(src_high.Valid());
Ian Rogersef6a7762013-12-19 17:58:05 -0800173 rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800174 RegStorage tmp1 = AllocTempDouble();
175 RegStorage tmp2 = AllocTempDouble();
Ian Rogersef6a7762013-12-19 17:58:05 -0800176
buzbee091cc402014-03-31 10:14:40 -0700177 NewLIR2(kThumb2VcvtF64S32, tmp1.GetReg(), src_high.GetReg());
178 NewLIR2(kThumb2VcvtF64U32, rl_result.reg.GetReg(), src_low.GetReg());
buzbee2700f7e2014-03-07 09:46:20 -0800179 LoadConstantWide(tmp2, 0x41f0000000000000LL);
buzbee091cc402014-03-31 10:14:40 -0700180 NewLIR3(kThumb2VmlaF64, rl_result.reg.GetReg(), tmp1.GetReg(), tmp2.GetReg());
Ian Rogersef6a7762013-12-19 17:58:05 -0800181 FreeTemp(tmp1);
182 FreeTemp(tmp2);
183 StoreValueWide(rl_dest, rl_result);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700184 return;
Ian Rogersef6a7762013-12-19 17:58:05 -0800185 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700186 case Instruction::FLOAT_TO_LONG:
Andreas Gampe98430592014-07-27 19:44:50 -0700187 GenConversionCall(kQuickF2l, rl_dest, rl_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700188 return;
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000189 case Instruction::LONG_TO_FLOAT: {
190 rl_src = LoadValueWide(rl_src, kFPReg);
buzbee85089dd2014-05-25 15:10:52 -0700191 RegisterInfo* info = GetRegInfo(rl_src.reg);
192 RegStorage src_low = info->FindMatchingView(RegisterInfo::kLowSingleStorageMask)->GetReg();
193 DCHECK(src_low.Valid());
194 RegStorage src_high = info->FindMatchingView(RegisterInfo::kHighSingleStorageMask)->GetReg();
195 DCHECK(src_high.Valid());
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000196 rl_result = EvalLoc(rl_dest, kFPReg, true);
197 // Allocate temp registers.
buzbee2700f7e2014-03-07 09:46:20 -0800198 RegStorage high_val = AllocTempDouble();
199 RegStorage low_val = AllocTempDouble();
200 RegStorage const_val = AllocTempDouble();
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000201 // Long to double.
buzbee091cc402014-03-31 10:14:40 -0700202 NewLIR2(kThumb2VcvtF64S32, high_val.GetReg(), src_high.GetReg());
203 NewLIR2(kThumb2VcvtF64U32, low_val.GetReg(), src_low.GetReg());
buzbee2700f7e2014-03-07 09:46:20 -0800204 LoadConstantWide(const_val, INT64_C(0x41f0000000000000));
buzbee091cc402014-03-31 10:14:40 -0700205 NewLIR3(kThumb2VmlaF64, low_val.GetReg(), high_val.GetReg(), const_val.GetReg());
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000206 // Double to float.
buzbee091cc402014-03-31 10:14:40 -0700207 NewLIR2(kThumb2VcvtDF, rl_result.reg.GetReg(), low_val.GetReg());
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000208 // Free temp registers.
209 FreeTemp(high_val);
210 FreeTemp(low_val);
211 FreeTemp(const_val);
212 // Store result.
213 StoreValue(rl_dest, rl_result);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700214 return;
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000215 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700216 case Instruction::DOUBLE_TO_LONG:
Andreas Gampe98430592014-07-27 19:44:50 -0700217 GenConversionCall(kQuickD2l, rl_dest, rl_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700218 return;
219 default:
220 LOG(FATAL) << "Unexpected opcode: " << opcode;
221 }
222 if (rl_src.wide) {
223 rl_src = LoadValueWide(rl_src, kFPReg);
buzbee091cc402014-03-31 10:14:40 -0700224 src_reg = rl_src.reg.GetReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700225 } else {
226 rl_src = LoadValue(rl_src, kFPReg);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000227 src_reg = rl_src.reg.GetReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700228 }
229 if (rl_dest.wide) {
230 rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee091cc402014-03-31 10:14:40 -0700231 NewLIR2(op, rl_result.reg.GetReg(), src_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700232 StoreValueWide(rl_dest, rl_result);
233 } else {
234 rl_result = EvalLoc(rl_dest, kFPReg, true);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000235 NewLIR2(op, rl_result.reg.GetReg(), src_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700236 StoreValue(rl_dest, rl_result);
237 }
238}
239
240void ArmMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700241 bool is_double) {
buzbee0d829482013-10-11 15:24:55 -0700242 LIR* target = &block_label_list_[bb->taken];
Brian Carlstrom7940e442013-07-12 13:46:57 -0700243 RegLocation rl_src1;
244 RegLocation rl_src2;
245 if (is_double) {
246 rl_src1 = mir_graph_->GetSrcWide(mir, 0);
247 rl_src2 = mir_graph_->GetSrcWide(mir, 2);
248 rl_src1 = LoadValueWide(rl_src1, kFPReg);
249 rl_src2 = LoadValueWide(rl_src2, kFPReg);
buzbee091cc402014-03-31 10:14:40 -0700250 NewLIR2(kThumb2Vcmpd, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700251 } else {
252 rl_src1 = mir_graph_->GetSrc(mir, 0);
253 rl_src2 = mir_graph_->GetSrc(mir, 1);
254 rl_src1 = LoadValue(rl_src1, kFPReg);
255 rl_src2 = LoadValue(rl_src2, kFPReg);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000256 NewLIR2(kThumb2Vcmps, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700257 }
258 NewLIR0(kThumb2Fmstat);
Vladimir Markoa8946072014-01-22 10:30:44 +0000259 ConditionCode ccode = mir->meta.ccode;
Brian Carlstromdf629502013-07-17 22:39:56 -0700260 switch (ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700261 case kCondEq:
262 case kCondNe:
263 break;
264 case kCondLt:
265 if (gt_bias) {
266 ccode = kCondMi;
267 }
268 break;
269 case kCondLe:
270 if (gt_bias) {
271 ccode = kCondLs;
272 }
273 break;
274 case kCondGt:
275 if (gt_bias) {
276 ccode = kCondHi;
277 }
278 break;
279 case kCondGe:
280 if (gt_bias) {
Vladimir Marko58af1f92013-12-19 13:31:15 +0000281 ccode = kCondUge;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700282 }
283 break;
284 default:
285 LOG(FATAL) << "Unexpected ccode: " << ccode;
286 }
287 OpCondBranch(ccode, target);
288}
289
290
291void ArmMir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700292 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700293 bool is_double = false;
294 int default_result = -1;
295 RegLocation rl_result;
296
297 switch (opcode) {
298 case Instruction::CMPL_FLOAT:
299 is_double = false;
300 default_result = -1;
301 break;
302 case Instruction::CMPG_FLOAT:
303 is_double = false;
304 default_result = 1;
305 break;
306 case Instruction::CMPL_DOUBLE:
307 is_double = true;
308 default_result = -1;
309 break;
310 case Instruction::CMPG_DOUBLE:
311 is_double = true;
312 default_result = 1;
313 break;
314 default:
315 LOG(FATAL) << "Unexpected opcode: " << opcode;
316 }
317 if (is_double) {
318 rl_src1 = LoadValueWide(rl_src1, kFPReg);
319 rl_src2 = LoadValueWide(rl_src2, kFPReg);
320 // In case result vreg is also a src vreg, break association to avoid useless copy by EvalLoc()
321 ClobberSReg(rl_dest.s_reg_low);
322 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800323 LoadConstant(rl_result.reg, default_result);
buzbee091cc402014-03-31 10:14:40 -0700324 NewLIR2(kThumb2Vcmpd, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700325 } else {
326 rl_src1 = LoadValue(rl_src1, kFPReg);
327 rl_src2 = LoadValue(rl_src2, kFPReg);
328 // In case result vreg is also a srcvreg, break association to avoid useless copy by EvalLoc()
329 ClobberSReg(rl_dest.s_reg_low);
330 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800331 LoadConstant(rl_result.reg, default_result);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000332 NewLIR2(kThumb2Vcmps, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700333 }
buzbee091cc402014-03-31 10:14:40 -0700334 DCHECK(!rl_result.reg.IsFloat());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700335 NewLIR0(kThumb2Fmstat);
336
Dave Allison3da67a52014-04-02 17:03:45 -0700337 LIR* it = OpIT((default_result == -1) ? kCondGt : kCondMi, "");
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000338 NewLIR2(kThumb2MovI8M, rl_result.reg.GetReg(),
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700339 ModifiedImmediate(-default_result)); // Must not alter ccodes
Dave Allison3da67a52014-04-02 17:03:45 -0700340 OpEndIT(it);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700341
Dave Allison3da67a52014-04-02 17:03:45 -0700342 it = OpIT(kCondEq, "");
buzbee2700f7e2014-03-07 09:46:20 -0800343 LoadConstant(rl_result.reg, 0);
Dave Allison3da67a52014-04-02 17:03:45 -0700344 OpEndIT(it);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700345
346 StoreValue(rl_dest, rl_result);
347}
348
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700349void ArmMir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700350 RegLocation rl_result;
351 rl_src = LoadValue(rl_src, kFPReg);
352 rl_result = EvalLoc(rl_dest, kFPReg, true);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000353 NewLIR2(kThumb2Vnegs, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700354 StoreValue(rl_dest, rl_result);
355}
356
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700357void ArmMir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700358 RegLocation rl_result;
359 rl_src = LoadValueWide(rl_src, kFPReg);
360 rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee091cc402014-03-31 10:14:40 -0700361 NewLIR2(kThumb2Vnegd, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700362 StoreValueWide(rl_dest, rl_result);
363}
364
Vladimir Marko5030d3e2014-07-17 10:43:08 +0100365static RegisterClass RegClassForAbsFP(RegLocation rl_src, RegLocation rl_dest) {
366 // If src is in a core reg or, unlikely, dest has been promoted to a core reg, use core reg.
367 if ((rl_src.location == kLocPhysReg && !rl_src.reg.IsFloat()) ||
368 (rl_dest.location == kLocPhysReg && !rl_dest.reg.IsFloat())) {
369 return kCoreReg;
370 }
371 // If src is in an fp reg or dest has been promoted to an fp reg, use fp reg.
372 if (rl_src.location == kLocPhysReg || rl_dest.location == kLocPhysReg) {
373 return kFPReg;
374 }
375 // With both src and dest in the stack frame we have to perform load+abs+store. Whether this
376 // is faster using a core reg or fp reg depends on the particular CPU. Without further
377 // investigation and testing we prefer core register. (If the result is subsequently used in
378 // another fp operation, the dalvik reg will probably get promoted and that should be handled
379 // by the cases above.)
380 return kCoreReg;
381}
382
383bool ArmMir2Lir::GenInlinedAbsFloat(CallInfo* info) {
384 if (info->result.location == kLocInvalid) {
385 return true; // Result is unused: inlining successful, no code generated.
386 }
387 RegLocation rl_dest = info->result;
388 RegLocation rl_src = UpdateLoc(info->args[0]);
389 RegisterClass reg_class = RegClassForAbsFP(rl_src, rl_dest);
390 rl_src = LoadValue(rl_src, reg_class);
391 RegLocation rl_result = EvalLoc(rl_dest, reg_class, true);
392 if (reg_class == kFPReg) {
393 NewLIR2(kThumb2Vabss, rl_result.reg.GetReg(), rl_src.reg.GetReg());
394 } else {
395 OpRegRegImm(kOpAnd, rl_result.reg, rl_src.reg, 0x7fffffff);
396 }
397 StoreValue(rl_dest, rl_result);
398 return true;
399}
400
401bool ArmMir2Lir::GenInlinedAbsDouble(CallInfo* info) {
402 if (info->result.location == kLocInvalid) {
403 return true; // Result is unused: inlining successful, no code generated.
404 }
405 RegLocation rl_dest = info->result;
406 RegLocation rl_src = UpdateLocWide(info->args[0]);
407 RegisterClass reg_class = RegClassForAbsFP(rl_src, rl_dest);
408 rl_src = LoadValueWide(rl_src, reg_class);
409 RegLocation rl_result = EvalLoc(rl_dest, reg_class, true);
410 if (reg_class == kFPReg) {
411 NewLIR2(kThumb2Vabsd, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Vladimir Markoa5f90b62014-08-14 15:23:32 +0100412 } else if (rl_result.reg.GetLow().GetReg() != rl_src.reg.GetHigh().GetReg()) {
413 // No inconvenient overlap.
414 OpRegCopy(rl_result.reg.GetLow(), rl_src.reg.GetLow());
415 OpRegRegImm(kOpAnd, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), 0x7fffffff);
Vladimir Marko5030d3e2014-07-17 10:43:08 +0100416 } else {
Vladimir Markoa5f90b62014-08-14 15:23:32 +0100417 // Inconvenient overlap, use a temp register to preserve the high word of the source.
418 RegStorage rs_tmp = AllocTemp();
419 OpRegCopy(rs_tmp, rl_src.reg.GetHigh());
420 OpRegCopy(rl_result.reg.GetLow(), rl_src.reg.GetLow());
421 OpRegRegImm(kOpAnd, rl_result.reg.GetHigh(), rs_tmp, 0x7fffffff);
422 FreeTemp(rs_tmp);
Vladimir Marko5030d3e2014-07-17 10:43:08 +0100423 }
424 StoreValueWide(rl_dest, rl_result);
425 return true;
426}
427
Brian Carlstrom7940e442013-07-12 13:46:57 -0700428bool ArmMir2Lir::GenInlinedSqrt(CallInfo* info) {
429 DCHECK_EQ(cu_->instruction_set, kThumb2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700430 RegLocation rl_src = info->args[0];
431 RegLocation rl_dest = InlineTargetWide(info); // double place for result
432 rl_src = LoadValueWide(rl_src, kFPReg);
433 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee091cc402014-03-31 10:14:40 -0700434 NewLIR2(kThumb2Vsqrtd, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700435 StoreValueWide(rl_dest, rl_result);
436 return true;
437}
438
439
440} // namespace art