blob: 5b89e6aa8fe81862352935eb6a1ec002d68d5add [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...
Ian Rogersab2b55d2012-03-18 00:06:11 -0700253 oatClobberCalleeSave(cUnit);
254 opReg(cUnit, kOpBlx, rTgt); // ( array*, fill_data* )
buzbeee3acd072012-02-25 17:03:10 -0800255}
256
buzbee71ac9942012-03-01 17:23:10 -0800257void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
258{
259 RegLocation rlResult;
260 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
261 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
262 opRegRegImm(cUnit, kOpAdd, rlResult.lowReg,
263 rlSrc.lowReg, 0x80000000);
264 storeValue(cUnit, rlDest, rlResult);
265}
266
267void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
268{
269 RegLocation rlResult;
270 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
271 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
272 opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg,
273 0x80000000);
buzbee82488f52012-03-02 08:20:26 -0800274 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
buzbee71ac9942012-03-01 17:23:10 -0800275 storeValueWide(cUnit, rlDest, rlResult);
276}
277
buzbee5de34942012-03-01 14:51:57 -0800278/*
279 * TODO: implement fast path to short-circuit thin-lock case
280 */
281void genMonitorEnter(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbeee3acd072012-02-25 17:03:10 -0800282{
buzbee5de34942012-03-01 14:51:57 -0800283 oatFlushAllRegs(cUnit);
284 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get obj
285 oatLockCallTemps(cUnit); // Prepare for explicit register usage
286 genNullCheck(cUnit, rlSrc.sRegLow, rARG0, mir);
287 // Go expensive route - artLockObjectFromCode(self, obj);
288 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pLockObjectFromCode));
Ian Rogersab2b55d2012-03-18 00:06:11 -0700289 oatClobberCalleeSave(cUnit);
290 opReg(cUnit, kOpBlx, rTgt);
buzbeee3acd072012-02-25 17:03:10 -0800291}
292
293/*
buzbee5de34942012-03-01 14:51:57 -0800294 * TODO: implement fast path to short-circuit thin-lock case
buzbeee3acd072012-02-25 17:03:10 -0800295 */
buzbee5de34942012-03-01 14:51:57 -0800296void genMonitorExit(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbeee3acd072012-02-25 17:03:10 -0800297{
buzbee5de34942012-03-01 14:51:57 -0800298 oatFlushAllRegs(cUnit);
299 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get obj
300 oatLockCallTemps(cUnit); // Prepare for explicit register usage
301 genNullCheck(cUnit, rlSrc.sRegLow, rARG0, mir);
302 // Go expensive route - UnlockObjectFromCode(obj);
303 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pUnlockObjectFromCode));
Ian Rogersab2b55d2012-03-18 00:06:11 -0700304 oatClobberCalleeSave(cUnit);
305 opReg(cUnit, kOpBlx, rTgt);
buzbee5de34942012-03-01 14:51:57 -0800306}
307
308/*
309 * Compare two 64-bit values
310 * x = y return 0
311 * x < y return -1
312 * x > y return 1
313 *
314 * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
315 * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
316 * subu res, t0, t1 # res = -1:1:0 for [ < > = ]
317 * bnez res, finish
318 * sltu t0, x.lo, y.lo
319 * sgtu r1, x.lo, y.lo
320 * subu res, t0, t1
321 * finish:
322 *
323 */
324void genCmpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
325 RegLocation rlSrc1, RegLocation rlSrc2)
326{
327 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
328 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
329 int t0 = oatAllocTemp(cUnit);
330 int t1 = oatAllocTemp(cUnit);
331 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
332 newLIR3(cUnit, kMipsSlt, t0, rlSrc1.highReg, rlSrc2.highReg);
333 newLIR3(cUnit, kMipsSlt, t1, rlSrc2.highReg, rlSrc1.highReg);
334 newLIR3(cUnit, kMipsSubu, rlResult.lowReg, t1, t0);
buzbee82488f52012-03-02 08:20:26 -0800335 LIR* branch = opCmpImmBranch(cUnit, kCondNe, rlResult.lowReg, 0, NULL);
buzbee5de34942012-03-01 14:51:57 -0800336 newLIR3(cUnit, kMipsSltu, t0, rlSrc1.lowReg, rlSrc2.lowReg);
337 newLIR3(cUnit, kMipsSltu, t1, rlSrc2.lowReg, rlSrc1.lowReg);
338 newLIR3(cUnit, kMipsSubu, rlResult.lowReg, t1, t0);
339 oatFreeTemp(cUnit, t0);
340 oatFreeTemp(cUnit, t1);
341 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee5de34942012-03-01 14:51:57 -0800342 branch->target = (LIR*)target;
buzbeee3acd072012-02-25 17:03:10 -0800343 storeValue(cUnit, rlDest, rlResult);
344}
345
buzbee82488f52012-03-02 08:20:26 -0800346LIR* opCmpBranch(CompilationUnit* cUnit, ConditionCode cond, int src1,
347 int src2, LIR* target)
buzbeee3acd072012-02-25 17:03:10 -0800348{
buzbee0398c422012-03-02 15:22:47 -0800349 LIR* branch;
350 MipsOpCode sltOp;
351 MipsOpCode brOp;
352 bool cmpZero = false;
353 bool swapped = false;
354 switch(cond) {
355 case kCondEq:
356 brOp = kMipsBeq;
357 cmpZero = true;
358 break;
359 case kCondNe:
360 brOp = kMipsBne;
361 cmpZero = true;
362 break;
363 case kCondCc:
364 sltOp = kMipsSltu;
365 brOp = kMipsBnez;
366 break;
367 case kCondCs:
368 sltOp = kMipsSltu;
369 brOp = kMipsBeqz;
370 break;
371 case kCondGe:
372 sltOp = kMipsSlt;
373 brOp = kMipsBeqz;
374 break;
375 case kCondGt:
376 sltOp = kMipsSlt;
377 brOp = kMipsBnez;
378 swapped = true;
379 break;
380 case kCondLe:
381 sltOp = kMipsSlt;
382 brOp = kMipsBeqz;
383 swapped = true;
384 break;
385 case kCondLt:
386 sltOp = kMipsSlt;
387 brOp = kMipsBnez;
388 break;
buzbeec5159d52012-03-03 11:48:39 -0800389 case kCondHi: // Gtu
390 sltOp = kMipsSltu;
391 brOp = kMipsBnez;
392 swapped = true;
393 break;
buzbee0398c422012-03-02 15:22:47 -0800394 default:
buzbeea2ebdd72012-03-04 14:57:06 -0800395 LOG(FATAL) << "No support for ConditionCode: " << (int) cond;
buzbee0398c422012-03-02 15:22:47 -0800396 return NULL;
397 }
398 if (cmpZero) {
399 branch = newLIR2(cUnit, brOp, src1, src2);
buzbee82488f52012-03-02 08:20:26 -0800400 } else {
buzbee82488f52012-03-02 08:20:26 -0800401 int tReg = oatAllocTemp(cUnit);
402 if (swapped) {
403 newLIR3(cUnit, sltOp, tReg, src2, src1);
404 } else {
405 newLIR3(cUnit, sltOp, tReg, src1, src2);
406 }
407 branch = newLIR1(cUnit, brOp, tReg);
buzbee0398c422012-03-02 15:22:47 -0800408 oatFreeTemp(cUnit, tReg);
buzbee5de34942012-03-01 14:51:57 -0800409 }
buzbee0398c422012-03-02 15:22:47 -0800410 branch->target = target;
buzbee82488f52012-03-02 08:20:26 -0800411 return branch;
buzbeee3acd072012-02-25 17:03:10 -0800412}
413
buzbee82488f52012-03-02 08:20:26 -0800414LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg,
415 int checkValue, LIR* target)
buzbeee3acd072012-02-25 17:03:10 -0800416{
buzbee82488f52012-03-02 08:20:26 -0800417 LIR* branch;
buzbee5de34942012-03-01 14:51:57 -0800418 if (checkValue != 0) {
419 // TUNING: handle s16 & kCondLt/Mi case using slti
420 int tReg = oatAllocTemp(cUnit);
421 loadConstant(cUnit, tReg, checkValue);
buzbee82488f52012-03-02 08:20:26 -0800422 branch = opCmpBranch(cUnit, cond, reg, tReg, target);
423 oatFreeTemp(cUnit, tReg);
424 return branch;
buzbee5de34942012-03-01 14:51:57 -0800425 }
426 MipsOpCode opc;
427 switch(cond) {
428 case kCondEq: opc = kMipsBeqz; break;
429 case kCondGe: opc = kMipsBgez; break;
430 case kCondGt: opc = kMipsBgtz; break;
431 case kCondLe: opc = kMipsBlez; break;
432 //case KCondMi:
433 case kCondLt: opc = kMipsBltz; break;
434 case kCondNe: opc = kMipsBnez; break;
435 default:
buzbee82488f52012-03-02 08:20:26 -0800436 // Tuning: use slti when applicable
buzbeee3acd072012-02-25 17:03:10 -0800437 int tReg = oatAllocTemp(cUnit);
buzbee5de34942012-03-01 14:51:57 -0800438 loadConstant(cUnit, tReg, checkValue);
buzbee82488f52012-03-02 08:20:26 -0800439 branch = opCmpBranch(cUnit, cond, reg, tReg, target);
440 oatFreeTemp(cUnit, tReg);
441 return branch;
buzbeee3acd072012-02-25 17:03:10 -0800442 }
buzbee82488f52012-03-02 08:20:26 -0800443 branch = newLIR1(cUnit, opc, reg);
444 branch->target = target;
445 return branch;
buzbeee3acd072012-02-25 17:03:10 -0800446}
447
buzbee82488f52012-03-02 08:20:26 -0800448LIR* opRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
buzbeee3acd072012-02-25 17:03:10 -0800449{
buzbeee3acd072012-02-25 17:03:10 -0800450#ifdef __mips_hard_float
buzbee5de34942012-03-01 14:51:57 -0800451 if (FPREG(rDest) || FPREG(rSrc))
452 return fpRegCopy(cUnit, rDest, rSrc);
453#endif
buzbeea2ebdd72012-03-04 14:57:06 -0800454 LIR* res = rawLIR(cUnit, cUnit->currentDalvikOffset, kMipsMove,
455 rDest, rSrc);
buzbee239c4e72012-03-16 08:42:29 -0700456 if (!(cUnit->disableOpt & (1 << kSafeOptimizations)) && rDest == rSrc) {
buzbee5de34942012-03-01 14:51:57 -0800457 res->flags.isNop = true;
458 }
459 return res;
460}
461
buzbee82488f52012-03-02 08:20:26 -0800462LIR* opRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
buzbee5de34942012-03-01 14:51:57 -0800463{
buzbee82488f52012-03-02 08:20:26 -0800464 LIR *res = opRegCopyNoInsert(cUnit, rDest, rSrc);
buzbee5de34942012-03-01 14:51:57 -0800465 oatAppendLIR(cUnit, (LIR*)res);
466 return res;
467}
468
buzbee82488f52012-03-02 08:20:26 -0800469void opRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
buzbee5de34942012-03-01 14:51:57 -0800470 int srcLo, int srcHi)
471{
472#ifdef __mips_hard_float
473 bool destFP = FPREG(destLo) && FPREG(destHi);
474 bool srcFP = FPREG(srcLo) && FPREG(srcHi);
475 assert(FPREG(srcLo) == FPREG(srcHi));
476 assert(FPREG(destLo) == FPREG(destHi));
477 if (destFP) {
478 if (srcFP) {
buzbee82488f52012-03-02 08:20:26 -0800479 opRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
buzbee5de34942012-03-01 14:51:57 -0800480 } else {
481 /* note the operands are swapped for the mtc1 instr */
482 newLIR2(cUnit, kMipsMtc1, srcLo, destLo);
483 newLIR2(cUnit, kMipsMtc1, srcHi, destHi);
484 }
485 } else {
486 if (srcFP) {
487 newLIR2(cUnit, kMipsMfc1, destLo, srcLo);
488 newLIR2(cUnit, kMipsMfc1, destHi, srcHi);
489 } else {
490 // Handle overlap
491 if (srcHi == destLo) {
buzbee82488f52012-03-02 08:20:26 -0800492 opRegCopy(cUnit, destHi, srcHi);
493 opRegCopy(cUnit, destLo, srcLo);
buzbee5de34942012-03-01 14:51:57 -0800494 } else {
buzbee82488f52012-03-02 08:20:26 -0800495 opRegCopy(cUnit, destLo, srcLo);
496 opRegCopy(cUnit, destHi, srcHi);
buzbee5de34942012-03-01 14:51:57 -0800497 }
498 }
499 }
buzbeee3acd072012-02-25 17:03:10 -0800500#else
buzbee5de34942012-03-01 14:51:57 -0800501 // Handle overlap
502 if (srcHi == destLo) {
buzbee82488f52012-03-02 08:20:26 -0800503 opRegCopy(cUnit, destHi, srcHi);
504 opRegCopy(cUnit, destLo, srcLo);
buzbee5de34942012-03-01 14:51:57 -0800505 } else {
buzbee82488f52012-03-02 08:20:26 -0800506 opRegCopy(cUnit, destLo, srcLo);
507 opRegCopy(cUnit, destHi, srcHi);
buzbee5de34942012-03-01 14:51:57 -0800508 }
buzbeee3acd072012-02-25 17:03:10 -0800509#endif
buzbeee3acd072012-02-25 17:03:10 -0800510}
511
512} // namespace art