blob: 3f7a7aef538101b607a258d0068cc32afb691c0f [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -07001/*
2 * Copyright (C) 2011 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 Thumb2 ISA and is intended to be
19 * includes by:
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 */
24
buzbee34cd9e52011-09-08 14:31:52 -070025#define SLOW_FIELD_PATH 0
26#define SLOW_INVOKE_PATH 0
buzbee34cd9e52011-09-08 14:31:52 -070027//#define EXERCISE_SLOWEST_FIELD_PATH
28
29std::string fieldNameFromIndex(const Method* method, uint32_t fieldIdx)
30{
31 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
32 const art::DexFile& dex_file = class_linker->FindDexFile(
33 method->GetDeclaringClass()->GetDexCache());
34 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
Elliott Hughes2bb97f92011-09-11 15:43:37 -070035 std::string class_name = dex_file.dexStringByTypeIdx(field_id.class_idx_);
buzbee34cd9e52011-09-08 14:31:52 -070036 std::string field_name = dex_file.dexStringById(field_id.name_idx_);
37 return class_name + "." + field_name;
38}
39
Elliott Hughes81bc5092011-09-30 17:25:59 -070040void warnIfUnresolved(CompilationUnit* cUnit, int fieldIdx, Field* field) {
41 if (field == NULL) {
42 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
43 << " unresolved at compile time";
44 } else {
45 // We also use the slow path for wide volatile fields.
46 }
47}
48
buzbee67bf8852011-08-17 17:51:35 -070049/*
50 * Construct an s4 from two consecutive half-words of switch data.
51 * This needs to check endianness because the DEX optimizer only swaps
52 * half-words in instruction stream.
53 *
54 * "switchData" must be 32-bit aligned.
55 */
56#if __BYTE_ORDER == __LITTLE_ENDIAN
buzbeeed3e9302011-09-23 17:34:19 -070057STATIC inline s4 s4FromSwitchData(const void* switchData) {
buzbee67bf8852011-08-17 17:51:35 -070058 return *(s4*) switchData;
59}
60#else
buzbeeed3e9302011-09-23 17:34:19 -070061STATIC inline s4 s4FromSwitchData(const void* switchData) {
buzbee67bf8852011-08-17 17:51:35 -070062 u2* data = switchData;
63 return data[0] | (((s4) data[1]) << 16);
64}
65#endif
66
buzbeeed3e9302011-09-23 17:34:19 -070067STATIC ArmLIR* callRuntimeHelper(CompilationUnit* cUnit, int reg)
buzbeeec5adf32011-09-11 15:25:43 -070068{
buzbee6181f792011-09-29 11:14:04 -070069 oatClobberCalleeSave(cUnit);
buzbeeec5adf32011-09-11 15:25:43 -070070 return opReg(cUnit, kOpBlx, reg);
71}
72
buzbee1b4c8592011-08-31 10:43:51 -070073/* Generate unconditional branch instructions */
buzbeeed3e9302011-09-23 17:34:19 -070074STATIC ArmLIR* genUnconditionalBranch(CompilationUnit* cUnit, ArmLIR* target)
buzbee1b4c8592011-08-31 10:43:51 -070075{
76 ArmLIR* branch = opNone(cUnit, kOpUncondBr);
77 branch->generic.target = (LIR*) target;
78 return branch;
79}
80
buzbee67bf8852011-08-17 17:51:35 -070081/*
82 * Generate a Thumb2 IT instruction, which can nullify up to
83 * four subsequent instructions based on a condition and its
84 * inverse. The condition applies to the first instruction, which
85 * is executed if the condition is met. The string "guide" consists
86 * of 0 to 3 chars, and applies to the 2nd through 4th instruction.
87 * A "T" means the instruction is executed if the condition is
88 * met, and an "E" means the instruction is executed if the condition
89 * is not met.
90 */
buzbeeed3e9302011-09-23 17:34:19 -070091STATIC ArmLIR* genIT(CompilationUnit* cUnit, ArmConditionCode code,
buzbee67bf8852011-08-17 17:51:35 -070092 const char* guide)
93{
94 int mask;
95 int condBit = code & 1;
96 int altBit = condBit ^ 1;
97 int mask3 = 0;
98 int mask2 = 0;
99 int mask1 = 0;
100
101 //Note: case fallthroughs intentional
102 switch(strlen(guide)) {
103 case 3:
104 mask1 = (guide[2] == 'T') ? condBit : altBit;
105 case 2:
106 mask2 = (guide[1] == 'T') ? condBit : altBit;
107 case 1:
108 mask3 = (guide[0] == 'T') ? condBit : altBit;
109 break;
110 case 0:
111 break;
112 default:
113 LOG(FATAL) << "OAT: bad case in genIT";
114 }
115 mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
116 (1 << (3 - strlen(guide)));
117 return newLIR2(cUnit, kThumb2It, code, mask);
118}
119
120/*
121 * Insert a kArmPseudoCaseLabel at the beginning of the Dalvik
122 * offset vaddr. This label will be used to fix up the case
123 * branch table during the assembly phase. Be sure to set
124 * all resource flags on this to prevent code motion across
125 * target boundaries. KeyVal is just there for debugging.
126 */
buzbeeed3e9302011-09-23 17:34:19 -0700127STATIC ArmLIR* insertCaseLabel(CompilationUnit* cUnit, int vaddr, int keyVal)
buzbee67bf8852011-08-17 17:51:35 -0700128{
129 ArmLIR* lir;
130 for (lir = (ArmLIR*)cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
131 if ((lir->opcode == kArmPseudoDalvikByteCodeBoundary) &&
132 (lir->generic.dalvikOffset == vaddr)) {
133 ArmLIR* newLabel = (ArmLIR*)oatNew(sizeof(ArmLIR), true);
134 newLabel->generic.dalvikOffset = vaddr;
135 newLabel->opcode = kArmPseudoCaseLabel;
136 newLabel->operands[0] = keyVal;
137 oatInsertLIRAfter((LIR*)lir, (LIR*)newLabel);
138 return newLabel;
139 }
140 }
141 oatCodegenDump(cUnit);
142 LOG(FATAL) << "Error: didn't find vaddr 0x" << std::hex << vaddr;
143 return NULL; // Quiet gcc
144}
145
buzbeeed3e9302011-09-23 17:34:19 -0700146STATIC void markPackedCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
buzbee67bf8852011-08-17 17:51:35 -0700147{
148 const u2* table = tabRec->table;
149 int baseVaddr = tabRec->vaddr;
150 int *targets = (int*)&table[4];
151 int entries = table[1];
152 int lowKey = s4FromSwitchData(&table[2]);
153 for (int i = 0; i < entries; i++) {
154 tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
155 i + lowKey);
156 }
157}
158
buzbeeed3e9302011-09-23 17:34:19 -0700159STATIC void markSparseCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
buzbee67bf8852011-08-17 17:51:35 -0700160{
161 const u2* table = tabRec->table;
162 int baseVaddr = tabRec->vaddr;
163 int entries = table[1];
164 int* keys = (int*)&table[2];
165 int* targets = &keys[entries];
166 for (int i = 0; i < entries; i++) {
167 tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
168 keys[i]);
169 }
170}
171
172void oatProcessSwitchTables(CompilationUnit* cUnit)
173{
174 GrowableListIterator iterator;
175 oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
176 while (true) {
177 SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
178 &iterator);
179 if (tabRec == NULL) break;
180 if (tabRec->table[0] == kPackedSwitchSignature)
181 markPackedCaseLabels(cUnit, tabRec);
182 else if (tabRec->table[0] == kSparseSwitchSignature)
183 markSparseCaseLabels(cUnit, tabRec);
184 else {
185 LOG(FATAL) << "Invalid switch table";
186 }
187 }
188}
189
buzbeeed3e9302011-09-23 17:34:19 -0700190STATIC void dumpSparseSwitchTable(const u2* table)
buzbee67bf8852011-08-17 17:51:35 -0700191 /*
192 * Sparse switch data format:
193 * ushort ident = 0x0200 magic value
194 * ushort size number of entries in the table; > 0
195 * int keys[size] keys, sorted low-to-high; 32-bit aligned
196 * int targets[size] branch targets, relative to switch opcode
197 *
198 * Total size is (2+size*4) 16-bit code units.
199 */
200{
201 u2 ident = table[0];
202 int entries = table[1];
203 int* keys = (int*)&table[2];
204 int* targets = &keys[entries];
205 LOG(INFO) << "Sparse switch table - ident:0x" << std::hex << ident <<
206 ", entries: " << std::dec << entries;
207 for (int i = 0; i < entries; i++) {
208 LOG(INFO) << " Key[" << keys[i] << "] -> 0x" << std::hex <<
209 targets[i];
210 }
211}
212
buzbeeed3e9302011-09-23 17:34:19 -0700213STATIC void dumpPackedSwitchTable(const u2* table)
buzbee67bf8852011-08-17 17:51:35 -0700214 /*
215 * Packed switch data format:
216 * ushort ident = 0x0100 magic value
217 * ushort size number of entries in the table
218 * int first_key first (and lowest) switch case value
219 * int targets[size] branch targets, relative to switch opcode
220 *
221 * Total size is (4+size*2) 16-bit code units.
222 */
223{
224 u2 ident = table[0];
225 int* targets = (int*)&table[4];
226 int entries = table[1];
227 int lowKey = s4FromSwitchData(&table[2]);
228 LOG(INFO) << "Packed switch table - ident:0x" << std::hex << ident <<
229 ", entries: " << std::dec << entries << ", lowKey: " << lowKey;
230 for (int i = 0; i < entries; i++) {
231 LOG(INFO) << " Key[" << (i + lowKey) << "] -> 0x" << std::hex <<
232 targets[i];
233 }
234}
235
236/*
237 * The sparse table in the literal pool is an array of <key,displacement>
238 * pairs. For each set, we'll load them as a pair using ldmia.
239 * This means that the register number of the temp we use for the key
240 * must be lower than the reg for the displacement.
241 *
242 * The test loop will look something like:
243 *
244 * adr rBase, <table>
245 * ldr rVal, [rSP, vRegOff]
246 * mov rIdx, #tableSize
247 * lp:
248 * ldmia rBase!, {rKey, rDisp}
249 * sub rIdx, #1
250 * cmp rVal, rKey
251 * ifeq
252 * add rPC, rDisp ; This is the branch from which we compute displacement
253 * cbnz rIdx, lp
254 */
buzbeeed3e9302011-09-23 17:34:19 -0700255STATIC void genSparseSwitch(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700256 RegLocation rlSrc)
257{
258 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
259 if (cUnit->printMe) {
260 dumpSparseSwitchTable(table);
261 }
262 // Add the table to the list - we'll process it later
263 SwitchTable *tabRec = (SwitchTable *)oatNew(sizeof(SwitchTable),
264 true);
265 tabRec->table = table;
266 tabRec->vaddr = mir->offset;
267 int size = table[1];
268 tabRec->targets = (ArmLIR* *)oatNew(size * sizeof(ArmLIR*), true);
269 oatInsertGrowableList(&cUnit->switchTables, (intptr_t)tabRec);
270
271 // Get the switch value
272 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
273 int rBase = oatAllocTemp(cUnit);
274 /* Allocate key and disp temps */
275 int rKey = oatAllocTemp(cUnit);
276 int rDisp = oatAllocTemp(cUnit);
277 // Make sure rKey's register number is less than rDisp's number for ldmia
278 if (rKey > rDisp) {
279 int tmp = rDisp;
280 rDisp = rKey;
281 rKey = tmp;
282 }
283 // Materialize a pointer to the switch table
buzbee03fa2632011-09-20 17:10:57 -0700284 newLIR3(cUnit, kThumb2Adr, rBase, 0, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700285 // Set up rIdx
286 int rIdx = oatAllocTemp(cUnit);
287 loadConstant(cUnit, rIdx, size);
288 // Establish loop branch target
289 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
290 target->defMask = ENCODE_ALL;
291 // Load next key/disp
292 newLIR2(cUnit, kThumb2LdmiaWB, rBase, (1 << rKey) | (1 << rDisp));
293 opRegReg(cUnit, kOpCmp, rKey, rlSrc.lowReg);
294 // Go if match. NOTE: No instruction set switch here - must stay Thumb2
295 genIT(cUnit, kArmCondEq, "");
296 ArmLIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, rDisp);
297 tabRec->bxInst = switchBranch;
298 // Needs to use setflags encoding here
299 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
300 ArmLIR* branch = opCondBranch(cUnit, kArmCondNe);
301 branch->generic.target = (LIR*)target;
302}
303
304
buzbeeed3e9302011-09-23 17:34:19 -0700305STATIC void genPackedSwitch(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700306 RegLocation rlSrc)
307{
308 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
309 if (cUnit->printMe) {
310 dumpPackedSwitchTable(table);
311 }
312 // Add the table to the list - we'll process it later
313 SwitchTable *tabRec = (SwitchTable *)oatNew(sizeof(SwitchTable),
314 true);
315 tabRec->table = table;
316 tabRec->vaddr = mir->offset;
317 int size = table[1];
318 tabRec->targets = (ArmLIR* *)oatNew(size * sizeof(ArmLIR*), true);
319 oatInsertGrowableList(&cUnit->switchTables, (intptr_t)tabRec);
320
321 // Get the switch value
322 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
323 int tableBase = oatAllocTemp(cUnit);
324 // Materialize a pointer to the switch table
buzbee03fa2632011-09-20 17:10:57 -0700325 newLIR3(cUnit, kThumb2Adr, tableBase, 0, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700326 int lowKey = s4FromSwitchData(&table[2]);
327 int keyReg;
328 // Remove the bias, if necessary
329 if (lowKey == 0) {
330 keyReg = rlSrc.lowReg;
331 } else {
332 keyReg = oatAllocTemp(cUnit);
333 opRegRegImm(cUnit, kOpSub, keyReg, rlSrc.lowReg, lowKey);
334 }
335 // Bounds check - if < 0 or >= size continue following switch
336 opRegImm(cUnit, kOpCmp, keyReg, size-1);
337 ArmLIR* branchOver = opCondBranch(cUnit, kArmCondHi);
338
339 // Load the displacement from the switch table
340 int dispReg = oatAllocTemp(cUnit);
341 loadBaseIndexed(cUnit, tableBase, keyReg, dispReg, 2, kWord);
342
343 // ..and go! NOTE: No instruction set switch here - must stay Thumb2
344 ArmLIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, dispReg);
345 tabRec->bxInst = switchBranch;
346
347 /* branchOver target here */
348 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
349 target->defMask = ENCODE_ALL;
350 branchOver->generic.target = (LIR*)target;
351}
352
353/*
354 * Array data table format:
355 * ushort ident = 0x0300 magic value
356 * ushort width width of each element in the table
357 * uint size number of elements in the table
358 * ubyte data[size*width] table of data values (may contain a single-byte
359 * padding at the end)
360 *
361 * Total size is 4+(width * size + 1)/2 16-bit code units.
362 */
buzbeeed3e9302011-09-23 17:34:19 -0700363STATIC void genFillArrayData(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700364 RegLocation rlSrc)
365{
366 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
367 // Add the table to the list - we'll process it later
368 FillArrayData *tabRec = (FillArrayData *)
369 oatNew(sizeof(FillArrayData), true);
370 tabRec->table = table;
371 tabRec->vaddr = mir->offset;
372 u2 width = tabRec->table[1];
373 u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
374 tabRec->size = (size * width) + 8;
375
376 oatInsertGrowableList(&cUnit->fillArrayData, (intptr_t)tabRec);
377
378 // Making a call - use explicit registers
379 oatFlushAllRegs(cUnit); /* Everything to home location */
380 loadValueDirectFixed(cUnit, rlSrc, r0);
381 loadWordDisp(cUnit, rSELF,
buzbee1b4c8592011-08-31 10:43:51 -0700382 OFFSETOF_MEMBER(Thread, pHandleFillArrayDataFromCode), rLR);
buzbeee6d61962011-08-27 11:58:19 -0700383 // Materialize a pointer to the fill data image
buzbee03fa2632011-09-20 17:10:57 -0700384 newLIR3(cUnit, kThumb2Adr, r1, 0, (intptr_t)tabRec);
Ian Rogersff1ed472011-09-20 13:46:24 -0700385 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700386}
387
388/*
389 * Mark garbage collection card. Skip if the value we're storing is null.
390 */
buzbeeed3e9302011-09-23 17:34:19 -0700391STATIC void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg)
buzbee67bf8852011-08-17 17:51:35 -0700392{
Elliott Hughes5ee7a8b2011-09-13 16:40:07 -0700393#ifdef CONCURRENT_GARBAGE_COLLECTOR
buzbee0d966cf2011-09-08 17:34:58 -0700394 // TODO: re-enable when concurrent collector is active
buzbee67bf8852011-08-17 17:51:35 -0700395 int regCardBase = oatAllocTemp(cUnit);
396 int regCardNo = oatAllocTemp(cUnit);
397 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondEq, valReg, 0);
buzbeec143c552011-08-20 17:38:58 -0700398 loadWordDisp(cUnit, rSELF, Thread::CardTableOffset().Int32Value(),
buzbee67bf8852011-08-17 17:51:35 -0700399 regCardBase);
400 opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT);
401 storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
402 kUnsignedByte);
403 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
404 target->defMask = ENCODE_ALL;
405 branchOver->generic.target = (LIR*)target;
406 oatFreeTemp(cUnit, regCardBase);
407 oatFreeTemp(cUnit, regCardNo);
Elliott Hughes0f4c41d2011-09-04 14:58:03 -0700408#endif
buzbee67bf8852011-08-17 17:51:35 -0700409}
410
buzbee34cd9e52011-09-08 14:31:52 -0700411/*
412 * Helper function for Iget/put when field not resolved at compile time.
413 * Will trash call temps and return with the field offset in r0.
414 */
Elliott Hughes81bc5092011-09-30 17:25:59 -0700415STATIC void getFieldOffset(CompilationUnit* cUnit, MIR* mir, Field* fieldPtr)
buzbee34cd9e52011-09-08 14:31:52 -0700416{
417 int fieldIdx = mir->dalvikInsn.vC;
buzbee6181f792011-09-29 11:14:04 -0700418 oatFlushAllRegs(cUnit);
Elliott Hughes81bc5092011-09-30 17:25:59 -0700419 warnIfUnresolved(cUnit, fieldIdx, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700420 oatLockCallTemps(cUnit); // Explicit register usage
421 loadCurrMethodDirect(cUnit, r1); // arg1 <= Method*
422 loadWordDisp(cUnit, r1,
423 Method::DexCacheResolvedFieldsOffset().Int32Value(), r0);
424 loadWordDisp(cUnit, r0, art::Array::DataOffset().Int32Value() +
425 sizeof(int32_t*)* fieldIdx, r0);
426 /*
427 * For testing, omit the test for run-time resolution. This will
428 * force all accesses to go through the runtime resolution path.
429 */
430#ifndef EXERCISE_SLOWEST_FIELD_PATH
431 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0);
432#endif
433 // Resolve
434 loadWordDisp(cUnit, rSELF,
Brian Carlstrom845490b2011-09-19 15:56:53 -0700435 OFFSETOF_MEMBER(Thread, pFindInstanceFieldFromCode), rLR);
buzbee34cd9e52011-09-08 14:31:52 -0700436 loadConstant(cUnit, r0, fieldIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700437 callRuntimeHelper(cUnit, rLR); // resolveTypeFromCode(idx, method)
buzbee34cd9e52011-09-08 14:31:52 -0700438 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
439 target->defMask = ENCODE_ALL;
440#ifndef EXERCISE_SLOWEST_FIELD_PATH
441 branchOver->generic.target = (LIR*)target;
442#endif
443 // Free temps (except for r0)
444 oatFreeTemp(cUnit, r1);
445 oatFreeTemp(cUnit, r2);
446 oatFreeTemp(cUnit, r3);
447 loadWordDisp(cUnit, r0, art::Field::OffsetOffset().Int32Value(), r0);
448}
449
buzbeeed3e9302011-09-23 17:34:19 -0700450STATIC void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -0700451 RegLocation rlDest, RegLocation rlObj)
452{
buzbeec143c552011-08-20 17:38:58 -0700453 Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
454 GetResolvedField(mir->dalvikInsn.vC);
buzbee67bf8852011-08-17 17:51:35 -0700455 RegLocation rlResult;
456 RegisterClass regClass = oatRegClassBySize(size);
buzbee34cd9e52011-09-08 14:31:52 -0700457 if (SLOW_FIELD_PATH || fieldPtr == NULL) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700458 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700459 // Field offset in r0
460 rlObj = loadValue(cUnit, rlObj, kCoreReg);
461 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
buzbee5ade1d22011-09-09 14:44:52 -0700462 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
buzbee58f92742011-10-01 11:22:17 -0700463 loadBaseIndexed(cUnit, rlObj.lowReg, r0, rlResult.lowReg, 0, kWord);
buzbee67bf8852011-08-17 17:51:35 -0700464 oatGenMemBarrier(cUnit, kSY);
buzbee34cd9e52011-09-08 14:31:52 -0700465 storeValue(cUnit, rlDest, rlResult);
466 } else {
467#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700468 bool isVolatile = fieldPtr->IsVolatile();
buzbee34cd9e52011-09-08 14:31:52 -0700469#else
470 bool isVolatile = false;
471#endif
472 int fieldOffset = fieldPtr->GetOffset().Int32Value();
473 rlObj = loadValue(cUnit, rlObj, kCoreReg);
474 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
buzbee5ade1d22011-09-09 14:44:52 -0700475 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
buzbee34cd9e52011-09-08 14:31:52 -0700476 loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
buzbee58f92742011-10-01 11:22:17 -0700477 kWord, rlObj.sRegLow);
buzbee34cd9e52011-09-08 14:31:52 -0700478 if (isVolatile) {
479 oatGenMemBarrier(cUnit, kSY);
480 }
481 storeValue(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -0700482 }
buzbee67bf8852011-08-17 17:51:35 -0700483}
484
buzbeeed3e9302011-09-23 17:34:19 -0700485STATIC void genIPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -0700486 RegLocation rlSrc, RegLocation rlObj, bool isObject)
487{
buzbeec143c552011-08-20 17:38:58 -0700488 Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
489 GetResolvedField(mir->dalvikInsn.vC);
buzbee67bf8852011-08-17 17:51:35 -0700490 RegisterClass regClass = oatRegClassBySize(size);
buzbee34cd9e52011-09-08 14:31:52 -0700491 if (SLOW_FIELD_PATH || fieldPtr == NULL) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700492 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700493 // Field offset in r0
494 rlObj = loadValue(cUnit, rlObj, kCoreReg);
495 rlSrc = loadValue(cUnit, rlSrc, regClass);
buzbee5ade1d22011-09-09 14:44:52 -0700496 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
buzbee67bf8852011-08-17 17:51:35 -0700497 oatGenMemBarrier(cUnit, kSY);
buzbee58f92742011-10-01 11:22:17 -0700498 storeBaseIndexed(cUnit, rlObj.lowReg, r0, rlSrc.lowReg, 0, kWord);
buzbee34cd9e52011-09-08 14:31:52 -0700499 } else {
500#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700501 bool isVolatile = fieldPtr->IsVolatile();
buzbee34cd9e52011-09-08 14:31:52 -0700502#else
503 bool isVolatile = false;
504#endif
505 int fieldOffset = fieldPtr->GetOffset().Int32Value();
506 rlObj = loadValue(cUnit, rlObj, kCoreReg);
507 rlSrc = loadValue(cUnit, rlSrc, regClass);
buzbee5ade1d22011-09-09 14:44:52 -0700508 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700509
510 if (isVolatile) {
buzbee12246b82011-09-29 14:15:05 -0700511 oatGenMemBarrier(cUnit, kST);
buzbee34cd9e52011-09-08 14:31:52 -0700512 }
buzbee58f92742011-10-01 11:22:17 -0700513 storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, kWord);
buzbee12246b82011-09-29 14:15:05 -0700514 if (isVolatile) {
515 oatGenMemBarrier(cUnit, kSY);
516 }
buzbee67bf8852011-08-17 17:51:35 -0700517 }
buzbee67bf8852011-08-17 17:51:35 -0700518 if (isObject) {
519 /* NOTE: marking card based on object head */
520 markGCCard(cUnit, rlSrc.lowReg, rlObj.lowReg);
521 }
522}
523
buzbeeed3e9302011-09-23 17:34:19 -0700524STATIC void genIGetWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700525 RegLocation rlObj)
526{
buzbee12246b82011-09-29 14:15:05 -0700527 RegLocation rlResult;
buzbeec143c552011-08-20 17:38:58 -0700528 Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
529 GetResolvedField(mir->dalvikInsn.vC);
buzbee12246b82011-09-29 14:15:05 -0700530#if ANDROID_SMP != 0
531 bool isVolatile = (fieldPtr == NULL) || fieldPtr->IsVolatile();
532#else
533 bool isVolatile = false;
534#endif
535 if ((fieldPtr == NULL) || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700536 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700537 // Field offset in r0
538 rlObj = loadValue(cUnit, rlObj, kCoreReg);
539 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee5ade1d22011-09-09 14:44:52 -0700540 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700541 opRegReg(cUnit, kOpAdd, r0, rlObj.lowReg);
542 loadPair(cUnit, r0, rlResult.lowReg, rlResult.highReg);
buzbee67bf8852011-08-17 17:51:35 -0700543 oatGenMemBarrier(cUnit, kSY);
buzbee12246b82011-09-29 14:15:05 -0700544 storeValueWide(cUnit, rlDest, rlResult);
buzbee34cd9e52011-09-08 14:31:52 -0700545 } else {
buzbee34cd9e52011-09-08 14:31:52 -0700546 int fieldOffset = fieldPtr->GetOffset().Int32Value();
547 rlObj = loadValue(cUnit, rlObj, kCoreReg);
548 int regPtr = oatAllocTemp(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700549
buzbeeed3e9302011-09-23 17:34:19 -0700550 DCHECK(rlDest.wide);
buzbee34cd9e52011-09-08 14:31:52 -0700551
buzbee5ade1d22011-09-09 14:44:52 -0700552 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700553 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
554 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
555
556 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
557
buzbee34cd9e52011-09-08 14:31:52 -0700558 oatFreeTemp(cUnit, regPtr);
559 storeValueWide(cUnit, rlDest, rlResult);
560 }
buzbee67bf8852011-08-17 17:51:35 -0700561}
562
buzbeeed3e9302011-09-23 17:34:19 -0700563STATIC void genIPutWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
buzbee67bf8852011-08-17 17:51:35 -0700564 RegLocation rlObj)
565{
buzbeec143c552011-08-20 17:38:58 -0700566 Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
567 GetResolvedField(mir->dalvikInsn.vC);
buzbee12246b82011-09-29 14:15:05 -0700568#if ANDROID_SMP != 0
569 bool isVolatile = (fieldPtr == NULL) || fieldPtr->IsVolatile();
570#else
571 bool isVolatile = false;
572#endif
573 if ((fieldPtr == NULL) || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700574 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700575 // Field offset in r0
576 rlObj = loadValue(cUnit, rlObj, kCoreReg);
577 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
buzbee5ade1d22011-09-09 14:44:52 -0700578 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700579 opRegReg(cUnit, kOpAdd, r0, rlObj.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700580 oatGenMemBarrier(cUnit, kSY);
buzbee34cd9e52011-09-08 14:31:52 -0700581 storePair(cUnit, r0, rlSrc.lowReg, rlSrc.highReg);
582 } else {
buzbee34cd9e52011-09-08 14:31:52 -0700583 int fieldOffset = fieldPtr->GetOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -0700584
buzbee34cd9e52011-09-08 14:31:52 -0700585 rlObj = loadValue(cUnit, rlObj, kCoreReg);
586 int regPtr;
587 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
buzbee5ade1d22011-09-09 14:44:52 -0700588 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700589 regPtr = oatAllocTemp(cUnit);
590 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
591
buzbee34cd9e52011-09-08 14:31:52 -0700592 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
593
594 oatFreeTemp(cUnit, regPtr);
595 }
buzbee67bf8852011-08-17 17:51:35 -0700596}
597
buzbeeed3e9302011-09-23 17:34:19 -0700598STATIC void genConstClass(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700599 RegLocation rlDest, RegLocation rlSrc)
600{
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700601 art::Class* classPtr = cUnit->method->GetDexCacheResolvedTypes()->
buzbee1b4c8592011-08-31 10:43:51 -0700602 Get(mir->dalvikInsn.vB);
603 int mReg = loadCurrMethod(cUnit);
604 int resReg = oatAllocTemp(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700605 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbee2a475e72011-09-07 17:19:17 -0700606 loadWordDisp(cUnit, mReg, Method::DexCacheResolvedTypesOffset().Int32Value(),
buzbee1b4c8592011-08-31 10:43:51 -0700607 resReg);
608 loadWordDisp(cUnit, resReg, Array::DataOffset().Int32Value() +
609 (sizeof(String*) * mir->dalvikInsn.vB), rlResult.lowReg);
610 if (classPtr != NULL) {
611 // Fast path, we're done - just store result
612 storeValue(cUnit, rlDest, rlResult);
613 } else {
614 // Slow path. Must test at runtime
buzbee6181f792011-09-29 11:14:04 -0700615 oatFlushAllRegs(cUnit);
buzbee1b4c8592011-08-31 10:43:51 -0700616 ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, rlResult.lowReg,
617 0);
618 // Resolved, store and hop over following code
619 storeValue(cUnit, rlDest, rlResult);
620 ArmLIR* branch2 = genUnconditionalBranch(cUnit,0);
621 // TUNING: move slow path to end & remove unconditional branch
622 ArmLIR* target1 = newLIR0(cUnit, kArmPseudoTargetLabel);
623 target1->defMask = ENCODE_ALL;
624 // Call out to helper, which will return resolved type in r0
625 loadWordDisp(cUnit, rSELF,
626 OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
627 genRegCopy(cUnit, r1, mReg);
628 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
Ian Rogersff1ed472011-09-20 13:46:24 -0700629 callRuntimeHelper(cUnit, rLR);
buzbee1b4c8592011-08-31 10:43:51 -0700630 RegLocation rlResult = oatGetReturn(cUnit);
631 storeValue(cUnit, rlDest, rlResult);
632 // Rejoin code paths
633 ArmLIR* target2 = newLIR0(cUnit, kArmPseudoTargetLabel);
634 target2->defMask = ENCODE_ALL;
635 branch1->generic.target = (LIR*)target1;
636 branch2->generic.target = (LIR*)target2;
637 }
buzbee67bf8852011-08-17 17:51:35 -0700638}
639
buzbeeed3e9302011-09-23 17:34:19 -0700640STATIC void genConstString(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700641 RegLocation rlDest, RegLocation rlSrc)
642{
buzbee1b4c8592011-08-31 10:43:51 -0700643 /* All strings should be available at compile time */
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700644 const art::String* str = cUnit->method->GetDexCacheStrings()->
buzbee1b4c8592011-08-31 10:43:51 -0700645 Get(mir->dalvikInsn.vB);
646 DCHECK(str != NULL);
buzbee67bf8852011-08-17 17:51:35 -0700647
buzbee1b4c8592011-08-31 10:43:51 -0700648 int mReg = loadCurrMethod(cUnit);
649 int resReg = oatAllocTemp(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700650 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700651 loadWordDisp(cUnit, mReg, Method::DexCacheStringsOffset().Int32Value(),
buzbee1b4c8592011-08-31 10:43:51 -0700652 resReg);
653 loadWordDisp(cUnit, resReg, Array::DataOffset().Int32Value() +
654 (sizeof(String*) * mir->dalvikInsn.vB), rlResult.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700655 storeValue(cUnit, rlDest, rlResult);
656}
657
buzbeedfd3d702011-08-28 12:56:51 -0700658/*
659 * Let helper function take care of everything. Will
660 * call Class::NewInstanceFromCode(type_idx, method);
661 */
buzbeeed3e9302011-09-23 17:34:19 -0700662STATIC void genNewInstance(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700663 RegLocation rlDest)
664{
buzbeedfd3d702011-08-28 12:56:51 -0700665 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee67bf8852011-08-17 17:51:35 -0700666 loadWordDisp(cUnit, rSELF,
Brian Carlstrom1f870082011-08-23 16:02:11 -0700667 OFFSETOF_MEMBER(Thread, pAllocObjectFromCode), rLR);
buzbeedfd3d702011-08-28 12:56:51 -0700668 loadCurrMethodDirect(cUnit, r1); // arg1 <= Method*
669 loadConstant(cUnit, r0, mir->dalvikInsn.vB); // arg0 <- type_id
Ian Rogersff1ed472011-09-20 13:46:24 -0700670 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700671 RegLocation rlResult = oatGetReturn(cUnit);
672 storeValue(cUnit, rlDest, rlResult);
673}
674
675void genThrow(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
676{
buzbee6181f792011-09-29 11:14:04 -0700677 oatFlushAllRegs(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700678 loadWordDisp(cUnit, rSELF,
Ian Rogers67375ac2011-09-14 00:55:44 -0700679 OFFSETOF_MEMBER(Thread, pDeliverException), rLR);
Ian Rogersbdb03912011-09-14 00:55:44 -0700680 loadValueDirectFixed(cUnit, rlSrc, r0); // Get exception object
Ian Rogersff1ed472011-09-20 13:46:24 -0700681 callRuntimeHelper(cUnit, rLR); // art_deliver_exception(exception);
buzbee67bf8852011-08-17 17:51:35 -0700682}
683
buzbeeed3e9302011-09-23 17:34:19 -0700684STATIC void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700685 RegLocation rlSrc)
686{
buzbee6181f792011-09-29 11:14:04 -0700687 oatFlushAllRegs(cUnit);
buzbee2a475e72011-09-07 17:19:17 -0700688 // May generate a call - use explicit registers
689 oatLockCallTemps(cUnit);
690 art::Class* classPtr = cUnit->method->GetDexCacheResolvedTypes()->
691 Get(mir->dalvikInsn.vC);
692 int classReg = r2; // Fixed usage
693 loadCurrMethodDirect(cUnit, r1); // r1 <= current Method*
buzbee991e3ac2011-09-29 15:44:22 -0700694 loadValueDirectFixed(cUnit, rlSrc, r0); /* Ref */
buzbee2a475e72011-09-07 17:19:17 -0700695 loadWordDisp(cUnit, r1, Method::DexCacheResolvedTypesOffset().Int32Value(),
696 classReg);
697 loadWordDisp(cUnit, classReg, Array::DataOffset().Int32Value() +
698 (sizeof(String*) * mir->dalvikInsn.vC), classReg);
buzbee67bf8852011-08-17 17:51:35 -0700699 if (classPtr == NULL) {
buzbee2a475e72011-09-07 17:19:17 -0700700 // Generate a runtime test
701 ArmLIR* hopBranch = genCmpImmBranch(cUnit, kArmCondNe, classReg, 0);
702 // Not resolved
703 // Call out to helper, which will return resolved type in r0
704 loadWordDisp(cUnit, rSELF,
705 OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
706 loadConstant(cUnit, r0, mir->dalvikInsn.vC);
Ian Rogersff1ed472011-09-20 13:46:24 -0700707 callRuntimeHelper(cUnit, rLR); // resolveTypeFromCode(idx, method)
buzbee2a475e72011-09-07 17:19:17 -0700708 genRegCopy(cUnit, r2, r0); // Align usage with fast path
buzbee991e3ac2011-09-29 15:44:22 -0700709 loadValueDirectFixed(cUnit, rlSrc, r0); /* reload Ref */
buzbee2a475e72011-09-07 17:19:17 -0700710 // Rejoin code paths
711 ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
712 hopTarget->defMask = ENCODE_ALL;
713 hopBranch->generic.target = (LIR*)hopTarget;
buzbee67bf8852011-08-17 17:51:35 -0700714 }
buzbee991e3ac2011-09-29 15:44:22 -0700715 /* r0 is ref, r2 is class. If ref==null, use directly as bool result */
716 ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, r0, 0);
buzbee2a475e72011-09-07 17:19:17 -0700717 /* load object->clazz */
buzbeeed3e9302011-09-23 17:34:19 -0700718 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
buzbee991e3ac2011-09-29 15:44:22 -0700719 loadWordDisp(cUnit, r0, Object::ClassOffset().Int32Value(), r1);
720 /* r0 is ref, r1 is ref->clazz, r2 is class */
buzbee67bf8852011-08-17 17:51:35 -0700721 loadWordDisp(cUnit, rSELF,
buzbee1b4c8592011-08-31 10:43:51 -0700722 OFFSETOF_MEMBER(Thread, pInstanceofNonTrivialFromCode), rLR);
buzbee991e3ac2011-09-29 15:44:22 -0700723 opRegReg(cUnit, kOpCmp, r1, r2); // Same?
724 genBarrier(cUnit);
725 genIT(cUnit, kArmCondEq, "EE"); // if-convert the test
726 loadConstant(cUnit, r0, 1); // .eq case - load true
727 genRegCopy(cUnit, r0, r2); // .ne case - arg0 <= class
728 opReg(cUnit, kOpBlx, rLR); // .ne case: helper(class, ref->class)
729 genBarrier(cUnit);
730 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700731 /* branch target here */
732 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
733 target->defMask = ENCODE_ALL;
buzbee2a475e72011-09-07 17:19:17 -0700734 RegLocation rlResult = oatGetReturn(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700735 storeValue(cUnit, rlDest, rlResult);
736 branch1->generic.target = (LIR*)target;
buzbee67bf8852011-08-17 17:51:35 -0700737}
738
buzbeeed3e9302011-09-23 17:34:19 -0700739STATIC void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700740{
buzbee6181f792011-09-29 11:14:04 -0700741 oatFlushAllRegs(cUnit);
buzbee2a475e72011-09-07 17:19:17 -0700742 // May generate a call - use explicit registers
743 oatLockCallTemps(cUnit);
744 art::Class* classPtr = cUnit->method->GetDexCacheResolvedTypes()->
745 Get(mir->dalvikInsn.vB);
746 int classReg = r2; // Fixed usage
747 loadCurrMethodDirect(cUnit, r1); // r1 <= current Method*
748 loadWordDisp(cUnit, r1, Method::DexCacheResolvedTypesOffset().Int32Value(),
749 classReg);
750 loadWordDisp(cUnit, classReg, Array::DataOffset().Int32Value() +
751 (sizeof(String*) * mir->dalvikInsn.vB), classReg);
buzbee67bf8852011-08-17 17:51:35 -0700752 if (classPtr == NULL) {
buzbee2a475e72011-09-07 17:19:17 -0700753 // Generate a runtime test
754 ArmLIR* hopBranch = genCmpImmBranch(cUnit, kArmCondNe, classReg, 0);
755 // Not resolved
756 // Call out to helper, which will return resolved type in r0
757 loadWordDisp(cUnit, rSELF,
758 OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
759 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
Ian Rogersff1ed472011-09-20 13:46:24 -0700760 callRuntimeHelper(cUnit, rLR); // resolveTypeFromCode(idx, method)
buzbee2a475e72011-09-07 17:19:17 -0700761 genRegCopy(cUnit, r2, r0); // Align usage with fast path
762 // Rejoin code paths
763 ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
764 hopTarget->defMask = ENCODE_ALL;
765 hopBranch->generic.target = (LIR*)hopTarget;
buzbee67bf8852011-08-17 17:51:35 -0700766 }
buzbee2a475e72011-09-07 17:19:17 -0700767 // At this point, r2 has class
768 loadValueDirectFixed(cUnit, rlSrc, r0); /* Ref */
769 /* Null is OK - continue */
770 ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, r0, 0);
771 /* load object->clazz */
buzbeeed3e9302011-09-23 17:34:19 -0700772 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
buzbee2a475e72011-09-07 17:19:17 -0700773 loadWordDisp(cUnit, r0, Object::ClassOffset().Int32Value(), r1);
774 /* r1 now contains object->clazz */
buzbee67bf8852011-08-17 17:51:35 -0700775 loadWordDisp(cUnit, rSELF,
buzbee2a475e72011-09-07 17:19:17 -0700776 OFFSETOF_MEMBER(Thread, pCheckCastFromCode), rLR);
777 opRegReg(cUnit, kOpCmp, r1, r2);
778 ArmLIR* branch2 = opCondBranch(cUnit, kArmCondEq); /* If equal, trivial yes */
779 genRegCopy(cUnit, r0, r1);
780 genRegCopy(cUnit, r1, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -0700781 callRuntimeHelper(cUnit, rLR);
buzbee2a475e72011-09-07 17:19:17 -0700782 /* branch target here */
buzbee67bf8852011-08-17 17:51:35 -0700783 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
784 target->defMask = ENCODE_ALL;
785 branch1->generic.target = (LIR*)target;
786 branch2->generic.target = (LIR*)target;
787}
788
buzbeeed3e9302011-09-23 17:34:19 -0700789STATIC void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700790 RegLocation rlSrc)
791{
792 RegLocation rlResult;
793 rlSrc = loadValue(cUnit, rlSrc, kFPReg);
794 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
795 newLIR2(cUnit, kThumb2Vnegs, rlResult.lowReg, rlSrc.lowReg);
796 storeValue(cUnit, rlDest, rlResult);
797}
798
buzbeeed3e9302011-09-23 17:34:19 -0700799STATIC void genNegDouble(CompilationUnit* cUnit, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700800 RegLocation rlSrc)
801{
802 RegLocation rlResult;
803 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
804 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
805 newLIR2(cUnit, kThumb2Vnegd, S2D(rlResult.lowReg, rlResult.highReg),
806 S2D(rlSrc.lowReg, rlSrc.highReg));
807 storeValueWide(cUnit, rlDest, rlResult);
808}
809
buzbeeed3e9302011-09-23 17:34:19 -0700810STATIC void freeRegLocTemps(CompilationUnit* cUnit, RegLocation rlKeep,
buzbee439c4fa2011-08-27 15:59:07 -0700811 RegLocation rlFree)
buzbee67bf8852011-08-17 17:51:35 -0700812{
buzbee6181f792011-09-29 11:14:04 -0700813 if ((rlFree.lowReg != rlKeep.lowReg) && (rlFree.lowReg != rlKeep.highReg) &&
814 (rlFree.highReg != rlKeep.lowReg) && (rlFree.highReg != rlKeep.highReg)) {
815 // No overlap, free both
buzbee439c4fa2011-08-27 15:59:07 -0700816 oatFreeTemp(cUnit, rlFree.lowReg);
buzbee6181f792011-09-29 11:14:04 -0700817 oatFreeTemp(cUnit, rlFree.highReg);
818 }
buzbee67bf8852011-08-17 17:51:35 -0700819}
820
buzbeeed3e9302011-09-23 17:34:19 -0700821STATIC void genLong3Addr(CompilationUnit* cUnit, MIR* mir, OpKind firstOp,
buzbee67bf8852011-08-17 17:51:35 -0700822 OpKind secondOp, RegLocation rlDest,
823 RegLocation rlSrc1, RegLocation rlSrc2)
824{
buzbee9e0f9b02011-08-24 15:32:46 -0700825 /*
826 * NOTE: This is the one place in the code in which we might have
827 * as many as six live temporary registers. There are 5 in the normal
828 * set for Arm. Until we have spill capabilities, temporarily add
829 * lr to the temp set. It is safe to do this locally, but note that
830 * lr is used explicitly elsewhere in the code generator and cannot
831 * normally be used as a general temp register.
832 */
buzbee67bf8852011-08-17 17:51:35 -0700833 RegLocation rlResult;
buzbee9e0f9b02011-08-24 15:32:46 -0700834 oatMarkTemp(cUnit, rLR); // Add lr to the temp pool
835 oatFreeTemp(cUnit, rLR); // and make it available
buzbee67bf8852011-08-17 17:51:35 -0700836 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
837 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
838 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbeec0ecd652011-09-25 18:11:54 -0700839 // The longs may overlap - use intermediate temp if so
840 if (rlResult.lowReg == rlSrc1.highReg) {
buzbeec0ecd652011-09-25 18:11:54 -0700841 int tReg = oatAllocTemp(cUnit);
842 genRegCopy(cUnit, tReg, rlSrc1.highReg);
843 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
844 rlSrc2.lowReg);
845 opRegRegReg(cUnit, secondOp, rlResult.highReg, tReg,
846 rlSrc2.highReg);
847 oatFreeTemp(cUnit, tReg);
848 } else {
849 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
850 rlSrc2.lowReg);
851 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
852 rlSrc2.highReg);
853 }
buzbee439c4fa2011-08-27 15:59:07 -0700854 /*
855 * NOTE: If rlDest refers to a frame variable in a large frame, the
856 * following storeValueWide might need to allocate a temp register.
857 * To further work around the lack of a spill capability, explicitly
858 * free any temps from rlSrc1 & rlSrc2 that aren't still live in rlResult.
859 * Remove when spill is functional.
860 */
861 freeRegLocTemps(cUnit, rlResult, rlSrc1);
862 freeRegLocTemps(cUnit, rlResult, rlSrc2);
buzbee67bf8852011-08-17 17:51:35 -0700863 storeValueWide(cUnit, rlDest, rlResult);
buzbee9e0f9b02011-08-24 15:32:46 -0700864 oatClobber(cUnit, rLR);
865 oatUnmarkTemp(cUnit, rLR); // Remove lr from the temp pool
buzbee67bf8852011-08-17 17:51:35 -0700866}
867
868void oatInitializeRegAlloc(CompilationUnit* cUnit)
869{
870 int numRegs = sizeof(coreRegs)/sizeof(*coreRegs);
871 int numReserved = sizeof(reservedRegs)/sizeof(*reservedRegs);
872 int numTemps = sizeof(coreTemps)/sizeof(*coreTemps);
873 int numFPRegs = sizeof(fpRegs)/sizeof(*fpRegs);
874 int numFPTemps = sizeof(fpTemps)/sizeof(*fpTemps);
875 RegisterPool *pool = (RegisterPool *)oatNew(sizeof(*pool), true);
876 cUnit->regPool = pool;
877 pool->numCoreRegs = numRegs;
878 pool->coreRegs = (RegisterInfo *)
879 oatNew(numRegs * sizeof(*cUnit->regPool->coreRegs), true);
880 pool->numFPRegs = numFPRegs;
881 pool->FPRegs = (RegisterInfo *)
882 oatNew(numFPRegs * sizeof(*cUnit->regPool->FPRegs), true);
883 oatInitPool(pool->coreRegs, coreRegs, pool->numCoreRegs);
884 oatInitPool(pool->FPRegs, fpRegs, pool->numFPRegs);
885 // Keep special registers from being allocated
886 for (int i = 0; i < numReserved; i++) {
buzbeec0ecd652011-09-25 18:11:54 -0700887 if (NO_SUSPEND && (reservedRegs[i] == rSUSPEND)) {
888 //To measure cost of suspend check
889 continue;
890 }
buzbee67bf8852011-08-17 17:51:35 -0700891 oatMarkInUse(cUnit, reservedRegs[i]);
892 }
893 // Mark temp regs - all others not in use can be used for promotion
894 for (int i = 0; i < numTemps; i++) {
895 oatMarkTemp(cUnit, coreTemps[i]);
896 }
897 for (int i = 0; i < numFPTemps; i++) {
898 oatMarkTemp(cUnit, fpTemps[i]);
899 }
buzbeec0ecd652011-09-25 18:11:54 -0700900 // Construct the alias map.
901 cUnit->phiAliasMap = (int*)oatNew(cUnit->numSSARegs *
902 sizeof(cUnit->phiAliasMap[0]), false);
903 for (int i = 0; i < cUnit->numSSARegs; i++) {
904 cUnit->phiAliasMap[i] = i;
905 }
906 for (MIR* phi = cUnit->phiList; phi; phi = phi->meta.phiNext) {
907 int defReg = phi->ssaRep->defs[0];
908 for (int i = 0; i < phi->ssaRep->numUses; i++) {
909 for (int j = 0; j < cUnit->numSSARegs; j++) {
910 if (cUnit->phiAliasMap[j] == phi->ssaRep->uses[i]) {
911 cUnit->phiAliasMap[j] = defReg;
912 }
913 }
914 }
915 }
buzbee67bf8852011-08-17 17:51:35 -0700916}
917
918/*
919 * Handle simple case (thin lock) inline. If it's complicated, bail
920 * out to the heavyweight lock/unlock routines. We'll use dedicated
921 * registers here in order to be in the right position in case we
922 * to bail to dvm[Lock/Unlock]Object(self, object)
923 *
924 * r0 -> self pointer [arg0 for dvm[Lock/Unlock]Object
925 * r1 -> object [arg1 for dvm[Lock/Unlock]Object
926 * r2 -> intial contents of object->lock, later result of strex
927 * r3 -> self->threadId
928 * r12 -> allow to be used by utilities as general temp
929 *
930 * The result of the strex is 0 if we acquire the lock.
931 *
932 * See comments in Sync.c for the layout of the lock word.
933 * Of particular interest to this code is the test for the
934 * simple case - which we handle inline. For monitor enter, the
935 * simple case is thin lock, held by no-one. For monitor exit,
936 * the simple case is thin lock, held by the unlocking thread with
937 * a recurse count of 0.
938 *
939 * A minor complication is that there is a field in the lock word
940 * unrelated to locking: the hash state. This field must be ignored, but
941 * preserved.
942 *
943 */
buzbeeed3e9302011-09-23 17:34:19 -0700944STATIC void genMonitorEnter(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700945 RegLocation rlSrc)
946{
947 ArmLIR* target;
948 ArmLIR* hopTarget;
949 ArmLIR* branch;
950 ArmLIR* hopBranch;
951
952 oatFlushAllRegs(cUnit);
Elliott Hughes5f791332011-09-15 17:45:30 -0700953 DCHECK_EQ(LW_SHAPE_THIN, 0);
buzbee67bf8852011-08-17 17:51:35 -0700954 loadValueDirectFixed(cUnit, rlSrc, r1); // Get obj
buzbee2e748f32011-08-29 21:02:19 -0700955 oatLockCallTemps(cUnit); // Prepare for explicit register usage
buzbee5ade1d22011-09-09 14:44:52 -0700956 genNullCheck(cUnit, rlSrc.sRegLow, r1, mir);
Elliott Hughes54e7df12011-09-16 11:47:04 -0700957 loadWordDisp(cUnit, rSELF, Thread::ThinLockIdOffset().Int32Value(), r3);
buzbee67bf8852011-08-17 17:51:35 -0700958 newLIR3(cUnit, kThumb2Ldrex, r2, r1,
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700959 Object::MonitorOffset().Int32Value() >> 2); // Get object->lock
buzbeec143c552011-08-20 17:38:58 -0700960 // Align owner
Elliott Hughes5f791332011-09-15 17:45:30 -0700961 opRegImm(cUnit, kOpLsl, r3, LW_LOCK_OWNER_SHIFT);
buzbee67bf8852011-08-17 17:51:35 -0700962 // Is lock unheld on lock or held by us (==threadId) on unlock?
Elliott Hughes5f791332011-09-15 17:45:30 -0700963 newLIR4(cUnit, kThumb2Bfi, r3, r2, 0, LW_LOCK_OWNER_SHIFT - 1);
964 newLIR3(cUnit, kThumb2Bfc, r2, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
buzbee67bf8852011-08-17 17:51:35 -0700965 hopBranch = newLIR2(cUnit, kThumb2Cbnz, r2, 0);
buzbeec143c552011-08-20 17:38:58 -0700966 newLIR4(cUnit, kThumb2Strex, r2, r3, r1,
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700967 Object::MonitorOffset().Int32Value() >> 2);
buzbee67bf8852011-08-17 17:51:35 -0700968 oatGenMemBarrier(cUnit, kSY);
969 branch = newLIR2(cUnit, kThumb2Cbz, r2, 0);
970
971 hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
972 hopTarget->defMask = ENCODE_ALL;
973 hopBranch->generic.target = (LIR*)hopTarget;
974
buzbee1b4c8592011-08-31 10:43:51 -0700975 // Go expensive route - artLockObjectFromCode(self, obj);
976 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pLockObjectFromCode),
buzbee67bf8852011-08-17 17:51:35 -0700977 rLR);
978 genRegCopy(cUnit, r0, rSELF);
Ian Rogersff1ed472011-09-20 13:46:24 -0700979 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700980
981 // Resume here
982 target = newLIR0(cUnit, kArmPseudoTargetLabel);
983 target->defMask = ENCODE_ALL;
984 branch->generic.target = (LIR*)target;
985}
986
987/*
988 * For monitor unlock, we don't have to use ldrex/strex. Once
989 * we've determined that the lock is thin and that we own it with
990 * a zero recursion count, it's safe to punch it back to the
991 * initial, unlock thin state with a store word.
992 */
buzbeeed3e9302011-09-23 17:34:19 -0700993STATIC void genMonitorExit(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700994 RegLocation rlSrc)
995{
996 ArmLIR* target;
997 ArmLIR* branch;
998 ArmLIR* hopTarget;
999 ArmLIR* hopBranch;
1000
Elliott Hughes5f791332011-09-15 17:45:30 -07001001 DCHECK_EQ(LW_SHAPE_THIN, 0);
buzbee67bf8852011-08-17 17:51:35 -07001002 oatFlushAllRegs(cUnit);
1003 loadValueDirectFixed(cUnit, rlSrc, r1); // Get obj
buzbee2e748f32011-08-29 21:02:19 -07001004 oatLockCallTemps(cUnit); // Prepare for explicit register usage
buzbee5ade1d22011-09-09 14:44:52 -07001005 genNullCheck(cUnit, rlSrc.sRegLow, r1, mir);
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001006 loadWordDisp(cUnit, r1, Object::MonitorOffset().Int32Value(), r2); // Get lock
Elliott Hughes54e7df12011-09-16 11:47:04 -07001007 loadWordDisp(cUnit, rSELF, Thread::ThinLockIdOffset().Int32Value(), r3);
buzbee67bf8852011-08-17 17:51:35 -07001008 // Is lock unheld on lock or held by us (==threadId) on unlock?
Elliott Hughes5f791332011-09-15 17:45:30 -07001009 opRegRegImm(cUnit, kOpAnd, r12, r2, (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
buzbeec143c552011-08-20 17:38:58 -07001010 // Align owner
Elliott Hughes5f791332011-09-15 17:45:30 -07001011 opRegImm(cUnit, kOpLsl, r3, LW_LOCK_OWNER_SHIFT);
1012 newLIR3(cUnit, kThumb2Bfc, r2, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
buzbee67bf8852011-08-17 17:51:35 -07001013 opRegReg(cUnit, kOpSub, r2, r3);
1014 hopBranch = opCondBranch(cUnit, kArmCondNe);
1015 oatGenMemBarrier(cUnit, kSY);
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001016 storeWordDisp(cUnit, r1, Object::MonitorOffset().Int32Value(), r12);
buzbee67bf8852011-08-17 17:51:35 -07001017 branch = opNone(cUnit, kOpUncondBr);
1018
1019 hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
1020 hopTarget->defMask = ENCODE_ALL;
1021 hopBranch->generic.target = (LIR*)hopTarget;
1022
buzbee1b4c8592011-08-31 10:43:51 -07001023 // Go expensive route - UnlockObjectFromCode(self, obj);
1024 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pUnlockObjectFromCode),
buzbee67bf8852011-08-17 17:51:35 -07001025 rLR);
1026 genRegCopy(cUnit, r0, rSELF);
Ian Rogersff1ed472011-09-20 13:46:24 -07001027 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001028
1029 // Resume here
1030 target = newLIR0(cUnit, kArmPseudoTargetLabel);
1031 target->defMask = ENCODE_ALL;
1032 branch->generic.target = (LIR*)target;
1033}
1034
1035/*
1036 * 64-bit 3way compare function.
1037 * mov rX, #-1
1038 * cmp op1hi, op2hi
1039 * blt done
1040 * bgt flip
1041 * sub rX, op1lo, op2lo (treat as unsigned)
1042 * beq done
1043 * ite hi
1044 * mov(hi) rX, #-1
1045 * mov(!hi) rX, #1
1046 * flip:
1047 * neg rX
1048 * done:
1049 */
buzbeeed3e9302011-09-23 17:34:19 -07001050STATIC void genCmpLong(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001051 RegLocation rlDest, RegLocation rlSrc1,
1052 RegLocation rlSrc2)
1053{
buzbee67bf8852011-08-17 17:51:35 -07001054 ArmLIR* target1;
1055 ArmLIR* target2;
1056 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
1057 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
buzbeeb29e4d12011-09-26 15:05:48 -07001058 int tReg = oatAllocTemp(cUnit);
1059 loadConstant(cUnit, tReg, -1);
buzbee67bf8852011-08-17 17:51:35 -07001060 opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg);
1061 ArmLIR* branch1 = opCondBranch(cUnit, kArmCondLt);
1062 ArmLIR* branch2 = opCondBranch(cUnit, kArmCondGt);
buzbeeb29e4d12011-09-26 15:05:48 -07001063 opRegRegReg(cUnit, kOpSub, tReg, rlSrc1.lowReg, rlSrc2.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001064 ArmLIR* branch3 = opCondBranch(cUnit, kArmCondEq);
1065
1066 genIT(cUnit, kArmCondHi, "E");
buzbeeb29e4d12011-09-26 15:05:48 -07001067 newLIR2(cUnit, kThumb2MovImmShift, tReg, modifiedImmediate(-1));
1068 loadConstant(cUnit, tReg, 1);
buzbee67bf8852011-08-17 17:51:35 -07001069 genBarrier(cUnit);
1070
1071 target2 = newLIR0(cUnit, kArmPseudoTargetLabel);
1072 target2->defMask = -1;
buzbeeb29e4d12011-09-26 15:05:48 -07001073 opRegReg(cUnit, kOpNeg, tReg, tReg);
buzbee67bf8852011-08-17 17:51:35 -07001074
1075 target1 = newLIR0(cUnit, kArmPseudoTargetLabel);
1076 target1->defMask = -1;
1077
buzbeeb29e4d12011-09-26 15:05:48 -07001078 RegLocation rlTemp = LOC_C_RETURN; // Just using as template, will change
1079 rlTemp.lowReg = tReg;
buzbee67bf8852011-08-17 17:51:35 -07001080 storeValue(cUnit, rlDest, rlTemp);
buzbeeb29e4d12011-09-26 15:05:48 -07001081 oatFreeTemp(cUnit, tReg);
buzbee67bf8852011-08-17 17:51:35 -07001082
1083 branch1->generic.target = (LIR*)target1;
1084 branch2->generic.target = (LIR*)target2;
1085 branch3->generic.target = branch1->generic.target;
1086}
1087
buzbeeed3e9302011-09-23 17:34:19 -07001088STATIC void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -07001089 RegLocation rlSrc, RegLocation rlResult, int lit,
1090 int firstBit, int secondBit)
1091{
1092 opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg,
1093 encodeShift(kArmLsl, secondBit - firstBit));
1094 if (firstBit != 0) {
1095 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
1096 }
1097}
1098
buzbeeed3e9302011-09-23 17:34:19 -07001099STATIC bool genConversionCall(CompilationUnit* cUnit, MIR* mir, int funcOffset,
buzbee67bf8852011-08-17 17:51:35 -07001100 int srcSize, int tgtSize)
1101{
1102 /*
1103 * Don't optimize the register usage since it calls out to support
1104 * functions
1105 */
1106 RegLocation rlSrc;
1107 RegLocation rlDest;
1108 oatFlushAllRegs(cUnit); /* Send everything to home location */
1109 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1110 if (srcSize == 1) {
1111 rlSrc = oatGetSrc(cUnit, mir, 0);
1112 loadValueDirectFixed(cUnit, rlSrc, r0);
1113 } else {
1114 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
1115 loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
1116 }
Ian Rogersff1ed472011-09-20 13:46:24 -07001117 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001118 if (tgtSize == 1) {
1119 RegLocation rlResult;
1120 rlDest = oatGetDest(cUnit, mir, 0);
1121 rlResult = oatGetReturn(cUnit);
1122 storeValue(cUnit, rlDest, rlResult);
1123 } else {
1124 RegLocation rlResult;
1125 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1126 rlResult = oatGetReturnWide(cUnit);
1127 storeValueWide(cUnit, rlDest, rlResult);
1128 }
1129 return false;
1130}
1131
buzbeeed3e9302011-09-23 17:34:19 -07001132STATIC bool genArithOpFloatPortable(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001133 RegLocation rlDest, RegLocation rlSrc1,
1134 RegLocation rlSrc2)
1135{
1136 RegLocation rlResult;
1137 int funcOffset;
1138
1139 switch (mir->dalvikInsn.opcode) {
1140 case OP_ADD_FLOAT_2ADDR:
1141 case OP_ADD_FLOAT:
1142 funcOffset = OFFSETOF_MEMBER(Thread, pFadd);
1143 break;
1144 case OP_SUB_FLOAT_2ADDR:
1145 case OP_SUB_FLOAT:
1146 funcOffset = OFFSETOF_MEMBER(Thread, pFsub);
1147 break;
1148 case OP_DIV_FLOAT_2ADDR:
1149 case OP_DIV_FLOAT:
1150 funcOffset = OFFSETOF_MEMBER(Thread, pFdiv);
1151 break;
1152 case OP_MUL_FLOAT_2ADDR:
1153 case OP_MUL_FLOAT:
1154 funcOffset = OFFSETOF_MEMBER(Thread, pFmul);
1155 break;
1156 case OP_REM_FLOAT_2ADDR:
1157 case OP_REM_FLOAT:
1158 funcOffset = OFFSETOF_MEMBER(Thread, pFmodf);
1159 break;
1160 case OP_NEG_FLOAT: {
1161 genNegFloat(cUnit, rlDest, rlSrc1);
1162 return false;
1163 }
1164 default:
1165 return true;
1166 }
1167 oatFlushAllRegs(cUnit); /* Send everything to home location */
1168 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1169 loadValueDirectFixed(cUnit, rlSrc1, r0);
1170 loadValueDirectFixed(cUnit, rlSrc2, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -07001171 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001172 rlResult = oatGetReturn(cUnit);
1173 storeValue(cUnit, rlDest, rlResult);
1174 return false;
1175}
1176
buzbeeed3e9302011-09-23 17:34:19 -07001177STATIC bool genArithOpDoublePortable(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001178 RegLocation rlDest, RegLocation rlSrc1,
1179 RegLocation rlSrc2)
1180{
1181 RegLocation rlResult;
1182 int funcOffset;
1183
1184 switch (mir->dalvikInsn.opcode) {
1185 case OP_ADD_DOUBLE_2ADDR:
1186 case OP_ADD_DOUBLE:
1187 funcOffset = OFFSETOF_MEMBER(Thread, pDadd);
1188 break;
1189 case OP_SUB_DOUBLE_2ADDR:
1190 case OP_SUB_DOUBLE:
1191 funcOffset = OFFSETOF_MEMBER(Thread, pDsub);
1192 break;
1193 case OP_DIV_DOUBLE_2ADDR:
1194 case OP_DIV_DOUBLE:
1195 funcOffset = OFFSETOF_MEMBER(Thread, pDdiv);
1196 break;
1197 case OP_MUL_DOUBLE_2ADDR:
1198 case OP_MUL_DOUBLE:
1199 funcOffset = OFFSETOF_MEMBER(Thread, pDmul);
1200 break;
1201 case OP_REM_DOUBLE_2ADDR:
1202 case OP_REM_DOUBLE:
1203 funcOffset = OFFSETOF_MEMBER(Thread, pFmod);
1204 break;
1205 case OP_NEG_DOUBLE: {
1206 genNegDouble(cUnit, rlDest, rlSrc1);
1207 return false;
1208 }
1209 default:
1210 return true;
1211 }
1212 oatFlushAllRegs(cUnit); /* Send everything to home location */
1213 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1214 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1215 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
Ian Rogersff1ed472011-09-20 13:46:24 -07001216 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001217 rlResult = oatGetReturnWide(cUnit);
1218 storeValueWide(cUnit, rlDest, rlResult);
1219 return false;
1220}
1221
buzbeeed3e9302011-09-23 17:34:19 -07001222STATIC bool genConversionPortable(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001223{
1224 Opcode opcode = mir->dalvikInsn.opcode;
1225
1226 switch (opcode) {
1227 case OP_INT_TO_FLOAT:
1228 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2f),
1229 1, 1);
1230 case OP_FLOAT_TO_INT:
1231 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2iz),
1232 1, 1);
1233 case OP_DOUBLE_TO_FLOAT:
1234 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2f),
1235 2, 1);
1236 case OP_FLOAT_TO_DOUBLE:
1237 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2d),
1238 1, 2);
1239 case OP_INT_TO_DOUBLE:
1240 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2d),
1241 1, 2);
1242 case OP_DOUBLE_TO_INT:
1243 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2iz),
1244 2, 1);
1245 case OP_FLOAT_TO_LONG:
1246 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
buzbee1b4c8592011-08-31 10:43:51 -07001247 pF2l), 1, 2);
buzbee67bf8852011-08-17 17:51:35 -07001248 case OP_LONG_TO_FLOAT:
1249 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2f),
1250 2, 1);
1251 case OP_DOUBLE_TO_LONG:
1252 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
buzbee1b4c8592011-08-31 10:43:51 -07001253 pD2l), 2, 2);
buzbee67bf8852011-08-17 17:51:35 -07001254 case OP_LONG_TO_DOUBLE:
1255 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2d),
1256 2, 2);
1257 default:
1258 return true;
1259 }
1260 return false;
1261}
1262
1263/* Generate conditional branch instructions */
buzbeeed3e9302011-09-23 17:34:19 -07001264STATIC ArmLIR* genConditionalBranch(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -07001265 ArmConditionCode cond,
1266 ArmLIR* target)
1267{
1268 ArmLIR* branch = opCondBranch(cUnit, cond);
1269 branch->generic.target = (LIR*) target;
1270 return branch;
1271}
1272
buzbee67bf8852011-08-17 17:51:35 -07001273/*
1274 * Generate array store
1275 *
1276 */
buzbeeed3e9302011-09-23 17:34:19 -07001277STATIC void genArrayObjPut(CompilationUnit* cUnit, MIR* mir,
buzbee1b4c8592011-08-31 10:43:51 -07001278 RegLocation rlArray, RegLocation rlIndex,
1279 RegLocation rlSrc, int scale)
buzbee67bf8852011-08-17 17:51:35 -07001280{
1281 RegisterClass regClass = oatRegClassBySize(kWord);
buzbeec143c552011-08-20 17:38:58 -07001282 int lenOffset = Array::LengthOffset().Int32Value();
1283 int dataOffset = Array::DataOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001284
buzbee6181f792011-09-29 11:14:04 -07001285 oatFlushAllRegs(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001286 /* Make sure it's a legal object Put. Use direct regs at first */
1287 loadValueDirectFixed(cUnit, rlArray, r1);
1288 loadValueDirectFixed(cUnit, rlSrc, r0);
1289
1290 /* null array object? */
buzbee43a36422011-09-14 14:00:13 -07001291 genNullCheck(cUnit, rlArray.sRegLow, r1, mir);
buzbee67bf8852011-08-17 17:51:35 -07001292 loadWordDisp(cUnit, rSELF,
buzbee1b4c8592011-08-31 10:43:51 -07001293 OFFSETOF_MEMBER(Thread, pCanPutArrayElementFromCode), rLR);
buzbee67bf8852011-08-17 17:51:35 -07001294 /* Get the array's clazz */
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001295 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), r1);
Ian Rogersff1ed472011-09-20 13:46:24 -07001296 callRuntimeHelper(cUnit, rLR);
buzbee6181f792011-09-29 11:14:04 -07001297 oatFreeTemp(cUnit, r0);
1298 oatFreeTemp(cUnit, r1);
buzbee67bf8852011-08-17 17:51:35 -07001299
1300 // Now, redo loadValues in case they didn't survive the call
1301
1302 int regPtr;
1303 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1304 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1305
1306 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1307 oatClobber(cUnit, rlArray.lowReg);
1308 regPtr = rlArray.lowReg;
1309 } else {
1310 regPtr = oatAllocTemp(cUnit);
1311 genRegCopy(cUnit, regPtr, rlArray.lowReg);
1312 }
1313
buzbee43a36422011-09-14 14:00:13 -07001314 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee67bf8852011-08-17 17:51:35 -07001315 int regLen = oatAllocTemp(cUnit);
1316 //NOTE: max live temps(4) here.
1317 /* Get len */
1318 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1319 /* regPtr -> array data */
1320 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
buzbeeec5adf32011-09-11 15:25:43 -07001321 genRegRegCheck(cUnit, kArmCondCs, rlIndex.lowReg, regLen, mir,
buzbee5ade1d22011-09-09 14:44:52 -07001322 kArmThrowArrayBounds);
buzbee67bf8852011-08-17 17:51:35 -07001323 oatFreeTemp(cUnit, regLen);
1324 } else {
1325 /* regPtr -> array data */
1326 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1327 }
1328 /* at this point, regPtr points to array, 2 live temps */
1329 rlSrc = loadValue(cUnit, rlSrc, regClass);
1330 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1331 scale, kWord);
1332}
1333
1334/*
1335 * Generate array load
1336 */
buzbeeed3e9302011-09-23 17:34:19 -07001337STATIC void genArrayGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -07001338 RegLocation rlArray, RegLocation rlIndex,
1339 RegLocation rlDest, int scale)
1340{
1341 RegisterClass regClass = oatRegClassBySize(size);
buzbeec143c552011-08-20 17:38:58 -07001342 int lenOffset = Array::LengthOffset().Int32Value();
1343 int dataOffset = Array::DataOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001344 RegLocation rlResult;
1345 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1346 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1347 int regPtr;
1348
1349 /* null object? */
buzbee43a36422011-09-14 14:00:13 -07001350 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001351
1352 regPtr = oatAllocTemp(cUnit);
1353
buzbee43a36422011-09-14 14:00:13 -07001354 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee67bf8852011-08-17 17:51:35 -07001355 int regLen = oatAllocTemp(cUnit);
1356 /* Get len */
1357 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1358 /* regPtr -> array data */
1359 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
buzbeeec5adf32011-09-11 15:25:43 -07001360 genRegRegCheck(cUnit, kArmCondCs, rlIndex.lowReg, regLen, mir,
buzbee5ade1d22011-09-09 14:44:52 -07001361 kArmThrowArrayBounds);
buzbee67bf8852011-08-17 17:51:35 -07001362 oatFreeTemp(cUnit, regLen);
1363 } else {
1364 /* regPtr -> array data */
1365 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1366 }
buzbeee9a72f62011-09-04 17:59:07 -07001367 oatFreeTemp(cUnit, rlArray.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001368 if ((size == kLong) || (size == kDouble)) {
1369 if (scale) {
1370 int rNewIndex = oatAllocTemp(cUnit);
1371 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1372 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1373 oatFreeTemp(cUnit, rNewIndex);
1374 } else {
1375 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1376 }
buzbeee9a72f62011-09-04 17:59:07 -07001377 oatFreeTemp(cUnit, rlIndex.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001378 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1379
1380 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1381
1382 oatFreeTemp(cUnit, regPtr);
1383 storeValueWide(cUnit, rlDest, rlResult);
1384 } else {
1385 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1386
1387 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
1388 scale, size);
1389
1390 oatFreeTemp(cUnit, regPtr);
1391 storeValue(cUnit, rlDest, rlResult);
1392 }
1393}
1394
1395/*
1396 * Generate array store
1397 *
1398 */
buzbeeed3e9302011-09-23 17:34:19 -07001399STATIC void genArrayPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -07001400 RegLocation rlArray, RegLocation rlIndex,
1401 RegLocation rlSrc, int scale)
1402{
1403 RegisterClass regClass = oatRegClassBySize(size);
buzbeec143c552011-08-20 17:38:58 -07001404 int lenOffset = Array::LengthOffset().Int32Value();
1405 int dataOffset = Array::DataOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001406
1407 int regPtr;
1408 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1409 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1410
1411 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1412 oatClobber(cUnit, rlArray.lowReg);
1413 regPtr = rlArray.lowReg;
1414 } else {
1415 regPtr = oatAllocTemp(cUnit);
1416 genRegCopy(cUnit, regPtr, rlArray.lowReg);
1417 }
1418
1419 /* null object? */
buzbee43a36422011-09-14 14:00:13 -07001420 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001421
buzbee43a36422011-09-14 14:00:13 -07001422 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee67bf8852011-08-17 17:51:35 -07001423 int regLen = oatAllocTemp(cUnit);
1424 //NOTE: max live temps(4) here.
1425 /* Get len */
1426 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1427 /* regPtr -> array data */
1428 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
buzbeeec5adf32011-09-11 15:25:43 -07001429 genRegRegCheck(cUnit, kArmCondCs, rlIndex.lowReg, regLen, mir,
buzbee5ade1d22011-09-09 14:44:52 -07001430 kArmThrowArrayBounds);
buzbee67bf8852011-08-17 17:51:35 -07001431 oatFreeTemp(cUnit, regLen);
1432 } else {
1433 /* regPtr -> array data */
1434 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1435 }
1436 /* at this point, regPtr points to array, 2 live temps */
1437 if ((size == kLong) || (size == kDouble)) {
buzbee5ade1d22011-09-09 14:44:52 -07001438 //TUNING: specific wide routine that can handle fp regs
buzbee67bf8852011-08-17 17:51:35 -07001439 if (scale) {
1440 int rNewIndex = oatAllocTemp(cUnit);
1441 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1442 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1443 oatFreeTemp(cUnit, rNewIndex);
1444 } else {
1445 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1446 }
1447 rlSrc = loadValueWide(cUnit, rlSrc, regClass);
1448
1449 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
1450
1451 oatFreeTemp(cUnit, regPtr);
1452 } else {
1453 rlSrc = loadValue(cUnit, rlSrc, regClass);
1454
1455 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1456 scale, size);
1457 }
1458}
1459
buzbeeed3e9302011-09-23 17:34:19 -07001460STATIC bool genShiftOpLong(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001461 RegLocation rlDest, RegLocation rlSrc1,
1462 RegLocation rlShift)
1463{
buzbee54330722011-08-23 16:46:55 -07001464 int funcOffset;
buzbee67bf8852011-08-17 17:51:35 -07001465
buzbee67bf8852011-08-17 17:51:35 -07001466 switch( mir->dalvikInsn.opcode) {
1467 case OP_SHL_LONG:
1468 case OP_SHL_LONG_2ADDR:
buzbee54330722011-08-23 16:46:55 -07001469 funcOffset = OFFSETOF_MEMBER(Thread, pShlLong);
buzbee67bf8852011-08-17 17:51:35 -07001470 break;
1471 case OP_SHR_LONG:
1472 case OP_SHR_LONG_2ADDR:
buzbee54330722011-08-23 16:46:55 -07001473 funcOffset = OFFSETOF_MEMBER(Thread, pShrLong);
buzbee67bf8852011-08-17 17:51:35 -07001474 break;
1475 case OP_USHR_LONG:
1476 case OP_USHR_LONG_2ADDR:
buzbee54330722011-08-23 16:46:55 -07001477 funcOffset = OFFSETOF_MEMBER(Thread, pUshrLong);
buzbee67bf8852011-08-17 17:51:35 -07001478 break;
1479 default:
buzbee54330722011-08-23 16:46:55 -07001480 LOG(FATAL) << "Unexpected case";
buzbee67bf8852011-08-17 17:51:35 -07001481 return true;
1482 }
buzbee54330722011-08-23 16:46:55 -07001483 oatFlushAllRegs(cUnit); /* Send everything to home location */
1484 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1485 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1486 loadValueDirect(cUnit, rlShift, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -07001487 callRuntimeHelper(cUnit, rLR);
buzbee54330722011-08-23 16:46:55 -07001488 RegLocation rlResult = oatGetReturnWide(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001489 storeValueWide(cUnit, rlDest, rlResult);
1490 return false;
1491}
1492
buzbeeed3e9302011-09-23 17:34:19 -07001493STATIC bool genArithOpLong(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001494 RegLocation rlDest, RegLocation rlSrc1,
1495 RegLocation rlSrc2)
1496{
1497 RegLocation rlResult;
1498 OpKind firstOp = kOpBkpt;
1499 OpKind secondOp = kOpBkpt;
1500 bool callOut = false;
buzbee58f92742011-10-01 11:22:17 -07001501 bool checkZero = false;
buzbee67bf8852011-08-17 17:51:35 -07001502 int funcOffset;
1503 int retReg = r0;
1504
1505 switch (mir->dalvikInsn.opcode) {
1506 case OP_NOT_LONG:
1507 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1508 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbeeb29e4d12011-09-26 15:05:48 -07001509 // Check for destructive overlap
1510 if (rlResult.lowReg == rlSrc2.highReg) {
1511 int tReg = oatAllocTemp(cUnit);
1512 genRegCopy(cUnit, tReg, rlSrc2.highReg);
1513 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1514 opRegReg(cUnit, kOpMvn, rlResult.highReg, tReg);
1515 oatFreeTemp(cUnit, tReg);
1516 } else {
1517 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1518 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
1519 }
buzbee67bf8852011-08-17 17:51:35 -07001520 storeValueWide(cUnit, rlDest, rlResult);
1521 return false;
1522 break;
1523 case OP_ADD_LONG:
1524 case OP_ADD_LONG_2ADDR:
1525 firstOp = kOpAdd;
1526 secondOp = kOpAdc;
1527 break;
1528 case OP_SUB_LONG:
1529 case OP_SUB_LONG_2ADDR:
1530 firstOp = kOpSub;
1531 secondOp = kOpSbc;
1532 break;
1533 case OP_MUL_LONG:
1534 case OP_MUL_LONG_2ADDR:
buzbee439c4fa2011-08-27 15:59:07 -07001535 callOut = true;
1536 retReg = r0;
1537 funcOffset = OFFSETOF_MEMBER(Thread, pLmul);
1538 break;
buzbee67bf8852011-08-17 17:51:35 -07001539 case OP_DIV_LONG:
1540 case OP_DIV_LONG_2ADDR:
1541 callOut = true;
buzbee58f92742011-10-01 11:22:17 -07001542 checkZero = true;
buzbee67bf8852011-08-17 17:51:35 -07001543 retReg = r0;
1544 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
1545 break;
1546 /* NOTE - result is in r2/r3 instead of r0/r1 */
1547 case OP_REM_LONG:
1548 case OP_REM_LONG_2ADDR:
1549 callOut = true;
buzbee58f92742011-10-01 11:22:17 -07001550 checkZero = true;
buzbee67bf8852011-08-17 17:51:35 -07001551 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
1552 retReg = r2;
1553 break;
1554 case OP_AND_LONG_2ADDR:
1555 case OP_AND_LONG:
1556 firstOp = kOpAnd;
1557 secondOp = kOpAnd;
1558 break;
1559 case OP_OR_LONG:
1560 case OP_OR_LONG_2ADDR:
1561 firstOp = kOpOr;
1562 secondOp = kOpOr;
1563 break;
1564 case OP_XOR_LONG:
1565 case OP_XOR_LONG_2ADDR:
1566 firstOp = kOpXor;
1567 secondOp = kOpXor;
1568 break;
1569 case OP_NEG_LONG: {
buzbee67bf8852011-08-17 17:51:35 -07001570 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1571 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbeeb29e4d12011-09-26 15:05:48 -07001572 int zReg = oatAllocTemp(cUnit);
1573 loadConstantNoClobber(cUnit, zReg, 0);
1574 // Check for destructive overlap
1575 if (rlResult.lowReg == rlSrc2.highReg) {
1576 int tReg = oatAllocTemp(cUnit);
1577 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1578 zReg, rlSrc2.lowReg);
1579 opRegRegReg(cUnit, kOpSbc, rlResult.highReg,
1580 zReg, tReg);
1581 oatFreeTemp(cUnit, tReg);
1582 } else {
1583 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1584 zReg, rlSrc2.lowReg);
1585 opRegRegReg(cUnit, kOpSbc, rlResult.highReg,
1586 zReg, rlSrc2.highReg);
1587 }
1588 oatFreeTemp(cUnit, zReg);
buzbee67bf8852011-08-17 17:51:35 -07001589 storeValueWide(cUnit, rlDest, rlResult);
1590 return false;
1591 }
1592 default:
1593 LOG(FATAL) << "Invalid long arith op";
1594 }
1595 if (!callOut) {
1596 genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
1597 } else {
buzbee67bf8852011-08-17 17:51:35 -07001598 oatFlushAllRegs(cUnit); /* Send everything to home location */
buzbee58f92742011-10-01 11:22:17 -07001599 if (checkZero) {
1600 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
1601 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1602 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1603 int tReg = oatAllocTemp(cUnit);
1604 newLIR4(cUnit, kThumb2OrrRRRs, tReg, r2, r3, 0);
1605 oatFreeTemp(cUnit, tReg);
1606 genCheck(cUnit, kArmCondEq, mir, kArmThrowDivZero);
1607 } else {
1608 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1609 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1610 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
1611 }
Ian Rogersff1ed472011-09-20 13:46:24 -07001612 callRuntimeHelper(cUnit, rLR);
buzbee58f92742011-10-01 11:22:17 -07001613 // Adjust return regs in to handle case of rem returning r2/r3
buzbee67bf8852011-08-17 17:51:35 -07001614 if (retReg == r0)
1615 rlResult = oatGetReturnWide(cUnit);
1616 else
1617 rlResult = oatGetReturnWideAlt(cUnit);
1618 storeValueWide(cUnit, rlDest, rlResult);
1619 }
1620 return false;
1621}
1622
buzbeeed3e9302011-09-23 17:34:19 -07001623STATIC bool genArithOpInt(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001624 RegLocation rlDest, RegLocation rlSrc1,
1625 RegLocation rlSrc2)
1626{
1627 OpKind op = kOpBkpt;
1628 bool callOut = false;
1629 bool checkZero = false;
1630 bool unary = false;
1631 int retReg = r0;
1632 int funcOffset;
1633 RegLocation rlResult;
1634 bool shiftOp = false;
1635
1636 switch (mir->dalvikInsn.opcode) {
1637 case OP_NEG_INT:
1638 op = kOpNeg;
1639 unary = true;
1640 break;
1641 case OP_NOT_INT:
1642 op = kOpMvn;
1643 unary = true;
1644 break;
1645 case OP_ADD_INT:
1646 case OP_ADD_INT_2ADDR:
1647 op = kOpAdd;
1648 break;
1649 case OP_SUB_INT:
1650 case OP_SUB_INT_2ADDR:
1651 op = kOpSub;
1652 break;
1653 case OP_MUL_INT:
1654 case OP_MUL_INT_2ADDR:
1655 op = kOpMul;
1656 break;
1657 case OP_DIV_INT:
1658 case OP_DIV_INT_2ADDR:
1659 callOut = true;
1660 checkZero = true;
1661 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
1662 retReg = r0;
1663 break;
1664 /* NOTE: returns in r1 */
1665 case OP_REM_INT:
1666 case OP_REM_INT_2ADDR:
1667 callOut = true;
1668 checkZero = true;
1669 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
1670 retReg = r1;
1671 break;
1672 case OP_AND_INT:
1673 case OP_AND_INT_2ADDR:
1674 op = kOpAnd;
1675 break;
1676 case OP_OR_INT:
1677 case OP_OR_INT_2ADDR:
1678 op = kOpOr;
1679 break;
1680 case OP_XOR_INT:
1681 case OP_XOR_INT_2ADDR:
1682 op = kOpXor;
1683 break;
1684 case OP_SHL_INT:
1685 case OP_SHL_INT_2ADDR:
1686 shiftOp = true;
1687 op = kOpLsl;
1688 break;
1689 case OP_SHR_INT:
1690 case OP_SHR_INT_2ADDR:
1691 shiftOp = true;
1692 op = kOpAsr;
1693 break;
1694 case OP_USHR_INT:
1695 case OP_USHR_INT_2ADDR:
1696 shiftOp = true;
1697 op = kOpLsr;
1698 break;
1699 default:
1700 LOG(FATAL) << "Invalid word arith op: " <<
1701 (int)mir->dalvikInsn.opcode;
1702 }
1703 if (!callOut) {
1704 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1705 if (unary) {
1706 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1707 opRegReg(cUnit, op, rlResult.lowReg,
1708 rlSrc1.lowReg);
1709 } else {
1710 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1711 if (shiftOp) {
1712 int tReg = oatAllocTemp(cUnit);
1713 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
1714 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1715 opRegRegReg(cUnit, op, rlResult.lowReg,
1716 rlSrc1.lowReg, tReg);
1717 oatFreeTemp(cUnit, tReg);
1718 } else {
1719 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1720 opRegRegReg(cUnit, op, rlResult.lowReg,
1721 rlSrc1.lowReg, rlSrc2.lowReg);
1722 }
1723 }
1724 storeValue(cUnit, rlDest, rlResult);
1725 } else {
1726 RegLocation rlResult;
1727 oatFlushAllRegs(cUnit); /* Send everything to home location */
1728 loadValueDirectFixed(cUnit, rlSrc2, r1);
1729 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1730 loadValueDirectFixed(cUnit, rlSrc1, r0);
1731 if (checkZero) {
buzbee5ade1d22011-09-09 14:44:52 -07001732 genImmedCheck(cUnit, kArmCondEq, r1, 0, mir, kArmThrowDivZero);
buzbee67bf8852011-08-17 17:51:35 -07001733 }
Ian Rogersff1ed472011-09-20 13:46:24 -07001734 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001735 if (retReg == r0)
1736 rlResult = oatGetReturn(cUnit);
1737 else
1738 rlResult = oatGetReturnAlt(cUnit);
1739 storeValue(cUnit, rlDest, rlResult);
1740 }
1741 return false;
1742}
1743
buzbeec1f45042011-09-21 16:03:19 -07001744/* Check if we need to check for pending suspend request */
buzbeeed3e9302011-09-23 17:34:19 -07001745STATIC void genSuspendTest(CompilationUnit* cUnit, MIR* mir)
buzbeec1f45042011-09-21 16:03:19 -07001746{
buzbeec0ecd652011-09-25 18:11:54 -07001747 if (NO_SUSPEND || mir->optimizationFlags & MIR_IGNORE_SUSPEND_CHECK) {
buzbeec1f45042011-09-21 16:03:19 -07001748 return;
1749 }
buzbee6181f792011-09-29 11:14:04 -07001750 oatFlushAllRegs(cUnit);
buzbeec1f45042011-09-21 16:03:19 -07001751 newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
1752 ArmLIR* branch = opCondBranch(cUnit, kArmCondEq);
1753 ArmLIR* retLab = newLIR0(cUnit, kArmPseudoTargetLabel);
1754 retLab->defMask = ENCODE_ALL;
1755 ArmLIR* target = (ArmLIR*)oatNew(sizeof(ArmLIR), true);
1756 target->generic.dalvikOffset = cUnit->currentDalvikOffset;
1757 target->opcode = kArmPseudoSuspendTarget;
1758 target->operands[0] = (intptr_t)retLab;
1759 target->operands[1] = mir->offset;
1760 branch->generic.target = (LIR*)target;
1761 oatInsertGrowableList(&cUnit->suspendLaunchpads, (intptr_t)target);
1762}
1763
buzbee0d966cf2011-09-08 17:34:58 -07001764/* Check for pending suspend request. */
buzbeeed3e9302011-09-23 17:34:19 -07001765STATIC void genSuspendPoll(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001766{
buzbeec0ecd652011-09-25 18:11:54 -07001767 if (NO_SUSPEND || mir->optimizationFlags & MIR_IGNORE_SUSPEND_CHECK) {
buzbeec1f45042011-09-21 16:03:19 -07001768 return;
1769 }
buzbee6181f792011-09-29 11:14:04 -07001770 oatFlushAllRegs(cUnit);
buzbee0d966cf2011-09-08 17:34:58 -07001771 oatLockCallTemps(cUnit); // Explicit register usage
1772 int rSuspendCount = r1;
buzbee67bf8852011-08-17 17:51:35 -07001773 ArmLIR* ld;
buzbee0d966cf2011-09-08 17:34:58 -07001774 ld = loadWordDisp(cUnit, rSELF,
1775 art::Thread::SuspendCountOffset().Int32Value(), rSuspendCount);
buzbee67bf8852011-08-17 17:51:35 -07001776 setMemRefType(ld, true /* isLoad */, kMustNotAlias);
buzbee0d966cf2011-09-08 17:34:58 -07001777 loadWordDisp(cUnit, rSELF,
1778 OFFSETOF_MEMBER(Thread, pCheckSuspendFromCode), rLR);
1779 genRegCopy(cUnit, r0, rSELF);
1780 opRegImm(cUnit, kOpCmp, rSuspendCount, 0);
buzbeeb0ebba02011-09-17 10:52:59 -07001781 /*
1782 * FIXME: for efficiency we should use an if-converted suspend
1783 * test here. However, support for IT is a bit weak at the
1784 * moment, and requires knowledge of the exact number of instructions
1785 * to fall in the skip shadow. While the exception mechanism
1786 * remains in flux, use a compare and branch sequence. Once
1787 * things firm up, restore the conditional skip (and perhaps
1788 * fix the utility to handle variable-sized shadows).
1789 */
1790#if 0
buzbee0d966cf2011-09-08 17:34:58 -07001791 genIT(cUnit, kArmCondNe, "");
buzbeeec5adf32011-09-11 15:25:43 -07001792 callUnwindableHelper(cUnit, rLR); // CheckSuspendFromCode(self)
buzbeeb0ebba02011-09-17 10:52:59 -07001793#else
1794 ArmLIR* branch = opCondBranch(cUnit, kArmCondEq);
Ian Rogersff1ed472011-09-20 13:46:24 -07001795 callRuntimeHelper(cUnit, rLR); // CheckSuspendFromCode(self)
buzbeeb0ebba02011-09-17 10:52:59 -07001796 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
1797 target->defMask = ENCODE_ALL;
1798 branch->generic.target = (LIR*)target;
1799#endif
buzbee0d966cf2011-09-08 17:34:58 -07001800 oatFreeCallTemps(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001801}
1802
1803/*
1804 * The following are the first-level codegen routines that analyze the format
1805 * of each bytecode then either dispatch special purpose codegen routines
1806 * or produce corresponding Thumb instructions directly.
1807 */
1808
buzbeeed3e9302011-09-23 17:34:19 -07001809STATIC bool isPowerOfTwo(int x)
buzbee67bf8852011-08-17 17:51:35 -07001810{
1811 return (x & (x - 1)) == 0;
1812}
1813
1814// Returns true if no more than two bits are set in 'x'.
buzbeeed3e9302011-09-23 17:34:19 -07001815STATIC bool isPopCountLE2(unsigned int x)
buzbee67bf8852011-08-17 17:51:35 -07001816{
1817 x &= x - 1;
1818 return (x & (x - 1)) == 0;
1819}
1820
1821// Returns the index of the lowest set bit in 'x'.
buzbeeed3e9302011-09-23 17:34:19 -07001822STATIC int lowestSetBit(unsigned int x) {
buzbee67bf8852011-08-17 17:51:35 -07001823 int bit_posn = 0;
1824 while ((x & 0xf) == 0) {
1825 bit_posn += 4;
1826 x >>= 4;
1827 }
1828 while ((x & 1) == 0) {
1829 bit_posn++;
1830 x >>= 1;
1831 }
1832 return bit_posn;
1833}
1834
1835// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
1836// and store the result in 'rlDest'.
buzbeeed3e9302011-09-23 17:34:19 -07001837STATIC bool handleEasyDivide(CompilationUnit* cUnit, Opcode dalvikOpcode,
buzbee67bf8852011-08-17 17:51:35 -07001838 RegLocation rlSrc, RegLocation rlDest, int lit)
1839{
1840 if (lit < 2 || !isPowerOfTwo(lit)) {
1841 return false;
1842 }
1843 int k = lowestSetBit(lit);
1844 if (k >= 30) {
1845 // Avoid special cases.
1846 return false;
1847 }
1848 bool div = (dalvikOpcode == OP_DIV_INT_LIT8 ||
1849 dalvikOpcode == OP_DIV_INT_LIT16);
1850 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1851 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1852 if (div) {
1853 int tReg = oatAllocTemp(cUnit);
1854 if (lit == 2) {
1855 // Division by 2 is by far the most common division by constant.
1856 opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
1857 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1858 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1859 } else {
1860 opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
1861 opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
1862 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1863 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1864 }
1865 } else {
1866 int cReg = oatAllocTemp(cUnit);
1867 loadConstant(cUnit, cReg, lit - 1);
1868 int tReg1 = oatAllocTemp(cUnit);
1869 int tReg2 = oatAllocTemp(cUnit);
1870 if (lit == 2) {
1871 opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
1872 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1873 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1874 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1875 } else {
1876 opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
1877 opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
1878 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1879 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1880 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1881 }
1882 }
1883 storeValue(cUnit, rlDest, rlResult);
1884 return true;
1885}
1886
1887// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
1888// and store the result in 'rlDest'.
buzbeeed3e9302011-09-23 17:34:19 -07001889STATIC bool handleEasyMultiply(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -07001890 RegLocation rlSrc, RegLocation rlDest, int lit)
1891{
1892 // Can we simplify this multiplication?
1893 bool powerOfTwo = false;
1894 bool popCountLE2 = false;
1895 bool powerOfTwoMinusOne = false;
1896 if (lit < 2) {
1897 // Avoid special cases.
1898 return false;
1899 } else if (isPowerOfTwo(lit)) {
1900 powerOfTwo = true;
1901 } else if (isPopCountLE2(lit)) {
1902 popCountLE2 = true;
1903 } else if (isPowerOfTwo(lit + 1)) {
1904 powerOfTwoMinusOne = true;
1905 } else {
1906 return false;
1907 }
1908 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1909 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1910 if (powerOfTwo) {
1911 // Shift.
1912 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
1913 lowestSetBit(lit));
1914 } else if (popCountLE2) {
1915 // Shift and add and shift.
1916 int firstBit = lowestSetBit(lit);
1917 int secondBit = lowestSetBit(lit ^ (1 << firstBit));
1918 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
1919 firstBit, secondBit);
1920 } else {
1921 // Reverse subtract: (src << (shift + 1)) - src.
buzbeeed3e9302011-09-23 17:34:19 -07001922 DCHECK(powerOfTwoMinusOne);
buzbee5ade1d22011-09-09 14:44:52 -07001923 // TUNING: rsb dst, src, src lsl#lowestSetBit(lit + 1)
buzbee67bf8852011-08-17 17:51:35 -07001924 int tReg = oatAllocTemp(cUnit);
1925 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
1926 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
1927 }
1928 storeValue(cUnit, rlDest, rlResult);
1929 return true;
1930}
1931
buzbeeed3e9302011-09-23 17:34:19 -07001932STATIC bool genArithOpIntLit(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001933 RegLocation rlDest, RegLocation rlSrc,
1934 int lit)
1935{
1936 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1937 RegLocation rlResult;
1938 OpKind op = (OpKind)0; /* Make gcc happy */
1939 int shiftOp = false;
1940 bool isDiv = false;
1941 int funcOffset;
1942
1943 switch (dalvikOpcode) {
1944 case OP_RSUB_INT_LIT8:
1945 case OP_RSUB_INT: {
1946 int tReg;
1947 //TUNING: add support for use of Arm rsub op
1948 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1949 tReg = oatAllocTemp(cUnit);
1950 loadConstant(cUnit, tReg, lit);
1951 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1952 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1953 tReg, rlSrc.lowReg);
1954 storeValue(cUnit, rlDest, rlResult);
1955 return false;
1956 break;
1957 }
1958
1959 case OP_ADD_INT_LIT8:
1960 case OP_ADD_INT_LIT16:
1961 op = kOpAdd;
1962 break;
1963 case OP_MUL_INT_LIT8:
1964 case OP_MUL_INT_LIT16: {
1965 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
1966 return false;
1967 }
1968 op = kOpMul;
1969 break;
1970 }
1971 case OP_AND_INT_LIT8:
1972 case OP_AND_INT_LIT16:
1973 op = kOpAnd;
1974 break;
1975 case OP_OR_INT_LIT8:
1976 case OP_OR_INT_LIT16:
1977 op = kOpOr;
1978 break;
1979 case OP_XOR_INT_LIT8:
1980 case OP_XOR_INT_LIT16:
1981 op = kOpXor;
1982 break;
1983 case OP_SHL_INT_LIT8:
1984 lit &= 31;
1985 shiftOp = true;
1986 op = kOpLsl;
1987 break;
1988 case OP_SHR_INT_LIT8:
1989 lit &= 31;
1990 shiftOp = true;
1991 op = kOpAsr;
1992 break;
1993 case OP_USHR_INT_LIT8:
1994 lit &= 31;
1995 shiftOp = true;
1996 op = kOpLsr;
1997 break;
1998
1999 case OP_DIV_INT_LIT8:
2000 case OP_DIV_INT_LIT16:
2001 case OP_REM_INT_LIT8:
2002 case OP_REM_INT_LIT16:
2003 if (lit == 0) {
buzbee5ade1d22011-09-09 14:44:52 -07002004 genImmedCheck(cUnit, kArmCondAl, 0, 0, mir, kArmThrowDivZero);
buzbee67bf8852011-08-17 17:51:35 -07002005 return false;
2006 }
2007 if (handleEasyDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit)) {
2008 return false;
2009 }
2010 oatFlushAllRegs(cUnit); /* Everything to home location */
2011 loadValueDirectFixed(cUnit, rlSrc, r0);
2012 oatClobber(cUnit, r0);
2013 if ((dalvikOpcode == OP_DIV_INT_LIT8) ||
2014 (dalvikOpcode == OP_DIV_INT_LIT16)) {
2015 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
2016 isDiv = true;
2017 } else {
2018 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
2019 isDiv = false;
2020 }
2021 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
2022 loadConstant(cUnit, r1, lit);
Ian Rogersff1ed472011-09-20 13:46:24 -07002023 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07002024 if (isDiv)
2025 rlResult = oatGetReturn(cUnit);
2026 else
2027 rlResult = oatGetReturnAlt(cUnit);
2028 storeValue(cUnit, rlDest, rlResult);
2029 return false;
2030 break;
2031 default:
2032 return true;
2033 }
2034 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2035 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2036 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
2037 if (shiftOp && (lit == 0)) {
2038 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2039 } else {
2040 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2041 }
2042 storeValue(cUnit, rlDest, rlResult);
2043 return false;
2044}
2045
2046/* Architectural-specific debugging helpers go here */
2047void oatArchDump(void)
2048{
2049 /* Print compiled opcode in this VM instance */
2050 int i, start, streak;
2051 char buf[1024];
2052
2053 streak = i = 0;
2054 buf[0] = 0;
2055 while (opcodeCoverage[i] == 0 && i < kNumPackedOpcodes) {
2056 i++;
2057 }
2058 if (i == kNumPackedOpcodes) {
2059 return;
2060 }
2061 for (start = i++, streak = 1; i < kNumPackedOpcodes; i++) {
2062 if (opcodeCoverage[i]) {
2063 streak++;
2064 } else {
2065 if (streak == 1) {
2066 sprintf(buf+strlen(buf), "%x,", start);
2067 } else {
2068 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
2069 }
2070 streak = 0;
2071 while (opcodeCoverage[i] == 0 && i < kNumPackedOpcodes) {
2072 i++;
2073 }
2074 if (i < kNumPackedOpcodes) {
2075 streak = 1;
2076 start = i;
2077 }
2078 }
2079 }
2080 if (streak) {
2081 if (streak == 1) {
2082 sprintf(buf+strlen(buf), "%x", start);
2083 } else {
2084 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
2085 }
2086 }
2087 if (strlen(buf)) {
2088 LOG(INFO) << "dalvik.vm.oat.op = " << buf;
2089 }
2090}