blob: 9c4ef1ebf5296ed1df4e0a7b573e1361b0d1b416 [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))
buzbee34c77ad2012-01-11 13:01:32 -080033#define EXERCISE_RESOLVE_METHOD (cUnit->enableDebug & \
34 (1 << kDebugExerciseResolveMethod))
buzbeece302932011-10-04 14:32:18 -070035
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080036namespace art {
37
buzbeece302932011-10-04 14:32:18 -070038STATIC RegLocation getRetLoc(CompilationUnit* cUnit);
buzbee34cd9e52011-09-08 14:31:52 -070039
Elliott Hughes81bc5092011-09-30 17:25:59 -070040void warnIfUnresolved(CompilationUnit* cUnit, int fieldIdx, Field* field) {
41 if (field == NULL) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080042 const DexFile::FieldId& field_id = cUnit->dex_file->GetFieldId(fieldIdx);
Elliott Hughes95572412011-12-13 18:14:20 -080043 std::string class_name(cUnit->dex_file->GetFieldDeclaringClassDescriptor(field_id));
44 std::string field_name(cUnit->dex_file->GetFieldName(field_id));
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080045 LOG(INFO) << "Field " << PrettyDescriptor(class_name) << "." << field_name
Elliott Hughes95572412011-12-13 18:14:20 -080046 << " unresolved at compile time";
Elliott Hughes81bc5092011-09-30 17:25:59 -070047 } else {
48 // We also use the slow path for wide volatile fields.
49 }
50}
51
buzbee67bf8852011-08-17 17:51:35 -070052/*
53 * Construct an s4 from two consecutive half-words of switch data.
54 * This needs to check endianness because the DEX optimizer only swaps
55 * half-words in instruction stream.
56 *
57 * "switchData" must be 32-bit aligned.
58 */
59#if __BYTE_ORDER == __LITTLE_ENDIAN
buzbeeed3e9302011-09-23 17:34:19 -070060STATIC inline s4 s4FromSwitchData(const void* switchData) {
buzbee67bf8852011-08-17 17:51:35 -070061 return *(s4*) switchData;
62}
63#else
buzbeeed3e9302011-09-23 17:34:19 -070064STATIC inline s4 s4FromSwitchData(const void* switchData) {
buzbee67bf8852011-08-17 17:51:35 -070065 u2* data = switchData;
66 return data[0] | (((s4) data[1]) << 16);
67}
68#endif
69
buzbeeed3e9302011-09-23 17:34:19 -070070STATIC ArmLIR* callRuntimeHelper(CompilationUnit* cUnit, int reg)
buzbeeec5adf32011-09-11 15:25:43 -070071{
buzbee6181f792011-09-29 11:14:04 -070072 oatClobberCalleeSave(cUnit);
buzbeeec5adf32011-09-11 15:25:43 -070073 return opReg(cUnit, kOpBlx, reg);
74}
75
buzbee1b4c8592011-08-31 10:43:51 -070076/* Generate unconditional branch instructions */
buzbeeed3e9302011-09-23 17:34:19 -070077STATIC ArmLIR* genUnconditionalBranch(CompilationUnit* cUnit, ArmLIR* target)
buzbee1b4c8592011-08-31 10:43:51 -070078{
79 ArmLIR* branch = opNone(cUnit, kOpUncondBr);
80 branch->generic.target = (LIR*) target;
81 return branch;
82}
83
buzbee67bf8852011-08-17 17:51:35 -070084/*
85 * Generate a Thumb2 IT instruction, which can nullify up to
86 * four subsequent instructions based on a condition and its
87 * inverse. The condition applies to the first instruction, which
88 * is executed if the condition is met. The string "guide" consists
89 * of 0 to 3 chars, and applies to the 2nd through 4th instruction.
90 * A "T" means the instruction is executed if the condition is
91 * met, and an "E" means the instruction is executed if the condition
92 * is not met.
93 */
buzbeeed3e9302011-09-23 17:34:19 -070094STATIC ArmLIR* genIT(CompilationUnit* cUnit, ArmConditionCode code,
buzbee67bf8852011-08-17 17:51:35 -070095 const char* guide)
96{
97 int mask;
98 int condBit = code & 1;
99 int altBit = condBit ^ 1;
100 int mask3 = 0;
101 int mask2 = 0;
102 int mask1 = 0;
103
104 //Note: case fallthroughs intentional
105 switch(strlen(guide)) {
106 case 3:
107 mask1 = (guide[2] == 'T') ? condBit : altBit;
108 case 2:
109 mask2 = (guide[1] == 'T') ? condBit : altBit;
110 case 1:
111 mask3 = (guide[0] == 'T') ? condBit : altBit;
112 break;
113 case 0:
114 break;
115 default:
116 LOG(FATAL) << "OAT: bad case in genIT";
117 }
118 mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
119 (1 << (3 - strlen(guide)));
120 return newLIR2(cUnit, kThumb2It, code, mask);
121}
122
123/*
124 * Insert a kArmPseudoCaseLabel at the beginning of the Dalvik
125 * offset vaddr. This label will be used to fix up the case
126 * branch table during the assembly phase. Be sure to set
127 * all resource flags on this to prevent code motion across
128 * target boundaries. KeyVal is just there for debugging.
129 */
buzbeeed3e9302011-09-23 17:34:19 -0700130STATIC ArmLIR* insertCaseLabel(CompilationUnit* cUnit, int vaddr, int keyVal)
buzbee67bf8852011-08-17 17:51:35 -0700131{
132 ArmLIR* lir;
133 for (lir = (ArmLIR*)cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
134 if ((lir->opcode == kArmPseudoDalvikByteCodeBoundary) &&
135 (lir->generic.dalvikOffset == vaddr)) {
136 ArmLIR* newLabel = (ArmLIR*)oatNew(sizeof(ArmLIR), true);
137 newLabel->generic.dalvikOffset = vaddr;
138 newLabel->opcode = kArmPseudoCaseLabel;
139 newLabel->operands[0] = keyVal;
140 oatInsertLIRAfter((LIR*)lir, (LIR*)newLabel);
141 return newLabel;
142 }
143 }
144 oatCodegenDump(cUnit);
145 LOG(FATAL) << "Error: didn't find vaddr 0x" << std::hex << vaddr;
146 return NULL; // Quiet gcc
147}
148
buzbeeed3e9302011-09-23 17:34:19 -0700149STATIC void markPackedCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
buzbee67bf8852011-08-17 17:51:35 -0700150{
151 const u2* table = tabRec->table;
152 int baseVaddr = tabRec->vaddr;
153 int *targets = (int*)&table[4];
154 int entries = table[1];
155 int lowKey = s4FromSwitchData(&table[2]);
156 for (int i = 0; i < entries; i++) {
157 tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
158 i + lowKey);
159 }
160}
161
buzbeeed3e9302011-09-23 17:34:19 -0700162STATIC void markSparseCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
buzbee67bf8852011-08-17 17:51:35 -0700163{
164 const u2* table = tabRec->table;
165 int baseVaddr = tabRec->vaddr;
166 int entries = table[1];
167 int* keys = (int*)&table[2];
168 int* targets = &keys[entries];
169 for (int i = 0; i < entries; i++) {
170 tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
171 keys[i]);
172 }
173}
174
175void oatProcessSwitchTables(CompilationUnit* cUnit)
176{
177 GrowableListIterator iterator;
178 oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
179 while (true) {
180 SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
181 &iterator);
182 if (tabRec == NULL) break;
183 if (tabRec->table[0] == kPackedSwitchSignature)
184 markPackedCaseLabels(cUnit, tabRec);
185 else if (tabRec->table[0] == kSparseSwitchSignature)
186 markSparseCaseLabels(cUnit, tabRec);
187 else {
188 LOG(FATAL) << "Invalid switch table";
189 }
190 }
191}
192
buzbeeed3e9302011-09-23 17:34:19 -0700193STATIC void dumpSparseSwitchTable(const u2* table)
buzbee67bf8852011-08-17 17:51:35 -0700194 /*
195 * Sparse switch data format:
196 * ushort ident = 0x0200 magic value
197 * ushort size number of entries in the table; > 0
198 * int keys[size] keys, sorted low-to-high; 32-bit aligned
199 * int targets[size] branch targets, relative to switch opcode
200 *
201 * Total size is (2+size*4) 16-bit code units.
202 */
203{
204 u2 ident = table[0];
205 int entries = table[1];
206 int* keys = (int*)&table[2];
207 int* targets = &keys[entries];
208 LOG(INFO) << "Sparse switch table - ident:0x" << std::hex << ident <<
209 ", entries: " << std::dec << entries;
210 for (int i = 0; i < entries; i++) {
211 LOG(INFO) << " Key[" << keys[i] << "] -> 0x" << std::hex <<
212 targets[i];
213 }
214}
215
buzbeeed3e9302011-09-23 17:34:19 -0700216STATIC void dumpPackedSwitchTable(const u2* table)
buzbee67bf8852011-08-17 17:51:35 -0700217 /*
218 * Packed switch data format:
219 * ushort ident = 0x0100 magic value
220 * ushort size number of entries in the table
221 * int first_key first (and lowest) switch case value
222 * int targets[size] branch targets, relative to switch opcode
223 *
224 * Total size is (4+size*2) 16-bit code units.
225 */
226{
227 u2 ident = table[0];
228 int* targets = (int*)&table[4];
229 int entries = table[1];
230 int lowKey = s4FromSwitchData(&table[2]);
231 LOG(INFO) << "Packed switch table - ident:0x" << std::hex << ident <<
232 ", entries: " << std::dec << entries << ", lowKey: " << lowKey;
233 for (int i = 0; i < entries; i++) {
234 LOG(INFO) << " Key[" << (i + lowKey) << "] -> 0x" << std::hex <<
235 targets[i];
236 }
237}
238
239/*
240 * The sparse table in the literal pool is an array of <key,displacement>
241 * pairs. For each set, we'll load them as a pair using ldmia.
242 * This means that the register number of the temp we use for the key
243 * must be lower than the reg for the displacement.
244 *
245 * The test loop will look something like:
246 *
247 * adr rBase, <table>
248 * ldr rVal, [rSP, vRegOff]
249 * mov rIdx, #tableSize
250 * lp:
251 * ldmia rBase!, {rKey, rDisp}
252 * sub rIdx, #1
253 * cmp rVal, rKey
254 * ifeq
255 * add rPC, rDisp ; This is the branch from which we compute displacement
256 * cbnz rIdx, lp
257 */
buzbeeed3e9302011-09-23 17:34:19 -0700258STATIC void genSparseSwitch(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700259 RegLocation rlSrc)
260{
261 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
262 if (cUnit->printMe) {
263 dumpSparseSwitchTable(table);
264 }
265 // Add the table to the list - we'll process it later
266 SwitchTable *tabRec = (SwitchTable *)oatNew(sizeof(SwitchTable),
267 true);
268 tabRec->table = table;
269 tabRec->vaddr = mir->offset;
270 int size = table[1];
271 tabRec->targets = (ArmLIR* *)oatNew(size * sizeof(ArmLIR*), true);
272 oatInsertGrowableList(&cUnit->switchTables, (intptr_t)tabRec);
273
274 // Get the switch value
275 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
276 int rBase = oatAllocTemp(cUnit);
277 /* Allocate key and disp temps */
278 int rKey = oatAllocTemp(cUnit);
279 int rDisp = oatAllocTemp(cUnit);
280 // Make sure rKey's register number is less than rDisp's number for ldmia
281 if (rKey > rDisp) {
282 int tmp = rDisp;
283 rDisp = rKey;
284 rKey = tmp;
285 }
286 // Materialize a pointer to the switch table
buzbee03fa2632011-09-20 17:10:57 -0700287 newLIR3(cUnit, kThumb2Adr, rBase, 0, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700288 // Set up rIdx
289 int rIdx = oatAllocTemp(cUnit);
290 loadConstant(cUnit, rIdx, size);
291 // Establish loop branch target
292 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
293 target->defMask = ENCODE_ALL;
294 // Load next key/disp
295 newLIR2(cUnit, kThumb2LdmiaWB, rBase, (1 << rKey) | (1 << rDisp));
296 opRegReg(cUnit, kOpCmp, rKey, rlSrc.lowReg);
297 // Go if match. NOTE: No instruction set switch here - must stay Thumb2
298 genIT(cUnit, kArmCondEq, "");
299 ArmLIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, rDisp);
300 tabRec->bxInst = switchBranch;
301 // Needs to use setflags encoding here
302 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
303 ArmLIR* branch = opCondBranch(cUnit, kArmCondNe);
304 branch->generic.target = (LIR*)target;
305}
306
307
buzbeeed3e9302011-09-23 17:34:19 -0700308STATIC void genPackedSwitch(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700309 RegLocation rlSrc)
310{
311 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
312 if (cUnit->printMe) {
313 dumpPackedSwitchTable(table);
314 }
315 // Add the table to the list - we'll process it later
316 SwitchTable *tabRec = (SwitchTable *)oatNew(sizeof(SwitchTable),
317 true);
318 tabRec->table = table;
319 tabRec->vaddr = mir->offset;
320 int size = table[1];
321 tabRec->targets = (ArmLIR* *)oatNew(size * sizeof(ArmLIR*), true);
322 oatInsertGrowableList(&cUnit->switchTables, (intptr_t)tabRec);
323
324 // Get the switch value
325 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
326 int tableBase = oatAllocTemp(cUnit);
327 // Materialize a pointer to the switch table
buzbee03fa2632011-09-20 17:10:57 -0700328 newLIR3(cUnit, kThumb2Adr, tableBase, 0, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700329 int lowKey = s4FromSwitchData(&table[2]);
330 int keyReg;
331 // Remove the bias, if necessary
332 if (lowKey == 0) {
333 keyReg = rlSrc.lowReg;
334 } else {
335 keyReg = oatAllocTemp(cUnit);
336 opRegRegImm(cUnit, kOpSub, keyReg, rlSrc.lowReg, lowKey);
337 }
338 // Bounds check - if < 0 or >= size continue following switch
339 opRegImm(cUnit, kOpCmp, keyReg, size-1);
340 ArmLIR* branchOver = opCondBranch(cUnit, kArmCondHi);
341
342 // Load the displacement from the switch table
343 int dispReg = oatAllocTemp(cUnit);
344 loadBaseIndexed(cUnit, tableBase, keyReg, dispReg, 2, kWord);
345
346 // ..and go! NOTE: No instruction set switch here - must stay Thumb2
347 ArmLIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, dispReg);
348 tabRec->bxInst = switchBranch;
349
350 /* branchOver target here */
351 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
352 target->defMask = ENCODE_ALL;
353 branchOver->generic.target = (LIR*)target;
354}
355
356/*
357 * Array data table format:
358 * ushort ident = 0x0300 magic value
359 * ushort width width of each element in the table
360 * uint size number of elements in the table
361 * ubyte data[size*width] table of data values (may contain a single-byte
362 * padding at the end)
363 *
364 * Total size is 4+(width * size + 1)/2 16-bit code units.
365 */
buzbeeed3e9302011-09-23 17:34:19 -0700366STATIC void genFillArrayData(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700367 RegLocation rlSrc)
368{
369 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
370 // Add the table to the list - we'll process it later
371 FillArrayData *tabRec = (FillArrayData *)
372 oatNew(sizeof(FillArrayData), true);
373 tabRec->table = table;
374 tabRec->vaddr = mir->offset;
375 u2 width = tabRec->table[1];
376 u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
377 tabRec->size = (size * width) + 8;
378
379 oatInsertGrowableList(&cUnit->fillArrayData, (intptr_t)tabRec);
380
381 // Making a call - use explicit registers
382 oatFlushAllRegs(cUnit); /* Everything to home location */
383 loadValueDirectFixed(cUnit, rlSrc, r0);
384 loadWordDisp(cUnit, rSELF,
buzbee1b4c8592011-08-31 10:43:51 -0700385 OFFSETOF_MEMBER(Thread, pHandleFillArrayDataFromCode), rLR);
buzbeee6d61962011-08-27 11:58:19 -0700386 // Materialize a pointer to the fill data image
buzbee03fa2632011-09-20 17:10:57 -0700387 newLIR3(cUnit, kThumb2Adr, r1, 0, (intptr_t)tabRec);
Ian Rogersff1ed472011-09-20 13:46:24 -0700388 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700389}
390
391/*
392 * Mark garbage collection card. Skip if the value we're storing is null.
393 */
buzbeeed3e9302011-09-23 17:34:19 -0700394STATIC void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg)
buzbee67bf8852011-08-17 17:51:35 -0700395{
396 int regCardBase = oatAllocTemp(cUnit);
397 int regCardNo = oatAllocTemp(cUnit);
398 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondEq, valReg, 0);
buzbeec143c552011-08-20 17:38:58 -0700399 loadWordDisp(cUnit, rSELF, Thread::CardTableOffset().Int32Value(),
buzbee67bf8852011-08-17 17:51:35 -0700400 regCardBase);
401 opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT);
402 storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
403 kUnsignedByte);
404 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
405 target->defMask = ENCODE_ALL;
406 branchOver->generic.target = (LIR*)target;
407 oatFreeTemp(cUnit, regCardBase);
408 oatFreeTemp(cUnit, regCardNo);
409}
410
buzbee34cd9e52011-09-08 14:31:52 -0700411/*
412 * Helper function for Iget/put when field not resolved at compile time.
413 * Will trash call temps and return with the field offset in r0.
414 */
Elliott Hughes81bc5092011-09-30 17:25:59 -0700415STATIC void getFieldOffset(CompilationUnit* cUnit, MIR* mir, Field* fieldPtr)
buzbee34cd9e52011-09-08 14:31:52 -0700416{
417 int fieldIdx = mir->dalvikInsn.vC;
buzbee6181f792011-09-29 11:14:04 -0700418 oatFlushAllRegs(cUnit);
Elliott Hughes81bc5092011-09-30 17:25:59 -0700419 warnIfUnresolved(cUnit, fieldIdx, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700420 oatLockCallTemps(cUnit); // Explicit register usage
421 loadCurrMethodDirect(cUnit, r1); // arg1 <= Method*
422 loadWordDisp(cUnit, r1,
423 Method::DexCacheResolvedFieldsOffset().Int32Value(), r0);
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800424 loadWordDisp(cUnit, r0, Array::DataOffset().Int32Value() +
buzbee34cd9e52011-09-08 14:31:52 -0700425 sizeof(int32_t*)* fieldIdx, r0);
426 /*
427 * For testing, omit the test for run-time resolution. This will
428 * force all accesses to go through the runtime resolution path.
429 */
buzbeece302932011-10-04 14:32:18 -0700430 ArmLIR* branchOver = NULL;
431 if (!EXERCISE_SLOWEST_FIELD_PATH) {
432 branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0);
433 }
buzbee34cd9e52011-09-08 14:31:52 -0700434 // Resolve
435 loadWordDisp(cUnit, rSELF,
Brian Carlstrom845490b2011-09-19 15:56:53 -0700436 OFFSETOF_MEMBER(Thread, pFindInstanceFieldFromCode), rLR);
buzbee34cd9e52011-09-08 14:31:52 -0700437 loadConstant(cUnit, r0, fieldIdx);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700438 callRuntimeHelper(cUnit, rLR); // FindInstanceFieldFromCoderesolveTypeFromCode(idx, method)
buzbee34cd9e52011-09-08 14:31:52 -0700439 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
440 target->defMask = ENCODE_ALL;
buzbeece302932011-10-04 14:32:18 -0700441 if (!EXERCISE_SLOWEST_FIELD_PATH) {
442 branchOver->generic.target = (LIR*)target;
443 }
buzbee34cd9e52011-09-08 14:31:52 -0700444 // Free temps (except for r0)
445 oatFreeTemp(cUnit, r1);
446 oatFreeTemp(cUnit, r2);
447 oatFreeTemp(cUnit, r3);
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800448 loadWordDisp(cUnit, r0, Field::OffsetOffset().Int32Value(), r0);
buzbee34cd9e52011-09-08 14:31:52 -0700449}
450
buzbeeed3e9302011-09-23 17:34:19 -0700451STATIC void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -0700452 RegLocation rlDest, RegLocation rlObj)
453{
Ian Rogersa3760aa2011-11-14 14:32:37 -0800454 Field* fieldPtr = cUnit->dex_cache->GetResolvedField(mir->dalvikInsn.vC);
buzbee67bf8852011-08-17 17:51:35 -0700455 RegLocation rlResult;
456 RegisterClass regClass = oatRegClassBySize(size);
buzbee34cd9e52011-09-08 14:31:52 -0700457 if (SLOW_FIELD_PATH || fieldPtr == NULL) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700458 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700459 // Field offset in r0
460 rlObj = loadValue(cUnit, rlObj, kCoreReg);
461 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
buzbee5ade1d22011-09-09 14:44:52 -0700462 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
buzbee58f92742011-10-01 11:22:17 -0700463 loadBaseIndexed(cUnit, rlObj.lowReg, r0, rlResult.lowReg, 0, kWord);
buzbee67bf8852011-08-17 17:51:35 -0700464 oatGenMemBarrier(cUnit, kSY);
buzbee34cd9e52011-09-08 14:31:52 -0700465 storeValue(cUnit, rlDest, rlResult);
466 } else {
467#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700468 bool isVolatile = fieldPtr->IsVolatile();
buzbee34cd9e52011-09-08 14:31:52 -0700469#else
470 bool isVolatile = false;
471#endif
472 int fieldOffset = fieldPtr->GetOffset().Int32Value();
473 rlObj = loadValue(cUnit, rlObj, kCoreReg);
474 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
buzbee5ade1d22011-09-09 14:44:52 -0700475 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
buzbee34cd9e52011-09-08 14:31:52 -0700476 loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
buzbee58f92742011-10-01 11:22:17 -0700477 kWord, rlObj.sRegLow);
buzbee34cd9e52011-09-08 14:31:52 -0700478 if (isVolatile) {
479 oatGenMemBarrier(cUnit, kSY);
480 }
481 storeValue(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -0700482 }
buzbee67bf8852011-08-17 17:51:35 -0700483}
484
buzbeeed3e9302011-09-23 17:34:19 -0700485STATIC void genIPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -0700486 RegLocation rlSrc, RegLocation rlObj, bool isObject)
487{
Ian Rogersa3760aa2011-11-14 14:32:37 -0800488 Field* fieldPtr = cUnit->dex_cache->GetResolvedField(mir->dalvikInsn.vC);
buzbee67bf8852011-08-17 17:51:35 -0700489 RegisterClass regClass = oatRegClassBySize(size);
buzbee34cd9e52011-09-08 14:31:52 -0700490 if (SLOW_FIELD_PATH || fieldPtr == NULL) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700491 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700492 // Field offset in r0
493 rlObj = loadValue(cUnit, rlObj, kCoreReg);
494 rlSrc = loadValue(cUnit, rlSrc, regClass);
buzbee5ade1d22011-09-09 14:44:52 -0700495 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
buzbee67bf8852011-08-17 17:51:35 -0700496 oatGenMemBarrier(cUnit, kSY);
buzbee58f92742011-10-01 11:22:17 -0700497 storeBaseIndexed(cUnit, rlObj.lowReg, r0, rlSrc.lowReg, 0, kWord);
buzbee34cd9e52011-09-08 14:31:52 -0700498 } else {
499#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700500 bool isVolatile = fieldPtr->IsVolatile();
buzbee34cd9e52011-09-08 14:31:52 -0700501#else
502 bool isVolatile = false;
503#endif
504 int fieldOffset = fieldPtr->GetOffset().Int32Value();
505 rlObj = loadValue(cUnit, rlObj, kCoreReg);
506 rlSrc = loadValue(cUnit, rlSrc, regClass);
buzbee5ade1d22011-09-09 14:44:52 -0700507 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700508
509 if (isVolatile) {
buzbee12246b82011-09-29 14:15:05 -0700510 oatGenMemBarrier(cUnit, kST);
buzbee34cd9e52011-09-08 14:31:52 -0700511 }
buzbee58f92742011-10-01 11:22:17 -0700512 storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, kWord);
buzbee12246b82011-09-29 14:15:05 -0700513 if (isVolatile) {
514 oatGenMemBarrier(cUnit, kSY);
515 }
buzbee67bf8852011-08-17 17:51:35 -0700516 }
buzbee67bf8852011-08-17 17:51:35 -0700517 if (isObject) {
518 /* NOTE: marking card based on object head */
519 markGCCard(cUnit, rlSrc.lowReg, rlObj.lowReg);
520 }
521}
522
buzbeeed3e9302011-09-23 17:34:19 -0700523STATIC void genIGetWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700524 RegLocation rlObj)
525{
buzbee12246b82011-09-29 14:15:05 -0700526 RegLocation rlResult;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800527 Field* fieldPtr = cUnit->dex_cache->GetResolvedField(mir->dalvikInsn.vC);
buzbee12246b82011-09-29 14:15:05 -0700528#if ANDROID_SMP != 0
529 bool isVolatile = (fieldPtr == NULL) || fieldPtr->IsVolatile();
530#else
531 bool isVolatile = false;
532#endif
buzbeece302932011-10-04 14:32:18 -0700533 if (SLOW_FIELD_PATH || (fieldPtr == NULL) || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700534 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700535 // Field offset in r0
536 rlObj = loadValue(cUnit, rlObj, kCoreReg);
537 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee5ade1d22011-09-09 14:44:52 -0700538 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700539 opRegReg(cUnit, kOpAdd, r0, rlObj.lowReg);
540 loadPair(cUnit, r0, rlResult.lowReg, rlResult.highReg);
buzbee67bf8852011-08-17 17:51:35 -0700541 oatGenMemBarrier(cUnit, kSY);
buzbee12246b82011-09-29 14:15:05 -0700542 storeValueWide(cUnit, rlDest, rlResult);
buzbee34cd9e52011-09-08 14:31:52 -0700543 } else {
buzbee34cd9e52011-09-08 14:31:52 -0700544 int fieldOffset = fieldPtr->GetOffset().Int32Value();
545 rlObj = loadValue(cUnit, rlObj, kCoreReg);
546 int regPtr = oatAllocTemp(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700547
buzbeeed3e9302011-09-23 17:34:19 -0700548 DCHECK(rlDest.wide);
buzbee34cd9e52011-09-08 14:31:52 -0700549
buzbee5ade1d22011-09-09 14:44:52 -0700550 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700551 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
552 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
553
554 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
555
buzbee34cd9e52011-09-08 14:31:52 -0700556 oatFreeTemp(cUnit, regPtr);
557 storeValueWide(cUnit, rlDest, rlResult);
558 }
buzbee67bf8852011-08-17 17:51:35 -0700559}
560
buzbeeed3e9302011-09-23 17:34:19 -0700561STATIC void genIPutWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
buzbee67bf8852011-08-17 17:51:35 -0700562 RegLocation rlObj)
563{
Ian Rogersa3760aa2011-11-14 14:32:37 -0800564 Field* fieldPtr = cUnit->dex_cache->GetResolvedField(mir->dalvikInsn.vC);
buzbee12246b82011-09-29 14:15:05 -0700565#if ANDROID_SMP != 0
566 bool isVolatile = (fieldPtr == NULL) || fieldPtr->IsVolatile();
567#else
568 bool isVolatile = false;
569#endif
buzbeece302932011-10-04 14:32:18 -0700570 if (SLOW_FIELD_PATH || (fieldPtr == NULL) || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700571 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700572 // Field offset in r0
573 rlObj = loadValue(cUnit, rlObj, kCoreReg);
574 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
buzbee5ade1d22011-09-09 14:44:52 -0700575 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700576 opRegReg(cUnit, kOpAdd, r0, rlObj.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700577 oatGenMemBarrier(cUnit, kSY);
buzbee34cd9e52011-09-08 14:31:52 -0700578 storePair(cUnit, r0, rlSrc.lowReg, rlSrc.highReg);
579 } else {
buzbee34cd9e52011-09-08 14:31:52 -0700580 int fieldOffset = fieldPtr->GetOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -0700581
buzbee34cd9e52011-09-08 14:31:52 -0700582 rlObj = loadValue(cUnit, rlObj, kCoreReg);
583 int regPtr;
584 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
buzbee5ade1d22011-09-09 14:44:52 -0700585 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700586 regPtr = oatAllocTemp(cUnit);
587 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
588
buzbee34cd9e52011-09-08 14:31:52 -0700589 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
590
591 oatFreeTemp(cUnit, regPtr);
592 }
buzbee67bf8852011-08-17 17:51:35 -0700593}
594
buzbeeed3e9302011-09-23 17:34:19 -0700595STATIC void genConstClass(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700596 RegLocation rlDest, RegLocation rlSrc)
597{
Ian Rogers28ad40d2011-10-27 15:19:26 -0700598 uint32_t type_idx = mir->dalvikInsn.vB;
buzbee1b4c8592011-08-31 10:43:51 -0700599 int mReg = loadCurrMethod(cUnit);
600 int resReg = oatAllocTemp(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700601 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
Ian Rogersa3760aa2011-11-14 14:32:37 -0800602 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
603 cUnit->dex_cache,
604 *cUnit->dex_file,
605 type_idx)) {
606 // Call out to helper which resolves type and verifies access.
607 // Resolved type returned in r0.
608 loadWordDisp(cUnit, rSELF,
609 OFFSETOF_MEMBER(Thread, pInitializeTypeAndVerifyAccessFromCode),
610 rLR);
611 genRegCopy(cUnit, r1, mReg);
612 loadConstant(cUnit, r0, type_idx);
613 callRuntimeHelper(cUnit, rLR);
614 RegLocation rlResult = oatGetReturn(cUnit);
615 storeValue(cUnit, rlDest, rlResult);
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);
Ian Rogersa3760aa2011-11-14 14:32:37 -0800622 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->dex_cache,
623 type_idx) ||
Ian Rogers28ad40d2011-10-27 15:19:26 -0700624 SLOW_TYPE_PATH) {
625 // Slow path, at runtime test if the type is null and if so initialize
626 oatFlushAllRegs(cUnit);
627 ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, rlResult.lowReg, 0);
628 // Resolved, store and hop over following code
629 storeValue(cUnit, rlDest, rlResult);
630 ArmLIR* branch2 = genUnconditionalBranch(cUnit,0);
631 // TUNING: move slow path to end & remove unconditional branch
632 ArmLIR* target1 = newLIR0(cUnit, kArmPseudoTargetLabel);
633 target1->defMask = ENCODE_ALL;
634 // Call out to helper, which will return resolved type in r0
635 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
636 genRegCopy(cUnit, r1, mReg);
637 loadConstant(cUnit, r0, type_idx);
638 callRuntimeHelper(cUnit, rLR);
639 RegLocation rlResult = oatGetReturn(cUnit);
640 storeValue(cUnit, rlDest, rlResult);
641 // Rejoin code paths
642 ArmLIR* target2 = newLIR0(cUnit, kArmPseudoTargetLabel);
643 target2->defMask = ENCODE_ALL;
644 branch1->generic.target = (LIR*)target1;
645 branch2->generic.target = (LIR*)target2;
646 } else {
647 // Fast path, we're done - just store result
648 storeValue(cUnit, rlDest, rlResult);
649 }
buzbee1b4c8592011-08-31 10:43:51 -0700650 }
buzbee67bf8852011-08-17 17:51:35 -0700651}
652
buzbeeed3e9302011-09-23 17:34:19 -0700653STATIC void genConstString(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700654 RegLocation rlDest, RegLocation rlSrc)
655{
buzbeece302932011-10-04 14:32:18 -0700656 /* NOTE: Most strings should be available at compile time */
Ian Rogers28ad40d2011-10-27 15:19:26 -0700657 uint32_t string_idx = mir->dalvikInsn.vB;
658 int32_t offset_of_string = Array::DataOffset().Int32Value() + (sizeof(String*) * string_idx);
Ian Rogersa3760aa2011-11-14 14:32:37 -0800659 if (!cUnit->compiler->CanAssumeStringIsPresentInDexCache(cUnit->dex_cache, string_idx) ||
Ian Rogers28ad40d2011-10-27 15:19:26 -0700660 SLOW_STRING_PATH) {
661 // slow path, resolve string if not in dex cache
buzbeece302932011-10-04 14:32:18 -0700662 oatFlushAllRegs(cUnit);
663 oatLockCallTemps(cUnit); // Using explicit registers
664 loadCurrMethodDirect(cUnit, r2);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700665 loadWordDisp(cUnit, r2, Method::DexCacheStringsOffset().Int32Value(), r0);
buzbeece302932011-10-04 14:32:18 -0700666 // Might call out to helper, which will return resolved string in r0
Ian Rogers28ad40d2011-10-27 15:19:26 -0700667 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pResolveStringFromCode), rLR);
668 loadWordDisp(cUnit, r0, offset_of_string, r0);
669 loadConstant(cUnit, r1, string_idx);
buzbeece302932011-10-04 14:32:18 -0700670 opRegImm(cUnit, kOpCmp, r0, 0); // Is resolved?
671 genBarrier(cUnit);
672 // For testing, always force through helper
673 if (!EXERCISE_SLOWEST_STRING_PATH) {
674 genIT(cUnit, kArmCondEq, "T");
675 }
676 genRegCopy(cUnit, r0, r2); // .eq
677 opReg(cUnit, kOpBlx, rLR); // .eq, helper(Method*, string_idx)
678 genBarrier(cUnit);
679 storeValue(cUnit, rlDest, getRetLoc(cUnit));
680 } else {
681 int mReg = loadCurrMethod(cUnit);
682 int resReg = oatAllocTemp(cUnit);
683 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700684 loadWordDisp(cUnit, mReg, Method::DexCacheStringsOffset().Int32Value(), resReg);
685 loadWordDisp(cUnit, resReg, offset_of_string, rlResult.lowReg);
buzbeece302932011-10-04 14:32:18 -0700686 storeValue(cUnit, rlDest, rlResult);
687 }
buzbee67bf8852011-08-17 17:51:35 -0700688}
689
buzbeedfd3d702011-08-28 12:56:51 -0700690/*
691 * Let helper function take care of everything. Will
692 * call Class::NewInstanceFromCode(type_idx, method);
693 */
buzbeeed3e9302011-09-23 17:34:19 -0700694STATIC void genNewInstance(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700695 RegLocation rlDest)
696{
buzbeedfd3d702011-08-28 12:56:51 -0700697 oatFlushAllRegs(cUnit); /* Everything to home location */
Ian Rogers28ad40d2011-10-27 15:19:26 -0700698 uint32_t type_idx = mir->dalvikInsn.vB;
699 // alloc will always check for resolution, do we also need to verify access because the
700 // verifier was unable to?
Ian Rogersa3760aa2011-11-14 14:32:37 -0800701 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
702 cUnit->dex_cache,
703 *cUnit->dex_file,
704 type_idx)) {
Ian Rogers28ad40d2011-10-27 15:19:26 -0700705 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pAllocObjectFromCode), rLR);
706 } else {
707 loadWordDisp(cUnit, rSELF,
708 OFFSETOF_MEMBER(Thread, pAllocObjectFromCodeWithAccessCheck), rLR);
709 }
710 loadCurrMethodDirect(cUnit, r1); // arg1 <= Method*
711 loadConstant(cUnit, r0, type_idx); // arg0 <- type_idx
Ian Rogersff1ed472011-09-20 13:46:24 -0700712 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700713 RegLocation rlResult = oatGetReturn(cUnit);
714 storeValue(cUnit, rlDest, rlResult);
715}
716
717void genThrow(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
718{
buzbee6181f792011-09-29 11:14:04 -0700719 oatFlushAllRegs(cUnit);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700720 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pDeliverException), rLR);
Ian Rogersbdb03912011-09-14 00:55:44 -0700721 loadValueDirectFixed(cUnit, rlSrc, r0); // Get exception object
Ian Rogersff1ed472011-09-20 13:46:24 -0700722 callRuntimeHelper(cUnit, rLR); // art_deliver_exception(exception);
buzbee67bf8852011-08-17 17:51:35 -0700723}
724
buzbeeed3e9302011-09-23 17:34:19 -0700725STATIC void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700726 RegLocation rlSrc)
727{
buzbee6181f792011-09-29 11:14:04 -0700728 oatFlushAllRegs(cUnit);
buzbee2a475e72011-09-07 17:19:17 -0700729 // May generate a call - use explicit registers
730 oatLockCallTemps(cUnit);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700731 uint32_t type_idx = mir->dalvikInsn.vC;
buzbee2a475e72011-09-07 17:19:17 -0700732 loadCurrMethodDirect(cUnit, r1); // r1 <= current Method*
Ian Rogers28ad40d2011-10-27 15:19:26 -0700733 int classReg = r2; // r2 will hold the Class*
Ian Rogersa3760aa2011-11-14 14:32:37 -0800734 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
735 cUnit->dex_cache,
736 *cUnit->dex_file,
737 type_idx)) {
Ian Rogersb093c6b2011-10-31 16:19:55 -0700738 // Check we have access to type_idx and if not throw IllegalAccessError,
739 // returns Class* in r0
740 loadWordDisp(cUnit, rSELF,
741 OFFSETOF_MEMBER(Thread, pInitializeTypeAndVerifyAccessFromCode),
742 rLR);
743 loadConstant(cUnit, r0, type_idx);
744 callRuntimeHelper(cUnit, rLR); // InitializeTypeAndVerifyAccess(idx, method)
745 genRegCopy(cUnit, classReg, r0); // Align usage with fast path
Ian Rogers6a996782011-10-31 17:06:39 -0700746 loadValueDirectFixed(cUnit, rlSrc, r0); // r0 <= ref
Ian Rogers28ad40d2011-10-27 15:19:26 -0700747 } else {
748 // Load dex cache entry into classReg (r2)
Ian Rogers6a996782011-10-31 17:06:39 -0700749 loadValueDirectFixed(cUnit, rlSrc, r0); // r0 <= ref
Ian Rogers28ad40d2011-10-27 15:19:26 -0700750 loadWordDisp(cUnit, r1, Method::DexCacheResolvedTypesOffset().Int32Value(), classReg);
751 int32_t offset_of_type = Array::DataOffset().Int32Value() + (sizeof(Class*) * type_idx);
752 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
Ian Rogersa3760aa2011-11-14 14:32:37 -0800753 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->dex_cache, type_idx)) {
Ian Rogers28ad40d2011-10-27 15:19:26 -0700754 // Need to test presence of type in dex cache at runtime
755 ArmLIR* hopBranch = genCmpImmBranch(cUnit, kArmCondNe, classReg, 0);
756 // Not resolved
757 // Call out to helper, which will return resolved type in r0
758 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
759 loadConstant(cUnit, r0, type_idx);
Ian Rogersb093c6b2011-10-31 16:19:55 -0700760 callRuntimeHelper(cUnit, rLR); // InitializeTypeFromCode(idx, method)
Ian Rogers28ad40d2011-10-27 15:19:26 -0700761 genRegCopy(cUnit, r2, r0); // Align usage with fast path
762 loadValueDirectFixed(cUnit, rlSrc, r0); /* reload Ref */
763 // Rejoin code paths
764 ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
765 hopTarget->defMask = ENCODE_ALL;
766 hopBranch->generic.target = (LIR*)hopTarget;
767 }
buzbee67bf8852011-08-17 17:51:35 -0700768 }
buzbee991e3ac2011-09-29 15:44:22 -0700769 /* r0 is ref, r2 is class. If ref==null, use directly as bool result */
770 ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, r0, 0);
buzbee2a475e72011-09-07 17:19:17 -0700771 /* load object->clazz */
buzbeeed3e9302011-09-23 17:34:19 -0700772 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
buzbee991e3ac2011-09-29 15:44:22 -0700773 loadWordDisp(cUnit, r0, Object::ClassOffset().Int32Value(), r1);
774 /* r0 is ref, r1 is ref->clazz, r2 is class */
Ian Rogers28ad40d2011-10-27 15:19:26 -0700775 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInstanceofNonTrivialFromCode), rLR);
buzbee991e3ac2011-09-29 15:44:22 -0700776 opRegReg(cUnit, kOpCmp, r1, r2); // Same?
777 genBarrier(cUnit);
778 genIT(cUnit, kArmCondEq, "EE"); // if-convert the test
779 loadConstant(cUnit, r0, 1); // .eq case - load true
780 genRegCopy(cUnit, r0, r2); // .ne case - arg0 <= class
781 opReg(cUnit, kOpBlx, rLR); // .ne case: helper(class, ref->class)
782 genBarrier(cUnit);
783 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700784 /* branch target here */
785 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
786 target->defMask = ENCODE_ALL;
buzbee2a475e72011-09-07 17:19:17 -0700787 RegLocation rlResult = oatGetReturn(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700788 storeValue(cUnit, rlDest, rlResult);
789 branch1->generic.target = (LIR*)target;
buzbee67bf8852011-08-17 17:51:35 -0700790}
791
buzbeeed3e9302011-09-23 17:34:19 -0700792STATIC void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700793{
buzbee6181f792011-09-29 11:14:04 -0700794 oatFlushAllRegs(cUnit);
buzbee2a475e72011-09-07 17:19:17 -0700795 // May generate a call - use explicit registers
796 oatLockCallTemps(cUnit);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700797 uint32_t type_idx = mir->dalvikInsn.vB;
buzbee2a475e72011-09-07 17:19:17 -0700798 loadCurrMethodDirect(cUnit, r1); // r1 <= current Method*
Ian Rogers28ad40d2011-10-27 15:19:26 -0700799 int classReg = r2; // r2 will hold the Class*
Ian Rogersa3760aa2011-11-14 14:32:37 -0800800 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
801 cUnit->dex_cache,
802 *cUnit->dex_file,
803 type_idx)) {
Ian Rogersb093c6b2011-10-31 16:19:55 -0700804 // Check we have access to type_idx and if not throw IllegalAccessError,
805 // returns Class* in r0
806 loadWordDisp(cUnit, rSELF,
807 OFFSETOF_MEMBER(Thread, pInitializeTypeAndVerifyAccessFromCode),
808 rLR);
809 loadConstant(cUnit, r0, type_idx);
810 callRuntimeHelper(cUnit, rLR); // InitializeTypeAndVerifyAccess(idx, method)
811 genRegCopy(cUnit, classReg, r0); // Align usage with fast path
Ian Rogers28ad40d2011-10-27 15:19:26 -0700812 } else {
813 // Load dex cache entry into classReg (r2)
814 loadWordDisp(cUnit, r1, Method::DexCacheResolvedTypesOffset().Int32Value(), classReg);
815 int32_t offset_of_type = Array::DataOffset().Int32Value() + (sizeof(Class*) * type_idx);
816 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
Ian Rogersa3760aa2011-11-14 14:32:37 -0800817 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->dex_cache, type_idx)) {
Ian Rogers28ad40d2011-10-27 15:19:26 -0700818 // Need to test presence of type in dex cache at runtime
819 ArmLIR* hopBranch = genCmpImmBranch(cUnit, kArmCondNe, classReg, 0);
820 // Not resolved
821 // Call out to helper, which will return resolved type in r0
822 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
823 loadConstant(cUnit, r0, type_idx);
Ian Rogersb093c6b2011-10-31 16:19:55 -0700824 callRuntimeHelper(cUnit, rLR); // InitializeTypeFromCode(idx, method)
825 genRegCopy(cUnit, classReg, r0); // Align usage with fast path
Ian Rogers28ad40d2011-10-27 15:19:26 -0700826 // Rejoin code paths
827 ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
828 hopTarget->defMask = ENCODE_ALL;
829 hopBranch->generic.target = (LIR*)hopTarget;
830 }
buzbee67bf8852011-08-17 17:51:35 -0700831 }
Ian Rogers28ad40d2011-10-27 15:19:26 -0700832 // At this point, classReg (r2) has class
833 loadValueDirectFixed(cUnit, rlSrc, r0); // r0 <= ref
buzbee2a475e72011-09-07 17:19:17 -0700834 /* Null is OK - continue */
835 ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, r0, 0);
836 /* load object->clazz */
buzbeeed3e9302011-09-23 17:34:19 -0700837 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
buzbee2a475e72011-09-07 17:19:17 -0700838 loadWordDisp(cUnit, r0, Object::ClassOffset().Int32Value(), r1);
839 /* r1 now contains object->clazz */
Ian Rogers28ad40d2011-10-27 15:19:26 -0700840 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pCheckCastFromCode), rLR);
Ian Rogersb093c6b2011-10-31 16:19:55 -0700841 opRegReg(cUnit, kOpCmp, r1, classReg);
buzbee2a475e72011-09-07 17:19:17 -0700842 ArmLIR* branch2 = opCondBranch(cUnit, kArmCondEq); /* If equal, trivial yes */
843 genRegCopy(cUnit, r0, r1);
844 genRegCopy(cUnit, r1, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -0700845 callRuntimeHelper(cUnit, rLR);
buzbee2a475e72011-09-07 17:19:17 -0700846 /* branch target here */
buzbee67bf8852011-08-17 17:51:35 -0700847 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
848 target->defMask = ENCODE_ALL;
849 branch1->generic.target = (LIR*)target;
850 branch2->generic.target = (LIR*)target;
851}
852
buzbeeed3e9302011-09-23 17:34:19 -0700853STATIC void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700854 RegLocation rlSrc)
855{
856 RegLocation rlResult;
857 rlSrc = loadValue(cUnit, rlSrc, kFPReg);
858 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
859 newLIR2(cUnit, kThumb2Vnegs, rlResult.lowReg, rlSrc.lowReg);
860 storeValue(cUnit, rlDest, rlResult);
861}
862
buzbeeed3e9302011-09-23 17:34:19 -0700863STATIC void genNegDouble(CompilationUnit* cUnit, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700864 RegLocation rlSrc)
865{
866 RegLocation rlResult;
867 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
868 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
869 newLIR2(cUnit, kThumb2Vnegd, S2D(rlResult.lowReg, rlResult.highReg),
870 S2D(rlSrc.lowReg, rlSrc.highReg));
871 storeValueWide(cUnit, rlDest, rlResult);
872}
873
buzbeeed3e9302011-09-23 17:34:19 -0700874STATIC void freeRegLocTemps(CompilationUnit* cUnit, RegLocation rlKeep,
buzbee439c4fa2011-08-27 15:59:07 -0700875 RegLocation rlFree)
buzbee67bf8852011-08-17 17:51:35 -0700876{
buzbee6181f792011-09-29 11:14:04 -0700877 if ((rlFree.lowReg != rlKeep.lowReg) && (rlFree.lowReg != rlKeep.highReg) &&
878 (rlFree.highReg != rlKeep.lowReg) && (rlFree.highReg != rlKeep.highReg)) {
879 // No overlap, free both
buzbee439c4fa2011-08-27 15:59:07 -0700880 oatFreeTemp(cUnit, rlFree.lowReg);
buzbee6181f792011-09-29 11:14:04 -0700881 oatFreeTemp(cUnit, rlFree.highReg);
882 }
buzbee67bf8852011-08-17 17:51:35 -0700883}
884
buzbeeed3e9302011-09-23 17:34:19 -0700885STATIC void genLong3Addr(CompilationUnit* cUnit, MIR* mir, OpKind firstOp,
buzbee67bf8852011-08-17 17:51:35 -0700886 OpKind secondOp, RegLocation rlDest,
887 RegLocation rlSrc1, RegLocation rlSrc2)
888{
buzbee9e0f9b02011-08-24 15:32:46 -0700889 /*
890 * NOTE: This is the one place in the code in which we might have
891 * as many as six live temporary registers. There are 5 in the normal
892 * set for Arm. Until we have spill capabilities, temporarily add
893 * lr to the temp set. It is safe to do this locally, but note that
894 * lr is used explicitly elsewhere in the code generator and cannot
895 * normally be used as a general temp register.
896 */
buzbee67bf8852011-08-17 17:51:35 -0700897 RegLocation rlResult;
buzbee9e0f9b02011-08-24 15:32:46 -0700898 oatMarkTemp(cUnit, rLR); // Add lr to the temp pool
899 oatFreeTemp(cUnit, rLR); // and make it available
buzbee67bf8852011-08-17 17:51:35 -0700900 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
901 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
902 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbeec0ecd652011-09-25 18:11:54 -0700903 // The longs may overlap - use intermediate temp if so
904 if (rlResult.lowReg == rlSrc1.highReg) {
buzbeec0ecd652011-09-25 18:11:54 -0700905 int tReg = oatAllocTemp(cUnit);
906 genRegCopy(cUnit, tReg, rlSrc1.highReg);
907 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
908 rlSrc2.lowReg);
909 opRegRegReg(cUnit, secondOp, rlResult.highReg, tReg,
910 rlSrc2.highReg);
911 oatFreeTemp(cUnit, tReg);
912 } else {
913 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
914 rlSrc2.lowReg);
915 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
916 rlSrc2.highReg);
917 }
buzbee439c4fa2011-08-27 15:59:07 -0700918 /*
919 * NOTE: If rlDest refers to a frame variable in a large frame, the
920 * following storeValueWide might need to allocate a temp register.
921 * To further work around the lack of a spill capability, explicitly
922 * free any temps from rlSrc1 & rlSrc2 that aren't still live in rlResult.
923 * Remove when spill is functional.
924 */
925 freeRegLocTemps(cUnit, rlResult, rlSrc1);
926 freeRegLocTemps(cUnit, rlResult, rlSrc2);
buzbee67bf8852011-08-17 17:51:35 -0700927 storeValueWide(cUnit, rlDest, rlResult);
buzbee9e0f9b02011-08-24 15:32:46 -0700928 oatClobber(cUnit, rLR);
929 oatUnmarkTemp(cUnit, rLR); // Remove lr from the temp pool
buzbee67bf8852011-08-17 17:51:35 -0700930}
931
932void oatInitializeRegAlloc(CompilationUnit* cUnit)
933{
934 int numRegs = sizeof(coreRegs)/sizeof(*coreRegs);
935 int numReserved = sizeof(reservedRegs)/sizeof(*reservedRegs);
936 int numTemps = sizeof(coreTemps)/sizeof(*coreTemps);
937 int numFPRegs = sizeof(fpRegs)/sizeof(*fpRegs);
938 int numFPTemps = sizeof(fpTemps)/sizeof(*fpTemps);
939 RegisterPool *pool = (RegisterPool *)oatNew(sizeof(*pool), true);
940 cUnit->regPool = pool;
941 pool->numCoreRegs = numRegs;
942 pool->coreRegs = (RegisterInfo *)
943 oatNew(numRegs * sizeof(*cUnit->regPool->coreRegs), true);
944 pool->numFPRegs = numFPRegs;
945 pool->FPRegs = (RegisterInfo *)
946 oatNew(numFPRegs * sizeof(*cUnit->regPool->FPRegs), true);
947 oatInitPool(pool->coreRegs, coreRegs, pool->numCoreRegs);
948 oatInitPool(pool->FPRegs, fpRegs, pool->numFPRegs);
949 // Keep special registers from being allocated
950 for (int i = 0; i < numReserved; i++) {
buzbeec0ecd652011-09-25 18:11:54 -0700951 if (NO_SUSPEND && (reservedRegs[i] == rSUSPEND)) {
952 //To measure cost of suspend check
953 continue;
954 }
buzbee67bf8852011-08-17 17:51:35 -0700955 oatMarkInUse(cUnit, reservedRegs[i]);
956 }
957 // Mark temp regs - all others not in use can be used for promotion
958 for (int i = 0; i < numTemps; i++) {
959 oatMarkTemp(cUnit, coreTemps[i]);
960 }
961 for (int i = 0; i < numFPTemps; i++) {
962 oatMarkTemp(cUnit, fpTemps[i]);
963 }
buzbeec0ecd652011-09-25 18:11:54 -0700964 // Construct the alias map.
965 cUnit->phiAliasMap = (int*)oatNew(cUnit->numSSARegs *
966 sizeof(cUnit->phiAliasMap[0]), false);
967 for (int i = 0; i < cUnit->numSSARegs; i++) {
968 cUnit->phiAliasMap[i] = i;
969 }
970 for (MIR* phi = cUnit->phiList; phi; phi = phi->meta.phiNext) {
971 int defReg = phi->ssaRep->defs[0];
972 for (int i = 0; i < phi->ssaRep->numUses; i++) {
973 for (int j = 0; j < cUnit->numSSARegs; j++) {
974 if (cUnit->phiAliasMap[j] == phi->ssaRep->uses[i]) {
975 cUnit->phiAliasMap[j] = defReg;
976 }
977 }
978 }
979 }
buzbee67bf8852011-08-17 17:51:35 -0700980}
981
982/*
983 * Handle simple case (thin lock) inline. If it's complicated, bail
984 * out to the heavyweight lock/unlock routines. We'll use dedicated
985 * registers here in order to be in the right position in case we
986 * to bail to dvm[Lock/Unlock]Object(self, object)
987 *
988 * r0 -> self pointer [arg0 for dvm[Lock/Unlock]Object
989 * r1 -> object [arg1 for dvm[Lock/Unlock]Object
990 * r2 -> intial contents of object->lock, later result of strex
991 * r3 -> self->threadId
992 * r12 -> allow to be used by utilities as general temp
993 *
994 * The result of the strex is 0 if we acquire the lock.
995 *
996 * See comments in Sync.c for the layout of the lock word.
997 * Of particular interest to this code is the test for the
998 * simple case - which we handle inline. For monitor enter, the
999 * simple case is thin lock, held by no-one. For monitor exit,
1000 * the simple case is thin lock, held by the unlocking thread with
1001 * a recurse count of 0.
1002 *
1003 * A minor complication is that there is a field in the lock word
1004 * unrelated to locking: the hash state. This field must be ignored, but
1005 * preserved.
1006 *
1007 */
buzbeeed3e9302011-09-23 17:34:19 -07001008STATIC void genMonitorEnter(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001009 RegLocation rlSrc)
1010{
1011 ArmLIR* target;
1012 ArmLIR* hopTarget;
1013 ArmLIR* branch;
1014 ArmLIR* hopBranch;
1015
1016 oatFlushAllRegs(cUnit);
Elliott Hughes5f791332011-09-15 17:45:30 -07001017 DCHECK_EQ(LW_SHAPE_THIN, 0);
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001018 loadValueDirectFixed(cUnit, rlSrc, r0); // Get obj
buzbee2e748f32011-08-29 21:02:19 -07001019 oatLockCallTemps(cUnit); // Prepare for explicit register usage
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001020 genNullCheck(cUnit, rlSrc.sRegLow, r0, mir);
1021 loadWordDisp(cUnit, rSELF, Thread::ThinLockIdOffset().Int32Value(), r2);
1022 newLIR3(cUnit, kThumb2Ldrex, r1, r0,
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001023 Object::MonitorOffset().Int32Value() >> 2); // Get object->lock
buzbeec143c552011-08-20 17:38:58 -07001024 // Align owner
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001025 opRegImm(cUnit, kOpLsl, r2, LW_LOCK_OWNER_SHIFT);
buzbee67bf8852011-08-17 17:51:35 -07001026 // Is lock unheld on lock or held by us (==threadId) on unlock?
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001027 newLIR4(cUnit, kThumb2Bfi, r2, r1, 0, LW_LOCK_OWNER_SHIFT - 1);
1028 newLIR3(cUnit, kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
1029 hopBranch = newLIR2(cUnit, kThumb2Cbnz, r1, 0);
1030 newLIR4(cUnit, kThumb2Strex, r1, r2, r0,
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001031 Object::MonitorOffset().Int32Value() >> 2);
buzbee67bf8852011-08-17 17:51:35 -07001032 oatGenMemBarrier(cUnit, kSY);
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001033 branch = newLIR2(cUnit, kThumb2Cbz, r1, 0);
buzbee67bf8852011-08-17 17:51:35 -07001034
1035 hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
1036 hopTarget->defMask = ENCODE_ALL;
1037 hopBranch->generic.target = (LIR*)hopTarget;
1038
buzbee1b4c8592011-08-31 10:43:51 -07001039 // Go expensive route - artLockObjectFromCode(self, obj);
1040 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pLockObjectFromCode),
buzbee67bf8852011-08-17 17:51:35 -07001041 rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07001042 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001043
1044 // Resume here
1045 target = newLIR0(cUnit, kArmPseudoTargetLabel);
1046 target->defMask = ENCODE_ALL;
1047 branch->generic.target = (LIR*)target;
1048}
1049
1050/*
1051 * For monitor unlock, we don't have to use ldrex/strex. Once
1052 * we've determined that the lock is thin and that we own it with
1053 * a zero recursion count, it's safe to punch it back to the
1054 * initial, unlock thin state with a store word.
1055 */
buzbeeed3e9302011-09-23 17:34:19 -07001056STATIC void genMonitorExit(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001057 RegLocation rlSrc)
1058{
1059 ArmLIR* target;
1060 ArmLIR* branch;
1061 ArmLIR* hopTarget;
1062 ArmLIR* hopBranch;
1063
Elliott Hughes5f791332011-09-15 17:45:30 -07001064 DCHECK_EQ(LW_SHAPE_THIN, 0);
buzbee67bf8852011-08-17 17:51:35 -07001065 oatFlushAllRegs(cUnit);
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001066 loadValueDirectFixed(cUnit, rlSrc, r0); // Get obj
buzbee2e748f32011-08-29 21:02:19 -07001067 oatLockCallTemps(cUnit); // Prepare for explicit register usage
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001068 genNullCheck(cUnit, rlSrc.sRegLow, r0, mir);
1069 loadWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r1); // Get lock
1070 loadWordDisp(cUnit, rSELF, Thread::ThinLockIdOffset().Int32Value(), r2);
buzbee67bf8852011-08-17 17:51:35 -07001071 // Is lock unheld on lock or held by us (==threadId) on unlock?
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001072 opRegRegImm(cUnit, kOpAnd, r3, r1, (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
buzbeec143c552011-08-20 17:38:58 -07001073 // Align owner
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001074 opRegImm(cUnit, kOpLsl, r2, LW_LOCK_OWNER_SHIFT);
1075 newLIR3(cUnit, kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
1076 opRegReg(cUnit, kOpSub, r1, r2);
buzbee67bf8852011-08-17 17:51:35 -07001077 hopBranch = opCondBranch(cUnit, kArmCondNe);
1078 oatGenMemBarrier(cUnit, kSY);
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001079 storeWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r3);
buzbee67bf8852011-08-17 17:51:35 -07001080 branch = opNone(cUnit, kOpUncondBr);
1081
1082 hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
1083 hopTarget->defMask = ENCODE_ALL;
1084 hopBranch->generic.target = (LIR*)hopTarget;
1085
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001086 // Go expensive route - UnlockObjectFromCode(obj);
buzbee1b4c8592011-08-31 10:43:51 -07001087 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pUnlockObjectFromCode),
buzbee67bf8852011-08-17 17:51:35 -07001088 rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07001089 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001090
1091 // Resume here
1092 target = newLIR0(cUnit, kArmPseudoTargetLabel);
1093 target->defMask = ENCODE_ALL;
1094 branch->generic.target = (LIR*)target;
1095}
1096
1097/*
1098 * 64-bit 3way compare function.
1099 * mov rX, #-1
1100 * cmp op1hi, op2hi
1101 * blt done
1102 * bgt flip
1103 * sub rX, op1lo, op2lo (treat as unsigned)
1104 * beq done
1105 * ite hi
1106 * mov(hi) rX, #-1
1107 * mov(!hi) rX, #1
1108 * flip:
1109 * neg rX
1110 * done:
1111 */
buzbeeed3e9302011-09-23 17:34:19 -07001112STATIC void genCmpLong(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001113 RegLocation rlDest, RegLocation rlSrc1,
1114 RegLocation rlSrc2)
1115{
buzbee67bf8852011-08-17 17:51:35 -07001116 ArmLIR* target1;
1117 ArmLIR* target2;
1118 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
1119 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
buzbeeb29e4d12011-09-26 15:05:48 -07001120 int tReg = oatAllocTemp(cUnit);
1121 loadConstant(cUnit, tReg, -1);
buzbee67bf8852011-08-17 17:51:35 -07001122 opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg);
1123 ArmLIR* branch1 = opCondBranch(cUnit, kArmCondLt);
1124 ArmLIR* branch2 = opCondBranch(cUnit, kArmCondGt);
buzbeeb29e4d12011-09-26 15:05:48 -07001125 opRegRegReg(cUnit, kOpSub, tReg, rlSrc1.lowReg, rlSrc2.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001126 ArmLIR* branch3 = opCondBranch(cUnit, kArmCondEq);
1127
1128 genIT(cUnit, kArmCondHi, "E");
buzbeeb29e4d12011-09-26 15:05:48 -07001129 newLIR2(cUnit, kThumb2MovImmShift, tReg, modifiedImmediate(-1));
1130 loadConstant(cUnit, tReg, 1);
buzbee67bf8852011-08-17 17:51:35 -07001131 genBarrier(cUnit);
1132
1133 target2 = newLIR0(cUnit, kArmPseudoTargetLabel);
1134 target2->defMask = -1;
buzbeeb29e4d12011-09-26 15:05:48 -07001135 opRegReg(cUnit, kOpNeg, tReg, tReg);
buzbee67bf8852011-08-17 17:51:35 -07001136
1137 target1 = newLIR0(cUnit, kArmPseudoTargetLabel);
1138 target1->defMask = -1;
1139
buzbeeb29e4d12011-09-26 15:05:48 -07001140 RegLocation rlTemp = LOC_C_RETURN; // Just using as template, will change
1141 rlTemp.lowReg = tReg;
buzbee67bf8852011-08-17 17:51:35 -07001142 storeValue(cUnit, rlDest, rlTemp);
buzbeeb29e4d12011-09-26 15:05:48 -07001143 oatFreeTemp(cUnit, tReg);
buzbee67bf8852011-08-17 17:51:35 -07001144
1145 branch1->generic.target = (LIR*)target1;
1146 branch2->generic.target = (LIR*)target2;
1147 branch3->generic.target = branch1->generic.target;
1148}
1149
buzbeeed3e9302011-09-23 17:34:19 -07001150STATIC void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -07001151 RegLocation rlSrc, RegLocation rlResult, int lit,
1152 int firstBit, int secondBit)
1153{
1154 opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg,
1155 encodeShift(kArmLsl, secondBit - firstBit));
1156 if (firstBit != 0) {
1157 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
1158 }
1159}
1160
buzbeeed3e9302011-09-23 17:34:19 -07001161STATIC bool genConversionCall(CompilationUnit* cUnit, MIR* mir, int funcOffset,
buzbee67bf8852011-08-17 17:51:35 -07001162 int srcSize, int tgtSize)
1163{
1164 /*
1165 * Don't optimize the register usage since it calls out to support
1166 * functions
1167 */
1168 RegLocation rlSrc;
1169 RegLocation rlDest;
1170 oatFlushAllRegs(cUnit); /* Send everything to home location */
1171 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1172 if (srcSize == 1) {
1173 rlSrc = oatGetSrc(cUnit, mir, 0);
1174 loadValueDirectFixed(cUnit, rlSrc, r0);
1175 } else {
1176 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
1177 loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
1178 }
Ian Rogersff1ed472011-09-20 13:46:24 -07001179 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001180 if (tgtSize == 1) {
1181 RegLocation rlResult;
1182 rlDest = oatGetDest(cUnit, mir, 0);
1183 rlResult = oatGetReturn(cUnit);
1184 storeValue(cUnit, rlDest, rlResult);
1185 } else {
1186 RegLocation rlResult;
1187 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1188 rlResult = oatGetReturnWide(cUnit);
1189 storeValueWide(cUnit, rlDest, rlResult);
1190 }
1191 return false;
1192}
1193
buzbeeed3e9302011-09-23 17:34:19 -07001194STATIC bool genArithOpFloatPortable(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001195 RegLocation rlDest, RegLocation rlSrc1,
1196 RegLocation rlSrc2)
1197{
1198 RegLocation rlResult;
1199 int funcOffset;
1200
1201 switch (mir->dalvikInsn.opcode) {
1202 case OP_ADD_FLOAT_2ADDR:
1203 case OP_ADD_FLOAT:
1204 funcOffset = OFFSETOF_MEMBER(Thread, pFadd);
1205 break;
1206 case OP_SUB_FLOAT_2ADDR:
1207 case OP_SUB_FLOAT:
1208 funcOffset = OFFSETOF_MEMBER(Thread, pFsub);
1209 break;
1210 case OP_DIV_FLOAT_2ADDR:
1211 case OP_DIV_FLOAT:
1212 funcOffset = OFFSETOF_MEMBER(Thread, pFdiv);
1213 break;
1214 case OP_MUL_FLOAT_2ADDR:
1215 case OP_MUL_FLOAT:
1216 funcOffset = OFFSETOF_MEMBER(Thread, pFmul);
1217 break;
1218 case OP_REM_FLOAT_2ADDR:
1219 case OP_REM_FLOAT:
1220 funcOffset = OFFSETOF_MEMBER(Thread, pFmodf);
1221 break;
1222 case OP_NEG_FLOAT: {
1223 genNegFloat(cUnit, rlDest, rlSrc1);
1224 return false;
1225 }
1226 default:
1227 return true;
1228 }
1229 oatFlushAllRegs(cUnit); /* Send everything to home location */
1230 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1231 loadValueDirectFixed(cUnit, rlSrc1, r0);
1232 loadValueDirectFixed(cUnit, rlSrc2, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -07001233 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001234 rlResult = oatGetReturn(cUnit);
1235 storeValue(cUnit, rlDest, rlResult);
1236 return false;
1237}
1238
buzbeeed3e9302011-09-23 17:34:19 -07001239STATIC bool genArithOpDoublePortable(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001240 RegLocation rlDest, RegLocation rlSrc1,
1241 RegLocation rlSrc2)
1242{
1243 RegLocation rlResult;
1244 int funcOffset;
1245
1246 switch (mir->dalvikInsn.opcode) {
1247 case OP_ADD_DOUBLE_2ADDR:
1248 case OP_ADD_DOUBLE:
1249 funcOffset = OFFSETOF_MEMBER(Thread, pDadd);
1250 break;
1251 case OP_SUB_DOUBLE_2ADDR:
1252 case OP_SUB_DOUBLE:
1253 funcOffset = OFFSETOF_MEMBER(Thread, pDsub);
1254 break;
1255 case OP_DIV_DOUBLE_2ADDR:
1256 case OP_DIV_DOUBLE:
1257 funcOffset = OFFSETOF_MEMBER(Thread, pDdiv);
1258 break;
1259 case OP_MUL_DOUBLE_2ADDR:
1260 case OP_MUL_DOUBLE:
1261 funcOffset = OFFSETOF_MEMBER(Thread, pDmul);
1262 break;
1263 case OP_REM_DOUBLE_2ADDR:
1264 case OP_REM_DOUBLE:
1265 funcOffset = OFFSETOF_MEMBER(Thread, pFmod);
1266 break;
1267 case OP_NEG_DOUBLE: {
1268 genNegDouble(cUnit, rlDest, rlSrc1);
1269 return false;
1270 }
1271 default:
1272 return true;
1273 }
1274 oatFlushAllRegs(cUnit); /* Send everything to home location */
1275 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1276 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1277 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
Ian Rogersff1ed472011-09-20 13:46:24 -07001278 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001279 rlResult = oatGetReturnWide(cUnit);
1280 storeValueWide(cUnit, rlDest, rlResult);
1281 return false;
1282}
1283
buzbeeed3e9302011-09-23 17:34:19 -07001284STATIC bool genConversionPortable(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001285{
1286 Opcode opcode = mir->dalvikInsn.opcode;
1287
1288 switch (opcode) {
1289 case OP_INT_TO_FLOAT:
1290 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2f),
1291 1, 1);
1292 case OP_FLOAT_TO_INT:
1293 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2iz),
1294 1, 1);
1295 case OP_DOUBLE_TO_FLOAT:
1296 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2f),
1297 2, 1);
1298 case OP_FLOAT_TO_DOUBLE:
1299 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2d),
1300 1, 2);
1301 case OP_INT_TO_DOUBLE:
1302 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2d),
1303 1, 2);
1304 case OP_DOUBLE_TO_INT:
1305 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2iz),
1306 2, 1);
1307 case OP_FLOAT_TO_LONG:
1308 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
buzbee1b4c8592011-08-31 10:43:51 -07001309 pF2l), 1, 2);
buzbee67bf8852011-08-17 17:51:35 -07001310 case OP_LONG_TO_FLOAT:
1311 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2f),
1312 2, 1);
1313 case OP_DOUBLE_TO_LONG:
1314 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
buzbee1b4c8592011-08-31 10:43:51 -07001315 pD2l), 2, 2);
buzbee67bf8852011-08-17 17:51:35 -07001316 case OP_LONG_TO_DOUBLE:
1317 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2d),
1318 2, 2);
1319 default:
1320 return true;
1321 }
1322 return false;
1323}
1324
1325/* Generate conditional branch instructions */
buzbeeed3e9302011-09-23 17:34:19 -07001326STATIC ArmLIR* genConditionalBranch(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -07001327 ArmConditionCode cond,
1328 ArmLIR* target)
1329{
1330 ArmLIR* branch = opCondBranch(cUnit, cond);
1331 branch->generic.target = (LIR*) target;
1332 return branch;
1333}
1334
buzbee67bf8852011-08-17 17:51:35 -07001335/*
1336 * Generate array store
1337 *
1338 */
buzbeeed3e9302011-09-23 17:34:19 -07001339STATIC void genArrayObjPut(CompilationUnit* cUnit, MIR* mir,
buzbee1b4c8592011-08-31 10:43:51 -07001340 RegLocation rlArray, RegLocation rlIndex,
1341 RegLocation rlSrc, int scale)
buzbee67bf8852011-08-17 17:51:35 -07001342{
1343 RegisterClass regClass = oatRegClassBySize(kWord);
buzbeec143c552011-08-20 17:38:58 -07001344 int lenOffset = Array::LengthOffset().Int32Value();
1345 int dataOffset = Array::DataOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001346
buzbee6181f792011-09-29 11:14:04 -07001347 oatFlushAllRegs(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001348 /* Make sure it's a legal object Put. Use direct regs at first */
1349 loadValueDirectFixed(cUnit, rlArray, r1);
1350 loadValueDirectFixed(cUnit, rlSrc, r0);
1351
1352 /* null array object? */
buzbee43a36422011-09-14 14:00:13 -07001353 genNullCheck(cUnit, rlArray.sRegLow, r1, mir);
buzbee67bf8852011-08-17 17:51:35 -07001354 loadWordDisp(cUnit, rSELF,
buzbee1b4c8592011-08-31 10:43:51 -07001355 OFFSETOF_MEMBER(Thread, pCanPutArrayElementFromCode), rLR);
buzbee67bf8852011-08-17 17:51:35 -07001356 /* Get the array's clazz */
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001357 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), r1);
Ian Rogersff1ed472011-09-20 13:46:24 -07001358 callRuntimeHelper(cUnit, rLR);
buzbee6181f792011-09-29 11:14:04 -07001359 oatFreeTemp(cUnit, r0);
1360 oatFreeTemp(cUnit, r1);
buzbee67bf8852011-08-17 17:51:35 -07001361
1362 // Now, redo loadValues in case they didn't survive the call
1363
1364 int regPtr;
1365 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1366 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1367
1368 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1369 oatClobber(cUnit, rlArray.lowReg);
1370 regPtr = rlArray.lowReg;
1371 } else {
1372 regPtr = oatAllocTemp(cUnit);
1373 genRegCopy(cUnit, regPtr, rlArray.lowReg);
1374 }
1375
buzbee43a36422011-09-14 14:00:13 -07001376 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee67bf8852011-08-17 17:51:35 -07001377 int regLen = oatAllocTemp(cUnit);
1378 //NOTE: max live temps(4) here.
1379 /* Get len */
1380 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1381 /* regPtr -> array data */
1382 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
buzbeeec5adf32011-09-11 15:25:43 -07001383 genRegRegCheck(cUnit, kArmCondCs, rlIndex.lowReg, regLen, mir,
buzbee5ade1d22011-09-09 14:44:52 -07001384 kArmThrowArrayBounds);
buzbee67bf8852011-08-17 17:51:35 -07001385 oatFreeTemp(cUnit, regLen);
1386 } else {
1387 /* regPtr -> array data */
1388 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1389 }
1390 /* at this point, regPtr points to array, 2 live temps */
1391 rlSrc = loadValue(cUnit, rlSrc, regClass);
1392 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1393 scale, kWord);
1394}
1395
1396/*
1397 * Generate array load
1398 */
buzbeeed3e9302011-09-23 17:34:19 -07001399STATIC void genArrayGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -07001400 RegLocation rlArray, RegLocation rlIndex,
1401 RegLocation rlDest, int scale)
1402{
1403 RegisterClass regClass = oatRegClassBySize(size);
buzbeec143c552011-08-20 17:38:58 -07001404 int lenOffset = Array::LengthOffset().Int32Value();
1405 int dataOffset = Array::DataOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001406 RegLocation rlResult;
1407 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1408 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1409 int regPtr;
1410
1411 /* null object? */
buzbee43a36422011-09-14 14:00:13 -07001412 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001413
1414 regPtr = oatAllocTemp(cUnit);
1415
buzbee43a36422011-09-14 14:00:13 -07001416 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee67bf8852011-08-17 17:51:35 -07001417 int regLen = oatAllocTemp(cUnit);
1418 /* Get len */
1419 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1420 /* regPtr -> array data */
1421 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
buzbeeec5adf32011-09-11 15:25:43 -07001422 genRegRegCheck(cUnit, kArmCondCs, rlIndex.lowReg, regLen, mir,
buzbee5ade1d22011-09-09 14:44:52 -07001423 kArmThrowArrayBounds);
buzbee67bf8852011-08-17 17:51:35 -07001424 oatFreeTemp(cUnit, regLen);
1425 } else {
1426 /* regPtr -> array data */
1427 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1428 }
buzbeee9a72f62011-09-04 17:59:07 -07001429 oatFreeTemp(cUnit, rlArray.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001430 if ((size == kLong) || (size == kDouble)) {
1431 if (scale) {
1432 int rNewIndex = oatAllocTemp(cUnit);
1433 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1434 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1435 oatFreeTemp(cUnit, rNewIndex);
1436 } else {
1437 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1438 }
buzbeee9a72f62011-09-04 17:59:07 -07001439 oatFreeTemp(cUnit, rlIndex.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001440 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1441
1442 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1443
1444 oatFreeTemp(cUnit, regPtr);
1445 storeValueWide(cUnit, rlDest, rlResult);
1446 } else {
1447 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1448
1449 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
1450 scale, size);
1451
1452 oatFreeTemp(cUnit, regPtr);
1453 storeValue(cUnit, rlDest, rlResult);
1454 }
1455}
1456
1457/*
1458 * Generate array store
1459 *
1460 */
buzbeeed3e9302011-09-23 17:34:19 -07001461STATIC void genArrayPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -07001462 RegLocation rlArray, RegLocation rlIndex,
1463 RegLocation rlSrc, int scale)
1464{
1465 RegisterClass regClass = oatRegClassBySize(size);
buzbeec143c552011-08-20 17:38:58 -07001466 int lenOffset = Array::LengthOffset().Int32Value();
1467 int dataOffset = Array::DataOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001468
1469 int regPtr;
1470 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1471 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1472
1473 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1474 oatClobber(cUnit, rlArray.lowReg);
1475 regPtr = rlArray.lowReg;
1476 } else {
1477 regPtr = oatAllocTemp(cUnit);
1478 genRegCopy(cUnit, regPtr, rlArray.lowReg);
1479 }
1480
1481 /* null object? */
buzbee43a36422011-09-14 14:00:13 -07001482 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001483
buzbee43a36422011-09-14 14:00:13 -07001484 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee67bf8852011-08-17 17:51:35 -07001485 int regLen = oatAllocTemp(cUnit);
1486 //NOTE: max live temps(4) here.
1487 /* Get len */
1488 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1489 /* regPtr -> array data */
1490 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
buzbeeec5adf32011-09-11 15:25:43 -07001491 genRegRegCheck(cUnit, kArmCondCs, rlIndex.lowReg, regLen, mir,
buzbee5ade1d22011-09-09 14:44:52 -07001492 kArmThrowArrayBounds);
buzbee67bf8852011-08-17 17:51:35 -07001493 oatFreeTemp(cUnit, regLen);
1494 } else {
1495 /* regPtr -> array data */
1496 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1497 }
1498 /* at this point, regPtr points to array, 2 live temps */
1499 if ((size == kLong) || (size == kDouble)) {
buzbee5ade1d22011-09-09 14:44:52 -07001500 //TUNING: specific wide routine that can handle fp regs
buzbee67bf8852011-08-17 17:51:35 -07001501 if (scale) {
1502 int rNewIndex = oatAllocTemp(cUnit);
1503 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1504 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1505 oatFreeTemp(cUnit, rNewIndex);
1506 } else {
1507 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1508 }
1509 rlSrc = loadValueWide(cUnit, rlSrc, regClass);
1510
1511 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
1512
1513 oatFreeTemp(cUnit, regPtr);
1514 } else {
1515 rlSrc = loadValue(cUnit, rlSrc, regClass);
1516
1517 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1518 scale, size);
1519 }
1520}
1521
buzbeeed3e9302011-09-23 17:34:19 -07001522STATIC bool genShiftOpLong(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001523 RegLocation rlDest, RegLocation rlSrc1,
1524 RegLocation rlShift)
1525{
buzbee54330722011-08-23 16:46:55 -07001526 int funcOffset;
buzbee67bf8852011-08-17 17:51:35 -07001527
buzbee67bf8852011-08-17 17:51:35 -07001528 switch( mir->dalvikInsn.opcode) {
1529 case OP_SHL_LONG:
1530 case OP_SHL_LONG_2ADDR:
buzbee54330722011-08-23 16:46:55 -07001531 funcOffset = OFFSETOF_MEMBER(Thread, pShlLong);
buzbee67bf8852011-08-17 17:51:35 -07001532 break;
1533 case OP_SHR_LONG:
1534 case OP_SHR_LONG_2ADDR:
buzbee54330722011-08-23 16:46:55 -07001535 funcOffset = OFFSETOF_MEMBER(Thread, pShrLong);
buzbee67bf8852011-08-17 17:51:35 -07001536 break;
1537 case OP_USHR_LONG:
1538 case OP_USHR_LONG_2ADDR:
buzbee54330722011-08-23 16:46:55 -07001539 funcOffset = OFFSETOF_MEMBER(Thread, pUshrLong);
buzbee67bf8852011-08-17 17:51:35 -07001540 break;
1541 default:
buzbee54330722011-08-23 16:46:55 -07001542 LOG(FATAL) << "Unexpected case";
buzbee67bf8852011-08-17 17:51:35 -07001543 return true;
1544 }
buzbee54330722011-08-23 16:46:55 -07001545 oatFlushAllRegs(cUnit); /* Send everything to home location */
1546 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1547 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1548 loadValueDirect(cUnit, rlShift, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -07001549 callRuntimeHelper(cUnit, rLR);
buzbee54330722011-08-23 16:46:55 -07001550 RegLocation rlResult = oatGetReturnWide(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001551 storeValueWide(cUnit, rlDest, rlResult);
1552 return false;
1553}
1554
buzbeeed3e9302011-09-23 17:34:19 -07001555STATIC bool genArithOpLong(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001556 RegLocation rlDest, RegLocation rlSrc1,
1557 RegLocation rlSrc2)
1558{
1559 RegLocation rlResult;
1560 OpKind firstOp = kOpBkpt;
1561 OpKind secondOp = kOpBkpt;
1562 bool callOut = false;
buzbee58f92742011-10-01 11:22:17 -07001563 bool checkZero = false;
buzbee67bf8852011-08-17 17:51:35 -07001564 int funcOffset;
1565 int retReg = r0;
1566
1567 switch (mir->dalvikInsn.opcode) {
1568 case OP_NOT_LONG:
1569 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1570 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbeeb29e4d12011-09-26 15:05:48 -07001571 // Check for destructive overlap
1572 if (rlResult.lowReg == rlSrc2.highReg) {
1573 int tReg = oatAllocTemp(cUnit);
1574 genRegCopy(cUnit, tReg, rlSrc2.highReg);
1575 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1576 opRegReg(cUnit, kOpMvn, rlResult.highReg, tReg);
1577 oatFreeTemp(cUnit, tReg);
1578 } else {
1579 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1580 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
1581 }
buzbee67bf8852011-08-17 17:51:35 -07001582 storeValueWide(cUnit, rlDest, rlResult);
1583 return false;
1584 break;
1585 case OP_ADD_LONG:
1586 case OP_ADD_LONG_2ADDR:
1587 firstOp = kOpAdd;
1588 secondOp = kOpAdc;
1589 break;
1590 case OP_SUB_LONG:
1591 case OP_SUB_LONG_2ADDR:
1592 firstOp = kOpSub;
1593 secondOp = kOpSbc;
1594 break;
1595 case OP_MUL_LONG:
1596 case OP_MUL_LONG_2ADDR:
buzbee439c4fa2011-08-27 15:59:07 -07001597 callOut = true;
1598 retReg = r0;
1599 funcOffset = OFFSETOF_MEMBER(Thread, pLmul);
1600 break;
buzbee67bf8852011-08-17 17:51:35 -07001601 case OP_DIV_LONG:
1602 case OP_DIV_LONG_2ADDR:
1603 callOut = true;
buzbee58f92742011-10-01 11:22:17 -07001604 checkZero = true;
buzbee67bf8852011-08-17 17:51:35 -07001605 retReg = r0;
1606 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
1607 break;
1608 /* NOTE - result is in r2/r3 instead of r0/r1 */
1609 case OP_REM_LONG:
1610 case OP_REM_LONG_2ADDR:
1611 callOut = true;
buzbee58f92742011-10-01 11:22:17 -07001612 checkZero = true;
buzbee67bf8852011-08-17 17:51:35 -07001613 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
1614 retReg = r2;
1615 break;
1616 case OP_AND_LONG_2ADDR:
1617 case OP_AND_LONG:
1618 firstOp = kOpAnd;
1619 secondOp = kOpAnd;
1620 break;
1621 case OP_OR_LONG:
1622 case OP_OR_LONG_2ADDR:
1623 firstOp = kOpOr;
1624 secondOp = kOpOr;
1625 break;
1626 case OP_XOR_LONG:
1627 case OP_XOR_LONG_2ADDR:
1628 firstOp = kOpXor;
1629 secondOp = kOpXor;
1630 break;
1631 case OP_NEG_LONG: {
buzbee67bf8852011-08-17 17:51:35 -07001632 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1633 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbeeb29e4d12011-09-26 15:05:48 -07001634 int zReg = oatAllocTemp(cUnit);
1635 loadConstantNoClobber(cUnit, zReg, 0);
1636 // Check for destructive overlap
1637 if (rlResult.lowReg == rlSrc2.highReg) {
1638 int tReg = oatAllocTemp(cUnit);
1639 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1640 zReg, rlSrc2.lowReg);
1641 opRegRegReg(cUnit, kOpSbc, rlResult.highReg,
1642 zReg, tReg);
1643 oatFreeTemp(cUnit, tReg);
1644 } else {
1645 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1646 zReg, rlSrc2.lowReg);
1647 opRegRegReg(cUnit, kOpSbc, rlResult.highReg,
1648 zReg, rlSrc2.highReg);
1649 }
1650 oatFreeTemp(cUnit, zReg);
buzbee67bf8852011-08-17 17:51:35 -07001651 storeValueWide(cUnit, rlDest, rlResult);
1652 return false;
1653 }
1654 default:
1655 LOG(FATAL) << "Invalid long arith op";
1656 }
1657 if (!callOut) {
1658 genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
1659 } else {
buzbee67bf8852011-08-17 17:51:35 -07001660 oatFlushAllRegs(cUnit); /* Send everything to home location */
buzbee58f92742011-10-01 11:22:17 -07001661 if (checkZero) {
1662 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
1663 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1664 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1665 int tReg = oatAllocTemp(cUnit);
1666 newLIR4(cUnit, kThumb2OrrRRRs, tReg, r2, r3, 0);
1667 oatFreeTemp(cUnit, tReg);
1668 genCheck(cUnit, kArmCondEq, mir, kArmThrowDivZero);
1669 } else {
1670 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1671 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1672 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
1673 }
Ian Rogersff1ed472011-09-20 13:46:24 -07001674 callRuntimeHelper(cUnit, rLR);
buzbee58f92742011-10-01 11:22:17 -07001675 // Adjust return regs in to handle case of rem returning r2/r3
buzbee67bf8852011-08-17 17:51:35 -07001676 if (retReg == r0)
1677 rlResult = oatGetReturnWide(cUnit);
1678 else
1679 rlResult = oatGetReturnWideAlt(cUnit);
1680 storeValueWide(cUnit, rlDest, rlResult);
1681 }
1682 return false;
1683}
1684
buzbeeed3e9302011-09-23 17:34:19 -07001685STATIC bool genArithOpInt(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001686 RegLocation rlDest, RegLocation rlSrc1,
1687 RegLocation rlSrc2)
1688{
1689 OpKind op = kOpBkpt;
1690 bool callOut = false;
1691 bool checkZero = false;
1692 bool unary = false;
1693 int retReg = r0;
1694 int funcOffset;
1695 RegLocation rlResult;
1696 bool shiftOp = false;
1697
1698 switch (mir->dalvikInsn.opcode) {
1699 case OP_NEG_INT:
1700 op = kOpNeg;
1701 unary = true;
1702 break;
1703 case OP_NOT_INT:
1704 op = kOpMvn;
1705 unary = true;
1706 break;
1707 case OP_ADD_INT:
1708 case OP_ADD_INT_2ADDR:
1709 op = kOpAdd;
1710 break;
1711 case OP_SUB_INT:
1712 case OP_SUB_INT_2ADDR:
1713 op = kOpSub;
1714 break;
1715 case OP_MUL_INT:
1716 case OP_MUL_INT_2ADDR:
1717 op = kOpMul;
1718 break;
1719 case OP_DIV_INT:
1720 case OP_DIV_INT_2ADDR:
1721 callOut = true;
1722 checkZero = true;
1723 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
1724 retReg = r0;
1725 break;
1726 /* NOTE: returns in r1 */
1727 case OP_REM_INT:
1728 case OP_REM_INT_2ADDR:
1729 callOut = true;
1730 checkZero = true;
1731 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
1732 retReg = r1;
1733 break;
1734 case OP_AND_INT:
1735 case OP_AND_INT_2ADDR:
1736 op = kOpAnd;
1737 break;
1738 case OP_OR_INT:
1739 case OP_OR_INT_2ADDR:
1740 op = kOpOr;
1741 break;
1742 case OP_XOR_INT:
1743 case OP_XOR_INT_2ADDR:
1744 op = kOpXor;
1745 break;
1746 case OP_SHL_INT:
1747 case OP_SHL_INT_2ADDR:
1748 shiftOp = true;
1749 op = kOpLsl;
1750 break;
1751 case OP_SHR_INT:
1752 case OP_SHR_INT_2ADDR:
1753 shiftOp = true;
1754 op = kOpAsr;
1755 break;
1756 case OP_USHR_INT:
1757 case OP_USHR_INT_2ADDR:
1758 shiftOp = true;
1759 op = kOpLsr;
1760 break;
1761 default:
1762 LOG(FATAL) << "Invalid word arith op: " <<
1763 (int)mir->dalvikInsn.opcode;
1764 }
1765 if (!callOut) {
1766 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1767 if (unary) {
1768 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1769 opRegReg(cUnit, op, rlResult.lowReg,
1770 rlSrc1.lowReg);
1771 } else {
1772 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1773 if (shiftOp) {
1774 int tReg = oatAllocTemp(cUnit);
1775 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
1776 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1777 opRegRegReg(cUnit, op, rlResult.lowReg,
1778 rlSrc1.lowReg, tReg);
1779 oatFreeTemp(cUnit, tReg);
1780 } else {
1781 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1782 opRegRegReg(cUnit, op, rlResult.lowReg,
1783 rlSrc1.lowReg, rlSrc2.lowReg);
1784 }
1785 }
1786 storeValue(cUnit, rlDest, rlResult);
1787 } else {
1788 RegLocation rlResult;
1789 oatFlushAllRegs(cUnit); /* Send everything to home location */
1790 loadValueDirectFixed(cUnit, rlSrc2, r1);
1791 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1792 loadValueDirectFixed(cUnit, rlSrc1, r0);
1793 if (checkZero) {
buzbee5ade1d22011-09-09 14:44:52 -07001794 genImmedCheck(cUnit, kArmCondEq, r1, 0, mir, kArmThrowDivZero);
buzbee67bf8852011-08-17 17:51:35 -07001795 }
Ian Rogersff1ed472011-09-20 13:46:24 -07001796 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001797 if (retReg == r0)
1798 rlResult = oatGetReturn(cUnit);
1799 else
1800 rlResult = oatGetReturnAlt(cUnit);
1801 storeValue(cUnit, rlDest, rlResult);
1802 }
1803 return false;
1804}
1805
buzbeec1f45042011-09-21 16:03:19 -07001806/* Check if we need to check for pending suspend request */
buzbeeed3e9302011-09-23 17:34:19 -07001807STATIC void genSuspendTest(CompilationUnit* cUnit, MIR* mir)
buzbeec1f45042011-09-21 16:03:19 -07001808{
Ian Rogersa3760aa2011-11-14 14:32:37 -08001809 if (NO_SUSPEND || (mir->optimizationFlags & MIR_IGNORE_SUSPEND_CHECK)) {
buzbeec1f45042011-09-21 16:03:19 -07001810 return;
1811 }
buzbee6181f792011-09-29 11:14:04 -07001812 oatFlushAllRegs(cUnit);
buzbeec1f45042011-09-21 16:03:19 -07001813 newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
1814 ArmLIR* branch = opCondBranch(cUnit, kArmCondEq);
1815 ArmLIR* retLab = newLIR0(cUnit, kArmPseudoTargetLabel);
1816 retLab->defMask = ENCODE_ALL;
1817 ArmLIR* target = (ArmLIR*)oatNew(sizeof(ArmLIR), true);
1818 target->generic.dalvikOffset = cUnit->currentDalvikOffset;
1819 target->opcode = kArmPseudoSuspendTarget;
1820 target->operands[0] = (intptr_t)retLab;
1821 target->operands[1] = mir->offset;
1822 branch->generic.target = (LIR*)target;
1823 oatInsertGrowableList(&cUnit->suspendLaunchpads, (intptr_t)target);
1824}
1825
buzbee67bf8852011-08-17 17:51:35 -07001826/*
1827 * The following are the first-level codegen routines that analyze the format
1828 * of each bytecode then either dispatch special purpose codegen routines
1829 * or produce corresponding Thumb instructions directly.
1830 */
1831
buzbeeed3e9302011-09-23 17:34:19 -07001832STATIC bool isPowerOfTwo(int x)
buzbee67bf8852011-08-17 17:51:35 -07001833{
1834 return (x & (x - 1)) == 0;
1835}
1836
1837// Returns true if no more than two bits are set in 'x'.
buzbeeed3e9302011-09-23 17:34:19 -07001838STATIC bool isPopCountLE2(unsigned int x)
buzbee67bf8852011-08-17 17:51:35 -07001839{
1840 x &= x - 1;
1841 return (x & (x - 1)) == 0;
1842}
1843
1844// Returns the index of the lowest set bit in 'x'.
buzbeeed3e9302011-09-23 17:34:19 -07001845STATIC int lowestSetBit(unsigned int x) {
buzbee67bf8852011-08-17 17:51:35 -07001846 int bit_posn = 0;
1847 while ((x & 0xf) == 0) {
1848 bit_posn += 4;
1849 x >>= 4;
1850 }
1851 while ((x & 1) == 0) {
1852 bit_posn++;
1853 x >>= 1;
1854 }
1855 return bit_posn;
1856}
1857
1858// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
1859// and store the result in 'rlDest'.
buzbeeed3e9302011-09-23 17:34:19 -07001860STATIC bool handleEasyDivide(CompilationUnit* cUnit, Opcode dalvikOpcode,
buzbee67bf8852011-08-17 17:51:35 -07001861 RegLocation rlSrc, RegLocation rlDest, int lit)
1862{
1863 if (lit < 2 || !isPowerOfTwo(lit)) {
1864 return false;
1865 }
1866 int k = lowestSetBit(lit);
1867 if (k >= 30) {
1868 // Avoid special cases.
1869 return false;
1870 }
1871 bool div = (dalvikOpcode == OP_DIV_INT_LIT8 ||
1872 dalvikOpcode == OP_DIV_INT_LIT16);
1873 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1874 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1875 if (div) {
1876 int tReg = oatAllocTemp(cUnit);
1877 if (lit == 2) {
1878 // Division by 2 is by far the most common division by constant.
1879 opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
1880 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1881 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1882 } else {
1883 opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
1884 opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
1885 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1886 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1887 }
1888 } else {
1889 int cReg = oatAllocTemp(cUnit);
1890 loadConstant(cUnit, cReg, lit - 1);
1891 int tReg1 = oatAllocTemp(cUnit);
1892 int tReg2 = oatAllocTemp(cUnit);
1893 if (lit == 2) {
1894 opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
1895 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1896 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1897 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1898 } else {
1899 opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
1900 opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
1901 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1902 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1903 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1904 }
1905 }
1906 storeValue(cUnit, rlDest, rlResult);
1907 return true;
1908}
1909
1910// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
1911// and store the result in 'rlDest'.
buzbeeed3e9302011-09-23 17:34:19 -07001912STATIC bool handleEasyMultiply(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -07001913 RegLocation rlSrc, RegLocation rlDest, int lit)
1914{
1915 // Can we simplify this multiplication?
1916 bool powerOfTwo = false;
1917 bool popCountLE2 = false;
1918 bool powerOfTwoMinusOne = false;
1919 if (lit < 2) {
1920 // Avoid special cases.
1921 return false;
1922 } else if (isPowerOfTwo(lit)) {
1923 powerOfTwo = true;
1924 } else if (isPopCountLE2(lit)) {
1925 popCountLE2 = true;
1926 } else if (isPowerOfTwo(lit + 1)) {
1927 powerOfTwoMinusOne = true;
1928 } else {
1929 return false;
1930 }
1931 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1932 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1933 if (powerOfTwo) {
1934 // Shift.
1935 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
1936 lowestSetBit(lit));
1937 } else if (popCountLE2) {
1938 // Shift and add and shift.
1939 int firstBit = lowestSetBit(lit);
1940 int secondBit = lowestSetBit(lit ^ (1 << firstBit));
1941 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
1942 firstBit, secondBit);
1943 } else {
1944 // Reverse subtract: (src << (shift + 1)) - src.
buzbeeed3e9302011-09-23 17:34:19 -07001945 DCHECK(powerOfTwoMinusOne);
buzbee5ade1d22011-09-09 14:44:52 -07001946 // TUNING: rsb dst, src, src lsl#lowestSetBit(lit + 1)
buzbee67bf8852011-08-17 17:51:35 -07001947 int tReg = oatAllocTemp(cUnit);
1948 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
1949 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
1950 }
1951 storeValue(cUnit, rlDest, rlResult);
1952 return true;
1953}
1954
buzbeeed3e9302011-09-23 17:34:19 -07001955STATIC bool genArithOpIntLit(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001956 RegLocation rlDest, RegLocation rlSrc,
1957 int lit)
1958{
1959 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1960 RegLocation rlResult;
1961 OpKind op = (OpKind)0; /* Make gcc happy */
1962 int shiftOp = false;
1963 bool isDiv = false;
1964 int funcOffset;
1965
1966 switch (dalvikOpcode) {
1967 case OP_RSUB_INT_LIT8:
1968 case OP_RSUB_INT: {
1969 int tReg;
1970 //TUNING: add support for use of Arm rsub op
1971 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1972 tReg = oatAllocTemp(cUnit);
1973 loadConstant(cUnit, tReg, lit);
1974 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1975 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1976 tReg, rlSrc.lowReg);
1977 storeValue(cUnit, rlDest, rlResult);
1978 return false;
1979 break;
1980 }
1981
1982 case OP_ADD_INT_LIT8:
1983 case OP_ADD_INT_LIT16:
1984 op = kOpAdd;
1985 break;
1986 case OP_MUL_INT_LIT8:
1987 case OP_MUL_INT_LIT16: {
1988 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
1989 return false;
1990 }
1991 op = kOpMul;
1992 break;
1993 }
1994 case OP_AND_INT_LIT8:
1995 case OP_AND_INT_LIT16:
1996 op = kOpAnd;
1997 break;
1998 case OP_OR_INT_LIT8:
1999 case OP_OR_INT_LIT16:
2000 op = kOpOr;
2001 break;
2002 case OP_XOR_INT_LIT8:
2003 case OP_XOR_INT_LIT16:
2004 op = kOpXor;
2005 break;
2006 case OP_SHL_INT_LIT8:
2007 lit &= 31;
2008 shiftOp = true;
2009 op = kOpLsl;
2010 break;
2011 case OP_SHR_INT_LIT8:
2012 lit &= 31;
2013 shiftOp = true;
2014 op = kOpAsr;
2015 break;
2016 case OP_USHR_INT_LIT8:
2017 lit &= 31;
2018 shiftOp = true;
2019 op = kOpLsr;
2020 break;
2021
2022 case OP_DIV_INT_LIT8:
2023 case OP_DIV_INT_LIT16:
2024 case OP_REM_INT_LIT8:
2025 case OP_REM_INT_LIT16:
2026 if (lit == 0) {
buzbee5ade1d22011-09-09 14:44:52 -07002027 genImmedCheck(cUnit, kArmCondAl, 0, 0, mir, kArmThrowDivZero);
buzbee67bf8852011-08-17 17:51:35 -07002028 return false;
2029 }
2030 if (handleEasyDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit)) {
2031 return false;
2032 }
2033 oatFlushAllRegs(cUnit); /* Everything to home location */
2034 loadValueDirectFixed(cUnit, rlSrc, r0);
2035 oatClobber(cUnit, r0);
2036 if ((dalvikOpcode == OP_DIV_INT_LIT8) ||
2037 (dalvikOpcode == OP_DIV_INT_LIT16)) {
2038 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
2039 isDiv = true;
2040 } else {
2041 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
2042 isDiv = false;
2043 }
2044 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
2045 loadConstant(cUnit, r1, lit);
Ian Rogersff1ed472011-09-20 13:46:24 -07002046 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07002047 if (isDiv)
2048 rlResult = oatGetReturn(cUnit);
2049 else
2050 rlResult = oatGetReturnAlt(cUnit);
2051 storeValue(cUnit, rlDest, rlResult);
2052 return false;
2053 break;
2054 default:
2055 return true;
2056 }
2057 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2058 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2059 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
2060 if (shiftOp && (lit == 0)) {
2061 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2062 } else {
2063 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2064 }
2065 storeValue(cUnit, rlDest, rlResult);
2066 return false;
2067}
2068
2069/* Architectural-specific debugging helpers go here */
2070void oatArchDump(void)
2071{
2072 /* Print compiled opcode in this VM instance */
2073 int i, start, streak;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002074 std::string buf;
buzbee67bf8852011-08-17 17:51:35 -07002075
2076 streak = i = 0;
buzbee67bf8852011-08-17 17:51:35 -07002077 while (opcodeCoverage[i] == 0 && i < kNumPackedOpcodes) {
2078 i++;
2079 }
2080 if (i == kNumPackedOpcodes) {
2081 return;
2082 }
2083 for (start = i++, streak = 1; i < kNumPackedOpcodes; i++) {
2084 if (opcodeCoverage[i]) {
2085 streak++;
2086 } else {
2087 if (streak == 1) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002088 StringAppendF(&buf, "%x,", start);
buzbee67bf8852011-08-17 17:51:35 -07002089 } else {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002090 StringAppendF(&buf, "%x-%x,", start, start + streak - 1);
buzbee67bf8852011-08-17 17:51:35 -07002091 }
2092 streak = 0;
2093 while (opcodeCoverage[i] == 0 && i < kNumPackedOpcodes) {
2094 i++;
2095 }
2096 if (i < kNumPackedOpcodes) {
2097 streak = 1;
2098 start = i;
2099 }
2100 }
2101 }
2102 if (streak) {
2103 if (streak == 1) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002104 StringAppendF(&buf, "%x", start);
buzbee67bf8852011-08-17 17:51:35 -07002105 } else {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002106 StringAppendF(&buf, "%x-%x", start, start + streak - 1);
buzbee67bf8852011-08-17 17:51:35 -07002107 }
2108 }
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002109 if (!buf.empty()) {
buzbee67bf8852011-08-17 17:51:35 -07002110 LOG(INFO) << "dalvik.vm.oat.op = " << buf;
2111 }
2112}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08002113
2114} // namespace art