blob: 372fe2b599feab190f49c826bc27d1a495604329 [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"
Douglas Leung22bb5a22015-07-02 16:42:08 -070024#include "dex/mir_graph.h"
Andreas Gampe0b9203e2015-01-22 20:39:27 -080025#include "driver/compiler_driver.h"
Douglas Leung22bb5a22015-07-02 16:42:08 -070026#include "driver/compiler_options.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070027#include "mips_lir.h"
28
29namespace art {
30
Goran Jakovljevic10957932015-03-24 18:42:56 +010031/* This file contains codegen for the Mips ISA */
buzbee2700f7e2014-03-07 09:46:20 -080032LIR* MipsMir2Lir::OpFpRegCopy(RegStorage r_dest, RegStorage r_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070033 int opcode;
Goran Jakovljevic10957932015-03-24 18:42:56 +010034 if (cu_->target64) {
35 DCHECK_EQ(r_dest.Is64Bit(), r_src.Is64Bit());
36 if (r_dest.Is64Bit()) {
37 if (r_dest.IsDouble()) {
38 if (r_src.IsDouble()) {
39 opcode = kMipsFmovd;
40 } else {
41 // Note the operands are swapped for the dmtc1 instr.
42 RegStorage t_opnd = r_src;
43 r_src = r_dest;
44 r_dest = t_opnd;
45 opcode = kMips64Dmtc1;
46 }
Brian Carlstrom7940e442013-07-12 13:46:57 -070047 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +010048 DCHECK(r_src.IsDouble());
49 opcode = kMips64Dmfc1;
Brian Carlstrom7940e442013-07-12 13:46:57 -070050 }
51 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +010052 if (r_dest.IsSingle()) {
53 if (r_src.IsSingle()) {
54 opcode = kMipsFmovs;
55 } else {
56 // Note the operands are swapped for the mtc1 instr.
57 RegStorage t_opnd = r_src;
58 r_src = r_dest;
59 r_dest = t_opnd;
60 opcode = kMipsMtc1;
61 }
62 } else {
63 DCHECK(r_src.IsSingle());
64 opcode = kMipsMfc1;
65 }
66 }
67 } else {
68 // Must be both DOUBLE or both not DOUBLE.
69 DCHECK_EQ(r_dest.IsDouble(), r_src.IsDouble());
70 if (r_dest.IsDouble()) {
71 opcode = kMipsFmovd;
72 } else {
73 if (r_dest.IsSingle()) {
74 if (r_src.IsSingle()) {
75 opcode = kMipsFmovs;
76 } else {
77 // Note the operands are swapped for the mtc1 instr.
78 RegStorage t_opnd = r_src;
79 r_src = r_dest;
80 r_dest = t_opnd;
81 opcode = kMipsMtc1;
82 }
83 } else {
84 DCHECK(r_src.IsSingle());
85 opcode = kMipsMfc1;
86 }
Brian Carlstrom7940e442013-07-12 13:46:57 -070087 }
88 }
Goran Jakovljevic10957932015-03-24 18:42:56 +010089 LIR* res;
90 if (cu_->target64) {
91 res = RawLIR(current_dalvik_offset_, opcode, r_dest.GetReg(), r_src.GetReg());
92 } else {
93 res = RawLIR(current_dalvik_offset_, opcode, r_src.GetReg(), r_dest.GetReg());
94 }
Brian Carlstrom7940e442013-07-12 13:46:57 -070095 if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
96 res->flags.is_nop = true;
97 }
98 return res;
99}
100
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700101bool MipsMir2Lir::InexpensiveConstantInt(int32_t value) {
Andreas Gampeab1eb0d2015-02-13 19:23:55 -0800102 // For encodings, see LoadConstantNoClobber below.
103 return ((value == 0) || IsUint<16>(value) || IsInt<16>(value));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700104}
105
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100106bool MipsMir2Lir::InexpensiveConstantFloat(int32_t value ATTRIBUTE_UNUSED) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700107 return false; // TUNING
108}
109
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100110bool MipsMir2Lir::InexpensiveConstantLong(int64_t value ATTRIBUTE_UNUSED) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700111 return false; // TUNING
112}
113
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100114bool MipsMir2Lir::InexpensiveConstantDouble(int64_t value ATTRIBUTE_UNUSED) {
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700115 return false; // TUNING
Brian Carlstrom7940e442013-07-12 13:46:57 -0700116}
117
118/*
119 * Load a immediate using a shortcut if possible; otherwise
120 * grab from the per-translation literal pool. If target is
121 * a high register, build constant into a low register and copy.
122 *
123 * No additional register clobbering operation performed. Use this version when
124 * 1) r_dest is freshly returned from AllocTemp or
125 * 2) The codegen is under fixed register usage
126 */
buzbee2700f7e2014-03-07 09:46:20 -0800127LIR* MipsMir2Lir::LoadConstantNoClobber(RegStorage r_dest, int value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700128 LIR *res;
129
buzbee2700f7e2014-03-07 09:46:20 -0800130 RegStorage r_dest_save = r_dest;
buzbee091cc402014-03-31 10:14:40 -0700131 int is_fp_reg = r_dest.IsFloat();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700132 if (is_fp_reg) {
buzbee091cc402014-03-31 10:14:40 -0700133 DCHECK(r_dest.IsSingle());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700134 r_dest = AllocTemp();
135 }
136
Goran Jakovljevic10957932015-03-24 18:42:56 +0100137 // See if the value can be constructed cheaply.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700138 if (value == 0) {
buzbee2700f7e2014-03-07 09:46:20 -0800139 res = NewLIR2(kMipsMove, r_dest.GetReg(), rZERO);
Andreas Gampeab1eb0d2015-02-13 19:23:55 -0800140 } else if (IsUint<16>(value)) {
141 // Use OR with (unsigned) immediate to encode 16b unsigned int.
buzbee2700f7e2014-03-07 09:46:20 -0800142 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZERO, value);
Andreas Gampeab1eb0d2015-02-13 19:23:55 -0800143 } else if (IsInt<16>(value)) {
144 // Use ADD with (signed) immediate to encode 16b signed int.
buzbee2700f7e2014-03-07 09:46:20 -0800145 res = NewLIR3(kMipsAddiu, r_dest.GetReg(), rZERO, value);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700146 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800147 res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700148 if (value & 0xffff)
buzbee2700f7e2014-03-07 09:46:20 -0800149 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), value);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700150 }
151
152 if (is_fp_reg) {
buzbee2700f7e2014-03-07 09:46:20 -0800153 NewLIR2(kMipsMtc1, r_dest.GetReg(), r_dest_save.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700154 FreeTemp(r_dest);
155 }
156
157 return res;
158}
159
Goran Jakovljevic10957932015-03-24 18:42:56 +0100160LIR* MipsMir2Lir::LoadConstantWideNoClobber(RegStorage r_dest, int64_t value) {
161 LIR* res = nullptr;
162 DCHECK(r_dest.Is64Bit());
163 RegStorage r_dest_save = r_dest;
164 int is_fp_reg = r_dest.IsFloat();
165 if (is_fp_reg) {
166 DCHECK(r_dest.IsDouble());
167 r_dest = AllocTemp();
168 }
169
170 int bit31 = (value & UINT64_C(0x80000000)) != 0;
171
172 // Loads with 1 instruction.
173 if (IsUint<16>(value)) {
174 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, value);
175 } else if (IsInt<16>(value)) {
176 res = NewLIR3(kMips64Daddiu, r_dest.GetReg(), rZEROd, value);
177 } else if ((value & 0xFFFF) == 0 && IsInt<16>(value >> 16)) {
178 res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
179 } else if (IsInt<32>(value)) {
180 // Loads with 2 instructions.
181 res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
182 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), value);
183 } else if ((value & 0xFFFF0000) == 0 && IsInt<16>(value >> 32)) {
184 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, value);
185 NewLIR2(kMips64Dahi, r_dest.GetReg(), value >> 32);
186 } else if ((value & UINT64_C(0xFFFFFFFF0000)) == 0) {
187 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, value);
188 NewLIR2(kMips64Dati, r_dest.GetReg(), value >> 48);
189 } else if ((value & 0xFFFF) == 0 && (value >> 32) >= (-32768 - bit31) &&
190 (value >> 32) <= (32767 - bit31)) {
191 res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
192 NewLIR2(kMips64Dahi, r_dest.GetReg(), (value >> 32) + bit31);
193 } else if ((value & 0xFFFF) == 0 && ((value >> 31) & 0x1FFFF) == ((0x20000 - bit31) & 0x1FFFF)) {
194 res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
195 NewLIR2(kMips64Dati, r_dest.GetReg(), (value >> 48) + bit31);
196 } else {
197 int64_t tmp = value;
198 int shift_cnt = 0;
199 while ((tmp & 1) == 0) {
200 tmp >>= 1;
201 shift_cnt++;
202 }
203
204 if (IsUint<16>(tmp)) {
205 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, tmp);
206 NewLIR3((shift_cnt < 32) ? kMips64Dsll : kMips64Dsll32, r_dest.GetReg(), r_dest.GetReg(),
207 shift_cnt & 0x1F);
208 } else if (IsInt<16>(tmp)) {
209 res = NewLIR3(kMips64Daddiu, r_dest.GetReg(), rZEROd, tmp);
210 NewLIR3((shift_cnt < 32) ? kMips64Dsll : kMips64Dsll32, r_dest.GetReg(), r_dest.GetReg(),
211 shift_cnt & 0x1F);
212 } else if (IsInt<32>(tmp)) {
213 // Loads with 3 instructions.
214 res = NewLIR2(kMipsLui, r_dest.GetReg(), tmp >> 16);
215 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), tmp);
216 NewLIR3((shift_cnt < 32) ? kMips64Dsll : kMips64Dsll32, r_dest.GetReg(), r_dest.GetReg(),
217 shift_cnt & 0x1F);
218 } else {
219 tmp = value >> 16;
220 shift_cnt = 16;
221 while ((tmp & 1) == 0) {
222 tmp >>= 1;
223 shift_cnt++;
224 }
225
226 if (IsUint<16>(tmp)) {
227 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, tmp);
228 NewLIR3((shift_cnt < 32) ? kMips64Dsll : kMips64Dsll32, r_dest.GetReg(), r_dest.GetReg(),
229 shift_cnt & 0x1F);
230 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), value);
231 } else if (IsInt<16>(tmp)) {
232 res = NewLIR3(kMips64Daddiu, r_dest.GetReg(), rZEROd, tmp);
233 NewLIR3((shift_cnt < 32) ? kMips64Dsll : kMips64Dsll32, r_dest.GetReg(), r_dest.GetReg(),
234 shift_cnt & 0x1F);
235 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), value);
236 } else {
237 // Loads with 3-4 instructions.
238 uint64_t tmp2 = value;
239 if (((tmp2 >> 16) & 0xFFFF) != 0 || (tmp2 & 0xFFFFFFFF) == 0) {
240 res = NewLIR2(kMipsLui, r_dest.GetReg(), tmp2 >> 16);
241 }
242 if ((tmp2 & 0xFFFF) != 0) {
243 if (res)
244 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), tmp2);
245 else
246 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, tmp2);
247 }
248 if (bit31) {
249 tmp2 += UINT64_C(0x100000000);
250 }
251 if (((tmp2 >> 32) & 0xFFFF) != 0) {
252 NewLIR2(kMips64Dahi, r_dest.GetReg(), tmp2 >> 32);
253 }
254 if (tmp2 & UINT64_C(0x800000000000)) {
255 tmp2 += UINT64_C(0x1000000000000);
256 }
257 if ((tmp2 >> 48) != 0) {
258 NewLIR2(kMips64Dati, r_dest.GetReg(), tmp2 >> 48);
259 }
260 }
261 }
262 }
263
264 if (is_fp_reg) {
265 NewLIR2(kMips64Dmtc1, r_dest.GetReg(), r_dest_save.GetReg());
266 FreeTemp(r_dest);
267 }
268 return res;
269}
270
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700271LIR* MipsMir2Lir::OpUnconditionalBranch(LIR* target) {
Brian Carlstromdf629502013-07-17 22:39:56 -0700272 LIR* res = NewLIR1(kMipsB, 0 /* offset to be patched during assembly*/);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700273 res->target = target;
274 return res;
275}
276
buzbee2700f7e2014-03-07 09:46:20 -0800277LIR* MipsMir2Lir::OpReg(OpKind op, RegStorage r_dest_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700278 MipsOpCode opcode = kMipsNop;
279 switch (op) {
280 case kOpBlx:
281 opcode = kMipsJalr;
282 break;
283 case kOpBx:
Andreas Gampe8d365912015-01-13 11:32:32 -0800284 return NewLIR2(kMipsJalr, rZERO, r_dest_src.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700285 default:
286 LOG(FATAL) << "Bad case in OpReg";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700287 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700288 }
Goran Jakovljevic10957932015-03-24 18:42:56 +0100289 return NewLIR2(opcode, cu_->target64 ? rRAd : rRA, r_dest_src.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700290}
291
buzbee2700f7e2014-03-07 09:46:20 -0800292LIR* MipsMir2Lir::OpRegImm(OpKind op, RegStorage r_dest_src1, int value) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100293 if ((op == kOpAdd) || (op == kOpSub)) {
294 return OpRegRegImm(op, r_dest_src1, r_dest_src1, value);
Brian Carlstrom9b7085a2013-07-18 15:15:21 -0700295 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100296 LOG(FATAL) << "Bad case in OpRegImm";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700297 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700298 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700299}
300
buzbee2700f7e2014-03-07 09:46:20 -0800301LIR* MipsMir2Lir::OpRegRegReg(OpKind op, RegStorage r_dest, RegStorage r_src1, RegStorage r_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700302 MipsOpCode opcode = kMipsNop;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100303 bool is64bit = cu_->target64 && (r_dest.Is64Bit() || r_src1.Is64Bit() || r_src2.Is64Bit());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700304 switch (op) {
305 case kOpAdd:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100306 opcode = is64bit ? kMips64Daddu : kMipsAddu;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700307 break;
308 case kOpSub:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100309 opcode = is64bit ? kMips64Dsubu : kMipsSubu;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700310 break;
311 case kOpAnd:
312 opcode = kMipsAnd;
313 break;
314 case kOpMul:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100315 opcode = isaIsR6_ ? kMipsR6Mul : kMipsR2Mul;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700316 break;
317 case kOpOr:
318 opcode = kMipsOr;
319 break;
320 case kOpXor:
321 opcode = kMipsXor;
322 break;
323 case kOpLsl:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100324 opcode = is64bit ? kMips64Dsllv : kMipsSllv;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700325 break;
326 case kOpLsr:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100327 opcode = is64bit ? kMips64Dsrlv : kMipsSrlv;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700328 break;
329 case kOpAsr:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100330 opcode = is64bit ? kMips64Dsrav : kMipsSrav;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700331 break;
332 case kOpAdc:
333 case kOpSbc:
334 LOG(FATAL) << "No carry bit on MIPS";
335 break;
336 default:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100337 LOG(FATAL) << "Bad case in OpRegRegReg";
Brian Carlstrom7940e442013-07-12 13:46:57 -0700338 break;
339 }
buzbee2700f7e2014-03-07 09:46:20 -0800340 return NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), r_src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700341}
342
buzbee2700f7e2014-03-07 09:46:20 -0800343LIR* MipsMir2Lir::OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src1, int value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700344 LIR *res;
345 MipsOpCode opcode = kMipsNop;
346 bool short_form = true;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100347 bool is64bit = cu_->target64 && (r_dest.Is64Bit() || r_src1.Is64Bit());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700348
349 switch (op) {
350 case kOpAdd:
351 if (IS_SIMM16(value)) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100352 opcode = is64bit ? kMips64Daddiu : kMipsAddiu;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700353 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700354 short_form = false;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100355 opcode = is64bit ? kMips64Daddu : kMipsAddu;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700356 }
357 break;
358 case kOpSub:
359 if (IS_SIMM16((-value))) {
360 value = -value;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100361 opcode = is64bit ? kMips64Daddiu : kMipsAddiu;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700362 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700363 short_form = false;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100364 opcode = is64bit ? kMips64Dsubu : kMipsSubu;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700365 }
366 break;
367 case kOpLsl:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100368 if (is64bit) {
369 DCHECK(value >= 0 && value <= 63);
370 if (value >= 0 && value <= 31) {
371 opcode = kMips64Dsll;
372 } else {
373 opcode = kMips64Dsll32;
374 value = value - 32;
375 }
376 } else {
377 DCHECK(value >= 0 && value <= 31);
378 opcode = kMipsSll;
379 }
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800380 break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700381 case kOpLsr:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100382 if (is64bit) {
383 DCHECK(value >= 0 && value <= 63);
384 if (value >= 0 && value <= 31) {
385 opcode = kMips64Dsrl;
386 } else {
387 opcode = kMips64Dsrl32;
388 value = value - 32;
389 }
390 } else {
391 DCHECK(value >= 0 && value <= 31);
392 opcode = kMipsSrl;
393 }
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800394 break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700395 case kOpAsr:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100396 if (is64bit) {
397 DCHECK(value >= 0 && value <= 63);
398 if (value >= 0 && value <= 31) {
399 opcode = kMips64Dsra;
400 } else {
401 opcode = kMips64Dsra32;
402 value = value - 32;
403 }
404 } else {
405 DCHECK(value >= 0 && value <= 31);
406 opcode = kMipsSra;
407 }
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800408 break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700409 case kOpAnd:
410 if (IS_UIMM16((value))) {
411 opcode = kMipsAndi;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700412 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700413 short_form = false;
414 opcode = kMipsAnd;
415 }
416 break;
417 case kOpOr:
418 if (IS_UIMM16((value))) {
419 opcode = kMipsOri;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700420 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700421 short_form = false;
422 opcode = kMipsOr;
423 }
424 break;
425 case kOpXor:
426 if (IS_UIMM16((value))) {
427 opcode = kMipsXori;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700428 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700429 short_form = false;
430 opcode = kMipsXor;
431 }
432 break;
433 case kOpMul:
434 short_form = false;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100435 opcode = isaIsR6_ ? kMipsR6Mul : kMipsR2Mul;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700436 break;
437 default:
438 LOG(FATAL) << "Bad case in OpRegRegImm";
439 break;
440 }
441
Brian Carlstrom9b7085a2013-07-18 15:15:21 -0700442 if (short_form) {
buzbee2700f7e2014-03-07 09:46:20 -0800443 res = NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), value);
Brian Carlstrom9b7085a2013-07-18 15:15:21 -0700444 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700445 if (r_dest != r_src1) {
446 res = LoadConstant(r_dest, value);
buzbee2700f7e2014-03-07 09:46:20 -0800447 NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), r_dest.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700448 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100449 RegStorage r_scratch;
450 if (is64bit) {
451 r_scratch = AllocTempWide();
452 res = LoadConstantWide(r_scratch, value);
453 } else {
454 r_scratch = AllocTemp();
455 res = LoadConstant(r_scratch, value);
456 }
buzbee2700f7e2014-03-07 09:46:20 -0800457 NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), r_scratch.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700458 }
459 }
460 return res;
461}
462
buzbee2700f7e2014-03-07 09:46:20 -0800463LIR* MipsMir2Lir::OpRegReg(OpKind op, RegStorage r_dest_src1, RegStorage r_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700464 MipsOpCode opcode = kMipsNop;
465 LIR *res;
466 switch (op) {
467 case kOpMov:
468 opcode = kMipsMove;
469 break;
470 case kOpMvn:
buzbee2700f7e2014-03-07 09:46:20 -0800471 return NewLIR3(kMipsNor, r_dest_src1.GetReg(), r_src2.GetReg(), rZERO);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700472 case kOpNeg:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100473 if (cu_->target64 && r_dest_src1.Is64Bit()) {
474 return NewLIR3(kMips64Dsubu, r_dest_src1.GetReg(), rZEROd, r_src2.GetReg());
475 } else {
476 return NewLIR3(kMipsSubu, r_dest_src1.GetReg(), rZERO, r_src2.GetReg());
477 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700478 case kOpAdd:
479 case kOpAnd:
480 case kOpMul:
481 case kOpOr:
482 case kOpSub:
483 case kOpXor:
484 return OpRegRegReg(op, r_dest_src1, r_dest_src1, r_src2);
485 case kOp2Byte:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100486 if (cu_->target64) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800487 res = NewLIR2(kMipsSeb, r_dest_src1.GetReg(), r_src2.GetReg());
488 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100489 if (cu_->compiler_driver->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()
490 ->IsMipsIsaRevGreaterThanEqual2()) {
491 res = NewLIR2(kMipsSeb, r_dest_src1.GetReg(), r_src2.GetReg());
492 } else {
493 res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 24);
494 OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 24);
495 }
Ian Rogersd582fa42014-11-05 23:46:43 -0800496 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700497 return res;
498 case kOp2Short:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100499 if (cu_->target64) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800500 res = NewLIR2(kMipsSeh, r_dest_src1.GetReg(), r_src2.GetReg());
501 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100502 if (cu_->compiler_driver->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()
503 ->IsMipsIsaRevGreaterThanEqual2()) {
504 res = NewLIR2(kMipsSeh, r_dest_src1.GetReg(), r_src2.GetReg());
505 } else {
506 res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 16);
507 OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 16);
508 }
Ian Rogersd582fa42014-11-05 23:46:43 -0800509 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700510 return res;
511 case kOp2Char:
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800512 return NewLIR3(kMipsAndi, r_dest_src1.GetReg(), r_src2.GetReg(), 0xFFFF);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700513 default:
514 LOG(FATAL) << "Bad case in OpRegReg";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700515 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700516 }
buzbee2700f7e2014-03-07 09:46:20 -0800517 return NewLIR2(opcode, r_dest_src1.GetReg(), r_src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700518}
519
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100520LIR* MipsMir2Lir::OpMovRegMem(RegStorage r_dest ATTRIBUTE_UNUSED,
521 RegStorage r_base ATTRIBUTE_UNUSED,
522 int offset ATTRIBUTE_UNUSED,
523 MoveType move_type ATTRIBUTE_UNUSED) {
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
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100528LIR* MipsMir2Lir::OpMovMemReg(RegStorage r_base ATTRIBUTE_UNUSED,
529 int offset ATTRIBUTE_UNUSED,
530 RegStorage r_src ATTRIBUTE_UNUSED,
531 MoveType move_type ATTRIBUTE_UNUSED) {
Razvan A Lupusoru2c498d12014-01-29 16:02:57 -0800532 UNIMPLEMENTED(FATAL);
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700533 UNREACHABLE();
Razvan A Lupusoru2c498d12014-01-29 16:02:57 -0800534}
535
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100536LIR* MipsMir2Lir::OpCondRegReg(OpKind op ATTRIBUTE_UNUSED,
537 ConditionCode cc ATTRIBUTE_UNUSED,
538 RegStorage r_dest ATTRIBUTE_UNUSED,
539 RegStorage r_src ATTRIBUTE_UNUSED) {
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800540 LOG(FATAL) << "Unexpected use of OpCondRegReg for MIPS";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700541 UNREACHABLE();
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800542}
543
buzbee2700f7e2014-03-07 09:46:20 -0800544LIR* MipsMir2Lir::LoadConstantWide(RegStorage r_dest, int64_t value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700545 LIR *res;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100546 if (cu_->target64) {
547 res = LoadConstantWideNoClobber(r_dest, value);
548 return res;
549 }
Douglas Leung027f0ff2015-02-27 19:05:03 -0800550 if (fpuIs32Bit_ || !r_dest.IsFloat()) {
551 // 32bit FPU (pairs) or loading into GPR.
552 if (!r_dest.IsPair()) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100553 // Form 64-bit pair.
Douglas Leung027f0ff2015-02-27 19:05:03 -0800554 r_dest = Solo64ToPair64(r_dest);
555 }
556 res = LoadConstantNoClobber(r_dest.GetLow(), Low32Bits(value));
557 LoadConstantNoClobber(r_dest.GetHigh(), High32Bits(value));
558 } else {
559 // Here if we have a 64bit FPU and loading into FPR.
560 RegStorage r_temp = AllocTemp();
561 r_dest = Fp64ToSolo32(r_dest);
562 res = LoadConstantNoClobber(r_dest, Low32Bits(value));
563 LoadConstantNoClobber(r_temp, High32Bits(value));
564 NewLIR2(kMipsMthc1, r_temp.GetReg(), r_dest.GetReg());
565 FreeTemp(r_temp);
Douglas Leung2db3e262014-06-25 16:02:55 -0700566 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700567 return res;
568}
569
570/* Load value from base + scaled index. */
buzbee2700f7e2014-03-07 09:46:20 -0800571LIR* MipsMir2Lir::LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700572 int scale, OpSize size) {
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700573 LIR *first = nullptr;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700574 LIR *res;
575 MipsOpCode opcode = kMipsNop;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100576 bool is64bit = cu_->target64 && r_dest.Is64Bit();
577 RegStorage t_reg = is64bit ? AllocTempWide() : AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700578
buzbee091cc402014-03-31 10:14:40 -0700579 if (r_dest.IsFloat()) {
580 DCHECK(r_dest.IsSingle());
buzbeefd698e62014-04-27 19:33:22 -0700581 DCHECK((size == k32) || (size == kSingle) || (size == kReference));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700582 size = kSingle;
583 } else {
584 if (size == kSingle)
buzbee695d13a2014-04-19 13:32:20 -0700585 size = k32;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700586 }
587
Goran Jakovljevic10957932015-03-24 18:42:56 +0100588 if (cu_->target64) {
589 if (!scale) {
590 if (is64bit) {
591 first = NewLIR3(kMips64Daddu, t_reg.GetReg() , r_base.GetReg(), r_index.GetReg());
592 } else {
593 first = NewLIR3(kMipsAddu, t_reg.GetReg() , r_base.GetReg(), r_index.GetReg());
594 }
595 } else {
596 first = OpRegRegImm(kOpLsl, t_reg, r_index, scale);
597 NewLIR3(kMips64Daddu, t_reg.GetReg() , r_base.GetReg(), t_reg.GetReg());
598 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700599 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100600 if (!scale) {
601 first = NewLIR3(kMipsAddu, t_reg.GetReg() , r_base.GetReg(), r_index.GetReg());
602 } else {
603 first = OpRegRegImm(kOpLsl, t_reg, r_index, scale);
604 NewLIR3(kMipsAddu, t_reg.GetReg() , r_base.GetReg(), t_reg.GetReg());
605 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700606 }
607
608 switch (size) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100609 case k64:
610 if (cu_->target64) {
611 opcode = kMips64Ld;
612 } else {
613 LOG(FATAL) << "Bad case in LoadBaseIndexed";
614 }
615 break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700616 case kSingle:
617 opcode = kMipsFlwc1;
618 break;
buzbee695d13a2014-04-19 13:32:20 -0700619 case k32:
620 case kReference:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700621 opcode = kMipsLw;
622 break;
623 case kUnsignedHalf:
624 opcode = kMipsLhu;
625 break;
626 case kSignedHalf:
627 opcode = kMipsLh;
628 break;
629 case kUnsignedByte:
630 opcode = kMipsLbu;
631 break;
632 case kSignedByte:
633 opcode = kMipsLb;
634 break;
635 default:
636 LOG(FATAL) << "Bad case in LoadBaseIndexed";
637 }
638
buzbee2700f7e2014-03-07 09:46:20 -0800639 res = NewLIR3(opcode, r_dest.GetReg(), 0, t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700640 FreeTemp(t_reg);
641 return (first) ? first : res;
642}
643
Goran Jakovljevic10957932015-03-24 18:42:56 +0100644// Store value base base + scaled index.
buzbee2700f7e2014-03-07 09:46:20 -0800645LIR* MipsMir2Lir::StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700646 int scale, OpSize size) {
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700647 LIR *first = nullptr;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700648 MipsOpCode opcode = kMipsNop;
buzbee2700f7e2014-03-07 09:46:20 -0800649 RegStorage t_reg = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700650
buzbee091cc402014-03-31 10:14:40 -0700651 if (r_src.IsFloat()) {
652 DCHECK(r_src.IsSingle());
buzbeefd698e62014-04-27 19:33:22 -0700653 DCHECK((size == k32) || (size == kSingle) || (size == kReference));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700654 size = kSingle;
655 } else {
656 if (size == kSingle)
buzbee695d13a2014-04-19 13:32:20 -0700657 size = k32;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700658 }
659
Goran Jakovljevic10957932015-03-24 18:42:56 +0100660 MipsOpCode add_opcode = cu_->target64 ? kMips64Daddu : kMipsAddu;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700661 if (!scale) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100662 first = NewLIR3(add_opcode, t_reg.GetReg() , r_base.GetReg(), r_index.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700663 } else {
664 first = OpRegRegImm(kOpLsl, t_reg, r_index, scale);
Goran Jakovljevic10957932015-03-24 18:42:56 +0100665 NewLIR3(add_opcode, t_reg.GetReg() , r_base.GetReg(), t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700666 }
667
668 switch (size) {
669 case kSingle:
670 opcode = kMipsFswc1;
671 break;
buzbee695d13a2014-04-19 13:32:20 -0700672 case k32:
673 case kReference:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700674 opcode = kMipsSw;
675 break;
676 case kUnsignedHalf:
677 case kSignedHalf:
678 opcode = kMipsSh;
679 break;
680 case kUnsignedByte:
681 case kSignedByte:
682 opcode = kMipsSb;
683 break;
684 default:
685 LOG(FATAL) << "Bad case in StoreBaseIndexed";
686 }
buzbee2700f7e2014-03-07 09:46:20 -0800687 NewLIR3(opcode, r_src.GetReg(), 0, t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700688 return first;
689}
690
buzbee2700f7e2014-03-07 09:46:20 -0800691// FIXME: don't split r_dest into 2 containers.
692LIR* MipsMir2Lir::LoadBaseDispBody(RegStorage r_base, int displacement, RegStorage r_dest,
Douglas Leung2db3e262014-06-25 16:02:55 -0700693 OpSize size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700694/*
695 * Load value from base + displacement. Optionally perform null check
696 * on base (which must have an associated s_reg and MIR). If not
697 * performing null check, incoming MIR can be null. IMPORTANT: this
698 * code must not allocate any new temps. If a new register is needed
699 * and base and dest are the same, spill some other register to
700 * rlp and then restore.
701 */
Brian Carlstrom7940e442013-07-12 13:46:57 -0700702 LIR *res;
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700703 LIR *load = nullptr;
704 LIR *load2 = nullptr;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700705 MipsOpCode opcode = kMipsNop;
706 bool short_form = IS_SIMM16(displacement);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800707 bool is64bit = false;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700708
709 switch (size) {
buzbee695d13a2014-04-19 13:32:20 -0700710 case k64:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700711 case kDouble:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100712 if (cu_->target64) {
713 r_dest = Check64BitReg(r_dest);
714 if (!r_dest.IsFloat()) {
715 opcode = kMips64Ld;
716 } else {
717 opcode = kMipsFldc1;
718 }
Roland Levillain14d90572015-07-16 10:52:26 +0100719 DCHECK_ALIGNED(displacement, 4);
Goran Jakovljevic10957932015-03-24 18:42:56 +0100720 break;
721 }
Douglas Leung027f0ff2015-02-27 19:05:03 -0800722 is64bit = true;
723 if (fpuIs32Bit_ && !r_dest.IsPair()) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100724 // Form 64-bit pair.
Douglas Leung2db3e262014-06-25 16:02:55 -0700725 r_dest = Solo64ToPair64(r_dest);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700726 }
727 short_form = IS_SIMM16_2WORD(displacement);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800728 FALLTHROUGH_INTENDED;
buzbee695d13a2014-04-19 13:32:20 -0700729 case k32:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700730 case kSingle:
buzbee695d13a2014-04-19 13:32:20 -0700731 case kReference:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700732 opcode = kMipsLw;
buzbee091cc402014-03-31 10:14:40 -0700733 if (r_dest.IsFloat()) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700734 opcode = kMipsFlwc1;
Douglas Leung027f0ff2015-02-27 19:05:03 -0800735 if (!is64bit) {
736 DCHECK(r_dest.IsSingle());
737 } else {
738 DCHECK(r_dest.IsDouble());
739 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700740 }
Roland Levillain14d90572015-07-16 10:52:26 +0100741 DCHECK_ALIGNED(displacement, 4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700742 break;
743 case kUnsignedHalf:
744 opcode = kMipsLhu;
Roland Levillain14d90572015-07-16 10:52:26 +0100745 DCHECK_ALIGNED(displacement, 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700746 break;
747 case kSignedHalf:
748 opcode = kMipsLh;
Roland Levillain14d90572015-07-16 10:52:26 +0100749 DCHECK_ALIGNED(displacement, 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700750 break;
751 case kUnsignedByte:
752 opcode = kMipsLbu;
753 break;
754 case kSignedByte:
755 opcode = kMipsLb;
756 break;
757 default:
758 LOG(FATAL) << "Bad case in LoadBaseIndexedBody";
759 }
760
Goran Jakovljevic10957932015-03-24 18:42:56 +0100761 if (cu_->target64) {
762 if (short_form) {
763 load = res = NewLIR3(opcode, r_dest.GetReg(), displacement, r_base.GetReg());
764 } else {
765 RegStorage r_tmp = (r_base == r_dest) ? AllocTemp() : r_dest;
766 res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement);
767 load = NewLIR3(opcode, r_dest.GetReg(), 0, r_tmp.GetReg());
768 if (r_tmp != r_dest)
769 FreeTemp(r_tmp);
770 }
771
772 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
773 DCHECK_EQ(r_base, TargetPtrReg(kSp));
774 AnnotateDalvikRegAccess(load, displacement >> 2, true /* is_load */, r_dest.Is64Bit());
775 }
776 return res;
777 }
778
Brian Carlstrom7940e442013-07-12 13:46:57 -0700779 if (short_form) {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800780 if (!is64bit) {
buzbee2700f7e2014-03-07 09:46:20 -0800781 load = res = NewLIR3(opcode, r_dest.GetReg(), displacement, r_base.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700782 } else {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800783 if (fpuIs32Bit_ || !r_dest.IsFloat()) {
784 DCHECK(r_dest.IsPair());
Goran Jakovljevic10957932015-03-24 18:42:56 +0100785 load = res = NewLIR3(opcode, r_dest.GetLowReg(), displacement + LOWORD_OFFSET,
786 r_base.GetReg());
Douglas Leung027f0ff2015-02-27 19:05:03 -0800787 load2 = NewLIR3(opcode, r_dest.GetHighReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
788 } else {
789 // Here if 64bit fpu and r_dest is a 64bit fp register.
790 RegStorage r_tmp = AllocTemp();
791 // FIXME: why is r_dest a 64BitPair here???
792 r_dest = Fp64ToSolo32(r_dest);
Goran Jakovljevic10957932015-03-24 18:42:56 +0100793 load = res = NewLIR3(kMipsFlwc1, r_dest.GetReg(), displacement + LOWORD_OFFSET,
794 r_base.GetReg());
Douglas Leung027f0ff2015-02-27 19:05:03 -0800795 load2 = NewLIR3(kMipsLw, r_tmp.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
796 NewLIR2(kMipsMthc1, r_tmp.GetReg(), r_dest.GetReg());
797 FreeTemp(r_tmp);
798 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700799 }
800 } else {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800801 if (!is64bit) {
802 RegStorage r_tmp = (r_base == r_dest || r_dest.IsFloat()) ? AllocTemp() : r_dest;
buzbee2700f7e2014-03-07 09:46:20 -0800803 res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement);
804 load = NewLIR3(opcode, r_dest.GetReg(), 0, r_tmp.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700805 if (r_tmp != r_dest)
806 FreeTemp(r_tmp);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800807 } else {
808 RegStorage r_tmp = AllocTemp();
809 res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement);
810 if (fpuIs32Bit_ || !r_dest.IsFloat()) {
811 DCHECK(r_dest.IsPair());
812 load = NewLIR3(opcode, r_dest.GetLowReg(), LOWORD_OFFSET, r_tmp.GetReg());
813 load2 = NewLIR3(opcode, r_dest.GetHighReg(), HIWORD_OFFSET, r_tmp.GetReg());
814 } else {
815 // Here if 64bit fpu and r_dest is a 64bit fp register
816 r_dest = Fp64ToSolo32(r_dest);
817 load = res = NewLIR3(kMipsFlwc1, r_dest.GetReg(), LOWORD_OFFSET, r_tmp.GetReg());
818 load2 = NewLIR3(kMipsLw, r_tmp.GetReg(), HIWORD_OFFSET, r_tmp.GetReg());
819 NewLIR2(kMipsMthc1, r_tmp.GetReg(), r_dest.GetReg());
820 }
821 FreeTemp(r_tmp);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700822 }
823 }
824
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100825 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100826 DCHECK_EQ(r_base, TargetPtrReg(kSp));
Douglas Leung027f0ff2015-02-27 19:05:03 -0800827 AnnotateDalvikRegAccess(load, (displacement + (is64bit ? LOWORD_OFFSET : 0)) >> 2,
828 true /* is_load */, is64bit /* is64bit */);
829 if (is64bit) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700830 AnnotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2,
Douglas Leung027f0ff2015-02-27 19:05:03 -0800831 true /* is_load */, is64bit /* is64bit */);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700832 }
833 }
Goran Jakovljevic10957932015-03-24 18:42:56 +0100834 return res;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700835}
836
Douglas Leung22bb5a22015-07-02 16:42:08 -0700837void MipsMir2Lir::ForceImplicitNullCheck(RegStorage reg, int opt_flags, bool is_wide) {
838 if (cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
839 if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) {
840 return;
841 }
842 // Force an implicit null check by performing a memory operation (load) from the given
843 // register with offset 0. This will cause a signal if the register contains 0 (null).
844 LIR* load = Load32Disp(reg, LOWORD_OFFSET, rs_rZERO);
845 MarkSafepointPC(load);
846 if (is_wide) {
847 load = Load32Disp(reg, HIWORD_OFFSET, rs_rZERO);
848 MarkSafepointPC(load);
849 }
850 }
851}
852
Goran Jakovljevic10957932015-03-24 18:42:56 +0100853LIR* MipsMir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest, OpSize size,
854 VolatileKind is_volatile) {
855 if (UNLIKELY(is_volatile == kVolatile && (size == k64 || size == kDouble))
856 && (!cu_->target64 || displacement & 0x7)) {
857 // TODO: use lld/scd instructions for Mips64.
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700858 // Do atomic 64-bit load.
859 return GenAtomic64Load(r_base, displacement, r_dest);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000860 }
861
buzbee695d13a2014-04-19 13:32:20 -0700862 // TODO: base this on target.
863 if (size == kWord) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100864 size = cu_->target64 ? k64 : k32;
buzbee695d13a2014-04-19 13:32:20 -0700865 }
Andreas Gampe3c12c512014-06-24 18:46:29 +0000866 LIR* load;
Douglas Leung2db3e262014-06-25 16:02:55 -0700867 load = LoadBaseDispBody(r_base, displacement, r_dest, size);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000868
869 if (UNLIKELY(is_volatile == kVolatile)) {
Hans Boehm48f5c472014-06-27 14:50:10 -0700870 GenMemBarrier(kLoadAny);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000871 }
872
873 return load;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700874}
875
Vladimir Marko455759b2014-05-06 20:49:36 +0100876// FIXME: don't split r_dest into 2 containers.
Goran Jakovljevic10957932015-03-24 18:42:56 +0100877LIR* MipsMir2Lir::StoreBaseDispBody(RegStorage r_base, int displacement, RegStorage r_src,
878 OpSize size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700879 LIR *res;
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700880 LIR *store = nullptr;
881 LIR *store2 = nullptr;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700882 MipsOpCode opcode = kMipsNop;
883 bool short_form = IS_SIMM16(displacement);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800884 bool is64bit = false;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700885
886 switch (size) {
buzbee695d13a2014-04-19 13:32:20 -0700887 case k64:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700888 case kDouble:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100889 if (cu_->target64) {
890 r_src = Check64BitReg(r_src);
891 if (!r_src.IsFloat()) {
892 opcode = kMips64Sd;
893 } else {
894 opcode = kMipsFsdc1;
895 }
Roland Levillain14d90572015-07-16 10:52:26 +0100896 DCHECK_ALIGNED(displacement, 4);
Goran Jakovljevic10957932015-03-24 18:42:56 +0100897 break;
898 }
Douglas Leung027f0ff2015-02-27 19:05:03 -0800899 is64bit = true;
900 if (fpuIs32Bit_ && !r_src.IsPair()) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100901 // Form 64-bit pair.
Douglas Leung2db3e262014-06-25 16:02:55 -0700902 r_src = Solo64ToPair64(r_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700903 }
904 short_form = IS_SIMM16_2WORD(displacement);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800905 FALLTHROUGH_INTENDED;
buzbee695d13a2014-04-19 13:32:20 -0700906 case k32:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700907 case kSingle:
buzbee695d13a2014-04-19 13:32:20 -0700908 case kReference:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700909 opcode = kMipsSw;
buzbee091cc402014-03-31 10:14:40 -0700910 if (r_src.IsFloat()) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700911 opcode = kMipsFswc1;
Douglas Leung027f0ff2015-02-27 19:05:03 -0800912 if (!is64bit) {
913 DCHECK(r_src.IsSingle());
914 } else {
915 DCHECK(r_src.IsDouble());
916 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700917 }
Roland Levillain14d90572015-07-16 10:52:26 +0100918 DCHECK_ALIGNED(displacement, 4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700919 break;
920 case kUnsignedHalf:
921 case kSignedHalf:
922 opcode = kMipsSh;
Roland Levillain14d90572015-07-16 10:52:26 +0100923 DCHECK_ALIGNED(displacement, 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700924 break;
925 case kUnsignedByte:
926 case kSignedByte:
927 opcode = kMipsSb;
928 break;
929 default:
buzbee2700f7e2014-03-07 09:46:20 -0800930 LOG(FATAL) << "Bad case in StoreBaseDispBody";
Brian Carlstrom7940e442013-07-12 13:46:57 -0700931 }
932
Goran Jakovljevic10957932015-03-24 18:42:56 +0100933 if (cu_->target64) {
934 if (short_form) {
935 store = res = NewLIR3(opcode, r_src.GetReg(), displacement, r_base.GetReg());
936 } else {
937 RegStorage r_scratch = AllocTemp();
938 res = OpRegRegImm(kOpAdd, r_scratch, r_base, displacement);
939 store = NewLIR3(opcode, r_src.GetReg(), 0, r_scratch.GetReg());
940 FreeTemp(r_scratch);
941 }
942
943 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
944 DCHECK_EQ(r_base, TargetPtrReg(kSp));
945 AnnotateDalvikRegAccess(store, displacement >> 2, false /* is_load */, r_src.Is64Bit());
946 }
947 return res;
948 }
949
Brian Carlstrom7940e442013-07-12 13:46:57 -0700950 if (short_form) {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800951 if (!is64bit) {
buzbee2700f7e2014-03-07 09:46:20 -0800952 store = res = NewLIR3(opcode, r_src.GetReg(), displacement, r_base.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700953 } else {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800954 if (fpuIs32Bit_ || !r_src.IsFloat()) {
955 DCHECK(r_src.IsPair());
Goran Jakovljevic10957932015-03-24 18:42:56 +0100956 store = res = NewLIR3(opcode, r_src.GetLowReg(), displacement + LOWORD_OFFSET,
957 r_base.GetReg());
Douglas Leung027f0ff2015-02-27 19:05:03 -0800958 store2 = NewLIR3(opcode, r_src.GetHighReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
959 } else {
960 // Here if 64bit fpu and r_src is a 64bit fp register
961 RegStorage r_tmp = AllocTemp();
962 r_src = Fp64ToSolo32(r_src);
Goran Jakovljevic10957932015-03-24 18:42:56 +0100963 store = res = NewLIR3(kMipsFswc1, r_src.GetReg(), displacement + LOWORD_OFFSET,
964 r_base.GetReg());
Douglas Leung027f0ff2015-02-27 19:05:03 -0800965 NewLIR2(kMipsMfhc1, r_tmp.GetReg(), r_src.GetReg());
966 store2 = NewLIR3(kMipsSw, r_tmp.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
967 FreeTemp(r_tmp);
968 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700969 }
970 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800971 RegStorage r_scratch = AllocTemp();
972 res = OpRegRegImm(kOpAdd, r_scratch, r_base, displacement);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800973 if (!is64bit) {
buzbee2700f7e2014-03-07 09:46:20 -0800974 store = NewLIR3(opcode, r_src.GetReg(), 0, r_scratch.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700975 } else {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800976 if (fpuIs32Bit_ || !r_src.IsFloat()) {
977 DCHECK(r_src.IsPair());
978 store = NewLIR3(opcode, r_src.GetLowReg(), LOWORD_OFFSET, r_scratch.GetReg());
979 store2 = NewLIR3(opcode, r_src.GetHighReg(), HIWORD_OFFSET, r_scratch.GetReg());
980 } else {
981 // Here if 64bit fpu and r_src is a 64bit fp register
982 RegStorage r_tmp = AllocTemp();
983 r_src = Fp64ToSolo32(r_src);
984 store = NewLIR3(kMipsFswc1, r_src.GetReg(), LOWORD_OFFSET, r_scratch.GetReg());
985 NewLIR2(kMipsMfhc1, r_tmp.GetReg(), r_src.GetReg());
986 store2 = NewLIR3(kMipsSw, r_tmp.GetReg(), HIWORD_OFFSET, r_scratch.GetReg());
987 FreeTemp(r_tmp);
988 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700989 }
990 FreeTemp(r_scratch);
991 }
992
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100993 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100994 DCHECK_EQ(r_base, TargetPtrReg(kSp));
Douglas Leung027f0ff2015-02-27 19:05:03 -0800995 AnnotateDalvikRegAccess(store, (displacement + (is64bit ? LOWORD_OFFSET : 0)) >> 2,
996 false /* is_load */, is64bit /* is64bit */);
997 if (is64bit) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700998 AnnotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2,
Douglas Leung027f0ff2015-02-27 19:05:03 -0800999 false /* is_load */, is64bit /* is64bit */);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001000 }
1001 }
1002
1003 return res;
1004}
1005
Goran Jakovljevic10957932015-03-24 18:42:56 +01001006LIR* MipsMir2Lir::StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src, OpSize size,
1007 VolatileKind is_volatile) {
Andreas Gampe3c12c512014-06-24 18:46:29 +00001008 if (is_volatile == kVolatile) {
Hans Boehm48f5c472014-06-27 14:50:10 -07001009 // Ensure that prior accesses become visible to other threads first.
1010 GenMemBarrier(kAnyStore);
Andreas Gampe3c12c512014-06-24 18:46:29 +00001011 }
1012
Andreas Gampe3c12c512014-06-24 18:46:29 +00001013 LIR* store;
Goran Jakovljevic10957932015-03-24 18:42:56 +01001014 if (UNLIKELY(is_volatile == kVolatile && (size == k64 || size == kDouble) &&
1015 (!cu_->target64 || displacement & 0x7))) {
1016 // TODO: use lld/scd instructions for Mips64.
Douglas Leungd9cb8ae2014-07-09 14:28:35 -07001017 // Do atomic 64-bit load.
1018 store = GenAtomic64Store(r_base, displacement, r_src);
1019 } else {
1020 // TODO: base this on target.
1021 if (size == kWord) {
Goran Jakovljevic10957932015-03-24 18:42:56 +01001022 size = cu_->target64 ? k64 : k32;
Douglas Leungd9cb8ae2014-07-09 14:28:35 -07001023 }
1024 store = StoreBaseDispBody(r_base, displacement, r_src, size);
1025 }
Andreas Gampe3c12c512014-06-24 18:46:29 +00001026
1027 if (UNLIKELY(is_volatile == kVolatile)) {
Hans Boehm48f5c472014-06-27 14:50:10 -07001028 // Preserve order with respect to any subsequent volatile loads.
1029 // We need StoreLoad, but that generally requires the most expensive barrier.
1030 GenMemBarrier(kAnyAny);
Andreas Gampe3c12c512014-06-24 18:46:29 +00001031 }
1032
1033 return store;
Brian Carlstrom7940e442013-07-12 13:46:57 -07001034}
1035
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001036LIR* MipsMir2Lir::OpMem(OpKind op ATTRIBUTE_UNUSED,
1037 RegStorage r_base ATTRIBUTE_UNUSED,
1038 int disp ATTRIBUTE_UNUSED) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001039 LOG(FATAL) << "Unexpected use of OpMem for MIPS";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001040 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -07001041}
1042
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001043LIR* MipsMir2Lir::OpCondBranch(ConditionCode cc ATTRIBUTE_UNUSED, LIR* target ATTRIBUTE_UNUSED) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001044 LOG(FATAL) << "Unexpected use of OpCondBranch for MIPS";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001045 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -07001046}
1047
Andreas Gampe98430592014-07-27 19:44:50 -07001048LIR* MipsMir2Lir::InvokeTrampoline(OpKind op, RegStorage r_tgt, QuickEntrypointEnum trampoline) {
Goran Jakovljevic10957932015-03-24 18:42:56 +01001049 if (!cu_->target64 && IsDirectEntrypoint(trampoline)) {
Nikola Veljkovic2d873b62015-02-20 17:21:15 +01001050 // Reserve argument space on stack (for $a0-$a3) for
1051 // entrypoints that directly reference native implementations.
1052 // This is not safe in general, as it violates the frame size
1053 // of the Quick method, but it is used here only for calling
1054 // native functions, outside of the runtime.
1055 OpRegImm(kOpSub, rs_rSP, 16);
1056 LIR* retVal = OpReg(op, r_tgt);
1057 OpRegImm(kOpAdd, rs_rSP, 16);
1058 return retVal;
1059 }
1060
Andreas Gampe98430592014-07-27 19:44:50 -07001061 return OpReg(op, r_tgt);
1062}
1063
Goran Jakovljevic10957932015-03-24 18:42:56 +01001064RegStorage MipsMir2Lir::AllocPtrSizeTemp(bool required) {
1065 return cu_->target64 ? AllocTempWide(required) : AllocTemp(required);
1066}
1067
Brian Carlstrom7940e442013-07-12 13:46:57 -07001068} // namespace art