blob: 86f0527bf18c33d5d8fd3ecfa7bb7d112109da72 [file] [log] [blame]
buzbeeefc63692012-11-14 16:31:52 -08001/*
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 "oat/runtime/oat_support_entrypoints.h"
buzbee1bc37c62012-11-20 13:35:41 -080020#include "mips_lir.h"
buzbee02031b12012-11-23 09:41:35 -080021#include "codegen_mips.h"
buzbee1bc37c62012-11-20 13:35:41 -080022#include "../codegen_util.h"
23#include "../ralloc_util.h"
buzbeeefc63692012-11-14 16:31:52 -080024
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 */
buzbee02031b12012-11-23 09:41:35 -080043void MipsCodegen::GenCmpLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
44 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -080045{
buzbeefa57c472012-11-21 12:06:18 -080046 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
47 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
48 int t0 = AllocTemp(cu);
49 int t1 = AllocTemp(cu);
50 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
51 NewLIR3(cu, kMipsSlt, t0, rl_src1.high_reg, rl_src2.high_reg);
52 NewLIR3(cu, kMipsSlt, t1, rl_src2.high_reg, rl_src1.high_reg);
53 NewLIR3(cu, kMipsSubu, rl_result.low_reg, t1, t0);
54 LIR* branch = OpCmpImmBranch(cu, kCondNe, rl_result.low_reg, 0, NULL);
55 NewLIR3(cu, kMipsSltu, t0, rl_src1.low_reg, rl_src2.low_reg);
56 NewLIR3(cu, kMipsSltu, t1, rl_src2.low_reg, rl_src1.low_reg);
57 NewLIR3(cu, kMipsSubu, rl_result.low_reg, t1, t0);
58 FreeTemp(cu, t0);
59 FreeTemp(cu, t1);
60 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
buzbeecbd6d442012-11-17 14:11:25 -080061 branch->target = target;
buzbeefa57c472012-11-21 12:06:18 -080062 StoreValue(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -080063}
64
buzbee02031b12012-11-23 09:41:35 -080065LIR* MipsCodegen::OpCmpBranch(CompilationUnit* cu, ConditionCode cond, int src1, int src2,
66 LIR* target)
buzbeeefc63692012-11-14 16:31:52 -080067{
68 LIR* branch;
buzbeefa57c472012-11-21 12:06:18 -080069 MipsOpCode slt_op;
70 MipsOpCode br_op;
71 bool cmp_zero = false;
buzbeeefc63692012-11-14 16:31:52 -080072 bool swapped = false;
73 switch (cond) {
74 case kCondEq:
buzbeefa57c472012-11-21 12:06:18 -080075 br_op = kMipsBeq;
76 cmp_zero = true;
buzbeeefc63692012-11-14 16:31:52 -080077 break;
78 case kCondNe:
buzbeefa57c472012-11-21 12:06:18 -080079 br_op = kMipsBne;
80 cmp_zero = true;
buzbeeefc63692012-11-14 16:31:52 -080081 break;
82 case kCondCc:
buzbeefa57c472012-11-21 12:06:18 -080083 slt_op = kMipsSltu;
84 br_op = kMipsBnez;
buzbeeefc63692012-11-14 16:31:52 -080085 break;
86 case kCondCs:
buzbeefa57c472012-11-21 12:06:18 -080087 slt_op = kMipsSltu;
88 br_op = kMipsBeqz;
buzbeeefc63692012-11-14 16:31:52 -080089 break;
90 case kCondGe:
buzbeefa57c472012-11-21 12:06:18 -080091 slt_op = kMipsSlt;
92 br_op = kMipsBeqz;
buzbeeefc63692012-11-14 16:31:52 -080093 break;
94 case kCondGt:
buzbeefa57c472012-11-21 12:06:18 -080095 slt_op = kMipsSlt;
96 br_op = kMipsBnez;
buzbeeefc63692012-11-14 16:31:52 -080097 swapped = true;
98 break;
99 case kCondLe:
buzbeefa57c472012-11-21 12:06:18 -0800100 slt_op = kMipsSlt;
101 br_op = kMipsBeqz;
buzbeeefc63692012-11-14 16:31:52 -0800102 swapped = true;
103 break;
104 case kCondLt:
buzbeefa57c472012-11-21 12:06:18 -0800105 slt_op = kMipsSlt;
106 br_op = kMipsBnez;
buzbeeefc63692012-11-14 16:31:52 -0800107 break;
108 case kCondHi: // Gtu
buzbeefa57c472012-11-21 12:06:18 -0800109 slt_op = kMipsSltu;
110 br_op = kMipsBnez;
buzbeeefc63692012-11-14 16:31:52 -0800111 swapped = true;
112 break;
113 default:
buzbeecbd6d442012-11-17 14:11:25 -0800114 LOG(FATAL) << "No support for ConditionCode: " << cond;
buzbeeefc63692012-11-14 16:31:52 -0800115 return NULL;
116 }
buzbeefa57c472012-11-21 12:06:18 -0800117 if (cmp_zero) {
118 branch = NewLIR2(cu, br_op, src1, src2);
buzbeeefc63692012-11-14 16:31:52 -0800119 } else {
buzbeefa57c472012-11-21 12:06:18 -0800120 int t_reg = AllocTemp(cu);
buzbeeefc63692012-11-14 16:31:52 -0800121 if (swapped) {
buzbeefa57c472012-11-21 12:06:18 -0800122 NewLIR3(cu, slt_op, t_reg, src2, src1);
buzbeeefc63692012-11-14 16:31:52 -0800123 } else {
buzbeefa57c472012-11-21 12:06:18 -0800124 NewLIR3(cu, slt_op, t_reg, src1, src2);
buzbeeefc63692012-11-14 16:31:52 -0800125 }
buzbeefa57c472012-11-21 12:06:18 -0800126 branch = NewLIR1(cu, br_op, t_reg);
127 FreeTemp(cu, t_reg);
buzbeeefc63692012-11-14 16:31:52 -0800128 }
129 branch->target = target;
130 return branch;
131}
132
buzbee02031b12012-11-23 09:41:35 -0800133LIR* MipsCodegen::OpCmpImmBranch(CompilationUnit* cu, ConditionCode cond, int reg,
134 int check_value, LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800135{
136 LIR* branch;
buzbeefa57c472012-11-21 12:06:18 -0800137 if (check_value != 0) {
buzbeeefc63692012-11-14 16:31:52 -0800138 // TUNING: handle s16 & kCondLt/Mi case using slti
buzbeefa57c472012-11-21 12:06:18 -0800139 int t_reg = AllocTemp(cu);
140 LoadConstant(cu, t_reg, check_value);
141 branch = OpCmpBranch(cu, cond, reg, t_reg, target);
142 FreeTemp(cu, t_reg);
buzbeeefc63692012-11-14 16:31:52 -0800143 return branch;
144 }
145 MipsOpCode opc;
146 switch (cond) {
147 case kCondEq: opc = kMipsBeqz; break;
148 case kCondGe: opc = kMipsBgez; break;
149 case kCondGt: opc = kMipsBgtz; break;
150 case kCondLe: opc = kMipsBlez; break;
151 //case KCondMi:
152 case kCondLt: opc = kMipsBltz; break;
153 case kCondNe: opc = kMipsBnez; break;
154 default:
155 // Tuning: use slti when applicable
buzbeefa57c472012-11-21 12:06:18 -0800156 int t_reg = AllocTemp(cu);
157 LoadConstant(cu, t_reg, check_value);
158 branch = OpCmpBranch(cu, cond, reg, t_reg, target);
159 FreeTemp(cu, t_reg);
buzbeeefc63692012-11-14 16:31:52 -0800160 return branch;
161 }
buzbeefa57c472012-11-21 12:06:18 -0800162 branch = NewLIR1(cu, opc, reg);
buzbeeefc63692012-11-14 16:31:52 -0800163 branch->target = target;
164 return branch;
165}
166
buzbee02031b12012-11-23 09:41:35 -0800167LIR* MipsCodegen::OpRegCopyNoInsert(CompilationUnit *cu, int r_dest, int r_src)
buzbeeefc63692012-11-14 16:31:52 -0800168{
buzbeefa57c472012-11-21 12:06:18 -0800169 if (MIPS_FPREG(r_dest) || MIPS_FPREG(r_src))
buzbee02031b12012-11-23 09:41:35 -0800170 return OpFpRegCopy(cu, r_dest, r_src);
buzbeefa57c472012-11-21 12:06:18 -0800171 LIR* res = RawLIR(cu, cu->current_dalvik_offset, kMipsMove,
172 r_dest, r_src);
173 if (!(cu->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) {
174 res->flags.is_nop = true;
buzbeeefc63692012-11-14 16:31:52 -0800175 }
176 return res;
177}
178
buzbee02031b12012-11-23 09:41:35 -0800179LIR* MipsCodegen::OpRegCopy(CompilationUnit *cu, int r_dest, int r_src)
buzbeeefc63692012-11-14 16:31:52 -0800180{
buzbeefa57c472012-11-21 12:06:18 -0800181 LIR *res = OpRegCopyNoInsert(cu, r_dest, r_src);
182 AppendLIR(cu, res);
buzbeeefc63692012-11-14 16:31:52 -0800183 return res;
184}
185
buzbee02031b12012-11-23 09:41:35 -0800186void MipsCodegen::OpRegCopyWide(CompilationUnit *cu, int dest_lo, int dest_hi, int src_lo,
187 int src_hi)
buzbeeefc63692012-11-14 16:31:52 -0800188{
buzbeefa57c472012-11-21 12:06:18 -0800189 bool dest_fp = MIPS_FPREG(dest_lo) && MIPS_FPREG(dest_hi);
190 bool src_fp = MIPS_FPREG(src_lo) && MIPS_FPREG(src_hi);
191 assert(MIPS_FPREG(src_lo) == MIPS_FPREG(src_hi));
192 assert(MIPS_FPREG(dest_lo) == MIPS_FPREG(dest_hi));
193 if (dest_fp) {
194 if (src_fp) {
195 OpRegCopy(cu, S2d(dest_lo, dest_hi), S2d(src_lo, src_hi));
buzbeeefc63692012-11-14 16:31:52 -0800196 } else {
197 /* note the operands are swapped for the mtc1 instr */
buzbeefa57c472012-11-21 12:06:18 -0800198 NewLIR2(cu, kMipsMtc1, src_lo, dest_lo);
199 NewLIR2(cu, kMipsMtc1, src_hi, dest_hi);
buzbeeefc63692012-11-14 16:31:52 -0800200 }
201 } else {
buzbeefa57c472012-11-21 12:06:18 -0800202 if (src_fp) {
203 NewLIR2(cu, kMipsMfc1, dest_lo, src_lo);
204 NewLIR2(cu, kMipsMfc1, dest_hi, src_hi);
buzbeeefc63692012-11-14 16:31:52 -0800205 } else {
206 // Handle overlap
buzbeefa57c472012-11-21 12:06:18 -0800207 if (src_hi == dest_lo) {
208 OpRegCopy(cu, dest_hi, src_hi);
209 OpRegCopy(cu, dest_lo, src_lo);
buzbeeefc63692012-11-14 16:31:52 -0800210 } else {
buzbeefa57c472012-11-21 12:06:18 -0800211 OpRegCopy(cu, dest_lo, src_lo);
212 OpRegCopy(cu, dest_hi, src_hi);
buzbeeefc63692012-11-14 16:31:52 -0800213 }
214 }
215 }
buzbeeefc63692012-11-14 16:31:52 -0800216}
217
buzbee02031b12012-11-23 09:41:35 -0800218void MipsCodegen::GenFusedLongCmpBranch(CompilationUnit* cu, BasicBlock* bb, MIR* mir)
buzbeeefc63692012-11-14 16:31:52 -0800219{
220 UNIMPLEMENTED(FATAL) << "Need codegen for fused long cmp branch";
221}
222
buzbee02031b12012-11-23 09:41:35 -0800223LIR* MipsCodegen::GenRegMemCheck(CompilationUnit* cu, ConditionCode c_code,
buzbeeefc63692012-11-14 16:31:52 -0800224 int reg1, int base, int offset, ThrowKind kind)
225{
buzbee52a77fc2012-11-20 19:50:46 -0800226 LOG(FATAL) << "Unexpected use of GenRegMemCheck for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800227 return NULL;
228}
229
buzbee02031b12012-11-23 09:41:35 -0800230RegLocation MipsCodegen::GenDivRem(CompilationUnit* cu, RegLocation rl_dest, int reg1, int reg2,
231 bool is_div)
buzbeeefc63692012-11-14 16:31:52 -0800232{
buzbeefa57c472012-11-21 12:06:18 -0800233 NewLIR4(cu, kMipsDiv, r_HI, r_LO, reg1, reg2);
234 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
235 if (is_div) {
236 NewLIR2(cu, kMipsMflo, rl_result.low_reg, r_LO);
buzbeeefc63692012-11-14 16:31:52 -0800237 } else {
buzbeefa57c472012-11-21 12:06:18 -0800238 NewLIR2(cu, kMipsMfhi, rl_result.low_reg, r_HI);
buzbeeefc63692012-11-14 16:31:52 -0800239 }
buzbeefa57c472012-11-21 12:06:18 -0800240 return rl_result;
buzbeeefc63692012-11-14 16:31:52 -0800241}
242
buzbee02031b12012-11-23 09:41:35 -0800243RegLocation MipsCodegen::GenDivRemLit(CompilationUnit* cu, RegLocation rl_dest, int reg1, int lit,
244 bool is_div)
buzbeeefc63692012-11-14 16:31:52 -0800245{
buzbeefa57c472012-11-21 12:06:18 -0800246 int t_reg = AllocTemp(cu);
247 NewLIR3(cu, kMipsAddiu, t_reg, r_ZERO, lit);
248 NewLIR4(cu, kMipsDiv, r_HI, r_LO, reg1, t_reg);
249 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
250 if (is_div) {
251 NewLIR2(cu, kMipsMflo, rl_result.low_reg, r_LO);
buzbeeefc63692012-11-14 16:31:52 -0800252 } else {
buzbeefa57c472012-11-21 12:06:18 -0800253 NewLIR2(cu, kMipsMfhi, rl_result.low_reg, r_HI);
buzbeeefc63692012-11-14 16:31:52 -0800254 }
buzbeefa57c472012-11-21 12:06:18 -0800255 FreeTemp(cu, t_reg);
256 return rl_result;
buzbeeefc63692012-11-14 16:31:52 -0800257}
258
buzbee02031b12012-11-23 09:41:35 -0800259void MipsCodegen::OpLea(CompilationUnit* cu, int rBase, int reg1, int reg2, int scale, int offset)
buzbeeefc63692012-11-14 16:31:52 -0800260{
buzbee52a77fc2012-11-20 19:50:46 -0800261 LOG(FATAL) << "Unexpected use of OpLea for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800262}
263
buzbee02031b12012-11-23 09:41:35 -0800264void MipsCodegen::OpTlsCmp(CompilationUnit* cu, int offset, int val)
buzbeeefc63692012-11-14 16:31:52 -0800265{
buzbee52a77fc2012-11-20 19:50:46 -0800266 LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800267}
268
buzbee02031b12012-11-23 09:41:35 -0800269bool MipsCodegen::GenInlinedCas32(CompilationUnit* cu, CallInfo* info, bool need_write_barrier) {
buzbeefa57c472012-11-21 12:06:18 -0800270 DCHECK_NE(cu->instruction_set, kThumb2);
buzbeeefc63692012-11-14 16:31:52 -0800271 return false;
272}
273
buzbee02031b12012-11-23 09:41:35 -0800274bool MipsCodegen::GenInlinedSqrt(CompilationUnit* cu, CallInfo* info) {
buzbeefa57c472012-11-21 12:06:18 -0800275 DCHECK_NE(cu->instruction_set, kThumb2);
buzbeeefc63692012-11-14 16:31:52 -0800276 return false;
277}
278
buzbee02031b12012-11-23 09:41:35 -0800279LIR* MipsCodegen::OpPcRelLoad(CompilationUnit* cu, int reg, LIR* target) {
buzbee52a77fc2012-11-20 19:50:46 -0800280 LOG(FATAL) << "Unexpected use of OpPcRelLoad for Mips";
buzbeeefc63692012-11-14 16:31:52 -0800281 return NULL;
282}
283
buzbee02031b12012-11-23 09:41:35 -0800284LIR* MipsCodegen::OpVldm(CompilationUnit* cu, int rBase, int count)
buzbeeefc63692012-11-14 16:31:52 -0800285{
buzbee52a77fc2012-11-20 19:50:46 -0800286 LOG(FATAL) << "Unexpected use of OpVldm for Mips";
buzbeeefc63692012-11-14 16:31:52 -0800287 return NULL;
288}
289
buzbee02031b12012-11-23 09:41:35 -0800290LIR* MipsCodegen::OpVstm(CompilationUnit* cu, int rBase, int count)
buzbeeefc63692012-11-14 16:31:52 -0800291{
buzbee52a77fc2012-11-20 19:50:46 -0800292 LOG(FATAL) << "Unexpected use of OpVstm for Mips";
buzbeeefc63692012-11-14 16:31:52 -0800293 return NULL;
294}
295
buzbee02031b12012-11-23 09:41:35 -0800296void MipsCodegen::GenMultiplyByTwoBitMultiplier(CompilationUnit* cu, RegLocation rl_src,
297 RegLocation rl_result, int lit,
298 int first_bit, int second_bit)
buzbeeefc63692012-11-14 16:31:52 -0800299{
buzbeefa57c472012-11-21 12:06:18 -0800300 int t_reg = AllocTemp(cu);
301 OpRegRegImm(cu, kOpLsl, t_reg, rl_src.low_reg, second_bit - first_bit);
302 OpRegRegReg(cu, kOpAdd, rl_result.low_reg, rl_src.low_reg, t_reg);
303 FreeTemp(cu, t_reg);
304 if (first_bit != 0) {
305 OpRegRegImm(cu, kOpLsl, rl_result.low_reg, rl_result.low_reg, first_bit);
buzbeeefc63692012-11-14 16:31:52 -0800306 }
307}
308
buzbee02031b12012-11-23 09:41:35 -0800309void MipsCodegen::GenDivZeroCheck(CompilationUnit* cu, int reg_lo, int reg_hi)
buzbeeefc63692012-11-14 16:31:52 -0800310{
buzbeefa57c472012-11-21 12:06:18 -0800311 int t_reg = AllocTemp(cu);
312 OpRegRegReg(cu, kOpOr, t_reg, reg_lo, reg_hi);
313 GenImmedCheck(cu, kCondEq, t_reg, 0, kThrowDivZero);
314 FreeTemp(cu, t_reg);
buzbeeefc63692012-11-14 16:31:52 -0800315}
316
317// Test suspend flag, return target of taken suspend branch
buzbee02031b12012-11-23 09:41:35 -0800318LIR* MipsCodegen::OpTestSuspend(CompilationUnit* cu, LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800319{
buzbeefa57c472012-11-21 12:06:18 -0800320 OpRegImm(cu, kOpSub, rMIPS_SUSPEND, 1);
321 return OpCmpImmBranch(cu, (target == NULL) ? kCondEq : kCondNe, rMIPS_SUSPEND, 0, target);
buzbeeefc63692012-11-14 16:31:52 -0800322}
323
324// Decrement register and branch on condition
buzbee02031b12012-11-23 09:41:35 -0800325LIR* MipsCodegen::OpDecAndBranch(CompilationUnit* cu, ConditionCode c_code, int reg, LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800326{
buzbeefa57c472012-11-21 12:06:18 -0800327 OpRegImm(cu, kOpSub, reg, 1);
328 return OpCmpImmBranch(cu, c_code, reg, 0, target);
buzbeeefc63692012-11-14 16:31:52 -0800329}
330
buzbee02031b12012-11-23 09:41:35 -0800331bool MipsCodegen::SmallLiteralDivide(CompilationUnit* cu, Instruction::Code dalvik_opcode,
332 RegLocation rl_src, RegLocation rl_dest, int lit)
buzbeeefc63692012-11-14 16:31:52 -0800333{
334 LOG(FATAL) << "Unexpected use of smallLiteralDive in Mips";
335 return false;
336}
337
buzbee02031b12012-11-23 09:41:35 -0800338LIR* MipsCodegen::OpIT(CompilationUnit* cu, ConditionCode cond, const char* guide)
buzbeeefc63692012-11-14 16:31:52 -0800339{
buzbee52a77fc2012-11-20 19:50:46 -0800340 LOG(FATAL) << "Unexpected use of OpIT in Mips";
buzbeeefc63692012-11-14 16:31:52 -0800341 return NULL;
342}
343
buzbee02031b12012-11-23 09:41:35 -0800344bool MipsCodegen::GenAddLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
345 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800346{
buzbeefa57c472012-11-21 12:06:18 -0800347 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
348 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
349 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
buzbeeefc63692012-11-14 16:31:52 -0800350 /*
351 * [v1 v0] = [a1 a0] + [a3 a2];
352 * addu v0,a2,a0
353 * addu t1,a3,a1
354 * sltu v1,v0,a2
355 * addu v1,v1,t1
356 */
357
buzbeefa57c472012-11-21 12:06:18 -0800358 OpRegRegReg(cu, kOpAdd, rl_result.low_reg, rl_src2.low_reg, rl_src1.low_reg);
359 int t_reg = AllocTemp(cu);
360 OpRegRegReg(cu, kOpAdd, t_reg, rl_src2.high_reg, rl_src1.high_reg);
361 NewLIR3(cu, kMipsSltu, rl_result.high_reg, rl_result.low_reg, rl_src2.low_reg);
362 OpRegRegReg(cu, kOpAdd, rl_result.high_reg, rl_result.high_reg, t_reg);
363 FreeTemp(cu, t_reg);
364 StoreValueWide(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800365 return false;
366}
367
buzbee02031b12012-11-23 09:41:35 -0800368bool MipsCodegen::GenSubLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
369 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800370{
buzbeefa57c472012-11-21 12:06:18 -0800371 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
372 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
373 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
buzbeeefc63692012-11-14 16:31:52 -0800374 /*
375 * [v1 v0] = [a1 a0] - [a3 a2];
376 * sltu t1,a0,a2
377 * subu v0,a0,a2
378 * subu v1,a1,a3
379 * subu v1,v1,t1
380 */
381
buzbeefa57c472012-11-21 12:06:18 -0800382 int t_reg = AllocTemp(cu);
383 NewLIR3(cu, kMipsSltu, t_reg, rl_src1.low_reg, rl_src2.low_reg);
384 OpRegRegReg(cu, kOpSub, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
385 OpRegRegReg(cu, kOpSub, rl_result.high_reg, rl_src1.high_reg, rl_src2.high_reg);
386 OpRegRegReg(cu, kOpSub, rl_result.high_reg, rl_result.high_reg, t_reg);
387 FreeTemp(cu, t_reg);
388 StoreValueWide(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800389 return false;
390}
391
buzbee02031b12012-11-23 09:41:35 -0800392bool MipsCodegen::GenNegLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
buzbeeefc63692012-11-14 16:31:52 -0800393{
buzbeefa57c472012-11-21 12:06:18 -0800394 rl_src = LoadValueWide(cu, rl_src, kCoreReg);
395 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
buzbeeefc63692012-11-14 16:31:52 -0800396 /*
397 * [v1 v0] = -[a1 a0]
398 * negu v0,a0
399 * negu v1,a1
400 * sltu t1,r_zero
401 * subu v1,v1,t1
402 */
403
buzbeefa57c472012-11-21 12:06:18 -0800404 OpRegReg(cu, kOpNeg, rl_result.low_reg, rl_src.low_reg);
405 OpRegReg(cu, kOpNeg, rl_result.high_reg, rl_src.high_reg);
406 int t_reg = AllocTemp(cu);
407 NewLIR3(cu, kMipsSltu, t_reg, r_ZERO, rl_result.low_reg);
408 OpRegRegReg(cu, kOpSub, rl_result.high_reg, rl_result.high_reg, t_reg);
409 FreeTemp(cu, t_reg);
410 StoreValueWide(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800411 return false;
412}
413
buzbee02031b12012-11-23 09:41:35 -0800414bool MipsCodegen::GenAndLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
415 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800416{
buzbee52a77fc2012-11-20 19:50:46 -0800417 LOG(FATAL) << "Unexpected use of GenAndLong for Mips";
buzbeeefc63692012-11-14 16:31:52 -0800418 return false;
419}
420
buzbee02031b12012-11-23 09:41:35 -0800421bool MipsCodegen::GenOrLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
422 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800423{
buzbee52a77fc2012-11-20 19:50:46 -0800424 LOG(FATAL) << "Unexpected use of GenOrLong for Mips";
buzbeeefc63692012-11-14 16:31:52 -0800425 return false;
426}
427
buzbee02031b12012-11-23 09:41:35 -0800428bool MipsCodegen::GenXorLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
429 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800430{
buzbee52a77fc2012-11-20 19:50:46 -0800431 LOG(FATAL) << "Unexpected use of GenXorLong for Mips";
buzbeeefc63692012-11-14 16:31:52 -0800432 return false;
433}
434
buzbeee6285f92012-12-06 15:57:46 -0800435/*
436 * Generate array load
437 */
438void MipsCodegen::GenArrayGet(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array,
439 RegLocation rl_index, RegLocation rl_dest, int scale)
440{
441 RegisterClass reg_class = oat_reg_class_by_size(size);
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800442 int len_offset = mirror::Array::LengthOffset().Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800443 int data_offset;
444 RegLocation rl_result;
445 rl_array = LoadValue(cu, rl_array, kCoreReg);
446 rl_index = LoadValue(cu, rl_index, kCoreReg);
447
448 if (size == kLong || size == kDouble) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800449 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800450 } else {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800451 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800452 }
453
454 /* null object? */
455 GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags);
456
457 int reg_ptr = AllocTemp(cu);
458 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
459 int reg_len = INVALID_REG;
460 if (needs_range_check) {
461 reg_len = AllocTemp(cu);
462 /* Get len */
463 LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len);
464 }
465 /* reg_ptr -> array data */
466 OpRegRegImm(cu, kOpAdd, reg_ptr, rl_array.low_reg, data_offset);
467 FreeTemp(cu, rl_array.low_reg);
468 if ((size == kLong) || (size == kDouble)) {
469 if (scale) {
470 int r_new_index = AllocTemp(cu);
471 OpRegRegImm(cu, kOpLsl, r_new_index, rl_index.low_reg, scale);
472 OpRegReg(cu, kOpAdd, reg_ptr, r_new_index);
473 FreeTemp(cu, r_new_index);
474 } else {
475 OpRegReg(cu, kOpAdd, reg_ptr, rl_index.low_reg);
476 }
477 FreeTemp(cu, rl_index.low_reg);
478 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
479
480 if (needs_range_check) {
481 // TODO: change kCondCS to a more meaningful name, is the sense of
482 // carry-set/clear flipped?
483 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
484 FreeTemp(cu, reg_len);
485 }
486 LoadBaseDispWide(cu, reg_ptr, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
487
488 FreeTemp(cu, reg_ptr);
489 StoreValueWide(cu, rl_dest, rl_result);
490 } else {
491 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
492
493 if (needs_range_check) {
494 // TODO: change kCondCS to a more meaningful name, is the sense of
495 // carry-set/clear flipped?
496 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
497 FreeTemp(cu, reg_len);
498 }
499 LoadBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_result.low_reg, scale, size);
500
501 FreeTemp(cu, reg_ptr);
502 StoreValue(cu, rl_dest, rl_result);
503 }
504}
505
506/*
507 * Generate array store
508 *
509 */
510void MipsCodegen::GenArrayPut(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array,
511 RegLocation rl_index, RegLocation rl_src, int scale)
512{
513 RegisterClass reg_class = oat_reg_class_by_size(size);
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800514 int len_offset = mirror::Array::LengthOffset().Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800515 int data_offset;
516
517 if (size == kLong || size == kDouble) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800518 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800519 } else {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800520 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800521 }
522
523 rl_array = LoadValue(cu, rl_array, kCoreReg);
524 rl_index = LoadValue(cu, rl_index, kCoreReg);
525 int reg_ptr = INVALID_REG;
526 if (IsTemp(cu, rl_array.low_reg)) {
527 Clobber(cu, rl_array.low_reg);
528 reg_ptr = rl_array.low_reg;
529 } else {
530 reg_ptr = AllocTemp(cu);
531 OpRegCopy(cu, reg_ptr, rl_array.low_reg);
532 }
533
534 /* null object? */
535 GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags);
536
537 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
538 int reg_len = INVALID_REG;
539 if (needs_range_check) {
540 reg_len = AllocTemp(cu);
541 //NOTE: max live temps(4) here.
542 /* Get len */
543 LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len);
544 }
545 /* reg_ptr -> array data */
546 OpRegImm(cu, kOpAdd, reg_ptr, data_offset);
547 /* at this point, reg_ptr points to array, 2 live temps */
548 if ((size == kLong) || (size == kDouble)) {
549 //TUNING: specific wide routine that can handle fp regs
550 if (scale) {
551 int r_new_index = AllocTemp(cu);
552 OpRegRegImm(cu, kOpLsl, r_new_index, rl_index.low_reg, scale);
553 OpRegReg(cu, kOpAdd, reg_ptr, r_new_index);
554 FreeTemp(cu, r_new_index);
555 } else {
556 OpRegReg(cu, kOpAdd, reg_ptr, rl_index.low_reg);
557 }
558 rl_src = LoadValueWide(cu, rl_src, reg_class);
559
560 if (needs_range_check) {
561 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
562 FreeTemp(cu, reg_len);
563 }
564
565 StoreBaseDispWide(cu, reg_ptr, 0, rl_src.low_reg, rl_src.high_reg);
566
567 FreeTemp(cu, reg_ptr);
568 } else {
569 rl_src = LoadValue(cu, rl_src, reg_class);
570 if (needs_range_check) {
571 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
572 FreeTemp(cu, reg_len);
573 }
574 StoreBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_src.low_reg,
575 scale, size);
576 }
577}
578
579/*
580 * Generate array store
581 *
582 */
583void MipsCodegen::GenArrayObjPut(CompilationUnit* cu, int opt_flags, RegLocation rl_array,
584 RegLocation rl_index, RegLocation rl_src, int scale)
585{
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800586 int len_offset = mirror::Array::LengthOffset().Int32Value();
587 int data_offset = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800588
589 FlushAllRegs(cu); // Use explicit registers
590 LockCallTemps(cu);
591
592 int r_value = TargetReg(kArg0); // Register holding value
593 int r_array_class = TargetReg(kArg1); // Register holding array's Class
594 int r_array = TargetReg(kArg2); // Register holding array
595 int r_index = TargetReg(kArg3); // Register holding index into array
596
597 LoadValueDirectFixed(cu, rl_array, r_array); // Grab array
598 LoadValueDirectFixed(cu, rl_src, r_value); // Grab value
599 LoadValueDirectFixed(cu, rl_index, r_index); // Grab index
600
601 GenNullCheck(cu, rl_array.s_reg_low, r_array, opt_flags); // NPE?
602
603 // Store of null?
604 LIR* null_value_check = OpCmpImmBranch(cu, kCondEq, r_value, 0, NULL);
605
606 // Get the array's class.
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800607 LoadWordDisp(cu, r_array, mirror::Object::ClassOffset().Int32Value(), r_array_class);
buzbeee6285f92012-12-06 15:57:46 -0800608 CallRuntimeHelperRegReg(cu, ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), r_value,
609 r_array_class, true);
610 // Redo LoadValues in case they didn't survive the call.
611 LoadValueDirectFixed(cu, rl_array, r_array); // Reload array
612 LoadValueDirectFixed(cu, rl_index, r_index); // Reload index
613 LoadValueDirectFixed(cu, rl_src, r_value); // Reload value
614 r_array_class = INVALID_REG;
615
616 // Branch here if value to be stored == null
617 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
618 null_value_check->target = target;
619
620 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
621 int reg_len = INVALID_REG;
622 if (needs_range_check) {
623 reg_len = TargetReg(kArg1);
624 LoadWordDisp(cu, r_array, len_offset, reg_len); // Get len
625 }
626 /* r_ptr -> array data */
627 int r_ptr = AllocTemp(cu);
628 OpRegRegImm(cu, kOpAdd, r_ptr, r_array, data_offset);
629 if (needs_range_check) {
630 GenRegRegCheck(cu, kCondCs, r_index, reg_len, kThrowArrayBounds);
631 }
632 StoreBaseIndexed(cu, r_ptr, r_index, r_value, scale, kWord);
633 FreeTemp(cu, r_ptr);
634 FreeTemp(cu, r_index);
635 MarkGCCard(cu, r_value, r_array);
636}
637
buzbeeefc63692012-11-14 16:31:52 -0800638} // namespace art