blob: b1fa623d8c2637ef93ba3c94765c0fc44f33f7b4 [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"
buzbee395116c2013-02-27 14:30:25 -080020#include "compiler/dex/quick/codegen_util.h"
21#include "compiler/dex/quick/ralloc_util.h"
Brian Carlstrom641ce032013-01-31 15:21:37 -080022#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
buzbeef662a7c2013-02-12 16:19:43 -0800218void MipsCodegen::GenSelect(CompilationUnit* cu, BasicBlock* bb, MIR* mir)
219{
220 UNIMPLEMENTED(FATAL) << "Need codegen for select";
221}
222
buzbee02031b12012-11-23 09:41:35 -0800223void MipsCodegen::GenFusedLongCmpBranch(CompilationUnit* cu, BasicBlock* bb, MIR* mir)
buzbeeefc63692012-11-14 16:31:52 -0800224{
225 UNIMPLEMENTED(FATAL) << "Need codegen for fused long cmp branch";
226}
227
buzbee02031b12012-11-23 09:41:35 -0800228LIR* MipsCodegen::GenRegMemCheck(CompilationUnit* cu, ConditionCode c_code,
buzbeeefc63692012-11-14 16:31:52 -0800229 int reg1, int base, int offset, ThrowKind kind)
230{
buzbee52a77fc2012-11-20 19:50:46 -0800231 LOG(FATAL) << "Unexpected use of GenRegMemCheck for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800232 return NULL;
233}
234
buzbee02031b12012-11-23 09:41:35 -0800235RegLocation MipsCodegen::GenDivRem(CompilationUnit* cu, RegLocation rl_dest, int reg1, int reg2,
236 bool is_div)
buzbeeefc63692012-11-14 16:31:52 -0800237{
buzbeefa57c472012-11-21 12:06:18 -0800238 NewLIR4(cu, kMipsDiv, r_HI, r_LO, reg1, reg2);
239 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
240 if (is_div) {
241 NewLIR2(cu, kMipsMflo, rl_result.low_reg, r_LO);
buzbeeefc63692012-11-14 16:31:52 -0800242 } else {
buzbeefa57c472012-11-21 12:06:18 -0800243 NewLIR2(cu, kMipsMfhi, rl_result.low_reg, r_HI);
buzbeeefc63692012-11-14 16:31:52 -0800244 }
buzbeefa57c472012-11-21 12:06:18 -0800245 return rl_result;
buzbeeefc63692012-11-14 16:31:52 -0800246}
247
buzbee02031b12012-11-23 09:41:35 -0800248RegLocation MipsCodegen::GenDivRemLit(CompilationUnit* cu, RegLocation rl_dest, int reg1, int lit,
249 bool is_div)
buzbeeefc63692012-11-14 16:31:52 -0800250{
buzbeefa57c472012-11-21 12:06:18 -0800251 int t_reg = AllocTemp(cu);
252 NewLIR3(cu, kMipsAddiu, t_reg, r_ZERO, lit);
253 NewLIR4(cu, kMipsDiv, r_HI, r_LO, reg1, t_reg);
254 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
255 if (is_div) {
256 NewLIR2(cu, kMipsMflo, rl_result.low_reg, r_LO);
buzbeeefc63692012-11-14 16:31:52 -0800257 } else {
buzbeefa57c472012-11-21 12:06:18 -0800258 NewLIR2(cu, kMipsMfhi, rl_result.low_reg, r_HI);
buzbeeefc63692012-11-14 16:31:52 -0800259 }
buzbeefa57c472012-11-21 12:06:18 -0800260 FreeTemp(cu, t_reg);
261 return rl_result;
buzbeeefc63692012-11-14 16:31:52 -0800262}
263
buzbee02031b12012-11-23 09:41:35 -0800264void MipsCodegen::OpLea(CompilationUnit* cu, int rBase, int reg1, int reg2, int scale, int offset)
buzbeeefc63692012-11-14 16:31:52 -0800265{
buzbee52a77fc2012-11-20 19:50:46 -0800266 LOG(FATAL) << "Unexpected use of OpLea for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800267}
268
buzbee02031b12012-11-23 09:41:35 -0800269void MipsCodegen::OpTlsCmp(CompilationUnit* cu, int offset, int val)
buzbeeefc63692012-11-14 16:31:52 -0800270{
buzbee52a77fc2012-11-20 19:50:46 -0800271 LOG(FATAL) << "Unexpected use of OpTlsCmp for Arm";
buzbeeefc63692012-11-14 16:31:52 -0800272}
273
buzbee02031b12012-11-23 09:41:35 -0800274bool MipsCodegen::GenInlinedCas32(CompilationUnit* cu, CallInfo* info, bool need_write_barrier) {
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 -0800279bool MipsCodegen::GenInlinedSqrt(CompilationUnit* cu, CallInfo* info) {
buzbeefa57c472012-11-21 12:06:18 -0800280 DCHECK_NE(cu->instruction_set, kThumb2);
buzbeeefc63692012-11-14 16:31:52 -0800281 return false;
282}
283
buzbee02031b12012-11-23 09:41:35 -0800284LIR* MipsCodegen::OpPcRelLoad(CompilationUnit* cu, int reg, LIR* target) {
buzbee52a77fc2012-11-20 19:50:46 -0800285 LOG(FATAL) << "Unexpected use of OpPcRelLoad for Mips";
buzbeeefc63692012-11-14 16:31:52 -0800286 return NULL;
287}
288
buzbee02031b12012-11-23 09:41:35 -0800289LIR* MipsCodegen::OpVldm(CompilationUnit* cu, int rBase, int count)
buzbeeefc63692012-11-14 16:31:52 -0800290{
buzbee52a77fc2012-11-20 19:50:46 -0800291 LOG(FATAL) << "Unexpected use of OpVldm for Mips";
buzbeeefc63692012-11-14 16:31:52 -0800292 return NULL;
293}
294
buzbee02031b12012-11-23 09:41:35 -0800295LIR* MipsCodegen::OpVstm(CompilationUnit* cu, int rBase, int count)
buzbeeefc63692012-11-14 16:31:52 -0800296{
buzbee52a77fc2012-11-20 19:50:46 -0800297 LOG(FATAL) << "Unexpected use of OpVstm for Mips";
buzbeeefc63692012-11-14 16:31:52 -0800298 return NULL;
299}
300
buzbee02031b12012-11-23 09:41:35 -0800301void MipsCodegen::GenMultiplyByTwoBitMultiplier(CompilationUnit* cu, RegLocation rl_src,
302 RegLocation rl_result, int lit,
303 int first_bit, int second_bit)
buzbeeefc63692012-11-14 16:31:52 -0800304{
buzbeefa57c472012-11-21 12:06:18 -0800305 int t_reg = AllocTemp(cu);
306 OpRegRegImm(cu, kOpLsl, t_reg, rl_src.low_reg, second_bit - first_bit);
307 OpRegRegReg(cu, kOpAdd, rl_result.low_reg, rl_src.low_reg, t_reg);
308 FreeTemp(cu, t_reg);
309 if (first_bit != 0) {
310 OpRegRegImm(cu, kOpLsl, rl_result.low_reg, rl_result.low_reg, first_bit);
buzbeeefc63692012-11-14 16:31:52 -0800311 }
312}
313
buzbee02031b12012-11-23 09:41:35 -0800314void MipsCodegen::GenDivZeroCheck(CompilationUnit* cu, int reg_lo, int reg_hi)
buzbeeefc63692012-11-14 16:31:52 -0800315{
buzbeefa57c472012-11-21 12:06:18 -0800316 int t_reg = AllocTemp(cu);
317 OpRegRegReg(cu, kOpOr, t_reg, reg_lo, reg_hi);
318 GenImmedCheck(cu, kCondEq, t_reg, 0, kThrowDivZero);
319 FreeTemp(cu, t_reg);
buzbeeefc63692012-11-14 16:31:52 -0800320}
321
322// Test suspend flag, return target of taken suspend branch
buzbee02031b12012-11-23 09:41:35 -0800323LIR* MipsCodegen::OpTestSuspend(CompilationUnit* cu, LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800324{
buzbeefa57c472012-11-21 12:06:18 -0800325 OpRegImm(cu, kOpSub, rMIPS_SUSPEND, 1);
326 return OpCmpImmBranch(cu, (target == NULL) ? kCondEq : kCondNe, rMIPS_SUSPEND, 0, target);
buzbeeefc63692012-11-14 16:31:52 -0800327}
328
329// Decrement register and branch on condition
buzbee02031b12012-11-23 09:41:35 -0800330LIR* MipsCodegen::OpDecAndBranch(CompilationUnit* cu, ConditionCode c_code, int reg, LIR* target)
buzbeeefc63692012-11-14 16:31:52 -0800331{
buzbeefa57c472012-11-21 12:06:18 -0800332 OpRegImm(cu, kOpSub, reg, 1);
333 return OpCmpImmBranch(cu, c_code, reg, 0, target);
buzbeeefc63692012-11-14 16:31:52 -0800334}
335
buzbee02031b12012-11-23 09:41:35 -0800336bool MipsCodegen::SmallLiteralDivide(CompilationUnit* cu, Instruction::Code dalvik_opcode,
337 RegLocation rl_src, RegLocation rl_dest, int lit)
buzbeeefc63692012-11-14 16:31:52 -0800338{
339 LOG(FATAL) << "Unexpected use of smallLiteralDive in Mips";
340 return false;
341}
342
buzbee02031b12012-11-23 09:41:35 -0800343LIR* MipsCodegen::OpIT(CompilationUnit* cu, ConditionCode cond, const char* guide)
buzbeeefc63692012-11-14 16:31:52 -0800344{
buzbee52a77fc2012-11-20 19:50:46 -0800345 LOG(FATAL) << "Unexpected use of OpIT in Mips";
buzbeeefc63692012-11-14 16:31:52 -0800346 return NULL;
347}
348
buzbee4ef3e452012-12-14 13:35:28 -0800349void MipsCodegen::GenMulLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
350 RegLocation rl_src2)
351{
352 LOG(FATAL) << "Unexpected use of GenMulLong for Mips";
buzbee4ef3e452012-12-14 13:35:28 -0800353}
354
buzbeea5954be2013-02-07 10:41:40 -0800355void MipsCodegen::GenAddLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
buzbee02031b12012-11-23 09:41:35 -0800356 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800357{
buzbeefa57c472012-11-21 12:06:18 -0800358 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
359 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
360 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
buzbeeefc63692012-11-14 16:31:52 -0800361 /*
362 * [v1 v0] = [a1 a0] + [a3 a2];
363 * addu v0,a2,a0
364 * addu t1,a3,a1
365 * sltu v1,v0,a2
366 * addu v1,v1,t1
367 */
368
buzbeefa57c472012-11-21 12:06:18 -0800369 OpRegRegReg(cu, kOpAdd, rl_result.low_reg, rl_src2.low_reg, rl_src1.low_reg);
370 int t_reg = AllocTemp(cu);
371 OpRegRegReg(cu, kOpAdd, t_reg, rl_src2.high_reg, rl_src1.high_reg);
372 NewLIR3(cu, kMipsSltu, rl_result.high_reg, rl_result.low_reg, rl_src2.low_reg);
373 OpRegRegReg(cu, kOpAdd, rl_result.high_reg, rl_result.high_reg, t_reg);
374 FreeTemp(cu, t_reg);
375 StoreValueWide(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800376}
377
buzbeea5954be2013-02-07 10:41:40 -0800378void MipsCodegen::GenSubLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
buzbee02031b12012-11-23 09:41:35 -0800379 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800380{
buzbeefa57c472012-11-21 12:06:18 -0800381 rl_src1 = LoadValueWide(cu, rl_src1, kCoreReg);
382 rl_src2 = LoadValueWide(cu, rl_src2, kCoreReg);
383 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
buzbeeefc63692012-11-14 16:31:52 -0800384 /*
385 * [v1 v0] = [a1 a0] - [a3 a2];
386 * sltu t1,a0,a2
387 * subu v0,a0,a2
388 * subu v1,a1,a3
389 * subu v1,v1,t1
390 */
391
buzbeefa57c472012-11-21 12:06:18 -0800392 int t_reg = AllocTemp(cu);
393 NewLIR3(cu, kMipsSltu, t_reg, rl_src1.low_reg, rl_src2.low_reg);
394 OpRegRegReg(cu, kOpSub, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg);
395 OpRegRegReg(cu, kOpSub, rl_result.high_reg, rl_src1.high_reg, rl_src2.high_reg);
396 OpRegRegReg(cu, kOpSub, rl_result.high_reg, rl_result.high_reg, t_reg);
397 FreeTemp(cu, t_reg);
398 StoreValueWide(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800399}
400
buzbeea5954be2013-02-07 10:41:40 -0800401void MipsCodegen::GenNegLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src)
buzbeeefc63692012-11-14 16:31:52 -0800402{
buzbeefa57c472012-11-21 12:06:18 -0800403 rl_src = LoadValueWide(cu, rl_src, kCoreReg);
404 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
buzbeeefc63692012-11-14 16:31:52 -0800405 /*
406 * [v1 v0] = -[a1 a0]
407 * negu v0,a0
408 * negu v1,a1
409 * sltu t1,r_zero
410 * subu v1,v1,t1
411 */
412
buzbeefa57c472012-11-21 12:06:18 -0800413 OpRegReg(cu, kOpNeg, rl_result.low_reg, rl_src.low_reg);
414 OpRegReg(cu, kOpNeg, rl_result.high_reg, rl_src.high_reg);
415 int t_reg = AllocTemp(cu);
416 NewLIR3(cu, kMipsSltu, t_reg, r_ZERO, rl_result.low_reg);
417 OpRegRegReg(cu, kOpSub, rl_result.high_reg, rl_result.high_reg, t_reg);
418 FreeTemp(cu, t_reg);
419 StoreValueWide(cu, rl_dest, rl_result);
buzbeeefc63692012-11-14 16:31:52 -0800420}
421
buzbeea5954be2013-02-07 10:41:40 -0800422void MipsCodegen::GenAndLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
buzbee02031b12012-11-23 09:41:35 -0800423 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800424{
buzbee52a77fc2012-11-20 19:50:46 -0800425 LOG(FATAL) << "Unexpected use of GenAndLong for Mips";
buzbeeefc63692012-11-14 16:31:52 -0800426}
427
buzbeea5954be2013-02-07 10:41:40 -0800428void MipsCodegen::GenOrLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
buzbee02031b12012-11-23 09:41:35 -0800429 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}
433
buzbeea5954be2013-02-07 10:41:40 -0800434void MipsCodegen::GenXorLong(CompilationUnit* cu, RegLocation rl_dest, RegLocation rl_src1,
buzbee02031b12012-11-23 09:41:35 -0800435 RegLocation rl_src2)
buzbeeefc63692012-11-14 16:31:52 -0800436{
buzbee52a77fc2012-11-20 19:50:46 -0800437 LOG(FATAL) << "Unexpected use of GenXorLong for Mips";
buzbeeefc63692012-11-14 16:31:52 -0800438}
439
buzbeee6285f92012-12-06 15:57:46 -0800440/*
441 * Generate array load
442 */
443void MipsCodegen::GenArrayGet(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array,
444 RegLocation rl_index, RegLocation rl_dest, int scale)
445{
446 RegisterClass reg_class = oat_reg_class_by_size(size);
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800447 int len_offset = mirror::Array::LengthOffset().Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800448 int data_offset;
449 RegLocation rl_result;
450 rl_array = LoadValue(cu, rl_array, kCoreReg);
451 rl_index = LoadValue(cu, rl_index, kCoreReg);
452
453 if (size == kLong || size == kDouble) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800454 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800455 } else {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800456 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800457 }
458
459 /* null object? */
460 GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags);
461
462 int reg_ptr = AllocTemp(cu);
463 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
464 int reg_len = INVALID_REG;
465 if (needs_range_check) {
466 reg_len = AllocTemp(cu);
467 /* Get len */
468 LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len);
469 }
470 /* reg_ptr -> array data */
471 OpRegRegImm(cu, kOpAdd, reg_ptr, rl_array.low_reg, data_offset);
472 FreeTemp(cu, rl_array.low_reg);
473 if ((size == kLong) || (size == kDouble)) {
474 if (scale) {
475 int r_new_index = AllocTemp(cu);
476 OpRegRegImm(cu, kOpLsl, r_new_index, rl_index.low_reg, scale);
477 OpRegReg(cu, kOpAdd, reg_ptr, r_new_index);
478 FreeTemp(cu, r_new_index);
479 } else {
480 OpRegReg(cu, kOpAdd, reg_ptr, rl_index.low_reg);
481 }
482 FreeTemp(cu, rl_index.low_reg);
483 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
484
485 if (needs_range_check) {
486 // TODO: change kCondCS to a more meaningful name, is the sense of
487 // carry-set/clear flipped?
488 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
489 FreeTemp(cu, reg_len);
490 }
491 LoadBaseDispWide(cu, reg_ptr, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
492
493 FreeTemp(cu, reg_ptr);
494 StoreValueWide(cu, rl_dest, rl_result);
495 } else {
496 rl_result = EvalLoc(cu, rl_dest, reg_class, true);
497
498 if (needs_range_check) {
499 // TODO: change kCondCS to a more meaningful name, is the sense of
500 // carry-set/clear flipped?
501 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
502 FreeTemp(cu, reg_len);
503 }
504 LoadBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_result.low_reg, scale, size);
505
506 FreeTemp(cu, reg_ptr);
507 StoreValue(cu, rl_dest, rl_result);
508 }
509}
510
511/*
512 * Generate array store
513 *
514 */
515void MipsCodegen::GenArrayPut(CompilationUnit* cu, int opt_flags, OpSize size, RegLocation rl_array,
516 RegLocation rl_index, RegLocation rl_src, int scale)
517{
518 RegisterClass reg_class = oat_reg_class_by_size(size);
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800519 int len_offset = mirror::Array::LengthOffset().Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800520 int data_offset;
521
522 if (size == kLong || size == kDouble) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800523 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800524 } else {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800525 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800526 }
527
528 rl_array = LoadValue(cu, rl_array, kCoreReg);
529 rl_index = LoadValue(cu, rl_index, kCoreReg);
530 int reg_ptr = INVALID_REG;
531 if (IsTemp(cu, rl_array.low_reg)) {
532 Clobber(cu, rl_array.low_reg);
533 reg_ptr = rl_array.low_reg;
534 } else {
535 reg_ptr = AllocTemp(cu);
536 OpRegCopy(cu, reg_ptr, rl_array.low_reg);
537 }
538
539 /* null object? */
540 GenNullCheck(cu, rl_array.s_reg_low, rl_array.low_reg, opt_flags);
541
542 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
543 int reg_len = INVALID_REG;
544 if (needs_range_check) {
545 reg_len = AllocTemp(cu);
546 //NOTE: max live temps(4) here.
547 /* Get len */
548 LoadWordDisp(cu, rl_array.low_reg, len_offset, reg_len);
549 }
550 /* reg_ptr -> array data */
551 OpRegImm(cu, kOpAdd, reg_ptr, data_offset);
552 /* at this point, reg_ptr points to array, 2 live temps */
553 if ((size == kLong) || (size == kDouble)) {
554 //TUNING: specific wide routine that can handle fp regs
555 if (scale) {
556 int r_new_index = AllocTemp(cu);
557 OpRegRegImm(cu, kOpLsl, r_new_index, rl_index.low_reg, scale);
558 OpRegReg(cu, kOpAdd, reg_ptr, r_new_index);
559 FreeTemp(cu, r_new_index);
560 } else {
561 OpRegReg(cu, kOpAdd, reg_ptr, rl_index.low_reg);
562 }
563 rl_src = LoadValueWide(cu, rl_src, reg_class);
564
565 if (needs_range_check) {
566 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
567 FreeTemp(cu, reg_len);
568 }
569
570 StoreBaseDispWide(cu, reg_ptr, 0, rl_src.low_reg, rl_src.high_reg);
571
572 FreeTemp(cu, reg_ptr);
573 } else {
574 rl_src = LoadValue(cu, rl_src, reg_class);
575 if (needs_range_check) {
576 GenRegRegCheck(cu, kCondCs, rl_index.low_reg, reg_len, kThrowArrayBounds);
577 FreeTemp(cu, reg_len);
578 }
579 StoreBaseIndexed(cu, reg_ptr, rl_index.low_reg, rl_src.low_reg,
580 scale, size);
581 }
582}
583
584/*
585 * Generate array store
586 *
587 */
588void MipsCodegen::GenArrayObjPut(CompilationUnit* cu, int opt_flags, RegLocation rl_array,
589 RegLocation rl_index, RegLocation rl_src, int scale)
590{
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800591 int len_offset = mirror::Array::LengthOffset().Int32Value();
592 int data_offset = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value();
buzbeee6285f92012-12-06 15:57:46 -0800593
594 FlushAllRegs(cu); // Use explicit registers
595 LockCallTemps(cu);
596
597 int r_value = TargetReg(kArg0); // Register holding value
598 int r_array_class = TargetReg(kArg1); // Register holding array's Class
599 int r_array = TargetReg(kArg2); // Register holding array
600 int r_index = TargetReg(kArg3); // Register holding index into array
601
602 LoadValueDirectFixed(cu, rl_array, r_array); // Grab array
603 LoadValueDirectFixed(cu, rl_src, r_value); // Grab value
604 LoadValueDirectFixed(cu, rl_index, r_index); // Grab index
605
606 GenNullCheck(cu, rl_array.s_reg_low, r_array, opt_flags); // NPE?
607
608 // Store of null?
609 LIR* null_value_check = OpCmpImmBranch(cu, kCondEq, r_value, 0, NULL);
610
611 // Get the array's class.
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800612 LoadWordDisp(cu, r_array, mirror::Object::ClassOffset().Int32Value(), r_array_class);
buzbeee6285f92012-12-06 15:57:46 -0800613 CallRuntimeHelperRegReg(cu, ENTRYPOINT_OFFSET(pCanPutArrayElementFromCode), r_value,
614 r_array_class, true);
615 // Redo LoadValues in case they didn't survive the call.
616 LoadValueDirectFixed(cu, rl_array, r_array); // Reload array
617 LoadValueDirectFixed(cu, rl_index, r_index); // Reload index
618 LoadValueDirectFixed(cu, rl_src, r_value); // Reload value
619 r_array_class = INVALID_REG;
620
621 // Branch here if value to be stored == null
622 LIR* target = NewLIR0(cu, kPseudoTargetLabel);
623 null_value_check->target = target;
624
625 bool needs_range_check = (!(opt_flags & MIR_IGNORE_RANGE_CHECK));
626 int reg_len = INVALID_REG;
627 if (needs_range_check) {
628 reg_len = TargetReg(kArg1);
629 LoadWordDisp(cu, r_array, len_offset, reg_len); // Get len
630 }
631 /* r_ptr -> array data */
632 int r_ptr = AllocTemp(cu);
633 OpRegRegImm(cu, kOpAdd, r_ptr, r_array, data_offset);
634 if (needs_range_check) {
635 GenRegRegCheck(cu, kCondCs, r_index, reg_len, kThrowArrayBounds);
636 }
637 StoreBaseIndexed(cu, r_ptr, r_index, r_value, scale, kWord);
638 FreeTemp(cu, r_ptr);
639 FreeTemp(cu, r_index);
buzbee311ca162013-02-28 15:56:43 -0800640 if (!cu->mir_graph->IsConstantNullRef(rl_src)) {
buzbee6a791b22013-02-07 05:35:08 -0800641 MarkGCCard(cu, r_value, r_array);
642 }
buzbeee6285f92012-12-06 15:57:46 -0800643}
644
buzbeea5954be2013-02-07 10:41:40 -0800645void MipsCodegen::GenShiftImmOpLong(CompilationUnit* cu, Instruction::Code opcode, RegLocation rl_dest,
buzbee4ef3e452012-12-14 13:35:28 -0800646 RegLocation rl_src1, RegLocation rl_shift)
647{
648 // Default implementation is just to ignore the constant case.
buzbeea5954be2013-02-07 10:41:40 -0800649 GenShiftOpLong(cu, opcode, rl_dest, rl_src1, rl_shift);
buzbee4ef3e452012-12-14 13:35:28 -0800650}
651
buzbeea5954be2013-02-07 10:41:40 -0800652void MipsCodegen::GenArithImmOpLong(CompilationUnit* cu, Instruction::Code opcode,
buzbee4ef3e452012-12-14 13:35:28 -0800653 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2)
654{
655 // Default - bail to non-const handler.
buzbeea5954be2013-02-07 10:41:40 -0800656 GenArithOpLong(cu, opcode, rl_dest, rl_src1, rl_src2);
buzbee4ef3e452012-12-14 13:35:28 -0800657}
658
buzbeeefc63692012-11-14 16:31:52 -0800659} // namespace art