blob: 8093c9772c2e4315cb6cbea0b11381f25b48a157 [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"
Ian Rogersd582fa42014-11-05 23:46:43 -080020
Andreas Gampe0b9203e2015-01-22 20:39:27 -080021#include "base/logging.h"
22#include "dex/mir_graph.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070023#include "dex/quick/mir_to_lir-inl.h"
buzbeeb5860fb2014-06-21 15:31:01 -070024#include "dex/reg_storage_eq.h"
Ian Rogers166db042013-07-26 12:05:57 -070025#include "entrypoints/quick/quick_entrypoints.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070026#include "mips_lir.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070027#include "mirror/array-inl.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070028
29namespace art {
30
31/*
32 * Compare two 64-bit values
33 * x = y return 0
34 * x < y return -1
35 * x > y return 1
36 *
37 * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
38 * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
39 * subu res, t0, t1 # res = -1:1:0 for [ < > = ]
40 * bnez res, finish
41 * sltu t0, x.lo, y.lo
42 * sgtu r1, x.lo, y.lo
43 * subu res, t0, t1
44 * finish:
45 *
46 */
47void MipsMir2Lir::GenCmpLong(RegLocation rl_dest, RegLocation rl_src1,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070048 RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070049 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
50 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
buzbee091cc402014-03-31 10:14:40 -070051 RegStorage t0 = AllocTemp();
52 RegStorage t1 = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -070053 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee091cc402014-03-31 10:14:40 -070054 NewLIR3(kMipsSlt, t0.GetReg(), rl_src1.reg.GetHighReg(), rl_src2.reg.GetHighReg());
55 NewLIR3(kMipsSlt, t1.GetReg(), rl_src2.reg.GetHighReg(), rl_src1.reg.GetHighReg());
56 NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1.GetReg(), t0.GetReg());
buzbee2700f7e2014-03-07 09:46:20 -080057 LIR* branch = OpCmpImmBranch(kCondNe, rl_result.reg, 0, NULL);
buzbee091cc402014-03-31 10:14:40 -070058 NewLIR3(kMipsSltu, t0.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
59 NewLIR3(kMipsSltu, t1.GetReg(), rl_src2.reg.GetLowReg(), rl_src1.reg.GetLowReg());
60 NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1.GetReg(), t0.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -070061 FreeTemp(t0);
62 FreeTemp(t1);
63 LIR* target = NewLIR0(kPseudoTargetLabel);
64 branch->target = target;
65 StoreValue(rl_dest, rl_result);
66}
67
buzbee2700f7e2014-03-07 09:46:20 -080068LIR* MipsMir2Lir::OpCmpBranch(ConditionCode cond, RegStorage src1, RegStorage src2, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070069 LIR* branch;
70 MipsOpCode slt_op;
71 MipsOpCode br_op;
72 bool cmp_zero = false;
73 bool swapped = false;
74 switch (cond) {
75 case kCondEq:
76 br_op = kMipsBeq;
77 cmp_zero = true;
78 break;
79 case kCondNe:
80 br_op = kMipsBne;
81 cmp_zero = true;
82 break;
Vladimir Marko58af1f92013-12-19 13:31:15 +000083 case kCondUlt:
Brian Carlstrom7940e442013-07-12 13:46:57 -070084 slt_op = kMipsSltu;
85 br_op = kMipsBnez;
86 break;
Vladimir Marko58af1f92013-12-19 13:31:15 +000087 case kCondUge:
Brian Carlstrom7940e442013-07-12 13:46:57 -070088 slt_op = kMipsSltu;
89 br_op = kMipsBeqz;
90 break;
91 case kCondGe:
92 slt_op = kMipsSlt;
93 br_op = kMipsBeqz;
94 break;
95 case kCondGt:
96 slt_op = kMipsSlt;
97 br_op = kMipsBnez;
98 swapped = true;
99 break;
100 case kCondLe:
101 slt_op = kMipsSlt;
102 br_op = kMipsBeqz;
103 swapped = true;
104 break;
105 case kCondLt:
106 slt_op = kMipsSlt;
107 br_op = kMipsBnez;
108 break;
109 case kCondHi: // Gtu
110 slt_op = kMipsSltu;
111 br_op = kMipsBnez;
112 swapped = true;
113 break;
114 default:
115 LOG(FATAL) << "No support for ConditionCode: " << cond;
116 return NULL;
117 }
118 if (cmp_zero) {
buzbee2700f7e2014-03-07 09:46:20 -0800119 branch = NewLIR2(br_op, src1.GetReg(), src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700120 } else {
buzbee091cc402014-03-31 10:14:40 -0700121 RegStorage t_reg = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700122 if (swapped) {
buzbee091cc402014-03-31 10:14:40 -0700123 NewLIR3(slt_op, t_reg.GetReg(), src2.GetReg(), src1.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700124 } else {
buzbee091cc402014-03-31 10:14:40 -0700125 NewLIR3(slt_op, t_reg.GetReg(), src1.GetReg(), src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700126 }
buzbee091cc402014-03-31 10:14:40 -0700127 branch = NewLIR1(br_op, t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700128 FreeTemp(t_reg);
129 }
130 branch->target = target;
131 return branch;
132}
133
buzbee2700f7e2014-03-07 09:46:20 -0800134LIR* MipsMir2Lir::OpCmpImmBranch(ConditionCode cond, RegStorage reg, int check_value, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700135 LIR* branch;
136 if (check_value != 0) {
137 // TUNING: handle s16 & kCondLt/Mi case using slti
buzbee2700f7e2014-03-07 09:46:20 -0800138 RegStorage t_reg = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700139 LoadConstant(t_reg, check_value);
140 branch = OpCmpBranch(cond, reg, t_reg, target);
141 FreeTemp(t_reg);
142 return branch;
143 }
144 MipsOpCode opc;
145 switch (cond) {
146 case kCondEq: opc = kMipsBeqz; break;
147 case kCondGe: opc = kMipsBgez; break;
148 case kCondGt: opc = kMipsBgtz; break;
149 case kCondLe: opc = kMipsBlez; break;
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700150 // case KCondMi:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700151 case kCondLt: opc = kMipsBltz; break;
152 case kCondNe: opc = kMipsBnez; break;
153 default:
154 // Tuning: use slti when applicable
buzbee2700f7e2014-03-07 09:46:20 -0800155 RegStorage t_reg = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700156 LoadConstant(t_reg, check_value);
157 branch = OpCmpBranch(cond, reg, t_reg, target);
158 FreeTemp(t_reg);
159 return branch;
160 }
buzbee2700f7e2014-03-07 09:46:20 -0800161 branch = NewLIR1(opc, reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700162 branch->target = target;
163 return branch;
164}
165
buzbee2700f7e2014-03-07 09:46:20 -0800166LIR* MipsMir2Lir::OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src) {
167 // If src or dest is a pair, we'll be using low reg.
168 if (r_dest.IsPair()) {
169 r_dest = r_dest.GetLow();
170 }
171 if (r_src.IsPair()) {
172 r_src = r_src.GetLow();
173 }
buzbee091cc402014-03-31 10:14:40 -0700174 if (r_dest.IsFloat() || r_src.IsFloat())
Brian Carlstrom7940e442013-07-12 13:46:57 -0700175 return OpFpRegCopy(r_dest, r_src);
176 LIR* res = RawLIR(current_dalvik_offset_, kMipsMove,
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800177 r_dest.GetReg(), r_src.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700178 if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
179 res->flags.is_nop = true;
180 }
181 return res;
182}
183
buzbee7a11ab02014-04-28 20:02:38 -0700184void MipsMir2Lir::OpRegCopy(RegStorage r_dest, RegStorage r_src) {
185 if (r_dest != r_src) {
186 LIR *res = OpRegCopyNoInsert(r_dest, r_src);
187 AppendLIR(res);
188 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700189}
190
buzbee2700f7e2014-03-07 09:46:20 -0800191void MipsMir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) {
buzbee7a11ab02014-04-28 20:02:38 -0700192 if (r_dest != r_src) {
buzbee091cc402014-03-31 10:14:40 -0700193 bool dest_fp = r_dest.IsFloat();
194 bool src_fp = r_src.IsFloat();
buzbee7a11ab02014-04-28 20:02:38 -0700195 if (dest_fp) {
196 if (src_fp) {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800197 // Here if both src and dest are fp registers. OpRegCopy will choose the right copy
198 // (solo or pair).
buzbee091cc402014-03-31 10:14:40 -0700199 OpRegCopy(r_dest, r_src);
200 } else {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800201 // note the operands are swapped for the mtc1 and mthc1 instr.
202 // Here if dest is fp reg and src is core reg.
203 if (fpuIs32Bit_) {
204 NewLIR2(kMipsMtc1, r_src.GetLowReg(), r_dest.GetLowReg());
205 NewLIR2(kMipsMtc1, r_src.GetHighReg(), r_dest.GetHighReg());
206 } else {
207 r_dest = Fp64ToSolo32(r_dest);
208 NewLIR2(kMipsMtc1, r_src.GetLowReg(), r_dest.GetReg());
209 NewLIR2(kMipsMthc1, r_src.GetHighReg(), r_dest.GetReg());
210 }
buzbee7a11ab02014-04-28 20:02:38 -0700211 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700212 } else {
buzbee7a11ab02014-04-28 20:02:38 -0700213 if (src_fp) {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800214 // Here if dest is core reg and src is fp reg.
215 if (fpuIs32Bit_) {
216 NewLIR2(kMipsMfc1, r_dest.GetLowReg(), r_src.GetLowReg());
217 NewLIR2(kMipsMfc1, r_dest.GetHighReg(), r_src.GetHighReg());
218 } else {
219 r_src = Fp64ToSolo32(r_src);
220 NewLIR2(kMipsMfc1, r_dest.GetLowReg(), r_src.GetReg());
221 NewLIR2(kMipsMfhc1, r_dest.GetHighReg(), r_src.GetReg());
222 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700223 } else {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800224 // Here if both src and dest are core registers.
buzbee7a11ab02014-04-28 20:02:38 -0700225 // Handle overlap
226 if (r_src.GetHighReg() == r_dest.GetLowReg()) {
227 OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
228 OpRegCopy(r_dest.GetLow(), r_src.GetLow());
229 } else {
230 OpRegCopy(r_dest.GetLow(), r_src.GetLow());
231 OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
232 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700233 }
234 }
235 }
236}
237
Andreas Gampe90969af2014-07-15 23:02:11 -0700238void MipsMir2Lir::GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code,
239 int32_t true_val, int32_t false_val, RegStorage rs_dest,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700240 RegisterClass dest_reg_class) {
241 UNUSED(dest_reg_class);
Andreas Gampe90969af2014-07-15 23:02:11 -0700242 // Implement as a branch-over.
243 // TODO: Conditional move?
Andreas Gampe90969af2014-07-15 23:02:11 -0700244 LoadConstant(rs_dest, true_val);
Raghu Gandham08f8d4c2014-08-14 13:46:53 -0700245 LIR* ne_branchover = OpCmpBranch(code, left_op, right_op, NULL);
246 LoadConstant(rs_dest, false_val);
Andreas Gampe90969af2014-07-15 23:02:11 -0700247 LIR* target_label = NewLIR0(kPseudoTargetLabel);
248 ne_branchover->target = target_label;
249}
250
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700251void MipsMir2Lir::GenSelect(BasicBlock* bb, MIR* mir) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700252 UNUSED(bb, mir);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700253 UNIMPLEMENTED(FATAL) << "Need codegen for select";
254}
255
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700256void MipsMir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700257 UNUSED(bb, mir);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700258 UNIMPLEMENTED(FATAL) << "Need codegen for fused long cmp branch";
259}
260
buzbee2700f7e2014-03-07 09:46:20 -0800261RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegStorage reg1, RegStorage reg2,
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800262 bool is_div) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700263 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800264
265 if (isaIsR6_) {
266 NewLIR3(is_div ? kMipsR6Div : kMipsR6Mod,
267 rl_result.reg.GetReg(), reg1.GetReg(), reg2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700268 } else {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800269 NewLIR2(kMipsDiv, reg1.GetReg(), reg2.GetReg());
270 NewLIR1(is_div ? kMipsMflo : kMipsMfhi, rl_result.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700271 }
272 return rl_result;
273}
274
buzbee2700f7e2014-03-07 09:46:20 -0800275RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegStorage reg1, int lit,
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800276 bool is_div) {
buzbee091cc402014-03-31 10:14:40 -0700277 RegStorage t_reg = AllocTemp();
278 NewLIR3(kMipsAddiu, t_reg.GetReg(), rZERO, lit);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800279 RegLocation rl_result = GenDivRem(rl_dest, reg1, t_reg, is_div);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700280 FreeTemp(t_reg);
281 return rl_result;
282}
283
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700284RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
285 bool is_div, int flags) {
286 UNUSED(rl_dest, rl_src1, rl_src2, is_div, flags);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800287 LOG(FATAL) << "Unexpected use of GenDivRem for Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700288 UNREACHABLE();
Mark Mendell2bf31e62014-01-23 12:13:40 -0800289}
290
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700291RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit,
292 bool is_div) {
293 UNUSED(rl_dest, rl_src1, lit, is_div);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800294 LOG(FATAL) << "Unexpected use of GenDivRemLit for Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700295 UNREACHABLE();
Mark Mendell2bf31e62014-01-23 12:13:40 -0800296}
297
Vladimir Marko1c282e22013-11-21 14:49:47 +0000298bool MipsMir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700299 UNUSED(info, is_long, is_object);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700300 return false;
301}
302
Vladimir Marko5030d3e2014-07-17 10:43:08 +0100303bool MipsMir2Lir::GenInlinedAbsFloat(CallInfo* info) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700304 UNUSED(info);
305 // TODO: add Mips implementation.
Vladimir Marko5030d3e2014-07-17 10:43:08 +0100306 return false;
307}
308
309bool MipsMir2Lir::GenInlinedAbsDouble(CallInfo* info) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700310 UNUSED(info);
311 // TODO: add Mips implementation.
Vladimir Marko5030d3e2014-07-17 10:43:08 +0100312 return false;
313}
314
Brian Carlstrom7940e442013-07-12 13:46:57 -0700315bool MipsMir2Lir::GenInlinedSqrt(CallInfo* info) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700316 UNUSED(info);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700317 return false;
318}
319
Vladimir Markoe508a202013-11-04 15:24:22 +0000320bool MipsMir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
321 if (size != kSignedByte) {
322 // MIPS supports only aligned access. Defer unaligned access to JNI implementation.
323 return false;
324 }
325 RegLocation rl_src_address = info->args[0]; // long address
buzbee2700f7e2014-03-07 09:46:20 -0800326 rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1]
Vladimir Markoe508a202013-11-04 15:24:22 +0000327 RegLocation rl_dest = InlineTarget(info);
328 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
329 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
330 DCHECK(size == kSignedByte);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000331 LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size, kNotVolatile);
Vladimir Markoe508a202013-11-04 15:24:22 +0000332 StoreValue(rl_dest, rl_result);
333 return true;
334}
335
336bool MipsMir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) {
337 if (size != kSignedByte) {
338 // MIPS supports only aligned access. Defer unaligned access to JNI implementation.
339 return false;
340 }
341 RegLocation rl_src_address = info->args[0]; // long address
buzbee2700f7e2014-03-07 09:46:20 -0800342 rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1]
Vladimir Markoe508a202013-11-04 15:24:22 +0000343 RegLocation rl_src_value = info->args[2]; // [size] value
344 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
345 DCHECK(size == kSignedByte);
346 RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000347 StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size, kNotVolatile);
Vladimir Markoe508a202013-11-04 15:24:22 +0000348 return true;
349}
350
Vladimir Markof6737f72015-03-23 17:05:14 +0000351void MipsMir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700352 UNUSED(reg, target);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700353 LOG(FATAL) << "Unexpected use of OpPcRelLoad for Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700354 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700355}
356
buzbee2700f7e2014-03-07 09:46:20 -0800357LIR* MipsMir2Lir::OpVldm(RegStorage r_base, int count) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700358 UNUSED(r_base, count);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700359 LOG(FATAL) << "Unexpected use of OpVldm for Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700360 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700361}
362
buzbee2700f7e2014-03-07 09:46:20 -0800363LIR* MipsMir2Lir::OpVstm(RegStorage r_base, int count) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700364 UNUSED(r_base, count);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700365 LOG(FATAL) << "Unexpected use of OpVstm for Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700366 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700367}
368
369void MipsMir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
370 RegLocation rl_result, int lit,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700371 int first_bit, int second_bit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700372 UNUSED(lit);
buzbee2700f7e2014-03-07 09:46:20 -0800373 RegStorage t_reg = AllocTemp();
374 OpRegRegImm(kOpLsl, t_reg, rl_src.reg, second_bit - first_bit);
375 OpRegRegReg(kOpAdd, rl_result.reg, rl_src.reg, t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700376 FreeTemp(t_reg);
377 if (first_bit != 0) {
buzbee2700f7e2014-03-07 09:46:20 -0800378 OpRegRegImm(kOpLsl, rl_result.reg, rl_result.reg, first_bit);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700379 }
380}
381
Mingyao Yange643a172014-04-08 11:02:52 -0700382void MipsMir2Lir::GenDivZeroCheckWide(RegStorage reg) {
buzbee2700f7e2014-03-07 09:46:20 -0800383 DCHECK(reg.IsPair()); // TODO: support k64BitSolo.
384 RegStorage t_reg = AllocTemp();
385 OpRegRegReg(kOpOr, t_reg, reg.GetLow(), reg.GetHigh());
Mingyao Yangd15f4e22014-04-17 18:46:24 -0700386 GenDivZeroCheck(t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700387 FreeTemp(t_reg);
388}
389
390// Test suspend flag, return target of taken suspend branch
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700391LIR* MipsMir2Lir::OpTestSuspend(LIR* target) {
buzbee2700f7e2014-03-07 09:46:20 -0800392 OpRegImm(kOpSub, rs_rMIPS_SUSPEND, 1);
393 return OpCmpImmBranch((target == NULL) ? kCondEq : kCondNe, rs_rMIPS_SUSPEND, 0, target);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700394}
395
396// Decrement register and branch on condition
buzbee2700f7e2014-03-07 09:46:20 -0800397LIR* MipsMir2Lir::OpDecAndBranch(ConditionCode c_code, RegStorage reg, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700398 OpRegImm(kOpSub, reg, 1);
399 return OpCmpImmBranch(c_code, reg, 0, target);
400}
401
buzbee11b63d12013-08-27 07:34:17 -0700402bool MipsMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700403 RegLocation rl_src, RegLocation rl_dest, int lit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700404 UNUSED(dalvik_opcode, is_div, rl_src, rl_dest, lit);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700405 LOG(FATAL) << "Unexpected use of smallLiteralDive in Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700406 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700407}
408
Ian Rogerse2143c02014-03-28 08:47:16 -0700409bool MipsMir2Lir::EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700410 UNUSED(rl_src, rl_dest, lit);
Ian Rogerse2143c02014-03-28 08:47:16 -0700411 LOG(FATAL) << "Unexpected use of easyMultiply in Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700412 UNREACHABLE();
Ian Rogerse2143c02014-03-28 08:47:16 -0700413}
414
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700415LIR* MipsMir2Lir::OpIT(ConditionCode cond, const char* guide) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700416 UNUSED(cond, guide);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700417 LOG(FATAL) << "Unexpected use of OpIT in Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700418 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700419}
420
Dave Allison3da67a52014-04-02 17:03:45 -0700421void MipsMir2Lir::OpEndIT(LIR* it) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700422 UNUSED(it);
Dave Allison3da67a52014-04-02 17:03:45 -0700423 LOG(FATAL) << "Unexpected use of OpEndIT in Mips";
424}
425
Mark Mendelle02d48f2014-01-15 11:19:23 -0800426void MipsMir2Lir::GenAddLong(Instruction::Code opcode, RegLocation rl_dest,
427 RegLocation rl_src1, RegLocation rl_src2) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700428 UNUSED(opcode);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700429 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
430 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
431 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
432 /*
433 * [v1 v0] = [a1 a0] + [a3 a2];
434 * addu v0,a2,a0
435 * addu t1,a3,a1
436 * sltu v1,v0,a2
437 * addu v1,v1,t1
438 */
439
buzbee2700f7e2014-03-07 09:46:20 -0800440 OpRegRegReg(kOpAdd, rl_result.reg.GetLow(), rl_src2.reg.GetLow(), rl_src1.reg.GetLow());
441 RegStorage t_reg = AllocTemp();
442 OpRegRegReg(kOpAdd, t_reg, rl_src2.reg.GetHigh(), rl_src1.reg.GetHigh());
443 NewLIR3(kMipsSltu, rl_result.reg.GetHighReg(), rl_result.reg.GetLowReg(), rl_src2.reg.GetLowReg());
444 OpRegRegReg(kOpAdd, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700445 FreeTemp(t_reg);
446 StoreValueWide(rl_dest, rl_result);
447}
448
Mark Mendelle02d48f2014-01-15 11:19:23 -0800449void MipsMir2Lir::GenSubLong(Instruction::Code opcode, RegLocation rl_dest,
450 RegLocation rl_src1, RegLocation rl_src2) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700451 UNUSED(opcode);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700452 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
453 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
454 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
455 /*
456 * [v1 v0] = [a1 a0] - [a3 a2];
457 * sltu t1,a0,a2
458 * subu v0,a0,a2
459 * subu v1,a1,a3
460 * subu v1,v1,t1
461 */
462
buzbee2700f7e2014-03-07 09:46:20 -0800463 RegStorage t_reg = AllocTemp();
464 NewLIR3(kMipsSltu, t_reg.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
465 OpRegRegReg(kOpSub, rl_result.reg.GetLow(), rl_src1.reg.GetLow(), rl_src2.reg.GetLow());
466 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_src1.reg.GetHigh(), rl_src2.reg.GetHigh());
467 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700468 FreeTemp(t_reg);
469 StoreValueWide(rl_dest, rl_result);
470}
471
Andreas Gampec76c6142014-08-04 16:30:03 -0700472void MipsMir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -0700473 RegLocation rl_src2, int flags) {
Andreas Gampec76c6142014-08-04 16:30:03 -0700474 switch (opcode) {
475 case Instruction::ADD_LONG:
476 case Instruction::ADD_LONG_2ADDR:
477 GenAddLong(opcode, rl_dest, rl_src1, rl_src2);
478 return;
479 case Instruction::SUB_LONG:
480 case Instruction::SUB_LONG_2ADDR:
481 GenSubLong(opcode, rl_dest, rl_src1, rl_src2);
482 return;
483 case Instruction::NEG_LONG:
484 GenNegLong(rl_dest, rl_src2);
485 return;
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100486
Andreas Gampec76c6142014-08-04 16:30:03 -0700487 default:
488 break;
489 }
490
491 // Fallback for all other ops.
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -0700492 Mir2Lir::GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2, flags);
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100493}
494
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700495void MipsMir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700496 rl_src = LoadValueWide(rl_src, kCoreReg);
497 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
498 /*
499 * [v1 v0] = -[a1 a0]
500 * negu v0,a0
501 * negu v1,a1
502 * sltu t1,r_zero
503 * subu v1,v1,t1
504 */
505
buzbee2700f7e2014-03-07 09:46:20 -0800506 OpRegReg(kOpNeg, rl_result.reg.GetLow(), rl_src.reg.GetLow());
507 OpRegReg(kOpNeg, rl_result.reg.GetHigh(), rl_src.reg.GetHigh());
508 RegStorage t_reg = AllocTemp();
509 NewLIR3(kMipsSltu, t_reg.GetReg(), rZERO, rl_result.reg.GetLowReg());
510 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700511 FreeTemp(t_reg);
512 StoreValueWide(rl_dest, rl_result);
513}
514
Brian Carlstrom7940e442013-07-12 13:46:57 -0700515/*
516 * Generate array load
517 */
518void MipsMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800519 RegLocation rl_index, RegLocation rl_dest, int scale) {
buzbee091cc402014-03-31 10:14:40 -0700520 RegisterClass reg_class = RegClassBySize(size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700521 int len_offset = mirror::Array::LengthOffset().Int32Value();
522 int data_offset;
523 RegLocation rl_result;
Douglas Leung2db3e262014-06-25 16:02:55 -0700524 rl_array = LoadValue(rl_array, kRefReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700525 rl_index = LoadValue(rl_index, kCoreReg);
526
Douglas Leung2db3e262014-06-25 16:02:55 -0700527 // FIXME: need to add support for rl_index.is_const.
528
buzbee695d13a2014-04-19 13:32:20 -0700529 if (size == k64 || size == kDouble) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700530 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
531 } else {
532 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
533 }
534
535 /* null object? */
buzbee2700f7e2014-03-07 09:46:20 -0800536 GenNullCheck(rl_array.reg, opt_flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700537
buzbee2700f7e2014-03-07 09:46:20 -0800538 RegStorage reg_ptr = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700539 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
buzbee2700f7e2014-03-07 09:46:20 -0800540 RegStorage reg_len;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700541 if (needs_range_check) {
542 reg_len = AllocTemp();
543 /* Get len */
buzbee695d13a2014-04-19 13:32:20 -0700544 Load32Disp(rl_array.reg, len_offset, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700545 }
546 /* reg_ptr -> array data */
buzbee2700f7e2014-03-07 09:46:20 -0800547 OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
buzbee091cc402014-03-31 10:14:40 -0700548 FreeTemp(rl_array.reg);
buzbee695d13a2014-04-19 13:32:20 -0700549 if ((size == k64) || (size == kDouble)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700550 if (scale) {
buzbee2700f7e2014-03-07 09:46:20 -0800551 RegStorage r_new_index = AllocTemp();
552 OpRegRegImm(kOpLsl, r_new_index, rl_index.reg, scale);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700553 OpRegReg(kOpAdd, reg_ptr, r_new_index);
554 FreeTemp(r_new_index);
555 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800556 OpRegReg(kOpAdd, reg_ptr, rl_index.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700557 }
buzbee2700f7e2014-03-07 09:46:20 -0800558 FreeTemp(rl_index.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700559 rl_result = EvalLoc(rl_dest, reg_class, true);
560
561 if (needs_range_check) {
Mingyao Yang80365d92014-04-18 12:10:58 -0700562 GenArrayBoundsCheck(rl_index.reg, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700563 FreeTemp(reg_len);
564 }
Andreas Gampe3c12c512014-06-24 18:46:29 +0000565 LoadBaseDisp(reg_ptr, 0, rl_result.reg, size, kNotVolatile);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700566
567 FreeTemp(reg_ptr);
568 StoreValueWide(rl_dest, rl_result);
569 } else {
570 rl_result = EvalLoc(rl_dest, reg_class, true);
571
572 if (needs_range_check) {
Mingyao Yang80365d92014-04-18 12:10:58 -0700573 GenArrayBoundsCheck(rl_index.reg, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700574 FreeTemp(reg_len);
575 }
buzbee2700f7e2014-03-07 09:46:20 -0800576 LoadBaseIndexed(reg_ptr, rl_index.reg, rl_result.reg, scale, size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700577
578 FreeTemp(reg_ptr);
579 StoreValue(rl_dest, rl_result);
580 }
581}
582
583/*
584 * Generate array store
585 *
586 */
587void MipsMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800588 RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
buzbee091cc402014-03-31 10:14:40 -0700589 RegisterClass reg_class = RegClassBySize(size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700590 int len_offset = mirror::Array::LengthOffset().Int32Value();
591 int data_offset;
592
buzbee695d13a2014-04-19 13:32:20 -0700593 if (size == k64 || size == kDouble) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700594 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
595 } else {
596 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
597 }
598
Douglas Leung2db3e262014-06-25 16:02:55 -0700599 rl_array = LoadValue(rl_array, kRefReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700600 rl_index = LoadValue(rl_index, kCoreReg);
Douglas Leung2db3e262014-06-25 16:02:55 -0700601
602 // FIXME: need to add support for rl_index.is_const.
603
buzbee2700f7e2014-03-07 09:46:20 -0800604 RegStorage reg_ptr;
Ian Rogers773aab12013-10-14 13:50:10 -0700605 bool allocated_reg_ptr_temp = false;
buzbee091cc402014-03-31 10:14:40 -0700606 if (IsTemp(rl_array.reg) && !card_mark) {
607 Clobber(rl_array.reg);
buzbee2700f7e2014-03-07 09:46:20 -0800608 reg_ptr = rl_array.reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700609 } else {
610 reg_ptr = AllocTemp();
buzbee2700f7e2014-03-07 09:46:20 -0800611 OpRegCopy(reg_ptr, rl_array.reg);
Ian Rogers773aab12013-10-14 13:50:10 -0700612 allocated_reg_ptr_temp = true;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700613 }
614
615 /* null object? */
buzbee2700f7e2014-03-07 09:46:20 -0800616 GenNullCheck(rl_array.reg, opt_flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700617
618 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
buzbee2700f7e2014-03-07 09:46:20 -0800619 RegStorage reg_len;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700620 if (needs_range_check) {
621 reg_len = AllocTemp();
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700622 // NOTE: max live temps(4) here.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700623 /* Get len */
buzbee695d13a2014-04-19 13:32:20 -0700624 Load32Disp(rl_array.reg, len_offset, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700625 }
626 /* reg_ptr -> array data */
627 OpRegImm(kOpAdd, reg_ptr, data_offset);
628 /* at this point, reg_ptr points to array, 2 live temps */
buzbee695d13a2014-04-19 13:32:20 -0700629 if ((size == k64) || (size == kDouble)) {
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700630 // TUNING: specific wide routine that can handle fp regs
Brian Carlstrom7940e442013-07-12 13:46:57 -0700631 if (scale) {
buzbee2700f7e2014-03-07 09:46:20 -0800632 RegStorage r_new_index = AllocTemp();
633 OpRegRegImm(kOpLsl, r_new_index, rl_index.reg, scale);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700634 OpRegReg(kOpAdd, reg_ptr, r_new_index);
635 FreeTemp(r_new_index);
636 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800637 OpRegReg(kOpAdd, reg_ptr, rl_index.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700638 }
639 rl_src = LoadValueWide(rl_src, reg_class);
640
641 if (needs_range_check) {
Mingyao Yang80365d92014-04-18 12:10:58 -0700642 GenArrayBoundsCheck(rl_index.reg, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700643 FreeTemp(reg_len);
644 }
645
Andreas Gampe3c12c512014-06-24 18:46:29 +0000646 StoreBaseDisp(reg_ptr, 0, rl_src.reg, size, kNotVolatile);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700647 } else {
648 rl_src = LoadValue(rl_src, reg_class);
649 if (needs_range_check) {
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800650 GenArrayBoundsCheck(rl_index.reg, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700651 FreeTemp(reg_len);
652 }
buzbee2700f7e2014-03-07 09:46:20 -0800653 StoreBaseIndexed(reg_ptr, rl_index.reg, rl_src.reg, scale, size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700654 }
Ian Rogers773aab12013-10-14 13:50:10 -0700655 if (allocated_reg_ptr_temp) {
656 FreeTemp(reg_ptr);
657 }
Ian Rogersa9a82542013-10-04 11:17:26 -0700658 if (card_mark) {
Vladimir Marko743b98c2014-11-24 19:45:41 +0000659 MarkGCCard(opt_flags, rl_src.reg, rl_array.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700660 }
661}
662
663void MipsMir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -0700664 RegLocation rl_src1, RegLocation rl_shift, int flags) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700665 UNUSED(flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700666 // Default implementation is just to ignore the constant case.
667 GenShiftOpLong(opcode, rl_dest, rl_src1, rl_shift);
668}
669
670void MipsMir2Lir::GenArithImmOpLong(Instruction::Code opcode,
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -0700671 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
672 int flags) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700673 // Default - bail to non-const handler.
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -0700674 GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2, flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700675}
676
677} // namespace art