blob: f49cdab44ba0c07351295cad1fcc74917da7adb7 [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; }
65
66
67
68
69
70
71
72
73STATIC RegLocation getRetLoc(CompilationUnit* cUnit);
74
75void warnIfUnresolved(CompilationUnit* cUnit, int fieldIdx, Field* field) {
76 if (field == NULL) {
77 const DexFile::FieldId& field_id = cUnit->dex_file->GetFieldId(fieldIdx);
78 std::string class_name(cUnit->dex_file->GetFieldDeclaringClassDescriptor(field_id));
79 std::string field_name(cUnit->dex_file->GetFieldName(field_id));
80 LOG(INFO) << "Field " << PrettyDescriptor(class_name) << "." << field_name
81 << " unresolved at compile time";
82 } else {
83 // We also use the slow path for wide volatile fields.
84 }
85}
86
87/*
88 * Construct an s4 from two consecutive half-words of switch data.
89 * This needs to check endianness because the DEX optimizer only swaps
90 * half-words in instruction stream.
91 *
92 * "switchData" must be 32-bit aligned.
93 */
94#if __BYTE_ORDER == __LITTLE_ENDIAN
95STATIC inline s4 s4FromSwitchData(const void* switchData) {
96 return *(s4*) switchData;
97}
98#else
99STATIC inline s4 s4FromSwitchData(const void* switchData) {
100 u2* data = switchData;
101 return data[0] | (((s4) data[1]) << 16);
102}
103#endif
104/*
105 * Insert a kMipsPseudoCaseLabel at the beginning of the Dalvik
106 * offset vaddr. This label will be used to fix up the case
107 * branch table during the assembly phase. Be sure to set
108 * all resource flags on this to prevent code motion across
109 * target boundaries. KeyVal is just there for debugging.
110 */
111STATIC MipsLIR* insertCaseLabel(CompilationUnit* cUnit, int vaddr, int keyVal)
112{
113 std::map<unsigned int, LIR*>::iterator it;
114 it = cUnit->boundaryMap.find(vaddr);
115 if (it == cUnit->boundaryMap.end()) {
116 LOG(FATAL) << "Error: didn't find vaddr 0x" << std::hex << vaddr;
117 }
118 MipsLIR* newLabel = (MipsLIR*)oatNew(cUnit, sizeof(MipsLIR), true, kAllocLIR);
119 newLabel->generic.dalvikOffset = vaddr;
120 newLabel->opcode = kMipsPseudoCaseLabel;
121 newLabel->operands[0] = keyVal;
122 oatInsertLIRAfter(it->second, (LIR*)newLabel);
123 return newLabel;
124}
125
126STATIC void markPackedCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
127{
128 const u2* table = tabRec->table;
129 int baseVaddr = tabRec->vaddr;
130 int *targets = (int*)&table[4];
131 int entries = table[1];
132 int lowKey = s4FromSwitchData(&table[2]);
133 for (int i = 0; i < entries; i++) {
134 tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
135 i + lowKey);
136 }
137}
138
139STATIC void markSparseCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
140{
141 const u2* table = tabRec->table;
142 int baseVaddr = tabRec->vaddr;
143 int entries = table[1];
144 int* keys = (int*)&table[2];
145 int* targets = &keys[entries];
146 for (int i = 0; i < entries; i++) {
147 tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
148 keys[i]);
149 }
150}
151
152void oatProcessSwitchTables(CompilationUnit* cUnit)
153{
154 GrowableListIterator iterator;
155 oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
156 while (true) {
157 SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
158 &iterator);
159 if (tabRec == NULL) break;
160 if (tabRec->table[0] == kPackedSwitchSignature)
161 markPackedCaseLabels(cUnit, tabRec);
162 else if (tabRec->table[0] == kSparseSwitchSignature)
163 markSparseCaseLabels(cUnit, tabRec);
164 else {
165 LOG(FATAL) << "Invalid switch table";
166 }
167 }
168}
169
170STATIC void dumpSparseSwitchTable(const u2* table)
171 /*
172 * Sparse switch data format:
173 * ushort ident = 0x0200 magic value
174 * ushort size number of entries in the table; > 0
175 * int keys[size] keys, sorted low-to-high; 32-bit aligned
176 * int targets[size] branch targets, relative to switch opcode
177 *
178 * Total size is (2+size*4) 16-bit code units.
179 */
180{
181 u2 ident = table[0];
182 int entries = table[1];
183 int* keys = (int*)&table[2];
184 int* targets = &keys[entries];
185 LOG(INFO) << "Sparse switch table - ident:0x" << std::hex << ident <<
186 ", entries: " << std::dec << entries;
187 for (int i = 0; i < entries; i++) {
188 LOG(INFO) << " Key[" << keys[i] << "] -> 0x" << std::hex <<
189 targets[i];
190 }
191}
192
193STATIC void dumpPackedSwitchTable(const u2* table)
194 /*
195 * Packed switch data format:
196 * ushort ident = 0x0100 magic value
197 * ushort size number of entries in the table
198 * int first_key first (and lowest) switch case value
199 * int targets[size] branch targets, relative to switch opcode
200 *
201 * Total size is (4+size*2) 16-bit code units.
202 */
203{
204 u2 ident = table[0];
205 int* targets = (int*)&table[4];
206 int entries = table[1];
207 int lowKey = s4FromSwitchData(&table[2]);
208 LOG(INFO) << "Packed switch table - ident:0x" << std::hex << ident <<
209 ", entries: " << std::dec << entries << ", lowKey: " << lowKey;
210 for (int i = 0; i < entries; i++) {
211 LOG(INFO) << " Key[" << (i + lowKey) << "] -> 0x" << std::hex <<
212 targets[i];
213 }
214}
215
216/*
217 * The sparse table in the literal pool is an array of <key,displacement>
218 * pairs. For each set, we'll load them as a pair using ldmia.
219 * This means that the register number of the temp we use for the key
220 * must be lower than the reg for the displacement.
221 *
222 * The test loop will look something like:
223 *
224 * adr rBase, <table>
225 * ldr rVal, [rSP, vRegOff]
226 * mov rIdx, #tableSize
227 * lp:
228 * ldmia rBase!, {rKey, rDisp}
229 * sub rIdx, #1
230 * cmp rVal, rKey
231 * ifeq
232 * add rPC, rDisp ; This is the branch from which we compute displacement
233 * cbnz rIdx, lp
234 */
235STATIC void genSparseSwitch(CompilationUnit* cUnit, MIR* mir,
236 RegLocation rlSrc)
237{
238 UNIMPLEMENTED(FATAL) << "Need Mips implementation";
239#if 0
240 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
241 if (cUnit->printMe) {
242 dumpSparseSwitchTable(table);
243 }
244 // Add the table to the list - we'll process it later
245 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
246 true, kAllocData);
247 tabRec->table = table;
248 tabRec->vaddr = mir->offset;
249 int size = table[1];
250 tabRec->targets = (MipsLIR* *)oatNew(cUnit, size * sizeof(MipsLIR*), true,
251 kAllocLIR);
252 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
253
254 // Get the switch value
255 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
256 int rBase = oatAllocTemp(cUnit);
257 /* Allocate key and disp temps */
258 int rKey = oatAllocTemp(cUnit);
259 int rDisp = oatAllocTemp(cUnit);
260 // Make sure rKey's register number is less than rDisp's number for ldmia
261 if (rKey > rDisp) {
262 int tmp = rDisp;
263 rDisp = rKey;
264 rKey = tmp;
265 }
266 // Materialize a pointer to the switch table
267 newLIR3(cUnit, kThumb2Adr, rBase, 0, (intptr_t)tabRec);
268 // Set up rIdx
269 int rIdx = oatAllocTemp(cUnit);
270 loadConstant(cUnit, rIdx, size);
271 // Establish loop branch target
272 MipsLIR* target = newLIR0(cUnit, kMipsPseudoTargetLabel);
273 target->defMask = ENCODE_ALL;
274 // Load next key/disp
275 newLIR2(cUnit, kThumb2LdmiaWB, rBase, (1 << rKey) | (1 << rDisp));
276 opRegReg(cUnit, kOpCmp, rKey, rlSrc.lowReg);
277 // Go if match. NOTE: No instruction set switch here - must stay Thumb2
278 genIT(cUnit, kMipsCondEq, "");
279 MipsLIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, rDisp);
280 tabRec->bxInst = switchBranch;
281 // Needs to use setflags encoding here
282 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
283 MipsLIR* branch = opCondBranch(cUnit, kMipsCondNe);
284 branch->generic.target = (LIR*)target;
285#endif
286}
287
288STATIC void genPackedSwitch(CompilationUnit* cUnit, MIR* mir,
289 RegLocation rlSrc)
290{
291 UNIMPLEMENTED(FATAL) << "Need Mips implementation";
292#if 0
293 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
294 if (cUnit->printMe) {
295 dumpPackedSwitchTable(table);
296 }
297 // Add the table to the list - we'll process it later
298 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
299 true, kAllocData);
300 tabRec->table = table;
301 tabRec->vaddr = mir->offset;
302 int size = table[1];
303 tabRec->targets = (MipsLIR* *)oatNew(cUnit, size * sizeof(MipsLIR*), true,
304 kAllocLIR);
305 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
306
307 // Get the switch value
308 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
309 int tableBase = oatAllocTemp(cUnit);
310 // Materialize a pointer to the switch table
311 newLIR3(cUnit, kThumb2Adr, tableBase, 0, (intptr_t)tabRec);
312 int lowKey = s4FromSwitchData(&table[2]);
313 int keyReg;
314 // Remove the bias, if necessary
315 if (lowKey == 0) {
316 keyReg = rlSrc.lowReg;
317 } else {
318 keyReg = oatAllocTemp(cUnit);
319 opRegRegImm(cUnit, kOpSub, keyReg, rlSrc.lowReg, lowKey);
320 }
321 // Bounds check - if < 0 or >= size continue following switch
322 opRegImm(cUnit, kOpCmp, keyReg, size-1);
323 MipsLIR* branchOver = opCondBranch(cUnit, kMipsCondHi);
324
325 // Load the displacement from the switch table
326 int dispReg = oatAllocTemp(cUnit);
327 loadBaseIndexed(cUnit, tableBase, keyReg, dispReg, 2, kWord);
328
329 // ..and go! NOTE: No instruction set switch here - must stay Thumb2
330 MipsLIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, dispReg);
331 tabRec->bxInst = switchBranch;
332
333 /* branchOver target here */
334 MipsLIR* target = newLIR0(cUnit, kMipsPseudoTargetLabel);
335 target->defMask = ENCODE_ALL;
336 branchOver->generic.target = (LIR*)target;
337#endif
338}
339
340/*
341 * Array data table format:
342 * ushort ident = 0x0300 magic value
343 * ushort width width of each element in the table
344 * uint size number of elements in the table
345 * ubyte data[size*width] table of data values (may contain a single-byte
346 * padding at the end)
347 *
348 * Total size is 4+(width * size + 1)/2 16-bit code units.
349 */
350STATIC void genFillArrayData(CompilationUnit* cUnit, MIR* mir,
351 RegLocation rlSrc)
352{
353 UNIMPLEMENTED(FATAL) << "Need Mips implementation";
354#if 0
355 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
356 // Add the table to the list - we'll process it later
357 FillArrayData *tabRec = (FillArrayData *)
358 oatNew(cUnit, sizeof(FillArrayData), true, kAllocData);
359 tabRec->table = table;
360 tabRec->vaddr = mir->offset;
361 u2 width = tabRec->table[1];
362 u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
363 tabRec->size = (size * width) + 8;
364
365 oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec);
366
367 // Making a call - use explicit registers
368 oatFlushAllRegs(cUnit); /* Everything to home location */
369 loadValueDirectFixed(cUnit, rlSrc, r0);
370 loadWordDisp(cUnit, rSELF,
371 OFFSETOF_MEMBER(Thread, pHandleFillArrayDataFromCode), rLR);
372 // Materialize a pointer to the fill data image
373 newLIR3(cUnit, kThumb2Adr, r1, 0, (intptr_t)tabRec);
374 callRuntimeHelper(cUnit, rLR);
375#endif
376}
377
378STATIC void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
379 RegLocation rlDest, RegLocation rlObj,
380 bool isLongOrDouble, bool isObject)
381{
382 UNIMPLEMENTED(FATAL) << "Need Mips implementation";
383#if 0
384 int fieldOffset;
385 bool isVolatile;
386 uint32_t fieldIdx = mir->dalvikInsn.vC;
387 bool fastPath =
388 cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, cUnit,
389 fieldOffset, isVolatile, false);
390 if (fastPath && !SLOW_FIELD_PATH) {
391 RegLocation rlResult;
392 RegisterClass regClass = oatRegClassBySize(size);
393 DCHECK_GE(fieldOffset, 0);
394 rlObj = loadValue(cUnit, rlObj, kCoreReg);
395 if (isLongOrDouble) {
396 DCHECK(rlDest.wide);
397 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
398 int regPtr = oatAllocTemp(cUnit);
399 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
400 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
401 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
402 if (isVolatile) {
403 oatGenMemBarrier(cUnit, kSY);
404 }
405 oatFreeTemp(cUnit, regPtr);
406 storeValueWide(cUnit, rlDest, rlResult);
407 } else {
408 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
409 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
410 loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
411 kWord, rlObj.sRegLow);
412 if (isVolatile) {
413 oatGenMemBarrier(cUnit, kSY);
414 }
415 storeValue(cUnit, rlDest, rlResult);
416 }
417 } else {
418 int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Instance) :
419 (isObject ? OFFSETOF_MEMBER(Thread, pGetObjInstance)
420 : OFFSETOF_MEMBER(Thread, pGet32Instance));
421 loadWordDisp(cUnit, rSELF, getterOffset, rLR);
422 loadValueDirect(cUnit, rlObj, r1);
423 loadConstant(cUnit, r0, fieldIdx);
424 callRuntimeHelper(cUnit, rLR);
425 if (isLongOrDouble) {
426 RegLocation rlResult = oatGetReturnWide(cUnit);
427 storeValueWide(cUnit, rlDest, rlResult);
428 } else {
429 RegLocation rlResult = oatGetReturn(cUnit);
430 storeValue(cUnit, rlDest, rlResult);
431 }
432 }
433#endif
434}
435
436/*
437 * Perform a "reg cmp imm" operation and jump to the PCR region if condition
438 * satisfies.
439 */
440STATIC void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest,
441 RegLocation rlSrc)
442{
443 RegLocation rlResult;
444 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
445 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
446 opRegRegImm(cUnit, kOpAdd, rlResult.lowReg,
447 rlSrc.lowReg, 0x80000000);
448 storeValue(cUnit, rlDest, rlResult);
449}
450
451STATIC void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest,
452 RegLocation rlSrc)
453{
454 RegLocation rlResult;
455 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
456 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
457 opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg,
458 0x80000000);
459 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
460 storeValueWide(cUnit, rlDest, rlResult);
461}
462
463STATIC void genMulLong(CompilationUnit *cUnit, RegLocation rlDest,
464 RegLocation rlSrc1, RegLocation rlSrc2)
465{
466 UNIMPLEMENTED(FATAL) << "Need Mips implementation";
467#if 0
468 RegLocation rlResult;
469 loadValueDirectWideFixed(cUnit, rlSrc1, r_ARG0, r_ARG1);
470 loadValueDirectWideFixed(cUnit, rlSrc2, r_ARG2, r_ARG3);
471 genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
472 rlResult = oatGetReturnWide(cUnit);
473 storeValueWide(cUnit, rlDest, rlResult);
474#endif
475}
476
477STATIC bool partialOverlap(int sreg1, int sreg2)
478{
479 return abs(sreg1 - sreg2) == 1;
480}
481
482STATIC void withCarryHelper(CompilationUnit *cUnit, MipsOpCode opc,
483 RegLocation rlDest, RegLocation rlSrc1,
484 RegLocation rlSrc2, int sltuSrc1, int sltuSrc2)
485{
486 int tReg = oatAllocTemp(cUnit);
487 newLIR3(cUnit, opc, rlDest.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
488 newLIR3(cUnit, kMipsSltu, tReg, sltuSrc1, sltuSrc2);
489 newLIR3(cUnit, opc, rlDest.highReg, rlSrc1.highReg, rlSrc2.highReg);
490 newLIR3(cUnit, opc, rlDest.highReg, rlDest.highReg, tReg);
491 oatFreeTemp(cUnit, tReg);
492}
493
494STATIC void genLong3Addr(CompilationUnit *cUnit, MIR *mir, OpKind firstOp,
495 OpKind secondOp, RegLocation rlDest,
496 RegLocation rlSrc1, RegLocation rlSrc2)
497{
498 UNIMPLEMENTED(FATAL) << "Need Mips implementation";
499#if 0
500 RegLocation rlResult;
501 int carryOp = (secondOp == kOpAdc || secondOp == kOpSbc);
502
503 if (partialOverlap(rlSrc1.sRegLow,rlSrc2.sRegLow) ||
504 partialOverlap(rlSrc1.sRegLow,rlDest.sRegLow) ||
505 partialOverlap(rlSrc2.sRegLow,rlDest.sRegLow)) {
506 // Rare case - not enough registers to properly handle
507 genInterpSingleStep(cUnit, mir);
508 } else if (rlDest.sRegLow == rlSrc1.sRegLow) {
509 rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
510 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
511 if (!carryOp) {
512 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlResult.lowReg, rlSrc2.lowReg);
513 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlResult.highReg, rlSrc2.highReg);
514 } else if (secondOp == kOpAdc) {
515 withCarryHelper(cUnit, kMipsAddu, rlResult, rlResult, rlSrc2,
516 rlResult.lowReg, rlSrc2.lowReg);
517 } else {
518 int tReg = oatAllocTemp(cUnit);
519 newLIR2(cUnit, kMipsMove, tReg, rlResult.lowReg);
520 withCarryHelper(cUnit, kMipsSubu, rlResult, rlResult, rlSrc2,
521 tReg, rlResult.lowReg);
522 oatFreeTemp(cUnit, tReg);
523 }
524 storeValueWide(cUnit, rlDest, rlResult);
525 } else if (rlDest.sRegLow == rlSrc2.sRegLow) {
526 rlResult = loadValueWide(cUnit, rlDest, kCoreReg);
527 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
528 if (!carryOp) {
529 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlResult.lowReg);
530 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg, rlResult.highReg);
531 } else if (secondOp == kOpAdc) {
532 withCarryHelper(cUnit, kMipsAddu, rlResult, rlSrc1, rlResult,
533 rlResult.lowReg, rlSrc1.lowReg);
534 } else {
535 withCarryHelper(cUnit, kMipsSubu, rlResult, rlSrc1, rlResult,
536 rlSrc1.lowReg, rlResult.lowReg);
537 }
538 storeValueWide(cUnit, rlDest, rlResult);
539 } else {
540 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
541 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
542 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
543 if (!carryOp) {
544 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
545 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg, rlSrc2.highReg);
546 } else if (secondOp == kOpAdc) {
547 withCarryHelper(cUnit, kMipsAddu, rlResult, rlSrc1, rlSrc2,
548 rlResult.lowReg, rlSrc1.lowReg);
549 } else {
550 withCarryHelper(cUnit, kMipsSubu, rlResult, rlSrc1, rlSrc2,
551 rlSrc1.lowReg, rlResult.lowReg);
552 }
553 storeValueWide(cUnit, rlDest, rlResult);
554 }
555#endif
556}
557
558void oatInitializeRegAlloc(CompilationUnit* cUnit)
559{
560 int numRegs = sizeof(coreRegs)/sizeof(*coreRegs);
561 int numReserved = sizeof(reservedRegs)/sizeof(*reservedRegs);
562 int numTemps = sizeof(coreTemps)/sizeof(*coreTemps);
563#ifdef __mips_hard_float
564 int numFPRegs = sizeof(fpRegs)/sizeof(*fpRegs);
565 int numFPTemps = sizeof(fpTemps)/sizeof(*fpTemps);
566#else
567 int numFPRegs = 0;
568 int numFPTemps = 0;
569#endif
570 RegisterPool *pool = (RegisterPool *)oatNew(cUnit, sizeof(*pool), true,
571 kAllocRegAlloc);
572 cUnit->regPool = pool;
573 pool->numCoreRegs = numRegs;
574 pool->coreRegs = (RegisterInfo *)
575 oatNew(cUnit, numRegs * sizeof(*cUnit->regPool->coreRegs),
576 true, kAllocRegAlloc);
577 pool->numFPRegs = numFPRegs;
578 pool->FPRegs = numFPRegs == 0 ? NULL : (RegisterInfo *)
579 oatNew(cUnit, numFPRegs * sizeof(*cUnit->regPool->FPRegs), true,
580 kAllocRegAlloc);
581 oatInitPool(pool->coreRegs, coreRegs, pool->numCoreRegs);
582 oatInitPool(pool->FPRegs, fpRegs, pool->numFPRegs);
583 // Keep special registers from being allocated
584 for (int i = 0; i < numReserved; i++) {
585 if (NO_SUSPEND && !cUnit->genDebugger &&
586 (reservedRegs[i] == rSUSPEND)) {
587 //To measure cost of suspend check
588 continue;
589 }
590 oatMarkInUse(cUnit, reservedRegs[i]);
591 }
592 // Mark temp regs - all others not in use can be used for promotion
593 for (int i = 0; i < numTemps; i++) {
594 oatMarkTemp(cUnit, coreTemps[i]);
595 }
596 for (int i = 0; i < numFPTemps; i++) {
597 oatMarkTemp(cUnit, fpTemps[i]);
598 }
599 // Construct the alias map.
600 cUnit->phiAliasMap = (int*)oatNew(cUnit, cUnit->numSSARegs *
601 sizeof(cUnit->phiAliasMap[0]), false,
602 kAllocDFInfo);
603 for (int i = 0; i < cUnit->numSSARegs; i++) {
604 cUnit->phiAliasMap[i] = i;
605 }
606 for (MIR* phi = cUnit->phiList; phi; phi = phi->meta.phiNext) {
607 int defReg = phi->ssaRep->defs[0];
608 for (int i = 0; i < phi->ssaRep->numUses; i++) {
609 for (int j = 0; j < cUnit->numSSARegs; j++) {
610 if (cUnit->phiAliasMap[j] == phi->ssaRep->uses[i]) {
611 cUnit->phiAliasMap[j] = defReg;
612 }
613 }
614 }
615 }
616}
617
618STATIC void genMonitor(CompilationUnit *cUnit, MIR *mir)
619{
620 UNIMPLEMENTED(FATAL) << "Need Mips implementation";
621#if 0
622 genMonitorPortable(cUnit, mir);
623#endif
624}
625
626STATIC void genCmpLong(CompilationUnit *cUnit, MIR *mir, RegLocation rlDest,
627 RegLocation rlSrc1, RegLocation rlSrc2)
628{
629 UNIMPLEMENTED(FATAL) << "Need Mips implementation";
630#if 0
631 RegLocation rlResult;
632 loadValueDirectWideFixed(cUnit, rlSrc1, r_ARG0, r_ARG1);
633 loadValueDirectWideFixed(cUnit, rlSrc2, r_ARG2, r_ARG3);
634 genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG);
635 rlResult = oatGetReturn(cUnit);
636 storeValue(cUnit, rlDest, rlResult);
637#endif
638}
639
640STATIC void genMultiplyByTwoBitMultiplier(CompilationUnit *cUnit,
641 RegLocation rlSrc, RegLocation rlResult, int lit,
642 int firstBit, int secondBit)
643{
644 // We can't implement "add src, src, src, lsl#shift" on Thumb, so we have
645 // to do a regular multiply.
646 opRegRegImm(cUnit, kOpMul, rlResult.lowReg, rlSrc.lowReg, lit);
647}
648
649} // namespace art