blob: bff53beb06e8943d56bbc347b2d40873a2548826 [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
buzbeece302932011-10-04 14:32:18 -070025#define SLOW_FIELD_PATH (cUnit->enableDebug & (1 << kDebugSlowFieldPath))
26#define SLOW_INVOKE_PATH (cUnit->enableDebug & (1 << kDebugSlowInvokePath))
27#define SLOW_STRING_PATH (cUnit->enableDebug & (1 << kDebugSlowStringPath))
28#define SLOW_TYPE_PATH (cUnit->enableDebug & (1 << kDebugSlowTypePath))
29#define EXERCISE_SLOWEST_FIELD_PATH (cUnit->enableDebug & \
30 (1 << kDebugSlowestFieldPath))
31#define EXERCISE_SLOWEST_STRING_PATH (cUnit->enableDebug & \
32 (1 << kDebugSlowestStringPath))
33
34STATIC RegLocation getRetLoc(CompilationUnit* cUnit);
buzbee34cd9e52011-09-08 14:31:52 -070035
36std::string fieldNameFromIndex(const Method* method, uint32_t fieldIdx)
37{
38 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
39 const art::DexFile& dex_file = class_linker->FindDexFile(
40 method->GetDeclaringClass()->GetDexCache());
41 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
Elliott Hughes2bb97f92011-09-11 15:43:37 -070042 std::string class_name = dex_file.dexStringByTypeIdx(field_id.class_idx_);
buzbee34cd9e52011-09-08 14:31:52 -070043 std::string field_name = dex_file.dexStringById(field_id.name_idx_);
44 return class_name + "." + field_name;
45}
46
Elliott Hughes81bc5092011-09-30 17:25:59 -070047void warnIfUnresolved(CompilationUnit* cUnit, int fieldIdx, Field* field) {
48 if (field == NULL) {
49 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
50 << " unresolved at compile time";
51 } else {
52 // We also use the slow path for wide volatile fields.
53 }
54}
55
buzbee67bf8852011-08-17 17:51:35 -070056/*
57 * Construct an s4 from two consecutive half-words of switch data.
58 * This needs to check endianness because the DEX optimizer only swaps
59 * half-words in instruction stream.
60 *
61 * "switchData" must be 32-bit aligned.
62 */
63#if __BYTE_ORDER == __LITTLE_ENDIAN
buzbeeed3e9302011-09-23 17:34:19 -070064STATIC inline s4 s4FromSwitchData(const void* switchData) {
buzbee67bf8852011-08-17 17:51:35 -070065 return *(s4*) switchData;
66}
67#else
buzbeeed3e9302011-09-23 17:34:19 -070068STATIC inline s4 s4FromSwitchData(const void* switchData) {
buzbee67bf8852011-08-17 17:51:35 -070069 u2* data = switchData;
70 return data[0] | (((s4) data[1]) << 16);
71}
72#endif
73
buzbeeed3e9302011-09-23 17:34:19 -070074STATIC ArmLIR* callRuntimeHelper(CompilationUnit* cUnit, int reg)
buzbeeec5adf32011-09-11 15:25:43 -070075{
buzbee6181f792011-09-29 11:14:04 -070076 oatClobberCalleeSave(cUnit);
buzbeeec5adf32011-09-11 15:25:43 -070077 return opReg(cUnit, kOpBlx, reg);
78}
79
buzbee1b4c8592011-08-31 10:43:51 -070080/* Generate unconditional branch instructions */
buzbeeed3e9302011-09-23 17:34:19 -070081STATIC ArmLIR* genUnconditionalBranch(CompilationUnit* cUnit, ArmLIR* target)
buzbee1b4c8592011-08-31 10:43:51 -070082{
83 ArmLIR* branch = opNone(cUnit, kOpUncondBr);
84 branch->generic.target = (LIR*) target;
85 return branch;
86}
87
buzbee67bf8852011-08-17 17:51:35 -070088/*
89 * Generate a Thumb2 IT instruction, which can nullify up to
90 * four subsequent instructions based on a condition and its
91 * inverse. The condition applies to the first instruction, which
92 * is executed if the condition is met. The string "guide" consists
93 * of 0 to 3 chars, and applies to the 2nd through 4th instruction.
94 * A "T" means the instruction is executed if the condition is
95 * met, and an "E" means the instruction is executed if the condition
96 * is not met.
97 */
buzbeeed3e9302011-09-23 17:34:19 -070098STATIC ArmLIR* genIT(CompilationUnit* cUnit, ArmConditionCode code,
buzbee67bf8852011-08-17 17:51:35 -070099 const char* guide)
100{
101 int mask;
102 int condBit = code & 1;
103 int altBit = condBit ^ 1;
104 int mask3 = 0;
105 int mask2 = 0;
106 int mask1 = 0;
107
108 //Note: case fallthroughs intentional
109 switch(strlen(guide)) {
110 case 3:
111 mask1 = (guide[2] == 'T') ? condBit : altBit;
112 case 2:
113 mask2 = (guide[1] == 'T') ? condBit : altBit;
114 case 1:
115 mask3 = (guide[0] == 'T') ? condBit : altBit;
116 break;
117 case 0:
118 break;
119 default:
120 LOG(FATAL) << "OAT: bad case in genIT";
121 }
122 mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
123 (1 << (3 - strlen(guide)));
124 return newLIR2(cUnit, kThumb2It, code, mask);
125}
126
127/*
128 * Insert a kArmPseudoCaseLabel at the beginning of the Dalvik
129 * offset vaddr. This label will be used to fix up the case
130 * branch table during the assembly phase. Be sure to set
131 * all resource flags on this to prevent code motion across
132 * target boundaries. KeyVal is just there for debugging.
133 */
buzbeeed3e9302011-09-23 17:34:19 -0700134STATIC ArmLIR* insertCaseLabel(CompilationUnit* cUnit, int vaddr, int keyVal)
buzbee67bf8852011-08-17 17:51:35 -0700135{
136 ArmLIR* lir;
137 for (lir = (ArmLIR*)cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
138 if ((lir->opcode == kArmPseudoDalvikByteCodeBoundary) &&
139 (lir->generic.dalvikOffset == vaddr)) {
140 ArmLIR* newLabel = (ArmLIR*)oatNew(sizeof(ArmLIR), true);
141 newLabel->generic.dalvikOffset = vaddr;
142 newLabel->opcode = kArmPseudoCaseLabel;
143 newLabel->operands[0] = keyVal;
144 oatInsertLIRAfter((LIR*)lir, (LIR*)newLabel);
145 return newLabel;
146 }
147 }
148 oatCodegenDump(cUnit);
149 LOG(FATAL) << "Error: didn't find vaddr 0x" << std::hex << vaddr;
150 return NULL; // Quiet gcc
151}
152
buzbeeed3e9302011-09-23 17:34:19 -0700153STATIC void markPackedCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
buzbee67bf8852011-08-17 17:51:35 -0700154{
155 const u2* table = tabRec->table;
156 int baseVaddr = tabRec->vaddr;
157 int *targets = (int*)&table[4];
158 int entries = table[1];
159 int lowKey = s4FromSwitchData(&table[2]);
160 for (int i = 0; i < entries; i++) {
161 tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
162 i + lowKey);
163 }
164}
165
buzbeeed3e9302011-09-23 17:34:19 -0700166STATIC void markSparseCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
buzbee67bf8852011-08-17 17:51:35 -0700167{
168 const u2* table = tabRec->table;
169 int baseVaddr = tabRec->vaddr;
170 int entries = table[1];
171 int* keys = (int*)&table[2];
172 int* targets = &keys[entries];
173 for (int i = 0; i < entries; i++) {
174 tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
175 keys[i]);
176 }
177}
178
179void oatProcessSwitchTables(CompilationUnit* cUnit)
180{
181 GrowableListIterator iterator;
182 oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
183 while (true) {
184 SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
185 &iterator);
186 if (tabRec == NULL) break;
187 if (tabRec->table[0] == kPackedSwitchSignature)
188 markPackedCaseLabels(cUnit, tabRec);
189 else if (tabRec->table[0] == kSparseSwitchSignature)
190 markSparseCaseLabels(cUnit, tabRec);
191 else {
192 LOG(FATAL) << "Invalid switch table";
193 }
194 }
195}
196
buzbeeed3e9302011-09-23 17:34:19 -0700197STATIC void dumpSparseSwitchTable(const u2* table)
buzbee67bf8852011-08-17 17:51:35 -0700198 /*
199 * Sparse switch data format:
200 * ushort ident = 0x0200 magic value
201 * ushort size number of entries in the table; > 0
202 * int keys[size] keys, sorted low-to-high; 32-bit aligned
203 * int targets[size] branch targets, relative to switch opcode
204 *
205 * Total size is (2+size*4) 16-bit code units.
206 */
207{
208 u2 ident = table[0];
209 int entries = table[1];
210 int* keys = (int*)&table[2];
211 int* targets = &keys[entries];
212 LOG(INFO) << "Sparse switch table - ident:0x" << std::hex << ident <<
213 ", entries: " << std::dec << entries;
214 for (int i = 0; i < entries; i++) {
215 LOG(INFO) << " Key[" << keys[i] << "] -> 0x" << std::hex <<
216 targets[i];
217 }
218}
219
buzbeeed3e9302011-09-23 17:34:19 -0700220STATIC void dumpPackedSwitchTable(const u2* table)
buzbee67bf8852011-08-17 17:51:35 -0700221 /*
222 * Packed switch data format:
223 * ushort ident = 0x0100 magic value
224 * ushort size number of entries in the table
225 * int first_key first (and lowest) switch case value
226 * int targets[size] branch targets, relative to switch opcode
227 *
228 * Total size is (4+size*2) 16-bit code units.
229 */
230{
231 u2 ident = table[0];
232 int* targets = (int*)&table[4];
233 int entries = table[1];
234 int lowKey = s4FromSwitchData(&table[2]);
235 LOG(INFO) << "Packed switch table - ident:0x" << std::hex << ident <<
236 ", entries: " << std::dec << entries << ", lowKey: " << lowKey;
237 for (int i = 0; i < entries; i++) {
238 LOG(INFO) << " Key[" << (i + lowKey) << "] -> 0x" << std::hex <<
239 targets[i];
240 }
241}
242
243/*
244 * The sparse table in the literal pool is an array of <key,displacement>
245 * pairs. For each set, we'll load them as a pair using ldmia.
246 * This means that the register number of the temp we use for the key
247 * must be lower than the reg for the displacement.
248 *
249 * The test loop will look something like:
250 *
251 * adr rBase, <table>
252 * ldr rVal, [rSP, vRegOff]
253 * mov rIdx, #tableSize
254 * lp:
255 * ldmia rBase!, {rKey, rDisp}
256 * sub rIdx, #1
257 * cmp rVal, rKey
258 * ifeq
259 * add rPC, rDisp ; This is the branch from which we compute displacement
260 * cbnz rIdx, lp
261 */
buzbeeed3e9302011-09-23 17:34:19 -0700262STATIC void genSparseSwitch(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700263 RegLocation rlSrc)
264{
265 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
266 if (cUnit->printMe) {
267 dumpSparseSwitchTable(table);
268 }
269 // Add the table to the list - we'll process it later
270 SwitchTable *tabRec = (SwitchTable *)oatNew(sizeof(SwitchTable),
271 true);
272 tabRec->table = table;
273 tabRec->vaddr = mir->offset;
274 int size = table[1];
275 tabRec->targets = (ArmLIR* *)oatNew(size * sizeof(ArmLIR*), true);
276 oatInsertGrowableList(&cUnit->switchTables, (intptr_t)tabRec);
277
278 // Get the switch value
279 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
280 int rBase = oatAllocTemp(cUnit);
281 /* Allocate key and disp temps */
282 int rKey = oatAllocTemp(cUnit);
283 int rDisp = oatAllocTemp(cUnit);
284 // Make sure rKey's register number is less than rDisp's number for ldmia
285 if (rKey > rDisp) {
286 int tmp = rDisp;
287 rDisp = rKey;
288 rKey = tmp;
289 }
290 // Materialize a pointer to the switch table
buzbee03fa2632011-09-20 17:10:57 -0700291 newLIR3(cUnit, kThumb2Adr, rBase, 0, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700292 // Set up rIdx
293 int rIdx = oatAllocTemp(cUnit);
294 loadConstant(cUnit, rIdx, size);
295 // Establish loop branch target
296 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
297 target->defMask = ENCODE_ALL;
298 // Load next key/disp
299 newLIR2(cUnit, kThumb2LdmiaWB, rBase, (1 << rKey) | (1 << rDisp));
300 opRegReg(cUnit, kOpCmp, rKey, rlSrc.lowReg);
301 // Go if match. NOTE: No instruction set switch here - must stay Thumb2
302 genIT(cUnit, kArmCondEq, "");
303 ArmLIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, rDisp);
304 tabRec->bxInst = switchBranch;
305 // Needs to use setflags encoding here
306 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
307 ArmLIR* branch = opCondBranch(cUnit, kArmCondNe);
308 branch->generic.target = (LIR*)target;
309}
310
311
buzbeeed3e9302011-09-23 17:34:19 -0700312STATIC void genPackedSwitch(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700313 RegLocation rlSrc)
314{
315 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
316 if (cUnit->printMe) {
317 dumpPackedSwitchTable(table);
318 }
319 // Add the table to the list - we'll process it later
320 SwitchTable *tabRec = (SwitchTable *)oatNew(sizeof(SwitchTable),
321 true);
322 tabRec->table = table;
323 tabRec->vaddr = mir->offset;
324 int size = table[1];
325 tabRec->targets = (ArmLIR* *)oatNew(size * sizeof(ArmLIR*), true);
326 oatInsertGrowableList(&cUnit->switchTables, (intptr_t)tabRec);
327
328 // Get the switch value
329 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
330 int tableBase = oatAllocTemp(cUnit);
331 // Materialize a pointer to the switch table
buzbee03fa2632011-09-20 17:10:57 -0700332 newLIR3(cUnit, kThumb2Adr, tableBase, 0, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700333 int lowKey = s4FromSwitchData(&table[2]);
334 int keyReg;
335 // Remove the bias, if necessary
336 if (lowKey == 0) {
337 keyReg = rlSrc.lowReg;
338 } else {
339 keyReg = oatAllocTemp(cUnit);
340 opRegRegImm(cUnit, kOpSub, keyReg, rlSrc.lowReg, lowKey);
341 }
342 // Bounds check - if < 0 or >= size continue following switch
343 opRegImm(cUnit, kOpCmp, keyReg, size-1);
344 ArmLIR* branchOver = opCondBranch(cUnit, kArmCondHi);
345
346 // Load the displacement from the switch table
347 int dispReg = oatAllocTemp(cUnit);
348 loadBaseIndexed(cUnit, tableBase, keyReg, dispReg, 2, kWord);
349
350 // ..and go! NOTE: No instruction set switch here - must stay Thumb2
351 ArmLIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, dispReg);
352 tabRec->bxInst = switchBranch;
353
354 /* branchOver target here */
355 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
356 target->defMask = ENCODE_ALL;
357 branchOver->generic.target = (LIR*)target;
358}
359
360/*
361 * Array data table format:
362 * ushort ident = 0x0300 magic value
363 * ushort width width of each element in the table
364 * uint size number of elements in the table
365 * ubyte data[size*width] table of data values (may contain a single-byte
366 * padding at the end)
367 *
368 * Total size is 4+(width * size + 1)/2 16-bit code units.
369 */
buzbeeed3e9302011-09-23 17:34:19 -0700370STATIC void genFillArrayData(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700371 RegLocation rlSrc)
372{
373 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
374 // Add the table to the list - we'll process it later
375 FillArrayData *tabRec = (FillArrayData *)
376 oatNew(sizeof(FillArrayData), true);
377 tabRec->table = table;
378 tabRec->vaddr = mir->offset;
379 u2 width = tabRec->table[1];
380 u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
381 tabRec->size = (size * width) + 8;
382
383 oatInsertGrowableList(&cUnit->fillArrayData, (intptr_t)tabRec);
384
385 // Making a call - use explicit registers
386 oatFlushAllRegs(cUnit); /* Everything to home location */
387 loadValueDirectFixed(cUnit, rlSrc, r0);
388 loadWordDisp(cUnit, rSELF,
buzbee1b4c8592011-08-31 10:43:51 -0700389 OFFSETOF_MEMBER(Thread, pHandleFillArrayDataFromCode), rLR);
buzbeee6d61962011-08-27 11:58:19 -0700390 // Materialize a pointer to the fill data image
buzbee03fa2632011-09-20 17:10:57 -0700391 newLIR3(cUnit, kThumb2Adr, r1, 0, (intptr_t)tabRec);
Ian Rogersff1ed472011-09-20 13:46:24 -0700392 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700393}
394
395/*
396 * Mark garbage collection card. Skip if the value we're storing is null.
397 */
buzbeeed3e9302011-09-23 17:34:19 -0700398STATIC void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg)
buzbee67bf8852011-08-17 17:51:35 -0700399{
400 int regCardBase = oatAllocTemp(cUnit);
401 int regCardNo = oatAllocTemp(cUnit);
402 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondEq, valReg, 0);
buzbeec143c552011-08-20 17:38:58 -0700403 loadWordDisp(cUnit, rSELF, Thread::CardTableOffset().Int32Value(),
buzbee67bf8852011-08-17 17:51:35 -0700404 regCardBase);
405 opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT);
406 storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
407 kUnsignedByte);
408 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
409 target->defMask = ENCODE_ALL;
410 branchOver->generic.target = (LIR*)target;
411 oatFreeTemp(cUnit, regCardBase);
412 oatFreeTemp(cUnit, regCardNo);
413}
414
buzbee34cd9e52011-09-08 14:31:52 -0700415/*
416 * Helper function for Iget/put when field not resolved at compile time.
417 * Will trash call temps and return with the field offset in r0.
418 */
Elliott Hughes81bc5092011-09-30 17:25:59 -0700419STATIC void getFieldOffset(CompilationUnit* cUnit, MIR* mir, Field* fieldPtr)
buzbee34cd9e52011-09-08 14:31:52 -0700420{
421 int fieldIdx = mir->dalvikInsn.vC;
buzbee6181f792011-09-29 11:14:04 -0700422 oatFlushAllRegs(cUnit);
Elliott Hughes81bc5092011-09-30 17:25:59 -0700423 warnIfUnresolved(cUnit, fieldIdx, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700424 oatLockCallTemps(cUnit); // Explicit register usage
425 loadCurrMethodDirect(cUnit, r1); // arg1 <= Method*
426 loadWordDisp(cUnit, r1,
427 Method::DexCacheResolvedFieldsOffset().Int32Value(), r0);
428 loadWordDisp(cUnit, r0, art::Array::DataOffset().Int32Value() +
429 sizeof(int32_t*)* fieldIdx, r0);
430 /*
431 * For testing, omit the test for run-time resolution. This will
432 * force all accesses to go through the runtime resolution path.
433 */
buzbeece302932011-10-04 14:32:18 -0700434 ArmLIR* branchOver = NULL;
435 if (!EXERCISE_SLOWEST_FIELD_PATH) {
436 branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0);
437 }
buzbee34cd9e52011-09-08 14:31:52 -0700438 // Resolve
439 loadWordDisp(cUnit, rSELF,
Brian Carlstrom845490b2011-09-19 15:56:53 -0700440 OFFSETOF_MEMBER(Thread, pFindInstanceFieldFromCode), rLR);
buzbee34cd9e52011-09-08 14:31:52 -0700441 loadConstant(cUnit, r0, fieldIdx);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700442 callRuntimeHelper(cUnit, rLR); // FindInstanceFieldFromCoderesolveTypeFromCode(idx, method)
buzbee34cd9e52011-09-08 14:31:52 -0700443 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
444 target->defMask = ENCODE_ALL;
buzbeece302932011-10-04 14:32:18 -0700445 if (!EXERCISE_SLOWEST_FIELD_PATH) {
446 branchOver->generic.target = (LIR*)target;
447 }
buzbee34cd9e52011-09-08 14:31:52 -0700448 // Free temps (except for r0)
449 oatFreeTemp(cUnit, r1);
450 oatFreeTemp(cUnit, r2);
451 oatFreeTemp(cUnit, r3);
452 loadWordDisp(cUnit, r0, art::Field::OffsetOffset().Int32Value(), r0);
453}
454
buzbeeed3e9302011-09-23 17:34:19 -0700455STATIC void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -0700456 RegLocation rlDest, RegLocation rlObj)
457{
buzbeec143c552011-08-20 17:38:58 -0700458 Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
459 GetResolvedField(mir->dalvikInsn.vC);
buzbee67bf8852011-08-17 17:51:35 -0700460 RegLocation rlResult;
461 RegisterClass regClass = oatRegClassBySize(size);
buzbee34cd9e52011-09-08 14:31:52 -0700462 if (SLOW_FIELD_PATH || fieldPtr == NULL) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700463 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700464 // Field offset in r0
465 rlObj = loadValue(cUnit, rlObj, kCoreReg);
466 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
buzbee5ade1d22011-09-09 14:44:52 -0700467 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
buzbee58f92742011-10-01 11:22:17 -0700468 loadBaseIndexed(cUnit, rlObj.lowReg, r0, rlResult.lowReg, 0, kWord);
buzbee67bf8852011-08-17 17:51:35 -0700469 oatGenMemBarrier(cUnit, kSY);
buzbee34cd9e52011-09-08 14:31:52 -0700470 storeValue(cUnit, rlDest, rlResult);
471 } else {
472#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700473 bool isVolatile = fieldPtr->IsVolatile();
buzbee34cd9e52011-09-08 14:31:52 -0700474#else
475 bool isVolatile = false;
476#endif
477 int fieldOffset = fieldPtr->GetOffset().Int32Value();
478 rlObj = loadValue(cUnit, rlObj, kCoreReg);
479 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
buzbee5ade1d22011-09-09 14:44:52 -0700480 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
buzbee34cd9e52011-09-08 14:31:52 -0700481 loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
buzbee58f92742011-10-01 11:22:17 -0700482 kWord, rlObj.sRegLow);
buzbee34cd9e52011-09-08 14:31:52 -0700483 if (isVolatile) {
484 oatGenMemBarrier(cUnit, kSY);
485 }
486 storeValue(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -0700487 }
buzbee67bf8852011-08-17 17:51:35 -0700488}
489
buzbeeed3e9302011-09-23 17:34:19 -0700490STATIC void genIPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -0700491 RegLocation rlSrc, RegLocation rlObj, bool isObject)
492{
buzbeec143c552011-08-20 17:38:58 -0700493 Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
494 GetResolvedField(mir->dalvikInsn.vC);
buzbee67bf8852011-08-17 17:51:35 -0700495 RegisterClass regClass = oatRegClassBySize(size);
buzbee34cd9e52011-09-08 14:31:52 -0700496 if (SLOW_FIELD_PATH || fieldPtr == NULL) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700497 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700498 // Field offset in r0
499 rlObj = loadValue(cUnit, rlObj, kCoreReg);
500 rlSrc = loadValue(cUnit, rlSrc, regClass);
buzbee5ade1d22011-09-09 14:44:52 -0700501 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
buzbee67bf8852011-08-17 17:51:35 -0700502 oatGenMemBarrier(cUnit, kSY);
buzbee58f92742011-10-01 11:22:17 -0700503 storeBaseIndexed(cUnit, rlObj.lowReg, r0, rlSrc.lowReg, 0, kWord);
buzbee34cd9e52011-09-08 14:31:52 -0700504 } else {
505#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700506 bool isVolatile = fieldPtr->IsVolatile();
buzbee34cd9e52011-09-08 14:31:52 -0700507#else
508 bool isVolatile = false;
509#endif
510 int fieldOffset = fieldPtr->GetOffset().Int32Value();
511 rlObj = loadValue(cUnit, rlObj, kCoreReg);
512 rlSrc = loadValue(cUnit, rlSrc, regClass);
buzbee5ade1d22011-09-09 14:44:52 -0700513 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700514
515 if (isVolatile) {
buzbee12246b82011-09-29 14:15:05 -0700516 oatGenMemBarrier(cUnit, kST);
buzbee34cd9e52011-09-08 14:31:52 -0700517 }
buzbee58f92742011-10-01 11:22:17 -0700518 storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, kWord);
buzbee12246b82011-09-29 14:15:05 -0700519 if (isVolatile) {
520 oatGenMemBarrier(cUnit, kSY);
521 }
buzbee67bf8852011-08-17 17:51:35 -0700522 }
buzbee67bf8852011-08-17 17:51:35 -0700523 if (isObject) {
524 /* NOTE: marking card based on object head */
525 markGCCard(cUnit, rlSrc.lowReg, rlObj.lowReg);
526 }
527}
528
buzbeeed3e9302011-09-23 17:34:19 -0700529STATIC void genIGetWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700530 RegLocation rlObj)
531{
buzbee12246b82011-09-29 14:15:05 -0700532 RegLocation rlResult;
buzbeec143c552011-08-20 17:38:58 -0700533 Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
534 GetResolvedField(mir->dalvikInsn.vC);
buzbee12246b82011-09-29 14:15:05 -0700535#if ANDROID_SMP != 0
536 bool isVolatile = (fieldPtr == NULL) || fieldPtr->IsVolatile();
537#else
538 bool isVolatile = false;
539#endif
buzbeece302932011-10-04 14:32:18 -0700540 if (SLOW_FIELD_PATH || (fieldPtr == NULL) || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700541 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700542 // Field offset in r0
543 rlObj = loadValue(cUnit, rlObj, kCoreReg);
544 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee5ade1d22011-09-09 14:44:52 -0700545 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700546 opRegReg(cUnit, kOpAdd, r0, rlObj.lowReg);
547 loadPair(cUnit, r0, rlResult.lowReg, rlResult.highReg);
buzbee67bf8852011-08-17 17:51:35 -0700548 oatGenMemBarrier(cUnit, kSY);
buzbee12246b82011-09-29 14:15:05 -0700549 storeValueWide(cUnit, rlDest, rlResult);
buzbee34cd9e52011-09-08 14:31:52 -0700550 } else {
buzbee34cd9e52011-09-08 14:31:52 -0700551 int fieldOffset = fieldPtr->GetOffset().Int32Value();
552 rlObj = loadValue(cUnit, rlObj, kCoreReg);
553 int regPtr = oatAllocTemp(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700554
buzbeeed3e9302011-09-23 17:34:19 -0700555 DCHECK(rlDest.wide);
buzbee34cd9e52011-09-08 14:31:52 -0700556
buzbee5ade1d22011-09-09 14:44:52 -0700557 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700558 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
559 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
560
561 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
562
buzbee34cd9e52011-09-08 14:31:52 -0700563 oatFreeTemp(cUnit, regPtr);
564 storeValueWide(cUnit, rlDest, rlResult);
565 }
buzbee67bf8852011-08-17 17:51:35 -0700566}
567
buzbeeed3e9302011-09-23 17:34:19 -0700568STATIC void genIPutWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
buzbee67bf8852011-08-17 17:51:35 -0700569 RegLocation rlObj)
570{
buzbeec143c552011-08-20 17:38:58 -0700571 Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
572 GetResolvedField(mir->dalvikInsn.vC);
buzbee12246b82011-09-29 14:15:05 -0700573#if ANDROID_SMP != 0
574 bool isVolatile = (fieldPtr == NULL) || fieldPtr->IsVolatile();
575#else
576 bool isVolatile = false;
577#endif
buzbeece302932011-10-04 14:32:18 -0700578 if (SLOW_FIELD_PATH || (fieldPtr == NULL) || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700579 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700580 // Field offset in r0
581 rlObj = loadValue(cUnit, rlObj, kCoreReg);
582 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
buzbee5ade1d22011-09-09 14:44:52 -0700583 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700584 opRegReg(cUnit, kOpAdd, r0, rlObj.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700585 oatGenMemBarrier(cUnit, kSY);
buzbee34cd9e52011-09-08 14:31:52 -0700586 storePair(cUnit, r0, rlSrc.lowReg, rlSrc.highReg);
587 } else {
buzbee34cd9e52011-09-08 14:31:52 -0700588 int fieldOffset = fieldPtr->GetOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -0700589
buzbee34cd9e52011-09-08 14:31:52 -0700590 rlObj = loadValue(cUnit, rlObj, kCoreReg);
591 int regPtr;
592 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
buzbee5ade1d22011-09-09 14:44:52 -0700593 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700594 regPtr = oatAllocTemp(cUnit);
595 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
596
buzbee34cd9e52011-09-08 14:31:52 -0700597 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
598
599 oatFreeTemp(cUnit, regPtr);
600 }
buzbee67bf8852011-08-17 17:51:35 -0700601}
602
buzbeeed3e9302011-09-23 17:34:19 -0700603STATIC void genConstClass(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700604 RegLocation rlDest, RegLocation rlSrc)
605{
Ian Rogers28ad40d2011-10-27 15:19:26 -0700606 uint32_t type_idx = mir->dalvikInsn.vB;
buzbee1b4c8592011-08-31 10:43:51 -0700607 int mReg = loadCurrMethod(cUnit);
608 int resReg = oatAllocTemp(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700609 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700610 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method, type_idx)) {
611 // Check we have access to type_idx and if not throw IllegalAccessError
612 UNIMPLEMENTED(FATAL);
buzbee1b4c8592011-08-31 10:43:51 -0700613 } else {
Ian Rogers28ad40d2011-10-27 15:19:26 -0700614 // We're don't need access checks, load type from dex cache
615 int32_t dex_cache_offset = Method::DexCacheResolvedTypesOffset().Int32Value();
616 loadWordDisp(cUnit, mReg, dex_cache_offset, resReg);
617 int32_t offset_of_type = Array::DataOffset().Int32Value() + (sizeof(Class*) * type_idx);
618 loadWordDisp(cUnit, resReg, offset_of_type, rlResult.lowReg);
619 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->method, type_idx) ||
620 SLOW_TYPE_PATH) {
621 // Slow path, at runtime test if the type is null and if so initialize
622 oatFlushAllRegs(cUnit);
623 ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, rlResult.lowReg, 0);
624 // Resolved, store and hop over following code
625 storeValue(cUnit, rlDest, rlResult);
626 ArmLIR* branch2 = genUnconditionalBranch(cUnit,0);
627 // TUNING: move slow path to end & remove unconditional branch
628 ArmLIR* target1 = newLIR0(cUnit, kArmPseudoTargetLabel);
629 target1->defMask = ENCODE_ALL;
630 // Call out to helper, which will return resolved type in r0
631 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
632 genRegCopy(cUnit, r1, mReg);
633 loadConstant(cUnit, r0, type_idx);
634 callRuntimeHelper(cUnit, rLR);
635 RegLocation rlResult = oatGetReturn(cUnit);
636 storeValue(cUnit, rlDest, rlResult);
637 // Rejoin code paths
638 ArmLIR* target2 = newLIR0(cUnit, kArmPseudoTargetLabel);
639 target2->defMask = ENCODE_ALL;
640 branch1->generic.target = (LIR*)target1;
641 branch2->generic.target = (LIR*)target2;
642 } else {
643 // Fast path, we're done - just store result
644 storeValue(cUnit, rlDest, rlResult);
645 }
buzbee1b4c8592011-08-31 10:43:51 -0700646 }
buzbee67bf8852011-08-17 17:51:35 -0700647}
648
buzbeeed3e9302011-09-23 17:34:19 -0700649STATIC void genConstString(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700650 RegLocation rlDest, RegLocation rlSrc)
651{
buzbeece302932011-10-04 14:32:18 -0700652 /* NOTE: Most strings should be available at compile time */
Ian Rogers28ad40d2011-10-27 15:19:26 -0700653 uint32_t string_idx = mir->dalvikInsn.vB;
654 int32_t offset_of_string = Array::DataOffset().Int32Value() + (sizeof(String*) * string_idx);
655 if (!cUnit->compiler->CanAssumeStringIsPresentInDexCache(cUnit->method, string_idx) ||
656 SLOW_STRING_PATH) {
657 // slow path, resolve string if not in dex cache
buzbeece302932011-10-04 14:32:18 -0700658 oatFlushAllRegs(cUnit);
659 oatLockCallTemps(cUnit); // Using explicit registers
660 loadCurrMethodDirect(cUnit, r2);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700661 loadWordDisp(cUnit, r2, Method::DexCacheStringsOffset().Int32Value(), r0);
buzbeece302932011-10-04 14:32:18 -0700662 // Might call out to helper, which will return resolved string in r0
Ian Rogers28ad40d2011-10-27 15:19:26 -0700663 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pResolveStringFromCode), rLR);
664 loadWordDisp(cUnit, r0, offset_of_string, r0);
665 loadConstant(cUnit, r1, string_idx);
buzbeece302932011-10-04 14:32:18 -0700666 opRegImm(cUnit, kOpCmp, r0, 0); // Is resolved?
667 genBarrier(cUnit);
668 // For testing, always force through helper
669 if (!EXERCISE_SLOWEST_STRING_PATH) {
670 genIT(cUnit, kArmCondEq, "T");
671 }
672 genRegCopy(cUnit, r0, r2); // .eq
673 opReg(cUnit, kOpBlx, rLR); // .eq, helper(Method*, string_idx)
674 genBarrier(cUnit);
675 storeValue(cUnit, rlDest, getRetLoc(cUnit));
676 } else {
677 int mReg = loadCurrMethod(cUnit);
678 int resReg = oatAllocTemp(cUnit);
679 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700680 loadWordDisp(cUnit, mReg, Method::DexCacheStringsOffset().Int32Value(), resReg);
681 loadWordDisp(cUnit, resReg, offset_of_string, rlResult.lowReg);
buzbeece302932011-10-04 14:32:18 -0700682 storeValue(cUnit, rlDest, rlResult);
683 }
buzbee67bf8852011-08-17 17:51:35 -0700684}
685
buzbeedfd3d702011-08-28 12:56:51 -0700686/*
687 * Let helper function take care of everything. Will
688 * call Class::NewInstanceFromCode(type_idx, method);
689 */
buzbeeed3e9302011-09-23 17:34:19 -0700690STATIC void genNewInstance(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700691 RegLocation rlDest)
692{
buzbeedfd3d702011-08-28 12:56:51 -0700693 oatFlushAllRegs(cUnit); /* Everything to home location */
Ian Rogers28ad40d2011-10-27 15:19:26 -0700694 uint32_t type_idx = mir->dalvikInsn.vB;
695 // alloc will always check for resolution, do we also need to verify access because the
696 // verifier was unable to?
697 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method, type_idx)) {
698 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pAllocObjectFromCode), rLR);
699 } else {
700 loadWordDisp(cUnit, rSELF,
701 OFFSETOF_MEMBER(Thread, pAllocObjectFromCodeWithAccessCheck), rLR);
702 }
703 loadCurrMethodDirect(cUnit, r1); // arg1 <= Method*
704 loadConstant(cUnit, r0, type_idx); // arg0 <- type_idx
Ian Rogersff1ed472011-09-20 13:46:24 -0700705 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700706 RegLocation rlResult = oatGetReturn(cUnit);
707 storeValue(cUnit, rlDest, rlResult);
708}
709
710void genThrow(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
711{
buzbee6181f792011-09-29 11:14:04 -0700712 oatFlushAllRegs(cUnit);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700713 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pDeliverException), rLR);
Ian Rogersbdb03912011-09-14 00:55:44 -0700714 loadValueDirectFixed(cUnit, rlSrc, r0); // Get exception object
Ian Rogersff1ed472011-09-20 13:46:24 -0700715 callRuntimeHelper(cUnit, rLR); // art_deliver_exception(exception);
buzbee67bf8852011-08-17 17:51:35 -0700716}
717
buzbeeed3e9302011-09-23 17:34:19 -0700718STATIC void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700719 RegLocation rlSrc)
720{
buzbee6181f792011-09-29 11:14:04 -0700721 oatFlushAllRegs(cUnit);
buzbee2a475e72011-09-07 17:19:17 -0700722 // May generate a call - use explicit registers
723 oatLockCallTemps(cUnit);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700724 uint32_t type_idx = mir->dalvikInsn.vC;
buzbee2a475e72011-09-07 17:19:17 -0700725 loadCurrMethodDirect(cUnit, r1); // r1 <= current Method*
Ian Rogers28ad40d2011-10-27 15:19:26 -0700726 int classReg = r2; // r2 will hold the Class*
727 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method, type_idx)) {
Ian Rogersb093c6b2011-10-31 16:19:55 -0700728 // Check we have access to type_idx and if not throw IllegalAccessError,
729 // returns Class* in r0
730 loadWordDisp(cUnit, rSELF,
731 OFFSETOF_MEMBER(Thread, pInitializeTypeAndVerifyAccessFromCode),
732 rLR);
733 loadConstant(cUnit, r0, type_idx);
734 callRuntimeHelper(cUnit, rLR); // InitializeTypeAndVerifyAccess(idx, method)
735 genRegCopy(cUnit, classReg, r0); // Align usage with fast path
Ian Rogers6a996782011-10-31 17:06:39 -0700736 loadValueDirectFixed(cUnit, rlSrc, r0); // r0 <= ref
Ian Rogers28ad40d2011-10-27 15:19:26 -0700737 } else {
738 // Load dex cache entry into classReg (r2)
Ian Rogers6a996782011-10-31 17:06:39 -0700739 loadValueDirectFixed(cUnit, rlSrc, r0); // r0 <= ref
Ian Rogers28ad40d2011-10-27 15:19:26 -0700740 loadWordDisp(cUnit, r1, Method::DexCacheResolvedTypesOffset().Int32Value(), classReg);
741 int32_t offset_of_type = Array::DataOffset().Int32Value() + (sizeof(Class*) * type_idx);
742 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
743 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->method, type_idx)) {
744 // Need to test presence of type in dex cache at runtime
745 ArmLIR* hopBranch = genCmpImmBranch(cUnit, kArmCondNe, classReg, 0);
746 // Not resolved
747 // Call out to helper, which will return resolved type in r0
748 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
749 loadConstant(cUnit, r0, type_idx);
Ian Rogersb093c6b2011-10-31 16:19:55 -0700750 callRuntimeHelper(cUnit, rLR); // InitializeTypeFromCode(idx, method)
Ian Rogers28ad40d2011-10-27 15:19:26 -0700751 genRegCopy(cUnit, r2, r0); // Align usage with fast path
752 loadValueDirectFixed(cUnit, rlSrc, r0); /* reload Ref */
753 // Rejoin code paths
754 ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
755 hopTarget->defMask = ENCODE_ALL;
756 hopBranch->generic.target = (LIR*)hopTarget;
757 }
buzbee67bf8852011-08-17 17:51:35 -0700758 }
buzbee991e3ac2011-09-29 15:44:22 -0700759 /* r0 is ref, r2 is class. If ref==null, use directly as bool result */
760 ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, r0, 0);
buzbee2a475e72011-09-07 17:19:17 -0700761 /* load object->clazz */
buzbeeed3e9302011-09-23 17:34:19 -0700762 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
buzbee991e3ac2011-09-29 15:44:22 -0700763 loadWordDisp(cUnit, r0, Object::ClassOffset().Int32Value(), r1);
764 /* r0 is ref, r1 is ref->clazz, r2 is class */
Ian Rogers28ad40d2011-10-27 15:19:26 -0700765 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInstanceofNonTrivialFromCode), rLR);
buzbee991e3ac2011-09-29 15:44:22 -0700766 opRegReg(cUnit, kOpCmp, r1, r2); // Same?
767 genBarrier(cUnit);
768 genIT(cUnit, kArmCondEq, "EE"); // if-convert the test
769 loadConstant(cUnit, r0, 1); // .eq case - load true
770 genRegCopy(cUnit, r0, r2); // .ne case - arg0 <= class
771 opReg(cUnit, kOpBlx, rLR); // .ne case: helper(class, ref->class)
772 genBarrier(cUnit);
773 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700774 /* branch target here */
775 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
776 target->defMask = ENCODE_ALL;
buzbee2a475e72011-09-07 17:19:17 -0700777 RegLocation rlResult = oatGetReturn(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700778 storeValue(cUnit, rlDest, rlResult);
779 branch1->generic.target = (LIR*)target;
buzbee67bf8852011-08-17 17:51:35 -0700780}
781
buzbeeed3e9302011-09-23 17:34:19 -0700782STATIC void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700783{
buzbee6181f792011-09-29 11:14:04 -0700784 oatFlushAllRegs(cUnit);
buzbee2a475e72011-09-07 17:19:17 -0700785 // May generate a call - use explicit registers
786 oatLockCallTemps(cUnit);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700787 uint32_t type_idx = mir->dalvikInsn.vB;
buzbee2a475e72011-09-07 17:19:17 -0700788 loadCurrMethodDirect(cUnit, r1); // r1 <= current Method*
Ian Rogers28ad40d2011-10-27 15:19:26 -0700789 int classReg = r2; // r2 will hold the Class*
790 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method, type_idx)) {
Ian Rogersb093c6b2011-10-31 16:19:55 -0700791 // Check we have access to type_idx and if not throw IllegalAccessError,
792 // returns Class* in r0
793 loadWordDisp(cUnit, rSELF,
794 OFFSETOF_MEMBER(Thread, pInitializeTypeAndVerifyAccessFromCode),
795 rLR);
796 loadConstant(cUnit, r0, type_idx);
797 callRuntimeHelper(cUnit, rLR); // InitializeTypeAndVerifyAccess(idx, method)
798 genRegCopy(cUnit, classReg, r0); // Align usage with fast path
Ian Rogers28ad40d2011-10-27 15:19:26 -0700799 } else {
800 // Load dex cache entry into classReg (r2)
801 loadWordDisp(cUnit, r1, Method::DexCacheResolvedTypesOffset().Int32Value(), classReg);
802 int32_t offset_of_type = Array::DataOffset().Int32Value() + (sizeof(Class*) * type_idx);
803 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
804 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->method, type_idx)) {
805 // Need to test presence of type in dex cache at runtime
806 ArmLIR* hopBranch = genCmpImmBranch(cUnit, kArmCondNe, classReg, 0);
807 // Not resolved
808 // Call out to helper, which will return resolved type in r0
809 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
810 loadConstant(cUnit, r0, type_idx);
Ian Rogersb093c6b2011-10-31 16:19:55 -0700811 callRuntimeHelper(cUnit, rLR); // InitializeTypeFromCode(idx, method)
812 genRegCopy(cUnit, classReg, r0); // Align usage with fast path
Ian Rogers28ad40d2011-10-27 15:19:26 -0700813 // Rejoin code paths
814 ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
815 hopTarget->defMask = ENCODE_ALL;
816 hopBranch->generic.target = (LIR*)hopTarget;
817 }
buzbee67bf8852011-08-17 17:51:35 -0700818 }
Ian Rogers28ad40d2011-10-27 15:19:26 -0700819 // At this point, classReg (r2) has class
820 loadValueDirectFixed(cUnit, rlSrc, r0); // r0 <= ref
buzbee2a475e72011-09-07 17:19:17 -0700821 /* Null is OK - continue */
822 ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, r0, 0);
823 /* load object->clazz */
buzbeeed3e9302011-09-23 17:34:19 -0700824 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
buzbee2a475e72011-09-07 17:19:17 -0700825 loadWordDisp(cUnit, r0, Object::ClassOffset().Int32Value(), r1);
826 /* r1 now contains object->clazz */
Ian Rogers28ad40d2011-10-27 15:19:26 -0700827 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pCheckCastFromCode), rLR);
Ian Rogersb093c6b2011-10-31 16:19:55 -0700828 opRegReg(cUnit, kOpCmp, r1, classReg);
buzbee2a475e72011-09-07 17:19:17 -0700829 ArmLIR* branch2 = opCondBranch(cUnit, kArmCondEq); /* If equal, trivial yes */
830 genRegCopy(cUnit, r0, r1);
831 genRegCopy(cUnit, r1, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -0700832 callRuntimeHelper(cUnit, rLR);
buzbee2a475e72011-09-07 17:19:17 -0700833 /* branch target here */
buzbee67bf8852011-08-17 17:51:35 -0700834 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
835 target->defMask = ENCODE_ALL;
836 branch1->generic.target = (LIR*)target;
837 branch2->generic.target = (LIR*)target;
838}
839
buzbeeed3e9302011-09-23 17:34:19 -0700840STATIC void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700841 RegLocation rlSrc)
842{
843 RegLocation rlResult;
844 rlSrc = loadValue(cUnit, rlSrc, kFPReg);
845 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
846 newLIR2(cUnit, kThumb2Vnegs, rlResult.lowReg, rlSrc.lowReg);
847 storeValue(cUnit, rlDest, rlResult);
848}
849
buzbeeed3e9302011-09-23 17:34:19 -0700850STATIC void genNegDouble(CompilationUnit* cUnit, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700851 RegLocation rlSrc)
852{
853 RegLocation rlResult;
854 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
855 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
856 newLIR2(cUnit, kThumb2Vnegd, S2D(rlResult.lowReg, rlResult.highReg),
857 S2D(rlSrc.lowReg, rlSrc.highReg));
858 storeValueWide(cUnit, rlDest, rlResult);
859}
860
buzbeeed3e9302011-09-23 17:34:19 -0700861STATIC void freeRegLocTemps(CompilationUnit* cUnit, RegLocation rlKeep,
buzbee439c4fa2011-08-27 15:59:07 -0700862 RegLocation rlFree)
buzbee67bf8852011-08-17 17:51:35 -0700863{
buzbee6181f792011-09-29 11:14:04 -0700864 if ((rlFree.lowReg != rlKeep.lowReg) && (rlFree.lowReg != rlKeep.highReg) &&
865 (rlFree.highReg != rlKeep.lowReg) && (rlFree.highReg != rlKeep.highReg)) {
866 // No overlap, free both
buzbee439c4fa2011-08-27 15:59:07 -0700867 oatFreeTemp(cUnit, rlFree.lowReg);
buzbee6181f792011-09-29 11:14:04 -0700868 oatFreeTemp(cUnit, rlFree.highReg);
869 }
buzbee67bf8852011-08-17 17:51:35 -0700870}
871
buzbeeed3e9302011-09-23 17:34:19 -0700872STATIC void genLong3Addr(CompilationUnit* cUnit, MIR* mir, OpKind firstOp,
buzbee67bf8852011-08-17 17:51:35 -0700873 OpKind secondOp, RegLocation rlDest,
874 RegLocation rlSrc1, RegLocation rlSrc2)
875{
buzbee9e0f9b02011-08-24 15:32:46 -0700876 /*
877 * NOTE: This is the one place in the code in which we might have
878 * as many as six live temporary registers. There are 5 in the normal
879 * set for Arm. Until we have spill capabilities, temporarily add
880 * lr to the temp set. It is safe to do this locally, but note that
881 * lr is used explicitly elsewhere in the code generator and cannot
882 * normally be used as a general temp register.
883 */
buzbee67bf8852011-08-17 17:51:35 -0700884 RegLocation rlResult;
buzbee9e0f9b02011-08-24 15:32:46 -0700885 oatMarkTemp(cUnit, rLR); // Add lr to the temp pool
886 oatFreeTemp(cUnit, rLR); // and make it available
buzbee67bf8852011-08-17 17:51:35 -0700887 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
888 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
889 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbeec0ecd652011-09-25 18:11:54 -0700890 // The longs may overlap - use intermediate temp if so
891 if (rlResult.lowReg == rlSrc1.highReg) {
buzbeec0ecd652011-09-25 18:11:54 -0700892 int tReg = oatAllocTemp(cUnit);
893 genRegCopy(cUnit, tReg, rlSrc1.highReg);
894 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
895 rlSrc2.lowReg);
896 opRegRegReg(cUnit, secondOp, rlResult.highReg, tReg,
897 rlSrc2.highReg);
898 oatFreeTemp(cUnit, tReg);
899 } else {
900 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
901 rlSrc2.lowReg);
902 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
903 rlSrc2.highReg);
904 }
buzbee439c4fa2011-08-27 15:59:07 -0700905 /*
906 * NOTE: If rlDest refers to a frame variable in a large frame, the
907 * following storeValueWide might need to allocate a temp register.
908 * To further work around the lack of a spill capability, explicitly
909 * free any temps from rlSrc1 & rlSrc2 that aren't still live in rlResult.
910 * Remove when spill is functional.
911 */
912 freeRegLocTemps(cUnit, rlResult, rlSrc1);
913 freeRegLocTemps(cUnit, rlResult, rlSrc2);
buzbee67bf8852011-08-17 17:51:35 -0700914 storeValueWide(cUnit, rlDest, rlResult);
buzbee9e0f9b02011-08-24 15:32:46 -0700915 oatClobber(cUnit, rLR);
916 oatUnmarkTemp(cUnit, rLR); // Remove lr from the temp pool
buzbee67bf8852011-08-17 17:51:35 -0700917}
918
919void oatInitializeRegAlloc(CompilationUnit* cUnit)
920{
921 int numRegs = sizeof(coreRegs)/sizeof(*coreRegs);
922 int numReserved = sizeof(reservedRegs)/sizeof(*reservedRegs);
923 int numTemps = sizeof(coreTemps)/sizeof(*coreTemps);
924 int numFPRegs = sizeof(fpRegs)/sizeof(*fpRegs);
925 int numFPTemps = sizeof(fpTemps)/sizeof(*fpTemps);
926 RegisterPool *pool = (RegisterPool *)oatNew(sizeof(*pool), true);
927 cUnit->regPool = pool;
928 pool->numCoreRegs = numRegs;
929 pool->coreRegs = (RegisterInfo *)
930 oatNew(numRegs * sizeof(*cUnit->regPool->coreRegs), true);
931 pool->numFPRegs = numFPRegs;
932 pool->FPRegs = (RegisterInfo *)
933 oatNew(numFPRegs * sizeof(*cUnit->regPool->FPRegs), true);
934 oatInitPool(pool->coreRegs, coreRegs, pool->numCoreRegs);
935 oatInitPool(pool->FPRegs, fpRegs, pool->numFPRegs);
936 // Keep special registers from being allocated
937 for (int i = 0; i < numReserved; i++) {
buzbeec0ecd652011-09-25 18:11:54 -0700938 if (NO_SUSPEND && (reservedRegs[i] == rSUSPEND)) {
939 //To measure cost of suspend check
940 continue;
941 }
buzbee67bf8852011-08-17 17:51:35 -0700942 oatMarkInUse(cUnit, reservedRegs[i]);
943 }
944 // Mark temp regs - all others not in use can be used for promotion
945 for (int i = 0; i < numTemps; i++) {
946 oatMarkTemp(cUnit, coreTemps[i]);
947 }
948 for (int i = 0; i < numFPTemps; i++) {
949 oatMarkTemp(cUnit, fpTemps[i]);
950 }
buzbeec0ecd652011-09-25 18:11:54 -0700951 // Construct the alias map.
952 cUnit->phiAliasMap = (int*)oatNew(cUnit->numSSARegs *
953 sizeof(cUnit->phiAliasMap[0]), false);
954 for (int i = 0; i < cUnit->numSSARegs; i++) {
955 cUnit->phiAliasMap[i] = i;
956 }
957 for (MIR* phi = cUnit->phiList; phi; phi = phi->meta.phiNext) {
958 int defReg = phi->ssaRep->defs[0];
959 for (int i = 0; i < phi->ssaRep->numUses; i++) {
960 for (int j = 0; j < cUnit->numSSARegs; j++) {
961 if (cUnit->phiAliasMap[j] == phi->ssaRep->uses[i]) {
962 cUnit->phiAliasMap[j] = defReg;
963 }
964 }
965 }
966 }
buzbee67bf8852011-08-17 17:51:35 -0700967}
968
969/*
970 * Handle simple case (thin lock) inline. If it's complicated, bail
971 * out to the heavyweight lock/unlock routines. We'll use dedicated
972 * registers here in order to be in the right position in case we
973 * to bail to dvm[Lock/Unlock]Object(self, object)
974 *
975 * r0 -> self pointer [arg0 for dvm[Lock/Unlock]Object
976 * r1 -> object [arg1 for dvm[Lock/Unlock]Object
977 * r2 -> intial contents of object->lock, later result of strex
978 * r3 -> self->threadId
979 * r12 -> allow to be used by utilities as general temp
980 *
981 * The result of the strex is 0 if we acquire the lock.
982 *
983 * See comments in Sync.c for the layout of the lock word.
984 * Of particular interest to this code is the test for the
985 * simple case - which we handle inline. For monitor enter, the
986 * simple case is thin lock, held by no-one. For monitor exit,
987 * the simple case is thin lock, held by the unlocking thread with
988 * a recurse count of 0.
989 *
990 * A minor complication is that there is a field in the lock word
991 * unrelated to locking: the hash state. This field must be ignored, but
992 * preserved.
993 *
994 */
buzbeeed3e9302011-09-23 17:34:19 -0700995STATIC void genMonitorEnter(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700996 RegLocation rlSrc)
997{
998 ArmLIR* target;
999 ArmLIR* hopTarget;
1000 ArmLIR* branch;
1001 ArmLIR* hopBranch;
1002
1003 oatFlushAllRegs(cUnit);
Elliott Hughes5f791332011-09-15 17:45:30 -07001004 DCHECK_EQ(LW_SHAPE_THIN, 0);
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001005 loadValueDirectFixed(cUnit, rlSrc, r0); // Get obj
buzbee2e748f32011-08-29 21:02:19 -07001006 oatLockCallTemps(cUnit); // Prepare for explicit register usage
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001007 genNullCheck(cUnit, rlSrc.sRegLow, r0, mir);
1008 loadWordDisp(cUnit, rSELF, Thread::ThinLockIdOffset().Int32Value(), r2);
1009 newLIR3(cUnit, kThumb2Ldrex, r1, r0,
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001010 Object::MonitorOffset().Int32Value() >> 2); // Get object->lock
buzbeec143c552011-08-20 17:38:58 -07001011 // Align owner
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001012 opRegImm(cUnit, kOpLsl, r2, LW_LOCK_OWNER_SHIFT);
buzbee67bf8852011-08-17 17:51:35 -07001013 // Is lock unheld on lock or held by us (==threadId) on unlock?
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001014 newLIR4(cUnit, kThumb2Bfi, r2, r1, 0, LW_LOCK_OWNER_SHIFT - 1);
1015 newLIR3(cUnit, kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
1016 hopBranch = newLIR2(cUnit, kThumb2Cbnz, r1, 0);
1017 newLIR4(cUnit, kThumb2Strex, r1, r2, r0,
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001018 Object::MonitorOffset().Int32Value() >> 2);
buzbee67bf8852011-08-17 17:51:35 -07001019 oatGenMemBarrier(cUnit, kSY);
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001020 branch = newLIR2(cUnit, kThumb2Cbz, r1, 0);
buzbee67bf8852011-08-17 17:51:35 -07001021
1022 hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
1023 hopTarget->defMask = ENCODE_ALL;
1024 hopBranch->generic.target = (LIR*)hopTarget;
1025
buzbee1b4c8592011-08-31 10:43:51 -07001026 // Go expensive route - artLockObjectFromCode(self, obj);
1027 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pLockObjectFromCode),
buzbee67bf8852011-08-17 17:51:35 -07001028 rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07001029 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001030
1031 // Resume here
1032 target = newLIR0(cUnit, kArmPseudoTargetLabel);
1033 target->defMask = ENCODE_ALL;
1034 branch->generic.target = (LIR*)target;
1035}
1036
1037/*
1038 * For monitor unlock, we don't have to use ldrex/strex. Once
1039 * we've determined that the lock is thin and that we own it with
1040 * a zero recursion count, it's safe to punch it back to the
1041 * initial, unlock thin state with a store word.
1042 */
buzbeeed3e9302011-09-23 17:34:19 -07001043STATIC void genMonitorExit(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001044 RegLocation rlSrc)
1045{
1046 ArmLIR* target;
1047 ArmLIR* branch;
1048 ArmLIR* hopTarget;
1049 ArmLIR* hopBranch;
1050
Elliott Hughes5f791332011-09-15 17:45:30 -07001051 DCHECK_EQ(LW_SHAPE_THIN, 0);
buzbee67bf8852011-08-17 17:51:35 -07001052 oatFlushAllRegs(cUnit);
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001053 loadValueDirectFixed(cUnit, rlSrc, r0); // Get obj
buzbee2e748f32011-08-29 21:02:19 -07001054 oatLockCallTemps(cUnit); // Prepare for explicit register usage
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001055 genNullCheck(cUnit, rlSrc.sRegLow, r0, mir);
1056 loadWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r1); // Get lock
1057 loadWordDisp(cUnit, rSELF, Thread::ThinLockIdOffset().Int32Value(), r2);
buzbee67bf8852011-08-17 17:51:35 -07001058 // Is lock unheld on lock or held by us (==threadId) on unlock?
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001059 opRegRegImm(cUnit, kOpAnd, r3, r1, (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
buzbeec143c552011-08-20 17:38:58 -07001060 // Align owner
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001061 opRegImm(cUnit, kOpLsl, r2, LW_LOCK_OWNER_SHIFT);
1062 newLIR3(cUnit, kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
1063 opRegReg(cUnit, kOpSub, r1, r2);
buzbee67bf8852011-08-17 17:51:35 -07001064 hopBranch = opCondBranch(cUnit, kArmCondNe);
1065 oatGenMemBarrier(cUnit, kSY);
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001066 storeWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r3);
buzbee67bf8852011-08-17 17:51:35 -07001067 branch = opNone(cUnit, kOpUncondBr);
1068
1069 hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
1070 hopTarget->defMask = ENCODE_ALL;
1071 hopBranch->generic.target = (LIR*)hopTarget;
1072
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001073 // Go expensive route - UnlockObjectFromCode(obj);
buzbee1b4c8592011-08-31 10:43:51 -07001074 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pUnlockObjectFromCode),
buzbee67bf8852011-08-17 17:51:35 -07001075 rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07001076 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001077
1078 // Resume here
1079 target = newLIR0(cUnit, kArmPseudoTargetLabel);
1080 target->defMask = ENCODE_ALL;
1081 branch->generic.target = (LIR*)target;
1082}
1083
1084/*
1085 * 64-bit 3way compare function.
1086 * mov rX, #-1
1087 * cmp op1hi, op2hi
1088 * blt done
1089 * bgt flip
1090 * sub rX, op1lo, op2lo (treat as unsigned)
1091 * beq done
1092 * ite hi
1093 * mov(hi) rX, #-1
1094 * mov(!hi) rX, #1
1095 * flip:
1096 * neg rX
1097 * done:
1098 */
buzbeeed3e9302011-09-23 17:34:19 -07001099STATIC void genCmpLong(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001100 RegLocation rlDest, RegLocation rlSrc1,
1101 RegLocation rlSrc2)
1102{
buzbee67bf8852011-08-17 17:51:35 -07001103 ArmLIR* target1;
1104 ArmLIR* target2;
1105 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
1106 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
buzbeeb29e4d12011-09-26 15:05:48 -07001107 int tReg = oatAllocTemp(cUnit);
1108 loadConstant(cUnit, tReg, -1);
buzbee67bf8852011-08-17 17:51:35 -07001109 opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg);
1110 ArmLIR* branch1 = opCondBranch(cUnit, kArmCondLt);
1111 ArmLIR* branch2 = opCondBranch(cUnit, kArmCondGt);
buzbeeb29e4d12011-09-26 15:05:48 -07001112 opRegRegReg(cUnit, kOpSub, tReg, rlSrc1.lowReg, rlSrc2.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001113 ArmLIR* branch3 = opCondBranch(cUnit, kArmCondEq);
1114
1115 genIT(cUnit, kArmCondHi, "E");
buzbeeb29e4d12011-09-26 15:05:48 -07001116 newLIR2(cUnit, kThumb2MovImmShift, tReg, modifiedImmediate(-1));
1117 loadConstant(cUnit, tReg, 1);
buzbee67bf8852011-08-17 17:51:35 -07001118 genBarrier(cUnit);
1119
1120 target2 = newLIR0(cUnit, kArmPseudoTargetLabel);
1121 target2->defMask = -1;
buzbeeb29e4d12011-09-26 15:05:48 -07001122 opRegReg(cUnit, kOpNeg, tReg, tReg);
buzbee67bf8852011-08-17 17:51:35 -07001123
1124 target1 = newLIR0(cUnit, kArmPseudoTargetLabel);
1125 target1->defMask = -1;
1126
buzbeeb29e4d12011-09-26 15:05:48 -07001127 RegLocation rlTemp = LOC_C_RETURN; // Just using as template, will change
1128 rlTemp.lowReg = tReg;
buzbee67bf8852011-08-17 17:51:35 -07001129 storeValue(cUnit, rlDest, rlTemp);
buzbeeb29e4d12011-09-26 15:05:48 -07001130 oatFreeTemp(cUnit, tReg);
buzbee67bf8852011-08-17 17:51:35 -07001131
1132 branch1->generic.target = (LIR*)target1;
1133 branch2->generic.target = (LIR*)target2;
1134 branch3->generic.target = branch1->generic.target;
1135}
1136
buzbeeed3e9302011-09-23 17:34:19 -07001137STATIC void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -07001138 RegLocation rlSrc, RegLocation rlResult, int lit,
1139 int firstBit, int secondBit)
1140{
1141 opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg,
1142 encodeShift(kArmLsl, secondBit - firstBit));
1143 if (firstBit != 0) {
1144 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
1145 }
1146}
1147
buzbeeed3e9302011-09-23 17:34:19 -07001148STATIC bool genConversionCall(CompilationUnit* cUnit, MIR* mir, int funcOffset,
buzbee67bf8852011-08-17 17:51:35 -07001149 int srcSize, int tgtSize)
1150{
1151 /*
1152 * Don't optimize the register usage since it calls out to support
1153 * functions
1154 */
1155 RegLocation rlSrc;
1156 RegLocation rlDest;
1157 oatFlushAllRegs(cUnit); /* Send everything to home location */
1158 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1159 if (srcSize == 1) {
1160 rlSrc = oatGetSrc(cUnit, mir, 0);
1161 loadValueDirectFixed(cUnit, rlSrc, r0);
1162 } else {
1163 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
1164 loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
1165 }
Ian Rogersff1ed472011-09-20 13:46:24 -07001166 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001167 if (tgtSize == 1) {
1168 RegLocation rlResult;
1169 rlDest = oatGetDest(cUnit, mir, 0);
1170 rlResult = oatGetReturn(cUnit);
1171 storeValue(cUnit, rlDest, rlResult);
1172 } else {
1173 RegLocation rlResult;
1174 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1175 rlResult = oatGetReturnWide(cUnit);
1176 storeValueWide(cUnit, rlDest, rlResult);
1177 }
1178 return false;
1179}
1180
buzbeeed3e9302011-09-23 17:34:19 -07001181STATIC bool genArithOpFloatPortable(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001182 RegLocation rlDest, RegLocation rlSrc1,
1183 RegLocation rlSrc2)
1184{
1185 RegLocation rlResult;
1186 int funcOffset;
1187
1188 switch (mir->dalvikInsn.opcode) {
1189 case OP_ADD_FLOAT_2ADDR:
1190 case OP_ADD_FLOAT:
1191 funcOffset = OFFSETOF_MEMBER(Thread, pFadd);
1192 break;
1193 case OP_SUB_FLOAT_2ADDR:
1194 case OP_SUB_FLOAT:
1195 funcOffset = OFFSETOF_MEMBER(Thread, pFsub);
1196 break;
1197 case OP_DIV_FLOAT_2ADDR:
1198 case OP_DIV_FLOAT:
1199 funcOffset = OFFSETOF_MEMBER(Thread, pFdiv);
1200 break;
1201 case OP_MUL_FLOAT_2ADDR:
1202 case OP_MUL_FLOAT:
1203 funcOffset = OFFSETOF_MEMBER(Thread, pFmul);
1204 break;
1205 case OP_REM_FLOAT_2ADDR:
1206 case OP_REM_FLOAT:
1207 funcOffset = OFFSETOF_MEMBER(Thread, pFmodf);
1208 break;
1209 case OP_NEG_FLOAT: {
1210 genNegFloat(cUnit, rlDest, rlSrc1);
1211 return false;
1212 }
1213 default:
1214 return true;
1215 }
1216 oatFlushAllRegs(cUnit); /* Send everything to home location */
1217 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1218 loadValueDirectFixed(cUnit, rlSrc1, r0);
1219 loadValueDirectFixed(cUnit, rlSrc2, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -07001220 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001221 rlResult = oatGetReturn(cUnit);
1222 storeValue(cUnit, rlDest, rlResult);
1223 return false;
1224}
1225
buzbeeed3e9302011-09-23 17:34:19 -07001226STATIC bool genArithOpDoublePortable(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001227 RegLocation rlDest, RegLocation rlSrc1,
1228 RegLocation rlSrc2)
1229{
1230 RegLocation rlResult;
1231 int funcOffset;
1232
1233 switch (mir->dalvikInsn.opcode) {
1234 case OP_ADD_DOUBLE_2ADDR:
1235 case OP_ADD_DOUBLE:
1236 funcOffset = OFFSETOF_MEMBER(Thread, pDadd);
1237 break;
1238 case OP_SUB_DOUBLE_2ADDR:
1239 case OP_SUB_DOUBLE:
1240 funcOffset = OFFSETOF_MEMBER(Thread, pDsub);
1241 break;
1242 case OP_DIV_DOUBLE_2ADDR:
1243 case OP_DIV_DOUBLE:
1244 funcOffset = OFFSETOF_MEMBER(Thread, pDdiv);
1245 break;
1246 case OP_MUL_DOUBLE_2ADDR:
1247 case OP_MUL_DOUBLE:
1248 funcOffset = OFFSETOF_MEMBER(Thread, pDmul);
1249 break;
1250 case OP_REM_DOUBLE_2ADDR:
1251 case OP_REM_DOUBLE:
1252 funcOffset = OFFSETOF_MEMBER(Thread, pFmod);
1253 break;
1254 case OP_NEG_DOUBLE: {
1255 genNegDouble(cUnit, rlDest, rlSrc1);
1256 return false;
1257 }
1258 default:
1259 return true;
1260 }
1261 oatFlushAllRegs(cUnit); /* Send everything to home location */
1262 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1263 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1264 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
Ian Rogersff1ed472011-09-20 13:46:24 -07001265 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001266 rlResult = oatGetReturnWide(cUnit);
1267 storeValueWide(cUnit, rlDest, rlResult);
1268 return false;
1269}
1270
buzbeeed3e9302011-09-23 17:34:19 -07001271STATIC bool genConversionPortable(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001272{
1273 Opcode opcode = mir->dalvikInsn.opcode;
1274
1275 switch (opcode) {
1276 case OP_INT_TO_FLOAT:
1277 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2f),
1278 1, 1);
1279 case OP_FLOAT_TO_INT:
1280 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2iz),
1281 1, 1);
1282 case OP_DOUBLE_TO_FLOAT:
1283 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2f),
1284 2, 1);
1285 case OP_FLOAT_TO_DOUBLE:
1286 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2d),
1287 1, 2);
1288 case OP_INT_TO_DOUBLE:
1289 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2d),
1290 1, 2);
1291 case OP_DOUBLE_TO_INT:
1292 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2iz),
1293 2, 1);
1294 case OP_FLOAT_TO_LONG:
1295 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
buzbee1b4c8592011-08-31 10:43:51 -07001296 pF2l), 1, 2);
buzbee67bf8852011-08-17 17:51:35 -07001297 case OP_LONG_TO_FLOAT:
1298 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2f),
1299 2, 1);
1300 case OP_DOUBLE_TO_LONG:
1301 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
buzbee1b4c8592011-08-31 10:43:51 -07001302 pD2l), 2, 2);
buzbee67bf8852011-08-17 17:51:35 -07001303 case OP_LONG_TO_DOUBLE:
1304 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2d),
1305 2, 2);
1306 default:
1307 return true;
1308 }
1309 return false;
1310}
1311
1312/* Generate conditional branch instructions */
buzbeeed3e9302011-09-23 17:34:19 -07001313STATIC ArmLIR* genConditionalBranch(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -07001314 ArmConditionCode cond,
1315 ArmLIR* target)
1316{
1317 ArmLIR* branch = opCondBranch(cUnit, cond);
1318 branch->generic.target = (LIR*) target;
1319 return branch;
1320}
1321
buzbee67bf8852011-08-17 17:51:35 -07001322/*
1323 * Generate array store
1324 *
1325 */
buzbeeed3e9302011-09-23 17:34:19 -07001326STATIC void genArrayObjPut(CompilationUnit* cUnit, MIR* mir,
buzbee1b4c8592011-08-31 10:43:51 -07001327 RegLocation rlArray, RegLocation rlIndex,
1328 RegLocation rlSrc, int scale)
buzbee67bf8852011-08-17 17:51:35 -07001329{
1330 RegisterClass regClass = oatRegClassBySize(kWord);
buzbeec143c552011-08-20 17:38:58 -07001331 int lenOffset = Array::LengthOffset().Int32Value();
1332 int dataOffset = Array::DataOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001333
buzbee6181f792011-09-29 11:14:04 -07001334 oatFlushAllRegs(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001335 /* Make sure it's a legal object Put. Use direct regs at first */
1336 loadValueDirectFixed(cUnit, rlArray, r1);
1337 loadValueDirectFixed(cUnit, rlSrc, r0);
1338
1339 /* null array object? */
buzbee43a36422011-09-14 14:00:13 -07001340 genNullCheck(cUnit, rlArray.sRegLow, r1, mir);
buzbee67bf8852011-08-17 17:51:35 -07001341 loadWordDisp(cUnit, rSELF,
buzbee1b4c8592011-08-31 10:43:51 -07001342 OFFSETOF_MEMBER(Thread, pCanPutArrayElementFromCode), rLR);
buzbee67bf8852011-08-17 17:51:35 -07001343 /* Get the array's clazz */
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001344 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), r1);
Ian Rogersff1ed472011-09-20 13:46:24 -07001345 callRuntimeHelper(cUnit, rLR);
buzbee6181f792011-09-29 11:14:04 -07001346 oatFreeTemp(cUnit, r0);
1347 oatFreeTemp(cUnit, r1);
buzbee67bf8852011-08-17 17:51:35 -07001348
1349 // Now, redo loadValues in case they didn't survive the call
1350
1351 int regPtr;
1352 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1353 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1354
1355 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1356 oatClobber(cUnit, rlArray.lowReg);
1357 regPtr = rlArray.lowReg;
1358 } else {
1359 regPtr = oatAllocTemp(cUnit);
1360 genRegCopy(cUnit, regPtr, rlArray.lowReg);
1361 }
1362
buzbee43a36422011-09-14 14:00:13 -07001363 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee67bf8852011-08-17 17:51:35 -07001364 int regLen = oatAllocTemp(cUnit);
1365 //NOTE: max live temps(4) here.
1366 /* Get len */
1367 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1368 /* regPtr -> array data */
1369 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
buzbeeec5adf32011-09-11 15:25:43 -07001370 genRegRegCheck(cUnit, kArmCondCs, rlIndex.lowReg, regLen, mir,
buzbee5ade1d22011-09-09 14:44:52 -07001371 kArmThrowArrayBounds);
buzbee67bf8852011-08-17 17:51:35 -07001372 oatFreeTemp(cUnit, regLen);
1373 } else {
1374 /* regPtr -> array data */
1375 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1376 }
1377 /* at this point, regPtr points to array, 2 live temps */
1378 rlSrc = loadValue(cUnit, rlSrc, regClass);
1379 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1380 scale, kWord);
1381}
1382
1383/*
1384 * Generate array load
1385 */
buzbeeed3e9302011-09-23 17:34:19 -07001386STATIC void genArrayGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -07001387 RegLocation rlArray, RegLocation rlIndex,
1388 RegLocation rlDest, int scale)
1389{
1390 RegisterClass regClass = oatRegClassBySize(size);
buzbeec143c552011-08-20 17:38:58 -07001391 int lenOffset = Array::LengthOffset().Int32Value();
1392 int dataOffset = Array::DataOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001393 RegLocation rlResult;
1394 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1395 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1396 int regPtr;
1397
1398 /* null object? */
buzbee43a36422011-09-14 14:00:13 -07001399 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001400
1401 regPtr = oatAllocTemp(cUnit);
1402
buzbee43a36422011-09-14 14:00:13 -07001403 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee67bf8852011-08-17 17:51:35 -07001404 int regLen = oatAllocTemp(cUnit);
1405 /* Get len */
1406 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1407 /* regPtr -> array data */
1408 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
buzbeeec5adf32011-09-11 15:25:43 -07001409 genRegRegCheck(cUnit, kArmCondCs, rlIndex.lowReg, regLen, mir,
buzbee5ade1d22011-09-09 14:44:52 -07001410 kArmThrowArrayBounds);
buzbee67bf8852011-08-17 17:51:35 -07001411 oatFreeTemp(cUnit, regLen);
1412 } else {
1413 /* regPtr -> array data */
1414 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1415 }
buzbeee9a72f62011-09-04 17:59:07 -07001416 oatFreeTemp(cUnit, rlArray.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001417 if ((size == kLong) || (size == kDouble)) {
1418 if (scale) {
1419 int rNewIndex = oatAllocTemp(cUnit);
1420 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1421 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1422 oatFreeTemp(cUnit, rNewIndex);
1423 } else {
1424 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1425 }
buzbeee9a72f62011-09-04 17:59:07 -07001426 oatFreeTemp(cUnit, rlIndex.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001427 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1428
1429 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1430
1431 oatFreeTemp(cUnit, regPtr);
1432 storeValueWide(cUnit, rlDest, rlResult);
1433 } else {
1434 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1435
1436 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
1437 scale, size);
1438
1439 oatFreeTemp(cUnit, regPtr);
1440 storeValue(cUnit, rlDest, rlResult);
1441 }
1442}
1443
1444/*
1445 * Generate array store
1446 *
1447 */
buzbeeed3e9302011-09-23 17:34:19 -07001448STATIC void genArrayPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -07001449 RegLocation rlArray, RegLocation rlIndex,
1450 RegLocation rlSrc, int scale)
1451{
1452 RegisterClass regClass = oatRegClassBySize(size);
buzbeec143c552011-08-20 17:38:58 -07001453 int lenOffset = Array::LengthOffset().Int32Value();
1454 int dataOffset = Array::DataOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001455
1456 int regPtr;
1457 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1458 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1459
1460 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1461 oatClobber(cUnit, rlArray.lowReg);
1462 regPtr = rlArray.lowReg;
1463 } else {
1464 regPtr = oatAllocTemp(cUnit);
1465 genRegCopy(cUnit, regPtr, rlArray.lowReg);
1466 }
1467
1468 /* null object? */
buzbee43a36422011-09-14 14:00:13 -07001469 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001470
buzbee43a36422011-09-14 14:00:13 -07001471 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee67bf8852011-08-17 17:51:35 -07001472 int regLen = oatAllocTemp(cUnit);
1473 //NOTE: max live temps(4) here.
1474 /* Get len */
1475 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1476 /* regPtr -> array data */
1477 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
buzbeeec5adf32011-09-11 15:25:43 -07001478 genRegRegCheck(cUnit, kArmCondCs, rlIndex.lowReg, regLen, mir,
buzbee5ade1d22011-09-09 14:44:52 -07001479 kArmThrowArrayBounds);
buzbee67bf8852011-08-17 17:51:35 -07001480 oatFreeTemp(cUnit, regLen);
1481 } else {
1482 /* regPtr -> array data */
1483 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1484 }
1485 /* at this point, regPtr points to array, 2 live temps */
1486 if ((size == kLong) || (size == kDouble)) {
buzbee5ade1d22011-09-09 14:44:52 -07001487 //TUNING: specific wide routine that can handle fp regs
buzbee67bf8852011-08-17 17:51:35 -07001488 if (scale) {
1489 int rNewIndex = oatAllocTemp(cUnit);
1490 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1491 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1492 oatFreeTemp(cUnit, rNewIndex);
1493 } else {
1494 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1495 }
1496 rlSrc = loadValueWide(cUnit, rlSrc, regClass);
1497
1498 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
1499
1500 oatFreeTemp(cUnit, regPtr);
1501 } else {
1502 rlSrc = loadValue(cUnit, rlSrc, regClass);
1503
1504 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1505 scale, size);
1506 }
1507}
1508
buzbeeed3e9302011-09-23 17:34:19 -07001509STATIC bool genShiftOpLong(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001510 RegLocation rlDest, RegLocation rlSrc1,
1511 RegLocation rlShift)
1512{
buzbee54330722011-08-23 16:46:55 -07001513 int funcOffset;
buzbee67bf8852011-08-17 17:51:35 -07001514
buzbee67bf8852011-08-17 17:51:35 -07001515 switch( mir->dalvikInsn.opcode) {
1516 case OP_SHL_LONG:
1517 case OP_SHL_LONG_2ADDR:
buzbee54330722011-08-23 16:46:55 -07001518 funcOffset = OFFSETOF_MEMBER(Thread, pShlLong);
buzbee67bf8852011-08-17 17:51:35 -07001519 break;
1520 case OP_SHR_LONG:
1521 case OP_SHR_LONG_2ADDR:
buzbee54330722011-08-23 16:46:55 -07001522 funcOffset = OFFSETOF_MEMBER(Thread, pShrLong);
buzbee67bf8852011-08-17 17:51:35 -07001523 break;
1524 case OP_USHR_LONG:
1525 case OP_USHR_LONG_2ADDR:
buzbee54330722011-08-23 16:46:55 -07001526 funcOffset = OFFSETOF_MEMBER(Thread, pUshrLong);
buzbee67bf8852011-08-17 17:51:35 -07001527 break;
1528 default:
buzbee54330722011-08-23 16:46:55 -07001529 LOG(FATAL) << "Unexpected case";
buzbee67bf8852011-08-17 17:51:35 -07001530 return true;
1531 }
buzbee54330722011-08-23 16:46:55 -07001532 oatFlushAllRegs(cUnit); /* Send everything to home location */
1533 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1534 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1535 loadValueDirect(cUnit, rlShift, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -07001536 callRuntimeHelper(cUnit, rLR);
buzbee54330722011-08-23 16:46:55 -07001537 RegLocation rlResult = oatGetReturnWide(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001538 storeValueWide(cUnit, rlDest, rlResult);
1539 return false;
1540}
1541
buzbeeed3e9302011-09-23 17:34:19 -07001542STATIC bool genArithOpLong(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001543 RegLocation rlDest, RegLocation rlSrc1,
1544 RegLocation rlSrc2)
1545{
1546 RegLocation rlResult;
1547 OpKind firstOp = kOpBkpt;
1548 OpKind secondOp = kOpBkpt;
1549 bool callOut = false;
buzbee58f92742011-10-01 11:22:17 -07001550 bool checkZero = false;
buzbee67bf8852011-08-17 17:51:35 -07001551 int funcOffset;
1552 int retReg = r0;
1553
1554 switch (mir->dalvikInsn.opcode) {
1555 case OP_NOT_LONG:
1556 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1557 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbeeb29e4d12011-09-26 15:05:48 -07001558 // Check for destructive overlap
1559 if (rlResult.lowReg == rlSrc2.highReg) {
1560 int tReg = oatAllocTemp(cUnit);
1561 genRegCopy(cUnit, tReg, rlSrc2.highReg);
1562 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1563 opRegReg(cUnit, kOpMvn, rlResult.highReg, tReg);
1564 oatFreeTemp(cUnit, tReg);
1565 } else {
1566 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1567 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
1568 }
buzbee67bf8852011-08-17 17:51:35 -07001569 storeValueWide(cUnit, rlDest, rlResult);
1570 return false;
1571 break;
1572 case OP_ADD_LONG:
1573 case OP_ADD_LONG_2ADDR:
1574 firstOp = kOpAdd;
1575 secondOp = kOpAdc;
1576 break;
1577 case OP_SUB_LONG:
1578 case OP_SUB_LONG_2ADDR:
1579 firstOp = kOpSub;
1580 secondOp = kOpSbc;
1581 break;
1582 case OP_MUL_LONG:
1583 case OP_MUL_LONG_2ADDR:
buzbee439c4fa2011-08-27 15:59:07 -07001584 callOut = true;
1585 retReg = r0;
1586 funcOffset = OFFSETOF_MEMBER(Thread, pLmul);
1587 break;
buzbee67bf8852011-08-17 17:51:35 -07001588 case OP_DIV_LONG:
1589 case OP_DIV_LONG_2ADDR:
1590 callOut = true;
buzbee58f92742011-10-01 11:22:17 -07001591 checkZero = true;
buzbee67bf8852011-08-17 17:51:35 -07001592 retReg = r0;
1593 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
1594 break;
1595 /* NOTE - result is in r2/r3 instead of r0/r1 */
1596 case OP_REM_LONG:
1597 case OP_REM_LONG_2ADDR:
1598 callOut = true;
buzbee58f92742011-10-01 11:22:17 -07001599 checkZero = true;
buzbee67bf8852011-08-17 17:51:35 -07001600 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
1601 retReg = r2;
1602 break;
1603 case OP_AND_LONG_2ADDR:
1604 case OP_AND_LONG:
1605 firstOp = kOpAnd;
1606 secondOp = kOpAnd;
1607 break;
1608 case OP_OR_LONG:
1609 case OP_OR_LONG_2ADDR:
1610 firstOp = kOpOr;
1611 secondOp = kOpOr;
1612 break;
1613 case OP_XOR_LONG:
1614 case OP_XOR_LONG_2ADDR:
1615 firstOp = kOpXor;
1616 secondOp = kOpXor;
1617 break;
1618 case OP_NEG_LONG: {
buzbee67bf8852011-08-17 17:51:35 -07001619 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1620 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbeeb29e4d12011-09-26 15:05:48 -07001621 int zReg = oatAllocTemp(cUnit);
1622 loadConstantNoClobber(cUnit, zReg, 0);
1623 // Check for destructive overlap
1624 if (rlResult.lowReg == rlSrc2.highReg) {
1625 int tReg = oatAllocTemp(cUnit);
1626 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1627 zReg, rlSrc2.lowReg);
1628 opRegRegReg(cUnit, kOpSbc, rlResult.highReg,
1629 zReg, tReg);
1630 oatFreeTemp(cUnit, tReg);
1631 } else {
1632 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1633 zReg, rlSrc2.lowReg);
1634 opRegRegReg(cUnit, kOpSbc, rlResult.highReg,
1635 zReg, rlSrc2.highReg);
1636 }
1637 oatFreeTemp(cUnit, zReg);
buzbee67bf8852011-08-17 17:51:35 -07001638 storeValueWide(cUnit, rlDest, rlResult);
1639 return false;
1640 }
1641 default:
1642 LOG(FATAL) << "Invalid long arith op";
1643 }
1644 if (!callOut) {
1645 genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
1646 } else {
buzbee67bf8852011-08-17 17:51:35 -07001647 oatFlushAllRegs(cUnit); /* Send everything to home location */
buzbee58f92742011-10-01 11:22:17 -07001648 if (checkZero) {
1649 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
1650 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1651 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1652 int tReg = oatAllocTemp(cUnit);
1653 newLIR4(cUnit, kThumb2OrrRRRs, tReg, r2, r3, 0);
1654 oatFreeTemp(cUnit, tReg);
1655 genCheck(cUnit, kArmCondEq, mir, kArmThrowDivZero);
1656 } else {
1657 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1658 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1659 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
1660 }
Ian Rogersff1ed472011-09-20 13:46:24 -07001661 callRuntimeHelper(cUnit, rLR);
buzbee58f92742011-10-01 11:22:17 -07001662 // Adjust return regs in to handle case of rem returning r2/r3
buzbee67bf8852011-08-17 17:51:35 -07001663 if (retReg == r0)
1664 rlResult = oatGetReturnWide(cUnit);
1665 else
1666 rlResult = oatGetReturnWideAlt(cUnit);
1667 storeValueWide(cUnit, rlDest, rlResult);
1668 }
1669 return false;
1670}
1671
buzbeeed3e9302011-09-23 17:34:19 -07001672STATIC bool genArithOpInt(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001673 RegLocation rlDest, RegLocation rlSrc1,
1674 RegLocation rlSrc2)
1675{
1676 OpKind op = kOpBkpt;
1677 bool callOut = false;
1678 bool checkZero = false;
1679 bool unary = false;
1680 int retReg = r0;
1681 int funcOffset;
1682 RegLocation rlResult;
1683 bool shiftOp = false;
1684
1685 switch (mir->dalvikInsn.opcode) {
1686 case OP_NEG_INT:
1687 op = kOpNeg;
1688 unary = true;
1689 break;
1690 case OP_NOT_INT:
1691 op = kOpMvn;
1692 unary = true;
1693 break;
1694 case OP_ADD_INT:
1695 case OP_ADD_INT_2ADDR:
1696 op = kOpAdd;
1697 break;
1698 case OP_SUB_INT:
1699 case OP_SUB_INT_2ADDR:
1700 op = kOpSub;
1701 break;
1702 case OP_MUL_INT:
1703 case OP_MUL_INT_2ADDR:
1704 op = kOpMul;
1705 break;
1706 case OP_DIV_INT:
1707 case OP_DIV_INT_2ADDR:
1708 callOut = true;
1709 checkZero = true;
1710 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
1711 retReg = r0;
1712 break;
1713 /* NOTE: returns in r1 */
1714 case OP_REM_INT:
1715 case OP_REM_INT_2ADDR:
1716 callOut = true;
1717 checkZero = true;
1718 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
1719 retReg = r1;
1720 break;
1721 case OP_AND_INT:
1722 case OP_AND_INT_2ADDR:
1723 op = kOpAnd;
1724 break;
1725 case OP_OR_INT:
1726 case OP_OR_INT_2ADDR:
1727 op = kOpOr;
1728 break;
1729 case OP_XOR_INT:
1730 case OP_XOR_INT_2ADDR:
1731 op = kOpXor;
1732 break;
1733 case OP_SHL_INT:
1734 case OP_SHL_INT_2ADDR:
1735 shiftOp = true;
1736 op = kOpLsl;
1737 break;
1738 case OP_SHR_INT:
1739 case OP_SHR_INT_2ADDR:
1740 shiftOp = true;
1741 op = kOpAsr;
1742 break;
1743 case OP_USHR_INT:
1744 case OP_USHR_INT_2ADDR:
1745 shiftOp = true;
1746 op = kOpLsr;
1747 break;
1748 default:
1749 LOG(FATAL) << "Invalid word arith op: " <<
1750 (int)mir->dalvikInsn.opcode;
1751 }
1752 if (!callOut) {
1753 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1754 if (unary) {
1755 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1756 opRegReg(cUnit, op, rlResult.lowReg,
1757 rlSrc1.lowReg);
1758 } else {
1759 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1760 if (shiftOp) {
1761 int tReg = oatAllocTemp(cUnit);
1762 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
1763 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1764 opRegRegReg(cUnit, op, rlResult.lowReg,
1765 rlSrc1.lowReg, tReg);
1766 oatFreeTemp(cUnit, tReg);
1767 } else {
1768 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1769 opRegRegReg(cUnit, op, rlResult.lowReg,
1770 rlSrc1.lowReg, rlSrc2.lowReg);
1771 }
1772 }
1773 storeValue(cUnit, rlDest, rlResult);
1774 } else {
1775 RegLocation rlResult;
1776 oatFlushAllRegs(cUnit); /* Send everything to home location */
1777 loadValueDirectFixed(cUnit, rlSrc2, r1);
1778 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1779 loadValueDirectFixed(cUnit, rlSrc1, r0);
1780 if (checkZero) {
buzbee5ade1d22011-09-09 14:44:52 -07001781 genImmedCheck(cUnit, kArmCondEq, r1, 0, mir, kArmThrowDivZero);
buzbee67bf8852011-08-17 17:51:35 -07001782 }
Ian Rogersff1ed472011-09-20 13:46:24 -07001783 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001784 if (retReg == r0)
1785 rlResult = oatGetReturn(cUnit);
1786 else
1787 rlResult = oatGetReturnAlt(cUnit);
1788 storeValue(cUnit, rlDest, rlResult);
1789 }
1790 return false;
1791}
1792
buzbeec1f45042011-09-21 16:03:19 -07001793/* Check if we need to check for pending suspend request */
buzbeeed3e9302011-09-23 17:34:19 -07001794STATIC void genSuspendTest(CompilationUnit* cUnit, MIR* mir)
buzbeec1f45042011-09-21 16:03:19 -07001795{
buzbeec0ecd652011-09-25 18:11:54 -07001796 if (NO_SUSPEND || mir->optimizationFlags & MIR_IGNORE_SUSPEND_CHECK) {
buzbeec1f45042011-09-21 16:03:19 -07001797 return;
1798 }
buzbee6181f792011-09-29 11:14:04 -07001799 oatFlushAllRegs(cUnit);
buzbeec1f45042011-09-21 16:03:19 -07001800 newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
1801 ArmLIR* branch = opCondBranch(cUnit, kArmCondEq);
1802 ArmLIR* retLab = newLIR0(cUnit, kArmPseudoTargetLabel);
1803 retLab->defMask = ENCODE_ALL;
1804 ArmLIR* target = (ArmLIR*)oatNew(sizeof(ArmLIR), true);
1805 target->generic.dalvikOffset = cUnit->currentDalvikOffset;
1806 target->opcode = kArmPseudoSuspendTarget;
1807 target->operands[0] = (intptr_t)retLab;
1808 target->operands[1] = mir->offset;
1809 branch->generic.target = (LIR*)target;
1810 oatInsertGrowableList(&cUnit->suspendLaunchpads, (intptr_t)target);
1811}
1812
buzbee67bf8852011-08-17 17:51:35 -07001813/*
1814 * The following are the first-level codegen routines that analyze the format
1815 * of each bytecode then either dispatch special purpose codegen routines
1816 * or produce corresponding Thumb instructions directly.
1817 */
1818
buzbeeed3e9302011-09-23 17:34:19 -07001819STATIC bool isPowerOfTwo(int x)
buzbee67bf8852011-08-17 17:51:35 -07001820{
1821 return (x & (x - 1)) == 0;
1822}
1823
1824// Returns true if no more than two bits are set in 'x'.
buzbeeed3e9302011-09-23 17:34:19 -07001825STATIC bool isPopCountLE2(unsigned int x)
buzbee67bf8852011-08-17 17:51:35 -07001826{
1827 x &= x - 1;
1828 return (x & (x - 1)) == 0;
1829}
1830
1831// Returns the index of the lowest set bit in 'x'.
buzbeeed3e9302011-09-23 17:34:19 -07001832STATIC int lowestSetBit(unsigned int x) {
buzbee67bf8852011-08-17 17:51:35 -07001833 int bit_posn = 0;
1834 while ((x & 0xf) == 0) {
1835 bit_posn += 4;
1836 x >>= 4;
1837 }
1838 while ((x & 1) == 0) {
1839 bit_posn++;
1840 x >>= 1;
1841 }
1842 return bit_posn;
1843}
1844
1845// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
1846// and store the result in 'rlDest'.
buzbeeed3e9302011-09-23 17:34:19 -07001847STATIC bool handleEasyDivide(CompilationUnit* cUnit, Opcode dalvikOpcode,
buzbee67bf8852011-08-17 17:51:35 -07001848 RegLocation rlSrc, RegLocation rlDest, int lit)
1849{
1850 if (lit < 2 || !isPowerOfTwo(lit)) {
1851 return false;
1852 }
1853 int k = lowestSetBit(lit);
1854 if (k >= 30) {
1855 // Avoid special cases.
1856 return false;
1857 }
1858 bool div = (dalvikOpcode == OP_DIV_INT_LIT8 ||
1859 dalvikOpcode == OP_DIV_INT_LIT16);
1860 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1861 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1862 if (div) {
1863 int tReg = oatAllocTemp(cUnit);
1864 if (lit == 2) {
1865 // Division by 2 is by far the most common division by constant.
1866 opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
1867 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1868 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1869 } else {
1870 opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
1871 opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
1872 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1873 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1874 }
1875 } else {
1876 int cReg = oatAllocTemp(cUnit);
1877 loadConstant(cUnit, cReg, lit - 1);
1878 int tReg1 = oatAllocTemp(cUnit);
1879 int tReg2 = oatAllocTemp(cUnit);
1880 if (lit == 2) {
1881 opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
1882 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1883 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1884 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1885 } else {
1886 opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
1887 opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
1888 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1889 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1890 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1891 }
1892 }
1893 storeValue(cUnit, rlDest, rlResult);
1894 return true;
1895}
1896
1897// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
1898// and store the result in 'rlDest'.
buzbeeed3e9302011-09-23 17:34:19 -07001899STATIC bool handleEasyMultiply(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -07001900 RegLocation rlSrc, RegLocation rlDest, int lit)
1901{
1902 // Can we simplify this multiplication?
1903 bool powerOfTwo = false;
1904 bool popCountLE2 = false;
1905 bool powerOfTwoMinusOne = false;
1906 if (lit < 2) {
1907 // Avoid special cases.
1908 return false;
1909 } else if (isPowerOfTwo(lit)) {
1910 powerOfTwo = true;
1911 } else if (isPopCountLE2(lit)) {
1912 popCountLE2 = true;
1913 } else if (isPowerOfTwo(lit + 1)) {
1914 powerOfTwoMinusOne = true;
1915 } else {
1916 return false;
1917 }
1918 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1919 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1920 if (powerOfTwo) {
1921 // Shift.
1922 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
1923 lowestSetBit(lit));
1924 } else if (popCountLE2) {
1925 // Shift and add and shift.
1926 int firstBit = lowestSetBit(lit);
1927 int secondBit = lowestSetBit(lit ^ (1 << firstBit));
1928 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
1929 firstBit, secondBit);
1930 } else {
1931 // Reverse subtract: (src << (shift + 1)) - src.
buzbeeed3e9302011-09-23 17:34:19 -07001932 DCHECK(powerOfTwoMinusOne);
buzbee5ade1d22011-09-09 14:44:52 -07001933 // TUNING: rsb dst, src, src lsl#lowestSetBit(lit + 1)
buzbee67bf8852011-08-17 17:51:35 -07001934 int tReg = oatAllocTemp(cUnit);
1935 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
1936 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
1937 }
1938 storeValue(cUnit, rlDest, rlResult);
1939 return true;
1940}
1941
buzbeeed3e9302011-09-23 17:34:19 -07001942STATIC bool genArithOpIntLit(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001943 RegLocation rlDest, RegLocation rlSrc,
1944 int lit)
1945{
1946 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1947 RegLocation rlResult;
1948 OpKind op = (OpKind)0; /* Make gcc happy */
1949 int shiftOp = false;
1950 bool isDiv = false;
1951 int funcOffset;
1952
1953 switch (dalvikOpcode) {
1954 case OP_RSUB_INT_LIT8:
1955 case OP_RSUB_INT: {
1956 int tReg;
1957 //TUNING: add support for use of Arm rsub op
1958 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1959 tReg = oatAllocTemp(cUnit);
1960 loadConstant(cUnit, tReg, lit);
1961 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1962 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1963 tReg, rlSrc.lowReg);
1964 storeValue(cUnit, rlDest, rlResult);
1965 return false;
1966 break;
1967 }
1968
1969 case OP_ADD_INT_LIT8:
1970 case OP_ADD_INT_LIT16:
1971 op = kOpAdd;
1972 break;
1973 case OP_MUL_INT_LIT8:
1974 case OP_MUL_INT_LIT16: {
1975 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
1976 return false;
1977 }
1978 op = kOpMul;
1979 break;
1980 }
1981 case OP_AND_INT_LIT8:
1982 case OP_AND_INT_LIT16:
1983 op = kOpAnd;
1984 break;
1985 case OP_OR_INT_LIT8:
1986 case OP_OR_INT_LIT16:
1987 op = kOpOr;
1988 break;
1989 case OP_XOR_INT_LIT8:
1990 case OP_XOR_INT_LIT16:
1991 op = kOpXor;
1992 break;
1993 case OP_SHL_INT_LIT8:
1994 lit &= 31;
1995 shiftOp = true;
1996 op = kOpLsl;
1997 break;
1998 case OP_SHR_INT_LIT8:
1999 lit &= 31;
2000 shiftOp = true;
2001 op = kOpAsr;
2002 break;
2003 case OP_USHR_INT_LIT8:
2004 lit &= 31;
2005 shiftOp = true;
2006 op = kOpLsr;
2007 break;
2008
2009 case OP_DIV_INT_LIT8:
2010 case OP_DIV_INT_LIT16:
2011 case OP_REM_INT_LIT8:
2012 case OP_REM_INT_LIT16:
2013 if (lit == 0) {
buzbee5ade1d22011-09-09 14:44:52 -07002014 genImmedCheck(cUnit, kArmCondAl, 0, 0, mir, kArmThrowDivZero);
buzbee67bf8852011-08-17 17:51:35 -07002015 return false;
2016 }
2017 if (handleEasyDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit)) {
2018 return false;
2019 }
2020 oatFlushAllRegs(cUnit); /* Everything to home location */
2021 loadValueDirectFixed(cUnit, rlSrc, r0);
2022 oatClobber(cUnit, r0);
2023 if ((dalvikOpcode == OP_DIV_INT_LIT8) ||
2024 (dalvikOpcode == OP_DIV_INT_LIT16)) {
2025 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
2026 isDiv = true;
2027 } else {
2028 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
2029 isDiv = false;
2030 }
2031 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
2032 loadConstant(cUnit, r1, lit);
Ian Rogersff1ed472011-09-20 13:46:24 -07002033 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07002034 if (isDiv)
2035 rlResult = oatGetReturn(cUnit);
2036 else
2037 rlResult = oatGetReturnAlt(cUnit);
2038 storeValue(cUnit, rlDest, rlResult);
2039 return false;
2040 break;
2041 default:
2042 return true;
2043 }
2044 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2045 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2046 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
2047 if (shiftOp && (lit == 0)) {
2048 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2049 } else {
2050 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2051 }
2052 storeValue(cUnit, rlDest, rlResult);
2053 return false;
2054}
2055
2056/* Architectural-specific debugging helpers go here */
2057void oatArchDump(void)
2058{
2059 /* Print compiled opcode in this VM instance */
2060 int i, start, streak;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002061 std::string buf;
buzbee67bf8852011-08-17 17:51:35 -07002062
2063 streak = i = 0;
buzbee67bf8852011-08-17 17:51:35 -07002064 while (opcodeCoverage[i] == 0 && i < kNumPackedOpcodes) {
2065 i++;
2066 }
2067 if (i == kNumPackedOpcodes) {
2068 return;
2069 }
2070 for (start = i++, streak = 1; i < kNumPackedOpcodes; i++) {
2071 if (opcodeCoverage[i]) {
2072 streak++;
2073 } else {
2074 if (streak == 1) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002075 StringAppendF(&buf, "%x,", start);
buzbee67bf8852011-08-17 17:51:35 -07002076 } else {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002077 StringAppendF(&buf, "%x-%x,", start, start + streak - 1);
buzbee67bf8852011-08-17 17:51:35 -07002078 }
2079 streak = 0;
2080 while (opcodeCoverage[i] == 0 && i < kNumPackedOpcodes) {
2081 i++;
2082 }
2083 if (i < kNumPackedOpcodes) {
2084 streak = 1;
2085 start = i;
2086 }
2087 }
2088 }
2089 if (streak) {
2090 if (streak == 1) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002091 StringAppendF(&buf, "%x", start);
buzbee67bf8852011-08-17 17:51:35 -07002092 } else {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002093 StringAppendF(&buf, "%x-%x", start, start + streak - 1);
buzbee67bf8852011-08-17 17:51:35 -07002094 }
2095 }
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002096 if (!buf.empty()) {
buzbee67bf8852011-08-17 17:51:35 -07002097 LOG(INFO) << "dalvik.vm.oat.op = " << buf;
2098 }
2099}