blob: 0a8e57947752837e7f6daad6548d4ec72db07769 [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
buzbeeb046e162012-10-30 15:48:42 -070017/* This file contains codegen for the Thumb2 ISA. */
buzbee67bf8852011-08-17 17:51:35 -070018
Logan Chien4dd96f52012-02-29 01:26:58 +080019#include "oat_compilation_unit.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070020#include "oat/runtime/oat_support_entrypoints.h"
Logan Chien4dd96f52012-02-29 01:26:58 +080021
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080022namespace art {
23
buzbeee62076c2012-03-21 14:26:16 -070024
25/* Return the position of an ssa name within the argument list */
26int inPosition(CompilationUnit* cUnit, int sReg)
buzbee16da88c2012-03-20 10:38:17 -070027{
Bill Buzbeea114add2012-05-03 15:00:40 -070028 int vReg = SRegToVReg(cUnit, sReg);
29 return vReg - cUnit->numRegs;
buzbeee62076c2012-03-21 14:26:16 -070030}
31
32/*
33 * Describe an argument. If it's already in an arg register, just leave it
34 * there. NOTE: all live arg registers must be locked prior to this call
35 * to avoid having them allocated as a temp by downstream utilities.
36 */
37RegLocation argLoc(CompilationUnit* cUnit, RegLocation loc)
38{
Bill Buzbeea114add2012-05-03 15:00:40 -070039 int argNum = inPosition(cUnit, loc.sRegLow);
40 if (loc.wide) {
41 if (argNum == 2) {
42 // Bad case - half in register, half in frame. Just punt
43 loc.location = kLocInvalid;
44 } else if (argNum < 2) {
buzbeef0504cd2012-11-13 16:31:10 -080045 loc.lowReg = rARM_ARG1 + argNum;
Bill Buzbeea114add2012-05-03 15:00:40 -070046 loc.highReg = loc.lowReg + 1;
47 loc.location = kLocPhysReg;
buzbee16da88c2012-03-20 10:38:17 -070048 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -070049 loc.location = kLocDalvikFrame;
buzbee16da88c2012-03-20 10:38:17 -070050 }
Bill Buzbeea114add2012-05-03 15:00:40 -070051 } else {
52 if (argNum < 3) {
buzbeef0504cd2012-11-13 16:31:10 -080053 loc.lowReg = rARM_ARG1 + argNum;
Bill Buzbeea114add2012-05-03 15:00:40 -070054 loc.location = kLocPhysReg;
55 } else {
56 loc.location = kLocDalvikFrame;
57 }
58 }
59 return loc;
buzbee16da88c2012-03-20 10:38:17 -070060}
61
buzbeee62076c2012-03-21 14:26:16 -070062/*
63 * Load an argument. If already in a register, just return. If in
64 * the frame, we can't use the normal loadValue() because it assumed
65 * a proper frame - and we're frameless.
66 */
67RegLocation loadArg(CompilationUnit* cUnit, RegLocation loc)
68{
Bill Buzbeea114add2012-05-03 15:00:40 -070069 if (loc.location == kLocDalvikFrame) {
70 int start = (inPosition(cUnit, loc.sRegLow) + 1) * sizeof(uint32_t);
71 loc.lowReg = oatAllocTemp(cUnit);
buzbeef0504cd2012-11-13 16:31:10 -080072 loadWordDisp(cUnit, rARM_SP, start, loc.lowReg);
Bill Buzbeea114add2012-05-03 15:00:40 -070073 if (loc.wide) {
74 loc.highReg = oatAllocTemp(cUnit);
buzbeef0504cd2012-11-13 16:31:10 -080075 loadWordDisp(cUnit, rARM_SP, start + sizeof(uint32_t), loc.highReg);
buzbeee62076c2012-03-21 14:26:16 -070076 }
Bill Buzbeea114add2012-05-03 15:00:40 -070077 loc.location = kLocPhysReg;
78 }
79 return loc;
buzbeee62076c2012-03-21 14:26:16 -070080}
81
82/* Lock any referenced arguments that arrive in registers */
83void lockLiveArgs(CompilationUnit* cUnit, MIR* mir)
84{
Bill Buzbeea114add2012-05-03 15:00:40 -070085 int firstIn = cUnit->numRegs;
86 const int numArgRegs = 3; // TODO: generalize & move to RegUtil.cc
87 for (int i = 0; i < mir->ssaRep->numUses; i++) {
88 int vReg = SRegToVReg(cUnit, mir->ssaRep->uses[i]);
89 int inPosition = vReg - firstIn;
90 if (inPosition < numArgRegs) {
buzbeef0504cd2012-11-13 16:31:10 -080091 oatLockTemp(cUnit, rARM_ARG1 + inPosition);
buzbeee62076c2012-03-21 14:26:16 -070092 }
Bill Buzbeea114add2012-05-03 15:00:40 -070093 }
buzbeee62076c2012-03-21 14:26:16 -070094}
95
buzbee16da88c2012-03-20 10:38:17 -070096/* Find the next MIR, which may be in a following basic block */
97MIR* getNextMir(CompilationUnit* cUnit, BasicBlock** pBb, MIR* mir)
98{
Bill Buzbeea114add2012-05-03 15:00:40 -070099 BasicBlock* bb = *pBb;
100 MIR* origMir = mir;
101 while (bb != NULL) {
102 if (mir != NULL) {
103 mir = mir->next;
buzbee16da88c2012-03-20 10:38:17 -0700104 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700105 if (mir != NULL) {
106 return mir;
107 } else {
108 bb = bb->fallThrough;
109 *pBb = bb;
110 if (bb) {
111 mir = bb->firstMIRInsn;
112 if (mir != NULL) {
113 return mir;
114 }
115 }
116 }
117 }
118 return origMir;
buzbee16da88c2012-03-20 10:38:17 -0700119}
120
121/* Used for the "printMe" listing */
122void genPrintLabel(CompilationUnit *cUnit, MIR* mir)
123{
Bill Buzbeea114add2012-05-03 15:00:40 -0700124 /* Mark the beginning of a Dalvik instruction for line tracking */
125 char* instStr = cUnit->printMe ?
126 oatGetDalvikDisassembly(cUnit, mir->dalvikInsn, "") : NULL;
buzbeed1643e42012-09-05 14:06:51 -0700127 markBoundary(cUnit, mir->offset, instStr);
Bill Buzbeea114add2012-05-03 15:00:40 -0700128 /* Don't generate the SSA annotation unless verbose mode is on */
129 if (cUnit->printMe && mir->ssaRep) {
130 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
131 newLIR1(cUnit, kPseudoSSARep, (int) ssaString);
132 }
buzbee16da88c2012-03-20 10:38:17 -0700133}
134
135MIR* specialIGet(CompilationUnit* cUnit, BasicBlock** bb, MIR* mir,
136 OpSize size, bool longOrDouble, bool isObject)
137{
Bill Buzbeea114add2012-05-03 15:00:40 -0700138 int fieldOffset;
139 bool isVolatile;
140 uint32_t fieldIdx = mir->dalvikInsn.vC;
141 bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile, false);
142 if (!fastPath || !(mir->optimizationFlags & MIR_IGNORE_NULL_CHECK)) {
143 return NULL;
144 }
145 RegLocation rlObj = oatGetSrc(cUnit, mir, 0);
146 lockLiveArgs(cUnit, mir);
147 rlObj = argLoc(cUnit, rlObj);
148 RegLocation rlDest;
149 if (longOrDouble) {
150 rlDest = oatGetReturnWide(cUnit, false);
151 } else {
152 rlDest = oatGetReturn(cUnit, false);
153 }
154 // Point of no return - no aborts after this
155 genPrintLabel(cUnit, mir);
156 rlObj = loadArg(cUnit, rlObj);
buzbee408ad162012-06-06 16:45:18 -0700157 genIGet(cUnit, fieldIdx, mir->optimizationFlags, size, rlDest, rlObj,
158 longOrDouble, isObject);
Bill Buzbeea114add2012-05-03 15:00:40 -0700159 return getNextMir(cUnit, bb, mir);
buzbee16da88c2012-03-20 10:38:17 -0700160}
161
162MIR* specialIPut(CompilationUnit* cUnit, BasicBlock** bb, MIR* mir,
163 OpSize size, bool longOrDouble, bool isObject)
164{
Bill Buzbeea114add2012-05-03 15:00:40 -0700165 int fieldOffset;
166 bool isVolatile;
167 uint32_t fieldIdx = mir->dalvikInsn.vC;
168 bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile, false);
169 if (!fastPath || !(mir->optimizationFlags & MIR_IGNORE_NULL_CHECK)) {
170 return NULL;
171 }
172 RegLocation rlSrc;
173 RegLocation rlObj;
174 lockLiveArgs(cUnit, mir);
175 if (longOrDouble) {
buzbee15bf9802012-06-12 17:49:27 -0700176 rlSrc = oatGetSrcWide(cUnit, mir, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700177 rlObj = oatGetSrc(cUnit, mir, 2);
178 } else {
179 rlSrc = oatGetSrc(cUnit, mir, 0);
180 rlObj = oatGetSrc(cUnit, mir, 1);
181 }
182 rlSrc = argLoc(cUnit, rlSrc);
183 rlObj = argLoc(cUnit, rlObj);
184 // Reject if source is split across registers & frame
185 if (rlObj.location == kLocInvalid) {
186 oatResetRegPool(cUnit);
187 return NULL;
188 }
189 // Point of no return - no aborts after this
190 genPrintLabel(cUnit, mir);
191 rlObj = loadArg(cUnit, rlObj);
192 rlSrc = loadArg(cUnit, rlSrc);
buzbee408ad162012-06-06 16:45:18 -0700193 genIPut(cUnit, fieldIdx, mir->optimizationFlags, size, rlSrc, rlObj,
194 longOrDouble, isObject);
Bill Buzbeea114add2012-05-03 15:00:40 -0700195 return getNextMir(cUnit, bb, mir);
buzbee16da88c2012-03-20 10:38:17 -0700196}
197
buzbeee62076c2012-03-21 14:26:16 -0700198MIR* specialIdentity(CompilationUnit* cUnit, MIR* mir)
199{
Bill Buzbeea114add2012-05-03 15:00:40 -0700200 RegLocation rlSrc;
201 RegLocation rlDest;
202 bool wide = (mir->ssaRep->numUses == 2);
203 if (wide) {
buzbee15bf9802012-06-12 17:49:27 -0700204 rlSrc = oatGetSrcWide(cUnit, mir, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700205 rlDest = oatGetReturnWide(cUnit, false);
206 } else {
207 rlSrc = oatGetSrc(cUnit, mir, 0);
208 rlDest = oatGetReturn(cUnit, false);
209 }
210 lockLiveArgs(cUnit, mir);
211 rlSrc = argLoc(cUnit, rlSrc);
212 if (rlSrc.location == kLocInvalid) {
213 oatResetRegPool(cUnit);
214 return NULL;
215 }
216 // Point of no return - no aborts after this
217 genPrintLabel(cUnit, mir);
218 rlSrc = loadArg(cUnit, rlSrc);
219 if (wide) {
220 storeValueWide(cUnit, rlDest, rlSrc);
221 } else {
222 storeValue(cUnit, rlDest, rlSrc);
223 }
224 return mir;
buzbeee62076c2012-03-21 14:26:16 -0700225}
226
buzbee16da88c2012-03-20 10:38:17 -0700227/*
228 * Special-case code genration for simple non-throwing leaf methods.
229 */
230void genSpecialCase(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
Bill Buzbeea114add2012-05-03 15:00:40 -0700231 SpecialCaseHandler specialCase)
buzbee16da88c2012-03-20 10:38:17 -0700232{
233 cUnit->currentDalvikOffset = mir->offset;
234 MIR* nextMir = NULL;
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700235 switch (specialCase) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700236 case kNullMethod:
237 DCHECK(mir->dalvikInsn.opcode == Instruction::RETURN_VOID);
238 nextMir = mir;
239 break;
240 case kConstFunction:
241 genPrintLabel(cUnit, mir);
buzbeef0504cd2012-11-13 16:31:10 -0800242 loadConstant(cUnit, rARM_RET0, mir->dalvikInsn.vB);
Bill Buzbeea114add2012-05-03 15:00:40 -0700243 nextMir = getNextMir(cUnit, &bb, mir);
244 break;
245 case kIGet:
246 nextMir = specialIGet(cUnit, &bb, mir, kWord, false, false);
247 break;
248 case kIGetBoolean:
249 case kIGetByte:
250 nextMir = specialIGet(cUnit, &bb, mir, kUnsignedByte, false, false);
251 break;
252 case kIGetObject:
253 nextMir = specialIGet(cUnit, &bb, mir, kWord, false, true);
254 break;
255 case kIGetChar:
256 nextMir = specialIGet(cUnit, &bb, mir, kUnsignedHalf, false, false);
257 break;
258 case kIGetShort:
259 nextMir = specialIGet(cUnit, &bb, mir, kSignedHalf, false, false);
260 break;
261 case kIGetWide:
262 nextMir = specialIGet(cUnit, &bb, mir, kLong, true, false);
263 break;
264 case kIPut:
265 nextMir = specialIPut(cUnit, &bb, mir, kWord, false, false);
266 break;
267 case kIPutBoolean:
268 case kIPutByte:
269 nextMir = specialIPut(cUnit, &bb, mir, kUnsignedByte, false, false);
270 break;
271 case kIPutObject:
272 nextMir = specialIPut(cUnit, &bb, mir, kWord, false, true);
273 break;
274 case kIPutChar:
275 nextMir = specialIPut(cUnit, &bb, mir, kUnsignedHalf, false, false);
276 break;
277 case kIPutShort:
278 nextMir = specialIPut(cUnit, &bb, mir, kSignedHalf, false, false);
279 break;
280 case kIPutWide:
281 nextMir = specialIPut(cUnit, &bb, mir, kLong, true, false);
282 break;
283 case kIdentity:
284 nextMir = specialIdentity(cUnit, mir);
285 break;
286 default:
287 return;
buzbee16da88c2012-03-20 10:38:17 -0700288 }
289 if (nextMir != NULL) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700290 cUnit->currentDalvikOffset = nextMir->offset;
291 if (specialCase != kIdentity) {
292 genPrintLabel(cUnit, nextMir);
buzbee16da88c2012-03-20 10:38:17 -0700293 }
buzbeef0504cd2012-11-13 16:31:10 -0800294 newLIR1(cUnit, kThumbBx, rARM_LR);
Bill Buzbeea114add2012-05-03 15:00:40 -0700295 cUnit->coreSpillMask = 0;
296 cUnit->numCoreSpills = 0;
297 cUnit->fpSpillMask = 0;
298 cUnit->numFPSpills = 0;
299 cUnit->frameSize = 0;
300 cUnit->coreVmapTable.clear();
301 cUnit->fpVmapTable.clear();
302 }
buzbee16da88c2012-03-20 10:38:17 -0700303}
buzbee67bf8852011-08-17 17:51:35 -0700304
buzbeeb046e162012-10-30 15:48:42 -0700305LIR* opCmpBranch(CompilationUnit* cUnit, ConditionCode cond, int src1,
306 int src2, LIR* target)
307{
308 opRegReg(cUnit, kOpCmp, src1, src2);
309 return opCondBranch(cUnit, cond, target);
310}
311
buzbee67bf8852011-08-17 17:51:35 -0700312/*
313 * Generate a Thumb2 IT instruction, which can nullify up to
314 * four subsequent instructions based on a condition and its
315 * inverse. The condition applies to the first instruction, which
316 * is executed if the condition is met. The string "guide" consists
317 * of 0 to 3 chars, and applies to the 2nd through 4th instruction.
318 * A "T" means the instruction is executed if the condition is
319 * met, and an "E" means the instruction is executed if the condition
320 * is not met.
321 */
buzbee82488f52012-03-02 08:20:26 -0800322LIR* opIT(CompilationUnit* cUnit, ArmConditionCode code, const char* guide)
buzbee67bf8852011-08-17 17:51:35 -0700323{
Bill Buzbeea114add2012-05-03 15:00:40 -0700324 int mask;
325 int condBit = code & 1;
326 int altBit = condBit ^ 1;
327 int mask3 = 0;
328 int mask2 = 0;
329 int mask1 = 0;
buzbee67bf8852011-08-17 17:51:35 -0700330
Bill Buzbeea114add2012-05-03 15:00:40 -0700331 //Note: case fallthroughs intentional
332 switch (strlen(guide)) {
333 case 3:
334 mask1 = (guide[2] == 'T') ? condBit : altBit;
335 case 2:
336 mask2 = (guide[1] == 'T') ? condBit : altBit;
337 case 1:
338 mask3 = (guide[0] == 'T') ? condBit : altBit;
339 break;
340 case 0:
341 break;
342 default:
343 LOG(FATAL) << "OAT: bad case in opIT";
344 }
345 mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
346 (1 << (3 - strlen(guide)));
347 return newLIR2(cUnit, kThumb2It, code, mask);
buzbee67bf8852011-08-17 17:51:35 -0700348}
349
350/*
buzbee67bf8852011-08-17 17:51:35 -0700351 * The sparse table in the literal pool is an array of <key,displacement>
352 * pairs. For each set, we'll load them as a pair using ldmia.
353 * This means that the register number of the temp we use for the key
354 * must be lower than the reg for the displacement.
355 *
356 * The test loop will look something like:
357 *
358 * adr rBase, <table>
buzbeef0504cd2012-11-13 16:31:10 -0800359 * ldr rVal, [rARM_SP, vRegOff]
buzbee67bf8852011-08-17 17:51:35 -0700360 * mov rIdx, #tableSize
361 * lp:
362 * ldmia rBase!, {rKey, rDisp}
363 * sub rIdx, #1
364 * cmp rVal, rKey
365 * ifeq
buzbeef0504cd2012-11-13 16:31:10 -0800366 * add rARM_PC, rDisp ; This is the branch from which we compute displacement
buzbee67bf8852011-08-17 17:51:35 -0700367 * cbnz rIdx, lp
368 */
buzbee408ad162012-06-06 16:45:18 -0700369void genSparseSwitch(CompilationUnit* cUnit, uint32_t tableOffset,
buzbeea1da8a52012-07-09 14:00:21 -0700370 RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700371{
buzbee408ad162012-06-06 16:45:18 -0700372 const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700373 if (cUnit->printMe) {
374 dumpSparseSwitchTable(table);
375 }
376 // Add the table to the list - we'll process it later
377 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
378 true, kAllocData);
379 tabRec->table = table;
buzbee408ad162012-06-06 16:45:18 -0700380 tabRec->vaddr = cUnit->currentDalvikOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700381 int size = table[1];
382 tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true, kAllocLIR);
383 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700384
Bill Buzbeea114add2012-05-03 15:00:40 -0700385 // Get the switch value
386 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
387 int rBase = oatAllocTemp(cUnit);
388 /* Allocate key and disp temps */
389 int rKey = oatAllocTemp(cUnit);
390 int rDisp = oatAllocTemp(cUnit);
391 // Make sure rKey's register number is less than rDisp's number for ldmia
392 if (rKey > rDisp) {
393 int tmp = rDisp;
394 rDisp = rKey;
395 rKey = tmp;
396 }
397 // Materialize a pointer to the switch table
398 newLIR3(cUnit, kThumb2Adr, rBase, 0, (intptr_t)tabRec);
399 // Set up rIdx
400 int rIdx = oatAllocTemp(cUnit);
401 loadConstant(cUnit, rIdx, size);
402 // Establish loop branch target
403 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
404 // Load next key/disp
405 newLIR2(cUnit, kThumb2LdmiaWB, rBase, (1 << rKey) | (1 << rDisp));
406 opRegReg(cUnit, kOpCmp, rKey, rlSrc.lowReg);
407 // Go if match. NOTE: No instruction set switch here - must stay Thumb2
408 opIT(cUnit, kArmCondEq, "");
409 LIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, rDisp);
410 tabRec->anchor = switchBranch;
411 // Needs to use setflags encoding here
412 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
413 opCondBranch(cUnit, kCondNe, target);
buzbee67bf8852011-08-17 17:51:35 -0700414}
415
416
buzbee408ad162012-06-06 16:45:18 -0700417void genPackedSwitch(CompilationUnit* cUnit, uint32_t tableOffset,
418 RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700419{
buzbee408ad162012-06-06 16:45:18 -0700420 const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700421 if (cUnit->printMe) {
422 dumpPackedSwitchTable(table);
423 }
424 // Add the table to the list - we'll process it later
425 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
426 true, kAllocData);
427 tabRec->table = table;
buzbee408ad162012-06-06 16:45:18 -0700428 tabRec->vaddr = cUnit->currentDalvikOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700429 int size = table[1];
430 tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true, kAllocLIR);
431 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700432
Bill Buzbeea114add2012-05-03 15:00:40 -0700433 // Get the switch value
434 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
435 int tableBase = oatAllocTemp(cUnit);
436 // Materialize a pointer to the switch table
437 newLIR3(cUnit, kThumb2Adr, tableBase, 0, (intptr_t)tabRec);
438 int lowKey = s4FromSwitchData(&table[2]);
439 int keyReg;
440 // Remove the bias, if necessary
441 if (lowKey == 0) {
442 keyReg = rlSrc.lowReg;
443 } else {
444 keyReg = oatAllocTemp(cUnit);
445 opRegRegImm(cUnit, kOpSub, keyReg, rlSrc.lowReg, lowKey);
446 }
447 // Bounds check - if < 0 or >= size continue following switch
448 opRegImm(cUnit, kOpCmp, keyReg, size-1);
449 LIR* branchOver = opCondBranch(cUnit, kCondHi, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700450
Bill Buzbeea114add2012-05-03 15:00:40 -0700451 // Load the displacement from the switch table
452 int dispReg = oatAllocTemp(cUnit);
453 loadBaseIndexed(cUnit, tableBase, keyReg, dispReg, 2, kWord);
buzbee67bf8852011-08-17 17:51:35 -0700454
Bill Buzbeea114add2012-05-03 15:00:40 -0700455 // ..and go! NOTE: No instruction set switch here - must stay Thumb2
456 LIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, dispReg);
457 tabRec->anchor = switchBranch;
buzbee67bf8852011-08-17 17:51:35 -0700458
Bill Buzbeea114add2012-05-03 15:00:40 -0700459 /* branchOver target here */
460 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
461 branchOver->target = (LIR*)target;
buzbee67bf8852011-08-17 17:51:35 -0700462}
463
464/*
465 * Array data table format:
466 * ushort ident = 0x0300 magic value
467 * ushort width width of each element in the table
468 * uint size number of elements in the table
469 * ubyte data[size*width] table of data values (may contain a single-byte
470 * padding at the end)
471 *
472 * Total size is 4+(width * size + 1)/2 16-bit code units.
473 */
buzbee408ad162012-06-06 16:45:18 -0700474void genFillArrayData(CompilationUnit* cUnit, uint32_t tableOffset, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700475{
buzbee408ad162012-06-06 16:45:18 -0700476 const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700477 // Add the table to the list - we'll process it later
478 FillArrayData *tabRec = (FillArrayData *)
479 oatNew(cUnit, sizeof(FillArrayData), true, kAllocData);
480 tabRec->table = table;
buzbee408ad162012-06-06 16:45:18 -0700481 tabRec->vaddr = cUnit->currentDalvikOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700482 u2 width = tabRec->table[1];
483 u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
484 tabRec->size = (size * width) + 8;
buzbee67bf8852011-08-17 17:51:35 -0700485
Bill Buzbeea114add2012-05-03 15:00:40 -0700486 oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700487
Bill Buzbeea114add2012-05-03 15:00:40 -0700488 // Making a call - use explicit registers
489 oatFlushAllRegs(cUnit); /* Everything to home location */
490 loadValueDirectFixed(cUnit, rlSrc, r0);
buzbeef0504cd2012-11-13 16:31:10 -0800491 loadWordDisp(cUnit, rARM_SELF, ENTRYPOINT_OFFSET(pHandleFillArrayDataFromCode),
492 rARM_LR);
Bill Buzbeea114add2012-05-03 15:00:40 -0700493 // Materialize a pointer to the fill data image
494 newLIR3(cUnit, kThumb2Adr, r1, 0, (intptr_t)tabRec);
495 oatClobberCalleeSave(cUnit);
buzbeef0504cd2012-11-13 16:31:10 -0800496 LIR* callInst = opReg(cUnit, kOpBlx, rARM_LR);
buzbee8320f382012-09-11 16:29:42 -0700497 markSafepointPC(cUnit, callInst);
buzbee67bf8852011-08-17 17:51:35 -0700498}
499
buzbee31a4a6f2012-02-28 15:36:15 -0800500void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700501{
Bill Buzbeea114add2012-05-03 15:00:40 -0700502 RegLocation rlResult;
503 rlSrc = loadValue(cUnit, rlSrc, kFPReg);
504 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
505 newLIR2(cUnit, kThumb2Vnegs, rlResult.lowReg, rlSrc.lowReg);
506 storeValue(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -0700507}
508
buzbee31a4a6f2012-02-28 15:36:15 -0800509void genNegDouble(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700510{
Bill Buzbeea114add2012-05-03 15:00:40 -0700511 RegLocation rlResult;
512 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
513 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
buzbeef0504cd2012-11-13 16:31:10 -0800514 newLIR2(cUnit, kThumb2Vnegd, s2d(rlResult.lowReg, rlResult.highReg),
515 s2d(rlSrc.lowReg, rlSrc.highReg));
Bill Buzbeea114add2012-05-03 15:00:40 -0700516 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -0700517}
518
buzbee67bf8852011-08-17 17:51:35 -0700519/*
520 * Handle simple case (thin lock) inline. If it's complicated, bail
521 * out to the heavyweight lock/unlock routines. We'll use dedicated
522 * registers here in order to be in the right position in case we
523 * to bail to dvm[Lock/Unlock]Object(self, object)
524 *
525 * r0 -> self pointer [arg0 for dvm[Lock/Unlock]Object
526 * r1 -> object [arg1 for dvm[Lock/Unlock]Object
527 * r2 -> intial contents of object->lock, later result of strex
528 * r3 -> self->threadId
529 * r12 -> allow to be used by utilities as general temp
530 *
531 * The result of the strex is 0 if we acquire the lock.
532 *
533 * See comments in Sync.c for the layout of the lock word.
534 * Of particular interest to this code is the test for the
535 * simple case - which we handle inline. For monitor enter, the
536 * simple case is thin lock, held by no-one. For monitor exit,
537 * the simple case is thin lock, held by the unlocking thread with
538 * a recurse count of 0.
539 *
540 * A minor complication is that there is a field in the lock word
541 * unrelated to locking: the hash state. This field must be ignored, but
542 * preserved.
543 *
544 */
buzbee408ad162012-06-06 16:45:18 -0700545void genMonitorEnter(CompilationUnit* cUnit, int optFlags, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700546{
Bill Buzbeea114add2012-05-03 15:00:40 -0700547 oatFlushAllRegs(cUnit);
548 DCHECK_EQ(LW_SHAPE_THIN, 0);
549 loadValueDirectFixed(cUnit, rlSrc, r0); // Get obj
550 oatLockCallTemps(cUnit); // Prepare for explicit register usage
buzbee408ad162012-06-06 16:45:18 -0700551 genNullCheck(cUnit, rlSrc.sRegLow, r0, optFlags);
buzbeef0504cd2012-11-13 16:31:10 -0800552 loadWordDisp(cUnit, rARM_SELF, Thread::ThinLockIdOffset().Int32Value(), r2);
Bill Buzbeea114add2012-05-03 15:00:40 -0700553 newLIR3(cUnit, kThumb2Ldrex, r1, r0,
554 Object::MonitorOffset().Int32Value() >> 2); // Get object->lock
555 // Align owner
556 opRegImm(cUnit, kOpLsl, r2, LW_LOCK_OWNER_SHIFT);
557 // Is lock unheld on lock or held by us (==threadId) on unlock?
558 newLIR4(cUnit, kThumb2Bfi, r2, r1, 0, LW_LOCK_OWNER_SHIFT - 1);
559 newLIR3(cUnit, kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
560 opRegImm(cUnit, kOpCmp, r1, 0);
561 opIT(cUnit, kArmCondEq, "");
562 newLIR4(cUnit, kThumb2Strex, r1, r2, r0,
563 Object::MonitorOffset().Int32Value() >> 2);
564 opRegImm(cUnit, kOpCmp, r1, 0);
565 opIT(cUnit, kArmCondNe, "T");
566 // Go expensive route - artLockObjectFromCode(self, obj);
buzbeef0504cd2012-11-13 16:31:10 -0800567 loadWordDisp(cUnit, rARM_SELF, ENTRYPOINT_OFFSET(pLockObjectFromCode), rARM_LR);
Bill Buzbeea114add2012-05-03 15:00:40 -0700568 oatClobberCalleeSave(cUnit);
buzbeef0504cd2012-11-13 16:31:10 -0800569 LIR* callInst = opReg(cUnit, kOpBlx, rARM_LR);
buzbee8320f382012-09-11 16:29:42 -0700570 markSafepointPC(cUnit, callInst);
Bill Buzbeea114add2012-05-03 15:00:40 -0700571 oatGenMemBarrier(cUnit, kSY);
buzbee67bf8852011-08-17 17:51:35 -0700572}
573
574/*
575 * For monitor unlock, we don't have to use ldrex/strex. Once
576 * we've determined that the lock is thin and that we own it with
577 * a zero recursion count, it's safe to punch it back to the
578 * initial, unlock thin state with a store word.
579 */
buzbee408ad162012-06-06 16:45:18 -0700580void genMonitorExit(CompilationUnit* cUnit, int optFlags, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700581{
Bill Buzbeea114add2012-05-03 15:00:40 -0700582 DCHECK_EQ(LW_SHAPE_THIN, 0);
583 oatFlushAllRegs(cUnit);
584 loadValueDirectFixed(cUnit, rlSrc, r0); // Get obj
585 oatLockCallTemps(cUnit); // Prepare for explicit register usage
buzbee408ad162012-06-06 16:45:18 -0700586 genNullCheck(cUnit, rlSrc.sRegLow, r0, optFlags);
Bill Buzbeea114add2012-05-03 15:00:40 -0700587 loadWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r1); // Get lock
buzbeef0504cd2012-11-13 16:31:10 -0800588 loadWordDisp(cUnit, rARM_SELF, Thread::ThinLockIdOffset().Int32Value(), r2);
Bill Buzbeea114add2012-05-03 15:00:40 -0700589 // Is lock unheld on lock or held by us (==threadId) on unlock?
590 opRegRegImm(cUnit, kOpAnd, r3, r1,
591 (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
592 // Align owner
593 opRegImm(cUnit, kOpLsl, r2, LW_LOCK_OWNER_SHIFT);
594 newLIR3(cUnit, kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
595 opRegReg(cUnit, kOpSub, r1, r2);
596 opIT(cUnit, kArmCondEq, "EE");
597 storeWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r3);
598 // Go expensive route - UnlockObjectFromCode(obj);
buzbeef0504cd2012-11-13 16:31:10 -0800599 loadWordDisp(cUnit, rARM_SELF, ENTRYPOINT_OFFSET(pUnlockObjectFromCode), rARM_LR);
Bill Buzbeea114add2012-05-03 15:00:40 -0700600 oatClobberCalleeSave(cUnit);
buzbeef0504cd2012-11-13 16:31:10 -0800601 LIR* callInst = opReg(cUnit, kOpBlx, rARM_LR);
buzbee8320f382012-09-11 16:29:42 -0700602 markSafepointPC(cUnit, callInst);
Bill Buzbeea114add2012-05-03 15:00:40 -0700603 oatGenMemBarrier(cUnit, kSY);
buzbee67bf8852011-08-17 17:51:35 -0700604}
605
606/*
607 * 64-bit 3way compare function.
608 * mov rX, #-1
609 * cmp op1hi, op2hi
610 * blt done
611 * bgt flip
612 * sub rX, op1lo, op2lo (treat as unsigned)
613 * beq done
614 * ite hi
615 * mov(hi) rX, #-1
616 * mov(!hi) rX, #1
617 * flip:
618 * neg rX
619 * done:
620 */
buzbee408ad162012-06-06 16:45:18 -0700621void genCmpLong(CompilationUnit* cUnit, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -0700622 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee67bf8852011-08-17 17:51:35 -0700623{
Bill Buzbeea114add2012-05-03 15:00:40 -0700624 LIR* target1;
625 LIR* target2;
626 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
627 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
628 int tReg = oatAllocTemp(cUnit);
629 loadConstant(cUnit, tReg, -1);
630 opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg);
631 LIR* branch1 = opCondBranch(cUnit, kCondLt, NULL);
632 LIR* branch2 = opCondBranch(cUnit, kCondGt, NULL);
633 opRegRegReg(cUnit, kOpSub, tReg, rlSrc1.lowReg, rlSrc2.lowReg);
634 LIR* branch3 = opCondBranch(cUnit, kCondEq, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700635
Bill Buzbeea114add2012-05-03 15:00:40 -0700636 opIT(cUnit, kArmCondHi, "E");
637 newLIR2(cUnit, kThumb2MovImmShift, tReg, modifiedImmediate(-1));
638 loadConstant(cUnit, tReg, 1);
639 genBarrier(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700640
Bill Buzbeea114add2012-05-03 15:00:40 -0700641 target2 = newLIR0(cUnit, kPseudoTargetLabel);
642 opRegReg(cUnit, kOpNeg, tReg, tReg);
buzbee67bf8852011-08-17 17:51:35 -0700643
Bill Buzbeea114add2012-05-03 15:00:40 -0700644 target1 = newLIR0(cUnit, kPseudoTargetLabel);
buzbee67bf8852011-08-17 17:51:35 -0700645
buzbeef0504cd2012-11-13 16:31:10 -0800646 RegLocation rlTemp = locCReturn(); // Just using as template, will change
Bill Buzbeea114add2012-05-03 15:00:40 -0700647 rlTemp.lowReg = tReg;
648 storeValue(cUnit, rlDest, rlTemp);
649 oatFreeTemp(cUnit, tReg);
buzbee67bf8852011-08-17 17:51:35 -0700650
Bill Buzbeea114add2012-05-03 15:00:40 -0700651 branch1->target = (LIR*)target1;
652 branch2->target = (LIR*)target2;
653 branch3->target = branch1->target;
buzbee67bf8852011-08-17 17:51:35 -0700654}
655
buzbee84fd6932012-03-29 16:44:16 -0700656void genFusedLongCmpBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir)
657{
buzbeea1da8a52012-07-09 14:00:21 -0700658 LIR* labelList = cUnit->blockLabelList;
Bill Buzbeea114add2012-05-03 15:00:40 -0700659 LIR* taken = &labelList[bb->taken->id];
660 LIR* notTaken = &labelList[bb->fallThrough->id];
buzbee15bf9802012-06-12 17:49:27 -0700661 RegLocation rlSrc1 = oatGetSrcWide(cUnit, mir, 0);
662 RegLocation rlSrc2 = oatGetSrcWide(cUnit, mir, 2);
Bill Buzbeea114add2012-05-03 15:00:40 -0700663 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
664 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
665 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
666 opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg);
667 switch(ccode) {
668 case kCondEq:
669 opCondBranch(cUnit, kCondNe, notTaken);
670 break;
671 case kCondNe:
672 opCondBranch(cUnit, kCondNe, taken);
673 break;
674 case kCondLt:
675 opCondBranch(cUnit, kCondLt, taken);
676 opCondBranch(cUnit, kCondGt, notTaken);
677 ccode = kCondCc;
678 break;
679 case kCondLe:
680 opCondBranch(cUnit, kCondLt, taken);
681 opCondBranch(cUnit, kCondGt, notTaken);
682 ccode = kCondLs;
683 break;
684 case kCondGt:
685 opCondBranch(cUnit, kCondGt, taken);
686 opCondBranch(cUnit, kCondLt, notTaken);
687 ccode = kCondHi;
688 break;
689 case kCondGe:
690 opCondBranch(cUnit, kCondGt, taken);
691 opCondBranch(cUnit, kCondLt, notTaken);
692 ccode = kCondCs;
693 break;
694 default:
695 LOG(FATAL) << "Unexpected ccode: " << (int)ccode;
696 }
697 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
698 opCondBranch(cUnit, ccode, taken);
buzbee84fd6932012-03-29 16:44:16 -0700699}
700
buzbee67bf8852011-08-17 17:51:35 -0700701/*
buzbee31a4a6f2012-02-28 15:36:15 -0800702 * Generate a register comparison to an immediate and branch. Caller
703 * is responsible for setting branch target field.
buzbee67bf8852011-08-17 17:51:35 -0700704 */
buzbee82488f52012-03-02 08:20:26 -0800705LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg,
Bill Buzbeea114add2012-05-03 15:00:40 -0700706 int checkValue, LIR* target)
buzbee67bf8852011-08-17 17:51:35 -0700707{
Bill Buzbeea114add2012-05-03 15:00:40 -0700708 LIR* branch;
709 int modImm;
710 ArmConditionCode armCond = oatArmConditionEncoding(cond);
buzbeef0504cd2012-11-13 16:31:10 -0800711 if ((ARM_LOWREG(reg)) && (checkValue == 0) &&
Bill Buzbeea114add2012-05-03 15:00:40 -0700712 ((armCond == kArmCondEq) || (armCond == kArmCondNe))) {
713 branch = newLIR2(cUnit, (armCond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
714 reg, 0);
715 } else {
716 modImm = modifiedImmediate(checkValue);
buzbeef0504cd2012-11-13 16:31:10 -0800717 if (ARM_LOWREG(reg) && ((checkValue & 0xff) == checkValue)) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700718 newLIR2(cUnit, kThumbCmpRI8, reg, checkValue);
719 } else if (modImm >= 0) {
720 newLIR2(cUnit, kThumb2CmpRI8, reg, modImm);
buzbee67bf8852011-08-17 17:51:35 -0700721 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700722 int tReg = oatAllocTemp(cUnit);
723 loadConstant(cUnit, tReg, checkValue);
724 opRegReg(cUnit, kOpCmp, reg, tReg);
buzbee67bf8852011-08-17 17:51:35 -0700725 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700726 branch = newLIR2(cUnit, kThumbBCond, 0, armCond);
727 }
728 branch->target = target;
729 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -0800730}
buzbee82488f52012-03-02 08:20:26 -0800731LIR* opRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
buzbee31a4a6f2012-02-28 15:36:15 -0800732{
Bill Buzbeea114add2012-05-03 15:00:40 -0700733 LIR* res;
buzbeeb046e162012-10-30 15:48:42 -0700734 int opcode;
buzbeef0504cd2012-11-13 16:31:10 -0800735 if (ARM_FPREG(rDest) || ARM_FPREG(rSrc))
Bill Buzbeea114add2012-05-03 15:00:40 -0700736 return fpRegCopy(cUnit, rDest, rSrc);
buzbeef0504cd2012-11-13 16:31:10 -0800737 if (ARM_LOWREG(rDest) && ARM_LOWREG(rSrc))
Bill Buzbeea114add2012-05-03 15:00:40 -0700738 opcode = kThumbMovRR;
buzbeef0504cd2012-11-13 16:31:10 -0800739 else if (!ARM_LOWREG(rDest) && !ARM_LOWREG(rSrc))
Bill Buzbeea114add2012-05-03 15:00:40 -0700740 opcode = kThumbMovRR_H2H;
buzbeef0504cd2012-11-13 16:31:10 -0800741 else if (ARM_LOWREG(rDest))
Bill Buzbeea114add2012-05-03 15:00:40 -0700742 opcode = kThumbMovRR_H2L;
743 else
744 opcode = kThumbMovRR_L2H;
745 res = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, rDest, rSrc);
746 if (!(cUnit->disableOpt & (1 << kSafeOptimizations)) && rDest == rSrc) {
747 res->flags.isNop = true;
748 }
749 return res;
buzbee67bf8852011-08-17 17:51:35 -0700750}
751
buzbee82488f52012-03-02 08:20:26 -0800752LIR* opRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
buzbee67bf8852011-08-17 17:51:35 -0700753{
Bill Buzbeea114add2012-05-03 15:00:40 -0700754 LIR* res = opRegCopyNoInsert(cUnit, rDest, rSrc);
755 oatAppendLIR(cUnit, (LIR*)res);
756 return res;
buzbee31a4a6f2012-02-28 15:36:15 -0800757}
buzbee67bf8852011-08-17 17:51:35 -0700758
buzbee82488f52012-03-02 08:20:26 -0800759void opRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
Bill Buzbeea114add2012-05-03 15:00:40 -0700760 int srcLo, int srcHi)
buzbee31a4a6f2012-02-28 15:36:15 -0800761{
buzbeef0504cd2012-11-13 16:31:10 -0800762 bool destFP = ARM_FPREG(destLo) && ARM_FPREG(destHi);
763 bool srcFP = ARM_FPREG(srcLo) && ARM_FPREG(srcHi);
764 DCHECK_EQ(ARM_FPREG(srcLo), ARM_FPREG(srcHi));
765 DCHECK_EQ(ARM_FPREG(destLo), ARM_FPREG(destHi));
Bill Buzbeea114add2012-05-03 15:00:40 -0700766 if (destFP) {
767 if (srcFP) {
buzbeef0504cd2012-11-13 16:31:10 -0800768 opRegCopy(cUnit, s2d(destLo, destHi), s2d(srcLo, srcHi));
buzbee31a4a6f2012-02-28 15:36:15 -0800769 } else {
buzbeef0504cd2012-11-13 16:31:10 -0800770 newLIR3(cUnit, kThumb2Fmdrr, s2d(destLo, destHi), srcLo, srcHi);
buzbee67bf8852011-08-17 17:51:35 -0700771 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700772 } else {
773 if (srcFP) {
buzbeef0504cd2012-11-13 16:31:10 -0800774 newLIR3(cUnit, kThumb2Fmrrd, destLo, destHi, s2d(srcLo, srcHi));
Bill Buzbeea114add2012-05-03 15:00:40 -0700775 } else {
776 // Handle overlap
777 if (srcHi == destLo) {
778 opRegCopy(cUnit, destHi, srcHi);
779 opRegCopy(cUnit, destLo, srcLo);
780 } else {
781 opRegCopy(cUnit, destLo, srcLo);
782 opRegCopy(cUnit, destHi, srcHi);
783 }
784 }
785 }
buzbee67bf8852011-08-17 17:51:35 -0700786}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800787
buzbeef3aac972012-04-11 16:33:36 -0700788// Table of magic divisors
789enum DividePattern {
Bill Buzbeea114add2012-05-03 15:00:40 -0700790 DivideNone,
791 Divide3,
792 Divide5,
793 Divide7,
buzbeef3aac972012-04-11 16:33:36 -0700794};
795
796struct MagicTable {
Bill Buzbeea114add2012-05-03 15:00:40 -0700797 uint32_t magic;
798 uint32_t shift;
799 DividePattern pattern;
buzbeef3aac972012-04-11 16:33:36 -0700800};
801
802static const MagicTable magicTable[] = {
Bill Buzbeea114add2012-05-03 15:00:40 -0700803 {0, 0, DivideNone}, // 0
804 {0, 0, DivideNone}, // 1
805 {0, 0, DivideNone}, // 2
806 {0x55555556, 0, Divide3}, // 3
807 {0, 0, DivideNone}, // 4
808 {0x66666667, 1, Divide5}, // 5
809 {0x2AAAAAAB, 0, Divide3}, // 6
810 {0x92492493, 2, Divide7}, // 7
811 {0, 0, DivideNone}, // 8
812 {0x38E38E39, 1, Divide5}, // 9
813 {0x66666667, 2, Divide5}, // 10
814 {0x2E8BA2E9, 1, Divide5}, // 11
815 {0x2AAAAAAB, 1, Divide5}, // 12
816 {0x4EC4EC4F, 2, Divide5}, // 13
817 {0x92492493, 3, Divide7}, // 14
818 {0x88888889, 3, Divide7}, // 15
buzbeef3aac972012-04-11 16:33:36 -0700819};
820
821// Integer division by constant via reciprocal multiply (Hacker's Delight, 10-4)
822bool smallLiteralDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode,
823 RegLocation rlSrc, RegLocation rlDest, int lit)
824{
Bill Buzbeea114add2012-05-03 15:00:40 -0700825 if ((lit < 0) || (lit >= (int)(sizeof(magicTable)/sizeof(magicTable[0])))) {
826 return false;
827 }
828 DividePattern pattern = magicTable[lit].pattern;
829 if (pattern == DivideNone) {
830 return false;
831 }
832 // Tuning: add rem patterns
833 if (dalvikOpcode != Instruction::DIV_INT_LIT8) {
834 return false;
835 }
buzbeef3aac972012-04-11 16:33:36 -0700836
Bill Buzbeea114add2012-05-03 15:00:40 -0700837 int rMagic = oatAllocTemp(cUnit);
838 loadConstant(cUnit, rMagic, magicTable[lit].magic);
839 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
840 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
841 int rHi = oatAllocTemp(cUnit);
842 int rLo = oatAllocTemp(cUnit);
843 newLIR4(cUnit, kThumb2Smull, rLo, rHi, rMagic, rlSrc.lowReg);
844 switch(pattern) {
845 case Divide3:
846 opRegRegRegShift(cUnit, kOpSub, rlResult.lowReg, rHi,
847 rlSrc.lowReg, encodeShift(kArmAsr, 31));
848 break;
849 case Divide5:
850 opRegRegImm(cUnit, kOpAsr, rLo, rlSrc.lowReg, 31);
851 opRegRegRegShift(cUnit, kOpRsub, rlResult.lowReg, rLo, rHi,
852 encodeShift(kArmAsr, magicTable[lit].shift));
853 break;
854 case Divide7:
855 opRegReg(cUnit, kOpAdd, rHi, rlSrc.lowReg);
856 opRegRegImm(cUnit, kOpAsr, rLo, rlSrc.lowReg, 31);
857 opRegRegRegShift(cUnit, kOpRsub, rlResult.lowReg, rLo, rHi,
858 encodeShift(kArmAsr, magicTable[lit].shift));
859 break;
860 default:
861 LOG(FATAL) << "Unexpected pattern: " << (int)pattern;
862 }
863 storeValue(cUnit, rlDest, rlResult);
864 return true;
buzbeef3aac972012-04-11 16:33:36 -0700865}
buzbee31a4a6f2012-02-28 15:36:15 -0800866
buzbeeb046e162012-10-30 15:48:42 -0700867/*
868 * Mark garbage collection card. Skip if the value we're storing is null.
869 */
870void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg)
871{
872 int regCardBase = oatAllocTemp(cUnit);
873 int regCardNo = oatAllocTemp(cUnit);
874 LIR* branchOver = opCmpImmBranch(cUnit, kCondEq, valReg, 0, NULL);
buzbeef0504cd2012-11-13 16:31:10 -0800875 loadWordDisp(cUnit, rARM_SELF, Thread::CardTableOffset().Int32Value(), regCardBase);
buzbeeb046e162012-10-30 15:48:42 -0700876 opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, CardTable::kCardShift);
877 storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
878 kUnsignedByte);
879 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
880 branchOver->target = (LIR*)target;
881 oatFreeTemp(cUnit, regCardBase);
882 oatFreeTemp(cUnit, regCardNo);
883}
884
885LIR* genRegMemCheck(CompilationUnit* cUnit, ConditionCode cCode,
886 int reg1, int base, int offset, ThrowKind kind)
887{
888 LOG(FATAL) << "Unexpected use of genRegMemCheck for Arm";
889 return NULL;
890}
891
892RegLocation genDivRemLit(CompilationUnit* cUnit, RegLocation rlDest, int reg1, int lit, bool isDiv)
893{
894 LOG(FATAL) << "Unexpected use of genDivRemLit for Arm";
895 return rlDest;
896}
897
898RegLocation genDivRem(CompilationUnit* cUnit, RegLocation rlDest, int reg1, int reg2, bool isDiv)
899{
900 LOG(FATAL) << "Unexpected use of genDivRem for Arm";
901 return rlDest;
902}
903
904bool genInlinedMinMaxInt(CompilationUnit *cUnit, CallInfo* info, bool isMin)
905{
906 DCHECK_EQ(cUnit->instructionSet, kThumb2);
907 RegLocation rlSrc1 = info->args[0];
908 RegLocation rlSrc2 = info->args[1];
909 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
910 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
911 RegLocation rlDest = inlineTarget(cUnit, info);
912 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
913 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
914 opIT(cUnit, (isMin) ? kArmCondGt : kArmCondLt, "E");
915 opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc2.lowReg);
916 opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc1.lowReg);
917 genBarrier(cUnit);
918 storeValue(cUnit, rlDest, rlResult);
919 return true;
920}
921
922void opLea(CompilationUnit* cUnit, int rBase, int reg1, int reg2, int scale, int offset)
923{
924 LOG(FATAL) << "Unexpected use of opLea for Arm";
925}
926
927void opTlsCmp(CompilationUnit* cUnit, int offset, int val)
928{
929 LOG(FATAL) << "Unexpected use of opTlsCmp for Arm";
930}
931
932bool genInlinedCas32(CompilationUnit* cUnit, CallInfo* info, bool need_write_barrier) {
933 DCHECK_EQ(cUnit->instructionSet, kThumb2);
934 // Unused - RegLocation rlSrcUnsafe = info->args[0];
935 RegLocation rlSrcObj= info->args[1]; // Object - known non-null
936 RegLocation rlSrcOffset= info->args[2]; // long low
937 rlSrcOffset.wide = 0; // ignore high half in info->args[3]
938 RegLocation rlSrcExpected= info->args[4]; // int or Object
939 RegLocation rlSrcNewValue= info->args[5]; // int or Object
940 RegLocation rlDest = inlineTarget(cUnit, info); // boolean place for result
941
942
943 // Release store semantics, get the barrier out of the way.
944 oatGenMemBarrier(cUnit, kSY);
945
946 RegLocation rlObject = loadValue(cUnit, rlSrcObj, kCoreReg);
947 RegLocation rlNewValue = loadValue(cUnit, rlSrcNewValue, kCoreReg);
948
949 if (need_write_barrier) {
950 // Mark card for object assuming new value is stored.
951 markGCCard(cUnit, rlNewValue.lowReg, rlObject.lowReg);
952 }
953
954 RegLocation rlOffset = loadValue(cUnit, rlSrcOffset, kCoreReg);
955
956 int rPtr = oatAllocTemp(cUnit);
957 opRegRegReg(cUnit, kOpAdd, rPtr, rlObject.lowReg, rlOffset.lowReg);
958
959 // Free now unneeded rlObject and rlOffset to give more temps.
960 oatClobberSReg(cUnit, rlObject.sRegLow);
961 oatFreeTemp(cUnit, rlObject.lowReg);
962 oatClobberSReg(cUnit, rlOffset.sRegLow);
963 oatFreeTemp(cUnit, rlOffset.lowReg);
964
965 int rOldValue = oatAllocTemp(cUnit);
966 newLIR3(cUnit, kThumb2Ldrex, rOldValue, rPtr, 0); // rOldValue := [rPtr]
967
968 RegLocation rlExpected = loadValue(cUnit, rlSrcExpected, kCoreReg);
969
970 // if (rOldValue == rExpected) {
971 // [rPtr] <- rNewValue && rResult := success ? 0 : 1
972 // rResult ^= 1
973 // } else {
974 // rResult := 0
975 // }
976 opRegReg(cUnit, kOpCmp, rOldValue, rlExpected.lowReg);
977 oatFreeTemp(cUnit, rOldValue); // Now unneeded.
978 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
979 opIT(cUnit, kArmCondEq, "TE");
980 newLIR4(cUnit, kThumb2Strex, rlResult.lowReg, rlNewValue.lowReg, rPtr, 0);
981 oatFreeTemp(cUnit, rPtr); // Now unneeded.
982 opRegImm(cUnit, kOpXor, rlResult.lowReg, 1);
983 opRegReg(cUnit, kOpXor, rlResult.lowReg, rlResult.lowReg);
984
985 storeValue(cUnit, rlDest, rlResult);
986
987 return true;
988}
989
990bool genInlinedSqrt(CompilationUnit* cUnit, CallInfo* info) {
991 DCHECK_EQ(cUnit->instructionSet, kThumb2);
992 LIR *branch;
993 RegLocation rlSrc = info->args[0];
994 RegLocation rlDest = inlineTargetWide(cUnit, info); // double place for result
995 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
996 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
buzbeef0504cd2012-11-13 16:31:10 -0800997 newLIR2(cUnit, kThumb2Vsqrtd, s2d(rlResult.lowReg, rlResult.highReg),
998 s2d(rlSrc.lowReg, rlSrc.highReg));
999 newLIR2(cUnit, kThumb2Vcmpd, s2d(rlResult.lowReg, rlResult.highReg),
1000 s2d(rlResult.lowReg, rlResult.highReg));
buzbeeb046e162012-10-30 15:48:42 -07001001 newLIR0(cUnit, kThumb2Fmstat);
1002 branch = newLIR2(cUnit, kThumbBCond, 0, kArmCondEq);
1003 oatClobberCalleeSave(cUnit);
1004 oatLockCallTemps(cUnit); // Using fixed registers
1005 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pSqrt));
buzbeef0504cd2012-11-13 16:31:10 -08001006 newLIR3(cUnit, kThumb2Fmrrd, r0, r1, s2d(rlSrc.lowReg, rlSrc.highReg));
buzbeeb046e162012-10-30 15:48:42 -07001007 newLIR1(cUnit, kThumbBlxR, rTgt);
buzbeef0504cd2012-11-13 16:31:10 -08001008 newLIR3(cUnit, kThumb2Fmdrr, s2d(rlResult.lowReg, rlResult.highReg), r0, r1);
buzbeeb046e162012-10-30 15:48:42 -07001009 branch->target = newLIR0(cUnit, kPseudoTargetLabel);
1010 storeValueWide(cUnit, rlDest, rlResult);
1011 return true;
1012}
1013
1014LIR* opPcRelLoad(CompilationUnit* cUnit, int reg, LIR* target)
1015{
1016 return rawLIR(cUnit, cUnit->currentDalvikOffset, kThumb2LdrPcRel12, reg, 0, 0, 0, 0, target);
1017}
1018
1019LIR* opVldm(CompilationUnit* cUnit, int rBase, int count)
1020{
1021 return newLIR3(cUnit, kThumb2Vldms, rBase, fr0, count);
1022}
1023
1024LIR* opVstm(CompilationUnit* cUnit, int rBase, int count)
1025{
1026 return newLIR3(cUnit, kThumb2Vstms, rBase, fr0, count);
1027}
1028
1029void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc,
1030 RegLocation rlResult, int lit,
1031 int firstBit, int secondBit)
1032{
1033 opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg,
1034 encodeShift(kArmLsl, secondBit - firstBit));
1035 if (firstBit != 0) {
1036 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
1037 }
1038}
1039
1040void genDivZeroCheck(CompilationUnit* cUnit, int regLo, int regHi)
1041{
1042 int tReg = oatAllocTemp(cUnit);
1043 newLIR4(cUnit, kThumb2OrrRRRs, tReg, regLo, regHi, 0);
1044 oatFreeTemp(cUnit, tReg);
1045 genCheck(cUnit, kCondEq, kThrowDivZero);
1046}
1047
1048// Test suspend flag, return target of taken suspend branch
1049LIR* opTestSuspend(CompilationUnit* cUnit, LIR* target)
1050{
buzbeef0504cd2012-11-13 16:31:10 -08001051 newLIR2(cUnit, kThumbSubRI8, rARM_SUSPEND, 1);
buzbeeb046e162012-10-30 15:48:42 -07001052 return opCondBranch(cUnit, (target == NULL) ? kCondEq : kCondNe, target);
1053}
1054
1055// Decrement register and branch on condition
1056LIR* opDecAndBranch(CompilationUnit* cUnit, ConditionCode cCode, int reg, LIR* target)
1057{
1058 // Combine sub & test using sub setflags encoding here
1059 newLIR3(cUnit, kThumb2SubsRRI12, reg, reg, 1);
1060 return opCondBranch(cUnit, cCode, target);
1061}
1062
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001063} // namespace art