blob: 044972cc5f72d44c06a27903153e9c5952945fbb [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"
18#include "dex/quick/mir_to_lir-inl.h"
buzbeeb5860fb2014-06-21 15:31:01 -070019#include "dex/reg_storage_eq.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070020#include "mips_lir.h"
21
22namespace art {
23
24/* This file contains codegen for the MIPS32 ISA. */
buzbee2700f7e2014-03-07 09:46:20 -080025LIR* MipsMir2Lir::OpFpRegCopy(RegStorage r_dest, RegStorage r_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070026 int opcode;
27 /* must be both DOUBLE or both not DOUBLE */
buzbee091cc402014-03-31 10:14:40 -070028 DCHECK_EQ(r_dest.IsDouble(), r_src.IsDouble());
29 if (r_dest.IsDouble()) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070030 opcode = kMipsFmovd;
31 } else {
buzbee091cc402014-03-31 10:14:40 -070032 if (r_dest.IsSingle()) {
33 if (r_src.IsSingle()) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070034 opcode = kMipsFmovs;
35 } else {
36 /* note the operands are swapped for the mtc1 instr */
buzbee2700f7e2014-03-07 09:46:20 -080037 RegStorage t_opnd = r_src;
Brian Carlstrom7940e442013-07-12 13:46:57 -070038 r_src = r_dest;
39 r_dest = t_opnd;
40 opcode = kMipsMtc1;
41 }
42 } else {
buzbee091cc402014-03-31 10:14:40 -070043 DCHECK(r_src.IsSingle());
Brian Carlstrom7940e442013-07-12 13:46:57 -070044 opcode = kMipsMfc1;
45 }
46 }
buzbee2700f7e2014-03-07 09:46:20 -080047 LIR* res = RawLIR(current_dalvik_offset_, opcode, r_src.GetReg(), r_dest.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -070048 if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
49 res->flags.is_nop = true;
50 }
51 return res;
52}
53
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070054bool MipsMir2Lir::InexpensiveConstantInt(int32_t value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070055 return ((value == 0) || IsUint(16, value) || ((value < 0) && (value >= -32768)));
56}
57
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070058bool MipsMir2Lir::InexpensiveConstantFloat(int32_t value) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070059 UNUSED(value);
Brian Carlstrom7940e442013-07-12 13:46:57 -070060 return false; // TUNING
61}
62
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070063bool MipsMir2Lir::InexpensiveConstantLong(int64_t value) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070064 UNUSED(value);
Brian Carlstrom7940e442013-07-12 13:46:57 -070065 return false; // TUNING
66}
67
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070068bool MipsMir2Lir::InexpensiveConstantDouble(int64_t value) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -070069 UNUSED(value);
Brian Carlstrom7934ac22013-07-26 10:54:15 -070070 return false; // TUNING
Brian Carlstrom7940e442013-07-12 13:46:57 -070071}
72
73/*
74 * Load a immediate using a shortcut if possible; otherwise
75 * grab from the per-translation literal pool. If target is
76 * a high register, build constant into a low register and copy.
77 *
78 * No additional register clobbering operation performed. Use this version when
79 * 1) r_dest is freshly returned from AllocTemp or
80 * 2) The codegen is under fixed register usage
81 */
buzbee2700f7e2014-03-07 09:46:20 -080082LIR* MipsMir2Lir::LoadConstantNoClobber(RegStorage r_dest, int value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070083 LIR *res;
84
buzbee2700f7e2014-03-07 09:46:20 -080085 RegStorage r_dest_save = r_dest;
buzbee091cc402014-03-31 10:14:40 -070086 int is_fp_reg = r_dest.IsFloat();
Brian Carlstrom7940e442013-07-12 13:46:57 -070087 if (is_fp_reg) {
buzbee091cc402014-03-31 10:14:40 -070088 DCHECK(r_dest.IsSingle());
Brian Carlstrom7940e442013-07-12 13:46:57 -070089 r_dest = AllocTemp();
90 }
91
92 /* See if the value can be constructed cheaply */
93 if (value == 0) {
buzbee2700f7e2014-03-07 09:46:20 -080094 res = NewLIR2(kMipsMove, r_dest.GetReg(), rZERO);
Brian Carlstrom7940e442013-07-12 13:46:57 -070095 } else if ((value > 0) && (value <= 65535)) {
buzbee2700f7e2014-03-07 09:46:20 -080096 res = NewLIR3(kMipsOri, r_dest.GetReg(), rZERO, value);
Brian Carlstrom7940e442013-07-12 13:46:57 -070097 } else if ((value < 0) && (value >= -32768)) {
buzbee2700f7e2014-03-07 09:46:20 -080098 res = NewLIR3(kMipsAddiu, r_dest.GetReg(), rZERO, value);
Brian Carlstrom7940e442013-07-12 13:46:57 -070099 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800100 res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700101 if (value & 0xffff)
buzbee2700f7e2014-03-07 09:46:20 -0800102 NewLIR3(kMipsOri, r_dest.GetReg(), r_dest.GetReg(), value);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700103 }
104
105 if (is_fp_reg) {
buzbee2700f7e2014-03-07 09:46:20 -0800106 NewLIR2(kMipsMtc1, r_dest.GetReg(), r_dest_save.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700107 FreeTemp(r_dest);
108 }
109
110 return res;
111}
112
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700113LIR* MipsMir2Lir::OpUnconditionalBranch(LIR* target) {
Brian Carlstromdf629502013-07-17 22:39:56 -0700114 LIR* res = NewLIR1(kMipsB, 0 /* offset to be patched during assembly*/);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700115 res->target = target;
116 return res;
117}
118
buzbee2700f7e2014-03-07 09:46:20 -0800119LIR* MipsMir2Lir::OpReg(OpKind op, RegStorage r_dest_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700120 MipsOpCode opcode = kMipsNop;
121 switch (op) {
122 case kOpBlx:
123 opcode = kMipsJalr;
124 break;
125 case kOpBx:
buzbee2700f7e2014-03-07 09:46:20 -0800126 return NewLIR1(kMipsJr, r_dest_src.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700127 break;
128 default:
129 LOG(FATAL) << "Bad case in OpReg";
130 }
buzbee2700f7e2014-03-07 09:46:20 -0800131 return NewLIR2(opcode, rRA, r_dest_src.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700132}
133
buzbee2700f7e2014-03-07 09:46:20 -0800134LIR* MipsMir2Lir::OpRegImm(OpKind op, RegStorage r_dest_src1, int value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700135 LIR *res;
136 bool neg = (value < 0);
137 int abs_value = (neg) ? -value : value;
138 bool short_form = (abs_value & 0xff) == abs_value;
139 MipsOpCode opcode = kMipsNop;
140 switch (op) {
141 case kOpAdd:
142 return OpRegRegImm(op, r_dest_src1, r_dest_src1, value);
143 break;
144 case kOpSub:
145 return OpRegRegImm(op, r_dest_src1, r_dest_src1, value);
146 break;
147 default:
148 LOG(FATAL) << "Bad case in OpRegImm";
149 break;
150 }
Brian Carlstrom9b7085a2013-07-18 15:15:21 -0700151 if (short_form) {
buzbee2700f7e2014-03-07 09:46:20 -0800152 res = NewLIR2(opcode, r_dest_src1.GetReg(), abs_value);
Brian Carlstrom9b7085a2013-07-18 15:15:21 -0700153 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800154 RegStorage r_scratch = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700155 res = LoadConstant(r_scratch, value);
156 if (op == kOpCmp)
buzbee2700f7e2014-03-07 09:46:20 -0800157 NewLIR2(opcode, r_dest_src1.GetReg(), r_scratch.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700158 else
buzbee2700f7e2014-03-07 09:46:20 -0800159 NewLIR3(opcode, r_dest_src1.GetReg(), r_dest_src1.GetReg(), r_scratch.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700160 }
161 return res;
162}
163
buzbee2700f7e2014-03-07 09:46:20 -0800164LIR* MipsMir2Lir::OpRegRegReg(OpKind op, RegStorage r_dest, RegStorage r_src1, RegStorage r_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700165 MipsOpCode opcode = kMipsNop;
166 switch (op) {
167 case kOpAdd:
168 opcode = kMipsAddu;
169 break;
170 case kOpSub:
171 opcode = kMipsSubu;
172 break;
173 case kOpAnd:
174 opcode = kMipsAnd;
175 break;
176 case kOpMul:
177 opcode = kMipsMul;
178 break;
179 case kOpOr:
180 opcode = kMipsOr;
181 break;
182 case kOpXor:
183 opcode = kMipsXor;
184 break;
185 case kOpLsl:
186 opcode = kMipsSllv;
187 break;
188 case kOpLsr:
189 opcode = kMipsSrlv;
190 break;
191 case kOpAsr:
192 opcode = kMipsSrav;
193 break;
194 case kOpAdc:
195 case kOpSbc:
196 LOG(FATAL) << "No carry bit on MIPS";
197 break;
198 default:
199 LOG(FATAL) << "bad case in OpRegRegReg";
200 break;
201 }
buzbee2700f7e2014-03-07 09:46:20 -0800202 return NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), r_src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700203}
204
buzbee2700f7e2014-03-07 09:46:20 -0800205LIR* MipsMir2Lir::OpRegRegImm(OpKind op, RegStorage r_dest, RegStorage r_src1, int value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700206 LIR *res;
207 MipsOpCode opcode = kMipsNop;
208 bool short_form = true;
209
210 switch (op) {
211 case kOpAdd:
212 if (IS_SIMM16(value)) {
213 opcode = kMipsAddiu;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700214 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700215 short_form = false;
216 opcode = kMipsAddu;
217 }
218 break;
219 case kOpSub:
220 if (IS_SIMM16((-value))) {
221 value = -value;
222 opcode = kMipsAddiu;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700223 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700224 short_form = false;
225 opcode = kMipsSubu;
226 }
227 break;
228 case kOpLsl:
229 DCHECK(value >= 0 && value <= 31);
230 opcode = kMipsSll;
231 break;
232 case kOpLsr:
233 DCHECK(value >= 0 && value <= 31);
234 opcode = kMipsSrl;
235 break;
236 case kOpAsr:
237 DCHECK(value >= 0 && value <= 31);
238 opcode = kMipsSra;
239 break;
240 case kOpAnd:
241 if (IS_UIMM16((value))) {
242 opcode = kMipsAndi;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700243 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700244 short_form = false;
245 opcode = kMipsAnd;
246 }
247 break;
248 case kOpOr:
249 if (IS_UIMM16((value))) {
250 opcode = kMipsOri;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700251 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700252 short_form = false;
253 opcode = kMipsOr;
254 }
255 break;
256 case kOpXor:
257 if (IS_UIMM16((value))) {
258 opcode = kMipsXori;
Brian Carlstromf69863b2013-07-17 21:53:13 -0700259 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700260 short_form = false;
261 opcode = kMipsXor;
262 }
263 break;
264 case kOpMul:
265 short_form = false;
266 opcode = kMipsMul;
267 break;
268 default:
269 LOG(FATAL) << "Bad case in OpRegRegImm";
270 break;
271 }
272
Brian Carlstrom9b7085a2013-07-18 15:15:21 -0700273 if (short_form) {
buzbee2700f7e2014-03-07 09:46:20 -0800274 res = NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), value);
Brian Carlstrom9b7085a2013-07-18 15:15:21 -0700275 } else {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700276 if (r_dest != r_src1) {
277 res = LoadConstant(r_dest, value);
buzbee2700f7e2014-03-07 09:46:20 -0800278 NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), r_dest.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700279 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800280 RegStorage r_scratch = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700281 res = LoadConstant(r_scratch, value);
buzbee2700f7e2014-03-07 09:46:20 -0800282 NewLIR3(opcode, r_dest.GetReg(), r_src1.GetReg(), r_scratch.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700283 }
284 }
285 return res;
286}
287
buzbee2700f7e2014-03-07 09:46:20 -0800288LIR* MipsMir2Lir::OpRegReg(OpKind op, RegStorage r_dest_src1, RegStorage r_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700289 MipsOpCode opcode = kMipsNop;
290 LIR *res;
291 switch (op) {
292 case kOpMov:
293 opcode = kMipsMove;
294 break;
295 case kOpMvn:
buzbee2700f7e2014-03-07 09:46:20 -0800296 return NewLIR3(kMipsNor, r_dest_src1.GetReg(), r_src2.GetReg(), rZERO);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700297 case kOpNeg:
buzbee2700f7e2014-03-07 09:46:20 -0800298 return NewLIR3(kMipsSubu, r_dest_src1.GetReg(), rZERO, r_src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700299 case kOpAdd:
300 case kOpAnd:
301 case kOpMul:
302 case kOpOr:
303 case kOpSub:
304 case kOpXor:
305 return OpRegRegReg(op, r_dest_src1, r_dest_src1, r_src2);
306 case kOp2Byte:
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700307#if __mips_isa_rev >= 2
buzbee2700f7e2014-03-07 09:46:20 -0800308 res = NewLIR2(kMipsSeb, r_dest_src1.GetReg(), r_src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700309#else
310 res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 24);
311 OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 24);
312#endif
313 return res;
314 case kOp2Short:
Brian Carlstrom38f85e42013-07-18 14:45:22 -0700315#if __mips_isa_rev >= 2
buzbee2700f7e2014-03-07 09:46:20 -0800316 res = NewLIR2(kMipsSeh, r_dest_src1.GetReg(), r_src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700317#else
318 res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 16);
319 OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 16);
320#endif
321 return res;
322 case kOp2Char:
buzbee2700f7e2014-03-07 09:46:20 -0800323 return NewLIR3(kMipsAndi, r_dest_src1.GetReg(), r_src2.GetReg(), 0xFFFF);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700324 default:
325 LOG(FATAL) << "Bad case in OpRegReg";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700326 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700327 }
buzbee2700f7e2014-03-07 09:46:20 -0800328 return NewLIR2(opcode, r_dest_src1.GetReg(), r_src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700329}
330
buzbee2700f7e2014-03-07 09:46:20 -0800331LIR* MipsMir2Lir::OpMovRegMem(RegStorage r_dest, RegStorage r_base, int offset,
332 MoveType move_type) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700333 UNUSED(r_dest, r_base, offset, move_type);
Razvan A Lupusoru2c498d12014-01-29 16:02:57 -0800334 UNIMPLEMENTED(FATAL);
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700335 UNREACHABLE();
Razvan A Lupusoru2c498d12014-01-29 16:02:57 -0800336}
337
buzbee2700f7e2014-03-07 09:46:20 -0800338LIR* MipsMir2Lir::OpMovMemReg(RegStorage r_base, int offset, RegStorage r_src, MoveType move_type) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700339 UNUSED(r_base, offset, r_src, move_type);
Razvan A Lupusoru2c498d12014-01-29 16:02:57 -0800340 UNIMPLEMENTED(FATAL);
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700341 UNREACHABLE();
Razvan A Lupusoru2c498d12014-01-29 16:02:57 -0800342}
343
buzbee2700f7e2014-03-07 09:46:20 -0800344LIR* MipsMir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, RegStorage r_dest, RegStorage r_src) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700345 UNUSED(op, cc, r_dest, r_src);
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800346 LOG(FATAL) << "Unexpected use of OpCondRegReg for MIPS";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700347 UNREACHABLE();
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800348}
349
buzbee2700f7e2014-03-07 09:46:20 -0800350LIR* MipsMir2Lir::LoadConstantWide(RegStorage r_dest, int64_t value) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700351 LIR *res;
Douglas Leung2db3e262014-06-25 16:02:55 -0700352 if (!r_dest.IsPair()) {
353 // Form 64-bit pair
354 r_dest = Solo64ToPair64(r_dest);
355 }
buzbee2700f7e2014-03-07 09:46:20 -0800356 res = LoadConstantNoClobber(r_dest.GetLow(), Low32Bits(value));
357 LoadConstantNoClobber(r_dest.GetHigh(), High32Bits(value));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700358 return res;
359}
360
361/* Load value from base + scaled index. */
buzbee2700f7e2014-03-07 09:46:20 -0800362LIR* MipsMir2Lir::LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700363 int scale, OpSize size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700364 LIR *first = NULL;
365 LIR *res;
366 MipsOpCode opcode = kMipsNop;
buzbee2700f7e2014-03-07 09:46:20 -0800367 RegStorage t_reg = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700368
buzbee091cc402014-03-31 10:14:40 -0700369 if (r_dest.IsFloat()) {
370 DCHECK(r_dest.IsSingle());
buzbeefd698e62014-04-27 19:33:22 -0700371 DCHECK((size == k32) || (size == kSingle) || (size == kReference));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700372 size = kSingle;
373 } else {
374 if (size == kSingle)
buzbee695d13a2014-04-19 13:32:20 -0700375 size = k32;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700376 }
377
378 if (!scale) {
buzbee2700f7e2014-03-07 09:46:20 -0800379 first = NewLIR3(kMipsAddu, t_reg.GetReg() , r_base.GetReg(), r_index.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700380 } else {
381 first = OpRegRegImm(kOpLsl, t_reg, r_index, scale);
buzbee2700f7e2014-03-07 09:46:20 -0800382 NewLIR3(kMipsAddu, t_reg.GetReg() , r_base.GetReg(), t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700383 }
384
385 switch (size) {
386 case kSingle:
387 opcode = kMipsFlwc1;
388 break;
buzbee695d13a2014-04-19 13:32:20 -0700389 case k32:
390 case kReference:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700391 opcode = kMipsLw;
392 break;
393 case kUnsignedHalf:
394 opcode = kMipsLhu;
395 break;
396 case kSignedHalf:
397 opcode = kMipsLh;
398 break;
399 case kUnsignedByte:
400 opcode = kMipsLbu;
401 break;
402 case kSignedByte:
403 opcode = kMipsLb;
404 break;
405 default:
406 LOG(FATAL) << "Bad case in LoadBaseIndexed";
407 }
408
buzbee2700f7e2014-03-07 09:46:20 -0800409 res = NewLIR3(opcode, r_dest.GetReg(), 0, t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700410 FreeTemp(t_reg);
411 return (first) ? first : res;
412}
413
414/* store value base base + scaled index. */
buzbee2700f7e2014-03-07 09:46:20 -0800415LIR* MipsMir2Lir::StoreBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_src,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700416 int scale, OpSize size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700417 LIR *first = NULL;
418 MipsOpCode opcode = kMipsNop;
buzbee2700f7e2014-03-07 09:46:20 -0800419 RegStorage t_reg = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700420
buzbee091cc402014-03-31 10:14:40 -0700421 if (r_src.IsFloat()) {
422 DCHECK(r_src.IsSingle());
buzbeefd698e62014-04-27 19:33:22 -0700423 DCHECK((size == k32) || (size == kSingle) || (size == kReference));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700424 size = kSingle;
425 } else {
426 if (size == kSingle)
buzbee695d13a2014-04-19 13:32:20 -0700427 size = k32;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700428 }
429
430 if (!scale) {
buzbee2700f7e2014-03-07 09:46:20 -0800431 first = NewLIR3(kMipsAddu, t_reg.GetReg() , r_base.GetReg(), r_index.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700432 } else {
433 first = OpRegRegImm(kOpLsl, t_reg, r_index, scale);
buzbee2700f7e2014-03-07 09:46:20 -0800434 NewLIR3(kMipsAddu, t_reg.GetReg() , r_base.GetReg(), t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700435 }
436
437 switch (size) {
438 case kSingle:
439 opcode = kMipsFswc1;
440 break;
buzbee695d13a2014-04-19 13:32:20 -0700441 case k32:
442 case kReference:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700443 opcode = kMipsSw;
444 break;
445 case kUnsignedHalf:
446 case kSignedHalf:
447 opcode = kMipsSh;
448 break;
449 case kUnsignedByte:
450 case kSignedByte:
451 opcode = kMipsSb;
452 break;
453 default:
454 LOG(FATAL) << "Bad case in StoreBaseIndexed";
455 }
buzbee2700f7e2014-03-07 09:46:20 -0800456 NewLIR3(opcode, r_src.GetReg(), 0, t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700457 return first;
458}
459
buzbee2700f7e2014-03-07 09:46:20 -0800460// FIXME: don't split r_dest into 2 containers.
461LIR* MipsMir2Lir::LoadBaseDispBody(RegStorage r_base, int displacement, RegStorage r_dest,
Douglas Leung2db3e262014-06-25 16:02:55 -0700462 OpSize size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700463/*
464 * Load value from base + displacement. Optionally perform null check
465 * on base (which must have an associated s_reg and MIR). If not
466 * performing null check, incoming MIR can be null. IMPORTANT: this
467 * code must not allocate any new temps. If a new register is needed
468 * and base and dest are the same, spill some other register to
469 * rlp and then restore.
470 */
Brian Carlstrom7940e442013-07-12 13:46:57 -0700471 LIR *res;
472 LIR *load = NULL;
473 LIR *load2 = NULL;
474 MipsOpCode opcode = kMipsNop;
475 bool short_form = IS_SIMM16(displacement);
Douglas Leung2db3e262014-06-25 16:02:55 -0700476 bool pair = r_dest.IsPair();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700477
478 switch (size) {
buzbee695d13a2014-04-19 13:32:20 -0700479 case k64:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700480 case kDouble:
Douglas Leung2db3e262014-06-25 16:02:55 -0700481 if (!pair) {
482 // Form 64-bit pair
483 r_dest = Solo64ToPair64(r_dest);
484 pair = 1;
485 }
buzbee091cc402014-03-31 10:14:40 -0700486 if (r_dest.IsFloat()) {
Douglas Leung2db3e262014-06-25 16:02:55 -0700487 DCHECK_EQ(r_dest.GetLowReg(), r_dest.GetHighReg() - 1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700488 opcode = kMipsFlwc1;
Douglas Leung2db3e262014-06-25 16:02:55 -0700489 } else {
490 opcode = kMipsLw;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700491 }
492 short_form = IS_SIMM16_2WORD(displacement);
493 DCHECK_EQ((displacement & 0x3), 0);
494 break;
buzbee695d13a2014-04-19 13:32:20 -0700495 case k32:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700496 case kSingle:
buzbee695d13a2014-04-19 13:32:20 -0700497 case kReference:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700498 opcode = kMipsLw;
buzbee091cc402014-03-31 10:14:40 -0700499 if (r_dest.IsFloat()) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700500 opcode = kMipsFlwc1;
buzbee091cc402014-03-31 10:14:40 -0700501 DCHECK(r_dest.IsSingle());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700502 }
503 DCHECK_EQ((displacement & 0x3), 0);
504 break;
505 case kUnsignedHalf:
506 opcode = kMipsLhu;
507 DCHECK_EQ((displacement & 0x1), 0);
508 break;
509 case kSignedHalf:
510 opcode = kMipsLh;
511 DCHECK_EQ((displacement & 0x1), 0);
512 break;
513 case kUnsignedByte:
514 opcode = kMipsLbu;
515 break;
516 case kSignedByte:
517 opcode = kMipsLb;
518 break;
519 default:
520 LOG(FATAL) << "Bad case in LoadBaseIndexedBody";
521 }
522
523 if (short_form) {
524 if (!pair) {
buzbee2700f7e2014-03-07 09:46:20 -0800525 load = res = NewLIR3(opcode, r_dest.GetReg(), displacement, r_base.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700526 } else {
Douglas Leung2db3e262014-06-25 16:02:55 -0700527 load = res = NewLIR3(opcode, r_dest.GetLowReg(), displacement + LOWORD_OFFSET, r_base.GetReg());
528 load2 = NewLIR3(opcode, r_dest.GetHighReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700529 }
530 } else {
531 if (pair) {
buzbee2700f7e2014-03-07 09:46:20 -0800532 RegStorage r_tmp = AllocTemp();
533 res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement);
Douglas Leung2db3e262014-06-25 16:02:55 -0700534 load = NewLIR3(opcode, r_dest.GetLowReg(), LOWORD_OFFSET, r_tmp.GetReg());
535 load2 = NewLIR3(opcode, r_dest.GetHighReg(), HIWORD_OFFSET, r_tmp.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700536 FreeTemp(r_tmp);
537 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800538 RegStorage r_tmp = (r_base == r_dest) ? AllocTemp() : r_dest;
539 res = OpRegRegImm(kOpAdd, r_tmp, r_base, displacement);
540 load = NewLIR3(opcode, r_dest.GetReg(), 0, r_tmp.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700541 if (r_tmp != r_dest)
542 FreeTemp(r_tmp);
543 }
544 }
545
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100546 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
547 DCHECK(r_base == rs_rMIPS_SP);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700548 AnnotateDalvikRegAccess(load, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
549 true /* is_load */, pair /* is64bit */);
550 if (pair) {
551 AnnotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2,
552 true /* is_load */, pair /* is64bit */);
553 }
554 }
555 return load;
556}
557
Andreas Gampede686762014-06-24 18:42:06 +0000558LIR* MipsMir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest,
Andreas Gampe3c12c512014-06-24 18:46:29 +0000559 OpSize size, VolatileKind is_volatile) {
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700560 if (UNLIKELY(is_volatile == kVolatile && (size == k64 || size == kDouble))) {
561 // Do atomic 64-bit load.
562 return GenAtomic64Load(r_base, displacement, r_dest);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000563 }
564
buzbee695d13a2014-04-19 13:32:20 -0700565 // TODO: base this on target.
566 if (size == kWord) {
567 size = k32;
568 }
Andreas Gampe3c12c512014-06-24 18:46:29 +0000569 LIR* load;
Douglas Leung2db3e262014-06-25 16:02:55 -0700570 load = LoadBaseDispBody(r_base, displacement, r_dest, size);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000571
572 if (UNLIKELY(is_volatile == kVolatile)) {
Hans Boehm48f5c472014-06-27 14:50:10 -0700573 GenMemBarrier(kLoadAny);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000574 }
575
576 return load;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700577}
578
Vladimir Marko455759b2014-05-06 20:49:36 +0100579// FIXME: don't split r_dest into 2 containers.
buzbee2700f7e2014-03-07 09:46:20 -0800580LIR* MipsMir2Lir::StoreBaseDispBody(RegStorage r_base, int displacement,
Douglas Leung2db3e262014-06-25 16:02:55 -0700581 RegStorage r_src, OpSize size) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700582 LIR *res;
583 LIR *store = NULL;
584 LIR *store2 = NULL;
585 MipsOpCode opcode = kMipsNop;
586 bool short_form = IS_SIMM16(displacement);
buzbee091cc402014-03-31 10:14:40 -0700587 bool pair = r_src.IsPair();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700588
589 switch (size) {
buzbee695d13a2014-04-19 13:32:20 -0700590 case k64:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700591 case kDouble:
Douglas Leung2db3e262014-06-25 16:02:55 -0700592 if (!pair) {
593 // Form 64-bit pair
594 r_src = Solo64ToPair64(r_src);
595 pair = 1;
596 }
buzbee091cc402014-03-31 10:14:40 -0700597 if (r_src.IsFloat()) {
Douglas Leung2db3e262014-06-25 16:02:55 -0700598 DCHECK_EQ(r_src.GetLowReg(), r_src.GetHighReg() - 1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700599 opcode = kMipsFswc1;
Douglas Leung2db3e262014-06-25 16:02:55 -0700600 } else {
601 opcode = kMipsSw;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700602 }
603 short_form = IS_SIMM16_2WORD(displacement);
604 DCHECK_EQ((displacement & 0x3), 0);
605 break;
buzbee695d13a2014-04-19 13:32:20 -0700606 case k32:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700607 case kSingle:
buzbee695d13a2014-04-19 13:32:20 -0700608 case kReference:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700609 opcode = kMipsSw;
buzbee091cc402014-03-31 10:14:40 -0700610 if (r_src.IsFloat()) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700611 opcode = kMipsFswc1;
buzbee091cc402014-03-31 10:14:40 -0700612 DCHECK(r_src.IsSingle());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700613 }
614 DCHECK_EQ((displacement & 0x3), 0);
615 break;
616 case kUnsignedHalf:
617 case kSignedHalf:
618 opcode = kMipsSh;
619 DCHECK_EQ((displacement & 0x1), 0);
620 break;
621 case kUnsignedByte:
622 case kSignedByte:
623 opcode = kMipsSb;
624 break;
625 default:
buzbee2700f7e2014-03-07 09:46:20 -0800626 LOG(FATAL) << "Bad case in StoreBaseDispBody";
Brian Carlstrom7940e442013-07-12 13:46:57 -0700627 }
628
629 if (short_form) {
630 if (!pair) {
buzbee2700f7e2014-03-07 09:46:20 -0800631 store = res = NewLIR3(opcode, r_src.GetReg(), displacement, r_base.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700632 } else {
Douglas Leung2db3e262014-06-25 16:02:55 -0700633 store = res = NewLIR3(opcode, r_src.GetLowReg(), displacement + LOWORD_OFFSET, r_base.GetReg());
634 store2 = NewLIR3(opcode, r_src.GetHighReg(), displacement + HIWORD_OFFSET, r_base.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700635 }
636 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800637 RegStorage r_scratch = AllocTemp();
638 res = OpRegRegImm(kOpAdd, r_scratch, r_base, displacement);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700639 if (!pair) {
buzbee2700f7e2014-03-07 09:46:20 -0800640 store = NewLIR3(opcode, r_src.GetReg(), 0, r_scratch.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700641 } else {
Douglas Leung2db3e262014-06-25 16:02:55 -0700642 store = NewLIR3(opcode, r_src.GetLowReg(), LOWORD_OFFSET, r_scratch.GetReg());
643 store2 = NewLIR3(opcode, r_src.GetHighReg(), HIWORD_OFFSET, r_scratch.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700644 }
645 FreeTemp(r_scratch);
646 }
647
Vladimir Marko8dea81c2014-06-06 14:50:36 +0100648 if (mem_ref_type_ == ResourceMask::kDalvikReg) {
649 DCHECK(r_base == rs_rMIPS_SP);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700650 AnnotateDalvikRegAccess(store, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
651 false /* is_load */, pair /* is64bit */);
652 if (pair) {
653 AnnotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2,
654 false /* is_load */, pair /* is64bit */);
655 }
656 }
657
658 return res;
659}
660
Andreas Gampede686762014-06-24 18:42:06 +0000661LIR* MipsMir2Lir::StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r_src,
Andreas Gampe3c12c512014-06-24 18:46:29 +0000662 OpSize size, VolatileKind is_volatile) {
663 if (is_volatile == kVolatile) {
Hans Boehm48f5c472014-06-27 14:50:10 -0700664 // Ensure that prior accesses become visible to other threads first.
665 GenMemBarrier(kAnyStore);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000666 }
667
Andreas Gampe3c12c512014-06-24 18:46:29 +0000668 LIR* store;
Douglas Leungd9cb8ae2014-07-09 14:28:35 -0700669 if (UNLIKELY(is_volatile == kVolatile && (size == k64 || size == kDouble))) {
670 // Do atomic 64-bit load.
671 store = GenAtomic64Store(r_base, displacement, r_src);
672 } else {
673 // TODO: base this on target.
674 if (size == kWord) {
675 size = k32;
676 }
677 store = StoreBaseDispBody(r_base, displacement, r_src, size);
678 }
Andreas Gampe3c12c512014-06-24 18:46:29 +0000679
680 if (UNLIKELY(is_volatile == kVolatile)) {
Hans Boehm48f5c472014-06-27 14:50:10 -0700681 // Preserve order with respect to any subsequent volatile loads.
682 // We need StoreLoad, but that generally requires the most expensive barrier.
683 GenMemBarrier(kAnyAny);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000684 }
685
686 return store;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700687}
688
buzbee2700f7e2014-03-07 09:46:20 -0800689LIR* MipsMir2Lir::OpMem(OpKind op, RegStorage r_base, int disp) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700690 UNUSED(op, r_base, disp);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700691 LOG(FATAL) << "Unexpected use of OpMem for MIPS";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700692 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700693}
694
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700695LIR* MipsMir2Lir::OpCondBranch(ConditionCode cc, LIR* target) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700696 UNUSED(cc, target);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700697 LOG(FATAL) << "Unexpected use of OpCondBranch for MIPS";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700698 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700699}
700
Andreas Gampe98430592014-07-27 19:44:50 -0700701LIR* MipsMir2Lir::InvokeTrampoline(OpKind op, RegStorage r_tgt, QuickEntrypointEnum trampoline) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700702 UNUSED(trampoline); // The address of the trampoline is already loaded into r_tgt.
Andreas Gampe98430592014-07-27 19:44:50 -0700703 return OpReg(op, r_tgt);
704}
705
Brian Carlstrom7940e442013-07-12 13:46:57 -0700706} // namespace art