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 
19 #include "base/logging.h"
20 #include "dex/quick/mir_to_lir-inl.h"
21 #include "entrypoints/quick/quick_entrypoints.h"
22 #include "mips_lir.h"
23 
24 namespace art {
25 
GenArithOpFloat(Instruction::Code opcode,RegLocation rl_dest,RegLocation rl_src1,RegLocation rl_src2)26 void MipsMir2Lir::GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
27                                   RegLocation rl_src1, RegLocation rl_src2) {
28   int op = kMipsNop;
29   RegLocation rl_result;
30 
31   /*
32    * Don't attempt to optimize register usage since these opcodes call out to
33    * the handlers.
34    */
35   switch (opcode) {
36     case Instruction::ADD_FLOAT_2ADDR:
37     case Instruction::ADD_FLOAT:
38       op = kMipsFadds;
39       break;
40     case Instruction::SUB_FLOAT_2ADDR:
41     case Instruction::SUB_FLOAT:
42       op = kMipsFsubs;
43       break;
44     case Instruction::DIV_FLOAT_2ADDR:
45     case Instruction::DIV_FLOAT:
46       op = kMipsFdivs;
47       break;
48     case Instruction::MUL_FLOAT_2ADDR:
49     case Instruction::MUL_FLOAT:
50       op = kMipsFmuls;
51       break;
52     case Instruction::REM_FLOAT_2ADDR:
53     case Instruction::REM_FLOAT:
54       FlushAllRegs();   // Send everything to home location.
55       CallRuntimeHelperRegLocationRegLocation(kQuickFmodf, rl_src1, rl_src2, false);
56       rl_result = GetReturn(kFPReg);
57       StoreValue(rl_dest, rl_result);
58       return;
59     case Instruction::NEG_FLOAT:
60       GenNegFloat(rl_dest, rl_src1);
61       return;
62     default:
63       LOG(FATAL) << "Unexpected opcode: " << opcode;
64   }
65   rl_src1 = LoadValue(rl_src1, kFPReg);
66   rl_src2 = LoadValue(rl_src2, kFPReg);
67   rl_result = EvalLoc(rl_dest, kFPReg, true);
68   NewLIR3(op, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
69   StoreValue(rl_dest, rl_result);
70 }
71 
GenArithOpDouble(Instruction::Code opcode,RegLocation rl_dest,RegLocation rl_src1,RegLocation rl_src2)72 void MipsMir2Lir::GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
73                                    RegLocation rl_src1, RegLocation rl_src2) {
74   int op = kMipsNop;
75   RegLocation rl_result;
76 
77   switch (opcode) {
78     case Instruction::ADD_DOUBLE_2ADDR:
79     case Instruction::ADD_DOUBLE:
80       op = kMipsFaddd;
81       break;
82     case Instruction::SUB_DOUBLE_2ADDR:
83     case Instruction::SUB_DOUBLE:
84       op = kMipsFsubd;
85       break;
86     case Instruction::DIV_DOUBLE_2ADDR:
87     case Instruction::DIV_DOUBLE:
88       op = kMipsFdivd;
89       break;
90     case Instruction::MUL_DOUBLE_2ADDR:
91     case Instruction::MUL_DOUBLE:
92       op = kMipsFmuld;
93       break;
94     case Instruction::REM_DOUBLE_2ADDR:
95     case Instruction::REM_DOUBLE:
96       FlushAllRegs();   // Send everything to home location.
97       CallRuntimeHelperRegLocationRegLocation(kQuickFmod, rl_src1, rl_src2, 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 
GenMultiplyByConstantFloat(RegLocation rl_dest,RegLocation rl_src1,int32_t constant)118 void MipsMir2Lir::GenMultiplyByConstantFloat(RegLocation rl_dest, RegLocation rl_src1,
119                                              int32_t constant) {
120   // TODO: need mips implementation.
121   UNUSED(rl_dest, rl_src1, constant);
122   LOG(FATAL) << "Unimplemented GenMultiplyByConstantFloat in mips";
123 }
124 
GenMultiplyByConstantDouble(RegLocation rl_dest,RegLocation rl_src1,int64_t constant)125 void MipsMir2Lir::GenMultiplyByConstantDouble(RegLocation rl_dest, RegLocation rl_src1,
126                                               int64_t constant) {
127   // TODO: need mips implementation.
128   UNUSED(rl_dest, rl_src1, constant);
129   LOG(FATAL) << "Unimplemented GenMultiplyByConstantDouble in mips";
130 }
131 
GenConversion(Instruction::Code opcode,RegLocation rl_dest,RegLocation rl_src)132 void MipsMir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest,
133                                 RegLocation rl_src) {
134   int op = kMipsNop;
135   RegLocation rl_result;
136   switch (opcode) {
137     case Instruction::INT_TO_FLOAT:
138       op = kMipsFcvtsw;
139       break;
140     case Instruction::DOUBLE_TO_FLOAT:
141       op = kMipsFcvtsd;
142       break;
143     case Instruction::FLOAT_TO_DOUBLE:
144       op = kMipsFcvtds;
145       break;
146     case Instruction::INT_TO_DOUBLE:
147       op = kMipsFcvtdw;
148       break;
149     case Instruction::FLOAT_TO_INT:
150       GenConversionCall(kQuickF2iz, rl_dest, rl_src, kCoreReg);
151       return;
152     case Instruction::DOUBLE_TO_INT:
153       GenConversionCall(kQuickD2iz, rl_dest, rl_src, kCoreReg);
154       return;
155     case Instruction::LONG_TO_DOUBLE:
156       GenConversionCall(kQuickL2d, rl_dest, rl_src, kFPReg);
157       return;
158     case Instruction::FLOAT_TO_LONG:
159       GenConversionCall(kQuickF2l, rl_dest, rl_src, kCoreReg);
160       return;
161     case Instruction::LONG_TO_FLOAT:
162       GenConversionCall(kQuickL2f, rl_dest, rl_src, kFPReg);
163       return;
164     case Instruction::DOUBLE_TO_LONG:
165       GenConversionCall(kQuickD2l, rl_dest, rl_src, kCoreReg);
166       return;
167     default:
168       LOG(FATAL) << "Unexpected opcode: " << opcode;
169   }
170   if (rl_src.wide) {
171     rl_src = LoadValueWide(rl_src, kFPReg);
172   } else {
173     rl_src = LoadValue(rl_src, kFPReg);
174   }
175   rl_result = EvalLoc(rl_dest, kFPReg, true);
176   NewLIR2(op, rl_result.reg.GetReg(), rl_src.reg.GetReg());
177   if (rl_dest.wide) {
178     StoreValueWide(rl_dest, rl_result);
179   } else {
180     StoreValue(rl_dest, rl_result);
181   }
182 }
183 
184 // Get the reg storage for a wide FP. Is either a solo or a pair. Base is Mips-counted, e.g., even
185 // values are valid (0, 2).
GetWideArgFP(bool fpuIs32Bit,size_t base)186 static RegStorage GetWideArgFP(bool fpuIs32Bit, size_t base) {
187   // Think about how to make this be able to be computed. E.g., rMIPS_FARG0 + base. Right now
188   // inlining should optimize everything.
189   if (fpuIs32Bit) {
190     switch (base) {
191       case 0:
192         return RegStorage(RegStorage::k64BitPair, rFARG0, rFARG1);
193       case 2:
194         return RegStorage(RegStorage::k64BitPair, rFARG2, rFARG3);
195     }
196   } else {
197     switch (base) {
198       case 0:
199         return RegStorage(RegStorage::k64BitSolo, rFARG0);
200       case 2:
201         return RegStorage(RegStorage::k64BitSolo, rFARG2);
202     }
203   }
204   LOG(FATAL) << "Unsupported Mips.GetWideFP: " << fpuIs32Bit << " " << base;
205   UNREACHABLE();
206 }
207 
GenCmpFP(Instruction::Code opcode,RegLocation rl_dest,RegLocation rl_src1,RegLocation rl_src2)208 void MipsMir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
209                            RegLocation rl_src2) {
210   bool wide = true;
211   QuickEntrypointEnum target;
212 
213   switch (opcode) {
214     case Instruction::CMPL_FLOAT:
215       target = kQuickCmplFloat;
216       wide = false;
217       break;
218     case Instruction::CMPG_FLOAT:
219       target = kQuickCmpgFloat;
220       wide = false;
221       break;
222     case Instruction::CMPL_DOUBLE:
223       target = kQuickCmplDouble;
224       break;
225     case Instruction::CMPG_DOUBLE:
226       target = kQuickCmpgDouble;
227       break;
228     default:
229       LOG(FATAL) << "Unexpected opcode: " << opcode;
230       target = kQuickCmplFloat;
231   }
232   FlushAllRegs();
233   LockCallTemps();
234   if (wide) {
235     RegStorage r_tmp1;
236     RegStorage r_tmp2;
237     if (cu_->target64) {
238       r_tmp1 = RegStorage(RegStorage::k64BitSolo, rFARG0);
239       r_tmp2 = RegStorage(RegStorage::k64BitSolo, rFARG1);
240     } else {
241       r_tmp1 = GetWideArgFP(fpuIs32Bit_, 0);
242       r_tmp2 = GetWideArgFP(fpuIs32Bit_, 2);
243     }
244     LoadValueDirectWideFixed(rl_src1, r_tmp1);
245     LoadValueDirectWideFixed(rl_src2, r_tmp2);
246   } else {
247     LoadValueDirectFixed(rl_src1, rs_rFARG0);
248     LoadValueDirectFixed(rl_src2, cu_->target64 ? rs_rFARG1 : rs_rFARG2);
249   }
250   RegStorage r_tgt = LoadHelper(target);
251   // NOTE: not a safepoint.
252   OpReg(kOpBlx, r_tgt);
253   RegLocation rl_result = GetReturn(kCoreReg);
254   StoreValue(rl_dest, rl_result);
255 }
256 
GenFusedFPCmpBranch(BasicBlock * bb,MIR * mir,bool gt_bias,bool is_double)257 void MipsMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double) {
258   UNUSED(bb, mir, gt_bias, is_double);
259   UNIMPLEMENTED(FATAL) << "Need codegen for fused fp cmp branch";
260 }
261 
GenNegFloat(RegLocation rl_dest,RegLocation rl_src)262 void MipsMir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
263   RegLocation rl_result;
264   if (cu_->target64) {
265     rl_src = LoadValue(rl_src, kFPReg);
266     rl_result = EvalLoc(rl_dest, kFPReg, true);
267     NewLIR2(kMipsFnegs, rl_result.reg.GetReg(), rl_src.reg.GetReg());
268   } else {
269     rl_src = LoadValue(rl_src, kCoreReg);
270     rl_result = EvalLoc(rl_dest, kCoreReg, true);
271     OpRegRegImm(kOpAdd, rl_result.reg, rl_src.reg, 0x80000000);
272   }
273   StoreValue(rl_dest, rl_result);
274 }
275 
GenNegDouble(RegLocation rl_dest,RegLocation rl_src)276 void MipsMir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
277   RegLocation rl_result;
278   if (cu_->target64) {
279     rl_src = LoadValueWide(rl_src, kFPReg);
280     rl_result = EvalLocWide(rl_dest, kFPReg, true);
281     NewLIR2(kMipsFnegd, rl_result.reg.GetReg(), rl_src.reg.GetReg());
282   } else {
283     rl_src = LoadValueWide(rl_src, kCoreReg);
284     rl_result = EvalLoc(rl_dest, kCoreReg, true);
285     OpRegRegImm(kOpAdd, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), 0x80000000);
286     OpRegCopy(rl_result.reg, rl_src.reg);
287   }
288   StoreValueWide(rl_dest, rl_result);
289 }
290 
GenInlinedMinMax(CallInfo * info,bool is_min,bool is_long)291 bool MipsMir2Lir::GenInlinedMinMax(CallInfo* info, bool is_min, bool is_long) {
292   // TODO: need Mips implementation.
293   UNUSED(info, is_min, is_long);
294   return false;
295 }
296 
297 }  // namespace art
298