blob: 3584a52e3675ac3e887d984e01e7c3a5728fcd40 [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"
Ian Rogers57b86d42012-03-27 16:05:41 -070026#include "oat/runtime/oat_support_entrypoints.h"
Logan Chien4dd96f52012-02-29 01:26:58 +080027
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080028namespace art {
29
buzbeee62076c2012-03-21 14:26:16 -070030
31/* Return the position of an ssa name within the argument list */
32int inPosition(CompilationUnit* cUnit, int sReg)
buzbee16da88c2012-03-20 10:38:17 -070033{
Bill Buzbeea114add2012-05-03 15:00:40 -070034 int vReg = SRegToVReg(cUnit, sReg);
35 return vReg - cUnit->numRegs;
buzbeee62076c2012-03-21 14:26:16 -070036}
37
38/*
39 * Describe an argument. If it's already in an arg register, just leave it
40 * there. NOTE: all live arg registers must be locked prior to this call
41 * to avoid having them allocated as a temp by downstream utilities.
42 */
43RegLocation argLoc(CompilationUnit* cUnit, RegLocation loc)
44{
Bill Buzbeea114add2012-05-03 15:00:40 -070045 int argNum = inPosition(cUnit, loc.sRegLow);
46 if (loc.wide) {
47 if (argNum == 2) {
48 // Bad case - half in register, half in frame. Just punt
49 loc.location = kLocInvalid;
50 } else if (argNum < 2) {
51 loc.lowReg = rARG1 + argNum;
52 loc.highReg = loc.lowReg + 1;
53 loc.location = kLocPhysReg;
buzbee16da88c2012-03-20 10:38:17 -070054 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -070055 loc.location = kLocDalvikFrame;
buzbee16da88c2012-03-20 10:38:17 -070056 }
Bill Buzbeea114add2012-05-03 15:00:40 -070057 } else {
58 if (argNum < 3) {
59 loc.lowReg = rARG1 + argNum;
60 loc.location = kLocPhysReg;
61 } else {
62 loc.location = kLocDalvikFrame;
63 }
64 }
65 return loc;
buzbee16da88c2012-03-20 10:38:17 -070066}
67
buzbeee62076c2012-03-21 14:26:16 -070068/*
69 * Load an argument. If already in a register, just return. If in
70 * the frame, we can't use the normal loadValue() because it assumed
71 * a proper frame - and we're frameless.
72 */
73RegLocation loadArg(CompilationUnit* cUnit, RegLocation loc)
74{
Bill Buzbeea114add2012-05-03 15:00:40 -070075 if (loc.location == kLocDalvikFrame) {
76 int start = (inPosition(cUnit, loc.sRegLow) + 1) * sizeof(uint32_t);
77 loc.lowReg = oatAllocTemp(cUnit);
78 loadWordDisp(cUnit, rSP, start, loc.lowReg);
79 if (loc.wide) {
80 loc.highReg = oatAllocTemp(cUnit);
81 loadWordDisp(cUnit, rSP, start + sizeof(uint32_t), loc.highReg);
buzbeee62076c2012-03-21 14:26:16 -070082 }
Bill Buzbeea114add2012-05-03 15:00:40 -070083 loc.location = kLocPhysReg;
84 }
85 return loc;
buzbeee62076c2012-03-21 14:26:16 -070086}
87
88/* Lock any referenced arguments that arrive in registers */
89void lockLiveArgs(CompilationUnit* cUnit, MIR* mir)
90{
Bill Buzbeea114add2012-05-03 15:00:40 -070091 int firstIn = cUnit->numRegs;
92 const int numArgRegs = 3; // TODO: generalize & move to RegUtil.cc
93 for (int i = 0; i < mir->ssaRep->numUses; i++) {
94 int vReg = SRegToVReg(cUnit, mir->ssaRep->uses[i]);
95 int inPosition = vReg - firstIn;
96 if (inPosition < numArgRegs) {
97 oatLockTemp(cUnit, rARG1 + inPosition);
buzbeee62076c2012-03-21 14:26:16 -070098 }
Bill Buzbeea114add2012-05-03 15:00:40 -070099 }
buzbeee62076c2012-03-21 14:26:16 -0700100}
101
buzbee16da88c2012-03-20 10:38:17 -0700102/* Find the next MIR, which may be in a following basic block */
103MIR* getNextMir(CompilationUnit* cUnit, BasicBlock** pBb, MIR* mir)
104{
Bill Buzbeea114add2012-05-03 15:00:40 -0700105 BasicBlock* bb = *pBb;
106 MIR* origMir = mir;
107 while (bb != NULL) {
108 if (mir != NULL) {
109 mir = mir->next;
buzbee16da88c2012-03-20 10:38:17 -0700110 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700111 if (mir != NULL) {
112 return mir;
113 } else {
114 bb = bb->fallThrough;
115 *pBb = bb;
116 if (bb) {
117 mir = bb->firstMIRInsn;
118 if (mir != NULL) {
119 return mir;
120 }
121 }
122 }
123 }
124 return origMir;
buzbee16da88c2012-03-20 10:38:17 -0700125}
126
127/* Used for the "printMe" listing */
128void genPrintLabel(CompilationUnit *cUnit, MIR* mir)
129{
Bill Buzbeea114add2012-05-03 15:00:40 -0700130 /* Mark the beginning of a Dalvik instruction for line tracking */
131 char* instStr = cUnit->printMe ?
132 oatGetDalvikDisassembly(cUnit, mir->dalvikInsn, "") : NULL;
buzbeed1643e42012-09-05 14:06:51 -0700133 markBoundary(cUnit, mir->offset, instStr);
Bill Buzbeea114add2012-05-03 15:00:40 -0700134 /* Don't generate the SSA annotation unless verbose mode is on */
135 if (cUnit->printMe && mir->ssaRep) {
136 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
137 newLIR1(cUnit, kPseudoSSARep, (int) ssaString);
138 }
buzbee16da88c2012-03-20 10:38:17 -0700139}
140
141MIR* specialIGet(CompilationUnit* cUnit, BasicBlock** bb, MIR* mir,
142 OpSize size, bool longOrDouble, bool isObject)
143{
Bill Buzbeea114add2012-05-03 15:00:40 -0700144 int fieldOffset;
145 bool isVolatile;
146 uint32_t fieldIdx = mir->dalvikInsn.vC;
147 bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile, false);
148 if (!fastPath || !(mir->optimizationFlags & MIR_IGNORE_NULL_CHECK)) {
149 return NULL;
150 }
151 RegLocation rlObj = oatGetSrc(cUnit, mir, 0);
152 lockLiveArgs(cUnit, mir);
153 rlObj = argLoc(cUnit, rlObj);
154 RegLocation rlDest;
155 if (longOrDouble) {
156 rlDest = oatGetReturnWide(cUnit, false);
157 } else {
158 rlDest = oatGetReturn(cUnit, false);
159 }
160 // Point of no return - no aborts after this
161 genPrintLabel(cUnit, mir);
162 rlObj = loadArg(cUnit, rlObj);
buzbee408ad162012-06-06 16:45:18 -0700163 genIGet(cUnit, fieldIdx, mir->optimizationFlags, size, rlDest, rlObj,
164 longOrDouble, isObject);
Bill Buzbeea114add2012-05-03 15:00:40 -0700165 return getNextMir(cUnit, bb, mir);
buzbee16da88c2012-03-20 10:38:17 -0700166}
167
168MIR* specialIPut(CompilationUnit* cUnit, BasicBlock** bb, MIR* mir,
169 OpSize size, bool longOrDouble, bool isObject)
170{
Bill Buzbeea114add2012-05-03 15:00:40 -0700171 int fieldOffset;
172 bool isVolatile;
173 uint32_t fieldIdx = mir->dalvikInsn.vC;
174 bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile, false);
175 if (!fastPath || !(mir->optimizationFlags & MIR_IGNORE_NULL_CHECK)) {
176 return NULL;
177 }
178 RegLocation rlSrc;
179 RegLocation rlObj;
180 lockLiveArgs(cUnit, mir);
181 if (longOrDouble) {
buzbee15bf9802012-06-12 17:49:27 -0700182 rlSrc = oatGetSrcWide(cUnit, mir, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700183 rlObj = oatGetSrc(cUnit, mir, 2);
184 } else {
185 rlSrc = oatGetSrc(cUnit, mir, 0);
186 rlObj = oatGetSrc(cUnit, mir, 1);
187 }
188 rlSrc = argLoc(cUnit, rlSrc);
189 rlObj = argLoc(cUnit, rlObj);
190 // Reject if source is split across registers & frame
191 if (rlObj.location == kLocInvalid) {
192 oatResetRegPool(cUnit);
193 return NULL;
194 }
195 // Point of no return - no aborts after this
196 genPrintLabel(cUnit, mir);
197 rlObj = loadArg(cUnit, rlObj);
198 rlSrc = loadArg(cUnit, rlSrc);
buzbee408ad162012-06-06 16:45:18 -0700199 genIPut(cUnit, fieldIdx, mir->optimizationFlags, size, rlSrc, rlObj,
200 longOrDouble, isObject);
Bill Buzbeea114add2012-05-03 15:00:40 -0700201 return getNextMir(cUnit, bb, mir);
buzbee16da88c2012-03-20 10:38:17 -0700202}
203
buzbeee62076c2012-03-21 14:26:16 -0700204MIR* specialIdentity(CompilationUnit* cUnit, MIR* mir)
205{
Bill Buzbeea114add2012-05-03 15:00:40 -0700206 RegLocation rlSrc;
207 RegLocation rlDest;
208 bool wide = (mir->ssaRep->numUses == 2);
209 if (wide) {
buzbee15bf9802012-06-12 17:49:27 -0700210 rlSrc = oatGetSrcWide(cUnit, mir, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700211 rlDest = oatGetReturnWide(cUnit, false);
212 } else {
213 rlSrc = oatGetSrc(cUnit, mir, 0);
214 rlDest = oatGetReturn(cUnit, false);
215 }
216 lockLiveArgs(cUnit, mir);
217 rlSrc = argLoc(cUnit, rlSrc);
218 if (rlSrc.location == kLocInvalid) {
219 oatResetRegPool(cUnit);
220 return NULL;
221 }
222 // Point of no return - no aborts after this
223 genPrintLabel(cUnit, mir);
224 rlSrc = loadArg(cUnit, rlSrc);
225 if (wide) {
226 storeValueWide(cUnit, rlDest, rlSrc);
227 } else {
228 storeValue(cUnit, rlDest, rlSrc);
229 }
230 return mir;
buzbeee62076c2012-03-21 14:26:16 -0700231}
232
buzbee16da88c2012-03-20 10:38:17 -0700233/*
234 * Special-case code genration for simple non-throwing leaf methods.
235 */
236void genSpecialCase(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
Bill Buzbeea114add2012-05-03 15:00:40 -0700237 SpecialCaseHandler specialCase)
buzbee16da88c2012-03-20 10:38:17 -0700238{
239 cUnit->currentDalvikOffset = mir->offset;
240 MIR* nextMir = NULL;
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700241 switch (specialCase) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700242 case kNullMethod:
243 DCHECK(mir->dalvikInsn.opcode == Instruction::RETURN_VOID);
244 nextMir = mir;
245 break;
246 case kConstFunction:
247 genPrintLabel(cUnit, mir);
248 loadConstant(cUnit, rRET0, mir->dalvikInsn.vB);
249 nextMir = getNextMir(cUnit, &bb, mir);
250 break;
251 case kIGet:
252 nextMir = specialIGet(cUnit, &bb, mir, kWord, false, false);
253 break;
254 case kIGetBoolean:
255 case kIGetByte:
256 nextMir = specialIGet(cUnit, &bb, mir, kUnsignedByte, false, false);
257 break;
258 case kIGetObject:
259 nextMir = specialIGet(cUnit, &bb, mir, kWord, false, true);
260 break;
261 case kIGetChar:
262 nextMir = specialIGet(cUnit, &bb, mir, kUnsignedHalf, false, false);
263 break;
264 case kIGetShort:
265 nextMir = specialIGet(cUnit, &bb, mir, kSignedHalf, false, false);
266 break;
267 case kIGetWide:
268 nextMir = specialIGet(cUnit, &bb, mir, kLong, true, false);
269 break;
270 case kIPut:
271 nextMir = specialIPut(cUnit, &bb, mir, kWord, false, false);
272 break;
273 case kIPutBoolean:
274 case kIPutByte:
275 nextMir = specialIPut(cUnit, &bb, mir, kUnsignedByte, false, false);
276 break;
277 case kIPutObject:
278 nextMir = specialIPut(cUnit, &bb, mir, kWord, false, true);
279 break;
280 case kIPutChar:
281 nextMir = specialIPut(cUnit, &bb, mir, kUnsignedHalf, false, false);
282 break;
283 case kIPutShort:
284 nextMir = specialIPut(cUnit, &bb, mir, kSignedHalf, false, false);
285 break;
286 case kIPutWide:
287 nextMir = specialIPut(cUnit, &bb, mir, kLong, true, false);
288 break;
289 case kIdentity:
290 nextMir = specialIdentity(cUnit, mir);
291 break;
292 default:
293 return;
buzbee16da88c2012-03-20 10:38:17 -0700294 }
295 if (nextMir != NULL) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700296 cUnit->currentDalvikOffset = nextMir->offset;
297 if (specialCase != kIdentity) {
298 genPrintLabel(cUnit, nextMir);
buzbee16da88c2012-03-20 10:38:17 -0700299 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700300 newLIR1(cUnit, kThumbBx, rLR);
301 cUnit->coreSpillMask = 0;
302 cUnit->numCoreSpills = 0;
303 cUnit->fpSpillMask = 0;
304 cUnit->numFPSpills = 0;
305 cUnit->frameSize = 0;
306 cUnit->coreVmapTable.clear();
307 cUnit->fpVmapTable.clear();
308 }
buzbee16da88c2012-03-20 10:38:17 -0700309}
buzbee67bf8852011-08-17 17:51:35 -0700310
311/*
312 * Generate a Thumb2 IT instruction, which can nullify up to
313 * four subsequent instructions based on a condition and its
314 * inverse. The condition applies to the first instruction, which
315 * is executed if the condition is met. The string "guide" consists
316 * of 0 to 3 chars, and applies to the 2nd through 4th instruction.
317 * A "T" means the instruction is executed if the condition is
318 * met, and an "E" means the instruction is executed if the condition
319 * is not met.
320 */
buzbee82488f52012-03-02 08:20:26 -0800321LIR* opIT(CompilationUnit* cUnit, ArmConditionCode code, const char* guide)
buzbee67bf8852011-08-17 17:51:35 -0700322{
Bill Buzbeea114add2012-05-03 15:00:40 -0700323 int mask;
324 int condBit = code & 1;
325 int altBit = condBit ^ 1;
326 int mask3 = 0;
327 int mask2 = 0;
328 int mask1 = 0;
buzbee67bf8852011-08-17 17:51:35 -0700329
Bill Buzbeea114add2012-05-03 15:00:40 -0700330 //Note: case fallthroughs intentional
331 switch (strlen(guide)) {
332 case 3:
333 mask1 = (guide[2] == 'T') ? condBit : altBit;
334 case 2:
335 mask2 = (guide[1] == 'T') ? condBit : altBit;
336 case 1:
337 mask3 = (guide[0] == 'T') ? condBit : altBit;
338 break;
339 case 0:
340 break;
341 default:
342 LOG(FATAL) << "OAT: bad case in opIT";
343 }
344 mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
345 (1 << (3 - strlen(guide)));
346 return newLIR2(cUnit, kThumb2It, code, mask);
buzbee67bf8852011-08-17 17:51:35 -0700347}
348
349/*
buzbee67bf8852011-08-17 17:51:35 -0700350 * The sparse table in the literal pool is an array of <key,displacement>
351 * pairs. For each set, we'll load them as a pair using ldmia.
352 * This means that the register number of the temp we use for the key
353 * must be lower than the reg for the displacement.
354 *
355 * The test loop will look something like:
356 *
357 * adr rBase, <table>
358 * ldr rVal, [rSP, vRegOff]
359 * mov rIdx, #tableSize
360 * lp:
361 * ldmia rBase!, {rKey, rDisp}
362 * sub rIdx, #1
363 * cmp rVal, rKey
364 * ifeq
365 * add rPC, rDisp ; This is the branch from which we compute displacement
366 * cbnz rIdx, lp
367 */
buzbee408ad162012-06-06 16:45:18 -0700368void genSparseSwitch(CompilationUnit* cUnit, uint32_t tableOffset,
buzbeea1da8a52012-07-09 14:00:21 -0700369 RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700370{
buzbee408ad162012-06-06 16:45:18 -0700371 const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700372 if (cUnit->printMe) {
373 dumpSparseSwitchTable(table);
374 }
375 // Add the table to the list - we'll process it later
376 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
377 true, kAllocData);
378 tabRec->table = table;
buzbee408ad162012-06-06 16:45:18 -0700379 tabRec->vaddr = cUnit->currentDalvikOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700380 int size = table[1];
381 tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true, kAllocLIR);
382 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700383
Bill Buzbeea114add2012-05-03 15:00:40 -0700384 // Get the switch value
385 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
386 int rBase = oatAllocTemp(cUnit);
387 /* Allocate key and disp temps */
388 int rKey = oatAllocTemp(cUnit);
389 int rDisp = oatAllocTemp(cUnit);
390 // Make sure rKey's register number is less than rDisp's number for ldmia
391 if (rKey > rDisp) {
392 int tmp = rDisp;
393 rDisp = rKey;
394 rKey = tmp;
395 }
396 // Materialize a pointer to the switch table
397 newLIR3(cUnit, kThumb2Adr, rBase, 0, (intptr_t)tabRec);
398 // Set up rIdx
399 int rIdx = oatAllocTemp(cUnit);
400 loadConstant(cUnit, rIdx, size);
401 // Establish loop branch target
402 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
403 // Load next key/disp
404 newLIR2(cUnit, kThumb2LdmiaWB, rBase, (1 << rKey) | (1 << rDisp));
405 opRegReg(cUnit, kOpCmp, rKey, rlSrc.lowReg);
406 // Go if match. NOTE: No instruction set switch here - must stay Thumb2
407 opIT(cUnit, kArmCondEq, "");
408 LIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, rDisp);
409 tabRec->anchor = switchBranch;
410 // Needs to use setflags encoding here
411 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
412 opCondBranch(cUnit, kCondNe, target);
buzbee67bf8852011-08-17 17:51:35 -0700413}
414
415
buzbee408ad162012-06-06 16:45:18 -0700416void genPackedSwitch(CompilationUnit* cUnit, uint32_t tableOffset,
417 RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700418{
buzbee408ad162012-06-06 16:45:18 -0700419 const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700420 if (cUnit->printMe) {
421 dumpPackedSwitchTable(table);
422 }
423 // Add the table to the list - we'll process it later
424 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
425 true, kAllocData);
426 tabRec->table = table;
buzbee408ad162012-06-06 16:45:18 -0700427 tabRec->vaddr = cUnit->currentDalvikOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700428 int size = table[1];
429 tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true, kAllocLIR);
430 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700431
Bill Buzbeea114add2012-05-03 15:00:40 -0700432 // Get the switch value
433 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
434 int tableBase = oatAllocTemp(cUnit);
435 // Materialize a pointer to the switch table
436 newLIR3(cUnit, kThumb2Adr, tableBase, 0, (intptr_t)tabRec);
437 int lowKey = s4FromSwitchData(&table[2]);
438 int keyReg;
439 // Remove the bias, if necessary
440 if (lowKey == 0) {
441 keyReg = rlSrc.lowReg;
442 } else {
443 keyReg = oatAllocTemp(cUnit);
444 opRegRegImm(cUnit, kOpSub, keyReg, rlSrc.lowReg, lowKey);
445 }
446 // Bounds check - if < 0 or >= size continue following switch
447 opRegImm(cUnit, kOpCmp, keyReg, size-1);
448 LIR* branchOver = opCondBranch(cUnit, kCondHi, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700449
Bill Buzbeea114add2012-05-03 15:00:40 -0700450 // Load the displacement from the switch table
451 int dispReg = oatAllocTemp(cUnit);
452 loadBaseIndexed(cUnit, tableBase, keyReg, dispReg, 2, kWord);
buzbee67bf8852011-08-17 17:51:35 -0700453
Bill Buzbeea114add2012-05-03 15:00:40 -0700454 // ..and go! NOTE: No instruction set switch here - must stay Thumb2
455 LIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, dispReg);
456 tabRec->anchor = switchBranch;
buzbee67bf8852011-08-17 17:51:35 -0700457
Bill Buzbeea114add2012-05-03 15:00:40 -0700458 /* branchOver target here */
459 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
460 branchOver->target = (LIR*)target;
buzbee67bf8852011-08-17 17:51:35 -0700461}
462
463/*
464 * Array data table format:
465 * ushort ident = 0x0300 magic value
466 * ushort width width of each element in the table
467 * uint size number of elements in the table
468 * ubyte data[size*width] table of data values (may contain a single-byte
469 * padding at the end)
470 *
471 * Total size is 4+(width * size + 1)/2 16-bit code units.
472 */
buzbee408ad162012-06-06 16:45:18 -0700473void genFillArrayData(CompilationUnit* cUnit, uint32_t tableOffset, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700474{
buzbee408ad162012-06-06 16:45:18 -0700475 const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700476 // Add the table to the list - we'll process it later
477 FillArrayData *tabRec = (FillArrayData *)
478 oatNew(cUnit, sizeof(FillArrayData), true, kAllocData);
479 tabRec->table = table;
buzbee408ad162012-06-06 16:45:18 -0700480 tabRec->vaddr = cUnit->currentDalvikOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700481 u2 width = tabRec->table[1];
482 u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
483 tabRec->size = (size * width) + 8;
buzbee67bf8852011-08-17 17:51:35 -0700484
Bill Buzbeea114add2012-05-03 15:00:40 -0700485 oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700486
Bill Buzbeea114add2012-05-03 15:00:40 -0700487 // Making a call - use explicit registers
488 oatFlushAllRegs(cUnit); /* Everything to home location */
489 loadValueDirectFixed(cUnit, rlSrc, r0);
490 loadWordDisp(cUnit, rSELF, ENTRYPOINT_OFFSET(pHandleFillArrayDataFromCode),
491 rLR);
492 // Materialize a pointer to the fill data image
493 newLIR3(cUnit, kThumb2Adr, r1, 0, (intptr_t)tabRec);
494 oatClobberCalleeSave(cUnit);
buzbee8320f382012-09-11 16:29:42 -0700495 LIR* callInst = opReg(cUnit, kOpBlx, rLR);
496 markSafepointPC(cUnit, callInst);
buzbee67bf8852011-08-17 17:51:35 -0700497}
498
buzbee31a4a6f2012-02-28 15:36:15 -0800499void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700500{
Bill Buzbeea114add2012-05-03 15:00:40 -0700501 RegLocation rlResult;
502 rlSrc = loadValue(cUnit, rlSrc, kFPReg);
503 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
504 newLIR2(cUnit, kThumb2Vnegs, rlResult.lowReg, rlSrc.lowReg);
505 storeValue(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -0700506}
507
buzbee31a4a6f2012-02-28 15:36:15 -0800508void genNegDouble(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700509{
Bill Buzbeea114add2012-05-03 15:00:40 -0700510 RegLocation rlResult;
511 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
512 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
513 newLIR2(cUnit, kThumb2Vnegd, S2D(rlResult.lowReg, rlResult.highReg),
514 S2D(rlSrc.lowReg, rlSrc.highReg));
515 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -0700516}
517
buzbee67bf8852011-08-17 17:51:35 -0700518/*
519 * Handle simple case (thin lock) inline. If it's complicated, bail
520 * out to the heavyweight lock/unlock routines. We'll use dedicated
521 * registers here in order to be in the right position in case we
522 * to bail to dvm[Lock/Unlock]Object(self, object)
523 *
524 * r0 -> self pointer [arg0 for dvm[Lock/Unlock]Object
525 * r1 -> object [arg1 for dvm[Lock/Unlock]Object
526 * r2 -> intial contents of object->lock, later result of strex
527 * r3 -> self->threadId
528 * r12 -> allow to be used by utilities as general temp
529 *
530 * The result of the strex is 0 if we acquire the lock.
531 *
532 * See comments in Sync.c for the layout of the lock word.
533 * Of particular interest to this code is the test for the
534 * simple case - which we handle inline. For monitor enter, the
535 * simple case is thin lock, held by no-one. For monitor exit,
536 * the simple case is thin lock, held by the unlocking thread with
537 * a recurse count of 0.
538 *
539 * A minor complication is that there is a field in the lock word
540 * unrelated to locking: the hash state. This field must be ignored, but
541 * preserved.
542 *
543 */
buzbee408ad162012-06-06 16:45:18 -0700544void genMonitorEnter(CompilationUnit* cUnit, int optFlags, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700545{
Bill Buzbeea114add2012-05-03 15:00:40 -0700546 oatFlushAllRegs(cUnit);
547 DCHECK_EQ(LW_SHAPE_THIN, 0);
548 loadValueDirectFixed(cUnit, rlSrc, r0); // Get obj
549 oatLockCallTemps(cUnit); // Prepare for explicit register usage
buzbee408ad162012-06-06 16:45:18 -0700550 genNullCheck(cUnit, rlSrc.sRegLow, r0, optFlags);
Bill Buzbeea114add2012-05-03 15:00:40 -0700551 loadWordDisp(cUnit, rSELF, Thread::ThinLockIdOffset().Int32Value(), r2);
552 newLIR3(cUnit, kThumb2Ldrex, r1, r0,
553 Object::MonitorOffset().Int32Value() >> 2); // Get object->lock
554 // Align owner
555 opRegImm(cUnit, kOpLsl, r2, LW_LOCK_OWNER_SHIFT);
556 // Is lock unheld on lock or held by us (==threadId) on unlock?
557 newLIR4(cUnit, kThumb2Bfi, r2, r1, 0, LW_LOCK_OWNER_SHIFT - 1);
558 newLIR3(cUnit, kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
559 opRegImm(cUnit, kOpCmp, r1, 0);
560 opIT(cUnit, kArmCondEq, "");
561 newLIR4(cUnit, kThumb2Strex, r1, r2, r0,
562 Object::MonitorOffset().Int32Value() >> 2);
563 opRegImm(cUnit, kOpCmp, r1, 0);
564 opIT(cUnit, kArmCondNe, "T");
565 // Go expensive route - artLockObjectFromCode(self, obj);
566 loadWordDisp(cUnit, rSELF, ENTRYPOINT_OFFSET(pLockObjectFromCode), rLR);
567 oatClobberCalleeSave(cUnit);
buzbee8320f382012-09-11 16:29:42 -0700568 LIR* callInst = opReg(cUnit, kOpBlx, rLR);
569 markSafepointPC(cUnit, callInst);
Bill Buzbeea114add2012-05-03 15:00:40 -0700570 oatGenMemBarrier(cUnit, kSY);
buzbee67bf8852011-08-17 17:51:35 -0700571}
572
573/*
574 * For monitor unlock, we don't have to use ldrex/strex. Once
575 * we've determined that the lock is thin and that we own it with
576 * a zero recursion count, it's safe to punch it back to the
577 * initial, unlock thin state with a store word.
578 */
buzbee408ad162012-06-06 16:45:18 -0700579void genMonitorExit(CompilationUnit* cUnit, int optFlags, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700580{
Bill Buzbeea114add2012-05-03 15:00:40 -0700581 DCHECK_EQ(LW_SHAPE_THIN, 0);
582 oatFlushAllRegs(cUnit);
583 loadValueDirectFixed(cUnit, rlSrc, r0); // Get obj
584 oatLockCallTemps(cUnit); // Prepare for explicit register usage
buzbee408ad162012-06-06 16:45:18 -0700585 genNullCheck(cUnit, rlSrc.sRegLow, r0, optFlags);
Bill Buzbeea114add2012-05-03 15:00:40 -0700586 loadWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r1); // Get lock
587 loadWordDisp(cUnit, rSELF, Thread::ThinLockIdOffset().Int32Value(), r2);
588 // Is lock unheld on lock or held by us (==threadId) on unlock?
589 opRegRegImm(cUnit, kOpAnd, r3, r1,
590 (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
591 // Align owner
592 opRegImm(cUnit, kOpLsl, r2, LW_LOCK_OWNER_SHIFT);
593 newLIR3(cUnit, kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
594 opRegReg(cUnit, kOpSub, r1, r2);
595 opIT(cUnit, kArmCondEq, "EE");
596 storeWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r3);
597 // Go expensive route - UnlockObjectFromCode(obj);
598 loadWordDisp(cUnit, rSELF, ENTRYPOINT_OFFSET(pUnlockObjectFromCode), rLR);
599 oatClobberCalleeSave(cUnit);
buzbee8320f382012-09-11 16:29:42 -0700600 LIR* callInst = opReg(cUnit, kOpBlx, rLR);
601 markSafepointPC(cUnit, callInst);
Bill Buzbeea114add2012-05-03 15:00:40 -0700602 oatGenMemBarrier(cUnit, kSY);
buzbee67bf8852011-08-17 17:51:35 -0700603}
604
605/*
606 * 64-bit 3way compare function.
607 * mov rX, #-1
608 * cmp op1hi, op2hi
609 * blt done
610 * bgt flip
611 * sub rX, op1lo, op2lo (treat as unsigned)
612 * beq done
613 * ite hi
614 * mov(hi) rX, #-1
615 * mov(!hi) rX, #1
616 * flip:
617 * neg rX
618 * done:
619 */
buzbee408ad162012-06-06 16:45:18 -0700620void genCmpLong(CompilationUnit* cUnit, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -0700621 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee67bf8852011-08-17 17:51:35 -0700622{
Bill Buzbeea114add2012-05-03 15:00:40 -0700623 LIR* target1;
624 LIR* target2;
625 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
626 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
627 int tReg = oatAllocTemp(cUnit);
628 loadConstant(cUnit, tReg, -1);
629 opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg);
630 LIR* branch1 = opCondBranch(cUnit, kCondLt, NULL);
631 LIR* branch2 = opCondBranch(cUnit, kCondGt, NULL);
632 opRegRegReg(cUnit, kOpSub, tReg, rlSrc1.lowReg, rlSrc2.lowReg);
633 LIR* branch3 = opCondBranch(cUnit, kCondEq, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700634
Bill Buzbeea114add2012-05-03 15:00:40 -0700635 opIT(cUnit, kArmCondHi, "E");
636 newLIR2(cUnit, kThumb2MovImmShift, tReg, modifiedImmediate(-1));
637 loadConstant(cUnit, tReg, 1);
638 genBarrier(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700639
Bill Buzbeea114add2012-05-03 15:00:40 -0700640 target2 = newLIR0(cUnit, kPseudoTargetLabel);
641 opRegReg(cUnit, kOpNeg, tReg, tReg);
buzbee67bf8852011-08-17 17:51:35 -0700642
Bill Buzbeea114add2012-05-03 15:00:40 -0700643 target1 = newLIR0(cUnit, kPseudoTargetLabel);
buzbee67bf8852011-08-17 17:51:35 -0700644
Bill Buzbeea114add2012-05-03 15:00:40 -0700645 RegLocation rlTemp = LOC_C_RETURN; // Just using as template, will change
646 rlTemp.lowReg = tReg;
647 storeValue(cUnit, rlDest, rlTemp);
648 oatFreeTemp(cUnit, tReg);
buzbee67bf8852011-08-17 17:51:35 -0700649
Bill Buzbeea114add2012-05-03 15:00:40 -0700650 branch1->target = (LIR*)target1;
651 branch2->target = (LIR*)target2;
652 branch3->target = branch1->target;
buzbee67bf8852011-08-17 17:51:35 -0700653}
654
buzbee84fd6932012-03-29 16:44:16 -0700655void genFusedLongCmpBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir)
656{
buzbeea1da8a52012-07-09 14:00:21 -0700657 LIR* labelList = cUnit->blockLabelList;
Bill Buzbeea114add2012-05-03 15:00:40 -0700658 LIR* taken = &labelList[bb->taken->id];
659 LIR* notTaken = &labelList[bb->fallThrough->id];
buzbee15bf9802012-06-12 17:49:27 -0700660 RegLocation rlSrc1 = oatGetSrcWide(cUnit, mir, 0);
661 RegLocation rlSrc2 = oatGetSrcWide(cUnit, mir, 2);
Bill Buzbeea114add2012-05-03 15:00:40 -0700662 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
663 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
664 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
665 opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg);
666 switch(ccode) {
667 case kCondEq:
668 opCondBranch(cUnit, kCondNe, notTaken);
669 break;
670 case kCondNe:
671 opCondBranch(cUnit, kCondNe, taken);
672 break;
673 case kCondLt:
674 opCondBranch(cUnit, kCondLt, taken);
675 opCondBranch(cUnit, kCondGt, notTaken);
676 ccode = kCondCc;
677 break;
678 case kCondLe:
679 opCondBranch(cUnit, kCondLt, taken);
680 opCondBranch(cUnit, kCondGt, notTaken);
681 ccode = kCondLs;
682 break;
683 case kCondGt:
684 opCondBranch(cUnit, kCondGt, taken);
685 opCondBranch(cUnit, kCondLt, notTaken);
686 ccode = kCondHi;
687 break;
688 case kCondGe:
689 opCondBranch(cUnit, kCondGt, taken);
690 opCondBranch(cUnit, kCondLt, notTaken);
691 ccode = kCondCs;
692 break;
693 default:
694 LOG(FATAL) << "Unexpected ccode: " << (int)ccode;
695 }
696 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
697 opCondBranch(cUnit, ccode, taken);
buzbee84fd6932012-03-29 16:44:16 -0700698}
699
buzbee67bf8852011-08-17 17:51:35 -0700700/*
buzbee31a4a6f2012-02-28 15:36:15 -0800701 * Generate a register comparison to an immediate and branch. Caller
702 * is responsible for setting branch target field.
buzbee67bf8852011-08-17 17:51:35 -0700703 */
buzbee82488f52012-03-02 08:20:26 -0800704LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg,
Bill Buzbeea114add2012-05-03 15:00:40 -0700705 int checkValue, LIR* target)
buzbee67bf8852011-08-17 17:51:35 -0700706{
Bill Buzbeea114add2012-05-03 15:00:40 -0700707 LIR* branch;
708 int modImm;
709 ArmConditionCode armCond = oatArmConditionEncoding(cond);
710 if ((LOWREG(reg)) && (checkValue == 0) &&
711 ((armCond == kArmCondEq) || (armCond == kArmCondNe))) {
712 branch = newLIR2(cUnit, (armCond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
713 reg, 0);
714 } else {
715 modImm = modifiedImmediate(checkValue);
716 if (LOWREG(reg) && ((checkValue & 0xff) == checkValue)) {
717 newLIR2(cUnit, kThumbCmpRI8, reg, checkValue);
718 } else if (modImm >= 0) {
719 newLIR2(cUnit, kThumb2CmpRI8, reg, modImm);
buzbee67bf8852011-08-17 17:51:35 -0700720 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700721 int tReg = oatAllocTemp(cUnit);
722 loadConstant(cUnit, tReg, checkValue);
723 opRegReg(cUnit, kOpCmp, reg, tReg);
buzbee67bf8852011-08-17 17:51:35 -0700724 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700725 branch = newLIR2(cUnit, kThumbBCond, 0, armCond);
726 }
727 branch->target = target;
728 return branch;
buzbee31a4a6f2012-02-28 15:36:15 -0800729}
buzbee82488f52012-03-02 08:20:26 -0800730LIR* opRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
buzbee31a4a6f2012-02-28 15:36:15 -0800731{
Bill Buzbeea114add2012-05-03 15:00:40 -0700732 LIR* res;
733 ArmOpcode opcode;
734 if (FPREG(rDest) || FPREG(rSrc))
735 return fpRegCopy(cUnit, rDest, rSrc);
736 if (LOWREG(rDest) && LOWREG(rSrc))
737 opcode = kThumbMovRR;
738 else if (!LOWREG(rDest) && !LOWREG(rSrc))
739 opcode = kThumbMovRR_H2H;
740 else if (LOWREG(rDest))
741 opcode = kThumbMovRR_H2L;
742 else
743 opcode = kThumbMovRR_L2H;
744 res = rawLIR(cUnit, cUnit->currentDalvikOffset, opcode, rDest, rSrc);
745 if (!(cUnit->disableOpt & (1 << kSafeOptimizations)) && rDest == rSrc) {
746 res->flags.isNop = true;
747 }
748 return res;
buzbee67bf8852011-08-17 17:51:35 -0700749}
750
buzbee82488f52012-03-02 08:20:26 -0800751LIR* opRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
buzbee67bf8852011-08-17 17:51:35 -0700752{
Bill Buzbeea114add2012-05-03 15:00:40 -0700753 LIR* res = opRegCopyNoInsert(cUnit, rDest, rSrc);
754 oatAppendLIR(cUnit, (LIR*)res);
755 return res;
buzbee31a4a6f2012-02-28 15:36:15 -0800756}
buzbee67bf8852011-08-17 17:51:35 -0700757
buzbee82488f52012-03-02 08:20:26 -0800758void opRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
Bill Buzbeea114add2012-05-03 15:00:40 -0700759 int srcLo, int srcHi)
buzbee31a4a6f2012-02-28 15:36:15 -0800760{
Bill Buzbeea114add2012-05-03 15:00:40 -0700761 bool destFP = FPREG(destLo) && FPREG(destHi);
762 bool srcFP = FPREG(srcLo) && FPREG(srcHi);
763 DCHECK_EQ(FPREG(srcLo), FPREG(srcHi));
764 DCHECK_EQ(FPREG(destLo), FPREG(destHi));
765 if (destFP) {
766 if (srcFP) {
767 opRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
buzbee31a4a6f2012-02-28 15:36:15 -0800768 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700769 newLIR3(cUnit, kThumb2Fmdrr, S2D(destLo, destHi), srcLo, srcHi);
buzbee67bf8852011-08-17 17:51:35 -0700770 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700771 } else {
772 if (srcFP) {
773 newLIR3(cUnit, kThumb2Fmrrd, destLo, destHi, S2D(srcLo, srcHi));
774 } else {
775 // Handle overlap
776 if (srcHi == destLo) {
777 opRegCopy(cUnit, destHi, srcHi);
778 opRegCopy(cUnit, destLo, srcLo);
779 } else {
780 opRegCopy(cUnit, destLo, srcLo);
781 opRegCopy(cUnit, destHi, srcHi);
782 }
783 }
784 }
buzbee67bf8852011-08-17 17:51:35 -0700785}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800786
buzbeef3aac972012-04-11 16:33:36 -0700787// Table of magic divisors
788enum DividePattern {
Bill Buzbeea114add2012-05-03 15:00:40 -0700789 DivideNone,
790 Divide3,
791 Divide5,
792 Divide7,
buzbeef3aac972012-04-11 16:33:36 -0700793};
794
795struct MagicTable {
Bill Buzbeea114add2012-05-03 15:00:40 -0700796 uint32_t magic;
797 uint32_t shift;
798 DividePattern pattern;
buzbeef3aac972012-04-11 16:33:36 -0700799};
800
801static const MagicTable magicTable[] = {
Bill Buzbeea114add2012-05-03 15:00:40 -0700802 {0, 0, DivideNone}, // 0
803 {0, 0, DivideNone}, // 1
804 {0, 0, DivideNone}, // 2
805 {0x55555556, 0, Divide3}, // 3
806 {0, 0, DivideNone}, // 4
807 {0x66666667, 1, Divide5}, // 5
808 {0x2AAAAAAB, 0, Divide3}, // 6
809 {0x92492493, 2, Divide7}, // 7
810 {0, 0, DivideNone}, // 8
811 {0x38E38E39, 1, Divide5}, // 9
812 {0x66666667, 2, Divide5}, // 10
813 {0x2E8BA2E9, 1, Divide5}, // 11
814 {0x2AAAAAAB, 1, Divide5}, // 12
815 {0x4EC4EC4F, 2, Divide5}, // 13
816 {0x92492493, 3, Divide7}, // 14
817 {0x88888889, 3, Divide7}, // 15
buzbeef3aac972012-04-11 16:33:36 -0700818};
819
820// Integer division by constant via reciprocal multiply (Hacker's Delight, 10-4)
821bool smallLiteralDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode,
822 RegLocation rlSrc, RegLocation rlDest, int lit)
823{
Bill Buzbeea114add2012-05-03 15:00:40 -0700824 if ((lit < 0) || (lit >= (int)(sizeof(magicTable)/sizeof(magicTable[0])))) {
825 return false;
826 }
827 DividePattern pattern = magicTable[lit].pattern;
828 if (pattern == DivideNone) {
829 return false;
830 }
831 // Tuning: add rem patterns
832 if (dalvikOpcode != Instruction::DIV_INT_LIT8) {
833 return false;
834 }
buzbeef3aac972012-04-11 16:33:36 -0700835
Bill Buzbeea114add2012-05-03 15:00:40 -0700836 int rMagic = oatAllocTemp(cUnit);
837 loadConstant(cUnit, rMagic, magicTable[lit].magic);
838 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
839 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
840 int rHi = oatAllocTemp(cUnit);
841 int rLo = oatAllocTemp(cUnit);
842 newLIR4(cUnit, kThumb2Smull, rLo, rHi, rMagic, rlSrc.lowReg);
843 switch(pattern) {
844 case Divide3:
845 opRegRegRegShift(cUnit, kOpSub, rlResult.lowReg, rHi,
846 rlSrc.lowReg, encodeShift(kArmAsr, 31));
847 break;
848 case Divide5:
849 opRegRegImm(cUnit, kOpAsr, rLo, rlSrc.lowReg, 31);
850 opRegRegRegShift(cUnit, kOpRsub, rlResult.lowReg, rLo, rHi,
851 encodeShift(kArmAsr, magicTable[lit].shift));
852 break;
853 case Divide7:
854 opRegReg(cUnit, kOpAdd, rHi, rlSrc.lowReg);
855 opRegRegImm(cUnit, kOpAsr, rLo, rlSrc.lowReg, 31);
856 opRegRegRegShift(cUnit, kOpRsub, rlResult.lowReg, rLo, rHi,
857 encodeShift(kArmAsr, magicTable[lit].shift));
858 break;
859 default:
860 LOG(FATAL) << "Unexpected pattern: " << (int)pattern;
861 }
862 storeValue(cUnit, rlDest, rlResult);
863 return true;
buzbeef3aac972012-04-11 16:33:36 -0700864}
buzbee31a4a6f2012-02-28 15:36:15 -0800865
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800866} // namespace art