fp_mips.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_mips.h"
18#include "dex/quick/mir_to_lir-inl.h"
19#include "entrypoints/quick/quick_entrypoints.h"
20#include "mips_lir.h"
21
22namespace art {
23
24void MipsMir2Lir::GenArithOpFloat(Instruction::Code opcode,
25                                  RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
26  int op = kMipsNop;
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 = kMipsFadds;
37      break;
38    case Instruction::SUB_FLOAT_2ADDR:
39    case Instruction::SUB_FLOAT:
40      op = kMipsFsubs;
41      break;
42    case Instruction::DIV_FLOAT_2ADDR:
43    case Instruction::DIV_FLOAT:
44      op = kMipsFdivs;
45      break;
46    case Instruction::MUL_FLOAT_2ADDR:
47    case Instruction::MUL_FLOAT:
48      op = kMipsFmuls;
49      break;
50    case Instruction::REM_FLOAT_2ADDR:
51    case Instruction::REM_FLOAT:
52      FlushAllRegs();   // Send everything to home location
53      CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(pFmodf), rl_src1, rl_src2,
54                                              false);
55      rl_result = GetReturn(true);
56      StoreValue(rl_dest, rl_result);
57      return;
58    case Instruction::NEG_FLOAT:
59      GenNegFloat(rl_dest, rl_src1);
60      return;
61    default:
62      LOG(FATAL) << "Unexpected opcode: " << opcode;
63  }
64  rl_src1 = LoadValue(rl_src1, kFPReg);
65  rl_src2 = LoadValue(rl_src2, kFPReg);
66  rl_result = EvalLoc(rl_dest, kFPReg, true);
67  NewLIR3(op, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
68  StoreValue(rl_dest, rl_result);
69}
70
71void MipsMir2Lir::GenArithOpDouble(Instruction::Code opcode,
72                                   RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
73  int op = kMipsNop;
74  RegLocation rl_result;
75
76  switch (opcode) {
77    case Instruction::ADD_DOUBLE_2ADDR:
78    case Instruction::ADD_DOUBLE:
79      op = kMipsFaddd;
80      break;
81    case Instruction::SUB_DOUBLE_2ADDR:
82    case Instruction::SUB_DOUBLE:
83      op = kMipsFsubd;
84      break;
85    case Instruction::DIV_DOUBLE_2ADDR:
86    case Instruction::DIV_DOUBLE:
87      op = kMipsFdivd;
88      break;
89    case Instruction::MUL_DOUBLE_2ADDR:
90    case Instruction::MUL_DOUBLE:
91      op = kMipsFmuld;
92      break;
93    case Instruction::REM_DOUBLE_2ADDR:
94    case Instruction::REM_DOUBLE:
95      FlushAllRegs();   // Send everything to home location
96      CallRuntimeHelperRegLocationRegLocation(QUICK_ENTRYPOINT_OFFSET(pFmod), rl_src1, rl_src2,
97                                              false);
98      rl_result = GetReturnWide(true);
99      StoreValueWide(rl_dest, rl_result);
100      return;
101    case Instruction::NEG_DOUBLE:
102      GenNegDouble(rl_dest, rl_src1);
103      return;
104    default:
105      LOG(FATAL) << "Unpexpected opcode: " << opcode;
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 MipsMir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest,
120                                RegLocation rl_src) {
121  int op = kMipsNop;
122  int src_reg;
123  RegLocation rl_result;
124  switch (opcode) {
125    case Instruction::INT_TO_FLOAT:
126      op = kMipsFcvtsw;
127      break;
128    case Instruction::DOUBLE_TO_FLOAT:
129      op = kMipsFcvtsd;
130      break;
131    case Instruction::FLOAT_TO_DOUBLE:
132      op = kMipsFcvtds;
133      break;
134    case Instruction::INT_TO_DOUBLE:
135      op = kMipsFcvtdw;
136      break;
137    case Instruction::FLOAT_TO_INT:
138      GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pF2iz), rl_dest, rl_src);
139      return;
140    case Instruction::DOUBLE_TO_INT:
141      GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pD2iz), rl_dest, rl_src);
142      return;
143    case Instruction::LONG_TO_DOUBLE:
144      GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pL2d), rl_dest, rl_src);
145      return;
146    case Instruction::FLOAT_TO_LONG:
147      GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pF2l), rl_dest, rl_src);
148      return;
149    case Instruction::LONG_TO_FLOAT:
150      GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pL2f), rl_dest, rl_src);
151      return;
152    case Instruction::DOUBLE_TO_LONG:
153      GenConversionCall(QUICK_ENTRYPOINT_OFFSET(pD2l), rl_dest, rl_src);
154      return;
155    default:
156      LOG(FATAL) << "Unexpected opcode: " << opcode;
157  }
158  if (rl_src.wide) {
159    rl_src = LoadValueWide(rl_src, kFPReg);
160    src_reg = S2d(rl_src.low_reg, rl_src.high_reg);
161  } else {
162    rl_src = LoadValue(rl_src, kFPReg);
163    src_reg = rl_src.low_reg;
164  }
165  if (rl_dest.wide) {
166    rl_result = EvalLoc(rl_dest, kFPReg, true);
167    NewLIR2(op, S2d(rl_result.low_reg, rl_result.high_reg), src_reg);
168    StoreValueWide(rl_dest, rl_result);
169  } else {
170    rl_result = EvalLoc(rl_dest, kFPReg, true);
171    NewLIR2(op, rl_result.low_reg, src_reg);
172    StoreValue(rl_dest, rl_result);
173  }
174}
175
176void MipsMir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest,
177                           RegLocation rl_src1, RegLocation rl_src2) {
178  bool wide = true;
179  int offset = -1;  // Make gcc happy.
180
181  switch (opcode) {
182    case Instruction::CMPL_FLOAT:
183      offset = QUICK_ENTRYPOINT_OFFSET(pCmplFloat);
184      wide = false;
185      break;
186    case Instruction::CMPG_FLOAT:
187      offset = QUICK_ENTRYPOINT_OFFSET(pCmpgFloat);
188      wide = false;
189      break;
190    case Instruction::CMPL_DOUBLE:
191      offset = QUICK_ENTRYPOINT_OFFSET(pCmplDouble);
192      break;
193    case Instruction::CMPG_DOUBLE:
194      offset = QUICK_ENTRYPOINT_OFFSET(pCmpgDouble);
195      break;
196    default:
197      LOG(FATAL) << "Unexpected opcode: " << opcode;
198  }
199  FlushAllRegs();
200  LockCallTemps();
201  if (wide) {
202    LoadValueDirectWideFixed(rl_src1, rMIPS_FARG0, rMIPS_FARG1);
203    LoadValueDirectWideFixed(rl_src2, rMIPS_FARG2, rMIPS_FARG3);
204  } else {
205    LoadValueDirectFixed(rl_src1, rMIPS_FARG0);
206    LoadValueDirectFixed(rl_src2, rMIPS_FARG2);
207  }
208  int r_tgt = LoadHelper(offset);
209  // NOTE: not a safepoint
210  OpReg(kOpBlx, r_tgt);
211  RegLocation rl_result = GetReturn(false);
212  StoreValue(rl_dest, rl_result);
213}
214
215void MipsMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir,
216                                bool gt_bias, bool is_double) {
217  UNIMPLEMENTED(FATAL) << "Need codegen for fused fp cmp branch";
218}
219
220void MipsMir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
221  RegLocation rl_result;
222  rl_src = LoadValue(rl_src, kCoreReg);
223  rl_result = EvalLoc(rl_dest, kCoreReg, true);
224  OpRegRegImm(kOpAdd, rl_result.low_reg, rl_src.low_reg, 0x80000000);
225  StoreValue(rl_dest, rl_result);
226}
227
228void MipsMir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
229  RegLocation rl_result;
230  rl_src = LoadValueWide(rl_src, kCoreReg);
231  rl_result = EvalLoc(rl_dest, kCoreReg, true);
232  OpRegRegImm(kOpAdd, rl_result.high_reg, rl_src.high_reg, 0x80000000);
233  OpRegCopy(rl_result.low_reg, rl_src.low_reg);
234  StoreValueWide(rl_dest, rl_result);
235}
236
237bool MipsMir2Lir::GenInlinedMinMaxInt(CallInfo* info, bool is_min) {
238  // TODO: need Mips implementation
239  return false;
240}
241
242}  // namespace art
243