blob: 37e5804f180f07b43c84515aef4e7df12d0df3ad [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
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700106bool MipsMir2Lir::InexpensiveConstantFloat(int32_t value) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700107 UNUSED(value);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700108 return false; // TUNING
109}
110
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700111bool MipsMir2Lir::InexpensiveConstantLong(int64_t value) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700112 UNUSED(value);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700113 return false; // TUNING
114}
115
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700116bool MipsMir2Lir::InexpensiveConstantDouble(int64_t value) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700117 UNUSED(value);
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700118 return false; // TUNING
Brian Carlstrom7940e442013-07-12 13:46:57 -0700119}
120
121/*
122 * Load a immediate using a shortcut if possible; otherwise
123 * grab from the per-translation literal pool. If target is
124 * a high register, build constant into a low register and copy.
125 *
126 * No additional register clobbering operation performed. Use this version when
127 * 1) r_dest is freshly returned from AllocTemp or
128 * 2) The codegen is under fixed register usage
129 */
buzbee2700f7e2014-03-07 09:46:20 -0800130LIR* MipsMir2Lir::LoadConstantNoClobber(RegStorage r_dest, int value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700131 LIR *res;
132
buzbee2700f7e2014-03-07 09:46:20 -0800133 RegStorage r_dest_save = r_dest;
buzbee091cc402014-03-31 10:14:40 -0700134 int is_fp_reg = r_dest.IsFloat();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700135 if (is_fp_reg) {
buzbee091cc402014-03-31 10:14:40 -0700136 DCHECK(r_dest.IsSingle());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700137 r_dest = AllocTemp();
138 }
139
Goran Jakovljevic10957932015-03-24 18:42:56 +0100140 // See if the value can be constructed cheaply.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700141 if (value == 0) {
buzbee2700f7e2014-03-07 09:46:20 -0800142 res = NewLIR2(kMipsMove, r_dest.GetReg(), rZERO);
Andreas Gampeab1eb0d2015-02-13 19:23:55 -0800143 } else if (IsUint<16>(value)) {
144 // Use OR with (unsigned) immediate to encode 16b unsigned int.
buzbee2700f7e2014-03-07 09:46:20 -0800145 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZERO, value);
Andreas Gampeab1eb0d2015-02-13 19:23:55 -0800146 } else if (IsInt<16>(value)) {
147 // Use ADD with (signed) immediate to encode 16b signed int.
buzbee2700f7e2014-03-07 09:46:20 -0800148 res = NewLIR3(kMipsAddiu, r_dest.GetReg(), rZERO, value);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700149 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800150 res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700151 if (value & 0xffff)
buzbee2700f7e2014-03-07 09:46:20 -0800152 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), value);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700153 }
154
155 if (is_fp_reg) {
buzbee2700f7e2014-03-07 09:46:20 -0800156 NewLIR2(kMipsMtc1, r_dest.GetReg(), r_dest_save.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700157 FreeTemp(r_dest);
158 }
159
160 return res;
161}
162
Goran Jakovljevic10957932015-03-24 18:42:56 +0100163LIR* MipsMir2Lir::LoadConstantWideNoClobber(RegStorage r_dest, int64_t value) {
164 LIR* res = nullptr;
165 DCHECK(r_dest.Is64Bit());
166 RegStorage r_dest_save = r_dest;
167 int is_fp_reg = r_dest.IsFloat();
168 if (is_fp_reg) {
169 DCHECK(r_dest.IsDouble());
170 r_dest = AllocTemp();
171 }
172
173 int bit31 = (value & UINT64_C(0x80000000)) != 0;
174
175 // Loads with 1 instruction.
176 if (IsUint<16>(value)) {
177 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, value);
178 } else if (IsInt<16>(value)) {
179 res = NewLIR3(kMips64Daddiu, r_dest.GetReg(), rZEROd, value);
180 } else if ((value & 0xFFFF) == 0 && IsInt<16>(value >> 16)) {
181 res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
182 } else if (IsInt<32>(value)) {
183 // Loads with 2 instructions.
184 res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
185 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), value);
186 } else if ((value & 0xFFFF0000) == 0 && IsInt<16>(value >> 32)) {
187 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, value);
188 NewLIR2(kMips64Dahi, r_dest.GetReg(), value >> 32);
189 } else if ((value & UINT64_C(0xFFFFFFFF0000)) == 0) {
190 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, value);
191 NewLIR2(kMips64Dati, r_dest.GetReg(), value >> 48);
192 } else if ((value & 0xFFFF) == 0 && (value >> 32) >= (-32768 - bit31) &&
193 (value >> 32) <= (32767 - bit31)) {
194 res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
195 NewLIR2(kMips64Dahi, r_dest.GetReg(), (value >> 32) + bit31);
196 } else if ((value & 0xFFFF) == 0 && ((value >> 31) & 0x1FFFF) == ((0x20000 - bit31) & 0x1FFFF)) {
197 res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
198 NewLIR2(kMips64Dati, r_dest.GetReg(), (value >> 48) + bit31);
199 } else {
200 int64_t tmp = value;
201 int shift_cnt = 0;
202 while ((tmp & 1) == 0) {
203 tmp >>= 1;
204 shift_cnt++;
205 }
206
207 if (IsUint<16>(tmp)) {
208 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, tmp);
209 NewLIR3((shift_cnt < 32) ? kMips64Dsll : kMips64Dsll32, r_dest.GetReg(), r_dest.GetReg(),
210 shift_cnt & 0x1F);
211 } else if (IsInt<16>(tmp)) {
212 res = NewLIR3(kMips64Daddiu, r_dest.GetReg(), rZEROd, tmp);
213 NewLIR3((shift_cnt < 32) ? kMips64Dsll : kMips64Dsll32, r_dest.GetReg(), r_dest.GetReg(),
214 shift_cnt & 0x1F);
215 } else if (IsInt<32>(tmp)) {
216 // Loads with 3 instructions.
217 res = NewLIR2(kMipsLui, r_dest.GetReg(), tmp >> 16);
218 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), tmp);
219 NewLIR3((shift_cnt < 32) ? kMips64Dsll : kMips64Dsll32, r_dest.GetReg(), r_dest.GetReg(),
220 shift_cnt & 0x1F);
221 } else {
222 tmp = value >> 16;
223 shift_cnt = 16;
224 while ((tmp & 1) == 0) {
225 tmp >>= 1;
226 shift_cnt++;
227 }
228
229 if (IsUint<16>(tmp)) {
230 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, tmp);
231 NewLIR3((shift_cnt < 32) ? kMips64Dsll : kMips64Dsll32, r_dest.GetReg(), r_dest.GetReg(),
232 shift_cnt & 0x1F);
233 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), value);
234 } else if (IsInt<16>(tmp)) {
235 res = NewLIR3(kMips64Daddiu, r_dest.GetReg(), rZEROd, tmp);
236 NewLIR3((shift_cnt < 32) ? kMips64Dsll : kMips64Dsll32, r_dest.GetReg(), r_dest.GetReg(),
237 shift_cnt & 0x1F);
238 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), value);
239 } else {
240 // Loads with 3-4 instructions.
241 uint64_t tmp2 = value;
242 if (((tmp2 >> 16) & 0xFFFF) != 0 || (tmp2 & 0xFFFFFFFF) == 0) {
243 res = NewLIR2(kMipsLui, r_dest.GetReg(), tmp2 >> 16);
244 }
245 if ((tmp2 & 0xFFFF) != 0) {
246 if (res)
247 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), tmp2);
248 else
249 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZEROd, tmp2);
250 }
251 if (bit31) {
252 tmp2 += UINT64_C(0x100000000);
253 }
254 if (((tmp2 >> 32) & 0xFFFF) != 0) {
255 NewLIR2(kMips64Dahi, r_dest.GetReg(), tmp2 >> 32);
256 }
257 if (tmp2 & UINT64_C(0x800000000000)) {
258 tmp2 += UINT64_C(0x1000000000000);
259 }
260 if ((tmp2 >> 48) != 0) {
261 NewLIR2(kMips64Dati, r_dest.GetReg(), tmp2 >> 48);
262 }
263 }
264 }
265 }
266
267 if (is_fp_reg) {
268 NewLIR2(kMips64Dmtc1, r_dest.GetReg(), r_dest_save.GetReg());
269 FreeTemp(r_dest);
270 }
271 return res;
272}
273
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700274LIR* MipsMir2Lir::OpUnconditionalBranch(LIR* target) {
Brian Carlstromdf629502013-07-17 22:39:56 -0700275 LIR* res = NewLIR1(kMipsB, 0 /* offset to be patched during assembly*/);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700276 res->target = target;
277 return res;
278}
279
buzbee2700f7e2014-03-07 09:46:20 -0800280LIR* MipsMir2Lir::OpReg(OpKind op, RegStorage r_dest_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700281 MipsOpCode opcode = kMipsNop;
282 switch (op) {
283 case kOpBlx:
284 opcode = kMipsJalr;
285 break;
286 case kOpBx:
Andreas Gampe8d365912015-01-13 11:32:32 -0800287 return NewLIR2(kMipsJalr, rZERO, r_dest_src.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700288 default:
289 LOG(FATAL) << "Bad case in OpReg";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700290 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700291 }
Goran Jakovljevic10957932015-03-24 18:42:56 +0100292 return NewLIR2(opcode, cu_->target64 ? rRAd : rRA, r_dest_src.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700293}
294
buzbee2700f7e2014-03-07 09:46:20 -0800295LIR* MipsMir2Lir::OpRegImm(OpKind op, RegStorage r_dest_src1, int value) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100296 if ((op == kOpAdd) || (op == kOpSub)) {
297 return OpRegRegImm(op, r_dest_src1, r_dest_src1, value);
Brian Carlstrom9b7085a2013-07-18 15:15:21 -0700298 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100299 LOG(FATAL) << "Bad case in OpRegImm";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700300 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700301 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700302}
303
buzbee2700f7e2014-03-07 09:46:20 -0800304LIR* MipsMir2Lir::OpRegRegReg(OpKind op, RegStorage r_dest, RegStorage r_src1, RegStorage r_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700305 MipsOpCode opcode = kMipsNop;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100306 bool is64bit = cu_->target64 && (r_dest.Is64Bit() || r_src1.Is64Bit() || r_src2.Is64Bit());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700307 switch (op) {
308 case kOpAdd:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100309 opcode = is64bit ? kMips64Daddu : kMipsAddu;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700310 break;
311 case kOpSub:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100312 opcode = is64bit ? kMips64Dsubu : kMipsSubu;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700313 break;
314 case kOpAnd:
315 opcode = kMipsAnd;
316 break;
317 case kOpMul:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100318 opcode = isaIsR6_ ? kMipsR6Mul : kMipsR2Mul;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700319 break;
320 case kOpOr:
321 opcode = kMipsOr;
322 break;
323 case kOpXor:
324 opcode = kMipsXor;
325 break;
326 case kOpLsl:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100327 opcode = is64bit ? kMips64Dsllv : kMipsSllv;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700328 break;
329 case kOpLsr:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100330 opcode = is64bit ? kMips64Dsrlv : kMipsSrlv;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700331 break;
332 case kOpAsr:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100333 opcode = is64bit ? kMips64Dsrav : kMipsSrav;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700334 break;
335 case kOpAdc:
336 case kOpSbc:
337 LOG(FATAL) << "No carry bit on MIPS";
338 break;
339 default:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100340 LOG(FATAL) << "Bad case in OpRegRegReg";
Brian Carlstrom7940e442013-07-12 13:46:57 -0700341 break;
342 }
buzbee2700f7e2014-03-07 09:46:20 -0800343 return NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), r_src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700344}
345
buzbee2700f7e2014-03-07 09:46:20 -0800346LIR* MipsMir2Lir::OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src1, int value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700347 LIR *res;
348 MipsOpCode opcode = kMipsNop;
349 bool short_form = true;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100350 bool is64bit = cu_->target64 && (r_dest.Is64Bit() || r_src1.Is64Bit());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700351
352 switch (op) {
353 case kOpAdd:
354 if (IS_SIMM16(value)) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100355 opcode = is64bit ? kMips64Daddiu : kMipsAddiu;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700356 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700357 short_form = false;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100358 opcode = is64bit ? kMips64Daddu : kMipsAddu;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700359 }
360 break;
361 case kOpSub:
362 if (IS_SIMM16((-value))) {
363 value = -value;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100364 opcode = is64bit ? kMips64Daddiu : kMipsAddiu;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700365 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700366 short_form = false;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100367 opcode = is64bit ? kMips64Dsubu : kMipsSubu;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700368 }
369 break;
370 case kOpLsl:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100371 if (is64bit) {
372 DCHECK(value >= 0 && value <= 63);
373 if (value >= 0 && value <= 31) {
374 opcode = kMips64Dsll;
375 } else {
376 opcode = kMips64Dsll32;
377 value = value - 32;
378 }
379 } else {
380 DCHECK(value >= 0 && value <= 31);
381 opcode = kMipsSll;
382 }
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800383 break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700384 case kOpLsr:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100385 if (is64bit) {
386 DCHECK(value >= 0 && value <= 63);
387 if (value >= 0 && value <= 31) {
388 opcode = kMips64Dsrl;
389 } else {
390 opcode = kMips64Dsrl32;
391 value = value - 32;
392 }
393 } else {
394 DCHECK(value >= 0 && value <= 31);
395 opcode = kMipsSrl;
396 }
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800397 break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700398 case kOpAsr:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100399 if (is64bit) {
400 DCHECK(value >= 0 && value <= 63);
401 if (value >= 0 && value <= 31) {
402 opcode = kMips64Dsra;
403 } else {
404 opcode = kMips64Dsra32;
405 value = value - 32;
406 }
407 } else {
408 DCHECK(value >= 0 && value <= 31);
409 opcode = kMipsSra;
410 }
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800411 break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700412 case kOpAnd:
413 if (IS_UIMM16((value))) {
414 opcode = kMipsAndi;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700415 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700416 short_form = false;
417 opcode = kMipsAnd;
418 }
419 break;
420 case kOpOr:
421 if (IS_UIMM16((value))) {
422 opcode = kMipsOri;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700423 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700424 short_form = false;
425 opcode = kMipsOr;
426 }
427 break;
428 case kOpXor:
429 if (IS_UIMM16((value))) {
430 opcode = kMipsXori;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700431 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700432 short_form = false;
433 opcode = kMipsXor;
434 }
435 break;
436 case kOpMul:
437 short_form = false;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100438 opcode = isaIsR6_ ? kMipsR6Mul : kMipsR2Mul;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700439 break;
440 default:
441 LOG(FATAL) << "Bad case in OpRegRegImm";
442 break;
443 }
444
Brian Carlstrom9b7085a2013-07-18 15:15:21 -0700445 if (short_form) {
buzbee2700f7e2014-03-07 09:46:20 -0800446 res = NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), value);
Brian Carlstrom9b7085a2013-07-18 15:15:21 -0700447 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700448 if (r_dest != r_src1) {
449 res = LoadConstant(r_dest, value);
buzbee2700f7e2014-03-07 09:46:20 -0800450 NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), r_dest.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700451 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100452 RegStorage r_scratch;
453 if (is64bit) {
454 r_scratch = AllocTempWide();
455 res = LoadConstantWide(r_scratch, value);
456 } else {
457 r_scratch = AllocTemp();
458 res = LoadConstant(r_scratch, value);
459 }
buzbee2700f7e2014-03-07 09:46:20 -0800460 NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), r_scratch.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700461 }
462 }
463 return res;
464}
465
buzbee2700f7e2014-03-07 09:46:20 -0800466LIR* MipsMir2Lir::OpRegReg(OpKind op, RegStorage r_dest_src1, RegStorage r_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700467 MipsOpCode opcode = kMipsNop;
468 LIR *res;
469 switch (op) {
470 case kOpMov:
471 opcode = kMipsMove;
472 break;
473 case kOpMvn:
buzbee2700f7e2014-03-07 09:46:20 -0800474 return NewLIR3(kMipsNor, r_dest_src1.GetReg(), r_src2.GetReg(), rZERO);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700475 case kOpNeg:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100476 if (cu_->target64 && r_dest_src1.Is64Bit()) {
477 return NewLIR3(kMips64Dsubu, r_dest_src1.GetReg(), rZEROd, r_src2.GetReg());
478 } else {
479 return NewLIR3(kMipsSubu, r_dest_src1.GetReg(), rZERO, r_src2.GetReg());
480 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700481 case kOpAdd:
482 case kOpAnd:
483 case kOpMul:
484 case kOpOr:
485 case kOpSub:
486 case kOpXor:
487 return OpRegRegReg(op, r_dest_src1, r_dest_src1, r_src2);
488 case kOp2Byte:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100489 if (cu_->target64) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800490 res = NewLIR2(kMipsSeb, r_dest_src1.GetReg(), r_src2.GetReg());
491 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100492 if (cu_->compiler_driver->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()
493 ->IsMipsIsaRevGreaterThanEqual2()) {
494 res = NewLIR2(kMipsSeb, r_dest_src1.GetReg(), r_src2.GetReg());
495 } else {
496 res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 24);
497 OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 24);
498 }
Ian Rogersd582fa42014-11-05 23:46:43 -0800499 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700500 return res;
501 case kOp2Short:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100502 if (cu_->target64) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800503 res = NewLIR2(kMipsSeh, r_dest_src1.GetReg(), r_src2.GetReg());
504 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100505 if (cu_->compiler_driver->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()
506 ->IsMipsIsaRevGreaterThanEqual2()) {
507 res = NewLIR2(kMipsSeh, r_dest_src1.GetReg(), r_src2.GetReg());
508 } else {
509 res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 16);
510 OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 16);
511 }
Ian Rogersd582fa42014-11-05 23:46:43 -0800512 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700513 return res;
514 case kOp2Char:
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800515 return NewLIR3(kMipsAndi, r_dest_src1.GetReg(), r_src2.GetReg(), 0xFFFF);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700516 default:
517 LOG(FATAL) << "Bad case in OpRegReg";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700518 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700519 }
buzbee2700f7e2014-03-07 09:46:20 -0800520 return NewLIR2(opcode, r_dest_src1.GetReg(), r_src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700521}
522
buzbee2700f7e2014-03-07 09:46:20 -0800523LIR* MipsMir2Lir::OpMovRegMem(RegStorage r_dest, RegStorage r_base, int offset,
524 MoveType move_type) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700525 UNUSED(r_dest, r_base, offset, move_type);
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
buzbee2700f7e2014-03-07 09:46:20 -0800530LIR* MipsMir2Lir::OpMovMemReg(RegStorage r_base, int offset, RegStorage r_src, MoveType move_type) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700531 UNUSED(r_base, offset, r_src, move_type);
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
buzbee2700f7e2014-03-07 09:46:20 -0800536LIR* MipsMir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, RegStorage r_dest, RegStorage r_src) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700537 UNUSED(op, cc, r_dest, r_src);
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800538 LOG(FATAL) << "Unexpected use of OpCondRegReg for MIPS";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700539 UNREACHABLE();
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800540}
541
buzbee2700f7e2014-03-07 09:46:20 -0800542LIR* MipsMir2Lir::LoadConstantWide(RegStorage r_dest, int64_t value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700543 LIR *res;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100544 if (cu_->target64) {
545 res = LoadConstantWideNoClobber(r_dest, value);
546 return res;
547 }
Douglas Leung027f0ff2015-02-27 19:05:03 -0800548 if (fpuIs32Bit_ || !r_dest.IsFloat()) {
549 // 32bit FPU (pairs) or loading into GPR.
550 if (!r_dest.IsPair()) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100551 // Form 64-bit pair.
Douglas Leung027f0ff2015-02-27 19:05:03 -0800552 r_dest = Solo64ToPair64(r_dest);
553 }
554 res = LoadConstantNoClobber(r_dest.GetLow(), Low32Bits(value));
555 LoadConstantNoClobber(r_dest.GetHigh(), High32Bits(value));
556 } else {
557 // Here if we have a 64bit FPU and loading into FPR.
558 RegStorage r_temp = AllocTemp();
559 r_dest = Fp64ToSolo32(r_dest);
560 res = LoadConstantNoClobber(r_dest, Low32Bits(value));
561 LoadConstantNoClobber(r_temp, High32Bits(value));
562 NewLIR2(kMipsMthc1, r_temp.GetReg(), r_dest.GetReg());
563 FreeTemp(r_temp);
Douglas Leung2db3e262014-06-25 16:02:55 -0700564 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700565 return res;
566}
567
568/* Load value from base + scaled index. */
buzbee2700f7e2014-03-07 09:46:20 -0800569LIR* MipsMir2Lir::LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700570 int scale, OpSize size) {
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700571 LIR *first = nullptr;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700572 LIR *res;
573 MipsOpCode opcode = kMipsNop;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100574 bool is64bit = cu_->target64 && r_dest.Is64Bit();
575 RegStorage t_reg = is64bit ? AllocTempWide() : AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700576
buzbee091cc402014-03-31 10:14:40 -0700577 if (r_dest.IsFloat()) {
578 DCHECK(r_dest.IsSingle());
buzbeefd698e62014-04-27 19:33:22 -0700579 DCHECK((size == k32) || (size == kSingle) || (size == kReference));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700580 size = kSingle;
581 } else {
582 if (size == kSingle)
buzbee695d13a2014-04-19 13:32:20 -0700583 size = k32;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700584 }
585
Goran Jakovljevic10957932015-03-24 18:42:56 +0100586 if (cu_->target64) {
587 if (!scale) {
588 if (is64bit) {
589 first = NewLIR3(kMips64Daddu, t_reg.GetReg() , r_base.GetReg(), r_index.GetReg());
590 } else {
591 first = NewLIR3(kMipsAddu, t_reg.GetReg() , r_base.GetReg(), r_index.GetReg());
592 }
593 } else {
594 first = OpRegRegImm(kOpLsl, t_reg, r_index, scale);
595 NewLIR3(kMips64Daddu, t_reg.GetReg() , r_base.GetReg(), t_reg.GetReg());
596 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700597 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100598 if (!scale) {
599 first = NewLIR3(kMipsAddu, t_reg.GetReg() , r_base.GetReg(), r_index.GetReg());
600 } else {
601 first = OpRegRegImm(kOpLsl, t_reg, r_index, scale);
602 NewLIR3(kMipsAddu, t_reg.GetReg() , r_base.GetReg(), t_reg.GetReg());
603 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700604 }
605
606 switch (size) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100607 case k64:
608 if (cu_->target64) {
609 opcode = kMips64Ld;
610 } else {
611 LOG(FATAL) << "Bad case in LoadBaseIndexed";
612 }
613 break;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700614 case kSingle:
615 opcode = kMipsFlwc1;
616 break;
buzbee695d13a2014-04-19 13:32:20 -0700617 case k32:
618 case kReference:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700619 opcode = kMipsLw;
620 break;
621 case kUnsignedHalf:
622 opcode = kMipsLhu;
623 break;
624 case kSignedHalf:
625 opcode = kMipsLh;
626 break;
627 case kUnsignedByte:
628 opcode = kMipsLbu;
629 break;
630 case kSignedByte:
631 opcode = kMipsLb;
632 break;
633 default:
634 LOG(FATAL) << "Bad case in LoadBaseIndexed";
635 }
636
buzbee2700f7e2014-03-07 09:46:20 -0800637 res = NewLIR3(opcode, r_dest.GetReg(), 0, t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700638 FreeTemp(t_reg);
639 return (first) ? first : res;
640}
641
Goran Jakovljevic10957932015-03-24 18:42:56 +0100642// Store value base base + scaled index.
buzbee2700f7e2014-03-07 09:46:20 -0800643LIR* MipsMir2Lir::StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700644 int scale, OpSize size) {
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700645 LIR *first = nullptr;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700646 MipsOpCode opcode = kMipsNop;
buzbee2700f7e2014-03-07 09:46:20 -0800647 RegStorage t_reg = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700648
buzbee091cc402014-03-31 10:14:40 -0700649 if (r_src.IsFloat()) {
650 DCHECK(r_src.IsSingle());
buzbeefd698e62014-04-27 19:33:22 -0700651 DCHECK((size == k32) || (size == kSingle) || (size == kReference));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700652 size = kSingle;
653 } else {
654 if (size == kSingle)
buzbee695d13a2014-04-19 13:32:20 -0700655 size = k32;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700656 }
657
Goran Jakovljevic10957932015-03-24 18:42:56 +0100658 MipsOpCode add_opcode = cu_->target64 ? kMips64Daddu : kMipsAddu;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700659 if (!scale) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100660 first = NewLIR3(add_opcode, t_reg.GetReg() , r_base.GetReg(), r_index.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700661 } else {
662 first = OpRegRegImm(kOpLsl, t_reg, r_index, scale);
Goran Jakovljevic10957932015-03-24 18:42:56 +0100663 NewLIR3(add_opcode, t_reg.GetReg() , r_base.GetReg(), t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700664 }
665
666 switch (size) {
667 case kSingle:
668 opcode = kMipsFswc1;
669 break;
buzbee695d13a2014-04-19 13:32:20 -0700670 case k32:
671 case kReference:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700672 opcode = kMipsSw;
673 break;
674 case kUnsignedHalf:
675 case kSignedHalf:
676 opcode = kMipsSh;
677 break;
678 case kUnsignedByte:
679 case kSignedByte:
680 opcode = kMipsSb;
681 break;
682 default:
683 LOG(FATAL) << "Bad case in StoreBaseIndexed";
684 }
buzbee2700f7e2014-03-07 09:46:20 -0800685 NewLIR3(opcode, r_src.GetReg(), 0, t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700686 return first;
687}
688
buzbee2700f7e2014-03-07 09:46:20 -0800689// FIXME: don't split r_dest into 2 containers.
690LIR* MipsMir2Lir::LoadBaseDispBody(RegStorage r_base, int displacement, RegStorage r_dest,
Douglas Leung2db3e262014-06-25 16:02:55 -0700691 OpSize size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700692/*
693 * Load value from base + displacement. Optionally perform null check
694 * on base (which must have an associated s_reg and MIR). If not
695 * performing null check, incoming MIR can be null. IMPORTANT: this
696 * code must not allocate any new temps. If a new register is needed
697 * and base and dest are the same, spill some other register to
698 * rlp and then restore.
699 */
Brian Carlstrom7940e442013-07-12 13:46:57 -0700700 LIR *res;
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700701 LIR *load = nullptr;
702 LIR *load2 = nullptr;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700703 MipsOpCode opcode = kMipsNop;
704 bool short_form = IS_SIMM16(displacement);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800705 bool is64bit = false;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700706
707 switch (size) {
buzbee695d13a2014-04-19 13:32:20 -0700708 case k64:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700709 case kDouble:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100710 if (cu_->target64) {
711 r_dest = Check64BitReg(r_dest);
712 if (!r_dest.IsFloat()) {
713 opcode = kMips64Ld;
714 } else {
715 opcode = kMipsFldc1;
716 }
717 DCHECK_EQ((displacement & 0x3), 0);
718 break;
719 }
Douglas Leung027f0ff2015-02-27 19:05:03 -0800720 is64bit = true;
721 if (fpuIs32Bit_ && !r_dest.IsPair()) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100722 // Form 64-bit pair.
Douglas Leung2db3e262014-06-25 16:02:55 -0700723 r_dest = Solo64ToPair64(r_dest);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700724 }
725 short_form = IS_SIMM16_2WORD(displacement);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800726 FALLTHROUGH_INTENDED;
buzbee695d13a2014-04-19 13:32:20 -0700727 case k32:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700728 case kSingle:
buzbee695d13a2014-04-19 13:32:20 -0700729 case kReference:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700730 opcode = kMipsLw;
buzbee091cc402014-03-31 10:14:40 -0700731 if (r_dest.IsFloat()) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700732 opcode = kMipsFlwc1;
Douglas Leung027f0ff2015-02-27 19:05:03 -0800733 if (!is64bit) {
734 DCHECK(r_dest.IsSingle());
735 } else {
736 DCHECK(r_dest.IsDouble());
737 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700738 }
739 DCHECK_EQ((displacement & 0x3), 0);
740 break;
741 case kUnsignedHalf:
742 opcode = kMipsLhu;
743 DCHECK_EQ((displacement & 0x1), 0);
744 break;
745 case kSignedHalf:
746 opcode = kMipsLh;
747 DCHECK_EQ((displacement & 0x1), 0);
748 break;
749 case kUnsignedByte:
750 opcode = kMipsLbu;
751 break;
752 case kSignedByte:
753 opcode = kMipsLb;
754 break;
755 default:
756 LOG(FATAL) << "Bad case in LoadBaseIndexedBody";
757 }
758
Goran Jakovljevic10957932015-03-24 18:42:56 +0100759 if (cu_->target64) {
760 if (short_form) {
761 load = res = NewLIR3(opcode, r_dest.GetReg(), displacement, r_base.GetReg());
762 } else {
763 RegStorage r_tmp = (r_base == r_dest) ? AllocTemp() : r_dest;
764 res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement);
765 load = NewLIR3(opcode, r_dest.GetReg(), 0, r_tmp.GetReg());
766 if (r_tmp != r_dest)
767 FreeTemp(r_tmp);
768 }
769
770 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
771 DCHECK_EQ(r_base, TargetPtrReg(kSp));
772 AnnotateDalvikRegAccess(load, displacement >> 2, true /* is_load */, r_dest.Is64Bit());
773 }
774 return res;
775 }
776
Brian Carlstrom7940e442013-07-12 13:46:57 -0700777 if (short_form) {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800778 if (!is64bit) {
buzbee2700f7e2014-03-07 09:46:20 -0800779 load = res = NewLIR3(opcode, r_dest.GetReg(), displacement, r_base.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700780 } else {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800781 if (fpuIs32Bit_ || !r_dest.IsFloat()) {
782 DCHECK(r_dest.IsPair());
Goran Jakovljevic10957932015-03-24 18:42:56 +0100783 load = res = NewLIR3(opcode, r_dest.GetLowReg(), displacement + LOWORD_OFFSET,
784 r_base.GetReg());
Douglas Leung027f0ff2015-02-27 19:05:03 -0800785 load2 = NewLIR3(opcode, r_dest.GetHighReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
786 } else {
787 // Here if 64bit fpu and r_dest is a 64bit fp register.
788 RegStorage r_tmp = AllocTemp();
789 // FIXME: why is r_dest a 64BitPair here???
790 r_dest = Fp64ToSolo32(r_dest);
Goran Jakovljevic10957932015-03-24 18:42:56 +0100791 load = res = NewLIR3(kMipsFlwc1, r_dest.GetReg(), displacement + LOWORD_OFFSET,
792 r_base.GetReg());
Douglas Leung027f0ff2015-02-27 19:05:03 -0800793 load2 = NewLIR3(kMipsLw, r_tmp.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
794 NewLIR2(kMipsMthc1, r_tmp.GetReg(), r_dest.GetReg());
795 FreeTemp(r_tmp);
796 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700797 }
798 } else {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800799 if (!is64bit) {
800 RegStorage r_tmp = (r_base == r_dest || r_dest.IsFloat()) ? AllocTemp() : r_dest;
buzbee2700f7e2014-03-07 09:46:20 -0800801 res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement);
802 load = NewLIR3(opcode, r_dest.GetReg(), 0, r_tmp.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700803 if (r_tmp != r_dest)
804 FreeTemp(r_tmp);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800805 } else {
806 RegStorage r_tmp = AllocTemp();
807 res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement);
808 if (fpuIs32Bit_ || !r_dest.IsFloat()) {
809 DCHECK(r_dest.IsPair());
810 load = NewLIR3(opcode, r_dest.GetLowReg(), LOWORD_OFFSET, r_tmp.GetReg());
811 load2 = NewLIR3(opcode, r_dest.GetHighReg(), HIWORD_OFFSET, r_tmp.GetReg());
812 } else {
813 // Here if 64bit fpu and r_dest is a 64bit fp register
814 r_dest = Fp64ToSolo32(r_dest);
815 load = res = NewLIR3(kMipsFlwc1, r_dest.GetReg(), LOWORD_OFFSET, r_tmp.GetReg());
816 load2 = NewLIR3(kMipsLw, r_tmp.GetReg(), HIWORD_OFFSET, r_tmp.GetReg());
817 NewLIR2(kMipsMthc1, r_tmp.GetReg(), r_dest.GetReg());
818 }
819 FreeTemp(r_tmp);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700820 }
821 }
822
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100823 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100824 DCHECK_EQ(r_base, TargetPtrReg(kSp));
Douglas Leung027f0ff2015-02-27 19:05:03 -0800825 AnnotateDalvikRegAccess(load, (displacement + (is64bit ? LOWORD_OFFSET : 0)) >> 2,
826 true /* is_load */, is64bit /* is64bit */);
827 if (is64bit) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700828 AnnotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2,
Douglas Leung027f0ff2015-02-27 19:05:03 -0800829 true /* is_load */, is64bit /* is64bit */);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700830 }
831 }
Goran Jakovljevic10957932015-03-24 18:42:56 +0100832 return res;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700833}
834
Douglas Leung22bb5a22015-07-02 16:42:08 -0700835void MipsMir2Lir::ForceImplicitNullCheck(RegStorage reg, int opt_flags, bool is_wide) {
836 if (cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
837 if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) {
838 return;
839 }
840 // Force an implicit null check by performing a memory operation (load) from the given
841 // register with offset 0. This will cause a signal if the register contains 0 (null).
842 LIR* load = Load32Disp(reg, LOWORD_OFFSET, rs_rZERO);
843 MarkSafepointPC(load);
844 if (is_wide) {
845 load = Load32Disp(reg, HIWORD_OFFSET, rs_rZERO);
846 MarkSafepointPC(load);
847 }
848 }
849}
850
Goran Jakovljevic10957932015-03-24 18:42:56 +0100851LIR* MipsMir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest, OpSize size,
852 VolatileKind is_volatile) {
853 if (UNLIKELY(is_volatile == kVolatile && (size == k64 || size == kDouble))
854 && (!cu_->target64 || displacement & 0x7)) {
855 // TODO: use lld/scd instructions for Mips64.
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700856 // Do atomic 64-bit load.
857 return GenAtomic64Load(r_base, displacement, r_dest);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000858 }
859
buzbee695d13a2014-04-19 13:32:20 -0700860 // TODO: base this on target.
861 if (size == kWord) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100862 size = cu_->target64 ? k64 : k32;
buzbee695d13a2014-04-19 13:32:20 -0700863 }
Andreas Gampe3c12c512014-06-24 18:46:29 +0000864 LIR* load;
Douglas Leung2db3e262014-06-25 16:02:55 -0700865 load = LoadBaseDispBody(r_base, displacement, r_dest, size);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000866
867 if (UNLIKELY(is_volatile == kVolatile)) {
Hans Boehm48f5c472014-06-27 14:50:10 -0700868 GenMemBarrier(kLoadAny);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000869 }
870
871 return load;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700872}
873
Vladimir Marko455759b2014-05-06 20:49:36 +0100874// FIXME: don't split r_dest into 2 containers.
Goran Jakovljevic10957932015-03-24 18:42:56 +0100875LIR* MipsMir2Lir::StoreBaseDispBody(RegStorage r_base, int displacement, RegStorage r_src,
876 OpSize size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700877 LIR *res;
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700878 LIR *store = nullptr;
879 LIR *store2 = nullptr;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700880 MipsOpCode opcode = kMipsNop;
881 bool short_form = IS_SIMM16(displacement);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800882 bool is64bit = false;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700883
884 switch (size) {
buzbee695d13a2014-04-19 13:32:20 -0700885 case k64:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700886 case kDouble:
Goran Jakovljevic10957932015-03-24 18:42:56 +0100887 if (cu_->target64) {
888 r_src = Check64BitReg(r_src);
889 if (!r_src.IsFloat()) {
890 opcode = kMips64Sd;
891 } else {
892 opcode = kMipsFsdc1;
893 }
894 DCHECK_EQ((displacement & 0x3), 0);
895 break;
896 }
Douglas Leung027f0ff2015-02-27 19:05:03 -0800897 is64bit = true;
898 if (fpuIs32Bit_ && !r_src.IsPair()) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100899 // Form 64-bit pair.
Douglas Leung2db3e262014-06-25 16:02:55 -0700900 r_src = Solo64ToPair64(r_src);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700901 }
902 short_form = IS_SIMM16_2WORD(displacement);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800903 FALLTHROUGH_INTENDED;
buzbee695d13a2014-04-19 13:32:20 -0700904 case k32:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700905 case kSingle:
buzbee695d13a2014-04-19 13:32:20 -0700906 case kReference:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700907 opcode = kMipsSw;
buzbee091cc402014-03-31 10:14:40 -0700908 if (r_src.IsFloat()) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700909 opcode = kMipsFswc1;
Douglas Leung027f0ff2015-02-27 19:05:03 -0800910 if (!is64bit) {
911 DCHECK(r_src.IsSingle());
912 } else {
913 DCHECK(r_src.IsDouble());
914 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700915 }
916 DCHECK_EQ((displacement & 0x3), 0);
917 break;
918 case kUnsignedHalf:
919 case kSignedHalf:
920 opcode = kMipsSh;
921 DCHECK_EQ((displacement & 0x1), 0);
922 break;
923 case kUnsignedByte:
924 case kSignedByte:
925 opcode = kMipsSb;
926 break;
927 default:
buzbee2700f7e2014-03-07 09:46:20 -0800928 LOG(FATAL) << "Bad case in StoreBaseDispBody";
Brian Carlstrom7940e442013-07-12 13:46:57 -0700929 }
930
Goran Jakovljevic10957932015-03-24 18:42:56 +0100931 if (cu_->target64) {
932 if (short_form) {
933 store = res = NewLIR3(opcode, r_src.GetReg(), displacement, r_base.GetReg());
934 } else {
935 RegStorage r_scratch = AllocTemp();
936 res = OpRegRegImm(kOpAdd, r_scratch, r_base, displacement);
937 store = NewLIR3(opcode, r_src.GetReg(), 0, r_scratch.GetReg());
938 FreeTemp(r_scratch);
939 }
940
941 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
942 DCHECK_EQ(r_base, TargetPtrReg(kSp));
943 AnnotateDalvikRegAccess(store, displacement >> 2, false /* is_load */, r_src.Is64Bit());
944 }
945 return res;
946 }
947
Brian Carlstrom7940e442013-07-12 13:46:57 -0700948 if (short_form) {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800949 if (!is64bit) {
buzbee2700f7e2014-03-07 09:46:20 -0800950 store = res = NewLIR3(opcode, r_src.GetReg(), displacement, r_base.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700951 } else {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800952 if (fpuIs32Bit_ || !r_src.IsFloat()) {
953 DCHECK(r_src.IsPair());
Goran Jakovljevic10957932015-03-24 18:42:56 +0100954 store = res = NewLIR3(opcode, r_src.GetLowReg(), displacement + LOWORD_OFFSET,
955 r_base.GetReg());
Douglas Leung027f0ff2015-02-27 19:05:03 -0800956 store2 = NewLIR3(opcode, r_src.GetHighReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
957 } else {
958 // Here if 64bit fpu and r_src is a 64bit fp register
959 RegStorage r_tmp = AllocTemp();
960 r_src = Fp64ToSolo32(r_src);
Goran Jakovljevic10957932015-03-24 18:42:56 +0100961 store = res = NewLIR3(kMipsFswc1, r_src.GetReg(), displacement + LOWORD_OFFSET,
962 r_base.GetReg());
Douglas Leung027f0ff2015-02-27 19:05:03 -0800963 NewLIR2(kMipsMfhc1, r_tmp.GetReg(), r_src.GetReg());
964 store2 = NewLIR3(kMipsSw, r_tmp.GetReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
965 FreeTemp(r_tmp);
966 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700967 }
968 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800969 RegStorage r_scratch = AllocTemp();
970 res = OpRegRegImm(kOpAdd, r_scratch, r_base, displacement);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800971 if (!is64bit) {
buzbee2700f7e2014-03-07 09:46:20 -0800972 store = NewLIR3(opcode, r_src.GetReg(), 0, r_scratch.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700973 } else {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800974 if (fpuIs32Bit_ || !r_src.IsFloat()) {
975 DCHECK(r_src.IsPair());
976 store = NewLIR3(opcode, r_src.GetLowReg(), LOWORD_OFFSET, r_scratch.GetReg());
977 store2 = NewLIR3(opcode, r_src.GetHighReg(), HIWORD_OFFSET, r_scratch.GetReg());
978 } else {
979 // Here if 64bit fpu and r_src is a 64bit fp register
980 RegStorage r_tmp = AllocTemp();
981 r_src = Fp64ToSolo32(r_src);
982 store = NewLIR3(kMipsFswc1, r_src.GetReg(), LOWORD_OFFSET, r_scratch.GetReg());
983 NewLIR2(kMipsMfhc1, r_tmp.GetReg(), r_src.GetReg());
984 store2 = NewLIR3(kMipsSw, r_tmp.GetReg(), HIWORD_OFFSET, r_scratch.GetReg());
985 FreeTemp(r_tmp);
986 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700987 }
988 FreeTemp(r_scratch);
989 }
990
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100991 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100992 DCHECK_EQ(r_base, TargetPtrReg(kSp));
Douglas Leung027f0ff2015-02-27 19:05:03 -0800993 AnnotateDalvikRegAccess(store, (displacement + (is64bit ? LOWORD_OFFSET : 0)) >> 2,
994 false /* is_load */, is64bit /* is64bit */);
995 if (is64bit) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700996 AnnotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2,
Douglas Leung027f0ff2015-02-27 19:05:03 -0800997 false /* is_load */, is64bit /* is64bit */);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700998 }
999 }
1000
1001 return res;
1002}
1003
Goran Jakovljevic10957932015-03-24 18:42:56 +01001004LIR* MipsMir2Lir::StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src, OpSize size,
1005 VolatileKind is_volatile) {
Andreas Gampe3c12c512014-06-24 18:46:29 +00001006 if (is_volatile == kVolatile) {
Hans Boehm48f5c472014-06-27 14:50:10 -07001007 // Ensure that prior accesses become visible to other threads first.
1008 GenMemBarrier(kAnyStore);
Andreas Gampe3c12c512014-06-24 18:46:29 +00001009 }
1010
Andreas Gampe3c12c512014-06-24 18:46:29 +00001011 LIR* store;
Goran Jakovljevic10957932015-03-24 18:42:56 +01001012 if (UNLIKELY(is_volatile == kVolatile && (size == k64 || size == kDouble) &&
1013 (!cu_->target64 || displacement & 0x7))) {
1014 // TODO: use lld/scd instructions for Mips64.
Douglas Leungd9cb8ae2014-07-09 14:28:35 -07001015 // Do atomic 64-bit load.
1016 store = GenAtomic64Store(r_base, displacement, r_src);
1017 } else {
1018 // TODO: base this on target.
1019 if (size == kWord) {
Goran Jakovljevic10957932015-03-24 18:42:56 +01001020 size = cu_->target64 ? k64 : k32;
Douglas Leungd9cb8ae2014-07-09 14:28:35 -07001021 }
1022 store = StoreBaseDispBody(r_base, displacement, r_src, size);
1023 }
Andreas Gampe3c12c512014-06-24 18:46:29 +00001024
1025 if (UNLIKELY(is_volatile == kVolatile)) {
Hans Boehm48f5c472014-06-27 14:50:10 -07001026 // Preserve order with respect to any subsequent volatile loads.
1027 // We need StoreLoad, but that generally requires the most expensive barrier.
1028 GenMemBarrier(kAnyAny);
Andreas Gampe3c12c512014-06-24 18:46:29 +00001029 }
1030
1031 return store;
Brian Carlstrom7940e442013-07-12 13:46:57 -07001032}
1033
buzbee2700f7e2014-03-07 09:46:20 -08001034LIR* MipsMir2Lir::OpMem(OpKind op, RegStorage r_base, int disp) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001035 UNUSED(op, r_base, disp);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001036 LOG(FATAL) << "Unexpected use of OpMem for MIPS";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001037 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -07001038}
1039
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001040LIR* MipsMir2Lir::OpCondBranch(ConditionCode cc, LIR* target) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001041 UNUSED(cc, target);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001042 LOG(FATAL) << "Unexpected use of OpCondBranch for MIPS";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001043 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -07001044}
1045
Andreas Gampe98430592014-07-27 19:44:50 -07001046LIR* MipsMir2Lir::InvokeTrampoline(OpKind op, RegStorage r_tgt, QuickEntrypointEnum trampoline) {
Goran Jakovljevic10957932015-03-24 18:42:56 +01001047 if (!cu_->target64 && IsDirectEntrypoint(trampoline)) {
Nikola Veljkovic2d873b62015-02-20 17:21:15 +01001048 // Reserve argument space on stack (for $a0-$a3) for
1049 // entrypoints that directly reference native implementations.
1050 // This is not safe in general, as it violates the frame size
1051 // of the Quick method, but it is used here only for calling
1052 // native functions, outside of the runtime.
1053 OpRegImm(kOpSub, rs_rSP, 16);
1054 LIR* retVal = OpReg(op, r_tgt);
1055 OpRegImm(kOpAdd, rs_rSP, 16);
1056 return retVal;
1057 }
1058
Andreas Gampe98430592014-07-27 19:44:50 -07001059 return OpReg(op, r_tgt);
1060}
1061
Goran Jakovljevic10957932015-03-24 18:42:56 +01001062RegStorage MipsMir2Lir::AllocPtrSizeTemp(bool required) {
1063 return cu_->target64 ? AllocTempWide(required) : AllocTemp(required);
1064}
1065
Brian Carlstrom7940e442013-07-12 13:46:57 -07001066} // namespace art