blob: 4d6c058bdfd5ad78ca7d46dca850afb2b0881e5f [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
Lazar Trsicd9672662015-09-03 17:33:01 +020031static constexpr size_t kMips64DoublewordSize = 8;
32
Goran Jakovljevic10957932015-03-24 18:42:56 +010033/* This file contains codegen for the Mips ISA */
buzbee2700f7e2014-03-07 09:46:20 -080034LIR* MipsMir2Lir::OpFpRegCopy(RegStorage r_dest, RegStorage r_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070035 int opcode;
Goran Jakovljevic10957932015-03-24 18:42:56 +010036 if (cu_->target64) {
37 DCHECK_EQ(r_dest.Is64Bit(), r_src.Is64Bit());
38 if (r_dest.Is64Bit()) {
39 if (r_dest.IsDouble()) {
40 if (r_src.IsDouble()) {
41 opcode = kMipsFmovd;
42 } else {
43 // Note the operands are swapped for the dmtc1 instr.
44 RegStorage t_opnd = r_src;
45 r_src = r_dest;
46 r_dest = t_opnd;
47 opcode = kMips64Dmtc1;
48 }
Brian Carlstrom7940e442013-07-12 13:46:57 -070049 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +010050 DCHECK(r_src.IsDouble());
51 opcode = kMips64Dmfc1;
Brian Carlstrom7940e442013-07-12 13:46:57 -070052 }
53 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +010054 if (r_dest.IsSingle()) {
55 if (r_src.IsSingle()) {
56 opcode = kMipsFmovs;
57 } else {
58 // Note the operands are swapped for the mtc1 instr.
59 RegStorage t_opnd = r_src;
60 r_src = r_dest;
61 r_dest = t_opnd;
62 opcode = kMipsMtc1;
63 }
64 } else {
65 DCHECK(r_src.IsSingle());
66 opcode = kMipsMfc1;
67 }
68 }
69 } else {
70 // Must be both DOUBLE or both not DOUBLE.
71 DCHECK_EQ(r_dest.IsDouble(), r_src.IsDouble());
72 if (r_dest.IsDouble()) {
73 opcode = kMipsFmovd;
74 } else {
75 if (r_dest.IsSingle()) {
76 if (r_src.IsSingle()) {
77 opcode = kMipsFmovs;
78 } else {
79 // Note the operands are swapped for the mtc1 instr.
80 RegStorage t_opnd = r_src;
81 r_src = r_dest;
82 r_dest = t_opnd;
83 opcode = kMipsMtc1;
84 }
85 } else {
86 DCHECK(r_src.IsSingle());
87 opcode = kMipsMfc1;
88 }
Brian Carlstrom7940e442013-07-12 13:46:57 -070089 }
90 }
Goran Jakovljevic10957932015-03-24 18:42:56 +010091 LIR* res;
92 if (cu_->target64) {
93 res = RawLIR(current_dalvik_offset_, opcode, r_dest.GetReg(), r_src.GetReg());
94 } else {
95 res = RawLIR(current_dalvik_offset_, opcode, r_src.GetReg(), r_dest.GetReg());
96 }
Brian Carlstrom7940e442013-07-12 13:46:57 -070097 if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
98 res->flags.is_nop = true;
99 }
100 return res;
101}
102
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700103bool MipsMir2Lir::InexpensiveConstantInt(int32_t value) {
Andreas Gampeab1eb0d2015-02-13 19:23:55 -0800104 // For encodings, see LoadConstantNoClobber below.
105 return ((value == 0) || IsUint<16>(value) || IsInt<16>(value));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700106}
107
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100108bool MipsMir2Lir::InexpensiveConstantFloat(int32_t value ATTRIBUTE_UNUSED) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700109 return false; // TUNING
110}
111
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100112bool MipsMir2Lir::InexpensiveConstantLong(int64_t value ATTRIBUTE_UNUSED) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700113 return false; // TUNING
114}
115
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100116bool MipsMir2Lir::InexpensiveConstantDouble(int64_t value ATTRIBUTE_UNUSED) {
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700117 return false; // TUNING
Brian Carlstrom7940e442013-07-12 13:46:57 -0700118}
119
120/*
121 * Load a immediate using a shortcut if possible; otherwise
122 * grab from the per-translation literal pool. If target is
123 * a high register, build constant into a low register and copy.
124 *
125 * No additional register clobbering operation performed. Use this version when
126 * 1) r_dest is freshly returned from AllocTemp or
127 * 2) The codegen is under fixed register usage
128 */
buzbee2700f7e2014-03-07 09:46:20 -0800129LIR* MipsMir2Lir::LoadConstantNoClobber(RegStorage r_dest, int value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700130 LIR *res;
131
buzbee2700f7e2014-03-07 09:46:20 -0800132 RegStorage r_dest_save = r_dest;
buzbee091cc402014-03-31 10:14:40 -0700133 int is_fp_reg = r_dest.IsFloat();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700134 if (is_fp_reg) {
buzbee091cc402014-03-31 10:14:40 -0700135 DCHECK(r_dest.IsSingle());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700136 r_dest = AllocTemp();
137 }
138
Goran Jakovljevic10957932015-03-24 18:42:56 +0100139 // See if the value can be constructed cheaply.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700140 if (value == 0) {
buzbee2700f7e2014-03-07 09:46:20 -0800141 res = NewLIR2(kMipsMove, r_dest.GetReg(), rZERO);
Andreas Gampeab1eb0d2015-02-13 19:23:55 -0800142 } else if (IsUint<16>(value)) {
143 // Use OR with (unsigned) immediate to encode 16b unsigned int.
buzbee2700f7e2014-03-07 09:46:20 -0800144 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZERO, value);
Andreas Gampeab1eb0d2015-02-13 19:23:55 -0800145 } else if (IsInt<16>(value)) {
146 // Use ADD with (signed) immediate to encode 16b signed int.
buzbee2700f7e2014-03-07 09:46:20 -0800147 res = NewLIR3(kMipsAddiu, r_dest.GetReg(), rZERO, value);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700148 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800149 res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700150 if (value & 0xffff)
buzbee2700f7e2014-03-07 09:46:20 -0800151 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), value);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700152 }
153
154 if (is_fp_reg) {
buzbee2700f7e2014-03-07 09:46:20 -0800155 NewLIR2(kMipsMtc1, r_dest.GetReg(), r_dest_save.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700156 FreeTemp(r_dest);
157 }
158
159 return res;
160}
161
Goran Jakovljevic10957932015-03-24 18:42:56 +0100162LIR* MipsMir2Lir::LoadConstantWideNoClobber(RegStorage r_dest, int64_t value) {
163 LIR* res = nullptr;
164 DCHECK(r_dest.Is64Bit());
165 RegStorage r_dest_save = r_dest;
166 int is_fp_reg = r_dest.IsFloat();
167 if (is_fp_reg) {
168 DCHECK(r_dest.IsDouble());
169 r_dest = AllocTemp();
170 }
171
172 int bit31 = (value & UINT64_C(0x80000000)) != 0;
173
174 // Loads with 1 instruction.
175 if (IsUint<16>(value)) {
176 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, value);
177 } else if (IsInt<16>(value)) {
178 res = NewLIR3(kMips64Daddiu, r_dest.GetReg(), rZEROd, value);
179 } else if ((value & 0xFFFF) == 0 && IsInt<16>(value >> 16)) {
180 res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
181 } else if (IsInt<32>(value)) {
182 // Loads with 2 instructions.
183 res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
184 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), value);
185 } else if ((value & 0xFFFF0000) == 0 && IsInt<16>(value >> 32)) {
186 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, value);
187 NewLIR2(kMips64Dahi, r_dest.GetReg(), value >> 32);
188 } else if ((value & UINT64_C(0xFFFFFFFF0000)) == 0) {
189 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, value);
190 NewLIR2(kMips64Dati, r_dest.GetReg(), value >> 48);
191 } else if ((value & 0xFFFF) == 0 && (value >> 32) >= (-32768 - bit31) &&
192 (value >> 32) <= (32767 - bit31)) {
193 res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
194 NewLIR2(kMips64Dahi, r_dest.GetReg(), (value >> 32) + bit31);
195 } else if ((value & 0xFFFF) == 0 && ((value >> 31) & 0x1FFFF) == ((0x20000 - bit31) & 0x1FFFF)) {
196 res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
197 NewLIR2(kMips64Dati, r_dest.GetReg(), (value >> 48) + bit31);
198 } else {
199 int64_t tmp = value;
200 int shift_cnt = 0;
201 while ((tmp & 1) == 0) {
202 tmp >>= 1;
203 shift_cnt++;
204 }
205
206 if (IsUint<16>(tmp)) {
207 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, tmp);
208 NewLIR3((shift_cnt < 32) ? kMips64Dsll : kMips64Dsll32, r_dest.GetReg(), r_dest.GetReg(),
209 shift_cnt & 0x1F);
210 } else if (IsInt<16>(tmp)) {
211 res = NewLIR3(kMips64Daddiu, r_dest.GetReg(), rZEROd, tmp);
212 NewLIR3((shift_cnt < 32) ? kMips64Dsll : kMips64Dsll32, r_dest.GetReg(), r_dest.GetReg(),
213 shift_cnt & 0x1F);
214 } else if (IsInt<32>(tmp)) {
215 // Loads with 3 instructions.
216 res = NewLIR2(kMipsLui, r_dest.GetReg(), tmp >> 16);
217 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), tmp);
218 NewLIR3((shift_cnt < 32) ? kMips64Dsll : kMips64Dsll32, r_dest.GetReg(), r_dest.GetReg(),
219 shift_cnt & 0x1F);
220 } else {
221 tmp = value >> 16;
222 shift_cnt = 16;
223 while ((tmp & 1) == 0) {
224 tmp >>= 1;
225 shift_cnt++;
226 }
227
228 if (IsUint<16>(tmp)) {
229 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, tmp);
230 NewLIR3((shift_cnt < 32) ? kMips64Dsll : kMips64Dsll32, r_dest.GetReg(), r_dest.GetReg(),
231 shift_cnt & 0x1F);
232 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), value);
233 } else if (IsInt<16>(tmp)) {
234 res = NewLIR3(kMips64Daddiu, r_dest.GetReg(), rZEROd, tmp);
235 NewLIR3((shift_cnt < 32) ? kMips64Dsll : kMips64Dsll32, r_dest.GetReg(), r_dest.GetReg(),
236 shift_cnt & 0x1F);
237 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), value);
238 } else {
239 // Loads with 3-4 instructions.
240 uint64_t tmp2 = value;
241 if (((tmp2 >> 16) & 0xFFFF) != 0 || (tmp2 & 0xFFFFFFFF) == 0) {
242 res = NewLIR2(kMipsLui, r_dest.GetReg(), tmp2 >> 16);
243 }
244 if ((tmp2 & 0xFFFF) != 0) {
245 if (res)
246 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), tmp2);
247 else
248 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, tmp2);
249 }
250 if (bit31) {
251 tmp2 += UINT64_C(0x100000000);
252 }
253 if (((tmp2 >> 32) & 0xFFFF) != 0) {
254 NewLIR2(kMips64Dahi, r_dest.GetReg(), tmp2 >> 32);
255 }
256 if (tmp2 & UINT64_C(0x800000000000)) {
257 tmp2 += UINT64_C(0x1000000000000);
258 }
259 if ((tmp2 >> 48) != 0) {
260 NewLIR2(kMips64Dati, r_dest.GetReg(), tmp2 >> 48);
261 }
262 }
263 }
264 }
265
266 if (is_fp_reg) {
267 NewLIR2(kMips64Dmtc1, r_dest.GetReg(), r_dest_save.GetReg());
268 FreeTemp(r_dest);
269 }
270 return res;
271}
272
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700273LIR* MipsMir2Lir::OpUnconditionalBranch(LIR* target) {
Brian Carlstromdf629502013-07-17 22:39:56 -0700274 LIR* res = NewLIR1(kMipsB, 0 /* offset to be patched during assembly*/);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700275 res->target = target;
276 return res;
277}
278
buzbee2700f7e2014-03-07 09:46:20 -0800279LIR* MipsMir2Lir::OpReg(OpKind op, RegStorage r_dest_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700280 MipsOpCode opcode = kMipsNop;
281 switch (op) {
282 case kOpBlx:
283 opcode = kMipsJalr;
284 break;
285 case kOpBx:
Andreas Gampe8d365912015-01-13 11:32:32 -0800286 return NewLIR2(kMipsJalr, rZERO, r_dest_src.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700287 default:
288 LOG(FATAL) << "Bad case in OpReg";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700289 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700290 }
Goran Jakovljevic10957932015-03-24 18:42:56 +0100291 return NewLIR2(opcode, cu_->target64 ? rRAd : rRA, r_dest_src.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700292}
293
buzbee2700f7e2014-03-07 09:46:20 -0800294LIR* MipsMir2Lir::OpRegImm(OpKind op, RegStorage r_dest_src1, int value) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100295 if ((op == kOpAdd) || (op == kOpSub)) {
296 return OpRegRegImm(op, r_dest_src1, r_dest_src1, value);
Brian Carlstrom9b7085a2013-07-18 15:15:21 -0700297 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100298 LOG(FATAL) << "Bad case in OpRegImm";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700299 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700300 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700301}
302
buzbee2700f7e2014-03-07 09:46:20 -0800303LIR* MipsMir2Lir::OpRegRegReg(OpKind op, RegStorage r_dest, RegStorage r_src1, RegStorage r_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700304 MipsOpCode opcode = kMipsNop;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100305 bool is64bit = cu_->target64 && (r_dest.Is64Bit() || r_src1.Is64Bit() || r_src2.Is64Bit());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700306 switch (op) {
307 case kOpAdd:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100308 opcode = is64bit ? kMips64Daddu : kMipsAddu;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700309 break;
310 case kOpSub:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100311 opcode = is64bit ? kMips64Dsubu : kMipsSubu;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700312 break;
313 case kOpAnd:
314 opcode = kMipsAnd;
315 break;
316 case kOpMul:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100317 opcode = isaIsR6_ ? kMipsR6Mul : kMipsR2Mul;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700318 break;
319 case kOpOr:
320 opcode = kMipsOr;
321 break;
322 case kOpXor:
323 opcode = kMipsXor;
324 break;
325 case kOpLsl:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100326 opcode = is64bit ? kMips64Dsllv : kMipsSllv;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700327 break;
328 case kOpLsr:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100329 opcode = is64bit ? kMips64Dsrlv : kMipsSrlv;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700330 break;
331 case kOpAsr:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100332 opcode = is64bit ? kMips64Dsrav : kMipsSrav;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700333 break;
334 case kOpAdc:
335 case kOpSbc:
336 LOG(FATAL) << "No carry bit on MIPS";
337 break;
338 default:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100339 LOG(FATAL) << "Bad case in OpRegRegReg";
Brian Carlstrom7940e442013-07-12 13:46:57 -0700340 break;
341 }
buzbee2700f7e2014-03-07 09:46:20 -0800342 return NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), r_src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700343}
344
buzbee2700f7e2014-03-07 09:46:20 -0800345LIR* MipsMir2Lir::OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src1, int value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700346 LIR *res;
347 MipsOpCode opcode = kMipsNop;
348 bool short_form = true;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100349 bool is64bit = cu_->target64 && (r_dest.Is64Bit() || r_src1.Is64Bit());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700350
351 switch (op) {
352 case kOpAdd:
353 if (IS_SIMM16(value)) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100354 opcode = is64bit ? kMips64Daddiu : kMipsAddiu;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700355 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700356 short_form = false;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100357 opcode = is64bit ? kMips64Daddu : kMipsAddu;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700358 }
359 break;
360 case kOpSub:
361 if (IS_SIMM16((-value))) {
362 value = -value;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100363 opcode = is64bit ? kMips64Daddiu : kMipsAddiu;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700364 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700365 short_form = false;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100366 opcode = is64bit ? kMips64Dsubu : kMipsSubu;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700367 }
368 break;
369 case kOpLsl:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100370 if (is64bit) {
371 DCHECK(value >= 0 && value <= 63);
372 if (value >= 0 && value <= 31) {
373 opcode = kMips64Dsll;
374 } else {
375 opcode = kMips64Dsll32;
376 value = value - 32;
377 }
378 } else {
379 DCHECK(value >= 0 && value <= 31);
380 opcode = kMipsSll;
381 }
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800382 break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700383 case kOpLsr:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100384 if (is64bit) {
385 DCHECK(value >= 0 && value <= 63);
386 if (value >= 0 && value <= 31) {
387 opcode = kMips64Dsrl;
388 } else {
389 opcode = kMips64Dsrl32;
390 value = value - 32;
391 }
392 } else {
393 DCHECK(value >= 0 && value <= 31);
394 opcode = kMipsSrl;
395 }
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800396 break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700397 case kOpAsr:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100398 if (is64bit) {
399 DCHECK(value >= 0 && value <= 63);
400 if (value >= 0 && value <= 31) {
401 opcode = kMips64Dsra;
402 } else {
403 opcode = kMips64Dsra32;
404 value = value - 32;
405 }
406 } else {
407 DCHECK(value >= 0 && value <= 31);
408 opcode = kMipsSra;
409 }
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800410 break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700411 case kOpAnd:
412 if (IS_UIMM16((value))) {
413 opcode = kMipsAndi;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700414 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700415 short_form = false;
416 opcode = kMipsAnd;
417 }
418 break;
419 case kOpOr:
420 if (IS_UIMM16((value))) {
421 opcode = kMipsOri;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700422 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700423 short_form = false;
424 opcode = kMipsOr;
425 }
426 break;
427 case kOpXor:
428 if (IS_UIMM16((value))) {
429 opcode = kMipsXori;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700430 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700431 short_form = false;
432 opcode = kMipsXor;
433 }
434 break;
435 case kOpMul:
436 short_form = false;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100437 opcode = isaIsR6_ ? kMipsR6Mul : kMipsR2Mul;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700438 break;
439 default:
440 LOG(FATAL) << "Bad case in OpRegRegImm";
441 break;
442 }
443
Brian Carlstrom9b7085a2013-07-18 15:15:21 -0700444 if (short_form) {
buzbee2700f7e2014-03-07 09:46:20 -0800445 res = NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), value);
Brian Carlstrom9b7085a2013-07-18 15:15:21 -0700446 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700447 if (r_dest != r_src1) {
448 res = LoadConstant(r_dest, value);
buzbee2700f7e2014-03-07 09:46:20 -0800449 NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), r_dest.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700450 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100451 RegStorage r_scratch;
452 if (is64bit) {
453 r_scratch = AllocTempWide();
454 res = LoadConstantWide(r_scratch, value);
455 } else {
456 r_scratch = AllocTemp();
457 res = LoadConstant(r_scratch, value);
458 }
buzbee2700f7e2014-03-07 09:46:20 -0800459 NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), r_scratch.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700460 }
461 }
462 return res;
463}
464
buzbee2700f7e2014-03-07 09:46:20 -0800465LIR* MipsMir2Lir::OpRegReg(OpKind op, RegStorage r_dest_src1, RegStorage r_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700466 MipsOpCode opcode = kMipsNop;
467 LIR *res;
468 switch (op) {
469 case kOpMov:
470 opcode = kMipsMove;
471 break;
472 case kOpMvn:
buzbee2700f7e2014-03-07 09:46:20 -0800473 return NewLIR3(kMipsNor, r_dest_src1.GetReg(), r_src2.GetReg(), rZERO);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700474 case kOpNeg:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100475 if (cu_->target64 && r_dest_src1.Is64Bit()) {
476 return NewLIR3(kMips64Dsubu, r_dest_src1.GetReg(), rZEROd, r_src2.GetReg());
477 } else {
478 return NewLIR3(kMipsSubu, r_dest_src1.GetReg(), rZERO, r_src2.GetReg());
479 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700480 case kOpAdd:
481 case kOpAnd:
482 case kOpMul:
483 case kOpOr:
484 case kOpSub:
485 case kOpXor:
486 return OpRegRegReg(op, r_dest_src1, r_dest_src1, r_src2);
487 case kOp2Byte:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100488 if (cu_->target64) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800489 res = NewLIR2(kMipsSeb, r_dest_src1.GetReg(), r_src2.GetReg());
490 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100491 if (cu_->compiler_driver->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()
492 ->IsMipsIsaRevGreaterThanEqual2()) {
493 res = NewLIR2(kMipsSeb, r_dest_src1.GetReg(), r_src2.GetReg());
494 } else {
495 res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 24);
496 OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 24);
497 }
Ian Rogersd582fa42014-11-05 23:46:43 -0800498 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700499 return res;
500 case kOp2Short:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100501 if (cu_->target64) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800502 res = NewLIR2(kMipsSeh, r_dest_src1.GetReg(), r_src2.GetReg());
503 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100504 if (cu_->compiler_driver->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()
505 ->IsMipsIsaRevGreaterThanEqual2()) {
506 res = NewLIR2(kMipsSeh, r_dest_src1.GetReg(), r_src2.GetReg());
507 } else {
508 res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 16);
509 OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 16);
510 }
Ian Rogersd582fa42014-11-05 23:46:43 -0800511 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700512 return res;
513 case kOp2Char:
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800514 return NewLIR3(kMipsAndi, r_dest_src1.GetReg(), r_src2.GetReg(), 0xFFFF);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700515 default:
516 LOG(FATAL) << "Bad case in OpRegReg";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700517 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700518 }
buzbee2700f7e2014-03-07 09:46:20 -0800519 return NewLIR2(opcode, r_dest_src1.GetReg(), r_src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700520}
521
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100522LIR* MipsMir2Lir::OpMovRegMem(RegStorage r_dest ATTRIBUTE_UNUSED,
523 RegStorage r_base ATTRIBUTE_UNUSED,
524 int offset ATTRIBUTE_UNUSED,
525 MoveType move_type ATTRIBUTE_UNUSED) {
Razvan A Lupusoru2c498d12014-01-29 16:02:57 -0800526 UNIMPLEMENTED(FATAL);
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700527 UNREACHABLE();
Razvan A Lupusoru2c498d12014-01-29 16:02:57 -0800528}
529
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100530LIR* MipsMir2Lir::OpMovMemReg(RegStorage r_base ATTRIBUTE_UNUSED,
531 int offset ATTRIBUTE_UNUSED,
532 RegStorage r_src ATTRIBUTE_UNUSED,
533 MoveType move_type ATTRIBUTE_UNUSED) {
Razvan A Lupusoru2c498d12014-01-29 16:02:57 -0800534 UNIMPLEMENTED(FATAL);
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700535 UNREACHABLE();
Razvan A Lupusoru2c498d12014-01-29 16:02:57 -0800536}
537
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100538LIR* MipsMir2Lir::OpCondRegReg(OpKind op ATTRIBUTE_UNUSED,
539 ConditionCode cc ATTRIBUTE_UNUSED,
540 RegStorage r_dest ATTRIBUTE_UNUSED,
541 RegStorage r_src ATTRIBUTE_UNUSED) {
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800542 LOG(FATAL) << "Unexpected use of OpCondRegReg for MIPS";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700543 UNREACHABLE();
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800544}
545
buzbee2700f7e2014-03-07 09:46:20 -0800546LIR* MipsMir2Lir::LoadConstantWide(RegStorage r_dest, int64_t value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700547 LIR *res;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100548 if (cu_->target64) {
549 res = LoadConstantWideNoClobber(r_dest, value);
550 return res;
551 }
Douglas Leung027f0ff2015-02-27 19:05:03 -0800552 if (fpuIs32Bit_ || !r_dest.IsFloat()) {
553 // 32bit FPU (pairs) or loading into GPR.
554 if (!r_dest.IsPair()) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100555 // Form 64-bit pair.
Douglas Leung027f0ff2015-02-27 19:05:03 -0800556 r_dest = Solo64ToPair64(r_dest);
557 }
558 res = LoadConstantNoClobber(r_dest.GetLow(), Low32Bits(value));
559 LoadConstantNoClobber(r_dest.GetHigh(), High32Bits(value));
560 } else {
561 // Here if we have a 64bit FPU and loading into FPR.
562 RegStorage r_temp = AllocTemp();
563 r_dest = Fp64ToSolo32(r_dest);
564 res = LoadConstantNoClobber(r_dest, Low32Bits(value));
565 LoadConstantNoClobber(r_temp, High32Bits(value));
566 NewLIR2(kMipsMthc1, r_temp.GetReg(), r_dest.GetReg());
567 FreeTemp(r_temp);
Douglas Leung2db3e262014-06-25 16:02:55 -0700568 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700569 return res;
570}
571
572/* Load value from base + scaled index. */
buzbee2700f7e2014-03-07 09:46:20 -0800573LIR* MipsMir2Lir::LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700574 int scale, OpSize size) {
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700575 LIR *first = nullptr;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700576 LIR *res;
577 MipsOpCode opcode = kMipsNop;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100578 bool is64bit = cu_->target64 && r_dest.Is64Bit();
579 RegStorage t_reg = is64bit ? AllocTempWide() : AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700580
buzbee091cc402014-03-31 10:14:40 -0700581 if (r_dest.IsFloat()) {
582 DCHECK(r_dest.IsSingle());
buzbeefd698e62014-04-27 19:33:22 -0700583 DCHECK((size == k32) || (size == kSingle) || (size == kReference));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700584 size = kSingle;
585 } else {
586 if (size == kSingle)
buzbee695d13a2014-04-19 13:32:20 -0700587 size = k32;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700588 }
589
Goran Jakovljevic10957932015-03-24 18:42:56 +0100590 if (cu_->target64) {
591 if (!scale) {
592 if (is64bit) {
593 first = NewLIR3(kMips64Daddu, t_reg.GetReg() , r_base.GetReg(), r_index.GetReg());
594 } else {
595 first = NewLIR3(kMipsAddu, t_reg.GetReg() , r_base.GetReg(), r_index.GetReg());
596 }
597 } else {
598 first = OpRegRegImm(kOpLsl, t_reg, r_index, scale);
599 NewLIR3(kMips64Daddu, t_reg.GetReg() , r_base.GetReg(), t_reg.GetReg());
600 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700601 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100602 if (!scale) {
603 first = NewLIR3(kMipsAddu, t_reg.GetReg() , r_base.GetReg(), r_index.GetReg());
604 } else {
605 first = OpRegRegImm(kOpLsl, t_reg, r_index, scale);
606 NewLIR3(kMipsAddu, t_reg.GetReg() , r_base.GetReg(), t_reg.GetReg());
607 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700608 }
609
610 switch (size) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100611 case k64:
612 if (cu_->target64) {
613 opcode = kMips64Ld;
614 } else {
615 LOG(FATAL) << "Bad case in LoadBaseIndexed";
616 }
617 break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700618 case kSingle:
619 opcode = kMipsFlwc1;
620 break;
buzbee695d13a2014-04-19 13:32:20 -0700621 case k32:
622 case kReference:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700623 opcode = kMipsLw;
624 break;
625 case kUnsignedHalf:
626 opcode = kMipsLhu;
627 break;
628 case kSignedHalf:
629 opcode = kMipsLh;
630 break;
631 case kUnsignedByte:
632 opcode = kMipsLbu;
633 break;
634 case kSignedByte:
635 opcode = kMipsLb;
636 break;
637 default:
638 LOG(FATAL) << "Bad case in LoadBaseIndexed";
639 }
640
buzbee2700f7e2014-03-07 09:46:20 -0800641 res = NewLIR3(opcode, r_dest.GetReg(), 0, t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700642 FreeTemp(t_reg);
643 return (first) ? first : res;
644}
645
Goran Jakovljevic10957932015-03-24 18:42:56 +0100646// Store value base base + scaled index.
buzbee2700f7e2014-03-07 09:46:20 -0800647LIR* MipsMir2Lir::StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700648 int scale, OpSize size) {
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700649 LIR *first = nullptr;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700650 MipsOpCode opcode = kMipsNop;
buzbee2700f7e2014-03-07 09:46:20 -0800651 RegStorage t_reg = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700652
buzbee091cc402014-03-31 10:14:40 -0700653 if (r_src.IsFloat()) {
654 DCHECK(r_src.IsSingle());
buzbeefd698e62014-04-27 19:33:22 -0700655 DCHECK((size == k32) || (size == kSingle) || (size == kReference));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700656 size = kSingle;
657 } else {
658 if (size == kSingle)
buzbee695d13a2014-04-19 13:32:20 -0700659 size = k32;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700660 }
661
Goran Jakovljevic10957932015-03-24 18:42:56 +0100662 MipsOpCode add_opcode = cu_->target64 ? kMips64Daddu : kMipsAddu;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700663 if (!scale) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100664 first = NewLIR3(add_opcode, t_reg.GetReg() , r_base.GetReg(), r_index.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700665 } else {
666 first = OpRegRegImm(kOpLsl, t_reg, r_index, scale);
Goran Jakovljevic10957932015-03-24 18:42:56 +0100667 NewLIR3(add_opcode, t_reg.GetReg() , r_base.GetReg(), t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700668 }
669
670 switch (size) {
671 case kSingle:
672 opcode = kMipsFswc1;
673 break;
buzbee695d13a2014-04-19 13:32:20 -0700674 case k32:
675 case kReference:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700676 opcode = kMipsSw;
677 break;
678 case kUnsignedHalf:
679 case kSignedHalf:
680 opcode = kMipsSh;
681 break;
682 case kUnsignedByte:
683 case kSignedByte:
684 opcode = kMipsSb;
685 break;
686 default:
687 LOG(FATAL) << "Bad case in StoreBaseIndexed";
688 }
buzbee2700f7e2014-03-07 09:46:20 -0800689 NewLIR3(opcode, r_src.GetReg(), 0, t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700690 return first;
691}
692
buzbee2700f7e2014-03-07 09:46:20 -0800693// FIXME: don't split r_dest into 2 containers.
694LIR* MipsMir2Lir::LoadBaseDispBody(RegStorage r_base, int displacement, RegStorage r_dest,
Douglas Leung2db3e262014-06-25 16:02:55 -0700695 OpSize size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700696/*
697 * Load value from base + displacement. Optionally perform null check
698 * on base (which must have an associated s_reg and MIR). If not
699 * performing null check, incoming MIR can be null. IMPORTANT: this
700 * code must not allocate any new temps. If a new register is needed
701 * and base and dest are the same, spill some other register to
702 * rlp and then restore.
703 */
Brian Carlstrom7940e442013-07-12 13:46:57 -0700704 LIR *res;
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700705 LIR *load = nullptr;
706 LIR *load2 = nullptr;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700707 MipsOpCode opcode = kMipsNop;
708 bool short_form = IS_SIMM16(displacement);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800709 bool is64bit = false;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700710
711 switch (size) {
buzbee695d13a2014-04-19 13:32:20 -0700712 case k64:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700713 case kDouble:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100714 if (cu_->target64) {
715 r_dest = Check64BitReg(r_dest);
716 if (!r_dest.IsFloat()) {
717 opcode = kMips64Ld;
718 } else {
719 opcode = kMipsFldc1;
720 }
Roland Levillain14d90572015-07-16 10:52:26 +0100721 DCHECK_ALIGNED(displacement, 4);
Goran Jakovljevic10957932015-03-24 18:42:56 +0100722 break;
723 }
Douglas Leung027f0ff2015-02-27 19:05:03 -0800724 is64bit = true;
725 if (fpuIs32Bit_ && !r_dest.IsPair()) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100726 // Form 64-bit pair.
Douglas Leung2db3e262014-06-25 16:02:55 -0700727 r_dest = Solo64ToPair64(r_dest);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700728 }
729 short_form = IS_SIMM16_2WORD(displacement);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800730 FALLTHROUGH_INTENDED;
buzbee695d13a2014-04-19 13:32:20 -0700731 case k32:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700732 case kSingle:
buzbee695d13a2014-04-19 13:32:20 -0700733 case kReference:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700734 opcode = kMipsLw;
buzbee091cc402014-03-31 10:14:40 -0700735 if (r_dest.IsFloat()) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700736 opcode = kMipsFlwc1;
Douglas Leung027f0ff2015-02-27 19:05:03 -0800737 if (!is64bit) {
738 DCHECK(r_dest.IsSingle());
739 } else {
740 DCHECK(r_dest.IsDouble());
741 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700742 }
Roland Levillain14d90572015-07-16 10:52:26 +0100743 DCHECK_ALIGNED(displacement, 4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700744 break;
745 case kUnsignedHalf:
746 opcode = kMipsLhu;
Roland Levillain14d90572015-07-16 10:52:26 +0100747 DCHECK_ALIGNED(displacement, 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700748 break;
749 case kSignedHalf:
750 opcode = kMipsLh;
Roland Levillain14d90572015-07-16 10:52:26 +0100751 DCHECK_ALIGNED(displacement, 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700752 break;
753 case kUnsignedByte:
754 opcode = kMipsLbu;
755 break;
756 case kSignedByte:
757 opcode = kMipsLb;
758 break;
759 default:
760 LOG(FATAL) << "Bad case in LoadBaseIndexedBody";
761 }
762
Goran Jakovljevic10957932015-03-24 18:42:56 +0100763 if (cu_->target64) {
764 if (short_form) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200765 if (!IsAligned<kMips64DoublewordSize>(displacement) && opcode == kMips64Ld) {
766 RegStorage r_tmp = AllocTemp();
767 load = res = NewLIR3(kMips64Lwu, r_dest.GetReg(), displacement + LOWORD_OFFSET,
768 r_base.GetReg());
769 load2 = NewLIR3(kMips64Lwu, r_tmp.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
770 NewLIR3(kMips64Dsll32, r_tmp.GetReg(), r_tmp.GetReg(), 0x0);
771 NewLIR3(kMipsOr, r_dest.GetReg(), r_dest.GetReg(), r_tmp.GetReg());
772 FreeTemp(r_tmp);
773 } else if (!IsAligned<kMips64DoublewordSize>(displacement) && opcode == kMipsFldc1) {
774 RegStorage r_tmp = AllocTemp();
775 r_dest = Fp64ToSolo32(r_dest);
776 load = res = NewLIR3(kMipsFlwc1, r_dest.GetReg(), displacement + LOWORD_OFFSET,
777 r_base.GetReg());
778 load2 = NewLIR3(kMipsLw, r_tmp.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
779 NewLIR2(kMipsMthc1, r_tmp.GetReg(), r_dest.GetReg());
780 FreeTemp(r_tmp);
781 } else {
782 load = res = NewLIR3(opcode, r_dest.GetReg(), displacement, r_base.GetReg());
783 }
Goran Jakovljevic10957932015-03-24 18:42:56 +0100784 } else {
785 RegStorage r_tmp = (r_base == r_dest) ? AllocTemp() : r_dest;
786 res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement);
787 load = NewLIR3(opcode, r_dest.GetReg(), 0, r_tmp.GetReg());
788 if (r_tmp != r_dest)
789 FreeTemp(r_tmp);
790 }
791
792 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
793 DCHECK_EQ(r_base, TargetPtrReg(kSp));
Lazar Trsicd9672662015-09-03 17:33:01 +0200794 AnnotateDalvikRegAccess(load, (displacement + LOWORD_OFFSET) >> 2,
795 true /* is_load */, r_dest.Is64Bit() /* is64bit */);
796 if (load2 != nullptr) {
797 AnnotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2,
798 true /* is_load */, r_dest.Is64Bit() /* is64bit */);
799 }
Goran Jakovljevic10957932015-03-24 18:42:56 +0100800 }
801 return res;
802 }
803
Brian Carlstrom7940e442013-07-12 13:46:57 -0700804 if (short_form) {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800805 if (!is64bit) {
buzbee2700f7e2014-03-07 09:46:20 -0800806 load = res = NewLIR3(opcode, r_dest.GetReg(), displacement, r_base.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700807 } else {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800808 if (fpuIs32Bit_ || !r_dest.IsFloat()) {
809 DCHECK(r_dest.IsPair());
Goran Jakovljevic10957932015-03-24 18:42:56 +0100810 load = res = NewLIR3(opcode, r_dest.GetLowReg(), displacement + LOWORD_OFFSET,
811 r_base.GetReg());
Douglas Leung027f0ff2015-02-27 19:05:03 -0800812 load2 = NewLIR3(opcode, r_dest.GetHighReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
813 } else {
814 // Here if 64bit fpu and r_dest is a 64bit fp register.
815 RegStorage r_tmp = AllocTemp();
816 // FIXME: why is r_dest a 64BitPair here???
817 r_dest = Fp64ToSolo32(r_dest);
Goran Jakovljevic10957932015-03-24 18:42:56 +0100818 load = res = NewLIR3(kMipsFlwc1, r_dest.GetReg(), displacement + LOWORD_OFFSET,
819 r_base.GetReg());
Douglas Leung027f0ff2015-02-27 19:05:03 -0800820 load2 = NewLIR3(kMipsLw, r_tmp.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
821 NewLIR2(kMipsMthc1, r_tmp.GetReg(), r_dest.GetReg());
822 FreeTemp(r_tmp);
823 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700824 }
825 } else {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800826 if (!is64bit) {
827 RegStorage r_tmp = (r_base == r_dest || r_dest.IsFloat()) ? AllocTemp() : r_dest;
buzbee2700f7e2014-03-07 09:46:20 -0800828 res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement);
829 load = NewLIR3(opcode, r_dest.GetReg(), 0, r_tmp.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700830 if (r_tmp != r_dest)
831 FreeTemp(r_tmp);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800832 } else {
833 RegStorage r_tmp = AllocTemp();
834 res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement);
835 if (fpuIs32Bit_ || !r_dest.IsFloat()) {
836 DCHECK(r_dest.IsPair());
837 load = NewLIR3(opcode, r_dest.GetLowReg(), LOWORD_OFFSET, r_tmp.GetReg());
838 load2 = NewLIR3(opcode, r_dest.GetHighReg(), HIWORD_OFFSET, r_tmp.GetReg());
839 } else {
840 // Here if 64bit fpu and r_dest is a 64bit fp register
841 r_dest = Fp64ToSolo32(r_dest);
842 load = res = NewLIR3(kMipsFlwc1, r_dest.GetReg(), LOWORD_OFFSET, r_tmp.GetReg());
843 load2 = NewLIR3(kMipsLw, r_tmp.GetReg(), HIWORD_OFFSET, r_tmp.GetReg());
844 NewLIR2(kMipsMthc1, r_tmp.GetReg(), r_dest.GetReg());
845 }
846 FreeTemp(r_tmp);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700847 }
848 }
849
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100850 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100851 DCHECK_EQ(r_base, TargetPtrReg(kSp));
Douglas Leung027f0ff2015-02-27 19:05:03 -0800852 AnnotateDalvikRegAccess(load, (displacement + (is64bit ? LOWORD_OFFSET : 0)) >> 2,
853 true /* is_load */, is64bit /* is64bit */);
854 if (is64bit) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700855 AnnotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2,
Douglas Leung027f0ff2015-02-27 19:05:03 -0800856 true /* is_load */, is64bit /* is64bit */);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700857 }
858 }
Goran Jakovljevic10957932015-03-24 18:42:56 +0100859 return res;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700860}
861
Douglas Leung22bb5a22015-07-02 16:42:08 -0700862void MipsMir2Lir::ForceImplicitNullCheck(RegStorage reg, int opt_flags, bool is_wide) {
863 if (cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
864 if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) {
865 return;
866 }
867 // Force an implicit null check by performing a memory operation (load) from the given
868 // register with offset 0. This will cause a signal if the register contains 0 (null).
869 LIR* load = Load32Disp(reg, LOWORD_OFFSET, rs_rZERO);
870 MarkSafepointPC(load);
871 if (is_wide) {
872 load = Load32Disp(reg, HIWORD_OFFSET, rs_rZERO);
873 MarkSafepointPC(load);
874 }
875 }
876}
877
Goran Jakovljevic10957932015-03-24 18:42:56 +0100878LIR* MipsMir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest, OpSize size,
879 VolatileKind is_volatile) {
880 if (UNLIKELY(is_volatile == kVolatile && (size == k64 || size == kDouble))
881 && (!cu_->target64 || displacement & 0x7)) {
882 // TODO: use lld/scd instructions for Mips64.
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700883 // Do atomic 64-bit load.
884 return GenAtomic64Load(r_base, displacement, r_dest);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000885 }
886
buzbee695d13a2014-04-19 13:32:20 -0700887 // TODO: base this on target.
888 if (size == kWord) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100889 size = cu_->target64 ? k64 : k32;
buzbee695d13a2014-04-19 13:32:20 -0700890 }
Andreas Gampe3c12c512014-06-24 18:46:29 +0000891 LIR* load;
Douglas Leung2db3e262014-06-25 16:02:55 -0700892 load = LoadBaseDispBody(r_base, displacement, r_dest, size);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000893
894 if (UNLIKELY(is_volatile == kVolatile)) {
Hans Boehm48f5c472014-06-27 14:50:10 -0700895 GenMemBarrier(kLoadAny);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000896 }
897
898 return load;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700899}
900
Vladimir Marko455759b2014-05-06 20:49:36 +0100901// FIXME: don't split r_dest into 2 containers.
Goran Jakovljevic10957932015-03-24 18:42:56 +0100902LIR* MipsMir2Lir::StoreBaseDispBody(RegStorage r_base, int displacement, RegStorage r_src,
903 OpSize size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700904 LIR *res;
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700905 LIR *store = nullptr;
906 LIR *store2 = nullptr;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700907 MipsOpCode opcode = kMipsNop;
908 bool short_form = IS_SIMM16(displacement);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800909 bool is64bit = false;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700910
911 switch (size) {
buzbee695d13a2014-04-19 13:32:20 -0700912 case k64:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700913 case kDouble:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100914 if (cu_->target64) {
915 r_src = Check64BitReg(r_src);
916 if (!r_src.IsFloat()) {
917 opcode = kMips64Sd;
918 } else {
919 opcode = kMipsFsdc1;
920 }
Roland Levillain14d90572015-07-16 10:52:26 +0100921 DCHECK_ALIGNED(displacement, 4);
Goran Jakovljevic10957932015-03-24 18:42:56 +0100922 break;
923 }
Douglas Leung027f0ff2015-02-27 19:05:03 -0800924 is64bit = true;
925 if (fpuIs32Bit_ && !r_src.IsPair()) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100926 // Form 64-bit pair.
Douglas Leung2db3e262014-06-25 16:02:55 -0700927 r_src = Solo64ToPair64(r_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700928 }
929 short_form = IS_SIMM16_2WORD(displacement);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800930 FALLTHROUGH_INTENDED;
buzbee695d13a2014-04-19 13:32:20 -0700931 case k32:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700932 case kSingle:
buzbee695d13a2014-04-19 13:32:20 -0700933 case kReference:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700934 opcode = kMipsSw;
buzbee091cc402014-03-31 10:14:40 -0700935 if (r_src.IsFloat()) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700936 opcode = kMipsFswc1;
Douglas Leung027f0ff2015-02-27 19:05:03 -0800937 if (!is64bit) {
938 DCHECK(r_src.IsSingle());
939 } else {
940 DCHECK(r_src.IsDouble());
941 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700942 }
Roland Levillain14d90572015-07-16 10:52:26 +0100943 DCHECK_ALIGNED(displacement, 4);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700944 break;
945 case kUnsignedHalf:
946 case kSignedHalf:
947 opcode = kMipsSh;
Roland Levillain14d90572015-07-16 10:52:26 +0100948 DCHECK_ALIGNED(displacement, 2);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700949 break;
950 case kUnsignedByte:
951 case kSignedByte:
952 opcode = kMipsSb;
953 break;
954 default:
buzbee2700f7e2014-03-07 09:46:20 -0800955 LOG(FATAL) << "Bad case in StoreBaseDispBody";
Brian Carlstrom7940e442013-07-12 13:46:57 -0700956 }
957
Goran Jakovljevic10957932015-03-24 18:42:56 +0100958 if (cu_->target64) {
959 if (short_form) {
Lazar Trsicd9672662015-09-03 17:33:01 +0200960 if (!IsAligned<kMips64DoublewordSize>(displacement) && opcode == kMips64Sd) {
961 RegStorage r_tmp = AllocTemp();
962 res = NewLIR2(kMipsMove, r_tmp.GetReg(), r_src.GetReg());
963 store = NewLIR3(kMipsSw, r_tmp.GetReg(), displacement + LOWORD_OFFSET, r_base.GetReg());
964 NewLIR3(kMips64Dsrl32, r_tmp.GetReg(), r_tmp.GetReg(), 0x0);
965 store2 = NewLIR3(kMipsSw, r_tmp.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
966 FreeTemp(r_tmp);
967 } else if (!IsAligned<kMips64DoublewordSize>(displacement) && opcode == kMipsFsdc1) {
968 RegStorage r_tmp = AllocTemp();
969 r_src = Fp64ToSolo32(r_src);
970 store = res = NewLIR3(kMipsFswc1, r_src.GetReg(), displacement + LOWORD_OFFSET,
971 r_base.GetReg());
972 NewLIR2(kMipsMfhc1, r_tmp.GetReg(), r_src.GetReg());
973 store2 = NewLIR3(kMipsSw, r_tmp.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
974 FreeTemp(r_tmp);
975 } else {
976 store = res = NewLIR3(opcode, r_src.GetReg(), displacement, r_base.GetReg());
977 }
Goran Jakovljevic10957932015-03-24 18:42:56 +0100978 } else {
979 RegStorage r_scratch = AllocTemp();
980 res = OpRegRegImm(kOpAdd, r_scratch, r_base, displacement);
981 store = NewLIR3(opcode, r_src.GetReg(), 0, r_scratch.GetReg());
982 FreeTemp(r_scratch);
983 }
984
985 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
986 DCHECK_EQ(r_base, TargetPtrReg(kSp));
Lazar Trsicd9672662015-09-03 17:33:01 +0200987 AnnotateDalvikRegAccess(store, (displacement + LOWORD_OFFSET) >> 2,
988 false /* is_load */, r_src.Is64Bit() /* is64bit */);
989 if (store2 != nullptr) {
990 AnnotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2,
991 false /* is_load */, r_src.Is64Bit() /* is64bit */);
992 }
Goran Jakovljevic10957932015-03-24 18:42:56 +0100993 }
994 return res;
995 }
996
Brian Carlstrom7940e442013-07-12 13:46:57 -0700997 if (short_form) {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800998 if (!is64bit) {
buzbee2700f7e2014-03-07 09:46:20 -0800999 store = res = NewLIR3(opcode, r_src.GetReg(), displacement, r_base.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -07001000 } else {
Douglas Leung027f0ff2015-02-27 19:05:03 -08001001 if (fpuIs32Bit_ || !r_src.IsFloat()) {
1002 DCHECK(r_src.IsPair());
Goran Jakovljevic10957932015-03-24 18:42:56 +01001003 store = res = NewLIR3(opcode, r_src.GetLowReg(), displacement + LOWORD_OFFSET,
1004 r_base.GetReg());
Douglas Leung027f0ff2015-02-27 19:05:03 -08001005 store2 = NewLIR3(opcode, r_src.GetHighReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
1006 } else {
1007 // Here if 64bit fpu and r_src is a 64bit fp register
1008 RegStorage r_tmp = AllocTemp();
1009 r_src = Fp64ToSolo32(r_src);
Goran Jakovljevic10957932015-03-24 18:42:56 +01001010 store = res = NewLIR3(kMipsFswc1, r_src.GetReg(), displacement + LOWORD_OFFSET,
1011 r_base.GetReg());
Douglas Leung027f0ff2015-02-27 19:05:03 -08001012 NewLIR2(kMipsMfhc1, r_tmp.GetReg(), r_src.GetReg());
1013 store2 = NewLIR3(kMipsSw, r_tmp.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
1014 FreeTemp(r_tmp);
1015 }
Brian Carlstrom7940e442013-07-12 13:46:57 -07001016 }
1017 } else {
buzbee2700f7e2014-03-07 09:46:20 -08001018 RegStorage r_scratch = AllocTemp();
1019 res = OpRegRegImm(kOpAdd, r_scratch, r_base, displacement);
Douglas Leung027f0ff2015-02-27 19:05:03 -08001020 if (!is64bit) {
buzbee2700f7e2014-03-07 09:46:20 -08001021 store = NewLIR3(opcode, r_src.GetReg(), 0, r_scratch.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -07001022 } else {
Douglas Leung027f0ff2015-02-27 19:05:03 -08001023 if (fpuIs32Bit_ || !r_src.IsFloat()) {
1024 DCHECK(r_src.IsPair());
1025 store = NewLIR3(opcode, r_src.GetLowReg(), LOWORD_OFFSET, r_scratch.GetReg());
1026 store2 = NewLIR3(opcode, r_src.GetHighReg(), HIWORD_OFFSET, r_scratch.GetReg());
1027 } else {
1028 // Here if 64bit fpu and r_src is a 64bit fp register
1029 RegStorage r_tmp = AllocTemp();
1030 r_src = Fp64ToSolo32(r_src);
1031 store = NewLIR3(kMipsFswc1, r_src.GetReg(), LOWORD_OFFSET, r_scratch.GetReg());
1032 NewLIR2(kMipsMfhc1, r_tmp.GetReg(), r_src.GetReg());
1033 store2 = NewLIR3(kMipsSw, r_tmp.GetReg(), HIWORD_OFFSET, r_scratch.GetReg());
1034 FreeTemp(r_tmp);
1035 }
Brian Carlstrom7940e442013-07-12 13:46:57 -07001036 }
1037 FreeTemp(r_scratch);
1038 }
1039
Vladimir Marko8dea81c2014-06-06 14:50:36 +01001040 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
Goran Jakovljevic10957932015-03-24 18:42:56 +01001041 DCHECK_EQ(r_base, TargetPtrReg(kSp));
Douglas Leung027f0ff2015-02-27 19:05:03 -08001042 AnnotateDalvikRegAccess(store, (displacement + (is64bit ? LOWORD_OFFSET : 0)) >> 2,
1043 false /* is_load */, is64bit /* is64bit */);
1044 if (is64bit) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001045 AnnotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2,
Douglas Leung027f0ff2015-02-27 19:05:03 -08001046 false /* is_load */, is64bit /* is64bit */);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001047 }
1048 }
1049
1050 return res;
1051}
1052
Goran Jakovljevic10957932015-03-24 18:42:56 +01001053LIR* MipsMir2Lir::StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src, OpSize size,
1054 VolatileKind is_volatile) {
Andreas Gampe3c12c512014-06-24 18:46:29 +00001055 if (is_volatile == kVolatile) {
Hans Boehm48f5c472014-06-27 14:50:10 -07001056 // Ensure that prior accesses become visible to other threads first.
1057 GenMemBarrier(kAnyStore);
Andreas Gampe3c12c512014-06-24 18:46:29 +00001058 }
1059
Andreas Gampe3c12c512014-06-24 18:46:29 +00001060 LIR* store;
Goran Jakovljevic10957932015-03-24 18:42:56 +01001061 if (UNLIKELY(is_volatile == kVolatile && (size == k64 || size == kDouble) &&
1062 (!cu_->target64 || displacement & 0x7))) {
1063 // TODO: use lld/scd instructions for Mips64.
Douglas Leungd9cb8ae2014-07-09 14:28:35 -07001064 // Do atomic 64-bit load.
1065 store = GenAtomic64Store(r_base, displacement, r_src);
1066 } else {
1067 // TODO: base this on target.
1068 if (size == kWord) {
Goran Jakovljevic10957932015-03-24 18:42:56 +01001069 size = cu_->target64 ? k64 : k32;
Douglas Leungd9cb8ae2014-07-09 14:28:35 -07001070 }
1071 store = StoreBaseDispBody(r_base, displacement, r_src, size);
1072 }
Andreas Gampe3c12c512014-06-24 18:46:29 +00001073
1074 if (UNLIKELY(is_volatile == kVolatile)) {
Hans Boehm48f5c472014-06-27 14:50:10 -07001075 // Preserve order with respect to any subsequent volatile loads.
1076 // We need StoreLoad, but that generally requires the most expensive barrier.
1077 GenMemBarrier(kAnyAny);
Andreas Gampe3c12c512014-06-24 18:46:29 +00001078 }
1079
1080 return store;
Brian Carlstrom7940e442013-07-12 13:46:57 -07001081}
1082
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001083LIR* MipsMir2Lir::OpMem(OpKind op ATTRIBUTE_UNUSED,
1084 RegStorage r_base ATTRIBUTE_UNUSED,
1085 int disp ATTRIBUTE_UNUSED) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001086 LOG(FATAL) << "Unexpected use of OpMem for MIPS";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001087 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -07001088}
1089
Roland Levillain4b8f1ec2015-08-26 18:34:03 +01001090LIR* MipsMir2Lir::OpCondBranch(ConditionCode cc ATTRIBUTE_UNUSED, LIR* target ATTRIBUTE_UNUSED) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001091 LOG(FATAL) << "Unexpected use of OpCondBranch for MIPS";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001092 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -07001093}
1094
Andreas Gampe98430592014-07-27 19:44:50 -07001095LIR* MipsMir2Lir::InvokeTrampoline(OpKind op, RegStorage r_tgt, QuickEntrypointEnum trampoline) {
Goran Jakovljevic10957932015-03-24 18:42:56 +01001096 if (!cu_->target64 && IsDirectEntrypoint(trampoline)) {
Nikola Veljkovic2d873b62015-02-20 17:21:15 +01001097 // Reserve argument space on stack (for $a0-$a3) for
1098 // entrypoints that directly reference native implementations.
1099 // This is not safe in general, as it violates the frame size
1100 // of the Quick method, but it is used here only for calling
1101 // native functions, outside of the runtime.
1102 OpRegImm(kOpSub, rs_rSP, 16);
1103 LIR* retVal = OpReg(op, r_tgt);
1104 OpRegImm(kOpAdd, rs_rSP, 16);
1105 return retVal;
1106 }
1107
Andreas Gampe98430592014-07-27 19:44:50 -07001108 return OpReg(op, r_tgt);
1109}
1110
Goran Jakovljevic10957932015-03-24 18:42:56 +01001111RegStorage MipsMir2Lir::AllocPtrSizeTemp(bool required) {
1112 return cu_->target64 ? AllocTempWide(required) : AllocTemp(required);
1113}
1114
Brian Carlstrom7940e442013-07-12 13:46:57 -07001115} // namespace art