blob: 880169272e7e81dcc2117792dd7442e31a278582 [file] [log] [blame]
buzbeee3acd072012-02-25 17:03:10 -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// FIXME: need the following:
28void genSuspendTest(CompilationUnit* cUnit, MIR* mir) {}
29void genMonitorEnter(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) {}
30void genMonitorExit(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) {}
31void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) {}
32void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
33 RegLocation rlSrc) {}
34void genNewInstance(CompilationUnit* cUnit, MIR* mir,
35 RegLocation rlDest) {}
36void genThrow(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) {}
37void genConstString(CompilationUnit* cUnit, MIR* mir,
38 RegLocation rlDest, RegLocation rlSrc) {}
39void genConstClass(CompilationUnit* cUnit, MIR* mir,
40 RegLocation rlDest, RegLocation rlSrc) {}
41void genArrayGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
42 RegLocation rlArray, RegLocation rlIndex,
43 RegLocation rlDest, int scale) {}
44void genArrayPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
45 RegLocation rlArray, RegLocation rlIndex,
46 RegLocation rlSrc, int scale) {}
47void genArrayObjPut(CompilationUnit* cUnit, MIR* mir,
48 RegLocation rlArray, RegLocation rlIndex,
49 RegLocation rlSrc, int scale) {}
50void genIPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
51 RegLocation rlSrc, RegLocation rlObj,
52 bool isLongOrDouble, bool isObject) {}
53bool genArithOpInt(CompilationUnit* cUnit, MIR* mir,
54 RegLocation rlDest, RegLocation rlSrc1,
55 RegLocation rlSrc2) { return 0; }
56bool genArithOpLong(CompilationUnit* cUnit, MIR* mir,
57 RegLocation rlDest, RegLocation rlSrc1,
58 RegLocation rlSrc2) { return 0; }
59bool genShiftOpLong(CompilationUnit* cUnit, MIR* mir,
60 RegLocation rlDest, RegLocation rlSrc1,
61 RegLocation rlShift) { return 0; }
62bool genArithOpIntLit(CompilationUnit* cUnit, MIR* mir,
63 RegLocation rlDest, RegLocation rlSrc,
64 int lit) { return 0; }
buzbee31a4a6f2012-02-28 15:36:15 -080065void oatArchDump(void) {};
66void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset) {};
buzbeee3acd072012-02-25 17:03:10 -080067
68
69
70
buzbee31a4a6f2012-02-28 15:36:15 -080071STATIC bool genConversionCall(CompilationUnit* cUnit, MIR* mir, int funcOffset,
72 int srcSize, int tgtSize)
73{
74 UNIMPLEMENTED(FATAL) << "Need Mips implementation";
75 return 0;
76#if 0
77 /*
78 * Don't optimize the register usage since it calls out to support
79 * functions
80 */
81 RegLocation rlSrc;
82 RegLocation rlDest;
83 oatFlushAllRegs(cUnit); /* Send everything to home location */
84 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
85 if (srcSize == 1) {
86 rlSrc = oatGetSrc(cUnit, mir, 0);
87 loadValueDirectFixed(cUnit, rlSrc, r0);
88 } else {
89 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
90 loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
91 }
92 callRuntimeHelper(cUnit, rLR);
93 if (tgtSize == 1) {
94 RegLocation rlResult;
95 rlDest = oatGetDest(cUnit, mir, 0);
96 rlResult = oatGetReturn(cUnit);
97 storeValue(cUnit, rlDest, rlResult);
98 } else {
99 RegLocation rlResult;
100 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
101 rlResult = oatGetReturnWide(cUnit);
102 storeValueWide(cUnit, rlDest, rlResult);
103 }
104 return false;
105#endif
106}
107
108bool genArithOpFloatPortable(CompilationUnit* cUnit, MIR* mir,
109 RegLocation rlDest, RegLocation rlSrc1,
110 RegLocation rlSrc2)
111{
112 UNIMPLEMENTED(FATAL) << "Need Mips implementation";
113 return 0;
114#if 0
115 RegLocation rlResult;
116 int funcOffset;
117
118 switch (mir->dalvikInsn.opcode) {
119 case OP_ADD_FLOAT_2ADDR:
120 case OP_ADD_FLOAT:
121 funcOffset = OFFSETOF_MEMBER(Thread, pFadd);
122 break;
123 case OP_SUB_FLOAT_2ADDR:
124 case OP_SUB_FLOAT:
125 funcOffset = OFFSETOF_MEMBER(Thread, pFsub);
126 break;
127 case OP_DIV_FLOAT_2ADDR:
128 case OP_DIV_FLOAT:
129 funcOffset = OFFSETOF_MEMBER(Thread, pFdiv);
130 break;
131 case OP_MUL_FLOAT_2ADDR:
132 case OP_MUL_FLOAT:
133 funcOffset = OFFSETOF_MEMBER(Thread, pFmul);
134 break;
135 case OP_REM_FLOAT_2ADDR:
136 case OP_REM_FLOAT:
137 funcOffset = OFFSETOF_MEMBER(Thread, pFmodf);
138 break;
139 case OP_NEG_FLOAT: {
140 genNegFloat(cUnit, rlDest, rlSrc1);
141 return false;
142 }
143 default:
144 return true;
145 }
146 oatFlushAllRegs(cUnit); /* Send everything to home location */
147 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
148 loadValueDirectFixed(cUnit, rlSrc1, r0);
149 loadValueDirectFixed(cUnit, rlSrc2, r1);
150 callRuntimeHelper(cUnit, rLR);
151 rlResult = oatGetReturn(cUnit);
152 storeValue(cUnit, rlDest, rlResult);
153 return false;
154#endif
155}
156
157bool genArithOpDoublePortable(CompilationUnit* cUnit, MIR* mir,
158 RegLocation rlDest, RegLocation rlSrc1,
159 RegLocation rlSrc2)
160{
161 UNIMPLEMENTED(FATAL) << "Need Mips implementation";
162 return 0;
163#if 0
164 RegLocation rlResult;
165 int funcOffset;
166
167 switch (mir->dalvikInsn.opcode) {
168 case OP_ADD_DOUBLE_2ADDR:
169 case OP_ADD_DOUBLE:
170 funcOffset = OFFSETOF_MEMBER(Thread, pDadd);
171 break;
172 case OP_SUB_DOUBLE_2ADDR:
173 case OP_SUB_DOUBLE:
174 funcOffset = OFFSETOF_MEMBER(Thread, pDsub);
175 break;
176 case OP_DIV_DOUBLE_2ADDR:
177 case OP_DIV_DOUBLE:
178 funcOffset = OFFSETOF_MEMBER(Thread, pDdiv);
179 break;
180 case OP_MUL_DOUBLE_2ADDR:
181 case OP_MUL_DOUBLE:
182 funcOffset = OFFSETOF_MEMBER(Thread, pDmul);
183 break;
184 case OP_REM_DOUBLE_2ADDR:
185 case OP_REM_DOUBLE:
186 funcOffset = OFFSETOF_MEMBER(Thread, pFmod);
187 break;
188 case OP_NEG_DOUBLE: {
189 genNegDouble(cUnit, rlDest, rlSrc1);
190 return false;
191 }
192 default:
193 return true;
194 }
195 oatFlushAllRegs(cUnit); /* Send everything to home location */
196 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
197 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
198 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
199 callRuntimeHelper(cUnit, rLR);
200 rlResult = oatGetReturnWide(cUnit);
201 storeValueWide(cUnit, rlDest, rlResult);
202 return false;
203#endif
204}
205
206bool genConversionPortable(CompilationUnit* cUnit, MIR* mir)
207{
208 UNIMPLEMENTED(FATAL) << "Need Mips implementation";
209 return 0;
210#if 0
211 Opcode opcode = mir->dalvikInsn.opcode;
212
213 switch (opcode) {
214 case OP_INT_TO_FLOAT:
215 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2f),
216 1, 1);
217 case OP_FLOAT_TO_INT:
218 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2iz),
219 1, 1);
220 case OP_DOUBLE_TO_FLOAT:
221 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2f),
222 2, 1);
223 case OP_FLOAT_TO_DOUBLE:
224 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2d),
225 1, 2);
226 case OP_INT_TO_DOUBLE:
227 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2d),
228 1, 2);
229 case OP_DOUBLE_TO_INT:
230 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2iz),
231 2, 1);
232 case OP_FLOAT_TO_LONG:
233 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
234 pF2l), 1, 2);
235 case OP_LONG_TO_FLOAT:
236 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2f),
237 2, 1);
238 case OP_DOUBLE_TO_LONG:
239 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
240 pD2l), 2, 2);
241 case OP_LONG_TO_DOUBLE:
242 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2d),
243 2, 2);
244 default:
245 return true;
246 }
247 return false;
248#endif
249}
250
buzbeee3acd072012-02-25 17:03:10 -0800251
252
253
254
255STATIC RegLocation getRetLoc(CompilationUnit* cUnit);
256
257void warnIfUnresolved(CompilationUnit* cUnit, int fieldIdx, Field* field) {
258 if (field == NULL) {
259 const DexFile::FieldId& field_id = cUnit->dex_file->GetFieldId(fieldIdx);
260 std::string class_name(cUnit->dex_file->GetFieldDeclaringClassDescriptor(field_id));
261 std::string field_name(cUnit->dex_file->GetFieldName(field_id));
262 LOG(INFO) << "Field " << PrettyDescriptor(class_name) << "." << field_name
263 << " unresolved at compile time";
264 } else {
265 // We also use the slow path for wide volatile fields.
266 }
267}
268
269/*
270 * Construct an s4 from two consecutive half-words of switch data.
271 * This needs to check endianness because the DEX optimizer only swaps
272 * half-words in instruction stream.
273 *
274 * "switchData" must be 32-bit aligned.
275 */
276#if __BYTE_ORDER == __LITTLE_ENDIAN
277STATIC inline s4 s4FromSwitchData(const void* switchData) {
278 return *(s4*) switchData;
279}
280#else
281STATIC inline s4 s4FromSwitchData(const void* switchData) {
282 u2* data = switchData;
283 return data[0] | (((s4) data[1]) << 16);
284}
285#endif
286/*
buzbee31a4a6f2012-02-28 15:36:15 -0800287 * Insert a kPseudoCaseLabel at the beginning of the Dalvik
buzbeee3acd072012-02-25 17:03:10 -0800288 * offset vaddr. This label will be used to fix up the case
289 * branch table during the assembly phase. Be sure to set
290 * all resource flags on this to prevent code motion across
291 * target boundaries. KeyVal is just there for debugging.
292 */
293STATIC MipsLIR* insertCaseLabel(CompilationUnit* cUnit, int vaddr, int keyVal)
294{
295 std::map<unsigned int, LIR*>::iterator it;
296 it = cUnit->boundaryMap.find(vaddr);
297 if (it == cUnit->boundaryMap.end()) {
298 LOG(FATAL) << "Error: didn't find vaddr 0x" << std::hex << vaddr;
299 }
300 MipsLIR* newLabel = (MipsLIR*)oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
301 newLabel->generic.dalvikOffset = vaddr;
buzbee31a4a6f2012-02-28 15:36:15 -0800302 newLabel->opcode = kPseudoCaseLabel;
buzbeee3acd072012-02-25 17:03:10 -0800303 newLabel->operands[0] = keyVal;
304 oatInsertLIRAfter(it->second, (LIR*)newLabel);
305 return newLabel;
306}
307
308STATIC void markPackedCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
309{
310 const u2* table = tabRec->table;
311 int baseVaddr = tabRec->vaddr;
312 int *targets = (int*)&table[4];
313 int entries = table[1];
314 int lowKey = s4FromSwitchData(&table[2]);
315 for (int i = 0; i < entries; i++) {
316 tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
317 i + lowKey);
318 }
319}
320
321STATIC void markSparseCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
322{
323 const u2* table = tabRec->table;
324 int baseVaddr = tabRec->vaddr;
325 int entries = table[1];
326 int* keys = (int*)&table[2];
327 int* targets = &keys[entries];
328 for (int i = 0; i < entries; i++) {
329 tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
330 keys[i]);
331 }
332}
333
334void oatProcessSwitchTables(CompilationUnit* cUnit)
335{
336 GrowableListIterator iterator;
337 oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
338 while (true) {
339 SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
340 &iterator);
341 if (tabRec == NULL) break;
342 if (tabRec->table[0] == kPackedSwitchSignature)
343 markPackedCaseLabels(cUnit, tabRec);
344 else if (tabRec->table[0] == kSparseSwitchSignature)
345 markSparseCaseLabels(cUnit, tabRec);
346 else {
347 LOG(FATAL) << "Invalid switch table";
348 }
349 }
350}
351
352STATIC void dumpSparseSwitchTable(const u2* table)
353 /*
354 * Sparse switch data format:
355 * ushort ident = 0x0200 magic value
356 * ushort size number of entries in the table; > 0
357 * int keys[size] keys, sorted low-to-high; 32-bit aligned
358 * int targets[size] branch targets, relative to switch opcode
359 *
360 * Total size is (2+size*4) 16-bit code units.
361 */
362{
363 u2 ident = table[0];
364 int entries = table[1];
365 int* keys = (int*)&table[2];
366 int* targets = &keys[entries];
367 LOG(INFO) << "Sparse switch table - ident:0x" << std::hex << ident <<
368 ", entries: " << std::dec << entries;
369 for (int i = 0; i < entries; i++) {
370 LOG(INFO) << " Key[" << keys[i] << "] -> 0x" << std::hex <<
371 targets[i];
372 }
373}
374
375STATIC void dumpPackedSwitchTable(const u2* table)
376 /*
377 * Packed switch data format:
378 * ushort ident = 0x0100 magic value
379 * ushort size number of entries in the table
380 * int first_key first (and lowest) switch case value
381 * int targets[size] branch targets, relative to switch opcode
382 *
383 * Total size is (4+size*2) 16-bit code units.
384 */
385{
386 u2 ident = table[0];
387 int* targets = (int*)&table[4];
388 int entries = table[1];
389 int lowKey = s4FromSwitchData(&table[2]);
390 LOG(INFO) << "Packed switch table - ident:0x" << std::hex << ident <<
391 ", entries: " << std::dec << entries << ", lowKey: " << lowKey;
392 for (int i = 0; i < entries; i++) {
393 LOG(INFO) << " Key[" << (i + lowKey) << "] -> 0x" << std::hex <<
394 targets[i];
395 }
396}
397
398/*
399 * The sparse table in the literal pool is an array of <key,displacement>
400 * pairs. For each set, we'll load them as a pair using ldmia.
401 * This means that the register number of the temp we use for the key
402 * must be lower than the reg for the displacement.
403 *
404 * The test loop will look something like:
405 *
406 * adr rBase, <table>
407 * ldr rVal, [rSP, vRegOff]
408 * mov rIdx, #tableSize
409 * lp:
410 * ldmia rBase!, {rKey, rDisp}
411 * sub rIdx, #1
412 * cmp rVal, rKey
413 * ifeq
414 * add rPC, rDisp ; This is the branch from which we compute displacement
415 * cbnz rIdx, lp
416 */
417STATIC void genSparseSwitch(CompilationUnit* cUnit, MIR* mir,
418 RegLocation rlSrc)
419{
420 UNIMPLEMENTED(FATAL) << "Need Mips implementation";
421#if 0
422 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
423 if (cUnit->printMe) {
424 dumpSparseSwitchTable(table);
425 }
426 // Add the table to the list - we'll process it later
427 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
428 true, kAllocData);
429 tabRec->table = table;
430 tabRec->vaddr = mir->offset;
431 int size = table[1];
432 tabRec->targets = (MipsLIR* *)oatNew(cUnit, size * sizeof(MipsLIR*), true,
433 kAllocLIR);
434 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
435
436 // Get the switch value
437 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
438 int rBase = oatAllocTemp(cUnit);
439 /* Allocate key and disp temps */
440 int rKey = oatAllocTemp(cUnit);
441 int rDisp = oatAllocTemp(cUnit);
442 // Make sure rKey's register number is less than rDisp's number for ldmia
443 if (rKey > rDisp) {
444 int tmp = rDisp;
445 rDisp = rKey;
446 rKey = tmp;
447 }
448 // Materialize a pointer to the switch table
449 newLIR3(cUnit, kThumb2Adr, rBase, 0, (intptr_t)tabRec);
450 // Set up rIdx
451 int rIdx = oatAllocTemp(cUnit);
452 loadConstant(cUnit, rIdx, size);
453 // Establish loop branch target
buzbee31a4a6f2012-02-28 15:36:15 -0800454 MipsLIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbeee3acd072012-02-25 17:03:10 -0800455 target->defMask = ENCODE_ALL;
456 // Load next key/disp
457 newLIR2(cUnit, kThumb2LdmiaWB, rBase, (1 << rKey) | (1 << rDisp));
458 opRegReg(cUnit, kOpCmp, rKey, rlSrc.lowReg);
459 // Go if match. NOTE: No instruction set switch here - must stay Thumb2
460 genIT(cUnit, kMipsCondEq, "");
461 MipsLIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, rDisp);
462 tabRec->bxInst = switchBranch;
463 // Needs to use setflags encoding here
464 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
465 MipsLIR* branch = opCondBranch(cUnit, kMipsCondNe);
466 branch->generic.target = (LIR*)target;
467#endif
468}
469
470STATIC void genPackedSwitch(CompilationUnit* cUnit, MIR* mir,
471 RegLocation rlSrc)
472{
473 UNIMPLEMENTED(FATAL) << "Need Mips implementation";
474#if 0
475 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
476 if (cUnit->printMe) {
477 dumpPackedSwitchTable(table);
478 }
479 // Add the table to the list - we'll process it later
480 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
481 true, kAllocData);
482 tabRec->table = table;
483 tabRec->vaddr = mir->offset;
484 int size = table[1];
485 tabRec->targets = (MipsLIR* *)oatNew(cUnit, size * sizeof(MipsLIR*), true,
486 kAllocLIR);
487 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
488
489 // Get the switch value
490 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
491 int tableBase = oatAllocTemp(cUnit);
492 // Materialize a pointer to the switch table
493 newLIR3(cUnit, kThumb2Adr, tableBase, 0, (intptr_t)tabRec);
494 int lowKey = s4FromSwitchData(&table[2]);
495 int keyReg;
496 // Remove the bias, if necessary
497 if (lowKey == 0) {
498 keyReg = rlSrc.lowReg;
499 } else {
500 keyReg = oatAllocTemp(cUnit);
501 opRegRegImm(cUnit, kOpSub, keyReg, rlSrc.lowReg, lowKey);
502 }
503 // Bounds check - if < 0 or >= size continue following switch
504 opRegImm(cUnit, kOpCmp, keyReg, size-1);
505 MipsLIR* branchOver = opCondBranch(cUnit, kMipsCondHi);
506
507 // Load the displacement from the switch table
508 int dispReg = oatAllocTemp(cUnit);
509 loadBaseIndexed(cUnit, tableBase, keyReg, dispReg, 2, kWord);
510
511 // ..and go! NOTE: No instruction set switch here - must stay Thumb2
512 MipsLIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, dispReg);
513 tabRec->bxInst = switchBranch;
514
515 /* branchOver target here */
buzbee31a4a6f2012-02-28 15:36:15 -0800516 MipsLIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbeee3acd072012-02-25 17:03:10 -0800517 target->defMask = ENCODE_ALL;
518 branchOver->generic.target = (LIR*)target;
519#endif
520}
521
522/*
523 * Array data table format:
524 * ushort ident = 0x0300 magic value
525 * ushort width width of each element in the table
526 * uint size number of elements in the table
527 * ubyte data[size*width] table of data values (may contain a single-byte
528 * padding at the end)
529 *
530 * Total size is 4+(width * size + 1)/2 16-bit code units.
531 */
532STATIC void genFillArrayData(CompilationUnit* cUnit, MIR* mir,
533 RegLocation rlSrc)
534{
535 UNIMPLEMENTED(FATAL) << "Need Mips implementation";
536#if 0
537 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
538 // Add the table to the list - we'll process it later
539 FillArrayData *tabRec = (FillArrayData *)
540 oatNew(cUnit, sizeof(FillArrayData), true, kAllocData);
541 tabRec->table = table;
542 tabRec->vaddr = mir->offset;
543 u2 width = tabRec->table[1];
544 u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
545 tabRec->size = (size * width) + 8;
546
547 oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec);
548
549 // Making a call - use explicit registers
550 oatFlushAllRegs(cUnit); /* Everything to home location */
551 loadValueDirectFixed(cUnit, rlSrc, r0);
552 loadWordDisp(cUnit, rSELF,
553 OFFSETOF_MEMBER(Thread, pHandleFillArrayDataFromCode), rLR);
554 // Materialize a pointer to the fill data image
555 newLIR3(cUnit, kThumb2Adr, r1, 0, (intptr_t)tabRec);
556 callRuntimeHelper(cUnit, rLR);
557#endif
558}
559
560STATIC void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
561 RegLocation rlDest, RegLocation rlObj,
562 bool isLongOrDouble, bool isObject)
563{
564 UNIMPLEMENTED(FATAL) << "Need Mips implementation";
565#if 0
566 int fieldOffset;
567 bool isVolatile;
568 uint32_t fieldIdx = mir->dalvikInsn.vC;
569 bool fastPath =
570 cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, cUnit,
571 fieldOffset, isVolatile, false);
572 if (fastPath && !SLOW_FIELD_PATH) {
573 RegLocation rlResult;
574 RegisterClass regClass = oatRegClassBySize(size);
575 DCHECK_GE(fieldOffset, 0);
576 rlObj = loadValue(cUnit, rlObj, kCoreReg);
577 if (isLongOrDouble) {
578 DCHECK(rlDest.wide);
579 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
580 int regPtr = oatAllocTemp(cUnit);
581 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
582 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
583 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
584 if (isVolatile) {
585 oatGenMemBarrier(cUnit, kSY);
586 }
587 oatFreeTemp(cUnit, regPtr);
588 storeValueWide(cUnit, rlDest, rlResult);
589 } else {
590 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
591 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
592 loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
593 kWord, rlObj.sRegLow);
594 if (isVolatile) {
595 oatGenMemBarrier(cUnit, kSY);
596 }
597 storeValue(cUnit, rlDest, rlResult);
598 }
599 } else {
600 int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Instance) :
601 (isObject ? OFFSETOF_MEMBER(Thread, pGetObjInstance)
602 : OFFSETOF_MEMBER(Thread, pGet32Instance));
603 loadWordDisp(cUnit, rSELF, getterOffset, rLR);
604 loadValueDirect(cUnit, rlObj, r1);
605 loadConstant(cUnit, r0, fieldIdx);
606 callRuntimeHelper(cUnit, rLR);
607 if (isLongOrDouble) {
608 RegLocation rlResult = oatGetReturnWide(cUnit);
609 storeValueWide(cUnit, rlDest, rlResult);
610 } else {
611 RegLocation rlResult = oatGetReturn(cUnit);
612 storeValue(cUnit, rlDest, rlResult);
613 }
614 }
615#endif
616}
617
618/*
619 * Perform a "reg cmp imm" operation and jump to the PCR region if condition
620 * satisfies.
621 */
622STATIC void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest,
623 RegLocation rlSrc)
624{
625 RegLocation rlResult;
626 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
627 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
628 opRegRegImm(cUnit, kOpAdd, rlResult.lowReg,
629 rlSrc.lowReg, 0x80000000);
630 storeValue(cUnit, rlDest, rlResult);
631}
632
633STATIC void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest,
634 RegLocation rlSrc)
635{
636 RegLocation rlResult;
637 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
638 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
639 opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg,
640 0x80000000);
641 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
642 storeValueWide(cUnit, rlDest, rlResult);
643}
644
645STATIC void genMulLong(CompilationUnit *cUnit, RegLocation rlDest,
646 RegLocation rlSrc1, RegLocation rlSrc2)
647{
648 UNIMPLEMENTED(FATAL) << "Need Mips implementation";
649#if 0
650 RegLocation rlResult;
651 loadValueDirectWideFixed(cUnit, rlSrc1, r_ARG0, r_ARG1);
652 loadValueDirectWideFixed(cUnit, rlSrc2, r_ARG2, r_ARG3);
653 genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
654 rlResult = oatGetReturnWide(cUnit);
655 storeValueWide(cUnit, rlDest, rlResult);
656#endif
657}
658
659STATIC bool partialOverlap(int sreg1, int sreg2)
660{
661 return abs(sreg1 - sreg2) == 1;
662}
663
664STATIC void withCarryHelper(CompilationUnit *cUnit, MipsOpCode opc,
665 RegLocation rlDest, RegLocation rlSrc1,
666 RegLocation rlSrc2, int sltuSrc1, int sltuSrc2)
667{
668 int tReg = oatAllocTemp(cUnit);
669 newLIR3(cUnit, opc, rlDest.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
670 newLIR3(cUnit, kMipsSltu, tReg, sltuSrc1, sltuSrc2);
671 newLIR3(cUnit, opc, rlDest.highReg, rlSrc1.highReg, rlSrc2.highReg);
672 newLIR3(cUnit, opc, rlDest.highReg, rlDest.highReg, tReg);
673 oatFreeTemp(cUnit, tReg);
674}
675
676STATIC void genLong3Addr(CompilationUnit *cUnit, MIR *mir, OpKind firstOp,
677 OpKind secondOp, RegLocation rlDest,
678 RegLocation rlSrc1, RegLocation rlSrc2)
679{
680 UNIMPLEMENTED(FATAL) << "Need Mips implementation";
681#if 0
682 RegLocation rlResult;
683 int carryOp = (secondOp == kOpAdc || secondOp == kOpSbc);
684
685 if (partialOverlap(rlSrc1.sRegLow,rlSrc2.sRegLow) ||
686 partialOverlap(rlSrc1.sRegLow,rlDest.sRegLow) ||
687 partialOverlap(rlSrc2.sRegLow,rlDest.sRegLow)) {
688 // Rare case - not enough registers to properly handle
689 genInterpSingleStep(cUnit, mir);
690 } else if (rlDest.sRegLow == rlSrc1.sRegLow) {
691 rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
692 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
693 if (!carryOp) {
694 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlResult.lowReg, rlSrc2.lowReg);
695 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlResult.highReg, rlSrc2.highReg);
696 } else if (secondOp == kOpAdc) {
697 withCarryHelper(cUnit, kMipsAddu, rlResult, rlResult, rlSrc2,
698 rlResult.lowReg, rlSrc2.lowReg);
699 } else {
700 int tReg = oatAllocTemp(cUnit);
701 newLIR2(cUnit, kMipsMove, tReg, rlResult.lowReg);
702 withCarryHelper(cUnit, kMipsSubu, rlResult, rlResult, rlSrc2,
703 tReg, rlResult.lowReg);
704 oatFreeTemp(cUnit, tReg);
705 }
706 storeValueWide(cUnit, rlDest, rlResult);
707 } else if (rlDest.sRegLow == rlSrc2.sRegLow) {
708 rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
709 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
710 if (!carryOp) {
711 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlResult.lowReg);
712 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg, rlResult.highReg);
713 } else if (secondOp == kOpAdc) {
714 withCarryHelper(cUnit, kMipsAddu, rlResult, rlSrc1, rlResult,
715 rlResult.lowReg, rlSrc1.lowReg);
716 } else {
717 withCarryHelper(cUnit, kMipsSubu, rlResult, rlSrc1, rlResult,
718 rlSrc1.lowReg, rlResult.lowReg);
719 }
720 storeValueWide(cUnit, rlDest, rlResult);
721 } else {
722 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
723 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
724 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
725 if (!carryOp) {
726 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
727 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg, rlSrc2.highReg);
728 } else if (secondOp == kOpAdc) {
729 withCarryHelper(cUnit, kMipsAddu, rlResult, rlSrc1, rlSrc2,
730 rlResult.lowReg, rlSrc1.lowReg);
731 } else {
732 withCarryHelper(cUnit, kMipsSubu, rlResult, rlSrc1, rlSrc2,
733 rlSrc1.lowReg, rlResult.lowReg);
734 }
735 storeValueWide(cUnit, rlDest, rlResult);
736 }
737#endif
738}
739
740void oatInitializeRegAlloc(CompilationUnit* cUnit)
741{
742 int numRegs = sizeof(coreRegs)/sizeof(*coreRegs);
743 int numReserved = sizeof(reservedRegs)/sizeof(*reservedRegs);
744 int numTemps = sizeof(coreTemps)/sizeof(*coreTemps);
745#ifdef __mips_hard_float
746 int numFPRegs = sizeof(fpRegs)/sizeof(*fpRegs);
747 int numFPTemps = sizeof(fpTemps)/sizeof(*fpTemps);
748#else
749 int numFPRegs = 0;
750 int numFPTemps = 0;
751#endif
752 RegisterPool *pool = (RegisterPool *)oatNew(cUnit, sizeof(*pool), true,
753 kAllocRegAlloc);
754 cUnit->regPool = pool;
755 pool->numCoreRegs = numRegs;
756 pool->coreRegs = (RegisterInfo *)
757 oatNew(cUnit, numRegs * sizeof(*cUnit->regPool->coreRegs),
758 true, kAllocRegAlloc);
759 pool->numFPRegs = numFPRegs;
760 pool->FPRegs = numFPRegs == 0 ? NULL : (RegisterInfo *)
761 oatNew(cUnit, numFPRegs * sizeof(*cUnit->regPool->FPRegs), true,
762 kAllocRegAlloc);
763 oatInitPool(pool->coreRegs, coreRegs, pool->numCoreRegs);
764 oatInitPool(pool->FPRegs, fpRegs, pool->numFPRegs);
765 // Keep special registers from being allocated
766 for (int i = 0; i < numReserved; i++) {
767 if (NO_SUSPEND && !cUnit->genDebugger &&
768 (reservedRegs[i] == rSUSPEND)) {
769 //To measure cost of suspend check
770 continue;
771 }
772 oatMarkInUse(cUnit, reservedRegs[i]);
773 }
774 // Mark temp regs - all others not in use can be used for promotion
775 for (int i = 0; i < numTemps; i++) {
776 oatMarkTemp(cUnit, coreTemps[i]);
777 }
778 for (int i = 0; i < numFPTemps; i++) {
779 oatMarkTemp(cUnit, fpTemps[i]);
780 }
781 // Construct the alias map.
782 cUnit->phiAliasMap = (int*)oatNew(cUnit, cUnit->numSSARegs *
783 sizeof(cUnit->phiAliasMap[0]), false,
784 kAllocDFInfo);
785 for (int i = 0; i < cUnit->numSSARegs; i++) {
786 cUnit->phiAliasMap[i] = i;
787 }
788 for (MIR* phi = cUnit->phiList; phi; phi = phi->meta.phiNext) {
789 int defReg = phi->ssaRep->defs[0];
790 for (int i = 0; i < phi->ssaRep->numUses; i++) {
791 for (int j = 0; j < cUnit->numSSARegs; j++) {
792 if (cUnit->phiAliasMap[j] == phi->ssaRep->uses[i]) {
793 cUnit->phiAliasMap[j] = defReg;
794 }
795 }
796 }
797 }
798}
799
800STATIC void genMonitor(CompilationUnit *cUnit, MIR *mir)
801{
802 UNIMPLEMENTED(FATAL) << "Need Mips implementation";
803#if 0
804 genMonitorPortable(cUnit, mir);
805#endif
806}
807
808STATIC void genCmpLong(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
809 RegLocation rlSrc1, RegLocation rlSrc2)
810{
811 UNIMPLEMENTED(FATAL) << "Need Mips implementation";
812#if 0
813 RegLocation rlResult;
814 loadValueDirectWideFixed(cUnit, rlSrc1, r_ARG0, r_ARG1);
815 loadValueDirectWideFixed(cUnit, rlSrc2, r_ARG2, r_ARG3);
816 genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG);
817 rlResult = oatGetReturn(cUnit);
818 storeValue(cUnit, rlDest, rlResult);
819#endif
820}
821
822STATIC void genMultiplyByTwoBitMultiplier(CompilationUnit *cUnit,
823 RegLocation rlSrc, RegLocation rlResult, int lit,
824 int firstBit, int secondBit)
825{
826 // We can't implement "add src, src, src, lsl#shift" on Thumb, so we have
827 // to do a regular multiply.
828 opRegRegImm(cUnit, kOpMul, rlResult.lowReg, rlSrc.lowReg, lit);
829}
830
831} // namespace art