blob: 1938960b30efcb572b517bb669ea9e237f48e3d5 [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
buzbeee62076c2012-03-21 14:26:16 -070029
30/* Return the position of an ssa name within the argument list */
31int inPosition(CompilationUnit* cUnit, int sReg)
buzbee16da88c2012-03-20 10:38:17 -070032{
buzbeee62076c2012-03-21 14:26:16 -070033 int vReg = SRegToVReg(cUnit, sReg);
34 return vReg - cUnit->numRegs;
35}
36
37/*
38 * Describe an argument. If it's already in an arg register, just leave it
39 * there. NOTE: all live arg registers must be locked prior to this call
40 * to avoid having them allocated as a temp by downstream utilities.
41 */
42RegLocation argLoc(CompilationUnit* cUnit, RegLocation loc)
43{
44 int argNum = inPosition(cUnit, loc.sRegLow);
buzbee16da88c2012-03-20 10:38:17 -070045 if (loc.wide) {
buzbeee62076c2012-03-21 14:26:16 -070046 if (argNum == 2) {
47 // Bad case - half in register, half in frame. Just punt
48 loc.location = kLocInvalid;
49 } else if (argNum < 2) {
50 loc.lowReg = rARG1 + argNum;
51 loc.highReg = loc.lowReg + 1;
52 loc.location = kLocPhysReg;
53 } else {
54 loc.location = kLocDalvikFrame;
55 }
buzbee16da88c2012-03-20 10:38:17 -070056 } else {
buzbeee62076c2012-03-21 14:26:16 -070057 if (argNum < 3) {
58 loc.lowReg = rARG1 + argNum;
59 loc.location = kLocPhysReg;
60 } else {
61 loc.location = kLocDalvikFrame;
62 }
buzbee16da88c2012-03-20 10:38:17 -070063 }
64 return loc;
65}
66
buzbeee62076c2012-03-21 14:26:16 -070067/*
68 * Load an argument. If already in a register, just return. If in
69 * the frame, we can't use the normal loadValue() because it assumed
70 * a proper frame - and we're frameless.
71 */
72RegLocation loadArg(CompilationUnit* cUnit, RegLocation loc)
73{
74 if (loc.location == kLocDalvikFrame) {
75 int start = (inPosition(cUnit, loc.sRegLow) + 1) * sizeof(uint32_t);
76 loc.lowReg = oatAllocTemp(cUnit);
77 loadWordDisp(cUnit, rSP, start, loc.lowReg);
78 if (loc.wide) {
79 loc.highReg = oatAllocTemp(cUnit);
80 loadWordDisp(cUnit, rSP, start + sizeof(uint32_t), loc.highReg);
81 }
82 loc.location = kLocPhysReg;
83 }
84 return loc;
85}
86
87/* Lock any referenced arguments that arrive in registers */
88void lockLiveArgs(CompilationUnit* cUnit, MIR* mir)
89{
90 int firstIn = cUnit->numRegs;
91 const int numArgRegs = 3; // TODO: generalize & move to RegUtil.cc
92 for (int i = 0; i < mir->ssaRep->numUses; i++) {
93 int vReg = SRegToVReg(cUnit, mir->ssaRep->uses[i]);
94 int inPosition = vReg - firstIn;
95 if (inPosition < numArgRegs) {
96 oatLockTemp(cUnit, rARG1 + inPosition);
97 }
98 }
99}
100
buzbee16da88c2012-03-20 10:38:17 -0700101/* Find the next MIR, which may be in a following basic block */
102MIR* getNextMir(CompilationUnit* cUnit, BasicBlock** pBb, MIR* mir)
103{
104 BasicBlock* bb = *pBb;
105 MIR* origMir = mir;
106 while (bb != NULL) {
107 if (mir != NULL) {
108 mir = mir->next;
109 }
110 if (mir != NULL) {
111 return mir;
112 } else {
113 bb = bb->fallThrough;
114 *pBb = bb;
115 if (bb) {
116 mir = bb->firstMIRInsn;
117 if (mir != NULL) {
118 return mir;
119 }
120 }
121 }
122 }
123 return origMir;
124}
125
126/* Used for the "printMe" listing */
127void genPrintLabel(CompilationUnit *cUnit, MIR* mir)
128{
129 LIR* boundaryLIR;
130 /* Mark the beginning of a Dalvik instruction for line tracking */
131 char* instStr = cUnit->printMe ?
132 oatGetDalvikDisassembly(cUnit, mir->dalvikInsn, "") : NULL;
133 boundaryLIR = newLIR1(cUnit, kPseudoDalvikByteCodeBoundary,
134 (intptr_t) instStr);
135 cUnit->boundaryMap.insert(std::make_pair(mir->offset,
136 (LIR*)boundaryLIR));
137 /* Don't generate the SSA annotation unless verbose mode is on */
138 if (cUnit->printMe && mir->ssaRep) {
139 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
140 newLIR1(cUnit, kPseudoSSARep, (int) ssaString);
141 }
142}
143
144MIR* specialIGet(CompilationUnit* cUnit, BasicBlock** bb, MIR* mir,
145 OpSize size, bool longOrDouble, bool isObject)
146{
147 int fieldOffset;
148 bool isVolatile;
149 uint32_t fieldIdx = mir->dalvikInsn.vC;
150 bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile,
151 false);
152 if (!fastPath) {
153 return NULL;
154 }
buzbee16da88c2012-03-20 10:38:17 -0700155 RegLocation rlObj = oatGetSrc(cUnit, mir, 0);
buzbeee62076c2012-03-21 14:26:16 -0700156 lockLiveArgs(cUnit, mir);
157 rlObj = argLoc(cUnit, rlObj);
158 // Reject if object reference is not "this"
159 if ((rlObj.location == kLocInvalid) ||
160 (inPosition(cUnit, rlObj.sRegLow) != 0)) {
161 oatResetRegPool(cUnit);
162 return NULL;
163 }
buzbee16da88c2012-03-20 10:38:17 -0700164 RegLocation rlDest;
165 if (longOrDouble) {
166 rlDest = oatGetReturnWide(cUnit, false);
167 } else {
168 rlDest = oatGetReturn(cUnit, false);
169 }
buzbeee62076c2012-03-21 14:26:16 -0700170 // Point of no return - no aborts after this
171 mir->optimizationFlags |= MIR_IGNORE_NULL_CHECK;
172 genPrintLabel(cUnit, mir);
173 rlObj = loadArg(cUnit, rlObj);
buzbee16da88c2012-03-20 10:38:17 -0700174 genIGet(cUnit, mir, size, rlDest, rlObj, longOrDouble, isObject);
175 return getNextMir(cUnit, bb, mir);
176}
177
178MIR* specialIPut(CompilationUnit* cUnit, BasicBlock** bb, MIR* mir,
179 OpSize size, bool longOrDouble, bool isObject)
180{
181 int fieldOffset;
182 bool isVolatile;
183 uint32_t fieldIdx = mir->dalvikInsn.vC;
184 bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile,
185 false);
186 if (!fastPath) {
187 return NULL;
188 }
buzbee16da88c2012-03-20 10:38:17 -0700189 RegLocation rlSrc;
190 RegLocation rlObj;
buzbeee62076c2012-03-21 14:26:16 -0700191 lockLiveArgs(cUnit, mir);
buzbee16da88c2012-03-20 10:38:17 -0700192 if (longOrDouble) {
193 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
194 rlObj = oatGetSrc(cUnit, mir, 2);
buzbee16da88c2012-03-20 10:38:17 -0700195 } else {
196 rlSrc = oatGetSrc(cUnit, mir, 0);
197 rlObj = oatGetSrc(cUnit, mir, 1);
buzbee16da88c2012-03-20 10:38:17 -0700198 }
buzbeee62076c2012-03-21 14:26:16 -0700199 rlSrc = argLoc(cUnit, rlSrc);
200 rlObj = argLoc(cUnit, rlObj);
201 // Reject if object reference is not "this"
202 if ((rlObj.location == kLocInvalid) ||
203 (inPosition(cUnit, rlObj.sRegLow) != 0) ||
204 (rlSrc.location == kLocInvalid)) {
205 oatResetRegPool(cUnit);
206 return NULL;
207 }
208 // Point of no return - no aborts after this
209 mir->optimizationFlags |= MIR_IGNORE_NULL_CHECK;
210 genPrintLabel(cUnit, mir);
211 rlObj = loadArg(cUnit, rlObj);
212 rlSrc = loadArg(cUnit, rlSrc);
buzbee16da88c2012-03-20 10:38:17 -0700213 genIPut(cUnit, mir, size, rlSrc, rlObj, longOrDouble, isObject);
214 return getNextMir(cUnit, bb, mir);
215}
216
buzbeee62076c2012-03-21 14:26:16 -0700217MIR* specialIdentity(CompilationUnit* cUnit, MIR* mir)
218{
219 RegLocation rlSrc;
220 RegLocation rlDest;
221 bool wide = (mir->ssaRep->numUses == 2);
222 if (wide) {
223 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
224 rlDest = oatGetReturnWide(cUnit, false);
225 } else {
226 rlSrc = oatGetSrc(cUnit, mir, 0);
227 rlDest = oatGetReturn(cUnit, false);
228 }
229 lockLiveArgs(cUnit, mir);
230 rlSrc = argLoc(cUnit, rlSrc);
231 if (rlSrc.location == kLocInvalid) {
232 oatResetRegPool(cUnit);
233 return NULL;
234 }
235 // Point of no return - no aborts after this
236 genPrintLabel(cUnit, mir);
237 rlSrc = loadArg(cUnit, rlSrc);
238 if (wide) {
239 storeValueWide(cUnit, rlDest, rlSrc);
240 } else {
241 storeValue(cUnit, rlDest, rlSrc);
242 }
243 return mir;
244}
245
buzbee16da88c2012-03-20 10:38:17 -0700246/*
247 * Special-case code genration for simple non-throwing leaf methods.
248 */
249void genSpecialCase(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
250 SpecialCaseHandler specialCase)
251{
252 cUnit->currentDalvikOffset = mir->offset;
253 MIR* nextMir = NULL;
254 switch(specialCase) {
255 case kNullMethod:
256 DCHECK(mir->dalvikInsn.opcode == Instruction::RETURN_VOID);
257 nextMir = mir;
258 break;
259 case kConstFunction:
260 genPrintLabel(cUnit, mir);
261 loadConstant(cUnit, rRET0, mir->dalvikInsn.vB);
262 nextMir = getNextMir(cUnit, &bb, mir);
263 break;
264 case kIGet:
265 nextMir = specialIGet(cUnit, &bb, mir, kWord, false, false);
buzbeee62076c2012-03-21 14:26:16 -0700266 break;
buzbee16da88c2012-03-20 10:38:17 -0700267 case kIGetBoolean:
268 case kIGetByte:
269 nextMir = specialIGet(cUnit, &bb, mir, kUnsignedByte, false, false);
buzbeee62076c2012-03-21 14:26:16 -0700270 break;
buzbee16da88c2012-03-20 10:38:17 -0700271 case kIGetObject:
272 nextMir = specialIGet(cUnit, &bb, mir, kWord, false, true);
buzbeee62076c2012-03-21 14:26:16 -0700273 break;
buzbee16da88c2012-03-20 10:38:17 -0700274 case kIGetChar:
275 nextMir = specialIGet(cUnit, &bb, mir, kUnsignedHalf, false, false);
buzbeee62076c2012-03-21 14:26:16 -0700276 break;
buzbee16da88c2012-03-20 10:38:17 -0700277 case kIGetShort:
278 nextMir = specialIGet(cUnit, &bb, mir, kSignedHalf, false, false);
buzbeee62076c2012-03-21 14:26:16 -0700279 break;
buzbee16da88c2012-03-20 10:38:17 -0700280 case kIGetWide:
281 nextMir = specialIGet(cUnit, &bb, mir, kLong, true, false);
buzbeee62076c2012-03-21 14:26:16 -0700282 break;
buzbee16da88c2012-03-20 10:38:17 -0700283 case kIPut:
284 nextMir = specialIPut(cUnit, &bb, mir, kWord, false, false);
buzbeee62076c2012-03-21 14:26:16 -0700285 break;
buzbee16da88c2012-03-20 10:38:17 -0700286 case kIPutBoolean:
287 case kIPutByte:
288 nextMir = specialIPut(cUnit, &bb, mir, kUnsignedByte, false, false);
buzbeee62076c2012-03-21 14:26:16 -0700289 break;
buzbee16da88c2012-03-20 10:38:17 -0700290 case kIPutObject:
291 nextMir = specialIPut(cUnit, &bb, mir, kWord, false, true);
buzbeee62076c2012-03-21 14:26:16 -0700292 break;
buzbee16da88c2012-03-20 10:38:17 -0700293 case kIPutChar:
294 nextMir = specialIPut(cUnit, &bb, mir, kUnsignedHalf, false, false);
buzbeee62076c2012-03-21 14:26:16 -0700295 break;
buzbee16da88c2012-03-20 10:38:17 -0700296 case kIPutShort:
297 nextMir = specialIPut(cUnit, &bb, mir, kSignedHalf, false, false);
buzbeee62076c2012-03-21 14:26:16 -0700298 break;
buzbee16da88c2012-03-20 10:38:17 -0700299 case kIPutWide:
300 nextMir = specialIPut(cUnit, &bb, mir, kLong, true, false);
buzbeee62076c2012-03-21 14:26:16 -0700301 break;
302 case kIdentity:
303 nextMir = specialIdentity(cUnit, mir);
304 break;
buzbee16da88c2012-03-20 10:38:17 -0700305 default:
306 return;
307 }
308 if (nextMir != NULL) {
309 cUnit->currentDalvikOffset = nextMir->offset;
buzbeee62076c2012-03-21 14:26:16 -0700310 if (specialCase != kIdentity) {
311 genPrintLabel(cUnit, nextMir);
312 }
buzbee16da88c2012-03-20 10:38:17 -0700313 newLIR1(cUnit, kThumbBx, rLR);
314 cUnit->coreSpillMask = 0;
315 cUnit->numCoreSpills = 0;
316 cUnit->fpSpillMask = 0;
317 cUnit->numFPSpills = 0;
318 cUnit->frameSize = 0;
319 cUnit->coreVmapTable.clear();
320 cUnit->fpVmapTable.clear();
321 }
322}
buzbee67bf8852011-08-17 17:51:35 -0700323
324/*
325 * Generate a Thumb2 IT instruction, which can nullify up to
326 * four subsequent instructions based on a condition and its
327 * inverse. The condition applies to the first instruction, which
328 * is executed if the condition is met. The string "guide" consists
329 * of 0 to 3 chars, and applies to the 2nd through 4th instruction.
330 * A "T" means the instruction is executed if the condition is
331 * met, and an "E" means the instruction is executed if the condition
332 * is not met.
333 */
buzbee82488f52012-03-02 08:20:26 -0800334LIR* opIT(CompilationUnit* cUnit, ArmConditionCode code, const char* guide)
buzbee67bf8852011-08-17 17:51:35 -0700335{
336 int mask;
337 int condBit = code & 1;
338 int altBit = condBit ^ 1;
339 int mask3 = 0;
340 int mask2 = 0;
341 int mask1 = 0;
342
343 //Note: case fallthroughs intentional
344 switch(strlen(guide)) {
345 case 3:
346 mask1 = (guide[2] == 'T') ? condBit : altBit;
347 case 2:
348 mask2 = (guide[1] == 'T') ? condBit : altBit;
349 case 1:
350 mask3 = (guide[0] == 'T') ? condBit : altBit;
351 break;
352 case 0:
353 break;
354 default:
buzbee82488f52012-03-02 08:20:26 -0800355 LOG(FATAL) << "OAT: bad case in opIT";
buzbee67bf8852011-08-17 17:51:35 -0700356 }
357 mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
358 (1 << (3 - strlen(guide)));
359 return newLIR2(cUnit, kThumb2It, code, mask);
360}
361
362/*
buzbee67bf8852011-08-17 17:51:35 -0700363 * The sparse table in the literal pool is an array of <key,displacement>
364 * pairs. For each set, we'll load them as a pair using ldmia.
365 * This means that the register number of the temp we use for the key
366 * must be lower than the reg for the displacement.
367 *
368 * The test loop will look something like:
369 *
370 * adr rBase, <table>
371 * ldr rVal, [rSP, vRegOff]
372 * mov rIdx, #tableSize
373 * lp:
374 * ldmia rBase!, {rKey, rDisp}
375 * sub rIdx, #1
376 * cmp rVal, rKey
377 * ifeq
378 * add rPC, rDisp ; This is the branch from which we compute displacement
379 * cbnz rIdx, lp
380 */
buzbee31a4a6f2012-02-28 15:36:15 -0800381void genSparseSwitch(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700382{
383 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
384 if (cUnit->printMe) {
385 dumpSparseSwitchTable(table);
386 }
387 // Add the table to the list - we'll process it later
buzbeeba938cb2012-02-03 14:47:55 -0800388 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
buzbee5abfa3e2012-01-31 17:01:43 -0800389 true, kAllocData);
buzbee67bf8852011-08-17 17:51:35 -0700390 tabRec->table = table;
391 tabRec->vaddr = mir->offset;
392 int size = table[1];
buzbee31a4a6f2012-02-28 15:36:15 -0800393 tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true,
394 kAllocLIR);
buzbeeba938cb2012-02-03 14:47:55 -0800395 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700396
397 // Get the switch value
398 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
399 int rBase = oatAllocTemp(cUnit);
400 /* Allocate key and disp temps */
401 int rKey = oatAllocTemp(cUnit);
402 int rDisp = oatAllocTemp(cUnit);
403 // Make sure rKey's register number is less than rDisp's number for ldmia
404 if (rKey > rDisp) {
405 int tmp = rDisp;
406 rDisp = rKey;
407 rKey = tmp;
408 }
409 // Materialize a pointer to the switch table
buzbee03fa2632011-09-20 17:10:57 -0700410 newLIR3(cUnit, kThumb2Adr, rBase, 0, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700411 // Set up rIdx
412 int rIdx = oatAllocTemp(cUnit);
413 loadConstant(cUnit, rIdx, size);
414 // Establish loop branch target
buzbee31a4a6f2012-02-28 15:36:15 -0800415 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee67bf8852011-08-17 17:51:35 -0700416 // Load next key/disp
417 newLIR2(cUnit, kThumb2LdmiaWB, rBase, (1 << rKey) | (1 << rDisp));
418 opRegReg(cUnit, kOpCmp, rKey, rlSrc.lowReg);
419 // Go if match. NOTE: No instruction set switch here - must stay Thumb2
buzbee82488f52012-03-02 08:20:26 -0800420 opIT(cUnit, kArmCondEq, "");
buzbee31a4a6f2012-02-28 15:36:15 -0800421 LIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, rDisp);
buzbeec5159d52012-03-03 11:48:39 -0800422 tabRec->anchor = switchBranch;
buzbee67bf8852011-08-17 17:51:35 -0700423 // Needs to use setflags encoding here
424 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
buzbee82488f52012-03-02 08:20:26 -0800425 opCondBranch(cUnit, kCondNe, target);
buzbee67bf8852011-08-17 17:51:35 -0700426}
427
428
buzbee31a4a6f2012-02-28 15:36:15 -0800429void genPackedSwitch(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700430{
431 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
432 if (cUnit->printMe) {
433 dumpPackedSwitchTable(table);
434 }
435 // Add the table to the list - we'll process it later
buzbeeba938cb2012-02-03 14:47:55 -0800436 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
buzbee5abfa3e2012-01-31 17:01:43 -0800437 true, kAllocData);
buzbee67bf8852011-08-17 17:51:35 -0700438 tabRec->table = table;
439 tabRec->vaddr = mir->offset;
440 int size = table[1];
buzbee31a4a6f2012-02-28 15:36:15 -0800441 tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true,
buzbee5abfa3e2012-01-31 17:01:43 -0800442 kAllocLIR);
buzbeeba938cb2012-02-03 14:47:55 -0800443 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700444
445 // Get the switch value
446 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
447 int tableBase = oatAllocTemp(cUnit);
448 // Materialize a pointer to the switch table
buzbee03fa2632011-09-20 17:10:57 -0700449 newLIR3(cUnit, kThumb2Adr, tableBase, 0, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700450 int lowKey = s4FromSwitchData(&table[2]);
451 int keyReg;
452 // Remove the bias, if necessary
453 if (lowKey == 0) {
454 keyReg = rlSrc.lowReg;
455 } else {
456 keyReg = oatAllocTemp(cUnit);
457 opRegRegImm(cUnit, kOpSub, keyReg, rlSrc.lowReg, lowKey);
458 }
459 // Bounds check - if < 0 or >= size continue following switch
460 opRegImm(cUnit, kOpCmp, keyReg, size-1);
buzbee82488f52012-03-02 08:20:26 -0800461 LIR* branchOver = opCondBranch(cUnit, kCondHi, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700462
463 // Load the displacement from the switch table
464 int dispReg = oatAllocTemp(cUnit);
465 loadBaseIndexed(cUnit, tableBase, keyReg, dispReg, 2, kWord);
466
467 // ..and go! NOTE: No instruction set switch here - must stay Thumb2
buzbee31a4a6f2012-02-28 15:36:15 -0800468 LIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, dispReg);
buzbeec5159d52012-03-03 11:48:39 -0800469 tabRec->anchor = switchBranch;
buzbee67bf8852011-08-17 17:51:35 -0700470
471 /* branchOver target here */
buzbee31a4a6f2012-02-28 15:36:15 -0800472 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800473 branchOver->target = (LIR*)target;
buzbee67bf8852011-08-17 17:51:35 -0700474}
475
476/*
477 * Array data table format:
478 * ushort ident = 0x0300 magic value
479 * ushort width width of each element in the table
480 * uint size number of elements in the table
481 * ubyte data[size*width] table of data values (may contain a single-byte
482 * padding at the end)
483 *
484 * Total size is 4+(width * size + 1)/2 16-bit code units.
485 */
buzbee31a4a6f2012-02-28 15:36:15 -0800486void genFillArrayData(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700487{
488 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
489 // Add the table to the list - we'll process it later
490 FillArrayData *tabRec = (FillArrayData *)
buzbeeba938cb2012-02-03 14:47:55 -0800491 oatNew(cUnit, sizeof(FillArrayData), true, kAllocData);
buzbee67bf8852011-08-17 17:51:35 -0700492 tabRec->table = table;
493 tabRec->vaddr = mir->offset;
494 u2 width = tabRec->table[1];
495 u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
496 tabRec->size = (size * width) + 8;
497
buzbeeba938cb2012-02-03 14:47:55 -0800498 oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700499
500 // Making a call - use explicit registers
501 oatFlushAllRegs(cUnit); /* Everything to home location */
502 loadValueDirectFixed(cUnit, rlSrc, r0);
503 loadWordDisp(cUnit, rSELF,
buzbee1b4c8592011-08-31 10:43:51 -0700504 OFFSETOF_MEMBER(Thread, pHandleFillArrayDataFromCode), rLR);
buzbeee6d61962011-08-27 11:58:19 -0700505 // Materialize a pointer to the fill data image
buzbee03fa2632011-09-20 17:10:57 -0700506 newLIR3(cUnit, kThumb2Adr, r1, 0, (intptr_t)tabRec);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700507 oatClobberCalleeSave(cUnit);
508 opReg(cUnit, kOpBlx, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700509}
510
buzbee31a4a6f2012-02-28 15:36:15 -0800511void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700512{
513 RegLocation rlResult;
514 rlSrc = loadValue(cUnit, rlSrc, kFPReg);
515 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
516 newLIR2(cUnit, kThumb2Vnegs, rlResult.lowReg, rlSrc.lowReg);
517 storeValue(cUnit, rlDest, rlResult);
518}
519
buzbee31a4a6f2012-02-28 15:36:15 -0800520void genNegDouble(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700521{
522 RegLocation rlResult;
523 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
524 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
525 newLIR2(cUnit, kThumb2Vnegd, S2D(rlResult.lowReg, rlResult.highReg),
526 S2D(rlSrc.lowReg, rlSrc.highReg));
527 storeValueWide(cUnit, rlDest, rlResult);
528}
529
buzbee67bf8852011-08-17 17:51:35 -0700530/*
531 * Handle simple case (thin lock) inline. If it's complicated, bail
532 * out to the heavyweight lock/unlock routines. We'll use dedicated
533 * registers here in order to be in the right position in case we
534 * to bail to dvm[Lock/Unlock]Object(self, object)
535 *
536 * r0 -> self pointer [arg0 for dvm[Lock/Unlock]Object
537 * r1 -> object [arg1 for dvm[Lock/Unlock]Object
538 * r2 -> intial contents of object->lock, later result of strex
539 * r3 -> self->threadId
540 * r12 -> allow to be used by utilities as general temp
541 *
542 * The result of the strex is 0 if we acquire the lock.
543 *
544 * See comments in Sync.c for the layout of the lock word.
545 * Of particular interest to this code is the test for the
546 * simple case - which we handle inline. For monitor enter, the
547 * simple case is thin lock, held by no-one. For monitor exit,
548 * the simple case is thin lock, held by the unlocking thread with
549 * a recurse count of 0.
550 *
551 * A minor complication is that there is a field in the lock word
552 * unrelated to locking: the hash state. This field must be ignored, but
553 * preserved.
554 *
555 */
buzbee31a4a6f2012-02-28 15:36:15 -0800556void genMonitorEnter(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700557{
buzbee67bf8852011-08-17 17:51:35 -0700558 oatFlushAllRegs(cUnit);
Elliott Hughes5f791332011-09-15 17:45:30 -0700559 DCHECK_EQ(LW_SHAPE_THIN, 0);
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700560 loadValueDirectFixed(cUnit, rlSrc, r0); // Get obj
buzbee2e748f32011-08-29 21:02:19 -0700561 oatLockCallTemps(cUnit); // Prepare for explicit register usage
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700562 genNullCheck(cUnit, rlSrc.sRegLow, r0, mir);
563 loadWordDisp(cUnit, rSELF, Thread::ThinLockIdOffset().Int32Value(), r2);
564 newLIR3(cUnit, kThumb2Ldrex, r1, r0,
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700565 Object::MonitorOffset().Int32Value() >> 2); // Get object->lock
buzbeec143c552011-08-20 17:38:58 -0700566 // Align owner
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700567 opRegImm(cUnit, kOpLsl, r2, LW_LOCK_OWNER_SHIFT);
buzbee67bf8852011-08-17 17:51:35 -0700568 // Is lock unheld on lock or held by us (==threadId) on unlock?
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700569 newLIR4(cUnit, kThumb2Bfi, r2, r1, 0, LW_LOCK_OWNER_SHIFT - 1);
570 newLIR3(cUnit, kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
buzbee05eba362012-03-10 20:11:27 -0800571 opRegImm(cUnit, kOpCmp, r1, 0);
572 opIT(cUnit, kArmCondEq, "");
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700573 newLIR4(cUnit, kThumb2Strex, r1, r2, r0,
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700574 Object::MonitorOffset().Int32Value() >> 2);
buzbee05eba362012-03-10 20:11:27 -0800575 opRegImm(cUnit, kOpCmp, r1, 0);
576 opIT(cUnit, kArmCondNe, "T");
buzbee1b4c8592011-08-31 10:43:51 -0700577 // Go expensive route - artLockObjectFromCode(self, obj);
578 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pLockObjectFromCode),
buzbee67bf8852011-08-17 17:51:35 -0700579 rLR);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700580 oatClobberCalleeSave(cUnit);
581 opReg(cUnit, kOpBlx, rLR);
buzbee05eba362012-03-10 20:11:27 -0800582 oatGenMemBarrier(cUnit, kSY);
buzbee67bf8852011-08-17 17:51:35 -0700583}
584
585/*
586 * For monitor unlock, we don't have to use ldrex/strex. Once
587 * we've determined that the lock is thin and that we own it with
588 * a zero recursion count, it's safe to punch it back to the
589 * initial, unlock thin state with a store word.
590 */
buzbee31a4a6f2012-02-28 15:36:15 -0800591void genMonitorExit(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700592{
Elliott Hughes5f791332011-09-15 17:45:30 -0700593 DCHECK_EQ(LW_SHAPE_THIN, 0);
buzbee67bf8852011-08-17 17:51:35 -0700594 oatFlushAllRegs(cUnit);
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700595 loadValueDirectFixed(cUnit, rlSrc, r0); // Get obj
buzbee2e748f32011-08-29 21:02:19 -0700596 oatLockCallTemps(cUnit); // Prepare for explicit register usage
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700597 genNullCheck(cUnit, rlSrc.sRegLow, r0, mir);
598 loadWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r1); // Get lock
599 loadWordDisp(cUnit, rSELF, Thread::ThinLockIdOffset().Int32Value(), r2);
buzbee67bf8852011-08-17 17:51:35 -0700600 // Is lock unheld on lock or held by us (==threadId) on unlock?
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700601 opRegRegImm(cUnit, kOpAnd, r3, r1, (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
buzbeec143c552011-08-20 17:38:58 -0700602 // Align owner
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700603 opRegImm(cUnit, kOpLsl, r2, LW_LOCK_OWNER_SHIFT);
604 newLIR3(cUnit, kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
605 opRegReg(cUnit, kOpSub, r1, r2);
buzbee05eba362012-03-10 20:11:27 -0800606 opIT(cUnit, kArmCondEq, "EE");
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700607 storeWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r3);
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700608 // Go expensive route - UnlockObjectFromCode(obj);
buzbee1b4c8592011-08-31 10:43:51 -0700609 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pUnlockObjectFromCode),
buzbee67bf8852011-08-17 17:51:35 -0700610 rLR);
Ian Rogersab2b55d2012-03-18 00:06:11 -0700611 oatClobberCalleeSave(cUnit);
612 opReg(cUnit, kOpBlx, rLR);
buzbee05eba362012-03-10 20:11:27 -0800613 oatGenMemBarrier(cUnit, kSY);
buzbee67bf8852011-08-17 17:51:35 -0700614}
615
616/*
617 * 64-bit 3way compare function.
618 * mov rX, #-1
619 * cmp op1hi, op2hi
620 * blt done
621 * bgt flip
622 * sub rX, op1lo, op2lo (treat as unsigned)
623 * beq done
624 * ite hi
625 * mov(hi) rX, #-1
626 * mov(!hi) rX, #1
627 * flip:
628 * neg rX
629 * done:
630 */
buzbee31a4a6f2012-02-28 15:36:15 -0800631void genCmpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
632 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee67bf8852011-08-17 17:51:35 -0700633{
buzbee31a4a6f2012-02-28 15:36:15 -0800634 LIR* target1;
635 LIR* target2;
buzbee67bf8852011-08-17 17:51:35 -0700636 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
637 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
buzbeeb29e4d12011-09-26 15:05:48 -0700638 int tReg = oatAllocTemp(cUnit);
639 loadConstant(cUnit, tReg, -1);
buzbee67bf8852011-08-17 17:51:35 -0700640 opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg);
buzbee82488f52012-03-02 08:20:26 -0800641 LIR* branch1 = opCondBranch(cUnit, kCondLt, NULL);
642 LIR* branch2 = opCondBranch(cUnit, kCondGt, NULL);
buzbeeb29e4d12011-09-26 15:05:48 -0700643 opRegRegReg(cUnit, kOpSub, tReg, rlSrc1.lowReg, rlSrc2.lowReg);
buzbee82488f52012-03-02 08:20:26 -0800644 LIR* branch3 = opCondBranch(cUnit, kCondEq, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700645
buzbee82488f52012-03-02 08:20:26 -0800646 opIT(cUnit, kArmCondHi, "E");
buzbeeb29e4d12011-09-26 15:05:48 -0700647 newLIR2(cUnit, kThumb2MovImmShift, tReg, modifiedImmediate(-1));
648 loadConstant(cUnit, tReg, 1);
buzbee67bf8852011-08-17 17:51:35 -0700649 genBarrier(cUnit);
650
buzbee31a4a6f2012-02-28 15:36:15 -0800651 target2 = newLIR0(cUnit, kPseudoTargetLabel);
buzbeeb29e4d12011-09-26 15:05:48 -0700652 opRegReg(cUnit, kOpNeg, tReg, tReg);
buzbee67bf8852011-08-17 17:51:35 -0700653
buzbee31a4a6f2012-02-28 15:36:15 -0800654 target1 = newLIR0(cUnit, kPseudoTargetLabel);
buzbee67bf8852011-08-17 17:51:35 -0700655
buzbeeb29e4d12011-09-26 15:05:48 -0700656 RegLocation rlTemp = LOC_C_RETURN; // Just using as template, will change
657 rlTemp.lowReg = tReg;
buzbee67bf8852011-08-17 17:51:35 -0700658 storeValue(cUnit, rlDest, rlTemp);
buzbeeb29e4d12011-09-26 15:05:48 -0700659 oatFreeTemp(cUnit, tReg);
buzbee67bf8852011-08-17 17:51:35 -0700660
buzbee31a4a6f2012-02-28 15:36:15 -0800661 branch1->target = (LIR*)target1;
662 branch2->target = (LIR*)target2;
663 branch3->target = branch1->target;
buzbee67bf8852011-08-17 17:51:35 -0700664}
665
buzbee67bf8852011-08-17 17:51:35 -0700666/*
buzbee31a4a6f2012-02-28 15:36:15 -0800667 * Generate a register comparison to an immediate and branch. Caller
668 * is responsible for setting branch target field.
buzbee67bf8852011-08-17 17:51:35 -0700669 */
buzbee82488f52012-03-02 08:20:26 -0800670LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg,
671 int checkValue, LIR* target)
buzbee67bf8852011-08-17 17:51:35 -0700672{
buzbee31a4a6f2012-02-28 15:36:15 -0800673 LIR* branch;
674 int modImm;
675 ArmConditionCode armCond = oatArmConditionEncoding(cond);
676 if ((LOWREG(reg)) && (checkValue == 0) &&
677 ((armCond == kArmCondEq) || (armCond == kArmCondNe))) {
678 branch = newLIR2(cUnit,
679 (armCond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
680 reg, 0);
buzbee67bf8852011-08-17 17:51:35 -0700681 } else {
buzbee31a4a6f2012-02-28 15:36:15 -0800682 modImm = modifiedImmediate(checkValue);
683 if (LOWREG(reg) && ((checkValue & 0xff) == checkValue)) {
684 newLIR2(cUnit, kThumbCmpRI8, reg, checkValue);
685 } else if (modImm >= 0) {
686 newLIR2(cUnit, kThumb2CmpRI8, reg, modImm);
buzbee67bf8852011-08-17 17:51:35 -0700687 } else {
buzbee58f92742011-10-01 11:22:17 -0700688 int tReg = oatAllocTemp(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -0800689 loadConstant(cUnit, tReg, checkValue);
690 opRegReg(cUnit, kOpCmp, reg, tReg);
buzbee58f92742011-10-01 11:22:17 -0700691 }
buzbee31a4a6f2012-02-28 15:36:15 -0800692 branch = newLIR2(cUnit, kThumbBCond, 0, armCond);
buzbee67bf8852011-08-17 17:51:35 -0700693 }
buzbee82488f52012-03-02 08:20:26 -0800694 branch->target = target;
buzbee31a4a6f2012-02-28 15:36:15 -0800695 return branch;
696}
buzbee82488f52012-03-02 08:20:26 -0800697LIR* opRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
buzbee31a4a6f2012-02-28 15:36:15 -0800698{
699 LIR* res;
700 ArmOpcode opcode;
701 if (FPREG(rDest) || FPREG(rSrc))
702 return fpRegCopy(cUnit, rDest, rSrc);
buzbee31a4a6f2012-02-28 15:36:15 -0800703 if (LOWREG(rDest) && LOWREG(rSrc))
704 opcode = kThumbMovRR;
705 else if (!LOWREG(rDest) && !LOWREG(rSrc))
706 opcode = kThumbMovRR_H2H;
707 else if (LOWREG(rDest))
708 opcode = kThumbMovRR_H2L;
709 else
710 opcode = kThumbMovRR_L2H;
buzbeea2ebdd72012-03-04 14:57:06 -0800711 res = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, rDest, rSrc);
buzbee86a4bce2012-03-06 18:15:00 -0800712 if (!(cUnit->disableOpt & (1 << kSafeOptimizations)) && rDest == rSrc) {
buzbee31a4a6f2012-02-28 15:36:15 -0800713 res->flags.isNop = true;
714 }
715 return res;
buzbee67bf8852011-08-17 17:51:35 -0700716}
717
buzbee82488f52012-03-02 08:20:26 -0800718LIR* opRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
buzbee67bf8852011-08-17 17:51:35 -0700719{
buzbee82488f52012-03-02 08:20:26 -0800720 LIR* res = opRegCopyNoInsert(cUnit, rDest, rSrc);
buzbee31a4a6f2012-02-28 15:36:15 -0800721 oatAppendLIR(cUnit, (LIR*)res);
722 return res;
723}
buzbee67bf8852011-08-17 17:51:35 -0700724
buzbee82488f52012-03-02 08:20:26 -0800725void opRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
buzbee31a4a6f2012-02-28 15:36:15 -0800726 int srcLo, int srcHi)
727{
728 bool destFP = FPREG(destLo) && FPREG(destHi);
729 bool srcFP = FPREG(srcLo) && FPREG(srcHi);
730 DCHECK_EQ(FPREG(srcLo), FPREG(srcHi));
731 DCHECK_EQ(FPREG(destLo), FPREG(destHi));
732 if (destFP) {
733 if (srcFP) {
buzbee82488f52012-03-02 08:20:26 -0800734 opRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
buzbee67bf8852011-08-17 17:51:35 -0700735 } else {
buzbee31a4a6f2012-02-28 15:36:15 -0800736 newLIR3(cUnit, kThumb2Fmdrr, S2D(destLo, destHi), srcLo, srcHi);
737 }
738 } else {
739 if (srcFP) {
740 newLIR3(cUnit, kThumb2Fmrrd, destLo, destHi, S2D(srcLo, srcHi));
741 } else {
742 // Handle overlap
743 if (srcHi == destLo) {
buzbee82488f52012-03-02 08:20:26 -0800744 opRegCopy(cUnit, destHi, srcHi);
745 opRegCopy(cUnit, destLo, srcLo);
buzbee67bf8852011-08-17 17:51:35 -0700746 } else {
buzbee82488f52012-03-02 08:20:26 -0800747 opRegCopy(cUnit, destLo, srcLo);
748 opRegCopy(cUnit, destHi, srcHi);
buzbee67bf8852011-08-17 17:51:35 -0700749 }
750 }
751 }
buzbee67bf8852011-08-17 17:51:35 -0700752}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800753
buzbee31a4a6f2012-02-28 15:36:15 -0800754
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800755} // namespace art