blob: 297a5d92280dfdf6505f3443db47513a5fe2cd14 [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"
21#include "../codegen_util.h"
22#include "../ralloc_util.h"
buzbeeefc63692012-11-14 16:31:52 -080023
24namespace art {
25
26/*
27 * Compare two 64-bit values
28 * x = y return 0
29 * x < y return -1
30 * x > y return 1
31 *
32 * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
33 * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
34 * subu res, t0, t1 # res = -1:1:0 for [ < > = ]
35 * bnez res, finish
36 * sltu t0, x.lo, y.lo
37 * sgtu r1, x.lo, y.lo
38 * subu res, t0, t1
39 * finish:
40 *
41 */
42void genCmpLong(CompilationUnit* cUnit, RegLocation rlDest,
43 RegLocation rlSrc1, RegLocation rlSrc2)
44{
45 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
46 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
47 int t0 = oatAllocTemp(cUnit);
48 int t1 = oatAllocTemp(cUnit);
49 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
50 newLIR3(cUnit, kMipsSlt, t0, rlSrc1.highReg, rlSrc2.highReg);
51 newLIR3(cUnit, kMipsSlt, t1, rlSrc2.highReg, rlSrc1.highReg);
52 newLIR3(cUnit, kMipsSubu, rlResult.lowReg, t1, t0);
53 LIR* branch = opCmpImmBranch(cUnit, kCondNe, rlResult.lowReg, 0, NULL);
54 newLIR3(cUnit, kMipsSltu, t0, rlSrc1.lowReg, rlSrc2.lowReg);
55 newLIR3(cUnit, kMipsSltu, t1, rlSrc2.lowReg, rlSrc1.lowReg);
56 newLIR3(cUnit, kMipsSubu, rlResult.lowReg, t1, t0);
57 oatFreeTemp(cUnit, t0);
58 oatFreeTemp(cUnit, t1);
59 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbeecbd6d442012-11-17 14:11:25 -080060 branch->target = target;
buzbeeefc63692012-11-14 16:31:52 -080061 storeValue(cUnit, rlDest, rlResult);
62}
63
64LIR* opCmpBranch(CompilationUnit* cUnit, ConditionCode cond, int src1,
65 int src2, LIR* target)
66{
67 LIR* branch;
68 MipsOpCode sltOp;
69 MipsOpCode brOp;
70 bool cmpZero = false;
71 bool swapped = false;
72 switch (cond) {
73 case kCondEq:
74 brOp = kMipsBeq;
75 cmpZero = true;
76 break;
77 case kCondNe:
78 brOp = kMipsBne;
79 cmpZero = true;
80 break;
81 case kCondCc:
82 sltOp = kMipsSltu;
83 brOp = kMipsBnez;
84 break;
85 case kCondCs:
86 sltOp = kMipsSltu;
87 brOp = kMipsBeqz;
88 break;
89 case kCondGe:
90 sltOp = kMipsSlt;
91 brOp = kMipsBeqz;
92 break;
93 case kCondGt:
94 sltOp = kMipsSlt;
95 brOp = kMipsBnez;
96 swapped = true;
97 break;
98 case kCondLe:
99 sltOp = kMipsSlt;
100 brOp = kMipsBeqz;
101 swapped = true;
102 break;
103 case kCondLt:
104 sltOp = kMipsSlt;
105 brOp = kMipsBnez;
106 break;
107 case kCondHi: // Gtu
108 sltOp = kMipsSltu;
109 brOp = kMipsBnez;
110 swapped = true;
111 break;
112 default:
buzbeecbd6d442012-11-17 14:11:25 -0800113 LOG(FATAL) << "No support for ConditionCode: " << cond;
buzbeeefc63692012-11-14 16:31:52 -0800114 return NULL;
115 }
116 if (cmpZero) {
117 branch = newLIR2(cUnit, brOp, src1, src2);
118 } else {
119 int tReg = oatAllocTemp(cUnit);
120 if (swapped) {
121 newLIR3(cUnit, sltOp, tReg, src2, src1);
122 } else {
123 newLIR3(cUnit, sltOp, tReg, src1, src2);
124 }
125 branch = newLIR1(cUnit, brOp, tReg);
126 oatFreeTemp(cUnit, tReg);
127 }
128 branch->target = target;
129 return branch;
130}
131
132LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg,
133 int checkValue, LIR* target)
134{
135 LIR* branch;
136 if (checkValue != 0) {
137 // TUNING: handle s16 & kCondLt/Mi case using slti
138 int tReg = oatAllocTemp(cUnit);
139 loadConstant(cUnit, tReg, checkValue);
140 branch = opCmpBranch(cUnit, cond, reg, tReg, target);
141 oatFreeTemp(cUnit, tReg);
142 return branch;
143 }
144 MipsOpCode opc;
145 switch (cond) {
146 case kCondEq: opc = kMipsBeqz; break;
147 case kCondGe: opc = kMipsBgez; break;
148 case kCondGt: opc = kMipsBgtz; break;
149 case kCondLe: opc = kMipsBlez; break;
150 //case KCondMi:
151 case kCondLt: opc = kMipsBltz; break;
152 case kCondNe: opc = kMipsBnez; break;
153 default:
154 // Tuning: use slti when applicable
155 int tReg = oatAllocTemp(cUnit);
156 loadConstant(cUnit, tReg, checkValue);
157 branch = opCmpBranch(cUnit, cond, reg, tReg, target);
158 oatFreeTemp(cUnit, tReg);
159 return branch;
160 }
161 branch = newLIR1(cUnit, opc, reg);
162 branch->target = target;
163 return branch;
164}
165
166LIR* opRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
167{
168#ifdef __mips_hard_float
169 if (MIPS_FPREG(rDest) || MIPS_FPREG(rSrc))
170 return fpRegCopy(cUnit, rDest, rSrc);
171#endif
172 LIR* res = rawLIR(cUnit, cUnit->currentDalvikOffset, kMipsMove,
173 rDest, rSrc);
174 if (!(cUnit->disableOpt & (1 << kSafeOptimizations)) && rDest == rSrc) {
175 res->flags.isNop = true;
176 }
177 return res;
178}
179
180LIR* opRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
181{
182 LIR *res = opRegCopyNoInsert(cUnit, rDest, rSrc);
buzbeecbd6d442012-11-17 14:11:25 -0800183 oatAppendLIR(cUnit, res);
buzbeeefc63692012-11-14 16:31:52 -0800184 return res;
185}
186
187void opRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
188 int srcLo, int srcHi)
189{
190#ifdef __mips_hard_float
191 bool destFP = MIPS_FPREG(destLo) && MIPS_FPREG(destHi);
192 bool srcFP = MIPS_FPREG(srcLo) && MIPS_FPREG(srcHi);
193 assert(MIPS_FPREG(srcLo) == MIPS_FPREG(srcHi));
194 assert(MIPS_FPREG(destLo) == MIPS_FPREG(destHi));
195 if (destFP) {
196 if (srcFP) {
197 opRegCopy(cUnit, s2d(destLo, destHi), s2d(srcLo, srcHi));
198 } else {
199 /* note the operands are swapped for the mtc1 instr */
200 newLIR2(cUnit, kMipsMtc1, srcLo, destLo);
201 newLIR2(cUnit, kMipsMtc1, srcHi, destHi);
202 }
203 } else {
204 if (srcFP) {
205 newLIR2(cUnit, kMipsMfc1, destLo, srcLo);
206 newLIR2(cUnit, kMipsMfc1, destHi, srcHi);
207 } else {
208 // Handle overlap
209 if (srcHi == destLo) {
210 opRegCopy(cUnit, destHi, srcHi);
211 opRegCopy(cUnit, destLo, srcLo);
212 } else {
213 opRegCopy(cUnit, destLo, srcLo);
214 opRegCopy(cUnit, destHi, srcHi);
215 }
216 }
217 }
218#else
219 // Handle overlap
220 if (srcHi == destLo) {
221 opRegCopy(cUnit, destHi, srcHi);
222 opRegCopy(cUnit, destLo, srcLo);
223 } else {
224 opRegCopy(cUnit, destLo, srcLo);
225 opRegCopy(cUnit, destHi, srcHi);
226 }
227#endif
228}
229
230void genFusedLongCmpBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir)
231{
232 UNIMPLEMENTED(FATAL) << "Need codegen for fused long cmp branch";
233}
234
235LIR* genRegMemCheck(CompilationUnit* cUnit, ConditionCode cCode,
236 int reg1, int base, int offset, ThrowKind kind)
237{
238 LOG(FATAL) << "Unexpected use of genRegMemCheck for Arm";
239 return NULL;
240}
241
242RegLocation genDivRem(CompilationUnit* cUnit, RegLocation rlDest, int reg1, int reg2, bool isDiv)
243{
244 newLIR4(cUnit, kMipsDiv, r_HI, r_LO, reg1, reg2);
245 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
246 if (isDiv) {
247 newLIR2(cUnit, kMipsMflo, rlResult.lowReg, r_LO);
248 } else {
249 newLIR2(cUnit, kMipsMfhi, rlResult.lowReg, r_HI);
250 }
251 return rlResult;
252}
253
254RegLocation genDivRemLit(CompilationUnit* cUnit, RegLocation rlDest, int reg1, int lit, bool isDiv)
255{
256 int tReg = oatAllocTemp(cUnit);
257 newLIR3(cUnit, kMipsAddiu, tReg, r_ZERO, lit);
258 newLIR4(cUnit, kMipsDiv, r_HI, r_LO, reg1, tReg);
259 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
260 if (isDiv) {
261 newLIR2(cUnit, kMipsMflo, rlResult.lowReg, r_LO);
262 } else {
263 newLIR2(cUnit, kMipsMfhi, rlResult.lowReg, r_HI);
264 }
265 oatFreeTemp(cUnit, tReg);
266 return rlResult;
267}
268
269void opLea(CompilationUnit* cUnit, int rBase, int reg1, int reg2, int scale, int offset)
270{
271 LOG(FATAL) << "Unexpected use of opLea for Arm";
272}
273
274void opTlsCmp(CompilationUnit* cUnit, int offset, int val)
275{
276 LOG(FATAL) << "Unexpected use of opTlsCmp for Arm";
277}
278
279bool genInlinedCas32(CompilationUnit* cUnit, CallInfo* info, bool need_write_barrier) {
280 DCHECK_NE(cUnit->instructionSet, kThumb2);
281 return false;
282}
283
284bool genInlinedSqrt(CompilationUnit* cUnit, CallInfo* info) {
285 DCHECK_NE(cUnit->instructionSet, kThumb2);
286 return false;
287}
288
289LIR* opPcRelLoad(CompilationUnit* cUnit, int reg, LIR* target) {
290 LOG(FATAL) << "Unexpected use of opPcRelLoad for Mips";
291 return NULL;
292}
293
294LIR* opVldm(CompilationUnit* cUnit, int rBase, int count)
295{
296 LOG(FATAL) << "Unexpected use of opVldm for Mips";
297 return NULL;
298}
299
300LIR* opVstm(CompilationUnit* cUnit, int rBase, int count)
301{
302 LOG(FATAL) << "Unexpected use of opVstm for Mips";
303 return NULL;
304}
305
306void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc,
307 RegLocation rlResult, int lit,
308 int firstBit, int secondBit)
309{
310 int tReg = oatAllocTemp(cUnit);
311 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, secondBit - firstBit);
312 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, tReg);
313 oatFreeTemp(cUnit, tReg);
314 if (firstBit != 0) {
315 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
316 }
317}
318
319void genDivZeroCheck(CompilationUnit* cUnit, int regLo, int regHi)
320{
321 int tReg = oatAllocTemp(cUnit);
322 opRegRegReg(cUnit, kOpOr, tReg, regLo, regHi);
323 genImmedCheck(cUnit, kCondEq, tReg, 0, kThrowDivZero);
324 oatFreeTemp(cUnit, tReg);
325}
326
327// Test suspend flag, return target of taken suspend branch
328LIR* opTestSuspend(CompilationUnit* cUnit, LIR* target)
329{
330 opRegImm(cUnit, kOpSub, rMIPS_SUSPEND, 1);
331 return opCmpImmBranch(cUnit, (target == NULL) ? kCondEq : kCondNe, rMIPS_SUSPEND, 0, target);
332}
333
334// Decrement register and branch on condition
335LIR* opDecAndBranch(CompilationUnit* cUnit, ConditionCode cCode, int reg, LIR* target)
336{
337 opRegImm(cUnit, kOpSub, reg, 1);
338 return opCmpImmBranch(cUnit, cCode, reg, 0, target);
339}
340
341bool smallLiteralDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode,
342 RegLocation rlSrc, RegLocation rlDest, int lit)
343{
344 LOG(FATAL) << "Unexpected use of smallLiteralDive in Mips";
345 return false;
346}
347
348LIR* opIT(CompilationUnit* cUnit, ArmConditionCode cond, const char* guide)
349{
350 LOG(FATAL) << "Unexpected use of opIT in Mips";
351 return NULL;
352}
353
354bool genAddLong(CompilationUnit* cUnit, RegLocation rlDest,
355 RegLocation rlSrc1, RegLocation rlSrc2)
356{
357 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
358 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
359 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
360 /*
361 * [v1 v0] = [a1 a0] + [a3 a2];
362 * addu v0,a2,a0
363 * addu t1,a3,a1
364 * sltu v1,v0,a2
365 * addu v1,v1,t1
366 */
367
368 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc2.lowReg, rlSrc1.lowReg);
369 int tReg = oatAllocTemp(cUnit);
370 opRegRegReg(cUnit, kOpAdd, tReg, rlSrc2.highReg, rlSrc1.highReg);
371 newLIR3(cUnit, kMipsSltu, rlResult.highReg, rlResult.lowReg, rlSrc2.lowReg);
372 opRegRegReg(cUnit, kOpAdd, rlResult.highReg, rlResult.highReg, tReg);
373 oatFreeTemp(cUnit, tReg);
374 storeValueWide(cUnit, rlDest, rlResult);
375 return false;
376}
377
378bool genSubLong(CompilationUnit* cUnit, RegLocation rlDest,
379 RegLocation rlSrc1, RegLocation rlSrc2)
380{
381 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
382 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
383 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
384 /*
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
392 int tReg = oatAllocTemp(cUnit);
393 newLIR3(cUnit, kMipsSltu, tReg, rlSrc1.lowReg, rlSrc2.lowReg);
394 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
395 opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlSrc1.highReg, rlSrc2.highReg);
396 opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlResult.highReg, tReg);
397 oatFreeTemp(cUnit, tReg);
398 storeValueWide(cUnit, rlDest, rlResult);
399 return false;
400}
401
402bool genNegLong(CompilationUnit* cUnit, RegLocation rlDest,
403 RegLocation rlSrc)
404{
405 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
406 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
407 /*
408 * [v1 v0] = -[a1 a0]
409 * negu v0,a0
410 * negu v1,a1
411 * sltu t1,r_zero
412 * subu v1,v1,t1
413 */
414
415 opRegReg(cUnit, kOpNeg, rlResult.lowReg, rlSrc.lowReg);
416 opRegReg(cUnit, kOpNeg, rlResult.highReg, rlSrc.highReg);
417 int tReg = oatAllocTemp(cUnit);
418 newLIR3(cUnit, kMipsSltu, tReg, r_ZERO, rlResult.lowReg);
419 opRegRegReg(cUnit, kOpSub, rlResult.highReg, rlResult.highReg, tReg);
420 oatFreeTemp(cUnit, tReg);
421 storeValueWide(cUnit, rlDest, rlResult);
422 return false;
423}
424
425bool genAndLong(CompilationUnit* cUnit, RegLocation rlDest,
426 RegLocation rlSrc1, RegLocation rlSrc2)
427{
428 LOG(FATAL) << "Unexpected use of genAndLong for Mips";
429 return false;
430}
431
432bool genOrLong(CompilationUnit* cUnit, RegLocation rlDest,
433 RegLocation rlSrc1, RegLocation rlSrc2)
434{
435 LOG(FATAL) << "Unexpected use of genOrLong for Mips";
436 return false;
437}
438
439bool genXorLong(CompilationUnit* cUnit, RegLocation rlDest,
440 RegLocation rlSrc1, RegLocation rlSrc2)
441{
442 LOG(FATAL) << "Unexpected use of genXorLong for Mips";
443 return false;
444}
445
446} // namespace art