blob: e58a9827e364721828d53ee035f515a55a82cb15 [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{
Elliott Hughes5ee7a8b2011-09-13 16:40:07 -0700400#ifdef CONCURRENT_GARBAGE_COLLECTOR
buzbee0d966cf2011-09-08 17:34:58 -0700401 // TODO: re-enable when concurrent collector is active
buzbee67bf8852011-08-17 17:51:35 -0700402 int regCardBase = oatAllocTemp(cUnit);
403 int regCardNo = oatAllocTemp(cUnit);
404 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondEq, valReg, 0);
buzbeec143c552011-08-20 17:38:58 -0700405 loadWordDisp(cUnit, rSELF, Thread::CardTableOffset().Int32Value(),
buzbee67bf8852011-08-17 17:51:35 -0700406 regCardBase);
407 opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT);
408 storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
409 kUnsignedByte);
410 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
411 target->defMask = ENCODE_ALL;
412 branchOver->generic.target = (LIR*)target;
413 oatFreeTemp(cUnit, regCardBase);
414 oatFreeTemp(cUnit, regCardNo);
Elliott Hughes0f4c41d2011-09-04 14:58:03 -0700415#endif
buzbee67bf8852011-08-17 17:51:35 -0700416}
417
buzbee34cd9e52011-09-08 14:31:52 -0700418/*
419 * Helper function for Iget/put when field not resolved at compile time.
420 * Will trash call temps and return with the field offset in r0.
421 */
Elliott Hughes81bc5092011-09-30 17:25:59 -0700422STATIC void getFieldOffset(CompilationUnit* cUnit, MIR* mir, Field* fieldPtr)
buzbee34cd9e52011-09-08 14:31:52 -0700423{
424 int fieldIdx = mir->dalvikInsn.vC;
buzbee6181f792011-09-29 11:14:04 -0700425 oatFlushAllRegs(cUnit);
Elliott Hughes81bc5092011-09-30 17:25:59 -0700426 warnIfUnresolved(cUnit, fieldIdx, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700427 oatLockCallTemps(cUnit); // Explicit register usage
428 loadCurrMethodDirect(cUnit, r1); // arg1 <= Method*
429 loadWordDisp(cUnit, r1,
430 Method::DexCacheResolvedFieldsOffset().Int32Value(), r0);
431 loadWordDisp(cUnit, r0, art::Array::DataOffset().Int32Value() +
432 sizeof(int32_t*)* fieldIdx, r0);
433 /*
434 * For testing, omit the test for run-time resolution. This will
435 * force all accesses to go through the runtime resolution path.
436 */
buzbeece302932011-10-04 14:32:18 -0700437 ArmLIR* branchOver = NULL;
438 if (!EXERCISE_SLOWEST_FIELD_PATH) {
439 branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0);
440 }
buzbee34cd9e52011-09-08 14:31:52 -0700441 // Resolve
442 loadWordDisp(cUnit, rSELF,
Brian Carlstrom845490b2011-09-19 15:56:53 -0700443 OFFSETOF_MEMBER(Thread, pFindInstanceFieldFromCode), rLR);
buzbee34cd9e52011-09-08 14:31:52 -0700444 loadConstant(cUnit, r0, fieldIdx);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700445 callRuntimeHelper(cUnit, rLR); // FindInstanceFieldFromCoderesolveTypeFromCode(idx, method)
buzbee34cd9e52011-09-08 14:31:52 -0700446 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
447 target->defMask = ENCODE_ALL;
buzbeece302932011-10-04 14:32:18 -0700448 if (!EXERCISE_SLOWEST_FIELD_PATH) {
449 branchOver->generic.target = (LIR*)target;
450 }
buzbee34cd9e52011-09-08 14:31:52 -0700451 // Free temps (except for r0)
452 oatFreeTemp(cUnit, r1);
453 oatFreeTemp(cUnit, r2);
454 oatFreeTemp(cUnit, r3);
455 loadWordDisp(cUnit, r0, art::Field::OffsetOffset().Int32Value(), r0);
456}
457
buzbeeed3e9302011-09-23 17:34:19 -0700458STATIC void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -0700459 RegLocation rlDest, RegLocation rlObj)
460{
buzbeec143c552011-08-20 17:38:58 -0700461 Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
462 GetResolvedField(mir->dalvikInsn.vC);
buzbee67bf8852011-08-17 17:51:35 -0700463 RegLocation rlResult;
464 RegisterClass regClass = oatRegClassBySize(size);
buzbee34cd9e52011-09-08 14:31:52 -0700465 if (SLOW_FIELD_PATH || fieldPtr == NULL) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700466 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700467 // Field offset in r0
468 rlObj = loadValue(cUnit, rlObj, kCoreReg);
469 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
buzbee5ade1d22011-09-09 14:44:52 -0700470 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
buzbee58f92742011-10-01 11:22:17 -0700471 loadBaseIndexed(cUnit, rlObj.lowReg, r0, rlResult.lowReg, 0, kWord);
buzbee67bf8852011-08-17 17:51:35 -0700472 oatGenMemBarrier(cUnit, kSY);
buzbee34cd9e52011-09-08 14:31:52 -0700473 storeValue(cUnit, rlDest, rlResult);
474 } else {
475#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700476 bool isVolatile = fieldPtr->IsVolatile();
buzbee34cd9e52011-09-08 14:31:52 -0700477#else
478 bool isVolatile = false;
479#endif
480 int fieldOffset = fieldPtr->GetOffset().Int32Value();
481 rlObj = loadValue(cUnit, rlObj, kCoreReg);
482 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
buzbee5ade1d22011-09-09 14:44:52 -0700483 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
buzbee34cd9e52011-09-08 14:31:52 -0700484 loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
buzbee58f92742011-10-01 11:22:17 -0700485 kWord, rlObj.sRegLow);
buzbee34cd9e52011-09-08 14:31:52 -0700486 if (isVolatile) {
487 oatGenMemBarrier(cUnit, kSY);
488 }
489 storeValue(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -0700490 }
buzbee67bf8852011-08-17 17:51:35 -0700491}
492
buzbeeed3e9302011-09-23 17:34:19 -0700493STATIC void genIPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -0700494 RegLocation rlSrc, RegLocation rlObj, bool isObject)
495{
buzbeec143c552011-08-20 17:38:58 -0700496 Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
497 GetResolvedField(mir->dalvikInsn.vC);
buzbee67bf8852011-08-17 17:51:35 -0700498 RegisterClass regClass = oatRegClassBySize(size);
buzbee34cd9e52011-09-08 14:31:52 -0700499 if (SLOW_FIELD_PATH || fieldPtr == NULL) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700500 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700501 // Field offset in r0
502 rlObj = loadValue(cUnit, rlObj, kCoreReg);
503 rlSrc = loadValue(cUnit, rlSrc, regClass);
buzbee5ade1d22011-09-09 14:44:52 -0700504 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
buzbee67bf8852011-08-17 17:51:35 -0700505 oatGenMemBarrier(cUnit, kSY);
buzbee58f92742011-10-01 11:22:17 -0700506 storeBaseIndexed(cUnit, rlObj.lowReg, r0, rlSrc.lowReg, 0, kWord);
buzbee34cd9e52011-09-08 14:31:52 -0700507 } else {
508#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700509 bool isVolatile = fieldPtr->IsVolatile();
buzbee34cd9e52011-09-08 14:31:52 -0700510#else
511 bool isVolatile = false;
512#endif
513 int fieldOffset = fieldPtr->GetOffset().Int32Value();
514 rlObj = loadValue(cUnit, rlObj, kCoreReg);
515 rlSrc = loadValue(cUnit, rlSrc, regClass);
buzbee5ade1d22011-09-09 14:44:52 -0700516 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700517
518 if (isVolatile) {
buzbee12246b82011-09-29 14:15:05 -0700519 oatGenMemBarrier(cUnit, kST);
buzbee34cd9e52011-09-08 14:31:52 -0700520 }
buzbee58f92742011-10-01 11:22:17 -0700521 storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, kWord);
buzbee12246b82011-09-29 14:15:05 -0700522 if (isVolatile) {
523 oatGenMemBarrier(cUnit, kSY);
524 }
buzbee67bf8852011-08-17 17:51:35 -0700525 }
buzbee67bf8852011-08-17 17:51:35 -0700526 if (isObject) {
527 /* NOTE: marking card based on object head */
528 markGCCard(cUnit, rlSrc.lowReg, rlObj.lowReg);
529 }
530}
531
buzbeeed3e9302011-09-23 17:34:19 -0700532STATIC void genIGetWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700533 RegLocation rlObj)
534{
buzbee12246b82011-09-29 14:15:05 -0700535 RegLocation rlResult;
buzbeec143c552011-08-20 17:38:58 -0700536 Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
537 GetResolvedField(mir->dalvikInsn.vC);
buzbee12246b82011-09-29 14:15:05 -0700538#if ANDROID_SMP != 0
539 bool isVolatile = (fieldPtr == NULL) || fieldPtr->IsVolatile();
540#else
541 bool isVolatile = false;
542#endif
buzbeece302932011-10-04 14:32:18 -0700543 if (SLOW_FIELD_PATH || (fieldPtr == NULL) || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700544 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700545 // Field offset in r0
546 rlObj = loadValue(cUnit, rlObj, kCoreReg);
547 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee5ade1d22011-09-09 14:44:52 -0700548 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700549 opRegReg(cUnit, kOpAdd, r0, rlObj.lowReg);
550 loadPair(cUnit, r0, rlResult.lowReg, rlResult.highReg);
buzbee67bf8852011-08-17 17:51:35 -0700551 oatGenMemBarrier(cUnit, kSY);
buzbee12246b82011-09-29 14:15:05 -0700552 storeValueWide(cUnit, rlDest, rlResult);
buzbee34cd9e52011-09-08 14:31:52 -0700553 } else {
buzbee34cd9e52011-09-08 14:31:52 -0700554 int fieldOffset = fieldPtr->GetOffset().Int32Value();
555 rlObj = loadValue(cUnit, rlObj, kCoreReg);
556 int regPtr = oatAllocTemp(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700557
buzbeeed3e9302011-09-23 17:34:19 -0700558 DCHECK(rlDest.wide);
buzbee34cd9e52011-09-08 14:31:52 -0700559
buzbee5ade1d22011-09-09 14:44:52 -0700560 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700561 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
562 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
563
564 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
565
buzbee34cd9e52011-09-08 14:31:52 -0700566 oatFreeTemp(cUnit, regPtr);
567 storeValueWide(cUnit, rlDest, rlResult);
568 }
buzbee67bf8852011-08-17 17:51:35 -0700569}
570
buzbeeed3e9302011-09-23 17:34:19 -0700571STATIC void genIPutWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
buzbee67bf8852011-08-17 17:51:35 -0700572 RegLocation rlObj)
573{
buzbeec143c552011-08-20 17:38:58 -0700574 Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
575 GetResolvedField(mir->dalvikInsn.vC);
buzbee12246b82011-09-29 14:15:05 -0700576#if ANDROID_SMP != 0
577 bool isVolatile = (fieldPtr == NULL) || fieldPtr->IsVolatile();
578#else
579 bool isVolatile = false;
580#endif
buzbeece302932011-10-04 14:32:18 -0700581 if (SLOW_FIELD_PATH || (fieldPtr == NULL) || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700582 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700583 // Field offset in r0
584 rlObj = loadValue(cUnit, rlObj, kCoreReg);
585 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
buzbee5ade1d22011-09-09 14:44:52 -0700586 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700587 opRegReg(cUnit, kOpAdd, r0, rlObj.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700588 oatGenMemBarrier(cUnit, kSY);
buzbee34cd9e52011-09-08 14:31:52 -0700589 storePair(cUnit, r0, rlSrc.lowReg, rlSrc.highReg);
590 } else {
buzbee34cd9e52011-09-08 14:31:52 -0700591 int fieldOffset = fieldPtr->GetOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -0700592
buzbee34cd9e52011-09-08 14:31:52 -0700593 rlObj = loadValue(cUnit, rlObj, kCoreReg);
594 int regPtr;
595 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
buzbee5ade1d22011-09-09 14:44:52 -0700596 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700597 regPtr = oatAllocTemp(cUnit);
598 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
599
buzbee34cd9e52011-09-08 14:31:52 -0700600 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
601
602 oatFreeTemp(cUnit, regPtr);
603 }
buzbee67bf8852011-08-17 17:51:35 -0700604}
605
buzbeeed3e9302011-09-23 17:34:19 -0700606STATIC void genConstClass(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700607 RegLocation rlDest, RegLocation rlSrc)
608{
Ian Rogers28ad40d2011-10-27 15:19:26 -0700609 uint32_t type_idx = mir->dalvikInsn.vB;
buzbee1b4c8592011-08-31 10:43:51 -0700610 int mReg = loadCurrMethod(cUnit);
611 int resReg = oatAllocTemp(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700612 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700613 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method, type_idx)) {
614 // Check we have access to type_idx and if not throw IllegalAccessError
615 UNIMPLEMENTED(FATAL);
buzbee1b4c8592011-08-31 10:43:51 -0700616 } else {
Ian Rogers28ad40d2011-10-27 15:19:26 -0700617 // We're don't need access checks, load type from dex cache
618 int32_t dex_cache_offset = Method::DexCacheResolvedTypesOffset().Int32Value();
619 loadWordDisp(cUnit, mReg, dex_cache_offset, resReg);
620 int32_t offset_of_type = Array::DataOffset().Int32Value() + (sizeof(Class*) * type_idx);
621 loadWordDisp(cUnit, resReg, offset_of_type, rlResult.lowReg);
622 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->method, type_idx) ||
623 SLOW_TYPE_PATH) {
624 // Slow path, at runtime test if the type is null and if so initialize
625 oatFlushAllRegs(cUnit);
626 ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, rlResult.lowReg, 0);
627 // Resolved, store and hop over following code
628 storeValue(cUnit, rlDest, rlResult);
629 ArmLIR* branch2 = genUnconditionalBranch(cUnit,0);
630 // TUNING: move slow path to end & remove unconditional branch
631 ArmLIR* target1 = newLIR0(cUnit, kArmPseudoTargetLabel);
632 target1->defMask = ENCODE_ALL;
633 // Call out to helper, which will return resolved type in r0
634 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
635 genRegCopy(cUnit, r1, mReg);
636 loadConstant(cUnit, r0, type_idx);
637 callRuntimeHelper(cUnit, rLR);
638 RegLocation rlResult = oatGetReturn(cUnit);
639 storeValue(cUnit, rlDest, rlResult);
640 // Rejoin code paths
641 ArmLIR* target2 = newLIR0(cUnit, kArmPseudoTargetLabel);
642 target2->defMask = ENCODE_ALL;
643 branch1->generic.target = (LIR*)target1;
644 branch2->generic.target = (LIR*)target2;
645 } else {
646 // Fast path, we're done - just store result
647 storeValue(cUnit, rlDest, rlResult);
648 }
buzbee1b4c8592011-08-31 10:43:51 -0700649 }
buzbee67bf8852011-08-17 17:51:35 -0700650}
651
buzbeeed3e9302011-09-23 17:34:19 -0700652STATIC void genConstString(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700653 RegLocation rlDest, RegLocation rlSrc)
654{
buzbeece302932011-10-04 14:32:18 -0700655 /* NOTE: Most strings should be available at compile time */
Ian Rogers28ad40d2011-10-27 15:19:26 -0700656 uint32_t string_idx = mir->dalvikInsn.vB;
657 int32_t offset_of_string = Array::DataOffset().Int32Value() + (sizeof(String*) * string_idx);
658 if (!cUnit->compiler->CanAssumeStringIsPresentInDexCache(cUnit->method, string_idx) ||
659 SLOW_STRING_PATH) {
660 // slow path, resolve string if not in dex cache
buzbeece302932011-10-04 14:32:18 -0700661 oatFlushAllRegs(cUnit);
662 oatLockCallTemps(cUnit); // Using explicit registers
663 loadCurrMethodDirect(cUnit, r2);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700664 loadWordDisp(cUnit, r2, Method::DexCacheStringsOffset().Int32Value(), r0);
buzbeece302932011-10-04 14:32:18 -0700665 // Might call out to helper, which will return resolved string in r0
Ian Rogers28ad40d2011-10-27 15:19:26 -0700666 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pResolveStringFromCode), rLR);
667 loadWordDisp(cUnit, r0, offset_of_string, r0);
668 loadConstant(cUnit, r1, string_idx);
buzbeece302932011-10-04 14:32:18 -0700669 opRegImm(cUnit, kOpCmp, r0, 0); // Is resolved?
670 genBarrier(cUnit);
671 // For testing, always force through helper
672 if (!EXERCISE_SLOWEST_STRING_PATH) {
673 genIT(cUnit, kArmCondEq, "T");
674 }
675 genRegCopy(cUnit, r0, r2); // .eq
676 opReg(cUnit, kOpBlx, rLR); // .eq, helper(Method*, string_idx)
677 genBarrier(cUnit);
678 storeValue(cUnit, rlDest, getRetLoc(cUnit));
679 } else {
680 int mReg = loadCurrMethod(cUnit);
681 int resReg = oatAllocTemp(cUnit);
682 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700683 loadWordDisp(cUnit, mReg, Method::DexCacheStringsOffset().Int32Value(), resReg);
684 loadWordDisp(cUnit, resReg, offset_of_string, rlResult.lowReg);
buzbeece302932011-10-04 14:32:18 -0700685 storeValue(cUnit, rlDest, rlResult);
686 }
buzbee67bf8852011-08-17 17:51:35 -0700687}
688
buzbeedfd3d702011-08-28 12:56:51 -0700689/*
690 * Let helper function take care of everything. Will
691 * call Class::NewInstanceFromCode(type_idx, method);
692 */
buzbeeed3e9302011-09-23 17:34:19 -0700693STATIC void genNewInstance(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700694 RegLocation rlDest)
695{
buzbeedfd3d702011-08-28 12:56:51 -0700696 oatFlushAllRegs(cUnit); /* Everything to home location */
Ian Rogers28ad40d2011-10-27 15:19:26 -0700697 uint32_t type_idx = mir->dalvikInsn.vB;
698 // alloc will always check for resolution, do we also need to verify access because the
699 // verifier was unable to?
700 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method, type_idx)) {
701 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pAllocObjectFromCode), rLR);
702 } else {
703 loadWordDisp(cUnit, rSELF,
704 OFFSETOF_MEMBER(Thread, pAllocObjectFromCodeWithAccessCheck), rLR);
705 }
706 loadCurrMethodDirect(cUnit, r1); // arg1 <= Method*
707 loadConstant(cUnit, r0, type_idx); // arg0 <- type_idx
Ian Rogersff1ed472011-09-20 13:46:24 -0700708 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700709 RegLocation rlResult = oatGetReturn(cUnit);
710 storeValue(cUnit, rlDest, rlResult);
711}
712
713void genThrow(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
714{
buzbee6181f792011-09-29 11:14:04 -0700715 oatFlushAllRegs(cUnit);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700716 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pDeliverException), rLR);
Ian Rogersbdb03912011-09-14 00:55:44 -0700717 loadValueDirectFixed(cUnit, rlSrc, r0); // Get exception object
Ian Rogersff1ed472011-09-20 13:46:24 -0700718 callRuntimeHelper(cUnit, rLR); // art_deliver_exception(exception);
buzbee67bf8852011-08-17 17:51:35 -0700719}
720
buzbeeed3e9302011-09-23 17:34:19 -0700721STATIC void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700722 RegLocation rlSrc)
723{
buzbee6181f792011-09-29 11:14:04 -0700724 oatFlushAllRegs(cUnit);
buzbee2a475e72011-09-07 17:19:17 -0700725 // May generate a call - use explicit registers
726 oatLockCallTemps(cUnit);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700727 uint32_t type_idx = mir->dalvikInsn.vC;
buzbee2a475e72011-09-07 17:19:17 -0700728 loadCurrMethodDirect(cUnit, r1); // r1 <= current Method*
Ian Rogers28ad40d2011-10-27 15:19:26 -0700729 loadValueDirectFixed(cUnit, rlSrc, r0); // r0 <= ref
730 int classReg = r2; // r2 will hold the Class*
731 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method, type_idx)) {
Ian Rogersb093c6b2011-10-31 16:19:55 -0700732 // Check we have access to type_idx and if not throw IllegalAccessError,
733 // returns Class* in r0
734 loadWordDisp(cUnit, rSELF,
735 OFFSETOF_MEMBER(Thread, pInitializeTypeAndVerifyAccessFromCode),
736 rLR);
737 loadConstant(cUnit, r0, type_idx);
738 callRuntimeHelper(cUnit, rLR); // InitializeTypeAndVerifyAccess(idx, method)
739 genRegCopy(cUnit, classReg, r0); // Align usage with fast path
Ian Rogers28ad40d2011-10-27 15:19:26 -0700740 } else {
741 // Load dex cache entry into classReg (r2)
742 loadWordDisp(cUnit, r1, Method::DexCacheResolvedTypesOffset().Int32Value(), classReg);
743 int32_t offset_of_type = Array::DataOffset().Int32Value() + (sizeof(Class*) * type_idx);
744 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
745 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->method, type_idx)) {
746 // Need to test presence of type in dex cache at runtime
747 ArmLIR* hopBranch = genCmpImmBranch(cUnit, kArmCondNe, classReg, 0);
748 // Not resolved
749 // Call out to helper, which will return resolved type in r0
750 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
751 loadConstant(cUnit, r0, type_idx);
Ian Rogersb093c6b2011-10-31 16:19:55 -0700752 callRuntimeHelper(cUnit, rLR); // InitializeTypeFromCode(idx, method)
Ian Rogers28ad40d2011-10-27 15:19:26 -0700753 genRegCopy(cUnit, r2, r0); // Align usage with fast path
754 loadValueDirectFixed(cUnit, rlSrc, r0); /* reload Ref */
755 // Rejoin code paths
756 ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
757 hopTarget->defMask = ENCODE_ALL;
758 hopBranch->generic.target = (LIR*)hopTarget;
759 }
buzbee67bf8852011-08-17 17:51:35 -0700760 }
buzbee991e3ac2011-09-29 15:44:22 -0700761 /* r0 is ref, r2 is class. If ref==null, use directly as bool result */
762 ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, r0, 0);
buzbee2a475e72011-09-07 17:19:17 -0700763 /* load object->clazz */
buzbeeed3e9302011-09-23 17:34:19 -0700764 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
buzbee991e3ac2011-09-29 15:44:22 -0700765 loadWordDisp(cUnit, r0, Object::ClassOffset().Int32Value(), r1);
766 /* r0 is ref, r1 is ref->clazz, r2 is class */
Ian Rogers28ad40d2011-10-27 15:19:26 -0700767 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInstanceofNonTrivialFromCode), rLR);
buzbee991e3ac2011-09-29 15:44:22 -0700768 opRegReg(cUnit, kOpCmp, r1, r2); // Same?
769 genBarrier(cUnit);
770 genIT(cUnit, kArmCondEq, "EE"); // if-convert the test
771 loadConstant(cUnit, r0, 1); // .eq case - load true
772 genRegCopy(cUnit, r0, r2); // .ne case - arg0 <= class
773 opReg(cUnit, kOpBlx, rLR); // .ne case: helper(class, ref->class)
774 genBarrier(cUnit);
775 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700776 /* branch target here */
777 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
778 target->defMask = ENCODE_ALL;
buzbee2a475e72011-09-07 17:19:17 -0700779 RegLocation rlResult = oatGetReturn(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700780 storeValue(cUnit, rlDest, rlResult);
781 branch1->generic.target = (LIR*)target;
buzbee67bf8852011-08-17 17:51:35 -0700782}
783
buzbeeed3e9302011-09-23 17:34:19 -0700784STATIC void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700785{
buzbee6181f792011-09-29 11:14:04 -0700786 oatFlushAllRegs(cUnit);
buzbee2a475e72011-09-07 17:19:17 -0700787 // May generate a call - use explicit registers
788 oatLockCallTemps(cUnit);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700789 uint32_t type_idx = mir->dalvikInsn.vB;
buzbee2a475e72011-09-07 17:19:17 -0700790 loadCurrMethodDirect(cUnit, r1); // r1 <= current Method*
Ian Rogers28ad40d2011-10-27 15:19:26 -0700791 int classReg = r2; // r2 will hold the Class*
792 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method, type_idx)) {
Ian Rogersb093c6b2011-10-31 16:19:55 -0700793 // Check we have access to type_idx and if not throw IllegalAccessError,
794 // returns Class* in r0
795 loadWordDisp(cUnit, rSELF,
796 OFFSETOF_MEMBER(Thread, pInitializeTypeAndVerifyAccessFromCode),
797 rLR);
798 loadConstant(cUnit, r0, type_idx);
799 callRuntimeHelper(cUnit, rLR); // InitializeTypeAndVerifyAccess(idx, method)
800 genRegCopy(cUnit, classReg, r0); // Align usage with fast path
Ian Rogers28ad40d2011-10-27 15:19:26 -0700801 } else {
802 // Load dex cache entry into classReg (r2)
803 loadWordDisp(cUnit, r1, Method::DexCacheResolvedTypesOffset().Int32Value(), classReg);
804 int32_t offset_of_type = Array::DataOffset().Int32Value() + (sizeof(Class*) * type_idx);
805 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
806 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->method, type_idx)) {
807 // Need to test presence of type in dex cache at runtime
808 ArmLIR* hopBranch = genCmpImmBranch(cUnit, kArmCondNe, classReg, 0);
809 // Not resolved
810 // Call out to helper, which will return resolved type in r0
811 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
812 loadConstant(cUnit, r0, type_idx);
Ian Rogersb093c6b2011-10-31 16:19:55 -0700813 callRuntimeHelper(cUnit, rLR); // InitializeTypeFromCode(idx, method)
814 genRegCopy(cUnit, classReg, r0); // Align usage with fast path
Ian Rogers28ad40d2011-10-27 15:19:26 -0700815 // Rejoin code paths
816 ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
817 hopTarget->defMask = ENCODE_ALL;
818 hopBranch->generic.target = (LIR*)hopTarget;
819 }
buzbee67bf8852011-08-17 17:51:35 -0700820 }
Ian Rogers28ad40d2011-10-27 15:19:26 -0700821 // At this point, classReg (r2) has class
822 loadValueDirectFixed(cUnit, rlSrc, r0); // r0 <= ref
buzbee2a475e72011-09-07 17:19:17 -0700823 /* Null is OK - continue */
824 ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, r0, 0);
825 /* load object->clazz */
buzbeeed3e9302011-09-23 17:34:19 -0700826 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
buzbee2a475e72011-09-07 17:19:17 -0700827 loadWordDisp(cUnit, r0, Object::ClassOffset().Int32Value(), r1);
828 /* r1 now contains object->clazz */
Ian Rogers28ad40d2011-10-27 15:19:26 -0700829 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pCheckCastFromCode), rLR);
Ian Rogersb093c6b2011-10-31 16:19:55 -0700830 opRegReg(cUnit, kOpCmp, r1, classReg);
buzbee2a475e72011-09-07 17:19:17 -0700831 ArmLIR* branch2 = opCondBranch(cUnit, kArmCondEq); /* If equal, trivial yes */
832 genRegCopy(cUnit, r0, r1);
833 genRegCopy(cUnit, r1, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -0700834 callRuntimeHelper(cUnit, rLR);
buzbee2a475e72011-09-07 17:19:17 -0700835 /* branch target here */
buzbee67bf8852011-08-17 17:51:35 -0700836 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
837 target->defMask = ENCODE_ALL;
838 branch1->generic.target = (LIR*)target;
839 branch2->generic.target = (LIR*)target;
840}
841
buzbeeed3e9302011-09-23 17:34:19 -0700842STATIC void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700843 RegLocation rlSrc)
844{
845 RegLocation rlResult;
846 rlSrc = loadValue(cUnit, rlSrc, kFPReg);
847 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
848 newLIR2(cUnit, kThumb2Vnegs, rlResult.lowReg, rlSrc.lowReg);
849 storeValue(cUnit, rlDest, rlResult);
850}
851
buzbeeed3e9302011-09-23 17:34:19 -0700852STATIC void genNegDouble(CompilationUnit* cUnit, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700853 RegLocation rlSrc)
854{
855 RegLocation rlResult;
856 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
857 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
858 newLIR2(cUnit, kThumb2Vnegd, S2D(rlResult.lowReg, rlResult.highReg),
859 S2D(rlSrc.lowReg, rlSrc.highReg));
860 storeValueWide(cUnit, rlDest, rlResult);
861}
862
buzbeeed3e9302011-09-23 17:34:19 -0700863STATIC void freeRegLocTemps(CompilationUnit* cUnit, RegLocation rlKeep,
buzbee439c4fa2011-08-27 15:59:07 -0700864 RegLocation rlFree)
buzbee67bf8852011-08-17 17:51:35 -0700865{
buzbee6181f792011-09-29 11:14:04 -0700866 if ((rlFree.lowReg != rlKeep.lowReg) && (rlFree.lowReg != rlKeep.highReg) &&
867 (rlFree.highReg != rlKeep.lowReg) && (rlFree.highReg != rlKeep.highReg)) {
868 // No overlap, free both
buzbee439c4fa2011-08-27 15:59:07 -0700869 oatFreeTemp(cUnit, rlFree.lowReg);
buzbee6181f792011-09-29 11:14:04 -0700870 oatFreeTemp(cUnit, rlFree.highReg);
871 }
buzbee67bf8852011-08-17 17:51:35 -0700872}
873
buzbeeed3e9302011-09-23 17:34:19 -0700874STATIC void genLong3Addr(CompilationUnit* cUnit, MIR* mir, OpKind firstOp,
buzbee67bf8852011-08-17 17:51:35 -0700875 OpKind secondOp, RegLocation rlDest,
876 RegLocation rlSrc1, RegLocation rlSrc2)
877{
buzbee9e0f9b02011-08-24 15:32:46 -0700878 /*
879 * NOTE: This is the one place in the code in which we might have
880 * as many as six live temporary registers. There are 5 in the normal
881 * set for Arm. Until we have spill capabilities, temporarily add
882 * lr to the temp set. It is safe to do this locally, but note that
883 * lr is used explicitly elsewhere in the code generator and cannot
884 * normally be used as a general temp register.
885 */
buzbee67bf8852011-08-17 17:51:35 -0700886 RegLocation rlResult;
buzbee9e0f9b02011-08-24 15:32:46 -0700887 oatMarkTemp(cUnit, rLR); // Add lr to the temp pool
888 oatFreeTemp(cUnit, rLR); // and make it available
buzbee67bf8852011-08-17 17:51:35 -0700889 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
890 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
891 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbeec0ecd652011-09-25 18:11:54 -0700892 // The longs may overlap - use intermediate temp if so
893 if (rlResult.lowReg == rlSrc1.highReg) {
buzbeec0ecd652011-09-25 18:11:54 -0700894 int tReg = oatAllocTemp(cUnit);
895 genRegCopy(cUnit, tReg, rlSrc1.highReg);
896 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
897 rlSrc2.lowReg);
898 opRegRegReg(cUnit, secondOp, rlResult.highReg, tReg,
899 rlSrc2.highReg);
900 oatFreeTemp(cUnit, tReg);
901 } else {
902 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
903 rlSrc2.lowReg);
904 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
905 rlSrc2.highReg);
906 }
buzbee439c4fa2011-08-27 15:59:07 -0700907 /*
908 * NOTE: If rlDest refers to a frame variable in a large frame, the
909 * following storeValueWide might need to allocate a temp register.
910 * To further work around the lack of a spill capability, explicitly
911 * free any temps from rlSrc1 & rlSrc2 that aren't still live in rlResult.
912 * Remove when spill is functional.
913 */
914 freeRegLocTemps(cUnit, rlResult, rlSrc1);
915 freeRegLocTemps(cUnit, rlResult, rlSrc2);
buzbee67bf8852011-08-17 17:51:35 -0700916 storeValueWide(cUnit, rlDest, rlResult);
buzbee9e0f9b02011-08-24 15:32:46 -0700917 oatClobber(cUnit, rLR);
918 oatUnmarkTemp(cUnit, rLR); // Remove lr from the temp pool
buzbee67bf8852011-08-17 17:51:35 -0700919}
920
921void oatInitializeRegAlloc(CompilationUnit* cUnit)
922{
923 int numRegs = sizeof(coreRegs)/sizeof(*coreRegs);
924 int numReserved = sizeof(reservedRegs)/sizeof(*reservedRegs);
925 int numTemps = sizeof(coreTemps)/sizeof(*coreTemps);
926 int numFPRegs = sizeof(fpRegs)/sizeof(*fpRegs);
927 int numFPTemps = sizeof(fpTemps)/sizeof(*fpTemps);
928 RegisterPool *pool = (RegisterPool *)oatNew(sizeof(*pool), true);
929 cUnit->regPool = pool;
930 pool->numCoreRegs = numRegs;
931 pool->coreRegs = (RegisterInfo *)
932 oatNew(numRegs * sizeof(*cUnit->regPool->coreRegs), true);
933 pool->numFPRegs = numFPRegs;
934 pool->FPRegs = (RegisterInfo *)
935 oatNew(numFPRegs * sizeof(*cUnit->regPool->FPRegs), true);
936 oatInitPool(pool->coreRegs, coreRegs, pool->numCoreRegs);
937 oatInitPool(pool->FPRegs, fpRegs, pool->numFPRegs);
938 // Keep special registers from being allocated
939 for (int i = 0; i < numReserved; i++) {
buzbeec0ecd652011-09-25 18:11:54 -0700940 if (NO_SUSPEND && (reservedRegs[i] == rSUSPEND)) {
941 //To measure cost of suspend check
942 continue;
943 }
buzbee67bf8852011-08-17 17:51:35 -0700944 oatMarkInUse(cUnit, reservedRegs[i]);
945 }
946 // Mark temp regs - all others not in use can be used for promotion
947 for (int i = 0; i < numTemps; i++) {
948 oatMarkTemp(cUnit, coreTemps[i]);
949 }
950 for (int i = 0; i < numFPTemps; i++) {
951 oatMarkTemp(cUnit, fpTemps[i]);
952 }
buzbeec0ecd652011-09-25 18:11:54 -0700953 // Construct the alias map.
954 cUnit->phiAliasMap = (int*)oatNew(cUnit->numSSARegs *
955 sizeof(cUnit->phiAliasMap[0]), false);
956 for (int i = 0; i < cUnit->numSSARegs; i++) {
957 cUnit->phiAliasMap[i] = i;
958 }
959 for (MIR* phi = cUnit->phiList; phi; phi = phi->meta.phiNext) {
960 int defReg = phi->ssaRep->defs[0];
961 for (int i = 0; i < phi->ssaRep->numUses; i++) {
962 for (int j = 0; j < cUnit->numSSARegs; j++) {
963 if (cUnit->phiAliasMap[j] == phi->ssaRep->uses[i]) {
964 cUnit->phiAliasMap[j] = defReg;
965 }
966 }
967 }
968 }
buzbee67bf8852011-08-17 17:51:35 -0700969}
970
971/*
972 * Handle simple case (thin lock) inline. If it's complicated, bail
973 * out to the heavyweight lock/unlock routines. We'll use dedicated
974 * registers here in order to be in the right position in case we
975 * to bail to dvm[Lock/Unlock]Object(self, object)
976 *
977 * r0 -> self pointer [arg0 for dvm[Lock/Unlock]Object
978 * r1 -> object [arg1 for dvm[Lock/Unlock]Object
979 * r2 -> intial contents of object->lock, later result of strex
980 * r3 -> self->threadId
981 * r12 -> allow to be used by utilities as general temp
982 *
983 * The result of the strex is 0 if we acquire the lock.
984 *
985 * See comments in Sync.c for the layout of the lock word.
986 * Of particular interest to this code is the test for the
987 * simple case - which we handle inline. For monitor enter, the
988 * simple case is thin lock, held by no-one. For monitor exit,
989 * the simple case is thin lock, held by the unlocking thread with
990 * a recurse count of 0.
991 *
992 * A minor complication is that there is a field in the lock word
993 * unrelated to locking: the hash state. This field must be ignored, but
994 * preserved.
995 *
996 */
buzbeeed3e9302011-09-23 17:34:19 -0700997STATIC void genMonitorEnter(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700998 RegLocation rlSrc)
999{
1000 ArmLIR* target;
1001 ArmLIR* hopTarget;
1002 ArmLIR* branch;
1003 ArmLIR* hopBranch;
1004
1005 oatFlushAllRegs(cUnit);
Elliott Hughes5f791332011-09-15 17:45:30 -07001006 DCHECK_EQ(LW_SHAPE_THIN, 0);
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001007 loadValueDirectFixed(cUnit, rlSrc, r0); // Get obj
buzbee2e748f32011-08-29 21:02:19 -07001008 oatLockCallTemps(cUnit); // Prepare for explicit register usage
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001009 genNullCheck(cUnit, rlSrc.sRegLow, r0, mir);
1010 loadWordDisp(cUnit, rSELF, Thread::ThinLockIdOffset().Int32Value(), r2);
1011 newLIR3(cUnit, kThumb2Ldrex, r1, r0,
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001012 Object::MonitorOffset().Int32Value() >> 2); // Get object->lock
buzbeec143c552011-08-20 17:38:58 -07001013 // Align owner
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001014 opRegImm(cUnit, kOpLsl, r2, LW_LOCK_OWNER_SHIFT);
buzbee67bf8852011-08-17 17:51:35 -07001015 // Is lock unheld on lock or held by us (==threadId) on unlock?
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001016 newLIR4(cUnit, kThumb2Bfi, r2, r1, 0, LW_LOCK_OWNER_SHIFT - 1);
1017 newLIR3(cUnit, kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
1018 hopBranch = newLIR2(cUnit, kThumb2Cbnz, r1, 0);
1019 newLIR4(cUnit, kThumb2Strex, r1, r2, r0,
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001020 Object::MonitorOffset().Int32Value() >> 2);
buzbee67bf8852011-08-17 17:51:35 -07001021 oatGenMemBarrier(cUnit, kSY);
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001022 branch = newLIR2(cUnit, kThumb2Cbz, r1, 0);
buzbee67bf8852011-08-17 17:51:35 -07001023
1024 hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
1025 hopTarget->defMask = ENCODE_ALL;
1026 hopBranch->generic.target = (LIR*)hopTarget;
1027
buzbee1b4c8592011-08-31 10:43:51 -07001028 // Go expensive route - artLockObjectFromCode(self, obj);
1029 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pLockObjectFromCode),
buzbee67bf8852011-08-17 17:51:35 -07001030 rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07001031 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001032
1033 // Resume here
1034 target = newLIR0(cUnit, kArmPseudoTargetLabel);
1035 target->defMask = ENCODE_ALL;
1036 branch->generic.target = (LIR*)target;
1037}
1038
1039/*
1040 * For monitor unlock, we don't have to use ldrex/strex. Once
1041 * we've determined that the lock is thin and that we own it with
1042 * a zero recursion count, it's safe to punch it back to the
1043 * initial, unlock thin state with a store word.
1044 */
buzbeeed3e9302011-09-23 17:34:19 -07001045STATIC void genMonitorExit(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001046 RegLocation rlSrc)
1047{
1048 ArmLIR* target;
1049 ArmLIR* branch;
1050 ArmLIR* hopTarget;
1051 ArmLIR* hopBranch;
1052
Elliott Hughes5f791332011-09-15 17:45:30 -07001053 DCHECK_EQ(LW_SHAPE_THIN, 0);
buzbee67bf8852011-08-17 17:51:35 -07001054 oatFlushAllRegs(cUnit);
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001055 loadValueDirectFixed(cUnit, rlSrc, r0); // Get obj
buzbee2e748f32011-08-29 21:02:19 -07001056 oatLockCallTemps(cUnit); // Prepare for explicit register usage
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001057 genNullCheck(cUnit, rlSrc.sRegLow, r0, mir);
1058 loadWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r1); // Get lock
1059 loadWordDisp(cUnit, rSELF, Thread::ThinLockIdOffset().Int32Value(), r2);
buzbee67bf8852011-08-17 17:51:35 -07001060 // Is lock unheld on lock or held by us (==threadId) on unlock?
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001061 opRegRegImm(cUnit, kOpAnd, r3, r1, (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
buzbeec143c552011-08-20 17:38:58 -07001062 // Align owner
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001063 opRegImm(cUnit, kOpLsl, r2, LW_LOCK_OWNER_SHIFT);
1064 newLIR3(cUnit, kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
1065 opRegReg(cUnit, kOpSub, r1, r2);
buzbee67bf8852011-08-17 17:51:35 -07001066 hopBranch = opCondBranch(cUnit, kArmCondNe);
1067 oatGenMemBarrier(cUnit, kSY);
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001068 storeWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r3);
buzbee67bf8852011-08-17 17:51:35 -07001069 branch = opNone(cUnit, kOpUncondBr);
1070
1071 hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
1072 hopTarget->defMask = ENCODE_ALL;
1073 hopBranch->generic.target = (LIR*)hopTarget;
1074
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001075 // Go expensive route - UnlockObjectFromCode(obj);
buzbee1b4c8592011-08-31 10:43:51 -07001076 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pUnlockObjectFromCode),
buzbee67bf8852011-08-17 17:51:35 -07001077 rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07001078 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001079
1080 // Resume here
1081 target = newLIR0(cUnit, kArmPseudoTargetLabel);
1082 target->defMask = ENCODE_ALL;
1083 branch->generic.target = (LIR*)target;
1084}
1085
1086/*
1087 * 64-bit 3way compare function.
1088 * mov rX, #-1
1089 * cmp op1hi, op2hi
1090 * blt done
1091 * bgt flip
1092 * sub rX, op1lo, op2lo (treat as unsigned)
1093 * beq done
1094 * ite hi
1095 * mov(hi) rX, #-1
1096 * mov(!hi) rX, #1
1097 * flip:
1098 * neg rX
1099 * done:
1100 */
buzbeeed3e9302011-09-23 17:34:19 -07001101STATIC void genCmpLong(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001102 RegLocation rlDest, RegLocation rlSrc1,
1103 RegLocation rlSrc2)
1104{
buzbee67bf8852011-08-17 17:51:35 -07001105 ArmLIR* target1;
1106 ArmLIR* target2;
1107 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
1108 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
buzbeeb29e4d12011-09-26 15:05:48 -07001109 int tReg = oatAllocTemp(cUnit);
1110 loadConstant(cUnit, tReg, -1);
buzbee67bf8852011-08-17 17:51:35 -07001111 opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg);
1112 ArmLIR* branch1 = opCondBranch(cUnit, kArmCondLt);
1113 ArmLIR* branch2 = opCondBranch(cUnit, kArmCondGt);
buzbeeb29e4d12011-09-26 15:05:48 -07001114 opRegRegReg(cUnit, kOpSub, tReg, rlSrc1.lowReg, rlSrc2.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001115 ArmLIR* branch3 = opCondBranch(cUnit, kArmCondEq);
1116
1117 genIT(cUnit, kArmCondHi, "E");
buzbeeb29e4d12011-09-26 15:05:48 -07001118 newLIR2(cUnit, kThumb2MovImmShift, tReg, modifiedImmediate(-1));
1119 loadConstant(cUnit, tReg, 1);
buzbee67bf8852011-08-17 17:51:35 -07001120 genBarrier(cUnit);
1121
1122 target2 = newLIR0(cUnit, kArmPseudoTargetLabel);
1123 target2->defMask = -1;
buzbeeb29e4d12011-09-26 15:05:48 -07001124 opRegReg(cUnit, kOpNeg, tReg, tReg);
buzbee67bf8852011-08-17 17:51:35 -07001125
1126 target1 = newLIR0(cUnit, kArmPseudoTargetLabel);
1127 target1->defMask = -1;
1128
buzbeeb29e4d12011-09-26 15:05:48 -07001129 RegLocation rlTemp = LOC_C_RETURN; // Just using as template, will change
1130 rlTemp.lowReg = tReg;
buzbee67bf8852011-08-17 17:51:35 -07001131 storeValue(cUnit, rlDest, rlTemp);
buzbeeb29e4d12011-09-26 15:05:48 -07001132 oatFreeTemp(cUnit, tReg);
buzbee67bf8852011-08-17 17:51:35 -07001133
1134 branch1->generic.target = (LIR*)target1;
1135 branch2->generic.target = (LIR*)target2;
1136 branch3->generic.target = branch1->generic.target;
1137}
1138
buzbeeed3e9302011-09-23 17:34:19 -07001139STATIC void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -07001140 RegLocation rlSrc, RegLocation rlResult, int lit,
1141 int firstBit, int secondBit)
1142{
1143 opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg,
1144 encodeShift(kArmLsl, secondBit - firstBit));
1145 if (firstBit != 0) {
1146 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
1147 }
1148}
1149
buzbeeed3e9302011-09-23 17:34:19 -07001150STATIC bool genConversionCall(CompilationUnit* cUnit, MIR* mir, int funcOffset,
buzbee67bf8852011-08-17 17:51:35 -07001151 int srcSize, int tgtSize)
1152{
1153 /*
1154 * Don't optimize the register usage since it calls out to support
1155 * functions
1156 */
1157 RegLocation rlSrc;
1158 RegLocation rlDest;
1159 oatFlushAllRegs(cUnit); /* Send everything to home location */
1160 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1161 if (srcSize == 1) {
1162 rlSrc = oatGetSrc(cUnit, mir, 0);
1163 loadValueDirectFixed(cUnit, rlSrc, r0);
1164 } else {
1165 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
1166 loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
1167 }
Ian Rogersff1ed472011-09-20 13:46:24 -07001168 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001169 if (tgtSize == 1) {
1170 RegLocation rlResult;
1171 rlDest = oatGetDest(cUnit, mir, 0);
1172 rlResult = oatGetReturn(cUnit);
1173 storeValue(cUnit, rlDest, rlResult);
1174 } else {
1175 RegLocation rlResult;
1176 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1177 rlResult = oatGetReturnWide(cUnit);
1178 storeValueWide(cUnit, rlDest, rlResult);
1179 }
1180 return false;
1181}
1182
buzbeeed3e9302011-09-23 17:34:19 -07001183STATIC bool genArithOpFloatPortable(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001184 RegLocation rlDest, RegLocation rlSrc1,
1185 RegLocation rlSrc2)
1186{
1187 RegLocation rlResult;
1188 int funcOffset;
1189
1190 switch (mir->dalvikInsn.opcode) {
1191 case OP_ADD_FLOAT_2ADDR:
1192 case OP_ADD_FLOAT:
1193 funcOffset = OFFSETOF_MEMBER(Thread, pFadd);
1194 break;
1195 case OP_SUB_FLOAT_2ADDR:
1196 case OP_SUB_FLOAT:
1197 funcOffset = OFFSETOF_MEMBER(Thread, pFsub);
1198 break;
1199 case OP_DIV_FLOAT_2ADDR:
1200 case OP_DIV_FLOAT:
1201 funcOffset = OFFSETOF_MEMBER(Thread, pFdiv);
1202 break;
1203 case OP_MUL_FLOAT_2ADDR:
1204 case OP_MUL_FLOAT:
1205 funcOffset = OFFSETOF_MEMBER(Thread, pFmul);
1206 break;
1207 case OP_REM_FLOAT_2ADDR:
1208 case OP_REM_FLOAT:
1209 funcOffset = OFFSETOF_MEMBER(Thread, pFmodf);
1210 break;
1211 case OP_NEG_FLOAT: {
1212 genNegFloat(cUnit, rlDest, rlSrc1);
1213 return false;
1214 }
1215 default:
1216 return true;
1217 }
1218 oatFlushAllRegs(cUnit); /* Send everything to home location */
1219 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1220 loadValueDirectFixed(cUnit, rlSrc1, r0);
1221 loadValueDirectFixed(cUnit, rlSrc2, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -07001222 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001223 rlResult = oatGetReturn(cUnit);
1224 storeValue(cUnit, rlDest, rlResult);
1225 return false;
1226}
1227
buzbeeed3e9302011-09-23 17:34:19 -07001228STATIC bool genArithOpDoublePortable(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001229 RegLocation rlDest, RegLocation rlSrc1,
1230 RegLocation rlSrc2)
1231{
1232 RegLocation rlResult;
1233 int funcOffset;
1234
1235 switch (mir->dalvikInsn.opcode) {
1236 case OP_ADD_DOUBLE_2ADDR:
1237 case OP_ADD_DOUBLE:
1238 funcOffset = OFFSETOF_MEMBER(Thread, pDadd);
1239 break;
1240 case OP_SUB_DOUBLE_2ADDR:
1241 case OP_SUB_DOUBLE:
1242 funcOffset = OFFSETOF_MEMBER(Thread, pDsub);
1243 break;
1244 case OP_DIV_DOUBLE_2ADDR:
1245 case OP_DIV_DOUBLE:
1246 funcOffset = OFFSETOF_MEMBER(Thread, pDdiv);
1247 break;
1248 case OP_MUL_DOUBLE_2ADDR:
1249 case OP_MUL_DOUBLE:
1250 funcOffset = OFFSETOF_MEMBER(Thread, pDmul);
1251 break;
1252 case OP_REM_DOUBLE_2ADDR:
1253 case OP_REM_DOUBLE:
1254 funcOffset = OFFSETOF_MEMBER(Thread, pFmod);
1255 break;
1256 case OP_NEG_DOUBLE: {
1257 genNegDouble(cUnit, rlDest, rlSrc1);
1258 return false;
1259 }
1260 default:
1261 return true;
1262 }
1263 oatFlushAllRegs(cUnit); /* Send everything to home location */
1264 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1265 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1266 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
Ian Rogersff1ed472011-09-20 13:46:24 -07001267 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001268 rlResult = oatGetReturnWide(cUnit);
1269 storeValueWide(cUnit, rlDest, rlResult);
1270 return false;
1271}
1272
buzbeeed3e9302011-09-23 17:34:19 -07001273STATIC bool genConversionPortable(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001274{
1275 Opcode opcode = mir->dalvikInsn.opcode;
1276
1277 switch (opcode) {
1278 case OP_INT_TO_FLOAT:
1279 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2f),
1280 1, 1);
1281 case OP_FLOAT_TO_INT:
1282 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2iz),
1283 1, 1);
1284 case OP_DOUBLE_TO_FLOAT:
1285 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2f),
1286 2, 1);
1287 case OP_FLOAT_TO_DOUBLE:
1288 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2d),
1289 1, 2);
1290 case OP_INT_TO_DOUBLE:
1291 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2d),
1292 1, 2);
1293 case OP_DOUBLE_TO_INT:
1294 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2iz),
1295 2, 1);
1296 case OP_FLOAT_TO_LONG:
1297 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
buzbee1b4c8592011-08-31 10:43:51 -07001298 pF2l), 1, 2);
buzbee67bf8852011-08-17 17:51:35 -07001299 case OP_LONG_TO_FLOAT:
1300 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2f),
1301 2, 1);
1302 case OP_DOUBLE_TO_LONG:
1303 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
buzbee1b4c8592011-08-31 10:43:51 -07001304 pD2l), 2, 2);
buzbee67bf8852011-08-17 17:51:35 -07001305 case OP_LONG_TO_DOUBLE:
1306 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2d),
1307 2, 2);
1308 default:
1309 return true;
1310 }
1311 return false;
1312}
1313
1314/* Generate conditional branch instructions */
buzbeeed3e9302011-09-23 17:34:19 -07001315STATIC ArmLIR* genConditionalBranch(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -07001316 ArmConditionCode cond,
1317 ArmLIR* target)
1318{
1319 ArmLIR* branch = opCondBranch(cUnit, cond);
1320 branch->generic.target = (LIR*) target;
1321 return branch;
1322}
1323
buzbee67bf8852011-08-17 17:51:35 -07001324/*
1325 * Generate array store
1326 *
1327 */
buzbeeed3e9302011-09-23 17:34:19 -07001328STATIC void genArrayObjPut(CompilationUnit* cUnit, MIR* mir,
buzbee1b4c8592011-08-31 10:43:51 -07001329 RegLocation rlArray, RegLocation rlIndex,
1330 RegLocation rlSrc, int scale)
buzbee67bf8852011-08-17 17:51:35 -07001331{
1332 RegisterClass regClass = oatRegClassBySize(kWord);
buzbeec143c552011-08-20 17:38:58 -07001333 int lenOffset = Array::LengthOffset().Int32Value();
1334 int dataOffset = Array::DataOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001335
buzbee6181f792011-09-29 11:14:04 -07001336 oatFlushAllRegs(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001337 /* Make sure it's a legal object Put. Use direct regs at first */
1338 loadValueDirectFixed(cUnit, rlArray, r1);
1339 loadValueDirectFixed(cUnit, rlSrc, r0);
1340
1341 /* null array object? */
buzbee43a36422011-09-14 14:00:13 -07001342 genNullCheck(cUnit, rlArray.sRegLow, r1, mir);
buzbee67bf8852011-08-17 17:51:35 -07001343 loadWordDisp(cUnit, rSELF,
buzbee1b4c8592011-08-31 10:43:51 -07001344 OFFSETOF_MEMBER(Thread, pCanPutArrayElementFromCode), rLR);
buzbee67bf8852011-08-17 17:51:35 -07001345 /* Get the array's clazz */
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001346 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), r1);
Ian Rogersff1ed472011-09-20 13:46:24 -07001347 callRuntimeHelper(cUnit, rLR);
buzbee6181f792011-09-29 11:14:04 -07001348 oatFreeTemp(cUnit, r0);
1349 oatFreeTemp(cUnit, r1);
buzbee67bf8852011-08-17 17:51:35 -07001350
1351 // Now, redo loadValues in case they didn't survive the call
1352
1353 int regPtr;
1354 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1355 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1356
1357 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1358 oatClobber(cUnit, rlArray.lowReg);
1359 regPtr = rlArray.lowReg;
1360 } else {
1361 regPtr = oatAllocTemp(cUnit);
1362 genRegCopy(cUnit, regPtr, rlArray.lowReg);
1363 }
1364
buzbee43a36422011-09-14 14:00:13 -07001365 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee67bf8852011-08-17 17:51:35 -07001366 int regLen = oatAllocTemp(cUnit);
1367 //NOTE: max live temps(4) here.
1368 /* Get len */
1369 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1370 /* regPtr -> array data */
1371 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
buzbeeec5adf32011-09-11 15:25:43 -07001372 genRegRegCheck(cUnit, kArmCondCs, rlIndex.lowReg, regLen, mir,
buzbee5ade1d22011-09-09 14:44:52 -07001373 kArmThrowArrayBounds);
buzbee67bf8852011-08-17 17:51:35 -07001374 oatFreeTemp(cUnit, regLen);
1375 } else {
1376 /* regPtr -> array data */
1377 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1378 }
1379 /* at this point, regPtr points to array, 2 live temps */
1380 rlSrc = loadValue(cUnit, rlSrc, regClass);
1381 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1382 scale, kWord);
1383}
1384
1385/*
1386 * Generate array load
1387 */
buzbeeed3e9302011-09-23 17:34:19 -07001388STATIC void genArrayGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -07001389 RegLocation rlArray, RegLocation rlIndex,
1390 RegLocation rlDest, int scale)
1391{
1392 RegisterClass regClass = oatRegClassBySize(size);
buzbeec143c552011-08-20 17:38:58 -07001393 int lenOffset = Array::LengthOffset().Int32Value();
1394 int dataOffset = Array::DataOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001395 RegLocation rlResult;
1396 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1397 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1398 int regPtr;
1399
1400 /* null object? */
buzbee43a36422011-09-14 14:00:13 -07001401 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001402
1403 regPtr = oatAllocTemp(cUnit);
1404
buzbee43a36422011-09-14 14:00:13 -07001405 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee67bf8852011-08-17 17:51:35 -07001406 int regLen = oatAllocTemp(cUnit);
1407 /* Get len */
1408 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1409 /* regPtr -> array data */
1410 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
buzbeeec5adf32011-09-11 15:25:43 -07001411 genRegRegCheck(cUnit, kArmCondCs, rlIndex.lowReg, regLen, mir,
buzbee5ade1d22011-09-09 14:44:52 -07001412 kArmThrowArrayBounds);
buzbee67bf8852011-08-17 17:51:35 -07001413 oatFreeTemp(cUnit, regLen);
1414 } else {
1415 /* regPtr -> array data */
1416 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1417 }
buzbeee9a72f62011-09-04 17:59:07 -07001418 oatFreeTemp(cUnit, rlArray.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001419 if ((size == kLong) || (size == kDouble)) {
1420 if (scale) {
1421 int rNewIndex = oatAllocTemp(cUnit);
1422 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1423 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1424 oatFreeTemp(cUnit, rNewIndex);
1425 } else {
1426 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1427 }
buzbeee9a72f62011-09-04 17:59:07 -07001428 oatFreeTemp(cUnit, rlIndex.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001429 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1430
1431 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1432
1433 oatFreeTemp(cUnit, regPtr);
1434 storeValueWide(cUnit, rlDest, rlResult);
1435 } else {
1436 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1437
1438 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
1439 scale, size);
1440
1441 oatFreeTemp(cUnit, regPtr);
1442 storeValue(cUnit, rlDest, rlResult);
1443 }
1444}
1445
1446/*
1447 * Generate array store
1448 *
1449 */
buzbeeed3e9302011-09-23 17:34:19 -07001450STATIC void genArrayPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -07001451 RegLocation rlArray, RegLocation rlIndex,
1452 RegLocation rlSrc, int scale)
1453{
1454 RegisterClass regClass = oatRegClassBySize(size);
buzbeec143c552011-08-20 17:38:58 -07001455 int lenOffset = Array::LengthOffset().Int32Value();
1456 int dataOffset = Array::DataOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001457
1458 int regPtr;
1459 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1460 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1461
1462 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1463 oatClobber(cUnit, rlArray.lowReg);
1464 regPtr = rlArray.lowReg;
1465 } else {
1466 regPtr = oatAllocTemp(cUnit);
1467 genRegCopy(cUnit, regPtr, rlArray.lowReg);
1468 }
1469
1470 /* null object? */
buzbee43a36422011-09-14 14:00:13 -07001471 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001472
buzbee43a36422011-09-14 14:00:13 -07001473 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee67bf8852011-08-17 17:51:35 -07001474 int regLen = oatAllocTemp(cUnit);
1475 //NOTE: max live temps(4) here.
1476 /* Get len */
1477 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1478 /* regPtr -> array data */
1479 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
buzbeeec5adf32011-09-11 15:25:43 -07001480 genRegRegCheck(cUnit, kArmCondCs, rlIndex.lowReg, regLen, mir,
buzbee5ade1d22011-09-09 14:44:52 -07001481 kArmThrowArrayBounds);
buzbee67bf8852011-08-17 17:51:35 -07001482 oatFreeTemp(cUnit, regLen);
1483 } else {
1484 /* regPtr -> array data */
1485 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1486 }
1487 /* at this point, regPtr points to array, 2 live temps */
1488 if ((size == kLong) || (size == kDouble)) {
buzbee5ade1d22011-09-09 14:44:52 -07001489 //TUNING: specific wide routine that can handle fp regs
buzbee67bf8852011-08-17 17:51:35 -07001490 if (scale) {
1491 int rNewIndex = oatAllocTemp(cUnit);
1492 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1493 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1494 oatFreeTemp(cUnit, rNewIndex);
1495 } else {
1496 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1497 }
1498 rlSrc = loadValueWide(cUnit, rlSrc, regClass);
1499
1500 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
1501
1502 oatFreeTemp(cUnit, regPtr);
1503 } else {
1504 rlSrc = loadValue(cUnit, rlSrc, regClass);
1505
1506 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1507 scale, size);
1508 }
1509}
1510
buzbeeed3e9302011-09-23 17:34:19 -07001511STATIC bool genShiftOpLong(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001512 RegLocation rlDest, RegLocation rlSrc1,
1513 RegLocation rlShift)
1514{
buzbee54330722011-08-23 16:46:55 -07001515 int funcOffset;
buzbee67bf8852011-08-17 17:51:35 -07001516
buzbee67bf8852011-08-17 17:51:35 -07001517 switch( mir->dalvikInsn.opcode) {
1518 case OP_SHL_LONG:
1519 case OP_SHL_LONG_2ADDR:
buzbee54330722011-08-23 16:46:55 -07001520 funcOffset = OFFSETOF_MEMBER(Thread, pShlLong);
buzbee67bf8852011-08-17 17:51:35 -07001521 break;
1522 case OP_SHR_LONG:
1523 case OP_SHR_LONG_2ADDR:
buzbee54330722011-08-23 16:46:55 -07001524 funcOffset = OFFSETOF_MEMBER(Thread, pShrLong);
buzbee67bf8852011-08-17 17:51:35 -07001525 break;
1526 case OP_USHR_LONG:
1527 case OP_USHR_LONG_2ADDR:
buzbee54330722011-08-23 16:46:55 -07001528 funcOffset = OFFSETOF_MEMBER(Thread, pUshrLong);
buzbee67bf8852011-08-17 17:51:35 -07001529 break;
1530 default:
buzbee54330722011-08-23 16:46:55 -07001531 LOG(FATAL) << "Unexpected case";
buzbee67bf8852011-08-17 17:51:35 -07001532 return true;
1533 }
buzbee54330722011-08-23 16:46:55 -07001534 oatFlushAllRegs(cUnit); /* Send everything to home location */
1535 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1536 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1537 loadValueDirect(cUnit, rlShift, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -07001538 callRuntimeHelper(cUnit, rLR);
buzbee54330722011-08-23 16:46:55 -07001539 RegLocation rlResult = oatGetReturnWide(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001540 storeValueWide(cUnit, rlDest, rlResult);
1541 return false;
1542}
1543
buzbeeed3e9302011-09-23 17:34:19 -07001544STATIC bool genArithOpLong(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001545 RegLocation rlDest, RegLocation rlSrc1,
1546 RegLocation rlSrc2)
1547{
1548 RegLocation rlResult;
1549 OpKind firstOp = kOpBkpt;
1550 OpKind secondOp = kOpBkpt;
1551 bool callOut = false;
buzbee58f92742011-10-01 11:22:17 -07001552 bool checkZero = false;
buzbee67bf8852011-08-17 17:51:35 -07001553 int funcOffset;
1554 int retReg = r0;
1555
1556 switch (mir->dalvikInsn.opcode) {
1557 case OP_NOT_LONG:
1558 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1559 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbeeb29e4d12011-09-26 15:05:48 -07001560 // Check for destructive overlap
1561 if (rlResult.lowReg == rlSrc2.highReg) {
1562 int tReg = oatAllocTemp(cUnit);
1563 genRegCopy(cUnit, tReg, rlSrc2.highReg);
1564 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1565 opRegReg(cUnit, kOpMvn, rlResult.highReg, tReg);
1566 oatFreeTemp(cUnit, tReg);
1567 } else {
1568 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1569 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
1570 }
buzbee67bf8852011-08-17 17:51:35 -07001571 storeValueWide(cUnit, rlDest, rlResult);
1572 return false;
1573 break;
1574 case OP_ADD_LONG:
1575 case OP_ADD_LONG_2ADDR:
1576 firstOp = kOpAdd;
1577 secondOp = kOpAdc;
1578 break;
1579 case OP_SUB_LONG:
1580 case OP_SUB_LONG_2ADDR:
1581 firstOp = kOpSub;
1582 secondOp = kOpSbc;
1583 break;
1584 case OP_MUL_LONG:
1585 case OP_MUL_LONG_2ADDR:
buzbee439c4fa2011-08-27 15:59:07 -07001586 callOut = true;
1587 retReg = r0;
1588 funcOffset = OFFSETOF_MEMBER(Thread, pLmul);
1589 break;
buzbee67bf8852011-08-17 17:51:35 -07001590 case OP_DIV_LONG:
1591 case OP_DIV_LONG_2ADDR:
1592 callOut = true;
buzbee58f92742011-10-01 11:22:17 -07001593 checkZero = true;
buzbee67bf8852011-08-17 17:51:35 -07001594 retReg = r0;
1595 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
1596 break;
1597 /* NOTE - result is in r2/r3 instead of r0/r1 */
1598 case OP_REM_LONG:
1599 case OP_REM_LONG_2ADDR:
1600 callOut = true;
buzbee58f92742011-10-01 11:22:17 -07001601 checkZero = true;
buzbee67bf8852011-08-17 17:51:35 -07001602 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
1603 retReg = r2;
1604 break;
1605 case OP_AND_LONG_2ADDR:
1606 case OP_AND_LONG:
1607 firstOp = kOpAnd;
1608 secondOp = kOpAnd;
1609 break;
1610 case OP_OR_LONG:
1611 case OP_OR_LONG_2ADDR:
1612 firstOp = kOpOr;
1613 secondOp = kOpOr;
1614 break;
1615 case OP_XOR_LONG:
1616 case OP_XOR_LONG_2ADDR:
1617 firstOp = kOpXor;
1618 secondOp = kOpXor;
1619 break;
1620 case OP_NEG_LONG: {
buzbee67bf8852011-08-17 17:51:35 -07001621 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1622 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbeeb29e4d12011-09-26 15:05:48 -07001623 int zReg = oatAllocTemp(cUnit);
1624 loadConstantNoClobber(cUnit, zReg, 0);
1625 // Check for destructive overlap
1626 if (rlResult.lowReg == rlSrc2.highReg) {
1627 int tReg = oatAllocTemp(cUnit);
1628 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1629 zReg, rlSrc2.lowReg);
1630 opRegRegReg(cUnit, kOpSbc, rlResult.highReg,
1631 zReg, tReg);
1632 oatFreeTemp(cUnit, tReg);
1633 } else {
1634 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1635 zReg, rlSrc2.lowReg);
1636 opRegRegReg(cUnit, kOpSbc, rlResult.highReg,
1637 zReg, rlSrc2.highReg);
1638 }
1639 oatFreeTemp(cUnit, zReg);
buzbee67bf8852011-08-17 17:51:35 -07001640 storeValueWide(cUnit, rlDest, rlResult);
1641 return false;
1642 }
1643 default:
1644 LOG(FATAL) << "Invalid long arith op";
1645 }
1646 if (!callOut) {
1647 genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
1648 } else {
buzbee67bf8852011-08-17 17:51:35 -07001649 oatFlushAllRegs(cUnit); /* Send everything to home location */
buzbee58f92742011-10-01 11:22:17 -07001650 if (checkZero) {
1651 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
1652 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1653 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1654 int tReg = oatAllocTemp(cUnit);
1655 newLIR4(cUnit, kThumb2OrrRRRs, tReg, r2, r3, 0);
1656 oatFreeTemp(cUnit, tReg);
1657 genCheck(cUnit, kArmCondEq, mir, kArmThrowDivZero);
1658 } else {
1659 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1660 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1661 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
1662 }
Ian Rogersff1ed472011-09-20 13:46:24 -07001663 callRuntimeHelper(cUnit, rLR);
buzbee58f92742011-10-01 11:22:17 -07001664 // Adjust return regs in to handle case of rem returning r2/r3
buzbee67bf8852011-08-17 17:51:35 -07001665 if (retReg == r0)
1666 rlResult = oatGetReturnWide(cUnit);
1667 else
1668 rlResult = oatGetReturnWideAlt(cUnit);
1669 storeValueWide(cUnit, rlDest, rlResult);
1670 }
1671 return false;
1672}
1673
buzbeeed3e9302011-09-23 17:34:19 -07001674STATIC bool genArithOpInt(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001675 RegLocation rlDest, RegLocation rlSrc1,
1676 RegLocation rlSrc2)
1677{
1678 OpKind op = kOpBkpt;
1679 bool callOut = false;
1680 bool checkZero = false;
1681 bool unary = false;
1682 int retReg = r0;
1683 int funcOffset;
1684 RegLocation rlResult;
1685 bool shiftOp = false;
1686
1687 switch (mir->dalvikInsn.opcode) {
1688 case OP_NEG_INT:
1689 op = kOpNeg;
1690 unary = true;
1691 break;
1692 case OP_NOT_INT:
1693 op = kOpMvn;
1694 unary = true;
1695 break;
1696 case OP_ADD_INT:
1697 case OP_ADD_INT_2ADDR:
1698 op = kOpAdd;
1699 break;
1700 case OP_SUB_INT:
1701 case OP_SUB_INT_2ADDR:
1702 op = kOpSub;
1703 break;
1704 case OP_MUL_INT:
1705 case OP_MUL_INT_2ADDR:
1706 op = kOpMul;
1707 break;
1708 case OP_DIV_INT:
1709 case OP_DIV_INT_2ADDR:
1710 callOut = true;
1711 checkZero = true;
1712 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
1713 retReg = r0;
1714 break;
1715 /* NOTE: returns in r1 */
1716 case OP_REM_INT:
1717 case OP_REM_INT_2ADDR:
1718 callOut = true;
1719 checkZero = true;
1720 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
1721 retReg = r1;
1722 break;
1723 case OP_AND_INT:
1724 case OP_AND_INT_2ADDR:
1725 op = kOpAnd;
1726 break;
1727 case OP_OR_INT:
1728 case OP_OR_INT_2ADDR:
1729 op = kOpOr;
1730 break;
1731 case OP_XOR_INT:
1732 case OP_XOR_INT_2ADDR:
1733 op = kOpXor;
1734 break;
1735 case OP_SHL_INT:
1736 case OP_SHL_INT_2ADDR:
1737 shiftOp = true;
1738 op = kOpLsl;
1739 break;
1740 case OP_SHR_INT:
1741 case OP_SHR_INT_2ADDR:
1742 shiftOp = true;
1743 op = kOpAsr;
1744 break;
1745 case OP_USHR_INT:
1746 case OP_USHR_INT_2ADDR:
1747 shiftOp = true;
1748 op = kOpLsr;
1749 break;
1750 default:
1751 LOG(FATAL) << "Invalid word arith op: " <<
1752 (int)mir->dalvikInsn.opcode;
1753 }
1754 if (!callOut) {
1755 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1756 if (unary) {
1757 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1758 opRegReg(cUnit, op, rlResult.lowReg,
1759 rlSrc1.lowReg);
1760 } else {
1761 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1762 if (shiftOp) {
1763 int tReg = oatAllocTemp(cUnit);
1764 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
1765 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1766 opRegRegReg(cUnit, op, rlResult.lowReg,
1767 rlSrc1.lowReg, tReg);
1768 oatFreeTemp(cUnit, tReg);
1769 } else {
1770 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1771 opRegRegReg(cUnit, op, rlResult.lowReg,
1772 rlSrc1.lowReg, rlSrc2.lowReg);
1773 }
1774 }
1775 storeValue(cUnit, rlDest, rlResult);
1776 } else {
1777 RegLocation rlResult;
1778 oatFlushAllRegs(cUnit); /* Send everything to home location */
1779 loadValueDirectFixed(cUnit, rlSrc2, r1);
1780 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1781 loadValueDirectFixed(cUnit, rlSrc1, r0);
1782 if (checkZero) {
buzbee5ade1d22011-09-09 14:44:52 -07001783 genImmedCheck(cUnit, kArmCondEq, r1, 0, mir, kArmThrowDivZero);
buzbee67bf8852011-08-17 17:51:35 -07001784 }
Ian Rogersff1ed472011-09-20 13:46:24 -07001785 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001786 if (retReg == r0)
1787 rlResult = oatGetReturn(cUnit);
1788 else
1789 rlResult = oatGetReturnAlt(cUnit);
1790 storeValue(cUnit, rlDest, rlResult);
1791 }
1792 return false;
1793}
1794
buzbeec1f45042011-09-21 16:03:19 -07001795/* Check if we need to check for pending suspend request */
buzbeeed3e9302011-09-23 17:34:19 -07001796STATIC void genSuspendTest(CompilationUnit* cUnit, MIR* mir)
buzbeec1f45042011-09-21 16:03:19 -07001797{
buzbeec0ecd652011-09-25 18:11:54 -07001798 if (NO_SUSPEND || mir->optimizationFlags & MIR_IGNORE_SUSPEND_CHECK) {
buzbeec1f45042011-09-21 16:03:19 -07001799 return;
1800 }
buzbee6181f792011-09-29 11:14:04 -07001801 oatFlushAllRegs(cUnit);
buzbeec1f45042011-09-21 16:03:19 -07001802 newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
1803 ArmLIR* branch = opCondBranch(cUnit, kArmCondEq);
1804 ArmLIR* retLab = newLIR0(cUnit, kArmPseudoTargetLabel);
1805 retLab->defMask = ENCODE_ALL;
1806 ArmLIR* target = (ArmLIR*)oatNew(sizeof(ArmLIR), true);
1807 target->generic.dalvikOffset = cUnit->currentDalvikOffset;
1808 target->opcode = kArmPseudoSuspendTarget;
1809 target->operands[0] = (intptr_t)retLab;
1810 target->operands[1] = mir->offset;
1811 branch->generic.target = (LIR*)target;
1812 oatInsertGrowableList(&cUnit->suspendLaunchpads, (intptr_t)target);
1813}
1814
buzbee67bf8852011-08-17 17:51:35 -07001815/*
1816 * The following are the first-level codegen routines that analyze the format
1817 * of each bytecode then either dispatch special purpose codegen routines
1818 * or produce corresponding Thumb instructions directly.
1819 */
1820
buzbeeed3e9302011-09-23 17:34:19 -07001821STATIC bool isPowerOfTwo(int x)
buzbee67bf8852011-08-17 17:51:35 -07001822{
1823 return (x & (x - 1)) == 0;
1824}
1825
1826// Returns true if no more than two bits are set in 'x'.
buzbeeed3e9302011-09-23 17:34:19 -07001827STATIC bool isPopCountLE2(unsigned int x)
buzbee67bf8852011-08-17 17:51:35 -07001828{
1829 x &= x - 1;
1830 return (x & (x - 1)) == 0;
1831}
1832
1833// Returns the index of the lowest set bit in 'x'.
buzbeeed3e9302011-09-23 17:34:19 -07001834STATIC int lowestSetBit(unsigned int x) {
buzbee67bf8852011-08-17 17:51:35 -07001835 int bit_posn = 0;
1836 while ((x & 0xf) == 0) {
1837 bit_posn += 4;
1838 x >>= 4;
1839 }
1840 while ((x & 1) == 0) {
1841 bit_posn++;
1842 x >>= 1;
1843 }
1844 return bit_posn;
1845}
1846
1847// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
1848// and store the result in 'rlDest'.
buzbeeed3e9302011-09-23 17:34:19 -07001849STATIC bool handleEasyDivide(CompilationUnit* cUnit, Opcode dalvikOpcode,
buzbee67bf8852011-08-17 17:51:35 -07001850 RegLocation rlSrc, RegLocation rlDest, int lit)
1851{
1852 if (lit < 2 || !isPowerOfTwo(lit)) {
1853 return false;
1854 }
1855 int k = lowestSetBit(lit);
1856 if (k >= 30) {
1857 // Avoid special cases.
1858 return false;
1859 }
1860 bool div = (dalvikOpcode == OP_DIV_INT_LIT8 ||
1861 dalvikOpcode == OP_DIV_INT_LIT16);
1862 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1863 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1864 if (div) {
1865 int tReg = oatAllocTemp(cUnit);
1866 if (lit == 2) {
1867 // Division by 2 is by far the most common division by constant.
1868 opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
1869 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1870 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1871 } else {
1872 opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
1873 opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
1874 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1875 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1876 }
1877 } else {
1878 int cReg = oatAllocTemp(cUnit);
1879 loadConstant(cUnit, cReg, lit - 1);
1880 int tReg1 = oatAllocTemp(cUnit);
1881 int tReg2 = oatAllocTemp(cUnit);
1882 if (lit == 2) {
1883 opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
1884 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1885 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1886 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1887 } else {
1888 opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
1889 opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
1890 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1891 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1892 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1893 }
1894 }
1895 storeValue(cUnit, rlDest, rlResult);
1896 return true;
1897}
1898
1899// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
1900// and store the result in 'rlDest'.
buzbeeed3e9302011-09-23 17:34:19 -07001901STATIC bool handleEasyMultiply(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -07001902 RegLocation rlSrc, RegLocation rlDest, int lit)
1903{
1904 // Can we simplify this multiplication?
1905 bool powerOfTwo = false;
1906 bool popCountLE2 = false;
1907 bool powerOfTwoMinusOne = false;
1908 if (lit < 2) {
1909 // Avoid special cases.
1910 return false;
1911 } else if (isPowerOfTwo(lit)) {
1912 powerOfTwo = true;
1913 } else if (isPopCountLE2(lit)) {
1914 popCountLE2 = true;
1915 } else if (isPowerOfTwo(lit + 1)) {
1916 powerOfTwoMinusOne = true;
1917 } else {
1918 return false;
1919 }
1920 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1921 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1922 if (powerOfTwo) {
1923 // Shift.
1924 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
1925 lowestSetBit(lit));
1926 } else if (popCountLE2) {
1927 // Shift and add and shift.
1928 int firstBit = lowestSetBit(lit);
1929 int secondBit = lowestSetBit(lit ^ (1 << firstBit));
1930 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
1931 firstBit, secondBit);
1932 } else {
1933 // Reverse subtract: (src << (shift + 1)) - src.
buzbeeed3e9302011-09-23 17:34:19 -07001934 DCHECK(powerOfTwoMinusOne);
buzbee5ade1d22011-09-09 14:44:52 -07001935 // TUNING: rsb dst, src, src lsl#lowestSetBit(lit + 1)
buzbee67bf8852011-08-17 17:51:35 -07001936 int tReg = oatAllocTemp(cUnit);
1937 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
1938 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
1939 }
1940 storeValue(cUnit, rlDest, rlResult);
1941 return true;
1942}
1943
buzbeeed3e9302011-09-23 17:34:19 -07001944STATIC bool genArithOpIntLit(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001945 RegLocation rlDest, RegLocation rlSrc,
1946 int lit)
1947{
1948 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1949 RegLocation rlResult;
1950 OpKind op = (OpKind)0; /* Make gcc happy */
1951 int shiftOp = false;
1952 bool isDiv = false;
1953 int funcOffset;
1954
1955 switch (dalvikOpcode) {
1956 case OP_RSUB_INT_LIT8:
1957 case OP_RSUB_INT: {
1958 int tReg;
1959 //TUNING: add support for use of Arm rsub op
1960 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1961 tReg = oatAllocTemp(cUnit);
1962 loadConstant(cUnit, tReg, lit);
1963 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1964 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1965 tReg, rlSrc.lowReg);
1966 storeValue(cUnit, rlDest, rlResult);
1967 return false;
1968 break;
1969 }
1970
1971 case OP_ADD_INT_LIT8:
1972 case OP_ADD_INT_LIT16:
1973 op = kOpAdd;
1974 break;
1975 case OP_MUL_INT_LIT8:
1976 case OP_MUL_INT_LIT16: {
1977 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
1978 return false;
1979 }
1980 op = kOpMul;
1981 break;
1982 }
1983 case OP_AND_INT_LIT8:
1984 case OP_AND_INT_LIT16:
1985 op = kOpAnd;
1986 break;
1987 case OP_OR_INT_LIT8:
1988 case OP_OR_INT_LIT16:
1989 op = kOpOr;
1990 break;
1991 case OP_XOR_INT_LIT8:
1992 case OP_XOR_INT_LIT16:
1993 op = kOpXor;
1994 break;
1995 case OP_SHL_INT_LIT8:
1996 lit &= 31;
1997 shiftOp = true;
1998 op = kOpLsl;
1999 break;
2000 case OP_SHR_INT_LIT8:
2001 lit &= 31;
2002 shiftOp = true;
2003 op = kOpAsr;
2004 break;
2005 case OP_USHR_INT_LIT8:
2006 lit &= 31;
2007 shiftOp = true;
2008 op = kOpLsr;
2009 break;
2010
2011 case OP_DIV_INT_LIT8:
2012 case OP_DIV_INT_LIT16:
2013 case OP_REM_INT_LIT8:
2014 case OP_REM_INT_LIT16:
2015 if (lit == 0) {
buzbee5ade1d22011-09-09 14:44:52 -07002016 genImmedCheck(cUnit, kArmCondAl, 0, 0, mir, kArmThrowDivZero);
buzbee67bf8852011-08-17 17:51:35 -07002017 return false;
2018 }
2019 if (handleEasyDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit)) {
2020 return false;
2021 }
2022 oatFlushAllRegs(cUnit); /* Everything to home location */
2023 loadValueDirectFixed(cUnit, rlSrc, r0);
2024 oatClobber(cUnit, r0);
2025 if ((dalvikOpcode == OP_DIV_INT_LIT8) ||
2026 (dalvikOpcode == OP_DIV_INT_LIT16)) {
2027 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
2028 isDiv = true;
2029 } else {
2030 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
2031 isDiv = false;
2032 }
2033 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
2034 loadConstant(cUnit, r1, lit);
Ian Rogersff1ed472011-09-20 13:46:24 -07002035 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07002036 if (isDiv)
2037 rlResult = oatGetReturn(cUnit);
2038 else
2039 rlResult = oatGetReturnAlt(cUnit);
2040 storeValue(cUnit, rlDest, rlResult);
2041 return false;
2042 break;
2043 default:
2044 return true;
2045 }
2046 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2047 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2048 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
2049 if (shiftOp && (lit == 0)) {
2050 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2051 } else {
2052 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2053 }
2054 storeValue(cUnit, rlDest, rlResult);
2055 return false;
2056}
2057
2058/* Architectural-specific debugging helpers go here */
2059void oatArchDump(void)
2060{
2061 /* Print compiled opcode in this VM instance */
2062 int i, start, streak;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002063 std::string buf;
buzbee67bf8852011-08-17 17:51:35 -07002064
2065 streak = i = 0;
buzbee67bf8852011-08-17 17:51:35 -07002066 while (opcodeCoverage[i] == 0 && i < kNumPackedOpcodes) {
2067 i++;
2068 }
2069 if (i == kNumPackedOpcodes) {
2070 return;
2071 }
2072 for (start = i++, streak = 1; i < kNumPackedOpcodes; i++) {
2073 if (opcodeCoverage[i]) {
2074 streak++;
2075 } else {
2076 if (streak == 1) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002077 StringAppendF(&buf, "%x,", start);
buzbee67bf8852011-08-17 17:51:35 -07002078 } else {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002079 StringAppendF(&buf, "%x-%x,", start, start + streak - 1);
buzbee67bf8852011-08-17 17:51:35 -07002080 }
2081 streak = 0;
2082 while (opcodeCoverage[i] == 0 && i < kNumPackedOpcodes) {
2083 i++;
2084 }
2085 if (i < kNumPackedOpcodes) {
2086 streak = 1;
2087 start = i;
2088 }
2089 }
2090 }
2091 if (streak) {
2092 if (streak == 1) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002093 StringAppendF(&buf, "%x", start);
buzbee67bf8852011-08-17 17:51:35 -07002094 } else {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002095 StringAppendF(&buf, "%x-%x", start, start + streak - 1);
buzbee67bf8852011-08-17 17:51:35 -07002096 }
2097 }
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002098 if (!buf.empty()) {
buzbee67bf8852011-08-17 17:51:35 -07002099 LOG(INFO) << "dalvik.vm.oat.op = " << buf;
2100 }
2101}