blob: 55e93d7d78bef85f11b79b8858de68b39e374c52 [file] [log] [blame]
Brian Carlstrom7940e442013-07-12 13:46:57 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/* This file contains codegen for the Mips ISA */
18
19#include "codegen_mips.h"
20#include "dex/quick/mir_to_lir-inl.h"
Ian Rogers166db042013-07-26 12:05:57 -070021#include "entrypoints/quick/quick_entrypoints.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070022#include "mips_lir.h"
23#include "mirror/array.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070024
25namespace art {
26
27/*
28 * Compare two 64-bit values
29 * x = y return 0
30 * x < y return -1
31 * x > y return 1
32 *
33 * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
34 * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
35 * subu res, t0, t1 # res = -1:1:0 for [ < > = ]
36 * bnez res, finish
37 * sltu t0, x.lo, y.lo
38 * sgtu r1, x.lo, y.lo
39 * subu res, t0, t1
40 * finish:
41 *
42 */
43void MipsMir2Lir::GenCmpLong(RegLocation rl_dest, RegLocation rl_src1,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070044 RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070045 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
46 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
buzbee091cc402014-03-31 10:14:40 -070047 RegStorage t0 = AllocTemp();
48 RegStorage t1 = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -070049 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
buzbee091cc402014-03-31 10:14:40 -070050 NewLIR3(kMipsSlt, t0.GetReg(), rl_src1.reg.GetHighReg(), rl_src2.reg.GetHighReg());
51 NewLIR3(kMipsSlt, t1.GetReg(), rl_src2.reg.GetHighReg(), rl_src1.reg.GetHighReg());
52 NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1.GetReg(), t0.GetReg());
buzbee2700f7e2014-03-07 09:46:20 -080053 LIR* branch = OpCmpImmBranch(kCondNe, rl_result.reg, 0, NULL);
buzbee091cc402014-03-31 10:14:40 -070054 NewLIR3(kMipsSltu, t0.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
55 NewLIR3(kMipsSltu, t1.GetReg(), rl_src2.reg.GetLowReg(), rl_src1.reg.GetLowReg());
56 NewLIR3(kMipsSubu, rl_result.reg.GetReg(), t1.GetReg(), t0.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -070057 FreeTemp(t0);
58 FreeTemp(t1);
59 LIR* target = NewLIR0(kPseudoTargetLabel);
60 branch->target = target;
61 StoreValue(rl_dest, rl_result);
62}
63
buzbee2700f7e2014-03-07 09:46:20 -080064LIR* MipsMir2Lir::OpCmpBranch(ConditionCode cond, RegStorage src1, RegStorage src2, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070065 LIR* branch;
66 MipsOpCode slt_op;
67 MipsOpCode br_op;
68 bool cmp_zero = false;
69 bool swapped = false;
70 switch (cond) {
71 case kCondEq:
72 br_op = kMipsBeq;
73 cmp_zero = true;
74 break;
75 case kCondNe:
76 br_op = kMipsBne;
77 cmp_zero = true;
78 break;
Vladimir Marko58af1f92013-12-19 13:31:15 +000079 case kCondUlt:
Brian Carlstrom7940e442013-07-12 13:46:57 -070080 slt_op = kMipsSltu;
81 br_op = kMipsBnez;
82 break;
Vladimir Marko58af1f92013-12-19 13:31:15 +000083 case kCondUge:
Brian Carlstrom7940e442013-07-12 13:46:57 -070084 slt_op = kMipsSltu;
85 br_op = kMipsBeqz;
86 break;
87 case kCondGe:
88 slt_op = kMipsSlt;
89 br_op = kMipsBeqz;
90 break;
91 case kCondGt:
92 slt_op = kMipsSlt;
93 br_op = kMipsBnez;
94 swapped = true;
95 break;
96 case kCondLe:
97 slt_op = kMipsSlt;
98 br_op = kMipsBeqz;
99 swapped = true;
100 break;
101 case kCondLt:
102 slt_op = kMipsSlt;
103 br_op = kMipsBnez;
104 break;
105 case kCondHi: // Gtu
106 slt_op = kMipsSltu;
107 br_op = kMipsBnez;
108 swapped = true;
109 break;
110 default:
111 LOG(FATAL) << "No support for ConditionCode: " << cond;
112 return NULL;
113 }
114 if (cmp_zero) {
buzbee2700f7e2014-03-07 09:46:20 -0800115 branch = NewLIR2(br_op, src1.GetReg(), src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700116 } else {
buzbee091cc402014-03-31 10:14:40 -0700117 RegStorage t_reg = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700118 if (swapped) {
buzbee091cc402014-03-31 10:14:40 -0700119 NewLIR3(slt_op, t_reg.GetReg(), src2.GetReg(), src1.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700120 } else {
buzbee091cc402014-03-31 10:14:40 -0700121 NewLIR3(slt_op, t_reg.GetReg(), src1.GetReg(), src2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700122 }
buzbee091cc402014-03-31 10:14:40 -0700123 branch = NewLIR1(br_op, t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700124 FreeTemp(t_reg);
125 }
126 branch->target = target;
127 return branch;
128}
129
buzbee2700f7e2014-03-07 09:46:20 -0800130LIR* MipsMir2Lir::OpCmpImmBranch(ConditionCode cond, RegStorage reg, int check_value, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700131 LIR* branch;
132 if (check_value != 0) {
133 // TUNING: handle s16 & kCondLt/Mi case using slti
buzbee2700f7e2014-03-07 09:46:20 -0800134 RegStorage t_reg = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700135 LoadConstant(t_reg, check_value);
136 branch = OpCmpBranch(cond, reg, t_reg, target);
137 FreeTemp(t_reg);
138 return branch;
139 }
140 MipsOpCode opc;
141 switch (cond) {
142 case kCondEq: opc = kMipsBeqz; break;
143 case kCondGe: opc = kMipsBgez; break;
144 case kCondGt: opc = kMipsBgtz; break;
145 case kCondLe: opc = kMipsBlez; break;
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700146 // case KCondMi:
Brian Carlstrom7940e442013-07-12 13:46:57 -0700147 case kCondLt: opc = kMipsBltz; break;
148 case kCondNe: opc = kMipsBnez; break;
149 default:
150 // Tuning: use slti when applicable
buzbee2700f7e2014-03-07 09:46:20 -0800151 RegStorage t_reg = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700152 LoadConstant(t_reg, check_value);
153 branch = OpCmpBranch(cond, reg, t_reg, target);
154 FreeTemp(t_reg);
155 return branch;
156 }
buzbee2700f7e2014-03-07 09:46:20 -0800157 branch = NewLIR1(opc, reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700158 branch->target = target;
159 return branch;
160}
161
buzbee2700f7e2014-03-07 09:46:20 -0800162LIR* MipsMir2Lir::OpRegCopyNoInsert(RegStorage r_dest, RegStorage r_src) {
163 // If src or dest is a pair, we'll be using low reg.
164 if (r_dest.IsPair()) {
165 r_dest = r_dest.GetLow();
166 }
167 if (r_src.IsPair()) {
168 r_src = r_src.GetLow();
169 }
buzbee091cc402014-03-31 10:14:40 -0700170 if (r_dest.IsFloat() || r_src.IsFloat())
Brian Carlstrom7940e442013-07-12 13:46:57 -0700171 return OpFpRegCopy(r_dest, r_src);
172 LIR* res = RawLIR(current_dalvik_offset_, kMipsMove,
buzbee2700f7e2014-03-07 09:46:20 -0800173 r_dest.GetReg(), r_src.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700174 if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
175 res->flags.is_nop = true;
176 }
177 return res;
178}
179
buzbee7a11ab02014-04-28 20:02:38 -0700180void MipsMir2Lir::OpRegCopy(RegStorage r_dest, RegStorage r_src) {
181 if (r_dest != r_src) {
182 LIR *res = OpRegCopyNoInsert(r_dest, r_src);
183 AppendLIR(res);
184 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700185}
186
buzbee2700f7e2014-03-07 09:46:20 -0800187void MipsMir2Lir::OpRegCopyWide(RegStorage r_dest, RegStorage r_src) {
buzbee7a11ab02014-04-28 20:02:38 -0700188 if (r_dest != r_src) {
buzbee091cc402014-03-31 10:14:40 -0700189 bool dest_fp = r_dest.IsFloat();
190 bool src_fp = r_src.IsFloat();
buzbee7a11ab02014-04-28 20:02:38 -0700191 if (dest_fp) {
192 if (src_fp) {
buzbee091cc402014-03-31 10:14:40 -0700193 OpRegCopy(r_dest, r_src);
194 } else {
195 /* note the operands are swapped for the mtc1 instr */
196 NewLIR2(kMipsMtc1, r_src.GetLowReg(), r_dest.GetLowReg());
197 NewLIR2(kMipsMtc1, r_src.GetHighReg(), r_dest.GetHighReg());
buzbee7a11ab02014-04-28 20:02:38 -0700198 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700199 } else {
buzbee7a11ab02014-04-28 20:02:38 -0700200 if (src_fp) {
201 NewLIR2(kMipsMfc1, r_dest.GetLowReg(), r_src.GetLowReg());
202 NewLIR2(kMipsMfc1, r_dest.GetHighReg(), r_src.GetHighReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700203 } else {
buzbee7a11ab02014-04-28 20:02:38 -0700204 // Handle overlap
205 if (r_src.GetHighReg() == r_dest.GetLowReg()) {
206 OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
207 OpRegCopy(r_dest.GetLow(), r_src.GetLow());
208 } else {
209 OpRegCopy(r_dest.GetLow(), r_src.GetLow());
210 OpRegCopy(r_dest.GetHigh(), r_src.GetHigh());
211 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700212 }
213 }
214 }
215}
216
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700217void MipsMir2Lir::GenSelect(BasicBlock* bb, MIR* mir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700218 UNIMPLEMENTED(FATAL) << "Need codegen for select";
219}
220
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700221void MipsMir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700222 UNIMPLEMENTED(FATAL) << "Need codegen for fused long cmp branch";
223}
224
buzbee2700f7e2014-03-07 09:46:20 -0800225RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegStorage reg1, RegStorage reg2,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700226 bool is_div) {
buzbee9da5c102014-03-28 12:59:18 -0700227 NewLIR2(kMipsDiv, reg1.GetReg(), reg2.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700228 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
229 if (is_div) {
buzbee9da5c102014-03-28 12:59:18 -0700230 NewLIR1(kMipsMflo, rl_result.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700231 } else {
buzbee9da5c102014-03-28 12:59:18 -0700232 NewLIR1(kMipsMfhi, rl_result.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700233 }
234 return rl_result;
235}
236
buzbee2700f7e2014-03-07 09:46:20 -0800237RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegStorage reg1, int lit,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700238 bool is_div) {
buzbee091cc402014-03-31 10:14:40 -0700239 RegStorage t_reg = AllocTemp();
240 NewLIR3(kMipsAddiu, t_reg.GetReg(), rZERO, lit);
241 NewLIR2(kMipsDiv, reg1.GetReg(), t_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700242 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
243 if (is_div) {
buzbee9da5c102014-03-28 12:59:18 -0700244 NewLIR1(kMipsMflo, rl_result.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700245 } else {
buzbee9da5c102014-03-28 12:59:18 -0700246 NewLIR1(kMipsMfhi, rl_result.reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700247 }
248 FreeTemp(t_reg);
249 return rl_result;
250}
251
Mark Mendell2bf31e62014-01-23 12:13:40 -0800252RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
253 RegLocation rl_src2, bool is_div, bool check_zero) {
254 LOG(FATAL) << "Unexpected use of GenDivRem for Mips";
255 return rl_dest;
256}
257
258RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) {
259 LOG(FATAL) << "Unexpected use of GenDivRemLit for Mips";
260 return rl_dest;
261}
262
buzbee2700f7e2014-03-07 09:46:20 -0800263void MipsMir2Lir::OpLea(RegStorage r_base, RegStorage reg1, RegStorage reg2, int scale,
264 int offset) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700265 LOG(FATAL) << "Unexpected use of OpLea for Arm";
266}
267
Ian Rogersdd7624d2014-03-14 17:43:00 -0700268void MipsMir2Lir::OpTlsCmp(ThreadOffset<4> offset, int val) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700269 LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm";
270}
271
Andreas Gampe2f244e92014-05-08 03:35:25 -0700272void MipsMir2Lir::OpTlsCmp(ThreadOffset<8> offset, int val) {
273 UNIMPLEMENTED(FATAL) << "Should not be called.";
274}
275
Vladimir Marko1c282e22013-11-21 14:49:47 +0000276bool MipsMir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700277 DCHECK_NE(cu_->instruction_set, kThumb2);
278 return false;
279}
280
281bool MipsMir2Lir::GenInlinedSqrt(CallInfo* info) {
282 DCHECK_NE(cu_->instruction_set, kThumb2);
283 return false;
284}
285
Vladimir Markoe508a202013-11-04 15:24:22 +0000286bool MipsMir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
287 if (size != kSignedByte) {
288 // MIPS supports only aligned access. Defer unaligned access to JNI implementation.
289 return false;
290 }
291 RegLocation rl_src_address = info->args[0]; // long address
buzbee2700f7e2014-03-07 09:46:20 -0800292 rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1]
Vladimir Markoe508a202013-11-04 15:24:22 +0000293 RegLocation rl_dest = InlineTarget(info);
294 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
295 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
296 DCHECK(size == kSignedByte);
Vladimir Marko3bf7c602014-05-07 14:55:43 +0100297 LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size);
Vladimir Markoe508a202013-11-04 15:24:22 +0000298 StoreValue(rl_dest, rl_result);
299 return true;
300}
301
302bool MipsMir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) {
303 if (size != kSignedByte) {
304 // MIPS supports only aligned access. Defer unaligned access to JNI implementation.
305 return false;
306 }
307 RegLocation rl_src_address = info->args[0]; // long address
buzbee2700f7e2014-03-07 09:46:20 -0800308 rl_src_address = NarrowRegLoc(rl_src_address); // ignore high half in info->args[1]
Vladimir Markoe508a202013-11-04 15:24:22 +0000309 RegLocation rl_src_value = info->args[2]; // [size] value
310 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
311 DCHECK(size == kSignedByte);
312 RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
buzbee2700f7e2014-03-07 09:46:20 -0800313 StoreBaseDisp(rl_address.reg, 0, rl_value.reg, size);
Vladimir Markoe508a202013-11-04 15:24:22 +0000314 return true;
315}
316
buzbee2700f7e2014-03-07 09:46:20 -0800317LIR* MipsMir2Lir::OpPcRelLoad(RegStorage reg, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700318 LOG(FATAL) << "Unexpected use of OpPcRelLoad for Mips";
319 return NULL;
320}
321
buzbee2700f7e2014-03-07 09:46:20 -0800322LIR* MipsMir2Lir::OpVldm(RegStorage r_base, int count) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700323 LOG(FATAL) << "Unexpected use of OpVldm for Mips";
324 return NULL;
325}
326
buzbee2700f7e2014-03-07 09:46:20 -0800327LIR* MipsMir2Lir::OpVstm(RegStorage r_base, int count) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700328 LOG(FATAL) << "Unexpected use of OpVstm for Mips";
329 return NULL;
330}
331
332void MipsMir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
333 RegLocation rl_result, int lit,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700334 int first_bit, int second_bit) {
buzbee2700f7e2014-03-07 09:46:20 -0800335 RegStorage t_reg = AllocTemp();
336 OpRegRegImm(kOpLsl, t_reg, rl_src.reg, second_bit - first_bit);
337 OpRegRegReg(kOpAdd, rl_result.reg, rl_src.reg, t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700338 FreeTemp(t_reg);
339 if (first_bit != 0) {
buzbee2700f7e2014-03-07 09:46:20 -0800340 OpRegRegImm(kOpLsl, rl_result.reg, rl_result.reg, first_bit);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700341 }
342}
343
Mingyao Yange643a172014-04-08 11:02:52 -0700344void MipsMir2Lir::GenDivZeroCheckWide(RegStorage reg) {
buzbee2700f7e2014-03-07 09:46:20 -0800345 DCHECK(reg.IsPair()); // TODO: support k64BitSolo.
346 RegStorage t_reg = AllocTemp();
347 OpRegRegReg(kOpOr, t_reg, reg.GetLow(), reg.GetHigh());
Mingyao Yangd15f4e22014-04-17 18:46:24 -0700348 GenDivZeroCheck(t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700349 FreeTemp(t_reg);
350}
351
352// Test suspend flag, return target of taken suspend branch
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700353LIR* MipsMir2Lir::OpTestSuspend(LIR* target) {
buzbee2700f7e2014-03-07 09:46:20 -0800354 OpRegImm(kOpSub, rs_rMIPS_SUSPEND, 1);
355 return OpCmpImmBranch((target == NULL) ? kCondEq : kCondNe, rs_rMIPS_SUSPEND, 0, target);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700356}
357
358// Decrement register and branch on condition
buzbee2700f7e2014-03-07 09:46:20 -0800359LIR* MipsMir2Lir::OpDecAndBranch(ConditionCode c_code, RegStorage reg, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700360 OpRegImm(kOpSub, reg, 1);
361 return OpCmpImmBranch(c_code, reg, 0, target);
362}
363
buzbee11b63d12013-08-27 07:34:17 -0700364bool MipsMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700365 RegLocation rl_src, RegLocation rl_dest, int lit) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700366 LOG(FATAL) << "Unexpected use of smallLiteralDive in Mips";
367 return false;
368}
369
Ian Rogerse2143c02014-03-28 08:47:16 -0700370bool MipsMir2Lir::EasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) {
371 LOG(FATAL) << "Unexpected use of easyMultiply in Mips";
372 return false;
373}
374
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700375LIR* MipsMir2Lir::OpIT(ConditionCode cond, const char* guide) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700376 LOG(FATAL) << "Unexpected use of OpIT in Mips";
377 return NULL;
378}
379
Dave Allison3da67a52014-04-02 17:03:45 -0700380void MipsMir2Lir::OpEndIT(LIR* it) {
381 LOG(FATAL) << "Unexpected use of OpEndIT in Mips";
382}
383
384
Mark Mendelle02d48f2014-01-15 11:19:23 -0800385void MipsMir2Lir::GenMulLong(Instruction::Code opcode, RegLocation rl_dest,
386 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700387 LOG(FATAL) << "Unexpected use of GenMulLong for Mips";
388}
389
Mark Mendelle02d48f2014-01-15 11:19:23 -0800390void MipsMir2Lir::GenAddLong(Instruction::Code opcode, RegLocation rl_dest,
391 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700392 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
393 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
394 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
395 /*
396 * [v1 v0] = [a1 a0] + [a3 a2];
397 * addu v0,a2,a0
398 * addu t1,a3,a1
399 * sltu v1,v0,a2
400 * addu v1,v1,t1
401 */
402
buzbee2700f7e2014-03-07 09:46:20 -0800403 OpRegRegReg(kOpAdd, rl_result.reg.GetLow(), rl_src2.reg.GetLow(), rl_src1.reg.GetLow());
404 RegStorage t_reg = AllocTemp();
405 OpRegRegReg(kOpAdd, t_reg, rl_src2.reg.GetHigh(), rl_src1.reg.GetHigh());
406 NewLIR3(kMipsSltu, rl_result.reg.GetHighReg(), rl_result.reg.GetLowReg(), rl_src2.reg.GetLowReg());
407 OpRegRegReg(kOpAdd, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700408 FreeTemp(t_reg);
409 StoreValueWide(rl_dest, rl_result);
410}
411
Mark Mendelle02d48f2014-01-15 11:19:23 -0800412void MipsMir2Lir::GenSubLong(Instruction::Code opcode, RegLocation rl_dest,
413 RegLocation rl_src1, RegLocation rl_src2) {
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 * sltu t1,a0,a2
420 * subu v0,a0,a2
421 * subu v1,a1,a3
422 * subu v1,v1,t1
423 */
424
buzbee2700f7e2014-03-07 09:46:20 -0800425 RegStorage t_reg = AllocTemp();
426 NewLIR3(kMipsSltu, t_reg.GetReg(), rl_src1.reg.GetLowReg(), rl_src2.reg.GetLowReg());
427 OpRegRegReg(kOpSub, rl_result.reg.GetLow(), rl_src1.reg.GetLow(), rl_src2.reg.GetLow());
428 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_src1.reg.GetHigh(), rl_src2.reg.GetHigh());
429 OpRegRegReg(kOpSub, 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
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700434void MipsMir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700435 rl_src = LoadValueWide(rl_src, kCoreReg);
436 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
437 /*
438 * [v1 v0] = -[a1 a0]
439 * negu v0,a0
440 * negu v1,a1
441 * sltu t1,r_zero
442 * subu v1,v1,t1
443 */
444
buzbee2700f7e2014-03-07 09:46:20 -0800445 OpRegReg(kOpNeg, rl_result.reg.GetLow(), rl_src.reg.GetLow());
446 OpRegReg(kOpNeg, rl_result.reg.GetHigh(), rl_src.reg.GetHigh());
447 RegStorage t_reg = AllocTemp();
448 NewLIR3(kMipsSltu, t_reg.GetReg(), rZERO, rl_result.reg.GetLowReg());
449 OpRegRegReg(kOpSub, rl_result.reg.GetHigh(), rl_result.reg.GetHigh(), t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700450 FreeTemp(t_reg);
451 StoreValueWide(rl_dest, rl_result);
452}
453
Mark Mendelle02d48f2014-01-15 11:19:23 -0800454void MipsMir2Lir::GenAndLong(Instruction::Code opcode, RegLocation rl_dest,
455 RegLocation rl_src1,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700456 RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700457 LOG(FATAL) << "Unexpected use of GenAndLong for Mips";
458}
459
Mark Mendelle02d48f2014-01-15 11:19:23 -0800460void MipsMir2Lir::GenOrLong(Instruction::Code opcode, RegLocation rl_dest,
461 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700462 LOG(FATAL) << "Unexpected use of GenOrLong for Mips";
463}
464
Mark Mendelle02d48f2014-01-15 11:19:23 -0800465void MipsMir2Lir::GenXorLong(Instruction::Code opcode, RegLocation rl_dest,
466 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700467 LOG(FATAL) << "Unexpected use of GenXorLong for Mips";
468}
469
470/*
471 * Generate array load
472 */
473void MipsMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700474 RegLocation rl_index, RegLocation rl_dest, int scale) {
buzbee091cc402014-03-31 10:14:40 -0700475 RegisterClass reg_class = RegClassBySize(size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700476 int len_offset = mirror::Array::LengthOffset().Int32Value();
477 int data_offset;
478 RegLocation rl_result;
479 rl_array = LoadValue(rl_array, kCoreReg);
480 rl_index = LoadValue(rl_index, kCoreReg);
481
buzbee695d13a2014-04-19 13:32:20 -0700482 if (size == k64 || size == kDouble) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700483 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
484 } else {
485 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
486 }
487
488 /* null object? */
buzbee2700f7e2014-03-07 09:46:20 -0800489 GenNullCheck(rl_array.reg, opt_flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700490
buzbee2700f7e2014-03-07 09:46:20 -0800491 RegStorage reg_ptr = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700492 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
buzbee2700f7e2014-03-07 09:46:20 -0800493 RegStorage reg_len;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700494 if (needs_range_check) {
495 reg_len = AllocTemp();
496 /* Get len */
buzbee695d13a2014-04-19 13:32:20 -0700497 Load32Disp(rl_array.reg, len_offset, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700498 }
499 /* reg_ptr -> array data */
buzbee2700f7e2014-03-07 09:46:20 -0800500 OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
buzbee091cc402014-03-31 10:14:40 -0700501 FreeTemp(rl_array.reg);
buzbee695d13a2014-04-19 13:32:20 -0700502 if ((size == k64) || (size == kDouble)) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700503 if (scale) {
buzbee2700f7e2014-03-07 09:46:20 -0800504 RegStorage r_new_index = AllocTemp();
505 OpRegRegImm(kOpLsl, r_new_index, rl_index.reg, scale);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700506 OpRegReg(kOpAdd, reg_ptr, r_new_index);
507 FreeTemp(r_new_index);
508 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800509 OpRegReg(kOpAdd, reg_ptr, rl_index.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700510 }
buzbee2700f7e2014-03-07 09:46:20 -0800511 FreeTemp(rl_index.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700512 rl_result = EvalLoc(rl_dest, reg_class, true);
513
514 if (needs_range_check) {
Mingyao Yang80365d92014-04-18 12:10:58 -0700515 GenArrayBoundsCheck(rl_index.reg, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700516 FreeTemp(reg_len);
517 }
Vladimir Marko3bf7c602014-05-07 14:55:43 +0100518 LoadBaseDisp(reg_ptr, 0, rl_result.reg, size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700519
520 FreeTemp(reg_ptr);
521 StoreValueWide(rl_dest, rl_result);
522 } else {
523 rl_result = EvalLoc(rl_dest, reg_class, true);
524
525 if (needs_range_check) {
Mingyao Yang80365d92014-04-18 12:10:58 -0700526 GenArrayBoundsCheck(rl_index.reg, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700527 FreeTemp(reg_len);
528 }
buzbee2700f7e2014-03-07 09:46:20 -0800529 LoadBaseIndexed(reg_ptr, rl_index.reg, rl_result.reg, scale, size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700530
531 FreeTemp(reg_ptr);
532 StoreValue(rl_dest, rl_result);
533 }
534}
535
536/*
537 * Generate array store
538 *
539 */
540void MipsMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
Ian Rogersa9a82542013-10-04 11:17:26 -0700541 RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
buzbee091cc402014-03-31 10:14:40 -0700542 RegisterClass reg_class = RegClassBySize(size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700543 int len_offset = mirror::Array::LengthOffset().Int32Value();
544 int data_offset;
545
buzbee695d13a2014-04-19 13:32:20 -0700546 if (size == k64 || size == kDouble) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700547 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
548 } else {
549 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
550 }
551
552 rl_array = LoadValue(rl_array, kCoreReg);
553 rl_index = LoadValue(rl_index, kCoreReg);
buzbee2700f7e2014-03-07 09:46:20 -0800554 RegStorage reg_ptr;
Ian Rogers773aab12013-10-14 13:50:10 -0700555 bool allocated_reg_ptr_temp = false;
buzbee091cc402014-03-31 10:14:40 -0700556 if (IsTemp(rl_array.reg) && !card_mark) {
557 Clobber(rl_array.reg);
buzbee2700f7e2014-03-07 09:46:20 -0800558 reg_ptr = rl_array.reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700559 } else {
560 reg_ptr = AllocTemp();
buzbee2700f7e2014-03-07 09:46:20 -0800561 OpRegCopy(reg_ptr, rl_array.reg);
Ian Rogers773aab12013-10-14 13:50:10 -0700562 allocated_reg_ptr_temp = true;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700563 }
564
565 /* null object? */
buzbee2700f7e2014-03-07 09:46:20 -0800566 GenNullCheck(rl_array.reg, opt_flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700567
568 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
buzbee2700f7e2014-03-07 09:46:20 -0800569 RegStorage reg_len;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700570 if (needs_range_check) {
571 reg_len = AllocTemp();
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700572 // NOTE: max live temps(4) here.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700573 /* Get len */
buzbee695d13a2014-04-19 13:32:20 -0700574 Load32Disp(rl_array.reg, len_offset, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700575 }
576 /* reg_ptr -> array data */
577 OpRegImm(kOpAdd, reg_ptr, data_offset);
578 /* at this point, reg_ptr points to array, 2 live temps */
buzbee695d13a2014-04-19 13:32:20 -0700579 if ((size == k64) || (size == kDouble)) {
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700580 // TUNING: specific wide routine that can handle fp regs
Brian Carlstrom7940e442013-07-12 13:46:57 -0700581 if (scale) {
buzbee2700f7e2014-03-07 09:46:20 -0800582 RegStorage r_new_index = AllocTemp();
583 OpRegRegImm(kOpLsl, r_new_index, rl_index.reg, scale);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700584 OpRegReg(kOpAdd, reg_ptr, r_new_index);
585 FreeTemp(r_new_index);
586 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800587 OpRegReg(kOpAdd, reg_ptr, rl_index.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700588 }
589 rl_src = LoadValueWide(rl_src, reg_class);
590
591 if (needs_range_check) {
Mingyao Yang80365d92014-04-18 12:10:58 -0700592 GenArrayBoundsCheck(rl_index.reg, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700593 FreeTemp(reg_len);
594 }
595
Vladimir Marko455759b2014-05-06 20:49:36 +0100596 StoreBaseDisp(reg_ptr, 0, rl_src.reg, size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700597 } else {
598 rl_src = LoadValue(rl_src, reg_class);
599 if (needs_range_check) {
Mingyao Yang80365d92014-04-18 12:10:58 -0700600 GenArrayBoundsCheck(rl_index.reg, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700601 FreeTemp(reg_len);
602 }
buzbee2700f7e2014-03-07 09:46:20 -0800603 StoreBaseIndexed(reg_ptr, rl_index.reg, rl_src.reg, scale, size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700604 }
Ian Rogers773aab12013-10-14 13:50:10 -0700605 if (allocated_reg_ptr_temp) {
606 FreeTemp(reg_ptr);
607 }
Ian Rogersa9a82542013-10-04 11:17:26 -0700608 if (card_mark) {
buzbee2700f7e2014-03-07 09:46:20 -0800609 MarkGCCard(rl_src.reg, rl_array.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700610 }
611}
612
613void MipsMir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700614 RegLocation rl_src1, RegLocation rl_shift) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700615 // Default implementation is just to ignore the constant case.
616 GenShiftOpLong(opcode, rl_dest, rl_src1, rl_shift);
617}
618
619void MipsMir2Lir::GenArithImmOpLong(Instruction::Code opcode,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700620 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700621 // Default - bail to non-const handler.
622 GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
623}
624
625} // namespace art