blob: 1ea94c92b17e1b40a78d37c9f8347b53f3929678 [file] [log] [blame]
buzbeee88dfbf2012-03-05 11:19:57 -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/*
18 * This file contains codegen for the Mips ISA and is intended to be
19 * includes by:
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 */
24
25namespace art {
26
27/*
28 * The lack of pc-relative loads on Mips presents somewhat of a challenge
29 * for our PIC switch table strategy. To materialize the current location
30 * we'll do a dummy JAL and reference our tables using r_RA as the
31 * base register. Note that r_RA will be used both as the base to
32 * locate the switch table data and as the reference base for the switch
33 * target offsets stored in the table. We'll use a special pseudo-instruction
34 * to represent the jal and trigger the construction of the
35 * switch table offsets (which will happen after final assembly and all
36 * labels are fixed).
37 *
38 * The test loop will look something like:
39 *
40 * ori rEnd, r_ZERO, #tableSize ; size in bytes
41 * jal BaseLabel ; stores "return address" (BaseLabel) in r_RA
42 * nop ; opportunistically fill
43 * BaseLabel:
44 * addiu rBase, r_RA, <table> - <BaseLabel> ; table relative to BaseLabel
45 addu rEnd, rEnd, rBase ; end of table
46 * lw rVal, [rSP, vRegOff] ; Test Value
47 * loop:
48 * beq rBase, rEnd, done
49 * lw rKey, 0(rBase)
50 * addu rBase, 8
51 * bne rVal, rKey, loop
52 * lw rDisp, -4(rBase)
53 * addu r_RA, rDisp
54 * jr r_RA
55 * done:
56 *
57 */
58void genSparseSwitch(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
59{
60 UNIMPLEMENTED(WARNING) << "genSparseSwitch";
61 return NULL;
62#if 0
63 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
64 if (cUnit->printMe) {
65 dumpSparseSwitchTable(table);
66 }
67 // Add the table to the list - we'll process it later
68 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
69 true, kAllocData);
70 tabRec->table = table;
71 tabRec->vaddr = mir->offset;
72 int elements = table[1];
73 tabRec->targets = (LIR* *)oatNew(cUnit, elements * sizeof(LIR*), true,
74 kAllocLIR);
75 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
76
77 // The table is composed of 8-byte key/disp pairs
78 int byteSize = elements * 8;
79
80 int sizeHi = byteSize >> 16;
81 int sizeLo = byteSize & 0xffff;
82
83 int rEnd = oatAllocTemp(cUnit);
84 if (sizeHi) {
85 newLIR2(cUnit, kMipsLui, rEnd, sizeHi);
86 }
87 // Must prevent code motion for the curr pc pair
88 genBarrier(cUnit); // Scheduling barrier
89 newLIR0(cUnit, kMipsCurrPC); // Really a jal to .+8
90 // Now, fill the branch delay slot
91 if (sizeHi) {
92 newLIR3(cUnit, kMipsOri, rEnd, rEnd, sizeLo);
93 } else {
94 newLIR3(cUnit, kMipsOri, rEnd, r_ZERO, sizeLo);
95 }
96 genBarrier(cUnit); // Scheduling barrier
97
98 // Construct BaseLabel and set up table base register
99 LIR* baseLabel = newLIR0(cUnit, kPseudoTargetLabel);
100 // Remember base label so offsets can be computed later
101 tabRec->anchor = baseLabel;
102 int rBase = oatAllocTemp(cUnit);
103 newLIR4(cUnit, kMipsDelta, rBase, 0, (intptr_t)baseLabel, (intptr_t)tabRec);
104 opRegRegReg(cUnit, kOpAdd, rEnd, rEnd, rBase);
105
106 // Grab switch test value
107 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
108
109 // Test loop
110 int rKey = oatAllocTemp(cUnit);
111 LIR* loopLabel = newLIR0(cUnit, kPseudoTargetLabel);
112 LIR* exitBranch = opCmpBranch(cUnit , kCondEq, rBase, rEnd, NULL);
113 loadWordDisp(cUnit, rBase, 0, rKey);
114 opRegImm(cUnit, kOpAdd, rBase, 8);
115 opCmpBranch(cUnit, kCondNe, rlSrc.lowReg, rKey, loopLabel);
116 int rDisp = oatAllocTemp(cUnit);
117 loadWordDisp(cUnit, rBase, -4, rDisp);
118 opRegRegReg(cUnit, kOpAdd, r_RA, r_RA, rDisp);
119 opReg(cUnit, kOpBx, r_RA);
120
121 // Loop exit
122 LIR* exitLabel = newLIR0(cUnit, kPseudoTargetLabel);
123 exitBranch->target = exitLabel;
124#endif
125}
126
127/*
128 * Code pattern will look something like:
129 *
130 * lw rVal
131 * jal BaseLabel ; stores "return address" (BaseLabel) in r_RA
132 * nop ; opportunistically fill
133 * [subiu rVal, bias] ; Remove bias if lowVal != 0
134 * bound check -> done
135 * lw rDisp, [r_RA, rVal]
136 * addu r_RA, rDisp
137 * jr r_RA
138 * done:
139 */
140void genPackedSwitch(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
141{
142 UNIMPLEMENTED(WARNING) << "genPackedSwitch";
143#if 0
144 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
145 if (cUnit->printMe) {
146 dumpPackedSwitchTable(table);
147 }
148 // Add the table to the list - we'll process it later
149 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
150 true, kAllocData);
151 tabRec->table = table;
152 tabRec->vaddr = mir->offset;
153 int size = table[1];
154 tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true,
155 kAllocLIR);
156 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
157
158 // Get the switch value
159 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
160
161 // Prepare the bias. If too big, handle 1st stage here
162 int lowKey = s4FromSwitchData(&table[2]);
163 bool largeBias = false;
164 int rKey;
165 if (lowKey == 0) {
166 rKey = rlSrc.lowReg;
167 } else if ((lowKey & 0xffff) != lowKey) {
168 rKey = oatAllocTemp(cUnit);
169 loadConstant(cUnit, rKey, lowKey);
170 largeBias = true;
171 } else {
172 rKey = oatAllocTemp(cUnit);
173 }
174
175 // Must prevent code motion for the curr pc pair
176 genBarrier(cUnit);
177 newLIR0(cUnit, kMipsCurrPC); // Really a jal to .+8
178 // Now, fill the branch delay slot with bias strip
179 if (lowKey == 0) {
180 newLIR0(cUnit, kMipsNop);
181 } else {
182 if (largeBias) {
183 opRegRegReg(cUnit, kOpSub, rKey, rlSrc.lowReg, rKey);
184 } else {
185 opRegRegImm(cUnit, kOpSub, rKey, rlSrc.lowReg, lowKey);
186 }
187 }
188 genBarrier(cUnit); // Scheduling barrier
189
190 // Construct BaseLabel and set up table base register
191 LIR* baseLabel = newLIR0(cUnit, kPseudoTargetLabel);
192 // Remember base label so offsets can be computed later
193 tabRec->anchor = baseLabel;
194
195 // Bounds check - if < 0 or >= size continue following switch
196 LIR* branchOver = opCmpImmBranch(cUnit, kCondHi, rKey, size-1, NULL);
197
198 // Materialize the table base pointer
199 int rBase = oatAllocTemp(cUnit);
200 newLIR4(cUnit, kMipsDelta, rBase, 0, (intptr_t)baseLabel, (intptr_t)tabRec);
201
202 // Load the displacement from the switch table
203 int rDisp = oatAllocTemp(cUnit);
204 loadBaseIndexed(cUnit, rBase, rKey, rDisp, 2, kWord);
205
206 // Add to r_AP and go
207 opRegRegReg(cUnit, kOpAdd, r_RA, r_RA, rDisp);
208 opReg(cUnit, kOpBx, r_RA);
209
210 /* branchOver target here */
211 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
212 branchOver->target = (LIR*)target;
213#endif
214}
215
216/*
217 * Array data table format:
218 * ushort ident = 0x0300 magic value
219 * ushort width width of each element in the table
220 * uint size number of elements in the table
221 * ubyte data[size*width] table of data values (may contain a single-byte
222 * padding at the end)
223 *
224 * Total size is 4+(width * size + 1)/2 16-bit code units.
225 */
226void genFillArrayData(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
227{
228 UNIMPLEMENTED(WARNING) << "genFillArrayData";
229#if 0
230 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
231 // Add the table to the list - we'll process it later
232 FillArrayData *tabRec = (FillArrayData *)
233 oatNew(cUnit, sizeof(FillArrayData), true, kAllocData);
234 tabRec->table = table;
235 tabRec->vaddr = mir->offset;
236 u2 width = tabRec->table[1];
237 u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
238 tabRec->size = (size * width) + 8;
239
240 oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec);
241
242 // Making a call - use explicit registers
243 oatFlushAllRegs(cUnit); /* Everything to home location */
244 oatLockCallTemps(cUnit);
245 loadValueDirectFixed(cUnit, rlSrc, rARG0);
246
247 // Must prevent code motion for the curr pc pair
248 genBarrier(cUnit);
249 newLIR0(cUnit, kMipsCurrPC); // Really a jal to .+8
250 // Now, fill the branch delay slot with the helper load
251 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
252 pHandleFillArrayDataFromCode));
253 genBarrier(cUnit); // Scheduling barrier
254
255 // Construct BaseLabel and set up table base register
256 LIR* baseLabel = newLIR0(cUnit, kPseudoTargetLabel);
257
258 // Materialize a pointer to the fill data image
259 newLIR4(cUnit, kMipsDelta, rARG1, 0, (intptr_t)baseLabel, (intptr_t)tabRec);
260
261 // And go...
262 callRuntimeHelper(cUnit, rTgt); // ( array*, fill_data* )
263}
264
265void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
266{
267 RegLocation rlResult;
268 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
269 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
270 opRegRegImm(cUnit, kOpAdd, rlResult.lowReg,
271 rlSrc.lowReg, 0x80000000);
272 storeValue(cUnit, rlDest, rlResult);
273#endif
274}
275
276void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
277{
278 UNIMPLEMENTED(WARNING) << "genNegDouble";
279#if 0
280 RegLocation rlResult;
281 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
282 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
283 opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg,
284 0x80000000);
285 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
286 storeValueWide(cUnit, rlDest, rlResult);
287#endif
288}
289
290/*
291 * TODO: implement fast path to short-circuit thin-lock case
292 */
293void genMonitorEnter(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
294{
295 UNIMPLEMENTED(WARNING) << "genMonitorEnter";
296#if 0
297 oatFlushAllRegs(cUnit);
298 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get obj
299 oatLockCallTemps(cUnit); // Prepare for explicit register usage
300 genNullCheck(cUnit, rlSrc.sRegLow, rARG0, mir);
301 // Go expensive route - artLockObjectFromCode(self, obj);
302 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pLockObjectFromCode));
303 callRuntimeHelper(cUnit, rTgt);
304#endif
305}
306
307/*
308 * TODO: implement fast path to short-circuit thin-lock case
309 */
310void genMonitorExit(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
311{
312 UNIMPLEMENTED(WARNING) << "genMonitor";
313#if 0
314 oatFlushAllRegs(cUnit);
315 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get obj
316 oatLockCallTemps(cUnit); // Prepare for explicit register usage
317 genNullCheck(cUnit, rlSrc.sRegLow, rARG0, mir);
318 // Go expensive route - UnlockObjectFromCode(obj);
319 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pUnlockObjectFromCode));
320 callRuntimeHelper(cUnit, rTgt);
321#endif
322}
323
324/*
325 * Compare two 64-bit values
326 * x = y return 0
327 * x < y return -1
328 * x > y return 1
329 *
330 * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
331 * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
332 * subu res, t0, t1 # res = -1:1:0 for [ < > = ]
333 * bnez res, finish
334 * sltu t0, x.lo, y.lo
335 * sgtu r1, x.lo, y.lo
336 * subu res, t0, t1
337 * finish:
338 *
339 */
340void genCmpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
341 RegLocation rlSrc1, RegLocation rlSrc2)
342{
343 UNIMPLEMENTED(WARNING) << "genCmpLong";
344#if 0
345 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
346 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
347 int t0 = oatAllocTemp(cUnit);
348 int t1 = oatAllocTemp(cUnit);
349 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
350 newLIR3(cUnit, kMipsSlt, t0, rlSrc1.highReg, rlSrc2.highReg);
351 newLIR3(cUnit, kMipsSlt, t1, rlSrc2.highReg, rlSrc1.highReg);
352 newLIR3(cUnit, kMipsSubu, rlResult.lowReg, t1, t0);
353 LIR* branch = opCmpImmBranch(cUnit, kCondNe, rlResult.lowReg, 0, NULL);
354 newLIR3(cUnit, kMipsSltu, t0, rlSrc1.lowReg, rlSrc2.lowReg);
355 newLIR3(cUnit, kMipsSltu, t1, rlSrc2.lowReg, rlSrc1.lowReg);
356 newLIR3(cUnit, kMipsSubu, rlResult.lowReg, t1, t0);
357 oatFreeTemp(cUnit, t0);
358 oatFreeTemp(cUnit, t1);
359 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
360 branch->target = (LIR*)target;
361 storeValue(cUnit, rlDest, rlResult);
362#endif
363}
364
365LIR* opCmpBranch(CompilationUnit* cUnit, ConditionCode cond, int src1,
366 int src2, LIR* target)
367{
368 UNIMPLEMENTED(WARNING) << "opCmpBranch";
369 return NULL;
370#if 0
371 LIR* branch;
372 MipsOpCode sltOp;
373 MipsOpCode brOp;
374 bool cmpZero = false;
375 bool swapped = false;
376 switch(cond) {
377 case kCondEq:
378 brOp = kMipsBeq;
379 cmpZero = true;
380 break;
381 case kCondNe:
382 brOp = kMipsBne;
383 cmpZero = true;
384 break;
385 case kCondCc:
386 sltOp = kMipsSltu;
387 brOp = kMipsBnez;
388 break;
389 case kCondCs:
390 sltOp = kMipsSltu;
391 brOp = kMipsBeqz;
392 break;
393 case kCondGe:
394 sltOp = kMipsSlt;
395 brOp = kMipsBeqz;
396 break;
397 case kCondGt:
398 sltOp = kMipsSlt;
399 brOp = kMipsBnez;
400 swapped = true;
401 break;
402 case kCondLe:
403 sltOp = kMipsSlt;
404 brOp = kMipsBeqz;
405 swapped = true;
406 break;
407 case kCondLt:
408 sltOp = kMipsSlt;
409 brOp = kMipsBnez;
410 break;
411 case kCondHi: // Gtu
412 sltOp = kMipsSltu;
413 brOp = kMipsBnez;
414 swapped = true;
415 break;
416 default:
417 LOG(FATAL) << "No support for ConditionCode: " << (int) cond;
418 return NULL;
419 }
420 if (cmpZero) {
421 branch = newLIR2(cUnit, brOp, src1, src2);
422 } else {
423 int tReg = oatAllocTemp(cUnit);
424 if (swapped) {
425 newLIR3(cUnit, sltOp, tReg, src2, src1);
426 } else {
427 newLIR3(cUnit, sltOp, tReg, src1, src2);
428 }
429 branch = newLIR1(cUnit, brOp, tReg);
430 oatFreeTemp(cUnit, tReg);
431 }
432 branch->target = target;
433 return branch;
434#endif
435}
436
437LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg,
438 int checkValue, LIR* target)
439{
440 UNIMPLEMENTED(WARNING) >> "opCmpImmBranch";
441 return NULL;
442#if 0
443 LIR* branch;
444 if (checkValue != 0) {
445 // TUNING: handle s16 & kCondLt/Mi case using slti
446 int tReg = oatAllocTemp(cUnit);
447 loadConstant(cUnit, tReg, checkValue);
448 branch = opCmpBranch(cUnit, cond, reg, tReg, target);
449 oatFreeTemp(cUnit, tReg);
450 return branch;
451 }
452 MipsOpCode opc;
453 switch(cond) {
454 case kCondEq: opc = kMipsBeqz; break;
455 case kCondGe: opc = kMipsBgez; break;
456 case kCondGt: opc = kMipsBgtz; break;
457 case kCondLe: opc = kMipsBlez; break;
458 //case KCondMi:
459 case kCondLt: opc = kMipsBltz; break;
460 case kCondNe: opc = kMipsBnez; break;
461 default:
462 // Tuning: use slti when applicable
463 int tReg = oatAllocTemp(cUnit);
464 loadConstant(cUnit, tReg, checkValue);
465 branch = opCmpBranch(cUnit, cond, reg, tReg, target);
466 oatFreeTemp(cUnit, tReg);
467 return branch;
468 }
469 branch = newLIR1(cUnit, opc, reg);
470 branch->target = target;
471 return branch;
472#endif
473}
474
475LIR* opRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
476{
477 UNIMPLEMENTED(WARNING) << "opRegCopyNoInsert";
478 return NULL;
479#if 0
480 if (FPREG(rDest) || FPREG(rSrc))
481 return fpRegCopy(cUnit, rDest, rSrc);
482 LIR* res = rawLIR(cUnit, cUnit->currentDalvikOffset, kMipsMove,
483 rDest, rSrc);
484 if (rDest == rSrc) {
485 res->flags.isNop = true;
486 }
487 return res;
488#endif
489}
490
491LIR* opRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
492{
493 LIR *res = opRegCopyNoInsert(cUnit, rDest, rSrc);
494 oatAppendLIR(cUnit, (LIR*)res);
495 return res;
496}
497
498void opRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
499 int srcLo, int srcHi)
500{
501 UNIMPLEMENTED(WARNING) << "opRegCopyWide";
502#if 0
503 bool destFP = FPREG(destLo) && FPREG(destHi);
504 bool srcFP = FPREG(srcLo) && FPREG(srcHi);
505 assert(FPREG(srcLo) == FPREG(srcHi));
506 assert(FPREG(destLo) == FPREG(destHi));
507 if (destFP) {
508 if (srcFP) {
509 opRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
510 } else {
511 /* note the operands are swapped for the mtc1 instr */
512 newLIR2(cUnit, kMipsMtc1, srcLo, destLo);
513 newLIR2(cUnit, kMipsMtc1, srcHi, destHi);
514 }
515 } else {
516 if (srcFP) {
517 newLIR2(cUnit, kMipsMfc1, destLo, srcLo);
518 newLIR2(cUnit, kMipsMfc1, destHi, srcHi);
519 } else {
520 // Handle overlap
521 if (srcHi == destLo) {
522 opRegCopy(cUnit, destHi, srcHi);
523 opRegCopy(cUnit, destLo, srcLo);
524 } else {
525 opRegCopy(cUnit, destLo, srcLo);
526 opRegCopy(cUnit, destHi, srcHi);
527 }
528 }
529 }
530 // Handle overlap
531 if (srcHi == destLo) {
532 opRegCopy(cUnit, destHi, srcHi);
533 opRegCopy(cUnit, destLo, srcLo);
534 } else {
535 opRegCopy(cUnit, destLo, srcLo);
536 opRegCopy(cUnit, destHi, srcHi);
537 }
538#endif
539}
540
541} // namespace art