blob: c922eb19b8fcfa04ff94dffc4d34626164c6f8ff [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
Ian Rogersdd7624d2014-03-14 17:43:00 -070052 CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(4, pFmodf), rl_src1, rl_src2,
Ian Rogers7655f292013-07-29 11:07:13 -070053 false);
Brian Carlstrom7940e442013-07-12 13:46:57 -070054 rl_result = GetReturn(true);
55 StoreValue(rl_dest, rl_result);
56 return;
57 case Instruction::NEG_FLOAT:
58 GenNegFloat(rl_dest, rl_src1);
59 return;
60 default:
61 LOG(FATAL) << "Unexpected opcode: " << opcode;
62 }
63 rl_src1 = LoadValue(rl_src1, kFPReg);
64 rl_src2 = LoadValue(rl_src2, kFPReg);
65 rl_result = EvalLoc(rl_dest, kFPReg, true);
Bill Buzbee00e1ec62014-02-27 23:44:13 +000066 NewLIR3(op, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -070067 StoreValue(rl_dest, rl_result);
68}
69
70void ArmMir2Lir::GenArithOpDouble(Instruction::Code opcode,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070071 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070072 int op = kThumbBkpt;
73 RegLocation rl_result;
74
75 switch (opcode) {
76 case Instruction::ADD_DOUBLE_2ADDR:
77 case Instruction::ADD_DOUBLE:
78 op = kThumb2Vaddd;
79 break;
80 case Instruction::SUB_DOUBLE_2ADDR:
81 case Instruction::SUB_DOUBLE:
82 op = kThumb2Vsubd;
83 break;
84 case Instruction::DIV_DOUBLE_2ADDR:
85 case Instruction::DIV_DOUBLE:
86 op = kThumb2Vdivd;
87 break;
88 case Instruction::MUL_DOUBLE_2ADDR:
89 case Instruction::MUL_DOUBLE:
90 op = kThumb2Vmuld;
91 break;
92 case Instruction::REM_DOUBLE_2ADDR:
93 case Instruction::REM_DOUBLE:
94 FlushAllRegs(); // Send everything to home location
Ian Rogersdd7624d2014-03-14 17:43:00 -070095 CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(4, pFmod), rl_src1, rl_src2,
Ian Rogers7655f292013-07-29 11:07:13 -070096 false);
Brian Carlstrom7940e442013-07-12 13:46:57 -070097 rl_result = GetReturnWide(true);
98 StoreValueWide(rl_dest, rl_result);
99 return;
100 case Instruction::NEG_DOUBLE:
101 GenNegDouble(rl_dest, rl_src1);
102 return;
103 default:
104 LOG(FATAL) << "Unexpected opcode: " << opcode;
105 }
106
107 rl_src1 = LoadValueWide(rl_src1, kFPReg);
108 DCHECK(rl_src1.wide);
109 rl_src2 = LoadValueWide(rl_src2, kFPReg);
110 DCHECK(rl_src2.wide);
111 rl_result = EvalLoc(rl_dest, kFPReg, true);
112 DCHECK(rl_dest.wide);
113 DCHECK(rl_result.wide);
buzbee091cc402014-03-31 10:14:40 -0700114 NewLIR3(op, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700115 StoreValueWide(rl_dest, rl_result);
116}
117
buzbee091cc402014-03-31 10:14:40 -0700118void ArmMir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700119 int op = kThumbBkpt;
120 int src_reg;
121 RegLocation rl_result;
122
123 switch (opcode) {
124 case Instruction::INT_TO_FLOAT:
125 op = kThumb2VcvtIF;
126 break;
127 case Instruction::FLOAT_TO_INT:
128 op = kThumb2VcvtFI;
129 break;
130 case Instruction::DOUBLE_TO_FLOAT:
131 op = kThumb2VcvtDF;
132 break;
133 case Instruction::FLOAT_TO_DOUBLE:
134 op = kThumb2VcvtFd;
135 break;
136 case Instruction::INT_TO_DOUBLE:
Zheng Xue19649a2014-02-27 13:30:55 +0000137 op = kThumb2VcvtF64S32;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700138 break;
139 case Instruction::DOUBLE_TO_INT:
140 op = kThumb2VcvtDI;
141 break;
Ian Rogersef6a7762013-12-19 17:58:05 -0800142 case Instruction::LONG_TO_DOUBLE: {
143 rl_src = LoadValueWide(rl_src, kFPReg);
buzbee85089dd2014-05-25 15:10:52 -0700144 RegisterInfo* info = GetRegInfo(rl_src.reg);
145 RegStorage src_low = info->FindMatchingView(RegisterInfo::kLowSingleStorageMask)->GetReg();
146 DCHECK(src_low.Valid());
147 RegStorage src_high = info->FindMatchingView(RegisterInfo::kHighSingleStorageMask)->GetReg();
148 DCHECK(src_high.Valid());
Ian Rogersef6a7762013-12-19 17:58:05 -0800149 rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800150 RegStorage tmp1 = AllocTempDouble();
151 RegStorage tmp2 = AllocTempDouble();
Ian Rogersef6a7762013-12-19 17:58:05 -0800152
buzbee091cc402014-03-31 10:14:40 -0700153 NewLIR2(kThumb2VcvtF64S32, tmp1.GetReg(), src_high.GetReg());
154 NewLIR2(kThumb2VcvtF64U32, rl_result.reg.GetReg(), src_low.GetReg());
buzbee2700f7e2014-03-07 09:46:20 -0800155 LoadConstantWide(tmp2, 0x41f0000000000000LL);
buzbee091cc402014-03-31 10:14:40 -0700156 NewLIR3(kThumb2VmlaF64, rl_result.reg.GetReg(), tmp1.GetReg(), tmp2.GetReg());
Ian Rogersef6a7762013-12-19 17:58:05 -0800157 FreeTemp(tmp1);
158 FreeTemp(tmp2);
159 StoreValueWide(rl_dest, rl_result);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700160 return;
Ian Rogersef6a7762013-12-19 17:58:05 -0800161 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700162 case Instruction::FLOAT_TO_LONG:
Ian Rogersdd7624d2014-03-14 17:43:00 -0700163 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(4, pF2l), rl_dest, rl_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700164 return;
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000165 case Instruction::LONG_TO_FLOAT: {
166 rl_src = LoadValueWide(rl_src, kFPReg);
buzbee85089dd2014-05-25 15:10:52 -0700167 RegisterInfo* info = GetRegInfo(rl_src.reg);
168 RegStorage src_low = info->FindMatchingView(RegisterInfo::kLowSingleStorageMask)->GetReg();
169 DCHECK(src_low.Valid());
170 RegStorage src_high = info->FindMatchingView(RegisterInfo::kHighSingleStorageMask)->GetReg();
171 DCHECK(src_high.Valid());
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000172 rl_result = EvalLoc(rl_dest, kFPReg, true);
173 // Allocate temp registers.
buzbee2700f7e2014-03-07 09:46:20 -0800174 RegStorage high_val = AllocTempDouble();
175 RegStorage low_val = AllocTempDouble();
176 RegStorage const_val = AllocTempDouble();
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000177 // Long to double.
buzbee091cc402014-03-31 10:14:40 -0700178 NewLIR2(kThumb2VcvtF64S32, high_val.GetReg(), src_high.GetReg());
179 NewLIR2(kThumb2VcvtF64U32, low_val.GetReg(), src_low.GetReg());
buzbee2700f7e2014-03-07 09:46:20 -0800180 LoadConstantWide(const_val, INT64_C(0x41f0000000000000));
buzbee091cc402014-03-31 10:14:40 -0700181 NewLIR3(kThumb2VmlaF64, low_val.GetReg(), high_val.GetReg(), const_val.GetReg());
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000182 // Double to float.
buzbee091cc402014-03-31 10:14:40 -0700183 NewLIR2(kThumb2VcvtDF, rl_result.reg.GetReg(), low_val.GetReg());
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000184 // Free temp registers.
185 FreeTemp(high_val);
186 FreeTemp(low_val);
187 FreeTemp(const_val);
188 // Store result.
189 StoreValue(rl_dest, rl_result);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700190 return;
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000191 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700192 case Instruction::DOUBLE_TO_LONG:
Ian Rogersdd7624d2014-03-14 17:43:00 -0700193 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(4, pD2l), rl_dest, rl_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700194 return;
195 default:
196 LOG(FATAL) << "Unexpected opcode: " << opcode;
197 }
198 if (rl_src.wide) {
199 rl_src = LoadValueWide(rl_src, kFPReg);
buzbee091cc402014-03-31 10:14:40 -0700200 src_reg = rl_src.reg.GetReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700201 } else {
202 rl_src = LoadValue(rl_src, kFPReg);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000203 src_reg = rl_src.reg.GetReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700204 }
205 if (rl_dest.wide) {
206 rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee091cc402014-03-31 10:14:40 -0700207 NewLIR2(op, rl_result.reg.GetReg(), src_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700208 StoreValueWide(rl_dest, rl_result);
209 } else {
210 rl_result = EvalLoc(rl_dest, kFPReg, true);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000211 NewLIR2(op, rl_result.reg.GetReg(), src_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700212 StoreValue(rl_dest, rl_result);
213 }
214}
215
216void ArmMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700217 bool is_double) {
buzbee0d829482013-10-11 15:24:55 -0700218 LIR* target = &block_label_list_[bb->taken];
Brian Carlstrom7940e442013-07-12 13:46:57 -0700219 RegLocation rl_src1;
220 RegLocation rl_src2;
221 if (is_double) {
222 rl_src1 = mir_graph_->GetSrcWide(mir, 0);
223 rl_src2 = mir_graph_->GetSrcWide(mir, 2);
224 rl_src1 = LoadValueWide(rl_src1, kFPReg);
225 rl_src2 = LoadValueWide(rl_src2, kFPReg);
buzbee091cc402014-03-31 10:14:40 -0700226 NewLIR2(kThumb2Vcmpd, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700227 } else {
228 rl_src1 = mir_graph_->GetSrc(mir, 0);
229 rl_src2 = mir_graph_->GetSrc(mir, 1);
230 rl_src1 = LoadValue(rl_src1, kFPReg);
231 rl_src2 = LoadValue(rl_src2, kFPReg);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000232 NewLIR2(kThumb2Vcmps, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700233 }
234 NewLIR0(kThumb2Fmstat);
Vladimir Markoa8946072014-01-22 10:30:44 +0000235 ConditionCode ccode = mir->meta.ccode;
Brian Carlstromdf629502013-07-17 22:39:56 -0700236 switch (ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700237 case kCondEq:
238 case kCondNe:
239 break;
240 case kCondLt:
241 if (gt_bias) {
242 ccode = kCondMi;
243 }
244 break;
245 case kCondLe:
246 if (gt_bias) {
247 ccode = kCondLs;
248 }
249 break;
250 case kCondGt:
251 if (gt_bias) {
252 ccode = kCondHi;
253 }
254 break;
255 case kCondGe:
256 if (gt_bias) {
Vladimir Marko58af1f92013-12-19 13:31:15 +0000257 ccode = kCondUge;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700258 }
259 break;
260 default:
261 LOG(FATAL) << "Unexpected ccode: " << ccode;
262 }
263 OpCondBranch(ccode, target);
264}
265
266
267void ArmMir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700268 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700269 bool is_double = false;
270 int default_result = -1;
271 RegLocation rl_result;
272
273 switch (opcode) {
274 case Instruction::CMPL_FLOAT:
275 is_double = false;
276 default_result = -1;
277 break;
278 case Instruction::CMPG_FLOAT:
279 is_double = false;
280 default_result = 1;
281 break;
282 case Instruction::CMPL_DOUBLE:
283 is_double = true;
284 default_result = -1;
285 break;
286 case Instruction::CMPG_DOUBLE:
287 is_double = true;
288 default_result = 1;
289 break;
290 default:
291 LOG(FATAL) << "Unexpected opcode: " << opcode;
292 }
293 if (is_double) {
294 rl_src1 = LoadValueWide(rl_src1, kFPReg);
295 rl_src2 = LoadValueWide(rl_src2, kFPReg);
296 // In case result vreg is also a src vreg, break association to avoid useless copy by EvalLoc()
297 ClobberSReg(rl_dest.s_reg_low);
298 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800299 LoadConstant(rl_result.reg, default_result);
buzbee091cc402014-03-31 10:14:40 -0700300 NewLIR2(kThumb2Vcmpd, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700301 } else {
302 rl_src1 = LoadValue(rl_src1, kFPReg);
303 rl_src2 = LoadValue(rl_src2, kFPReg);
304 // In case result vreg is also a srcvreg, break association to avoid useless copy by EvalLoc()
305 ClobberSReg(rl_dest.s_reg_low);
306 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800307 LoadConstant(rl_result.reg, default_result);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000308 NewLIR2(kThumb2Vcmps, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700309 }
buzbee091cc402014-03-31 10:14:40 -0700310 DCHECK(!rl_result.reg.IsFloat());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700311 NewLIR0(kThumb2Fmstat);
312
Dave Allison3da67a52014-04-02 17:03:45 -0700313 LIR* it = OpIT((default_result == -1) ? kCondGt : kCondMi, "");
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000314 NewLIR2(kThumb2MovI8M, rl_result.reg.GetReg(),
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700315 ModifiedImmediate(-default_result)); // Must not alter ccodes
Dave Allison3da67a52014-04-02 17:03:45 -0700316 OpEndIT(it);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700317
Dave Allison3da67a52014-04-02 17:03:45 -0700318 it = OpIT(kCondEq, "");
buzbee2700f7e2014-03-07 09:46:20 -0800319 LoadConstant(rl_result.reg, 0);
Dave Allison3da67a52014-04-02 17:03:45 -0700320 OpEndIT(it);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700321
322 StoreValue(rl_dest, rl_result);
323}
324
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700325void ArmMir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700326 RegLocation rl_result;
327 rl_src = LoadValue(rl_src, kFPReg);
328 rl_result = EvalLoc(rl_dest, kFPReg, true);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000329 NewLIR2(kThumb2Vnegs, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700330 StoreValue(rl_dest, rl_result);
331}
332
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700333void ArmMir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700334 RegLocation rl_result;
335 rl_src = LoadValueWide(rl_src, kFPReg);
336 rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee091cc402014-03-31 10:14:40 -0700337 NewLIR2(kThumb2Vnegd, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700338 StoreValueWide(rl_dest, rl_result);
339}
340
341bool ArmMir2Lir::GenInlinedSqrt(CallInfo* info) {
342 DCHECK_EQ(cu_->instruction_set, kThumb2);
343 LIR *branch;
344 RegLocation rl_src = info->args[0];
345 RegLocation rl_dest = InlineTargetWide(info); // double place for result
346 rl_src = LoadValueWide(rl_src, kFPReg);
347 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee091cc402014-03-31 10:14:40 -0700348 NewLIR2(kThumb2Vsqrtd, rl_result.reg.GetReg(), rl_src.reg.GetReg());
349 NewLIR2(kThumb2Vcmpd, rl_result.reg.GetReg(), rl_result.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700350 NewLIR0(kThumb2Fmstat);
351 branch = NewLIR2(kThumbBCond, 0, kArmCondEq);
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000352 ClobberCallerSave();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700353 LockCallTemps(); // Using fixed registers
Ian Rogersdd7624d2014-03-14 17:43:00 -0700354 RegStorage r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(4, pSqrt));
buzbee091cc402014-03-31 10:14:40 -0700355 NewLIR3(kThumb2Fmrrd, rs_r0.GetReg(), rs_r1.GetReg(), rl_src.reg.GetReg());
buzbee2700f7e2014-03-07 09:46:20 -0800356 NewLIR1(kThumbBlxR, r_tgt.GetReg());
buzbee091cc402014-03-31 10:14:40 -0700357 NewLIR3(kThumb2Fmdrr, rl_result.reg.GetReg(), rs_r0.GetReg(), rs_r1.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700358 branch->target = NewLIR0(kPseudoTargetLabel);
359 StoreValueWide(rl_dest, rl_result);
360 return true;
361}
362
363
364} // namespace art