blob: dd0a429a85196c2b5c4107ebdbadd97330f8f232 [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 Rogers7655f292013-07-29 11:07:13 -070052 CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(pFmodf), rl_src1, rl_src2,
53 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 Rogers7655f292013-07-29 11:07:13 -070095 CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(pFmod), rl_src1, rl_src2,
96 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);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000114 NewLIR3(op, S2d(rl_result.reg.GetReg(), rl_result.reg.GetHighReg()), S2d(rl_src1.reg.GetReg(), rl_src1.reg.GetHighReg()),
115 S2d(rl_src2.reg.GetReg(), 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:
139 op = kThumb2VcvtID;
140 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);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000146 src_reg = S2d(rl_src.reg.GetReg(), rl_src.reg.GetHighReg());
Ian Rogersef6a7762013-12-19 17:58:05 -0800147 rl_result = EvalLoc(rl_dest, kFPReg, true);
148 // TODO: clean up AllocTempDouble so that its result has the double bits set.
149 int tmp1 = AllocTempDouble();
150 int tmp2 = AllocTempDouble();
151
152 NewLIR2(kThumb2VcvtF64S32, tmp1 | ARM_FP_DOUBLE, (src_reg & ~ARM_FP_DOUBLE) + 1);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000153 NewLIR2(kThumb2VcvtF64U32, S2d(rl_result.reg.GetReg(), rl_result.reg.GetHighReg()), (src_reg & ~ARM_FP_DOUBLE));
Ian Rogersef6a7762013-12-19 17:58:05 -0800154 LoadConstantWide(tmp2, tmp2 + 1, 0x41f0000000000000LL);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000155 NewLIR3(kThumb2VmlaF64, S2d(rl_result.reg.GetReg(), rl_result.reg.GetHighReg()), tmp1 | ARM_FP_DOUBLE,
Ian Rogersef6a7762013-12-19 17:58:05 -0800156 tmp2 | ARM_FP_DOUBLE);
157 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 Rogers7655f292013-07-29 11:07:13 -0700163 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pF2l), rl_dest, rl_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700164 return;
165 case Instruction::LONG_TO_FLOAT:
Ian Rogers7655f292013-07-29 11:07:13 -0700166 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pL2f), rl_dest, rl_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700167 return;
168 case Instruction::DOUBLE_TO_LONG:
Ian Rogers7655f292013-07-29 11:07:13 -0700169 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pD2l), rl_dest, rl_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700170 return;
171 default:
172 LOG(FATAL) << "Unexpected opcode: " << opcode;
173 }
174 if (rl_src.wide) {
175 rl_src = LoadValueWide(rl_src, kFPReg);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000176 src_reg = S2d(rl_src.reg.GetReg(), rl_src.reg.GetHighReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700177 } else {
178 rl_src = LoadValue(rl_src, kFPReg);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000179 src_reg = rl_src.reg.GetReg();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700180 }
181 if (rl_dest.wide) {
182 rl_result = EvalLoc(rl_dest, kFPReg, true);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000183 NewLIR2(op, S2d(rl_result.reg.GetReg(), rl_result.reg.GetHighReg()), src_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700184 StoreValueWide(rl_dest, rl_result);
185 } else {
186 rl_result = EvalLoc(rl_dest, kFPReg, true);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000187 NewLIR2(op, rl_result.reg.GetReg(), src_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700188 StoreValue(rl_dest, rl_result);
189 }
190}
191
192void ArmMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700193 bool is_double) {
buzbee0d829482013-10-11 15:24:55 -0700194 LIR* target = &block_label_list_[bb->taken];
Brian Carlstrom7940e442013-07-12 13:46:57 -0700195 RegLocation rl_src1;
196 RegLocation rl_src2;
197 if (is_double) {
198 rl_src1 = mir_graph_->GetSrcWide(mir, 0);
199 rl_src2 = mir_graph_->GetSrcWide(mir, 2);
200 rl_src1 = LoadValueWide(rl_src1, kFPReg);
201 rl_src2 = LoadValueWide(rl_src2, kFPReg);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000202 NewLIR2(kThumb2Vcmpd, S2d(rl_src1.reg.GetReg(), rl_src2.reg.GetHighReg()),
203 S2d(rl_src2.reg.GetReg(), rl_src2.reg.GetHighReg()));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700204 } else {
205 rl_src1 = mir_graph_->GetSrc(mir, 0);
206 rl_src2 = mir_graph_->GetSrc(mir, 1);
207 rl_src1 = LoadValue(rl_src1, kFPReg);
208 rl_src2 = LoadValue(rl_src2, kFPReg);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000209 NewLIR2(kThumb2Vcmps, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700210 }
211 NewLIR0(kThumb2Fmstat);
Vladimir Markoa8946072014-01-22 10:30:44 +0000212 ConditionCode ccode = mir->meta.ccode;
Brian Carlstromdf629502013-07-17 22:39:56 -0700213 switch (ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700214 case kCondEq:
215 case kCondNe:
216 break;
217 case kCondLt:
218 if (gt_bias) {
219 ccode = kCondMi;
220 }
221 break;
222 case kCondLe:
223 if (gt_bias) {
224 ccode = kCondLs;
225 }
226 break;
227 case kCondGt:
228 if (gt_bias) {
229 ccode = kCondHi;
230 }
231 break;
232 case kCondGe:
233 if (gt_bias) {
Vladimir Marko58af1f92013-12-19 13:31:15 +0000234 ccode = kCondUge;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700235 }
236 break;
237 default:
238 LOG(FATAL) << "Unexpected ccode: " << ccode;
239 }
240 OpCondBranch(ccode, target);
241}
242
243
244void ArmMir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700245 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700246 bool is_double = false;
247 int default_result = -1;
248 RegLocation rl_result;
249
250 switch (opcode) {
251 case Instruction::CMPL_FLOAT:
252 is_double = false;
253 default_result = -1;
254 break;
255 case Instruction::CMPG_FLOAT:
256 is_double = false;
257 default_result = 1;
258 break;
259 case Instruction::CMPL_DOUBLE:
260 is_double = true;
261 default_result = -1;
262 break;
263 case Instruction::CMPG_DOUBLE:
264 is_double = true;
265 default_result = 1;
266 break;
267 default:
268 LOG(FATAL) << "Unexpected opcode: " << opcode;
269 }
270 if (is_double) {
271 rl_src1 = LoadValueWide(rl_src1, kFPReg);
272 rl_src2 = LoadValueWide(rl_src2, kFPReg);
273 // In case result vreg is also a src vreg, break association to avoid useless copy by EvalLoc()
274 ClobberSReg(rl_dest.s_reg_low);
275 rl_result = EvalLoc(rl_dest, kCoreReg, true);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000276 LoadConstant(rl_result.reg.GetReg(), default_result);
277 NewLIR2(kThumb2Vcmpd, S2d(rl_src1.reg.GetReg(), rl_src2.reg.GetHighReg()),
278 S2d(rl_src2.reg.GetReg(), rl_src2.reg.GetHighReg()));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700279 } else {
280 rl_src1 = LoadValue(rl_src1, kFPReg);
281 rl_src2 = LoadValue(rl_src2, kFPReg);
282 // In case result vreg is also a srcvreg, break association to avoid useless copy by EvalLoc()
283 ClobberSReg(rl_dest.s_reg_low);
284 rl_result = EvalLoc(rl_dest, kCoreReg, true);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000285 LoadConstant(rl_result.reg.GetReg(), default_result);
286 NewLIR2(kThumb2Vcmps, rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700287 }
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000288 DCHECK(!ARM_FPREG(rl_result.reg.GetReg()));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700289 NewLIR0(kThumb2Fmstat);
290
291 OpIT((default_result == -1) ? kCondGt : kCondMi, "");
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000292 NewLIR2(kThumb2MovI8M, rl_result.reg.GetReg(),
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700293 ModifiedImmediate(-default_result)); // Must not alter ccodes
Brian Carlstrom7940e442013-07-12 13:46:57 -0700294 GenBarrier();
295
296 OpIT(kCondEq, "");
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000297 LoadConstant(rl_result.reg.GetReg(), 0);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700298 GenBarrier();
299
300 StoreValue(rl_dest, rl_result);
301}
302
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700303void ArmMir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700304 RegLocation rl_result;
305 rl_src = LoadValue(rl_src, kFPReg);
306 rl_result = EvalLoc(rl_dest, kFPReg, true);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000307 NewLIR2(kThumb2Vnegs, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700308 StoreValue(rl_dest, rl_result);
309}
310
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700311void ArmMir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700312 RegLocation rl_result;
313 rl_src = LoadValueWide(rl_src, kFPReg);
314 rl_result = EvalLoc(rl_dest, kFPReg, true);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000315 NewLIR2(kThumb2Vnegd, S2d(rl_result.reg.GetReg(), rl_result.reg.GetHighReg()),
316 S2d(rl_src.reg.GetReg(), rl_src.reg.GetHighReg()));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700317 StoreValueWide(rl_dest, rl_result);
318}
319
320bool ArmMir2Lir::GenInlinedSqrt(CallInfo* info) {
321 DCHECK_EQ(cu_->instruction_set, kThumb2);
322 LIR *branch;
323 RegLocation rl_src = info->args[0];
324 RegLocation rl_dest = InlineTargetWide(info); // double place for result
325 rl_src = LoadValueWide(rl_src, kFPReg);
326 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000327 NewLIR2(kThumb2Vsqrtd, S2d(rl_result.reg.GetReg(), rl_result.reg.GetHighReg()),
328 S2d(rl_src.reg.GetReg(), rl_src.reg.GetHighReg()));
329 NewLIR2(kThumb2Vcmpd, S2d(rl_result.reg.GetReg(), rl_result.reg.GetHighReg()),
330 S2d(rl_result.reg.GetReg(), rl_result.reg.GetHighReg()));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700331 NewLIR0(kThumb2Fmstat);
332 branch = NewLIR2(kThumbBCond, 0, kArmCondEq);
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000333 ClobberCallerSave();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700334 LockCallTemps(); // Using fixed registers
Ian Rogers7655f292013-07-29 11:07:13 -0700335 int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pSqrt));
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000336 NewLIR3(kThumb2Fmrrd, r0, r1, S2d(rl_src.reg.GetReg(), rl_src.reg.GetHighReg()));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700337 NewLIR1(kThumbBlxR, r_tgt);
Bill Buzbee00e1ec62014-02-27 23:44:13 +0000338 NewLIR3(kThumb2Fmdrr, S2d(rl_result.reg.GetReg(), rl_result.reg.GetHighReg()), r0, r1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700339 branch->target = NewLIR0(kPseudoTargetLabel);
340 StoreValueWide(rl_dest, rl_result);
341 return true;
342}
343
344
345} // namespace art