blob: b02cde50c08ac46078293c579fadc6458bbea72e [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * This file contains codegen for the Thumb2 ISA and is intended to be
19 * includes by:
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 */
24
buzbeece302932011-10-04 14:32:18 -070025#define SLOW_FIELD_PATH (cUnit->enableDebug & (1 << kDebugSlowFieldPath))
26#define SLOW_INVOKE_PATH (cUnit->enableDebug & (1 << kDebugSlowInvokePath))
27#define SLOW_STRING_PATH (cUnit->enableDebug & (1 << kDebugSlowStringPath))
28#define SLOW_TYPE_PATH (cUnit->enableDebug & (1 << kDebugSlowTypePath))
29#define EXERCISE_SLOWEST_FIELD_PATH (cUnit->enableDebug & \
30 (1 << kDebugSlowestFieldPath))
31#define EXERCISE_SLOWEST_STRING_PATH (cUnit->enableDebug & \
32 (1 << kDebugSlowestStringPath))
33
34STATIC RegLocation getRetLoc(CompilationUnit* cUnit);
buzbee34cd9e52011-09-08 14:31:52 -070035
Elliott Hughes81bc5092011-09-30 17:25:59 -070036void warnIfUnresolved(CompilationUnit* cUnit, int fieldIdx, Field* field) {
37 if (field == NULL) {
Ian Rogersa3760aa2011-11-14 14:32:37 -080038 const art::DexFile::FieldId& field_id = cUnit->dex_file->GetFieldId(fieldIdx);
39 std::string class_name = cUnit->dex_file->GetFieldDeclaringClassDescriptor(field_id);
40 std::string field_name = cUnit->dex_file->GetFieldName(field_id);
41 LOG(INFO) << "Field " << art::PrettyDescriptor(class_name) << "."
42 << field_name << " unresolved at compile time";
Elliott Hughes81bc5092011-09-30 17:25:59 -070043 } else {
44 // We also use the slow path for wide volatile fields.
45 }
46}
47
buzbee67bf8852011-08-17 17:51:35 -070048/*
49 * Construct an s4 from two consecutive half-words of switch data.
50 * This needs to check endianness because the DEX optimizer only swaps
51 * half-words in instruction stream.
52 *
53 * "switchData" must be 32-bit aligned.
54 */
55#if __BYTE_ORDER == __LITTLE_ENDIAN
buzbeeed3e9302011-09-23 17:34:19 -070056STATIC inline s4 s4FromSwitchData(const void* switchData) {
buzbee67bf8852011-08-17 17:51:35 -070057 return *(s4*) switchData;
58}
59#else
buzbeeed3e9302011-09-23 17:34:19 -070060STATIC inline s4 s4FromSwitchData(const void* switchData) {
buzbee67bf8852011-08-17 17:51:35 -070061 u2* data = switchData;
62 return data[0] | (((s4) data[1]) << 16);
63}
64#endif
65
buzbeeed3e9302011-09-23 17:34:19 -070066STATIC ArmLIR* callRuntimeHelper(CompilationUnit* cUnit, int reg)
buzbeeec5adf32011-09-11 15:25:43 -070067{
buzbee6181f792011-09-29 11:14:04 -070068 oatClobberCalleeSave(cUnit);
buzbeeec5adf32011-09-11 15:25:43 -070069 return opReg(cUnit, kOpBlx, reg);
70}
71
buzbee1b4c8592011-08-31 10:43:51 -070072/* Generate unconditional branch instructions */
buzbeeed3e9302011-09-23 17:34:19 -070073STATIC ArmLIR* genUnconditionalBranch(CompilationUnit* cUnit, ArmLIR* target)
buzbee1b4c8592011-08-31 10:43:51 -070074{
75 ArmLIR* branch = opNone(cUnit, kOpUncondBr);
76 branch->generic.target = (LIR*) target;
77 return branch;
78}
79
buzbee67bf8852011-08-17 17:51:35 -070080/*
81 * Generate a Thumb2 IT instruction, which can nullify up to
82 * four subsequent instructions based on a condition and its
83 * inverse. The condition applies to the first instruction, which
84 * is executed if the condition is met. The string "guide" consists
85 * of 0 to 3 chars, and applies to the 2nd through 4th instruction.
86 * A "T" means the instruction is executed if the condition is
87 * met, and an "E" means the instruction is executed if the condition
88 * is not met.
89 */
buzbeeed3e9302011-09-23 17:34:19 -070090STATIC ArmLIR* genIT(CompilationUnit* cUnit, ArmConditionCode code,
buzbee67bf8852011-08-17 17:51:35 -070091 const char* guide)
92{
93 int mask;
94 int condBit = code & 1;
95 int altBit = condBit ^ 1;
96 int mask3 = 0;
97 int mask2 = 0;
98 int mask1 = 0;
99
100 //Note: case fallthroughs intentional
101 switch(strlen(guide)) {
102 case 3:
103 mask1 = (guide[2] == 'T') ? condBit : altBit;
104 case 2:
105 mask2 = (guide[1] == 'T') ? condBit : altBit;
106 case 1:
107 mask3 = (guide[0] == 'T') ? condBit : altBit;
108 break;
109 case 0:
110 break;
111 default:
112 LOG(FATAL) << "OAT: bad case in genIT";
113 }
114 mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
115 (1 << (3 - strlen(guide)));
116 return newLIR2(cUnit, kThumb2It, code, mask);
117}
118
119/*
120 * Insert a kArmPseudoCaseLabel at the beginning of the Dalvik
121 * offset vaddr. This label will be used to fix up the case
122 * branch table during the assembly phase. Be sure to set
123 * all resource flags on this to prevent code motion across
124 * target boundaries. KeyVal is just there for debugging.
125 */
buzbeeed3e9302011-09-23 17:34:19 -0700126STATIC ArmLIR* insertCaseLabel(CompilationUnit* cUnit, int vaddr, int keyVal)
buzbee67bf8852011-08-17 17:51:35 -0700127{
128 ArmLIR* lir;
129 for (lir = (ArmLIR*)cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
130 if ((lir->opcode == kArmPseudoDalvikByteCodeBoundary) &&
131 (lir->generic.dalvikOffset == vaddr)) {
132 ArmLIR* newLabel = (ArmLIR*)oatNew(sizeof(ArmLIR), true);
133 newLabel->generic.dalvikOffset = vaddr;
134 newLabel->opcode = kArmPseudoCaseLabel;
135 newLabel->operands[0] = keyVal;
136 oatInsertLIRAfter((LIR*)lir, (LIR*)newLabel);
137 return newLabel;
138 }
139 }
140 oatCodegenDump(cUnit);
141 LOG(FATAL) << "Error: didn't find vaddr 0x" << std::hex << vaddr;
142 return NULL; // Quiet gcc
143}
144
buzbeeed3e9302011-09-23 17:34:19 -0700145STATIC void markPackedCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
buzbee67bf8852011-08-17 17:51:35 -0700146{
147 const u2* table = tabRec->table;
148 int baseVaddr = tabRec->vaddr;
149 int *targets = (int*)&table[4];
150 int entries = table[1];
151 int lowKey = s4FromSwitchData(&table[2]);
152 for (int i = 0; i < entries; i++) {
153 tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
154 i + lowKey);
155 }
156}
157
buzbeeed3e9302011-09-23 17:34:19 -0700158STATIC void markSparseCaseLabels(CompilationUnit* cUnit, SwitchTable *tabRec)
buzbee67bf8852011-08-17 17:51:35 -0700159{
160 const u2* table = tabRec->table;
161 int baseVaddr = tabRec->vaddr;
162 int entries = table[1];
163 int* keys = (int*)&table[2];
164 int* targets = &keys[entries];
165 for (int i = 0; i < entries; i++) {
166 tabRec->targets[i] = insertCaseLabel(cUnit, baseVaddr + targets[i],
167 keys[i]);
168 }
169}
170
171void oatProcessSwitchTables(CompilationUnit* cUnit)
172{
173 GrowableListIterator iterator;
174 oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
175 while (true) {
176 SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
177 &iterator);
178 if (tabRec == NULL) break;
179 if (tabRec->table[0] == kPackedSwitchSignature)
180 markPackedCaseLabels(cUnit, tabRec);
181 else if (tabRec->table[0] == kSparseSwitchSignature)
182 markSparseCaseLabels(cUnit, tabRec);
183 else {
184 LOG(FATAL) << "Invalid switch table";
185 }
186 }
187}
188
buzbeeed3e9302011-09-23 17:34:19 -0700189STATIC void dumpSparseSwitchTable(const u2* table)
buzbee67bf8852011-08-17 17:51:35 -0700190 /*
191 * Sparse switch data format:
192 * ushort ident = 0x0200 magic value
193 * ushort size number of entries in the table; > 0
194 * int keys[size] keys, sorted low-to-high; 32-bit aligned
195 * int targets[size] branch targets, relative to switch opcode
196 *
197 * Total size is (2+size*4) 16-bit code units.
198 */
199{
200 u2 ident = table[0];
201 int entries = table[1];
202 int* keys = (int*)&table[2];
203 int* targets = &keys[entries];
204 LOG(INFO) << "Sparse switch table - ident:0x" << std::hex << ident <<
205 ", entries: " << std::dec << entries;
206 for (int i = 0; i < entries; i++) {
207 LOG(INFO) << " Key[" << keys[i] << "] -> 0x" << std::hex <<
208 targets[i];
209 }
210}
211
buzbeeed3e9302011-09-23 17:34:19 -0700212STATIC void dumpPackedSwitchTable(const u2* table)
buzbee67bf8852011-08-17 17:51:35 -0700213 /*
214 * Packed switch data format:
215 * ushort ident = 0x0100 magic value
216 * ushort size number of entries in the table
217 * int first_key first (and lowest) switch case value
218 * int targets[size] branch targets, relative to switch opcode
219 *
220 * Total size is (4+size*2) 16-bit code units.
221 */
222{
223 u2 ident = table[0];
224 int* targets = (int*)&table[4];
225 int entries = table[1];
226 int lowKey = s4FromSwitchData(&table[2]);
227 LOG(INFO) << "Packed switch table - ident:0x" << std::hex << ident <<
228 ", entries: " << std::dec << entries << ", lowKey: " << lowKey;
229 for (int i = 0; i < entries; i++) {
230 LOG(INFO) << " Key[" << (i + lowKey) << "] -> 0x" << std::hex <<
231 targets[i];
232 }
233}
234
235/*
236 * The sparse table in the literal pool is an array of <key,displacement>
237 * pairs. For each set, we'll load them as a pair using ldmia.
238 * This means that the register number of the temp we use for the key
239 * must be lower than the reg for the displacement.
240 *
241 * The test loop will look something like:
242 *
243 * adr rBase, <table>
244 * ldr rVal, [rSP, vRegOff]
245 * mov rIdx, #tableSize
246 * lp:
247 * ldmia rBase!, {rKey, rDisp}
248 * sub rIdx, #1
249 * cmp rVal, rKey
250 * ifeq
251 * add rPC, rDisp ; This is the branch from which we compute displacement
252 * cbnz rIdx, lp
253 */
buzbeeed3e9302011-09-23 17:34:19 -0700254STATIC void genSparseSwitch(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700255 RegLocation rlSrc)
256{
257 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
258 if (cUnit->printMe) {
259 dumpSparseSwitchTable(table);
260 }
261 // Add the table to the list - we'll process it later
262 SwitchTable *tabRec = (SwitchTable *)oatNew(sizeof(SwitchTable),
263 true);
264 tabRec->table = table;
265 tabRec->vaddr = mir->offset;
266 int size = table[1];
267 tabRec->targets = (ArmLIR* *)oatNew(size * sizeof(ArmLIR*), true);
268 oatInsertGrowableList(&cUnit->switchTables, (intptr_t)tabRec);
269
270 // Get the switch value
271 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
272 int rBase = oatAllocTemp(cUnit);
273 /* Allocate key and disp temps */
274 int rKey = oatAllocTemp(cUnit);
275 int rDisp = oatAllocTemp(cUnit);
276 // Make sure rKey's register number is less than rDisp's number for ldmia
277 if (rKey > rDisp) {
278 int tmp = rDisp;
279 rDisp = rKey;
280 rKey = tmp;
281 }
282 // Materialize a pointer to the switch table
buzbee03fa2632011-09-20 17:10:57 -0700283 newLIR3(cUnit, kThumb2Adr, rBase, 0, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700284 // Set up rIdx
285 int rIdx = oatAllocTemp(cUnit);
286 loadConstant(cUnit, rIdx, size);
287 // Establish loop branch target
288 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
289 target->defMask = ENCODE_ALL;
290 // Load next key/disp
291 newLIR2(cUnit, kThumb2LdmiaWB, rBase, (1 << rKey) | (1 << rDisp));
292 opRegReg(cUnit, kOpCmp, rKey, rlSrc.lowReg);
293 // Go if match. NOTE: No instruction set switch here - must stay Thumb2
294 genIT(cUnit, kArmCondEq, "");
295 ArmLIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, rDisp);
296 tabRec->bxInst = switchBranch;
297 // Needs to use setflags encoding here
298 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
299 ArmLIR* branch = opCondBranch(cUnit, kArmCondNe);
300 branch->generic.target = (LIR*)target;
301}
302
303
buzbeeed3e9302011-09-23 17:34:19 -0700304STATIC void genPackedSwitch(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700305 RegLocation rlSrc)
306{
307 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
308 if (cUnit->printMe) {
309 dumpPackedSwitchTable(table);
310 }
311 // Add the table to the list - we'll process it later
312 SwitchTable *tabRec = (SwitchTable *)oatNew(sizeof(SwitchTable),
313 true);
314 tabRec->table = table;
315 tabRec->vaddr = mir->offset;
316 int size = table[1];
317 tabRec->targets = (ArmLIR* *)oatNew(size * sizeof(ArmLIR*), true);
318 oatInsertGrowableList(&cUnit->switchTables, (intptr_t)tabRec);
319
320 // Get the switch value
321 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
322 int tableBase = oatAllocTemp(cUnit);
323 // Materialize a pointer to the switch table
buzbee03fa2632011-09-20 17:10:57 -0700324 newLIR3(cUnit, kThumb2Adr, tableBase, 0, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700325 int lowKey = s4FromSwitchData(&table[2]);
326 int keyReg;
327 // Remove the bias, if necessary
328 if (lowKey == 0) {
329 keyReg = rlSrc.lowReg;
330 } else {
331 keyReg = oatAllocTemp(cUnit);
332 opRegRegImm(cUnit, kOpSub, keyReg, rlSrc.lowReg, lowKey);
333 }
334 // Bounds check - if < 0 or >= size continue following switch
335 opRegImm(cUnit, kOpCmp, keyReg, size-1);
336 ArmLIR* branchOver = opCondBranch(cUnit, kArmCondHi);
337
338 // Load the displacement from the switch table
339 int dispReg = oatAllocTemp(cUnit);
340 loadBaseIndexed(cUnit, tableBase, keyReg, dispReg, 2, kWord);
341
342 // ..and go! NOTE: No instruction set switch here - must stay Thumb2
343 ArmLIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, dispReg);
344 tabRec->bxInst = switchBranch;
345
346 /* branchOver target here */
347 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
348 target->defMask = ENCODE_ALL;
349 branchOver->generic.target = (LIR*)target;
350}
351
352/*
353 * Array data table format:
354 * ushort ident = 0x0300 magic value
355 * ushort width width of each element in the table
356 * uint size number of elements in the table
357 * ubyte data[size*width] table of data values (may contain a single-byte
358 * padding at the end)
359 *
360 * Total size is 4+(width * size + 1)/2 16-bit code units.
361 */
buzbeeed3e9302011-09-23 17:34:19 -0700362STATIC void genFillArrayData(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700363 RegLocation rlSrc)
364{
365 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
366 // Add the table to the list - we'll process it later
367 FillArrayData *tabRec = (FillArrayData *)
368 oatNew(sizeof(FillArrayData), true);
369 tabRec->table = table;
370 tabRec->vaddr = mir->offset;
371 u2 width = tabRec->table[1];
372 u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
373 tabRec->size = (size * width) + 8;
374
375 oatInsertGrowableList(&cUnit->fillArrayData, (intptr_t)tabRec);
376
377 // Making a call - use explicit registers
378 oatFlushAllRegs(cUnit); /* Everything to home location */
379 loadValueDirectFixed(cUnit, rlSrc, r0);
380 loadWordDisp(cUnit, rSELF,
buzbee1b4c8592011-08-31 10:43:51 -0700381 OFFSETOF_MEMBER(Thread, pHandleFillArrayDataFromCode), rLR);
buzbeee6d61962011-08-27 11:58:19 -0700382 // Materialize a pointer to the fill data image
buzbee03fa2632011-09-20 17:10:57 -0700383 newLIR3(cUnit, kThumb2Adr, r1, 0, (intptr_t)tabRec);
Ian Rogersff1ed472011-09-20 13:46:24 -0700384 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700385}
386
387/*
388 * Mark garbage collection card. Skip if the value we're storing is null.
389 */
buzbeeed3e9302011-09-23 17:34:19 -0700390STATIC void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg)
buzbee67bf8852011-08-17 17:51:35 -0700391{
392 int regCardBase = oatAllocTemp(cUnit);
393 int regCardNo = oatAllocTemp(cUnit);
394 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondEq, valReg, 0);
buzbeec143c552011-08-20 17:38:58 -0700395 loadWordDisp(cUnit, rSELF, Thread::CardTableOffset().Int32Value(),
buzbee67bf8852011-08-17 17:51:35 -0700396 regCardBase);
397 opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT);
398 storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
399 kUnsignedByte);
400 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
401 target->defMask = ENCODE_ALL;
402 branchOver->generic.target = (LIR*)target;
403 oatFreeTemp(cUnit, regCardBase);
404 oatFreeTemp(cUnit, regCardNo);
405}
406
buzbee34cd9e52011-09-08 14:31:52 -0700407/*
408 * Helper function for Iget/put when field not resolved at compile time.
409 * Will trash call temps and return with the field offset in r0.
410 */
Elliott Hughes81bc5092011-09-30 17:25:59 -0700411STATIC void getFieldOffset(CompilationUnit* cUnit, MIR* mir, Field* fieldPtr)
buzbee34cd9e52011-09-08 14:31:52 -0700412{
413 int fieldIdx = mir->dalvikInsn.vC;
buzbee6181f792011-09-29 11:14:04 -0700414 oatFlushAllRegs(cUnit);
Elliott Hughes81bc5092011-09-30 17:25:59 -0700415 warnIfUnresolved(cUnit, fieldIdx, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700416 oatLockCallTemps(cUnit); // Explicit register usage
417 loadCurrMethodDirect(cUnit, r1); // arg1 <= Method*
418 loadWordDisp(cUnit, r1,
419 Method::DexCacheResolvedFieldsOffset().Int32Value(), r0);
420 loadWordDisp(cUnit, r0, art::Array::DataOffset().Int32Value() +
421 sizeof(int32_t*)* fieldIdx, r0);
422 /*
423 * For testing, omit the test for run-time resolution. This will
424 * force all accesses to go through the runtime resolution path.
425 */
buzbeece302932011-10-04 14:32:18 -0700426 ArmLIR* branchOver = NULL;
427 if (!EXERCISE_SLOWEST_FIELD_PATH) {
428 branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0);
429 }
buzbee34cd9e52011-09-08 14:31:52 -0700430 // Resolve
431 loadWordDisp(cUnit, rSELF,
Brian Carlstrom845490b2011-09-19 15:56:53 -0700432 OFFSETOF_MEMBER(Thread, pFindInstanceFieldFromCode), rLR);
buzbee34cd9e52011-09-08 14:31:52 -0700433 loadConstant(cUnit, r0, fieldIdx);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700434 callRuntimeHelper(cUnit, rLR); // FindInstanceFieldFromCoderesolveTypeFromCode(idx, method)
buzbee34cd9e52011-09-08 14:31:52 -0700435 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
436 target->defMask = ENCODE_ALL;
buzbeece302932011-10-04 14:32:18 -0700437 if (!EXERCISE_SLOWEST_FIELD_PATH) {
438 branchOver->generic.target = (LIR*)target;
439 }
buzbee34cd9e52011-09-08 14:31:52 -0700440 // Free temps (except for r0)
441 oatFreeTemp(cUnit, r1);
442 oatFreeTemp(cUnit, r2);
443 oatFreeTemp(cUnit, r3);
444 loadWordDisp(cUnit, r0, art::Field::OffsetOffset().Int32Value(), r0);
445}
446
buzbeeed3e9302011-09-23 17:34:19 -0700447STATIC void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -0700448 RegLocation rlDest, RegLocation rlObj)
449{
Ian Rogersa3760aa2011-11-14 14:32:37 -0800450 Field* fieldPtr = cUnit->dex_cache->GetResolvedField(mir->dalvikInsn.vC);
buzbee67bf8852011-08-17 17:51:35 -0700451 RegLocation rlResult;
452 RegisterClass regClass = oatRegClassBySize(size);
buzbee34cd9e52011-09-08 14:31:52 -0700453 if (SLOW_FIELD_PATH || fieldPtr == NULL) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700454 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700455 // Field offset in r0
456 rlObj = loadValue(cUnit, rlObj, kCoreReg);
457 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
buzbee5ade1d22011-09-09 14:44:52 -0700458 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
buzbee58f92742011-10-01 11:22:17 -0700459 loadBaseIndexed(cUnit, rlObj.lowReg, r0, rlResult.lowReg, 0, kWord);
buzbee67bf8852011-08-17 17:51:35 -0700460 oatGenMemBarrier(cUnit, kSY);
buzbee34cd9e52011-09-08 14:31:52 -0700461 storeValue(cUnit, rlDest, rlResult);
462 } else {
463#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700464 bool isVolatile = fieldPtr->IsVolatile();
buzbee34cd9e52011-09-08 14:31:52 -0700465#else
466 bool isVolatile = false;
467#endif
468 int fieldOffset = fieldPtr->GetOffset().Int32Value();
469 rlObj = loadValue(cUnit, rlObj, kCoreReg);
470 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
buzbee5ade1d22011-09-09 14:44:52 -0700471 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
buzbee34cd9e52011-09-08 14:31:52 -0700472 loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
buzbee58f92742011-10-01 11:22:17 -0700473 kWord, rlObj.sRegLow);
buzbee34cd9e52011-09-08 14:31:52 -0700474 if (isVolatile) {
475 oatGenMemBarrier(cUnit, kSY);
476 }
477 storeValue(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -0700478 }
buzbee67bf8852011-08-17 17:51:35 -0700479}
480
buzbeeed3e9302011-09-23 17:34:19 -0700481STATIC void genIPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -0700482 RegLocation rlSrc, RegLocation rlObj, bool isObject)
483{
Ian Rogersa3760aa2011-11-14 14:32:37 -0800484 Field* fieldPtr = cUnit->dex_cache->GetResolvedField(mir->dalvikInsn.vC);
buzbee67bf8852011-08-17 17:51:35 -0700485 RegisterClass regClass = oatRegClassBySize(size);
buzbee34cd9e52011-09-08 14:31:52 -0700486 if (SLOW_FIELD_PATH || fieldPtr == NULL) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700487 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700488 // Field offset in r0
489 rlObj = loadValue(cUnit, rlObj, kCoreReg);
490 rlSrc = loadValue(cUnit, rlSrc, regClass);
buzbee5ade1d22011-09-09 14:44:52 -0700491 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
buzbee67bf8852011-08-17 17:51:35 -0700492 oatGenMemBarrier(cUnit, kSY);
buzbee58f92742011-10-01 11:22:17 -0700493 storeBaseIndexed(cUnit, rlObj.lowReg, r0, rlSrc.lowReg, 0, kWord);
buzbee34cd9e52011-09-08 14:31:52 -0700494 } else {
495#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700496 bool isVolatile = fieldPtr->IsVolatile();
buzbee34cd9e52011-09-08 14:31:52 -0700497#else
498 bool isVolatile = false;
499#endif
500 int fieldOffset = fieldPtr->GetOffset().Int32Value();
501 rlObj = loadValue(cUnit, rlObj, kCoreReg);
502 rlSrc = loadValue(cUnit, rlSrc, regClass);
buzbee5ade1d22011-09-09 14:44:52 -0700503 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700504
505 if (isVolatile) {
buzbee12246b82011-09-29 14:15:05 -0700506 oatGenMemBarrier(cUnit, kST);
buzbee34cd9e52011-09-08 14:31:52 -0700507 }
buzbee58f92742011-10-01 11:22:17 -0700508 storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, kWord);
buzbee12246b82011-09-29 14:15:05 -0700509 if (isVolatile) {
510 oatGenMemBarrier(cUnit, kSY);
511 }
buzbee67bf8852011-08-17 17:51:35 -0700512 }
buzbee67bf8852011-08-17 17:51:35 -0700513 if (isObject) {
514 /* NOTE: marking card based on object head */
515 markGCCard(cUnit, rlSrc.lowReg, rlObj.lowReg);
516 }
517}
518
buzbeeed3e9302011-09-23 17:34:19 -0700519STATIC void genIGetWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700520 RegLocation rlObj)
521{
buzbee12246b82011-09-29 14:15:05 -0700522 RegLocation rlResult;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800523 Field* fieldPtr = cUnit->dex_cache->GetResolvedField(mir->dalvikInsn.vC);
buzbee12246b82011-09-29 14:15:05 -0700524#if ANDROID_SMP != 0
525 bool isVolatile = (fieldPtr == NULL) || fieldPtr->IsVolatile();
526#else
527 bool isVolatile = false;
528#endif
buzbeece302932011-10-04 14:32:18 -0700529 if (SLOW_FIELD_PATH || (fieldPtr == NULL) || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700530 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700531 // Field offset in r0
532 rlObj = loadValue(cUnit, rlObj, kCoreReg);
533 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee5ade1d22011-09-09 14:44:52 -0700534 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700535 opRegReg(cUnit, kOpAdd, r0, rlObj.lowReg);
536 loadPair(cUnit, r0, rlResult.lowReg, rlResult.highReg);
buzbee67bf8852011-08-17 17:51:35 -0700537 oatGenMemBarrier(cUnit, kSY);
buzbee12246b82011-09-29 14:15:05 -0700538 storeValueWide(cUnit, rlDest, rlResult);
buzbee34cd9e52011-09-08 14:31:52 -0700539 } else {
buzbee34cd9e52011-09-08 14:31:52 -0700540 int fieldOffset = fieldPtr->GetOffset().Int32Value();
541 rlObj = loadValue(cUnit, rlObj, kCoreReg);
542 int regPtr = oatAllocTemp(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700543
buzbeeed3e9302011-09-23 17:34:19 -0700544 DCHECK(rlDest.wide);
buzbee34cd9e52011-09-08 14:31:52 -0700545
buzbee5ade1d22011-09-09 14:44:52 -0700546 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700547 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
548 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
549
550 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
551
buzbee34cd9e52011-09-08 14:31:52 -0700552 oatFreeTemp(cUnit, regPtr);
553 storeValueWide(cUnit, rlDest, rlResult);
554 }
buzbee67bf8852011-08-17 17:51:35 -0700555}
556
buzbeeed3e9302011-09-23 17:34:19 -0700557STATIC void genIPutWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
buzbee67bf8852011-08-17 17:51:35 -0700558 RegLocation rlObj)
559{
Ian Rogersa3760aa2011-11-14 14:32:37 -0800560 Field* fieldPtr = cUnit->dex_cache->GetResolvedField(mir->dalvikInsn.vC);
buzbee12246b82011-09-29 14:15:05 -0700561#if ANDROID_SMP != 0
562 bool isVolatile = (fieldPtr == NULL) || fieldPtr->IsVolatile();
563#else
564 bool isVolatile = false;
565#endif
buzbeece302932011-10-04 14:32:18 -0700566 if (SLOW_FIELD_PATH || (fieldPtr == NULL) || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700567 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700568 // Field offset in r0
569 rlObj = loadValue(cUnit, rlObj, kCoreReg);
570 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
buzbee5ade1d22011-09-09 14:44:52 -0700571 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700572 opRegReg(cUnit, kOpAdd, r0, rlObj.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700573 oatGenMemBarrier(cUnit, kSY);
buzbee34cd9e52011-09-08 14:31:52 -0700574 storePair(cUnit, r0, rlSrc.lowReg, rlSrc.highReg);
575 } else {
buzbee34cd9e52011-09-08 14:31:52 -0700576 int fieldOffset = fieldPtr->GetOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -0700577
buzbee34cd9e52011-09-08 14:31:52 -0700578 rlObj = loadValue(cUnit, rlObj, kCoreReg);
579 int regPtr;
580 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
buzbee5ade1d22011-09-09 14:44:52 -0700581 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700582 regPtr = oatAllocTemp(cUnit);
583 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
584
buzbee34cd9e52011-09-08 14:31:52 -0700585 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
586
587 oatFreeTemp(cUnit, regPtr);
588 }
buzbee67bf8852011-08-17 17:51:35 -0700589}
590
buzbeeed3e9302011-09-23 17:34:19 -0700591STATIC void genConstClass(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700592 RegLocation rlDest, RegLocation rlSrc)
593{
Ian Rogers28ad40d2011-10-27 15:19:26 -0700594 uint32_t type_idx = mir->dalvikInsn.vB;
buzbee1b4c8592011-08-31 10:43:51 -0700595 int mReg = loadCurrMethod(cUnit);
596 int resReg = oatAllocTemp(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700597 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
Ian Rogersa3760aa2011-11-14 14:32:37 -0800598 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
599 cUnit->dex_cache,
600 *cUnit->dex_file,
601 type_idx)) {
602 // Call out to helper which resolves type and verifies access.
603 // Resolved type returned in r0.
604 loadWordDisp(cUnit, rSELF,
605 OFFSETOF_MEMBER(Thread, pInitializeTypeAndVerifyAccessFromCode),
606 rLR);
607 genRegCopy(cUnit, r1, mReg);
608 loadConstant(cUnit, r0, type_idx);
609 callRuntimeHelper(cUnit, rLR);
610 RegLocation rlResult = oatGetReturn(cUnit);
611 storeValue(cUnit, rlDest, rlResult);
buzbee1b4c8592011-08-31 10:43:51 -0700612 } else {
Ian Rogers28ad40d2011-10-27 15:19:26 -0700613 // We're don't need access checks, load type from dex cache
614 int32_t dex_cache_offset = Method::DexCacheResolvedTypesOffset().Int32Value();
615 loadWordDisp(cUnit, mReg, dex_cache_offset, resReg);
616 int32_t offset_of_type = Array::DataOffset().Int32Value() + (sizeof(Class*) * type_idx);
617 loadWordDisp(cUnit, resReg, offset_of_type, rlResult.lowReg);
Ian Rogersa3760aa2011-11-14 14:32:37 -0800618 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->dex_cache,
619 type_idx) ||
Ian Rogers28ad40d2011-10-27 15:19:26 -0700620 SLOW_TYPE_PATH) {
621 // Slow path, at runtime test if the type is null and if so initialize
622 oatFlushAllRegs(cUnit);
623 ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, rlResult.lowReg, 0);
624 // Resolved, store and hop over following code
625 storeValue(cUnit, rlDest, rlResult);
626 ArmLIR* branch2 = genUnconditionalBranch(cUnit,0);
627 // TUNING: move slow path to end & remove unconditional branch
628 ArmLIR* target1 = newLIR0(cUnit, kArmPseudoTargetLabel);
629 target1->defMask = ENCODE_ALL;
630 // Call out to helper, which will return resolved type in r0
631 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
632 genRegCopy(cUnit, r1, mReg);
633 loadConstant(cUnit, r0, type_idx);
634 callRuntimeHelper(cUnit, rLR);
635 RegLocation rlResult = oatGetReturn(cUnit);
636 storeValue(cUnit, rlDest, rlResult);
637 // Rejoin code paths
638 ArmLIR* target2 = newLIR0(cUnit, kArmPseudoTargetLabel);
639 target2->defMask = ENCODE_ALL;
640 branch1->generic.target = (LIR*)target1;
641 branch2->generic.target = (LIR*)target2;
642 } else {
643 // Fast path, we're done - just store result
644 storeValue(cUnit, rlDest, rlResult);
645 }
buzbee1b4c8592011-08-31 10:43:51 -0700646 }
buzbee67bf8852011-08-17 17:51:35 -0700647}
648
buzbeeed3e9302011-09-23 17:34:19 -0700649STATIC void genConstString(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700650 RegLocation rlDest, RegLocation rlSrc)
651{
buzbeece302932011-10-04 14:32:18 -0700652 /* NOTE: Most strings should be available at compile time */
Ian Rogers28ad40d2011-10-27 15:19:26 -0700653 uint32_t string_idx = mir->dalvikInsn.vB;
654 int32_t offset_of_string = Array::DataOffset().Int32Value() + (sizeof(String*) * string_idx);
Ian Rogersa3760aa2011-11-14 14:32:37 -0800655 if (!cUnit->compiler->CanAssumeStringIsPresentInDexCache(cUnit->dex_cache, string_idx) ||
Ian Rogers28ad40d2011-10-27 15:19:26 -0700656 SLOW_STRING_PATH) {
657 // slow path, resolve string if not in dex cache
buzbeece302932011-10-04 14:32:18 -0700658 oatFlushAllRegs(cUnit);
659 oatLockCallTemps(cUnit); // Using explicit registers
660 loadCurrMethodDirect(cUnit, r2);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700661 loadWordDisp(cUnit, r2, Method::DexCacheStringsOffset().Int32Value(), r0);
buzbeece302932011-10-04 14:32:18 -0700662 // Might call out to helper, which will return resolved string in r0
Ian Rogers28ad40d2011-10-27 15:19:26 -0700663 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pResolveStringFromCode), rLR);
664 loadWordDisp(cUnit, r0, offset_of_string, r0);
665 loadConstant(cUnit, r1, string_idx);
buzbeece302932011-10-04 14:32:18 -0700666 opRegImm(cUnit, kOpCmp, r0, 0); // Is resolved?
667 genBarrier(cUnit);
668 // For testing, always force through helper
669 if (!EXERCISE_SLOWEST_STRING_PATH) {
670 genIT(cUnit, kArmCondEq, "T");
671 }
672 genRegCopy(cUnit, r0, r2); // .eq
673 opReg(cUnit, kOpBlx, rLR); // .eq, helper(Method*, string_idx)
674 genBarrier(cUnit);
675 storeValue(cUnit, rlDest, getRetLoc(cUnit));
676 } else {
677 int mReg = loadCurrMethod(cUnit);
678 int resReg = oatAllocTemp(cUnit);
679 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700680 loadWordDisp(cUnit, mReg, Method::DexCacheStringsOffset().Int32Value(), resReg);
681 loadWordDisp(cUnit, resReg, offset_of_string, rlResult.lowReg);
buzbeece302932011-10-04 14:32:18 -0700682 storeValue(cUnit, rlDest, rlResult);
683 }
buzbee67bf8852011-08-17 17:51:35 -0700684}
685
buzbeedfd3d702011-08-28 12:56:51 -0700686/*
687 * Let helper function take care of everything. Will
688 * call Class::NewInstanceFromCode(type_idx, method);
689 */
buzbeeed3e9302011-09-23 17:34:19 -0700690STATIC void genNewInstance(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700691 RegLocation rlDest)
692{
buzbeedfd3d702011-08-28 12:56:51 -0700693 oatFlushAllRegs(cUnit); /* Everything to home location */
Ian Rogers28ad40d2011-10-27 15:19:26 -0700694 uint32_t type_idx = mir->dalvikInsn.vB;
695 // alloc will always check for resolution, do we also need to verify access because the
696 // verifier was unable to?
Ian Rogersa3760aa2011-11-14 14:32:37 -0800697 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
698 cUnit->dex_cache,
699 *cUnit->dex_file,
700 type_idx)) {
Ian Rogers28ad40d2011-10-27 15:19:26 -0700701 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pAllocObjectFromCode), rLR);
702 } else {
703 loadWordDisp(cUnit, rSELF,
704 OFFSETOF_MEMBER(Thread, pAllocObjectFromCodeWithAccessCheck), rLR);
705 }
706 loadCurrMethodDirect(cUnit, r1); // arg1 <= Method*
707 loadConstant(cUnit, r0, type_idx); // arg0 <- type_idx
Ian Rogersff1ed472011-09-20 13:46:24 -0700708 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700709 RegLocation rlResult = oatGetReturn(cUnit);
710 storeValue(cUnit, rlDest, rlResult);
711}
712
713void genThrow(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
714{
buzbee6181f792011-09-29 11:14:04 -0700715 oatFlushAllRegs(cUnit);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700716 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pDeliverException), rLR);
Ian Rogersbdb03912011-09-14 00:55:44 -0700717 loadValueDirectFixed(cUnit, rlSrc, r0); // Get exception object
Ian Rogersff1ed472011-09-20 13:46:24 -0700718 callRuntimeHelper(cUnit, rLR); // art_deliver_exception(exception);
buzbee67bf8852011-08-17 17:51:35 -0700719}
720
buzbeeed3e9302011-09-23 17:34:19 -0700721STATIC void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700722 RegLocation rlSrc)
723{
buzbee6181f792011-09-29 11:14:04 -0700724 oatFlushAllRegs(cUnit);
buzbee2a475e72011-09-07 17:19:17 -0700725 // May generate a call - use explicit registers
726 oatLockCallTemps(cUnit);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700727 uint32_t type_idx = mir->dalvikInsn.vC;
buzbee2a475e72011-09-07 17:19:17 -0700728 loadCurrMethodDirect(cUnit, r1); // r1 <= current Method*
Ian Rogers28ad40d2011-10-27 15:19:26 -0700729 int classReg = r2; // r2 will hold the Class*
Ian Rogersa3760aa2011-11-14 14:32:37 -0800730 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
731 cUnit->dex_cache,
732 *cUnit->dex_file,
733 type_idx)) {
Ian Rogersb093c6b2011-10-31 16:19:55 -0700734 // Check we have access to type_idx and if not throw IllegalAccessError,
735 // returns Class* in r0
736 loadWordDisp(cUnit, rSELF,
737 OFFSETOF_MEMBER(Thread, pInitializeTypeAndVerifyAccessFromCode),
738 rLR);
739 loadConstant(cUnit, r0, type_idx);
740 callRuntimeHelper(cUnit, rLR); // InitializeTypeAndVerifyAccess(idx, method)
741 genRegCopy(cUnit, classReg, r0); // Align usage with fast path
Ian Rogers6a996782011-10-31 17:06:39 -0700742 loadValueDirectFixed(cUnit, rlSrc, r0); // r0 <= ref
Ian Rogers28ad40d2011-10-27 15:19:26 -0700743 } else {
744 // Load dex cache entry into classReg (r2)
Ian Rogers6a996782011-10-31 17:06:39 -0700745 loadValueDirectFixed(cUnit, rlSrc, r0); // r0 <= ref
Ian Rogers28ad40d2011-10-27 15:19:26 -0700746 loadWordDisp(cUnit, r1, Method::DexCacheResolvedTypesOffset().Int32Value(), classReg);
747 int32_t offset_of_type = Array::DataOffset().Int32Value() + (sizeof(Class*) * type_idx);
748 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
Ian Rogersa3760aa2011-11-14 14:32:37 -0800749 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->dex_cache, type_idx)) {
Ian Rogers28ad40d2011-10-27 15:19:26 -0700750 // Need to test presence of type in dex cache at runtime
751 ArmLIR* hopBranch = genCmpImmBranch(cUnit, kArmCondNe, classReg, 0);
752 // Not resolved
753 // Call out to helper, which will return resolved type in r0
754 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
755 loadConstant(cUnit, r0, type_idx);
Ian Rogersb093c6b2011-10-31 16:19:55 -0700756 callRuntimeHelper(cUnit, rLR); // InitializeTypeFromCode(idx, method)
Ian Rogers28ad40d2011-10-27 15:19:26 -0700757 genRegCopy(cUnit, r2, r0); // Align usage with fast path
758 loadValueDirectFixed(cUnit, rlSrc, r0); /* reload Ref */
759 // Rejoin code paths
760 ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
761 hopTarget->defMask = ENCODE_ALL;
762 hopBranch->generic.target = (LIR*)hopTarget;
763 }
buzbee67bf8852011-08-17 17:51:35 -0700764 }
buzbee991e3ac2011-09-29 15:44:22 -0700765 /* r0 is ref, r2 is class. If ref==null, use directly as bool result */
766 ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, r0, 0);
buzbee2a475e72011-09-07 17:19:17 -0700767 /* load object->clazz */
buzbeeed3e9302011-09-23 17:34:19 -0700768 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
buzbee991e3ac2011-09-29 15:44:22 -0700769 loadWordDisp(cUnit, r0, Object::ClassOffset().Int32Value(), r1);
770 /* r0 is ref, r1 is ref->clazz, r2 is class */
Ian Rogers28ad40d2011-10-27 15:19:26 -0700771 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInstanceofNonTrivialFromCode), rLR);
buzbee991e3ac2011-09-29 15:44:22 -0700772 opRegReg(cUnit, kOpCmp, r1, r2); // Same?
773 genBarrier(cUnit);
774 genIT(cUnit, kArmCondEq, "EE"); // if-convert the test
775 loadConstant(cUnit, r0, 1); // .eq case - load true
776 genRegCopy(cUnit, r0, r2); // .ne case - arg0 <= class
777 opReg(cUnit, kOpBlx, rLR); // .ne case: helper(class, ref->class)
778 genBarrier(cUnit);
779 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700780 /* branch target here */
781 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
782 target->defMask = ENCODE_ALL;
buzbee2a475e72011-09-07 17:19:17 -0700783 RegLocation rlResult = oatGetReturn(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700784 storeValue(cUnit, rlDest, rlResult);
785 branch1->generic.target = (LIR*)target;
buzbee67bf8852011-08-17 17:51:35 -0700786}
787
buzbeeed3e9302011-09-23 17:34:19 -0700788STATIC void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700789{
buzbee6181f792011-09-29 11:14:04 -0700790 oatFlushAllRegs(cUnit);
buzbee2a475e72011-09-07 17:19:17 -0700791 // May generate a call - use explicit registers
792 oatLockCallTemps(cUnit);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700793 uint32_t type_idx = mir->dalvikInsn.vB;
buzbee2a475e72011-09-07 17:19:17 -0700794 loadCurrMethodDirect(cUnit, r1); // r1 <= current Method*
Ian Rogers28ad40d2011-10-27 15:19:26 -0700795 int classReg = r2; // r2 will hold the Class*
Ian Rogersa3760aa2011-11-14 14:32:37 -0800796 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
797 cUnit->dex_cache,
798 *cUnit->dex_file,
799 type_idx)) {
Ian Rogersb093c6b2011-10-31 16:19:55 -0700800 // Check we have access to type_idx and if not throw IllegalAccessError,
801 // returns Class* in r0
802 loadWordDisp(cUnit, rSELF,
803 OFFSETOF_MEMBER(Thread, pInitializeTypeAndVerifyAccessFromCode),
804 rLR);
805 loadConstant(cUnit, r0, type_idx);
806 callRuntimeHelper(cUnit, rLR); // InitializeTypeAndVerifyAccess(idx, method)
807 genRegCopy(cUnit, classReg, r0); // Align usage with fast path
Ian Rogers28ad40d2011-10-27 15:19:26 -0700808 } else {
809 // Load dex cache entry into classReg (r2)
810 loadWordDisp(cUnit, r1, Method::DexCacheResolvedTypesOffset().Int32Value(), classReg);
811 int32_t offset_of_type = Array::DataOffset().Int32Value() + (sizeof(Class*) * type_idx);
812 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
Ian Rogersa3760aa2011-11-14 14:32:37 -0800813 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->dex_cache, type_idx)) {
Ian Rogers28ad40d2011-10-27 15:19:26 -0700814 // Need to test presence of type in dex cache at runtime
815 ArmLIR* hopBranch = genCmpImmBranch(cUnit, kArmCondNe, classReg, 0);
816 // Not resolved
817 // Call out to helper, which will return resolved type in r0
818 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
819 loadConstant(cUnit, r0, type_idx);
Ian Rogersb093c6b2011-10-31 16:19:55 -0700820 callRuntimeHelper(cUnit, rLR); // InitializeTypeFromCode(idx, method)
821 genRegCopy(cUnit, classReg, r0); // Align usage with fast path
Ian Rogers28ad40d2011-10-27 15:19:26 -0700822 // Rejoin code paths
823 ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
824 hopTarget->defMask = ENCODE_ALL;
825 hopBranch->generic.target = (LIR*)hopTarget;
826 }
buzbee67bf8852011-08-17 17:51:35 -0700827 }
Ian Rogers28ad40d2011-10-27 15:19:26 -0700828 // At this point, classReg (r2) has class
829 loadValueDirectFixed(cUnit, rlSrc, r0); // r0 <= ref
buzbee2a475e72011-09-07 17:19:17 -0700830 /* Null is OK - continue */
831 ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, r0, 0);
832 /* load object->clazz */
buzbeeed3e9302011-09-23 17:34:19 -0700833 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
buzbee2a475e72011-09-07 17:19:17 -0700834 loadWordDisp(cUnit, r0, Object::ClassOffset().Int32Value(), r1);
835 /* r1 now contains object->clazz */
Ian Rogers28ad40d2011-10-27 15:19:26 -0700836 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pCheckCastFromCode), rLR);
Ian Rogersb093c6b2011-10-31 16:19:55 -0700837 opRegReg(cUnit, kOpCmp, r1, classReg);
buzbee2a475e72011-09-07 17:19:17 -0700838 ArmLIR* branch2 = opCondBranch(cUnit, kArmCondEq); /* If equal, trivial yes */
839 genRegCopy(cUnit, r0, r1);
840 genRegCopy(cUnit, r1, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -0700841 callRuntimeHelper(cUnit, rLR);
buzbee2a475e72011-09-07 17:19:17 -0700842 /* branch target here */
buzbee67bf8852011-08-17 17:51:35 -0700843 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
844 target->defMask = ENCODE_ALL;
845 branch1->generic.target = (LIR*)target;
846 branch2->generic.target = (LIR*)target;
847}
848
buzbeeed3e9302011-09-23 17:34:19 -0700849STATIC void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700850 RegLocation rlSrc)
851{
852 RegLocation rlResult;
853 rlSrc = loadValue(cUnit, rlSrc, kFPReg);
854 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
855 newLIR2(cUnit, kThumb2Vnegs, rlResult.lowReg, rlSrc.lowReg);
856 storeValue(cUnit, rlDest, rlResult);
857}
858
buzbeeed3e9302011-09-23 17:34:19 -0700859STATIC void genNegDouble(CompilationUnit* cUnit, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700860 RegLocation rlSrc)
861{
862 RegLocation rlResult;
863 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
864 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
865 newLIR2(cUnit, kThumb2Vnegd, S2D(rlResult.lowReg, rlResult.highReg),
866 S2D(rlSrc.lowReg, rlSrc.highReg));
867 storeValueWide(cUnit, rlDest, rlResult);
868}
869
buzbeeed3e9302011-09-23 17:34:19 -0700870STATIC void freeRegLocTemps(CompilationUnit* cUnit, RegLocation rlKeep,
buzbee439c4fa2011-08-27 15:59:07 -0700871 RegLocation rlFree)
buzbee67bf8852011-08-17 17:51:35 -0700872{
buzbee6181f792011-09-29 11:14:04 -0700873 if ((rlFree.lowReg != rlKeep.lowReg) && (rlFree.lowReg != rlKeep.highReg) &&
874 (rlFree.highReg != rlKeep.lowReg) && (rlFree.highReg != rlKeep.highReg)) {
875 // No overlap, free both
buzbee439c4fa2011-08-27 15:59:07 -0700876 oatFreeTemp(cUnit, rlFree.lowReg);
buzbee6181f792011-09-29 11:14:04 -0700877 oatFreeTemp(cUnit, rlFree.highReg);
878 }
buzbee67bf8852011-08-17 17:51:35 -0700879}
880
buzbeeed3e9302011-09-23 17:34:19 -0700881STATIC void genLong3Addr(CompilationUnit* cUnit, MIR* mir, OpKind firstOp,
buzbee67bf8852011-08-17 17:51:35 -0700882 OpKind secondOp, RegLocation rlDest,
883 RegLocation rlSrc1, RegLocation rlSrc2)
884{
buzbee9e0f9b02011-08-24 15:32:46 -0700885 /*
886 * NOTE: This is the one place in the code in which we might have
887 * as many as six live temporary registers. There are 5 in the normal
888 * set for Arm. Until we have spill capabilities, temporarily add
889 * lr to the temp set. It is safe to do this locally, but note that
890 * lr is used explicitly elsewhere in the code generator and cannot
891 * normally be used as a general temp register.
892 */
buzbee67bf8852011-08-17 17:51:35 -0700893 RegLocation rlResult;
buzbee9e0f9b02011-08-24 15:32:46 -0700894 oatMarkTemp(cUnit, rLR); // Add lr to the temp pool
895 oatFreeTemp(cUnit, rLR); // and make it available
buzbee67bf8852011-08-17 17:51:35 -0700896 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
897 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
898 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbeec0ecd652011-09-25 18:11:54 -0700899 // The longs may overlap - use intermediate temp if so
900 if (rlResult.lowReg == rlSrc1.highReg) {
buzbeec0ecd652011-09-25 18:11:54 -0700901 int tReg = oatAllocTemp(cUnit);
902 genRegCopy(cUnit, tReg, rlSrc1.highReg);
903 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
904 rlSrc2.lowReg);
905 opRegRegReg(cUnit, secondOp, rlResult.highReg, tReg,
906 rlSrc2.highReg);
907 oatFreeTemp(cUnit, tReg);
908 } else {
909 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
910 rlSrc2.lowReg);
911 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
912 rlSrc2.highReg);
913 }
buzbee439c4fa2011-08-27 15:59:07 -0700914 /*
915 * NOTE: If rlDest refers to a frame variable in a large frame, the
916 * following storeValueWide might need to allocate a temp register.
917 * To further work around the lack of a spill capability, explicitly
918 * free any temps from rlSrc1 & rlSrc2 that aren't still live in rlResult.
919 * Remove when spill is functional.
920 */
921 freeRegLocTemps(cUnit, rlResult, rlSrc1);
922 freeRegLocTemps(cUnit, rlResult, rlSrc2);
buzbee67bf8852011-08-17 17:51:35 -0700923 storeValueWide(cUnit, rlDest, rlResult);
buzbee9e0f9b02011-08-24 15:32:46 -0700924 oatClobber(cUnit, rLR);
925 oatUnmarkTemp(cUnit, rLR); // Remove lr from the temp pool
buzbee67bf8852011-08-17 17:51:35 -0700926}
927
928void oatInitializeRegAlloc(CompilationUnit* cUnit)
929{
930 int numRegs = sizeof(coreRegs)/sizeof(*coreRegs);
931 int numReserved = sizeof(reservedRegs)/sizeof(*reservedRegs);
932 int numTemps = sizeof(coreTemps)/sizeof(*coreTemps);
933 int numFPRegs = sizeof(fpRegs)/sizeof(*fpRegs);
934 int numFPTemps = sizeof(fpTemps)/sizeof(*fpTemps);
935 RegisterPool *pool = (RegisterPool *)oatNew(sizeof(*pool), true);
936 cUnit->regPool = pool;
937 pool->numCoreRegs = numRegs;
938 pool->coreRegs = (RegisterInfo *)
939 oatNew(numRegs * sizeof(*cUnit->regPool->coreRegs), true);
940 pool->numFPRegs = numFPRegs;
941 pool->FPRegs = (RegisterInfo *)
942 oatNew(numFPRegs * sizeof(*cUnit->regPool->FPRegs), true);
943 oatInitPool(pool->coreRegs, coreRegs, pool->numCoreRegs);
944 oatInitPool(pool->FPRegs, fpRegs, pool->numFPRegs);
945 // Keep special registers from being allocated
946 for (int i = 0; i < numReserved; i++) {
buzbeec0ecd652011-09-25 18:11:54 -0700947 if (NO_SUSPEND && (reservedRegs[i] == rSUSPEND)) {
948 //To measure cost of suspend check
949 continue;
950 }
buzbee67bf8852011-08-17 17:51:35 -0700951 oatMarkInUse(cUnit, reservedRegs[i]);
952 }
953 // Mark temp regs - all others not in use can be used for promotion
954 for (int i = 0; i < numTemps; i++) {
955 oatMarkTemp(cUnit, coreTemps[i]);
956 }
957 for (int i = 0; i < numFPTemps; i++) {
958 oatMarkTemp(cUnit, fpTemps[i]);
959 }
buzbeec0ecd652011-09-25 18:11:54 -0700960 // Construct the alias map.
961 cUnit->phiAliasMap = (int*)oatNew(cUnit->numSSARegs *
962 sizeof(cUnit->phiAliasMap[0]), false);
963 for (int i = 0; i < cUnit->numSSARegs; i++) {
964 cUnit->phiAliasMap[i] = i;
965 }
966 for (MIR* phi = cUnit->phiList; phi; phi = phi->meta.phiNext) {
967 int defReg = phi->ssaRep->defs[0];
968 for (int i = 0; i < phi->ssaRep->numUses; i++) {
969 for (int j = 0; j < cUnit->numSSARegs; j++) {
970 if (cUnit->phiAliasMap[j] == phi->ssaRep->uses[i]) {
971 cUnit->phiAliasMap[j] = defReg;
972 }
973 }
974 }
975 }
buzbee67bf8852011-08-17 17:51:35 -0700976}
977
978/*
979 * Handle simple case (thin lock) inline. If it's complicated, bail
980 * out to the heavyweight lock/unlock routines. We'll use dedicated
981 * registers here in order to be in the right position in case we
982 * to bail to dvm[Lock/Unlock]Object(self, object)
983 *
984 * r0 -> self pointer [arg0 for dvm[Lock/Unlock]Object
985 * r1 -> object [arg1 for dvm[Lock/Unlock]Object
986 * r2 -> intial contents of object->lock, later result of strex
987 * r3 -> self->threadId
988 * r12 -> allow to be used by utilities as general temp
989 *
990 * The result of the strex is 0 if we acquire the lock.
991 *
992 * See comments in Sync.c for the layout of the lock word.
993 * Of particular interest to this code is the test for the
994 * simple case - which we handle inline. For monitor enter, the
995 * simple case is thin lock, held by no-one. For monitor exit,
996 * the simple case is thin lock, held by the unlocking thread with
997 * a recurse count of 0.
998 *
999 * A minor complication is that there is a field in the lock word
1000 * unrelated to locking: the hash state. This field must be ignored, but
1001 * preserved.
1002 *
1003 */
buzbeeed3e9302011-09-23 17:34:19 -07001004STATIC void genMonitorEnter(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001005 RegLocation rlSrc)
1006{
1007 ArmLIR* target;
1008 ArmLIR* hopTarget;
1009 ArmLIR* branch;
1010 ArmLIR* hopBranch;
1011
1012 oatFlushAllRegs(cUnit);
Elliott Hughes5f791332011-09-15 17:45:30 -07001013 DCHECK_EQ(LW_SHAPE_THIN, 0);
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001014 loadValueDirectFixed(cUnit, rlSrc, r0); // Get obj
buzbee2e748f32011-08-29 21:02:19 -07001015 oatLockCallTemps(cUnit); // Prepare for explicit register usage
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001016 genNullCheck(cUnit, rlSrc.sRegLow, r0, mir);
1017 loadWordDisp(cUnit, rSELF, Thread::ThinLockIdOffset().Int32Value(), r2);
1018 newLIR3(cUnit, kThumb2Ldrex, r1, r0,
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001019 Object::MonitorOffset().Int32Value() >> 2); // Get object->lock
buzbeec143c552011-08-20 17:38:58 -07001020 // Align owner
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001021 opRegImm(cUnit, kOpLsl, r2, LW_LOCK_OWNER_SHIFT);
buzbee67bf8852011-08-17 17:51:35 -07001022 // Is lock unheld on lock or held by us (==threadId) on unlock?
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001023 newLIR4(cUnit, kThumb2Bfi, r2, r1, 0, LW_LOCK_OWNER_SHIFT - 1);
1024 newLIR3(cUnit, kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
1025 hopBranch = newLIR2(cUnit, kThumb2Cbnz, r1, 0);
1026 newLIR4(cUnit, kThumb2Strex, r1, r2, r0,
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001027 Object::MonitorOffset().Int32Value() >> 2);
buzbee67bf8852011-08-17 17:51:35 -07001028 oatGenMemBarrier(cUnit, kSY);
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001029 branch = newLIR2(cUnit, kThumb2Cbz, r1, 0);
buzbee67bf8852011-08-17 17:51:35 -07001030
1031 hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
1032 hopTarget->defMask = ENCODE_ALL;
1033 hopBranch->generic.target = (LIR*)hopTarget;
1034
buzbee1b4c8592011-08-31 10:43:51 -07001035 // Go expensive route - artLockObjectFromCode(self, obj);
1036 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pLockObjectFromCode),
buzbee67bf8852011-08-17 17:51:35 -07001037 rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07001038 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001039
1040 // Resume here
1041 target = newLIR0(cUnit, kArmPseudoTargetLabel);
1042 target->defMask = ENCODE_ALL;
1043 branch->generic.target = (LIR*)target;
1044}
1045
1046/*
1047 * For monitor unlock, we don't have to use ldrex/strex. Once
1048 * we've determined that the lock is thin and that we own it with
1049 * a zero recursion count, it's safe to punch it back to the
1050 * initial, unlock thin state with a store word.
1051 */
buzbeeed3e9302011-09-23 17:34:19 -07001052STATIC void genMonitorExit(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001053 RegLocation rlSrc)
1054{
1055 ArmLIR* target;
1056 ArmLIR* branch;
1057 ArmLIR* hopTarget;
1058 ArmLIR* hopBranch;
1059
Elliott Hughes5f791332011-09-15 17:45:30 -07001060 DCHECK_EQ(LW_SHAPE_THIN, 0);
buzbee67bf8852011-08-17 17:51:35 -07001061 oatFlushAllRegs(cUnit);
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001062 loadValueDirectFixed(cUnit, rlSrc, r0); // Get obj
buzbee2e748f32011-08-29 21:02:19 -07001063 oatLockCallTemps(cUnit); // Prepare for explicit register usage
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001064 genNullCheck(cUnit, rlSrc.sRegLow, r0, mir);
1065 loadWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r1); // Get lock
1066 loadWordDisp(cUnit, rSELF, Thread::ThinLockIdOffset().Int32Value(), r2);
buzbee67bf8852011-08-17 17:51:35 -07001067 // Is lock unheld on lock or held by us (==threadId) on unlock?
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001068 opRegRegImm(cUnit, kOpAnd, r3, r1, (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
buzbeec143c552011-08-20 17:38:58 -07001069 // Align owner
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001070 opRegImm(cUnit, kOpLsl, r2, LW_LOCK_OWNER_SHIFT);
1071 newLIR3(cUnit, kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
1072 opRegReg(cUnit, kOpSub, r1, r2);
buzbee67bf8852011-08-17 17:51:35 -07001073 hopBranch = opCondBranch(cUnit, kArmCondNe);
1074 oatGenMemBarrier(cUnit, kSY);
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001075 storeWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r3);
buzbee67bf8852011-08-17 17:51:35 -07001076 branch = opNone(cUnit, kOpUncondBr);
1077
1078 hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
1079 hopTarget->defMask = ENCODE_ALL;
1080 hopBranch->generic.target = (LIR*)hopTarget;
1081
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001082 // Go expensive route - UnlockObjectFromCode(obj);
buzbee1b4c8592011-08-31 10:43:51 -07001083 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pUnlockObjectFromCode),
buzbee67bf8852011-08-17 17:51:35 -07001084 rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07001085 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001086
1087 // Resume here
1088 target = newLIR0(cUnit, kArmPseudoTargetLabel);
1089 target->defMask = ENCODE_ALL;
1090 branch->generic.target = (LIR*)target;
1091}
1092
1093/*
1094 * 64-bit 3way compare function.
1095 * mov rX, #-1
1096 * cmp op1hi, op2hi
1097 * blt done
1098 * bgt flip
1099 * sub rX, op1lo, op2lo (treat as unsigned)
1100 * beq done
1101 * ite hi
1102 * mov(hi) rX, #-1
1103 * mov(!hi) rX, #1
1104 * flip:
1105 * neg rX
1106 * done:
1107 */
buzbeeed3e9302011-09-23 17:34:19 -07001108STATIC void genCmpLong(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001109 RegLocation rlDest, RegLocation rlSrc1,
1110 RegLocation rlSrc2)
1111{
buzbee67bf8852011-08-17 17:51:35 -07001112 ArmLIR* target1;
1113 ArmLIR* target2;
1114 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
1115 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
buzbeeb29e4d12011-09-26 15:05:48 -07001116 int tReg = oatAllocTemp(cUnit);
1117 loadConstant(cUnit, tReg, -1);
buzbee67bf8852011-08-17 17:51:35 -07001118 opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg);
1119 ArmLIR* branch1 = opCondBranch(cUnit, kArmCondLt);
1120 ArmLIR* branch2 = opCondBranch(cUnit, kArmCondGt);
buzbeeb29e4d12011-09-26 15:05:48 -07001121 opRegRegReg(cUnit, kOpSub, tReg, rlSrc1.lowReg, rlSrc2.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001122 ArmLIR* branch3 = opCondBranch(cUnit, kArmCondEq);
1123
1124 genIT(cUnit, kArmCondHi, "E");
buzbeeb29e4d12011-09-26 15:05:48 -07001125 newLIR2(cUnit, kThumb2MovImmShift, tReg, modifiedImmediate(-1));
1126 loadConstant(cUnit, tReg, 1);
buzbee67bf8852011-08-17 17:51:35 -07001127 genBarrier(cUnit);
1128
1129 target2 = newLIR0(cUnit, kArmPseudoTargetLabel);
1130 target2->defMask = -1;
buzbeeb29e4d12011-09-26 15:05:48 -07001131 opRegReg(cUnit, kOpNeg, tReg, tReg);
buzbee67bf8852011-08-17 17:51:35 -07001132
1133 target1 = newLIR0(cUnit, kArmPseudoTargetLabel);
1134 target1->defMask = -1;
1135
buzbeeb29e4d12011-09-26 15:05:48 -07001136 RegLocation rlTemp = LOC_C_RETURN; // Just using as template, will change
1137 rlTemp.lowReg = tReg;
buzbee67bf8852011-08-17 17:51:35 -07001138 storeValue(cUnit, rlDest, rlTemp);
buzbeeb29e4d12011-09-26 15:05:48 -07001139 oatFreeTemp(cUnit, tReg);
buzbee67bf8852011-08-17 17:51:35 -07001140
1141 branch1->generic.target = (LIR*)target1;
1142 branch2->generic.target = (LIR*)target2;
1143 branch3->generic.target = branch1->generic.target;
1144}
1145
buzbeeed3e9302011-09-23 17:34:19 -07001146STATIC void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -07001147 RegLocation rlSrc, RegLocation rlResult, int lit,
1148 int firstBit, int secondBit)
1149{
1150 opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg,
1151 encodeShift(kArmLsl, secondBit - firstBit));
1152 if (firstBit != 0) {
1153 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
1154 }
1155}
1156
buzbeeed3e9302011-09-23 17:34:19 -07001157STATIC bool genConversionCall(CompilationUnit* cUnit, MIR* mir, int funcOffset,
buzbee67bf8852011-08-17 17:51:35 -07001158 int srcSize, int tgtSize)
1159{
1160 /*
1161 * Don't optimize the register usage since it calls out to support
1162 * functions
1163 */
1164 RegLocation rlSrc;
1165 RegLocation rlDest;
1166 oatFlushAllRegs(cUnit); /* Send everything to home location */
1167 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1168 if (srcSize == 1) {
1169 rlSrc = oatGetSrc(cUnit, mir, 0);
1170 loadValueDirectFixed(cUnit, rlSrc, r0);
1171 } else {
1172 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
1173 loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
1174 }
Ian Rogersff1ed472011-09-20 13:46:24 -07001175 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001176 if (tgtSize == 1) {
1177 RegLocation rlResult;
1178 rlDest = oatGetDest(cUnit, mir, 0);
1179 rlResult = oatGetReturn(cUnit);
1180 storeValue(cUnit, rlDest, rlResult);
1181 } else {
1182 RegLocation rlResult;
1183 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1184 rlResult = oatGetReturnWide(cUnit);
1185 storeValueWide(cUnit, rlDest, rlResult);
1186 }
1187 return false;
1188}
1189
buzbeeed3e9302011-09-23 17:34:19 -07001190STATIC bool genArithOpFloatPortable(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001191 RegLocation rlDest, RegLocation rlSrc1,
1192 RegLocation rlSrc2)
1193{
1194 RegLocation rlResult;
1195 int funcOffset;
1196
1197 switch (mir->dalvikInsn.opcode) {
1198 case OP_ADD_FLOAT_2ADDR:
1199 case OP_ADD_FLOAT:
1200 funcOffset = OFFSETOF_MEMBER(Thread, pFadd);
1201 break;
1202 case OP_SUB_FLOAT_2ADDR:
1203 case OP_SUB_FLOAT:
1204 funcOffset = OFFSETOF_MEMBER(Thread, pFsub);
1205 break;
1206 case OP_DIV_FLOAT_2ADDR:
1207 case OP_DIV_FLOAT:
1208 funcOffset = OFFSETOF_MEMBER(Thread, pFdiv);
1209 break;
1210 case OP_MUL_FLOAT_2ADDR:
1211 case OP_MUL_FLOAT:
1212 funcOffset = OFFSETOF_MEMBER(Thread, pFmul);
1213 break;
1214 case OP_REM_FLOAT_2ADDR:
1215 case OP_REM_FLOAT:
1216 funcOffset = OFFSETOF_MEMBER(Thread, pFmodf);
1217 break;
1218 case OP_NEG_FLOAT: {
1219 genNegFloat(cUnit, rlDest, rlSrc1);
1220 return false;
1221 }
1222 default:
1223 return true;
1224 }
1225 oatFlushAllRegs(cUnit); /* Send everything to home location */
1226 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1227 loadValueDirectFixed(cUnit, rlSrc1, r0);
1228 loadValueDirectFixed(cUnit, rlSrc2, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -07001229 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001230 rlResult = oatGetReturn(cUnit);
1231 storeValue(cUnit, rlDest, rlResult);
1232 return false;
1233}
1234
buzbeeed3e9302011-09-23 17:34:19 -07001235STATIC bool genArithOpDoublePortable(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001236 RegLocation rlDest, RegLocation rlSrc1,
1237 RegLocation rlSrc2)
1238{
1239 RegLocation rlResult;
1240 int funcOffset;
1241
1242 switch (mir->dalvikInsn.opcode) {
1243 case OP_ADD_DOUBLE_2ADDR:
1244 case OP_ADD_DOUBLE:
1245 funcOffset = OFFSETOF_MEMBER(Thread, pDadd);
1246 break;
1247 case OP_SUB_DOUBLE_2ADDR:
1248 case OP_SUB_DOUBLE:
1249 funcOffset = OFFSETOF_MEMBER(Thread, pDsub);
1250 break;
1251 case OP_DIV_DOUBLE_2ADDR:
1252 case OP_DIV_DOUBLE:
1253 funcOffset = OFFSETOF_MEMBER(Thread, pDdiv);
1254 break;
1255 case OP_MUL_DOUBLE_2ADDR:
1256 case OP_MUL_DOUBLE:
1257 funcOffset = OFFSETOF_MEMBER(Thread, pDmul);
1258 break;
1259 case OP_REM_DOUBLE_2ADDR:
1260 case OP_REM_DOUBLE:
1261 funcOffset = OFFSETOF_MEMBER(Thread, pFmod);
1262 break;
1263 case OP_NEG_DOUBLE: {
1264 genNegDouble(cUnit, rlDest, rlSrc1);
1265 return false;
1266 }
1267 default:
1268 return true;
1269 }
1270 oatFlushAllRegs(cUnit); /* Send everything to home location */
1271 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1272 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1273 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
Ian Rogersff1ed472011-09-20 13:46:24 -07001274 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001275 rlResult = oatGetReturnWide(cUnit);
1276 storeValueWide(cUnit, rlDest, rlResult);
1277 return false;
1278}
1279
buzbeeed3e9302011-09-23 17:34:19 -07001280STATIC bool genConversionPortable(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001281{
1282 Opcode opcode = mir->dalvikInsn.opcode;
1283
1284 switch (opcode) {
1285 case OP_INT_TO_FLOAT:
1286 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2f),
1287 1, 1);
1288 case OP_FLOAT_TO_INT:
1289 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2iz),
1290 1, 1);
1291 case OP_DOUBLE_TO_FLOAT:
1292 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2f),
1293 2, 1);
1294 case OP_FLOAT_TO_DOUBLE:
1295 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2d),
1296 1, 2);
1297 case OP_INT_TO_DOUBLE:
1298 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2d),
1299 1, 2);
1300 case OP_DOUBLE_TO_INT:
1301 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2iz),
1302 2, 1);
1303 case OP_FLOAT_TO_LONG:
1304 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
buzbee1b4c8592011-08-31 10:43:51 -07001305 pF2l), 1, 2);
buzbee67bf8852011-08-17 17:51:35 -07001306 case OP_LONG_TO_FLOAT:
1307 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2f),
1308 2, 1);
1309 case OP_DOUBLE_TO_LONG:
1310 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
buzbee1b4c8592011-08-31 10:43:51 -07001311 pD2l), 2, 2);
buzbee67bf8852011-08-17 17:51:35 -07001312 case OP_LONG_TO_DOUBLE:
1313 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2d),
1314 2, 2);
1315 default:
1316 return true;
1317 }
1318 return false;
1319}
1320
1321/* Generate conditional branch instructions */
buzbeeed3e9302011-09-23 17:34:19 -07001322STATIC ArmLIR* genConditionalBranch(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -07001323 ArmConditionCode cond,
1324 ArmLIR* target)
1325{
1326 ArmLIR* branch = opCondBranch(cUnit, cond);
1327 branch->generic.target = (LIR*) target;
1328 return branch;
1329}
1330
buzbee67bf8852011-08-17 17:51:35 -07001331/*
1332 * Generate array store
1333 *
1334 */
buzbeeed3e9302011-09-23 17:34:19 -07001335STATIC void genArrayObjPut(CompilationUnit* cUnit, MIR* mir,
buzbee1b4c8592011-08-31 10:43:51 -07001336 RegLocation rlArray, RegLocation rlIndex,
1337 RegLocation rlSrc, int scale)
buzbee67bf8852011-08-17 17:51:35 -07001338{
1339 RegisterClass regClass = oatRegClassBySize(kWord);
buzbeec143c552011-08-20 17:38:58 -07001340 int lenOffset = Array::LengthOffset().Int32Value();
1341 int dataOffset = Array::DataOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001342
buzbee6181f792011-09-29 11:14:04 -07001343 oatFlushAllRegs(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001344 /* Make sure it's a legal object Put. Use direct regs at first */
1345 loadValueDirectFixed(cUnit, rlArray, r1);
1346 loadValueDirectFixed(cUnit, rlSrc, r0);
1347
1348 /* null array object? */
buzbee43a36422011-09-14 14:00:13 -07001349 genNullCheck(cUnit, rlArray.sRegLow, r1, mir);
buzbee67bf8852011-08-17 17:51:35 -07001350 loadWordDisp(cUnit, rSELF,
buzbee1b4c8592011-08-31 10:43:51 -07001351 OFFSETOF_MEMBER(Thread, pCanPutArrayElementFromCode), rLR);
buzbee67bf8852011-08-17 17:51:35 -07001352 /* Get the array's clazz */
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001353 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), r1);
Ian Rogersff1ed472011-09-20 13:46:24 -07001354 callRuntimeHelper(cUnit, rLR);
buzbee6181f792011-09-29 11:14:04 -07001355 oatFreeTemp(cUnit, r0);
1356 oatFreeTemp(cUnit, r1);
buzbee67bf8852011-08-17 17:51:35 -07001357
1358 // Now, redo loadValues in case they didn't survive the call
1359
1360 int regPtr;
1361 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1362 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1363
1364 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1365 oatClobber(cUnit, rlArray.lowReg);
1366 regPtr = rlArray.lowReg;
1367 } else {
1368 regPtr = oatAllocTemp(cUnit);
1369 genRegCopy(cUnit, regPtr, rlArray.lowReg);
1370 }
1371
buzbee43a36422011-09-14 14:00:13 -07001372 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee67bf8852011-08-17 17:51:35 -07001373 int regLen = oatAllocTemp(cUnit);
1374 //NOTE: max live temps(4) here.
1375 /* Get len */
1376 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1377 /* regPtr -> array data */
1378 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
buzbeeec5adf32011-09-11 15:25:43 -07001379 genRegRegCheck(cUnit, kArmCondCs, rlIndex.lowReg, regLen, mir,
buzbee5ade1d22011-09-09 14:44:52 -07001380 kArmThrowArrayBounds);
buzbee67bf8852011-08-17 17:51:35 -07001381 oatFreeTemp(cUnit, regLen);
1382 } else {
1383 /* regPtr -> array data */
1384 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1385 }
1386 /* at this point, regPtr points to array, 2 live temps */
1387 rlSrc = loadValue(cUnit, rlSrc, regClass);
1388 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1389 scale, kWord);
1390}
1391
1392/*
1393 * Generate array load
1394 */
buzbeeed3e9302011-09-23 17:34:19 -07001395STATIC void genArrayGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -07001396 RegLocation rlArray, RegLocation rlIndex,
1397 RegLocation rlDest, int scale)
1398{
1399 RegisterClass regClass = oatRegClassBySize(size);
buzbeec143c552011-08-20 17:38:58 -07001400 int lenOffset = Array::LengthOffset().Int32Value();
1401 int dataOffset = Array::DataOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001402 RegLocation rlResult;
1403 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1404 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1405 int regPtr;
1406
1407 /* null object? */
buzbee43a36422011-09-14 14:00:13 -07001408 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001409
1410 regPtr = oatAllocTemp(cUnit);
1411
buzbee43a36422011-09-14 14:00:13 -07001412 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee67bf8852011-08-17 17:51:35 -07001413 int regLen = oatAllocTemp(cUnit);
1414 /* Get len */
1415 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1416 /* regPtr -> array data */
1417 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
buzbeeec5adf32011-09-11 15:25:43 -07001418 genRegRegCheck(cUnit, kArmCondCs, rlIndex.lowReg, regLen, mir,
buzbee5ade1d22011-09-09 14:44:52 -07001419 kArmThrowArrayBounds);
buzbee67bf8852011-08-17 17:51:35 -07001420 oatFreeTemp(cUnit, regLen);
1421 } else {
1422 /* regPtr -> array data */
1423 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1424 }
buzbeee9a72f62011-09-04 17:59:07 -07001425 oatFreeTemp(cUnit, rlArray.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001426 if ((size == kLong) || (size == kDouble)) {
1427 if (scale) {
1428 int rNewIndex = oatAllocTemp(cUnit);
1429 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1430 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1431 oatFreeTemp(cUnit, rNewIndex);
1432 } else {
1433 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1434 }
buzbeee9a72f62011-09-04 17:59:07 -07001435 oatFreeTemp(cUnit, rlIndex.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001436 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1437
1438 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1439
1440 oatFreeTemp(cUnit, regPtr);
1441 storeValueWide(cUnit, rlDest, rlResult);
1442 } else {
1443 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1444
1445 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
1446 scale, size);
1447
1448 oatFreeTemp(cUnit, regPtr);
1449 storeValue(cUnit, rlDest, rlResult);
1450 }
1451}
1452
1453/*
1454 * Generate array store
1455 *
1456 */
buzbeeed3e9302011-09-23 17:34:19 -07001457STATIC void genArrayPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -07001458 RegLocation rlArray, RegLocation rlIndex,
1459 RegLocation rlSrc, int scale)
1460{
1461 RegisterClass regClass = oatRegClassBySize(size);
buzbeec143c552011-08-20 17:38:58 -07001462 int lenOffset = Array::LengthOffset().Int32Value();
1463 int dataOffset = Array::DataOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001464
1465 int regPtr;
1466 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1467 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1468
1469 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1470 oatClobber(cUnit, rlArray.lowReg);
1471 regPtr = rlArray.lowReg;
1472 } else {
1473 regPtr = oatAllocTemp(cUnit);
1474 genRegCopy(cUnit, regPtr, rlArray.lowReg);
1475 }
1476
1477 /* null object? */
buzbee43a36422011-09-14 14:00:13 -07001478 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001479
buzbee43a36422011-09-14 14:00:13 -07001480 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee67bf8852011-08-17 17:51:35 -07001481 int regLen = oatAllocTemp(cUnit);
1482 //NOTE: max live temps(4) here.
1483 /* Get len */
1484 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1485 /* regPtr -> array data */
1486 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
buzbeeec5adf32011-09-11 15:25:43 -07001487 genRegRegCheck(cUnit, kArmCondCs, rlIndex.lowReg, regLen, mir,
buzbee5ade1d22011-09-09 14:44:52 -07001488 kArmThrowArrayBounds);
buzbee67bf8852011-08-17 17:51:35 -07001489 oatFreeTemp(cUnit, regLen);
1490 } else {
1491 /* regPtr -> array data */
1492 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1493 }
1494 /* at this point, regPtr points to array, 2 live temps */
1495 if ((size == kLong) || (size == kDouble)) {
buzbee5ade1d22011-09-09 14:44:52 -07001496 //TUNING: specific wide routine that can handle fp regs
buzbee67bf8852011-08-17 17:51:35 -07001497 if (scale) {
1498 int rNewIndex = oatAllocTemp(cUnit);
1499 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1500 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1501 oatFreeTemp(cUnit, rNewIndex);
1502 } else {
1503 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1504 }
1505 rlSrc = loadValueWide(cUnit, rlSrc, regClass);
1506
1507 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
1508
1509 oatFreeTemp(cUnit, regPtr);
1510 } else {
1511 rlSrc = loadValue(cUnit, rlSrc, regClass);
1512
1513 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1514 scale, size);
1515 }
1516}
1517
buzbeeed3e9302011-09-23 17:34:19 -07001518STATIC bool genShiftOpLong(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001519 RegLocation rlDest, RegLocation rlSrc1,
1520 RegLocation rlShift)
1521{
buzbee54330722011-08-23 16:46:55 -07001522 int funcOffset;
buzbee67bf8852011-08-17 17:51:35 -07001523
buzbee67bf8852011-08-17 17:51:35 -07001524 switch( mir->dalvikInsn.opcode) {
1525 case OP_SHL_LONG:
1526 case OP_SHL_LONG_2ADDR:
buzbee54330722011-08-23 16:46:55 -07001527 funcOffset = OFFSETOF_MEMBER(Thread, pShlLong);
buzbee67bf8852011-08-17 17:51:35 -07001528 break;
1529 case OP_SHR_LONG:
1530 case OP_SHR_LONG_2ADDR:
buzbee54330722011-08-23 16:46:55 -07001531 funcOffset = OFFSETOF_MEMBER(Thread, pShrLong);
buzbee67bf8852011-08-17 17:51:35 -07001532 break;
1533 case OP_USHR_LONG:
1534 case OP_USHR_LONG_2ADDR:
buzbee54330722011-08-23 16:46:55 -07001535 funcOffset = OFFSETOF_MEMBER(Thread, pUshrLong);
buzbee67bf8852011-08-17 17:51:35 -07001536 break;
1537 default:
buzbee54330722011-08-23 16:46:55 -07001538 LOG(FATAL) << "Unexpected case";
buzbee67bf8852011-08-17 17:51:35 -07001539 return true;
1540 }
buzbee54330722011-08-23 16:46:55 -07001541 oatFlushAllRegs(cUnit); /* Send everything to home location */
1542 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1543 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1544 loadValueDirect(cUnit, rlShift, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -07001545 callRuntimeHelper(cUnit, rLR);
buzbee54330722011-08-23 16:46:55 -07001546 RegLocation rlResult = oatGetReturnWide(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001547 storeValueWide(cUnit, rlDest, rlResult);
1548 return false;
1549}
1550
buzbeeed3e9302011-09-23 17:34:19 -07001551STATIC bool genArithOpLong(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001552 RegLocation rlDest, RegLocation rlSrc1,
1553 RegLocation rlSrc2)
1554{
1555 RegLocation rlResult;
1556 OpKind firstOp = kOpBkpt;
1557 OpKind secondOp = kOpBkpt;
1558 bool callOut = false;
buzbee58f92742011-10-01 11:22:17 -07001559 bool checkZero = false;
buzbee67bf8852011-08-17 17:51:35 -07001560 int funcOffset;
1561 int retReg = r0;
1562
1563 switch (mir->dalvikInsn.opcode) {
1564 case OP_NOT_LONG:
1565 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1566 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbeeb29e4d12011-09-26 15:05:48 -07001567 // Check for destructive overlap
1568 if (rlResult.lowReg == rlSrc2.highReg) {
1569 int tReg = oatAllocTemp(cUnit);
1570 genRegCopy(cUnit, tReg, rlSrc2.highReg);
1571 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1572 opRegReg(cUnit, kOpMvn, rlResult.highReg, tReg);
1573 oatFreeTemp(cUnit, tReg);
1574 } else {
1575 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1576 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
1577 }
buzbee67bf8852011-08-17 17:51:35 -07001578 storeValueWide(cUnit, rlDest, rlResult);
1579 return false;
1580 break;
1581 case OP_ADD_LONG:
1582 case OP_ADD_LONG_2ADDR:
1583 firstOp = kOpAdd;
1584 secondOp = kOpAdc;
1585 break;
1586 case OP_SUB_LONG:
1587 case OP_SUB_LONG_2ADDR:
1588 firstOp = kOpSub;
1589 secondOp = kOpSbc;
1590 break;
1591 case OP_MUL_LONG:
1592 case OP_MUL_LONG_2ADDR:
buzbee439c4fa2011-08-27 15:59:07 -07001593 callOut = true;
1594 retReg = r0;
1595 funcOffset = OFFSETOF_MEMBER(Thread, pLmul);
1596 break;
buzbee67bf8852011-08-17 17:51:35 -07001597 case OP_DIV_LONG:
1598 case OP_DIV_LONG_2ADDR:
1599 callOut = true;
buzbee58f92742011-10-01 11:22:17 -07001600 checkZero = true;
buzbee67bf8852011-08-17 17:51:35 -07001601 retReg = r0;
1602 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
1603 break;
1604 /* NOTE - result is in r2/r3 instead of r0/r1 */
1605 case OP_REM_LONG:
1606 case OP_REM_LONG_2ADDR:
1607 callOut = true;
buzbee58f92742011-10-01 11:22:17 -07001608 checkZero = true;
buzbee67bf8852011-08-17 17:51:35 -07001609 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
1610 retReg = r2;
1611 break;
1612 case OP_AND_LONG_2ADDR:
1613 case OP_AND_LONG:
1614 firstOp = kOpAnd;
1615 secondOp = kOpAnd;
1616 break;
1617 case OP_OR_LONG:
1618 case OP_OR_LONG_2ADDR:
1619 firstOp = kOpOr;
1620 secondOp = kOpOr;
1621 break;
1622 case OP_XOR_LONG:
1623 case OP_XOR_LONG_2ADDR:
1624 firstOp = kOpXor;
1625 secondOp = kOpXor;
1626 break;
1627 case OP_NEG_LONG: {
buzbee67bf8852011-08-17 17:51:35 -07001628 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1629 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbeeb29e4d12011-09-26 15:05:48 -07001630 int zReg = oatAllocTemp(cUnit);
1631 loadConstantNoClobber(cUnit, zReg, 0);
1632 // Check for destructive overlap
1633 if (rlResult.lowReg == rlSrc2.highReg) {
1634 int tReg = oatAllocTemp(cUnit);
1635 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1636 zReg, rlSrc2.lowReg);
1637 opRegRegReg(cUnit, kOpSbc, rlResult.highReg,
1638 zReg, tReg);
1639 oatFreeTemp(cUnit, tReg);
1640 } else {
1641 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1642 zReg, rlSrc2.lowReg);
1643 opRegRegReg(cUnit, kOpSbc, rlResult.highReg,
1644 zReg, rlSrc2.highReg);
1645 }
1646 oatFreeTemp(cUnit, zReg);
buzbee67bf8852011-08-17 17:51:35 -07001647 storeValueWide(cUnit, rlDest, rlResult);
1648 return false;
1649 }
1650 default:
1651 LOG(FATAL) << "Invalid long arith op";
1652 }
1653 if (!callOut) {
1654 genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
1655 } else {
buzbee67bf8852011-08-17 17:51:35 -07001656 oatFlushAllRegs(cUnit); /* Send everything to home location */
buzbee58f92742011-10-01 11:22:17 -07001657 if (checkZero) {
1658 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
1659 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1660 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1661 int tReg = oatAllocTemp(cUnit);
1662 newLIR4(cUnit, kThumb2OrrRRRs, tReg, r2, r3, 0);
1663 oatFreeTemp(cUnit, tReg);
1664 genCheck(cUnit, kArmCondEq, mir, kArmThrowDivZero);
1665 } else {
1666 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1667 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1668 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
1669 }
Ian Rogersff1ed472011-09-20 13:46:24 -07001670 callRuntimeHelper(cUnit, rLR);
buzbee58f92742011-10-01 11:22:17 -07001671 // Adjust return regs in to handle case of rem returning r2/r3
buzbee67bf8852011-08-17 17:51:35 -07001672 if (retReg == r0)
1673 rlResult = oatGetReturnWide(cUnit);
1674 else
1675 rlResult = oatGetReturnWideAlt(cUnit);
1676 storeValueWide(cUnit, rlDest, rlResult);
1677 }
1678 return false;
1679}
1680
buzbeeed3e9302011-09-23 17:34:19 -07001681STATIC bool genArithOpInt(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001682 RegLocation rlDest, RegLocation rlSrc1,
1683 RegLocation rlSrc2)
1684{
1685 OpKind op = kOpBkpt;
1686 bool callOut = false;
1687 bool checkZero = false;
1688 bool unary = false;
1689 int retReg = r0;
1690 int funcOffset;
1691 RegLocation rlResult;
1692 bool shiftOp = false;
1693
1694 switch (mir->dalvikInsn.opcode) {
1695 case OP_NEG_INT:
1696 op = kOpNeg;
1697 unary = true;
1698 break;
1699 case OP_NOT_INT:
1700 op = kOpMvn;
1701 unary = true;
1702 break;
1703 case OP_ADD_INT:
1704 case OP_ADD_INT_2ADDR:
1705 op = kOpAdd;
1706 break;
1707 case OP_SUB_INT:
1708 case OP_SUB_INT_2ADDR:
1709 op = kOpSub;
1710 break;
1711 case OP_MUL_INT:
1712 case OP_MUL_INT_2ADDR:
1713 op = kOpMul;
1714 break;
1715 case OP_DIV_INT:
1716 case OP_DIV_INT_2ADDR:
1717 callOut = true;
1718 checkZero = true;
1719 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
1720 retReg = r0;
1721 break;
1722 /* NOTE: returns in r1 */
1723 case OP_REM_INT:
1724 case OP_REM_INT_2ADDR:
1725 callOut = true;
1726 checkZero = true;
1727 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
1728 retReg = r1;
1729 break;
1730 case OP_AND_INT:
1731 case OP_AND_INT_2ADDR:
1732 op = kOpAnd;
1733 break;
1734 case OP_OR_INT:
1735 case OP_OR_INT_2ADDR:
1736 op = kOpOr;
1737 break;
1738 case OP_XOR_INT:
1739 case OP_XOR_INT_2ADDR:
1740 op = kOpXor;
1741 break;
1742 case OP_SHL_INT:
1743 case OP_SHL_INT_2ADDR:
1744 shiftOp = true;
1745 op = kOpLsl;
1746 break;
1747 case OP_SHR_INT:
1748 case OP_SHR_INT_2ADDR:
1749 shiftOp = true;
1750 op = kOpAsr;
1751 break;
1752 case OP_USHR_INT:
1753 case OP_USHR_INT_2ADDR:
1754 shiftOp = true;
1755 op = kOpLsr;
1756 break;
1757 default:
1758 LOG(FATAL) << "Invalid word arith op: " <<
1759 (int)mir->dalvikInsn.opcode;
1760 }
1761 if (!callOut) {
1762 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1763 if (unary) {
1764 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1765 opRegReg(cUnit, op, rlResult.lowReg,
1766 rlSrc1.lowReg);
1767 } else {
1768 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1769 if (shiftOp) {
1770 int tReg = oatAllocTemp(cUnit);
1771 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
1772 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1773 opRegRegReg(cUnit, op, rlResult.lowReg,
1774 rlSrc1.lowReg, tReg);
1775 oatFreeTemp(cUnit, tReg);
1776 } else {
1777 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1778 opRegRegReg(cUnit, op, rlResult.lowReg,
1779 rlSrc1.lowReg, rlSrc2.lowReg);
1780 }
1781 }
1782 storeValue(cUnit, rlDest, rlResult);
1783 } else {
1784 RegLocation rlResult;
1785 oatFlushAllRegs(cUnit); /* Send everything to home location */
1786 loadValueDirectFixed(cUnit, rlSrc2, r1);
1787 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1788 loadValueDirectFixed(cUnit, rlSrc1, r0);
1789 if (checkZero) {
buzbee5ade1d22011-09-09 14:44:52 -07001790 genImmedCheck(cUnit, kArmCondEq, r1, 0, mir, kArmThrowDivZero);
buzbee67bf8852011-08-17 17:51:35 -07001791 }
Ian Rogersff1ed472011-09-20 13:46:24 -07001792 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001793 if (retReg == r0)
1794 rlResult = oatGetReturn(cUnit);
1795 else
1796 rlResult = oatGetReturnAlt(cUnit);
1797 storeValue(cUnit, rlDest, rlResult);
1798 }
1799 return false;
1800}
1801
buzbeec1f45042011-09-21 16:03:19 -07001802/* Check if we need to check for pending suspend request */
buzbeeed3e9302011-09-23 17:34:19 -07001803STATIC void genSuspendTest(CompilationUnit* cUnit, MIR* mir)
buzbeec1f45042011-09-21 16:03:19 -07001804{
Ian Rogersa3760aa2011-11-14 14:32:37 -08001805 if (NO_SUSPEND || (mir->optimizationFlags & MIR_IGNORE_SUSPEND_CHECK)) {
buzbeec1f45042011-09-21 16:03:19 -07001806 return;
1807 }
buzbee6181f792011-09-29 11:14:04 -07001808 oatFlushAllRegs(cUnit);
buzbeec1f45042011-09-21 16:03:19 -07001809 newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
1810 ArmLIR* branch = opCondBranch(cUnit, kArmCondEq);
1811 ArmLIR* retLab = newLIR0(cUnit, kArmPseudoTargetLabel);
1812 retLab->defMask = ENCODE_ALL;
1813 ArmLIR* target = (ArmLIR*)oatNew(sizeof(ArmLIR), true);
1814 target->generic.dalvikOffset = cUnit->currentDalvikOffset;
1815 target->opcode = kArmPseudoSuspendTarget;
1816 target->operands[0] = (intptr_t)retLab;
1817 target->operands[1] = mir->offset;
1818 branch->generic.target = (LIR*)target;
1819 oatInsertGrowableList(&cUnit->suspendLaunchpads, (intptr_t)target);
1820}
1821
buzbee67bf8852011-08-17 17:51:35 -07001822/*
1823 * The following are the first-level codegen routines that analyze the format
1824 * of each bytecode then either dispatch special purpose codegen routines
1825 * or produce corresponding Thumb instructions directly.
1826 */
1827
buzbeeed3e9302011-09-23 17:34:19 -07001828STATIC bool isPowerOfTwo(int x)
buzbee67bf8852011-08-17 17:51:35 -07001829{
1830 return (x & (x - 1)) == 0;
1831}
1832
1833// Returns true if no more than two bits are set in 'x'.
buzbeeed3e9302011-09-23 17:34:19 -07001834STATIC bool isPopCountLE2(unsigned int x)
buzbee67bf8852011-08-17 17:51:35 -07001835{
1836 x &= x - 1;
1837 return (x & (x - 1)) == 0;
1838}
1839
1840// Returns the index of the lowest set bit in 'x'.
buzbeeed3e9302011-09-23 17:34:19 -07001841STATIC int lowestSetBit(unsigned int x) {
buzbee67bf8852011-08-17 17:51:35 -07001842 int bit_posn = 0;
1843 while ((x & 0xf) == 0) {
1844 bit_posn += 4;
1845 x >>= 4;
1846 }
1847 while ((x & 1) == 0) {
1848 bit_posn++;
1849 x >>= 1;
1850 }
1851 return bit_posn;
1852}
1853
1854// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
1855// and store the result in 'rlDest'.
buzbeeed3e9302011-09-23 17:34:19 -07001856STATIC bool handleEasyDivide(CompilationUnit* cUnit, Opcode dalvikOpcode,
buzbee67bf8852011-08-17 17:51:35 -07001857 RegLocation rlSrc, RegLocation rlDest, int lit)
1858{
1859 if (lit < 2 || !isPowerOfTwo(lit)) {
1860 return false;
1861 }
1862 int k = lowestSetBit(lit);
1863 if (k >= 30) {
1864 // Avoid special cases.
1865 return false;
1866 }
1867 bool div = (dalvikOpcode == OP_DIV_INT_LIT8 ||
1868 dalvikOpcode == OP_DIV_INT_LIT16);
1869 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1870 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1871 if (div) {
1872 int tReg = oatAllocTemp(cUnit);
1873 if (lit == 2) {
1874 // Division by 2 is by far the most common division by constant.
1875 opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
1876 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1877 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1878 } else {
1879 opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
1880 opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
1881 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1882 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1883 }
1884 } else {
1885 int cReg = oatAllocTemp(cUnit);
1886 loadConstant(cUnit, cReg, lit - 1);
1887 int tReg1 = oatAllocTemp(cUnit);
1888 int tReg2 = oatAllocTemp(cUnit);
1889 if (lit == 2) {
1890 opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
1891 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1892 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1893 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1894 } else {
1895 opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
1896 opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
1897 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1898 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1899 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1900 }
1901 }
1902 storeValue(cUnit, rlDest, rlResult);
1903 return true;
1904}
1905
1906// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
1907// and store the result in 'rlDest'.
buzbeeed3e9302011-09-23 17:34:19 -07001908STATIC bool handleEasyMultiply(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -07001909 RegLocation rlSrc, RegLocation rlDest, int lit)
1910{
1911 // Can we simplify this multiplication?
1912 bool powerOfTwo = false;
1913 bool popCountLE2 = false;
1914 bool powerOfTwoMinusOne = false;
1915 if (lit < 2) {
1916 // Avoid special cases.
1917 return false;
1918 } else if (isPowerOfTwo(lit)) {
1919 powerOfTwo = true;
1920 } else if (isPopCountLE2(lit)) {
1921 popCountLE2 = true;
1922 } else if (isPowerOfTwo(lit + 1)) {
1923 powerOfTwoMinusOne = true;
1924 } else {
1925 return false;
1926 }
1927 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1928 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1929 if (powerOfTwo) {
1930 // Shift.
1931 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
1932 lowestSetBit(lit));
1933 } else if (popCountLE2) {
1934 // Shift and add and shift.
1935 int firstBit = lowestSetBit(lit);
1936 int secondBit = lowestSetBit(lit ^ (1 << firstBit));
1937 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
1938 firstBit, secondBit);
1939 } else {
1940 // Reverse subtract: (src << (shift + 1)) - src.
buzbeeed3e9302011-09-23 17:34:19 -07001941 DCHECK(powerOfTwoMinusOne);
buzbee5ade1d22011-09-09 14:44:52 -07001942 // TUNING: rsb dst, src, src lsl#lowestSetBit(lit + 1)
buzbee67bf8852011-08-17 17:51:35 -07001943 int tReg = oatAllocTemp(cUnit);
1944 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
1945 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
1946 }
1947 storeValue(cUnit, rlDest, rlResult);
1948 return true;
1949}
1950
buzbeeed3e9302011-09-23 17:34:19 -07001951STATIC bool genArithOpIntLit(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001952 RegLocation rlDest, RegLocation rlSrc,
1953 int lit)
1954{
1955 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1956 RegLocation rlResult;
1957 OpKind op = (OpKind)0; /* Make gcc happy */
1958 int shiftOp = false;
1959 bool isDiv = false;
1960 int funcOffset;
1961
1962 switch (dalvikOpcode) {
1963 case OP_RSUB_INT_LIT8:
1964 case OP_RSUB_INT: {
1965 int tReg;
1966 //TUNING: add support for use of Arm rsub op
1967 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1968 tReg = oatAllocTemp(cUnit);
1969 loadConstant(cUnit, tReg, lit);
1970 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1971 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1972 tReg, rlSrc.lowReg);
1973 storeValue(cUnit, rlDest, rlResult);
1974 return false;
1975 break;
1976 }
1977
1978 case OP_ADD_INT_LIT8:
1979 case OP_ADD_INT_LIT16:
1980 op = kOpAdd;
1981 break;
1982 case OP_MUL_INT_LIT8:
1983 case OP_MUL_INT_LIT16: {
1984 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
1985 return false;
1986 }
1987 op = kOpMul;
1988 break;
1989 }
1990 case OP_AND_INT_LIT8:
1991 case OP_AND_INT_LIT16:
1992 op = kOpAnd;
1993 break;
1994 case OP_OR_INT_LIT8:
1995 case OP_OR_INT_LIT16:
1996 op = kOpOr;
1997 break;
1998 case OP_XOR_INT_LIT8:
1999 case OP_XOR_INT_LIT16:
2000 op = kOpXor;
2001 break;
2002 case OP_SHL_INT_LIT8:
2003 lit &= 31;
2004 shiftOp = true;
2005 op = kOpLsl;
2006 break;
2007 case OP_SHR_INT_LIT8:
2008 lit &= 31;
2009 shiftOp = true;
2010 op = kOpAsr;
2011 break;
2012 case OP_USHR_INT_LIT8:
2013 lit &= 31;
2014 shiftOp = true;
2015 op = kOpLsr;
2016 break;
2017
2018 case OP_DIV_INT_LIT8:
2019 case OP_DIV_INT_LIT16:
2020 case OP_REM_INT_LIT8:
2021 case OP_REM_INT_LIT16:
2022 if (lit == 0) {
buzbee5ade1d22011-09-09 14:44:52 -07002023 genImmedCheck(cUnit, kArmCondAl, 0, 0, mir, kArmThrowDivZero);
buzbee67bf8852011-08-17 17:51:35 -07002024 return false;
2025 }
2026 if (handleEasyDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit)) {
2027 return false;
2028 }
2029 oatFlushAllRegs(cUnit); /* Everything to home location */
2030 loadValueDirectFixed(cUnit, rlSrc, r0);
2031 oatClobber(cUnit, r0);
2032 if ((dalvikOpcode == OP_DIV_INT_LIT8) ||
2033 (dalvikOpcode == OP_DIV_INT_LIT16)) {
2034 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
2035 isDiv = true;
2036 } else {
2037 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
2038 isDiv = false;
2039 }
2040 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
2041 loadConstant(cUnit, r1, lit);
Ian Rogersff1ed472011-09-20 13:46:24 -07002042 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07002043 if (isDiv)
2044 rlResult = oatGetReturn(cUnit);
2045 else
2046 rlResult = oatGetReturnAlt(cUnit);
2047 storeValue(cUnit, rlDest, rlResult);
2048 return false;
2049 break;
2050 default:
2051 return true;
2052 }
2053 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2054 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2055 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
2056 if (shiftOp && (lit == 0)) {
2057 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2058 } else {
2059 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2060 }
2061 storeValue(cUnit, rlDest, rlResult);
2062 return false;
2063}
2064
2065/* Architectural-specific debugging helpers go here */
2066void oatArchDump(void)
2067{
2068 /* Print compiled opcode in this VM instance */
2069 int i, start, streak;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002070 std::string buf;
buzbee67bf8852011-08-17 17:51:35 -07002071
2072 streak = i = 0;
buzbee67bf8852011-08-17 17:51:35 -07002073 while (opcodeCoverage[i] == 0 && i < kNumPackedOpcodes) {
2074 i++;
2075 }
2076 if (i == kNumPackedOpcodes) {
2077 return;
2078 }
2079 for (start = i++, streak = 1; i < kNumPackedOpcodes; i++) {
2080 if (opcodeCoverage[i]) {
2081 streak++;
2082 } else {
2083 if (streak == 1) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002084 StringAppendF(&buf, "%x,", start);
buzbee67bf8852011-08-17 17:51:35 -07002085 } else {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002086 StringAppendF(&buf, "%x-%x,", start, start + streak - 1);
buzbee67bf8852011-08-17 17:51:35 -07002087 }
2088 streak = 0;
2089 while (opcodeCoverage[i] == 0 && i < kNumPackedOpcodes) {
2090 i++;
2091 }
2092 if (i < kNumPackedOpcodes) {
2093 streak = 1;
2094 start = i;
2095 }
2096 }
2097 }
2098 if (streak) {
2099 if (streak == 1) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002100 StringAppendF(&buf, "%x", start);
buzbee67bf8852011-08-17 17:51:35 -07002101 } else {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002102 StringAppendF(&buf, "%x-%x", start, start + streak - 1);
buzbee67bf8852011-08-17 17:51:35 -07002103 }
2104 }
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002105 if (!buf.empty()) {
buzbee67bf8852011-08-17 17:51:35 -07002106 LOG(INFO) << "dalvik.vm.oat.op = " << buf;
2107 }
2108}