blob: 94fc4743a4c60c9dea07dd355869d84d26032354 [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
Brian Carlstrom7940e442013-07-12 13:46:57 -070017#include "codegen_arm.h"
Andreas Gampe0b9203e2015-01-22 20:39:27 -080018
19#include "arm_lir.h"
20#include "base/logging.h"
21#include "dex/mir_graph.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070022#include "dex/quick/mir_to_lir-inl.h"
23
24namespace art {
25
26void ArmMir2Lir::GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070027 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070028 int op = kThumbBkpt;
29 RegLocation rl_result;
30
31 /*
32 * Don't attempt to optimize register usage since these opcodes call out to
33 * the handlers.
34 */
35 switch (opcode) {
36 case Instruction::ADD_FLOAT_2ADDR:
37 case Instruction::ADD_FLOAT:
38 op = kThumb2Vadds;
39 break;
40 case Instruction::SUB_FLOAT_2ADDR:
41 case Instruction::SUB_FLOAT:
42 op = kThumb2Vsubs;
43 break;
44 case Instruction::DIV_FLOAT_2ADDR:
45 case Instruction::DIV_FLOAT:
46 op = kThumb2Vdivs;
47 break;
48 case Instruction::MUL_FLOAT_2ADDR:
49 case Instruction::MUL_FLOAT:
50 op = kThumb2Vmuls;
51 break;
52 case Instruction::REM_FLOAT_2ADDR:
53 case Instruction::REM_FLOAT:
54 FlushAllRegs(); // Send everything to home location
Andreas Gampe98430592014-07-27 19:44:50 -070055 CallRuntimeHelperRegLocationRegLocation(kQuickFmodf, rl_src1, rl_src2, false);
buzbeea0cd2d72014-06-01 09:33:49 -070056 rl_result = GetReturn(kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -070057 StoreValue(rl_dest, rl_result);
58 return;
59 case Instruction::NEG_FLOAT:
60 GenNegFloat(rl_dest, rl_src1);
61 return;
62 default:
63 LOG(FATAL) << "Unexpected opcode: " << opcode;
64 }
65 rl_src1 = LoadValue(rl_src1, kFPReg);
66 rl_src2 = LoadValue(rl_src2, kFPReg);
67 rl_result = EvalLoc(rl_dest, kFPReg, true);
Bill Buzbee00e1ec62014-02-27 23:44:13 +000068 NewLIR3(op, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -070069 StoreValue(rl_dest, rl_result);
70}
71
72void ArmMir2Lir::GenArithOpDouble(Instruction::Code opcode,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070073 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070074 int op = kThumbBkpt;
75 RegLocation rl_result;
76
77 switch (opcode) {
78 case Instruction::ADD_DOUBLE_2ADDR:
79 case Instruction::ADD_DOUBLE:
80 op = kThumb2Vaddd;
81 break;
82 case Instruction::SUB_DOUBLE_2ADDR:
83 case Instruction::SUB_DOUBLE:
84 op = kThumb2Vsubd;
85 break;
86 case Instruction::DIV_DOUBLE_2ADDR:
87 case Instruction::DIV_DOUBLE:
88 op = kThumb2Vdivd;
89 break;
90 case Instruction::MUL_DOUBLE_2ADDR:
91 case Instruction::MUL_DOUBLE:
92 op = kThumb2Vmuld;
93 break;
94 case Instruction::REM_DOUBLE_2ADDR:
95 case Instruction::REM_DOUBLE:
96 FlushAllRegs(); // Send everything to home location
Andreas Gampe98430592014-07-27 19:44:50 -070097 CallRuntimeHelperRegLocationRegLocation(kQuickFmod, rl_src1, rl_src2, false);
buzbeea0cd2d72014-06-01 09:33:49 -070098 rl_result = GetReturnWide(kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -070099 StoreValueWide(rl_dest, rl_result);
100 return;
101 case Instruction::NEG_DOUBLE:
102 GenNegDouble(rl_dest, rl_src1);
103 return;
104 default:
105 LOG(FATAL) << "Unexpected opcode: " << opcode;
106 }
107
108 rl_src1 = LoadValueWide(rl_src1, kFPReg);
109 DCHECK(rl_src1.wide);
110 rl_src2 = LoadValueWide(rl_src2, kFPReg);
111 DCHECK(rl_src2.wide);
112 rl_result = EvalLoc(rl_dest, kFPReg, true);
113 DCHECK(rl_dest.wide);
114 DCHECK(rl_result.wide);
buzbee091cc402014-03-31 10:14:40 -0700115 NewLIR3(op, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700116 StoreValueWide(rl_dest, rl_result);
117}
118
Ningsheng Jian675e09b2014-10-23 13:48:36 +0800119void ArmMir2Lir::GenMultiplyByConstantFloat(RegLocation rl_dest, RegLocation rl_src1,
120 int32_t constant) {
121 RegLocation rl_result;
122 RegStorage r_tmp = AllocTempSingle();
123 LoadConstantNoClobber(r_tmp, constant);
124 rl_src1 = LoadValue(rl_src1, kFPReg);
125 rl_result = EvalLoc(rl_dest, kFPReg, true);
126 NewLIR3(kThumb2Vmuls, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), r_tmp.GetReg());
127 StoreValue(rl_dest, rl_result);
128}
129
130void ArmMir2Lir::GenMultiplyByConstantDouble(RegLocation rl_dest, RegLocation rl_src1,
131 int64_t constant) {
132 RegLocation rl_result;
133 RegStorage r_tmp = AllocTempDouble();
134 DCHECK(r_tmp.IsDouble());
135 LoadConstantWide(r_tmp, constant);
136 rl_src1 = LoadValueWide(rl_src1, kFPReg);
137 DCHECK(rl_src1.wide);
138 rl_result = EvalLocWide(rl_dest, kFPReg, true);
139 DCHECK(rl_dest.wide);
140 DCHECK(rl_result.wide);
141 NewLIR3(kThumb2Vmuld, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), r_tmp.GetReg());
142 StoreValueWide(rl_dest, rl_result);
143}
144
buzbee091cc402014-03-31 10:14:40 -0700145void ArmMir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700146 int op = kThumbBkpt;
147 int src_reg;
148 RegLocation rl_result;
149
150 switch (opcode) {
151 case Instruction::INT_TO_FLOAT:
152 op = kThumb2VcvtIF;
153 break;
154 case Instruction::FLOAT_TO_INT:
155 op = kThumb2VcvtFI;
156 break;
157 case Instruction::DOUBLE_TO_FLOAT:
158 op = kThumb2VcvtDF;
159 break;
160 case Instruction::FLOAT_TO_DOUBLE:
161 op = kThumb2VcvtFd;
162 break;
163 case Instruction::INT_TO_DOUBLE:
Zheng Xue19649a2014-02-27 13:30:55 +0000164 op = kThumb2VcvtF64S32;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700165 break;
166 case Instruction::DOUBLE_TO_INT:
167 op = kThumb2VcvtDI;
168 break;
Ian Rogersef6a7762013-12-19 17:58:05 -0800169 case Instruction::LONG_TO_DOUBLE: {
170 rl_src = LoadValueWide(rl_src, kFPReg);
buzbee85089dd2014-05-25 15:10:52 -0700171 RegisterInfo* info = GetRegInfo(rl_src.reg);
172 RegStorage src_low = info->FindMatchingView(RegisterInfo::kLowSingleStorageMask)->GetReg();
173 DCHECK(src_low.Valid());
174 RegStorage src_high = info->FindMatchingView(RegisterInfo::kHighSingleStorageMask)->GetReg();
175 DCHECK(src_high.Valid());
Ian Rogersef6a7762013-12-19 17:58:05 -0800176 rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800177 RegStorage tmp1 = AllocTempDouble();
178 RegStorage tmp2 = AllocTempDouble();
Ian Rogersef6a7762013-12-19 17:58:05 -0800179
buzbee091cc402014-03-31 10:14:40 -0700180 NewLIR2(kThumb2VcvtF64S32, tmp1.GetReg(), src_high.GetReg());
181 NewLIR2(kThumb2VcvtF64U32, rl_result.reg.GetReg(), src_low.GetReg());
buzbee2700f7e2014-03-07 09:46:20 -0800182 LoadConstantWide(tmp2, 0x41f0000000000000LL);
buzbee091cc402014-03-31 10:14:40 -0700183 NewLIR3(kThumb2VmlaF64, rl_result.reg.GetReg(), tmp1.GetReg(), tmp2.GetReg());
Ian Rogersef6a7762013-12-19 17:58:05 -0800184 FreeTemp(tmp1);
185 FreeTemp(tmp2);
186 StoreValueWide(rl_dest, rl_result);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700187 return;
Ian Rogersef6a7762013-12-19 17:58:05 -0800188 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700189 case Instruction::FLOAT_TO_LONG:
Vladimir Markofac10702015-04-22 11:51:52 +0100190 CheckEntrypointTypes<kQuickF2l, int64_t, float>(); // int64_t -> kCoreReg
191 GenConversionCall(kQuickF2l, rl_dest, rl_src, kCoreReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700192 return;
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000193 case Instruction::LONG_TO_FLOAT: {
194 rl_src = LoadValueWide(rl_src, kFPReg);
buzbee85089dd2014-05-25 15:10:52 -0700195 RegisterInfo* info = GetRegInfo(rl_src.reg);
196 RegStorage src_low = info->FindMatchingView(RegisterInfo::kLowSingleStorageMask)->GetReg();
197 DCHECK(src_low.Valid());
198 RegStorage src_high = info->FindMatchingView(RegisterInfo::kHighSingleStorageMask)->GetReg();
199 DCHECK(src_high.Valid());
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000200 rl_result = EvalLoc(rl_dest, kFPReg, true);
201 // Allocate temp registers.
buzbee2700f7e2014-03-07 09:46:20 -0800202 RegStorage high_val = AllocTempDouble();
203 RegStorage low_val = AllocTempDouble();
204 RegStorage const_val = AllocTempDouble();
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000205 // Long to double.
buzbee091cc402014-03-31 10:14:40 -0700206 NewLIR2(kThumb2VcvtF64S32, high_val.GetReg(), src_high.GetReg());
207 NewLIR2(kThumb2VcvtF64U32, low_val.GetReg(), src_low.GetReg());
buzbee2700f7e2014-03-07 09:46:20 -0800208 LoadConstantWide(const_val, INT64_C(0x41f0000000000000));
buzbee091cc402014-03-31 10:14:40 -0700209 NewLIR3(kThumb2VmlaF64, low_val.GetReg(), high_val.GetReg(), const_val.GetReg());
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000210 // Double to float.
buzbee091cc402014-03-31 10:14:40 -0700211 NewLIR2(kThumb2VcvtDF, rl_result.reg.GetReg(), low_val.GetReg());
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000212 // Free temp registers.
213 FreeTemp(high_val);
214 FreeTemp(low_val);
215 FreeTemp(const_val);
216 // Store result.
217 StoreValue(rl_dest, rl_result);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700218 return;
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000219 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700220 case Instruction::DOUBLE_TO_LONG:
Vladimir Markofac10702015-04-22 11:51:52 +0100221 CheckEntrypointTypes<kQuickD2l, int64_t, double>(); // int64_t -> kCoreReg
222 GenConversionCall(kQuickD2l, rl_dest, rl_src, kCoreReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700223 return;
224 default:
225 LOG(FATAL) << "Unexpected opcode: " << opcode;
226 }
227 if (rl_src.wide) {
228 rl_src = LoadValueWide(rl_src, kFPReg);
buzbee091cc402014-03-31 10:14:40 -0700229 src_reg = rl_src.reg.GetReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700230 } else {
231 rl_src = LoadValue(rl_src, kFPReg);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000232 src_reg = rl_src.reg.GetReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700233 }
234 if (rl_dest.wide) {
235 rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee091cc402014-03-31 10:14:40 -0700236 NewLIR2(op, rl_result.reg.GetReg(), src_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700237 StoreValueWide(rl_dest, rl_result);
238 } else {
239 rl_result = EvalLoc(rl_dest, kFPReg, true);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000240 NewLIR2(op, rl_result.reg.GetReg(), src_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700241 StoreValue(rl_dest, rl_result);
242 }
243}
244
245void ArmMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700246 bool is_double) {
buzbee0d829482013-10-11 15:24:55 -0700247 LIR* target = &block_label_list_[bb->taken];
Brian Carlstrom7940e442013-07-12 13:46:57 -0700248 RegLocation rl_src1;
249 RegLocation rl_src2;
250 if (is_double) {
251 rl_src1 = mir_graph_->GetSrcWide(mir, 0);
252 rl_src2 = mir_graph_->GetSrcWide(mir, 2);
253 rl_src1 = LoadValueWide(rl_src1, kFPReg);
254 rl_src2 = LoadValueWide(rl_src2, kFPReg);
buzbee091cc402014-03-31 10:14:40 -0700255 NewLIR2(kThumb2Vcmpd, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700256 } else {
257 rl_src1 = mir_graph_->GetSrc(mir, 0);
258 rl_src2 = mir_graph_->GetSrc(mir, 1);
259 rl_src1 = LoadValue(rl_src1, kFPReg);
260 rl_src2 = LoadValue(rl_src2, kFPReg);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000261 NewLIR2(kThumb2Vcmps, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700262 }
263 NewLIR0(kThumb2Fmstat);
Vladimir Markoa8946072014-01-22 10:30:44 +0000264 ConditionCode ccode = mir->meta.ccode;
Brian Carlstromdf629502013-07-17 22:39:56 -0700265 switch (ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700266 case kCondEq:
267 case kCondNe:
268 break;
269 case kCondLt:
270 if (gt_bias) {
271 ccode = kCondMi;
272 }
273 break;
274 case kCondLe:
275 if (gt_bias) {
276 ccode = kCondLs;
277 }
278 break;
279 case kCondGt:
280 if (gt_bias) {
281 ccode = kCondHi;
282 }
283 break;
284 case kCondGe:
285 if (gt_bias) {
Vladimir Marko58af1f92013-12-19 13:31:15 +0000286 ccode = kCondUge;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700287 }
288 break;
289 default:
290 LOG(FATAL) << "Unexpected ccode: " << ccode;
291 }
292 OpCondBranch(ccode, target);
293}
294
295
296void ArmMir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700297 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700298 bool is_double = false;
299 int default_result = -1;
300 RegLocation rl_result;
301
302 switch (opcode) {
303 case Instruction::CMPL_FLOAT:
304 is_double = false;
305 default_result = -1;
306 break;
307 case Instruction::CMPG_FLOAT:
308 is_double = false;
309 default_result = 1;
310 break;
311 case Instruction::CMPL_DOUBLE:
312 is_double = true;
313 default_result = -1;
314 break;
315 case Instruction::CMPG_DOUBLE:
316 is_double = true;
317 default_result = 1;
318 break;
319 default:
320 LOG(FATAL) << "Unexpected opcode: " << opcode;
321 }
322 if (is_double) {
323 rl_src1 = LoadValueWide(rl_src1, kFPReg);
324 rl_src2 = LoadValueWide(rl_src2, kFPReg);
325 // In case result vreg is also a src vreg, break association to avoid useless copy by EvalLoc()
326 ClobberSReg(rl_dest.s_reg_low);
327 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800328 LoadConstant(rl_result.reg, default_result);
buzbee091cc402014-03-31 10:14:40 -0700329 NewLIR2(kThumb2Vcmpd, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700330 } else {
331 rl_src1 = LoadValue(rl_src1, kFPReg);
332 rl_src2 = LoadValue(rl_src2, kFPReg);
333 // In case result vreg is also a srcvreg, break association to avoid useless copy by EvalLoc()
334 ClobberSReg(rl_dest.s_reg_low);
335 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800336 LoadConstant(rl_result.reg, default_result);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000337 NewLIR2(kThumb2Vcmps, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700338 }
buzbee091cc402014-03-31 10:14:40 -0700339 DCHECK(!rl_result.reg.IsFloat());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700340 NewLIR0(kThumb2Fmstat);
341
Dave Allison3da67a52014-04-02 17:03:45 -0700342 LIR* it = OpIT((default_result == -1) ? kCondGt : kCondMi, "");
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000343 NewLIR2(kThumb2MovI8M, rl_result.reg.GetReg(),
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700344 ModifiedImmediate(-default_result)); // Must not alter ccodes
Dave Allison3da67a52014-04-02 17:03:45 -0700345 OpEndIT(it);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700346
Dave Allison3da67a52014-04-02 17:03:45 -0700347 it = OpIT(kCondEq, "");
buzbee2700f7e2014-03-07 09:46:20 -0800348 LoadConstant(rl_result.reg, 0);
Dave Allison3da67a52014-04-02 17:03:45 -0700349 OpEndIT(it);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700350
351 StoreValue(rl_dest, rl_result);
352}
353
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700354void ArmMir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700355 RegLocation rl_result;
356 rl_src = LoadValue(rl_src, kFPReg);
357 rl_result = EvalLoc(rl_dest, kFPReg, true);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000358 NewLIR2(kThumb2Vnegs, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700359 StoreValue(rl_dest, rl_result);
360}
361
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700362void ArmMir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700363 RegLocation rl_result;
364 rl_src = LoadValueWide(rl_src, kFPReg);
365 rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee091cc402014-03-31 10:14:40 -0700366 NewLIR2(kThumb2Vnegd, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700367 StoreValueWide(rl_dest, rl_result);
368}
369
Vladimir Marko5030d3e2014-07-17 10:43:08 +0100370static RegisterClass RegClassForAbsFP(RegLocation rl_src, RegLocation rl_dest) {
371 // If src is in a core reg or, unlikely, dest has been promoted to a core reg, use core reg.
372 if ((rl_src.location == kLocPhysReg && !rl_src.reg.IsFloat()) ||
373 (rl_dest.location == kLocPhysReg && !rl_dest.reg.IsFloat())) {
374 return kCoreReg;
375 }
376 // If src is in an fp reg or dest has been promoted to an fp reg, use fp reg.
377 if (rl_src.location == kLocPhysReg || rl_dest.location == kLocPhysReg) {
378 return kFPReg;
379 }
380 // With both src and dest in the stack frame we have to perform load+abs+store. Whether this
381 // is faster using a core reg or fp reg depends on the particular CPU. Without further
382 // investigation and testing we prefer core register. (If the result is subsequently used in
383 // another fp operation, the dalvik reg will probably get promoted and that should be handled
384 // by the cases above.)
385 return kCoreReg;
386}
387
388bool ArmMir2Lir::GenInlinedAbsFloat(CallInfo* info) {
389 if (info->result.location == kLocInvalid) {
390 return true; // Result is unused: inlining successful, no code generated.
391 }
392 RegLocation rl_dest = info->result;
393 RegLocation rl_src = UpdateLoc(info->args[0]);
394 RegisterClass reg_class = RegClassForAbsFP(rl_src, rl_dest);
395 rl_src = LoadValue(rl_src, reg_class);
396 RegLocation rl_result = EvalLoc(rl_dest, reg_class, true);
397 if (reg_class == kFPReg) {
398 NewLIR2(kThumb2Vabss, rl_result.reg.GetReg(), rl_src.reg.GetReg());
399 } else {
400 OpRegRegImm(kOpAnd, rl_result.reg, rl_src.reg, 0x7fffffff);
401 }
402 StoreValue(rl_dest, rl_result);
403 return true;
404}
405
406bool ArmMir2Lir::GenInlinedAbsDouble(CallInfo* info) {
407 if (info->result.location == kLocInvalid) {
408 return true; // Result is unused: inlining successful, no code generated.
409 }
410 RegLocation rl_dest = info->result;
411 RegLocation rl_src = UpdateLocWide(info->args[0]);
412 RegisterClass reg_class = RegClassForAbsFP(rl_src, rl_dest);
413 rl_src = LoadValueWide(rl_src, reg_class);
414 RegLocation rl_result = EvalLoc(rl_dest, reg_class, true);
415 if (reg_class == kFPReg) {
416 NewLIR2(kThumb2Vabsd, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Vladimir Markoa5f90b62014-08-14 15:23:32 +0100417 } else if (rl_result.reg.GetLow().GetReg() != rl_src.reg.GetHigh().GetReg()) {
418 // No inconvenient overlap.
419 OpRegCopy(rl_result.reg.GetLow(), rl_src.reg.GetLow());
420 OpRegRegImm(kOpAnd, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), 0x7fffffff);
Vladimir Marko5030d3e2014-07-17 10:43:08 +0100421 } else {
Vladimir Markoa5f90b62014-08-14 15:23:32 +0100422 // Inconvenient overlap, use a temp register to preserve the high word of the source.
423 RegStorage rs_tmp = AllocTemp();
424 OpRegCopy(rs_tmp, rl_src.reg.GetHigh());
425 OpRegCopy(rl_result.reg.GetLow(), rl_src.reg.GetLow());
426 OpRegRegImm(kOpAnd, rl_result.reg.GetHigh(), rs_tmp, 0x7fffffff);
427 FreeTemp(rs_tmp);
Vladimir Marko5030d3e2014-07-17 10:43:08 +0100428 }
429 StoreValueWide(rl_dest, rl_result);
430 return true;
431}
432
Brian Carlstrom7940e442013-07-12 13:46:57 -0700433bool ArmMir2Lir::GenInlinedSqrt(CallInfo* info) {
434 DCHECK_EQ(cu_->instruction_set, kThumb2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700435 RegLocation rl_src = info->args[0];
436 RegLocation rl_dest = InlineTargetWide(info); // double place for result
437 rl_src = LoadValueWide(rl_src, kFPReg);
438 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee091cc402014-03-31 10:14:40 -0700439 NewLIR2(kThumb2Vsqrtd, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700440 StoreValueWide(rl_dest, rl_result);
441 return true;
442}
443
444
445} // namespace art