blob: bf65ba64d1734aacb9eb4fd81fe01690baa296d9 [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
buzbee16da88c2012-03-20 10:38:17 -070027void genSpecialCase(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
28 SpecialCaseHandler specialCase)
29{
30 // TODO
31}
32
buzbeee3acd072012-02-25 17:03:10 -080033/*
buzbeec5159d52012-03-03 11:48:39 -080034 * The lack of pc-relative loads on Mips presents somewhat of a challenge
35 * for our PIC switch table strategy. To materialize the current location
36 * we'll do a dummy JAL and reference our tables using r_RA as the
37 * base register. Note that r_RA will be used both as the base to
38 * locate the switch table data and as the reference base for the switch
39 * target offsets stored in the table. We'll use a special pseudo-instruction
40 * to represent the jal and trigger the construction of the
41 * switch table offsets (which will happen after final assembly and all
42 * labels are fixed).
buzbeee3acd072012-02-25 17:03:10 -080043 *
44 * The test loop will look something like:
45 *
buzbeec5159d52012-03-03 11:48:39 -080046 * ori rEnd, r_ZERO, #tableSize ; size in bytes
47 * jal BaseLabel ; stores "return address" (BaseLabel) in r_RA
48 * nop ; opportunistically fill
49 * BaseLabel:
50 * addiu rBase, r_RA, <table> - <BaseLabel> ; table relative to BaseLabel
51 addu rEnd, rEnd, rBase ; end of table
52 * lw rVal, [rSP, vRegOff] ; Test Value
53 * loop:
54 * beq rBase, rEnd, done
55 * lw rKey, 0(rBase)
56 * addu rBase, 8
57 * bne rVal, rKey, loop
58 * lw rDisp, -4(rBase)
59 * addu r_RA, rDisp
60 * jr r_RA
61 * done:
62 *
buzbeee3acd072012-02-25 17:03:10 -080063 */
buzbee5de34942012-03-01 14:51:57 -080064void genSparseSwitch(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbeee3acd072012-02-25 17:03:10 -080065{
buzbeee3acd072012-02-25 17:03:10 -080066 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
67 if (cUnit->printMe) {
68 dumpSparseSwitchTable(table);
69 }
70 // Add the table to the list - we'll process it later
71 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
72 true, kAllocData);
73 tabRec->table = table;
74 tabRec->vaddr = mir->offset;
buzbeec5159d52012-03-03 11:48:39 -080075 int elements = table[1];
76 tabRec->targets = (LIR* *)oatNew(cUnit, elements * sizeof(LIR*), true,
buzbee5de34942012-03-01 14:51:57 -080077 kAllocLIR);
buzbeee3acd072012-02-25 17:03:10 -080078 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
79
buzbeec5159d52012-03-03 11:48:39 -080080 // The table is composed of 8-byte key/disp pairs
81 int byteSize = elements * 8;
82
83 int sizeHi = byteSize >> 16;
84 int sizeLo = byteSize & 0xffff;
85
86 int rEnd = oatAllocTemp(cUnit);
87 if (sizeHi) {
88 newLIR2(cUnit, kMipsLui, rEnd, sizeHi);
buzbeee3acd072012-02-25 17:03:10 -080089 }
buzbeec5159d52012-03-03 11:48:39 -080090 // Must prevent code motion for the curr pc pair
91 genBarrier(cUnit); // Scheduling barrier
92 newLIR0(cUnit, kMipsCurrPC); // Really a jal to .+8
93 // Now, fill the branch delay slot
94 if (sizeHi) {
95 newLIR3(cUnit, kMipsOri, rEnd, rEnd, sizeLo);
96 } else {
97 newLIR3(cUnit, kMipsOri, rEnd, r_ZERO, sizeLo);
98 }
99 genBarrier(cUnit); // Scheduling barrier
100
101 // Construct BaseLabel and set up table base register
102 LIR* baseLabel = newLIR0(cUnit, kPseudoTargetLabel);
103 // Remember base label so offsets can be computed later
104 tabRec->anchor = baseLabel;
105 int rBase = oatAllocTemp(cUnit);
106 newLIR4(cUnit, kMipsDelta, rBase, 0, (intptr_t)baseLabel, (intptr_t)tabRec);
107 opRegRegReg(cUnit, kOpAdd, rEnd, rEnd, rBase);
108
109 // Grab switch test value
110 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
111
112 // Test loop
113 int rKey = oatAllocTemp(cUnit);
114 LIR* loopLabel = newLIR0(cUnit, kPseudoTargetLabel);
115 LIR* exitBranch = opCmpBranch(cUnit , kCondEq, rBase, rEnd, NULL);
116 loadWordDisp(cUnit, rBase, 0, rKey);
117 opRegImm(cUnit, kOpAdd, rBase, 8);
118 opCmpBranch(cUnit, kCondNe, rlSrc.lowReg, rKey, loopLabel);
119 int rDisp = oatAllocTemp(cUnit);
120 loadWordDisp(cUnit, rBase, -4, rDisp);
121 opRegRegReg(cUnit, kOpAdd, r_RA, r_RA, rDisp);
122 opReg(cUnit, kOpBx, r_RA);
123
124 // Loop exit
125 LIR* exitLabel = newLIR0(cUnit, kPseudoTargetLabel);
126 exitBranch->target = exitLabel;
buzbeee3acd072012-02-25 17:03:10 -0800127}
128
buzbeec5159d52012-03-03 11:48:39 -0800129/*
130 * Code pattern will look something like:
131 *
132 * lw rVal
133 * jal BaseLabel ; stores "return address" (BaseLabel) in r_RA
134 * nop ; opportunistically fill
135 * [subiu rVal, bias] ; Remove bias if lowVal != 0
136 * bound check -> done
137 * lw rDisp, [r_RA, rVal]
138 * addu r_RA, rDisp
139 * jr r_RA
140 * done:
141 */
buzbee5de34942012-03-01 14:51:57 -0800142void genPackedSwitch(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbeee3acd072012-02-25 17:03:10 -0800143{
buzbeee3acd072012-02-25 17:03:10 -0800144 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
145 if (cUnit->printMe) {
146 dumpPackedSwitchTable(table);
147 }
148 // Add the table to the list - we'll process it later
149 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
150 true, kAllocData);
151 tabRec->table = table;
152 tabRec->vaddr = mir->offset;
153 int size = table[1];
buzbee5de34942012-03-01 14:51:57 -0800154 tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true,
buzbeee3acd072012-02-25 17:03:10 -0800155 kAllocLIR);
156 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
157
158 // Get the switch value
159 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
buzbeec5159d52012-03-03 11:48:39 -0800160
161 // Prepare the bias. If too big, handle 1st stage here
buzbeee3acd072012-02-25 17:03:10 -0800162 int lowKey = s4FromSwitchData(&table[2]);
buzbeec5159d52012-03-03 11:48:39 -0800163 bool largeBias = false;
164 int rKey;
buzbeee3acd072012-02-25 17:03:10 -0800165 if (lowKey == 0) {
buzbeec5159d52012-03-03 11:48:39 -0800166 rKey = rlSrc.lowReg;
167 } else if ((lowKey & 0xffff) != lowKey) {
168 rKey = oatAllocTemp(cUnit);
169 loadConstant(cUnit, rKey, lowKey);
170 largeBias = true;
buzbeee3acd072012-02-25 17:03:10 -0800171 } else {
buzbeec5159d52012-03-03 11:48:39 -0800172 rKey = oatAllocTemp(cUnit);
buzbeee3acd072012-02-25 17:03:10 -0800173 }
buzbeec5159d52012-03-03 11:48:39 -0800174
175 // Must prevent code motion for the curr pc pair
176 genBarrier(cUnit);
177 newLIR0(cUnit, kMipsCurrPC); // Really a jal to .+8
178 // Now, fill the branch delay slot with bias strip
179 if (lowKey == 0) {
180 newLIR0(cUnit, kMipsNop);
181 } else {
182 if (largeBias) {
183 opRegRegReg(cUnit, kOpSub, rKey, rlSrc.lowReg, rKey);
184 } else {
185 opRegRegImm(cUnit, kOpSub, rKey, rlSrc.lowReg, lowKey);
186 }
187 }
188 genBarrier(cUnit); // Scheduling barrier
189
190 // Construct BaseLabel and set up table base register
191 LIR* baseLabel = newLIR0(cUnit, kPseudoTargetLabel);
192 // Remember base label so offsets can be computed later
193 tabRec->anchor = baseLabel;
194
buzbeee3acd072012-02-25 17:03:10 -0800195 // Bounds check - if < 0 or >= size continue following switch
buzbeec5159d52012-03-03 11:48:39 -0800196 LIR* branchOver = opCmpImmBranch(cUnit, kCondHi, rKey, size-1, NULL);
197
198 // Materialize the table base pointer
199 int rBase = oatAllocTemp(cUnit);
200 newLIR4(cUnit, kMipsDelta, rBase, 0, (intptr_t)baseLabel, (intptr_t)tabRec);
buzbeee3acd072012-02-25 17:03:10 -0800201
202 // Load the displacement from the switch table
buzbeec5159d52012-03-03 11:48:39 -0800203 int rDisp = oatAllocTemp(cUnit);
204 loadBaseIndexed(cUnit, rBase, rKey, rDisp, 2, kWord);
buzbeee3acd072012-02-25 17:03:10 -0800205
buzbeec5159d52012-03-03 11:48:39 -0800206 // Add to r_AP and go
207 opRegRegReg(cUnit, kOpAdd, r_RA, r_RA, rDisp);
208 opReg(cUnit, kOpBx, r_RA);
buzbeee3acd072012-02-25 17:03:10 -0800209
210 /* branchOver target here */
buzbee5de34942012-03-01 14:51:57 -0800211 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee5de34942012-03-01 14:51:57 -0800212 branchOver->target = (LIR*)target;
buzbeee3acd072012-02-25 17:03:10 -0800213}
214
215/*
216 * Array data table format:
217 * ushort ident = 0x0300 magic value
218 * ushort width width of each element in the table
219 * uint size number of elements in the table
220 * ubyte data[size*width] table of data values (may contain a single-byte
221 * padding at the end)
222 *
223 * Total size is 4+(width * size + 1)/2 16-bit code units.
224 */
buzbee5de34942012-03-01 14:51:57 -0800225void genFillArrayData(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbeee3acd072012-02-25 17:03:10 -0800226{
buzbeee3acd072012-02-25 17:03:10 -0800227 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
228 // Add the table to the list - we'll process it later
229 FillArrayData *tabRec = (FillArrayData *)
230 oatNew(cUnit, sizeof(FillArrayData), true, kAllocData);
231 tabRec->table = table;
232 tabRec->vaddr = mir->offset;
233 u2 width = tabRec->table[1];
234 u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
235 tabRec->size = (size * width) + 8;
236
237 oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec);
238
239 // Making a call - use explicit registers
240 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbeec5159d52012-03-03 11:48:39 -0800241 oatLockCallTemps(cUnit);
buzbee5de34942012-03-01 14:51:57 -0800242 loadValueDirectFixed(cUnit, rlSrc, rARG0);
buzbeec5159d52012-03-03 11:48:39 -0800243
244 // Must prevent code motion for the curr pc pair
245 genBarrier(cUnit);
246 newLIR0(cUnit, kMipsCurrPC); // Really a jal to .+8
247 // Now, fill the branch delay slot with the helper load
248 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
249 pHandleFillArrayDataFromCode));
250 genBarrier(cUnit); // Scheduling barrier
251
252 // Construct BaseLabel and set up table base register
253 LIR* baseLabel = newLIR0(cUnit, kPseudoTargetLabel);
254
buzbeee3acd072012-02-25 17:03:10 -0800255 // Materialize a pointer to the fill data image
buzbeec5159d52012-03-03 11:48:39 -0800256 newLIR4(cUnit, kMipsDelta, rARG1, 0, (intptr_t)baseLabel, (intptr_t)tabRec);
257
258 // And go...
Ian Rogersab2b55d2012-03-18 00:06:11 -0700259 oatClobberCalleeSave(cUnit);
260 opReg(cUnit, kOpBlx, rTgt); // ( array*, fill_data* )
buzbeee3acd072012-02-25 17:03:10 -0800261}
262
buzbee71ac9942012-03-01 17:23:10 -0800263void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
264{
265 RegLocation rlResult;
266 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
267 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
268 opRegRegImm(cUnit, kOpAdd, rlResult.lowReg,
269 rlSrc.lowReg, 0x80000000);
270 storeValue(cUnit, rlDest, rlResult);
271}
272
273void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
274{
275 RegLocation rlResult;
276 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
277 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
278 opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg,
279 0x80000000);
buzbee82488f52012-03-02 08:20:26 -0800280 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
buzbee71ac9942012-03-01 17:23:10 -0800281 storeValueWide(cUnit, rlDest, rlResult);
282}
283
buzbee5de34942012-03-01 14:51:57 -0800284/*
285 * TODO: implement fast path to short-circuit thin-lock case
286 */
287void genMonitorEnter(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbeee3acd072012-02-25 17:03:10 -0800288{
buzbee5de34942012-03-01 14:51:57 -0800289 oatFlushAllRegs(cUnit);
290 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get obj
291 oatLockCallTemps(cUnit); // Prepare for explicit register usage
292 genNullCheck(cUnit, rlSrc.sRegLow, rARG0, mir);
293 // Go expensive route - artLockObjectFromCode(self, obj);
294 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pLockObjectFromCode));
Ian Rogersab2b55d2012-03-18 00:06:11 -0700295 oatClobberCalleeSave(cUnit);
296 opReg(cUnit, kOpBlx, rTgt);
buzbeee3acd072012-02-25 17:03:10 -0800297}
298
299/*
buzbee5de34942012-03-01 14:51:57 -0800300 * TODO: implement fast path to short-circuit thin-lock case
buzbeee3acd072012-02-25 17:03:10 -0800301 */
buzbee5de34942012-03-01 14:51:57 -0800302void genMonitorExit(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbeee3acd072012-02-25 17:03:10 -0800303{
buzbee5de34942012-03-01 14:51:57 -0800304 oatFlushAllRegs(cUnit);
305 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get obj
306 oatLockCallTemps(cUnit); // Prepare for explicit register usage
307 genNullCheck(cUnit, rlSrc.sRegLow, rARG0, mir);
308 // Go expensive route - UnlockObjectFromCode(obj);
309 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pUnlockObjectFromCode));
Ian Rogersab2b55d2012-03-18 00:06:11 -0700310 oatClobberCalleeSave(cUnit);
311 opReg(cUnit, kOpBlx, rTgt);
buzbee5de34942012-03-01 14:51:57 -0800312}
313
314/*
315 * Compare two 64-bit values
316 * x = y return 0
317 * x < y return -1
318 * x > y return 1
319 *
320 * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
321 * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
322 * subu res, t0, t1 # res = -1:1:0 for [ < > = ]
323 * bnez res, finish
324 * sltu t0, x.lo, y.lo
325 * sgtu r1, x.lo, y.lo
326 * subu res, t0, t1
327 * finish:
328 *
329 */
330void genCmpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
331 RegLocation rlSrc1, RegLocation rlSrc2)
332{
333 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
334 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
335 int t0 = oatAllocTemp(cUnit);
336 int t1 = oatAllocTemp(cUnit);
337 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
338 newLIR3(cUnit, kMipsSlt, t0, rlSrc1.highReg, rlSrc2.highReg);
339 newLIR3(cUnit, kMipsSlt, t1, rlSrc2.highReg, rlSrc1.highReg);
340 newLIR3(cUnit, kMipsSubu, rlResult.lowReg, t1, t0);
buzbee82488f52012-03-02 08:20:26 -0800341 LIR* branch = opCmpImmBranch(cUnit, kCondNe, rlResult.lowReg, 0, NULL);
buzbee5de34942012-03-01 14:51:57 -0800342 newLIR3(cUnit, kMipsSltu, t0, rlSrc1.lowReg, rlSrc2.lowReg);
343 newLIR3(cUnit, kMipsSltu, t1, rlSrc2.lowReg, rlSrc1.lowReg);
344 newLIR3(cUnit, kMipsSubu, rlResult.lowReg, t1, t0);
345 oatFreeTemp(cUnit, t0);
346 oatFreeTemp(cUnit, t1);
347 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee5de34942012-03-01 14:51:57 -0800348 branch->target = (LIR*)target;
buzbeee3acd072012-02-25 17:03:10 -0800349 storeValue(cUnit, rlDest, rlResult);
350}
351
buzbee82488f52012-03-02 08:20:26 -0800352LIR* opCmpBranch(CompilationUnit* cUnit, ConditionCode cond, int src1,
353 int src2, LIR* target)
buzbeee3acd072012-02-25 17:03:10 -0800354{
buzbee0398c422012-03-02 15:22:47 -0800355 LIR* branch;
356 MipsOpCode sltOp;
357 MipsOpCode brOp;
358 bool cmpZero = false;
359 bool swapped = false;
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700360 switch (cond) {
buzbee0398c422012-03-02 15:22:47 -0800361 case kCondEq:
362 brOp = kMipsBeq;
363 cmpZero = true;
364 break;
365 case kCondNe:
366 brOp = kMipsBne;
367 cmpZero = true;
368 break;
369 case kCondCc:
370 sltOp = kMipsSltu;
371 brOp = kMipsBnez;
372 break;
373 case kCondCs:
374 sltOp = kMipsSltu;
375 brOp = kMipsBeqz;
376 break;
377 case kCondGe:
378 sltOp = kMipsSlt;
379 brOp = kMipsBeqz;
380 break;
381 case kCondGt:
382 sltOp = kMipsSlt;
383 brOp = kMipsBnez;
384 swapped = true;
385 break;
386 case kCondLe:
387 sltOp = kMipsSlt;
388 brOp = kMipsBeqz;
389 swapped = true;
390 break;
391 case kCondLt:
392 sltOp = kMipsSlt;
393 brOp = kMipsBnez;
394 break;
buzbeec5159d52012-03-03 11:48:39 -0800395 case kCondHi: // Gtu
396 sltOp = kMipsSltu;
397 brOp = kMipsBnez;
398 swapped = true;
399 break;
buzbee0398c422012-03-02 15:22:47 -0800400 default:
buzbeea2ebdd72012-03-04 14:57:06 -0800401 LOG(FATAL) << "No support for ConditionCode: " << (int) cond;
buzbee0398c422012-03-02 15:22:47 -0800402 return NULL;
403 }
404 if (cmpZero) {
405 branch = newLIR2(cUnit, brOp, src1, src2);
buzbee82488f52012-03-02 08:20:26 -0800406 } else {
buzbee82488f52012-03-02 08:20:26 -0800407 int tReg = oatAllocTemp(cUnit);
408 if (swapped) {
409 newLIR3(cUnit, sltOp, tReg, src2, src1);
410 } else {
411 newLIR3(cUnit, sltOp, tReg, src1, src2);
412 }
413 branch = newLIR1(cUnit, brOp, tReg);
buzbee0398c422012-03-02 15:22:47 -0800414 oatFreeTemp(cUnit, tReg);
buzbee5de34942012-03-01 14:51:57 -0800415 }
buzbee0398c422012-03-02 15:22:47 -0800416 branch->target = target;
buzbee82488f52012-03-02 08:20:26 -0800417 return branch;
buzbeee3acd072012-02-25 17:03:10 -0800418}
419
buzbee82488f52012-03-02 08:20:26 -0800420LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg,
421 int checkValue, LIR* target)
buzbeee3acd072012-02-25 17:03:10 -0800422{
buzbee82488f52012-03-02 08:20:26 -0800423 LIR* branch;
buzbee5de34942012-03-01 14:51:57 -0800424 if (checkValue != 0) {
425 // TUNING: handle s16 & kCondLt/Mi case using slti
426 int tReg = oatAllocTemp(cUnit);
427 loadConstant(cUnit, tReg, checkValue);
buzbee82488f52012-03-02 08:20:26 -0800428 branch = opCmpBranch(cUnit, cond, reg, tReg, target);
429 oatFreeTemp(cUnit, tReg);
430 return branch;
buzbee5de34942012-03-01 14:51:57 -0800431 }
432 MipsOpCode opc;
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700433 switch (cond) {
buzbee5de34942012-03-01 14:51:57 -0800434 case kCondEq: opc = kMipsBeqz; break;
435 case kCondGe: opc = kMipsBgez; break;
436 case kCondGt: opc = kMipsBgtz; break;
437 case kCondLe: opc = kMipsBlez; break;
438 //case KCondMi:
439 case kCondLt: opc = kMipsBltz; break;
440 case kCondNe: opc = kMipsBnez; break;
441 default:
buzbee82488f52012-03-02 08:20:26 -0800442 // Tuning: use slti when applicable
buzbeee3acd072012-02-25 17:03:10 -0800443 int tReg = oatAllocTemp(cUnit);
buzbee5de34942012-03-01 14:51:57 -0800444 loadConstant(cUnit, tReg, checkValue);
buzbee82488f52012-03-02 08:20:26 -0800445 branch = opCmpBranch(cUnit, cond, reg, tReg, target);
446 oatFreeTemp(cUnit, tReg);
447 return branch;
buzbeee3acd072012-02-25 17:03:10 -0800448 }
buzbee82488f52012-03-02 08:20:26 -0800449 branch = newLIR1(cUnit, opc, reg);
450 branch->target = target;
451 return branch;
buzbeee3acd072012-02-25 17:03:10 -0800452}
453
buzbee82488f52012-03-02 08:20:26 -0800454LIR* opRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
buzbeee3acd072012-02-25 17:03:10 -0800455{
buzbeee3acd072012-02-25 17:03:10 -0800456#ifdef __mips_hard_float
buzbee5de34942012-03-01 14:51:57 -0800457 if (FPREG(rDest) || FPREG(rSrc))
458 return fpRegCopy(cUnit, rDest, rSrc);
459#endif
buzbeea2ebdd72012-03-04 14:57:06 -0800460 LIR* res = rawLIR(cUnit, cUnit->currentDalvikOffset, kMipsMove,
461 rDest, rSrc);
buzbee239c4e72012-03-16 08:42:29 -0700462 if (!(cUnit->disableOpt & (1 << kSafeOptimizations)) && rDest == rSrc) {
buzbee5de34942012-03-01 14:51:57 -0800463 res->flags.isNop = true;
464 }
465 return res;
466}
467
buzbee82488f52012-03-02 08:20:26 -0800468LIR* opRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
buzbee5de34942012-03-01 14:51:57 -0800469{
buzbee82488f52012-03-02 08:20:26 -0800470 LIR *res = opRegCopyNoInsert(cUnit, rDest, rSrc);
buzbee5de34942012-03-01 14:51:57 -0800471 oatAppendLIR(cUnit, (LIR*)res);
472 return res;
473}
474
buzbee82488f52012-03-02 08:20:26 -0800475void opRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
buzbee5de34942012-03-01 14:51:57 -0800476 int srcLo, int srcHi)
477{
478#ifdef __mips_hard_float
479 bool destFP = FPREG(destLo) && FPREG(destHi);
480 bool srcFP = FPREG(srcLo) && FPREG(srcHi);
481 assert(FPREG(srcLo) == FPREG(srcHi));
482 assert(FPREG(destLo) == FPREG(destHi));
483 if (destFP) {
484 if (srcFP) {
buzbee82488f52012-03-02 08:20:26 -0800485 opRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
buzbee5de34942012-03-01 14:51:57 -0800486 } else {
487 /* note the operands are swapped for the mtc1 instr */
488 newLIR2(cUnit, kMipsMtc1, srcLo, destLo);
489 newLIR2(cUnit, kMipsMtc1, srcHi, destHi);
490 }
491 } else {
492 if (srcFP) {
493 newLIR2(cUnit, kMipsMfc1, destLo, srcLo);
494 newLIR2(cUnit, kMipsMfc1, destHi, srcHi);
495 } else {
496 // Handle overlap
497 if (srcHi == destLo) {
buzbee82488f52012-03-02 08:20:26 -0800498 opRegCopy(cUnit, destHi, srcHi);
499 opRegCopy(cUnit, destLo, srcLo);
buzbee5de34942012-03-01 14:51:57 -0800500 } else {
buzbee82488f52012-03-02 08:20:26 -0800501 opRegCopy(cUnit, destLo, srcLo);
502 opRegCopy(cUnit, destHi, srcHi);
buzbee5de34942012-03-01 14:51:57 -0800503 }
504 }
505 }
buzbeee3acd072012-02-25 17:03:10 -0800506#else
buzbee5de34942012-03-01 14:51:57 -0800507 // Handle overlap
508 if (srcHi == destLo) {
buzbee82488f52012-03-02 08:20:26 -0800509 opRegCopy(cUnit, destHi, srcHi);
510 opRegCopy(cUnit, destLo, srcLo);
buzbee5de34942012-03-01 14:51:57 -0800511 } else {
buzbee82488f52012-03-02 08:20:26 -0800512 opRegCopy(cUnit, destLo, srcLo);
513 opRegCopy(cUnit, destHi, srcHi);
buzbee5de34942012-03-01 14:51:57 -0800514 }
buzbeee3acd072012-02-25 17:03:10 -0800515#endif
buzbeee3acd072012-02-25 17:03:10 -0800516}
517
518} // namespace art