blob: 8f73f0c2f522ae987a1d3c40efdbc3d587fcdf7e [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
52 CallRuntimeHelperRegLocationRegLocation(ENTRYPOINT_OFFSET(pFmodf), rl_src1, rl_src2, false);
53 rl_result = GetReturn(true);
54 StoreValue(rl_dest, rl_result);
55 return;
56 case Instruction::NEG_FLOAT:
57 GenNegFloat(rl_dest, rl_src1);
58 return;
59 default:
60 LOG(FATAL) << "Unexpected opcode: " << opcode;
61 }
62 rl_src1 = LoadValue(rl_src1, kFPReg);
63 rl_src2 = LoadValue(rl_src2, kFPReg);
64 rl_result = EvalLoc(rl_dest, kFPReg, true);
65 NewLIR3(op, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
66 StoreValue(rl_dest, rl_result);
67}
68
69void ArmMir2Lir::GenArithOpDouble(Instruction::Code opcode,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070070 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070071 int op = kThumbBkpt;
72 RegLocation rl_result;
73
74 switch (opcode) {
75 case Instruction::ADD_DOUBLE_2ADDR:
76 case Instruction::ADD_DOUBLE:
77 op = kThumb2Vaddd;
78 break;
79 case Instruction::SUB_DOUBLE_2ADDR:
80 case Instruction::SUB_DOUBLE:
81 op = kThumb2Vsubd;
82 break;
83 case Instruction::DIV_DOUBLE_2ADDR:
84 case Instruction::DIV_DOUBLE:
85 op = kThumb2Vdivd;
86 break;
87 case Instruction::MUL_DOUBLE_2ADDR:
88 case Instruction::MUL_DOUBLE:
89 op = kThumb2Vmuld;
90 break;
91 case Instruction::REM_DOUBLE_2ADDR:
92 case Instruction::REM_DOUBLE:
93 FlushAllRegs(); // Send everything to home location
94 CallRuntimeHelperRegLocationRegLocation(ENTRYPOINT_OFFSET(pFmod), rl_src1, rl_src2, false);
95 rl_result = GetReturnWide(true);
96 StoreValueWide(rl_dest, rl_result);
97 return;
98 case Instruction::NEG_DOUBLE:
99 GenNegDouble(rl_dest, rl_src1);
100 return;
101 default:
102 LOG(FATAL) << "Unexpected opcode: " << opcode;
103 }
104
105 rl_src1 = LoadValueWide(rl_src1, kFPReg);
106 DCHECK(rl_src1.wide);
107 rl_src2 = LoadValueWide(rl_src2, kFPReg);
108 DCHECK(rl_src2.wide);
109 rl_result = EvalLoc(rl_dest, kFPReg, true);
110 DCHECK(rl_dest.wide);
111 DCHECK(rl_result.wide);
112 NewLIR3(op, S2d(rl_result.low_reg, rl_result.high_reg), S2d(rl_src1.low_reg, rl_src1.high_reg),
113 S2d(rl_src2.low_reg, rl_src2.high_reg));
114 StoreValueWide(rl_dest, rl_result);
115}
116
117void ArmMir2Lir::GenConversion(Instruction::Code opcode,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700118 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:
137 op = kThumb2VcvtID;
138 break;
139 case Instruction::DOUBLE_TO_INT:
140 op = kThumb2VcvtDI;
141 break;
142 case Instruction::LONG_TO_DOUBLE:
143 GenConversionCall(ENTRYPOINT_OFFSET(pL2d), rl_dest, rl_src);
144 return;
145 case Instruction::FLOAT_TO_LONG:
146 GenConversionCall(ENTRYPOINT_OFFSET(pF2l), rl_dest, rl_src);
147 return;
148 case Instruction::LONG_TO_FLOAT:
149 GenConversionCall(ENTRYPOINT_OFFSET(pL2f), rl_dest, rl_src);
150 return;
151 case Instruction::DOUBLE_TO_LONG:
152 GenConversionCall(ENTRYPOINT_OFFSET(pD2l), rl_dest, rl_src);
153 return;
154 default:
155 LOG(FATAL) << "Unexpected opcode: " << opcode;
156 }
157 if (rl_src.wide) {
158 rl_src = LoadValueWide(rl_src, kFPReg);
159 src_reg = S2d(rl_src.low_reg, rl_src.high_reg);
160 } else {
161 rl_src = LoadValue(rl_src, kFPReg);
162 src_reg = rl_src.low_reg;
163 }
164 if (rl_dest.wide) {
165 rl_result = EvalLoc(rl_dest, kFPReg, true);
166 NewLIR2(op, S2d(rl_result.low_reg, rl_result.high_reg), src_reg);
167 StoreValueWide(rl_dest, rl_result);
168 } else {
169 rl_result = EvalLoc(rl_dest, kFPReg, true);
170 NewLIR2(op, rl_result.low_reg, src_reg);
171 StoreValue(rl_dest, rl_result);
172 }
173}
174
175void ArmMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700176 bool is_double) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700177 LIR* target = &block_label_list_[bb->taken->id];
178 RegLocation rl_src1;
179 RegLocation rl_src2;
180 if (is_double) {
181 rl_src1 = mir_graph_->GetSrcWide(mir, 0);
182 rl_src2 = mir_graph_->GetSrcWide(mir, 2);
183 rl_src1 = LoadValueWide(rl_src1, kFPReg);
184 rl_src2 = LoadValueWide(rl_src2, kFPReg);
185 NewLIR2(kThumb2Vcmpd, S2d(rl_src1.low_reg, rl_src2.high_reg),
186 S2d(rl_src2.low_reg, rl_src2.high_reg));
187 } else {
188 rl_src1 = mir_graph_->GetSrc(mir, 0);
189 rl_src2 = mir_graph_->GetSrc(mir, 1);
190 rl_src1 = LoadValue(rl_src1, kFPReg);
191 rl_src2 = LoadValue(rl_src2, kFPReg);
192 NewLIR2(kThumb2Vcmps, rl_src1.low_reg, rl_src2.low_reg);
193 }
194 NewLIR0(kThumb2Fmstat);
195 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
Brian Carlstromdf629502013-07-17 22:39:56 -0700196 switch (ccode) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700197 case kCondEq:
198 case kCondNe:
199 break;
200 case kCondLt:
201 if (gt_bias) {
202 ccode = kCondMi;
203 }
204 break;
205 case kCondLe:
206 if (gt_bias) {
207 ccode = kCondLs;
208 }
209 break;
210 case kCondGt:
211 if (gt_bias) {
212 ccode = kCondHi;
213 }
214 break;
215 case kCondGe:
216 if (gt_bias) {
217 ccode = kCondCs;
218 }
219 break;
220 default:
221 LOG(FATAL) << "Unexpected ccode: " << ccode;
222 }
223 OpCondBranch(ccode, target);
224}
225
226
227void ArmMir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700228 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700229 bool is_double = false;
230 int default_result = -1;
231 RegLocation rl_result;
232
233 switch (opcode) {
234 case Instruction::CMPL_FLOAT:
235 is_double = false;
236 default_result = -1;
237 break;
238 case Instruction::CMPG_FLOAT:
239 is_double = false;
240 default_result = 1;
241 break;
242 case Instruction::CMPL_DOUBLE:
243 is_double = true;
244 default_result = -1;
245 break;
246 case Instruction::CMPG_DOUBLE:
247 is_double = true;
248 default_result = 1;
249 break;
250 default:
251 LOG(FATAL) << "Unexpected opcode: " << opcode;
252 }
253 if (is_double) {
254 rl_src1 = LoadValueWide(rl_src1, kFPReg);
255 rl_src2 = LoadValueWide(rl_src2, kFPReg);
256 // In case result vreg is also a src vreg, break association to avoid useless copy by EvalLoc()
257 ClobberSReg(rl_dest.s_reg_low);
258 rl_result = EvalLoc(rl_dest, kCoreReg, true);
259 LoadConstant(rl_result.low_reg, default_result);
260 NewLIR2(kThumb2Vcmpd, S2d(rl_src1.low_reg, rl_src2.high_reg),
261 S2d(rl_src2.low_reg, rl_src2.high_reg));
262 } else {
263 rl_src1 = LoadValue(rl_src1, kFPReg);
264 rl_src2 = LoadValue(rl_src2, kFPReg);
265 // In case result vreg is also a srcvreg, break association to avoid useless copy by EvalLoc()
266 ClobberSReg(rl_dest.s_reg_low);
267 rl_result = EvalLoc(rl_dest, kCoreReg, true);
268 LoadConstant(rl_result.low_reg, default_result);
269 NewLIR2(kThumb2Vcmps, rl_src1.low_reg, rl_src2.low_reg);
270 }
271 DCHECK(!ARM_FPREG(rl_result.low_reg));
272 NewLIR0(kThumb2Fmstat);
273
274 OpIT((default_result == -1) ? kCondGt : kCondMi, "");
275 NewLIR2(kThumb2MovImmShift, rl_result.low_reg,
276 ModifiedImmediate(-default_result)); // Must not alter ccodes
277 GenBarrier();
278
279 OpIT(kCondEq, "");
280 LoadConstant(rl_result.low_reg, 0);
281 GenBarrier();
282
283 StoreValue(rl_dest, rl_result);
284}
285
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700286void ArmMir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700287 RegLocation rl_result;
288 rl_src = LoadValue(rl_src, kFPReg);
289 rl_result = EvalLoc(rl_dest, kFPReg, true);
290 NewLIR2(kThumb2Vnegs, rl_result.low_reg, rl_src.low_reg);
291 StoreValue(rl_dest, rl_result);
292}
293
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700294void ArmMir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700295 RegLocation rl_result;
296 rl_src = LoadValueWide(rl_src, kFPReg);
297 rl_result = EvalLoc(rl_dest, kFPReg, true);
298 NewLIR2(kThumb2Vnegd, S2d(rl_result.low_reg, rl_result.high_reg),
299 S2d(rl_src.low_reg, rl_src.high_reg));
300 StoreValueWide(rl_dest, rl_result);
301}
302
303bool ArmMir2Lir::GenInlinedSqrt(CallInfo* info) {
304 DCHECK_EQ(cu_->instruction_set, kThumb2);
305 LIR *branch;
306 RegLocation rl_src = info->args[0];
307 RegLocation rl_dest = InlineTargetWide(info); // double place for result
308 rl_src = LoadValueWide(rl_src, kFPReg);
309 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
310 NewLIR2(kThumb2Vsqrtd, S2d(rl_result.low_reg, rl_result.high_reg),
311 S2d(rl_src.low_reg, rl_src.high_reg));
312 NewLIR2(kThumb2Vcmpd, S2d(rl_result.low_reg, rl_result.high_reg),
313 S2d(rl_result.low_reg, rl_result.high_reg));
314 NewLIR0(kThumb2Fmstat);
315 branch = NewLIR2(kThumbBCond, 0, kArmCondEq);
316 ClobberCalleeSave();
317 LockCallTemps(); // Using fixed registers
318 int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pSqrt));
319 NewLIR3(kThumb2Fmrrd, r0, r1, S2d(rl_src.low_reg, rl_src.high_reg));
320 NewLIR1(kThumbBlxR, r_tgt);
321 NewLIR3(kThumb2Fmdrr, S2d(rl_result.low_reg, rl_result.high_reg), r0, r1);
322 branch->target = NewLIR0(kPseudoTargetLabel);
323 StoreValueWide(rl_dest, rl_result);
324 return true;
325}
326
327
328} // namespace art