blob: aabef60c30f8b8f4bb807fdd5f26083580e41ae7 [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
Brian Carlstrom7940e442013-07-12 13:46:57 -070021#include "dex/quick/mir_to_lir-inl.h"
buzbeeb5860fb2014-06-21 15:31:01 -070022#include "dex/reg_storage_eq.h"
Ian Rogers166db042013-07-26 12:05:57 -070023#include "entrypoints/quick/quick_entrypoints.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070024#include "mips_lir.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070025#include "mirror/array-inl.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070026
27namespace art {
28
29/*
30 * Compare two 64-bit values
31 * x = y return 0
32 * x < y return -1
33 * x > y return 1
34 *
35 * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
36 * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
37 * subu res, t0, t1 # res = -1:1:0 for [ < > = ]
38 * bnez res, finish
39 * sltu t0, x.lo, y.lo
40 * sgtu r1, x.lo, y.lo
41 * subu res, t0, t1
42 * finish:
43 *
44 */
45void MipsMir2Lir::GenCmpLong(RegLocation rl_dest, RegLocation rl_src1,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070046 RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070047 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
48 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
buzbee091cc402014-03-31 10:14:40 -070049 RegStorage t0 = AllocTemp();
50 RegStorage t1 = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -070051 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee091cc402014-03-31 10:14:40 -070052 NewLIR3(kMipsSlt, t0.GetReg(), rl_src1.reg.GetHighReg(), rl_src2.reg.GetHighReg());
53 NewLIR3(kMipsSlt, t1.GetReg(), rl_src2.reg.GetHighReg(), rl_src1.reg.GetHighReg());
54 NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1.GetReg(), t0.GetReg());
buzbee2700f7e2014-03-07 09:46:20 -080055 LIR* branch = OpCmpImmBranch(kCondNe, rl_result.reg, 0, NULL);
buzbee091cc402014-03-31 10:14:40 -070056 NewLIR3(kMipsSltu, t0.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
57 NewLIR3(kMipsSltu, t1.GetReg(), rl_src2.reg.GetLowReg(), rl_src1.reg.GetLowReg());
58 NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1.GetReg(), t0.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -070059 FreeTemp(t0);
60 FreeTemp(t1);
61 LIR* target = NewLIR0(kPseudoTargetLabel);
62 branch->target = target;
63 StoreValue(rl_dest, rl_result);
64}
65
buzbee2700f7e2014-03-07 09:46:20 -080066LIR* MipsMir2Lir::OpCmpBranch(ConditionCode cond, RegStorage src1, RegStorage src2, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070067 LIR* branch;
68 MipsOpCode slt_op;
69 MipsOpCode br_op;
70 bool cmp_zero = false;
71 bool swapped = false;
72 switch (cond) {
73 case kCondEq:
74 br_op = kMipsBeq;
75 cmp_zero = true;
76 break;
77 case kCondNe:
78 br_op = kMipsBne;
79 cmp_zero = true;
80 break;
Vladimir Marko58af1f92013-12-19 13:31:15 +000081 case kCondUlt:
Brian Carlstrom7940e442013-07-12 13:46:57 -070082 slt_op = kMipsSltu;
83 br_op = kMipsBnez;
84 break;
Vladimir Marko58af1f92013-12-19 13:31:15 +000085 case kCondUge:
Brian Carlstrom7940e442013-07-12 13:46:57 -070086 slt_op = kMipsSltu;
87 br_op = kMipsBeqz;
88 break;
89 case kCondGe:
90 slt_op = kMipsSlt;
91 br_op = kMipsBeqz;
92 break;
93 case kCondGt:
94 slt_op = kMipsSlt;
95 br_op = kMipsBnez;
96 swapped = true;
97 break;
98 case kCondLe:
99 slt_op = kMipsSlt;
100 br_op = kMipsBeqz;
101 swapped = true;
102 break;
103 case kCondLt:
104 slt_op = kMipsSlt;
105 br_op = kMipsBnez;
106 break;
107 case kCondHi: // Gtu
108 slt_op = kMipsSltu;
109 br_op = kMipsBnez;
110 swapped = true;
111 break;
112 default:
113 LOG(FATAL) << "No support for ConditionCode: " << cond;
114 return NULL;
115 }
116 if (cmp_zero) {
buzbee2700f7e2014-03-07 09:46:20 -0800117 branch = NewLIR2(br_op, src1.GetReg(), src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700118 } else {
buzbee091cc402014-03-31 10:14:40 -0700119 RegStorage t_reg = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700120 if (swapped) {
buzbee091cc402014-03-31 10:14:40 -0700121 NewLIR3(slt_op, t_reg.GetReg(), src2.GetReg(), src1.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700122 } else {
buzbee091cc402014-03-31 10:14:40 -0700123 NewLIR3(slt_op, t_reg.GetReg(), src1.GetReg(), src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700124 }
buzbee091cc402014-03-31 10:14:40 -0700125 branch = NewLIR1(br_op, t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700126 FreeTemp(t_reg);
127 }
128 branch->target = target;
129 return branch;
130}
131
buzbee2700f7e2014-03-07 09:46:20 -0800132LIR* MipsMir2Lir::OpCmpImmBranch(ConditionCode cond, RegStorage reg, int check_value, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700133 LIR* branch;
134 if (check_value != 0) {
135 // TUNING: handle s16 & kCondLt/Mi case using slti
buzbee2700f7e2014-03-07 09:46:20 -0800136 RegStorage t_reg = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700137 LoadConstant(t_reg, check_value);
138 branch = OpCmpBranch(cond, reg, t_reg, target);
139 FreeTemp(t_reg);
140 return branch;
141 }
142 MipsOpCode opc;
143 switch (cond) {
144 case kCondEq: opc = kMipsBeqz; break;
145 case kCondGe: opc = kMipsBgez; break;
146 case kCondGt: opc = kMipsBgtz; break;
147 case kCondLe: opc = kMipsBlez; break;
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700148 // case KCondMi:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700149 case kCondLt: opc = kMipsBltz; break;
150 case kCondNe: opc = kMipsBnez; break;
151 default:
152 // Tuning: use slti when applicable
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 }
buzbee2700f7e2014-03-07 09:46:20 -0800159 branch = NewLIR1(opc, reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700160 branch->target = target;
161 return branch;
162}
163
buzbee2700f7e2014-03-07 09:46:20 -0800164LIR* MipsMir2Lir::OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src) {
165 // If src or dest is a pair, we'll be using low reg.
166 if (r_dest.IsPair()) {
167 r_dest = r_dest.GetLow();
168 }
169 if (r_src.IsPair()) {
170 r_src = r_src.GetLow();
171 }
buzbee091cc402014-03-31 10:14:40 -0700172 if (r_dest.IsFloat() || r_src.IsFloat())
Brian Carlstrom7940e442013-07-12 13:46:57 -0700173 return OpFpRegCopy(r_dest, r_src);
174 LIR* res = RawLIR(current_dalvik_offset_, kMipsMove,
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800175 r_dest.GetReg(), r_src.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700176 if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
177 res->flags.is_nop = true;
178 }
179 return res;
180}
181
buzbee7a11ab02014-04-28 20:02:38 -0700182void MipsMir2Lir::OpRegCopy(RegStorage r_dest, RegStorage r_src) {
183 if (r_dest != r_src) {
184 LIR *res = OpRegCopyNoInsert(r_dest, r_src);
185 AppendLIR(res);
186 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700187}
188
buzbee2700f7e2014-03-07 09:46:20 -0800189void MipsMir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) {
buzbee7a11ab02014-04-28 20:02:38 -0700190 if (r_dest != r_src) {
buzbee091cc402014-03-31 10:14:40 -0700191 bool dest_fp = r_dest.IsFloat();
192 bool src_fp = r_src.IsFloat();
buzbee7a11ab02014-04-28 20:02:38 -0700193 if (dest_fp) {
194 if (src_fp) {
buzbee091cc402014-03-31 10:14:40 -0700195 OpRegCopy(r_dest, r_src);
196 } else {
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800197 /* note the operands are swapped for the mtc1 instr */
buzbee091cc402014-03-31 10:14:40 -0700198 NewLIR2(kMipsMtc1, r_src.GetLowReg(), r_dest.GetLowReg());
199 NewLIR2(kMipsMtc1, r_src.GetHighReg(), r_dest.GetHighReg());
buzbee7a11ab02014-04-28 20:02:38 -0700200 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700201 } else {
buzbee7a11ab02014-04-28 20:02:38 -0700202 if (src_fp) {
203 NewLIR2(kMipsMfc1, r_dest.GetLowReg(), r_src.GetLowReg());
204 NewLIR2(kMipsMfc1, r_dest.GetHighReg(), r_src.GetHighReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700205 } else {
buzbee7a11ab02014-04-28 20:02:38 -0700206 // Handle overlap
207 if (r_src.GetHighReg() == r_dest.GetLowReg()) {
208 OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
209 OpRegCopy(r_dest.GetLow(), r_src.GetLow());
210 } else {
211 OpRegCopy(r_dest.GetLow(), r_src.GetLow());
212 OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
213 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700214 }
215 }
216 }
217}
218
Andreas Gampe90969af2014-07-15 23:02:11 -0700219void MipsMir2Lir::GenSelectConst32(RegStorage left_op, RegStorage right_op, ConditionCode code,
220 int32_t true_val, int32_t false_val, RegStorage rs_dest,
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700221 RegisterClass dest_reg_class) {
222 UNUSED(dest_reg_class);
Andreas Gampe90969af2014-07-15 23:02:11 -0700223 // Implement as a branch-over.
224 // TODO: Conditional move?
Andreas Gampe90969af2014-07-15 23:02:11 -0700225 LoadConstant(rs_dest, true_val);
Raghu Gandham08f8d4c2014-08-14 13:46:53 -0700226 LIR* ne_branchover = OpCmpBranch(code, left_op, right_op, NULL);
227 LoadConstant(rs_dest, false_val);
Andreas Gampe90969af2014-07-15 23:02:11 -0700228 LIR* target_label = NewLIR0(kPseudoTargetLabel);
229 ne_branchover->target = target_label;
230}
231
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700232void MipsMir2Lir::GenSelect(BasicBlock* bb, MIR* mir) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700233 UNUSED(bb, mir);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700234 UNIMPLEMENTED(FATAL) << "Need codegen for select";
235}
236
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700237void MipsMir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700238 UNUSED(bb, mir);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700239 UNIMPLEMENTED(FATAL) << "Need codegen for fused long cmp branch";
240}
241
buzbee2700f7e2014-03-07 09:46:20 -0800242RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegStorage reg1, RegStorage reg2,
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800243 bool is_div) {
buzbee9da5c102014-03-28 12:59:18 -0700244 NewLIR2(kMipsDiv, reg1.GetReg(), reg2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700245 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
246 if (is_div) {
buzbee9da5c102014-03-28 12:59:18 -0700247 NewLIR1(kMipsMflo, rl_result.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700248 } else {
buzbee9da5c102014-03-28 12:59:18 -0700249 NewLIR1(kMipsMfhi, rl_result.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700250 }
251 return rl_result;
252}
253
buzbee2700f7e2014-03-07 09:46:20 -0800254RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegStorage reg1, int lit,
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800255 bool is_div) {
buzbee091cc402014-03-31 10:14:40 -0700256 RegStorage t_reg = AllocTemp();
257 NewLIR3(kMipsAddiu, t_reg.GetReg(), rZERO, lit);
258 NewLIR2(kMipsDiv, reg1.GetReg(), t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700259 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
260 if (is_div) {
buzbee9da5c102014-03-28 12:59:18 -0700261 NewLIR1(kMipsMflo, rl_result.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700262 } else {
buzbee9da5c102014-03-28 12:59:18 -0700263 NewLIR1(kMipsMfhi, rl_result.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700264 }
265 FreeTemp(t_reg);
266 return rl_result;
267}
268
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700269RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
270 bool is_div, int flags) {
271 UNUSED(rl_dest, rl_src1, rl_src2, is_div, flags);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800272 LOG(FATAL) << "Unexpected use of GenDivRem for Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700273 UNREACHABLE();
Mark Mendell2bf31e62014-01-23 12:13:40 -0800274}
275
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700276RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit,
277 bool is_div) {
278 UNUSED(rl_dest, rl_src1, lit, is_div);
Mark Mendell2bf31e62014-01-23 12:13:40 -0800279 LOG(FATAL) << "Unexpected use of GenDivRemLit for Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700280 UNREACHABLE();
Mark Mendell2bf31e62014-01-23 12:13:40 -0800281}
282
Vladimir Marko1c282e22013-11-21 14:49:47 +0000283bool MipsMir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700284 UNUSED(info, is_long, is_object);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700285 return false;
286}
287
Vladimir Marko5030d3e2014-07-17 10:43:08 +0100288bool MipsMir2Lir::GenInlinedAbsFloat(CallInfo* info) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700289 UNUSED(info);
290 // TODO: add Mips implementation.
Vladimir Marko5030d3e2014-07-17 10:43:08 +0100291 return false;
292}
293
294bool MipsMir2Lir::GenInlinedAbsDouble(CallInfo* info) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700295 UNUSED(info);
296 // TODO: add Mips implementation.
Vladimir Marko5030d3e2014-07-17 10:43:08 +0100297 return false;
298}
299
Brian Carlstrom7940e442013-07-12 13:46:57 -0700300bool MipsMir2Lir::GenInlinedSqrt(CallInfo* info) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700301 UNUSED(info);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700302 return false;
303}
304
Vladimir Markoe508a202013-11-04 15:24:22 +0000305bool MipsMir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
306 if (size != kSignedByte) {
307 // MIPS supports only aligned access. Defer unaligned access to JNI implementation.
308 return false;
309 }
310 RegLocation rl_src_address = info->args[0]; // long address
buzbee2700f7e2014-03-07 09:46:20 -0800311 rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1]
Vladimir Markoe508a202013-11-04 15:24:22 +0000312 RegLocation rl_dest = InlineTarget(info);
313 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
314 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
315 DCHECK(size == kSignedByte);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000316 LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size, kNotVolatile);
Vladimir Markoe508a202013-11-04 15:24:22 +0000317 StoreValue(rl_dest, rl_result);
318 return true;
319}
320
321bool MipsMir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) {
322 if (size != kSignedByte) {
323 // MIPS supports only aligned access. Defer unaligned access to JNI implementation.
324 return false;
325 }
326 RegLocation rl_src_address = info->args[0]; // long address
buzbee2700f7e2014-03-07 09:46:20 -0800327 rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1]
Vladimir Markoe508a202013-11-04 15:24:22 +0000328 RegLocation rl_src_value = info->args[2]; // [size] value
329 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
330 DCHECK(size == kSignedByte);
331 RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000332 StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size, kNotVolatile);
Vladimir Markoe508a202013-11-04 15:24:22 +0000333 return true;
334}
335
buzbee2700f7e2014-03-07 09:46:20 -0800336LIR* MipsMir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700337 UNUSED(reg, target);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700338 LOG(FATAL) << "Unexpected use of OpPcRelLoad for Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700339 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700340}
341
buzbee2700f7e2014-03-07 09:46:20 -0800342LIR* MipsMir2Lir::OpVldm(RegStorage r_base, int count) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700343 UNUSED(r_base, count);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700344 LOG(FATAL) << "Unexpected use of OpVldm for Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700345 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700346}
347
buzbee2700f7e2014-03-07 09:46:20 -0800348LIR* MipsMir2Lir::OpVstm(RegStorage r_base, int count) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700349 UNUSED(r_base, count);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700350 LOG(FATAL) << "Unexpected use of OpVstm for Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700351 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700352}
353
354void MipsMir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
355 RegLocation rl_result, int lit,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700356 int first_bit, int second_bit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700357 UNUSED(lit);
buzbee2700f7e2014-03-07 09:46:20 -0800358 RegStorage t_reg = AllocTemp();
359 OpRegRegImm(kOpLsl, t_reg, rl_src.reg, second_bit - first_bit);
360 OpRegRegReg(kOpAdd, rl_result.reg, rl_src.reg, t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700361 FreeTemp(t_reg);
362 if (first_bit != 0) {
buzbee2700f7e2014-03-07 09:46:20 -0800363 OpRegRegImm(kOpLsl, rl_result.reg, rl_result.reg, first_bit);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700364 }
365}
366
Mingyao Yange643a172014-04-08 11:02:52 -0700367void MipsMir2Lir::GenDivZeroCheckWide(RegStorage reg) {
buzbee2700f7e2014-03-07 09:46:20 -0800368 DCHECK(reg.IsPair()); // TODO: support k64BitSolo.
369 RegStorage t_reg = AllocTemp();
370 OpRegRegReg(kOpOr, t_reg, reg.GetLow(), reg.GetHigh());
Mingyao Yangd15f4e22014-04-17 18:46:24 -0700371 GenDivZeroCheck(t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700372 FreeTemp(t_reg);
373}
374
375// Test suspend flag, return target of taken suspend branch
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700376LIR* MipsMir2Lir::OpTestSuspend(LIR* target) {
buzbee2700f7e2014-03-07 09:46:20 -0800377 OpRegImm(kOpSub, rs_rMIPS_SUSPEND, 1);
378 return OpCmpImmBranch((target == NULL) ? kCondEq : kCondNe, rs_rMIPS_SUSPEND, 0, target);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700379}
380
381// Decrement register and branch on condition
buzbee2700f7e2014-03-07 09:46:20 -0800382LIR* MipsMir2Lir::OpDecAndBranch(ConditionCode c_code, RegStorage reg, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700383 OpRegImm(kOpSub, reg, 1);
384 return OpCmpImmBranch(c_code, reg, 0, target);
385}
386
buzbee11b63d12013-08-27 07:34:17 -0700387bool MipsMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700388 RegLocation rl_src, RegLocation rl_dest, int lit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700389 UNUSED(dalvik_opcode, is_div, rl_src, rl_dest, lit);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700390 LOG(FATAL) << "Unexpected use of smallLiteralDive in Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700391 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700392}
393
Ian Rogerse2143c02014-03-28 08:47:16 -0700394bool MipsMir2Lir::EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700395 UNUSED(rl_src, rl_dest, lit);
Ian Rogerse2143c02014-03-28 08:47:16 -0700396 LOG(FATAL) << "Unexpected use of easyMultiply in Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700397 UNREACHABLE();
Ian Rogerse2143c02014-03-28 08:47:16 -0700398}
399
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700400LIR* MipsMir2Lir::OpIT(ConditionCode cond, const char* guide) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700401 UNUSED(cond, guide);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700402 LOG(FATAL) << "Unexpected use of OpIT in Mips";
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700403 UNREACHABLE();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700404}
405
Dave Allison3da67a52014-04-02 17:03:45 -0700406void MipsMir2Lir::OpEndIT(LIR* it) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700407 UNUSED(it);
Dave Allison3da67a52014-04-02 17:03:45 -0700408 LOG(FATAL) << "Unexpected use of OpEndIT in Mips";
409}
410
Mark Mendelle02d48f2014-01-15 11:19:23 -0800411void MipsMir2Lir::GenAddLong(Instruction::Code opcode, RegLocation rl_dest,
412 RegLocation rl_src1, RegLocation rl_src2) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700413 UNUSED(opcode);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700414 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
415 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
416 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
417 /*
418 * [v1 v0] = [a1 a0] + [a3 a2];
419 * addu v0,a2,a0
420 * addu t1,a3,a1
421 * sltu v1,v0,a2
422 * addu v1,v1,t1
423 */
424
buzbee2700f7e2014-03-07 09:46:20 -0800425 OpRegRegReg(kOpAdd, rl_result.reg.GetLow(), rl_src2.reg.GetLow(), rl_src1.reg.GetLow());
426 RegStorage t_reg = AllocTemp();
427 OpRegRegReg(kOpAdd, t_reg, rl_src2.reg.GetHigh(), rl_src1.reg.GetHigh());
428 NewLIR3(kMipsSltu, rl_result.reg.GetHighReg(), rl_result.reg.GetLowReg(), rl_src2.reg.GetLowReg());
429 OpRegRegReg(kOpAdd, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700430 FreeTemp(t_reg);
431 StoreValueWide(rl_dest, rl_result);
432}
433
Mark Mendelle02d48f2014-01-15 11:19:23 -0800434void MipsMir2Lir::GenSubLong(Instruction::Code opcode, RegLocation rl_dest,
435 RegLocation rl_src1, RegLocation rl_src2) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700436 UNUSED(opcode);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700437 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
438 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
439 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
440 /*
441 * [v1 v0] = [a1 a0] - [a3 a2];
442 * sltu t1,a0,a2
443 * subu v0,a0,a2
444 * subu v1,a1,a3
445 * subu v1,v1,t1
446 */
447
buzbee2700f7e2014-03-07 09:46:20 -0800448 RegStorage t_reg = AllocTemp();
449 NewLIR3(kMipsSltu, t_reg.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
450 OpRegRegReg(kOpSub, rl_result.reg.GetLow(), rl_src1.reg.GetLow(), rl_src2.reg.GetLow());
451 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_src1.reg.GetHigh(), rl_src2.reg.GetHigh());
452 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700453 FreeTemp(t_reg);
454 StoreValueWide(rl_dest, rl_result);
455}
456
Andreas Gampec76c6142014-08-04 16:30:03 -0700457void MipsMir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -0700458 RegLocation rl_src2, int flags) {
Andreas Gampec76c6142014-08-04 16:30:03 -0700459 switch (opcode) {
460 case Instruction::ADD_LONG:
461 case Instruction::ADD_LONG_2ADDR:
462 GenAddLong(opcode, rl_dest, rl_src1, rl_src2);
463 return;
464 case Instruction::SUB_LONG:
465 case Instruction::SUB_LONG_2ADDR:
466 GenSubLong(opcode, rl_dest, rl_src1, rl_src2);
467 return;
468 case Instruction::NEG_LONG:
469 GenNegLong(rl_dest, rl_src2);
470 return;
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100471
Andreas Gampec76c6142014-08-04 16:30:03 -0700472 default:
473 break;
474 }
475
476 // Fallback for all other ops.
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -0700477 Mir2Lir::GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2, flags);
Serban Constantinescued65c5e2014-05-22 15:10:18 +0100478}
479
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700480void MipsMir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700481 rl_src = LoadValueWide(rl_src, kCoreReg);
482 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
483 /*
484 * [v1 v0] = -[a1 a0]
485 * negu v0,a0
486 * negu v1,a1
487 * sltu t1,r_zero
488 * subu v1,v1,t1
489 */
490
buzbee2700f7e2014-03-07 09:46:20 -0800491 OpRegReg(kOpNeg, rl_result.reg.GetLow(), rl_src.reg.GetLow());
492 OpRegReg(kOpNeg, rl_result.reg.GetHigh(), rl_src.reg.GetHigh());
493 RegStorage t_reg = AllocTemp();
494 NewLIR3(kMipsSltu, t_reg.GetReg(), rZERO, rl_result.reg.GetLowReg());
495 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700496 FreeTemp(t_reg);
497 StoreValueWide(rl_dest, rl_result);
498}
499
Brian Carlstrom7940e442013-07-12 13:46:57 -0700500/*
501 * Generate array load
502 */
503void MipsMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800504 RegLocation rl_index, RegLocation rl_dest, int scale) {
buzbee091cc402014-03-31 10:14:40 -0700505 RegisterClass reg_class = RegClassBySize(size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700506 int len_offset = mirror::Array::LengthOffset().Int32Value();
507 int data_offset;
508 RegLocation rl_result;
Douglas Leung2db3e262014-06-25 16:02:55 -0700509 rl_array = LoadValue(rl_array, kRefReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700510 rl_index = LoadValue(rl_index, kCoreReg);
511
Douglas Leung2db3e262014-06-25 16:02:55 -0700512 // FIXME: need to add support for rl_index.is_const.
513
buzbee695d13a2014-04-19 13:32:20 -0700514 if (size == k64 || size == kDouble) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700515 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
516 } else {
517 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
518 }
519
520 /* null object? */
buzbee2700f7e2014-03-07 09:46:20 -0800521 GenNullCheck(rl_array.reg, opt_flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700522
buzbee2700f7e2014-03-07 09:46:20 -0800523 RegStorage reg_ptr = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700524 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
buzbee2700f7e2014-03-07 09:46:20 -0800525 RegStorage reg_len;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700526 if (needs_range_check) {
527 reg_len = AllocTemp();
528 /* Get len */
buzbee695d13a2014-04-19 13:32:20 -0700529 Load32Disp(rl_array.reg, len_offset, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700530 }
531 /* reg_ptr -> array data */
buzbee2700f7e2014-03-07 09:46:20 -0800532 OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
buzbee091cc402014-03-31 10:14:40 -0700533 FreeTemp(rl_array.reg);
buzbee695d13a2014-04-19 13:32:20 -0700534 if ((size == k64) || (size == kDouble)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700535 if (scale) {
buzbee2700f7e2014-03-07 09:46:20 -0800536 RegStorage r_new_index = AllocTemp();
537 OpRegRegImm(kOpLsl, r_new_index, rl_index.reg, scale);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700538 OpRegReg(kOpAdd, reg_ptr, r_new_index);
539 FreeTemp(r_new_index);
540 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800541 OpRegReg(kOpAdd, reg_ptr, rl_index.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700542 }
buzbee2700f7e2014-03-07 09:46:20 -0800543 FreeTemp(rl_index.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700544 rl_result = EvalLoc(rl_dest, reg_class, true);
545
546 if (needs_range_check) {
Mingyao Yang80365d92014-04-18 12:10:58 -0700547 GenArrayBoundsCheck(rl_index.reg, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700548 FreeTemp(reg_len);
549 }
Andreas Gampe3c12c512014-06-24 18:46:29 +0000550 LoadBaseDisp(reg_ptr, 0, rl_result.reg, size, kNotVolatile);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700551
552 FreeTemp(reg_ptr);
553 StoreValueWide(rl_dest, rl_result);
554 } else {
555 rl_result = EvalLoc(rl_dest, reg_class, true);
556
557 if (needs_range_check) {
Mingyao Yang80365d92014-04-18 12:10:58 -0700558 GenArrayBoundsCheck(rl_index.reg, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700559 FreeTemp(reg_len);
560 }
buzbee2700f7e2014-03-07 09:46:20 -0800561 LoadBaseIndexed(reg_ptr, rl_index.reg, rl_result.reg, scale, size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700562
563 FreeTemp(reg_ptr);
564 StoreValue(rl_dest, rl_result);
565 }
566}
567
568/*
569 * Generate array store
570 *
571 */
572void MipsMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800573 RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
buzbee091cc402014-03-31 10:14:40 -0700574 RegisterClass reg_class = RegClassBySize(size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700575 int len_offset = mirror::Array::LengthOffset().Int32Value();
576 int data_offset;
577
buzbee695d13a2014-04-19 13:32:20 -0700578 if (size == k64 || size == kDouble) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700579 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
580 } else {
581 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
582 }
583
Douglas Leung2db3e262014-06-25 16:02:55 -0700584 rl_array = LoadValue(rl_array, kRefReg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700585 rl_index = LoadValue(rl_index, kCoreReg);
Douglas Leung2db3e262014-06-25 16:02:55 -0700586
587 // FIXME: need to add support for rl_index.is_const.
588
buzbee2700f7e2014-03-07 09:46:20 -0800589 RegStorage reg_ptr;
Ian Rogers773aab12013-10-14 13:50:10 -0700590 bool allocated_reg_ptr_temp = false;
buzbee091cc402014-03-31 10:14:40 -0700591 if (IsTemp(rl_array.reg) && !card_mark) {
592 Clobber(rl_array.reg);
buzbee2700f7e2014-03-07 09:46:20 -0800593 reg_ptr = rl_array.reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700594 } else {
595 reg_ptr = AllocTemp();
buzbee2700f7e2014-03-07 09:46:20 -0800596 OpRegCopy(reg_ptr, rl_array.reg);
Ian Rogers773aab12013-10-14 13:50:10 -0700597 allocated_reg_ptr_temp = true;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700598 }
599
600 /* null object? */
buzbee2700f7e2014-03-07 09:46:20 -0800601 GenNullCheck(rl_array.reg, opt_flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700602
603 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
buzbee2700f7e2014-03-07 09:46:20 -0800604 RegStorage reg_len;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700605 if (needs_range_check) {
606 reg_len = AllocTemp();
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700607 // NOTE: max live temps(4) here.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700608 /* Get len */
buzbee695d13a2014-04-19 13:32:20 -0700609 Load32Disp(rl_array.reg, len_offset, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700610 }
611 /* reg_ptr -> array data */
612 OpRegImm(kOpAdd, reg_ptr, data_offset);
613 /* at this point, reg_ptr points to array, 2 live temps */
buzbee695d13a2014-04-19 13:32:20 -0700614 if ((size == k64) || (size == kDouble)) {
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700615 // TUNING: specific wide routine that can handle fp regs
Brian Carlstrom7940e442013-07-12 13:46:57 -0700616 if (scale) {
buzbee2700f7e2014-03-07 09:46:20 -0800617 RegStorage r_new_index = AllocTemp();
618 OpRegRegImm(kOpLsl, r_new_index, rl_index.reg, scale);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700619 OpRegReg(kOpAdd, reg_ptr, r_new_index);
620 FreeTemp(r_new_index);
621 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800622 OpRegReg(kOpAdd, reg_ptr, rl_index.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700623 }
624 rl_src = LoadValueWide(rl_src, reg_class);
625
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 }
630
Andreas Gampe3c12c512014-06-24 18:46:29 +0000631 StoreBaseDisp(reg_ptr, 0, rl_src.reg, size, kNotVolatile);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700632 } else {
633 rl_src = LoadValue(rl_src, reg_class);
634 if (needs_range_check) {
Andreas Gampe8ebdc2b2015-01-14 12:09:25 -0800635 GenArrayBoundsCheck(rl_index.reg, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700636 FreeTemp(reg_len);
637 }
buzbee2700f7e2014-03-07 09:46:20 -0800638 StoreBaseIndexed(reg_ptr, rl_index.reg, rl_src.reg, scale, size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700639 }
Ian Rogers773aab12013-10-14 13:50:10 -0700640 if (allocated_reg_ptr_temp) {
641 FreeTemp(reg_ptr);
642 }
Ian Rogersa9a82542013-10-04 11:17:26 -0700643 if (card_mark) {
Vladimir Marko743b98c2014-11-24 19:45:41 +0000644 MarkGCCard(opt_flags, rl_src.reg, rl_array.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700645 }
646}
647
648void MipsMir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -0700649 RegLocation rl_src1, RegLocation rl_shift, int flags) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700650 UNUSED(flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700651 // Default implementation is just to ignore the constant case.
652 GenShiftOpLong(opcode, rl_dest, rl_src1, rl_shift);
653}
654
655void MipsMir2Lir::GenArithImmOpLong(Instruction::Code opcode,
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -0700656 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2,
657 int flags) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700658 // Default - bail to non-const handler.
Razvan A Lupusoru5c5676b2014-09-29 16:42:11 -0700659 GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2, flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700660}
661
662} // namespace art