fp_mips.cc revision a0cd2d701f29e0bc6275f1b13c0edfd4ec391879
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(4, pFmodf), rl_src1, rl_src2,
54                                              false);
55      rl_result = GetReturn(kFPReg);
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.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
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(4, pFmod), rl_src1, rl_src2,
97                                              false);
98      rl_result = GetReturnWide(kFPReg);
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, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
115  StoreValueWide(rl_dest, rl_result);
116}
117
118void MipsMir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest,
119                                RegLocation rl_src) {
120  int op = kMipsNop;
121  RegLocation rl_result;
122  switch (opcode) {
123    case Instruction::INT_TO_FLOAT:
124      op = kMipsFcvtsw;
125      break;
126    case Instruction::DOUBLE_TO_FLOAT:
127      op = kMipsFcvtsd;
128      break;
129    case Instruction::FLOAT_TO_DOUBLE:
130      op = kMipsFcvtds;
131      break;
132    case Instruction::INT_TO_DOUBLE:
133      op = kMipsFcvtdw;
134      break;
135    case Instruction::FLOAT_TO_INT:
136      GenConversionCall(QUICK_ENTRYPOINT_OFFSET(4, pF2iz), rl_dest, rl_src);
137      return;
138    case Instruction::DOUBLE_TO_INT:
139      GenConversionCall(QUICK_ENTRYPOINT_OFFSET(4, pD2iz), rl_dest, rl_src);
140      return;
141    case Instruction::LONG_TO_DOUBLE:
142      GenConversionCall(QUICK_ENTRYPOINT_OFFSET(4, pL2d), rl_dest, rl_src);
143      return;
144    case Instruction::FLOAT_TO_LONG:
145      GenConversionCall(QUICK_ENTRYPOINT_OFFSET(4, pF2l), rl_dest, rl_src);
146      return;
147    case Instruction::LONG_TO_FLOAT:
148      GenConversionCall(QUICK_ENTRYPOINT_OFFSET(4, pL2f), rl_dest, rl_src);
149      return;
150    case Instruction::DOUBLE_TO_LONG:
151      GenConversionCall(QUICK_ENTRYPOINT_OFFSET(4, pD2l), rl_dest, rl_src);
152      return;
153    default:
154      LOG(FATAL) << "Unexpected opcode: " << opcode;
155  }
156  if (rl_src.wide) {
157    rl_src = LoadValueWide(rl_src, kFPReg);
158  } else {
159    rl_src = LoadValue(rl_src, kFPReg);
160  }
161  rl_result = EvalLoc(rl_dest, kFPReg, true);
162  NewLIR2(op, rl_result.reg.GetReg(), rl_src.reg.GetReg());
163  if (rl_dest.wide) {
164    StoreValueWide(rl_dest, rl_result);
165  } else {
166    StoreValue(rl_dest, rl_result);
167  }
168}
169
170void MipsMir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest,
171                           RegLocation rl_src1, RegLocation rl_src2) {
172  bool wide = true;
173  ThreadOffset<4> offset(-1);
174
175  switch (opcode) {
176    case Instruction::CMPL_FLOAT:
177      offset = QUICK_ENTRYPOINT_OFFSET(4, pCmplFloat);
178      wide = false;
179      break;
180    case Instruction::CMPG_FLOAT:
181      offset = QUICK_ENTRYPOINT_OFFSET(4, pCmpgFloat);
182      wide = false;
183      break;
184    case Instruction::CMPL_DOUBLE:
185      offset = QUICK_ENTRYPOINT_OFFSET(4, pCmplDouble);
186      break;
187    case Instruction::CMPG_DOUBLE:
188      offset = QUICK_ENTRYPOINT_OFFSET(4, pCmpgDouble);
189      break;
190    default:
191      LOG(FATAL) << "Unexpected opcode: " << opcode;
192  }
193  FlushAllRegs();
194  LockCallTemps();
195  if (wide) {
196    RegStorage r_tmp1(RegStorage::k64BitPair, rMIPS_FARG0, rMIPS_FARG1);
197    RegStorage r_tmp2(RegStorage::k64BitPair, rMIPS_FARG2, rMIPS_FARG3);
198    LoadValueDirectWideFixed(rl_src1, r_tmp1);
199    LoadValueDirectWideFixed(rl_src2, r_tmp2);
200  } else {
201    LoadValueDirectFixed(rl_src1, rs_rMIPS_FARG0);
202    LoadValueDirectFixed(rl_src2, rs_rMIPS_FARG2);
203  }
204  RegStorage r_tgt = LoadHelper(offset);
205  // NOTE: not a safepoint
206  OpReg(kOpBlx, r_tgt);
207  RegLocation rl_result = GetReturn(kCoreReg);
208  StoreValue(rl_dest, rl_result);
209}
210
211void MipsMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir,
212                                bool gt_bias, bool is_double) {
213  UNIMPLEMENTED(FATAL) << "Need codegen for fused fp cmp branch";
214}
215
216void MipsMir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
217  RegLocation rl_result;
218  rl_src = LoadValue(rl_src, kCoreReg);
219  rl_result = EvalLoc(rl_dest, kCoreReg, true);
220  OpRegRegImm(kOpAdd, rl_result.reg, rl_src.reg, 0x80000000);
221  StoreValue(rl_dest, rl_result);
222}
223
224void MipsMir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
225  RegLocation rl_result;
226  rl_src = LoadValueWide(rl_src, kCoreReg);
227  rl_result = EvalLoc(rl_dest, kCoreReg, true);
228  OpRegRegImm(kOpAdd, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), 0x80000000);
229  OpRegCopy(rl_result.reg, rl_src.reg);
230  StoreValueWide(rl_dest, rl_result);
231}
232
233bool MipsMir2Lir::GenInlinedMinMaxInt(CallInfo* info, bool is_min) {
234  // TODO: need Mips implementation
235  return false;
236}
237
238}  // namespace art
239