blob: 013041a9a5951cc07d51c45effefca07aafa3811 [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);
47 int t0 = AllocTemp();
48 int t1 = AllocTemp();
49 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Bill Buzbee86ec5202014-02-26 19:03:09 +000050 NewLIR3(kMipsSlt, t0, rl_src1.high_reg, rl_src2.high_reg);
51 NewLIR3(kMipsSlt, t1, rl_src2.high_reg, rl_src1.high_reg);
52 NewLIR3(kMipsSubu, rl_result.low_reg, t1, t0);
53 LIR* branch = OpCmpImmBranch(kCondNe, rl_result.low_reg, 0, NULL);
54 NewLIR3(kMipsSltu, t0, rl_src1.low_reg, rl_src2.low_reg);
55 NewLIR3(kMipsSltu, t1, rl_src2.low_reg, rl_src1.low_reg);
56 NewLIR3(kMipsSubu, rl_result.low_reg, t1, t0);
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
64LIR* MipsMir2Lir::OpCmpBranch(ConditionCode cond, int src1, int src2,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070065 LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070066 LIR* branch;
67 MipsOpCode slt_op;
68 MipsOpCode br_op;
69 bool cmp_zero = false;
70 bool swapped = false;
71 switch (cond) {
72 case kCondEq:
73 br_op = kMipsBeq;
74 cmp_zero = true;
75 break;
76 case kCondNe:
77 br_op = kMipsBne;
78 cmp_zero = true;
79 break;
Vladimir Marko58af1f92013-12-19 13:31:15 +000080 case kCondUlt:
Brian Carlstrom7940e442013-07-12 13:46:57 -070081 slt_op = kMipsSltu;
82 br_op = kMipsBnez;
83 break;
Vladimir Marko58af1f92013-12-19 13:31:15 +000084 case kCondUge:
Brian Carlstrom7940e442013-07-12 13:46:57 -070085 slt_op = kMipsSltu;
86 br_op = kMipsBeqz;
87 break;
88 case kCondGe:
89 slt_op = kMipsSlt;
90 br_op = kMipsBeqz;
91 break;
92 case kCondGt:
93 slt_op = kMipsSlt;
94 br_op = kMipsBnez;
95 swapped = true;
96 break;
97 case kCondLe:
98 slt_op = kMipsSlt;
99 br_op = kMipsBeqz;
100 swapped = true;
101 break;
102 case kCondLt:
103 slt_op = kMipsSlt;
104 br_op = kMipsBnez;
105 break;
106 case kCondHi: // Gtu
107 slt_op = kMipsSltu;
108 br_op = kMipsBnez;
109 swapped = true;
110 break;
111 default:
112 LOG(FATAL) << "No support for ConditionCode: " << cond;
113 return NULL;
114 }
115 if (cmp_zero) {
116 branch = NewLIR2(br_op, src1, src2);
117 } else {
118 int t_reg = AllocTemp();
119 if (swapped) {
120 NewLIR3(slt_op, t_reg, src2, src1);
121 } else {
122 NewLIR3(slt_op, t_reg, src1, src2);
123 }
124 branch = NewLIR1(br_op, t_reg);
125 FreeTemp(t_reg);
126 }
127 branch->target = target;
128 return branch;
129}
130
131LIR* MipsMir2Lir::OpCmpImmBranch(ConditionCode cond, int reg,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700132 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
136 int t_reg = AllocTemp();
137 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
153 int t_reg = AllocTemp();
154 LoadConstant(t_reg, check_value);
155 branch = OpCmpBranch(cond, reg, t_reg, target);
156 FreeTemp(t_reg);
157 return branch;
158 }
159 branch = NewLIR1(opc, reg);
160 branch->target = target;
161 return branch;
162}
163
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700164LIR* MipsMir2Lir::OpRegCopyNoInsert(int r_dest, int r_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700165 if (MIPS_FPREG(r_dest) || MIPS_FPREG(r_src))
166 return OpFpRegCopy(r_dest, r_src);
167 LIR* res = RawLIR(current_dalvik_offset_, kMipsMove,
168 r_dest, r_src);
169 if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
170 res->flags.is_nop = true;
171 }
172 return res;
173}
174
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700175LIR* MipsMir2Lir::OpRegCopy(int r_dest, int r_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700176 LIR *res = OpRegCopyNoInsert(r_dest, r_src);
177 AppendLIR(res);
178 return res;
179}
180
181void MipsMir2Lir::OpRegCopyWide(int dest_lo, int dest_hi, int src_lo,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700182 int src_hi) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700183 bool dest_fp = MIPS_FPREG(dest_lo) && MIPS_FPREG(dest_hi);
184 bool src_fp = MIPS_FPREG(src_lo) && MIPS_FPREG(src_hi);
185 assert(MIPS_FPREG(src_lo) == MIPS_FPREG(src_hi));
186 assert(MIPS_FPREG(dest_lo) == MIPS_FPREG(dest_hi));
187 if (dest_fp) {
188 if (src_fp) {
189 OpRegCopy(S2d(dest_lo, dest_hi), S2d(src_lo, src_hi));
190 } else {
191 /* note the operands are swapped for the mtc1 instr */
192 NewLIR2(kMipsMtc1, src_lo, dest_lo);
193 NewLIR2(kMipsMtc1, src_hi, dest_hi);
194 }
195 } else {
196 if (src_fp) {
197 NewLIR2(kMipsMfc1, dest_lo, src_lo);
198 NewLIR2(kMipsMfc1, dest_hi, src_hi);
199 } else {
200 // Handle overlap
201 if (src_hi == dest_lo) {
202 OpRegCopy(dest_hi, src_hi);
203 OpRegCopy(dest_lo, src_lo);
204 } else {
205 OpRegCopy(dest_lo, src_lo);
206 OpRegCopy(dest_hi, src_hi);
207 }
208 }
209 }
210}
211
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700212void MipsMir2Lir::GenSelect(BasicBlock* bb, MIR* mir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700213 UNIMPLEMENTED(FATAL) << "Need codegen for select";
214}
215
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700216void MipsMir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700217 UNIMPLEMENTED(FATAL) << "Need codegen for fused long cmp branch";
218}
219
220LIR* MipsMir2Lir::GenRegMemCheck(ConditionCode c_code,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700221 int reg1, int base, int offset, ThrowKind kind) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700222 LOG(FATAL) << "Unexpected use of GenRegMemCheck for Arm";
223 return NULL;
224}
225
226RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, int reg1, int reg2,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700227 bool is_div) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700228 NewLIR4(kMipsDiv, r_HI, r_LO, reg1, reg2);
229 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
230 if (is_div) {
Bill Buzbee86ec5202014-02-26 19:03:09 +0000231 NewLIR2(kMipsMflo, rl_result.low_reg, r_LO);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700232 } else {
Bill Buzbee86ec5202014-02-26 19:03:09 +0000233 NewLIR2(kMipsMfhi, rl_result.low_reg, r_HI);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700234 }
235 return rl_result;
236}
237
238RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, int reg1, int lit,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700239 bool is_div) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700240 int t_reg = AllocTemp();
241 NewLIR3(kMipsAddiu, t_reg, r_ZERO, lit);
242 NewLIR4(kMipsDiv, r_HI, r_LO, reg1, t_reg);
243 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
244 if (is_div) {
Bill Buzbee86ec5202014-02-26 19:03:09 +0000245 NewLIR2(kMipsMflo, rl_result.low_reg, r_LO);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700246 } else {
Bill Buzbee86ec5202014-02-26 19:03:09 +0000247 NewLIR2(kMipsMfhi, rl_result.low_reg, r_HI);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700248 }
249 FreeTemp(t_reg);
250 return rl_result;
251}
252
Mark Mendell2bf31e62014-01-23 12:13:40 -0800253RegLocation MipsMir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1,
254 RegLocation rl_src2, bool is_div, bool check_zero) {
255 LOG(FATAL) << "Unexpected use of GenDivRem for Mips";
256 return rl_dest;
257}
258
259RegLocation MipsMir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src1, int lit, bool is_div) {
260 LOG(FATAL) << "Unexpected use of GenDivRemLit for Mips";
261 return rl_dest;
262}
263
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700264void MipsMir2Lir::OpLea(int rBase, int reg1, int reg2, int scale, int offset) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700265 LOG(FATAL) << "Unexpected use of OpLea for Arm";
266}
267
Ian Rogers468532e2013-08-05 10:56:33 -0700268void MipsMir2Lir::OpTlsCmp(ThreadOffset offset, int val) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700269 LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm";
270}
271
Vladimir Marko1c282e22013-11-21 14:49:47 +0000272bool MipsMir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700273 DCHECK_NE(cu_->instruction_set, kThumb2);
274 return false;
275}
276
277bool MipsMir2Lir::GenInlinedSqrt(CallInfo* info) {
278 DCHECK_NE(cu_->instruction_set, kThumb2);
279 return false;
280}
281
Vladimir Markoe508a202013-11-04 15:24:22 +0000282bool MipsMir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
283 if (size != kSignedByte) {
284 // MIPS supports only aligned access. Defer unaligned access to JNI implementation.
285 return false;
286 }
287 RegLocation rl_src_address = info->args[0]; // long address
288 rl_src_address.wide = 0; // ignore high half in info->args[1]
289 RegLocation rl_dest = InlineTarget(info);
290 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
291 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
292 DCHECK(size == kSignedByte);
Bill Buzbee86ec5202014-02-26 19:03:09 +0000293 LoadBaseDisp(rl_address.low_reg, 0, rl_result.low_reg, size, INVALID_SREG);
Vladimir Markoe508a202013-11-04 15:24:22 +0000294 StoreValue(rl_dest, rl_result);
295 return true;
296}
297
298bool MipsMir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) {
299 if (size != kSignedByte) {
300 // MIPS supports only aligned access. Defer unaligned access to JNI implementation.
301 return false;
302 }
303 RegLocation rl_src_address = info->args[0]; // long address
304 rl_src_address.wide = 0; // ignore high half in info->args[1]
305 RegLocation rl_src_value = info->args[2]; // [size] value
306 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg);
307 DCHECK(size == kSignedByte);
308 RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
Bill Buzbee86ec5202014-02-26 19:03:09 +0000309 StoreBaseDisp(rl_address.low_reg, 0, rl_value.low_reg, size);
Vladimir Markoe508a202013-11-04 15:24:22 +0000310 return true;
311}
312
Brian Carlstrom7940e442013-07-12 13:46:57 -0700313LIR* MipsMir2Lir::OpPcRelLoad(int reg, LIR* target) {
314 LOG(FATAL) << "Unexpected use of OpPcRelLoad for Mips";
315 return NULL;
316}
317
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700318LIR* MipsMir2Lir::OpVldm(int rBase, int count) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700319 LOG(FATAL) << "Unexpected use of OpVldm for Mips";
320 return NULL;
321}
322
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700323LIR* MipsMir2Lir::OpVstm(int rBase, int count) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700324 LOG(FATAL) << "Unexpected use of OpVstm for Mips";
325 return NULL;
326}
327
328void MipsMir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src,
329 RegLocation rl_result, int lit,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700330 int first_bit, int second_bit) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700331 int t_reg = AllocTemp();
Bill Buzbee86ec5202014-02-26 19:03:09 +0000332 OpRegRegImm(kOpLsl, t_reg, rl_src.low_reg, second_bit - first_bit);
333 OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src.low_reg, t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700334 FreeTemp(t_reg);
335 if (first_bit != 0) {
Bill Buzbee86ec5202014-02-26 19:03:09 +0000336 OpRegRegImm(kOpLsl, rl_result.low_reg, rl_result.low_reg, first_bit);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700337 }
338}
339
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700340void MipsMir2Lir::GenDivZeroCheck(int reg_lo, int reg_hi) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700341 int t_reg = AllocTemp();
342 OpRegRegReg(kOpOr, t_reg, reg_lo, reg_hi);
343 GenImmedCheck(kCondEq, t_reg, 0, kThrowDivZero);
344 FreeTemp(t_reg);
345}
346
347// Test suspend flag, return target of taken suspend branch
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700348LIR* MipsMir2Lir::OpTestSuspend(LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700349 OpRegImm(kOpSub, rMIPS_SUSPEND, 1);
350 return OpCmpImmBranch((target == NULL) ? kCondEq : kCondNe, rMIPS_SUSPEND, 0, target);
351}
352
353// Decrement register and branch on condition
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700354LIR* MipsMir2Lir::OpDecAndBranch(ConditionCode c_code, int reg, LIR* target) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700355 OpRegImm(kOpSub, reg, 1);
356 return OpCmpImmBranch(c_code, reg, 0, target);
357}
358
buzbee11b63d12013-08-27 07:34:17 -0700359bool MipsMir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700360 RegLocation rl_src, RegLocation rl_dest, int lit) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700361 LOG(FATAL) << "Unexpected use of smallLiteralDive in Mips";
362 return false;
363}
364
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700365LIR* MipsMir2Lir::OpIT(ConditionCode cond, const char* guide) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700366 LOG(FATAL) << "Unexpected use of OpIT in Mips";
367 return NULL;
368}
369
Mark Mendelle02d48f2014-01-15 11:19:23 -0800370void MipsMir2Lir::GenMulLong(Instruction::Code opcode, RegLocation rl_dest,
371 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700372 LOG(FATAL) << "Unexpected use of GenMulLong for Mips";
373}
374
Mark Mendelle02d48f2014-01-15 11:19:23 -0800375void MipsMir2Lir::GenAddLong(Instruction::Code opcode, RegLocation rl_dest,
376 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700377 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
378 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
379 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
380 /*
381 * [v1 v0] = [a1 a0] + [a3 a2];
382 * addu v0,a2,a0
383 * addu t1,a3,a1
384 * sltu v1,v0,a2
385 * addu v1,v1,t1
386 */
387
Bill Buzbee86ec5202014-02-26 19:03:09 +0000388 OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src2.low_reg, rl_src1.low_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700389 int t_reg = AllocTemp();
Bill Buzbee86ec5202014-02-26 19:03:09 +0000390 OpRegRegReg(kOpAdd, t_reg, rl_src2.high_reg, rl_src1.high_reg);
391 NewLIR3(kMipsSltu, rl_result.high_reg, rl_result.low_reg, rl_src2.low_reg);
392 OpRegRegReg(kOpAdd, rl_result.high_reg, rl_result.high_reg, t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700393 FreeTemp(t_reg);
394 StoreValueWide(rl_dest, rl_result);
395}
396
Mark Mendelle02d48f2014-01-15 11:19:23 -0800397void MipsMir2Lir::GenSubLong(Instruction::Code opcode, RegLocation rl_dest,
398 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700399 rl_src1 = LoadValueWide(rl_src1, kCoreReg);
400 rl_src2 = LoadValueWide(rl_src2, kCoreReg);
401 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
402 /*
403 * [v1 v0] = [a1 a0] - [a3 a2];
404 * sltu t1,a0,a2
405 * subu v0,a0,a2
406 * subu v1,a1,a3
407 * subu v1,v1,t1
408 */
409
410 int t_reg = AllocTemp();
Bill Buzbee86ec5202014-02-26 19:03:09 +0000411 NewLIR3(kMipsSltu, t_reg, rl_src1.low_reg, rl_src2.low_reg);
412 OpRegRegReg(kOpSub, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
413 OpRegRegReg(kOpSub, rl_result.high_reg, rl_src1.high_reg, rl_src2.high_reg);
414 OpRegRegReg(kOpSub, rl_result.high_reg, rl_result.high_reg, t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700415 FreeTemp(t_reg);
416 StoreValueWide(rl_dest, rl_result);
417}
418
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700419void MipsMir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700420 rl_src = LoadValueWide(rl_src, kCoreReg);
421 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
422 /*
423 * [v1 v0] = -[a1 a0]
424 * negu v0,a0
425 * negu v1,a1
426 * sltu t1,r_zero
427 * subu v1,v1,t1
428 */
429
Bill Buzbee86ec5202014-02-26 19:03:09 +0000430 OpRegReg(kOpNeg, rl_result.low_reg, rl_src.low_reg);
431 OpRegReg(kOpNeg, rl_result.high_reg, rl_src.high_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700432 int t_reg = AllocTemp();
Bill Buzbee86ec5202014-02-26 19:03:09 +0000433 NewLIR3(kMipsSltu, t_reg, r_ZERO, rl_result.low_reg);
434 OpRegRegReg(kOpSub, rl_result.high_reg, rl_result.high_reg, t_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700435 FreeTemp(t_reg);
436 StoreValueWide(rl_dest, rl_result);
437}
438
Mark Mendelle02d48f2014-01-15 11:19:23 -0800439void MipsMir2Lir::GenAndLong(Instruction::Code opcode, RegLocation rl_dest,
440 RegLocation rl_src1,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700441 RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700442 LOG(FATAL) << "Unexpected use of GenAndLong for Mips";
443}
444
Mark Mendelle02d48f2014-01-15 11:19:23 -0800445void MipsMir2Lir::GenOrLong(Instruction::Code opcode, RegLocation rl_dest,
446 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700447 LOG(FATAL) << "Unexpected use of GenOrLong for Mips";
448}
449
Mark Mendelle02d48f2014-01-15 11:19:23 -0800450void MipsMir2Lir::GenXorLong(Instruction::Code opcode, RegLocation rl_dest,
451 RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700452 LOG(FATAL) << "Unexpected use of GenXorLong for Mips";
453}
454
455/*
456 * Generate array load
457 */
458void MipsMir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700459 RegLocation rl_index, RegLocation rl_dest, int scale) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700460 RegisterClass reg_class = oat_reg_class_by_size(size);
461 int len_offset = mirror::Array::LengthOffset().Int32Value();
462 int data_offset;
463 RegLocation rl_result;
464 rl_array = LoadValue(rl_array, kCoreReg);
465 rl_index = LoadValue(rl_index, kCoreReg);
466
467 if (size == kLong || size == kDouble) {
468 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
469 } else {
470 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
471 }
472
473 /* null object? */
Bill Buzbee86ec5202014-02-26 19:03:09 +0000474 GenNullCheck(rl_array.s_reg_low, rl_array.low_reg, opt_flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700475
476 int reg_ptr = AllocTemp();
477 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
478 int reg_len = INVALID_REG;
479 if (needs_range_check) {
480 reg_len = AllocTemp();
481 /* Get len */
Bill Buzbee86ec5202014-02-26 19:03:09 +0000482 LoadWordDisp(rl_array.low_reg, len_offset, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700483 }
484 /* reg_ptr -> array data */
Bill Buzbee86ec5202014-02-26 19:03:09 +0000485 OpRegRegImm(kOpAdd, reg_ptr, rl_array.low_reg, data_offset);
486 FreeTemp(rl_array.low_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700487 if ((size == kLong) || (size == kDouble)) {
488 if (scale) {
489 int r_new_index = AllocTemp();
Bill Buzbee86ec5202014-02-26 19:03:09 +0000490 OpRegRegImm(kOpLsl, r_new_index, rl_index.low_reg, scale);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700491 OpRegReg(kOpAdd, reg_ptr, r_new_index);
492 FreeTemp(r_new_index);
493 } else {
Bill Buzbee86ec5202014-02-26 19:03:09 +0000494 OpRegReg(kOpAdd, reg_ptr, rl_index.low_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700495 }
Bill Buzbee86ec5202014-02-26 19:03:09 +0000496 FreeTemp(rl_index.low_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700497 rl_result = EvalLoc(rl_dest, reg_class, true);
498
499 if (needs_range_check) {
Bill Buzbee86ec5202014-02-26 19:03:09 +0000500 GenRegRegCheck(kCondUge, rl_index.low_reg, reg_len, kThrowArrayBounds);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700501 FreeTemp(reg_len);
502 }
Bill Buzbee86ec5202014-02-26 19:03:09 +0000503 LoadBaseDispWide(reg_ptr, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700504
505 FreeTemp(reg_ptr);
506 StoreValueWide(rl_dest, rl_result);
507 } else {
508 rl_result = EvalLoc(rl_dest, reg_class, true);
509
510 if (needs_range_check) {
Bill Buzbee86ec5202014-02-26 19:03:09 +0000511 GenRegRegCheck(kCondUge, rl_index.low_reg, reg_len, kThrowArrayBounds);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700512 FreeTemp(reg_len);
513 }
Bill Buzbee86ec5202014-02-26 19:03:09 +0000514 LoadBaseIndexed(reg_ptr, rl_index.low_reg, rl_result.low_reg, scale, size);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700515
516 FreeTemp(reg_ptr);
517 StoreValue(rl_dest, rl_result);
518 }
519}
520
521/*
522 * Generate array store
523 *
524 */
525void MipsMir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
Ian Rogersa9a82542013-10-04 11:17:26 -0700526 RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700527 RegisterClass reg_class = oat_reg_class_by_size(size);
528 int len_offset = mirror::Array::LengthOffset().Int32Value();
529 int data_offset;
530
531 if (size == kLong || size == kDouble) {
532 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
533 } else {
534 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
535 }
536
537 rl_array = LoadValue(rl_array, kCoreReg);
538 rl_index = LoadValue(rl_index, kCoreReg);
539 int reg_ptr = INVALID_REG;
Ian Rogers773aab12013-10-14 13:50:10 -0700540 bool allocated_reg_ptr_temp = false;
Bill Buzbee86ec5202014-02-26 19:03:09 +0000541 if (IsTemp(rl_array.low_reg) && !card_mark) {
542 Clobber(rl_array.low_reg);
543 reg_ptr = rl_array.low_reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700544 } else {
545 reg_ptr = AllocTemp();
Bill Buzbee86ec5202014-02-26 19:03:09 +0000546 OpRegCopy(reg_ptr, rl_array.low_reg);
Ian Rogers773aab12013-10-14 13:50:10 -0700547 allocated_reg_ptr_temp = true;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700548 }
549
550 /* null object? */
Bill Buzbee86ec5202014-02-26 19:03:09 +0000551 GenNullCheck(rl_array.s_reg_low, rl_array.low_reg, opt_flags);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700552
553 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
554 int reg_len = INVALID_REG;
555 if (needs_range_check) {
556 reg_len = AllocTemp();
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700557 // NOTE: max live temps(4) here.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700558 /* Get len */
Bill Buzbee86ec5202014-02-26 19:03:09 +0000559 LoadWordDisp(rl_array.low_reg, len_offset, reg_len);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700560 }
561 /* reg_ptr -> array data */
562 OpRegImm(kOpAdd, reg_ptr, data_offset);
563 /* at this point, reg_ptr points to array, 2 live temps */
564 if ((size == kLong) || (size == kDouble)) {
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700565 // TUNING: specific wide routine that can handle fp regs
Brian Carlstrom7940e442013-07-12 13:46:57 -0700566 if (scale) {
567 int r_new_index = AllocTemp();
Bill Buzbee86ec5202014-02-26 19:03:09 +0000568 OpRegRegImm(kOpLsl, r_new_index, rl_index.low_reg, scale);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700569 OpRegReg(kOpAdd, reg_ptr, r_new_index);
570 FreeTemp(r_new_index);
571 } else {
Bill Buzbee86ec5202014-02-26 19:03:09 +0000572 OpRegReg(kOpAdd, reg_ptr, rl_index.low_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700573 }
574 rl_src = LoadValueWide(rl_src, reg_class);
575
576 if (needs_range_check) {
Bill Buzbee86ec5202014-02-26 19:03:09 +0000577 GenRegRegCheck(kCondUge, rl_index.low_reg, reg_len, kThrowArrayBounds);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700578 FreeTemp(reg_len);
579 }
580
Bill Buzbee86ec5202014-02-26 19:03:09 +0000581 StoreBaseDispWide(reg_ptr, 0, rl_src.low_reg, rl_src.high_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700582 } else {
583 rl_src = LoadValue(rl_src, reg_class);
584 if (needs_range_check) {
Bill Buzbee86ec5202014-02-26 19:03:09 +0000585 GenRegRegCheck(kCondUge, rl_index.low_reg, reg_len, kThrowArrayBounds);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700586 FreeTemp(reg_len);
587 }
Bill Buzbee86ec5202014-02-26 19:03:09 +0000588 StoreBaseIndexed(reg_ptr, rl_index.low_reg, rl_src.low_reg,
Brian Carlstrom7940e442013-07-12 13:46:57 -0700589 scale, size);
590 }
Ian Rogers773aab12013-10-14 13:50:10 -0700591 if (allocated_reg_ptr_temp) {
592 FreeTemp(reg_ptr);
593 }
Ian Rogersa9a82542013-10-04 11:17:26 -0700594 if (card_mark) {
Bill Buzbee86ec5202014-02-26 19:03:09 +0000595 MarkGCCard(rl_src.low_reg, rl_array.low_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700596 }
597}
598
599void MipsMir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700600 RegLocation rl_src1, RegLocation rl_shift) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700601 // Default implementation is just to ignore the constant case.
602 GenShiftOpLong(opcode, rl_dest, rl_src1, rl_shift);
603}
604
605void MipsMir2Lir::GenArithImmOpLong(Instruction::Code opcode,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700606 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700607 // Default - bail to non-const handler.
608 GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2);
609}
610
611} // namespace art