blob: 8ab542270d117bfbbfcd4684ebf131094ae607e3 [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
19#include "arch/mips/instruction_set_features_mips.h"
Nikola Veljkovic2d873b62015-02-20 17:21:15 +010020#include "arch/mips/entrypoints_direct_mips.h"
Andreas Gampe0b9203e2015-01-22 20:39:27 -080021#include "base/logging.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070022#include "dex/quick/mir_to_lir-inl.h"
buzbeeb5860fb2014-06-21 15:31:01 -070023#include "dex/reg_storage_eq.h"
Andreas Gampe0b9203e2015-01-22 20:39:27 -080024#include "driver/compiler_driver.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070025#include "mips_lir.h"
26
27namespace art {
28
Goran Jakovljevic10957932015-03-24 18:42:56 +010029/* This file contains codegen for the Mips ISA */
buzbee2700f7e2014-03-07 09:46:20 -080030LIR* MipsMir2Lir::OpFpRegCopy(RegStorage r_dest, RegStorage r_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070031 int opcode;
Goran Jakovljevic10957932015-03-24 18:42:56 +010032 if (cu_->target64) {
33 DCHECK_EQ(r_dest.Is64Bit(), r_src.Is64Bit());
34 if (r_dest.Is64Bit()) {
35 if (r_dest.IsDouble()) {
36 if (r_src.IsDouble()) {
37 opcode = kMipsFmovd;
38 } else {
39 // Note the operands are swapped for the dmtc1 instr.
40 RegStorage t_opnd = r_src;
41 r_src = r_dest;
42 r_dest = t_opnd;
43 opcode = kMips64Dmtc1;
44 }
Brian Carlstrom7940e442013-07-12 13:46:57 -070045 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +010046 DCHECK(r_src.IsDouble());
47 opcode = kMips64Dmfc1;
Brian Carlstrom7940e442013-07-12 13:46:57 -070048 }
49 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +010050 if (r_dest.IsSingle()) {
51 if (r_src.IsSingle()) {
52 opcode = kMipsFmovs;
53 } else {
54 // Note the operands are swapped for the mtc1 instr.
55 RegStorage t_opnd = r_src;
56 r_src = r_dest;
57 r_dest = t_opnd;
58 opcode = kMipsMtc1;
59 }
60 } else {
61 DCHECK(r_src.IsSingle());
62 opcode = kMipsMfc1;
63 }
64 }
65 } else {
66 // Must be both DOUBLE or both not DOUBLE.
67 DCHECK_EQ(r_dest.IsDouble(), r_src.IsDouble());
68 if (r_dest.IsDouble()) {
69 opcode = kMipsFmovd;
70 } else {
71 if (r_dest.IsSingle()) {
72 if (r_src.IsSingle()) {
73 opcode = kMipsFmovs;
74 } else {
75 // Note the operands are swapped for the mtc1 instr.
76 RegStorage t_opnd = r_src;
77 r_src = r_dest;
78 r_dest = t_opnd;
79 opcode = kMipsMtc1;
80 }
81 } else {
82 DCHECK(r_src.IsSingle());
83 opcode = kMipsMfc1;
84 }
Brian Carlstrom7940e442013-07-12 13:46:57 -070085 }
86 }
Goran Jakovljevic10957932015-03-24 18:42:56 +010087 LIR* res;
88 if (cu_->target64) {
89 res = RawLIR(current_dalvik_offset_, opcode, r_dest.GetReg(), r_src.GetReg());
90 } else {
91 res = RawLIR(current_dalvik_offset_, opcode, r_src.GetReg(), r_dest.GetReg());
92 }
Brian Carlstrom7940e442013-07-12 13:46:57 -070093 if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
94 res->flags.is_nop = true;
95 }
96 return res;
97}
98
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070099bool MipsMir2Lir::InexpensiveConstantInt(int32_t value) {
Andreas Gampeab1eb0d2015-02-13 19:23:55 -0800100 // For encodings, see LoadConstantNoClobber below.
101 return ((value == 0) || IsUint<16>(value) || IsInt<16>(value));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700102}
103
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700104bool MipsMir2Lir::InexpensiveConstantFloat(int32_t value) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700105 UNUSED(value);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700106 return false; // TUNING
107}
108
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700109bool MipsMir2Lir::InexpensiveConstantLong(int64_t value) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700110 UNUSED(value);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700111 return false; // TUNING
112}
113
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700114bool MipsMir2Lir::InexpensiveConstantDouble(int64_t value) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700115 UNUSED(value);
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700116 return false; // TUNING
Brian Carlstrom7940e442013-07-12 13:46:57 -0700117}
118
119/*
120 * Load a immediate using a shortcut if possible; otherwise
121 * grab from the per-translation literal pool. If target is
122 * a high register, build constant into a low register and copy.
123 *
124 * No additional register clobbering operation performed. Use this version when
125 * 1) r_dest is freshly returned from AllocTemp or
126 * 2) The codegen is under fixed register usage
127 */
buzbee2700f7e2014-03-07 09:46:20 -0800128LIR* MipsMir2Lir::LoadConstantNoClobber(RegStorage r_dest, int value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700129 LIR *res;
130
buzbee2700f7e2014-03-07 09:46:20 -0800131 RegStorage r_dest_save = r_dest;
buzbee091cc402014-03-31 10:14:40 -0700132 int is_fp_reg = r_dest.IsFloat();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700133 if (is_fp_reg) {
buzbee091cc402014-03-31 10:14:40 -0700134 DCHECK(r_dest.IsSingle());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700135 r_dest = AllocTemp();
136 }
137
Goran Jakovljevic10957932015-03-24 18:42:56 +0100138 // See if the value can be constructed cheaply.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700139 if (value == 0) {
buzbee2700f7e2014-03-07 09:46:20 -0800140 res = NewLIR2(kMipsMove, r_dest.GetReg(), rZERO);
Andreas Gampeab1eb0d2015-02-13 19:23:55 -0800141 } else if (IsUint<16>(value)) {
142 // Use OR with (unsigned) immediate to encode 16b unsigned int.
buzbee2700f7e2014-03-07 09:46:20 -0800143 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZERO, value);
Andreas Gampeab1eb0d2015-02-13 19:23:55 -0800144 } else if (IsInt<16>(value)) {
145 // Use ADD with (signed) immediate to encode 16b signed int.
buzbee2700f7e2014-03-07 09:46:20 -0800146 res = NewLIR3(kMipsAddiu, r_dest.GetReg(), rZERO, value);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700147 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800148 res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700149 if (value & 0xffff)
buzbee2700f7e2014-03-07 09:46:20 -0800150 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), value);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700151 }
152
153 if (is_fp_reg) {
buzbee2700f7e2014-03-07 09:46:20 -0800154 NewLIR2(kMipsMtc1, r_dest.GetReg(), r_dest_save.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700155 FreeTemp(r_dest);
156 }
157
158 return res;
159}
160
Goran Jakovljevic10957932015-03-24 18:42:56 +0100161LIR* MipsMir2Lir::LoadConstantWideNoClobber(RegStorage r_dest, int64_t value) {
162 LIR* res = nullptr;
163 DCHECK(r_dest.Is64Bit());
164 RegStorage r_dest_save = r_dest;
165 int is_fp_reg = r_dest.IsFloat();
166 if (is_fp_reg) {
167 DCHECK(r_dest.IsDouble());
168 r_dest = AllocTemp();
169 }
170
171 int bit31 = (value & UINT64_C(0x80000000)) != 0;
172
173 // Loads with 1 instruction.
174 if (IsUint<16>(value)) {
175 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, value);
176 } else if (IsInt<16>(value)) {
177 res = NewLIR3(kMips64Daddiu, r_dest.GetReg(), rZEROd, value);
178 } else if ((value & 0xFFFF) == 0 && IsInt<16>(value >> 16)) {
179 res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
180 } else if (IsInt<32>(value)) {
181 // Loads with 2 instructions.
182 res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
183 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), value);
184 } else if ((value & 0xFFFF0000) == 0 && IsInt<16>(value >> 32)) {
185 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, value);
186 NewLIR2(kMips64Dahi, r_dest.GetReg(), value >> 32);
187 } else if ((value & UINT64_C(0xFFFFFFFF0000)) == 0) {
188 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, value);
189 NewLIR2(kMips64Dati, r_dest.GetReg(), value >> 48);
190 } else if ((value & 0xFFFF) == 0 && (value >> 32) >= (-32768 - bit31) &&
191 (value >> 32) <= (32767 - bit31)) {
192 res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
193 NewLIR2(kMips64Dahi, r_dest.GetReg(), (value >> 32) + bit31);
194 } else if ((value & 0xFFFF) == 0 && ((value >> 31) & 0x1FFFF) == ((0x20000 - bit31) & 0x1FFFF)) {
195 res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
196 NewLIR2(kMips64Dati, r_dest.GetReg(), (value >> 48) + bit31);
197 } else {
198 int64_t tmp = value;
199 int shift_cnt = 0;
200 while ((tmp & 1) == 0) {
201 tmp >>= 1;
202 shift_cnt++;
203 }
204
205 if (IsUint<16>(tmp)) {
206 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, tmp);
207 NewLIR3((shift_cnt < 32) ? kMips64Dsll : kMips64Dsll32, r_dest.GetReg(), r_dest.GetReg(),
208 shift_cnt & 0x1F);
209 } else if (IsInt<16>(tmp)) {
210 res = NewLIR3(kMips64Daddiu, r_dest.GetReg(), rZEROd, tmp);
211 NewLIR3((shift_cnt < 32) ? kMips64Dsll : kMips64Dsll32, r_dest.GetReg(), r_dest.GetReg(),
212 shift_cnt & 0x1F);
213 } else if (IsInt<32>(tmp)) {
214 // Loads with 3 instructions.
215 res = NewLIR2(kMipsLui, r_dest.GetReg(), tmp >> 16);
216 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), tmp);
217 NewLIR3((shift_cnt < 32) ? kMips64Dsll : kMips64Dsll32, r_dest.GetReg(), r_dest.GetReg(),
218 shift_cnt & 0x1F);
219 } else {
220 tmp = value >> 16;
221 shift_cnt = 16;
222 while ((tmp & 1) == 0) {
223 tmp >>= 1;
224 shift_cnt++;
225 }
226
227 if (IsUint<16>(tmp)) {
228 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, tmp);
229 NewLIR3((shift_cnt < 32) ? kMips64Dsll : kMips64Dsll32, r_dest.GetReg(), r_dest.GetReg(),
230 shift_cnt & 0x1F);
231 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), value);
232 } else if (IsInt<16>(tmp)) {
233 res = NewLIR3(kMips64Daddiu, r_dest.GetReg(), rZEROd, tmp);
234 NewLIR3((shift_cnt < 32) ? kMips64Dsll : kMips64Dsll32, r_dest.GetReg(), r_dest.GetReg(),
235 shift_cnt & 0x1F);
236 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), value);
237 } else {
238 // Loads with 3-4 instructions.
239 uint64_t tmp2 = value;
240 if (((tmp2 >> 16) & 0xFFFF) != 0 || (tmp2 & 0xFFFFFFFF) == 0) {
241 res = NewLIR2(kMipsLui, r_dest.GetReg(), tmp2 >> 16);
242 }
243 if ((tmp2 & 0xFFFF) != 0) {
244 if (res)
245 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), tmp2);
246 else
247 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, tmp2);
248 }
249 if (bit31) {
250 tmp2 += UINT64_C(0x100000000);
251 }
252 if (((tmp2 >> 32) & 0xFFFF) != 0) {
253 NewLIR2(kMips64Dahi, r_dest.GetReg(), tmp2 >> 32);
254 }
255 if (tmp2 & UINT64_C(0x800000000000)) {
256 tmp2 += UINT64_C(0x1000000000000);
257 }
258 if ((tmp2 >> 48) != 0) {
259 NewLIR2(kMips64Dati, r_dest.GetReg(), tmp2 >> 48);
260 }
261 }
262 }
263 }
264
265 if (is_fp_reg) {
266 NewLIR2(kMips64Dmtc1, r_dest.GetReg(), r_dest_save.GetReg());
267 FreeTemp(r_dest);
268 }
269 return res;
270}
271
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700272LIR* MipsMir2Lir::OpUnconditionalBranch(LIR* target) {
Brian Carlstromdf629502013-07-17 22:39:56 -0700273 LIR* res = NewLIR1(kMipsB, 0 /* offset to be patched during assembly*/);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700274 res->target = target;
275 return res;
276}
277
buzbee2700f7e2014-03-07 09:46:20 -0800278LIR* MipsMir2Lir::OpReg(OpKind op, RegStorage r_dest_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700279 MipsOpCode opcode = kMipsNop;
280 switch (op) {
281 case kOpBlx:
282 opcode = kMipsJalr;
283 break;
284 case kOpBx:
Andreas Gampe8d365912015-01-13 11:32:32 -0800285 return NewLIR2(kMipsJalr, rZERO, r_dest_src.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700286 default:
287 LOG(FATAL) << "Bad case in OpReg";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700288 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700289 }
Goran Jakovljevic10957932015-03-24 18:42:56 +0100290 return NewLIR2(opcode, cu_->target64 ? rRAd : rRA, r_dest_src.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700291}
292
buzbee2700f7e2014-03-07 09:46:20 -0800293LIR* MipsMir2Lir::OpRegImm(OpKind op, RegStorage r_dest_src1, int value) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100294 if ((op == kOpAdd) || (op == kOpSub)) {
295 return OpRegRegImm(op, r_dest_src1, r_dest_src1, value);
Brian Carlstrom9b7085a2013-07-18 15:15:21 -0700296 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100297 LOG(FATAL) << "Bad case in OpRegImm";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700298 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700299 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700300}
301
buzbee2700f7e2014-03-07 09:46:20 -0800302LIR* MipsMir2Lir::OpRegRegReg(OpKind op, RegStorage r_dest, RegStorage r_src1, RegStorage r_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700303 MipsOpCode opcode = kMipsNop;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100304 bool is64bit = cu_->target64 && (r_dest.Is64Bit() || r_src1.Is64Bit() || r_src2.Is64Bit());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700305 switch (op) {
306 case kOpAdd:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100307 opcode = is64bit ? kMips64Daddu : kMipsAddu;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700308 break;
309 case kOpSub:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100310 opcode = is64bit ? kMips64Dsubu : kMipsSubu;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700311 break;
312 case kOpAnd:
313 opcode = kMipsAnd;
314 break;
315 case kOpMul:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100316 opcode = isaIsR6_ ? kMipsR6Mul : kMipsR2Mul;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700317 break;
318 case kOpOr:
319 opcode = kMipsOr;
320 break;
321 case kOpXor:
322 opcode = kMipsXor;
323 break;
324 case kOpLsl:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100325 opcode = is64bit ? kMips64Dsllv : kMipsSllv;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700326 break;
327 case kOpLsr:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100328 opcode = is64bit ? kMips64Dsrlv : kMipsSrlv;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700329 break;
330 case kOpAsr:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100331 opcode = is64bit ? kMips64Dsrav : kMipsSrav;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700332 break;
333 case kOpAdc:
334 case kOpSbc:
335 LOG(FATAL) << "No carry bit on MIPS";
336 break;
337 default:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100338 LOG(FATAL) << "Bad case in OpRegRegReg";
Brian Carlstrom7940e442013-07-12 13:46:57 -0700339 break;
340 }
buzbee2700f7e2014-03-07 09:46:20 -0800341 return NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), r_src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700342}
343
buzbee2700f7e2014-03-07 09:46:20 -0800344LIR* MipsMir2Lir::OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src1, int value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700345 LIR *res;
346 MipsOpCode opcode = kMipsNop;
347 bool short_form = true;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100348 bool is64bit = cu_->target64 && (r_dest.Is64Bit() || r_src1.Is64Bit());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700349
350 switch (op) {
351 case kOpAdd:
352 if (IS_SIMM16(value)) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100353 opcode = is64bit ? kMips64Daddiu : kMipsAddiu;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700354 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700355 short_form = false;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100356 opcode = is64bit ? kMips64Daddu : kMipsAddu;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700357 }
358 break;
359 case kOpSub:
360 if (IS_SIMM16((-value))) {
361 value = -value;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100362 opcode = is64bit ? kMips64Daddiu : kMipsAddiu;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700363 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700364 short_form = false;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100365 opcode = is64bit ? kMips64Dsubu : kMipsSubu;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700366 }
367 break;
368 case kOpLsl:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100369 if (is64bit) {
370 DCHECK(value >= 0 && value <= 63);
371 if (value >= 0 && value <= 31) {
372 opcode = kMips64Dsll;
373 } else {
374 opcode = kMips64Dsll32;
375 value = value - 32;
376 }
377 } else {
378 DCHECK(value >= 0 && value <= 31);
379 opcode = kMipsSll;
380 }
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800381 break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700382 case kOpLsr:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100383 if (is64bit) {
384 DCHECK(value >= 0 && value <= 63);
385 if (value >= 0 && value <= 31) {
386 opcode = kMips64Dsrl;
387 } else {
388 opcode = kMips64Dsrl32;
389 value = value - 32;
390 }
391 } else {
392 DCHECK(value >= 0 && value <= 31);
393 opcode = kMipsSrl;
394 }
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800395 break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700396 case kOpAsr:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100397 if (is64bit) {
398 DCHECK(value >= 0 && value <= 63);
399 if (value >= 0 && value <= 31) {
400 opcode = kMips64Dsra;
401 } else {
402 opcode = kMips64Dsra32;
403 value = value - 32;
404 }
405 } else {
406 DCHECK(value >= 0 && value <= 31);
407 opcode = kMipsSra;
408 }
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800409 break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700410 case kOpAnd:
411 if (IS_UIMM16((value))) {
412 opcode = kMipsAndi;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700413 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700414 short_form = false;
415 opcode = kMipsAnd;
416 }
417 break;
418 case kOpOr:
419 if (IS_UIMM16((value))) {
420 opcode = kMipsOri;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700421 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700422 short_form = false;
423 opcode = kMipsOr;
424 }
425 break;
426 case kOpXor:
427 if (IS_UIMM16((value))) {
428 opcode = kMipsXori;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700429 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700430 short_form = false;
431 opcode = kMipsXor;
432 }
433 break;
434 case kOpMul:
435 short_form = false;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100436 opcode = isaIsR6_ ? kMipsR6Mul : kMipsR2Mul;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700437 break;
438 default:
439 LOG(FATAL) << "Bad case in OpRegRegImm";
440 break;
441 }
442
Brian Carlstrom9b7085a2013-07-18 15:15:21 -0700443 if (short_form) {
buzbee2700f7e2014-03-07 09:46:20 -0800444 res = NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), value);
Brian Carlstrom9b7085a2013-07-18 15:15:21 -0700445 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700446 if (r_dest != r_src1) {
447 res = LoadConstant(r_dest, value);
buzbee2700f7e2014-03-07 09:46:20 -0800448 NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), r_dest.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700449 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100450 RegStorage r_scratch;
451 if (is64bit) {
452 r_scratch = AllocTempWide();
453 res = LoadConstantWide(r_scratch, value);
454 } else {
455 r_scratch = AllocTemp();
456 res = LoadConstant(r_scratch, value);
457 }
buzbee2700f7e2014-03-07 09:46:20 -0800458 NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), r_scratch.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700459 }
460 }
461 return res;
462}
463
buzbee2700f7e2014-03-07 09:46:20 -0800464LIR* MipsMir2Lir::OpRegReg(OpKind op, RegStorage r_dest_src1, RegStorage r_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700465 MipsOpCode opcode = kMipsNop;
466 LIR *res;
467 switch (op) {
468 case kOpMov:
469 opcode = kMipsMove;
470 break;
471 case kOpMvn:
buzbee2700f7e2014-03-07 09:46:20 -0800472 return NewLIR3(kMipsNor, r_dest_src1.GetReg(), r_src2.GetReg(), rZERO);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700473 case kOpNeg:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100474 if (cu_->target64 && r_dest_src1.Is64Bit()) {
475 return NewLIR3(kMips64Dsubu, r_dest_src1.GetReg(), rZEROd, r_src2.GetReg());
476 } else {
477 return NewLIR3(kMipsSubu, r_dest_src1.GetReg(), rZERO, r_src2.GetReg());
478 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700479 case kOpAdd:
480 case kOpAnd:
481 case kOpMul:
482 case kOpOr:
483 case kOpSub:
484 case kOpXor:
485 return OpRegRegReg(op, r_dest_src1, r_dest_src1, r_src2);
486 case kOp2Byte:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100487 if (cu_->target64) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800488 res = NewLIR2(kMipsSeb, r_dest_src1.GetReg(), r_src2.GetReg());
489 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100490 if (cu_->compiler_driver->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()
491 ->IsMipsIsaRevGreaterThanEqual2()) {
492 res = NewLIR2(kMipsSeb, r_dest_src1.GetReg(), r_src2.GetReg());
493 } else {
494 res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 24);
495 OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 24);
496 }
Ian Rogersd582fa42014-11-05 23:46:43 -0800497 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700498 return res;
499 case kOp2Short:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100500 if (cu_->target64) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800501 res = NewLIR2(kMipsSeh, r_dest_src1.GetReg(), r_src2.GetReg());
502 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100503 if (cu_->compiler_driver->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()
504 ->IsMipsIsaRevGreaterThanEqual2()) {
505 res = NewLIR2(kMipsSeh, r_dest_src1.GetReg(), r_src2.GetReg());
506 } else {
507 res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 16);
508 OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 16);
509 }
Ian Rogersd582fa42014-11-05 23:46:43 -0800510 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700511 return res;
512 case kOp2Char:
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800513 return NewLIR3(kMipsAndi, r_dest_src1.GetReg(), r_src2.GetReg(), 0xFFFF);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700514 default:
515 LOG(FATAL) << "Bad case in OpRegReg";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700516 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700517 }
buzbee2700f7e2014-03-07 09:46:20 -0800518 return NewLIR2(opcode, r_dest_src1.GetReg(), r_src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700519}
520
buzbee2700f7e2014-03-07 09:46:20 -0800521LIR* MipsMir2Lir::OpMovRegMem(RegStorage r_dest, RegStorage r_base, int offset,
522 MoveType move_type) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700523 UNUSED(r_dest, r_base, offset, move_type);
Razvan A Lupusoru2c498d12014-01-29 16:02:57 -0800524 UNIMPLEMENTED(FATAL);
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700525 UNREACHABLE();
Razvan A Lupusoru2c498d12014-01-29 16:02:57 -0800526}
527
buzbee2700f7e2014-03-07 09:46:20 -0800528LIR* MipsMir2Lir::OpMovMemReg(RegStorage r_base, int offset, RegStorage r_src, MoveType move_type) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700529 UNUSED(r_base, offset, r_src, move_type);
Razvan A Lupusoru2c498d12014-01-29 16:02:57 -0800530 UNIMPLEMENTED(FATAL);
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700531 UNREACHABLE();
Razvan A Lupusoru2c498d12014-01-29 16:02:57 -0800532}
533
buzbee2700f7e2014-03-07 09:46:20 -0800534LIR* MipsMir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, RegStorage r_dest, RegStorage r_src) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700535 UNUSED(op, cc, r_dest, r_src);
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800536 LOG(FATAL) << "Unexpected use of OpCondRegReg for MIPS";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700537 UNREACHABLE();
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800538}
539
buzbee2700f7e2014-03-07 09:46:20 -0800540LIR* MipsMir2Lir::LoadConstantWide(RegStorage r_dest, int64_t value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700541 LIR *res;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100542 if (cu_->target64) {
543 res = LoadConstantWideNoClobber(r_dest, value);
544 return res;
545 }
Douglas Leung027f0ff2015-02-27 19:05:03 -0800546 if (fpuIs32Bit_ || !r_dest.IsFloat()) {
547 // 32bit FPU (pairs) or loading into GPR.
548 if (!r_dest.IsPair()) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100549 // Form 64-bit pair.
Douglas Leung027f0ff2015-02-27 19:05:03 -0800550 r_dest = Solo64ToPair64(r_dest);
551 }
552 res = LoadConstantNoClobber(r_dest.GetLow(), Low32Bits(value));
553 LoadConstantNoClobber(r_dest.GetHigh(), High32Bits(value));
554 } else {
555 // Here if we have a 64bit FPU and loading into FPR.
556 RegStorage r_temp = AllocTemp();
557 r_dest = Fp64ToSolo32(r_dest);
558 res = LoadConstantNoClobber(r_dest, Low32Bits(value));
559 LoadConstantNoClobber(r_temp, High32Bits(value));
560 NewLIR2(kMipsMthc1, r_temp.GetReg(), r_dest.GetReg());
561 FreeTemp(r_temp);
Douglas Leung2db3e262014-06-25 16:02:55 -0700562 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700563 return res;
564}
565
566/* Load value from base + scaled index. */
buzbee2700f7e2014-03-07 09:46:20 -0800567LIR* MipsMir2Lir::LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700568 int scale, OpSize size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700569 LIR *first = NULL;
570 LIR *res;
571 MipsOpCode opcode = kMipsNop;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100572 bool is64bit = cu_->target64 && r_dest.Is64Bit();
573 RegStorage t_reg = is64bit ? AllocTempWide() : AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700574
buzbee091cc402014-03-31 10:14:40 -0700575 if (r_dest.IsFloat()) {
576 DCHECK(r_dest.IsSingle());
buzbeefd698e62014-04-27 19:33:22 -0700577 DCHECK((size == k32) || (size == kSingle) || (size == kReference));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700578 size = kSingle;
579 } else {
580 if (size == kSingle)
buzbee695d13a2014-04-19 13:32:20 -0700581 size = k32;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700582 }
583
Goran Jakovljevic10957932015-03-24 18:42:56 +0100584 if (cu_->target64) {
585 if (!scale) {
586 if (is64bit) {
587 first = NewLIR3(kMips64Daddu, t_reg.GetReg() , r_base.GetReg(), r_index.GetReg());
588 } else {
589 first = NewLIR3(kMipsAddu, t_reg.GetReg() , r_base.GetReg(), r_index.GetReg());
590 }
591 } else {
592 first = OpRegRegImm(kOpLsl, t_reg, r_index, scale);
593 NewLIR3(kMips64Daddu, t_reg.GetReg() , r_base.GetReg(), t_reg.GetReg());
594 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700595 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100596 if (!scale) {
597 first = NewLIR3(kMipsAddu, t_reg.GetReg() , r_base.GetReg(), r_index.GetReg());
598 } else {
599 first = OpRegRegImm(kOpLsl, t_reg, r_index, scale);
600 NewLIR3(kMipsAddu, t_reg.GetReg() , r_base.GetReg(), t_reg.GetReg());
601 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700602 }
603
604 switch (size) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100605 case k64:
606 if (cu_->target64) {
607 opcode = kMips64Ld;
608 } else {
609 LOG(FATAL) << "Bad case in LoadBaseIndexed";
610 }
611 break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700612 case kSingle:
613 opcode = kMipsFlwc1;
614 break;
buzbee695d13a2014-04-19 13:32:20 -0700615 case k32:
616 case kReference:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700617 opcode = kMipsLw;
618 break;
619 case kUnsignedHalf:
620 opcode = kMipsLhu;
621 break;
622 case kSignedHalf:
623 opcode = kMipsLh;
624 break;
625 case kUnsignedByte:
626 opcode = kMipsLbu;
627 break;
628 case kSignedByte:
629 opcode = kMipsLb;
630 break;
631 default:
632 LOG(FATAL) << "Bad case in LoadBaseIndexed";
633 }
634
buzbee2700f7e2014-03-07 09:46:20 -0800635 res = NewLIR3(opcode, r_dest.GetReg(), 0, t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700636 FreeTemp(t_reg);
637 return (first) ? first : res;
638}
639
Goran Jakovljevic10957932015-03-24 18:42:56 +0100640// Store value base base + scaled index.
buzbee2700f7e2014-03-07 09:46:20 -0800641LIR* MipsMir2Lir::StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700642 int scale, OpSize size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700643 LIR *first = NULL;
644 MipsOpCode opcode = kMipsNop;
buzbee2700f7e2014-03-07 09:46:20 -0800645 RegStorage t_reg = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700646
buzbee091cc402014-03-31 10:14:40 -0700647 if (r_src.IsFloat()) {
648 DCHECK(r_src.IsSingle());
buzbeefd698e62014-04-27 19:33:22 -0700649 DCHECK((size == k32) || (size == kSingle) || (size == kReference));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700650 size = kSingle;
651 } else {
652 if (size == kSingle)
buzbee695d13a2014-04-19 13:32:20 -0700653 size = k32;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700654 }
655
Goran Jakovljevic10957932015-03-24 18:42:56 +0100656 MipsOpCode add_opcode = cu_->target64 ? kMips64Daddu : kMipsAddu;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700657 if (!scale) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100658 first = NewLIR3(add_opcode, t_reg.GetReg() , r_base.GetReg(), r_index.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700659 } else {
660 first = OpRegRegImm(kOpLsl, t_reg, r_index, scale);
Goran Jakovljevic10957932015-03-24 18:42:56 +0100661 NewLIR3(add_opcode, t_reg.GetReg() , r_base.GetReg(), t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700662 }
663
664 switch (size) {
665 case kSingle:
666 opcode = kMipsFswc1;
667 break;
buzbee695d13a2014-04-19 13:32:20 -0700668 case k32:
669 case kReference:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700670 opcode = kMipsSw;
671 break;
672 case kUnsignedHalf:
673 case kSignedHalf:
674 opcode = kMipsSh;
675 break;
676 case kUnsignedByte:
677 case kSignedByte:
678 opcode = kMipsSb;
679 break;
680 default:
681 LOG(FATAL) << "Bad case in StoreBaseIndexed";
682 }
buzbee2700f7e2014-03-07 09:46:20 -0800683 NewLIR3(opcode, r_src.GetReg(), 0, t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700684 return first;
685}
686
buzbee2700f7e2014-03-07 09:46:20 -0800687// FIXME: don't split r_dest into 2 containers.
688LIR* MipsMir2Lir::LoadBaseDispBody(RegStorage r_base, int displacement, RegStorage r_dest,
Douglas Leung2db3e262014-06-25 16:02:55 -0700689 OpSize size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700690/*
691 * Load value from base + displacement. Optionally perform null check
692 * on base (which must have an associated s_reg and MIR). If not
693 * performing null check, incoming MIR can be null. IMPORTANT: this
694 * code must not allocate any new temps. If a new register is needed
695 * and base and dest are the same, spill some other register to
696 * rlp and then restore.
697 */
Brian Carlstrom7940e442013-07-12 13:46:57 -0700698 LIR *res;
699 LIR *load = NULL;
700 LIR *load2 = NULL;
701 MipsOpCode opcode = kMipsNop;
702 bool short_form = IS_SIMM16(displacement);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800703 bool is64bit = false;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700704
705 switch (size) {
buzbee695d13a2014-04-19 13:32:20 -0700706 case k64:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700707 case kDouble:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100708 if (cu_->target64) {
709 r_dest = Check64BitReg(r_dest);
710 if (!r_dest.IsFloat()) {
711 opcode = kMips64Ld;
712 } else {
713 opcode = kMipsFldc1;
714 }
715 DCHECK_EQ((displacement & 0x3), 0);
716 break;
717 }
Douglas Leung027f0ff2015-02-27 19:05:03 -0800718 is64bit = true;
719 if (fpuIs32Bit_ && !r_dest.IsPair()) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100720 // Form 64-bit pair.
Douglas Leung2db3e262014-06-25 16:02:55 -0700721 r_dest = Solo64ToPair64(r_dest);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700722 }
723 short_form = IS_SIMM16_2WORD(displacement);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800724 FALLTHROUGH_INTENDED;
buzbee695d13a2014-04-19 13:32:20 -0700725 case k32:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700726 case kSingle:
buzbee695d13a2014-04-19 13:32:20 -0700727 case kReference:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700728 opcode = kMipsLw;
buzbee091cc402014-03-31 10:14:40 -0700729 if (r_dest.IsFloat()) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700730 opcode = kMipsFlwc1;
Douglas Leung027f0ff2015-02-27 19:05:03 -0800731 if (!is64bit) {
732 DCHECK(r_dest.IsSingle());
733 } else {
734 DCHECK(r_dest.IsDouble());
735 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700736 }
737 DCHECK_EQ((displacement & 0x3), 0);
738 break;
739 case kUnsignedHalf:
740 opcode = kMipsLhu;
741 DCHECK_EQ((displacement & 0x1), 0);
742 break;
743 case kSignedHalf:
744 opcode = kMipsLh;
745 DCHECK_EQ((displacement & 0x1), 0);
746 break;
747 case kUnsignedByte:
748 opcode = kMipsLbu;
749 break;
750 case kSignedByte:
751 opcode = kMipsLb;
752 break;
753 default:
754 LOG(FATAL) << "Bad case in LoadBaseIndexedBody";
755 }
756
Goran Jakovljevic10957932015-03-24 18:42:56 +0100757 if (cu_->target64) {
758 if (short_form) {
759 load = res = NewLIR3(opcode, r_dest.GetReg(), displacement, r_base.GetReg());
760 } else {
761 RegStorage r_tmp = (r_base == r_dest) ? AllocTemp() : r_dest;
762 res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement);
763 load = NewLIR3(opcode, r_dest.GetReg(), 0, r_tmp.GetReg());
764 if (r_tmp != r_dest)
765 FreeTemp(r_tmp);
766 }
767
768 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
769 DCHECK_EQ(r_base, TargetPtrReg(kSp));
770 AnnotateDalvikRegAccess(load, displacement >> 2, true /* is_load */, r_dest.Is64Bit());
771 }
772 return res;
773 }
774
Brian Carlstrom7940e442013-07-12 13:46:57 -0700775 if (short_form) {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800776 if (!is64bit) {
buzbee2700f7e2014-03-07 09:46:20 -0800777 load = res = NewLIR3(opcode, r_dest.GetReg(), displacement, r_base.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700778 } else {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800779 if (fpuIs32Bit_ || !r_dest.IsFloat()) {
780 DCHECK(r_dest.IsPair());
Goran Jakovljevic10957932015-03-24 18:42:56 +0100781 load = res = NewLIR3(opcode, r_dest.GetLowReg(), displacement + LOWORD_OFFSET,
782 r_base.GetReg());
Douglas Leung027f0ff2015-02-27 19:05:03 -0800783 load2 = NewLIR3(opcode, r_dest.GetHighReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
784 } else {
785 // Here if 64bit fpu and r_dest is a 64bit fp register.
786 RegStorage r_tmp = AllocTemp();
787 // FIXME: why is r_dest a 64BitPair here???
788 r_dest = Fp64ToSolo32(r_dest);
Goran Jakovljevic10957932015-03-24 18:42:56 +0100789 load = res = NewLIR3(kMipsFlwc1, r_dest.GetReg(), displacement + LOWORD_OFFSET,
790 r_base.GetReg());
Douglas Leung027f0ff2015-02-27 19:05:03 -0800791 load2 = NewLIR3(kMipsLw, r_tmp.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
792 NewLIR2(kMipsMthc1, r_tmp.GetReg(), r_dest.GetReg());
793 FreeTemp(r_tmp);
794 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700795 }
796 } else {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800797 if (!is64bit) {
798 RegStorage r_tmp = (r_base == r_dest || r_dest.IsFloat()) ? AllocTemp() : r_dest;
buzbee2700f7e2014-03-07 09:46:20 -0800799 res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement);
800 load = NewLIR3(opcode, r_dest.GetReg(), 0, r_tmp.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700801 if (r_tmp != r_dest)
802 FreeTemp(r_tmp);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800803 } else {
804 RegStorage r_tmp = AllocTemp();
805 res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement);
806 if (fpuIs32Bit_ || !r_dest.IsFloat()) {
807 DCHECK(r_dest.IsPair());
808 load = NewLIR3(opcode, r_dest.GetLowReg(), LOWORD_OFFSET, r_tmp.GetReg());
809 load2 = NewLIR3(opcode, r_dest.GetHighReg(), HIWORD_OFFSET, r_tmp.GetReg());
810 } else {
811 // Here if 64bit fpu and r_dest is a 64bit fp register
812 r_dest = Fp64ToSolo32(r_dest);
813 load = res = NewLIR3(kMipsFlwc1, r_dest.GetReg(), LOWORD_OFFSET, r_tmp.GetReg());
814 load2 = NewLIR3(kMipsLw, r_tmp.GetReg(), HIWORD_OFFSET, r_tmp.GetReg());
815 NewLIR2(kMipsMthc1, r_tmp.GetReg(), r_dest.GetReg());
816 }
817 FreeTemp(r_tmp);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700818 }
819 }
820
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100821 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100822 DCHECK_EQ(r_base, TargetPtrReg(kSp));
Douglas Leung027f0ff2015-02-27 19:05:03 -0800823 AnnotateDalvikRegAccess(load, (displacement + (is64bit ? LOWORD_OFFSET : 0)) >> 2,
824 true /* is_load */, is64bit /* is64bit */);
825 if (is64bit) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700826 AnnotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2,
Douglas Leung027f0ff2015-02-27 19:05:03 -0800827 true /* is_load */, is64bit /* is64bit */);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700828 }
829 }
Goran Jakovljevic10957932015-03-24 18:42:56 +0100830 return res;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700831}
832
Goran Jakovljevic10957932015-03-24 18:42:56 +0100833LIR* MipsMir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest, OpSize size,
834 VolatileKind is_volatile) {
835 if (UNLIKELY(is_volatile == kVolatile && (size == k64 || size == kDouble))
836 && (!cu_->target64 || displacement & 0x7)) {
837 // TODO: use lld/scd instructions for Mips64.
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700838 // Do atomic 64-bit load.
839 return GenAtomic64Load(r_base, displacement, r_dest);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000840 }
841
buzbee695d13a2014-04-19 13:32:20 -0700842 // TODO: base this on target.
843 if (size == kWord) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100844 size = cu_->target64 ? k64 : k32;
buzbee695d13a2014-04-19 13:32:20 -0700845 }
Andreas Gampe3c12c512014-06-24 18:46:29 +0000846 LIR* load;
Douglas Leung2db3e262014-06-25 16:02:55 -0700847 load = LoadBaseDispBody(r_base, displacement, r_dest, size);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000848
849 if (UNLIKELY(is_volatile == kVolatile)) {
Hans Boehm48f5c472014-06-27 14:50:10 -0700850 GenMemBarrier(kLoadAny);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000851 }
852
853 return load;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700854}
855
Vladimir Marko455759b2014-05-06 20:49:36 +0100856// FIXME: don't split r_dest into 2 containers.
Goran Jakovljevic10957932015-03-24 18:42:56 +0100857LIR* MipsMir2Lir::StoreBaseDispBody(RegStorage r_base, int displacement, RegStorage r_src,
858 OpSize size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700859 LIR *res;
860 LIR *store = NULL;
861 LIR *store2 = NULL;
862 MipsOpCode opcode = kMipsNop;
863 bool short_form = IS_SIMM16(displacement);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800864 bool is64bit = false;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700865
866 switch (size) {
buzbee695d13a2014-04-19 13:32:20 -0700867 case k64:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700868 case kDouble:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100869 if (cu_->target64) {
870 r_src = Check64BitReg(r_src);
871 if (!r_src.IsFloat()) {
872 opcode = kMips64Sd;
873 } else {
874 opcode = kMipsFsdc1;
875 }
876 DCHECK_EQ((displacement & 0x3), 0);
877 break;
878 }
Douglas Leung027f0ff2015-02-27 19:05:03 -0800879 is64bit = true;
880 if (fpuIs32Bit_ && !r_src.IsPair()) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100881 // Form 64-bit pair.
Douglas Leung2db3e262014-06-25 16:02:55 -0700882 r_src = Solo64ToPair64(r_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700883 }
884 short_form = IS_SIMM16_2WORD(displacement);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800885 FALLTHROUGH_INTENDED;
buzbee695d13a2014-04-19 13:32:20 -0700886 case k32:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700887 case kSingle:
buzbee695d13a2014-04-19 13:32:20 -0700888 case kReference:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700889 opcode = kMipsSw;
buzbee091cc402014-03-31 10:14:40 -0700890 if (r_src.IsFloat()) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700891 opcode = kMipsFswc1;
Douglas Leung027f0ff2015-02-27 19:05:03 -0800892 if (!is64bit) {
893 DCHECK(r_src.IsSingle());
894 } else {
895 DCHECK(r_src.IsDouble());
896 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700897 }
898 DCHECK_EQ((displacement & 0x3), 0);
899 break;
900 case kUnsignedHalf:
901 case kSignedHalf:
902 opcode = kMipsSh;
903 DCHECK_EQ((displacement & 0x1), 0);
904 break;
905 case kUnsignedByte:
906 case kSignedByte:
907 opcode = kMipsSb;
908 break;
909 default:
buzbee2700f7e2014-03-07 09:46:20 -0800910 LOG(FATAL) << "Bad case in StoreBaseDispBody";
Brian Carlstrom7940e442013-07-12 13:46:57 -0700911 }
912
Goran Jakovljevic10957932015-03-24 18:42:56 +0100913 if (cu_->target64) {
914 if (short_form) {
915 store = res = NewLIR3(opcode, r_src.GetReg(), displacement, r_base.GetReg());
916 } else {
917 RegStorage r_scratch = AllocTemp();
918 res = OpRegRegImm(kOpAdd, r_scratch, r_base, displacement);
919 store = NewLIR3(opcode, r_src.GetReg(), 0, r_scratch.GetReg());
920 FreeTemp(r_scratch);
921 }
922
923 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
924 DCHECK_EQ(r_base, TargetPtrReg(kSp));
925 AnnotateDalvikRegAccess(store, displacement >> 2, false /* is_load */, r_src.Is64Bit());
926 }
927 return res;
928 }
929
Brian Carlstrom7940e442013-07-12 13:46:57 -0700930 if (short_form) {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800931 if (!is64bit) {
buzbee2700f7e2014-03-07 09:46:20 -0800932 store = res = NewLIR3(opcode, r_src.GetReg(), displacement, r_base.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700933 } else {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800934 if (fpuIs32Bit_ || !r_src.IsFloat()) {
935 DCHECK(r_src.IsPair());
Goran Jakovljevic10957932015-03-24 18:42:56 +0100936 store = res = NewLIR3(opcode, r_src.GetLowReg(), displacement + LOWORD_OFFSET,
937 r_base.GetReg());
Douglas Leung027f0ff2015-02-27 19:05:03 -0800938 store2 = NewLIR3(opcode, r_src.GetHighReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
939 } else {
940 // Here if 64bit fpu and r_src is a 64bit fp register
941 RegStorage r_tmp = AllocTemp();
942 r_src = Fp64ToSolo32(r_src);
Goran Jakovljevic10957932015-03-24 18:42:56 +0100943 store = res = NewLIR3(kMipsFswc1, r_src.GetReg(), displacement + LOWORD_OFFSET,
944 r_base.GetReg());
Douglas Leung027f0ff2015-02-27 19:05:03 -0800945 NewLIR2(kMipsMfhc1, r_tmp.GetReg(), r_src.GetReg());
946 store2 = NewLIR3(kMipsSw, r_tmp.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
947 FreeTemp(r_tmp);
948 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700949 }
950 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800951 RegStorage r_scratch = AllocTemp();
952 res = OpRegRegImm(kOpAdd, r_scratch, r_base, displacement);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800953 if (!is64bit) {
buzbee2700f7e2014-03-07 09:46:20 -0800954 store = NewLIR3(opcode, r_src.GetReg(), 0, r_scratch.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700955 } else {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800956 if (fpuIs32Bit_ || !r_src.IsFloat()) {
957 DCHECK(r_src.IsPair());
958 store = NewLIR3(opcode, r_src.GetLowReg(), LOWORD_OFFSET, r_scratch.GetReg());
959 store2 = NewLIR3(opcode, r_src.GetHighReg(), HIWORD_OFFSET, r_scratch.GetReg());
960 } else {
961 // Here if 64bit fpu and r_src is a 64bit fp register
962 RegStorage r_tmp = AllocTemp();
963 r_src = Fp64ToSolo32(r_src);
964 store = NewLIR3(kMipsFswc1, r_src.GetReg(), LOWORD_OFFSET, r_scratch.GetReg());
965 NewLIR2(kMipsMfhc1, r_tmp.GetReg(), r_src.GetReg());
966 store2 = NewLIR3(kMipsSw, r_tmp.GetReg(), HIWORD_OFFSET, r_scratch.GetReg());
967 FreeTemp(r_tmp);
968 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700969 }
970 FreeTemp(r_scratch);
971 }
972
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100973 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100974 DCHECK_EQ(r_base, TargetPtrReg(kSp));
Douglas Leung027f0ff2015-02-27 19:05:03 -0800975 AnnotateDalvikRegAccess(store, (displacement + (is64bit ? LOWORD_OFFSET : 0)) >> 2,
976 false /* is_load */, is64bit /* is64bit */);
977 if (is64bit) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700978 AnnotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2,
Douglas Leung027f0ff2015-02-27 19:05:03 -0800979 false /* is_load */, is64bit /* is64bit */);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700980 }
981 }
982
983 return res;
984}
985
Goran Jakovljevic10957932015-03-24 18:42:56 +0100986LIR* MipsMir2Lir::StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src, OpSize size,
987 VolatileKind is_volatile) {
Andreas Gampe3c12c512014-06-24 18:46:29 +0000988 if (is_volatile == kVolatile) {
Hans Boehm48f5c472014-06-27 14:50:10 -0700989 // Ensure that prior accesses become visible to other threads first.
990 GenMemBarrier(kAnyStore);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000991 }
992
Andreas Gampe3c12c512014-06-24 18:46:29 +0000993 LIR* store;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100994 if (UNLIKELY(is_volatile == kVolatile && (size == k64 || size == kDouble) &&
995 (!cu_->target64 || displacement & 0x7))) {
996 // TODO: use lld/scd instructions for Mips64.
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700997 // Do atomic 64-bit load.
998 store = GenAtomic64Store(r_base, displacement, r_src);
999 } else {
1000 // TODO: base this on target.
1001 if (size == kWord) {
Goran Jakovljevic10957932015-03-24 18:42:56 +01001002 size = cu_->target64 ? k64 : k32;
Douglas Leungd9cb8ae2014-07-09 14:28:35 -07001003 }
1004 store = StoreBaseDispBody(r_base, displacement, r_src, size);
1005 }
Andreas Gampe3c12c512014-06-24 18:46:29 +00001006
1007 if (UNLIKELY(is_volatile == kVolatile)) {
Hans Boehm48f5c472014-06-27 14:50:10 -07001008 // Preserve order with respect to any subsequent volatile loads.
1009 // We need StoreLoad, but that generally requires the most expensive barrier.
1010 GenMemBarrier(kAnyAny);
Andreas Gampe3c12c512014-06-24 18:46:29 +00001011 }
1012
1013 return store;
Brian Carlstrom7940e442013-07-12 13:46:57 -07001014}
1015
buzbee2700f7e2014-03-07 09:46:20 -08001016LIR* MipsMir2Lir::OpMem(OpKind op, RegStorage r_base, int disp) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001017 UNUSED(op, r_base, disp);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001018 LOG(FATAL) << "Unexpected use of OpMem for MIPS";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001019 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -07001020}
1021
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001022LIR* MipsMir2Lir::OpCondBranch(ConditionCode cc, LIR* target) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001023 UNUSED(cc, target);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001024 LOG(FATAL) << "Unexpected use of OpCondBranch for MIPS";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001025 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -07001026}
1027
Andreas Gampe98430592014-07-27 19:44:50 -07001028LIR* MipsMir2Lir::InvokeTrampoline(OpKind op, RegStorage r_tgt, QuickEntrypointEnum trampoline) {
Goran Jakovljevic10957932015-03-24 18:42:56 +01001029 if (!cu_->target64 && IsDirectEntrypoint(trampoline)) {
Nikola Veljkovic2d873b62015-02-20 17:21:15 +01001030 // Reserve argument space on stack (for $a0-$a3) for
1031 // entrypoints that directly reference native implementations.
1032 // This is not safe in general, as it violates the frame size
1033 // of the Quick method, but it is used here only for calling
1034 // native functions, outside of the runtime.
1035 OpRegImm(kOpSub, rs_rSP, 16);
1036 LIR* retVal = OpReg(op, r_tgt);
1037 OpRegImm(kOpAdd, rs_rSP, 16);
1038 return retVal;
1039 }
1040
Andreas Gampe98430592014-07-27 19:44:50 -07001041 return OpReg(op, r_tgt);
1042}
1043
Goran Jakovljevic10957932015-03-24 18:42:56 +01001044RegStorage MipsMir2Lir::AllocPtrSizeTemp(bool required) {
1045 return cu_->target64 ? AllocTempWide(required) : AllocTemp(required);
1046}
1047
Brian Carlstrom7940e442013-07-12 13:46:57 -07001048} // namespace art