fp_x86.cc revision 7655f29fabc0a12765de828914a18314382e5a35
1/*
2 * Copyright (C) 2012 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 "codegen_x86.h"
18#include "dex/quick/mir_to_lir-inl.h"
19#include "x86_lir.h"
20
21namespace art {
22
23void X86Mir2Lir::GenArithOpFloat(Instruction::Code opcode,
24                                 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
25  X86OpCode op = kX86Nop;
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 = kX86AddssRR;
36      break;
37    case Instruction::SUB_FLOAT_2ADDR:
38    case Instruction::SUB_FLOAT:
39      op = kX86SubssRR;
40      break;
41    case Instruction::DIV_FLOAT_2ADDR:
42    case Instruction::DIV_FLOAT:
43      op = kX86DivssRR;
44      break;
45    case Instruction::MUL_FLOAT_2ADDR:
46    case Instruction::MUL_FLOAT:
47      op = kX86MulssRR;
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  int r_dest = rl_result.low_reg;
67  int r_src1 = rl_src1.low_reg;
68  int r_src2 = rl_src2.low_reg;
69  if (r_dest == r_src2) {
70    r_src2 = AllocTempFloat();
71    OpRegCopy(r_src2, r_dest);
72  }
73  OpRegCopy(r_dest, r_src1);
74  NewLIR2(op, r_dest, r_src2);
75  StoreValue(rl_dest, rl_result);
76}
77
78void X86Mir2Lir::GenArithOpDouble(Instruction::Code opcode,
79                                  RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
80  X86OpCode op = kX86Nop;
81  RegLocation rl_result;
82
83  switch (opcode) {
84    case Instruction::ADD_DOUBLE_2ADDR:
85    case Instruction::ADD_DOUBLE:
86      op = kX86AddsdRR;
87      break;
88    case Instruction::SUB_DOUBLE_2ADDR:
89    case Instruction::SUB_DOUBLE:
90      op = kX86SubsdRR;
91      break;
92    case Instruction::DIV_DOUBLE_2ADDR:
93    case Instruction::DIV_DOUBLE:
94      op = kX86DivsdRR;
95      break;
96    case Instruction::MUL_DOUBLE_2ADDR:
97    case Instruction::MUL_DOUBLE:
98      op = kX86MulsdRR;
99      break;
100    case Instruction::REM_DOUBLE_2ADDR:
101    case Instruction::REM_DOUBLE:
102      FlushAllRegs();   // Send everything to home location
103      CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(pFmod), rl_src1, rl_src2,
104                                              false);
105      rl_result = GetReturnWide(true);
106      StoreValueWide(rl_dest, rl_result);
107      return;
108    case Instruction::NEG_DOUBLE:
109      GenNegDouble(rl_dest, rl_src1);
110      return;
111    default:
112      LOG(FATAL) << "Unexpected opcode: " << opcode;
113  }
114  rl_src1 = LoadValueWide(rl_src1, kFPReg);
115  DCHECK(rl_src1.wide);
116  rl_src2 = LoadValueWide(rl_src2, kFPReg);
117  DCHECK(rl_src2.wide);
118  rl_result = EvalLoc(rl_dest, kFPReg, true);
119  DCHECK(rl_dest.wide);
120  DCHECK(rl_result.wide);
121  int r_dest = S2d(rl_result.low_reg, rl_result.high_reg);
122  int r_src1 = S2d(rl_src1.low_reg, rl_src1.high_reg);
123  int r_src2 = S2d(rl_src2.low_reg, rl_src2.high_reg);
124  if (r_dest == r_src2) {
125    r_src2 = AllocTempDouble() | X86_FP_DOUBLE;
126    OpRegCopy(r_src2, r_dest);
127  }
128  OpRegCopy(r_dest, r_src1);
129  NewLIR2(op, r_dest, r_src2);
130  StoreValueWide(rl_dest, rl_result);
131}
132
133void X86Mir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest,
134                               RegLocation rl_src) {
135  RegisterClass rcSrc = kFPReg;
136  X86OpCode op = kX86Nop;
137  int src_reg;
138  RegLocation rl_result;
139  switch (opcode) {
140    case Instruction::INT_TO_FLOAT:
141      rcSrc = kCoreReg;
142      op = kX86Cvtsi2ssRR;
143      break;
144    case Instruction::DOUBLE_TO_FLOAT:
145      rcSrc = kFPReg;
146      op = kX86Cvtsd2ssRR;
147      break;
148    case Instruction::FLOAT_TO_DOUBLE:
149      rcSrc = kFPReg;
150      op = kX86Cvtss2sdRR;
151      break;
152    case Instruction::INT_TO_DOUBLE:
153      rcSrc = kCoreReg;
154      op = kX86Cvtsi2sdRR;
155      break;
156    case Instruction::FLOAT_TO_INT: {
157      rl_src = LoadValue(rl_src, kFPReg);
158      src_reg = rl_src.low_reg;
159      // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
160      ClobberSReg(rl_dest.s_reg_low);
161      rl_result = EvalLoc(rl_dest, kCoreReg, true);
162      int temp_reg = AllocTempFloat();
163
164      LoadConstant(rl_result.low_reg, 0x7fffffff);
165      NewLIR2(kX86Cvtsi2ssRR, temp_reg, rl_result.low_reg);
166      NewLIR2(kX86ComissRR, src_reg, temp_reg);
167      LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondA);
168      LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP);
169      NewLIR2(kX86Cvttss2siRR, rl_result.low_reg, src_reg);
170      LIR* branch_normal = NewLIR1(kX86Jmp8, 0);
171      branch_na_n->target = NewLIR0(kPseudoTargetLabel);
172      NewLIR2(kX86Xor32RR, rl_result.low_reg, rl_result.low_reg);
173      branch_pos_overflow->target = NewLIR0(kPseudoTargetLabel);
174      branch_normal->target = NewLIR0(kPseudoTargetLabel);
175      StoreValue(rl_dest, rl_result);
176      return;
177    }
178    case Instruction::DOUBLE_TO_INT: {
179      rl_src = LoadValueWide(rl_src, kFPReg);
180      src_reg = rl_src.low_reg;
181      // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
182      ClobberSReg(rl_dest.s_reg_low);
183      rl_result = EvalLoc(rl_dest, kCoreReg, true);
184      int temp_reg = AllocTempDouble() | X86_FP_DOUBLE;
185
186      LoadConstant(rl_result.low_reg, 0x7fffffff);
187      NewLIR2(kX86Cvtsi2sdRR, temp_reg, rl_result.low_reg);
188      NewLIR2(kX86ComisdRR, src_reg, temp_reg);
189      LIR* branch_pos_overflow = NewLIR2(kX86Jcc8, 0, kX86CondA);
190      LIR* branch_na_n = NewLIR2(kX86Jcc8, 0, kX86CondP);
191      NewLIR2(kX86Cvttsd2siRR, rl_result.low_reg, src_reg);
192      LIR* branch_normal = NewLIR1(kX86Jmp8, 0);
193      branch_na_n->target = NewLIR0(kPseudoTargetLabel);
194      NewLIR2(kX86Xor32RR, rl_result.low_reg, rl_result.low_reg);
195      branch_pos_overflow->target = NewLIR0(kPseudoTargetLabel);
196      branch_normal->target = NewLIR0(kPseudoTargetLabel);
197      StoreValue(rl_dest, rl_result);
198      return;
199    }
200    case Instruction::LONG_TO_DOUBLE:
201      GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pL2d), rl_dest, rl_src);
202      return;
203    case Instruction::LONG_TO_FLOAT:
204      // TODO: inline by using memory as a 64-bit source. Be careful about promoted registers.
205      GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pL2f), rl_dest, rl_src);
206      return;
207    case Instruction::FLOAT_TO_LONG:
208      GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pF2l), rl_dest, rl_src);
209      return;
210    case Instruction::DOUBLE_TO_LONG:
211      GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pD2l), rl_dest, rl_src);
212      return;
213    default:
214      LOG(INFO) << "Unexpected opcode: " << opcode;
215  }
216  if (rl_src.wide) {
217    rl_src = LoadValueWide(rl_src, rcSrc);
218    src_reg = S2d(rl_src.low_reg, rl_src.high_reg);
219  } else {
220    rl_src = LoadValue(rl_src, rcSrc);
221    src_reg = rl_src.low_reg;
222  }
223  if (rl_dest.wide) {
224    rl_result = EvalLoc(rl_dest, kFPReg, true);
225    NewLIR2(op, S2d(rl_result.low_reg, rl_result.high_reg), src_reg);
226    StoreValueWide(rl_dest, rl_result);
227  } else {
228    rl_result = EvalLoc(rl_dest, kFPReg, true);
229    NewLIR2(op, rl_result.low_reg, src_reg);
230    StoreValue(rl_dest, rl_result);
231  }
232}
233
234void X86Mir2Lir::GenCmpFP(Instruction::Code code, RegLocation rl_dest,
235                          RegLocation rl_src1, RegLocation rl_src2) {
236  bool single = (code == Instruction::CMPL_FLOAT) || (code == Instruction::CMPG_FLOAT);
237  bool unordered_gt = (code == Instruction::CMPG_DOUBLE) || (code == Instruction::CMPG_FLOAT);
238  int src_reg1;
239  int src_reg2;
240  if (single) {
241    rl_src1 = LoadValue(rl_src1, kFPReg);
242    src_reg1 = rl_src1.low_reg;
243    rl_src2 = LoadValue(rl_src2, kFPReg);
244    src_reg2 = rl_src2.low_reg;
245  } else {
246    rl_src1 = LoadValueWide(rl_src1, kFPReg);
247    src_reg1 = S2d(rl_src1.low_reg, rl_src1.high_reg);
248    rl_src2 = LoadValueWide(rl_src2, kFPReg);
249    src_reg2 = S2d(rl_src2.low_reg, rl_src2.high_reg);
250  }
251  // In case result vreg is also src vreg, break association to avoid useless copy by EvalLoc()
252  ClobberSReg(rl_dest.s_reg_low);
253  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
254  LoadConstantNoClobber(rl_result.low_reg, unordered_gt ? 1 : 0);
255  if (single) {
256    NewLIR2(kX86UcomissRR, src_reg1, src_reg2);
257  } else {
258    NewLIR2(kX86UcomisdRR, src_reg1, src_reg2);
259  }
260  LIR* branch = NULL;
261  if (unordered_gt) {
262    branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
263  }
264  // If the result reg can't be byte accessed, use a jump and move instead of a set.
265  if (rl_result.low_reg >= 4) {
266    LIR* branch2 = NULL;
267    if (unordered_gt) {
268      branch2 = NewLIR2(kX86Jcc8, 0, kX86CondA);
269      NewLIR2(kX86Mov32RI, rl_result.low_reg, 0x0);
270    } else {
271      branch2 = NewLIR2(kX86Jcc8, 0, kX86CondBe);
272      NewLIR2(kX86Mov32RI, rl_result.low_reg, 0x1);
273    }
274    branch2->target = NewLIR0(kPseudoTargetLabel);
275  } else {
276    NewLIR2(kX86Set8R, rl_result.low_reg, kX86CondA /* above - unsigned > */);
277  }
278  NewLIR2(kX86Sbb32RI, rl_result.low_reg, 0);
279  if (unordered_gt) {
280    branch->target = NewLIR0(kPseudoTargetLabel);
281  }
282  StoreValue(rl_dest, rl_result);
283}
284
285void X86Mir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias,
286                                     bool is_double) {
287  LIR* taken = &block_label_list_[bb->taken->id];
288  LIR* not_taken = &block_label_list_[bb->fall_through->id];
289  LIR* branch = NULL;
290  RegLocation rl_src1;
291  RegLocation rl_src2;
292  if (is_double) {
293    rl_src1 = mir_graph_->GetSrcWide(mir, 0);
294    rl_src2 = mir_graph_->GetSrcWide(mir, 2);
295    rl_src1 = LoadValueWide(rl_src1, kFPReg);
296    rl_src2 = LoadValueWide(rl_src2, kFPReg);
297    NewLIR2(kX86UcomisdRR, S2d(rl_src1.low_reg, rl_src1.high_reg),
298            S2d(rl_src2.low_reg, rl_src2.high_reg));
299  } else {
300    rl_src1 = mir_graph_->GetSrc(mir, 0);
301    rl_src2 = mir_graph_->GetSrc(mir, 1);
302    rl_src1 = LoadValue(rl_src1, kFPReg);
303    rl_src2 = LoadValue(rl_src2, kFPReg);
304    NewLIR2(kX86UcomissRR, rl_src1.low_reg, rl_src2.low_reg);
305  }
306  ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
307  switch (ccode) {
308    case kCondEq:
309      if (!gt_bias) {
310        branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
311        branch->target = not_taken;
312      }
313      break;
314    case kCondNe:
315      if (!gt_bias) {
316        branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
317        branch->target = taken;
318      }
319      break;
320    case kCondLt:
321      if (gt_bias) {
322        branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
323        branch->target = not_taken;
324      }
325      ccode = kCondCs;
326      break;
327    case kCondLe:
328      if (gt_bias) {
329        branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
330        branch->target = not_taken;
331      }
332      ccode = kCondLs;
333      break;
334    case kCondGt:
335      if (gt_bias) {
336        branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
337        branch->target = taken;
338      }
339      ccode = kCondHi;
340      break;
341    case kCondGe:
342      if (gt_bias) {
343        branch = NewLIR2(kX86Jcc8, 0, kX86CondPE);
344        branch->target = taken;
345      }
346      ccode = kCondCc;
347      break;
348    default:
349      LOG(FATAL) << "Unexpected ccode: " << ccode;
350  }
351  OpCondBranch(ccode, taken);
352}
353
354void X86Mir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
355  RegLocation rl_result;
356  rl_src = LoadValue(rl_src, kCoreReg);
357  rl_result = EvalLoc(rl_dest, kCoreReg, true);
358  OpRegRegImm(kOpAdd, rl_result.low_reg, rl_src.low_reg, 0x80000000);
359  StoreValue(rl_dest, rl_result);
360}
361
362void X86Mir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
363  RegLocation rl_result;
364  rl_src = LoadValueWide(rl_src, kCoreReg);
365  rl_result = EvalLoc(rl_dest, kCoreReg, true);
366  OpRegRegImm(kOpAdd, rl_result.high_reg, rl_src.high_reg, 0x80000000);
367  OpRegCopy(rl_result.low_reg, rl_src.low_reg);
368  StoreValueWide(rl_dest, rl_result);
369}
370
371bool X86Mir2Lir::GenInlinedSqrt(CallInfo* info) {
372  DCHECK_NE(cu_->instruction_set, kThumb2);
373  return false;
374}
375
376
377
378}  // namespace art
379