blob: 07a13ce10daa21ef5b754ffb8bada7fa40885bee [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);
buzbee2700f7e2014-03-07 09:46:20 -0800114 NewLIR3(op, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()), S2d(rl_src1.reg.GetLowReg(), rl_src1.reg.GetHighReg()),
115 S2d(rl_src2.reg.GetLowReg(), rl_src2.reg.GetHighReg()));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700116 StoreValueWide(rl_dest, rl_result);
117}
118
119void ArmMir2Lir::GenConversion(Instruction::Code opcode,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700120 RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700121 int op = kThumbBkpt;
122 int src_reg;
123 RegLocation rl_result;
124
125 switch (opcode) {
126 case Instruction::INT_TO_FLOAT:
127 op = kThumb2VcvtIF;
128 break;
129 case Instruction::FLOAT_TO_INT:
130 op = kThumb2VcvtFI;
131 break;
132 case Instruction::DOUBLE_TO_FLOAT:
133 op = kThumb2VcvtDF;
134 break;
135 case Instruction::FLOAT_TO_DOUBLE:
136 op = kThumb2VcvtFd;
137 break;
138 case Instruction::INT_TO_DOUBLE:
Zheng Xue19649a2014-02-27 13:30:55 +0000139 op = kThumb2VcvtF64S32;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700140 break;
141 case Instruction::DOUBLE_TO_INT:
142 op = kThumb2VcvtDI;
143 break;
Ian Rogersef6a7762013-12-19 17:58:05 -0800144 case Instruction::LONG_TO_DOUBLE: {
145 rl_src = LoadValueWide(rl_src, kFPReg);
buzbee2700f7e2014-03-07 09:46:20 -0800146 src_reg = S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg());
Ian Rogersef6a7762013-12-19 17:58:05 -0800147 rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800148 // TODO: fix AllocTempDouble to return a k64BitSolo double reg and lose the ARM_FP_DOUBLE.
149 RegStorage tmp1 = AllocTempDouble();
150 RegStorage tmp2 = AllocTempDouble();
Ian Rogersef6a7762013-12-19 17:58:05 -0800151
buzbee2700f7e2014-03-07 09:46:20 -0800152 // FIXME: needs 64-bit register cleanup.
153 NewLIR2(kThumb2VcvtF64S32, tmp1.GetLowReg() | ARM_FP_DOUBLE, (src_reg & ~ARM_FP_DOUBLE) + 1);
154 NewLIR2(kThumb2VcvtF64U32, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()),
155 (src_reg & ~ARM_FP_DOUBLE));
156 LoadConstantWide(tmp2, 0x41f0000000000000LL);
157 NewLIR3(kThumb2VmlaF64, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()),
158 tmp1.GetLowReg() | ARM_FP_DOUBLE, tmp2.GetLowReg() | ARM_FP_DOUBLE);
Ian Rogersef6a7762013-12-19 17:58:05 -0800159 FreeTemp(tmp1);
160 FreeTemp(tmp2);
161 StoreValueWide(rl_dest, rl_result);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700162 return;
Ian Rogersef6a7762013-12-19 17:58:05 -0800163 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700164 case Instruction::FLOAT_TO_LONG:
Ian Rogersdd7624d2014-03-14 17:43:00 -0700165 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(4, pF2l), rl_dest, rl_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700166 return;
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000167 case Instruction::LONG_TO_FLOAT: {
168 rl_src = LoadValueWide(rl_src, kFPReg);
buzbee2700f7e2014-03-07 09:46:20 -0800169 src_reg = S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg());
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000170 rl_result = EvalLoc(rl_dest, kFPReg, true);
171 // Allocate temp registers.
buzbee2700f7e2014-03-07 09:46:20 -0800172 RegStorage high_val = AllocTempDouble();
173 RegStorage low_val = AllocTempDouble();
174 RegStorage const_val = AllocTempDouble();
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000175 // Long to double.
buzbee2700f7e2014-03-07 09:46:20 -0800176 NewLIR2(kThumb2VcvtF64S32, high_val.GetLowReg() | ARM_FP_DOUBLE,
177 (src_reg & ~ARM_FP_DOUBLE) + 1);
178 NewLIR2(kThumb2VcvtF64U32, low_val.GetLowReg() | ARM_FP_DOUBLE,
179 (src_reg & ~ARM_FP_DOUBLE));
180 LoadConstantWide(const_val, INT64_C(0x41f0000000000000));
181 NewLIR3(kThumb2VmlaF64, low_val.GetLowReg() | ARM_FP_DOUBLE,
182 high_val.GetLowReg() | ARM_FP_DOUBLE,
183 const_val.GetLowReg() | ARM_FP_DOUBLE);
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000184 // Double to float.
buzbee2700f7e2014-03-07 09:46:20 -0800185 NewLIR2(kThumb2VcvtDF, rl_result.reg.GetReg(), low_val.GetLowReg() | ARM_FP_DOUBLE);
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000186 // Free temp registers.
187 FreeTemp(high_val);
188 FreeTemp(low_val);
189 FreeTemp(const_val);
190 // Store result.
191 StoreValue(rl_dest, rl_result);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700192 return;
Zheng Xuf0e6c9c2014-03-10 10:43:02 +0000193 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700194 case Instruction::DOUBLE_TO_LONG:
Ian Rogersdd7624d2014-03-14 17:43:00 -0700195 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(4, pD2l), rl_dest, rl_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700196 return;
197 default:
198 LOG(FATAL) << "Unexpected opcode: " << opcode;
199 }
200 if (rl_src.wide) {
201 rl_src = LoadValueWide(rl_src, kFPReg);
buzbee2700f7e2014-03-07 09:46:20 -0800202 src_reg = S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700203 } else {
204 rl_src = LoadValue(rl_src, kFPReg);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000205 src_reg = rl_src.reg.GetReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700206 }
207 if (rl_dest.wide) {
208 rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800209 NewLIR2(op, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()), src_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700210 StoreValueWide(rl_dest, rl_result);
211 } else {
212 rl_result = EvalLoc(rl_dest, kFPReg, true);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000213 NewLIR2(op, rl_result.reg.GetReg(), src_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700214 StoreValue(rl_dest, rl_result);
215 }
216}
217
218void ArmMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700219 bool is_double) {
buzbee0d829482013-10-11 15:24:55 -0700220 LIR* target = &block_label_list_[bb->taken];
Brian Carlstrom7940e442013-07-12 13:46:57 -0700221 RegLocation rl_src1;
222 RegLocation rl_src2;
223 if (is_double) {
224 rl_src1 = mir_graph_->GetSrcWide(mir, 0);
225 rl_src2 = mir_graph_->GetSrcWide(mir, 2);
226 rl_src1 = LoadValueWide(rl_src1, kFPReg);
227 rl_src2 = LoadValueWide(rl_src2, kFPReg);
buzbee2700f7e2014-03-07 09:46:20 -0800228 NewLIR2(kThumb2Vcmpd, S2d(rl_src1.reg.GetLowReg(), rl_src2.reg.GetHighReg()),
229 S2d(rl_src2.reg.GetLowReg(), rl_src2.reg.GetHighReg()));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700230 } else {
231 rl_src1 = mir_graph_->GetSrc(mir, 0);
232 rl_src2 = mir_graph_->GetSrc(mir, 1);
233 rl_src1 = LoadValue(rl_src1, kFPReg);
234 rl_src2 = LoadValue(rl_src2, kFPReg);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000235 NewLIR2(kThumb2Vcmps, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700236 }
237 NewLIR0(kThumb2Fmstat);
Vladimir Markoa8946072014-01-22 10:30:44 +0000238 ConditionCode ccode = mir->meta.ccode;
Brian Carlstromdf629502013-07-17 22:39:56 -0700239 switch (ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700240 case kCondEq:
241 case kCondNe:
242 break;
243 case kCondLt:
244 if (gt_bias) {
245 ccode = kCondMi;
246 }
247 break;
248 case kCondLe:
249 if (gt_bias) {
250 ccode = kCondLs;
251 }
252 break;
253 case kCondGt:
254 if (gt_bias) {
255 ccode = kCondHi;
256 }
257 break;
258 case kCondGe:
259 if (gt_bias) {
Vladimir Marko58af1f92013-12-19 13:31:15 +0000260 ccode = kCondUge;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700261 }
262 break;
263 default:
264 LOG(FATAL) << "Unexpected ccode: " << ccode;
265 }
266 OpCondBranch(ccode, target);
267}
268
269
270void ArmMir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700271 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700272 bool is_double = false;
273 int default_result = -1;
274 RegLocation rl_result;
275
276 switch (opcode) {
277 case Instruction::CMPL_FLOAT:
278 is_double = false;
279 default_result = -1;
280 break;
281 case Instruction::CMPG_FLOAT:
282 is_double = false;
283 default_result = 1;
284 break;
285 case Instruction::CMPL_DOUBLE:
286 is_double = true;
287 default_result = -1;
288 break;
289 case Instruction::CMPG_DOUBLE:
290 is_double = true;
291 default_result = 1;
292 break;
293 default:
294 LOG(FATAL) << "Unexpected opcode: " << opcode;
295 }
296 if (is_double) {
297 rl_src1 = LoadValueWide(rl_src1, kFPReg);
298 rl_src2 = LoadValueWide(rl_src2, kFPReg);
299 // In case result vreg is also a src vreg, break association to avoid useless copy by EvalLoc()
300 ClobberSReg(rl_dest.s_reg_low);
301 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800302 LoadConstant(rl_result.reg, default_result);
303 NewLIR2(kThumb2Vcmpd, S2d(rl_src1.reg.GetLowReg(), rl_src2.reg.GetHighReg()),
304 S2d(rl_src2.reg.GetLowReg(), rl_src2.reg.GetHighReg()));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700305 } else {
306 rl_src1 = LoadValue(rl_src1, kFPReg);
307 rl_src2 = LoadValue(rl_src2, kFPReg);
308 // In case result vreg is also a srcvreg, break association to avoid useless copy by EvalLoc()
309 ClobberSReg(rl_dest.s_reg_low);
310 rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800311 LoadConstant(rl_result.reg, default_result);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000312 NewLIR2(kThumb2Vcmps, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700313 }
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000314 DCHECK(!ARM_FPREG(rl_result.reg.GetReg()));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700315 NewLIR0(kThumb2Fmstat);
316
317 OpIT((default_result == -1) ? kCondGt : kCondMi, "");
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000318 NewLIR2(kThumb2MovI8M, rl_result.reg.GetReg(),
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700319 ModifiedImmediate(-default_result)); // Must not alter ccodes
Brian Carlstrom7940e442013-07-12 13:46:57 -0700320 GenBarrier();
321
322 OpIT(kCondEq, "");
buzbee2700f7e2014-03-07 09:46:20 -0800323 LoadConstant(rl_result.reg, 0);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700324 GenBarrier();
325
326 StoreValue(rl_dest, rl_result);
327}
328
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700329void ArmMir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700330 RegLocation rl_result;
331 rl_src = LoadValue(rl_src, kFPReg);
332 rl_result = EvalLoc(rl_dest, kFPReg, true);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000333 NewLIR2(kThumb2Vnegs, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700334 StoreValue(rl_dest, rl_result);
335}
336
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700337void ArmMir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700338 RegLocation rl_result;
339 rl_src = LoadValueWide(rl_src, kFPReg);
340 rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800341 NewLIR2(kThumb2Vnegd, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()),
342 S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg()));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700343 StoreValueWide(rl_dest, rl_result);
344}
345
346bool ArmMir2Lir::GenInlinedSqrt(CallInfo* info) {
347 DCHECK_EQ(cu_->instruction_set, kThumb2);
348 LIR *branch;
349 RegLocation rl_src = info->args[0];
350 RegLocation rl_dest = InlineTargetWide(info); // double place for result
351 rl_src = LoadValueWide(rl_src, kFPReg);
352 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
buzbee2700f7e2014-03-07 09:46:20 -0800353 // TODO: shouldn't need S2d once 64bitSolo has proper double tag bit.
354 NewLIR2(kThumb2Vsqrtd, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()),
355 S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg()));
356 NewLIR2(kThumb2Vcmpd, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()),
357 S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700358 NewLIR0(kThumb2Fmstat);
359 branch = NewLIR2(kThumbBCond, 0, kArmCondEq);
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000360 ClobberCallerSave();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700361 LockCallTemps(); // Using fixed registers
Ian Rogersdd7624d2014-03-14 17:43:00 -0700362 RegStorage r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(4, pSqrt));
buzbee2700f7e2014-03-07 09:46:20 -0800363 NewLIR3(kThumb2Fmrrd, r0, r1, S2d(rl_src.reg.GetLowReg(), rl_src.reg.GetHighReg()));
364 NewLIR1(kThumbBlxR, r_tgt.GetReg());
365 NewLIR3(kThumb2Fmdrr, S2d(rl_result.reg.GetLowReg(), rl_result.reg.GetHighReg()), r0, r1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700366 branch->target = NewLIR0(kPseudoTargetLabel);
367 StoreValueWide(rl_dest, rl_result);
368 return true;
369}
370
371
372} // namespace art