blob: 2bb2f7a560a94da2fdbb61c99427fc586f842869 [file] [log] [blame]
buzbeee3acd072012-02-25 17:03:10 -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/*
18 * This file contains codegen for the Mips ISA and is intended to be
19 * includes by:
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 */
24
25namespace art {
26
buzbeee3acd072012-02-25 17:03:10 -080027/*
buzbeec5159d52012-03-03 11:48:39 -080028 * The lack of pc-relative loads on Mips presents somewhat of a challenge
29 * for our PIC switch table strategy. To materialize the current location
30 * we'll do a dummy JAL and reference our tables using r_RA as the
31 * base register. Note that r_RA will be used both as the base to
32 * locate the switch table data and as the reference base for the switch
33 * target offsets stored in the table. We'll use a special pseudo-instruction
34 * to represent the jal and trigger the construction of the
35 * switch table offsets (which will happen after final assembly and all
36 * labels are fixed).
buzbeee3acd072012-02-25 17:03:10 -080037 *
38 * The test loop will look something like:
39 *
buzbeec5159d52012-03-03 11:48:39 -080040 * ori rEnd, r_ZERO, #tableSize ; size in bytes
41 * jal BaseLabel ; stores "return address" (BaseLabel) in r_RA
42 * nop ; opportunistically fill
43 * BaseLabel:
44 * addiu rBase, r_RA, <table> - <BaseLabel> ; table relative to BaseLabel
45 addu rEnd, rEnd, rBase ; end of table
46 * lw rVal, [rSP, vRegOff] ; Test Value
47 * loop:
48 * beq rBase, rEnd, done
49 * lw rKey, 0(rBase)
50 * addu rBase, 8
51 * bne rVal, rKey, loop
52 * lw rDisp, -4(rBase)
53 * addu r_RA, rDisp
54 * jr r_RA
55 * done:
56 *
buzbeee3acd072012-02-25 17:03:10 -080057 */
buzbee5de34942012-03-01 14:51:57 -080058void genSparseSwitch(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbeee3acd072012-02-25 17:03:10 -080059{
buzbeee3acd072012-02-25 17:03:10 -080060 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
61 if (cUnit->printMe) {
62 dumpSparseSwitchTable(table);
63 }
64 // Add the table to the list - we'll process it later
65 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
66 true, kAllocData);
67 tabRec->table = table;
68 tabRec->vaddr = mir->offset;
buzbeec5159d52012-03-03 11:48:39 -080069 int elements = table[1];
70 tabRec->targets = (LIR* *)oatNew(cUnit, elements * sizeof(LIR*), true,
buzbee5de34942012-03-01 14:51:57 -080071 kAllocLIR);
buzbeee3acd072012-02-25 17:03:10 -080072 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
73
buzbeec5159d52012-03-03 11:48:39 -080074 // The table is composed of 8-byte key/disp pairs
75 int byteSize = elements * 8;
76
77 int sizeHi = byteSize >> 16;
78 int sizeLo = byteSize & 0xffff;
79
80 int rEnd = oatAllocTemp(cUnit);
81 if (sizeHi) {
82 newLIR2(cUnit, kMipsLui, rEnd, sizeHi);
buzbeee3acd072012-02-25 17:03:10 -080083 }
buzbeec5159d52012-03-03 11:48:39 -080084 // Must prevent code motion for the curr pc pair
85 genBarrier(cUnit); // Scheduling barrier
86 newLIR0(cUnit, kMipsCurrPC); // Really a jal to .+8
87 // Now, fill the branch delay slot
88 if (sizeHi) {
89 newLIR3(cUnit, kMipsOri, rEnd, rEnd, sizeLo);
90 } else {
91 newLIR3(cUnit, kMipsOri, rEnd, r_ZERO, sizeLo);
92 }
93 genBarrier(cUnit); // Scheduling barrier
94
95 // Construct BaseLabel and set up table base register
96 LIR* baseLabel = newLIR0(cUnit, kPseudoTargetLabel);
97 // Remember base label so offsets can be computed later
98 tabRec->anchor = baseLabel;
99 int rBase = oatAllocTemp(cUnit);
100 newLIR4(cUnit, kMipsDelta, rBase, 0, (intptr_t)baseLabel, (intptr_t)tabRec);
101 opRegRegReg(cUnit, kOpAdd, rEnd, rEnd, rBase);
102
103 // Grab switch test value
104 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
105
106 // Test loop
107 int rKey = oatAllocTemp(cUnit);
108 LIR* loopLabel = newLIR0(cUnit, kPseudoTargetLabel);
109 LIR* exitBranch = opCmpBranch(cUnit , kCondEq, rBase, rEnd, NULL);
110 loadWordDisp(cUnit, rBase, 0, rKey);
111 opRegImm(cUnit, kOpAdd, rBase, 8);
112 opCmpBranch(cUnit, kCondNe, rlSrc.lowReg, rKey, loopLabel);
113 int rDisp = oatAllocTemp(cUnit);
114 loadWordDisp(cUnit, rBase, -4, rDisp);
115 opRegRegReg(cUnit, kOpAdd, r_RA, r_RA, rDisp);
116 opReg(cUnit, kOpBx, r_RA);
117
118 // Loop exit
119 LIR* exitLabel = newLIR0(cUnit, kPseudoTargetLabel);
120 exitBranch->target = exitLabel;
buzbeee3acd072012-02-25 17:03:10 -0800121}
122
buzbeec5159d52012-03-03 11:48:39 -0800123/*
124 * Code pattern will look something like:
125 *
126 * lw rVal
127 * jal BaseLabel ; stores "return address" (BaseLabel) in r_RA
128 * nop ; opportunistically fill
129 * [subiu rVal, bias] ; Remove bias if lowVal != 0
130 * bound check -> done
131 * lw rDisp, [r_RA, rVal]
132 * addu r_RA, rDisp
133 * jr r_RA
134 * done:
135 */
buzbee5de34942012-03-01 14:51:57 -0800136void genPackedSwitch(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbeee3acd072012-02-25 17:03:10 -0800137{
buzbeee3acd072012-02-25 17:03:10 -0800138 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
143 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
144 true, kAllocData);
145 tabRec->table = table;
146 tabRec->vaddr = mir->offset;
147 int size = table[1];
buzbee5de34942012-03-01 14:51:57 -0800148 tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true,
buzbeee3acd072012-02-25 17:03:10 -0800149 kAllocLIR);
150 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
151
152 // Get the switch value
153 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
buzbeec5159d52012-03-03 11:48:39 -0800154
155 // Prepare the bias. If too big, handle 1st stage here
buzbeee3acd072012-02-25 17:03:10 -0800156 int lowKey = s4FromSwitchData(&table[2]);
buzbeec5159d52012-03-03 11:48:39 -0800157 bool largeBias = false;
158 int rKey;
buzbeee3acd072012-02-25 17:03:10 -0800159 if (lowKey == 0) {
buzbeec5159d52012-03-03 11:48:39 -0800160 rKey = rlSrc.lowReg;
161 } else if ((lowKey & 0xffff) != lowKey) {
162 rKey = oatAllocTemp(cUnit);
163 loadConstant(cUnit, rKey, lowKey);
164 largeBias = true;
buzbeee3acd072012-02-25 17:03:10 -0800165 } else {
buzbeec5159d52012-03-03 11:48:39 -0800166 rKey = oatAllocTemp(cUnit);
buzbeee3acd072012-02-25 17:03:10 -0800167 }
buzbeec5159d52012-03-03 11:48:39 -0800168
169 // Must prevent code motion for the curr pc pair
170 genBarrier(cUnit);
171 newLIR0(cUnit, kMipsCurrPC); // Really a jal to .+8
172 // Now, fill the branch delay slot with bias strip
173 if (lowKey == 0) {
174 newLIR0(cUnit, kMipsNop);
175 } else {
176 if (largeBias) {
177 opRegRegReg(cUnit, kOpSub, rKey, rlSrc.lowReg, rKey);
178 } else {
179 opRegRegImm(cUnit, kOpSub, rKey, rlSrc.lowReg, lowKey);
180 }
181 }
182 genBarrier(cUnit); // Scheduling barrier
183
184 // Construct BaseLabel and set up table base register
185 LIR* baseLabel = newLIR0(cUnit, kPseudoTargetLabel);
186 // Remember base label so offsets can be computed later
187 tabRec->anchor = baseLabel;
188
buzbeee3acd072012-02-25 17:03:10 -0800189 // Bounds check - if < 0 or >= size continue following switch
buzbeec5159d52012-03-03 11:48:39 -0800190 LIR* branchOver = opCmpImmBranch(cUnit, kCondHi, rKey, size-1, NULL);
191
192 // Materialize the table base pointer
193 int rBase = oatAllocTemp(cUnit);
194 newLIR4(cUnit, kMipsDelta, rBase, 0, (intptr_t)baseLabel, (intptr_t)tabRec);
buzbeee3acd072012-02-25 17:03:10 -0800195
196 // Load the displacement from the switch table
buzbeec5159d52012-03-03 11:48:39 -0800197 int rDisp = oatAllocTemp(cUnit);
198 loadBaseIndexed(cUnit, rBase, rKey, rDisp, 2, kWord);
buzbeee3acd072012-02-25 17:03:10 -0800199
buzbeec5159d52012-03-03 11:48:39 -0800200 // Add to r_AP and go
201 opRegRegReg(cUnit, kOpAdd, r_RA, r_RA, rDisp);
202 opReg(cUnit, kOpBx, r_RA);
buzbeee3acd072012-02-25 17:03:10 -0800203
204 /* branchOver target here */
buzbee5de34942012-03-01 14:51:57 -0800205 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee5de34942012-03-01 14:51:57 -0800206 branchOver->target = (LIR*)target;
buzbeee3acd072012-02-25 17:03:10 -0800207}
208
209/*
210 * Array data table format:
211 * ushort ident = 0x0300 magic value
212 * ushort width width of each element in the table
213 * uint size number of elements in the table
214 * ubyte data[size*width] table of data values (may contain a single-byte
215 * padding at the end)
216 *
217 * Total size is 4+(width * size + 1)/2 16-bit code units.
218 */
buzbee5de34942012-03-01 14:51:57 -0800219void genFillArrayData(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbeee3acd072012-02-25 17:03:10 -0800220{
buzbeee3acd072012-02-25 17:03:10 -0800221 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
222 // Add the table to the list - we'll process it later
223 FillArrayData *tabRec = (FillArrayData *)
224 oatNew(cUnit, sizeof(FillArrayData), true, kAllocData);
225 tabRec->table = table;
226 tabRec->vaddr = mir->offset;
227 u2 width = tabRec->table[1];
228 u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
229 tabRec->size = (size * width) + 8;
230
231 oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec);
232
233 // Making a call - use explicit registers
234 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbeec5159d52012-03-03 11:48:39 -0800235 oatLockCallTemps(cUnit);
buzbee5de34942012-03-01 14:51:57 -0800236 loadValueDirectFixed(cUnit, rlSrc, rARG0);
buzbeec5159d52012-03-03 11:48:39 -0800237
238 // Must prevent code motion for the curr pc pair
239 genBarrier(cUnit);
240 newLIR0(cUnit, kMipsCurrPC); // Really a jal to .+8
241 // Now, fill the branch delay slot with the helper load
242 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
243 pHandleFillArrayDataFromCode));
244 genBarrier(cUnit); // Scheduling barrier
245
246 // Construct BaseLabel and set up table base register
247 LIR* baseLabel = newLIR0(cUnit, kPseudoTargetLabel);
248
buzbeee3acd072012-02-25 17:03:10 -0800249 // Materialize a pointer to the fill data image
buzbeec5159d52012-03-03 11:48:39 -0800250 newLIR4(cUnit, kMipsDelta, rARG1, 0, (intptr_t)baseLabel, (intptr_t)tabRec);
251
252 // And go...
253 callRuntimeHelper(cUnit, rTgt); // ( array*, fill_data* )
buzbeee3acd072012-02-25 17:03:10 -0800254}
255
buzbee71ac9942012-03-01 17:23:10 -0800256void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
257{
258 RegLocation rlResult;
259 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
260 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
261 opRegRegImm(cUnit, kOpAdd, rlResult.lowReg,
262 rlSrc.lowReg, 0x80000000);
263 storeValue(cUnit, rlDest, rlResult);
264}
265
266void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
267{
268 RegLocation rlResult;
269 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
270 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
271 opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg,
272 0x80000000);
buzbee82488f52012-03-02 08:20:26 -0800273 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
buzbee71ac9942012-03-01 17:23:10 -0800274 storeValueWide(cUnit, rlDest, rlResult);
275}
276
buzbee5de34942012-03-01 14:51:57 -0800277/*
278 * TODO: implement fast path to short-circuit thin-lock case
279 */
280void genMonitorEnter(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbeee3acd072012-02-25 17:03:10 -0800281{
buzbee5de34942012-03-01 14:51:57 -0800282 oatFlushAllRegs(cUnit);
283 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get obj
284 oatLockCallTemps(cUnit); // Prepare for explicit register usage
285 genNullCheck(cUnit, rlSrc.sRegLow, rARG0, mir);
286 // Go expensive route - artLockObjectFromCode(self, obj);
287 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pLockObjectFromCode));
288 callRuntimeHelper(cUnit, rTgt);
buzbeee3acd072012-02-25 17:03:10 -0800289}
290
291/*
buzbee5de34942012-03-01 14:51:57 -0800292 * TODO: implement fast path to short-circuit thin-lock case
buzbeee3acd072012-02-25 17:03:10 -0800293 */
buzbee5de34942012-03-01 14:51:57 -0800294void genMonitorExit(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbeee3acd072012-02-25 17:03:10 -0800295{
buzbee5de34942012-03-01 14:51:57 -0800296 oatFlushAllRegs(cUnit);
297 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get obj
298 oatLockCallTemps(cUnit); // Prepare for explicit register usage
299 genNullCheck(cUnit, rlSrc.sRegLow, rARG0, mir);
300 // Go expensive route - UnlockObjectFromCode(obj);
301 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pUnlockObjectFromCode));
302 callRuntimeHelper(cUnit, rTgt);
303}
304
305/*
306 * Compare two 64-bit values
307 * x = y return 0
308 * x < y return -1
309 * x > y return 1
310 *
311 * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
312 * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
313 * subu res, t0, t1 # res = -1:1:0 for [ < > = ]
314 * bnez res, finish
315 * sltu t0, x.lo, y.lo
316 * sgtu r1, x.lo, y.lo
317 * subu res, t0, t1
318 * finish:
319 *
320 */
321void genCmpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
322 RegLocation rlSrc1, RegLocation rlSrc2)
323{
324 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
325 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
326 int t0 = oatAllocTemp(cUnit);
327 int t1 = oatAllocTemp(cUnit);
328 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
329 newLIR3(cUnit, kMipsSlt, t0, rlSrc1.highReg, rlSrc2.highReg);
330 newLIR3(cUnit, kMipsSlt, t1, rlSrc2.highReg, rlSrc1.highReg);
331 newLIR3(cUnit, kMipsSubu, rlResult.lowReg, t1, t0);
buzbee82488f52012-03-02 08:20:26 -0800332 LIR* branch = opCmpImmBranch(cUnit, kCondNe, rlResult.lowReg, 0, NULL);
buzbee5de34942012-03-01 14:51:57 -0800333 newLIR3(cUnit, kMipsSltu, t0, rlSrc1.lowReg, rlSrc2.lowReg);
334 newLIR3(cUnit, kMipsSltu, t1, rlSrc2.lowReg, rlSrc1.lowReg);
335 newLIR3(cUnit, kMipsSubu, rlResult.lowReg, t1, t0);
336 oatFreeTemp(cUnit, t0);
337 oatFreeTemp(cUnit, t1);
338 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee5de34942012-03-01 14:51:57 -0800339 branch->target = (LIR*)target;
buzbeee3acd072012-02-25 17:03:10 -0800340 storeValue(cUnit, rlDest, rlResult);
341}
342
buzbee82488f52012-03-02 08:20:26 -0800343LIR* opCmpBranch(CompilationUnit* cUnit, ConditionCode cond, int src1,
344 int src2, LIR* target)
buzbeee3acd072012-02-25 17:03:10 -0800345{
buzbee0398c422012-03-02 15:22:47 -0800346 LIR* branch;
347 MipsOpCode sltOp;
348 MipsOpCode brOp;
349 bool cmpZero = false;
350 bool swapped = false;
351 switch(cond) {
352 case kCondEq:
353 brOp = kMipsBeq;
354 cmpZero = true;
355 break;
356 case kCondNe:
357 brOp = kMipsBne;
358 cmpZero = true;
359 break;
360 case kCondCc:
361 sltOp = kMipsSltu;
362 brOp = kMipsBnez;
363 break;
364 case kCondCs:
365 sltOp = kMipsSltu;
366 brOp = kMipsBeqz;
367 break;
368 case kCondGe:
369 sltOp = kMipsSlt;
370 brOp = kMipsBeqz;
371 break;
372 case kCondGt:
373 sltOp = kMipsSlt;
374 brOp = kMipsBnez;
375 swapped = true;
376 break;
377 case kCondLe:
378 sltOp = kMipsSlt;
379 brOp = kMipsBeqz;
380 swapped = true;
381 break;
382 case kCondLt:
383 sltOp = kMipsSlt;
384 brOp = kMipsBnez;
385 break;
buzbeec5159d52012-03-03 11:48:39 -0800386 case kCondHi: // Gtu
387 sltOp = kMipsSltu;
388 brOp = kMipsBnez;
389 swapped = true;
390 break;
buzbee0398c422012-03-02 15:22:47 -0800391 default:
buzbeea2ebdd72012-03-04 14:57:06 -0800392 LOG(FATAL) << "No support for ConditionCode: " << (int) cond;
buzbee0398c422012-03-02 15:22:47 -0800393 return NULL;
394 }
395 if (cmpZero) {
396 branch = newLIR2(cUnit, brOp, src1, src2);
buzbee82488f52012-03-02 08:20:26 -0800397 } else {
buzbee82488f52012-03-02 08:20:26 -0800398 int tReg = oatAllocTemp(cUnit);
399 if (swapped) {
400 newLIR3(cUnit, sltOp, tReg, src2, src1);
401 } else {
402 newLIR3(cUnit, sltOp, tReg, src1, src2);
403 }
404 branch = newLIR1(cUnit, brOp, tReg);
buzbee0398c422012-03-02 15:22:47 -0800405 oatFreeTemp(cUnit, tReg);
buzbee5de34942012-03-01 14:51:57 -0800406 }
buzbee0398c422012-03-02 15:22:47 -0800407 branch->target = target;
buzbee82488f52012-03-02 08:20:26 -0800408 return branch;
buzbeee3acd072012-02-25 17:03:10 -0800409}
410
buzbee82488f52012-03-02 08:20:26 -0800411LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg,
412 int checkValue, LIR* target)
buzbeee3acd072012-02-25 17:03:10 -0800413{
buzbee82488f52012-03-02 08:20:26 -0800414 LIR* branch;
buzbee5de34942012-03-01 14:51:57 -0800415 if (checkValue != 0) {
416 // TUNING: handle s16 & kCondLt/Mi case using slti
417 int tReg = oatAllocTemp(cUnit);
418 loadConstant(cUnit, tReg, checkValue);
buzbee82488f52012-03-02 08:20:26 -0800419 branch = opCmpBranch(cUnit, cond, reg, tReg, target);
420 oatFreeTemp(cUnit, tReg);
421 return branch;
buzbee5de34942012-03-01 14:51:57 -0800422 }
423 MipsOpCode opc;
424 switch(cond) {
425 case kCondEq: opc = kMipsBeqz; break;
426 case kCondGe: opc = kMipsBgez; break;
427 case kCondGt: opc = kMipsBgtz; break;
428 case kCondLe: opc = kMipsBlez; break;
429 //case KCondMi:
430 case kCondLt: opc = kMipsBltz; break;
431 case kCondNe: opc = kMipsBnez; break;
432 default:
buzbee82488f52012-03-02 08:20:26 -0800433 // Tuning: use slti when applicable
buzbeee3acd072012-02-25 17:03:10 -0800434 int tReg = oatAllocTemp(cUnit);
buzbee5de34942012-03-01 14:51:57 -0800435 loadConstant(cUnit, tReg, checkValue);
buzbee82488f52012-03-02 08:20:26 -0800436 branch = opCmpBranch(cUnit, cond, reg, tReg, target);
437 oatFreeTemp(cUnit, tReg);
438 return branch;
buzbeee3acd072012-02-25 17:03:10 -0800439 }
buzbee82488f52012-03-02 08:20:26 -0800440 branch = newLIR1(cUnit, opc, reg);
441 branch->target = target;
442 return branch;
buzbeee3acd072012-02-25 17:03:10 -0800443}
444
buzbee82488f52012-03-02 08:20:26 -0800445LIR* opRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
buzbeee3acd072012-02-25 17:03:10 -0800446{
buzbeee3acd072012-02-25 17:03:10 -0800447#ifdef __mips_hard_float
buzbee5de34942012-03-01 14:51:57 -0800448 if (FPREG(rDest) || FPREG(rSrc))
449 return fpRegCopy(cUnit, rDest, rSrc);
450#endif
buzbeea2ebdd72012-03-04 14:57:06 -0800451 LIR* res = rawLIR(cUnit, cUnit->currentDalvikOffset, kMipsMove,
452 rDest, rSrc);
buzbee5de34942012-03-01 14:51:57 -0800453 if (rDest == rSrc) {
454 res->flags.isNop = true;
455 }
456 return res;
457}
458
buzbee82488f52012-03-02 08:20:26 -0800459LIR* opRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
buzbee5de34942012-03-01 14:51:57 -0800460{
buzbee82488f52012-03-02 08:20:26 -0800461 LIR *res = opRegCopyNoInsert(cUnit, rDest, rSrc);
buzbee5de34942012-03-01 14:51:57 -0800462 oatAppendLIR(cUnit, (LIR*)res);
463 return res;
464}
465
buzbee82488f52012-03-02 08:20:26 -0800466void opRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
buzbee5de34942012-03-01 14:51:57 -0800467 int srcLo, int srcHi)
468{
469#ifdef __mips_hard_float
470 bool destFP = FPREG(destLo) && FPREG(destHi);
471 bool srcFP = FPREG(srcLo) && FPREG(srcHi);
472 assert(FPREG(srcLo) == FPREG(srcHi));
473 assert(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));
buzbee5de34942012-03-01 14:51:57 -0800477 } else {
478 /* note the operands are swapped for the mtc1 instr */
479 newLIR2(cUnit, kMipsMtc1, srcLo, destLo);
480 newLIR2(cUnit, kMipsMtc1, srcHi, destHi);
481 }
482 } else {
483 if (srcFP) {
484 newLIR2(cUnit, kMipsMfc1, destLo, srcLo);
485 newLIR2(cUnit, kMipsMfc1, destHi, srcHi);
486 } else {
487 // Handle overlap
488 if (srcHi == destLo) {
buzbee82488f52012-03-02 08:20:26 -0800489 opRegCopy(cUnit, destHi, srcHi);
490 opRegCopy(cUnit, destLo, srcLo);
buzbee5de34942012-03-01 14:51:57 -0800491 } else {
buzbee82488f52012-03-02 08:20:26 -0800492 opRegCopy(cUnit, destLo, srcLo);
493 opRegCopy(cUnit, destHi, srcHi);
buzbee5de34942012-03-01 14:51:57 -0800494 }
495 }
496 }
buzbeee3acd072012-02-25 17:03:10 -0800497#else
buzbee5de34942012-03-01 14:51:57 -0800498 // Handle overlap
499 if (srcHi == destLo) {
buzbee82488f52012-03-02 08:20:26 -0800500 opRegCopy(cUnit, destHi, srcHi);
501 opRegCopy(cUnit, destLo, srcLo);
buzbee5de34942012-03-01 14:51:57 -0800502 } else {
buzbee82488f52012-03-02 08:20:26 -0800503 opRegCopy(cUnit, destLo, srcLo);
504 opRegCopy(cUnit, destHi, srcHi);
buzbee5de34942012-03-01 14:51:57 -0800505 }
buzbeee3acd072012-02-25 17:03:10 -0800506#endif
buzbeee3acd072012-02-25 17:03:10 -0800507}
508
509} // namespace art