blob: 675cf8d86af80f3a72c1a038e08c6a39cb4d575a [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
buzbee02031b12012-11-23 09:41:35 -080019#include "codegen_mips.h"
Brian Carlstrom641ce032013-01-31 15:21:37 -080020#include "compiler/codegen/codegen_util.h"
21#include "compiler/codegen/ralloc_util.h"
22#include "mips_lir.h"
23#include "oat/runtime/oat_support_entrypoints.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
buzbee4ef3e452012-12-14 13:35:28 -0800344void MipsCodegen::GenMulLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
345 RegLocation rl_src2)
346{
347 LOG(FATAL) << "Unexpected use of GenMulLong for Mips";
348 return;
349}
350
buzbee02031b12012-11-23 09:41:35 -0800351bool MipsCodegen::GenAddLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
352 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800353{
buzbeefa57c472012-11-21 12:06:18 -0800354 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
355 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
356 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
buzbeeefc63692012-11-14 16:31:52 -0800357 /*
358 * [v1 v0] = [a1 a0] + [a3 a2];
359 * addu v0,a2,a0
360 * addu t1,a3,a1
361 * sltu v1,v0,a2
362 * addu v1,v1,t1
363 */
364
buzbeefa57c472012-11-21 12:06:18 -0800365 OpRegRegReg(cu, kOpAdd, rl_result.low_reg, rl_src2.low_reg, rl_src1.low_reg);
366 int t_reg = AllocTemp(cu);
367 OpRegRegReg(cu, kOpAdd, t_reg, rl_src2.high_reg, rl_src1.high_reg);
368 NewLIR3(cu, kMipsSltu, rl_result.high_reg, rl_result.low_reg, rl_src2.low_reg);
369 OpRegRegReg(cu, kOpAdd, rl_result.high_reg, rl_result.high_reg, t_reg);
370 FreeTemp(cu, t_reg);
371 StoreValueWide(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800372 return false;
373}
374
buzbee02031b12012-11-23 09:41:35 -0800375bool MipsCodegen::GenSubLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
376 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800377{
buzbeefa57c472012-11-21 12:06:18 -0800378 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
379 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
380 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
buzbeeefc63692012-11-14 16:31:52 -0800381 /*
382 * [v1 v0] = [a1 a0] - [a3 a2];
383 * sltu t1,a0,a2
384 * subu v0,a0,a2
385 * subu v1,a1,a3
386 * subu v1,v1,t1
387 */
388
buzbeefa57c472012-11-21 12:06:18 -0800389 int t_reg = AllocTemp(cu);
390 NewLIR3(cu, kMipsSltu, t_reg, rl_src1.low_reg, rl_src2.low_reg);
391 OpRegRegReg(cu, kOpSub, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
392 OpRegRegReg(cu, kOpSub, rl_result.high_reg, rl_src1.high_reg, rl_src2.high_reg);
393 OpRegRegReg(cu, kOpSub, rl_result.high_reg, rl_result.high_reg, t_reg);
394 FreeTemp(cu, t_reg);
395 StoreValueWide(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800396 return false;
397}
398
buzbee02031b12012-11-23 09:41:35 -0800399bool MipsCodegen::GenNegLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
buzbeeefc63692012-11-14 16:31:52 -0800400{
buzbeefa57c472012-11-21 12:06:18 -0800401 rl_src = LoadValueWide(cu, rl_src, kCoreReg);
402 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
buzbeeefc63692012-11-14 16:31:52 -0800403 /*
404 * [v1 v0] = -[a1 a0]
405 * negu v0,a0
406 * negu v1,a1
407 * sltu t1,r_zero
408 * subu v1,v1,t1
409 */
410
buzbeefa57c472012-11-21 12:06:18 -0800411 OpRegReg(cu, kOpNeg, rl_result.low_reg, rl_src.low_reg);
412 OpRegReg(cu, kOpNeg, rl_result.high_reg, rl_src.high_reg);
413 int t_reg = AllocTemp(cu);
414 NewLIR3(cu, kMipsSltu, t_reg, r_ZERO, rl_result.low_reg);
415 OpRegRegReg(cu, kOpSub, rl_result.high_reg, rl_result.high_reg, t_reg);
416 FreeTemp(cu, t_reg);
417 StoreValueWide(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800418 return false;
419}
420
buzbee02031b12012-11-23 09:41:35 -0800421bool MipsCodegen::GenAndLong(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 GenAndLong for Mips";
buzbeeefc63692012-11-14 16:31:52 -0800425 return false;
426}
427
buzbee02031b12012-11-23 09:41:35 -0800428bool MipsCodegen::GenOrLong(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 GenOrLong for Mips";
buzbeeefc63692012-11-14 16:31:52 -0800432 return false;
433}
434
buzbee02031b12012-11-23 09:41:35 -0800435bool MipsCodegen::GenXorLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
436 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800437{
buzbee52a77fc2012-11-20 19:50:46 -0800438 LOG(FATAL) << "Unexpected use of GenXorLong for Mips";
buzbeeefc63692012-11-14 16:31:52 -0800439 return false;
440}
441
buzbeee6285f92012-12-06 15:57:46 -0800442/*
443 * Generate array load
444 */
445void MipsCodegen::GenArrayGet(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array,
446 RegLocation rl_index, RegLocation rl_dest, int scale)
447{
448 RegisterClass reg_class = oat_reg_class_by_size(size);
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800449 int len_offset = mirror::Array::LengthOffset().Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800450 int data_offset;
451 RegLocation rl_result;
452 rl_array = LoadValue(cu, rl_array, kCoreReg);
453 rl_index = LoadValue(cu, rl_index, kCoreReg);
454
455 if (size == kLong || size == kDouble) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800456 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800457 } else {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800458 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800459 }
460
461 /* null object? */
462 GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags);
463
464 int reg_ptr = AllocTemp(cu);
465 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
466 int reg_len = INVALID_REG;
467 if (needs_range_check) {
468 reg_len = AllocTemp(cu);
469 /* Get len */
470 LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len);
471 }
472 /* reg_ptr -> array data */
473 OpRegRegImm(cu, kOpAdd, reg_ptr, rl_array.low_reg, data_offset);
474 FreeTemp(cu, rl_array.low_reg);
475 if ((size == kLong) || (size == kDouble)) {
476 if (scale) {
477 int r_new_index = AllocTemp(cu);
478 OpRegRegImm(cu, kOpLsl, r_new_index, rl_index.low_reg, scale);
479 OpRegReg(cu, kOpAdd, reg_ptr, r_new_index);
480 FreeTemp(cu, r_new_index);
481 } else {
482 OpRegReg(cu, kOpAdd, reg_ptr, rl_index.low_reg);
483 }
484 FreeTemp(cu, rl_index.low_reg);
485 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
486
487 if (needs_range_check) {
488 // TODO: change kCondCS to a more meaningful name, is the sense of
489 // carry-set/clear flipped?
490 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
491 FreeTemp(cu, reg_len);
492 }
493 LoadBaseDispWide(cu, reg_ptr, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
494
495 FreeTemp(cu, reg_ptr);
496 StoreValueWide(cu, rl_dest, rl_result);
497 } else {
498 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
499
500 if (needs_range_check) {
501 // TODO: change kCondCS to a more meaningful name, is the sense of
502 // carry-set/clear flipped?
503 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
504 FreeTemp(cu, reg_len);
505 }
506 LoadBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_result.low_reg, scale, size);
507
508 FreeTemp(cu, reg_ptr);
509 StoreValue(cu, rl_dest, rl_result);
510 }
511}
512
513/*
514 * Generate array store
515 *
516 */
517void MipsCodegen::GenArrayPut(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array,
518 RegLocation rl_index, RegLocation rl_src, int scale)
519{
520 RegisterClass reg_class = oat_reg_class_by_size(size);
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800521 int len_offset = mirror::Array::LengthOffset().Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800522 int data_offset;
523
524 if (size == kLong || size == kDouble) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800525 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800526 } else {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800527 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800528 }
529
530 rl_array = LoadValue(cu, rl_array, kCoreReg);
531 rl_index = LoadValue(cu, rl_index, kCoreReg);
532 int reg_ptr = INVALID_REG;
533 if (IsTemp(cu, rl_array.low_reg)) {
534 Clobber(cu, rl_array.low_reg);
535 reg_ptr = rl_array.low_reg;
536 } else {
537 reg_ptr = AllocTemp(cu);
538 OpRegCopy(cu, reg_ptr, rl_array.low_reg);
539 }
540
541 /* null object? */
542 GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags);
543
544 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
545 int reg_len = INVALID_REG;
546 if (needs_range_check) {
547 reg_len = AllocTemp(cu);
548 //NOTE: max live temps(4) here.
549 /* Get len */
550 LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len);
551 }
552 /* reg_ptr -> array data */
553 OpRegImm(cu, kOpAdd, reg_ptr, data_offset);
554 /* at this point, reg_ptr points to array, 2 live temps */
555 if ((size == kLong) || (size == kDouble)) {
556 //TUNING: specific wide routine that can handle fp regs
557 if (scale) {
558 int r_new_index = AllocTemp(cu);
559 OpRegRegImm(cu, kOpLsl, r_new_index, rl_index.low_reg, scale);
560 OpRegReg(cu, kOpAdd, reg_ptr, r_new_index);
561 FreeTemp(cu, r_new_index);
562 } else {
563 OpRegReg(cu, kOpAdd, reg_ptr, rl_index.low_reg);
564 }
565 rl_src = LoadValueWide(cu, rl_src, reg_class);
566
567 if (needs_range_check) {
568 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
569 FreeTemp(cu, reg_len);
570 }
571
572 StoreBaseDispWide(cu, reg_ptr, 0, rl_src.low_reg, rl_src.high_reg);
573
574 FreeTemp(cu, reg_ptr);
575 } else {
576 rl_src = LoadValue(cu, rl_src, reg_class);
577 if (needs_range_check) {
578 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
579 FreeTemp(cu, reg_len);
580 }
581 StoreBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_src.low_reg,
582 scale, size);
583 }
584}
585
586/*
587 * Generate array store
588 *
589 */
590void MipsCodegen::GenArrayObjPut(CompilationUnit* cu, int opt_flags, RegLocation rl_array,
591 RegLocation rl_index, RegLocation rl_src, int scale)
592{
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800593 int len_offset = mirror::Array::LengthOffset().Int32Value();
594 int data_offset = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800595
596 FlushAllRegs(cu); // Use explicit registers
597 LockCallTemps(cu);
598
599 int r_value = TargetReg(kArg0); // Register holding value
600 int r_array_class = TargetReg(kArg1); // Register holding array's Class
601 int r_array = TargetReg(kArg2); // Register holding array
602 int r_index = TargetReg(kArg3); // Register holding index into array
603
604 LoadValueDirectFixed(cu, rl_array, r_array); // Grab array
605 LoadValueDirectFixed(cu, rl_src, r_value); // Grab value
606 LoadValueDirectFixed(cu, rl_index, r_index); // Grab index
607
608 GenNullCheck(cu, rl_array.s_reg_low, r_array, opt_flags); // NPE?
609
610 // Store of null?
611 LIR* null_value_check = OpCmpImmBranch(cu, kCondEq, r_value, 0, NULL);
612
613 // Get the array's class.
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800614 LoadWordDisp(cu, r_array, mirror::Object::ClassOffset().Int32Value(), r_array_class);
buzbeee6285f92012-12-06 15:57:46 -0800615 CallRuntimeHelperRegReg(cu, ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), r_value,
616 r_array_class, true);
617 // Redo LoadValues in case they didn't survive the call.
618 LoadValueDirectFixed(cu, rl_array, r_array); // Reload array
619 LoadValueDirectFixed(cu, rl_index, r_index); // Reload index
620 LoadValueDirectFixed(cu, rl_src, r_value); // Reload value
621 r_array_class = INVALID_REG;
622
623 // Branch here if value to be stored == null
624 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
625 null_value_check->target = target;
626
627 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
628 int reg_len = INVALID_REG;
629 if (needs_range_check) {
630 reg_len = TargetReg(kArg1);
631 LoadWordDisp(cu, r_array, len_offset, reg_len); // Get len
632 }
633 /* r_ptr -> array data */
634 int r_ptr = AllocTemp(cu);
635 OpRegRegImm(cu, kOpAdd, r_ptr, r_array, data_offset);
636 if (needs_range_check) {
637 GenRegRegCheck(cu, kCondCs, r_index, reg_len, kThrowArrayBounds);
638 }
639 StoreBaseIndexed(cu, r_ptr, r_index, r_value, scale, kWord);
640 FreeTemp(cu, r_ptr);
641 FreeTemp(cu, r_index);
642 MarkGCCard(cu, r_value, r_array);
643}
644
buzbee4ef3e452012-12-14 13:35:28 -0800645bool MipsCodegen::GenShiftImmOpLong(CompilationUnit* cu, Instruction::Code opcode, RegLocation rl_dest,
646 RegLocation rl_src1, RegLocation rl_shift)
647{
648 // Default implementation is just to ignore the constant case.
649 return GenShiftOpLong(cu, opcode, rl_dest, rl_src1, rl_shift);
650}
651
652bool MipsCodegen::GenArithImmOpLong(CompilationUnit* cu, Instruction::Code opcode,
653 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2)
654{
655 // Default - bail to non-const handler.
656 return GenArithOpLong(cu, opcode, rl_dest, rl_src1, rl_src2);
657}
658
buzbeeefc63692012-11-14 16:31:52 -0800659} // namespace art