blob: 1f8f9ece8dbdd7cec426fabe2c0ea4cc17baba7b [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/* This file contains codegen for the Mips ISA */
18
19#include "codegen_mips.h"
20#include "dex/quick/mir_to_lir-inl.h"
buzbeeb5860fb2014-06-21 15:31:01 -070021#include "dex/reg_storage_eq.h"
Ian Rogers166db042013-07-26 12:05:57 -070022#include "entrypoints/quick/quick_entrypoints.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070023#include "mips_lir.h"
24#include "mirror/array.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070025
26namespace art {
27
28/*
29 * Compare two 64-bit values
30 * x = y return 0
31 * x < y return -1
32 * x > y return 1
33 *
34 * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
35 * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
36 * subu res, t0, t1 # res = -1:1:0 for [ < > = ]
37 * bnez res, finish
38 * sltu t0, x.lo, y.lo
39 * sgtu r1, x.lo, y.lo
40 * subu res, t0, t1
41 * finish:
42 *
43 */
44void MipsMir2Lir::GenCmpLong(RegLocation rl_dest, RegLocation rl_src1,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070045 RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070046 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
47 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
buzbee091cc402014-03-31 10:14:40 -070048 RegStorage t0 = AllocTemp();
49 RegStorage t1 = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -070050 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee091cc402014-03-31 10:14:40 -070051 NewLIR3(kMipsSlt, t0.GetReg(), rl_src1.reg.GetHighReg(), rl_src2.reg.GetHighReg());
52 NewLIR3(kMipsSlt, t1.GetReg(), rl_src2.reg.GetHighReg(), rl_src1.reg.GetHighReg());
53 NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1.GetReg(), t0.GetReg());
buzbee2700f7e2014-03-07 09:46:20 -080054 LIR* branch = OpCmpImmBranch(kCondNe, rl_result.reg, 0, NULL);
buzbee091cc402014-03-31 10:14:40 -070055 NewLIR3(kMipsSltu, t0.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
56 NewLIR3(kMipsSltu, t1.GetReg(), rl_src2.reg.GetLowReg(), rl_src1.reg.GetLowReg());
57 NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1.GetReg(), t0.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -070058 FreeTemp(t0);
59 FreeTemp(t1);
60 LIR* target = NewLIR0(kPseudoTargetLabel);
61 branch->target = target;
62 StoreValue(rl_dest, rl_result);
63}
64
buzbee2700f7e2014-03-07 09:46:20 -080065LIR* MipsMir2Lir::OpCmpBranch(ConditionCode cond, RegStorage src1, RegStorage src2, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070066 LIR* branch;
67 MipsOpCode slt_op;
68 MipsOpCode br_op;
69 bool cmp_zero = false;
70 bool swapped = false;
71 switch (cond) {
72 case kCondEq:
73 br_op = kMipsBeq;
74 cmp_zero = true;
75 break;
76 case kCondNe:
77 br_op = kMipsBne;
78 cmp_zero = true;
79 break;
Vladimir Marko58af1f92013-12-19 13:31:15 +000080 case kCondUlt:
Brian Carlstrom7940e442013-07-12 13:46:57 -070081 slt_op = kMipsSltu;
82 br_op = kMipsBnez;
83 break;
Vladimir Marko58af1f92013-12-19 13:31:15 +000084 case kCondUge:
Brian Carlstrom7940e442013-07-12 13:46:57 -070085 slt_op = kMipsSltu;
86 br_op = kMipsBeqz;
87 break;
88 case kCondGe:
89 slt_op = kMipsSlt;
90 br_op = kMipsBeqz;
91 break;
92 case kCondGt:
93 slt_op = kMipsSlt;
94 br_op = kMipsBnez;
95 swapped = true;
96 break;
97 case kCondLe:
98 slt_op = kMipsSlt;
99 br_op = kMipsBeqz;
100 swapped = true;
101 break;
102 case kCondLt:
103 slt_op = kMipsSlt;
104 br_op = kMipsBnez;
105 break;
106 case kCondHi: // Gtu
107 slt_op = kMipsSltu;
108 br_op = kMipsBnez;
109 swapped = true;
110 break;
111 default:
112 LOG(FATAL) << "No support for ConditionCode: " << cond;
113 return NULL;
114 }
115 if (cmp_zero) {
buzbee2700f7e2014-03-07 09:46:20 -0800116 branch = NewLIR2(br_op, src1.GetReg(), src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700117 } else {
buzbee091cc402014-03-31 10:14:40 -0700118 RegStorage t_reg = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700119 if (swapped) {
buzbee091cc402014-03-31 10:14:40 -0700120 NewLIR3(slt_op, t_reg.GetReg(), src2.GetReg(), src1.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700121 } else {
buzbee091cc402014-03-31 10:14:40 -0700122 NewLIR3(slt_op, t_reg.GetReg(), src1.GetReg(), src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700123 }
buzbee091cc402014-03-31 10:14:40 -0700124 branch = NewLIR1(br_op, t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700125 FreeTemp(t_reg);
126 }
127 branch->target = target;
128 return branch;
129}
130
buzbee2700f7e2014-03-07 09:46:20 -0800131LIR* MipsMir2Lir::OpCmpImmBranch(ConditionCode cond, RegStorage reg, int check_value, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700132 LIR* branch;
133 if (check_value != 0) {
134 // TUNING: handle s16 & kCondLt/Mi case using slti
buzbee2700f7e2014-03-07 09:46:20 -0800135 RegStorage t_reg = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700136 LoadConstant(t_reg, check_value);
137 branch = OpCmpBranch(cond, reg, t_reg, target);
138 FreeTemp(t_reg);
139 return branch;
140 }
141 MipsOpCode opc;
142 switch (cond) {
143 case kCondEq: opc = kMipsBeqz; break;
144 case kCondGe: opc = kMipsBgez; break;
145 case kCondGt: opc = kMipsBgtz; break;
146 case kCondLe: opc = kMipsBlez; break;
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700147 // case KCondMi:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700148 case kCondLt: opc = kMipsBltz; break;
149 case kCondNe: opc = kMipsBnez; break;
150 default:
151 // Tuning: use slti when applicable
buzbee2700f7e2014-03-07 09:46:20 -0800152 RegStorage t_reg = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700153 LoadConstant(t_reg, check_value);
154 branch = OpCmpBranch(cond, reg, t_reg, target);
155 FreeTemp(t_reg);
156 return branch;
157 }
buzbee2700f7e2014-03-07 09:46:20 -0800158 branch = NewLIR1(opc, reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700159 branch->target = target;
160 return branch;
161}
162
buzbee2700f7e2014-03-07 09:46:20 -0800163LIR* MipsMir2Lir::OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src) {
164 // If src or dest is a pair, we'll be using low reg.
165 if (r_dest.IsPair()) {
166 r_dest = r_dest.GetLow();
167 }
168 if (r_src.IsPair()) {
169 r_src = r_src.GetLow();
170 }
buzbee091cc402014-03-31 10:14:40 -0700171 if (r_dest.IsFloat() || r_src.IsFloat())
Brian Carlstrom7940e442013-07-12 13:46:57 -0700172 return OpFpRegCopy(r_dest, r_src);
173 LIR* res = RawLIR(current_dalvik_offset_, kMipsMove,
buzbee2700f7e2014-03-07 09:46:20 -0800174 r_dest.GetReg(), r_src.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700175 if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
176 res->flags.is_nop = true;
177 }
178 return res;
179}
180
buzbee7a11ab02014-04-28 20:02:38 -0700181void MipsMir2Lir::OpRegCopy(RegStorage r_dest, RegStorage r_src) {
182 if (r_dest != r_src) {
183 LIR *res = OpRegCopyNoInsert(r_dest, r_src);
184 AppendLIR(res);
185 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700186}
187
buzbee2700f7e2014-03-07 09:46:20 -0800188void MipsMir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) {
buzbee7a11ab02014-04-28 20:02:38 -0700189 if (r_dest != r_src) {
buzbee091cc402014-03-31 10:14:40 -0700190 bool dest_fp = r_dest.IsFloat();
191 bool src_fp = r_src.IsFloat();
buzbee7a11ab02014-04-28 20:02:38 -0700192 if (dest_fp) {
193 if (src_fp) {
buzbee091cc402014-03-31 10:14:40 -0700194 OpRegCopy(r_dest, r_src);
195 } else {
196 /* note the operands are swapped for the mtc1 instr */
197 NewLIR2(kMipsMtc1, r_src.GetLowReg(), r_dest.GetLowReg());
198 NewLIR2(kMipsMtc1, r_src.GetHighReg(), r_dest.GetHighReg());
buzbee7a11ab02014-04-28 20:02:38 -0700199 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700200 } else {
buzbee7a11ab02014-04-28 20:02:38 -0700201 if (src_fp) {
202 NewLIR2(kMipsMfc1, r_dest.GetLowReg(), r_src.GetLowReg());
203 NewLIR2(kMipsMfc1, r_dest.GetHighReg(), r_src.GetHighReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700204 } else {
buzbee7a11ab02014-04-28 20:02:38 -0700205 // Handle overlap
206 if (r_src.GetHighReg() == r_dest.GetLowReg()) {
207 OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
208 OpRegCopy(r_dest.GetLow(), r_src.GetLow());
209 } else {
210 OpRegCopy(r_dest.GetLow(), r_src.GetLow());
211 OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
212 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700213 }
214 }
215 }
216}
217
Andreas Gampe90969af2014-07-15 23:02:11 -0700218void MipsMir2Lir::GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code,
219 int32_t true_val, int32_t false_val, RegStorage rs_dest,
220 int dest_reg_class) {
221 // Implement as a branch-over.
222 // TODO: Conditional move?
223 LoadConstant(rs_dest, false_val); // Favors false.
224 LIR* ne_branchover = OpCmpBranch(code, left_op, right_op, NULL);
225 LoadConstant(rs_dest, true_val);
226 LIR* target_label = NewLIR0(kPseudoTargetLabel);
227 ne_branchover->target = target_label;
228}
229
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700230void MipsMir2Lir::GenSelect(BasicBlock* bb, MIR* mir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700231 UNIMPLEMENTED(FATAL) << "Need codegen for select";
232}
233
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700234void MipsMir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700235 UNIMPLEMENTED(FATAL) << "Need codegen for fused long cmp branch";
236}
237
buzbee2700f7e2014-03-07 09:46:20 -0800238RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegStorage reg1, RegStorage reg2,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700239 bool is_div) {
buzbee9da5c102014-03-28 12:59:18 -0700240 NewLIR2(kMipsDiv, reg1.GetReg(), reg2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700241 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
242 if (is_div) {
buzbee9da5c102014-03-28 12:59:18 -0700243 NewLIR1(kMipsMflo, rl_result.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700244 } else {
buzbee9da5c102014-03-28 12:59:18 -0700245 NewLIR1(kMipsMfhi, rl_result.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700246 }
247 return rl_result;
248}
249
buzbee2700f7e2014-03-07 09:46:20 -0800250RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegStorage reg1, int lit,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700251 bool is_div) {
buzbee091cc402014-03-31 10:14:40 -0700252 RegStorage t_reg = AllocTemp();
253 NewLIR3(kMipsAddiu, t_reg.GetReg(), rZERO, lit);
254 NewLIR2(kMipsDiv, reg1.GetReg(), t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700255 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
256 if (is_div) {
buzbee9da5c102014-03-28 12:59:18 -0700257 NewLIR1(kMipsMflo, rl_result.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700258 } else {
buzbee9da5c102014-03-28 12:59:18 -0700259 NewLIR1(kMipsMfhi, rl_result.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700260 }
261 FreeTemp(t_reg);
262 return rl_result;
263}
264
Mark Mendell2bf31e62014-01-23 12:13:40 -0800265RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
266 RegLocation rl_src2, bool is_div, bool check_zero) {
267 LOG(FATAL) << "Unexpected use of GenDivRem for Mips";
268 return rl_dest;
269}
270
271RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) {
272 LOG(FATAL) << "Unexpected use of GenDivRemLit for Mips";
273 return rl_dest;
274}
275
buzbee2700f7e2014-03-07 09:46:20 -0800276void MipsMir2Lir::OpLea(RegStorage r_base, RegStorage reg1, RegStorage reg2, int scale,
277 int offset) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700278 LOG(FATAL) << "Unexpected use of OpLea for Arm";
279}
280
Ian Rogersdd7624d2014-03-14 17:43:00 -0700281void MipsMir2Lir::OpTlsCmp(ThreadOffset<4> offset, int val) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700282 LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm";
283}
284
Andreas Gampe2f244e92014-05-08 03:35:25 -0700285void MipsMir2Lir::OpTlsCmp(ThreadOffset<8> offset, int val) {
286 UNIMPLEMENTED(FATAL) << "Should not be called.";
287}
288
Vladimir Marko1c282e22013-11-21 14:49:47 +0000289bool MipsMir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700290 DCHECK_NE(cu_->instruction_set, kThumb2);
291 return false;
292}
293
294bool MipsMir2Lir::GenInlinedSqrt(CallInfo* info) {
295 DCHECK_NE(cu_->instruction_set, kThumb2);
296 return false;
297}
298
Vladimir Markoe508a202013-11-04 15:24:22 +0000299bool MipsMir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
300 if (size != kSignedByte) {
301 // MIPS supports only aligned access. Defer unaligned access to JNI implementation.
302 return false;
303 }
304 RegLocation rl_src_address = info->args[0]; // long address
buzbee2700f7e2014-03-07 09:46:20 -0800305 rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1]
Vladimir Markoe508a202013-11-04 15:24:22 +0000306 RegLocation rl_dest = InlineTarget(info);
307 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
308 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
309 DCHECK(size == kSignedByte);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000310 LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size, kNotVolatile);
Vladimir Markoe508a202013-11-04 15:24:22 +0000311 StoreValue(rl_dest, rl_result);
312 return true;
313}
314
315bool MipsMir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) {
316 if (size != kSignedByte) {
317 // MIPS supports only aligned access. Defer unaligned access to JNI implementation.
318 return false;
319 }
320 RegLocation rl_src_address = info->args[0]; // long address
buzbee2700f7e2014-03-07 09:46:20 -0800321 rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1]
Vladimir Markoe508a202013-11-04 15:24:22 +0000322 RegLocation rl_src_value = info->args[2]; // [size] value
323 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
324 DCHECK(size == kSignedByte);
325 RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000326 StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size, kNotVolatile);
Vladimir Markoe508a202013-11-04 15:24:22 +0000327 return true;
328}
329
buzbee2700f7e2014-03-07 09:46:20 -0800330LIR* MipsMir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700331 LOG(FATAL) << "Unexpected use of OpPcRelLoad for Mips";
332 return NULL;
333}
334
buzbee2700f7e2014-03-07 09:46:20 -0800335LIR* MipsMir2Lir::OpVldm(RegStorage r_base, int count) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700336 LOG(FATAL) << "Unexpected use of OpVldm for Mips";
337 return NULL;
338}
339
buzbee2700f7e2014-03-07 09:46:20 -0800340LIR* MipsMir2Lir::OpVstm(RegStorage r_base, int count) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700341 LOG(FATAL) << "Unexpected use of OpVstm for Mips";
342 return NULL;
343}
344
345void MipsMir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
346 RegLocation rl_result, int lit,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700347 int first_bit, int second_bit) {
buzbee2700f7e2014-03-07 09:46:20 -0800348 RegStorage t_reg = AllocTemp();
349 OpRegRegImm(kOpLsl, t_reg, rl_src.reg, second_bit - first_bit);
350 OpRegRegReg(kOpAdd, rl_result.reg, rl_src.reg, t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700351 FreeTemp(t_reg);
352 if (first_bit != 0) {
buzbee2700f7e2014-03-07 09:46:20 -0800353 OpRegRegImm(kOpLsl, rl_result.reg, rl_result.reg, first_bit);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700354 }
355}
356
Mingyao Yange643a172014-04-08 11:02:52 -0700357void MipsMir2Lir::GenDivZeroCheckWide(RegStorage reg) {
buzbee2700f7e2014-03-07 09:46:20 -0800358 DCHECK(reg.IsPair()); // TODO: support k64BitSolo.
359 RegStorage t_reg = AllocTemp();
360 OpRegRegReg(kOpOr, t_reg, reg.GetLow(), reg.GetHigh());
Mingyao Yangd15f4e22014-04-17 18:46:24 -0700361 GenDivZeroCheck(t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700362 FreeTemp(t_reg);
363}
364
365// Test suspend flag, return target of taken suspend branch
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700366LIR* MipsMir2Lir::OpTestSuspend(LIR* target) {
buzbee2700f7e2014-03-07 09:46:20 -0800367 OpRegImm(kOpSub, rs_rMIPS_SUSPEND, 1);
368 return OpCmpImmBranch((target == NULL) ? kCondEq : kCondNe, rs_rMIPS_SUSPEND, 0, target);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700369}
370
371// Decrement register and branch on condition
buzbee2700f7e2014-03-07 09:46:20 -0800372LIR* MipsMir2Lir::OpDecAndBranch(ConditionCode c_code, RegStorage reg, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700373 OpRegImm(kOpSub, reg, 1);
374 return OpCmpImmBranch(c_code, reg, 0, target);
375}
376
buzbee11b63d12013-08-27 07:34:17 -0700377bool MipsMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700378 RegLocation rl_src, RegLocation rl_dest, int lit) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700379 LOG(FATAL) << "Unexpected use of smallLiteralDive in Mips";
380 return false;
381}
382
Ian Rogerse2143c02014-03-28 08:47:16 -0700383bool MipsMir2Lir::EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) {
384 LOG(FATAL) << "Unexpected use of easyMultiply in Mips";
385 return false;
386}
387
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700388LIR* MipsMir2Lir::OpIT(ConditionCode cond, const char* guide) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700389 LOG(FATAL) << "Unexpected use of OpIT in Mips";
390 return NULL;
391}
392
Dave Allison3da67a52014-04-02 17:03:45 -0700393void MipsMir2Lir::OpEndIT(LIR* it) {
394 LOG(FATAL) << "Unexpected use of OpEndIT in Mips";
395}
396
397
Mark Mendelle02d48f2014-01-15 11:19:23 -0800398void MipsMir2Lir::GenMulLong(Instruction::Code opcode, RegLocation rl_dest,
399 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700400 LOG(FATAL) << "Unexpected use of GenMulLong for Mips";
401}
402
Mark Mendelle02d48f2014-01-15 11:19:23 -0800403void MipsMir2Lir::GenAddLong(Instruction::Code opcode, RegLocation rl_dest,
404 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700405 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
406 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
407 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
408 /*
409 * [v1 v0] = [a1 a0] + [a3 a2];
410 * addu v0,a2,a0
411 * addu t1,a3,a1
412 * sltu v1,v0,a2
413 * addu v1,v1,t1
414 */
415
buzbee2700f7e2014-03-07 09:46:20 -0800416 OpRegRegReg(kOpAdd, rl_result.reg.GetLow(), rl_src2.reg.GetLow(), rl_src1.reg.GetLow());
417 RegStorage t_reg = AllocTemp();
418 OpRegRegReg(kOpAdd, t_reg, rl_src2.reg.GetHigh(), rl_src1.reg.GetHigh());
419 NewLIR3(kMipsSltu, rl_result.reg.GetHighReg(), rl_result.reg.GetLowReg(), rl_src2.reg.GetLowReg());
420 OpRegRegReg(kOpAdd, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700421 FreeTemp(t_reg);
422 StoreValueWide(rl_dest, rl_result);
423}
424
Mark Mendelle02d48f2014-01-15 11:19:23 -0800425void MipsMir2Lir::GenSubLong(Instruction::Code opcode, RegLocation rl_dest,
426 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700427 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
428 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
429 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
430 /*
431 * [v1 v0] = [a1 a0] - [a3 a2];
432 * sltu t1,a0,a2
433 * subu v0,a0,a2
434 * subu v1,a1,a3
435 * subu v1,v1,t1
436 */
437
buzbee2700f7e2014-03-07 09:46:20 -0800438 RegStorage t_reg = AllocTemp();
439 NewLIR3(kMipsSltu, t_reg.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
440 OpRegRegReg(kOpSub, rl_result.reg.GetLow(), rl_src1.reg.GetLow(), rl_src2.reg.GetLow());
441 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_src1.reg.GetHigh(), rl_src2.reg.GetHigh());
442 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700443 FreeTemp(t_reg);
444 StoreValueWide(rl_dest, rl_result);
445}
446
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100447void MipsMir2Lir::GenNotLong(RegLocation rl_dest, RegLocation rl_src) {
448 LOG(FATAL) << "Unexpected use GenNotLong()";
449}
450
451void MipsMir2Lir::GenDivRemLong(Instruction::Code, RegLocation rl_dest, RegLocation rl_src1,
452 RegLocation rl_src2, bool is_div) {
453 LOG(FATAL) << "Unexpected use GenDivRemLong()";
454}
455
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700456void MipsMir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700457 rl_src = LoadValueWide(rl_src, kCoreReg);
458 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
459 /*
460 * [v1 v0] = -[a1 a0]
461 * negu v0,a0
462 * negu v1,a1
463 * sltu t1,r_zero
464 * subu v1,v1,t1
465 */
466
buzbee2700f7e2014-03-07 09:46:20 -0800467 OpRegReg(kOpNeg, rl_result.reg.GetLow(), rl_src.reg.GetLow());
468 OpRegReg(kOpNeg, rl_result.reg.GetHigh(), rl_src.reg.GetHigh());
469 RegStorage t_reg = AllocTemp();
470 NewLIR3(kMipsSltu, t_reg.GetReg(), rZERO, rl_result.reg.GetLowReg());
471 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700472 FreeTemp(t_reg);
473 StoreValueWide(rl_dest, rl_result);
474}
475
Mark Mendelle02d48f2014-01-15 11:19:23 -0800476void MipsMir2Lir::GenAndLong(Instruction::Code opcode, RegLocation rl_dest,
477 RegLocation rl_src1,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700478 RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700479 LOG(FATAL) << "Unexpected use of GenAndLong for Mips";
480}
481
Mark Mendelle02d48f2014-01-15 11:19:23 -0800482void MipsMir2Lir::GenOrLong(Instruction::Code opcode, RegLocation rl_dest,
483 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700484 LOG(FATAL) << "Unexpected use of GenOrLong for Mips";
485}
486
Mark Mendelle02d48f2014-01-15 11:19:23 -0800487void MipsMir2Lir::GenXorLong(Instruction::Code opcode, RegLocation rl_dest,
488 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700489 LOG(FATAL) << "Unexpected use of GenXorLong for Mips";
490}
491
492/*
493 * Generate array load
494 */
495void MipsMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700496 RegLocation rl_index, RegLocation rl_dest, int scale) {
buzbee091cc402014-03-31 10:14:40 -0700497 RegisterClass reg_class = RegClassBySize(size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700498 int len_offset = mirror::Array::LengthOffset().Int32Value();
499 int data_offset;
500 RegLocation rl_result;
Douglas Leung2db3e262014-06-25 16:02:55 -0700501 rl_array = LoadValue(rl_array, kRefReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700502 rl_index = LoadValue(rl_index, kCoreReg);
503
Douglas Leung2db3e262014-06-25 16:02:55 -0700504 // FIXME: need to add support for rl_index.is_const.
505
buzbee695d13a2014-04-19 13:32:20 -0700506 if (size == k64 || size == kDouble) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700507 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
508 } else {
509 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
510 }
511
512 /* null object? */
buzbee2700f7e2014-03-07 09:46:20 -0800513 GenNullCheck(rl_array.reg, opt_flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700514
buzbee2700f7e2014-03-07 09:46:20 -0800515 RegStorage reg_ptr = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700516 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
buzbee2700f7e2014-03-07 09:46:20 -0800517 RegStorage reg_len;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700518 if (needs_range_check) {
519 reg_len = AllocTemp();
520 /* Get len */
buzbee695d13a2014-04-19 13:32:20 -0700521 Load32Disp(rl_array.reg, len_offset, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700522 }
523 /* reg_ptr -> array data */
buzbee2700f7e2014-03-07 09:46:20 -0800524 OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
buzbee091cc402014-03-31 10:14:40 -0700525 FreeTemp(rl_array.reg);
buzbee695d13a2014-04-19 13:32:20 -0700526 if ((size == k64) || (size == kDouble)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700527 if (scale) {
buzbee2700f7e2014-03-07 09:46:20 -0800528 RegStorage r_new_index = AllocTemp();
529 OpRegRegImm(kOpLsl, r_new_index, rl_index.reg, scale);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700530 OpRegReg(kOpAdd, reg_ptr, r_new_index);
531 FreeTemp(r_new_index);
532 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800533 OpRegReg(kOpAdd, reg_ptr, rl_index.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700534 }
buzbee2700f7e2014-03-07 09:46:20 -0800535 FreeTemp(rl_index.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700536 rl_result = EvalLoc(rl_dest, reg_class, true);
537
538 if (needs_range_check) {
Mingyao Yang80365d92014-04-18 12:10:58 -0700539 GenArrayBoundsCheck(rl_index.reg, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700540 FreeTemp(reg_len);
541 }
Andreas Gampe3c12c512014-06-24 18:46:29 +0000542 LoadBaseDisp(reg_ptr, 0, rl_result.reg, size, kNotVolatile);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700543
544 FreeTemp(reg_ptr);
545 StoreValueWide(rl_dest, rl_result);
546 } else {
547 rl_result = EvalLoc(rl_dest, reg_class, true);
548
549 if (needs_range_check) {
Mingyao Yang80365d92014-04-18 12:10:58 -0700550 GenArrayBoundsCheck(rl_index.reg, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700551 FreeTemp(reg_len);
552 }
buzbee2700f7e2014-03-07 09:46:20 -0800553 LoadBaseIndexed(reg_ptr, rl_index.reg, rl_result.reg, scale, size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700554
555 FreeTemp(reg_ptr);
556 StoreValue(rl_dest, rl_result);
557 }
558}
559
560/*
561 * Generate array store
562 *
563 */
564void MipsMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
Ian Rogersa9a82542013-10-04 11:17:26 -0700565 RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
buzbee091cc402014-03-31 10:14:40 -0700566 RegisterClass reg_class = RegClassBySize(size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700567 int len_offset = mirror::Array::LengthOffset().Int32Value();
568 int data_offset;
569
buzbee695d13a2014-04-19 13:32:20 -0700570 if (size == k64 || size == kDouble) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700571 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
572 } else {
573 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
574 }
575
Douglas Leung2db3e262014-06-25 16:02:55 -0700576 rl_array = LoadValue(rl_array, kRefReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700577 rl_index = LoadValue(rl_index, kCoreReg);
Douglas Leung2db3e262014-06-25 16:02:55 -0700578
579 // FIXME: need to add support for rl_index.is_const.
580
buzbee2700f7e2014-03-07 09:46:20 -0800581 RegStorage reg_ptr;
Ian Rogers773aab12013-10-14 13:50:10 -0700582 bool allocated_reg_ptr_temp = false;
buzbee091cc402014-03-31 10:14:40 -0700583 if (IsTemp(rl_array.reg) && !card_mark) {
584 Clobber(rl_array.reg);
buzbee2700f7e2014-03-07 09:46:20 -0800585 reg_ptr = rl_array.reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700586 } else {
587 reg_ptr = AllocTemp();
buzbee2700f7e2014-03-07 09:46:20 -0800588 OpRegCopy(reg_ptr, rl_array.reg);
Ian Rogers773aab12013-10-14 13:50:10 -0700589 allocated_reg_ptr_temp = true;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700590 }
591
592 /* null object? */
buzbee2700f7e2014-03-07 09:46:20 -0800593 GenNullCheck(rl_array.reg, opt_flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700594
595 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
buzbee2700f7e2014-03-07 09:46:20 -0800596 RegStorage reg_len;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700597 if (needs_range_check) {
598 reg_len = AllocTemp();
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700599 // NOTE: max live temps(4) here.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700600 /* Get len */
buzbee695d13a2014-04-19 13:32:20 -0700601 Load32Disp(rl_array.reg, len_offset, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700602 }
603 /* reg_ptr -> array data */
604 OpRegImm(kOpAdd, reg_ptr, data_offset);
605 /* at this point, reg_ptr points to array, 2 live temps */
buzbee695d13a2014-04-19 13:32:20 -0700606 if ((size == k64) || (size == kDouble)) {
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700607 // TUNING: specific wide routine that can handle fp regs
Brian Carlstrom7940e442013-07-12 13:46:57 -0700608 if (scale) {
buzbee2700f7e2014-03-07 09:46:20 -0800609 RegStorage r_new_index = AllocTemp();
610 OpRegRegImm(kOpLsl, r_new_index, rl_index.reg, scale);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700611 OpRegReg(kOpAdd, reg_ptr, r_new_index);
612 FreeTemp(r_new_index);
613 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800614 OpRegReg(kOpAdd, reg_ptr, rl_index.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700615 }
616 rl_src = LoadValueWide(rl_src, reg_class);
617
618 if (needs_range_check) {
Mingyao Yang80365d92014-04-18 12:10:58 -0700619 GenArrayBoundsCheck(rl_index.reg, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700620 FreeTemp(reg_len);
621 }
622
Andreas Gampe3c12c512014-06-24 18:46:29 +0000623 StoreBaseDisp(reg_ptr, 0, rl_src.reg, size, kNotVolatile);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700624 } else {
625 rl_src = LoadValue(rl_src, reg_class);
626 if (needs_range_check) {
Mingyao Yang80365d92014-04-18 12:10:58 -0700627 GenArrayBoundsCheck(rl_index.reg, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700628 FreeTemp(reg_len);
629 }
buzbee2700f7e2014-03-07 09:46:20 -0800630 StoreBaseIndexed(reg_ptr, rl_index.reg, rl_src.reg, scale, size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700631 }
Ian Rogers773aab12013-10-14 13:50:10 -0700632 if (allocated_reg_ptr_temp) {
633 FreeTemp(reg_ptr);
634 }
Ian Rogersa9a82542013-10-04 11:17:26 -0700635 if (card_mark) {
buzbee2700f7e2014-03-07 09:46:20 -0800636 MarkGCCard(rl_src.reg, rl_array.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700637 }
638}
639
640void MipsMir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700641 RegLocation rl_src1, RegLocation rl_shift) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700642 // Default implementation is just to ignore the constant case.
643 GenShiftOpLong(opcode, rl_dest, rl_src1, rl_shift);
644}
645
646void MipsMir2Lir::GenArithImmOpLong(Instruction::Code opcode,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700647 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700648 // Default - bail to non-const handler.
649 GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
650}
651
652} // namespace art