blob: 08d67781295c5b9e0a44ba0cf75f4a74de740652 [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);
66 NewLIR3(op, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
67 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);
114 NewLIR3(op, S2d(rl_result.low_reg, rl_result.high_reg), S2d(rl_src1.low_reg, rl_src1.high_reg),
115 S2d(rl_src2.low_reg, rl_src2.high_reg));
116 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;
144 case Instruction::LONG_TO_DOUBLE:
Ian Rogers7655f292013-07-29 11:07:13 -0700145 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pL2d), rl_dest, rl_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700146 return;
147 case Instruction::FLOAT_TO_LONG:
Ian Rogers7655f292013-07-29 11:07:13 -0700148 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pF2l), rl_dest, rl_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700149 return;
150 case Instruction::LONG_TO_FLOAT:
Ian Rogers7655f292013-07-29 11:07:13 -0700151 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pL2f), rl_dest, rl_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700152 return;
153 case Instruction::DOUBLE_TO_LONG:
Ian Rogers7655f292013-07-29 11:07:13 -0700154 GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pD2l), rl_dest, rl_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700155 return;
156 default:
157 LOG(FATAL) << "Unexpected opcode: " << opcode;
158 }
159 if (rl_src.wide) {
160 rl_src = LoadValueWide(rl_src, kFPReg);
161 src_reg = S2d(rl_src.low_reg, rl_src.high_reg);
162 } else {
163 rl_src = LoadValue(rl_src, kFPReg);
164 src_reg = rl_src.low_reg;
165 }
166 if (rl_dest.wide) {
167 rl_result = EvalLoc(rl_dest, kFPReg, true);
168 NewLIR2(op, S2d(rl_result.low_reg, rl_result.high_reg), src_reg);
169 StoreValueWide(rl_dest, rl_result);
170 } else {
171 rl_result = EvalLoc(rl_dest, kFPReg, true);
172 NewLIR2(op, rl_result.low_reg, src_reg);
173 StoreValue(rl_dest, rl_result);
174 }
175}
176
177void ArmMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700178 bool is_double) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700179 LIR* target = &block_label_list_[bb->taken->id];
180 RegLocation rl_src1;
181 RegLocation rl_src2;
182 if (is_double) {
183 rl_src1 = mir_graph_->GetSrcWide(mir, 0);
184 rl_src2 = mir_graph_->GetSrcWide(mir, 2);
185 rl_src1 = LoadValueWide(rl_src1, kFPReg);
186 rl_src2 = LoadValueWide(rl_src2, kFPReg);
187 NewLIR2(kThumb2Vcmpd, S2d(rl_src1.low_reg, rl_src2.high_reg),
188 S2d(rl_src2.low_reg, rl_src2.high_reg));
189 } else {
190 rl_src1 = mir_graph_->GetSrc(mir, 0);
191 rl_src2 = mir_graph_->GetSrc(mir, 1);
192 rl_src1 = LoadValue(rl_src1, kFPReg);
193 rl_src2 = LoadValue(rl_src2, kFPReg);
194 NewLIR2(kThumb2Vcmps, rl_src1.low_reg, rl_src2.low_reg);
195 }
196 NewLIR0(kThumb2Fmstat);
197 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
Brian Carlstromdf629502013-07-17 22:39:56 -0700198 switch (ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700199 case kCondEq:
200 case kCondNe:
201 break;
202 case kCondLt:
203 if (gt_bias) {
204 ccode = kCondMi;
205 }
206 break;
207 case kCondLe:
208 if (gt_bias) {
209 ccode = kCondLs;
210 }
211 break;
212 case kCondGt:
213 if (gt_bias) {
214 ccode = kCondHi;
215 }
216 break;
217 case kCondGe:
218 if (gt_bias) {
219 ccode = kCondCs;
220 }
221 break;
222 default:
223 LOG(FATAL) << "Unexpected ccode: " << ccode;
224 }
225 OpCondBranch(ccode, target);
226}
227
228
229void ArmMir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700230 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700231 bool is_double = false;
232 int default_result = -1;
233 RegLocation rl_result;
234
235 switch (opcode) {
236 case Instruction::CMPL_FLOAT:
237 is_double = false;
238 default_result = -1;
239 break;
240 case Instruction::CMPG_FLOAT:
241 is_double = false;
242 default_result = 1;
243 break;
244 case Instruction::CMPL_DOUBLE:
245 is_double = true;
246 default_result = -1;
247 break;
248 case Instruction::CMPG_DOUBLE:
249 is_double = true;
250 default_result = 1;
251 break;
252 default:
253 LOG(FATAL) << "Unexpected opcode: " << opcode;
254 }
255 if (is_double) {
256 rl_src1 = LoadValueWide(rl_src1, kFPReg);
257 rl_src2 = LoadValueWide(rl_src2, kFPReg);
258 // In case result vreg is also a src vreg, break association to avoid useless copy by EvalLoc()
259 ClobberSReg(rl_dest.s_reg_low);
260 rl_result = EvalLoc(rl_dest, kCoreReg, true);
261 LoadConstant(rl_result.low_reg, default_result);
262 NewLIR2(kThumb2Vcmpd, S2d(rl_src1.low_reg, rl_src2.high_reg),
263 S2d(rl_src2.low_reg, rl_src2.high_reg));
264 } else {
265 rl_src1 = LoadValue(rl_src1, kFPReg);
266 rl_src2 = LoadValue(rl_src2, kFPReg);
267 // In case result vreg is also a srcvreg, break association to avoid useless copy by EvalLoc()
268 ClobberSReg(rl_dest.s_reg_low);
269 rl_result = EvalLoc(rl_dest, kCoreReg, true);
270 LoadConstant(rl_result.low_reg, default_result);
271 NewLIR2(kThumb2Vcmps, rl_src1.low_reg, rl_src2.low_reg);
272 }
273 DCHECK(!ARM_FPREG(rl_result.low_reg));
274 NewLIR0(kThumb2Fmstat);
275
276 OpIT((default_result == -1) ? kCondGt : kCondMi, "");
277 NewLIR2(kThumb2MovImmShift, rl_result.low_reg,
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700278 ModifiedImmediate(-default_result)); // Must not alter ccodes
Brian Carlstrom7940e442013-07-12 13:46:57 -0700279 GenBarrier();
280
281 OpIT(kCondEq, "");
282 LoadConstant(rl_result.low_reg, 0);
283 GenBarrier();
284
285 StoreValue(rl_dest, rl_result);
286}
287
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700288void ArmMir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700289 RegLocation rl_result;
290 rl_src = LoadValue(rl_src, kFPReg);
291 rl_result = EvalLoc(rl_dest, kFPReg, true);
292 NewLIR2(kThumb2Vnegs, rl_result.low_reg, rl_src.low_reg);
293 StoreValue(rl_dest, rl_result);
294}
295
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700296void ArmMir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700297 RegLocation rl_result;
298 rl_src = LoadValueWide(rl_src, kFPReg);
299 rl_result = EvalLoc(rl_dest, kFPReg, true);
300 NewLIR2(kThumb2Vnegd, S2d(rl_result.low_reg, rl_result.high_reg),
301 S2d(rl_src.low_reg, rl_src.high_reg));
302 StoreValueWide(rl_dest, rl_result);
303}
304
305bool ArmMir2Lir::GenInlinedSqrt(CallInfo* info) {
306 DCHECK_EQ(cu_->instruction_set, kThumb2);
307 LIR *branch;
308 RegLocation rl_src = info->args[0];
309 RegLocation rl_dest = InlineTargetWide(info); // double place for result
310 rl_src = LoadValueWide(rl_src, kFPReg);
311 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
312 NewLIR2(kThumb2Vsqrtd, S2d(rl_result.low_reg, rl_result.high_reg),
313 S2d(rl_src.low_reg, rl_src.high_reg));
314 NewLIR2(kThumb2Vcmpd, S2d(rl_result.low_reg, rl_result.high_reg),
315 S2d(rl_result.low_reg, rl_result.high_reg));
316 NewLIR0(kThumb2Fmstat);
317 branch = NewLIR2(kThumbBCond, 0, kArmCondEq);
318 ClobberCalleeSave();
319 LockCallTemps(); // Using fixed registers
Ian Rogers7655f292013-07-29 11:07:13 -0700320 int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pSqrt));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700321 NewLIR3(kThumb2Fmrrd, r0, r1, S2d(rl_src.low_reg, rl_src.high_reg));
322 NewLIR1(kThumbBlxR, r_tgt);
323 NewLIR3(kThumb2Fmdrr, S2d(rl_result.low_reg, rl_result.high_reg), r0, r1);
324 branch->target = NewLIR0(kPseudoTargetLabel);
325 StoreValueWide(rl_dest, rl_result);
326 return true;
327}
328
329
330} // namespace art