blob: eb1383fcff01615a140e243afbbd287d813f45a0 [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:
Andreas Gampe98430592014-07-27 19:44:50 -0700190 GenConversionCall(kQuickF2l, rl_dest, rl_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700191 return;
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000192 case Instruction::LONG_TO_FLOAT: {
193 rl_src = LoadValueWide(rl_src, kFPReg);
buzbee85089dd2014-05-25 15:10:52 -0700194 RegisterInfo* info = GetRegInfo(rl_src.reg);
195 RegStorage src_low = info->FindMatchingView(RegisterInfo::kLowSingleStorageMask)->GetReg();
196 DCHECK(src_low.Valid());
197 RegStorage src_high = info->FindMatchingView(RegisterInfo::kHighSingleStorageMask)->GetReg();
198 DCHECK(src_high.Valid());
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000199 rl_result = EvalLoc(rl_dest, kFPReg, true);
200 // Allocate temp registers.
buzbee2700f7e2014-03-07 09:46:20 -0800201 RegStorage high_val = AllocTempDouble();
202 RegStorage low_val = AllocTempDouble();
203 RegStorage const_val = AllocTempDouble();
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000204 // Long to double.
buzbee091cc402014-03-31 10:14:40 -0700205 NewLIR2(kThumb2VcvtF64S32, high_val.GetReg(), src_high.GetReg());
206 NewLIR2(kThumb2VcvtF64U32, low_val.GetReg(), src_low.GetReg());
buzbee2700f7e2014-03-07 09:46:20 -0800207 LoadConstantWide(const_val, INT64_C(0x41f0000000000000));
buzbee091cc402014-03-31 10:14:40 -0700208 NewLIR3(kThumb2VmlaF64, low_val.GetReg(), high_val.GetReg(), const_val.GetReg());
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000209 // Double to float.
buzbee091cc402014-03-31 10:14:40 -0700210 NewLIR2(kThumb2VcvtDF, rl_result.reg.GetReg(), low_val.GetReg());
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000211 // Free temp registers.
212 FreeTemp(high_val);
213 FreeTemp(low_val);
214 FreeTemp(const_val);
215 // Store result.
216 StoreValue(rl_dest, rl_result);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700217 return;
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000218 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700219 case Instruction::DOUBLE_TO_LONG:
Andreas Gampe98430592014-07-27 19:44:50 -0700220 GenConversionCall(kQuickD2l, rl_dest, rl_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700221 return;
222 default:
223 LOG(FATAL) << "Unexpected opcode: " << opcode;
224 }
225 if (rl_src.wide) {
226 rl_src = LoadValueWide(rl_src, kFPReg);
buzbee091cc402014-03-31 10:14:40 -0700227 src_reg = rl_src.reg.GetReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700228 } else {
229 rl_src = LoadValue(rl_src, kFPReg);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000230 src_reg = rl_src.reg.GetReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700231 }
232 if (rl_dest.wide) {
233 rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee091cc402014-03-31 10:14:40 -0700234 NewLIR2(op, rl_result.reg.GetReg(), src_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700235 StoreValueWide(rl_dest, rl_result);
236 } else {
237 rl_result = EvalLoc(rl_dest, kFPReg, true);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000238 NewLIR2(op, rl_result.reg.GetReg(), src_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700239 StoreValue(rl_dest, rl_result);
240 }
241}
242
243void ArmMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700244 bool is_double) {
buzbee0d829482013-10-11 15:24:55 -0700245 LIR* target = &block_label_list_[bb->taken];
Brian Carlstrom7940e442013-07-12 13:46:57 -0700246 RegLocation rl_src1;
247 RegLocation rl_src2;
248 if (is_double) {
249 rl_src1 = mir_graph_->GetSrcWide(mir, 0);
250 rl_src2 = mir_graph_->GetSrcWide(mir, 2);
251 rl_src1 = LoadValueWide(rl_src1, kFPReg);
252 rl_src2 = LoadValueWide(rl_src2, kFPReg);
buzbee091cc402014-03-31 10:14:40 -0700253 NewLIR2(kThumb2Vcmpd, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700254 } else {
255 rl_src1 = mir_graph_->GetSrc(mir, 0);
256 rl_src2 = mir_graph_->GetSrc(mir, 1);
257 rl_src1 = LoadValue(rl_src1, kFPReg);
258 rl_src2 = LoadValue(rl_src2, kFPReg);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000259 NewLIR2(kThumb2Vcmps, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700260 }
261 NewLIR0(kThumb2Fmstat);
Vladimir Markoa8946072014-01-22 10:30:44 +0000262 ConditionCode ccode = mir->meta.ccode;
Brian Carlstromdf629502013-07-17 22:39:56 -0700263 switch (ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700264 case kCondEq:
265 case kCondNe:
266 break;
267 case kCondLt:
268 if (gt_bias) {
269 ccode = kCondMi;
270 }
271 break;
272 case kCondLe:
273 if (gt_bias) {
274 ccode = kCondLs;
275 }
276 break;
277 case kCondGt:
278 if (gt_bias) {
279 ccode = kCondHi;
280 }
281 break;
282 case kCondGe:
283 if (gt_bias) {
Vladimir Marko58af1f92013-12-19 13:31:15 +0000284 ccode = kCondUge;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700285 }
286 break;
287 default:
288 LOG(FATAL) << "Unexpected ccode: " << ccode;
289 }
290 OpCondBranch(ccode, target);
291}
292
293
294void ArmMir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700295 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700296 bool is_double = false;
297 int default_result = -1;
298 RegLocation rl_result;
299
300 switch (opcode) {
301 case Instruction::CMPL_FLOAT:
302 is_double = false;
303 default_result = -1;
304 break;
305 case Instruction::CMPG_FLOAT:
306 is_double = false;
307 default_result = 1;
308 break;
309 case Instruction::CMPL_DOUBLE:
310 is_double = true;
311 default_result = -1;
312 break;
313 case Instruction::CMPG_DOUBLE:
314 is_double = true;
315 default_result = 1;
316 break;
317 default:
318 LOG(FATAL) << "Unexpected opcode: " << opcode;
319 }
320 if (is_double) {
321 rl_src1 = LoadValueWide(rl_src1, kFPReg);
322 rl_src2 = LoadValueWide(rl_src2, kFPReg);
323 // In case result vreg is also a src vreg, break association to avoid useless copy by EvalLoc()
324 ClobberSReg(rl_dest.s_reg_low);
325 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800326 LoadConstant(rl_result.reg, default_result);
buzbee091cc402014-03-31 10:14:40 -0700327 NewLIR2(kThumb2Vcmpd, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700328 } else {
329 rl_src1 = LoadValue(rl_src1, kFPReg);
330 rl_src2 = LoadValue(rl_src2, kFPReg);
331 // In case result vreg is also a srcvreg, break association to avoid useless copy by EvalLoc()
332 ClobberSReg(rl_dest.s_reg_low);
333 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800334 LoadConstant(rl_result.reg, default_result);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000335 NewLIR2(kThumb2Vcmps, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700336 }
buzbee091cc402014-03-31 10:14:40 -0700337 DCHECK(!rl_result.reg.IsFloat());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700338 NewLIR0(kThumb2Fmstat);
339
Dave Allison3da67a52014-04-02 17:03:45 -0700340 LIR* it = OpIT((default_result == -1) ? kCondGt : kCondMi, "");
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000341 NewLIR2(kThumb2MovI8M, rl_result.reg.GetReg(),
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700342 ModifiedImmediate(-default_result)); // Must not alter ccodes
Dave Allison3da67a52014-04-02 17:03:45 -0700343 OpEndIT(it);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700344
Dave Allison3da67a52014-04-02 17:03:45 -0700345 it = OpIT(kCondEq, "");
buzbee2700f7e2014-03-07 09:46:20 -0800346 LoadConstant(rl_result.reg, 0);
Dave Allison3da67a52014-04-02 17:03:45 -0700347 OpEndIT(it);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700348
349 StoreValue(rl_dest, rl_result);
350}
351
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700352void ArmMir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700353 RegLocation rl_result;
354 rl_src = LoadValue(rl_src, kFPReg);
355 rl_result = EvalLoc(rl_dest, kFPReg, true);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000356 NewLIR2(kThumb2Vnegs, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700357 StoreValue(rl_dest, rl_result);
358}
359
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700360void ArmMir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700361 RegLocation rl_result;
362 rl_src = LoadValueWide(rl_src, kFPReg);
363 rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee091cc402014-03-31 10:14:40 -0700364 NewLIR2(kThumb2Vnegd, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700365 StoreValueWide(rl_dest, rl_result);
366}
367
Vladimir Marko5030d3e2014-07-17 10:43:08 +0100368static RegisterClass RegClassForAbsFP(RegLocation rl_src, RegLocation rl_dest) {
369 // If src is in a core reg or, unlikely, dest has been promoted to a core reg, use core reg.
370 if ((rl_src.location == kLocPhysReg && !rl_src.reg.IsFloat()) ||
371 (rl_dest.location == kLocPhysReg && !rl_dest.reg.IsFloat())) {
372 return kCoreReg;
373 }
374 // If src is in an fp reg or dest has been promoted to an fp reg, use fp reg.
375 if (rl_src.location == kLocPhysReg || rl_dest.location == kLocPhysReg) {
376 return kFPReg;
377 }
378 // With both src and dest in the stack frame we have to perform load+abs+store. Whether this
379 // is faster using a core reg or fp reg depends on the particular CPU. Without further
380 // investigation and testing we prefer core register. (If the result is subsequently used in
381 // another fp operation, the dalvik reg will probably get promoted and that should be handled
382 // by the cases above.)
383 return kCoreReg;
384}
385
386bool ArmMir2Lir::GenInlinedAbsFloat(CallInfo* info) {
387 if (info->result.location == kLocInvalid) {
388 return true; // Result is unused: inlining successful, no code generated.
389 }
390 RegLocation rl_dest = info->result;
391 RegLocation rl_src = UpdateLoc(info->args[0]);
392 RegisterClass reg_class = RegClassForAbsFP(rl_src, rl_dest);
393 rl_src = LoadValue(rl_src, reg_class);
394 RegLocation rl_result = EvalLoc(rl_dest, reg_class, true);
395 if (reg_class == kFPReg) {
396 NewLIR2(kThumb2Vabss, rl_result.reg.GetReg(), rl_src.reg.GetReg());
397 } else {
398 OpRegRegImm(kOpAnd, rl_result.reg, rl_src.reg, 0x7fffffff);
399 }
400 StoreValue(rl_dest, rl_result);
401 return true;
402}
403
404bool ArmMir2Lir::GenInlinedAbsDouble(CallInfo* info) {
405 if (info->result.location == kLocInvalid) {
406 return true; // Result is unused: inlining successful, no code generated.
407 }
408 RegLocation rl_dest = info->result;
409 RegLocation rl_src = UpdateLocWide(info->args[0]);
410 RegisterClass reg_class = RegClassForAbsFP(rl_src, rl_dest);
411 rl_src = LoadValueWide(rl_src, reg_class);
412 RegLocation rl_result = EvalLoc(rl_dest, reg_class, true);
413 if (reg_class == kFPReg) {
414 NewLIR2(kThumb2Vabsd, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Vladimir Markoa5f90b62014-08-14 15:23:32 +0100415 } else if (rl_result.reg.GetLow().GetReg() != rl_src.reg.GetHigh().GetReg()) {
416 // No inconvenient overlap.
417 OpRegCopy(rl_result.reg.GetLow(), rl_src.reg.GetLow());
418 OpRegRegImm(kOpAnd, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), 0x7fffffff);
Vladimir Marko5030d3e2014-07-17 10:43:08 +0100419 } else {
Vladimir Markoa5f90b62014-08-14 15:23:32 +0100420 // Inconvenient overlap, use a temp register to preserve the high word of the source.
421 RegStorage rs_tmp = AllocTemp();
422 OpRegCopy(rs_tmp, rl_src.reg.GetHigh());
423 OpRegCopy(rl_result.reg.GetLow(), rl_src.reg.GetLow());
424 OpRegRegImm(kOpAnd, rl_result.reg.GetHigh(), rs_tmp, 0x7fffffff);
425 FreeTemp(rs_tmp);
Vladimir Marko5030d3e2014-07-17 10:43:08 +0100426 }
427 StoreValueWide(rl_dest, rl_result);
428 return true;
429}
430
Brian Carlstrom7940e442013-07-12 13:46:57 -0700431bool ArmMir2Lir::GenInlinedSqrt(CallInfo* info) {
432 DCHECK_EQ(cu_->instruction_set, kThumb2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700433 RegLocation rl_src = info->args[0];
434 RegLocation rl_dest = InlineTargetWide(info); // double place for result
435 rl_src = LoadValueWide(rl_src, kFPReg);
436 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee091cc402014-03-31 10:14:40 -0700437 NewLIR2(kThumb2Vsqrtd, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700438 StoreValueWide(rl_dest, rl_result);
439 return true;
440}
441
442
443} // namespace art