blob: 838fcafa3849d92331447357ef3cf1ffe72aab4c [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * This file contains codegen for the Thumb2 ISA and is intended to be
19 * includes by:
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 */
24
Logan Chien4dd96f52012-02-29 01:26:58 +080025#include "oat_compilation_unit.h"
26
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080027namespace art {
28
buzbee67bf8852011-08-17 17:51:35 -070029
30/*
31 * Generate a Thumb2 IT instruction, which can nullify up to
32 * four subsequent instructions based on a condition and its
33 * inverse. The condition applies to the first instruction, which
34 * is executed if the condition is met. The string "guide" consists
35 * of 0 to 3 chars, and applies to the 2nd through 4th instruction.
36 * A "T" means the instruction is executed if the condition is
37 * met, and an "E" means the instruction is executed if the condition
38 * is not met.
39 */
buzbee82488f52012-03-02 08:20:26 -080040LIR* opIT(CompilationUnit* cUnit, ArmConditionCode code, const char* guide)
buzbee67bf8852011-08-17 17:51:35 -070041{
42 int mask;
43 int condBit = code & 1;
44 int altBit = condBit ^ 1;
45 int mask3 = 0;
46 int mask2 = 0;
47 int mask1 = 0;
48
49 //Note: case fallthroughs intentional
50 switch(strlen(guide)) {
51 case 3:
52 mask1 = (guide[2] == 'T') ? condBit : altBit;
53 case 2:
54 mask2 = (guide[1] == 'T') ? condBit : altBit;
55 case 1:
56 mask3 = (guide[0] == 'T') ? condBit : altBit;
57 break;
58 case 0:
59 break;
60 default:
buzbee82488f52012-03-02 08:20:26 -080061 LOG(FATAL) << "OAT: bad case in opIT";
buzbee67bf8852011-08-17 17:51:35 -070062 }
63 mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
64 (1 << (3 - strlen(guide)));
65 return newLIR2(cUnit, kThumb2It, code, mask);
66}
67
68/*
buzbee67bf8852011-08-17 17:51:35 -070069 * The sparse table in the literal pool is an array of <key,displacement>
70 * pairs. For each set, we'll load them as a pair using ldmia.
71 * This means that the register number of the temp we use for the key
72 * must be lower than the reg for the displacement.
73 *
74 * The test loop will look something like:
75 *
76 * adr rBase, <table>
77 * ldr rVal, [rSP, vRegOff]
78 * mov rIdx, #tableSize
79 * lp:
80 * ldmia rBase!, {rKey, rDisp}
81 * sub rIdx, #1
82 * cmp rVal, rKey
83 * ifeq
84 * add rPC, rDisp ; This is the branch from which we compute displacement
85 * cbnz rIdx, lp
86 */
buzbee31a4a6f2012-02-28 15:36:15 -080087void genSparseSwitch(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -070088{
89 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
90 if (cUnit->printMe) {
91 dumpSparseSwitchTable(table);
92 }
93 // Add the table to the list - we'll process it later
buzbeeba938cb2012-02-03 14:47:55 -080094 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
buzbee5abfa3e2012-01-31 17:01:43 -080095 true, kAllocData);
buzbee67bf8852011-08-17 17:51:35 -070096 tabRec->table = table;
97 tabRec->vaddr = mir->offset;
98 int size = table[1];
buzbee31a4a6f2012-02-28 15:36:15 -080099 tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true,
100 kAllocLIR);
buzbeeba938cb2012-02-03 14:47:55 -0800101 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700102
103 // Get the switch value
104 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
105 int rBase = oatAllocTemp(cUnit);
106 /* Allocate key and disp temps */
107 int rKey = oatAllocTemp(cUnit);
108 int rDisp = oatAllocTemp(cUnit);
109 // Make sure rKey's register number is less than rDisp's number for ldmia
110 if (rKey > rDisp) {
111 int tmp = rDisp;
112 rDisp = rKey;
113 rKey = tmp;
114 }
115 // Materialize a pointer to the switch table
buzbee03fa2632011-09-20 17:10:57 -0700116 newLIR3(cUnit, kThumb2Adr, rBase, 0, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700117 // Set up rIdx
118 int rIdx = oatAllocTemp(cUnit);
119 loadConstant(cUnit, rIdx, size);
120 // Establish loop branch target
buzbee31a4a6f2012-02-28 15:36:15 -0800121 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee67bf8852011-08-17 17:51:35 -0700122 target->defMask = ENCODE_ALL;
123 // Load next key/disp
124 newLIR2(cUnit, kThumb2LdmiaWB, rBase, (1 << rKey) | (1 << rDisp));
125 opRegReg(cUnit, kOpCmp, rKey, rlSrc.lowReg);
126 // Go if match. NOTE: No instruction set switch here - must stay Thumb2
buzbee82488f52012-03-02 08:20:26 -0800127 opIT(cUnit, kArmCondEq, "");
buzbee31a4a6f2012-02-28 15:36:15 -0800128 LIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, rDisp);
buzbee67bf8852011-08-17 17:51:35 -0700129 tabRec->bxInst = switchBranch;
130 // Needs to use setflags encoding here
131 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
buzbee82488f52012-03-02 08:20:26 -0800132 opCondBranch(cUnit, kCondNe, target);
buzbee67bf8852011-08-17 17:51:35 -0700133}
134
135
buzbee31a4a6f2012-02-28 15:36:15 -0800136void genPackedSwitch(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700137{
138 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
139 if (cUnit->printMe) {
140 dumpPackedSwitchTable(table);
141 }
142 // Add the table to the list - we'll process it later
buzbeeba938cb2012-02-03 14:47:55 -0800143 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
buzbee5abfa3e2012-01-31 17:01:43 -0800144 true, kAllocData);
buzbee67bf8852011-08-17 17:51:35 -0700145 tabRec->table = table;
146 tabRec->vaddr = mir->offset;
147 int size = table[1];
buzbee31a4a6f2012-02-28 15:36:15 -0800148 tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true,
buzbee5abfa3e2012-01-31 17:01:43 -0800149 kAllocLIR);
buzbeeba938cb2012-02-03 14:47:55 -0800150 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700151
152 // Get the switch value
153 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
154 int tableBase = oatAllocTemp(cUnit);
155 // Materialize a pointer to the switch table
buzbee03fa2632011-09-20 17:10:57 -0700156 newLIR3(cUnit, kThumb2Adr, tableBase, 0, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700157 int lowKey = s4FromSwitchData(&table[2]);
158 int keyReg;
159 // Remove the bias, if necessary
160 if (lowKey == 0) {
161 keyReg = rlSrc.lowReg;
162 } else {
163 keyReg = oatAllocTemp(cUnit);
164 opRegRegImm(cUnit, kOpSub, keyReg, rlSrc.lowReg, lowKey);
165 }
166 // Bounds check - if < 0 or >= size continue following switch
167 opRegImm(cUnit, kOpCmp, keyReg, size-1);
buzbee82488f52012-03-02 08:20:26 -0800168 LIR* branchOver = opCondBranch(cUnit, kCondHi, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700169
170 // Load the displacement from the switch table
171 int dispReg = oatAllocTemp(cUnit);
172 loadBaseIndexed(cUnit, tableBase, keyReg, dispReg, 2, kWord);
173
174 // ..and go! NOTE: No instruction set switch here - must stay Thumb2
buzbee31a4a6f2012-02-28 15:36:15 -0800175 LIR* switchBranch = newLIR1(cUnit, kThumb2AddPCR, dispReg);
buzbee67bf8852011-08-17 17:51:35 -0700176 tabRec->bxInst = switchBranch;
177
178 /* branchOver target here */
buzbee31a4a6f2012-02-28 15:36:15 -0800179 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee67bf8852011-08-17 17:51:35 -0700180 target->defMask = ENCODE_ALL;
buzbee31a4a6f2012-02-28 15:36:15 -0800181 branchOver->target = (LIR*)target;
buzbee67bf8852011-08-17 17:51:35 -0700182}
183
184/*
185 * Array data table format:
186 * ushort ident = 0x0300 magic value
187 * ushort width width of each element in the table
188 * uint size number of elements in the table
189 * ubyte data[size*width] table of data values (may contain a single-byte
190 * padding at the end)
191 *
192 * Total size is 4+(width * size + 1)/2 16-bit code units.
193 */
buzbee31a4a6f2012-02-28 15:36:15 -0800194void genFillArrayData(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700195{
196 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
197 // Add the table to the list - we'll process it later
198 FillArrayData *tabRec = (FillArrayData *)
buzbeeba938cb2012-02-03 14:47:55 -0800199 oatNew(cUnit, sizeof(FillArrayData), true, kAllocData);
buzbee67bf8852011-08-17 17:51:35 -0700200 tabRec->table = table;
201 tabRec->vaddr = mir->offset;
202 u2 width = tabRec->table[1];
203 u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
204 tabRec->size = (size * width) + 8;
205
buzbeeba938cb2012-02-03 14:47:55 -0800206 oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec);
buzbee67bf8852011-08-17 17:51:35 -0700207
208 // Making a call - use explicit registers
209 oatFlushAllRegs(cUnit); /* Everything to home location */
210 loadValueDirectFixed(cUnit, rlSrc, r0);
211 loadWordDisp(cUnit, rSELF,
buzbee1b4c8592011-08-31 10:43:51 -0700212 OFFSETOF_MEMBER(Thread, pHandleFillArrayDataFromCode), rLR);
buzbeee6d61962011-08-27 11:58:19 -0700213 // Materialize a pointer to the fill data image
buzbee03fa2632011-09-20 17:10:57 -0700214 newLIR3(cUnit, kThumb2Adr, r1, 0, (intptr_t)tabRec);
Ian Rogersff1ed472011-09-20 13:46:24 -0700215 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700216}
217
buzbee31a4a6f2012-02-28 15:36:15 -0800218void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700219{
220 RegLocation rlResult;
221 rlSrc = loadValue(cUnit, rlSrc, kFPReg);
222 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
223 newLIR2(cUnit, kThumb2Vnegs, rlResult.lowReg, rlSrc.lowReg);
224 storeValue(cUnit, rlDest, rlResult);
225}
226
buzbee31a4a6f2012-02-28 15:36:15 -0800227void genNegDouble(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700228{
229 RegLocation rlResult;
230 rlSrc = loadValueWide(cUnit, rlSrc, kFPReg);
231 rlResult = oatEvalLoc(cUnit, rlDest, kFPReg, true);
232 newLIR2(cUnit, kThumb2Vnegd, S2D(rlResult.lowReg, rlResult.highReg),
233 S2D(rlSrc.lowReg, rlSrc.highReg));
234 storeValueWide(cUnit, rlDest, rlResult);
235}
236
buzbee67bf8852011-08-17 17:51:35 -0700237/*
238 * Handle simple case (thin lock) inline. If it's complicated, bail
239 * out to the heavyweight lock/unlock routines. We'll use dedicated
240 * registers here in order to be in the right position in case we
241 * to bail to dvm[Lock/Unlock]Object(self, object)
242 *
243 * r0 -> self pointer [arg0 for dvm[Lock/Unlock]Object
244 * r1 -> object [arg1 for dvm[Lock/Unlock]Object
245 * r2 -> intial contents of object->lock, later result of strex
246 * r3 -> self->threadId
247 * r12 -> allow to be used by utilities as general temp
248 *
249 * The result of the strex is 0 if we acquire the lock.
250 *
251 * See comments in Sync.c for the layout of the lock word.
252 * Of particular interest to this code is the test for the
253 * simple case - which we handle inline. For monitor enter, the
254 * simple case is thin lock, held by no-one. For monitor exit,
255 * the simple case is thin lock, held by the unlocking thread with
256 * a recurse count of 0.
257 *
258 * A minor complication is that there is a field in the lock word
259 * unrelated to locking: the hash state. This field must be ignored, but
260 * preserved.
261 *
262 */
buzbee31a4a6f2012-02-28 15:36:15 -0800263void genMonitorEnter(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700264{
buzbee31a4a6f2012-02-28 15:36:15 -0800265 LIR* target;
266 LIR* hopTarget;
267 LIR* branch;
268 LIR* hopBranch;
buzbee67bf8852011-08-17 17:51:35 -0700269
270 oatFlushAllRegs(cUnit);
Elliott Hughes5f791332011-09-15 17:45:30 -0700271 DCHECK_EQ(LW_SHAPE_THIN, 0);
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700272 loadValueDirectFixed(cUnit, rlSrc, r0); // Get obj
buzbee2e748f32011-08-29 21:02:19 -0700273 oatLockCallTemps(cUnit); // Prepare for explicit register usage
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700274 genNullCheck(cUnit, rlSrc.sRegLow, r0, mir);
275 loadWordDisp(cUnit, rSELF, Thread::ThinLockIdOffset().Int32Value(), r2);
276 newLIR3(cUnit, kThumb2Ldrex, r1, r0,
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700277 Object::MonitorOffset().Int32Value() >> 2); // Get object->lock
buzbeec143c552011-08-20 17:38:58 -0700278 // Align owner
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700279 opRegImm(cUnit, kOpLsl, r2, LW_LOCK_OWNER_SHIFT);
buzbee67bf8852011-08-17 17:51:35 -0700280 // Is lock unheld on lock or held by us (==threadId) on unlock?
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700281 newLIR4(cUnit, kThumb2Bfi, r2, r1, 0, LW_LOCK_OWNER_SHIFT - 1);
282 newLIR3(cUnit, kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
283 hopBranch = newLIR2(cUnit, kThumb2Cbnz, r1, 0);
284 newLIR4(cUnit, kThumb2Strex, r1, r2, r0,
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700285 Object::MonitorOffset().Int32Value() >> 2);
buzbee67bf8852011-08-17 17:51:35 -0700286 oatGenMemBarrier(cUnit, kSY);
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700287 branch = newLIR2(cUnit, kThumb2Cbz, r1, 0);
buzbee67bf8852011-08-17 17:51:35 -0700288
buzbee31a4a6f2012-02-28 15:36:15 -0800289 hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee67bf8852011-08-17 17:51:35 -0700290 hopTarget->defMask = ENCODE_ALL;
buzbee31a4a6f2012-02-28 15:36:15 -0800291 hopBranch->target = (LIR*)hopTarget;
buzbee67bf8852011-08-17 17:51:35 -0700292
buzbee1b4c8592011-08-31 10:43:51 -0700293 // Go expensive route - artLockObjectFromCode(self, obj);
294 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pLockObjectFromCode),
buzbee67bf8852011-08-17 17:51:35 -0700295 rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -0700296 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700297
298 // Resume here
buzbee31a4a6f2012-02-28 15:36:15 -0800299 target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee67bf8852011-08-17 17:51:35 -0700300 target->defMask = ENCODE_ALL;
buzbee31a4a6f2012-02-28 15:36:15 -0800301 branch->target = (LIR*)target;
buzbee67bf8852011-08-17 17:51:35 -0700302}
303
304/*
305 * For monitor unlock, we don't have to use ldrex/strex. Once
306 * we've determined that the lock is thin and that we own it with
307 * a zero recursion count, it's safe to punch it back to the
308 * initial, unlock thin state with a store word.
309 */
buzbee31a4a6f2012-02-28 15:36:15 -0800310void genMonitorExit(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700311{
buzbee31a4a6f2012-02-28 15:36:15 -0800312 LIR* target;
313 LIR* branch;
314 LIR* hopTarget;
315 LIR* hopBranch;
buzbee67bf8852011-08-17 17:51:35 -0700316
Elliott Hughes5f791332011-09-15 17:45:30 -0700317 DCHECK_EQ(LW_SHAPE_THIN, 0);
buzbee67bf8852011-08-17 17:51:35 -0700318 oatFlushAllRegs(cUnit);
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700319 loadValueDirectFixed(cUnit, rlSrc, r0); // Get obj
buzbee2e748f32011-08-29 21:02:19 -0700320 oatLockCallTemps(cUnit); // Prepare for explicit register usage
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700321 genNullCheck(cUnit, rlSrc.sRegLow, r0, mir);
322 loadWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r1); // Get lock
323 loadWordDisp(cUnit, rSELF, Thread::ThinLockIdOffset().Int32Value(), r2);
buzbee67bf8852011-08-17 17:51:35 -0700324 // Is lock unheld on lock or held by us (==threadId) on unlock?
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700325 opRegRegImm(cUnit, kOpAnd, r3, r1, (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
buzbeec143c552011-08-20 17:38:58 -0700326 // Align owner
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700327 opRegImm(cUnit, kOpLsl, r2, LW_LOCK_OWNER_SHIFT);
328 newLIR3(cUnit, kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1);
329 opRegReg(cUnit, kOpSub, r1, r2);
buzbee82488f52012-03-02 08:20:26 -0800330 hopBranch = opCondBranch(cUnit, kCondNe, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700331 oatGenMemBarrier(cUnit, kSY);
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700332 storeWordDisp(cUnit, r0, Object::MonitorOffset().Int32Value(), r3);
buzbee67bf8852011-08-17 17:51:35 -0700333 branch = opNone(cUnit, kOpUncondBr);
334
buzbee31a4a6f2012-02-28 15:36:15 -0800335 hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee67bf8852011-08-17 17:51:35 -0700336 hopTarget->defMask = ENCODE_ALL;
buzbee31a4a6f2012-02-28 15:36:15 -0800337 hopBranch->target = (LIR*)hopTarget;
buzbee67bf8852011-08-17 17:51:35 -0700338
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700339 // Go expensive route - UnlockObjectFromCode(obj);
buzbee1b4c8592011-08-31 10:43:51 -0700340 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pUnlockObjectFromCode),
buzbee67bf8852011-08-17 17:51:35 -0700341 rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -0700342 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700343
344 // Resume here
buzbee31a4a6f2012-02-28 15:36:15 -0800345 target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee67bf8852011-08-17 17:51:35 -0700346 target->defMask = ENCODE_ALL;
buzbee31a4a6f2012-02-28 15:36:15 -0800347 branch->target = (LIR*)target;
buzbee67bf8852011-08-17 17:51:35 -0700348}
349
350/*
351 * 64-bit 3way compare function.
352 * mov rX, #-1
353 * cmp op1hi, op2hi
354 * blt done
355 * bgt flip
356 * sub rX, op1lo, op2lo (treat as unsigned)
357 * beq done
358 * ite hi
359 * mov(hi) rX, #-1
360 * mov(!hi) rX, #1
361 * flip:
362 * neg rX
363 * done:
364 */
buzbee31a4a6f2012-02-28 15:36:15 -0800365void genCmpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
366 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee67bf8852011-08-17 17:51:35 -0700367{
buzbee31a4a6f2012-02-28 15:36:15 -0800368 LIR* target1;
369 LIR* target2;
buzbee67bf8852011-08-17 17:51:35 -0700370 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
371 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
buzbeeb29e4d12011-09-26 15:05:48 -0700372 int tReg = oatAllocTemp(cUnit);
373 loadConstant(cUnit, tReg, -1);
buzbee67bf8852011-08-17 17:51:35 -0700374 opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg);
buzbee82488f52012-03-02 08:20:26 -0800375 LIR* branch1 = opCondBranch(cUnit, kCondLt, NULL);
376 LIR* branch2 = opCondBranch(cUnit, kCondGt, NULL);
buzbeeb29e4d12011-09-26 15:05:48 -0700377 opRegRegReg(cUnit, kOpSub, tReg, rlSrc1.lowReg, rlSrc2.lowReg);
buzbee82488f52012-03-02 08:20:26 -0800378 LIR* branch3 = opCondBranch(cUnit, kCondEq, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700379
buzbee82488f52012-03-02 08:20:26 -0800380 opIT(cUnit, kArmCondHi, "E");
buzbeeb29e4d12011-09-26 15:05:48 -0700381 newLIR2(cUnit, kThumb2MovImmShift, tReg, modifiedImmediate(-1));
382 loadConstant(cUnit, tReg, 1);
buzbee67bf8852011-08-17 17:51:35 -0700383 genBarrier(cUnit);
384
buzbee31a4a6f2012-02-28 15:36:15 -0800385 target2 = newLIR0(cUnit, kPseudoTargetLabel);
buzbee67bf8852011-08-17 17:51:35 -0700386 target2->defMask = -1;
buzbeeb29e4d12011-09-26 15:05:48 -0700387 opRegReg(cUnit, kOpNeg, tReg, tReg);
buzbee67bf8852011-08-17 17:51:35 -0700388
buzbee31a4a6f2012-02-28 15:36:15 -0800389 target1 = newLIR0(cUnit, kPseudoTargetLabel);
buzbee67bf8852011-08-17 17:51:35 -0700390 target1->defMask = -1;
391
buzbeeb29e4d12011-09-26 15:05:48 -0700392 RegLocation rlTemp = LOC_C_RETURN; // Just using as template, will change
393 rlTemp.lowReg = tReg;
buzbee67bf8852011-08-17 17:51:35 -0700394 storeValue(cUnit, rlDest, rlTemp);
buzbeeb29e4d12011-09-26 15:05:48 -0700395 oatFreeTemp(cUnit, tReg);
buzbee67bf8852011-08-17 17:51:35 -0700396
buzbee31a4a6f2012-02-28 15:36:15 -0800397 branch1->target = (LIR*)target1;
398 branch2->target = (LIR*)target2;
399 branch3->target = branch1->target;
buzbee67bf8852011-08-17 17:51:35 -0700400}
401
buzbee67bf8852011-08-17 17:51:35 -0700402/*
buzbee31a4a6f2012-02-28 15:36:15 -0800403 * Generate a register comparison to an immediate and branch. Caller
404 * is responsible for setting branch target field.
buzbee67bf8852011-08-17 17:51:35 -0700405 */
buzbee82488f52012-03-02 08:20:26 -0800406LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg,
407 int checkValue, LIR* target)
buzbee67bf8852011-08-17 17:51:35 -0700408{
buzbee31a4a6f2012-02-28 15:36:15 -0800409 LIR* branch;
410 int modImm;
411 ArmConditionCode armCond = oatArmConditionEncoding(cond);
412 if ((LOWREG(reg)) && (checkValue == 0) &&
413 ((armCond == kArmCondEq) || (armCond == kArmCondNe))) {
414 branch = newLIR2(cUnit,
415 (armCond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
416 reg, 0);
buzbee67bf8852011-08-17 17:51:35 -0700417 } else {
buzbee31a4a6f2012-02-28 15:36:15 -0800418 modImm = modifiedImmediate(checkValue);
419 if (LOWREG(reg) && ((checkValue & 0xff) == checkValue)) {
420 newLIR2(cUnit, kThumbCmpRI8, reg, checkValue);
421 } else if (modImm >= 0) {
422 newLIR2(cUnit, kThumb2CmpRI8, reg, modImm);
buzbee67bf8852011-08-17 17:51:35 -0700423 } else {
buzbee58f92742011-10-01 11:22:17 -0700424 int tReg = oatAllocTemp(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -0800425 loadConstant(cUnit, tReg, checkValue);
426 opRegReg(cUnit, kOpCmp, reg, tReg);
buzbee58f92742011-10-01 11:22:17 -0700427 }
buzbee31a4a6f2012-02-28 15:36:15 -0800428 branch = newLIR2(cUnit, kThumbBCond, 0, armCond);
buzbee67bf8852011-08-17 17:51:35 -0700429 }
buzbee82488f52012-03-02 08:20:26 -0800430 branch->target = target;
buzbee31a4a6f2012-02-28 15:36:15 -0800431 return branch;
432}
buzbee82488f52012-03-02 08:20:26 -0800433LIR* opRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
buzbee31a4a6f2012-02-28 15:36:15 -0800434{
435 LIR* res;
436 ArmOpcode opcode;
437 if (FPREG(rDest) || FPREG(rSrc))
438 return fpRegCopy(cUnit, rDest, rSrc);
439 res = (LIR* ) oatNew(cUnit, sizeof(LIR), true, kAllocLIR);
440 res->dalvikOffset = cUnit->currentDalvikOffset;
441 if (LOWREG(rDest) && LOWREG(rSrc))
442 opcode = kThumbMovRR;
443 else if (!LOWREG(rDest) && !LOWREG(rSrc))
444 opcode = kThumbMovRR_H2H;
445 else if (LOWREG(rDest))
446 opcode = kThumbMovRR_H2L;
447 else
448 opcode = kThumbMovRR_L2H;
449
450 res->operands[0] = rDest;
451 res->operands[1] = rSrc;
452 res->opcode = opcode;
453 setupResourceMasks(res);
454 if (rDest == rSrc) {
455 res->flags.isNop = true;
456 }
457 return res;
buzbee67bf8852011-08-17 17:51:35 -0700458}
459
buzbee82488f52012-03-02 08:20:26 -0800460LIR* opRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
buzbee67bf8852011-08-17 17:51:35 -0700461{
buzbee82488f52012-03-02 08:20:26 -0800462 LIR* res = opRegCopyNoInsert(cUnit, rDest, rSrc);
buzbee31a4a6f2012-02-28 15:36:15 -0800463 oatAppendLIR(cUnit, (LIR*)res);
464 return res;
465}
buzbee67bf8852011-08-17 17:51:35 -0700466
buzbee82488f52012-03-02 08:20:26 -0800467void opRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
buzbee31a4a6f2012-02-28 15:36:15 -0800468 int srcLo, int srcHi)
469{
470 bool destFP = FPREG(destLo) && FPREG(destHi);
471 bool srcFP = FPREG(srcLo) && FPREG(srcHi);
472 DCHECK_EQ(FPREG(srcLo), FPREG(srcHi));
473 DCHECK_EQ(FPREG(destLo), FPREG(destHi));
474 if (destFP) {
475 if (srcFP) {
buzbee82488f52012-03-02 08:20:26 -0800476 opRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
buzbee67bf8852011-08-17 17:51:35 -0700477 } else {
buzbee31a4a6f2012-02-28 15:36:15 -0800478 newLIR3(cUnit, kThumb2Fmdrr, S2D(destLo, destHi), srcLo, srcHi);
479 }
480 } else {
481 if (srcFP) {
482 newLIR3(cUnit, kThumb2Fmrrd, destLo, destHi, S2D(srcLo, srcHi));
483 } else {
484 // Handle overlap
485 if (srcHi == destLo) {
buzbee82488f52012-03-02 08:20:26 -0800486 opRegCopy(cUnit, destHi, srcHi);
487 opRegCopy(cUnit, destLo, srcLo);
buzbee67bf8852011-08-17 17:51:35 -0700488 } else {
buzbee82488f52012-03-02 08:20:26 -0800489 opRegCopy(cUnit, destLo, srcLo);
490 opRegCopy(cUnit, destHi, srcHi);
buzbee67bf8852011-08-17 17:51:35 -0700491 }
492 }
493 }
buzbee67bf8852011-08-17 17:51:35 -0700494}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800495
buzbee31a4a6f2012-02-28 15:36:15 -0800496
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800497} // namespace art