blob: 31939f2e78489f05dcb3a2a812be5f446a8ed3d4 [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{
30 // TODO
31}
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,
37 int reg1, int base, int offset, MIR* mir, ThrowKind kind)
38{
39 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
40 mir ? mir->offset : 0, reg1, base, offset);
41 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;
46}
47
48/*
buzbeea7678db2012-03-05 15:35:46 -080049 * The lack of pc-relative loads on X86 presents somewhat of a challenge
buzbeee88dfbf2012-03-05 11:19:57 -080050 * for our PIC switch table strategy. To materialize the current location
51 * we'll do a dummy JAL and reference our tables using r_RA as the
52 * base register. Note that r_RA will be used both as the base to
53 * locate the switch table data and as the reference base for the switch
54 * target offsets stored in the table. We'll use a special pseudo-instruction
55 * to represent the jal and trigger the construction of the
56 * switch table offsets (which will happen after final assembly and all
57 * labels are fixed).
58 *
59 * The test loop will look something like:
60 *
61 * ori rEnd, r_ZERO, #tableSize ; size in bytes
62 * jal BaseLabel ; stores "return address" (BaseLabel) in r_RA
63 * nop ; opportunistically fill
64 * BaseLabel:
65 * addiu rBase, r_RA, <table> - <BaseLabel> ; table relative to BaseLabel
66 addu rEnd, rEnd, rBase ; end of table
67 * lw rVal, [rSP, vRegOff] ; Test Value
68 * loop:
69 * beq rBase, rEnd, done
70 * lw rKey, 0(rBase)
71 * addu rBase, 8
72 * bne rVal, rKey, loop
73 * lw rDisp, -4(rBase)
74 * addu r_RA, rDisp
75 * jr r_RA
76 * done:
77 *
78 */
79void genSparseSwitch(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
80{
81 UNIMPLEMENTED(WARNING) << "genSparseSwitch";
Ian Rogers7caad772012-03-30 01:07:54 -070082 newLIR0(cUnit, kX86Bkpt);
buzbeea7678db2012-03-05 15:35:46 -080083 return;
buzbeee88dfbf2012-03-05 11:19:57 -080084#if 0
85 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
86 if (cUnit->printMe) {
87 dumpSparseSwitchTable(table);
88 }
89 // Add the table to the list - we'll process it later
90 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
91 true, kAllocData);
92 tabRec->table = table;
93 tabRec->vaddr = mir->offset;
94 int elements = table[1];
95 tabRec->targets = (LIR* *)oatNew(cUnit, elements * sizeof(LIR*), true,
96 kAllocLIR);
97 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
98
99 // The table is composed of 8-byte key/disp pairs
100 int byteSize = elements * 8;
101
102 int sizeHi = byteSize >> 16;
103 int sizeLo = byteSize & 0xffff;
104
105 int rEnd = oatAllocTemp(cUnit);
106 if (sizeHi) {
buzbeea7678db2012-03-05 15:35:46 -0800107 newLIR2(cUnit, kX86Lui, rEnd, sizeHi);
buzbeee88dfbf2012-03-05 11:19:57 -0800108 }
109 // Must prevent code motion for the curr pc pair
110 genBarrier(cUnit); // Scheduling barrier
buzbeea7678db2012-03-05 15:35:46 -0800111 newLIR0(cUnit, kX86CurrPC); // Really a jal to .+8
buzbeee88dfbf2012-03-05 11:19:57 -0800112 // Now, fill the branch delay slot
113 if (sizeHi) {
buzbeea7678db2012-03-05 15:35:46 -0800114 newLIR3(cUnit, kX86Ori, rEnd, rEnd, sizeLo);
buzbeee88dfbf2012-03-05 11:19:57 -0800115 } else {
buzbeea7678db2012-03-05 15:35:46 -0800116 newLIR3(cUnit, kX86Ori, rEnd, r_ZERO, sizeLo);
buzbeee88dfbf2012-03-05 11:19:57 -0800117 }
118 genBarrier(cUnit); // Scheduling barrier
119
120 // Construct BaseLabel and set up table base register
121 LIR* baseLabel = newLIR0(cUnit, kPseudoTargetLabel);
122 // Remember base label so offsets can be computed later
123 tabRec->anchor = baseLabel;
124 int rBase = oatAllocTemp(cUnit);
buzbeea7678db2012-03-05 15:35:46 -0800125 newLIR4(cUnit, kX86Delta, rBase, 0, (intptr_t)baseLabel, (intptr_t)tabRec);
buzbeee88dfbf2012-03-05 11:19:57 -0800126 opRegRegReg(cUnit, kOpAdd, rEnd, rEnd, rBase);
127
128 // Grab switch test value
129 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
130
131 // Test loop
132 int rKey = oatAllocTemp(cUnit);
133 LIR* loopLabel = newLIR0(cUnit, kPseudoTargetLabel);
134 LIR* exitBranch = opCmpBranch(cUnit , kCondEq, rBase, rEnd, NULL);
135 loadWordDisp(cUnit, rBase, 0, rKey);
136 opRegImm(cUnit, kOpAdd, rBase, 8);
137 opCmpBranch(cUnit, kCondNe, rlSrc.lowReg, rKey, loopLabel);
138 int rDisp = oatAllocTemp(cUnit);
139 loadWordDisp(cUnit, rBase, -4, rDisp);
140 opRegRegReg(cUnit, kOpAdd, r_RA, r_RA, rDisp);
141 opReg(cUnit, kOpBx, r_RA);
142
143 // Loop exit
144 LIR* exitLabel = newLIR0(cUnit, kPseudoTargetLabel);
145 exitBranch->target = exitLabel;
146#endif
147}
148
149/*
150 * Code pattern will look something like:
151 *
152 * lw rVal
153 * jal BaseLabel ; stores "return address" (BaseLabel) in r_RA
154 * nop ; opportunistically fill
155 * [subiu rVal, bias] ; Remove bias if lowVal != 0
156 * bound check -> done
157 * lw rDisp, [r_RA, rVal]
158 * addu r_RA, rDisp
159 * jr r_RA
160 * done:
161 */
Ian Rogers7caad772012-03-30 01:07:54 -0700162void genPackedSwitch(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) {
163 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
164 if (cUnit->printMe) {
165 dumpPackedSwitchTable(table);
166 }
167 // Add the table to the list - we'll process it later
168 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
169 true, kAllocData);
170 tabRec->table = table;
171 tabRec->vaddr = mir->offset;
172 int size = table[1];
173 tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true,
174 kAllocLIR);
175 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
buzbeee88dfbf2012-03-05 11:19:57 -0800176
Ian Rogers7caad772012-03-30 01:07:54 -0700177 // Get the switch value
178 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
179 int startOfMethodReg = oatAllocTemp(cUnit);
180 // Materialize a pointer to the switch table
181 //newLIR0(cUnit, kX86Bkpt);
182 newLIR1(cUnit, kX86StartOfMethod, startOfMethodReg);
183 int lowKey = s4FromSwitchData(&table[2]);
184 int keyReg;
185 // Remove the bias, if necessary
186 if (lowKey == 0) {
187 keyReg = rlSrc.lowReg;
188 } else {
189 keyReg = oatAllocTemp(cUnit);
190 opRegRegImm(cUnit, kOpSub, keyReg, rlSrc.lowReg, lowKey);
191 }
192 // Bounds check - if < 0 or >= size continue following switch
193 opRegImm(cUnit, kOpCmp, keyReg, size-1);
194 LIR* branchOver = opCondBranch(cUnit, kCondHi, NULL);
buzbeee88dfbf2012-03-05 11:19:57 -0800195
Ian Rogers7caad772012-03-30 01:07:54 -0700196 // Load the displacement from the switch table
197 int dispReg = oatAllocTemp(cUnit);
198 newLIR5(cUnit, kX86PcRelLoadRA, dispReg, startOfMethodReg, keyReg, 2, (intptr_t)tabRec);
199 // Add displacement to start of method
200 opRegReg(cUnit, kOpAdd, startOfMethodReg, dispReg);
201 // ..and go!
202 LIR* switchBranch = newLIR1(cUnit, kX86JmpR, startOfMethodReg);
203 tabRec->anchor = switchBranch;
buzbeee88dfbf2012-03-05 11:19:57 -0800204
Ian Rogers7caad772012-03-30 01:07:54 -0700205 /* branchOver target here */
206 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
207 branchOver->target = (LIR*)target;
buzbeee88dfbf2012-03-05 11:19:57 -0800208}
209
Ian Rogers7caad772012-03-30 01:07:54 -0700210void callRuntimeHelperRegReg(CompilationUnit* cUnit, int helperOffset, int arg0, int arg1);
buzbeee88dfbf2012-03-05 11:19:57 -0800211/*
212 * Array data table format:
213 * ushort ident = 0x0300 magic value
214 * ushort width width of each element in the table
215 * uint size number of elements in the table
216 * ubyte data[size*width] table of data values (may contain a single-byte
217 * padding at the end)
218 *
219 * Total size is 4+(width * size + 1)/2 16-bit code units.
220 */
221void genFillArrayData(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
222{
Ian Rogers7caad772012-03-30 01:07:54 -0700223 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
224 // Add the table to the list - we'll process it later
225 FillArrayData *tabRec = (FillArrayData *)oatNew(cUnit, sizeof(FillArrayData), true, kAllocData);
226 tabRec->table = table;
227 tabRec->vaddr = mir->offset;
228 u2 width = tabRec->table[1];
229 u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
230 tabRec->size = (size * width) + 8;
buzbeee88dfbf2012-03-05 11:19:57 -0800231
Ian Rogers7caad772012-03-30 01:07:54 -0700232 oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec);
buzbeee88dfbf2012-03-05 11:19:57 -0800233
Ian Rogers7caad772012-03-30 01:07:54 -0700234 // Making a call - use explicit registers
235 oatFlushAllRegs(cUnit); /* Everything to home location */
236 loadValueDirectFixed(cUnit, rlSrc, rARG0);
237 // Materialize a pointer to the fill data image
238 newLIR1(cUnit, kX86StartOfMethod, rARG2);
239 newLIR2(cUnit, kX86PcRelAdr, rARG1, (intptr_t)tabRec);
240 newLIR2(cUnit, kX86Add32RR, rARG1, rARG2);
241 callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pHandleFillArrayDataFromCode), rARG0, rARG1);
buzbeee88dfbf2012-03-05 11:19:57 -0800242}
243
244void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
245{
buzbeea7678db2012-03-05 15:35:46 -0800246 UNIMPLEMENTED(WARNING) << "genNegFloat";
Ian Rogers7caad772012-03-30 01:07:54 -0700247 newLIR0(cUnit, kX86Bkpt);
buzbeea7678db2012-03-05 15:35:46 -0800248#if 0
buzbeee88dfbf2012-03-05 11:19:57 -0800249 RegLocation rlResult;
250 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
251 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
252 opRegRegImm(cUnit, kOpAdd, rlResult.lowReg,
253 rlSrc.lowReg, 0x80000000);
254 storeValue(cUnit, rlDest, rlResult);
255#endif
256}
257
258void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
259{
260 UNIMPLEMENTED(WARNING) << "genNegDouble";
Ian Rogers7caad772012-03-30 01:07:54 -0700261 newLIR0(cUnit, kX86Bkpt);
buzbeee88dfbf2012-03-05 11:19:57 -0800262#if 0
263 RegLocation rlResult;
264 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
265 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
266 opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg,
267 0x80000000);
268 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
269 storeValueWide(cUnit, rlDest, rlResult);
270#endif
271}
272
Ian Rogers7caad772012-03-30 01:07:54 -0700273LIR* genNullCheck(CompilationUnit* cUnit, int sReg, int mReg, MIR* mir);
274void callRuntimeHelperReg(CompilationUnit* cUnit, int helperOffset, int arg0);
275
buzbeee88dfbf2012-03-05 11:19:57 -0800276/*
277 * TODO: implement fast path to short-circuit thin-lock case
278 */
279void genMonitorEnter(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
280{
buzbeee88dfbf2012-03-05 11:19:57 -0800281 oatFlushAllRegs(cUnit);
282 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get obj
283 oatLockCallTemps(cUnit); // Prepare for explicit register usage
284 genNullCheck(cUnit, rlSrc.sRegLow, rARG0, mir);
285 // Go expensive route - artLockObjectFromCode(self, obj);
Ian Rogers7caad772012-03-30 01:07:54 -0700286 callRuntimeHelperReg(cUnit, ENTRYPOINT_OFFSET(pLockObjectFromCode), rARG0);
buzbeee88dfbf2012-03-05 11:19:57 -0800287}
288
289/*
290 * TODO: implement fast path to short-circuit thin-lock case
291 */
292void genMonitorExit(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
293{
buzbeee88dfbf2012-03-05 11:19:57 -0800294 oatFlushAllRegs(cUnit);
295 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get obj
296 oatLockCallTemps(cUnit); // Prepare for explicit register usage
297 genNullCheck(cUnit, rlSrc.sRegLow, rARG0, mir);
298 // Go expensive route - UnlockObjectFromCode(obj);
Ian Rogers7caad772012-03-30 01:07:54 -0700299 callRuntimeHelperReg(cUnit, ENTRYPOINT_OFFSET(pUnlockObjectFromCode), rARG0);
buzbeee88dfbf2012-03-05 11:19:57 -0800300}
301
302/*
303 * Compare two 64-bit values
304 * x = y return 0
305 * x < y return -1
306 * x > y return 1
307 *
308 * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
309 * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
310 * subu res, t0, t1 # res = -1:1:0 for [ < > = ]
311 * bnez res, finish
312 * sltu t0, x.lo, y.lo
313 * sgtu r1, x.lo, y.lo
314 * subu res, t0, t1
315 * finish:
316 *
317 */
318void genCmpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
319 RegLocation rlSrc1, RegLocation rlSrc2)
320{
Ian Rogers7caad772012-03-30 01:07:54 -0700321 oatFlushAllRegs(cUnit);
322 oatLockCallTemps(cUnit); // Prepare for explicit register usage
323 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
324 loadValueDirectWideFixed(cUnit, rlSrc1, r2, r3);
325 // Compute (r1:r0) = (r1:r0) - (r2:r3)
326 opRegReg(cUnit, kOpSub, r0, r2); // r0 = r0 - r2
327 opRegReg(cUnit, kOpSbc, r1, r3); // r1 = r1 - r3 - CF
328 opRegReg(cUnit, kOpOr, r0, r1); // r0 = high | low - sets ZF
329 newLIR2(cUnit, kX86Set8R, r0, kX86CondNz); // r0 = (r1:r0) != (r2:r3) ? 1 : 0
330 newLIR2(cUnit, kX86Movzx8RR, r0, r0);
331 opRegImm(cUnit, kOpAsr, r1, 31); // r1 = high >> 31
332 opRegReg(cUnit, kOpOr, r0, r1); // r0 holds result
333 RegLocation rlResult = LOC_C_RETURN;
buzbeee88dfbf2012-03-05 11:19:57 -0800334 storeValue(cUnit, rlDest, rlResult);
buzbeee88dfbf2012-03-05 11:19:57 -0800335}
336
Ian Rogersb5d09b22012-03-06 22:14:17 -0800337X86ConditionCode oatX86ConditionEncoding(ConditionCode cond) {
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700338 switch (cond) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800339 case kCondEq: return kX86CondEq;
340 case kCondNe: return kX86CondNe;
341 case kCondCs: return kX86CondC;
342 case kCondCc: return kX86CondNc;
343 case kCondMi: return kX86CondS;
344 case kCondPl: return kX86CondNs;
345 case kCondVs: return kX86CondO;
346 case kCondVc: return kX86CondNo;
347 case kCondHi: return kX86CondA;
348 case kCondLs: return kX86CondBe;
349 case kCondGe: return kX86CondGe;
350 case kCondLt: return kX86CondL;
351 case kCondGt: return kX86CondG;
352 case kCondLe: return kX86CondLe;
353 case kCondAl:
354 case kCondNv: LOG(FATAL) << "Should not reach here";
355 }
356 return kX86CondO;
357}
358
359LIR* opCmpBranch(CompilationUnit* cUnit, ConditionCode cond, int src1, int src2, LIR* target)
buzbeee88dfbf2012-03-05 11:19:57 -0800360{
Ian Rogersb5d09b22012-03-06 22:14:17 -0800361 newLIR2(cUnit, kX86Cmp32RR, src1, src2);
362 X86ConditionCode cc = oatX86ConditionEncoding(cond);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700363 LIR* branch = newLIR2(cUnit, kX86Jcc8, 0 /* lir operand for Jcc offset */ , cc);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800364 branch->target = target;
365 return branch;
buzbeee88dfbf2012-03-05 11:19:57 -0800366}
367
368LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg,
369 int checkValue, LIR* target)
370{
Ian Rogers7caad772012-03-30 01:07:54 -0700371 if (false && (checkValue == 0) && (cond == kCondEq || cond == kCondNe)) {
372 // TODO: when checkValue == 0 and reg is rCX, use the jcxz/nz opcode
373 // newLIR2(cUnit, kX86Test32RR, reg, reg);
374 } else {
375 newLIR2(cUnit, kX86Cmp32RI, reg, checkValue);
376 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800377 X86ConditionCode cc = oatX86ConditionEncoding(cond);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700378 LIR* branch = newLIR2(cUnit, kX86Jcc8, 0 /* lir operand for Jcc offset */ , cc);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800379 branch->target = target;
380 return branch;
buzbeee88dfbf2012-03-05 11:19:57 -0800381}
382
383LIR* opRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
384{
buzbeee88dfbf2012-03-05 11:19:57 -0800385 if (FPREG(rDest) || FPREG(rSrc))
386 return fpRegCopy(cUnit, rDest, rSrc);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800387 LIR* res = rawLIR(cUnit, cUnit->currentDalvikOffset, kX86Mov32RR,
buzbeee88dfbf2012-03-05 11:19:57 -0800388 rDest, rSrc);
389 if (rDest == rSrc) {
390 res->flags.isNop = true;
391 }
392 return res;
buzbeee88dfbf2012-03-05 11:19:57 -0800393}
394
395LIR* opRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
396{
397 LIR *res = opRegCopyNoInsert(cUnit, rDest, rSrc);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700398 oatAppendLIR(cUnit, res);
buzbeee88dfbf2012-03-05 11:19:57 -0800399 return res;
400}
401
402void opRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700403 int srcLo, int srcHi) {
404 bool destFP = FPREG(destLo) && FPREG(destHi);
405 bool srcFP = FPREG(srcLo) && FPREG(srcHi);
406 assert(FPREG(srcLo) == FPREG(srcHi));
407 assert(FPREG(destLo) == FPREG(destHi));
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700408 if (destFP) {
409 if (srcFP) {
410 opRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
buzbeee88dfbf2012-03-05 11:19:57 -0800411 } else {
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700412 UNIMPLEMENTED(WARNING);
Ian Rogers7caad772012-03-30 01:07:54 -0700413 newLIR0(cUnit, kX86Bkpt);
buzbeee88dfbf2012-03-05 11:19:57 -0800414 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700415 } else {
416 if (srcFP) {
417 UNIMPLEMENTED(WARNING);
Ian Rogers7caad772012-03-30 01:07:54 -0700418 newLIR0(cUnit, kX86Bkpt);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700419 } else {
420 // Handle overlap
421 if (srcHi == destLo) {
buzbeee88dfbf2012-03-05 11:19:57 -0800422 opRegCopy(cUnit, destHi, srcHi);
423 opRegCopy(cUnit, destLo, srcLo);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700424 } else {
buzbeee88dfbf2012-03-05 11:19:57 -0800425 opRegCopy(cUnit, destLo, srcLo);
426 opRegCopy(cUnit, destHi, srcHi);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700427 }
buzbeee88dfbf2012-03-05 11:19:57 -0800428 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700429 }
buzbeee88dfbf2012-03-05 11:19:57 -0800430}
431
432} // namespace art