blob: 8ca53ea2284065d915f586bee8a7eae4108e73dd [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 *
Goran Jakovljevic10957932015-03-24 18:42:56 +010037 * Mips32 implementation
Brian Carlstrom7940e442013-07-12 13:46:57 -070038 * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
39 * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
40 * subu res, t0, t1 # res = -1:1:0 for [ < > = ]
41 * bnez res, finish
42 * sltu t0, x.lo, y.lo
43 * sgtu r1, x.lo, y.lo
44 * subu res, t0, t1
45 * finish:
46 *
Goran Jakovljevic10957932015-03-24 18:42:56 +010047 * Mips64 implementation
48 * slt temp, x, y; # (x < y) ? 1:0
49 * slt res, y, x; # (x > y) ? 1:0
50 * subu res, res, temp; # res = -1:1:0 for [ < > = ]
51 *
Brian Carlstrom7940e442013-07-12 13:46:57 -070052 */
Goran Jakovljevic10957932015-03-24 18:42:56 +010053void MipsMir2Lir::GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070054 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
55 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
Goran Jakovljevic10957932015-03-24 18:42:56 +010056 if (cu_->target64) {
57 RegStorage temp = AllocTempWide();
58 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
59 NewLIR3(kMipsSlt, temp.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
60 NewLIR3(kMipsSlt, rl_result.reg.GetReg(), rl_src2.reg.GetReg(), rl_src1.reg.GetReg());
61 NewLIR3(kMipsSubu, rl_result.reg.GetReg(), rl_result.reg.GetReg(), temp.GetReg());
62 FreeTemp(temp);
63 StoreValue(rl_dest, rl_result);
64 } else {
65 RegStorage t0 = AllocTemp();
66 RegStorage t1 = AllocTemp();
67 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
68 NewLIR3(kMipsSlt, t0.GetReg(), rl_src1.reg.GetHighReg(), rl_src2.reg.GetHighReg());
69 NewLIR3(kMipsSlt, t1.GetReg(), rl_src2.reg.GetHighReg(), rl_src1.reg.GetHighReg());
70 NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1.GetReg(), t0.GetReg());
Mathieu Chartier2cebb242015-04-21 16:50:40 -070071 LIR* branch = OpCmpImmBranch(kCondNe, rl_result.reg, 0, nullptr);
Goran Jakovljevic10957932015-03-24 18:42:56 +010072 NewLIR3(kMipsSltu, t0.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
73 NewLIR3(kMipsSltu, t1.GetReg(), rl_src2.reg.GetLowReg(), rl_src1.reg.GetLowReg());
74 NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1.GetReg(), t0.GetReg());
75 FreeTemp(t0);
76 FreeTemp(t1);
77 LIR* target = NewLIR0(kPseudoTargetLabel);
78 branch->target = target;
79 StoreValue(rl_dest, rl_result);
80 }
Brian Carlstrom7940e442013-07-12 13:46:57 -070081}
82
buzbee2700f7e2014-03-07 09:46:20 -080083LIR* MipsMir2Lir::OpCmpBranch(ConditionCode cond, RegStorage src1, RegStorage src2, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070084 LIR* branch;
85 MipsOpCode slt_op;
86 MipsOpCode br_op;
87 bool cmp_zero = false;
88 bool swapped = false;
89 switch (cond) {
90 case kCondEq:
91 br_op = kMipsBeq;
92 cmp_zero = true;
93 break;
94 case kCondNe:
95 br_op = kMipsBne;
96 cmp_zero = true;
97 break;
Vladimir Marko58af1f92013-12-19 13:31:15 +000098 case kCondUlt:
Brian Carlstrom7940e442013-07-12 13:46:57 -070099 slt_op = kMipsSltu;
100 br_op = kMipsBnez;
101 break;
Vladimir Marko58af1f92013-12-19 13:31:15 +0000102 case kCondUge:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700103 slt_op = kMipsSltu;
104 br_op = kMipsBeqz;
105 break;
106 case kCondGe:
107 slt_op = kMipsSlt;
108 br_op = kMipsBeqz;
109 break;
110 case kCondGt:
111 slt_op = kMipsSlt;
112 br_op = kMipsBnez;
113 swapped = true;
114 break;
115 case kCondLe:
116 slt_op = kMipsSlt;
117 br_op = kMipsBeqz;
118 swapped = true;
119 break;
120 case kCondLt:
121 slt_op = kMipsSlt;
122 br_op = kMipsBnez;
123 break;
124 case kCondHi: // Gtu
125 slt_op = kMipsSltu;
126 br_op = kMipsBnez;
127 swapped = true;
128 break;
129 default:
130 LOG(FATAL) << "No support for ConditionCode: " << cond;
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700131 return nullptr;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700132 }
133 if (cmp_zero) {
buzbee2700f7e2014-03-07 09:46:20 -0800134 branch = NewLIR2(br_op, src1.GetReg(), src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700135 } else {
buzbee091cc402014-03-31 10:14:40 -0700136 RegStorage t_reg = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700137 if (swapped) {
buzbee091cc402014-03-31 10:14:40 -0700138 NewLIR3(slt_op, t_reg.GetReg(), src2.GetReg(), src1.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700139 } else {
buzbee091cc402014-03-31 10:14:40 -0700140 NewLIR3(slt_op, t_reg.GetReg(), src1.GetReg(), src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700141 }
buzbee091cc402014-03-31 10:14:40 -0700142 branch = NewLIR1(br_op, t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700143 FreeTemp(t_reg);
144 }
145 branch->target = target;
146 return branch;
147}
148
buzbee2700f7e2014-03-07 09:46:20 -0800149LIR* MipsMir2Lir::OpCmpImmBranch(ConditionCode cond, RegStorage reg, int check_value, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700150 LIR* branch;
151 if (check_value != 0) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100152 // TUNING: handle s16 & kCondLt/Mi case using slti.
buzbee2700f7e2014-03-07 09:46:20 -0800153 RegStorage t_reg = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700154 LoadConstant(t_reg, check_value);
155 branch = OpCmpBranch(cond, reg, t_reg, target);
156 FreeTemp(t_reg);
157 return branch;
158 }
159 MipsOpCode opc;
160 switch (cond) {
161 case kCondEq: opc = kMipsBeqz; break;
162 case kCondGe: opc = kMipsBgez; break;
163 case kCondGt: opc = kMipsBgtz; break;
164 case kCondLe: opc = kMipsBlez; break;
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700165 // case KCondMi:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700166 case kCondLt: opc = kMipsBltz; break;
167 case kCondNe: opc = kMipsBnez; break;
168 default:
169 // Tuning: use slti when applicable
buzbee2700f7e2014-03-07 09:46:20 -0800170 RegStorage t_reg = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700171 LoadConstant(t_reg, check_value);
172 branch = OpCmpBranch(cond, reg, t_reg, target);
173 FreeTemp(t_reg);
174 return branch;
175 }
buzbee2700f7e2014-03-07 09:46:20 -0800176 branch = NewLIR1(opc, reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700177 branch->target = target;
178 return branch;
179}
180
buzbee2700f7e2014-03-07 09:46:20 -0800181LIR* MipsMir2Lir::OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100182 LIR* res;
183 MipsOpCode opcode;
184
185 if (!cu_->target64) {
186 // If src or dest is a pair, we'll be using low reg.
187 if (r_dest.IsPair()) {
188 r_dest = r_dest.GetLow();
189 }
190 if (r_src.IsPair()) {
191 r_src = r_src.GetLow();
192 }
193 } else {
194 DCHECK(!r_dest.IsPair() && !r_src.IsPair());
buzbee2700f7e2014-03-07 09:46:20 -0800195 }
Goran Jakovljevic10957932015-03-24 18:42:56 +0100196
buzbee091cc402014-03-31 10:14:40 -0700197 if (r_dest.IsFloat() || r_src.IsFloat())
Brian Carlstrom7940e442013-07-12 13:46:57 -0700198 return OpFpRegCopy(r_dest, r_src);
Goran Jakovljevic10957932015-03-24 18:42:56 +0100199 if (cu_->target64) {
200 // TODO: Check that r_src and r_dest are both 32 or both 64 bits length on Mips64.
201 if (r_dest.Is64Bit() || r_src.Is64Bit()) {
202 opcode = kMipsMove;
203 } else {
204 opcode = kMipsSll;
205 }
206 } else {
207 opcode = kMipsMove;
208 }
209 res = RawLIR(current_dalvik_offset_, opcode, r_dest.GetReg(), r_src.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700210 if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
211 res->flags.is_nop = true;
212 }
213 return res;
214}
215
buzbee7a11ab02014-04-28 20:02:38 -0700216void MipsMir2Lir::OpRegCopy(RegStorage r_dest, RegStorage r_src) {
217 if (r_dest != r_src) {
218 LIR *res = OpRegCopyNoInsert(r_dest, r_src);
219 AppendLIR(res);
220 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700221}
222
buzbee2700f7e2014-03-07 09:46:20 -0800223void MipsMir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100224 if (cu_->target64) {
225 OpRegCopy(r_dest, r_src);
226 return;
227 }
buzbee7a11ab02014-04-28 20:02:38 -0700228 if (r_dest != r_src) {
buzbee091cc402014-03-31 10:14:40 -0700229 bool dest_fp = r_dest.IsFloat();
230 bool src_fp = r_src.IsFloat();
buzbee7a11ab02014-04-28 20:02:38 -0700231 if (dest_fp) {
232 if (src_fp) {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800233 // Here if both src and dest are fp registers. OpRegCopy will choose the right copy
234 // (solo or pair).
buzbee091cc402014-03-31 10:14:40 -0700235 OpRegCopy(r_dest, r_src);
236 } else {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800237 // note the operands are swapped for the mtc1 and mthc1 instr.
238 // Here if dest is fp reg and src is core reg.
239 if (fpuIs32Bit_) {
Andreas Gampe8f486f32015-04-09 15:30:51 -0700240 NewLIR2(kMipsMtc1, r_src.GetLowReg(), r_dest.GetLowReg());
241 NewLIR2(kMipsMtc1, r_src.GetHighReg(), r_dest.GetHighReg());
Douglas Leung027f0ff2015-02-27 19:05:03 -0800242 } else {
Andreas Gampe8f486f32015-04-09 15:30:51 -0700243 r_dest = Fp64ToSolo32(r_dest);
244 NewLIR2(kMipsMtc1, r_src.GetLowReg(), r_dest.GetReg());
245 NewLIR2(kMipsMthc1, r_src.GetHighReg(), r_dest.GetReg());
Douglas Leung027f0ff2015-02-27 19:05:03 -0800246 }
buzbee7a11ab02014-04-28 20:02:38 -0700247 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700248 } else {
buzbee7a11ab02014-04-28 20:02:38 -0700249 if (src_fp) {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800250 // Here if dest is core reg and src is fp reg.
251 if (fpuIs32Bit_) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100252 NewLIR2(kMipsMfc1, r_dest.GetLowReg(), r_src.GetLowReg());
253 NewLIR2(kMipsMfc1, r_dest.GetHighReg(), r_src.GetHighReg());
Douglas Leung027f0ff2015-02-27 19:05:03 -0800254 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100255 r_src = Fp64ToSolo32(r_src);
256 NewLIR2(kMipsMfc1, r_dest.GetLowReg(), r_src.GetReg());
257 NewLIR2(kMipsMfhc1, r_dest.GetHighReg(), r_src.GetReg());
Douglas Leung027f0ff2015-02-27 19:05:03 -0800258 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700259 } else {
Douglas Leung027f0ff2015-02-27 19:05:03 -0800260 // Here if both src and dest are core registers.
Vladimir Marko8958f7f2015-06-19 14:56:38 +0100261 // Handle overlap
262 if (r_src.GetHighReg() != r_dest.GetLowReg()) {
263 OpRegCopy(r_dest.GetLow(), r_src.GetLow());
264 OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
265 } else if (r_src.GetLowReg() != r_dest.GetHighReg()) {
buzbee7a11ab02014-04-28 20:02:38 -0700266 OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
267 OpRegCopy(r_dest.GetLow(), r_src.GetLow());
268 } else {
Vladimir Marko8958f7f2015-06-19 14:56:38 +0100269 RegStorage r_tmp = AllocTemp();
270 OpRegCopy(r_tmp, r_src.GetHigh());
buzbee7a11ab02014-04-28 20:02:38 -0700271 OpRegCopy(r_dest.GetLow(), r_src.GetLow());
Vladimir Marko8958f7f2015-06-19 14:56:38 +0100272 OpRegCopy(r_dest.GetHigh(), r_tmp);
273 FreeTemp(r_tmp);
buzbee7a11ab02014-04-28 20:02:38 -0700274 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700275 }
276 }
277 }
278}
279
Andreas Gampe90969af2014-07-15 23:02:11 -0700280void MipsMir2Lir::GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code,
281 int32_t true_val, int32_t false_val, RegStorage rs_dest,
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100282 RegisterClass dest_reg_class ATTRIBUTE_UNUSED) {
Andreas Gampe90969af2014-07-15 23:02:11 -0700283 // Implement as a branch-over.
284 // TODO: Conditional move?
Andreas Gampe90969af2014-07-15 23:02:11 -0700285 LoadConstant(rs_dest, true_val);
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700286 LIR* ne_branchover = OpCmpBranch(code, left_op, right_op, nullptr);
Raghu Gandham08f8d4c2014-08-14 13:46:53 -0700287 LoadConstant(rs_dest, false_val);
Andreas Gampe90969af2014-07-15 23:02:11 -0700288 LIR* target_label = NewLIR0(kPseudoTargetLabel);
289 ne_branchover->target = target_label;
290}
291
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100292void MipsMir2Lir::GenSelect(BasicBlock* bb ATTRIBUTE_UNUSED, MIR* mir ATTRIBUTE_UNUSED) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700293 UNIMPLEMENTED(FATAL) << "Need codegen for select";
294}
295
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100296void MipsMir2Lir::GenFusedLongCmpBranch(BasicBlock* bb ATTRIBUTE_UNUSED,
297 MIR* mir ATTRIBUTE_UNUSED) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700298 UNIMPLEMENTED(FATAL) << "Need codegen for fused long cmp branch";
299}
300
buzbee2700f7e2014-03-07 09:46:20 -0800301RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegStorage reg1, RegStorage reg2,
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800302 bool is_div) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700303 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Douglas Leung027f0ff2015-02-27 19:05:03 -0800304
305 if (isaIsR6_) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100306 NewLIR3(is_div ? kMipsR6Div : kMipsR6Mod, rl_result.reg.GetReg(), reg1.GetReg(), reg2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700307 } else {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100308 NewLIR2(kMipsR2Div, reg1.GetReg(), reg2.GetReg());
309 NewLIR1(is_div ? kMipsR2Mflo : kMipsR2Mfhi, rl_result.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700310 }
311 return rl_result;
312}
313
Goran Jakovljevic10957932015-03-24 18:42:56 +0100314RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegStorage reg1, int lit, bool is_div) {
buzbee091cc402014-03-31 10:14:40 -0700315 RegStorage t_reg = AllocTemp();
Douglas Leung7fa6e272015-04-07 13:25:56 -0700316 // lit is guarantee to be a 16-bit constant
317 if (IsUint<16>(lit)) {
Andreas Gampe8f486f32015-04-09 15:30:51 -0700318 NewLIR3(kMipsOri, t_reg.GetReg(), rZERO, lit);
Douglas Leung7fa6e272015-04-07 13:25:56 -0700319 } else {
Andreas Gampe8f486f32015-04-09 15:30:51 -0700320 // Addiu will sign extend the entire width (32 or 64) of the register.
321 NewLIR3(kMipsAddiu, t_reg.GetReg(), rZERO, lit);
Douglas Leung7fa6e272015-04-07 13:25:56 -0700322 }
Douglas Leung027f0ff2015-02-27 19:05:03 -0800323 RegLocation rl_result = GenDivRem(rl_dest, reg1, t_reg, is_div);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700324 FreeTemp(t_reg);
325 return rl_result;
326}
327
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100328RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest ATTRIBUTE_UNUSED,
329 RegLocation rl_src1 ATTRIBUTE_UNUSED,
330 RegLocation rl_src2 ATTRIBUTE_UNUSED,
331 bool is_div ATTRIBUTE_UNUSED,
332 int flags ATTRIBUTE_UNUSED) {
Mark Mendell2bf31e62014-01-23 12:13:40 -0800333 LOG(FATAL) << "Unexpected use of GenDivRem for Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700334 UNREACHABLE();
Mark Mendell2bf31e62014-01-23 12:13:40 -0800335}
336
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100337RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest ATTRIBUTE_UNUSED,
338 RegLocation rl_src1 ATTRIBUTE_UNUSED,
339 int lit ATTRIBUTE_UNUSED,
340 bool is_div ATTRIBUTE_UNUSED) {
Mark Mendell2bf31e62014-01-23 12:13:40 -0800341 LOG(FATAL) << "Unexpected use of GenDivRemLit for Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700342 UNREACHABLE();
Mark Mendell2bf31e62014-01-23 12:13:40 -0800343}
344
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100345bool MipsMir2Lir::GenInlinedCas(CallInfo* info ATTRIBUTE_UNUSED,
346 bool is_long ATTRIBUTE_UNUSED,
347 bool is_object ATTRIBUTE_UNUSED) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700348 return false;
349}
350
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100351bool MipsMir2Lir::GenInlinedAbsFloat(CallInfo* info ATTRIBUTE_UNUSED) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700352 // TODO: add Mips implementation.
Vladimir Marko5030d3e2014-07-17 10:43:08 +0100353 return false;
354}
355
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100356bool MipsMir2Lir::GenInlinedAbsDouble(CallInfo* info ATTRIBUTE_UNUSED) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700357 // TODO: add Mips implementation.
Vladimir Marko5030d3e2014-07-17 10:43:08 +0100358 return false;
359}
360
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100361bool MipsMir2Lir::GenInlinedSqrt(CallInfo* info ATTRIBUTE_UNUSED) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700362 return false;
363}
364
Vladimir Markoe508a202013-11-04 15:24:22 +0000365bool MipsMir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
366 if (size != kSignedByte) {
367 // MIPS supports only aligned access. Defer unaligned access to JNI implementation.
368 return false;
369 }
Goran Jakovljevic10957932015-03-24 18:42:56 +0100370 RegLocation rl_src_address = info->args[0]; // Long address.
371 if (!cu_->target64) {
372 rl_src_address = NarrowRegLoc(rl_src_address); // Ignore high half in info->args[1].
373 }
Vladimir Markoe508a202013-11-04 15:24:22 +0000374 RegLocation rl_dest = InlineTarget(info);
Goran Jakovljevic10957932015-03-24 18:42:56 +0100375 RegLocation rl_address;
376 if (cu_->target64) {
377 rl_address = LoadValueWide(rl_src_address, kCoreReg);
378 } else {
379 rl_address = LoadValue(rl_src_address, kCoreReg);
380 }
Vladimir Markoe508a202013-11-04 15:24:22 +0000381 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
382 DCHECK(size == kSignedByte);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000383 LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size, kNotVolatile);
Vladimir Markoe508a202013-11-04 15:24:22 +0000384 StoreValue(rl_dest, rl_result);
385 return true;
386}
387
388bool MipsMir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) {
389 if (size != kSignedByte) {
390 // MIPS supports only aligned access. Defer unaligned access to JNI implementation.
391 return false;
392 }
Goran Jakovljevic10957932015-03-24 18:42:56 +0100393 RegLocation rl_src_address = info->args[0]; // Long address.
394 if (!cu_->target64) {
395 rl_src_address = NarrowRegLoc(rl_src_address); // Ignore high half in info->args[1].
396 }
397 RegLocation rl_src_value = info->args[2]; // [size] value.
398 RegLocation rl_address;
399 if (cu_->target64) {
400 rl_address = LoadValueWide(rl_src_address, kCoreReg);
401 } else {
402 rl_address = LoadValue(rl_src_address, kCoreReg);
403 }
Vladimir Markoe508a202013-11-04 15:24:22 +0000404 DCHECK(size == kSignedByte);
405 RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000406 StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size, kNotVolatile);
Vladimir Markoe508a202013-11-04 15:24:22 +0000407 return true;
408}
409
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100410void MipsMir2Lir::OpPcRelLoad(RegStorage reg ATTRIBUTE_UNUSED, LIR* target ATTRIBUTE_UNUSED) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700411 LOG(FATAL) << "Unexpected use of OpPcRelLoad for Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700412 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700413}
414
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100415LIR* MipsMir2Lir::OpVldm(RegStorage r_base ATTRIBUTE_UNUSED, int count ATTRIBUTE_UNUSED) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700416 LOG(FATAL) << "Unexpected use of OpVldm for Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700417 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700418}
419
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100420LIR* MipsMir2Lir::OpVstm(RegStorage r_base ATTRIBUTE_UNUSED, int count ATTRIBUTE_UNUSED) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700421 LOG(FATAL) << "Unexpected use of OpVstm for Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700422 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700423}
424
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100425void MipsMir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
426 RegLocation rl_result,
427 int lit ATTRIBUTE_UNUSED,
428 int first_bit,
429 int second_bit) {
buzbee2700f7e2014-03-07 09:46:20 -0800430 RegStorage t_reg = AllocTemp();
431 OpRegRegImm(kOpLsl, t_reg, rl_src.reg, second_bit - first_bit);
432 OpRegRegReg(kOpAdd, rl_result.reg, rl_src.reg, t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700433 FreeTemp(t_reg);
434 if (first_bit != 0) {
buzbee2700f7e2014-03-07 09:46:20 -0800435 OpRegRegImm(kOpLsl, rl_result.reg, rl_result.reg, first_bit);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700436 }
437}
438
Mingyao Yange643a172014-04-08 11:02:52 -0700439void MipsMir2Lir::GenDivZeroCheckWide(RegStorage reg) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100440 if (cu_->target64) {
441 GenDivZeroCheck(reg);
442 } else {
443 DCHECK(reg.IsPair()); // TODO: support k64BitSolo.
444 RegStorage t_reg = AllocTemp();
445 OpRegRegReg(kOpOr, t_reg, reg.GetLow(), reg.GetHigh());
446 GenDivZeroCheck(t_reg);
447 FreeTemp(t_reg);
448 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700449}
450
Goran Jakovljevic10957932015-03-24 18:42:56 +0100451// Test suspend flag, return target of taken suspend branch.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700452LIR* MipsMir2Lir::OpTestSuspend(LIR* target) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100453 OpRegImm(kOpSub, TargetPtrReg(kSuspend), 1);
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700454 return OpCmpImmBranch((target == nullptr) ? kCondEq : kCondNe, TargetPtrReg(kSuspend), 0, target);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700455}
456
Goran Jakovljevic10957932015-03-24 18:42:56 +0100457// Decrement register and branch on condition.
buzbee2700f7e2014-03-07 09:46:20 -0800458LIR* MipsMir2Lir::OpDecAndBranch(ConditionCode c_code, RegStorage reg, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700459 OpRegImm(kOpSub, reg, 1);
460 return OpCmpImmBranch(c_code, reg, 0, target);
461}
462
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100463bool MipsMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode ATTRIBUTE_UNUSED,
464 bool is_div ATTRIBUTE_UNUSED,
465 RegLocation rl_src ATTRIBUTE_UNUSED,
466 RegLocation rl_dest ATTRIBUTE_UNUSED,
467 int lit ATTRIBUTE_UNUSED) {
468 LOG(FATAL) << "Unexpected use of smallLiteralDivRem in Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700469 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700470}
471
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100472bool MipsMir2Lir::EasyMultiply(RegLocation rl_src ATTRIBUTE_UNUSED,
473 RegLocation rl_dest ATTRIBUTE_UNUSED,
474 int lit ATTRIBUTE_UNUSED) {
Ian Rogerse2143c02014-03-28 08:47:16 -0700475 LOG(FATAL) << "Unexpected use of easyMultiply in Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700476 UNREACHABLE();
Ian Rogerse2143c02014-03-28 08:47:16 -0700477}
478
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100479LIR* MipsMir2Lir::OpIT(ConditionCode cond ATTRIBUTE_UNUSED, const char* guide ATTRIBUTE_UNUSED) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700480 LOG(FATAL) << "Unexpected use of OpIT in Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700481 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700482}
483
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100484void MipsMir2Lir::OpEndIT(LIR* it ATTRIBUTE_UNUSED) {
Dave Allison3da67a52014-04-02 17:03:45 -0700485 LOG(FATAL) << "Unexpected use of OpEndIT in Mips";
486}
487
Goran Jakovljevic10957932015-03-24 18:42:56 +0100488void MipsMir2Lir::GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700489 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
490 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
491 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
492 /*
493 * [v1 v0] = [a1 a0] + [a3 a2];
494 * addu v0,a2,a0
495 * addu t1,a3,a1
496 * sltu v1,v0,a2
497 * addu v1,v1,t1
498 */
499
buzbee2700f7e2014-03-07 09:46:20 -0800500 OpRegRegReg(kOpAdd, rl_result.reg.GetLow(), rl_src2.reg.GetLow(), rl_src1.reg.GetLow());
501 RegStorage t_reg = AllocTemp();
502 OpRegRegReg(kOpAdd, t_reg, rl_src2.reg.GetHigh(), rl_src1.reg.GetHigh());
Goran Jakovljevic10957932015-03-24 18:42:56 +0100503 NewLIR3(kMipsSltu, rl_result.reg.GetHighReg(), rl_result.reg.GetLowReg(),
504 rl_src2.reg.GetLowReg());
buzbee2700f7e2014-03-07 09:46:20 -0800505 OpRegRegReg(kOpAdd, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700506 FreeTemp(t_reg);
507 StoreValueWide(rl_dest, rl_result);
508}
509
Goran Jakovljevic10957932015-03-24 18:42:56 +0100510void MipsMir2Lir::GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700511 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
512 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
513 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
514 /*
515 * [v1 v0] = [a1 a0] - [a3 a2];
516 * sltu t1,a0,a2
517 * subu v0,a0,a2
518 * subu v1,a1,a3
519 * subu v1,v1,t1
520 */
521
buzbee2700f7e2014-03-07 09:46:20 -0800522 RegStorage t_reg = AllocTemp();
523 NewLIR3(kMipsSltu, t_reg.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
524 OpRegRegReg(kOpSub, rl_result.reg.GetLow(), rl_src1.reg.GetLow(), rl_src2.reg.GetLow());
525 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_src1.reg.GetHigh(), rl_src2.reg.GetHigh());
526 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700527 FreeTemp(t_reg);
528 StoreValueWide(rl_dest, rl_result);
529}
530
Andreas Gampec76c6142014-08-04 16:30:03 -0700531void MipsMir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -0700532 RegLocation rl_src2, int flags) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100533 if (cu_->target64) {
534 switch (opcode) {
535 case Instruction::NOT_LONG:
536 GenNotLong(rl_dest, rl_src2);
537 return;
538 case Instruction::ADD_LONG:
539 case Instruction::ADD_LONG_2ADDR:
540 GenLongOp(kOpAdd, rl_dest, rl_src1, rl_src2);
541 return;
542 case Instruction::SUB_LONG:
543 case Instruction::SUB_LONG_2ADDR:
544 GenLongOp(kOpSub, rl_dest, rl_src1, rl_src2);
545 return;
546 case Instruction::MUL_LONG:
547 case Instruction::MUL_LONG_2ADDR:
548 GenMulLong(rl_dest, rl_src1, rl_src2);
549 return;
550 case Instruction::DIV_LONG:
551 case Instruction::DIV_LONG_2ADDR:
552 GenDivRemLong(opcode, rl_dest, rl_src1, rl_src2, /*is_div*/ true, flags);
553 return;
554 case Instruction::REM_LONG:
555 case Instruction::REM_LONG_2ADDR:
556 GenDivRemLong(opcode, rl_dest, rl_src1, rl_src2, /*is_div*/ false, flags);
557 return;
558 case Instruction::AND_LONG:
559 case Instruction::AND_LONG_2ADDR:
560 GenLongOp(kOpAnd, rl_dest, rl_src1, rl_src2);
561 return;
562 case Instruction::OR_LONG:
563 case Instruction::OR_LONG_2ADDR:
564 GenLongOp(kOpOr, rl_dest, rl_src1, rl_src2);
565 return;
566 case Instruction::XOR_LONG:
567 case Instruction::XOR_LONG_2ADDR:
568 GenLongOp(kOpXor, rl_dest, rl_src1, rl_src2);
569 return;
570 case Instruction::NEG_LONG:
571 GenNegLong(rl_dest, rl_src2);
572 return;
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100573
Goran Jakovljevic10957932015-03-24 18:42:56 +0100574 default:
575 LOG(FATAL) << "Invalid long arith op";
576 return;
577 }
578 } else {
579 switch (opcode) {
580 case Instruction::ADD_LONG:
581 case Instruction::ADD_LONG_2ADDR:
582 GenAddLong(rl_dest, rl_src1, rl_src2);
583 return;
584 case Instruction::SUB_LONG:
585 case Instruction::SUB_LONG_2ADDR:
586 GenSubLong(rl_dest, rl_src1, rl_src2);
587 return;
588 case Instruction::NEG_LONG:
589 GenNegLong(rl_dest, rl_src2);
590 return;
591 default:
592 break;
593 }
594 // Fallback for all other ops.
595 Mir2Lir::GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2, flags);
Andreas Gampec76c6142014-08-04 16:30:03 -0700596 }
Goran Jakovljevic10957932015-03-24 18:42:56 +0100597}
Andreas Gampec76c6142014-08-04 16:30:03 -0700598
Goran Jakovljevic10957932015-03-24 18:42:56 +0100599void MipsMir2Lir::GenLongOp(OpKind op, RegLocation rl_dest, RegLocation rl_src1,
600 RegLocation rl_src2) {
601 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
602 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
603 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
604 OpRegRegReg(op, rl_result.reg, rl_src1.reg, rl_src2.reg);
605 StoreValueWide(rl_dest, rl_result);
606}
607
608void MipsMir2Lir::GenNotLong(RegLocation rl_dest, RegLocation rl_src) {
609 rl_src = LoadValueWide(rl_src, kCoreReg);
610 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
611 OpRegReg(kOpMvn, rl_result.reg, rl_src.reg);
612 StoreValueWide(rl_dest, rl_result);
613}
614
615void MipsMir2Lir::GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
616 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
617 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
618 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
619 NewLIR3(kMips64Dmul, rl_result.reg.GetReg(), rl_src1.reg.GetReg(), rl_src2.reg.GetReg());
620 StoreValueWide(rl_dest, rl_result);
621}
622
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100623void MipsMir2Lir::GenDivRemLong(Instruction::Code opcode ATTRIBUTE_UNUSED,
624 RegLocation rl_dest,
625 RegLocation rl_src1,
626 RegLocation rl_src2,
627 bool is_div,
628 int flags) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100629 // TODO: Implement easy div/rem?
630 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
631 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
632 if ((flags & MIR_IGNORE_DIV_ZERO_CHECK) == 0) {
633 GenDivZeroCheckWide(rl_src2.reg);
634 }
635 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
636 NewLIR3(is_div ? kMips64Ddiv : kMips64Dmod, rl_result.reg.GetReg(), rl_src1.reg.GetReg(),
637 rl_src2.reg.GetReg());
638 StoreValueWide(rl_dest, rl_result);
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100639}
640
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700641void MipsMir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700642 rl_src = LoadValueWide(rl_src, kCoreReg);
Goran Jakovljevic10957932015-03-24 18:42:56 +0100643 RegLocation rl_result;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700644
Goran Jakovljevic10957932015-03-24 18:42:56 +0100645 if (cu_->target64) {
646 rl_result = EvalLocWide(rl_dest, kCoreReg, true);
647 OpRegReg(kOpNeg, rl_result.reg, rl_src.reg);
648 StoreValueWide(rl_dest, rl_result);
649 } else {
650 rl_result = EvalLoc(rl_dest, kCoreReg, true);
651 // [v1 v0] = -[a1 a0]
652 // negu v0,a0
653 // negu v1,a1
654 // sltu t1,r_zero
655 // subu v1,v1,t1
656 OpRegReg(kOpNeg, rl_result.reg.GetLow(), rl_src.reg.GetLow());
657 OpRegReg(kOpNeg, rl_result.reg.GetHigh(), rl_src.reg.GetHigh());
658 RegStorage t_reg = AllocTemp();
659 NewLIR3(kMipsSltu, t_reg.GetReg(), rZERO, rl_result.reg.GetLowReg());
660 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
661 FreeTemp(t_reg);
662 StoreValueWide(rl_dest, rl_result);
663 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700664}
665
Brian Carlstrom7940e442013-07-12 13:46:57 -0700666/*
667 * Generate array load
668 */
669void MipsMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800670 RegLocation rl_index, RegLocation rl_dest, int scale) {
buzbee091cc402014-03-31 10:14:40 -0700671 RegisterClass reg_class = RegClassBySize(size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700672 int len_offset = mirror::Array::LengthOffset().Int32Value();
673 int data_offset;
674 RegLocation rl_result;
Douglas Leung2db3e262014-06-25 16:02:55 -0700675 rl_array = LoadValue(rl_array, kRefReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700676 rl_index = LoadValue(rl_index, kCoreReg);
677
Douglas Leung2db3e262014-06-25 16:02:55 -0700678 // FIXME: need to add support for rl_index.is_const.
679
buzbee695d13a2014-04-19 13:32:20 -0700680 if (size == k64 || size == kDouble) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700681 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
682 } else {
683 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
684 }
685
Goran Jakovljevic10957932015-03-24 18:42:56 +0100686 // Null object?
buzbee2700f7e2014-03-07 09:46:20 -0800687 GenNullCheck(rl_array.reg, opt_flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700688
Goran Jakovljevic10957932015-03-24 18:42:56 +0100689 RegStorage reg_ptr = (cu_->target64) ? AllocTempRef() : AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700690 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
buzbee2700f7e2014-03-07 09:46:20 -0800691 RegStorage reg_len;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700692 if (needs_range_check) {
693 reg_len = AllocTemp();
Goran Jakovljevic10957932015-03-24 18:42:56 +0100694 // Get len.
buzbee695d13a2014-04-19 13:32:20 -0700695 Load32Disp(rl_array.reg, len_offset, reg_len);
Douglas Leung22bb5a22015-07-02 16:42:08 -0700696 MarkPossibleNullPointerException(opt_flags);
697 } else {
698 ForceImplicitNullCheck(rl_array.reg, opt_flags, false);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700699 }
Goran Jakovljevic10957932015-03-24 18:42:56 +0100700 // reg_ptr -> array data.
buzbee2700f7e2014-03-07 09:46:20 -0800701 OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
buzbee091cc402014-03-31 10:14:40 -0700702 FreeTemp(rl_array.reg);
buzbee695d13a2014-04-19 13:32:20 -0700703 if ((size == k64) || (size == kDouble)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700704 if (scale) {
buzbee2700f7e2014-03-07 09:46:20 -0800705 RegStorage r_new_index = AllocTemp();
706 OpRegRegImm(kOpLsl, r_new_index, rl_index.reg, scale);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700707 OpRegReg(kOpAdd, reg_ptr, r_new_index);
708 FreeTemp(r_new_index);
709 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800710 OpRegReg(kOpAdd, reg_ptr, rl_index.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700711 }
buzbee2700f7e2014-03-07 09:46:20 -0800712 FreeTemp(rl_index.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700713 rl_result = EvalLoc(rl_dest, reg_class, true);
714
715 if (needs_range_check) {
Mingyao Yang80365d92014-04-18 12:10:58 -0700716 GenArrayBoundsCheck(rl_index.reg, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700717 FreeTemp(reg_len);
718 }
Andreas Gampe3c12c512014-06-24 18:46:29 +0000719 LoadBaseDisp(reg_ptr, 0, rl_result.reg, size, kNotVolatile);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700720
721 FreeTemp(reg_ptr);
722 StoreValueWide(rl_dest, rl_result);
723 } else {
724 rl_result = EvalLoc(rl_dest, reg_class, true);
725
726 if (needs_range_check) {
Mingyao Yang80365d92014-04-18 12:10:58 -0700727 GenArrayBoundsCheck(rl_index.reg, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700728 FreeTemp(reg_len);
729 }
Goran Jakovljevic10957932015-03-24 18:42:56 +0100730
731 if (cu_->target64) {
732 if (rl_result.ref) {
733 LoadBaseIndexed(reg_ptr, As64BitReg(rl_index.reg), As32BitReg(rl_result.reg), scale,
734 kReference);
735 } else {
736 LoadBaseIndexed(reg_ptr, As64BitReg(rl_index.reg), rl_result.reg, scale, size);
737 }
738 } else {
739 LoadBaseIndexed(reg_ptr, rl_index.reg, rl_result.reg, scale, size);
740 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700741
742 FreeTemp(reg_ptr);
743 StoreValue(rl_dest, rl_result);
744 }
745}
746
747/*
748 * Generate array store
749 *
750 */
751void MipsMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800752 RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
buzbee091cc402014-03-31 10:14:40 -0700753 RegisterClass reg_class = RegClassBySize(size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700754 int len_offset = mirror::Array::LengthOffset().Int32Value();
755 int data_offset;
756
buzbee695d13a2014-04-19 13:32:20 -0700757 if (size == k64 || size == kDouble) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700758 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
759 } else {
760 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
761 }
762
Douglas Leung2db3e262014-06-25 16:02:55 -0700763 rl_array = LoadValue(rl_array, kRefReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700764 rl_index = LoadValue(rl_index, kCoreReg);
Douglas Leung2db3e262014-06-25 16:02:55 -0700765
766 // FIXME: need to add support for rl_index.is_const.
767
buzbee2700f7e2014-03-07 09:46:20 -0800768 RegStorage reg_ptr;
Ian Rogers773aab12013-10-14 13:50:10 -0700769 bool allocated_reg_ptr_temp = false;
buzbee091cc402014-03-31 10:14:40 -0700770 if (IsTemp(rl_array.reg) && !card_mark) {
771 Clobber(rl_array.reg);
buzbee2700f7e2014-03-07 09:46:20 -0800772 reg_ptr = rl_array.reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700773 } else {
774 reg_ptr = AllocTemp();
buzbee2700f7e2014-03-07 09:46:20 -0800775 OpRegCopy(reg_ptr, rl_array.reg);
Ian Rogers773aab12013-10-14 13:50:10 -0700776 allocated_reg_ptr_temp = true;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700777 }
778
Goran Jakovljevic10957932015-03-24 18:42:56 +0100779 // Null object?
buzbee2700f7e2014-03-07 09:46:20 -0800780 GenNullCheck(rl_array.reg, opt_flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700781
782 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
buzbee2700f7e2014-03-07 09:46:20 -0800783 RegStorage reg_len;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700784 if (needs_range_check) {
785 reg_len = AllocTemp();
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700786 // NOTE: max live temps(4) here.
Goran Jakovljevic10957932015-03-24 18:42:56 +0100787 // Get len.
buzbee695d13a2014-04-19 13:32:20 -0700788 Load32Disp(rl_array.reg, len_offset, reg_len);
Douglas Leung22bb5a22015-07-02 16:42:08 -0700789 MarkPossibleNullPointerException(opt_flags);
790 } else {
791 ForceImplicitNullCheck(rl_array.reg, opt_flags, false);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700792 }
Goran Jakovljevic10957932015-03-24 18:42:56 +0100793 // reg_ptr -> array data.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700794 OpRegImm(kOpAdd, reg_ptr, data_offset);
Goran Jakovljevic10957932015-03-24 18:42:56 +0100795 // At this point, reg_ptr points to array, 2 live temps.
buzbee695d13a2014-04-19 13:32:20 -0700796 if ((size == k64) || (size == kDouble)) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100797 // TUNING: specific wide routine that can handle fp regs.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700798 if (scale) {
buzbee2700f7e2014-03-07 09:46:20 -0800799 RegStorage r_new_index = AllocTemp();
800 OpRegRegImm(kOpLsl, r_new_index, rl_index.reg, scale);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700801 OpRegReg(kOpAdd, reg_ptr, r_new_index);
802 FreeTemp(r_new_index);
803 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800804 OpRegReg(kOpAdd, reg_ptr, rl_index.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700805 }
806 rl_src = LoadValueWide(rl_src, reg_class);
807
808 if (needs_range_check) {
Mingyao Yang80365d92014-04-18 12:10:58 -0700809 GenArrayBoundsCheck(rl_index.reg, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700810 FreeTemp(reg_len);
811 }
812
Andreas Gampe3c12c512014-06-24 18:46:29 +0000813 StoreBaseDisp(reg_ptr, 0, rl_src.reg, size, kNotVolatile);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700814 } else {
815 rl_src = LoadValue(rl_src, reg_class);
816 if (needs_range_check) {
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800817 GenArrayBoundsCheck(rl_index.reg, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700818 FreeTemp(reg_len);
819 }
buzbee2700f7e2014-03-07 09:46:20 -0800820 StoreBaseIndexed(reg_ptr, rl_index.reg, rl_src.reg, scale, size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700821 }
Ian Rogers773aab12013-10-14 13:50:10 -0700822 if (allocated_reg_ptr_temp) {
823 FreeTemp(reg_ptr);
824 }
Ian Rogersa9a82542013-10-04 11:17:26 -0700825 if (card_mark) {
Vladimir Marko743b98c2014-11-24 19:45:41 +0000826 MarkGCCard(opt_flags, rl_src.reg, rl_array.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700827 }
828}
829
Goran Jakovljevic10957932015-03-24 18:42:56 +0100830void MipsMir2Lir::GenShiftOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
831 RegLocation rl_shift) {
832 if (!cu_->target64) {
833 Mir2Lir::GenShiftOpLong(opcode, rl_dest, rl_src1, rl_shift);
834 return;
835 }
836 OpKind op = kOpBkpt;
837 switch (opcode) {
Andreas Gampe8f486f32015-04-09 15:30:51 -0700838 case Instruction::SHL_LONG:
839 case Instruction::SHL_LONG_2ADDR:
840 op = kOpLsl;
841 break;
842 case Instruction::SHR_LONG:
843 case Instruction::SHR_LONG_2ADDR:
844 op = kOpAsr;
845 break;
846 case Instruction::USHR_LONG:
847 case Instruction::USHR_LONG_2ADDR:
848 op = kOpLsr;
849 break;
850 default:
851 LOG(FATAL) << "Unexpected case: " << opcode;
Goran Jakovljevic10957932015-03-24 18:42:56 +0100852 }
853 rl_shift = LoadValue(rl_shift, kCoreReg);
854 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
855 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
856 OpRegRegReg(op, rl_result.reg, rl_src1.reg, As64BitReg(rl_shift.reg));
857 StoreValueWide(rl_dest, rl_result);
858}
859
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100860void MipsMir2Lir::GenShiftImmOpLong(Instruction::Code opcode,
861 RegLocation rl_dest,
862 RegLocation rl_src1,
863 RegLocation rl_shift,
864 int flags ATTRIBUTE_UNUSED) {
Goran Jakovljevic10957932015-03-24 18:42:56 +0100865 if (!cu_->target64) {
866 // Default implementation is just to ignore the constant case.
867 GenShiftOpLong(opcode, rl_dest, rl_src1, rl_shift);
868 return;
869 }
870 OpKind op = kOpBkpt;
871 // Per spec, we only care about low 6 bits of shift amount.
872 int shift_amount = mir_graph_->ConstantValue(rl_shift) & 0x3f;
873 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
874 if (shift_amount == 0) {
875 StoreValueWide(rl_dest, rl_src1);
876 return;
877 }
878
879 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
880 switch (opcode) {
881 case Instruction::SHL_LONG:
882 case Instruction::SHL_LONG_2ADDR:
883 op = kOpLsl;
884 break;
885 case Instruction::SHR_LONG:
886 case Instruction::SHR_LONG_2ADDR:
887 op = kOpAsr;
888 break;
889 case Instruction::USHR_LONG:
890 case Instruction::USHR_LONG_2ADDR:
891 op = kOpLsr;
892 break;
893 default:
894 LOG(FATAL) << "Unexpected case";
895 }
896 OpRegRegImm(op, rl_result.reg, rl_src1.reg, shift_amount);
897 StoreValueWide(rl_dest, rl_result);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700898}
899
Goran Jakovljevic10957932015-03-24 18:42:56 +0100900void MipsMir2Lir::GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
901 RegLocation rl_src1, RegLocation rl_src2, int flags) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700902 // Default - bail to non-const handler.
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -0700903 GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2, flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700904}
905
Goran Jakovljevic10957932015-03-24 18:42:56 +0100906void MipsMir2Lir::GenIntToLong(RegLocation rl_dest, RegLocation rl_src) {
907 if (!cu_->target64) {
908 Mir2Lir::GenIntToLong(rl_dest, rl_src);
909 return;
910 }
911 rl_src = LoadValue(rl_src, kCoreReg);
912 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true);
913 NewLIR3(kMipsSll, rl_result.reg.GetReg(), As64BitReg(rl_src.reg).GetReg(), 0);
914 StoreValueWide(rl_dest, rl_result);
915}
916
917void MipsMir2Lir::GenConversionCall(QuickEntrypointEnum trampoline, RegLocation rl_dest,
918 RegLocation rl_src, RegisterClass reg_class) {
919 FlushAllRegs(); // Send everything to home location.
920 CallRuntimeHelperRegLocation(trampoline, rl_src, false);
921 if (rl_dest.wide) {
922 RegLocation rl_result;
923 rl_result = GetReturnWide(reg_class);
924 StoreValueWide(rl_dest, rl_result);
925 } else {
926 RegLocation rl_result;
927 rl_result = GetReturn(reg_class);
928 StoreValue(rl_dest, rl_result);
929 }
930}
931
Brian Carlstrom7940e442013-07-12 13:46:57 -0700932} // namespace art