blob: 52706df7a597921b4dc67bfad7cadef98a29fb43 [file] [log] [blame]
Brian Carlstrom7940e442013-07-12 13:46:57 -07001/*
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"
Ian Rogersd582fa42014-11-05 23:46:43 -080018
Andreas Gampe0b9203e2015-01-22 20:39:27 -080019#include "base/logging.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070020#include "dex/quick/mir_to_lir-inl.h"
Ian Rogers166db042013-07-26 12:05:57 -070021#include "entrypoints/quick/quick_entrypoints.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070022#include "mips_lir.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070023
24namespace art {
25
Goran Jakovljevic10957932015-03-24 18:42:56 +010026void MipsMir2Lir::GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
27 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070028 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:
Goran Jakovljevic10957932015-03-24 18:42:56 +010054 FlushAllRegs(); // Send everything to home location.
Andreas Gampe98430592014-07-27 19:44:50 -070055 CallRuntimeHelperRegLocationRegLocation(kQuickFmodf, rl_src1, rl_src2, false);
buzbeea0cd2d72014-06-01 09:33:49 -070056 rl_result = GetReturn(kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -070057 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);
Bill Buzbee00e1ec62014-02-27 23:44:13 +000068 NewLIR3(op, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -070069 StoreValue(rl_dest, rl_result);
70}
71
Goran Jakovljevic10957932015-03-24 18:42:56 +010072void MipsMir2Lir::GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
73 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070074 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:
Goran Jakovljevic10957932015-03-24 18:42:56 +010096 FlushAllRegs(); // Send everything to home location.
Andreas Gampe98430592014-07-27 19:44:50 -070097 CallRuntimeHelperRegLocationRegLocation(kQuickFmod, rl_src1, rl_src2, false);
buzbeea0cd2d72014-06-01 09:33:49 -070098 rl_result = GetReturnWide(kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -070099 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);
buzbee091cc402014-03-31 10:14:40 -0700114 NewLIR3(op, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700115 StoreValueWide(rl_dest, rl_result);
116}
117
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100118void MipsMir2Lir::GenMultiplyByConstantFloat(RegLocation rl_dest ATTRIBUTE_UNUSED,
119 RegLocation rl_src1 ATTRIBUTE_UNUSED,
120 int32_t constant ATTRIBUTE_UNUSED) {
Ningsheng Jian675e09b2014-10-23 13:48:36 +0800121 // TODO: need mips implementation.
Ningsheng Jian675e09b2014-10-23 13:48:36 +0800122 LOG(FATAL) << "Unimplemented GenMultiplyByConstantFloat in mips";
123}
124
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100125void MipsMir2Lir::GenMultiplyByConstantDouble(RegLocation rl_dest ATTRIBUTE_UNUSED,
126 RegLocation rl_src1 ATTRIBUTE_UNUSED,
127 int64_t constant ATTRIBUTE_UNUSED) {
Ningsheng Jian675e09b2014-10-23 13:48:36 +0800128 // TODO: need mips implementation.
Ningsheng Jian675e09b2014-10-23 13:48:36 +0800129 LOG(FATAL) << "Unimplemented GenMultiplyByConstantDouble in mips";
130}
131
Brian Carlstrom7940e442013-07-12 13:46:57 -0700132void MipsMir2Lir::GenConversion(Instruction::Code opcode, RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700133 RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700134 int op = kMipsNop;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700135 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:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100150 GenConversionCall(kQuickF2iz, rl_dest, rl_src, kCoreReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700151 return;
152 case Instruction::DOUBLE_TO_INT:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100153 GenConversionCall(kQuickD2iz, rl_dest, rl_src, kCoreReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700154 return;
155 case Instruction::LONG_TO_DOUBLE:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100156 GenConversionCall(kQuickL2d, rl_dest, rl_src, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700157 return;
158 case Instruction::FLOAT_TO_LONG:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100159 GenConversionCall(kQuickF2l, rl_dest, rl_src, kCoreReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700160 return;
161 case Instruction::LONG_TO_FLOAT:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100162 GenConversionCall(kQuickL2f, rl_dest, rl_src, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700163 return;
164 case Instruction::DOUBLE_TO_LONG:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100165 GenConversionCall(kQuickD2l, rl_dest, rl_src, kCoreReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700166 return;
167 default:
168 LOG(FATAL) << "Unexpected opcode: " << opcode;
169 }
170 if (rl_src.wide) {
171 rl_src = LoadValueWide(rl_src, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700172 } else {
173 rl_src = LoadValue(rl_src, kFPReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700174 }
buzbee091cc402014-03-31 10:14:40 -0700175 rl_result = EvalLoc(rl_dest, kFPReg, true);
176 NewLIR2(op, rl_result.reg.GetReg(), rl_src.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700177 if (rl_dest.wide) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700178 StoreValueWide(rl_dest, rl_result);
179 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700180 StoreValue(rl_dest, rl_result);
181 }
182}
183
Douglas Leung027f0ff2015-02-27 19:05:03 -0800184// 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).
186static 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:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100192 return RegStorage(RegStorage::k64BitPair, rFARG0, rFARG1);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800193 case 2:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100194 return RegStorage(RegStorage::k64BitPair, rFARG2, rFARG3);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800195 }
196 } else {
197 switch (base) {
198 case 0:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100199 return RegStorage(RegStorage::k64BitSolo, rFARG0);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800200 case 2:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100201 return RegStorage(RegStorage::k64BitSolo, rFARG2);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800202 }
203 }
204 LOG(FATAL) << "Unsupported Mips.GetWideFP: " << fpuIs32Bit << " " << base;
205 UNREACHABLE();
206}
207
Goran Jakovljevic10957932015-03-24 18:42:56 +0100208void MipsMir2Lir::GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
209 RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700210 bool wide = true;
Andreas Gampe98430592014-07-27 19:44:50 -0700211 QuickEntrypointEnum target;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700212
213 switch (opcode) {
214 case Instruction::CMPL_FLOAT:
Andreas Gampe98430592014-07-27 19:44:50 -0700215 target = kQuickCmplFloat;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700216 wide = false;
217 break;
218 case Instruction::CMPG_FLOAT:
Andreas Gampe98430592014-07-27 19:44:50 -0700219 target = kQuickCmpgFloat;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700220 wide = false;
221 break;
222 case Instruction::CMPL_DOUBLE:
Andreas Gampe98430592014-07-27 19:44:50 -0700223 target = kQuickCmplDouble;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700224 break;
225 case Instruction::CMPG_DOUBLE:
Andreas Gampe98430592014-07-27 19:44:50 -0700226 target = kQuickCmpgDouble;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700227 break;
228 default:
229 LOG(FATAL) << "Unexpected opcode: " << opcode;
Andreas Gampe98430592014-07-27 19:44:50 -0700230 target = kQuickCmplFloat;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700231 }
232 FlushAllRegs();
233 LockCallTemps();
234 if (wide) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100235 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 }
buzbee2700f7e2014-03-07 09:46:20 -0800244 LoadValueDirectWideFixed(rl_src1, r_tmp1);
245 LoadValueDirectWideFixed(rl_src2, r_tmp2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700246 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100247 LoadValueDirectFixed(rl_src1, rs_rFARG0);
248 LoadValueDirectFixed(rl_src2, cu_->target64 ? rs_rFARG1 : rs_rFARG2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700249 }
Andreas Gampe98430592014-07-27 19:44:50 -0700250 RegStorage r_tgt = LoadHelper(target);
Goran Jakovljevic10957932015-03-24 18:42:56 +0100251 // NOTE: not a safepoint.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700252 OpReg(kOpBlx, r_tgt);
buzbeea0cd2d72014-06-01 09:33:49 -0700253 RegLocation rl_result = GetReturn(kCoreReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700254 StoreValue(rl_dest, rl_result);
255}
256
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100257void MipsMir2Lir::GenFusedFPCmpBranch(BasicBlock* bb ATTRIBUTE_UNUSED,
258 MIR* mir ATTRIBUTE_UNUSED,
259 bool gt_bias ATTRIBUTE_UNUSED,
260 bool is_double ATTRIBUTE_UNUSED) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700261 UNIMPLEMENTED(FATAL) << "Need codegen for fused fp cmp branch";
262}
263
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700264void MipsMir2Lir::GenNegFloat(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700265 RegLocation rl_result;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100266 if (cu_->target64) {
267 rl_src = LoadValue(rl_src, kFPReg);
268 rl_result = EvalLoc(rl_dest, kFPReg, true);
269 NewLIR2(kMipsFnegs, rl_result.reg.GetReg(), rl_src.reg.GetReg());
270 } else {
271 rl_src = LoadValue(rl_src, kCoreReg);
272 rl_result = EvalLoc(rl_dest, kCoreReg, true);
273 OpRegRegImm(kOpAdd, rl_result.reg, rl_src.reg, 0x80000000);
274 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700275 StoreValue(rl_dest, rl_result);
276}
277
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700278void MipsMir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700279 RegLocation rl_result;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100280 if (cu_->target64) {
281 rl_src = LoadValueWide(rl_src, kFPReg);
282 rl_result = EvalLocWide(rl_dest, kFPReg, true);
283 NewLIR2(kMipsFnegd, rl_result.reg.GetReg(), rl_src.reg.GetReg());
284 } else {
285 rl_src = LoadValueWide(rl_src, kCoreReg);
286 rl_result = EvalLoc(rl_dest, kCoreReg, true);
287 OpRegRegImm(kOpAdd, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), 0x80000000);
288 OpRegCopy(rl_result.reg, rl_src.reg);
289 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700290 StoreValueWide(rl_dest, rl_result);
291}
292
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100293bool MipsMir2Lir::GenInlinedMinMax(CallInfo* info ATTRIBUTE_UNUSED,
294 bool is_min ATTRIBUTE_UNUSED,
295 bool is_long ATTRIBUTE_UNUSED) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700296 // TODO: need Mips implementation.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700297 return false;
298}
299
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700300} // namespace art