blob: 98137ad58faa7f5dd87e84ee82fe1741c10526bc [file] [log] [blame]
buzbeeefc63692012-11-14 16:31:52 -08001/*
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/* This file contains codegen for the Thumb2 ISA. */
18
19#include "oat_compilation_unit.h"
20#include "oat/runtime/oat_support_entrypoints.h"
buzbee1bc37c62012-11-20 13:35:41 -080021#include "arm_lir.h"
22#include "../codegen_util.h"
23#include "../ralloc_util.h"
buzbeeefc63692012-11-14 16:31:52 -080024
25namespace art {
26
27
28/* Return the position of an ssa name within the argument list */
buzbeeaad94382012-11-21 07:40:50 -080029static int InPosition(CompilationUnit* cUnit, int sReg)
buzbeeefc63692012-11-14 16:31:52 -080030{
31 int vReg = SRegToVReg(cUnit, sReg);
32 return vReg - cUnit->numRegs;
33}
34
35/*
36 * Describe an argument. If it's already in an arg register, just leave it
37 * there. NOTE: all live arg registers must be locked prior to this call
38 * to avoid having them allocated as a temp by downstream utilities.
39 */
buzbee52a77fc2012-11-20 19:50:46 -080040RegLocation ArgLoc(CompilationUnit* cUnit, RegLocation loc)
buzbeeefc63692012-11-14 16:31:52 -080041{
buzbee52a77fc2012-11-20 19:50:46 -080042 int argNum = InPosition(cUnit, loc.sRegLow);
buzbeeefc63692012-11-14 16:31:52 -080043 if (loc.wide) {
44 if (argNum == 2) {
45 // Bad case - half in register, half in frame. Just punt
46 loc.location = kLocInvalid;
47 } else if (argNum < 2) {
48 loc.lowReg = rARM_ARG1 + argNum;
49 loc.highReg = loc.lowReg + 1;
50 loc.location = kLocPhysReg;
51 } else {
52 loc.location = kLocDalvikFrame;
53 }
54 } else {
55 if (argNum < 3) {
56 loc.lowReg = rARM_ARG1 + argNum;
57 loc.location = kLocPhysReg;
58 } else {
59 loc.location = kLocDalvikFrame;
60 }
61 }
62 return loc;
63}
64
65/*
66 * Load an argument. If already in a register, just return. If in
buzbee52a77fc2012-11-20 19:50:46 -080067 * the frame, we can't use the normal LoadValue() because it assumed
buzbeeefc63692012-11-14 16:31:52 -080068 * a proper frame - and we're frameless.
69 */
buzbee52a77fc2012-11-20 19:50:46 -080070RegLocation LoadArg(CompilationUnit* cUnit, RegLocation loc)
buzbeeefc63692012-11-14 16:31:52 -080071{
72 if (loc.location == kLocDalvikFrame) {
buzbee52a77fc2012-11-20 19:50:46 -080073 int start = (InPosition(cUnit, loc.sRegLow) + 1) * sizeof(uint32_t);
74 loc.lowReg = AllocTemp(cUnit);
75 LoadWordDisp(cUnit, rARM_SP, start, loc.lowReg);
buzbeeefc63692012-11-14 16:31:52 -080076 if (loc.wide) {
buzbee52a77fc2012-11-20 19:50:46 -080077 loc.highReg = AllocTemp(cUnit);
78 LoadWordDisp(cUnit, rARM_SP, start + sizeof(uint32_t), loc.highReg);
buzbeeefc63692012-11-14 16:31:52 -080079 }
80 loc.location = kLocPhysReg;
81 }
82 return loc;
83}
84
85/* Lock any referenced arguments that arrive in registers */
buzbeeaad94382012-11-21 07:40:50 -080086static void LockLiveArgs(CompilationUnit* cUnit, MIR* mir)
buzbeeefc63692012-11-14 16:31:52 -080087{
88 int firstIn = cUnit->numRegs;
89 const int numArgRegs = 3; // TODO: generalize & move to RegUtil.cc
90 for (int i = 0; i < mir->ssaRep->numUses; i++) {
91 int vReg = SRegToVReg(cUnit, mir->ssaRep->uses[i]);
buzbee52a77fc2012-11-20 19:50:46 -080092 int InPosition = vReg - firstIn;
93 if (InPosition < numArgRegs) {
94 LockTemp(cUnit, rARM_ARG1 + InPosition);
buzbeeefc63692012-11-14 16:31:52 -080095 }
96 }
97}
98
99/* Find the next MIR, which may be in a following basic block */
buzbeeaad94382012-11-21 07:40:50 -0800100static MIR* GetNextMir(CompilationUnit* cUnit, BasicBlock** pBb, MIR* mir)
buzbeeefc63692012-11-14 16:31:52 -0800101{
102 BasicBlock* bb = *pBb;
103 MIR* origMir = mir;
104 while (bb != NULL) {
105 if (mir != NULL) {
106 mir = mir->next;
107 }
108 if (mir != NULL) {
109 return mir;
110 } else {
111 bb = bb->fallThrough;
112 *pBb = bb;
113 if (bb) {
114 mir = bb->firstMIRInsn;
115 if (mir != NULL) {
116 return mir;
117 }
118 }
119 }
120 }
121 return origMir;
122}
123
124/* Used for the "printMe" listing */
buzbee52a77fc2012-11-20 19:50:46 -0800125void GenPrintLabel(CompilationUnit *cUnit, MIR* mir)
buzbeeefc63692012-11-14 16:31:52 -0800126{
127 /* Mark the beginning of a Dalvik instruction for line tracking */
128 char* instStr = cUnit->printMe ?
buzbee52a77fc2012-11-20 19:50:46 -0800129 GetDalvikDisassembly(cUnit, mir->dalvikInsn, "") : NULL;
130 MarkBoundary(cUnit, mir->offset, instStr);
buzbeeefc63692012-11-14 16:31:52 -0800131 /* Don't generate the SSA annotation unless verbose mode is on */
132 if (cUnit->printMe && mir->ssaRep) {
buzbee52a77fc2012-11-20 19:50:46 -0800133 char* ssaString = GetSSAString(cUnit, mir->ssaRep);
134 NewLIR1(cUnit, kPseudoSSARep, reinterpret_cast<uintptr_t>(ssaString));
buzbeeefc63692012-11-14 16:31:52 -0800135 }
136}
137
buzbeeaad94382012-11-21 07:40:50 -0800138static MIR* SpecialIGet(CompilationUnit* cUnit, BasicBlock** bb, MIR* mir,
139 OpSize size, bool longOrDouble, bool isObject)
buzbeeefc63692012-11-14 16:31:52 -0800140{
141 int fieldOffset;
142 bool isVolatile;
143 uint32_t fieldIdx = mir->dalvikInsn.vC;
buzbee52a77fc2012-11-20 19:50:46 -0800144 bool fastPath = FastInstance(cUnit, fieldIdx, fieldOffset, isVolatile, false);
buzbeeefc63692012-11-14 16:31:52 -0800145 if (!fastPath || !(mir->optimizationFlags & MIR_IGNORE_NULL_CHECK)) {
146 return NULL;
147 }
buzbee52a77fc2012-11-20 19:50:46 -0800148 RegLocation rlObj = GetSrc(cUnit, mir, 0);
149 LockLiveArgs(cUnit, mir);
150 rlObj = ArgLoc(cUnit, rlObj);
buzbeeefc63692012-11-14 16:31:52 -0800151 RegLocation rlDest;
152 if (longOrDouble) {
buzbee52a77fc2012-11-20 19:50:46 -0800153 rlDest = GetReturnWide(cUnit, false);
buzbeeefc63692012-11-14 16:31:52 -0800154 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800155 rlDest = GetReturn(cUnit, false);
buzbeeefc63692012-11-14 16:31:52 -0800156 }
157 // Point of no return - no aborts after this
buzbee52a77fc2012-11-20 19:50:46 -0800158 GenPrintLabel(cUnit, mir);
159 rlObj = LoadArg(cUnit, rlObj);
160 GenIGet(cUnit, fieldIdx, mir->optimizationFlags, size, rlDest, rlObj,
buzbeeefc63692012-11-14 16:31:52 -0800161 longOrDouble, isObject);
buzbee52a77fc2012-11-20 19:50:46 -0800162 return GetNextMir(cUnit, bb, mir);
buzbeeefc63692012-11-14 16:31:52 -0800163}
164
buzbeeaad94382012-11-21 07:40:50 -0800165static MIR* SpecialIPut(CompilationUnit* cUnit, BasicBlock** bb, MIR* mir,
166 OpSize size, bool longOrDouble, bool isObject)
buzbeeefc63692012-11-14 16:31:52 -0800167{
168 int fieldOffset;
169 bool isVolatile;
170 uint32_t fieldIdx = mir->dalvikInsn.vC;
buzbee52a77fc2012-11-20 19:50:46 -0800171 bool fastPath = FastInstance(cUnit, fieldIdx, fieldOffset, isVolatile, false);
buzbeeefc63692012-11-14 16:31:52 -0800172 if (!fastPath || !(mir->optimizationFlags & MIR_IGNORE_NULL_CHECK)) {
173 return NULL;
174 }
175 RegLocation rlSrc;
176 RegLocation rlObj;
buzbee52a77fc2012-11-20 19:50:46 -0800177 LockLiveArgs(cUnit, mir);
buzbeeefc63692012-11-14 16:31:52 -0800178 if (longOrDouble) {
buzbee52a77fc2012-11-20 19:50:46 -0800179 rlSrc = GetSrcWide(cUnit, mir, 0);
180 rlObj = GetSrc(cUnit, mir, 2);
buzbeeefc63692012-11-14 16:31:52 -0800181 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800182 rlSrc = GetSrc(cUnit, mir, 0);
183 rlObj = GetSrc(cUnit, mir, 1);
buzbeeefc63692012-11-14 16:31:52 -0800184 }
buzbee52a77fc2012-11-20 19:50:46 -0800185 rlSrc = ArgLoc(cUnit, rlSrc);
186 rlObj = ArgLoc(cUnit, rlObj);
buzbeeefc63692012-11-14 16:31:52 -0800187 // Reject if source is split across registers & frame
188 if (rlObj.location == kLocInvalid) {
buzbee52a77fc2012-11-20 19:50:46 -0800189 ResetRegPool(cUnit);
buzbeeefc63692012-11-14 16:31:52 -0800190 return NULL;
191 }
192 // Point of no return - no aborts after this
buzbee52a77fc2012-11-20 19:50:46 -0800193 GenPrintLabel(cUnit, mir);
194 rlObj = LoadArg(cUnit, rlObj);
195 rlSrc = LoadArg(cUnit, rlSrc);
196 GenIPut(cUnit, fieldIdx, mir->optimizationFlags, size, rlSrc, rlObj,
buzbeeefc63692012-11-14 16:31:52 -0800197 longOrDouble, isObject);
buzbee52a77fc2012-11-20 19:50:46 -0800198 return GetNextMir(cUnit, bb, mir);
buzbeeefc63692012-11-14 16:31:52 -0800199}
200
buzbeeaad94382012-11-21 07:40:50 -0800201static MIR* SpecialIdentity(CompilationUnit* cUnit, MIR* mir)
buzbeeefc63692012-11-14 16:31:52 -0800202{
203 RegLocation rlSrc;
204 RegLocation rlDest;
205 bool wide = (mir->ssaRep->numUses == 2);
206 if (wide) {
buzbee52a77fc2012-11-20 19:50:46 -0800207 rlSrc = GetSrcWide(cUnit, mir, 0);
208 rlDest = GetReturnWide(cUnit, false);
buzbeeefc63692012-11-14 16:31:52 -0800209 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800210 rlSrc = GetSrc(cUnit, mir, 0);
211 rlDest = GetReturn(cUnit, false);
buzbeeefc63692012-11-14 16:31:52 -0800212 }
buzbee52a77fc2012-11-20 19:50:46 -0800213 LockLiveArgs(cUnit, mir);
214 rlSrc = ArgLoc(cUnit, rlSrc);
buzbeeefc63692012-11-14 16:31:52 -0800215 if (rlSrc.location == kLocInvalid) {
buzbee52a77fc2012-11-20 19:50:46 -0800216 ResetRegPool(cUnit);
buzbeeefc63692012-11-14 16:31:52 -0800217 return NULL;
218 }
219 // Point of no return - no aborts after this
buzbee52a77fc2012-11-20 19:50:46 -0800220 GenPrintLabel(cUnit, mir);
221 rlSrc = LoadArg(cUnit, rlSrc);
buzbeeefc63692012-11-14 16:31:52 -0800222 if (wide) {
buzbee52a77fc2012-11-20 19:50:46 -0800223 StoreValueWide(cUnit, rlDest, rlSrc);
buzbeeefc63692012-11-14 16:31:52 -0800224 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800225 StoreValue(cUnit, rlDest, rlSrc);
buzbeeefc63692012-11-14 16:31:52 -0800226 }
227 return mir;
228}
229
230/*
231 * Special-case code genration for simple non-throwing leaf methods.
232 */
buzbee52a77fc2012-11-20 19:50:46 -0800233void GenSpecialCase(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
buzbeeefc63692012-11-14 16:31:52 -0800234 SpecialCaseHandler specialCase)
235{
236 cUnit->currentDalvikOffset = mir->offset;
237 MIR* nextMir = NULL;
238 switch (specialCase) {
239 case kNullMethod:
240 DCHECK(mir->dalvikInsn.opcode == Instruction::RETURN_VOID);
241 nextMir = mir;
242 break;
243 case kConstFunction:
buzbee52a77fc2012-11-20 19:50:46 -0800244 GenPrintLabel(cUnit, mir);
245 LoadConstant(cUnit, rARM_RET0, mir->dalvikInsn.vB);
246 nextMir = GetNextMir(cUnit, &bb, mir);
buzbeeefc63692012-11-14 16:31:52 -0800247 break;
248 case kIGet:
buzbee52a77fc2012-11-20 19:50:46 -0800249 nextMir = SpecialIGet(cUnit, &bb, mir, kWord, false, false);
buzbeeefc63692012-11-14 16:31:52 -0800250 break;
251 case kIGetBoolean:
252 case kIGetByte:
buzbee52a77fc2012-11-20 19:50:46 -0800253 nextMir = SpecialIGet(cUnit, &bb, mir, kUnsignedByte, false, false);
buzbeeefc63692012-11-14 16:31:52 -0800254 break;
255 case kIGetObject:
buzbee52a77fc2012-11-20 19:50:46 -0800256 nextMir = SpecialIGet(cUnit, &bb, mir, kWord, false, true);
buzbeeefc63692012-11-14 16:31:52 -0800257 break;
258 case kIGetChar:
buzbee52a77fc2012-11-20 19:50:46 -0800259 nextMir = SpecialIGet(cUnit, &bb, mir, kUnsignedHalf, false, false);
buzbeeefc63692012-11-14 16:31:52 -0800260 break;
261 case kIGetShort:
buzbee52a77fc2012-11-20 19:50:46 -0800262 nextMir = SpecialIGet(cUnit, &bb, mir, kSignedHalf, false, false);
buzbeeefc63692012-11-14 16:31:52 -0800263 break;
264 case kIGetWide:
buzbee52a77fc2012-11-20 19:50:46 -0800265 nextMir = SpecialIGet(cUnit, &bb, mir, kLong, true, false);
buzbeeefc63692012-11-14 16:31:52 -0800266 break;
267 case kIPut:
buzbee52a77fc2012-11-20 19:50:46 -0800268 nextMir = SpecialIPut(cUnit, &bb, mir, kWord, false, false);
buzbeeefc63692012-11-14 16:31:52 -0800269 break;
270 case kIPutBoolean:
271 case kIPutByte:
buzbee52a77fc2012-11-20 19:50:46 -0800272 nextMir = SpecialIPut(cUnit, &bb, mir, kUnsignedByte, false, false);
buzbeeefc63692012-11-14 16:31:52 -0800273 break;
274 case kIPutObject:
buzbee52a77fc2012-11-20 19:50:46 -0800275 nextMir = SpecialIPut(cUnit, &bb, mir, kWord, false, true);
buzbeeefc63692012-11-14 16:31:52 -0800276 break;
277 case kIPutChar:
buzbee52a77fc2012-11-20 19:50:46 -0800278 nextMir = SpecialIPut(cUnit, &bb, mir, kUnsignedHalf, false, false);
buzbeeefc63692012-11-14 16:31:52 -0800279 break;
280 case kIPutShort:
buzbee52a77fc2012-11-20 19:50:46 -0800281 nextMir = SpecialIPut(cUnit, &bb, mir, kSignedHalf, false, false);
buzbeeefc63692012-11-14 16:31:52 -0800282 break;
283 case kIPutWide:
buzbee52a77fc2012-11-20 19:50:46 -0800284 nextMir = SpecialIPut(cUnit, &bb, mir, kLong, true, false);
buzbeeefc63692012-11-14 16:31:52 -0800285 break;
286 case kIdentity:
buzbee52a77fc2012-11-20 19:50:46 -0800287 nextMir = SpecialIdentity(cUnit, mir);
buzbeeefc63692012-11-14 16:31:52 -0800288 break;
289 default:
290 return;
291 }
292 if (nextMir != NULL) {
293 cUnit->currentDalvikOffset = nextMir->offset;
294 if (specialCase != kIdentity) {
buzbee52a77fc2012-11-20 19:50:46 -0800295 GenPrintLabel(cUnit, nextMir);
buzbeeefc63692012-11-14 16:31:52 -0800296 }
buzbee52a77fc2012-11-20 19:50:46 -0800297 NewLIR1(cUnit, kThumbBx, rARM_LR);
buzbeeefc63692012-11-14 16:31:52 -0800298 cUnit->coreSpillMask = 0;
299 cUnit->numCoreSpills = 0;
300 cUnit->fpSpillMask = 0;
301 cUnit->numFPSpills = 0;
302 cUnit->frameSize = 0;
303 cUnit->coreVmapTable.clear();
304 cUnit->fpVmapTable.clear();
305 }
306}
307
308/*
309 * The sparse table in the literal pool is an array of <key,displacement>
310 * pairs. For each set, we'll load them as a pair using ldmia.
311 * This means that the register number of the temp we use for the key
312 * must be lower than the reg for the displacement.
313 *
314 * The test loop will look something like:
315 *
316 * adr rBase, <table>
317 * ldr rVal, [rARM_SP, vRegOff]
318 * mov rIdx, #tableSize
319 * lp:
320 * ldmia rBase!, {rKey, rDisp}
321 * sub rIdx, #1
322 * cmp rVal, rKey
323 * ifeq
324 * add rARM_PC, rDisp ; This is the branch from which we compute displacement
325 * cbnz rIdx, lp
326 */
buzbee52a77fc2012-11-20 19:50:46 -0800327void GenSparseSwitch(CompilationUnit* cUnit, uint32_t tableOffset,
buzbeeefc63692012-11-14 16:31:52 -0800328 RegLocation rlSrc)
329{
buzbeeeaf09bc2012-11-15 14:51:41 -0800330 const uint16_t* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
buzbeeefc63692012-11-14 16:31:52 -0800331 if (cUnit->printMe) {
buzbee52a77fc2012-11-20 19:50:46 -0800332 DumpSparseSwitchTable(table);
buzbeeefc63692012-11-14 16:31:52 -0800333 }
334 // Add the table to the list - we'll process it later
buzbeecbd6d442012-11-17 14:11:25 -0800335 SwitchTable *tabRec =
buzbee52a77fc2012-11-20 19:50:46 -0800336 static_cast<SwitchTable*>(NewMem(cUnit, sizeof(SwitchTable), true, kAllocData));
buzbeeefc63692012-11-14 16:31:52 -0800337 tabRec->table = table;
338 tabRec->vaddr = cUnit->currentDalvikOffset;
339 int size = table[1];
buzbee52a77fc2012-11-20 19:50:46 -0800340 tabRec->targets = static_cast<LIR**>(NewMem(cUnit, size * sizeof(LIR*), true, kAllocLIR));
341 InsertGrowableList(cUnit, &cUnit->switchTables, reinterpret_cast<uintptr_t>(tabRec));
buzbeeefc63692012-11-14 16:31:52 -0800342
343 // Get the switch value
buzbee52a77fc2012-11-20 19:50:46 -0800344 rlSrc = LoadValue(cUnit, rlSrc, kCoreReg);
345 int rBase = AllocTemp(cUnit);
buzbeeefc63692012-11-14 16:31:52 -0800346 /* Allocate key and disp temps */
buzbee52a77fc2012-11-20 19:50:46 -0800347 int rKey = AllocTemp(cUnit);
348 int rDisp = AllocTemp(cUnit);
buzbeeefc63692012-11-14 16:31:52 -0800349 // Make sure rKey's register number is less than rDisp's number for ldmia
350 if (rKey > rDisp) {
351 int tmp = rDisp;
352 rDisp = rKey;
353 rKey = tmp;
354 }
355 // Materialize a pointer to the switch table
buzbee52a77fc2012-11-20 19:50:46 -0800356 NewLIR3(cUnit, kThumb2Adr, rBase, 0, reinterpret_cast<uintptr_t>(tabRec));
buzbeeefc63692012-11-14 16:31:52 -0800357 // Set up rIdx
buzbee52a77fc2012-11-20 19:50:46 -0800358 int rIdx = AllocTemp(cUnit);
359 LoadConstant(cUnit, rIdx, size);
buzbeeefc63692012-11-14 16:31:52 -0800360 // Establish loop branch target
buzbee52a77fc2012-11-20 19:50:46 -0800361 LIR* target = NewLIR0(cUnit, kPseudoTargetLabel);
buzbeeefc63692012-11-14 16:31:52 -0800362 // Load next key/disp
buzbee52a77fc2012-11-20 19:50:46 -0800363 NewLIR2(cUnit, kThumb2LdmiaWB, rBase, (1 << rKey) | (1 << rDisp));
364 OpRegReg(cUnit, kOpCmp, rKey, rlSrc.lowReg);
buzbeeefc63692012-11-14 16:31:52 -0800365 // Go if match. NOTE: No instruction set switch here - must stay Thumb2
buzbee52a77fc2012-11-20 19:50:46 -0800366 OpIT(cUnit, kArmCondEq, "");
367 LIR* switchBranch = NewLIR1(cUnit, kThumb2AddPCR, rDisp);
buzbeeefc63692012-11-14 16:31:52 -0800368 tabRec->anchor = switchBranch;
369 // Needs to use setflags encoding here
buzbee52a77fc2012-11-20 19:50:46 -0800370 NewLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
371 OpCondBranch(cUnit, kCondNe, target);
buzbeeefc63692012-11-14 16:31:52 -0800372}
373
374
buzbee52a77fc2012-11-20 19:50:46 -0800375void GenPackedSwitch(CompilationUnit* cUnit, uint32_t tableOffset,
buzbeeefc63692012-11-14 16:31:52 -0800376 RegLocation rlSrc)
377{
buzbeeeaf09bc2012-11-15 14:51:41 -0800378 const uint16_t* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
buzbeeefc63692012-11-14 16:31:52 -0800379 if (cUnit->printMe) {
buzbee52a77fc2012-11-20 19:50:46 -0800380 DumpPackedSwitchTable(table);
buzbeeefc63692012-11-14 16:31:52 -0800381 }
382 // Add the table to the list - we'll process it later
buzbeecbd6d442012-11-17 14:11:25 -0800383 SwitchTable *tabRec =
buzbee52a77fc2012-11-20 19:50:46 -0800384 static_cast<SwitchTable*>(NewMem(cUnit, sizeof(SwitchTable), true, kAllocData));
buzbeeefc63692012-11-14 16:31:52 -0800385 tabRec->table = table;
386 tabRec->vaddr = cUnit->currentDalvikOffset;
387 int size = table[1];
buzbee52a77fc2012-11-20 19:50:46 -0800388 tabRec->targets = static_cast<LIR**>(NewMem(cUnit, size * sizeof(LIR*), true, kAllocLIR));
389 InsertGrowableList(cUnit, &cUnit->switchTables, reinterpret_cast<uintptr_t>(tabRec));
buzbeeefc63692012-11-14 16:31:52 -0800390
391 // Get the switch value
buzbee52a77fc2012-11-20 19:50:46 -0800392 rlSrc = LoadValue(cUnit, rlSrc, kCoreReg);
393 int tableBase = AllocTemp(cUnit);
buzbeeefc63692012-11-14 16:31:52 -0800394 // Materialize a pointer to the switch table
buzbee52a77fc2012-11-20 19:50:46 -0800395 NewLIR3(cUnit, kThumb2Adr, tableBase, 0, reinterpret_cast<uintptr_t>(tabRec));
buzbeeefc63692012-11-14 16:31:52 -0800396 int lowKey = s4FromSwitchData(&table[2]);
397 int keyReg;
398 // Remove the bias, if necessary
399 if (lowKey == 0) {
400 keyReg = rlSrc.lowReg;
401 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800402 keyReg = AllocTemp(cUnit);
403 OpRegRegImm(cUnit, kOpSub, keyReg, rlSrc.lowReg, lowKey);
buzbeeefc63692012-11-14 16:31:52 -0800404 }
405 // Bounds check - if < 0 or >= size continue following switch
buzbee52a77fc2012-11-20 19:50:46 -0800406 OpRegImm(cUnit, kOpCmp, keyReg, size-1);
407 LIR* branchOver = OpCondBranch(cUnit, kCondHi, NULL);
buzbeeefc63692012-11-14 16:31:52 -0800408
409 // Load the displacement from the switch table
buzbee52a77fc2012-11-20 19:50:46 -0800410 int dispReg = AllocTemp(cUnit);
411 LoadBaseIndexed(cUnit, tableBase, keyReg, dispReg, 2, kWord);
buzbeeefc63692012-11-14 16:31:52 -0800412
413 // ..and go! NOTE: No instruction set switch here - must stay Thumb2
buzbee52a77fc2012-11-20 19:50:46 -0800414 LIR* switchBranch = NewLIR1(cUnit, kThumb2AddPCR, dispReg);
buzbeeefc63692012-11-14 16:31:52 -0800415 tabRec->anchor = switchBranch;
416
417 /* branchOver target here */
buzbee52a77fc2012-11-20 19:50:46 -0800418 LIR* target = NewLIR0(cUnit, kPseudoTargetLabel);
buzbeecbd6d442012-11-17 14:11:25 -0800419 branchOver->target = target;
buzbeeefc63692012-11-14 16:31:52 -0800420}
421
422/*
423 * Array data table format:
424 * ushort ident = 0x0300 magic value
425 * ushort width width of each element in the table
426 * uint size number of elements in the table
427 * ubyte data[size*width] table of data values (may contain a single-byte
428 * padding at the end)
429 *
430 * Total size is 4+(width * size + 1)/2 16-bit code units.
431 */
buzbee52a77fc2012-11-20 19:50:46 -0800432void GenFillArrayData(CompilationUnit* cUnit, uint32_t tableOffset, RegLocation rlSrc)
buzbeeefc63692012-11-14 16:31:52 -0800433{
buzbeeeaf09bc2012-11-15 14:51:41 -0800434 const uint16_t* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
buzbeeefc63692012-11-14 16:31:52 -0800435 // Add the table to the list - we'll process it later
buzbeecbd6d442012-11-17 14:11:25 -0800436 FillArrayData *tabRec =
buzbee52a77fc2012-11-20 19:50:46 -0800437 static_cast<FillArrayData*>(NewMem(cUnit, sizeof(FillArrayData), true, kAllocData));
buzbeeefc63692012-11-14 16:31:52 -0800438 tabRec->table = table;
439 tabRec->vaddr = cUnit->currentDalvikOffset;
buzbeeeaf09bc2012-11-15 14:51:41 -0800440 uint16_t width = tabRec->table[1];
441 uint32_t size = tabRec->table[2] | ((static_cast<uint32_t>(tabRec->table[3])) << 16);
buzbeeefc63692012-11-14 16:31:52 -0800442 tabRec->size = (size * width) + 8;
443
buzbee52a77fc2012-11-20 19:50:46 -0800444 InsertGrowableList(cUnit, &cUnit->fillArrayData, reinterpret_cast<uintptr_t>(tabRec));
buzbeeefc63692012-11-14 16:31:52 -0800445
446 // Making a call - use explicit registers
buzbee52a77fc2012-11-20 19:50:46 -0800447 FlushAllRegs(cUnit); /* Everything to home location */
448 LoadValueDirectFixed(cUnit, rlSrc, r0);
449 LoadWordDisp(cUnit, rARM_SELF, ENTRYPOINT_OFFSET(pHandleFillArrayDataFromCode),
buzbeeefc63692012-11-14 16:31:52 -0800450 rARM_LR);
451 // Materialize a pointer to the fill data image
buzbee52a77fc2012-11-20 19:50:46 -0800452 NewLIR3(cUnit, kThumb2Adr, r1, 0, reinterpret_cast<uintptr_t>(tabRec));
453 ClobberCalleeSave(cUnit);
454 LIR* callInst = OpReg(cUnit, kOpBlx, rARM_LR);
455 MarkSafepointPC(cUnit, callInst);
buzbeeefc63692012-11-14 16:31:52 -0800456}
457
458/*
459 * Handle simple case (thin lock) inline. If it's complicated, bail
460 * out to the heavyweight lock/unlock routines. We'll use dedicated
461 * registers here in order to be in the right position in case we
buzbeeeaf09bc2012-11-15 14:51:41 -0800462 * to bail to oat[Lock/Unlock]Object(self, object)
buzbeeefc63692012-11-14 16:31:52 -0800463 *
buzbeeeaf09bc2012-11-15 14:51:41 -0800464 * r0 -> self pointer [arg0 for oat[Lock/Unlock]Object
465 * r1 -> object [arg1 for oat[Lock/Unlock]Object
buzbeeefc63692012-11-14 16:31:52 -0800466 * r2 -> intial contents of object->lock, later result of strex
467 * r3 -> self->threadId
468 * r12 -> allow to be used by utilities as general temp
469 *
470 * The result of the strex is 0 if we acquire the lock.
471 *
472 * See comments in Sync.c for the layout of the lock word.
473 * Of particular interest to this code is the test for the
474 * simple case - which we handle inline. For monitor enter, the
475 * simple case is thin lock, held by no-one. For monitor exit,
476 * the simple case is thin lock, held by the unlocking thread with
477 * a recurse count of 0.
478 *
479 * A minor complication is that there is a field in the lock word
480 * unrelated to locking: the hash state. This field must be ignored, but
481 * preserved.
482 *
483 */
buzbee52a77fc2012-11-20 19:50:46 -0800484void GenMonitorEnter(CompilationUnit* cUnit, int optFlags, RegLocation rlSrc)
buzbeeefc63692012-11-14 16:31:52 -0800485{
buzbee52a77fc2012-11-20 19:50:46 -0800486 FlushAllRegs(cUnit);
buzbeeefc63692012-11-14 16:31:52 -0800487 DCHECK_EQ(LW_SHAPE_THIN, 0);
buzbee52a77fc2012-11-20 19:50:46 -0800488 LoadValueDirectFixed(cUnit, rlSrc, r0); // Get obj
489 LockCallTemps(cUnit); // Prepare for explicit register usage
490 GenNullCheck(cUnit, rlSrc.sRegLow, r0, optFlags);
491 LoadWordDisp(cUnit, rARM_SELF, Thread::ThinLockIdOffset().Int32Value(), r2);
492 NewLIR3(cUnit, kThumb2Ldrex, r1, r0,
buzbeeefc63692012-11-14 16:31:52 -0800493 Object::MonitorOffset().Int32Value() >> 2); // Get object->lock
494 // Align owner
buzbee52a77fc2012-11-20 19:50:46 -0800495 OpRegImm(cUnit, kOpLsl, r2, LW_LOCK_OWNER_SHIFT);
buzbeeefc63692012-11-14 16:31:52 -0800496 // Is lock unheld on lock or held by us (==threadId) on unlock?
buzbee52a77fc2012-11-20 19:50:46 -0800497 NewLIR4(cUnit, kThumb2Bfi, r2, r1, 0, LW_LOCK_OWNER_SHIFT - 1);
498 NewLIR3(cUnit, kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
499 OpRegImm(cUnit, kOpCmp, r1, 0);
500 OpIT(cUnit, kArmCondEq, "");
501 NewLIR4(cUnit, kThumb2Strex, r1, r2, r0,
buzbeeefc63692012-11-14 16:31:52 -0800502 Object::MonitorOffset().Int32Value() >> 2);
buzbee52a77fc2012-11-20 19:50:46 -0800503 OpRegImm(cUnit, kOpCmp, r1, 0);
504 OpIT(cUnit, kArmCondNe, "T");
buzbeeefc63692012-11-14 16:31:52 -0800505 // Go expensive route - artLockObjectFromCode(self, obj);
buzbee52a77fc2012-11-20 19:50:46 -0800506 LoadWordDisp(cUnit, rARM_SELF, ENTRYPOINT_OFFSET(pLockObjectFromCode), rARM_LR);
507 ClobberCalleeSave(cUnit);
508 LIR* callInst = OpReg(cUnit, kOpBlx, rARM_LR);
509 MarkSafepointPC(cUnit, callInst);
510 GenMemBarrier(cUnit, kLoadLoad);
buzbeeefc63692012-11-14 16:31:52 -0800511}
512
513/*
514 * For monitor unlock, we don't have to use ldrex/strex. Once
515 * we've determined that the lock is thin and that we own it with
516 * a zero recursion count, it's safe to punch it back to the
517 * initial, unlock thin state with a store word.
518 */
buzbee52a77fc2012-11-20 19:50:46 -0800519void GenMonitorExit(CompilationUnit* cUnit, int optFlags, RegLocation rlSrc)
buzbeeefc63692012-11-14 16:31:52 -0800520{
521 DCHECK_EQ(LW_SHAPE_THIN, 0);
buzbee52a77fc2012-11-20 19:50:46 -0800522 FlushAllRegs(cUnit);
523 LoadValueDirectFixed(cUnit, rlSrc, r0); // Get obj
524 LockCallTemps(cUnit); // Prepare for explicit register usage
525 GenNullCheck(cUnit, rlSrc.sRegLow, r0, optFlags);
526 LoadWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r1); // Get lock
527 LoadWordDisp(cUnit, rARM_SELF, Thread::ThinLockIdOffset().Int32Value(), r2);
buzbeeefc63692012-11-14 16:31:52 -0800528 // Is lock unheld on lock or held by us (==threadId) on unlock?
buzbee52a77fc2012-11-20 19:50:46 -0800529 OpRegRegImm(cUnit, kOpAnd, r3, r1,
buzbeeefc63692012-11-14 16:31:52 -0800530 (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
531 // Align owner
buzbee52a77fc2012-11-20 19:50:46 -0800532 OpRegImm(cUnit, kOpLsl, r2, LW_LOCK_OWNER_SHIFT);
533 NewLIR3(cUnit, kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
534 OpRegReg(cUnit, kOpSub, r1, r2);
535 OpIT(cUnit, kArmCondEq, "EE");
536 StoreWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r3);
buzbeeefc63692012-11-14 16:31:52 -0800537 // Go expensive route - UnlockObjectFromCode(obj);
buzbee52a77fc2012-11-20 19:50:46 -0800538 LoadWordDisp(cUnit, rARM_SELF, ENTRYPOINT_OFFSET(pUnlockObjectFromCode), rARM_LR);
539 ClobberCalleeSave(cUnit);
540 LIR* callInst = OpReg(cUnit, kOpBlx, rARM_LR);
541 MarkSafepointPC(cUnit, callInst);
542 GenMemBarrier(cUnit, kStoreLoad);
buzbeeefc63692012-11-14 16:31:52 -0800543}
544
545/*
546 * Mark garbage collection card. Skip if the value we're storing is null.
547 */
buzbee52a77fc2012-11-20 19:50:46 -0800548void MarkGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg)
buzbeeefc63692012-11-14 16:31:52 -0800549{
buzbee52a77fc2012-11-20 19:50:46 -0800550 int regCardBase = AllocTemp(cUnit);
551 int regCardNo = AllocTemp(cUnit);
552 LIR* branchOver = OpCmpImmBranch(cUnit, kCondEq, valReg, 0, NULL);
553 LoadWordDisp(cUnit, rARM_SELF, Thread::CardTableOffset().Int32Value(), regCardBase);
554 OpRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, CardTable::kCardShift);
555 StoreBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
buzbeeefc63692012-11-14 16:31:52 -0800556 kUnsignedByte);
buzbee52a77fc2012-11-20 19:50:46 -0800557 LIR* target = NewLIR0(cUnit, kPseudoTargetLabel);
buzbeecbd6d442012-11-17 14:11:25 -0800558 branchOver->target = target;
buzbee52a77fc2012-11-20 19:50:46 -0800559 FreeTemp(cUnit, regCardBase);
560 FreeTemp(cUnit, regCardNo);
buzbeeefc63692012-11-14 16:31:52 -0800561}
562
buzbee52a77fc2012-11-20 19:50:46 -0800563void GenEntrySequence(CompilationUnit* cUnit, RegLocation* ArgLocs,
buzbeeefc63692012-11-14 16:31:52 -0800564 RegLocation rlMethod)
565{
566 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
567 /*
568 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
569 * mechanism know so it doesn't try to use any of them when
570 * expanding the frame or flushing. This leaves the utility
571 * code with a single temp: r12. This should be enough.
572 */
buzbee52a77fc2012-11-20 19:50:46 -0800573 LockTemp(cUnit, r0);
574 LockTemp(cUnit, r1);
575 LockTemp(cUnit, r2);
576 LockTemp(cUnit, r3);
buzbeeefc63692012-11-14 16:31:52 -0800577
578 /*
579 * We can safely skip the stack overflow check if we're
580 * a leaf *and* our frame size < fudge factor.
581 */
582 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
buzbeecbd6d442012-11-17 14:11:25 -0800583 (static_cast<size_t>(cUnit->frameSize) <
buzbeeefc63692012-11-14 16:31:52 -0800584 Thread::kStackOverflowReservedBytes));
buzbee52a77fc2012-11-20 19:50:46 -0800585 NewLIR0(cUnit, kPseudoMethodEntry);
buzbeeefc63692012-11-14 16:31:52 -0800586 if (!skipOverflowCheck) {
587 /* Load stack limit */
buzbee52a77fc2012-11-20 19:50:46 -0800588 LoadWordDisp(cUnit, rARM_SELF, Thread::StackEndOffset().Int32Value(), r12);
buzbeeefc63692012-11-14 16:31:52 -0800589 }
590 /* Spill core callee saves */
buzbee52a77fc2012-11-20 19:50:46 -0800591 NewLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
buzbeeefc63692012-11-14 16:31:52 -0800592 /* Need to spill any FP regs? */
593 if (cUnit->numFPSpills) {
594 /*
595 * NOTE: fp spills are a little different from core spills in that
596 * they are pushed as a contiguous block. When promoting from
597 * the fp set, we must allocate all singles from s16..highest-promoted
598 */
buzbee52a77fc2012-11-20 19:50:46 -0800599 NewLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
buzbeeefc63692012-11-14 16:31:52 -0800600 }
601 if (!skipOverflowCheck) {
buzbee52a77fc2012-11-20 19:50:46 -0800602 OpRegRegImm(cUnit, kOpSub, rARM_LR, rARM_SP, cUnit->frameSize - (spillCount * 4));
603 GenRegRegCheck(cUnit, kCondCc, rARM_LR, r12, kThrowStackOverflow);
604 OpRegCopy(cUnit, rARM_SP, rARM_LR); // Establish stack
buzbeeefc63692012-11-14 16:31:52 -0800605 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800606 OpRegImm(cUnit, kOpSub, rARM_SP, cUnit->frameSize - (spillCount * 4));
buzbeeefc63692012-11-14 16:31:52 -0800607 }
608
buzbee52a77fc2012-11-20 19:50:46 -0800609 FlushIns(cUnit, ArgLocs, rlMethod);
buzbeeefc63692012-11-14 16:31:52 -0800610
buzbee52a77fc2012-11-20 19:50:46 -0800611 FreeTemp(cUnit, r0);
612 FreeTemp(cUnit, r1);
613 FreeTemp(cUnit, r2);
614 FreeTemp(cUnit, r3);
buzbeeefc63692012-11-14 16:31:52 -0800615}
616
buzbee52a77fc2012-11-20 19:50:46 -0800617void GenExitSequence(CompilationUnit* cUnit)
buzbeeefc63692012-11-14 16:31:52 -0800618{
619 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
620 /*
621 * In the exit path, r0/r1 are live - make sure they aren't
622 * allocated by the register utilities as temps.
623 */
buzbee52a77fc2012-11-20 19:50:46 -0800624 LockTemp(cUnit, r0);
625 LockTemp(cUnit, r1);
buzbeeefc63692012-11-14 16:31:52 -0800626
buzbee52a77fc2012-11-20 19:50:46 -0800627 NewLIR0(cUnit, kPseudoMethodExit);
628 OpRegImm(cUnit, kOpAdd, rARM_SP, cUnit->frameSize - (spillCount * 4));
buzbeeefc63692012-11-14 16:31:52 -0800629 /* Need to restore any FP callee saves? */
630 if (cUnit->numFPSpills) {
buzbee52a77fc2012-11-20 19:50:46 -0800631 NewLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
buzbeeefc63692012-11-14 16:31:52 -0800632 }
633 if (cUnit->coreSpillMask & (1 << rARM_LR)) {
634 /* Unspill rARM_LR to rARM_PC */
635 cUnit->coreSpillMask &= ~(1 << rARM_LR);
636 cUnit->coreSpillMask |= (1 << rARM_PC);
637 }
buzbee52a77fc2012-11-20 19:50:46 -0800638 NewLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
buzbeeefc63692012-11-14 16:31:52 -0800639 if (!(cUnit->coreSpillMask & (1 << rARM_PC))) {
640 /* We didn't pop to rARM_PC, so must do a bv rARM_LR */
buzbee52a77fc2012-11-20 19:50:46 -0800641 NewLIR1(cUnit, kThumbBx, rARM_LR);
buzbeeefc63692012-11-14 16:31:52 -0800642 }
643}
644
645} // namespace art