blob: c6cd55c2858b6808203069b7b01f89b84ee04c4e [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";
buzbeea7678db2012-03-05 15:35:46 -080082 return;
buzbeee88dfbf2012-03-05 11:19:57 -080083#if 0
84 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
85 if (cUnit->printMe) {
86 dumpSparseSwitchTable(table);
87 }
88 // Add the table to the list - we'll process it later
89 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
90 true, kAllocData);
91 tabRec->table = table;
92 tabRec->vaddr = mir->offset;
93 int elements = table[1];
94 tabRec->targets = (LIR* *)oatNew(cUnit, elements * sizeof(LIR*), true,
95 kAllocLIR);
96 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
97
98 // The table is composed of 8-byte key/disp pairs
99 int byteSize = elements * 8;
100
101 int sizeHi = byteSize >> 16;
102 int sizeLo = byteSize & 0xffff;
103
104 int rEnd = oatAllocTemp(cUnit);
105 if (sizeHi) {
buzbeea7678db2012-03-05 15:35:46 -0800106 newLIR2(cUnit, kX86Lui, rEnd, sizeHi);
buzbeee88dfbf2012-03-05 11:19:57 -0800107 }
108 // Must prevent code motion for the curr pc pair
109 genBarrier(cUnit); // Scheduling barrier
buzbeea7678db2012-03-05 15:35:46 -0800110 newLIR0(cUnit, kX86CurrPC); // Really a jal to .+8
buzbeee88dfbf2012-03-05 11:19:57 -0800111 // Now, fill the branch delay slot
112 if (sizeHi) {
buzbeea7678db2012-03-05 15:35:46 -0800113 newLIR3(cUnit, kX86Ori, rEnd, rEnd, sizeLo);
buzbeee88dfbf2012-03-05 11:19:57 -0800114 } else {
buzbeea7678db2012-03-05 15:35:46 -0800115 newLIR3(cUnit, kX86Ori, rEnd, r_ZERO, sizeLo);
buzbeee88dfbf2012-03-05 11:19:57 -0800116 }
117 genBarrier(cUnit); // Scheduling barrier
118
119 // Construct BaseLabel and set up table base register
120 LIR* baseLabel = newLIR0(cUnit, kPseudoTargetLabel);
121 // Remember base label so offsets can be computed later
122 tabRec->anchor = baseLabel;
123 int rBase = oatAllocTemp(cUnit);
buzbeea7678db2012-03-05 15:35:46 -0800124 newLIR4(cUnit, kX86Delta, rBase, 0, (intptr_t)baseLabel, (intptr_t)tabRec);
buzbeee88dfbf2012-03-05 11:19:57 -0800125 opRegRegReg(cUnit, kOpAdd, rEnd, rEnd, rBase);
126
127 // Grab switch test value
128 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
129
130 // Test loop
131 int rKey = oatAllocTemp(cUnit);
132 LIR* loopLabel = newLIR0(cUnit, kPseudoTargetLabel);
133 LIR* exitBranch = opCmpBranch(cUnit , kCondEq, rBase, rEnd, NULL);
134 loadWordDisp(cUnit, rBase, 0, rKey);
135 opRegImm(cUnit, kOpAdd, rBase, 8);
136 opCmpBranch(cUnit, kCondNe, rlSrc.lowReg, rKey, loopLabel);
137 int rDisp = oatAllocTemp(cUnit);
138 loadWordDisp(cUnit, rBase, -4, rDisp);
139 opRegRegReg(cUnit, kOpAdd, r_RA, r_RA, rDisp);
140 opReg(cUnit, kOpBx, r_RA);
141
142 // Loop exit
143 LIR* exitLabel = newLIR0(cUnit, kPseudoTargetLabel);
144 exitBranch->target = exitLabel;
145#endif
146}
147
148/*
149 * Code pattern will look something like:
150 *
151 * lw rVal
152 * jal BaseLabel ; stores "return address" (BaseLabel) in r_RA
153 * nop ; opportunistically fill
154 * [subiu rVal, bias] ; Remove bias if lowVal != 0
155 * bound check -> done
156 * lw rDisp, [r_RA, rVal]
157 * addu r_RA, rDisp
158 * jr r_RA
159 * done:
160 */
161void genPackedSwitch(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
162{
163 UNIMPLEMENTED(WARNING) << "genPackedSwitch";
164#if 0
165 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
166 if (cUnit->printMe) {
167 dumpPackedSwitchTable(table);
168 }
169 // Add the table to the list - we'll process it later
170 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
171 true, kAllocData);
172 tabRec->table = table;
173 tabRec->vaddr = mir->offset;
174 int size = table[1];
175 tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true,
176 kAllocLIR);
177 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
178
179 // Get the switch value
180 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
181
182 // Prepare the bias. If too big, handle 1st stage here
183 int lowKey = s4FromSwitchData(&table[2]);
184 bool largeBias = false;
185 int rKey;
186 if (lowKey == 0) {
187 rKey = rlSrc.lowReg;
188 } else if ((lowKey & 0xffff) != lowKey) {
189 rKey = oatAllocTemp(cUnit);
190 loadConstant(cUnit, rKey, lowKey);
191 largeBias = true;
192 } else {
193 rKey = oatAllocTemp(cUnit);
194 }
195
196 // Must prevent code motion for the curr pc pair
197 genBarrier(cUnit);
buzbeea7678db2012-03-05 15:35:46 -0800198 newLIR0(cUnit, kX86CurrPC); // Really a jal to .+8
buzbeee88dfbf2012-03-05 11:19:57 -0800199 // Now, fill the branch delay slot with bias strip
200 if (lowKey == 0) {
buzbeea7678db2012-03-05 15:35:46 -0800201 newLIR0(cUnit, kX86Nop);
buzbeee88dfbf2012-03-05 11:19:57 -0800202 } else {
203 if (largeBias) {
204 opRegRegReg(cUnit, kOpSub, rKey, rlSrc.lowReg, rKey);
205 } else {
206 opRegRegImm(cUnit, kOpSub, rKey, rlSrc.lowReg, lowKey);
207 }
208 }
209 genBarrier(cUnit); // Scheduling barrier
210
211 // Construct BaseLabel and set up table base register
212 LIR* baseLabel = newLIR0(cUnit, kPseudoTargetLabel);
213 // Remember base label so offsets can be computed later
214 tabRec->anchor = baseLabel;
215
216 // Bounds check - if < 0 or >= size continue following switch
217 LIR* branchOver = opCmpImmBranch(cUnit, kCondHi, rKey, size-1, NULL);
218
219 // Materialize the table base pointer
220 int rBase = oatAllocTemp(cUnit);
buzbeea7678db2012-03-05 15:35:46 -0800221 newLIR4(cUnit, kX86Delta, rBase, 0, (intptr_t)baseLabel, (intptr_t)tabRec);
buzbeee88dfbf2012-03-05 11:19:57 -0800222
223 // Load the displacement from the switch table
224 int rDisp = oatAllocTemp(cUnit);
225 loadBaseIndexed(cUnit, rBase, rKey, rDisp, 2, kWord);
226
227 // Add to r_AP and go
228 opRegRegReg(cUnit, kOpAdd, r_RA, r_RA, rDisp);
229 opReg(cUnit, kOpBx, r_RA);
230
231 /* branchOver target here */
232 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
233 branchOver->target = (LIR*)target;
234#endif
235}
236
237/*
238 * Array data table format:
239 * ushort ident = 0x0300 magic value
240 * ushort width width of each element in the table
241 * uint size number of elements in the table
242 * ubyte data[size*width] table of data values (may contain a single-byte
243 * padding at the end)
244 *
245 * Total size is 4+(width * size + 1)/2 16-bit code units.
246 */
247void genFillArrayData(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
248{
249 UNIMPLEMENTED(WARNING) << "genFillArrayData";
250#if 0
251 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
252 // Add the table to the list - we'll process it later
253 FillArrayData *tabRec = (FillArrayData *)
254 oatNew(cUnit, sizeof(FillArrayData), true, kAllocData);
255 tabRec->table = table;
256 tabRec->vaddr = mir->offset;
257 u2 width = tabRec->table[1];
258 u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
259 tabRec->size = (size * width) + 8;
260
261 oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec);
262
263 // Making a call - use explicit registers
264 oatFlushAllRegs(cUnit); /* Everything to home location */
265 oatLockCallTemps(cUnit);
266 loadValueDirectFixed(cUnit, rlSrc, rARG0);
267
268 // Must prevent code motion for the curr pc pair
269 genBarrier(cUnit);
buzbeea7678db2012-03-05 15:35:46 -0800270 newLIR0(cUnit, kX86CurrPC); // Really a jal to .+8
buzbeee88dfbf2012-03-05 11:19:57 -0800271 // Now, fill the branch delay slot with the helper load
272 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
273 pHandleFillArrayDataFromCode));
274 genBarrier(cUnit); // Scheduling barrier
275
276 // Construct BaseLabel and set up table base register
277 LIR* baseLabel = newLIR0(cUnit, kPseudoTargetLabel);
278
279 // Materialize a pointer to the fill data image
buzbeea7678db2012-03-05 15:35:46 -0800280 newLIR4(cUnit, kX86Delta, rARG1, 0, (intptr_t)baseLabel, (intptr_t)tabRec);
buzbeee88dfbf2012-03-05 11:19:57 -0800281
282 // And go...
283 callRuntimeHelper(cUnit, rTgt); // ( array*, fill_data* )
buzbeea7678db2012-03-05 15:35:46 -0800284#endif
buzbeee88dfbf2012-03-05 11:19:57 -0800285}
286
287void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
288{
buzbeea7678db2012-03-05 15:35:46 -0800289 UNIMPLEMENTED(WARNING) << "genNegFloat";
290#if 0
buzbeee88dfbf2012-03-05 11:19:57 -0800291 RegLocation rlResult;
292 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
293 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
294 opRegRegImm(cUnit, kOpAdd, rlResult.lowReg,
295 rlSrc.lowReg, 0x80000000);
296 storeValue(cUnit, rlDest, rlResult);
297#endif
298}
299
300void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
301{
302 UNIMPLEMENTED(WARNING) << "genNegDouble";
303#if 0
304 RegLocation rlResult;
305 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
306 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
307 opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg,
308 0x80000000);
309 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
310 storeValueWide(cUnit, rlDest, rlResult);
311#endif
312}
313
314/*
315 * TODO: implement fast path to short-circuit thin-lock case
316 */
317void genMonitorEnter(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
318{
319 UNIMPLEMENTED(WARNING) << "genMonitorEnter";
320#if 0
321 oatFlushAllRegs(cUnit);
322 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get obj
323 oatLockCallTemps(cUnit); // Prepare for explicit register usage
324 genNullCheck(cUnit, rlSrc.sRegLow, rARG0, mir);
325 // Go expensive route - artLockObjectFromCode(self, obj);
326 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pLockObjectFromCode));
327 callRuntimeHelper(cUnit, rTgt);
328#endif
329}
330
331/*
332 * TODO: implement fast path to short-circuit thin-lock case
333 */
334void genMonitorExit(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
335{
336 UNIMPLEMENTED(WARNING) << "genMonitor";
337#if 0
338 oatFlushAllRegs(cUnit);
339 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get obj
340 oatLockCallTemps(cUnit); // Prepare for explicit register usage
341 genNullCheck(cUnit, rlSrc.sRegLow, rARG0, mir);
342 // Go expensive route - UnlockObjectFromCode(obj);
343 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pUnlockObjectFromCode));
344 callRuntimeHelper(cUnit, rTgt);
345#endif
346}
347
348/*
349 * Compare two 64-bit values
350 * x = y return 0
351 * x < y return -1
352 * x > y return 1
353 *
354 * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
355 * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
356 * subu res, t0, t1 # res = -1:1:0 for [ < > = ]
357 * bnez res, finish
358 * sltu t0, x.lo, y.lo
359 * sgtu r1, x.lo, y.lo
360 * subu res, t0, t1
361 * finish:
362 *
363 */
364void genCmpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
365 RegLocation rlSrc1, RegLocation rlSrc2)
366{
367 UNIMPLEMENTED(WARNING) << "genCmpLong";
368#if 0
369 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
370 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
371 int t0 = oatAllocTemp(cUnit);
372 int t1 = oatAllocTemp(cUnit);
373 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
buzbeea7678db2012-03-05 15:35:46 -0800374 newLIR3(cUnit, kX86Slt, t0, rlSrc1.highReg, rlSrc2.highReg);
375 newLIR3(cUnit, kX86Slt, t1, rlSrc2.highReg, rlSrc1.highReg);
376 newLIR3(cUnit, kX86Subu, rlResult.lowReg, t1, t0);
buzbeee88dfbf2012-03-05 11:19:57 -0800377 LIR* branch = opCmpImmBranch(cUnit, kCondNe, rlResult.lowReg, 0, NULL);
buzbeea7678db2012-03-05 15:35:46 -0800378 newLIR3(cUnit, kX86Sltu, t0, rlSrc1.lowReg, rlSrc2.lowReg);
379 newLIR3(cUnit, kX86Sltu, t1, rlSrc2.lowReg, rlSrc1.lowReg);
380 newLIR3(cUnit, kX86Subu, rlResult.lowReg, t1, t0);
buzbeee88dfbf2012-03-05 11:19:57 -0800381 oatFreeTemp(cUnit, t0);
382 oatFreeTemp(cUnit, t1);
383 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
384 branch->target = (LIR*)target;
385 storeValue(cUnit, rlDest, rlResult);
386#endif
387}
388
Ian Rogersb5d09b22012-03-06 22:14:17 -0800389X86ConditionCode oatX86ConditionEncoding(ConditionCode cond) {
390 switch(cond) {
391 case kCondEq: return kX86CondEq;
392 case kCondNe: return kX86CondNe;
393 case kCondCs: return kX86CondC;
394 case kCondCc: return kX86CondNc;
395 case kCondMi: return kX86CondS;
396 case kCondPl: return kX86CondNs;
397 case kCondVs: return kX86CondO;
398 case kCondVc: return kX86CondNo;
399 case kCondHi: return kX86CondA;
400 case kCondLs: return kX86CondBe;
401 case kCondGe: return kX86CondGe;
402 case kCondLt: return kX86CondL;
403 case kCondGt: return kX86CondG;
404 case kCondLe: return kX86CondLe;
405 case kCondAl:
406 case kCondNv: LOG(FATAL) << "Should not reach here";
407 }
408 return kX86CondO;
409}
410
411LIR* opCmpBranch(CompilationUnit* cUnit, ConditionCode cond, int src1, int src2, LIR* target)
buzbeee88dfbf2012-03-05 11:19:57 -0800412{
Ian Rogersb5d09b22012-03-06 22:14:17 -0800413 newLIR2(cUnit, kX86Cmp32RR, src1, src2);
414 X86ConditionCode cc = oatX86ConditionEncoding(cond);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700415 LIR* branch = newLIR2(cUnit, kX86Jcc8, 0 /* lir operand for Jcc offset */ , cc);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800416 branch->target = target;
417 return branch;
buzbeee88dfbf2012-03-05 11:19:57 -0800418}
419
420LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg,
421 int checkValue, LIR* target)
422{
Ian Rogersb5d09b22012-03-06 22:14:17 -0800423 // TODO: when checkValue == 0 and reg is rCX, use the jcxz/nz opcode
424 newLIR2(cUnit, kX86Cmp32RI, reg, checkValue);
425 X86ConditionCode cc = oatX86ConditionEncoding(cond);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700426 LIR* branch = newLIR2(cUnit, kX86Jcc8, 0 /* lir operand for Jcc offset */ , cc);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800427 branch->target = target;
428 return branch;
buzbeee88dfbf2012-03-05 11:19:57 -0800429}
430
431LIR* opRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
432{
buzbeee88dfbf2012-03-05 11:19:57 -0800433 if (FPREG(rDest) || FPREG(rSrc))
434 return fpRegCopy(cUnit, rDest, rSrc);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800435 LIR* res = rawLIR(cUnit, cUnit->currentDalvikOffset, kX86Mov32RR,
buzbeee88dfbf2012-03-05 11:19:57 -0800436 rDest, rSrc);
437 if (rDest == rSrc) {
438 res->flags.isNop = true;
439 }
440 return res;
buzbeee88dfbf2012-03-05 11:19:57 -0800441}
442
443LIR* opRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
444{
445 LIR *res = opRegCopyNoInsert(cUnit, rDest, rSrc);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700446 oatAppendLIR(cUnit, res);
buzbeee88dfbf2012-03-05 11:19:57 -0800447 return res;
448}
449
450void opRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700451 int srcLo, int srcHi) {
452 bool destFP = FPREG(destLo) && FPREG(destHi);
453 bool srcFP = FPREG(srcLo) && FPREG(srcHi);
454 assert(FPREG(srcLo) == FPREG(srcHi));
455 assert(FPREG(destLo) == FPREG(destHi));
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700456 if (destFP) {
457 if (srcFP) {
458 opRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
buzbeee88dfbf2012-03-05 11:19:57 -0800459 } else {
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700460 UNIMPLEMENTED(WARNING);
buzbeee88dfbf2012-03-05 11:19:57 -0800461 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700462 } else {
463 if (srcFP) {
464 UNIMPLEMENTED(WARNING);
465 } else {
466 // Handle overlap
467 if (srcHi == destLo) {
buzbeee88dfbf2012-03-05 11:19:57 -0800468 opRegCopy(cUnit, destHi, srcHi);
469 opRegCopy(cUnit, destLo, srcLo);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700470 } else {
buzbeee88dfbf2012-03-05 11:19:57 -0800471 opRegCopy(cUnit, destLo, srcLo);
472 opRegCopy(cUnit, destHi, srcHi);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700473 }
buzbeee88dfbf2012-03-05 11:19:57 -0800474 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700475 }
buzbeee88dfbf2012-03-05 11:19:57 -0800476}
477
478} // namespace art