blob: 423ef4648a3b1123de7ec9350fe6c82c535b35f3 [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * This file contains codegen for the Thumb2 ISA and is intended to be
19 * includes by:
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 */
24
buzbeece302932011-10-04 14:32:18 -070025#define SLOW_FIELD_PATH (cUnit->enableDebug & (1 << kDebugSlowFieldPath))
26#define SLOW_INVOKE_PATH (cUnit->enableDebug & (1 << kDebugSlowInvokePath))
27#define SLOW_STRING_PATH (cUnit->enableDebug & (1 << kDebugSlowStringPath))
28#define SLOW_TYPE_PATH (cUnit->enableDebug & (1 << kDebugSlowTypePath))
29#define EXERCISE_SLOWEST_FIELD_PATH (cUnit->enableDebug & \
30 (1 << kDebugSlowestFieldPath))
31#define EXERCISE_SLOWEST_STRING_PATH (cUnit->enableDebug & \
32 (1 << kDebugSlowestStringPath))
buzbee34c77ad2012-01-11 13:01:32 -080033#define EXERCISE_RESOLVE_METHOD (cUnit->enableDebug & \
34 (1 << kDebugExerciseResolveMethod))
buzbeece302932011-10-04 14:32:18 -070035
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080036namespace art {
37
buzbeece302932011-10-04 14:32:18 -070038STATIC RegLocation getRetLoc(CompilationUnit* cUnit);
buzbee34cd9e52011-09-08 14:31:52 -070039
Elliott Hughes81bc5092011-09-30 17:25:59 -070040void warnIfUnresolved(CompilationUnit* cUnit, int fieldIdx, Field* field) {
41 if (field == NULL) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080042 const DexFile::FieldId& field_id = cUnit->dex_file->GetFieldId(fieldIdx);
Elliott Hughes95572412011-12-13 18:14:20 -080043 std::string class_name(cUnit->dex_file->GetFieldDeclaringClassDescriptor(field_id));
44 std::string field_name(cUnit->dex_file->GetFieldName(field_id));
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080045 LOG(INFO) << "Field " << PrettyDescriptor(class_name) << "." << field_name
Elliott Hughes95572412011-12-13 18:14:20 -080046 << " unresolved at compile time";
Elliott Hughes81bc5092011-09-30 17:25:59 -070047 } else {
48 // We also use the slow path for wide volatile fields.
49 }
50}
51
buzbee67bf8852011-08-17 17:51:35 -070052/*
53 * Construct an s4 from two consecutive half-words of switch data.
54 * This needs to check endianness because the DEX optimizer only swaps
55 * half-words in instruction stream.
56 *
57 * "switchData" must be 32-bit aligned.
58 */
59#if __BYTE_ORDER == __LITTLE_ENDIAN
buzbeeed3e9302011-09-23 17:34:19 -070060STATIC inline s4 s4FromSwitchData(const void* switchData) {
buzbee67bf8852011-08-17 17:51:35 -070061 return *(s4*) switchData;
62}
63#else
buzbeeed3e9302011-09-23 17:34:19 -070064STATIC inline s4 s4FromSwitchData(const void* switchData) {
buzbee67bf8852011-08-17 17:51:35 -070065 u2* data = switchData;
66 return data[0] | (((s4) data[1]) << 16);
67}
68#endif
69
buzbeeed3e9302011-09-23 17:34:19 -070070STATIC ArmLIR* callRuntimeHelper(CompilationUnit* cUnit, int reg)
buzbeeec5adf32011-09-11 15:25:43 -070071{
buzbee6181f792011-09-29 11:14:04 -070072 oatClobberCalleeSave(cUnit);
buzbeeec5adf32011-09-11 15:25:43 -070073 return opReg(cUnit, kOpBlx, reg);
74}
75
buzbee1b4c8592011-08-31 10:43:51 -070076/* Generate unconditional branch instructions */
buzbeeed3e9302011-09-23 17:34:19 -070077STATIC ArmLIR* genUnconditionalBranch(CompilationUnit* cUnit, ArmLIR* target)
buzbee1b4c8592011-08-31 10:43:51 -070078{
79 ArmLIR* branch = opNone(cUnit, kOpUncondBr);
80 branch->generic.target = (LIR*) target;
81 return branch;
82}
83
buzbee67bf8852011-08-17 17:51:35 -070084/*
85 * Generate a Thumb2 IT instruction, which can nullify up to
86 * four subsequent instructions based on a condition and its
87 * inverse. The condition applies to the first instruction, which
88 * is executed if the condition is met. The string "guide" consists
89 * of 0 to 3 chars, and applies to the 2nd through 4th instruction.
90 * A "T" means the instruction is executed if the condition is
91 * met, and an "E" means the instruction is executed if the condition
92 * is not met.
93 */
buzbeeed3e9302011-09-23 17:34:19 -070094STATIC ArmLIR* genIT(CompilationUnit* cUnit, ArmConditionCode code,
buzbee67bf8852011-08-17 17:51:35 -070095 const char* guide)
96{
97 int mask;
98 int condBit = code & 1;
99 int altBit = condBit ^ 1;
100 int mask3 = 0;
101 int mask2 = 0;
102 int mask1 = 0;
103
104 //Note: case fallthroughs intentional
105 switch(strlen(guide)) {
106 case 3:
107 mask1 = (guide[2] == 'T') ? condBit : altBit;
108 case 2:
109 mask2 = (guide[1] == 'T') ? condBit : altBit;
110 case 1:
111 mask3 = (guide[0] == 'T') ? condBit : altBit;
112 break;
113 case 0:
114 break;
115 default:
116 LOG(FATAL) << "OAT: bad case in genIT";
117 }
118 mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
119 (1 << (3 - strlen(guide)));
120 return newLIR2(cUnit, kThumb2It, code, mask);
121}
122
123/*
124 * Insert a kArmPseudoCaseLabel at the beginning of the Dalvik
125 * offset vaddr. This label will be used to fix up the case
126 * branch table during the assembly phase. Be sure to set
127 * all resource flags on this to prevent code motion across
128 * target boundaries. KeyVal is just there for debugging.
129 */
buzbeeed3e9302011-09-23 17:34:19 -0700130STATIC ArmLIR* insertCaseLabel(CompilationUnit* cUnit, int vaddr, int keyVal)
buzbee67bf8852011-08-17 17:51:35 -0700131{
buzbee85d8c1e2012-01-27 15:52:35 -0800132 std::map<unsigned int, LIR*>::iterator it;
133 it = cUnit->boundaryMap.find(vaddr);
134 if (it == cUnit->boundaryMap.end()) {
135 LOG(FATAL) << "Error: didn't find vaddr 0x" << std::hex << vaddr;
buzbee67bf8852011-08-17 17:51:35 -0700136 }
buzbeeba938cb2012-02-03 14:47:55 -0800137 ArmLIR* newLabel = (ArmLIR*)oatNew(cUnit, sizeof(ArmLIR), true, kAllocLIR);
buzbee85d8c1e2012-01-27 15:52:35 -0800138 newLabel->generic.dalvikOffset = vaddr;
139 newLabel->opcode = kArmPseudoCaseLabel;
140 newLabel->operands[0] = keyVal;
141 oatInsertLIRAfter(it->second, (LIR*)newLabel);
142 return newLabel;
buzbee67bf8852011-08-17 17:51:35 -0700143}
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
buzbeeba938cb2012-02-03 14:47:55 -0800262 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
buzbee5abfa3e2012-01-31 17:01:43 -0800263 true, kAllocData);
buzbee67bf8852011-08-17 17:51:35 -0700264 tabRec->table = table;
265 tabRec->vaddr = mir->offset;
266 int size = table[1];
buzbeeba938cb2012-02-03 14:47:55 -0800267 tabRec->targets = (ArmLIR* *)oatNew(cUnit, size * sizeof(ArmLIR*), true,
buzbee5abfa3e2012-01-31 17:01:43 -0800268 kAllocLIR);
buzbeeba938cb2012-02-03 14:47:55 -0800269 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700270
271 // Get the switch value
272 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
273 int rBase = oatAllocTemp(cUnit);
274 /* Allocate key and disp temps */
275 int rKey = oatAllocTemp(cUnit);
276 int rDisp = oatAllocTemp(cUnit);
277 // Make sure rKey's register number is less than rDisp's number for ldmia
278 if (rKey > rDisp) {
279 int tmp = rDisp;
280 rDisp = rKey;
281 rKey = tmp;
282 }
283 // Materialize a pointer to the switch table
buzbee03fa2632011-09-20 17:10:57 -0700284 newLIR3(cUnit, kThumb2Adr, rBase, 0, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700285 // Set up rIdx
286 int rIdx = oatAllocTemp(cUnit);
287 loadConstant(cUnit, rIdx, size);
288 // Establish loop branch target
289 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
290 target->defMask = ENCODE_ALL;
291 // Load next key/disp
292 newLIR2(cUnit, kThumb2LdmiaWB, rBase, (1 << rKey) | (1 << rDisp));
293 opRegReg(cUnit, kOpCmp, rKey, rlSrc.lowReg);
294 // Go if match. NOTE: No instruction set switch here - must stay Thumb2
295 genIT(cUnit, kArmCondEq, "");
296 ArmLIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, rDisp);
297 tabRec->bxInst = switchBranch;
298 // Needs to use setflags encoding here
299 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
300 ArmLIR* branch = opCondBranch(cUnit, kArmCondNe);
301 branch->generic.target = (LIR*)target;
302}
303
304
buzbeeed3e9302011-09-23 17:34:19 -0700305STATIC void genPackedSwitch(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700306 RegLocation rlSrc)
307{
308 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
309 if (cUnit->printMe) {
310 dumpPackedSwitchTable(table);
311 }
312 // Add the table to the list - we'll process it later
buzbeeba938cb2012-02-03 14:47:55 -0800313 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
buzbee5abfa3e2012-01-31 17:01:43 -0800314 true, kAllocData);
buzbee67bf8852011-08-17 17:51:35 -0700315 tabRec->table = table;
316 tabRec->vaddr = mir->offset;
317 int size = table[1];
buzbeeba938cb2012-02-03 14:47:55 -0800318 tabRec->targets = (ArmLIR* *)oatNew(cUnit, size * sizeof(ArmLIR*), true,
buzbee5abfa3e2012-01-31 17:01:43 -0800319 kAllocLIR);
buzbeeba938cb2012-02-03 14:47:55 -0800320 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700321
322 // Get the switch value
323 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
324 int tableBase = oatAllocTemp(cUnit);
325 // Materialize a pointer to the switch table
buzbee03fa2632011-09-20 17:10:57 -0700326 newLIR3(cUnit, kThumb2Adr, tableBase, 0, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700327 int lowKey = s4FromSwitchData(&table[2]);
328 int keyReg;
329 // Remove the bias, if necessary
330 if (lowKey == 0) {
331 keyReg = rlSrc.lowReg;
332 } else {
333 keyReg = oatAllocTemp(cUnit);
334 opRegRegImm(cUnit, kOpSub, keyReg, rlSrc.lowReg, lowKey);
335 }
336 // Bounds check - if < 0 or >= size continue following switch
337 opRegImm(cUnit, kOpCmp, keyReg, size-1);
338 ArmLIR* branchOver = opCondBranch(cUnit, kArmCondHi);
339
340 // Load the displacement from the switch table
341 int dispReg = oatAllocTemp(cUnit);
342 loadBaseIndexed(cUnit, tableBase, keyReg, dispReg, 2, kWord);
343
344 // ..and go! NOTE: No instruction set switch here - must stay Thumb2
345 ArmLIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, dispReg);
346 tabRec->bxInst = switchBranch;
347
348 /* branchOver target here */
349 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
350 target->defMask = ENCODE_ALL;
351 branchOver->generic.target = (LIR*)target;
352}
353
354/*
355 * Array data table format:
356 * ushort ident = 0x0300 magic value
357 * ushort width width of each element in the table
358 * uint size number of elements in the table
359 * ubyte data[size*width] table of data values (may contain a single-byte
360 * padding at the end)
361 *
362 * Total size is 4+(width * size + 1)/2 16-bit code units.
363 */
buzbeeed3e9302011-09-23 17:34:19 -0700364STATIC void genFillArrayData(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700365 RegLocation rlSrc)
366{
367 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
368 // Add the table to the list - we'll process it later
369 FillArrayData *tabRec = (FillArrayData *)
buzbeeba938cb2012-02-03 14:47:55 -0800370 oatNew(cUnit, sizeof(FillArrayData), true, kAllocData);
buzbee67bf8852011-08-17 17:51:35 -0700371 tabRec->table = table;
372 tabRec->vaddr = mir->offset;
373 u2 width = tabRec->table[1];
374 u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
375 tabRec->size = (size * width) + 8;
376
buzbeeba938cb2012-02-03 14:47:55 -0800377 oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700378
379 // Making a call - use explicit registers
380 oatFlushAllRegs(cUnit); /* Everything to home location */
381 loadValueDirectFixed(cUnit, rlSrc, r0);
382 loadWordDisp(cUnit, rSELF,
buzbee1b4c8592011-08-31 10:43:51 -0700383 OFFSETOF_MEMBER(Thread, pHandleFillArrayDataFromCode), rLR);
buzbeee6d61962011-08-27 11:58:19 -0700384 // Materialize a pointer to the fill data image
buzbee03fa2632011-09-20 17:10:57 -0700385 newLIR3(cUnit, kThumb2Adr, r1, 0, (intptr_t)tabRec);
Ian Rogersff1ed472011-09-20 13:46:24 -0700386 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700387}
388
389/*
390 * Mark garbage collection card. Skip if the value we're storing is null.
391 */
buzbeeed3e9302011-09-23 17:34:19 -0700392STATIC void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg)
buzbee67bf8852011-08-17 17:51:35 -0700393{
394 int regCardBase = oatAllocTemp(cUnit);
395 int regCardNo = oatAllocTemp(cUnit);
396 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondEq, valReg, 0);
buzbeec143c552011-08-20 17:38:58 -0700397 loadWordDisp(cUnit, rSELF, Thread::CardTableOffset().Int32Value(),
buzbee67bf8852011-08-17 17:51:35 -0700398 regCardBase);
399 opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT);
400 storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
401 kUnsignedByte);
402 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
403 target->defMask = ENCODE_ALL;
404 branchOver->generic.target = (LIR*)target;
405 oatFreeTemp(cUnit, regCardBase);
406 oatFreeTemp(cUnit, regCardNo);
407}
408
buzbee34cd9e52011-09-08 14:31:52 -0700409/*
410 * Helper function for Iget/put when field not resolved at compile time.
411 * Will trash call temps and return with the field offset in r0.
412 */
Elliott Hughes81bc5092011-09-30 17:25:59 -0700413STATIC void getFieldOffset(CompilationUnit* cUnit, MIR* mir, Field* fieldPtr)
buzbee34cd9e52011-09-08 14:31:52 -0700414{
415 int fieldIdx = mir->dalvikInsn.vC;
buzbee6181f792011-09-29 11:14:04 -0700416 oatFlushAllRegs(cUnit);
Elliott Hughes81bc5092011-09-30 17:25:59 -0700417 warnIfUnresolved(cUnit, fieldIdx, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700418 oatLockCallTemps(cUnit); // Explicit register usage
419 loadCurrMethodDirect(cUnit, r1); // arg1 <= Method*
420 loadWordDisp(cUnit, r1,
421 Method::DexCacheResolvedFieldsOffset().Int32Value(), r0);
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800422 loadWordDisp(cUnit, r0, Array::DataOffset().Int32Value() +
buzbee34cd9e52011-09-08 14:31:52 -0700423 sizeof(int32_t*)* fieldIdx, r0);
424 /*
425 * For testing, omit the test for run-time resolution. This will
426 * force all accesses to go through the runtime resolution path.
427 */
buzbeece302932011-10-04 14:32:18 -0700428 ArmLIR* branchOver = NULL;
429 if (!EXERCISE_SLOWEST_FIELD_PATH) {
430 branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0);
431 }
buzbee34cd9e52011-09-08 14:31:52 -0700432 // Resolve
433 loadWordDisp(cUnit, rSELF,
Brian Carlstrom845490b2011-09-19 15:56:53 -0700434 OFFSETOF_MEMBER(Thread, pFindInstanceFieldFromCode), rLR);
buzbee34cd9e52011-09-08 14:31:52 -0700435 loadConstant(cUnit, r0, fieldIdx);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700436 callRuntimeHelper(cUnit, rLR); // FindInstanceFieldFromCoderesolveTypeFromCode(idx, method)
buzbee34cd9e52011-09-08 14:31:52 -0700437 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
438 target->defMask = ENCODE_ALL;
buzbeece302932011-10-04 14:32:18 -0700439 if (!EXERCISE_SLOWEST_FIELD_PATH) {
440 branchOver->generic.target = (LIR*)target;
441 }
buzbee34cd9e52011-09-08 14:31:52 -0700442 // Free temps (except for r0)
443 oatFreeTemp(cUnit, r1);
444 oatFreeTemp(cUnit, r2);
445 oatFreeTemp(cUnit, r3);
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800446 loadWordDisp(cUnit, r0, Field::OffsetOffset().Int32Value(), r0);
buzbee34cd9e52011-09-08 14:31:52 -0700447}
448
buzbeeed3e9302011-09-23 17:34:19 -0700449STATIC void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -0700450 RegLocation rlDest, RegLocation rlObj)
451{
Ian Rogersa3760aa2011-11-14 14:32:37 -0800452 Field* fieldPtr = cUnit->dex_cache->GetResolvedField(mir->dalvikInsn.vC);
buzbee67bf8852011-08-17 17:51:35 -0700453 RegLocation rlResult;
454 RegisterClass regClass = oatRegClassBySize(size);
buzbee34cd9e52011-09-08 14:31:52 -0700455 if (SLOW_FIELD_PATH || fieldPtr == NULL) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700456 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700457 // Field offset in r0
458 rlObj = loadValue(cUnit, rlObj, kCoreReg);
459 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
buzbee5ade1d22011-09-09 14:44:52 -0700460 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
buzbee58f92742011-10-01 11:22:17 -0700461 loadBaseIndexed(cUnit, rlObj.lowReg, r0, rlResult.lowReg, 0, kWord);
buzbee67bf8852011-08-17 17:51:35 -0700462 oatGenMemBarrier(cUnit, kSY);
buzbee34cd9e52011-09-08 14:31:52 -0700463 storeValue(cUnit, rlDest, rlResult);
464 } else {
465#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700466 bool isVolatile = fieldPtr->IsVolatile();
buzbee34cd9e52011-09-08 14:31:52 -0700467#else
468 bool isVolatile = false;
469#endif
470 int fieldOffset = fieldPtr->GetOffset().Int32Value();
471 rlObj = loadValue(cUnit, rlObj, kCoreReg);
472 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
buzbee5ade1d22011-09-09 14:44:52 -0700473 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
buzbee34cd9e52011-09-08 14:31:52 -0700474 loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
buzbee58f92742011-10-01 11:22:17 -0700475 kWord, rlObj.sRegLow);
buzbee34cd9e52011-09-08 14:31:52 -0700476 if (isVolatile) {
477 oatGenMemBarrier(cUnit, kSY);
478 }
479 storeValue(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -0700480 }
buzbee67bf8852011-08-17 17:51:35 -0700481}
482
buzbeeed3e9302011-09-23 17:34:19 -0700483STATIC void genIPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -0700484 RegLocation rlSrc, RegLocation rlObj, bool isObject)
485{
Ian Rogersa3760aa2011-11-14 14:32:37 -0800486 Field* fieldPtr = cUnit->dex_cache->GetResolvedField(mir->dalvikInsn.vC);
buzbee67bf8852011-08-17 17:51:35 -0700487 RegisterClass regClass = oatRegClassBySize(size);
buzbee34cd9e52011-09-08 14:31:52 -0700488 if (SLOW_FIELD_PATH || fieldPtr == NULL) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700489 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700490 // Field offset in r0
491 rlObj = loadValue(cUnit, rlObj, kCoreReg);
492 rlSrc = loadValue(cUnit, rlSrc, regClass);
buzbee5ade1d22011-09-09 14:44:52 -0700493 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
buzbee67bf8852011-08-17 17:51:35 -0700494 oatGenMemBarrier(cUnit, kSY);
buzbee58f92742011-10-01 11:22:17 -0700495 storeBaseIndexed(cUnit, rlObj.lowReg, r0, rlSrc.lowReg, 0, kWord);
buzbee34cd9e52011-09-08 14:31:52 -0700496 } else {
497#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700498 bool isVolatile = fieldPtr->IsVolatile();
buzbee34cd9e52011-09-08 14:31:52 -0700499#else
500 bool isVolatile = false;
501#endif
502 int fieldOffset = fieldPtr->GetOffset().Int32Value();
503 rlObj = loadValue(cUnit, rlObj, kCoreReg);
504 rlSrc = loadValue(cUnit, rlSrc, regClass);
buzbee5ade1d22011-09-09 14:44:52 -0700505 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700506
507 if (isVolatile) {
buzbee12246b82011-09-29 14:15:05 -0700508 oatGenMemBarrier(cUnit, kST);
buzbee34cd9e52011-09-08 14:31:52 -0700509 }
buzbee58f92742011-10-01 11:22:17 -0700510 storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, kWord);
buzbee12246b82011-09-29 14:15:05 -0700511 if (isVolatile) {
512 oatGenMemBarrier(cUnit, kSY);
513 }
buzbee67bf8852011-08-17 17:51:35 -0700514 }
buzbee67bf8852011-08-17 17:51:35 -0700515 if (isObject) {
516 /* NOTE: marking card based on object head */
517 markGCCard(cUnit, rlSrc.lowReg, rlObj.lowReg);
518 }
519}
520
buzbeeed3e9302011-09-23 17:34:19 -0700521STATIC void genIGetWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700522 RegLocation rlObj)
523{
buzbee12246b82011-09-29 14:15:05 -0700524 RegLocation rlResult;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800525 Field* fieldPtr = cUnit->dex_cache->GetResolvedField(mir->dalvikInsn.vC);
buzbee12246b82011-09-29 14:15:05 -0700526#if ANDROID_SMP != 0
527 bool isVolatile = (fieldPtr == NULL) || fieldPtr->IsVolatile();
528#else
529 bool isVolatile = false;
530#endif
buzbeece302932011-10-04 14:32:18 -0700531 if (SLOW_FIELD_PATH || (fieldPtr == NULL) || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700532 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700533 // Field offset in r0
534 rlObj = loadValue(cUnit, rlObj, kCoreReg);
535 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee5ade1d22011-09-09 14:44:52 -0700536 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700537 opRegReg(cUnit, kOpAdd, r0, rlObj.lowReg);
538 loadPair(cUnit, r0, rlResult.lowReg, rlResult.highReg);
buzbee67bf8852011-08-17 17:51:35 -0700539 oatGenMemBarrier(cUnit, kSY);
buzbee12246b82011-09-29 14:15:05 -0700540 storeValueWide(cUnit, rlDest, rlResult);
buzbee34cd9e52011-09-08 14:31:52 -0700541 } else {
buzbee34cd9e52011-09-08 14:31:52 -0700542 int fieldOffset = fieldPtr->GetOffset().Int32Value();
543 rlObj = loadValue(cUnit, rlObj, kCoreReg);
544 int regPtr = oatAllocTemp(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700545
buzbeeed3e9302011-09-23 17:34:19 -0700546 DCHECK(rlDest.wide);
buzbee34cd9e52011-09-08 14:31:52 -0700547
buzbee5ade1d22011-09-09 14:44:52 -0700548 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700549 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
550 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
551
552 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
553
buzbee34cd9e52011-09-08 14:31:52 -0700554 oatFreeTemp(cUnit, regPtr);
555 storeValueWide(cUnit, rlDest, rlResult);
556 }
buzbee67bf8852011-08-17 17:51:35 -0700557}
558
buzbeeed3e9302011-09-23 17:34:19 -0700559STATIC void genIPutWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
buzbee67bf8852011-08-17 17:51:35 -0700560 RegLocation rlObj)
561{
Ian Rogersa3760aa2011-11-14 14:32:37 -0800562 Field* fieldPtr = cUnit->dex_cache->GetResolvedField(mir->dalvikInsn.vC);
buzbee12246b82011-09-29 14:15:05 -0700563#if ANDROID_SMP != 0
564 bool isVolatile = (fieldPtr == NULL) || fieldPtr->IsVolatile();
565#else
566 bool isVolatile = false;
567#endif
buzbeece302932011-10-04 14:32:18 -0700568 if (SLOW_FIELD_PATH || (fieldPtr == NULL) || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700569 getFieldOffset(cUnit, mir, fieldPtr);
buzbee34cd9e52011-09-08 14:31:52 -0700570 // Field offset in r0
571 rlObj = loadValue(cUnit, rlObj, kCoreReg);
572 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
buzbee5ade1d22011-09-09 14:44:52 -0700573 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700574 opRegReg(cUnit, kOpAdd, r0, rlObj.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700575 oatGenMemBarrier(cUnit, kSY);
buzbee34cd9e52011-09-08 14:31:52 -0700576 storePair(cUnit, r0, rlSrc.lowReg, rlSrc.highReg);
577 } else {
buzbee34cd9e52011-09-08 14:31:52 -0700578 int fieldOffset = fieldPtr->GetOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -0700579
buzbee34cd9e52011-09-08 14:31:52 -0700580 rlObj = loadValue(cUnit, rlObj, kCoreReg);
581 int regPtr;
582 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
buzbee5ade1d22011-09-09 14:44:52 -0700583 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
buzbee34cd9e52011-09-08 14:31:52 -0700584 regPtr = oatAllocTemp(cUnit);
585 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
586
buzbee34cd9e52011-09-08 14:31:52 -0700587 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
588
589 oatFreeTemp(cUnit, regPtr);
590 }
buzbee67bf8852011-08-17 17:51:35 -0700591}
592
buzbeeed3e9302011-09-23 17:34:19 -0700593STATIC void genConstClass(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700594 RegLocation rlDest, RegLocation rlSrc)
595{
Ian Rogers28ad40d2011-10-27 15:19:26 -0700596 uint32_t type_idx = mir->dalvikInsn.vB;
buzbee1b4c8592011-08-31 10:43:51 -0700597 int mReg = loadCurrMethod(cUnit);
598 int resReg = oatAllocTemp(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700599 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
Ian Rogersa3760aa2011-11-14 14:32:37 -0800600 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
601 cUnit->dex_cache,
602 *cUnit->dex_file,
603 type_idx)) {
604 // Call out to helper which resolves type and verifies access.
605 // Resolved type returned in r0.
606 loadWordDisp(cUnit, rSELF,
607 OFFSETOF_MEMBER(Thread, pInitializeTypeAndVerifyAccessFromCode),
608 rLR);
609 genRegCopy(cUnit, r1, mReg);
610 loadConstant(cUnit, r0, type_idx);
611 callRuntimeHelper(cUnit, rLR);
612 RegLocation rlResult = oatGetReturn(cUnit);
613 storeValue(cUnit, rlDest, rlResult);
buzbee1b4c8592011-08-31 10:43:51 -0700614 } else {
Ian Rogers28ad40d2011-10-27 15:19:26 -0700615 // We're don't need access checks, load type from dex cache
616 int32_t dex_cache_offset = Method::DexCacheResolvedTypesOffset().Int32Value();
617 loadWordDisp(cUnit, mReg, dex_cache_offset, resReg);
618 int32_t offset_of_type = Array::DataOffset().Int32Value() + (sizeof(Class*) * type_idx);
619 loadWordDisp(cUnit, resReg, offset_of_type, rlResult.lowReg);
Ian Rogersa3760aa2011-11-14 14:32:37 -0800620 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->dex_cache,
621 type_idx) ||
Ian Rogers28ad40d2011-10-27 15:19:26 -0700622 SLOW_TYPE_PATH) {
623 // Slow path, at runtime test if the type is null and if so initialize
624 oatFlushAllRegs(cUnit);
625 ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, rlResult.lowReg, 0);
626 // Resolved, store and hop over following code
627 storeValue(cUnit, rlDest, rlResult);
628 ArmLIR* branch2 = genUnconditionalBranch(cUnit,0);
629 // TUNING: move slow path to end & remove unconditional branch
630 ArmLIR* target1 = newLIR0(cUnit, kArmPseudoTargetLabel);
631 target1->defMask = ENCODE_ALL;
632 // Call out to helper, which will return resolved type in r0
633 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
634 genRegCopy(cUnit, r1, mReg);
635 loadConstant(cUnit, r0, type_idx);
636 callRuntimeHelper(cUnit, rLR);
637 RegLocation rlResult = oatGetReturn(cUnit);
638 storeValue(cUnit, rlDest, rlResult);
639 // Rejoin code paths
640 ArmLIR* target2 = newLIR0(cUnit, kArmPseudoTargetLabel);
641 target2->defMask = ENCODE_ALL;
642 branch1->generic.target = (LIR*)target1;
643 branch2->generic.target = (LIR*)target2;
644 } else {
645 // Fast path, we're done - just store result
646 storeValue(cUnit, rlDest, rlResult);
647 }
buzbee1b4c8592011-08-31 10:43:51 -0700648 }
buzbee67bf8852011-08-17 17:51:35 -0700649}
650
buzbeeed3e9302011-09-23 17:34:19 -0700651STATIC void genConstString(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700652 RegLocation rlDest, RegLocation rlSrc)
653{
buzbeece302932011-10-04 14:32:18 -0700654 /* NOTE: Most strings should be available at compile time */
Ian Rogers28ad40d2011-10-27 15:19:26 -0700655 uint32_t string_idx = mir->dalvikInsn.vB;
656 int32_t offset_of_string = Array::DataOffset().Int32Value() + (sizeof(String*) * string_idx);
Ian Rogersa3760aa2011-11-14 14:32:37 -0800657 if (!cUnit->compiler->CanAssumeStringIsPresentInDexCache(cUnit->dex_cache, string_idx) ||
Ian Rogers28ad40d2011-10-27 15:19:26 -0700658 SLOW_STRING_PATH) {
659 // slow path, resolve string if not in dex cache
buzbeece302932011-10-04 14:32:18 -0700660 oatFlushAllRegs(cUnit);
661 oatLockCallTemps(cUnit); // Using explicit registers
662 loadCurrMethodDirect(cUnit, r2);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700663 loadWordDisp(cUnit, r2, Method::DexCacheStringsOffset().Int32Value(), r0);
buzbeece302932011-10-04 14:32:18 -0700664 // Might call out to helper, which will return resolved string in r0
Ian Rogers28ad40d2011-10-27 15:19:26 -0700665 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pResolveStringFromCode), rLR);
666 loadWordDisp(cUnit, r0, offset_of_string, r0);
667 loadConstant(cUnit, r1, string_idx);
buzbeece302932011-10-04 14:32:18 -0700668 opRegImm(cUnit, kOpCmp, r0, 0); // Is resolved?
669 genBarrier(cUnit);
670 // For testing, always force through helper
671 if (!EXERCISE_SLOWEST_STRING_PATH) {
672 genIT(cUnit, kArmCondEq, "T");
673 }
674 genRegCopy(cUnit, r0, r2); // .eq
675 opReg(cUnit, kOpBlx, rLR); // .eq, helper(Method*, string_idx)
676 genBarrier(cUnit);
677 storeValue(cUnit, rlDest, getRetLoc(cUnit));
678 } else {
679 int mReg = loadCurrMethod(cUnit);
680 int resReg = oatAllocTemp(cUnit);
681 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700682 loadWordDisp(cUnit, mReg, Method::DexCacheStringsOffset().Int32Value(), resReg);
683 loadWordDisp(cUnit, resReg, offset_of_string, rlResult.lowReg);
buzbeece302932011-10-04 14:32:18 -0700684 storeValue(cUnit, rlDest, rlResult);
685 }
buzbee67bf8852011-08-17 17:51:35 -0700686}
687
buzbeedfd3d702011-08-28 12:56:51 -0700688/*
689 * Let helper function take care of everything. Will
690 * call Class::NewInstanceFromCode(type_idx, method);
691 */
buzbeeed3e9302011-09-23 17:34:19 -0700692STATIC void genNewInstance(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700693 RegLocation rlDest)
694{
buzbeedfd3d702011-08-28 12:56:51 -0700695 oatFlushAllRegs(cUnit); /* Everything to home location */
Ian Rogers28ad40d2011-10-27 15:19:26 -0700696 uint32_t type_idx = mir->dalvikInsn.vB;
697 // alloc will always check for resolution, do we also need to verify access because the
698 // verifier was unable to?
Ian Rogersd4135902012-02-03 18:05:08 -0800699 if (cUnit->compiler->CanAccessInstantiableTypeWithoutChecks(cUnit->method_idx,
700 cUnit->dex_cache,
701 *cUnit->dex_file,
702 type_idx)) {
Ian Rogers28ad40d2011-10-27 15:19:26 -0700703 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pAllocObjectFromCode), rLR);
704 } else {
705 loadWordDisp(cUnit, rSELF,
706 OFFSETOF_MEMBER(Thread, pAllocObjectFromCodeWithAccessCheck), rLR);
707 }
708 loadCurrMethodDirect(cUnit, r1); // arg1 <= Method*
709 loadConstant(cUnit, r0, type_idx); // arg0 <- type_idx
Ian Rogersff1ed472011-09-20 13:46:24 -0700710 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700711 RegLocation rlResult = oatGetReturn(cUnit);
712 storeValue(cUnit, rlDest, rlResult);
713}
714
715void genThrow(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
716{
buzbee6181f792011-09-29 11:14:04 -0700717 oatFlushAllRegs(cUnit);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700718 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pDeliverException), rLR);
Ian Rogersbdb03912011-09-14 00:55:44 -0700719 loadValueDirectFixed(cUnit, rlSrc, r0); // Get exception object
Ian Rogersff1ed472011-09-20 13:46:24 -0700720 callRuntimeHelper(cUnit, rLR); // art_deliver_exception(exception);
buzbee67bf8852011-08-17 17:51:35 -0700721}
722
buzbeeed3e9302011-09-23 17:34:19 -0700723STATIC void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700724 RegLocation rlSrc)
725{
buzbee6181f792011-09-29 11:14:04 -0700726 oatFlushAllRegs(cUnit);
buzbee2a475e72011-09-07 17:19:17 -0700727 // May generate a call - use explicit registers
728 oatLockCallTemps(cUnit);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700729 uint32_t type_idx = mir->dalvikInsn.vC;
buzbee2a475e72011-09-07 17:19:17 -0700730 loadCurrMethodDirect(cUnit, r1); // r1 <= current Method*
Ian Rogers28ad40d2011-10-27 15:19:26 -0700731 int classReg = r2; // r2 will hold the Class*
Ian Rogersa3760aa2011-11-14 14:32:37 -0800732 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
733 cUnit->dex_cache,
734 *cUnit->dex_file,
735 type_idx)) {
Ian Rogersb093c6b2011-10-31 16:19:55 -0700736 // Check we have access to type_idx and if not throw IllegalAccessError,
737 // returns Class* in r0
738 loadWordDisp(cUnit, rSELF,
739 OFFSETOF_MEMBER(Thread, pInitializeTypeAndVerifyAccessFromCode),
740 rLR);
741 loadConstant(cUnit, r0, type_idx);
742 callRuntimeHelper(cUnit, rLR); // InitializeTypeAndVerifyAccess(idx, method)
743 genRegCopy(cUnit, classReg, r0); // Align usage with fast path
Ian Rogers6a996782011-10-31 17:06:39 -0700744 loadValueDirectFixed(cUnit, rlSrc, r0); // r0 <= ref
Ian Rogers28ad40d2011-10-27 15:19:26 -0700745 } else {
746 // Load dex cache entry into classReg (r2)
Ian Rogers6a996782011-10-31 17:06:39 -0700747 loadValueDirectFixed(cUnit, rlSrc, r0); // r0 <= ref
Ian Rogers28ad40d2011-10-27 15:19:26 -0700748 loadWordDisp(cUnit, r1, Method::DexCacheResolvedTypesOffset().Int32Value(), classReg);
749 int32_t offset_of_type = Array::DataOffset().Int32Value() + (sizeof(Class*) * type_idx);
750 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
Ian Rogersa3760aa2011-11-14 14:32:37 -0800751 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->dex_cache, type_idx)) {
Ian Rogers28ad40d2011-10-27 15:19:26 -0700752 // Need to test presence of type in dex cache at runtime
753 ArmLIR* hopBranch = genCmpImmBranch(cUnit, kArmCondNe, classReg, 0);
754 // Not resolved
755 // Call out to helper, which will return resolved type in r0
756 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
757 loadConstant(cUnit, r0, type_idx);
Ian Rogersb093c6b2011-10-31 16:19:55 -0700758 callRuntimeHelper(cUnit, rLR); // InitializeTypeFromCode(idx, method)
Ian Rogers28ad40d2011-10-27 15:19:26 -0700759 genRegCopy(cUnit, r2, r0); // Align usage with fast path
760 loadValueDirectFixed(cUnit, rlSrc, r0); /* reload Ref */
761 // Rejoin code paths
762 ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
763 hopTarget->defMask = ENCODE_ALL;
764 hopBranch->generic.target = (LIR*)hopTarget;
765 }
buzbee67bf8852011-08-17 17:51:35 -0700766 }
buzbee991e3ac2011-09-29 15:44:22 -0700767 /* r0 is ref, r2 is class. If ref==null, use directly as bool result */
768 ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, r0, 0);
buzbee2a475e72011-09-07 17:19:17 -0700769 /* load object->clazz */
buzbeeed3e9302011-09-23 17:34:19 -0700770 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
buzbee991e3ac2011-09-29 15:44:22 -0700771 loadWordDisp(cUnit, r0, Object::ClassOffset().Int32Value(), r1);
772 /* r0 is ref, r1 is ref->clazz, r2 is class */
Ian Rogers28ad40d2011-10-27 15:19:26 -0700773 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInstanceofNonTrivialFromCode), rLR);
buzbee991e3ac2011-09-29 15:44:22 -0700774 opRegReg(cUnit, kOpCmp, r1, r2); // Same?
775 genBarrier(cUnit);
776 genIT(cUnit, kArmCondEq, "EE"); // if-convert the test
777 loadConstant(cUnit, r0, 1); // .eq case - load true
778 genRegCopy(cUnit, r0, r2); // .ne case - arg0 <= class
779 opReg(cUnit, kOpBlx, rLR); // .ne case: helper(class, ref->class)
780 genBarrier(cUnit);
781 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700782 /* branch target here */
783 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
784 target->defMask = ENCODE_ALL;
buzbee2a475e72011-09-07 17:19:17 -0700785 RegLocation rlResult = oatGetReturn(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700786 storeValue(cUnit, rlDest, rlResult);
787 branch1->generic.target = (LIR*)target;
buzbee67bf8852011-08-17 17:51:35 -0700788}
789
buzbeeed3e9302011-09-23 17:34:19 -0700790STATIC void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700791{
buzbee6181f792011-09-29 11:14:04 -0700792 oatFlushAllRegs(cUnit);
buzbee2a475e72011-09-07 17:19:17 -0700793 // May generate a call - use explicit registers
794 oatLockCallTemps(cUnit);
Ian Rogers28ad40d2011-10-27 15:19:26 -0700795 uint32_t type_idx = mir->dalvikInsn.vB;
buzbee2a475e72011-09-07 17:19:17 -0700796 loadCurrMethodDirect(cUnit, r1); // r1 <= current Method*
Ian Rogers28ad40d2011-10-27 15:19:26 -0700797 int classReg = r2; // r2 will hold the Class*
Ian Rogersa3760aa2011-11-14 14:32:37 -0800798 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
799 cUnit->dex_cache,
800 *cUnit->dex_file,
801 type_idx)) {
Ian Rogersb093c6b2011-10-31 16:19:55 -0700802 // Check we have access to type_idx and if not throw IllegalAccessError,
803 // returns Class* in r0
804 loadWordDisp(cUnit, rSELF,
805 OFFSETOF_MEMBER(Thread, pInitializeTypeAndVerifyAccessFromCode),
806 rLR);
807 loadConstant(cUnit, r0, type_idx);
808 callRuntimeHelper(cUnit, rLR); // InitializeTypeAndVerifyAccess(idx, method)
809 genRegCopy(cUnit, classReg, r0); // Align usage with fast path
Ian Rogers28ad40d2011-10-27 15:19:26 -0700810 } else {
811 // Load dex cache entry into classReg (r2)
812 loadWordDisp(cUnit, r1, Method::DexCacheResolvedTypesOffset().Int32Value(), classReg);
813 int32_t offset_of_type = Array::DataOffset().Int32Value() + (sizeof(Class*) * type_idx);
814 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
Ian Rogersa3760aa2011-11-14 14:32:37 -0800815 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->dex_cache, type_idx)) {
Ian Rogers28ad40d2011-10-27 15:19:26 -0700816 // Need to test presence of type in dex cache at runtime
817 ArmLIR* hopBranch = genCmpImmBranch(cUnit, kArmCondNe, classReg, 0);
818 // Not resolved
819 // Call out to helper, which will return resolved type in r0
820 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
821 loadConstant(cUnit, r0, type_idx);
Ian Rogersb093c6b2011-10-31 16:19:55 -0700822 callRuntimeHelper(cUnit, rLR); // InitializeTypeFromCode(idx, method)
823 genRegCopy(cUnit, classReg, r0); // Align usage with fast path
Ian Rogers28ad40d2011-10-27 15:19:26 -0700824 // Rejoin code paths
825 ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
826 hopTarget->defMask = ENCODE_ALL;
827 hopBranch->generic.target = (LIR*)hopTarget;
828 }
buzbee67bf8852011-08-17 17:51:35 -0700829 }
Ian Rogers28ad40d2011-10-27 15:19:26 -0700830 // At this point, classReg (r2) has class
831 loadValueDirectFixed(cUnit, rlSrc, r0); // r0 <= ref
buzbee2a475e72011-09-07 17:19:17 -0700832 /* Null is OK - continue */
833 ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, r0, 0);
834 /* load object->clazz */
buzbeeed3e9302011-09-23 17:34:19 -0700835 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
buzbee2a475e72011-09-07 17:19:17 -0700836 loadWordDisp(cUnit, r0, Object::ClassOffset().Int32Value(), r1);
837 /* r1 now contains object->clazz */
Ian Rogers28ad40d2011-10-27 15:19:26 -0700838 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pCheckCastFromCode), rLR);
Ian Rogersb093c6b2011-10-31 16:19:55 -0700839 opRegReg(cUnit, kOpCmp, r1, classReg);
buzbee2a475e72011-09-07 17:19:17 -0700840 ArmLIR* branch2 = opCondBranch(cUnit, kArmCondEq); /* If equal, trivial yes */
841 genRegCopy(cUnit, r0, r1);
842 genRegCopy(cUnit, r1, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -0700843 callRuntimeHelper(cUnit, rLR);
buzbee2a475e72011-09-07 17:19:17 -0700844 /* branch target here */
buzbee67bf8852011-08-17 17:51:35 -0700845 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
846 target->defMask = ENCODE_ALL;
847 branch1->generic.target = (LIR*)target;
848 branch2->generic.target = (LIR*)target;
849}
850
buzbeeed3e9302011-09-23 17:34:19 -0700851STATIC void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700852 RegLocation rlSrc)
853{
854 RegLocation rlResult;
855 rlSrc = loadValue(cUnit, rlSrc, kFPReg);
856 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
857 newLIR2(cUnit, kThumb2Vnegs, rlResult.lowReg, rlSrc.lowReg);
858 storeValue(cUnit, rlDest, rlResult);
859}
860
buzbeeed3e9302011-09-23 17:34:19 -0700861STATIC void genNegDouble(CompilationUnit* cUnit, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -0700862 RegLocation rlSrc)
863{
864 RegLocation rlResult;
865 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
866 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
867 newLIR2(cUnit, kThumb2Vnegd, S2D(rlResult.lowReg, rlResult.highReg),
868 S2D(rlSrc.lowReg, rlSrc.highReg));
869 storeValueWide(cUnit, rlDest, rlResult);
870}
871
buzbeeed3e9302011-09-23 17:34:19 -0700872STATIC void freeRegLocTemps(CompilationUnit* cUnit, RegLocation rlKeep,
buzbee439c4fa2011-08-27 15:59:07 -0700873 RegLocation rlFree)
buzbee67bf8852011-08-17 17:51:35 -0700874{
buzbee6181f792011-09-29 11:14:04 -0700875 if ((rlFree.lowReg != rlKeep.lowReg) && (rlFree.lowReg != rlKeep.highReg) &&
876 (rlFree.highReg != rlKeep.lowReg) && (rlFree.highReg != rlKeep.highReg)) {
877 // No overlap, free both
buzbee439c4fa2011-08-27 15:59:07 -0700878 oatFreeTemp(cUnit, rlFree.lowReg);
buzbee6181f792011-09-29 11:14:04 -0700879 oatFreeTemp(cUnit, rlFree.highReg);
880 }
buzbee67bf8852011-08-17 17:51:35 -0700881}
882
buzbeeed3e9302011-09-23 17:34:19 -0700883STATIC void genLong3Addr(CompilationUnit* cUnit, MIR* mir, OpKind firstOp,
buzbee67bf8852011-08-17 17:51:35 -0700884 OpKind secondOp, RegLocation rlDest,
885 RegLocation rlSrc1, RegLocation rlSrc2)
886{
buzbee9e0f9b02011-08-24 15:32:46 -0700887 /*
888 * NOTE: This is the one place in the code in which we might have
889 * as many as six live temporary registers. There are 5 in the normal
890 * set for Arm. Until we have spill capabilities, temporarily add
891 * lr to the temp set. It is safe to do this locally, but note that
892 * lr is used explicitly elsewhere in the code generator and cannot
893 * normally be used as a general temp register.
894 */
buzbee67bf8852011-08-17 17:51:35 -0700895 RegLocation rlResult;
buzbee9e0f9b02011-08-24 15:32:46 -0700896 oatMarkTemp(cUnit, rLR); // Add lr to the temp pool
897 oatFreeTemp(cUnit, rLR); // and make it available
buzbee67bf8852011-08-17 17:51:35 -0700898 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
899 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
900 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbeec0ecd652011-09-25 18:11:54 -0700901 // The longs may overlap - use intermediate temp if so
902 if (rlResult.lowReg == rlSrc1.highReg) {
buzbeec0ecd652011-09-25 18:11:54 -0700903 int tReg = oatAllocTemp(cUnit);
904 genRegCopy(cUnit, tReg, rlSrc1.highReg);
905 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
906 rlSrc2.lowReg);
907 opRegRegReg(cUnit, secondOp, rlResult.highReg, tReg,
908 rlSrc2.highReg);
909 oatFreeTemp(cUnit, tReg);
910 } else {
911 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
912 rlSrc2.lowReg);
913 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
914 rlSrc2.highReg);
915 }
buzbee439c4fa2011-08-27 15:59:07 -0700916 /*
917 * NOTE: If rlDest refers to a frame variable in a large frame, the
918 * following storeValueWide might need to allocate a temp register.
919 * To further work around the lack of a spill capability, explicitly
920 * free any temps from rlSrc1 & rlSrc2 that aren't still live in rlResult.
921 * Remove when spill is functional.
922 */
923 freeRegLocTemps(cUnit, rlResult, rlSrc1);
924 freeRegLocTemps(cUnit, rlResult, rlSrc2);
buzbee67bf8852011-08-17 17:51:35 -0700925 storeValueWide(cUnit, rlDest, rlResult);
buzbee9e0f9b02011-08-24 15:32:46 -0700926 oatClobber(cUnit, rLR);
927 oatUnmarkTemp(cUnit, rLR); // Remove lr from the temp pool
buzbee67bf8852011-08-17 17:51:35 -0700928}
929
930void oatInitializeRegAlloc(CompilationUnit* cUnit)
931{
932 int numRegs = sizeof(coreRegs)/sizeof(*coreRegs);
933 int numReserved = sizeof(reservedRegs)/sizeof(*reservedRegs);
934 int numTemps = sizeof(coreTemps)/sizeof(*coreTemps);
935 int numFPRegs = sizeof(fpRegs)/sizeof(*fpRegs);
936 int numFPTemps = sizeof(fpTemps)/sizeof(*fpTemps);
buzbeeba938cb2012-02-03 14:47:55 -0800937 RegisterPool *pool = (RegisterPool *)oatNew(cUnit, sizeof(*pool), true,
buzbee5abfa3e2012-01-31 17:01:43 -0800938 kAllocRegAlloc);
buzbee67bf8852011-08-17 17:51:35 -0700939 cUnit->regPool = pool;
940 pool->numCoreRegs = numRegs;
941 pool->coreRegs = (RegisterInfo *)
buzbeeba938cb2012-02-03 14:47:55 -0800942 oatNew(cUnit, numRegs * sizeof(*cUnit->regPool->coreRegs),
943 true, kAllocRegAlloc);
buzbee67bf8852011-08-17 17:51:35 -0700944 pool->numFPRegs = numFPRegs;
945 pool->FPRegs = (RegisterInfo *)
buzbeeba938cb2012-02-03 14:47:55 -0800946 oatNew(cUnit, numFPRegs * sizeof(*cUnit->regPool->FPRegs), true,
947 kAllocRegAlloc);
buzbee67bf8852011-08-17 17:51:35 -0700948 oatInitPool(pool->coreRegs, coreRegs, pool->numCoreRegs);
949 oatInitPool(pool->FPRegs, fpRegs, pool->numFPRegs);
950 // Keep special registers from being allocated
951 for (int i = 0; i < numReserved; i++) {
buzbeec0ecd652011-09-25 18:11:54 -0700952 if (NO_SUSPEND && (reservedRegs[i] == rSUSPEND)) {
953 //To measure cost of suspend check
954 continue;
955 }
buzbee67bf8852011-08-17 17:51:35 -0700956 oatMarkInUse(cUnit, reservedRegs[i]);
957 }
958 // Mark temp regs - all others not in use can be used for promotion
959 for (int i = 0; i < numTemps; i++) {
960 oatMarkTemp(cUnit, coreTemps[i]);
961 }
962 for (int i = 0; i < numFPTemps; i++) {
963 oatMarkTemp(cUnit, fpTemps[i]);
964 }
buzbeec0ecd652011-09-25 18:11:54 -0700965 // Construct the alias map.
buzbeeba938cb2012-02-03 14:47:55 -0800966 cUnit->phiAliasMap = (int*)oatNew(cUnit, cUnit->numSSARegs *
buzbee5abfa3e2012-01-31 17:01:43 -0800967 sizeof(cUnit->phiAliasMap[0]), false,
968 kAllocDFInfo);
buzbeec0ecd652011-09-25 18:11:54 -0700969 for (int i = 0; i < cUnit->numSSARegs; i++) {
970 cUnit->phiAliasMap[i] = i;
971 }
972 for (MIR* phi = cUnit->phiList; phi; phi = phi->meta.phiNext) {
973 int defReg = phi->ssaRep->defs[0];
974 for (int i = 0; i < phi->ssaRep->numUses; i++) {
975 for (int j = 0; j < cUnit->numSSARegs; j++) {
976 if (cUnit->phiAliasMap[j] == phi->ssaRep->uses[i]) {
977 cUnit->phiAliasMap[j] = defReg;
978 }
979 }
980 }
981 }
buzbee67bf8852011-08-17 17:51:35 -0700982}
983
984/*
985 * Handle simple case (thin lock) inline. If it's complicated, bail
986 * out to the heavyweight lock/unlock routines. We'll use dedicated
987 * registers here in order to be in the right position in case we
988 * to bail to dvm[Lock/Unlock]Object(self, object)
989 *
990 * r0 -> self pointer [arg0 for dvm[Lock/Unlock]Object
991 * r1 -> object [arg1 for dvm[Lock/Unlock]Object
992 * r2 -> intial contents of object->lock, later result of strex
993 * r3 -> self->threadId
994 * r12 -> allow to be used by utilities as general temp
995 *
996 * The result of the strex is 0 if we acquire the lock.
997 *
998 * See comments in Sync.c for the layout of the lock word.
999 * Of particular interest to this code is the test for the
1000 * simple case - which we handle inline. For monitor enter, the
1001 * simple case is thin lock, held by no-one. For monitor exit,
1002 * the simple case is thin lock, held by the unlocking thread with
1003 * a recurse count of 0.
1004 *
1005 * A minor complication is that there is a field in the lock word
1006 * unrelated to locking: the hash state. This field must be ignored, but
1007 * preserved.
1008 *
1009 */
buzbeeed3e9302011-09-23 17:34:19 -07001010STATIC void genMonitorEnter(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001011 RegLocation rlSrc)
1012{
1013 ArmLIR* target;
1014 ArmLIR* hopTarget;
1015 ArmLIR* branch;
1016 ArmLIR* hopBranch;
1017
1018 oatFlushAllRegs(cUnit);
Elliott Hughes5f791332011-09-15 17:45:30 -07001019 DCHECK_EQ(LW_SHAPE_THIN, 0);
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001020 loadValueDirectFixed(cUnit, rlSrc, r0); // Get obj
buzbee2e748f32011-08-29 21:02:19 -07001021 oatLockCallTemps(cUnit); // Prepare for explicit register usage
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001022 genNullCheck(cUnit, rlSrc.sRegLow, r0, mir);
1023 loadWordDisp(cUnit, rSELF, Thread::ThinLockIdOffset().Int32Value(), r2);
1024 newLIR3(cUnit, kThumb2Ldrex, r1, r0,
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001025 Object::MonitorOffset().Int32Value() >> 2); // Get object->lock
buzbeec143c552011-08-20 17:38:58 -07001026 // Align owner
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001027 opRegImm(cUnit, kOpLsl, r2, LW_LOCK_OWNER_SHIFT);
buzbee67bf8852011-08-17 17:51:35 -07001028 // Is lock unheld on lock or held by us (==threadId) on unlock?
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001029 newLIR4(cUnit, kThumb2Bfi, r2, r1, 0, LW_LOCK_OWNER_SHIFT - 1);
1030 newLIR3(cUnit, kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
1031 hopBranch = newLIR2(cUnit, kThumb2Cbnz, r1, 0);
1032 newLIR4(cUnit, kThumb2Strex, r1, r2, r0,
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001033 Object::MonitorOffset().Int32Value() >> 2);
buzbee67bf8852011-08-17 17:51:35 -07001034 oatGenMemBarrier(cUnit, kSY);
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001035 branch = newLIR2(cUnit, kThumb2Cbz, r1, 0);
buzbee67bf8852011-08-17 17:51:35 -07001036
1037 hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
1038 hopTarget->defMask = ENCODE_ALL;
1039 hopBranch->generic.target = (LIR*)hopTarget;
1040
buzbee1b4c8592011-08-31 10:43:51 -07001041 // Go expensive route - artLockObjectFromCode(self, obj);
1042 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pLockObjectFromCode),
buzbee67bf8852011-08-17 17:51:35 -07001043 rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07001044 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001045
1046 // Resume here
1047 target = newLIR0(cUnit, kArmPseudoTargetLabel);
1048 target->defMask = ENCODE_ALL;
1049 branch->generic.target = (LIR*)target;
1050}
1051
1052/*
1053 * For monitor unlock, we don't have to use ldrex/strex. Once
1054 * we've determined that the lock is thin and that we own it with
1055 * a zero recursion count, it's safe to punch it back to the
1056 * initial, unlock thin state with a store word.
1057 */
buzbeeed3e9302011-09-23 17:34:19 -07001058STATIC void genMonitorExit(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001059 RegLocation rlSrc)
1060{
1061 ArmLIR* target;
1062 ArmLIR* branch;
1063 ArmLIR* hopTarget;
1064 ArmLIR* hopBranch;
1065
Elliott Hughes5f791332011-09-15 17:45:30 -07001066 DCHECK_EQ(LW_SHAPE_THIN, 0);
buzbee67bf8852011-08-17 17:51:35 -07001067 oatFlushAllRegs(cUnit);
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001068 loadValueDirectFixed(cUnit, rlSrc, r0); // Get obj
buzbee2e748f32011-08-29 21:02:19 -07001069 oatLockCallTemps(cUnit); // Prepare for explicit register usage
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001070 genNullCheck(cUnit, rlSrc.sRegLow, r0, mir);
1071 loadWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r1); // Get lock
1072 loadWordDisp(cUnit, rSELF, Thread::ThinLockIdOffset().Int32Value(), r2);
buzbee67bf8852011-08-17 17:51:35 -07001073 // Is lock unheld on lock or held by us (==threadId) on unlock?
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001074 opRegRegImm(cUnit, kOpAnd, r3, r1, (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
buzbeec143c552011-08-20 17:38:58 -07001075 // Align owner
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001076 opRegImm(cUnit, kOpLsl, r2, LW_LOCK_OWNER_SHIFT);
1077 newLIR3(cUnit, kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
1078 opRegReg(cUnit, kOpSub, r1, r2);
buzbee67bf8852011-08-17 17:51:35 -07001079 hopBranch = opCondBranch(cUnit, kArmCondNe);
1080 oatGenMemBarrier(cUnit, kSY);
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001081 storeWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r3);
buzbee67bf8852011-08-17 17:51:35 -07001082 branch = opNone(cUnit, kOpUncondBr);
1083
1084 hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
1085 hopTarget->defMask = ENCODE_ALL;
1086 hopBranch->generic.target = (LIR*)hopTarget;
1087
Ian Rogers4f0d07c2011-10-06 23:38:47 -07001088 // Go expensive route - UnlockObjectFromCode(obj);
buzbee1b4c8592011-08-31 10:43:51 -07001089 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pUnlockObjectFromCode),
buzbee67bf8852011-08-17 17:51:35 -07001090 rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07001091 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001092
1093 // Resume here
1094 target = newLIR0(cUnit, kArmPseudoTargetLabel);
1095 target->defMask = ENCODE_ALL;
1096 branch->generic.target = (LIR*)target;
1097}
1098
1099/*
1100 * 64-bit 3way compare function.
1101 * mov rX, #-1
1102 * cmp op1hi, op2hi
1103 * blt done
1104 * bgt flip
1105 * sub rX, op1lo, op2lo (treat as unsigned)
1106 * beq done
1107 * ite hi
1108 * mov(hi) rX, #-1
1109 * mov(!hi) rX, #1
1110 * flip:
1111 * neg rX
1112 * done:
1113 */
buzbeeed3e9302011-09-23 17:34:19 -07001114STATIC void genCmpLong(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001115 RegLocation rlDest, RegLocation rlSrc1,
1116 RegLocation rlSrc2)
1117{
buzbee67bf8852011-08-17 17:51:35 -07001118 ArmLIR* target1;
1119 ArmLIR* target2;
1120 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
1121 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
buzbeeb29e4d12011-09-26 15:05:48 -07001122 int tReg = oatAllocTemp(cUnit);
1123 loadConstant(cUnit, tReg, -1);
buzbee67bf8852011-08-17 17:51:35 -07001124 opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg);
1125 ArmLIR* branch1 = opCondBranch(cUnit, kArmCondLt);
1126 ArmLIR* branch2 = opCondBranch(cUnit, kArmCondGt);
buzbeeb29e4d12011-09-26 15:05:48 -07001127 opRegRegReg(cUnit, kOpSub, tReg, rlSrc1.lowReg, rlSrc2.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001128 ArmLIR* branch3 = opCondBranch(cUnit, kArmCondEq);
1129
1130 genIT(cUnit, kArmCondHi, "E");
buzbeeb29e4d12011-09-26 15:05:48 -07001131 newLIR2(cUnit, kThumb2MovImmShift, tReg, modifiedImmediate(-1));
1132 loadConstant(cUnit, tReg, 1);
buzbee67bf8852011-08-17 17:51:35 -07001133 genBarrier(cUnit);
1134
1135 target2 = newLIR0(cUnit, kArmPseudoTargetLabel);
1136 target2->defMask = -1;
buzbeeb29e4d12011-09-26 15:05:48 -07001137 opRegReg(cUnit, kOpNeg, tReg, tReg);
buzbee67bf8852011-08-17 17:51:35 -07001138
1139 target1 = newLIR0(cUnit, kArmPseudoTargetLabel);
1140 target1->defMask = -1;
1141
buzbeeb29e4d12011-09-26 15:05:48 -07001142 RegLocation rlTemp = LOC_C_RETURN; // Just using as template, will change
1143 rlTemp.lowReg = tReg;
buzbee67bf8852011-08-17 17:51:35 -07001144 storeValue(cUnit, rlDest, rlTemp);
buzbeeb29e4d12011-09-26 15:05:48 -07001145 oatFreeTemp(cUnit, tReg);
buzbee67bf8852011-08-17 17:51:35 -07001146
1147 branch1->generic.target = (LIR*)target1;
1148 branch2->generic.target = (LIR*)target2;
1149 branch3->generic.target = branch1->generic.target;
1150}
1151
buzbeeed3e9302011-09-23 17:34:19 -07001152STATIC void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -07001153 RegLocation rlSrc, RegLocation rlResult, int lit,
1154 int firstBit, int secondBit)
1155{
1156 opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg,
1157 encodeShift(kArmLsl, secondBit - firstBit));
1158 if (firstBit != 0) {
1159 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
1160 }
1161}
1162
buzbeeed3e9302011-09-23 17:34:19 -07001163STATIC bool genConversionCall(CompilationUnit* cUnit, MIR* mir, int funcOffset,
buzbee67bf8852011-08-17 17:51:35 -07001164 int srcSize, int tgtSize)
1165{
1166 /*
1167 * Don't optimize the register usage since it calls out to support
1168 * functions
1169 */
1170 RegLocation rlSrc;
1171 RegLocation rlDest;
1172 oatFlushAllRegs(cUnit); /* Send everything to home location */
1173 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1174 if (srcSize == 1) {
1175 rlSrc = oatGetSrc(cUnit, mir, 0);
1176 loadValueDirectFixed(cUnit, rlSrc, r0);
1177 } else {
1178 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
1179 loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
1180 }
Ian Rogersff1ed472011-09-20 13:46:24 -07001181 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001182 if (tgtSize == 1) {
1183 RegLocation rlResult;
1184 rlDest = oatGetDest(cUnit, mir, 0);
1185 rlResult = oatGetReturn(cUnit);
1186 storeValue(cUnit, rlDest, rlResult);
1187 } else {
1188 RegLocation rlResult;
1189 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1190 rlResult = oatGetReturnWide(cUnit);
1191 storeValueWide(cUnit, rlDest, rlResult);
1192 }
1193 return false;
1194}
1195
buzbeeed3e9302011-09-23 17:34:19 -07001196STATIC bool genArithOpFloatPortable(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001197 RegLocation rlDest, RegLocation rlSrc1,
1198 RegLocation rlSrc2)
1199{
1200 RegLocation rlResult;
1201 int funcOffset;
1202
1203 switch (mir->dalvikInsn.opcode) {
1204 case OP_ADD_FLOAT_2ADDR:
1205 case OP_ADD_FLOAT:
1206 funcOffset = OFFSETOF_MEMBER(Thread, pFadd);
1207 break;
1208 case OP_SUB_FLOAT_2ADDR:
1209 case OP_SUB_FLOAT:
1210 funcOffset = OFFSETOF_MEMBER(Thread, pFsub);
1211 break;
1212 case OP_DIV_FLOAT_2ADDR:
1213 case OP_DIV_FLOAT:
1214 funcOffset = OFFSETOF_MEMBER(Thread, pFdiv);
1215 break;
1216 case OP_MUL_FLOAT_2ADDR:
1217 case OP_MUL_FLOAT:
1218 funcOffset = OFFSETOF_MEMBER(Thread, pFmul);
1219 break;
1220 case OP_REM_FLOAT_2ADDR:
1221 case OP_REM_FLOAT:
1222 funcOffset = OFFSETOF_MEMBER(Thread, pFmodf);
1223 break;
1224 case OP_NEG_FLOAT: {
1225 genNegFloat(cUnit, rlDest, rlSrc1);
1226 return false;
1227 }
1228 default:
1229 return true;
1230 }
1231 oatFlushAllRegs(cUnit); /* Send everything to home location */
1232 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1233 loadValueDirectFixed(cUnit, rlSrc1, r0);
1234 loadValueDirectFixed(cUnit, rlSrc2, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -07001235 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001236 rlResult = oatGetReturn(cUnit);
1237 storeValue(cUnit, rlDest, rlResult);
1238 return false;
1239}
1240
buzbeeed3e9302011-09-23 17:34:19 -07001241STATIC bool genArithOpDoublePortable(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001242 RegLocation rlDest, RegLocation rlSrc1,
1243 RegLocation rlSrc2)
1244{
1245 RegLocation rlResult;
1246 int funcOffset;
1247
1248 switch (mir->dalvikInsn.opcode) {
1249 case OP_ADD_DOUBLE_2ADDR:
1250 case OP_ADD_DOUBLE:
1251 funcOffset = OFFSETOF_MEMBER(Thread, pDadd);
1252 break;
1253 case OP_SUB_DOUBLE_2ADDR:
1254 case OP_SUB_DOUBLE:
1255 funcOffset = OFFSETOF_MEMBER(Thread, pDsub);
1256 break;
1257 case OP_DIV_DOUBLE_2ADDR:
1258 case OP_DIV_DOUBLE:
1259 funcOffset = OFFSETOF_MEMBER(Thread, pDdiv);
1260 break;
1261 case OP_MUL_DOUBLE_2ADDR:
1262 case OP_MUL_DOUBLE:
1263 funcOffset = OFFSETOF_MEMBER(Thread, pDmul);
1264 break;
1265 case OP_REM_DOUBLE_2ADDR:
1266 case OP_REM_DOUBLE:
1267 funcOffset = OFFSETOF_MEMBER(Thread, pFmod);
1268 break;
1269 case OP_NEG_DOUBLE: {
1270 genNegDouble(cUnit, rlDest, rlSrc1);
1271 return false;
1272 }
1273 default:
1274 return true;
1275 }
1276 oatFlushAllRegs(cUnit); /* Send everything to home location */
1277 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1278 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1279 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
Ian Rogersff1ed472011-09-20 13:46:24 -07001280 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001281 rlResult = oatGetReturnWide(cUnit);
1282 storeValueWide(cUnit, rlDest, rlResult);
1283 return false;
1284}
1285
buzbeeed3e9302011-09-23 17:34:19 -07001286STATIC bool genConversionPortable(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001287{
1288 Opcode opcode = mir->dalvikInsn.opcode;
1289
1290 switch (opcode) {
1291 case OP_INT_TO_FLOAT:
1292 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2f),
1293 1, 1);
1294 case OP_FLOAT_TO_INT:
1295 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2iz),
1296 1, 1);
1297 case OP_DOUBLE_TO_FLOAT:
1298 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2f),
1299 2, 1);
1300 case OP_FLOAT_TO_DOUBLE:
1301 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2d),
1302 1, 2);
1303 case OP_INT_TO_DOUBLE:
1304 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2d),
1305 1, 2);
1306 case OP_DOUBLE_TO_INT:
1307 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2iz),
1308 2, 1);
1309 case OP_FLOAT_TO_LONG:
1310 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
buzbee1b4c8592011-08-31 10:43:51 -07001311 pF2l), 1, 2);
buzbee67bf8852011-08-17 17:51:35 -07001312 case OP_LONG_TO_FLOAT:
1313 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2f),
1314 2, 1);
1315 case OP_DOUBLE_TO_LONG:
1316 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
buzbee1b4c8592011-08-31 10:43:51 -07001317 pD2l), 2, 2);
buzbee67bf8852011-08-17 17:51:35 -07001318 case OP_LONG_TO_DOUBLE:
1319 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2d),
1320 2, 2);
1321 default:
1322 return true;
1323 }
1324 return false;
1325}
1326
1327/* Generate conditional branch instructions */
buzbeeed3e9302011-09-23 17:34:19 -07001328STATIC ArmLIR* genConditionalBranch(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -07001329 ArmConditionCode cond,
1330 ArmLIR* target)
1331{
1332 ArmLIR* branch = opCondBranch(cUnit, cond);
1333 branch->generic.target = (LIR*) target;
1334 return branch;
1335}
1336
buzbee67bf8852011-08-17 17:51:35 -07001337/*
1338 * Generate array store
1339 *
1340 */
buzbeeed3e9302011-09-23 17:34:19 -07001341STATIC void genArrayObjPut(CompilationUnit* cUnit, MIR* mir,
buzbee1b4c8592011-08-31 10:43:51 -07001342 RegLocation rlArray, RegLocation rlIndex,
1343 RegLocation rlSrc, int scale)
buzbee67bf8852011-08-17 17:51:35 -07001344{
1345 RegisterClass regClass = oatRegClassBySize(kWord);
buzbeec143c552011-08-20 17:38:58 -07001346 int lenOffset = Array::LengthOffset().Int32Value();
1347 int dataOffset = Array::DataOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001348
buzbee6181f792011-09-29 11:14:04 -07001349 oatFlushAllRegs(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001350 /* Make sure it's a legal object Put. Use direct regs at first */
1351 loadValueDirectFixed(cUnit, rlArray, r1);
1352 loadValueDirectFixed(cUnit, rlSrc, r0);
1353
1354 /* null array object? */
buzbee43a36422011-09-14 14:00:13 -07001355 genNullCheck(cUnit, rlArray.sRegLow, r1, mir);
buzbee67bf8852011-08-17 17:51:35 -07001356 loadWordDisp(cUnit, rSELF,
buzbee1b4c8592011-08-31 10:43:51 -07001357 OFFSETOF_MEMBER(Thread, pCanPutArrayElementFromCode), rLR);
buzbee67bf8852011-08-17 17:51:35 -07001358 /* Get the array's clazz */
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001359 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), r1);
Ian Rogersff1ed472011-09-20 13:46:24 -07001360 callRuntimeHelper(cUnit, rLR);
buzbee6181f792011-09-29 11:14:04 -07001361 oatFreeTemp(cUnit, r0);
1362 oatFreeTemp(cUnit, r1);
buzbee67bf8852011-08-17 17:51:35 -07001363
1364 // Now, redo loadValues in case they didn't survive the call
1365
1366 int regPtr;
1367 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1368 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1369
1370 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1371 oatClobber(cUnit, rlArray.lowReg);
1372 regPtr = rlArray.lowReg;
1373 } else {
1374 regPtr = oatAllocTemp(cUnit);
1375 genRegCopy(cUnit, regPtr, rlArray.lowReg);
1376 }
1377
buzbee43a36422011-09-14 14:00:13 -07001378 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee67bf8852011-08-17 17:51:35 -07001379 int regLen = oatAllocTemp(cUnit);
1380 //NOTE: max live temps(4) here.
1381 /* Get len */
1382 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1383 /* regPtr -> array data */
1384 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
buzbeeec5adf32011-09-11 15:25:43 -07001385 genRegRegCheck(cUnit, kArmCondCs, rlIndex.lowReg, regLen, mir,
buzbee5ade1d22011-09-09 14:44:52 -07001386 kArmThrowArrayBounds);
buzbee67bf8852011-08-17 17:51:35 -07001387 oatFreeTemp(cUnit, regLen);
1388 } else {
1389 /* regPtr -> array data */
1390 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1391 }
1392 /* at this point, regPtr points to array, 2 live temps */
1393 rlSrc = loadValue(cUnit, rlSrc, regClass);
1394 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1395 scale, kWord);
1396}
1397
1398/*
1399 * Generate array load
1400 */
buzbeeed3e9302011-09-23 17:34:19 -07001401STATIC void genArrayGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -07001402 RegLocation rlArray, RegLocation rlIndex,
1403 RegLocation rlDest, int scale)
1404{
1405 RegisterClass regClass = oatRegClassBySize(size);
buzbeec143c552011-08-20 17:38:58 -07001406 int lenOffset = Array::LengthOffset().Int32Value();
1407 int dataOffset = Array::DataOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001408 RegLocation rlResult;
1409 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1410 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1411 int regPtr;
1412
1413 /* null object? */
buzbee43a36422011-09-14 14:00:13 -07001414 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001415
1416 regPtr = oatAllocTemp(cUnit);
1417
buzbee43a36422011-09-14 14:00:13 -07001418 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee67bf8852011-08-17 17:51:35 -07001419 int regLen = oatAllocTemp(cUnit);
1420 /* Get len */
1421 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1422 /* regPtr -> array data */
1423 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
buzbeeec5adf32011-09-11 15:25:43 -07001424 genRegRegCheck(cUnit, kArmCondCs, rlIndex.lowReg, regLen, mir,
buzbee5ade1d22011-09-09 14:44:52 -07001425 kArmThrowArrayBounds);
buzbee67bf8852011-08-17 17:51:35 -07001426 oatFreeTemp(cUnit, regLen);
1427 } else {
1428 /* regPtr -> array data */
1429 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1430 }
buzbeee9a72f62011-09-04 17:59:07 -07001431 oatFreeTemp(cUnit, rlArray.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001432 if ((size == kLong) || (size == kDouble)) {
1433 if (scale) {
1434 int rNewIndex = oatAllocTemp(cUnit);
1435 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1436 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1437 oatFreeTemp(cUnit, rNewIndex);
1438 } else {
1439 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1440 }
buzbeee9a72f62011-09-04 17:59:07 -07001441 oatFreeTemp(cUnit, rlIndex.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001442 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1443
1444 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1445
1446 oatFreeTemp(cUnit, regPtr);
1447 storeValueWide(cUnit, rlDest, rlResult);
1448 } else {
1449 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1450
1451 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
1452 scale, size);
1453
1454 oatFreeTemp(cUnit, regPtr);
1455 storeValue(cUnit, rlDest, rlResult);
1456 }
1457}
1458
1459/*
1460 * Generate array store
1461 *
1462 */
buzbeeed3e9302011-09-23 17:34:19 -07001463STATIC void genArrayPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
buzbee67bf8852011-08-17 17:51:35 -07001464 RegLocation rlArray, RegLocation rlIndex,
1465 RegLocation rlSrc, int scale)
1466{
1467 RegisterClass regClass = oatRegClassBySize(size);
buzbeec143c552011-08-20 17:38:58 -07001468 int lenOffset = Array::LengthOffset().Int32Value();
1469 int dataOffset = Array::DataOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001470
1471 int regPtr;
1472 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1473 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1474
1475 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1476 oatClobber(cUnit, rlArray.lowReg);
1477 regPtr = rlArray.lowReg;
1478 } else {
1479 regPtr = oatAllocTemp(cUnit);
1480 genRegCopy(cUnit, regPtr, rlArray.lowReg);
1481 }
1482
1483 /* null object? */
buzbee43a36422011-09-14 14:00:13 -07001484 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001485
buzbee43a36422011-09-14 14:00:13 -07001486 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee67bf8852011-08-17 17:51:35 -07001487 int regLen = oatAllocTemp(cUnit);
1488 //NOTE: max live temps(4) here.
1489 /* Get len */
1490 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1491 /* regPtr -> array data */
1492 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
buzbeeec5adf32011-09-11 15:25:43 -07001493 genRegRegCheck(cUnit, kArmCondCs, rlIndex.lowReg, regLen, mir,
buzbee5ade1d22011-09-09 14:44:52 -07001494 kArmThrowArrayBounds);
buzbee67bf8852011-08-17 17:51:35 -07001495 oatFreeTemp(cUnit, regLen);
1496 } else {
1497 /* regPtr -> array data */
1498 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1499 }
1500 /* at this point, regPtr points to array, 2 live temps */
1501 if ((size == kLong) || (size == kDouble)) {
buzbee5ade1d22011-09-09 14:44:52 -07001502 //TUNING: specific wide routine that can handle fp regs
buzbee67bf8852011-08-17 17:51:35 -07001503 if (scale) {
1504 int rNewIndex = oatAllocTemp(cUnit);
1505 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1506 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1507 oatFreeTemp(cUnit, rNewIndex);
1508 } else {
1509 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1510 }
1511 rlSrc = loadValueWide(cUnit, rlSrc, regClass);
1512
1513 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
1514
1515 oatFreeTemp(cUnit, regPtr);
1516 } else {
1517 rlSrc = loadValue(cUnit, rlSrc, regClass);
1518
1519 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1520 scale, size);
1521 }
1522}
1523
buzbeeed3e9302011-09-23 17:34:19 -07001524STATIC bool genShiftOpLong(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001525 RegLocation rlDest, RegLocation rlSrc1,
1526 RegLocation rlShift)
1527{
buzbee54330722011-08-23 16:46:55 -07001528 int funcOffset;
buzbee67bf8852011-08-17 17:51:35 -07001529
buzbee67bf8852011-08-17 17:51:35 -07001530 switch( mir->dalvikInsn.opcode) {
1531 case OP_SHL_LONG:
1532 case OP_SHL_LONG_2ADDR:
buzbee54330722011-08-23 16:46:55 -07001533 funcOffset = OFFSETOF_MEMBER(Thread, pShlLong);
buzbee67bf8852011-08-17 17:51:35 -07001534 break;
1535 case OP_SHR_LONG:
1536 case OP_SHR_LONG_2ADDR:
buzbee54330722011-08-23 16:46:55 -07001537 funcOffset = OFFSETOF_MEMBER(Thread, pShrLong);
buzbee67bf8852011-08-17 17:51:35 -07001538 break;
1539 case OP_USHR_LONG:
1540 case OP_USHR_LONG_2ADDR:
buzbee54330722011-08-23 16:46:55 -07001541 funcOffset = OFFSETOF_MEMBER(Thread, pUshrLong);
buzbee67bf8852011-08-17 17:51:35 -07001542 break;
1543 default:
buzbee54330722011-08-23 16:46:55 -07001544 LOG(FATAL) << "Unexpected case";
buzbee67bf8852011-08-17 17:51:35 -07001545 return true;
1546 }
buzbee54330722011-08-23 16:46:55 -07001547 oatFlushAllRegs(cUnit); /* Send everything to home location */
1548 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1549 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1550 loadValueDirect(cUnit, rlShift, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -07001551 callRuntimeHelper(cUnit, rLR);
buzbee54330722011-08-23 16:46:55 -07001552 RegLocation rlResult = oatGetReturnWide(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001553 storeValueWide(cUnit, rlDest, rlResult);
1554 return false;
1555}
1556
buzbeeed3e9302011-09-23 17:34:19 -07001557STATIC bool genArithOpLong(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001558 RegLocation rlDest, RegLocation rlSrc1,
1559 RegLocation rlSrc2)
1560{
1561 RegLocation rlResult;
1562 OpKind firstOp = kOpBkpt;
1563 OpKind secondOp = kOpBkpt;
1564 bool callOut = false;
buzbee58f92742011-10-01 11:22:17 -07001565 bool checkZero = false;
buzbee67bf8852011-08-17 17:51:35 -07001566 int funcOffset;
1567 int retReg = r0;
1568
1569 switch (mir->dalvikInsn.opcode) {
1570 case OP_NOT_LONG:
1571 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1572 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbeeb29e4d12011-09-26 15:05:48 -07001573 // Check for destructive overlap
1574 if (rlResult.lowReg == rlSrc2.highReg) {
1575 int tReg = oatAllocTemp(cUnit);
1576 genRegCopy(cUnit, tReg, rlSrc2.highReg);
1577 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1578 opRegReg(cUnit, kOpMvn, rlResult.highReg, tReg);
1579 oatFreeTemp(cUnit, tReg);
1580 } else {
1581 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1582 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
1583 }
buzbee67bf8852011-08-17 17:51:35 -07001584 storeValueWide(cUnit, rlDest, rlResult);
1585 return false;
1586 break;
1587 case OP_ADD_LONG:
1588 case OP_ADD_LONG_2ADDR:
1589 firstOp = kOpAdd;
1590 secondOp = kOpAdc;
1591 break;
1592 case OP_SUB_LONG:
1593 case OP_SUB_LONG_2ADDR:
1594 firstOp = kOpSub;
1595 secondOp = kOpSbc;
1596 break;
1597 case OP_MUL_LONG:
1598 case OP_MUL_LONG_2ADDR:
buzbee439c4fa2011-08-27 15:59:07 -07001599 callOut = true;
1600 retReg = r0;
1601 funcOffset = OFFSETOF_MEMBER(Thread, pLmul);
1602 break;
buzbee67bf8852011-08-17 17:51:35 -07001603 case OP_DIV_LONG:
1604 case OP_DIV_LONG_2ADDR:
1605 callOut = true;
buzbee58f92742011-10-01 11:22:17 -07001606 checkZero = true;
buzbee67bf8852011-08-17 17:51:35 -07001607 retReg = r0;
1608 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
1609 break;
1610 /* NOTE - result is in r2/r3 instead of r0/r1 */
1611 case OP_REM_LONG:
1612 case OP_REM_LONG_2ADDR:
1613 callOut = true;
buzbee58f92742011-10-01 11:22:17 -07001614 checkZero = true;
buzbee67bf8852011-08-17 17:51:35 -07001615 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
1616 retReg = r2;
1617 break;
1618 case OP_AND_LONG_2ADDR:
1619 case OP_AND_LONG:
1620 firstOp = kOpAnd;
1621 secondOp = kOpAnd;
1622 break;
1623 case OP_OR_LONG:
1624 case OP_OR_LONG_2ADDR:
1625 firstOp = kOpOr;
1626 secondOp = kOpOr;
1627 break;
1628 case OP_XOR_LONG:
1629 case OP_XOR_LONG_2ADDR:
1630 firstOp = kOpXor;
1631 secondOp = kOpXor;
1632 break;
1633 case OP_NEG_LONG: {
buzbee67bf8852011-08-17 17:51:35 -07001634 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1635 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbeeb29e4d12011-09-26 15:05:48 -07001636 int zReg = oatAllocTemp(cUnit);
1637 loadConstantNoClobber(cUnit, zReg, 0);
1638 // Check for destructive overlap
1639 if (rlResult.lowReg == rlSrc2.highReg) {
1640 int tReg = oatAllocTemp(cUnit);
1641 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1642 zReg, rlSrc2.lowReg);
1643 opRegRegReg(cUnit, kOpSbc, rlResult.highReg,
1644 zReg, tReg);
1645 oatFreeTemp(cUnit, tReg);
1646 } else {
1647 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1648 zReg, rlSrc2.lowReg);
1649 opRegRegReg(cUnit, kOpSbc, rlResult.highReg,
1650 zReg, rlSrc2.highReg);
1651 }
1652 oatFreeTemp(cUnit, zReg);
buzbee67bf8852011-08-17 17:51:35 -07001653 storeValueWide(cUnit, rlDest, rlResult);
1654 return false;
1655 }
1656 default:
1657 LOG(FATAL) << "Invalid long arith op";
1658 }
1659 if (!callOut) {
1660 genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
1661 } else {
buzbee67bf8852011-08-17 17:51:35 -07001662 oatFlushAllRegs(cUnit); /* Send everything to home location */
buzbee58f92742011-10-01 11:22:17 -07001663 if (checkZero) {
1664 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
1665 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1666 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1667 int tReg = oatAllocTemp(cUnit);
1668 newLIR4(cUnit, kThumb2OrrRRRs, tReg, r2, r3, 0);
1669 oatFreeTemp(cUnit, tReg);
1670 genCheck(cUnit, kArmCondEq, mir, kArmThrowDivZero);
1671 } else {
1672 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1673 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1674 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
1675 }
Ian Rogersff1ed472011-09-20 13:46:24 -07001676 callRuntimeHelper(cUnit, rLR);
buzbee58f92742011-10-01 11:22:17 -07001677 // Adjust return regs in to handle case of rem returning r2/r3
buzbee67bf8852011-08-17 17:51:35 -07001678 if (retReg == r0)
1679 rlResult = oatGetReturnWide(cUnit);
1680 else
1681 rlResult = oatGetReturnWideAlt(cUnit);
1682 storeValueWide(cUnit, rlDest, rlResult);
1683 }
1684 return false;
1685}
1686
buzbeeed3e9302011-09-23 17:34:19 -07001687STATIC bool genArithOpInt(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001688 RegLocation rlDest, RegLocation rlSrc1,
1689 RegLocation rlSrc2)
1690{
1691 OpKind op = kOpBkpt;
1692 bool callOut = false;
1693 bool checkZero = false;
1694 bool unary = false;
1695 int retReg = r0;
1696 int funcOffset;
1697 RegLocation rlResult;
1698 bool shiftOp = false;
1699
1700 switch (mir->dalvikInsn.opcode) {
1701 case OP_NEG_INT:
1702 op = kOpNeg;
1703 unary = true;
1704 break;
1705 case OP_NOT_INT:
1706 op = kOpMvn;
1707 unary = true;
1708 break;
1709 case OP_ADD_INT:
1710 case OP_ADD_INT_2ADDR:
1711 op = kOpAdd;
1712 break;
1713 case OP_SUB_INT:
1714 case OP_SUB_INT_2ADDR:
1715 op = kOpSub;
1716 break;
1717 case OP_MUL_INT:
1718 case OP_MUL_INT_2ADDR:
1719 op = kOpMul;
1720 break;
1721 case OP_DIV_INT:
1722 case OP_DIV_INT_2ADDR:
1723 callOut = true;
1724 checkZero = true;
1725 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
1726 retReg = r0;
1727 break;
1728 /* NOTE: returns in r1 */
1729 case OP_REM_INT:
1730 case OP_REM_INT_2ADDR:
1731 callOut = true;
1732 checkZero = true;
1733 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
1734 retReg = r1;
1735 break;
1736 case OP_AND_INT:
1737 case OP_AND_INT_2ADDR:
1738 op = kOpAnd;
1739 break;
1740 case OP_OR_INT:
1741 case OP_OR_INT_2ADDR:
1742 op = kOpOr;
1743 break;
1744 case OP_XOR_INT:
1745 case OP_XOR_INT_2ADDR:
1746 op = kOpXor;
1747 break;
1748 case OP_SHL_INT:
1749 case OP_SHL_INT_2ADDR:
1750 shiftOp = true;
1751 op = kOpLsl;
1752 break;
1753 case OP_SHR_INT:
1754 case OP_SHR_INT_2ADDR:
1755 shiftOp = true;
1756 op = kOpAsr;
1757 break;
1758 case OP_USHR_INT:
1759 case OP_USHR_INT_2ADDR:
1760 shiftOp = true;
1761 op = kOpLsr;
1762 break;
1763 default:
1764 LOG(FATAL) << "Invalid word arith op: " <<
1765 (int)mir->dalvikInsn.opcode;
1766 }
1767 if (!callOut) {
1768 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1769 if (unary) {
1770 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1771 opRegReg(cUnit, op, rlResult.lowReg,
1772 rlSrc1.lowReg);
1773 } else {
1774 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1775 if (shiftOp) {
1776 int tReg = oatAllocTemp(cUnit);
1777 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
1778 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1779 opRegRegReg(cUnit, op, rlResult.lowReg,
1780 rlSrc1.lowReg, tReg);
1781 oatFreeTemp(cUnit, tReg);
1782 } else {
1783 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1784 opRegRegReg(cUnit, op, rlResult.lowReg,
1785 rlSrc1.lowReg, rlSrc2.lowReg);
1786 }
1787 }
1788 storeValue(cUnit, rlDest, rlResult);
1789 } else {
1790 RegLocation rlResult;
1791 oatFlushAllRegs(cUnit); /* Send everything to home location */
1792 loadValueDirectFixed(cUnit, rlSrc2, r1);
1793 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
1794 loadValueDirectFixed(cUnit, rlSrc1, r0);
1795 if (checkZero) {
buzbee5ade1d22011-09-09 14:44:52 -07001796 genImmedCheck(cUnit, kArmCondEq, r1, 0, mir, kArmThrowDivZero);
buzbee67bf8852011-08-17 17:51:35 -07001797 }
Ian Rogersff1ed472011-09-20 13:46:24 -07001798 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001799 if (retReg == r0)
1800 rlResult = oatGetReturn(cUnit);
1801 else
1802 rlResult = oatGetReturnAlt(cUnit);
1803 storeValue(cUnit, rlDest, rlResult);
1804 }
1805 return false;
1806}
1807
buzbeec1f45042011-09-21 16:03:19 -07001808/* Check if we need to check for pending suspend request */
buzbeeed3e9302011-09-23 17:34:19 -07001809STATIC void genSuspendTest(CompilationUnit* cUnit, MIR* mir)
buzbeec1f45042011-09-21 16:03:19 -07001810{
Ian Rogersa3760aa2011-11-14 14:32:37 -08001811 if (NO_SUSPEND || (mir->optimizationFlags & MIR_IGNORE_SUSPEND_CHECK)) {
buzbeec1f45042011-09-21 16:03:19 -07001812 return;
1813 }
buzbee6181f792011-09-29 11:14:04 -07001814 oatFlushAllRegs(cUnit);
buzbeec1f45042011-09-21 16:03:19 -07001815 newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
1816 ArmLIR* branch = opCondBranch(cUnit, kArmCondEq);
1817 ArmLIR* retLab = newLIR0(cUnit, kArmPseudoTargetLabel);
1818 retLab->defMask = ENCODE_ALL;
buzbeeba938cb2012-02-03 14:47:55 -08001819 ArmLIR* target = (ArmLIR*)oatNew(cUnit, sizeof(ArmLIR), true, kAllocLIR);
buzbeec1f45042011-09-21 16:03:19 -07001820 target->generic.dalvikOffset = cUnit->currentDalvikOffset;
1821 target->opcode = kArmPseudoSuspendTarget;
1822 target->operands[0] = (intptr_t)retLab;
1823 target->operands[1] = mir->offset;
1824 branch->generic.target = (LIR*)target;
buzbeeba938cb2012-02-03 14:47:55 -08001825 oatInsertGrowableList(cUnit, &cUnit->suspendLaunchpads, (intptr_t)target);
buzbeec1f45042011-09-21 16:03:19 -07001826}
1827
buzbee67bf8852011-08-17 17:51:35 -07001828/*
1829 * The following are the first-level codegen routines that analyze the format
1830 * of each bytecode then either dispatch special purpose codegen routines
1831 * or produce corresponding Thumb instructions directly.
1832 */
1833
buzbeeed3e9302011-09-23 17:34:19 -07001834STATIC bool isPowerOfTwo(int x)
buzbee67bf8852011-08-17 17:51:35 -07001835{
1836 return (x & (x - 1)) == 0;
1837}
1838
1839// Returns true if no more than two bits are set in 'x'.
buzbeeed3e9302011-09-23 17:34:19 -07001840STATIC bool isPopCountLE2(unsigned int x)
buzbee67bf8852011-08-17 17:51:35 -07001841{
1842 x &= x - 1;
1843 return (x & (x - 1)) == 0;
1844}
1845
1846// Returns the index of the lowest set bit in 'x'.
buzbeeed3e9302011-09-23 17:34:19 -07001847STATIC int lowestSetBit(unsigned int x) {
buzbee67bf8852011-08-17 17:51:35 -07001848 int bit_posn = 0;
1849 while ((x & 0xf) == 0) {
1850 bit_posn += 4;
1851 x >>= 4;
1852 }
1853 while ((x & 1) == 0) {
1854 bit_posn++;
1855 x >>= 1;
1856 }
1857 return bit_posn;
1858}
1859
1860// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
1861// and store the result in 'rlDest'.
buzbeeed3e9302011-09-23 17:34:19 -07001862STATIC bool handleEasyDivide(CompilationUnit* cUnit, Opcode dalvikOpcode,
buzbee67bf8852011-08-17 17:51:35 -07001863 RegLocation rlSrc, RegLocation rlDest, int lit)
1864{
1865 if (lit < 2 || !isPowerOfTwo(lit)) {
1866 return false;
1867 }
1868 int k = lowestSetBit(lit);
1869 if (k >= 30) {
1870 // Avoid special cases.
1871 return false;
1872 }
1873 bool div = (dalvikOpcode == OP_DIV_INT_LIT8 ||
1874 dalvikOpcode == OP_DIV_INT_LIT16);
1875 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1876 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1877 if (div) {
1878 int tReg = oatAllocTemp(cUnit);
1879 if (lit == 2) {
1880 // Division by 2 is by far the most common division by constant.
1881 opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
1882 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1883 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1884 } else {
1885 opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
1886 opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
1887 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1888 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1889 }
1890 } else {
1891 int cReg = oatAllocTemp(cUnit);
1892 loadConstant(cUnit, cReg, lit - 1);
1893 int tReg1 = oatAllocTemp(cUnit);
1894 int tReg2 = oatAllocTemp(cUnit);
1895 if (lit == 2) {
1896 opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 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 } else {
1901 opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
1902 opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
1903 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1904 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1905 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1906 }
1907 }
1908 storeValue(cUnit, rlDest, rlResult);
1909 return true;
1910}
1911
1912// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
1913// and store the result in 'rlDest'.
buzbeeed3e9302011-09-23 17:34:19 -07001914STATIC bool handleEasyMultiply(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -07001915 RegLocation rlSrc, RegLocation rlDest, int lit)
1916{
1917 // Can we simplify this multiplication?
1918 bool powerOfTwo = false;
1919 bool popCountLE2 = false;
1920 bool powerOfTwoMinusOne = false;
1921 if (lit < 2) {
1922 // Avoid special cases.
1923 return false;
1924 } else if (isPowerOfTwo(lit)) {
1925 powerOfTwo = true;
1926 } else if (isPopCountLE2(lit)) {
1927 popCountLE2 = true;
1928 } else if (isPowerOfTwo(lit + 1)) {
1929 powerOfTwoMinusOne = true;
1930 } else {
1931 return false;
1932 }
1933 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1934 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1935 if (powerOfTwo) {
1936 // Shift.
1937 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
1938 lowestSetBit(lit));
1939 } else if (popCountLE2) {
1940 // Shift and add and shift.
1941 int firstBit = lowestSetBit(lit);
1942 int secondBit = lowestSetBit(lit ^ (1 << firstBit));
1943 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
1944 firstBit, secondBit);
1945 } else {
1946 // Reverse subtract: (src << (shift + 1)) - src.
buzbeeed3e9302011-09-23 17:34:19 -07001947 DCHECK(powerOfTwoMinusOne);
buzbee5ade1d22011-09-09 14:44:52 -07001948 // TUNING: rsb dst, src, src lsl#lowestSetBit(lit + 1)
buzbee67bf8852011-08-17 17:51:35 -07001949 int tReg = oatAllocTemp(cUnit);
1950 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
1951 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
1952 }
1953 storeValue(cUnit, rlDest, rlResult);
1954 return true;
1955}
1956
buzbeeed3e9302011-09-23 17:34:19 -07001957STATIC bool genArithOpIntLit(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001958 RegLocation rlDest, RegLocation rlSrc,
1959 int lit)
1960{
1961 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1962 RegLocation rlResult;
1963 OpKind op = (OpKind)0; /* Make gcc happy */
1964 int shiftOp = false;
1965 bool isDiv = false;
1966 int funcOffset;
1967
1968 switch (dalvikOpcode) {
1969 case OP_RSUB_INT_LIT8:
1970 case OP_RSUB_INT: {
1971 int tReg;
1972 //TUNING: add support for use of Arm rsub op
1973 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1974 tReg = oatAllocTemp(cUnit);
1975 loadConstant(cUnit, tReg, lit);
1976 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1977 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1978 tReg, rlSrc.lowReg);
1979 storeValue(cUnit, rlDest, rlResult);
1980 return false;
1981 break;
1982 }
1983
1984 case OP_ADD_INT_LIT8:
1985 case OP_ADD_INT_LIT16:
1986 op = kOpAdd;
1987 break;
1988 case OP_MUL_INT_LIT8:
1989 case OP_MUL_INT_LIT16: {
1990 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
1991 return false;
1992 }
1993 op = kOpMul;
1994 break;
1995 }
1996 case OP_AND_INT_LIT8:
1997 case OP_AND_INT_LIT16:
1998 op = kOpAnd;
1999 break;
2000 case OP_OR_INT_LIT8:
2001 case OP_OR_INT_LIT16:
2002 op = kOpOr;
2003 break;
2004 case OP_XOR_INT_LIT8:
2005 case OP_XOR_INT_LIT16:
2006 op = kOpXor;
2007 break;
2008 case OP_SHL_INT_LIT8:
2009 lit &= 31;
2010 shiftOp = true;
2011 op = kOpLsl;
2012 break;
2013 case OP_SHR_INT_LIT8:
2014 lit &= 31;
2015 shiftOp = true;
2016 op = kOpAsr;
2017 break;
2018 case OP_USHR_INT_LIT8:
2019 lit &= 31;
2020 shiftOp = true;
2021 op = kOpLsr;
2022 break;
2023
2024 case OP_DIV_INT_LIT8:
2025 case OP_DIV_INT_LIT16:
2026 case OP_REM_INT_LIT8:
2027 case OP_REM_INT_LIT16:
2028 if (lit == 0) {
buzbee5ade1d22011-09-09 14:44:52 -07002029 genImmedCheck(cUnit, kArmCondAl, 0, 0, mir, kArmThrowDivZero);
buzbee67bf8852011-08-17 17:51:35 -07002030 return false;
2031 }
2032 if (handleEasyDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit)) {
2033 return false;
2034 }
2035 oatFlushAllRegs(cUnit); /* Everything to home location */
2036 loadValueDirectFixed(cUnit, rlSrc, r0);
2037 oatClobber(cUnit, r0);
2038 if ((dalvikOpcode == OP_DIV_INT_LIT8) ||
2039 (dalvikOpcode == OP_DIV_INT_LIT16)) {
2040 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
2041 isDiv = true;
2042 } else {
2043 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
2044 isDiv = false;
2045 }
2046 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
2047 loadConstant(cUnit, r1, lit);
Ian Rogersff1ed472011-09-20 13:46:24 -07002048 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -07002049 if (isDiv)
2050 rlResult = oatGetReturn(cUnit);
2051 else
2052 rlResult = oatGetReturnAlt(cUnit);
2053 storeValue(cUnit, rlDest, rlResult);
2054 return false;
2055 break;
2056 default:
2057 return true;
2058 }
2059 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2060 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
2061 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
2062 if (shiftOp && (lit == 0)) {
2063 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2064 } else {
2065 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2066 }
2067 storeValue(cUnit, rlDest, rlResult);
2068 return false;
2069}
2070
2071/* Architectural-specific debugging helpers go here */
2072void oatArchDump(void)
2073{
2074 /* Print compiled opcode in this VM instance */
2075 int i, start, streak;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002076 std::string buf;
buzbee67bf8852011-08-17 17:51:35 -07002077
2078 streak = i = 0;
buzbee67bf8852011-08-17 17:51:35 -07002079 while (opcodeCoverage[i] == 0 && i < kNumPackedOpcodes) {
2080 i++;
2081 }
2082 if (i == kNumPackedOpcodes) {
2083 return;
2084 }
2085 for (start = i++, streak = 1; i < kNumPackedOpcodes; i++) {
2086 if (opcodeCoverage[i]) {
2087 streak++;
2088 } else {
2089 if (streak == 1) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002090 StringAppendF(&buf, "%x,", start);
buzbee67bf8852011-08-17 17:51:35 -07002091 } else {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002092 StringAppendF(&buf, "%x-%x,", start, start + streak - 1);
buzbee67bf8852011-08-17 17:51:35 -07002093 }
2094 streak = 0;
2095 while (opcodeCoverage[i] == 0 && i < kNumPackedOpcodes) {
2096 i++;
2097 }
2098 if (i < kNumPackedOpcodes) {
2099 streak = 1;
2100 start = i;
2101 }
2102 }
2103 }
2104 if (streak) {
2105 if (streak == 1) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002106 StringAppendF(&buf, "%x", start);
buzbee67bf8852011-08-17 17:51:35 -07002107 } else {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002108 StringAppendF(&buf, "%x-%x", start, start + streak - 1);
buzbee67bf8852011-08-17 17:51:35 -07002109 }
2110 }
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07002111 if (!buf.empty()) {
buzbee67bf8852011-08-17 17:51:35 -07002112 LOG(INFO) << "dalvik.vm.oat.op = " << buf;
2113 }
2114}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08002115
2116} // namespace art