fp_arm.cc revision 7934ac288acfb2552bb0b06ec1f61e5820d924a4
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(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,
70                                  RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
71  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,
118                               RegLocation rl_dest, RegLocation rl_src) {
119  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,
176                                     bool is_double) {
177  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]);
196  switch (ccode) {
197    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,
228                          RegLocation rl_src1, RegLocation rl_src2) {
229  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
286void ArmMir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
287  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
294void ArmMir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
295  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
329