blob: 21c995ff115c858aaa6608b99e2db392f2453007 [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
Logan Chien4dd96f52012-02-29 01:26:58 +080025#include "oat_compilation_unit.h"
26
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080027namespace art {
28
buzbee16da88c2012-03-20 10:38:17 -070029/* Return a RegLocation that describes an in-register argument */
30RegLocation argLoc(CompilationUnit* cUnit, RegLocation loc, int sReg)
31{
32 loc.location = kLocPhysReg;
33 int base = SRegToVReg(cUnit, sReg) - cUnit->numRegs;
34 loc.sRegLow = sReg;
35 loc.lowReg = rARG1 + base;
36 loc.home = true;
37 if (loc.wide) {
38 loc.highReg = loc.lowReg + 1;
39 oatLockTemp(cUnit, loc.lowReg);
40 oatLockTemp(cUnit, loc.highReg);
41 } else {
42 oatLockTemp(cUnit, loc.lowReg);
43 }
44 return loc;
45}
46
47/* Find the next MIR, which may be in a following basic block */
48MIR* getNextMir(CompilationUnit* cUnit, BasicBlock** pBb, MIR* mir)
49{
50 BasicBlock* bb = *pBb;
51 MIR* origMir = mir;
52 while (bb != NULL) {
53 if (mir != NULL) {
54 mir = mir->next;
55 }
56 if (mir != NULL) {
57 return mir;
58 } else {
59 bb = bb->fallThrough;
60 *pBb = bb;
61 if (bb) {
62 mir = bb->firstMIRInsn;
63 if (mir != NULL) {
64 return mir;
65 }
66 }
67 }
68 }
69 return origMir;
70}
71
72/* Used for the "printMe" listing */
73void genPrintLabel(CompilationUnit *cUnit, MIR* mir)
74{
75 LIR* boundaryLIR;
76 /* Mark the beginning of a Dalvik instruction for line tracking */
77 char* instStr = cUnit->printMe ?
78 oatGetDalvikDisassembly(cUnit, mir->dalvikInsn, "") : NULL;
79 boundaryLIR = newLIR1(cUnit, kPseudoDalvikByteCodeBoundary,
80 (intptr_t) instStr);
81 cUnit->boundaryMap.insert(std::make_pair(mir->offset,
82 (LIR*)boundaryLIR));
83 /* Don't generate the SSA annotation unless verbose mode is on */
84 if (cUnit->printMe && mir->ssaRep) {
85 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
86 newLIR1(cUnit, kPseudoSSARep, (int) ssaString);
87 }
88}
89
90MIR* specialIGet(CompilationUnit* cUnit, BasicBlock** bb, MIR* mir,
91 OpSize size, bool longOrDouble, bool isObject)
92{
93 int fieldOffset;
94 bool isVolatile;
95 uint32_t fieldIdx = mir->dalvikInsn.vC;
96 bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile,
97 false);
98 if (!fastPath) {
99 return NULL;
100 }
101 mir->optimizationFlags |= MIR_IGNORE_NULL_CHECK;
102 genPrintLabel(cUnit, mir);
103 RegLocation rlObj = oatGetSrc(cUnit, mir, 0);
104 rlObj = argLoc(cUnit, rlObj, mir->ssaRep->uses[0]);
105 RegLocation rlDest;
106 if (longOrDouble) {
107 rlDest = oatGetReturnWide(cUnit, false);
108 } else {
109 rlDest = oatGetReturn(cUnit, false);
110 }
111 genIGet(cUnit, mir, size, rlDest, rlObj, longOrDouble, isObject);
112 return getNextMir(cUnit, bb, mir);
113}
114
115MIR* specialIPut(CompilationUnit* cUnit, BasicBlock** bb, MIR* mir,
116 OpSize size, bool longOrDouble, bool isObject)
117{
118 int fieldOffset;
119 bool isVolatile;
120 uint32_t fieldIdx = mir->dalvikInsn.vC;
Ian Rogersf24132c2012-03-21 01:34:31 -0700121 if (cUnit->numIns > 3) {
122 return NULL; // TODO: fix register allocation for many in arguments
123 }
buzbee16da88c2012-03-20 10:38:17 -0700124 bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile,
125 false);
126 if (!fastPath) {
127 return NULL;
128 }
129 mir->optimizationFlags |= MIR_IGNORE_NULL_CHECK;
130 genPrintLabel(cUnit, mir);
131 RegLocation rlSrc;
132 RegLocation rlObj;
133 int sSreg = mir->ssaRep->uses[0];
134 int oSreg;
135 if (longOrDouble) {
136 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
137 rlObj = oatGetSrc(cUnit, mir, 2);
138 oSreg = mir->ssaRep->uses[2];
139 } else {
140 rlSrc = oatGetSrc(cUnit, mir, 0);
141 rlObj = oatGetSrc(cUnit, mir, 1);
142 oSreg = mir->ssaRep->uses[1];
143 }
144 rlSrc = argLoc(cUnit, rlSrc, sSreg);
145 rlObj = argLoc(cUnit, rlObj, oSreg);
146 genIPut(cUnit, mir, size, rlSrc, rlObj, longOrDouble, isObject);
147 return getNextMir(cUnit, bb, mir);
148}
149
150/*
151 * Special-case code genration for simple non-throwing leaf methods.
152 */
153void genSpecialCase(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
154 SpecialCaseHandler specialCase)
155{
156 cUnit->currentDalvikOffset = mir->offset;
157 MIR* nextMir = NULL;
158 switch(specialCase) {
159 case kNullMethod:
160 DCHECK(mir->dalvikInsn.opcode == Instruction::RETURN_VOID);
161 nextMir = mir;
162 break;
163 case kConstFunction:
164 genPrintLabel(cUnit, mir);
165 loadConstant(cUnit, rRET0, mir->dalvikInsn.vB);
166 nextMir = getNextMir(cUnit, &bb, mir);
167 break;
168 case kIGet:
169 nextMir = specialIGet(cUnit, &bb, mir, kWord, false, false);
170 break;;
171 case kIGetBoolean:
172 case kIGetByte:
173 nextMir = specialIGet(cUnit, &bb, mir, kUnsignedByte, false, false);
174 break;;
175 case kIGetObject:
176 nextMir = specialIGet(cUnit, &bb, mir, kWord, false, true);
177 break;;
178 case kIGetChar:
179 nextMir = specialIGet(cUnit, &bb, mir, kUnsignedHalf, false, false);
180 break;;
181 case kIGetShort:
182 nextMir = specialIGet(cUnit, &bb, mir, kSignedHalf, false, false);
183 break;;
184 case kIGetWide:
185 nextMir = specialIGet(cUnit, &bb, mir, kLong, true, false);
186 break;;
187 case kIPut:
188 nextMir = specialIPut(cUnit, &bb, mir, kWord, false, false);
189 break;;
190 case kIPutBoolean:
191 case kIPutByte:
192 nextMir = specialIPut(cUnit, &bb, mir, kUnsignedByte, false, false);
193 break;;
194 case kIPutObject:
195 nextMir = specialIPut(cUnit, &bb, mir, kWord, false, true);
196 break;;
197 case kIPutChar:
198 nextMir = specialIPut(cUnit, &bb, mir, kUnsignedHalf, false, false);
199 break;;
200 case kIPutShort:
201 nextMir = specialIPut(cUnit, &bb, mir, kSignedHalf, false, false);
202 break;;
203 case kIPutWide:
204 nextMir = specialIPut(cUnit, &bb, mir, kLong, true, false);
205 break;;
206 default:
207 return;
208 }
209 if (nextMir != NULL) {
210 cUnit->currentDalvikOffset = nextMir->offset;
211 genPrintLabel(cUnit, nextMir);
212 newLIR1(cUnit, kThumbBx, rLR);
213 cUnit->coreSpillMask = 0;
214 cUnit->numCoreSpills = 0;
215 cUnit->fpSpillMask = 0;
216 cUnit->numFPSpills = 0;
217 cUnit->frameSize = 0;
218 cUnit->coreVmapTable.clear();
219 cUnit->fpVmapTable.clear();
220 }
221}
buzbee67bf8852011-08-17 17:51:35 -0700222
223/*
224 * Generate a Thumb2 IT instruction, which can nullify up to
225 * four subsequent instructions based on a condition and its
226 * inverse. The condition applies to the first instruction, which
227 * is executed if the condition is met. The string "guide" consists
228 * of 0 to 3 chars, and applies to the 2nd through 4th instruction.
229 * A "T" means the instruction is executed if the condition is
230 * met, and an "E" means the instruction is executed if the condition
231 * is not met.
232 */
buzbee82488f52012-03-02 08:20:26 -0800233LIR* opIT(CompilationUnit* cUnit, ArmConditionCode code, const char* guide)
buzbee67bf8852011-08-17 17:51:35 -0700234{
235 int mask;
236 int condBit = code & 1;
237 int altBit = condBit ^ 1;
238 int mask3 = 0;
239 int mask2 = 0;
240 int mask1 = 0;
241
242 //Note: case fallthroughs intentional
243 switch(strlen(guide)) {
244 case 3:
245 mask1 = (guide[2] == 'T') ? condBit : altBit;
246 case 2:
247 mask2 = (guide[1] == 'T') ? condBit : altBit;
248 case 1:
249 mask3 = (guide[0] == 'T') ? condBit : altBit;
250 break;
251 case 0:
252 break;
253 default:
buzbee82488f52012-03-02 08:20:26 -0800254 LOG(FATAL) << "OAT: bad case in opIT";
buzbee67bf8852011-08-17 17:51:35 -0700255 }
256 mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
257 (1 << (3 - strlen(guide)));
258 return newLIR2(cUnit, kThumb2It, code, mask);
259}
260
261/*
buzbee67bf8852011-08-17 17:51:35 -0700262 * The sparse table in the literal pool is an array of <key,displacement>
263 * pairs. For each set, we'll load them as a pair using ldmia.
264 * This means that the register number of the temp we use for the key
265 * must be lower than the reg for the displacement.
266 *
267 * The test loop will look something like:
268 *
269 * adr rBase, <table>
270 * ldr rVal, [rSP, vRegOff]
271 * mov rIdx, #tableSize
272 * lp:
273 * ldmia rBase!, {rKey, rDisp}
274 * sub rIdx, #1
275 * cmp rVal, rKey
276 * ifeq
277 * add rPC, rDisp ; This is the branch from which we compute displacement
278 * cbnz rIdx, lp
279 */
buzbee31a4a6f2012-02-28 15:36:15 -0800280void genSparseSwitch(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700281{
282 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
283 if (cUnit->printMe) {
284 dumpSparseSwitchTable(table);
285 }
286 // Add the table to the list - we'll process it later
buzbeeba938cb2012-02-03 14:47:55 -0800287 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
buzbee5abfa3e2012-01-31 17:01:43 -0800288 true, kAllocData);
buzbee67bf8852011-08-17 17:51:35 -0700289 tabRec->table = table;
290 tabRec->vaddr = mir->offset;
291 int size = table[1];
buzbee31a4a6f2012-02-28 15:36:15 -0800292 tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true,
293 kAllocLIR);
buzbeeba938cb2012-02-03 14:47:55 -0800294 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700295
296 // Get the switch value
297 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
298 int rBase = oatAllocTemp(cUnit);
299 /* Allocate key and disp temps */
300 int rKey = oatAllocTemp(cUnit);
301 int rDisp = oatAllocTemp(cUnit);
302 // Make sure rKey's register number is less than rDisp's number for ldmia
303 if (rKey > rDisp) {
304 int tmp = rDisp;
305 rDisp = rKey;
306 rKey = tmp;
307 }
308 // Materialize a pointer to the switch table
buzbee03fa2632011-09-20 17:10:57 -0700309 newLIR3(cUnit, kThumb2Adr, rBase, 0, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700310 // Set up rIdx
311 int rIdx = oatAllocTemp(cUnit);
312 loadConstant(cUnit, rIdx, size);
313 // Establish loop branch target
buzbee31a4a6f2012-02-28 15:36:15 -0800314 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee67bf8852011-08-17 17:51:35 -0700315 // Load next key/disp
316 newLIR2(cUnit, kThumb2LdmiaWB, rBase, (1 << rKey) | (1 << rDisp));
317 opRegReg(cUnit, kOpCmp, rKey, rlSrc.lowReg);
318 // Go if match. NOTE: No instruction set switch here - must stay Thumb2
buzbee82488f52012-03-02 08:20:26 -0800319 opIT(cUnit, kArmCondEq, "");
buzbee31a4a6f2012-02-28 15:36:15 -0800320 LIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, rDisp);
buzbeec5159d52012-03-03 11:48:39 -0800321 tabRec->anchor = switchBranch;
buzbee67bf8852011-08-17 17:51:35 -0700322 // Needs to use setflags encoding here
323 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
buzbee82488f52012-03-02 08:20:26 -0800324 opCondBranch(cUnit, kCondNe, target);
buzbee67bf8852011-08-17 17:51:35 -0700325}
326
327
buzbee31a4a6f2012-02-28 15:36:15 -0800328void genPackedSwitch(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700329{
330 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
331 if (cUnit->printMe) {
332 dumpPackedSwitchTable(table);
333 }
334 // Add the table to the list - we'll process it later
buzbeeba938cb2012-02-03 14:47:55 -0800335 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
buzbee5abfa3e2012-01-31 17:01:43 -0800336 true, kAllocData);
buzbee67bf8852011-08-17 17:51:35 -0700337 tabRec->table = table;
338 tabRec->vaddr = mir->offset;
339 int size = table[1];
buzbee31a4a6f2012-02-28 15:36:15 -0800340 tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true,
buzbee5abfa3e2012-01-31 17:01:43 -0800341 kAllocLIR);
buzbeeba938cb2012-02-03 14:47:55 -0800342 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700343
344 // Get the switch value
345 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
346 int tableBase = oatAllocTemp(cUnit);
347 // Materialize a pointer to the switch table
buzbee03fa2632011-09-20 17:10:57 -0700348 newLIR3(cUnit, kThumb2Adr, tableBase, 0, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700349 int lowKey = s4FromSwitchData(&table[2]);
350 int keyReg;
351 // Remove the bias, if necessary
352 if (lowKey == 0) {
353 keyReg = rlSrc.lowReg;
354 } else {
355 keyReg = oatAllocTemp(cUnit);
356 opRegRegImm(cUnit, kOpSub, keyReg, rlSrc.lowReg, lowKey);
357 }
358 // Bounds check - if < 0 or >= size continue following switch
359 opRegImm(cUnit, kOpCmp, keyReg, size-1);
buzbee82488f52012-03-02 08:20:26 -0800360 LIR* branchOver = opCondBranch(cUnit, kCondHi, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700361
362 // Load the displacement from the switch table
363 int dispReg = oatAllocTemp(cUnit);
364 loadBaseIndexed(cUnit, tableBase, keyReg, dispReg, 2, kWord);
365
366 // ..and go! NOTE: No instruction set switch here - must stay Thumb2
buzbee31a4a6f2012-02-28 15:36:15 -0800367 LIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, dispReg);
buzbeec5159d52012-03-03 11:48:39 -0800368 tabRec->anchor = switchBranch;
buzbee67bf8852011-08-17 17:51:35 -0700369
370 /* branchOver target here */
buzbee31a4a6f2012-02-28 15:36:15 -0800371 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800372 branchOver->target = (LIR*)target;
buzbee67bf8852011-08-17 17:51:35 -0700373}
374
375/*
376 * Array data table format:
377 * ushort ident = 0x0300 magic value
378 * ushort width width of each element in the table
379 * uint size number of elements in the table
380 * ubyte data[size*width] table of data values (may contain a single-byte
381 * padding at the end)
382 *
383 * Total size is 4+(width * size + 1)/2 16-bit code units.
384 */
buzbee31a4a6f2012-02-28 15:36:15 -0800385void genFillArrayData(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700386{
387 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
388 // Add the table to the list - we'll process it later
389 FillArrayData *tabRec = (FillArrayData *)
buzbeeba938cb2012-02-03 14:47:55 -0800390 oatNew(cUnit, sizeof(FillArrayData), true, kAllocData);
buzbee67bf8852011-08-17 17:51:35 -0700391 tabRec->table = table;
392 tabRec->vaddr = mir->offset;
393 u2 width = tabRec->table[1];
394 u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
395 tabRec->size = (size * width) + 8;
396
buzbeeba938cb2012-02-03 14:47:55 -0800397 oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700398
399 // Making a call - use explicit registers
400 oatFlushAllRegs(cUnit); /* Everything to home location */
401 loadValueDirectFixed(cUnit, rlSrc, r0);
402 loadWordDisp(cUnit, rSELF,
buzbee1b4c8592011-08-31 10:43:51 -0700403 OFFSETOF_MEMBER(Thread, pHandleFillArrayDataFromCode), rLR);
buzbeee6d61962011-08-27 11:58:19 -0700404 // Materialize a pointer to the fill data image
buzbee03fa2632011-09-20 17:10:57 -0700405 newLIR3(cUnit, kThumb2Adr, r1, 0, (intptr_t)tabRec);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700406 oatClobberCalleeSave(cUnit);
407 opReg(cUnit, kOpBlx, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700408}
409
buzbee31a4a6f2012-02-28 15:36:15 -0800410void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700411{
412 RegLocation rlResult;
413 rlSrc = loadValue(cUnit, rlSrc, kFPReg);
414 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
415 newLIR2(cUnit, kThumb2Vnegs, rlResult.lowReg, rlSrc.lowReg);
416 storeValue(cUnit, rlDest, rlResult);
417}
418
buzbee31a4a6f2012-02-28 15:36:15 -0800419void genNegDouble(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700420{
421 RegLocation rlResult;
422 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
423 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
424 newLIR2(cUnit, kThumb2Vnegd, S2D(rlResult.lowReg, rlResult.highReg),
425 S2D(rlSrc.lowReg, rlSrc.highReg));
426 storeValueWide(cUnit, rlDest, rlResult);
427}
428
buzbee67bf8852011-08-17 17:51:35 -0700429/*
430 * Handle simple case (thin lock) inline. If it's complicated, bail
431 * out to the heavyweight lock/unlock routines. We'll use dedicated
432 * registers here in order to be in the right position in case we
433 * to bail to dvm[Lock/Unlock]Object(self, object)
434 *
435 * r0 -> self pointer [arg0 for dvm[Lock/Unlock]Object
436 * r1 -> object [arg1 for dvm[Lock/Unlock]Object
437 * r2 -> intial contents of object->lock, later result of strex
438 * r3 -> self->threadId
439 * r12 -> allow to be used by utilities as general temp
440 *
441 * The result of the strex is 0 if we acquire the lock.
442 *
443 * See comments in Sync.c for the layout of the lock word.
444 * Of particular interest to this code is the test for the
445 * simple case - which we handle inline. For monitor enter, the
446 * simple case is thin lock, held by no-one. For monitor exit,
447 * the simple case is thin lock, held by the unlocking thread with
448 * a recurse count of 0.
449 *
450 * A minor complication is that there is a field in the lock word
451 * unrelated to locking: the hash state. This field must be ignored, but
452 * preserved.
453 *
454 */
buzbee31a4a6f2012-02-28 15:36:15 -0800455void genMonitorEnter(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700456{
buzbee67bf8852011-08-17 17:51:35 -0700457 oatFlushAllRegs(cUnit);
Elliott Hughes5f791332011-09-15 17:45:30 -0700458 DCHECK_EQ(LW_SHAPE_THIN, 0);
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700459 loadValueDirectFixed(cUnit, rlSrc, r0); // Get obj
buzbee2e748f32011-08-29 21:02:19 -0700460 oatLockCallTemps(cUnit); // Prepare for explicit register usage
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700461 genNullCheck(cUnit, rlSrc.sRegLow, r0, mir);
462 loadWordDisp(cUnit, rSELF, Thread::ThinLockIdOffset().Int32Value(), r2);
463 newLIR3(cUnit, kThumb2Ldrex, r1, r0,
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700464 Object::MonitorOffset().Int32Value() >> 2); // Get object->lock
buzbeec143c552011-08-20 17:38:58 -0700465 // Align owner
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700466 opRegImm(cUnit, kOpLsl, r2, LW_LOCK_OWNER_SHIFT);
buzbee67bf8852011-08-17 17:51:35 -0700467 // Is lock unheld on lock or held by us (==threadId) on unlock?
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700468 newLIR4(cUnit, kThumb2Bfi, r2, r1, 0, LW_LOCK_OWNER_SHIFT - 1);
469 newLIR3(cUnit, kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
buzbee05eba362012-03-10 20:11:27 -0800470 opRegImm(cUnit, kOpCmp, r1, 0);
471 opIT(cUnit, kArmCondEq, "");
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700472 newLIR4(cUnit, kThumb2Strex, r1, r2, r0,
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700473 Object::MonitorOffset().Int32Value() >> 2);
buzbee05eba362012-03-10 20:11:27 -0800474 opRegImm(cUnit, kOpCmp, r1, 0);
475 opIT(cUnit, kArmCondNe, "T");
buzbee1b4c8592011-08-31 10:43:51 -0700476 // Go expensive route - artLockObjectFromCode(self, obj);
477 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pLockObjectFromCode),
buzbee67bf8852011-08-17 17:51:35 -0700478 rLR);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700479 oatClobberCalleeSave(cUnit);
480 opReg(cUnit, kOpBlx, rLR);
buzbee05eba362012-03-10 20:11:27 -0800481 oatGenMemBarrier(cUnit, kSY);
buzbee67bf8852011-08-17 17:51:35 -0700482}
483
484/*
485 * For monitor unlock, we don't have to use ldrex/strex. Once
486 * we've determined that the lock is thin and that we own it with
487 * a zero recursion count, it's safe to punch it back to the
488 * initial, unlock thin state with a store word.
489 */
buzbee31a4a6f2012-02-28 15:36:15 -0800490void genMonitorExit(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700491{
Elliott Hughes5f791332011-09-15 17:45:30 -0700492 DCHECK_EQ(LW_SHAPE_THIN, 0);
buzbee67bf8852011-08-17 17:51:35 -0700493 oatFlushAllRegs(cUnit);
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700494 loadValueDirectFixed(cUnit, rlSrc, r0); // Get obj
buzbee2e748f32011-08-29 21:02:19 -0700495 oatLockCallTemps(cUnit); // Prepare for explicit register usage
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700496 genNullCheck(cUnit, rlSrc.sRegLow, r0, mir);
497 loadWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r1); // Get lock
498 loadWordDisp(cUnit, rSELF, Thread::ThinLockIdOffset().Int32Value(), r2);
buzbee67bf8852011-08-17 17:51:35 -0700499 // Is lock unheld on lock or held by us (==threadId) on unlock?
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700500 opRegRegImm(cUnit, kOpAnd, r3, r1, (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
buzbeec143c552011-08-20 17:38:58 -0700501 // Align owner
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700502 opRegImm(cUnit, kOpLsl, r2, LW_LOCK_OWNER_SHIFT);
503 newLIR3(cUnit, kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
504 opRegReg(cUnit, kOpSub, r1, r2);
buzbee05eba362012-03-10 20:11:27 -0800505 opIT(cUnit, kArmCondEq, "EE");
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700506 storeWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r3);
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700507 // Go expensive route - UnlockObjectFromCode(obj);
buzbee1b4c8592011-08-31 10:43:51 -0700508 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pUnlockObjectFromCode),
buzbee67bf8852011-08-17 17:51:35 -0700509 rLR);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700510 oatClobberCalleeSave(cUnit);
511 opReg(cUnit, kOpBlx, rLR);
buzbee05eba362012-03-10 20:11:27 -0800512 oatGenMemBarrier(cUnit, kSY);
buzbee67bf8852011-08-17 17:51:35 -0700513}
514
515/*
516 * 64-bit 3way compare function.
517 * mov rX, #-1
518 * cmp op1hi, op2hi
519 * blt done
520 * bgt flip
521 * sub rX, op1lo, op2lo (treat as unsigned)
522 * beq done
523 * ite hi
524 * mov(hi) rX, #-1
525 * mov(!hi) rX, #1
526 * flip:
527 * neg rX
528 * done:
529 */
buzbee31a4a6f2012-02-28 15:36:15 -0800530void genCmpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
531 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee67bf8852011-08-17 17:51:35 -0700532{
buzbee31a4a6f2012-02-28 15:36:15 -0800533 LIR* target1;
534 LIR* target2;
buzbee67bf8852011-08-17 17:51:35 -0700535 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
536 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
buzbeeb29e4d12011-09-26 15:05:48 -0700537 int tReg = oatAllocTemp(cUnit);
538 loadConstant(cUnit, tReg, -1);
buzbee67bf8852011-08-17 17:51:35 -0700539 opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg);
buzbee82488f52012-03-02 08:20:26 -0800540 LIR* branch1 = opCondBranch(cUnit, kCondLt, NULL);
541 LIR* branch2 = opCondBranch(cUnit, kCondGt, NULL);
buzbeeb29e4d12011-09-26 15:05:48 -0700542 opRegRegReg(cUnit, kOpSub, tReg, rlSrc1.lowReg, rlSrc2.lowReg);
buzbee82488f52012-03-02 08:20:26 -0800543 LIR* branch3 = opCondBranch(cUnit, kCondEq, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700544
buzbee82488f52012-03-02 08:20:26 -0800545 opIT(cUnit, kArmCondHi, "E");
buzbeeb29e4d12011-09-26 15:05:48 -0700546 newLIR2(cUnit, kThumb2MovImmShift, tReg, modifiedImmediate(-1));
547 loadConstant(cUnit, tReg, 1);
buzbee67bf8852011-08-17 17:51:35 -0700548 genBarrier(cUnit);
549
buzbee31a4a6f2012-02-28 15:36:15 -0800550 target2 = newLIR0(cUnit, kPseudoTargetLabel);
buzbeeb29e4d12011-09-26 15:05:48 -0700551 opRegReg(cUnit, kOpNeg, tReg, tReg);
buzbee67bf8852011-08-17 17:51:35 -0700552
buzbee31a4a6f2012-02-28 15:36:15 -0800553 target1 = newLIR0(cUnit, kPseudoTargetLabel);
buzbee67bf8852011-08-17 17:51:35 -0700554
buzbeeb29e4d12011-09-26 15:05:48 -0700555 RegLocation rlTemp = LOC_C_RETURN; // Just using as template, will change
556 rlTemp.lowReg = tReg;
buzbee67bf8852011-08-17 17:51:35 -0700557 storeValue(cUnit, rlDest, rlTemp);
buzbeeb29e4d12011-09-26 15:05:48 -0700558 oatFreeTemp(cUnit, tReg);
buzbee67bf8852011-08-17 17:51:35 -0700559
buzbee31a4a6f2012-02-28 15:36:15 -0800560 branch1->target = (LIR*)target1;
561 branch2->target = (LIR*)target2;
562 branch3->target = branch1->target;
buzbee67bf8852011-08-17 17:51:35 -0700563}
564
buzbee67bf8852011-08-17 17:51:35 -0700565/*
buzbee31a4a6f2012-02-28 15:36:15 -0800566 * Generate a register comparison to an immediate and branch. Caller
567 * is responsible for setting branch target field.
buzbee67bf8852011-08-17 17:51:35 -0700568 */
buzbee82488f52012-03-02 08:20:26 -0800569LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg,
570 int checkValue, LIR* target)
buzbee67bf8852011-08-17 17:51:35 -0700571{
buzbee31a4a6f2012-02-28 15:36:15 -0800572 LIR* branch;
573 int modImm;
574 ArmConditionCode armCond = oatArmConditionEncoding(cond);
575 if ((LOWREG(reg)) && (checkValue == 0) &&
576 ((armCond == kArmCondEq) || (armCond == kArmCondNe))) {
577 branch = newLIR2(cUnit,
578 (armCond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
579 reg, 0);
buzbee67bf8852011-08-17 17:51:35 -0700580 } else {
buzbee31a4a6f2012-02-28 15:36:15 -0800581 modImm = modifiedImmediate(checkValue);
582 if (LOWREG(reg) && ((checkValue & 0xff) == checkValue)) {
583 newLIR2(cUnit, kThumbCmpRI8, reg, checkValue);
584 } else if (modImm >= 0) {
585 newLIR2(cUnit, kThumb2CmpRI8, reg, modImm);
buzbee67bf8852011-08-17 17:51:35 -0700586 } else {
buzbee58f92742011-10-01 11:22:17 -0700587 int tReg = oatAllocTemp(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -0800588 loadConstant(cUnit, tReg, checkValue);
589 opRegReg(cUnit, kOpCmp, reg, tReg);
buzbee58f92742011-10-01 11:22:17 -0700590 }
buzbee31a4a6f2012-02-28 15:36:15 -0800591 branch = newLIR2(cUnit, kThumbBCond, 0, armCond);
buzbee67bf8852011-08-17 17:51:35 -0700592 }
buzbee82488f52012-03-02 08:20:26 -0800593 branch->target = target;
buzbee31a4a6f2012-02-28 15:36:15 -0800594 return branch;
595}
buzbee82488f52012-03-02 08:20:26 -0800596LIR* opRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
buzbee31a4a6f2012-02-28 15:36:15 -0800597{
598 LIR* res;
599 ArmOpcode opcode;
600 if (FPREG(rDest) || FPREG(rSrc))
601 return fpRegCopy(cUnit, rDest, rSrc);
buzbee31a4a6f2012-02-28 15:36:15 -0800602 if (LOWREG(rDest) && LOWREG(rSrc))
603 opcode = kThumbMovRR;
604 else if (!LOWREG(rDest) && !LOWREG(rSrc))
605 opcode = kThumbMovRR_H2H;
606 else if (LOWREG(rDest))
607 opcode = kThumbMovRR_H2L;
608 else
609 opcode = kThumbMovRR_L2H;
buzbeea2ebdd72012-03-04 14:57:06 -0800610 res = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, rDest, rSrc);
buzbee86a4bce2012-03-06 18:15:00 -0800611 if (!(cUnit->disableOpt & (1 << kSafeOptimizations)) && rDest == rSrc) {
buzbee31a4a6f2012-02-28 15:36:15 -0800612 res->flags.isNop = true;
613 }
614 return res;
buzbee67bf8852011-08-17 17:51:35 -0700615}
616
buzbee82488f52012-03-02 08:20:26 -0800617LIR* opRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
buzbee67bf8852011-08-17 17:51:35 -0700618{
buzbee82488f52012-03-02 08:20:26 -0800619 LIR* res = opRegCopyNoInsert(cUnit, rDest, rSrc);
buzbee31a4a6f2012-02-28 15:36:15 -0800620 oatAppendLIR(cUnit, (LIR*)res);
621 return res;
622}
buzbee67bf8852011-08-17 17:51:35 -0700623
buzbee82488f52012-03-02 08:20:26 -0800624void opRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
buzbee31a4a6f2012-02-28 15:36:15 -0800625 int srcLo, int srcHi)
626{
627 bool destFP = FPREG(destLo) && FPREG(destHi);
628 bool srcFP = FPREG(srcLo) && FPREG(srcHi);
629 DCHECK_EQ(FPREG(srcLo), FPREG(srcHi));
630 DCHECK_EQ(FPREG(destLo), FPREG(destHi));
631 if (destFP) {
632 if (srcFP) {
buzbee82488f52012-03-02 08:20:26 -0800633 opRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
buzbee67bf8852011-08-17 17:51:35 -0700634 } else {
buzbee31a4a6f2012-02-28 15:36:15 -0800635 newLIR3(cUnit, kThumb2Fmdrr, S2D(destLo, destHi), srcLo, srcHi);
636 }
637 } else {
638 if (srcFP) {
639 newLIR3(cUnit, kThumb2Fmrrd, destLo, destHi, S2D(srcLo, srcHi));
640 } else {
641 // Handle overlap
642 if (srcHi == destLo) {
buzbee82488f52012-03-02 08:20:26 -0800643 opRegCopy(cUnit, destHi, srcHi);
644 opRegCopy(cUnit, destLo, srcLo);
buzbee67bf8852011-08-17 17:51:35 -0700645 } else {
buzbee82488f52012-03-02 08:20:26 -0800646 opRegCopy(cUnit, destLo, srcLo);
647 opRegCopy(cUnit, destHi, srcHi);
buzbee67bf8852011-08-17 17:51:35 -0700648 }
649 }
650 }
buzbee67bf8852011-08-17 17:51:35 -0700651}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800652
buzbee31a4a6f2012-02-28 15:36:15 -0800653
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800654} // namespace art