blob: 53a5e1a6dc8032d93f104d2c47448e30b69c25e3 [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,
24 RegLocation rl_src1, RegLocation rl_src2)
25{
26 int op = kThumbBkpt;
27 RegLocation rl_result;
28
29 /*
30 * Don't attempt to optimize register usage since these opcodes call out to
31 * the handlers.
32 */
33 switch (opcode) {
34 case Instruction::ADD_FLOAT_2ADDR:
35 case Instruction::ADD_FLOAT:
36 op = kThumb2Vadds;
37 break;
38 case Instruction::SUB_FLOAT_2ADDR:
39 case Instruction::SUB_FLOAT:
40 op = kThumb2Vsubs;
41 break;
42 case Instruction::DIV_FLOAT_2ADDR:
43 case Instruction::DIV_FLOAT:
44 op = kThumb2Vdivs;
45 break;
46 case Instruction::MUL_FLOAT_2ADDR:
47 case Instruction::MUL_FLOAT:
48 op = kThumb2Vmuls;
49 break;
50 case Instruction::REM_FLOAT_2ADDR:
51 case Instruction::REM_FLOAT:
52 FlushAllRegs(); // Send everything to home location
53 CallRuntimeHelperRegLocationRegLocation(ENTRYPOINT_OFFSET(pFmodf), rl_src1, rl_src2, false);
54 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,
71 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2)
72{
73 int op = kThumbBkpt;
74 RegLocation rl_result;
75
76 switch (opcode) {
77 case Instruction::ADD_DOUBLE_2ADDR:
78 case Instruction::ADD_DOUBLE:
79 op = kThumb2Vaddd;
80 break;
81 case Instruction::SUB_DOUBLE_2ADDR:
82 case Instruction::SUB_DOUBLE:
83 op = kThumb2Vsubd;
84 break;
85 case Instruction::DIV_DOUBLE_2ADDR:
86 case Instruction::DIV_DOUBLE:
87 op = kThumb2Vdivd;
88 break;
89 case Instruction::MUL_DOUBLE_2ADDR:
90 case Instruction::MUL_DOUBLE:
91 op = kThumb2Vmuld;
92 break;
93 case Instruction::REM_DOUBLE_2ADDR:
94 case Instruction::REM_DOUBLE:
95 FlushAllRegs(); // Send everything to home location
96 CallRuntimeHelperRegLocationRegLocation(ENTRYPOINT_OFFSET(pFmod), rl_src1, rl_src2, false);
97 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,
120 RegLocation rl_dest, RegLocation rl_src)
121{
122 int op = kThumbBkpt;
123 int src_reg;
124 RegLocation rl_result;
125
126 switch (opcode) {
127 case Instruction::INT_TO_FLOAT:
128 op = kThumb2VcvtIF;
129 break;
130 case Instruction::FLOAT_TO_INT:
131 op = kThumb2VcvtFI;
132 break;
133 case Instruction::DOUBLE_TO_FLOAT:
134 op = kThumb2VcvtDF;
135 break;
136 case Instruction::FLOAT_TO_DOUBLE:
137 op = kThumb2VcvtFd;
138 break;
139 case Instruction::INT_TO_DOUBLE:
140 op = kThumb2VcvtID;
141 break;
142 case Instruction::DOUBLE_TO_INT:
143 op = kThumb2VcvtDI;
144 break;
145 case Instruction::LONG_TO_DOUBLE:
146 GenConversionCall(ENTRYPOINT_OFFSET(pL2d), rl_dest, rl_src);
147 return;
148 case Instruction::FLOAT_TO_LONG:
149 GenConversionCall(ENTRYPOINT_OFFSET(pF2l), rl_dest, rl_src);
150 return;
151 case Instruction::LONG_TO_FLOAT:
152 GenConversionCall(ENTRYPOINT_OFFSET(pL2f), rl_dest, rl_src);
153 return;
154 case Instruction::DOUBLE_TO_LONG:
155 GenConversionCall(ENTRYPOINT_OFFSET(pD2l), rl_dest, rl_src);
156 return;
157 default:
158 LOG(FATAL) << "Unexpected opcode: " << opcode;
159 }
160 if (rl_src.wide) {
161 rl_src = LoadValueWide(rl_src, kFPReg);
162 src_reg = S2d(rl_src.low_reg, rl_src.high_reg);
163 } else {
164 rl_src = LoadValue(rl_src, kFPReg);
165 src_reg = rl_src.low_reg;
166 }
167 if (rl_dest.wide) {
168 rl_result = EvalLoc(rl_dest, kFPReg, true);
169 NewLIR2(op, S2d(rl_result.low_reg, rl_result.high_reg), src_reg);
170 StoreValueWide(rl_dest, rl_result);
171 } else {
172 rl_result = EvalLoc(rl_dest, kFPReg, true);
173 NewLIR2(op, rl_result.low_reg, src_reg);
174 StoreValue(rl_dest, rl_result);
175 }
176}
177
178void ArmMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
179 bool is_double)
180{
181 LIR* target = &block_label_list_[bb->taken->id];
182 RegLocation rl_src1;
183 RegLocation rl_src2;
184 if (is_double) {
185 rl_src1 = mir_graph_->GetSrcWide(mir, 0);
186 rl_src2 = mir_graph_->GetSrcWide(mir, 2);
187 rl_src1 = LoadValueWide(rl_src1, kFPReg);
188 rl_src2 = LoadValueWide(rl_src2, kFPReg);
189 NewLIR2(kThumb2Vcmpd, S2d(rl_src1.low_reg, rl_src2.high_reg),
190 S2d(rl_src2.low_reg, rl_src2.high_reg));
191 } else {
192 rl_src1 = mir_graph_->GetSrc(mir, 0);
193 rl_src2 = mir_graph_->GetSrc(mir, 1);
194 rl_src1 = LoadValue(rl_src1, kFPReg);
195 rl_src2 = LoadValue(rl_src2, kFPReg);
196 NewLIR2(kThumb2Vcmps, rl_src1.low_reg, rl_src2.low_reg);
197 }
198 NewLIR0(kThumb2Fmstat);
199 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
200 switch(ccode) {
201 case kCondEq:
202 case kCondNe:
203 break;
204 case kCondLt:
205 if (gt_bias) {
206 ccode = kCondMi;
207 }
208 break;
209 case kCondLe:
210 if (gt_bias) {
211 ccode = kCondLs;
212 }
213 break;
214 case kCondGt:
215 if (gt_bias) {
216 ccode = kCondHi;
217 }
218 break;
219 case kCondGe:
220 if (gt_bias) {
221 ccode = kCondCs;
222 }
223 break;
224 default:
225 LOG(FATAL) << "Unexpected ccode: " << ccode;
226 }
227 OpCondBranch(ccode, target);
228}
229
230
231void ArmMir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest,
232 RegLocation rl_src1, RegLocation rl_src2)
233{
234 bool is_double = false;
235 int default_result = -1;
236 RegLocation rl_result;
237
238 switch (opcode) {
239 case Instruction::CMPL_FLOAT:
240 is_double = false;
241 default_result = -1;
242 break;
243 case Instruction::CMPG_FLOAT:
244 is_double = false;
245 default_result = 1;
246 break;
247 case Instruction::CMPL_DOUBLE:
248 is_double = true;
249 default_result = -1;
250 break;
251 case Instruction::CMPG_DOUBLE:
252 is_double = true;
253 default_result = 1;
254 break;
255 default:
256 LOG(FATAL) << "Unexpected opcode: " << opcode;
257 }
258 if (is_double) {
259 rl_src1 = LoadValueWide(rl_src1, kFPReg);
260 rl_src2 = LoadValueWide(rl_src2, kFPReg);
261 // In case result vreg is also a src vreg, break association to avoid useless copy by EvalLoc()
262 ClobberSReg(rl_dest.s_reg_low);
263 rl_result = EvalLoc(rl_dest, kCoreReg, true);
264 LoadConstant(rl_result.low_reg, default_result);
265 NewLIR2(kThumb2Vcmpd, S2d(rl_src1.low_reg, rl_src2.high_reg),
266 S2d(rl_src2.low_reg, rl_src2.high_reg));
267 } else {
268 rl_src1 = LoadValue(rl_src1, kFPReg);
269 rl_src2 = LoadValue(rl_src2, kFPReg);
270 // In case result vreg is also a srcvreg, break association to avoid useless copy by EvalLoc()
271 ClobberSReg(rl_dest.s_reg_low);
272 rl_result = EvalLoc(rl_dest, kCoreReg, true);
273 LoadConstant(rl_result.low_reg, default_result);
274 NewLIR2(kThumb2Vcmps, rl_src1.low_reg, rl_src2.low_reg);
275 }
276 DCHECK(!ARM_FPREG(rl_result.low_reg));
277 NewLIR0(kThumb2Fmstat);
278
279 OpIT((default_result == -1) ? kCondGt : kCondMi, "");
280 NewLIR2(kThumb2MovImmShift, rl_result.low_reg,
281 ModifiedImmediate(-default_result)); // Must not alter ccodes
282 GenBarrier();
283
284 OpIT(kCondEq, "");
285 LoadConstant(rl_result.low_reg, 0);
286 GenBarrier();
287
288 StoreValue(rl_dest, rl_result);
289}
290
291void ArmMir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src)
292{
293 RegLocation rl_result;
294 rl_src = LoadValue(rl_src, kFPReg);
295 rl_result = EvalLoc(rl_dest, kFPReg, true);
296 NewLIR2(kThumb2Vnegs, rl_result.low_reg, rl_src.low_reg);
297 StoreValue(rl_dest, rl_result);
298}
299
300void ArmMir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src)
301{
302 RegLocation rl_result;
303 rl_src = LoadValueWide(rl_src, kFPReg);
304 rl_result = EvalLoc(rl_dest, kFPReg, true);
305 NewLIR2(kThumb2Vnegd, S2d(rl_result.low_reg, rl_result.high_reg),
306 S2d(rl_src.low_reg, rl_src.high_reg));
307 StoreValueWide(rl_dest, rl_result);
308}
309
310bool ArmMir2Lir::GenInlinedSqrt(CallInfo* info) {
311 DCHECK_EQ(cu_->instruction_set, kThumb2);
312 LIR *branch;
313 RegLocation rl_src = info->args[0];
314 RegLocation rl_dest = InlineTargetWide(info); // double place for result
315 rl_src = LoadValueWide(rl_src, kFPReg);
316 RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
317 NewLIR2(kThumb2Vsqrtd, S2d(rl_result.low_reg, rl_result.high_reg),
318 S2d(rl_src.low_reg, rl_src.high_reg));
319 NewLIR2(kThumb2Vcmpd, S2d(rl_result.low_reg, rl_result.high_reg),
320 S2d(rl_result.low_reg, rl_result.high_reg));
321 NewLIR0(kThumb2Fmstat);
322 branch = NewLIR2(kThumbBCond, 0, kArmCondEq);
323 ClobberCalleeSave();
324 LockCallTemps(); // Using fixed registers
325 int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pSqrt));
326 NewLIR3(kThumb2Fmrrd, r0, r1, S2d(rl_src.low_reg, rl_src.high_reg));
327 NewLIR1(kThumbBlxR, r_tgt);
328 NewLIR3(kThumb2Fmdrr, S2d(rl_result.low_reg, rl_result.high_reg), r0, r1);
329 branch->target = NewLIR0(kPseudoTargetLabel);
330 StoreValueWide(rl_dest, rl_result);
331 return true;
332}
333
334
335} // namespace art