fp_arm.cc revision 834b394ee759ed31c5371d8093d7cd8cd90014a8
1/*
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  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(QUICK_ENTRYPOINT_OFFSET(pFmodf), rl_src1, rl_src2,
53                                              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  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
95      CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(pFmod), rl_src1, rl_src2,
96                                              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  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:
145      GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pL2d), rl_dest, rl_src);
146      return;
147    case Instruction::FLOAT_TO_LONG:
148      GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pF2l), rl_dest, rl_src);
149      return;
150    case Instruction::LONG_TO_FLOAT:
151      GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pL2f), rl_dest, rl_src);
152      return;
153    case Instruction::DOUBLE_TO_LONG:
154      GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pD2l), rl_dest, rl_src);
155      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,
178                                     bool is_double) {
179  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]);
198  switch (ccode) {
199    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,
230                          RegLocation rl_src1, RegLocation rl_src2) {
231  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,
278          ModifiedImmediate(-default_result));  // Must not alter ccodes
279  GenBarrier();
280
281  OpIT(kCondEq, "");
282  LoadConstant(rl_result.low_reg, 0);
283  GenBarrier();
284
285  StoreValue(rl_dest, rl_result);
286}
287
288void ArmMir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
289  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
296void ArmMir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
297  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
320  int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pSqrt));
321  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
331