blob: b57acac271fa6235c9df08bcde24fca13728826a [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
buzbeeb046e162012-10-30 15:48:42 -070017/* This file contains codegen for the X86 ISA */
buzbeee88dfbf2012-03-05 11:19:57 -080018
19namespace art {
20
buzbee16da88c2012-03-20 10:38:17 -070021void genSpecialCase(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
22 SpecialCaseHandler specialCase)
23{
Bill Buzbeea114add2012-05-03 15:00:40 -070024 // TODO
buzbee16da88c2012-03-20 10:38:17 -070025}
26
buzbeee88dfbf2012-03-05 11:19:57 -080027/*
Ian Rogersb5d09b22012-03-06 22:14:17 -080028 * Perform register memory operation.
29 */
30LIR* genRegMemCheck(CompilationUnit* cUnit, ConditionCode cCode,
buzbee408ad162012-06-06 16:45:18 -070031 int reg1, int base, int offset, ThrowKind kind)
Ian Rogersb5d09b22012-03-06 22:14:17 -080032{
Bill Buzbeea114add2012-05-03 15:00:40 -070033 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
buzbee408ad162012-06-06 16:45:18 -070034 cUnit->currentDalvikOffset, reg1, base, offset);
Bill Buzbeea114add2012-05-03 15:00:40 -070035 opRegMem(cUnit, kOpCmp, reg1, base, offset);
36 LIR* branch = opCondBranch(cUnit, cCode, tgt);
37 // Remember branch target - will process later
38 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
39 return branch;
Ian Rogersb5d09b22012-03-06 22:14:17 -080040}
41
42/*
Ian Rogers55bd45f2012-04-04 17:31:20 -070043 * The sparse table in the literal pool is an array of <key,displacement>
44 * pairs.
buzbeee88dfbf2012-03-05 11:19:57 -080045 */
Ian Rogers55bd45f2012-04-04 17:31:20 -070046BasicBlock *findBlock(CompilationUnit* cUnit, unsigned int codeOffset,
47 bool split, bool create, BasicBlock** immedPredBlockP);
buzbee408ad162012-06-06 16:45:18 -070048void genSparseSwitch(CompilationUnit* cUnit, uint32_t tableOffset,
buzbeea1da8a52012-07-09 14:00:21 -070049 RegLocation rlSrc)
Bill Buzbeea114add2012-05-03 15:00:40 -070050{
buzbee408ad162012-06-06 16:45:18 -070051 const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
Ian Rogers55bd45f2012-04-04 17:31:20 -070052 if (cUnit->printMe) {
53 dumpSparseSwitchTable(table);
54 }
55 int entries = table[1];
56 int* keys = (int*)&table[2];
57 int* targets = &keys[entries];
58 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
59 for (int i = 0; i < entries; i++) {
60 int key = keys[i];
buzbee408ad162012-06-06 16:45:18 -070061 BasicBlock* case_block = findBlock(cUnit,
62 cUnit->currentDalvikOffset + targets[i],
Ian Rogers55bd45f2012-04-04 17:31:20 -070063 false, false, NULL);
buzbeea1da8a52012-07-09 14:00:21 -070064 LIR* labelList = cUnit->blockLabelList;
Bill Buzbeea114add2012-05-03 15:00:40 -070065 opCmpImmBranch(cUnit, kCondEq, rlSrc.lowReg, key,
66 &labelList[case_block->id]);
Ian Rogers55bd45f2012-04-04 17:31:20 -070067 }
buzbeee88dfbf2012-03-05 11:19:57 -080068}
69
70/*
71 * Code pattern will look something like:
72 *
Ian Rogers55bd45f2012-04-04 17:31:20 -070073 * mov rVal, ..
74 * call 0
75 * pop rStartOfMethod
76 * sub rStartOfMethod, ..
77 * mov rKeyReg, rVal
78 * sub rKeyReg, lowKey
79 * cmp rKeyReg, size-1 ; bound check
80 * ja done
81 * mov rDisp, [rStartOfMethod + rKeyReg * 4 + tableOffset]
82 * add rStartOfMethod, rDisp
83 * jmp rStartOfMethod
buzbeee88dfbf2012-03-05 11:19:57 -080084 * done:
85 */
buzbee408ad162012-06-06 16:45:18 -070086void genPackedSwitch(CompilationUnit* cUnit, uint32_t tableOffset,
87 RegLocation rlSrc)
Bill Buzbeea114add2012-05-03 15:00:40 -070088{
buzbee408ad162012-06-06 16:45:18 -070089 const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
Ian Rogers7caad772012-03-30 01:07:54 -070090 if (cUnit->printMe) {
91 dumpPackedSwitchTable(table);
92 }
93 // Add the table to the list - we'll process it later
94 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
95 true, kAllocData);
96 tabRec->table = table;
buzbee408ad162012-06-06 16:45:18 -070097 tabRec->vaddr = cUnit->currentDalvikOffset;
Ian Rogers7caad772012-03-30 01:07:54 -070098 int size = table[1];
99 tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true,
100 kAllocLIR);
101 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
buzbeee88dfbf2012-03-05 11:19:57 -0800102
Ian Rogers7caad772012-03-30 01:07:54 -0700103 // Get the switch value
104 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
105 int startOfMethodReg = oatAllocTemp(cUnit);
106 // Materialize a pointer to the switch table
107 //newLIR0(cUnit, kX86Bkpt);
108 newLIR1(cUnit, kX86StartOfMethod, startOfMethodReg);
109 int lowKey = s4FromSwitchData(&table[2]);
110 int keyReg;
111 // Remove the bias, if necessary
112 if (lowKey == 0) {
113 keyReg = rlSrc.lowReg;
114 } else {
115 keyReg = oatAllocTemp(cUnit);
116 opRegRegImm(cUnit, kOpSub, keyReg, rlSrc.lowReg, lowKey);
117 }
118 // Bounds check - if < 0 or >= size continue following switch
119 opRegImm(cUnit, kOpCmp, keyReg, size-1);
120 LIR* branchOver = opCondBranch(cUnit, kCondHi, NULL);
buzbeee88dfbf2012-03-05 11:19:57 -0800121
Ian Rogers7caad772012-03-30 01:07:54 -0700122 // Load the displacement from the switch table
123 int dispReg = oatAllocTemp(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -0700124 newLIR5(cUnit, kX86PcRelLoadRA, dispReg, startOfMethodReg, keyReg, 2,
125 (intptr_t)tabRec);
Ian Rogers7caad772012-03-30 01:07:54 -0700126 // Add displacement to start of method
127 opRegReg(cUnit, kOpAdd, startOfMethodReg, dispReg);
128 // ..and go!
129 LIR* switchBranch = newLIR1(cUnit, kX86JmpR, startOfMethodReg);
130 tabRec->anchor = switchBranch;
buzbeee88dfbf2012-03-05 11:19:57 -0800131
Ian Rogers7caad772012-03-30 01:07:54 -0700132 /* branchOver target here */
133 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
134 branchOver->target = (LIR*)target;
buzbeee88dfbf2012-03-05 11:19:57 -0800135}
136
Bill Buzbeea114add2012-05-03 15:00:40 -0700137void callRuntimeHelperRegReg(CompilationUnit* cUnit, int helperOffset,
buzbee8320f382012-09-11 16:29:42 -0700138 int arg0, int arg1, bool safepointPC);
buzbeee88dfbf2012-03-05 11:19:57 -0800139/*
140 * Array data table format:
141 * ushort ident = 0x0300 magic value
142 * ushort width width of each element in the table
143 * uint size number of elements in the table
144 * ubyte data[size*width] table of data values (may contain a single-byte
145 * padding at the end)
146 *
147 * Total size is 4+(width * size + 1)/2 16-bit code units.
148 */
buzbee408ad162012-06-06 16:45:18 -0700149void genFillArrayData(CompilationUnit* cUnit, uint32_t tableOffset,
150 RegLocation rlSrc)
buzbeee88dfbf2012-03-05 11:19:57 -0800151{
buzbee408ad162012-06-06 16:45:18 -0700152 const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
Ian Rogers7caad772012-03-30 01:07:54 -0700153 // Add the table to the list - we'll process it later
Bill Buzbeea114add2012-05-03 15:00:40 -0700154 FillArrayData *tabRec = (FillArrayData *)oatNew(cUnit, sizeof(FillArrayData),
155 true, kAllocData);
Ian Rogers7caad772012-03-30 01:07:54 -0700156 tabRec->table = table;
buzbee408ad162012-06-06 16:45:18 -0700157 tabRec->vaddr = cUnit->currentDalvikOffset;
Ian Rogers7caad772012-03-30 01:07:54 -0700158 u2 width = tabRec->table[1];
159 u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
160 tabRec->size = (size * width) + 8;
buzbeee88dfbf2012-03-05 11:19:57 -0800161
Ian Rogers7caad772012-03-30 01:07:54 -0700162 oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec);
buzbeee88dfbf2012-03-05 11:19:57 -0800163
Ian Rogers7caad772012-03-30 01:07:54 -0700164 // Making a call - use explicit registers
165 oatFlushAllRegs(cUnit); /* Everything to home location */
166 loadValueDirectFixed(cUnit, rlSrc, rARG0);
167 // Materialize a pointer to the fill data image
168 newLIR1(cUnit, kX86StartOfMethod, rARG2);
169 newLIR2(cUnit, kX86PcRelAdr, rARG1, (intptr_t)tabRec);
170 newLIR2(cUnit, kX86Add32RR, rARG1, rARG2);
buzbee8320f382012-09-11 16:29:42 -0700171 callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pHandleFillArrayDataFromCode), rARG0, rARG1,
172 true);
buzbeee88dfbf2012-03-05 11:19:57 -0800173}
174
175void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
176{
Bill Buzbeea114add2012-05-03 15:00:40 -0700177 RegLocation rlResult;
178 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
179 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
180 opRegRegImm(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, 0x80000000);
181 storeValue(cUnit, rlDest, rlResult);
buzbeee88dfbf2012-03-05 11:19:57 -0800182}
183
184void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
185{
Bill Buzbeea114add2012-05-03 15:00:40 -0700186 RegLocation rlResult;
187 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
188 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
189 opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg, 0x80000000);
190 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
191 storeValueWide(cUnit, rlDest, rlResult);
buzbeee88dfbf2012-03-05 11:19:57 -0800192}
193
buzbee408ad162012-06-06 16:45:18 -0700194LIR* genNullCheck(CompilationUnit* cUnit, int sReg, int mReg, int optFlags);
buzbee8320f382012-09-11 16:29:42 -0700195void callRuntimeHelperReg(CompilationUnit* cUnit, int helperOffset, int arg0, bool safepointPC);
Ian Rogers7caad772012-03-30 01:07:54 -0700196
buzbee408ad162012-06-06 16:45:18 -0700197void genMonitorEnter(CompilationUnit* cUnit, int optFlags, RegLocation rlSrc)
buzbeee88dfbf2012-03-05 11:19:57 -0800198{
Bill Buzbeea114add2012-05-03 15:00:40 -0700199 oatFlushAllRegs(cUnit);
jeffhao83025762012-08-02 11:08:56 -0700200 loadValueDirectFixed(cUnit, rlSrc, rCX); // Get obj
Bill Buzbeea114add2012-05-03 15:00:40 -0700201 oatLockCallTemps(cUnit); // Prepare for explicit register usage
jeffhao83025762012-08-02 11:08:56 -0700202 genNullCheck(cUnit, rlSrc.sRegLow, rCX, optFlags);
203 // If lock is unheld, try to grab it quickly with compare and exchange
204 // TODO: copy and clear hash state?
205 newLIR2(cUnit, kX86Mov32RT, rDX, Thread::ThinLockIdOffset().Int32Value());
206 newLIR2(cUnit, kX86Sal32RI, rDX, LW_LOCK_OWNER_SHIFT);
207 newLIR2(cUnit, kX86Xor32RR, rAX, rAX);
208 newLIR3(cUnit, kX86LockCmpxchgMR, rCX, Object::MonitorOffset().Int32Value(), rDX);
209 LIR* branch = newLIR2(cUnit, kX86Jcc8, 0, kX86CondEq);
210 // If lock is held, go the expensive route - artLockObjectFromCode(self, obj);
buzbee8320f382012-09-11 16:29:42 -0700211 callRuntimeHelperReg(cUnit, ENTRYPOINT_OFFSET(pLockObjectFromCode), rCX, true);
jeffhao83025762012-08-02 11:08:56 -0700212 branch->target = newLIR0(cUnit, kPseudoTargetLabel);
buzbeee88dfbf2012-03-05 11:19:57 -0800213}
214
buzbee408ad162012-06-06 16:45:18 -0700215void genMonitorExit(CompilationUnit* cUnit, int optFlags, RegLocation rlSrc)
buzbeee88dfbf2012-03-05 11:19:57 -0800216{
Bill Buzbeea114add2012-05-03 15:00:40 -0700217 oatFlushAllRegs(cUnit);
jeffhao83025762012-08-02 11:08:56 -0700218 loadValueDirectFixed(cUnit, rlSrc, rAX); // Get obj
Bill Buzbeea114add2012-05-03 15:00:40 -0700219 oatLockCallTemps(cUnit); // Prepare for explicit register usage
jeffhao83025762012-08-02 11:08:56 -0700220 genNullCheck(cUnit, rlSrc.sRegLow, rAX, optFlags);
221 // If lock is held by the current thread, clear it to quickly release it
222 // TODO: clear hash state?
223 newLIR2(cUnit, kX86Mov32RT, rDX, Thread::ThinLockIdOffset().Int32Value());
224 newLIR2(cUnit, kX86Sal32RI, rDX, LW_LOCK_OWNER_SHIFT);
225 newLIR3(cUnit, kX86Mov32RM, rCX, rAX, Object::MonitorOffset().Int32Value());
226 opRegReg(cUnit, kOpSub, rCX, rDX);
227 LIR* branch = newLIR2(cUnit, kX86Jcc8, 0, kX86CondNe);
228 newLIR3(cUnit, kX86Mov32MR, rAX, Object::MonitorOffset().Int32Value(), rCX);
229 LIR* branch2 = newLIR1(cUnit, kX86Jmp8, 0);
230 branch->target = newLIR0(cUnit, kPseudoTargetLabel);
231 // Otherwise, go the expensive route - UnlockObjectFromCode(obj);
buzbee8320f382012-09-11 16:29:42 -0700232 callRuntimeHelperReg(cUnit, ENTRYPOINT_OFFSET(pUnlockObjectFromCode), rAX, true);
jeffhao83025762012-08-02 11:08:56 -0700233 branch2->target = newLIR0(cUnit, kPseudoTargetLabel);
buzbeee88dfbf2012-03-05 11:19:57 -0800234}
235
236/*
237 * Compare two 64-bit values
238 * x = y return 0
239 * x < y return -1
240 * x > y return 1
241 *
242 * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
243 * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
244 * subu res, t0, t1 # res = -1:1:0 for [ < > = ]
245 * bnez res, finish
246 * sltu t0, x.lo, y.lo
247 * sgtu r1, x.lo, y.lo
248 * subu res, t0, t1
249 * finish:
250 *
251 */
buzbee408ad162012-06-06 16:45:18 -0700252void genCmpLong(CompilationUnit* cUnit, RegLocation rlDest,
buzbeee88dfbf2012-03-05 11:19:57 -0800253 RegLocation rlSrc1, RegLocation rlSrc2)
254{
Bill Buzbeea114add2012-05-03 15:00:40 -0700255 oatFlushAllRegs(cUnit);
256 oatLockCallTemps(cUnit); // Prepare for explicit register usage
257 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
jeffhao644d5312012-05-03 19:04:49 -0700258 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
259 // Compute (r1:r0) = (r1:r0) - (r3:r2)
Bill Buzbeea114add2012-05-03 15:00:40 -0700260 opRegReg(cUnit, kOpSub, r0, r2); // r0 = r0 - r2
261 opRegReg(cUnit, kOpSbc, r1, r3); // r1 = r1 - r3 - CF
jeffhao1395b1e2012-06-13 18:05:13 -0700262 newLIR2(cUnit, kX86Set8R, r2, kX86CondL); // r2 = (r1:r0) < (r3:r2) ? 1 : 0
263 newLIR2(cUnit, kX86Movzx8RR, r2, r2);
264 opReg(cUnit, kOpNeg, r2); // r2 = -r2
Bill Buzbeea114add2012-05-03 15:00:40 -0700265 opRegReg(cUnit, kOpOr, r0, r1); // r0 = high | low - sets ZF
jeffhao644d5312012-05-03 19:04:49 -0700266 newLIR2(cUnit, kX86Set8R, r0, kX86CondNz); // r0 = (r1:r0) != (r3:r2) ? 1 : 0
Bill Buzbeea114add2012-05-03 15:00:40 -0700267 newLIR2(cUnit, kX86Movzx8RR, r0, r0);
jeffhao1395b1e2012-06-13 18:05:13 -0700268 opRegReg(cUnit, kOpOr, r0, r2); // r0 = r0 | r2
Bill Buzbeea114add2012-05-03 15:00:40 -0700269 RegLocation rlResult = LOC_C_RETURN;
270 storeValue(cUnit, rlDest, rlResult);
buzbeee88dfbf2012-03-05 11:19:57 -0800271}
272
Ian Rogersb5d09b22012-03-06 22:14:17 -0800273X86ConditionCode oatX86ConditionEncoding(ConditionCode cond) {
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700274 switch (cond) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800275 case kCondEq: return kX86CondEq;
276 case kCondNe: return kX86CondNe;
277 case kCondCs: return kX86CondC;
278 case kCondCc: return kX86CondNc;
279 case kCondMi: return kX86CondS;
280 case kCondPl: return kX86CondNs;
281 case kCondVs: return kX86CondO;
282 case kCondVc: return kX86CondNo;
283 case kCondHi: return kX86CondA;
284 case kCondLs: return kX86CondBe;
285 case kCondGe: return kX86CondGe;
286 case kCondLt: return kX86CondL;
287 case kCondGt: return kX86CondG;
288 case kCondLe: return kX86CondLe;
289 case kCondAl:
290 case kCondNv: LOG(FATAL) << "Should not reach here";
291 }
292 return kX86CondO;
293}
294
Bill Buzbeea114add2012-05-03 15:00:40 -0700295LIR* opCmpBranch(CompilationUnit* cUnit, ConditionCode cond, int src1,
296 int src2, LIR* target)
buzbeee88dfbf2012-03-05 11:19:57 -0800297{
Ian Rogersb5d09b22012-03-06 22:14:17 -0800298 newLIR2(cUnit, kX86Cmp32RR, src1, src2);
299 X86ConditionCode cc = oatX86ConditionEncoding(cond);
Bill Buzbeea114add2012-05-03 15:00:40 -0700300 LIR* branch = newLIR2(cUnit, kX86Jcc8, 0 /* lir operand for Jcc offset */ ,
301 cc);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800302 branch->target = target;
303 return branch;
buzbeee88dfbf2012-03-05 11:19:57 -0800304}
305
306LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg,
307 int checkValue, LIR* target)
308{
Ian Rogers2e9f7ed2012-09-26 11:30:43 -0700309 if ((checkValue == 0) && (cond == kCondEq || cond == kCondNe)) {
Ian Rogers7caad772012-03-30 01:07:54 -0700310 // TODO: when checkValue == 0 and reg is rCX, use the jcxz/nz opcode
Ian Rogers2e9f7ed2012-09-26 11:30:43 -0700311 newLIR2(cUnit, kX86Test32RR, reg, reg);
Ian Rogers7caad772012-03-30 01:07:54 -0700312 } else {
Ian Rogers2e9f7ed2012-09-26 11:30:43 -0700313 newLIR2(cUnit, IS_SIMM8(checkValue) ? kX86Cmp32RI8 : kX86Cmp32RI, reg, checkValue);
Ian Rogers7caad772012-03-30 01:07:54 -0700314 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800315 X86ConditionCode cc = oatX86ConditionEncoding(cond);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700316 LIR* branch = newLIR2(cUnit, kX86Jcc8, 0 /* lir operand for Jcc offset */ , cc);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800317 branch->target = target;
318 return branch;
buzbeee88dfbf2012-03-05 11:19:57 -0800319}
320
321LIR* opRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
322{
Bill Buzbeea114add2012-05-03 15:00:40 -0700323 if (FPREG(rDest) || FPREG(rSrc))
324 return fpRegCopy(cUnit, rDest, rSrc);
325 LIR* res = rawLIR(cUnit, cUnit->currentDalvikOffset, kX86Mov32RR,
326 rDest, rSrc);
327 if (rDest == rSrc) {
328 res->flags.isNop = true;
329 }
330 return res;
buzbeee88dfbf2012-03-05 11:19:57 -0800331}
332
333LIR* opRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
334{
Bill Buzbeea114add2012-05-03 15:00:40 -0700335 LIR *res = opRegCopyNoInsert(cUnit, rDest, rSrc);
336 oatAppendLIR(cUnit, res);
337 return res;
buzbeee88dfbf2012-03-05 11:19:57 -0800338}
339
340void opRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
Bill Buzbeea114add2012-05-03 15:00:40 -0700341 int srcLo, int srcHi)
342{
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700343 bool destFP = FPREG(destLo) && FPREG(destHi);
344 bool srcFP = FPREG(srcLo) && FPREG(srcHi);
345 assert(FPREG(srcLo) == FPREG(srcHi));
346 assert(FPREG(destLo) == FPREG(destHi));
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700347 if (destFP) {
348 if (srcFP) {
349 opRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
buzbeee88dfbf2012-03-05 11:19:57 -0800350 } else {
jeffhaofdffdf82012-07-11 16:08:43 -0700351 // TODO: Prevent this from happening in the code. The result is often
352 // unused or could have been loaded more easily from memory.
353 newLIR2(cUnit, kX86MovdxrRR, destLo, srcLo);
354 newLIR2(cUnit, kX86MovdxrRR, destHi, srcHi);
355 newLIR2(cUnit, kX86PsllqRI, destHi, 32);
356 newLIR2(cUnit, kX86OrpsRR, destLo, destHi);
buzbeee88dfbf2012-03-05 11:19:57 -0800357 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700358 } else {
359 if (srcFP) {
jeffhaofdffdf82012-07-11 16:08:43 -0700360 newLIR2(cUnit, kX86MovdrxRR, destLo, srcLo);
361 newLIR2(cUnit, kX86PsrlqRI, srcLo, 32);
362 newLIR2(cUnit, kX86MovdrxRR, destHi, srcLo);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700363 } else {
364 // Handle overlap
365 if (srcHi == destLo) {
buzbeee88dfbf2012-03-05 11:19:57 -0800366 opRegCopy(cUnit, destHi, srcHi);
367 opRegCopy(cUnit, destLo, srcLo);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700368 } else {
buzbeee88dfbf2012-03-05 11:19:57 -0800369 opRegCopy(cUnit, destLo, srcLo);
370 opRegCopy(cUnit, destHi, srcHi);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700371 }
buzbeee88dfbf2012-03-05 11:19:57 -0800372 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700373 }
buzbeee88dfbf2012-03-05 11:19:57 -0800374}
375
jeffhao4b771a02012-07-25 15:07:21 -0700376void genFusedLongCmpBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir) {
377 LIR* labelList = cUnit->blockLabelList;
378 LIR* taken = &labelList[bb->taken->id];
379 RegLocation rlSrc1 = oatGetSrcWide(cUnit, mir, 0);
380 RegLocation rlSrc2 = oatGetSrcWide(cUnit, mir, 2);
381 oatFlushAllRegs(cUnit);
382 oatLockCallTemps(cUnit); // Prepare for explicit register usage
383 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
384 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
385 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
386 // Swap operands and condition code to prevent use of zero flag.
387 if (ccode == kCondLe || ccode == kCondGt) {
388 // Compute (r3:r2) = (r3:r2) - (r1:r0)
389 opRegReg(cUnit, kOpSub, r2, r0); // r2 = r2 - r0
390 opRegReg(cUnit, kOpSbc, r3, r1); // r3 = r3 - r1 - CF
391 } else {
392 // Compute (r1:r0) = (r1:r0) - (r3:r2)
393 opRegReg(cUnit, kOpSub, r0, r2); // r0 = r0 - r2
394 opRegReg(cUnit, kOpSbc, r1, r3); // r1 = r1 - r3 - CF
395 }
396 switch (ccode) {
397 case kCondEq:
398 case kCondNe:
399 opRegReg(cUnit, kOpOr, r0, r1); // r0 = r0 | r1
400 break;
401 case kCondLe:
402 ccode = kCondGe;
403 break;
404 case kCondGt:
405 ccode = kCondLt;
406 break;
407 case kCondLt:
408 case kCondGe:
409 break;
410 default:
411 LOG(FATAL) << "Unexpected ccode: " << (int)ccode;
412 }
413 opCondBranch(cUnit, ccode, taken);
414}
buzbeeb046e162012-10-30 15:48:42 -0700415RegLocation genDivRemLit(CompilationUnit* cUnit, RegLocation rlDest, int regLo, int lit, bool isDiv)
416{
417 LOG(FATAL) << "Unexpected use of genDivRemLit for x86";
418 return rlDest;
419}
420
421RegLocation genDivRem(CompilationUnit* cUnit, RegLocation rlDest, int regLo, int regHi, bool isDiv)
422{
423 LOG(FATAL) << "Unexpected use of genDivRem for x86";
424 return rlDest;
425}
426
427/*
428 * Mark garbage collection card. Skip if the value we're storing is null.
429 */
430void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg)
431{
432 int regCardBase = oatAllocTemp(cUnit);
433 int regCardNo = oatAllocTemp(cUnit);
434 LIR* branchOver = opCmpImmBranch(cUnit, kCondEq, valReg, 0, NULL);
435 newLIR2(cUnit, kX86Mov32RT, regCardBase, Thread::CardTableOffset().Int32Value());
436 opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, CardTable::kCardShift);
437 storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
438 kUnsignedByte);
439 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
440 branchOver->target = (LIR*)target;
441 oatFreeTemp(cUnit, regCardBase);
442 oatFreeTemp(cUnit, regCardNo);
443}
444
445bool genInlinedMinMaxInt(CompilationUnit *cUnit, CallInfo* info, bool isMin)
446{
447 DCHECK_EQ(cUnit->instructionSet, kX86);
448 RegLocation rlSrc1 = info->args[0];
449 RegLocation rlSrc2 = info->args[1];
450 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
451 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
452 RegLocation rlDest = inlineTarget(cUnit, info);
453 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
454 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
455 DCHECK_EQ(cUnit->instructionSet, kX86);
456 LIR* branch = newLIR2(cUnit, kX86Jcc8, 0, isMin ? kX86CondG : kX86CondL);
457 opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc1.lowReg);
458 LIR* branch2 = newLIR1(cUnit, kX86Jmp8, 0);
459 branch->target = newLIR0(cUnit, kPseudoTargetLabel);
460 opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc2.lowReg);
461 branch2->target = newLIR0(cUnit, kPseudoTargetLabel);
462 storeValue(cUnit, rlDest, rlResult);
463 return true;
464}
465
466void opLea(CompilationUnit* cUnit, int rBase, int reg1, int reg2, int scale, int offset)
467{
468 newLIR5(cUnit, kX86Lea32RA, rBase, reg1, reg2, scale, offset);
469}
470
471void opTlsCmp(CompilationUnit* cUnit, int offset, int val)
472{
473 newLIR2(cUnit, kX86Cmp16TI8, offset, val);
474}
475
476bool genInlinedCas32(CompilationUnit* cUnit, CallInfo* info, bool need_write_barrier) {
477 DCHECK_NE(cUnit->instructionSet, kThumb2);
478 return false;
479}
480
481bool genInlinedSqrt(CompilationUnit* cUnit, CallInfo* info) {
482 DCHECK_NE(cUnit->instructionSet, kThumb2);
483 return false;
484}
485
486LIR* opPcRelLoad(CompilationUnit* cUnit, int reg, LIR* target) {
487 LOG(FATAL) << "Unexpected use of opPcRelLoad for x86";
488 return NULL;
489}
490
491LIR* opVldm(CompilationUnit* cUnit, int rBase, int count)
492{
493 LOG(FATAL) << "Unexpected use of opVldm for x86";
494 return NULL;
495}
496
497LIR* opVstm(CompilationUnit* cUnit, int rBase, int count)
498{
499 LOG(FATAL) << "Unexpected use of opVstm for x86";
500 return NULL;
501}
502
503void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc,
504 RegLocation rlResult, int lit,
505 int firstBit, int secondBit)
506{
507 int tReg = oatAllocTemp(cUnit);
508 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, secondBit - firstBit);
509 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, tReg);
510 oatFreeTemp(cUnit, tReg);
511 if (firstBit != 0) {
512 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
513 }
514}
515
516void genDivZeroCheck(CompilationUnit* cUnit, int regLo, int regHi)
517{
518 int tReg = oatAllocTemp(cUnit);
519 opRegRegReg(cUnit, kOpOr, tReg, regLo, regHi);
520 genImmedCheck(cUnit, kCondEq, tReg, 0, kThrowDivZero);
521 oatFreeTemp(cUnit, tReg);
522}
523
524// Test suspend flag, return target of taken suspend branch
525LIR* opTestSuspend(CompilationUnit* cUnit, LIR* target)
526{
527 opTlsCmp(cUnit, Thread::ThreadFlagsOffset().Int32Value(), 0);
528 return opCondBranch(cUnit, (target == NULL) ? kCondNe : kCondEq, target);
529}
530
531// Decrement register and branch on condition
532LIR* opDecAndBranch(CompilationUnit* cUnit, ConditionCode cCode, int reg, LIR* target)
533{
534 opRegImm(cUnit, kOpSub, reg, 1);
535 return opCmpImmBranch(cUnit, cCode, reg, 0, target);
536}
537
538bool smallLiteralDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode,
539 RegLocation rlSrc, RegLocation rlDest, int lit)
540{
541 LOG(FATAL) << "Unexpected use of smallLiteralDive in x86";
542 return false;
543}
544
545LIR* opIT(CompilationUnit* cUnit, ArmConditionCode cond, const char* guide)
546{
547 LOG(FATAL) << "Unexpected use of opIT in x86";
548 return NULL;
549}
jeffhao4b771a02012-07-25 15:07:21 -0700550
buzbeee88dfbf2012-03-05 11:19:57 -0800551} // namespace art