blob: 28c691403fbbea15daa9477c1dbfada22dae1fbf [file] [log] [blame]
buzbeee88dfbf2012-03-05 11:19:57 -08001/*
2 * Copyright (C) 2012 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/*
buzbeea7678db2012-03-05 15:35:46 -080018 * This file contains codegen for the X86 ISA and is intended to be
buzbeee88dfbf2012-03-05 11:19:57 -080019 * includes by:
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 */
24
25namespace art {
26
buzbee16da88c2012-03-20 10:38:17 -070027void genSpecialCase(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
28 SpecialCaseHandler specialCase)
29{
Bill Buzbeea114add2012-05-03 15:00:40 -070030 // TODO
buzbee16da88c2012-03-20 10:38:17 -070031}
32
buzbeee88dfbf2012-03-05 11:19:57 -080033/*
Ian Rogersb5d09b22012-03-06 22:14:17 -080034 * Perform register memory operation.
35 */
36LIR* genRegMemCheck(CompilationUnit* cUnit, ConditionCode cCode,
buzbee408ad162012-06-06 16:45:18 -070037 int reg1, int base, int offset, ThrowKind kind)
Ian Rogersb5d09b22012-03-06 22:14:17 -080038{
Bill Buzbeea114add2012-05-03 15:00:40 -070039 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
buzbee408ad162012-06-06 16:45:18 -070040 cUnit->currentDalvikOffset, reg1, base, offset);
Bill Buzbeea114add2012-05-03 15:00:40 -070041 opRegMem(cUnit, kOpCmp, reg1, base, offset);
42 LIR* branch = opCondBranch(cUnit, cCode, tgt);
43 // Remember branch target - will process later
44 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
45 return branch;
Ian Rogersb5d09b22012-03-06 22:14:17 -080046}
47
48/*
Ian Rogers55bd45f2012-04-04 17:31:20 -070049 * The sparse table in the literal pool is an array of <key,displacement>
50 * pairs.
buzbeee88dfbf2012-03-05 11:19:57 -080051 */
Ian Rogers55bd45f2012-04-04 17:31:20 -070052BasicBlock *findBlock(CompilationUnit* cUnit, unsigned int codeOffset,
53 bool split, bool create, BasicBlock** immedPredBlockP);
buzbee408ad162012-06-06 16:45:18 -070054void genSparseSwitch(CompilationUnit* cUnit, uint32_t tableOffset,
buzbeea1da8a52012-07-09 14:00:21 -070055 RegLocation rlSrc)
Bill Buzbeea114add2012-05-03 15:00:40 -070056{
buzbee408ad162012-06-06 16:45:18 -070057 const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
Ian Rogers55bd45f2012-04-04 17:31:20 -070058 if (cUnit->printMe) {
59 dumpSparseSwitchTable(table);
60 }
61 int entries = table[1];
62 int* keys = (int*)&table[2];
63 int* targets = &keys[entries];
64 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
65 for (int i = 0; i < entries; i++) {
66 int key = keys[i];
buzbee408ad162012-06-06 16:45:18 -070067 BasicBlock* case_block = findBlock(cUnit,
68 cUnit->currentDalvikOffset + targets[i],
Ian Rogers55bd45f2012-04-04 17:31:20 -070069 false, false, NULL);
buzbeea1da8a52012-07-09 14:00:21 -070070 LIR* labelList = cUnit->blockLabelList;
Bill Buzbeea114add2012-05-03 15:00:40 -070071 opCmpImmBranch(cUnit, kCondEq, rlSrc.lowReg, key,
72 &labelList[case_block->id]);
Ian Rogers55bd45f2012-04-04 17:31:20 -070073 }
buzbeee88dfbf2012-03-05 11:19:57 -080074}
75
76/*
77 * Code pattern will look something like:
78 *
Ian Rogers55bd45f2012-04-04 17:31:20 -070079 * mov rVal, ..
80 * call 0
81 * pop rStartOfMethod
82 * sub rStartOfMethod, ..
83 * mov rKeyReg, rVal
84 * sub rKeyReg, lowKey
85 * cmp rKeyReg, size-1 ; bound check
86 * ja done
87 * mov rDisp, [rStartOfMethod + rKeyReg * 4 + tableOffset]
88 * add rStartOfMethod, rDisp
89 * jmp rStartOfMethod
buzbeee88dfbf2012-03-05 11:19:57 -080090 * done:
91 */
buzbee408ad162012-06-06 16:45:18 -070092void genPackedSwitch(CompilationUnit* cUnit, uint32_t tableOffset,
93 RegLocation rlSrc)
Bill Buzbeea114add2012-05-03 15:00:40 -070094{
buzbee408ad162012-06-06 16:45:18 -070095 const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
Ian Rogers7caad772012-03-30 01:07:54 -070096 if (cUnit->printMe) {
97 dumpPackedSwitchTable(table);
98 }
99 // Add the table to the list - we'll process it later
100 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
101 true, kAllocData);
102 tabRec->table = table;
buzbee408ad162012-06-06 16:45:18 -0700103 tabRec->vaddr = cUnit->currentDalvikOffset;
Ian Rogers7caad772012-03-30 01:07:54 -0700104 int size = table[1];
105 tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true,
106 kAllocLIR);
107 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
buzbeee88dfbf2012-03-05 11:19:57 -0800108
Ian Rogers7caad772012-03-30 01:07:54 -0700109 // Get the switch value
110 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
111 int startOfMethodReg = oatAllocTemp(cUnit);
112 // Materialize a pointer to the switch table
113 //newLIR0(cUnit, kX86Bkpt);
114 newLIR1(cUnit, kX86StartOfMethod, startOfMethodReg);
115 int lowKey = s4FromSwitchData(&table[2]);
116 int keyReg;
117 // Remove the bias, if necessary
118 if (lowKey == 0) {
119 keyReg = rlSrc.lowReg;
120 } else {
121 keyReg = oatAllocTemp(cUnit);
122 opRegRegImm(cUnit, kOpSub, keyReg, rlSrc.lowReg, lowKey);
123 }
124 // Bounds check - if < 0 or >= size continue following switch
125 opRegImm(cUnit, kOpCmp, keyReg, size-1);
126 LIR* branchOver = opCondBranch(cUnit, kCondHi, NULL);
buzbeee88dfbf2012-03-05 11:19:57 -0800127
Ian Rogers7caad772012-03-30 01:07:54 -0700128 // Load the displacement from the switch table
129 int dispReg = oatAllocTemp(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -0700130 newLIR5(cUnit, kX86PcRelLoadRA, dispReg, startOfMethodReg, keyReg, 2,
131 (intptr_t)tabRec);
Ian Rogers7caad772012-03-30 01:07:54 -0700132 // Add displacement to start of method
133 opRegReg(cUnit, kOpAdd, startOfMethodReg, dispReg);
134 // ..and go!
135 LIR* switchBranch = newLIR1(cUnit, kX86JmpR, startOfMethodReg);
136 tabRec->anchor = switchBranch;
buzbeee88dfbf2012-03-05 11:19:57 -0800137
Ian Rogers7caad772012-03-30 01:07:54 -0700138 /* branchOver target here */
139 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
140 branchOver->target = (LIR*)target;
buzbeee88dfbf2012-03-05 11:19:57 -0800141}
142
Bill Buzbeea114add2012-05-03 15:00:40 -0700143void callRuntimeHelperRegReg(CompilationUnit* cUnit, int helperOffset,
buzbee8320f382012-09-11 16:29:42 -0700144 int arg0, int arg1, bool safepointPC);
buzbeee88dfbf2012-03-05 11:19:57 -0800145/*
146 * Array data table format:
147 * ushort ident = 0x0300 magic value
148 * ushort width width of each element in the table
149 * uint size number of elements in the table
150 * ubyte data[size*width] table of data values (may contain a single-byte
151 * padding at the end)
152 *
153 * Total size is 4+(width * size + 1)/2 16-bit code units.
154 */
buzbee408ad162012-06-06 16:45:18 -0700155void genFillArrayData(CompilationUnit* cUnit, uint32_t tableOffset,
156 RegLocation rlSrc)
buzbeee88dfbf2012-03-05 11:19:57 -0800157{
buzbee408ad162012-06-06 16:45:18 -0700158 const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
Ian Rogers7caad772012-03-30 01:07:54 -0700159 // Add the table to the list - we'll process it later
Bill Buzbeea114add2012-05-03 15:00:40 -0700160 FillArrayData *tabRec = (FillArrayData *)oatNew(cUnit, sizeof(FillArrayData),
161 true, kAllocData);
Ian Rogers7caad772012-03-30 01:07:54 -0700162 tabRec->table = table;
buzbee408ad162012-06-06 16:45:18 -0700163 tabRec->vaddr = cUnit->currentDalvikOffset;
Ian Rogers7caad772012-03-30 01:07:54 -0700164 u2 width = tabRec->table[1];
165 u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
166 tabRec->size = (size * width) + 8;
buzbeee88dfbf2012-03-05 11:19:57 -0800167
Ian Rogers7caad772012-03-30 01:07:54 -0700168 oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec);
buzbeee88dfbf2012-03-05 11:19:57 -0800169
Ian Rogers7caad772012-03-30 01:07:54 -0700170 // Making a call - use explicit registers
171 oatFlushAllRegs(cUnit); /* Everything to home location */
172 loadValueDirectFixed(cUnit, rlSrc, rARG0);
173 // Materialize a pointer to the fill data image
174 newLIR1(cUnit, kX86StartOfMethod, rARG2);
175 newLIR2(cUnit, kX86PcRelAdr, rARG1, (intptr_t)tabRec);
176 newLIR2(cUnit, kX86Add32RR, rARG1, rARG2);
buzbee8320f382012-09-11 16:29:42 -0700177 callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pHandleFillArrayDataFromCode), rARG0, rARG1,
178 true);
buzbeee88dfbf2012-03-05 11:19:57 -0800179}
180
181void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
182{
Bill Buzbeea114add2012-05-03 15:00:40 -0700183 RegLocation rlResult;
184 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
185 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
186 opRegRegImm(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, 0x80000000);
187 storeValue(cUnit, rlDest, rlResult);
buzbeee88dfbf2012-03-05 11:19:57 -0800188}
189
190void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
191{
Bill Buzbeea114add2012-05-03 15:00:40 -0700192 RegLocation rlResult;
193 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
194 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
195 opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg, 0x80000000);
196 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
197 storeValueWide(cUnit, rlDest, rlResult);
buzbeee88dfbf2012-03-05 11:19:57 -0800198}
199
buzbee408ad162012-06-06 16:45:18 -0700200LIR* genNullCheck(CompilationUnit* cUnit, int sReg, int mReg, int optFlags);
buzbee8320f382012-09-11 16:29:42 -0700201void callRuntimeHelperReg(CompilationUnit* cUnit, int helperOffset, int arg0, bool safepointPC);
Ian Rogers7caad772012-03-30 01:07:54 -0700202
buzbee408ad162012-06-06 16:45:18 -0700203void genMonitorEnter(CompilationUnit* cUnit, int optFlags, RegLocation rlSrc)
buzbeee88dfbf2012-03-05 11:19:57 -0800204{
Bill Buzbeea114add2012-05-03 15:00:40 -0700205 oatFlushAllRegs(cUnit);
jeffhao83025762012-08-02 11:08:56 -0700206 loadValueDirectFixed(cUnit, rlSrc, rCX); // Get obj
Bill Buzbeea114add2012-05-03 15:00:40 -0700207 oatLockCallTemps(cUnit); // Prepare for explicit register usage
jeffhao83025762012-08-02 11:08:56 -0700208 genNullCheck(cUnit, rlSrc.sRegLow, rCX, optFlags);
209 // If lock is unheld, try to grab it quickly with compare and exchange
210 // TODO: copy and clear hash state?
211 newLIR2(cUnit, kX86Mov32RT, rDX, Thread::ThinLockIdOffset().Int32Value());
212 newLIR2(cUnit, kX86Sal32RI, rDX, LW_LOCK_OWNER_SHIFT);
213 newLIR2(cUnit, kX86Xor32RR, rAX, rAX);
214 newLIR3(cUnit, kX86LockCmpxchgMR, rCX, Object::MonitorOffset().Int32Value(), rDX);
215 LIR* branch = newLIR2(cUnit, kX86Jcc8, 0, kX86CondEq);
216 // If lock is held, go the expensive route - artLockObjectFromCode(self, obj);
buzbee8320f382012-09-11 16:29:42 -0700217 callRuntimeHelperReg(cUnit, ENTRYPOINT_OFFSET(pLockObjectFromCode), rCX, true);
jeffhao83025762012-08-02 11:08:56 -0700218 branch->target = newLIR0(cUnit, kPseudoTargetLabel);
buzbeee88dfbf2012-03-05 11:19:57 -0800219}
220
buzbee408ad162012-06-06 16:45:18 -0700221void genMonitorExit(CompilationUnit* cUnit, int optFlags, RegLocation rlSrc)
buzbeee88dfbf2012-03-05 11:19:57 -0800222{
Bill Buzbeea114add2012-05-03 15:00:40 -0700223 oatFlushAllRegs(cUnit);
jeffhao83025762012-08-02 11:08:56 -0700224 loadValueDirectFixed(cUnit, rlSrc, rAX); // Get obj
Bill Buzbeea114add2012-05-03 15:00:40 -0700225 oatLockCallTemps(cUnit); // Prepare for explicit register usage
jeffhao83025762012-08-02 11:08:56 -0700226 genNullCheck(cUnit, rlSrc.sRegLow, rAX, optFlags);
227 // If lock is held by the current thread, clear it to quickly release it
228 // TODO: clear hash state?
229 newLIR2(cUnit, kX86Mov32RT, rDX, Thread::ThinLockIdOffset().Int32Value());
230 newLIR2(cUnit, kX86Sal32RI, rDX, LW_LOCK_OWNER_SHIFT);
231 newLIR3(cUnit, kX86Mov32RM, rCX, rAX, Object::MonitorOffset().Int32Value());
232 opRegReg(cUnit, kOpSub, rCX, rDX);
233 LIR* branch = newLIR2(cUnit, kX86Jcc8, 0, kX86CondNe);
234 newLIR3(cUnit, kX86Mov32MR, rAX, Object::MonitorOffset().Int32Value(), rCX);
235 LIR* branch2 = newLIR1(cUnit, kX86Jmp8, 0);
236 branch->target = newLIR0(cUnit, kPseudoTargetLabel);
237 // Otherwise, go the expensive route - UnlockObjectFromCode(obj);
buzbee8320f382012-09-11 16:29:42 -0700238 callRuntimeHelperReg(cUnit, ENTRYPOINT_OFFSET(pUnlockObjectFromCode), rAX, true);
jeffhao83025762012-08-02 11:08:56 -0700239 branch2->target = newLIR0(cUnit, kPseudoTargetLabel);
buzbeee88dfbf2012-03-05 11:19:57 -0800240}
241
242/*
243 * Compare two 64-bit values
244 * x = y return 0
245 * x < y return -1
246 * x > y return 1
247 *
248 * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
249 * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
250 * subu res, t0, t1 # res = -1:1:0 for [ < > = ]
251 * bnez res, finish
252 * sltu t0, x.lo, y.lo
253 * sgtu r1, x.lo, y.lo
254 * subu res, t0, t1
255 * finish:
256 *
257 */
buzbee408ad162012-06-06 16:45:18 -0700258void genCmpLong(CompilationUnit* cUnit, RegLocation rlDest,
buzbeee88dfbf2012-03-05 11:19:57 -0800259 RegLocation rlSrc1, RegLocation rlSrc2)
260{
Bill Buzbeea114add2012-05-03 15:00:40 -0700261 oatFlushAllRegs(cUnit);
262 oatLockCallTemps(cUnit); // Prepare for explicit register usage
263 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
jeffhao644d5312012-05-03 19:04:49 -0700264 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
265 // Compute (r1:r0) = (r1:r0) - (r3:r2)
Bill Buzbeea114add2012-05-03 15:00:40 -0700266 opRegReg(cUnit, kOpSub, r0, r2); // r0 = r0 - r2
267 opRegReg(cUnit, kOpSbc, r1, r3); // r1 = r1 - r3 - CF
jeffhao1395b1e2012-06-13 18:05:13 -0700268 newLIR2(cUnit, kX86Set8R, r2, kX86CondL); // r2 = (r1:r0) < (r3:r2) ? 1 : 0
269 newLIR2(cUnit, kX86Movzx8RR, r2, r2);
270 opReg(cUnit, kOpNeg, r2); // r2 = -r2
Bill Buzbeea114add2012-05-03 15:00:40 -0700271 opRegReg(cUnit, kOpOr, r0, r1); // r0 = high | low - sets ZF
jeffhao644d5312012-05-03 19:04:49 -0700272 newLIR2(cUnit, kX86Set8R, r0, kX86CondNz); // r0 = (r1:r0) != (r3:r2) ? 1 : 0
Bill Buzbeea114add2012-05-03 15:00:40 -0700273 newLIR2(cUnit, kX86Movzx8RR, r0, r0);
jeffhao1395b1e2012-06-13 18:05:13 -0700274 opRegReg(cUnit, kOpOr, r0, r2); // r0 = r0 | r2
Bill Buzbeea114add2012-05-03 15:00:40 -0700275 RegLocation rlResult = LOC_C_RETURN;
276 storeValue(cUnit, rlDest, rlResult);
buzbeee88dfbf2012-03-05 11:19:57 -0800277}
278
Ian Rogersb5d09b22012-03-06 22:14:17 -0800279X86ConditionCode oatX86ConditionEncoding(ConditionCode cond) {
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700280 switch (cond) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800281 case kCondEq: return kX86CondEq;
282 case kCondNe: return kX86CondNe;
283 case kCondCs: return kX86CondC;
284 case kCondCc: return kX86CondNc;
285 case kCondMi: return kX86CondS;
286 case kCondPl: return kX86CondNs;
287 case kCondVs: return kX86CondO;
288 case kCondVc: return kX86CondNo;
289 case kCondHi: return kX86CondA;
290 case kCondLs: return kX86CondBe;
291 case kCondGe: return kX86CondGe;
292 case kCondLt: return kX86CondL;
293 case kCondGt: return kX86CondG;
294 case kCondLe: return kX86CondLe;
295 case kCondAl:
296 case kCondNv: LOG(FATAL) << "Should not reach here";
297 }
298 return kX86CondO;
299}
300
Bill Buzbeea114add2012-05-03 15:00:40 -0700301LIR* opCmpBranch(CompilationUnit* cUnit, ConditionCode cond, int src1,
302 int src2, LIR* target)
buzbeee88dfbf2012-03-05 11:19:57 -0800303{
Ian Rogersb5d09b22012-03-06 22:14:17 -0800304 newLIR2(cUnit, kX86Cmp32RR, src1, src2);
305 X86ConditionCode cc = oatX86ConditionEncoding(cond);
Bill Buzbeea114add2012-05-03 15:00:40 -0700306 LIR* branch = newLIR2(cUnit, kX86Jcc8, 0 /* lir operand for Jcc offset */ ,
307 cc);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800308 branch->target = target;
309 return branch;
buzbeee88dfbf2012-03-05 11:19:57 -0800310}
311
312LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg,
313 int checkValue, LIR* target)
314{
Ian Rogers2e9f7ed2012-09-26 11:30:43 -0700315 if ((checkValue == 0) && (cond == kCondEq || cond == kCondNe)) {
Ian Rogers7caad772012-03-30 01:07:54 -0700316 // TODO: when checkValue == 0 and reg is rCX, use the jcxz/nz opcode
Ian Rogers2e9f7ed2012-09-26 11:30:43 -0700317 newLIR2(cUnit, kX86Test32RR, reg, reg);
Ian Rogers7caad772012-03-30 01:07:54 -0700318 } else {
Ian Rogers2e9f7ed2012-09-26 11:30:43 -0700319 newLIR2(cUnit, IS_SIMM8(checkValue) ? kX86Cmp32RI8 : kX86Cmp32RI, reg, checkValue);
Ian Rogers7caad772012-03-30 01:07:54 -0700320 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800321 X86ConditionCode cc = oatX86ConditionEncoding(cond);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700322 LIR* branch = newLIR2(cUnit, kX86Jcc8, 0 /* lir operand for Jcc offset */ , cc);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800323 branch->target = target;
324 return branch;
buzbeee88dfbf2012-03-05 11:19:57 -0800325}
326
327LIR* opRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
328{
Bill Buzbeea114add2012-05-03 15:00:40 -0700329 if (FPREG(rDest) || FPREG(rSrc))
330 return fpRegCopy(cUnit, rDest, rSrc);
331 LIR* res = rawLIR(cUnit, cUnit->currentDalvikOffset, kX86Mov32RR,
332 rDest, rSrc);
333 if (rDest == rSrc) {
334 res->flags.isNop = true;
335 }
336 return res;
buzbeee88dfbf2012-03-05 11:19:57 -0800337}
338
339LIR* opRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
340{
Bill Buzbeea114add2012-05-03 15:00:40 -0700341 LIR *res = opRegCopyNoInsert(cUnit, rDest, rSrc);
342 oatAppendLIR(cUnit, res);
343 return res;
buzbeee88dfbf2012-03-05 11:19:57 -0800344}
345
346void opRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
Bill Buzbeea114add2012-05-03 15:00:40 -0700347 int srcLo, int srcHi)
348{
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700349 bool destFP = FPREG(destLo) && FPREG(destHi);
350 bool srcFP = FPREG(srcLo) && FPREG(srcHi);
351 assert(FPREG(srcLo) == FPREG(srcHi));
352 assert(FPREG(destLo) == FPREG(destHi));
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700353 if (destFP) {
354 if (srcFP) {
355 opRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
buzbeee88dfbf2012-03-05 11:19:57 -0800356 } else {
jeffhaofdffdf82012-07-11 16:08:43 -0700357 // TODO: Prevent this from happening in the code. The result is often
358 // unused or could have been loaded more easily from memory.
359 newLIR2(cUnit, kX86MovdxrRR, destLo, srcLo);
360 newLIR2(cUnit, kX86MovdxrRR, destHi, srcHi);
361 newLIR2(cUnit, kX86PsllqRI, destHi, 32);
362 newLIR2(cUnit, kX86OrpsRR, destLo, destHi);
buzbeee88dfbf2012-03-05 11:19:57 -0800363 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700364 } else {
365 if (srcFP) {
jeffhaofdffdf82012-07-11 16:08:43 -0700366 newLIR2(cUnit, kX86MovdrxRR, destLo, srcLo);
367 newLIR2(cUnit, kX86PsrlqRI, srcLo, 32);
368 newLIR2(cUnit, kX86MovdrxRR, destHi, srcLo);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700369 } else {
370 // Handle overlap
371 if (srcHi == destLo) {
buzbeee88dfbf2012-03-05 11:19:57 -0800372 opRegCopy(cUnit, destHi, srcHi);
373 opRegCopy(cUnit, destLo, srcLo);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700374 } else {
buzbeee88dfbf2012-03-05 11:19:57 -0800375 opRegCopy(cUnit, destLo, srcLo);
376 opRegCopy(cUnit, destHi, srcHi);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700377 }
buzbeee88dfbf2012-03-05 11:19:57 -0800378 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700379 }
buzbeee88dfbf2012-03-05 11:19:57 -0800380}
381
jeffhao4b771a02012-07-25 15:07:21 -0700382void genFusedLongCmpBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir) {
383 LIR* labelList = cUnit->blockLabelList;
384 LIR* taken = &labelList[bb->taken->id];
385 RegLocation rlSrc1 = oatGetSrcWide(cUnit, mir, 0);
386 RegLocation rlSrc2 = oatGetSrcWide(cUnit, mir, 2);
387 oatFlushAllRegs(cUnit);
388 oatLockCallTemps(cUnit); // Prepare for explicit register usage
389 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
390 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
391 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
392 // Swap operands and condition code to prevent use of zero flag.
393 if (ccode == kCondLe || ccode == kCondGt) {
394 // Compute (r3:r2) = (r3:r2) - (r1:r0)
395 opRegReg(cUnit, kOpSub, r2, r0); // r2 = r2 - r0
396 opRegReg(cUnit, kOpSbc, r3, r1); // r3 = r3 - r1 - CF
397 } else {
398 // Compute (r1:r0) = (r1:r0) - (r3:r2)
399 opRegReg(cUnit, kOpSub, r0, r2); // r0 = r0 - r2
400 opRegReg(cUnit, kOpSbc, r1, r3); // r1 = r1 - r3 - CF
401 }
402 switch (ccode) {
403 case kCondEq:
404 case kCondNe:
405 opRegReg(cUnit, kOpOr, r0, r1); // r0 = r0 | r1
406 break;
407 case kCondLe:
408 ccode = kCondGe;
409 break;
410 case kCondGt:
411 ccode = kCondLt;
412 break;
413 case kCondLt:
414 case kCondGe:
415 break;
416 default:
417 LOG(FATAL) << "Unexpected ccode: " << (int)ccode;
418 }
419 opCondBranch(cUnit, ccode, taken);
420}
421
buzbeee88dfbf2012-03-05 11:19:57 -0800422} // namespace art