blob: b0cad0f750d9e32d6ba4e6a8b6fcf28b4130e09e [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
Ian Rogers57b86d42012-03-27 16:05:41 -070025#include "oat/runtime/oat_support_entrypoints.h"
26
buzbeee3acd072012-02-25 17:03:10 -080027namespace art {
28
buzbee16da88c2012-03-20 10:38:17 -070029void genSpecialCase(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
30 SpecialCaseHandler specialCase)
31{
32 // TODO
33}
34
buzbeee3acd072012-02-25 17:03:10 -080035/*
buzbeec5159d52012-03-03 11:48:39 -080036 * The lack of pc-relative loads on Mips presents somewhat of a challenge
37 * for our PIC switch table strategy. To materialize the current location
38 * we'll do a dummy JAL and reference our tables using r_RA as the
39 * base register. Note that r_RA will be used both as the base to
40 * locate the switch table data and as the reference base for the switch
41 * target offsets stored in the table. We'll use a special pseudo-instruction
42 * to represent the jal and trigger the construction of the
43 * switch table offsets (which will happen after final assembly and all
44 * labels are fixed).
buzbeee3acd072012-02-25 17:03:10 -080045 *
46 * The test loop will look something like:
47 *
buzbeec5159d52012-03-03 11:48:39 -080048 * ori rEnd, r_ZERO, #tableSize ; size in bytes
49 * jal BaseLabel ; stores "return address" (BaseLabel) in r_RA
50 * nop ; opportunistically fill
51 * BaseLabel:
52 * addiu rBase, r_RA, <table> - <BaseLabel> ; table relative to BaseLabel
53 addu rEnd, rEnd, rBase ; end of table
54 * lw rVal, [rSP, vRegOff] ; Test Value
55 * loop:
56 * beq rBase, rEnd, done
57 * lw rKey, 0(rBase)
58 * addu rBase, 8
59 * bne rVal, rKey, loop
60 * lw rDisp, -4(rBase)
61 * addu r_RA, rDisp
62 * jr r_RA
63 * done:
64 *
buzbeee3acd072012-02-25 17:03:10 -080065 */
buzbee408ad162012-06-06 16:45:18 -070066void genSparseSwitch(CompilationUnit* cUnit, uint32_t tableOffset,
buzbeea1da8a52012-07-09 14:00:21 -070067 RegLocation rlSrc)
buzbeee3acd072012-02-25 17:03:10 -080068{
buzbee408ad162012-06-06 16:45:18 -070069 const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -070070 if (cUnit->printMe) {
71 dumpSparseSwitchTable(table);
72 }
73 // Add the table to the list - we'll process it later
74 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
75 true, kAllocData);
76 tabRec->table = table;
buzbee408ad162012-06-06 16:45:18 -070077 tabRec->vaddr = cUnit->currentDalvikOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -070078 int elements = table[1];
79 tabRec->targets = (LIR* *)oatNew(cUnit, elements * sizeof(LIR*), true,
80 kAllocLIR);
81 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
buzbeee3acd072012-02-25 17:03:10 -080082
Bill Buzbeea114add2012-05-03 15:00:40 -070083 // The table is composed of 8-byte key/disp pairs
84 int byteSize = elements * 8;
buzbeec5159d52012-03-03 11:48:39 -080085
Bill Buzbeea114add2012-05-03 15:00:40 -070086 int sizeHi = byteSize >> 16;
87 int sizeLo = byteSize & 0xffff;
buzbeec5159d52012-03-03 11:48:39 -080088
Bill Buzbeea114add2012-05-03 15:00:40 -070089 int rEnd = oatAllocTemp(cUnit);
90 if (sizeHi) {
91 newLIR2(cUnit, kMipsLui, rEnd, sizeHi);
92 }
93 // Must prevent code motion for the curr pc pair
94 genBarrier(cUnit); // Scheduling barrier
95 newLIR0(cUnit, kMipsCurrPC); // Really a jal to .+8
96 // Now, fill the branch delay slot
97 if (sizeHi) {
98 newLIR3(cUnit, kMipsOri, rEnd, rEnd, sizeLo);
99 } else {
100 newLIR3(cUnit, kMipsOri, rEnd, r_ZERO, sizeLo);
101 }
102 genBarrier(cUnit); // Scheduling barrier
buzbeec5159d52012-03-03 11:48:39 -0800103
Bill Buzbeea114add2012-05-03 15:00:40 -0700104 // Construct BaseLabel and set up table base register
105 LIR* baseLabel = newLIR0(cUnit, kPseudoTargetLabel);
106 // Remember base label so offsets can be computed later
107 tabRec->anchor = baseLabel;
108 int rBase = oatAllocTemp(cUnit);
109 newLIR4(cUnit, kMipsDelta, rBase, 0, (intptr_t)baseLabel, (intptr_t)tabRec);
110 opRegRegReg(cUnit, kOpAdd, rEnd, rEnd, rBase);
buzbeec5159d52012-03-03 11:48:39 -0800111
Bill Buzbeea114add2012-05-03 15:00:40 -0700112 // Grab switch test value
113 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
buzbeec5159d52012-03-03 11:48:39 -0800114
Bill Buzbeea114add2012-05-03 15:00:40 -0700115 // Test loop
116 int rKey = oatAllocTemp(cUnit);
117 LIR* loopLabel = newLIR0(cUnit, kPseudoTargetLabel);
118 LIR* exitBranch = opCmpBranch(cUnit , kCondEq, rBase, rEnd, NULL);
119 loadWordDisp(cUnit, rBase, 0, rKey);
120 opRegImm(cUnit, kOpAdd, rBase, 8);
121 opCmpBranch(cUnit, kCondNe, rlSrc.lowReg, rKey, loopLabel);
122 int rDisp = oatAllocTemp(cUnit);
123 loadWordDisp(cUnit, rBase, -4, rDisp);
124 opRegRegReg(cUnit, kOpAdd, r_RA, r_RA, rDisp);
125 opReg(cUnit, kOpBx, r_RA);
buzbeec5159d52012-03-03 11:48:39 -0800126
Bill Buzbeea114add2012-05-03 15:00:40 -0700127 // Loop exit
128 LIR* exitLabel = newLIR0(cUnit, kPseudoTargetLabel);
129 exitBranch->target = exitLabel;
buzbeee3acd072012-02-25 17:03:10 -0800130}
131
buzbeec5159d52012-03-03 11:48:39 -0800132/*
133 * Code pattern will look something like:
134 *
135 * lw rVal
136 * jal BaseLabel ; stores "return address" (BaseLabel) in r_RA
137 * nop ; opportunistically fill
138 * [subiu rVal, bias] ; Remove bias if lowVal != 0
139 * bound check -> done
140 * lw rDisp, [r_RA, rVal]
141 * addu r_RA, rDisp
142 * jr r_RA
143 * done:
144 */
buzbee408ad162012-06-06 16:45:18 -0700145void genPackedSwitch(CompilationUnit* cUnit, uint32_t tableOffset,
146 RegLocation rlSrc)
buzbeee3acd072012-02-25 17:03:10 -0800147{
buzbee408ad162012-06-06 16:45:18 -0700148 const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700149 if (cUnit->printMe) {
150 dumpPackedSwitchTable(table);
151 }
152 // Add the table to the list - we'll process it later
153 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
154 true, kAllocData);
155 tabRec->table = table;
buzbee408ad162012-06-06 16:45:18 -0700156 tabRec->vaddr = cUnit->currentDalvikOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700157 int size = table[1];
158 tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true,
159 kAllocLIR);
160 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
buzbeee3acd072012-02-25 17:03:10 -0800161
Bill Buzbeea114add2012-05-03 15:00:40 -0700162 // Get the switch value
163 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
buzbeec5159d52012-03-03 11:48:39 -0800164
Bill Buzbeea114add2012-05-03 15:00:40 -0700165 // Prepare the bias. If too big, handle 1st stage here
166 int lowKey = s4FromSwitchData(&table[2]);
167 bool largeBias = false;
168 int rKey;
169 if (lowKey == 0) {
170 rKey = rlSrc.lowReg;
171 } else if ((lowKey & 0xffff) != lowKey) {
172 rKey = oatAllocTemp(cUnit);
173 loadConstant(cUnit, rKey, lowKey);
174 largeBias = true;
175 } else {
176 rKey = oatAllocTemp(cUnit);
177 }
178
179 // Must prevent code motion for the curr pc pair
180 genBarrier(cUnit);
181 newLIR0(cUnit, kMipsCurrPC); // Really a jal to .+8
182 // Now, fill the branch delay slot with bias strip
183 if (lowKey == 0) {
184 newLIR0(cUnit, kMipsNop);
185 } else {
186 if (largeBias) {
187 opRegRegReg(cUnit, kOpSub, rKey, rlSrc.lowReg, rKey);
buzbeee3acd072012-02-25 17:03:10 -0800188 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700189 opRegRegImm(cUnit, kOpSub, rKey, rlSrc.lowReg, lowKey);
buzbeee3acd072012-02-25 17:03:10 -0800190 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700191 }
192 genBarrier(cUnit); // Scheduling barrier
buzbeec5159d52012-03-03 11:48:39 -0800193
Bill Buzbeea114add2012-05-03 15:00:40 -0700194 // Construct BaseLabel and set up table base register
195 LIR* baseLabel = newLIR0(cUnit, kPseudoTargetLabel);
196 // Remember base label so offsets can be computed later
197 tabRec->anchor = baseLabel;
buzbeec5159d52012-03-03 11:48:39 -0800198
Bill Buzbeea114add2012-05-03 15:00:40 -0700199 // Bounds check - if < 0 or >= size continue following switch
200 LIR* branchOver = opCmpImmBranch(cUnit, kCondHi, rKey, size-1, NULL);
buzbeec5159d52012-03-03 11:48:39 -0800201
Bill Buzbeea114add2012-05-03 15:00:40 -0700202 // Materialize the table base pointer
203 int rBase = oatAllocTemp(cUnit);
204 newLIR4(cUnit, kMipsDelta, rBase, 0, (intptr_t)baseLabel, (intptr_t)tabRec);
buzbeec5159d52012-03-03 11:48:39 -0800205
Bill Buzbeea114add2012-05-03 15:00:40 -0700206 // Load the displacement from the switch table
207 int rDisp = oatAllocTemp(cUnit);
208 loadBaseIndexed(cUnit, rBase, rKey, rDisp, 2, kWord);
buzbeee3acd072012-02-25 17:03:10 -0800209
Bill Buzbeea114add2012-05-03 15:00:40 -0700210 // Add to r_AP and go
211 opRegRegReg(cUnit, kOpAdd, r_RA, r_RA, rDisp);
212 opReg(cUnit, kOpBx, r_RA);
buzbeee3acd072012-02-25 17:03:10 -0800213
Bill Buzbeea114add2012-05-03 15:00:40 -0700214 /* branchOver target here */
215 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
216 branchOver->target = (LIR*)target;
buzbeee3acd072012-02-25 17:03:10 -0800217}
218
219/*
220 * Array data table format:
221 * ushort ident = 0x0300 magic value
222 * ushort width width of each element in the table
223 * uint size number of elements in the table
224 * ubyte data[size*width] table of data values (may contain a single-byte
225 * padding at the end)
226 *
227 * Total size is 4+(width * size + 1)/2 16-bit code units.
228 */
buzbee408ad162012-06-06 16:45:18 -0700229void genFillArrayData(CompilationUnit* cUnit, uint32_t tableOffset,
230 RegLocation rlSrc)
buzbeee3acd072012-02-25 17:03:10 -0800231{
buzbee408ad162012-06-06 16:45:18 -0700232 const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700233 // Add the table to the list - we'll process it later
234 FillArrayData *tabRec = (FillArrayData *)
235 oatNew(cUnit, sizeof(FillArrayData), true, kAllocData);
236 tabRec->table = table;
buzbee408ad162012-06-06 16:45:18 -0700237 tabRec->vaddr = cUnit->currentDalvikOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700238 u2 width = tabRec->table[1];
239 u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
240 tabRec->size = (size * width) + 8;
buzbeee3acd072012-02-25 17:03:10 -0800241
Bill Buzbeea114add2012-05-03 15:00:40 -0700242 oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec);
buzbeee3acd072012-02-25 17:03:10 -0800243
Bill Buzbeea114add2012-05-03 15:00:40 -0700244 // Making a call - use explicit registers
245 oatFlushAllRegs(cUnit); /* Everything to home location */
246 oatLockCallTemps(cUnit);
247 loadValueDirectFixed(cUnit, rlSrc, rARG0);
buzbeec5159d52012-03-03 11:48:39 -0800248
Bill Buzbeea114add2012-05-03 15:00:40 -0700249 // Must prevent code motion for the curr pc pair
250 genBarrier(cUnit);
251 newLIR0(cUnit, kMipsCurrPC); // Really a jal to .+8
252 // Now, fill the branch delay slot with the helper load
253 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pHandleFillArrayDataFromCode));
254 genBarrier(cUnit); // Scheduling barrier
buzbeec5159d52012-03-03 11:48:39 -0800255
Bill Buzbeea114add2012-05-03 15:00:40 -0700256 // Construct BaseLabel and set up table base register
257 LIR* baseLabel = newLIR0(cUnit, kPseudoTargetLabel);
buzbeec5159d52012-03-03 11:48:39 -0800258
Bill Buzbeea114add2012-05-03 15:00:40 -0700259 // Materialize a pointer to the fill data image
260 newLIR4(cUnit, kMipsDelta, rARG1, 0, (intptr_t)baseLabel, (intptr_t)tabRec);
buzbeec5159d52012-03-03 11:48:39 -0800261
Bill Buzbeea114add2012-05-03 15:00:40 -0700262 // And go...
263 oatClobberCalleeSave(cUnit);
buzbee8320f382012-09-11 16:29:42 -0700264 LIR* callInst = opReg(cUnit, kOpBlx, rTgt); // ( array*, fill_data* )
265 markSafepointPC(cUnit, callInst);
buzbeee3acd072012-02-25 17:03:10 -0800266}
267
buzbee71ac9942012-03-01 17:23:10 -0800268void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
269{
Bill Buzbeea114add2012-05-03 15:00:40 -0700270 RegLocation rlResult;
271 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
272 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
273 opRegRegImm(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, 0x80000000);
274 storeValue(cUnit, rlDest, rlResult);
buzbee71ac9942012-03-01 17:23:10 -0800275}
276
277void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
278{
Bill Buzbeea114add2012-05-03 15:00:40 -0700279 RegLocation rlResult;
280 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
281 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
282 opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg, 0x80000000);
283 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
284 storeValueWide(cUnit, rlDest, rlResult);
buzbee71ac9942012-03-01 17:23:10 -0800285}
286
buzbee5de34942012-03-01 14:51:57 -0800287/*
288 * TODO: implement fast path to short-circuit thin-lock case
289 */
buzbee408ad162012-06-06 16:45:18 -0700290void genMonitorEnter(CompilationUnit* cUnit, int optFlags, RegLocation rlSrc)
buzbeee3acd072012-02-25 17:03:10 -0800291{
Bill Buzbeea114add2012-05-03 15:00:40 -0700292 oatFlushAllRegs(cUnit);
293 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get obj
294 oatLockCallTemps(cUnit); // Prepare for explicit register usage
buzbee408ad162012-06-06 16:45:18 -0700295 genNullCheck(cUnit, rlSrc.sRegLow, rARG0, optFlags);
Bill Buzbeea114add2012-05-03 15:00:40 -0700296 // Go expensive route - artLockObjectFromCode(self, obj);
297 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pLockObjectFromCode));
298 oatClobberCalleeSave(cUnit);
buzbee8320f382012-09-11 16:29:42 -0700299 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
300 markSafepointPC(cUnit, callInst);
buzbeee3acd072012-02-25 17:03:10 -0800301}
302
303/*
buzbee5de34942012-03-01 14:51:57 -0800304 * TODO: implement fast path to short-circuit thin-lock case
buzbeee3acd072012-02-25 17:03:10 -0800305 */
buzbee408ad162012-06-06 16:45:18 -0700306void genMonitorExit(CompilationUnit* cUnit, int optFlags, RegLocation rlSrc)
buzbeee3acd072012-02-25 17:03:10 -0800307{
Bill Buzbeea114add2012-05-03 15:00:40 -0700308 oatFlushAllRegs(cUnit);
309 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get obj
310 oatLockCallTemps(cUnit); // Prepare for explicit register usage
buzbee408ad162012-06-06 16:45:18 -0700311 genNullCheck(cUnit, rlSrc.sRegLow, rARG0, optFlags);
Bill Buzbeea114add2012-05-03 15:00:40 -0700312 // Go expensive route - UnlockObjectFromCode(obj);
313 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pUnlockObjectFromCode));
314 oatClobberCalleeSave(cUnit);
buzbee8320f382012-09-11 16:29:42 -0700315 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
316 markSafepointPC(cUnit, callInst);
buzbee5de34942012-03-01 14:51:57 -0800317}
318
319/*
320 * Compare two 64-bit values
321 * x = y return 0
322 * x < y return -1
323 * x > y return 1
324 *
325 * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
326 * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
327 * subu res, t0, t1 # res = -1:1:0 for [ < > = ]
328 * bnez res, finish
329 * sltu t0, x.lo, y.lo
330 * sgtu r1, x.lo, y.lo
331 * subu res, t0, t1
332 * finish:
333 *
334 */
buzbee408ad162012-06-06 16:45:18 -0700335void genCmpLong(CompilationUnit* cUnit, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -0700336 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee5de34942012-03-01 14:51:57 -0800337{
Bill Buzbeea114add2012-05-03 15:00:40 -0700338 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
339 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
340 int t0 = oatAllocTemp(cUnit);
341 int t1 = oatAllocTemp(cUnit);
342 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
343 newLIR3(cUnit, kMipsSlt, t0, rlSrc1.highReg, rlSrc2.highReg);
344 newLIR3(cUnit, kMipsSlt, t1, rlSrc2.highReg, rlSrc1.highReg);
345 newLIR3(cUnit, kMipsSubu, rlResult.lowReg, t1, t0);
346 LIR* branch = opCmpImmBranch(cUnit, kCondNe, rlResult.lowReg, 0, NULL);
347 newLIR3(cUnit, kMipsSltu, t0, rlSrc1.lowReg, rlSrc2.lowReg);
348 newLIR3(cUnit, kMipsSltu, t1, rlSrc2.lowReg, rlSrc1.lowReg);
349 newLIR3(cUnit, kMipsSubu, rlResult.lowReg, t1, t0);
350 oatFreeTemp(cUnit, t0);
351 oatFreeTemp(cUnit, t1);
352 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
353 branch->target = (LIR*)target;
354 storeValue(cUnit, rlDest, rlResult);
buzbeee3acd072012-02-25 17:03:10 -0800355}
356
buzbee82488f52012-03-02 08:20:26 -0800357LIR* opCmpBranch(CompilationUnit* cUnit, ConditionCode cond, int src1,
Bill Buzbeea114add2012-05-03 15:00:40 -0700358 int src2, LIR* target)
buzbeee3acd072012-02-25 17:03:10 -0800359{
Bill Buzbeea114add2012-05-03 15:00:40 -0700360 LIR* branch;
361 MipsOpCode sltOp;
362 MipsOpCode brOp;
363 bool cmpZero = false;
364 bool swapped = false;
365 switch (cond) {
366 case kCondEq:
367 brOp = kMipsBeq;
368 cmpZero = true;
369 break;
370 case kCondNe:
371 brOp = kMipsBne;
372 cmpZero = true;
373 break;
374 case kCondCc:
375 sltOp = kMipsSltu;
376 brOp = kMipsBnez;
377 break;
378 case kCondCs:
379 sltOp = kMipsSltu;
380 brOp = kMipsBeqz;
381 break;
382 case kCondGe:
383 sltOp = kMipsSlt;
384 brOp = kMipsBeqz;
385 break;
386 case kCondGt:
387 sltOp = kMipsSlt;
388 brOp = kMipsBnez;
389 swapped = true;
390 break;
391 case kCondLe:
392 sltOp = kMipsSlt;
393 brOp = kMipsBeqz;
394 swapped = true;
395 break;
396 case kCondLt:
397 sltOp = kMipsSlt;
398 brOp = kMipsBnez;
399 break;
400 case kCondHi: // Gtu
401 sltOp = kMipsSltu;
402 brOp = kMipsBnez;
403 swapped = true;
404 break;
405 default:
406 LOG(FATAL) << "No support for ConditionCode: " << (int) cond;
407 return NULL;
408 }
409 if (cmpZero) {
410 branch = newLIR2(cUnit, brOp, src1, src2);
411 } else {
412 int tReg = oatAllocTemp(cUnit);
413 if (swapped) {
414 newLIR3(cUnit, sltOp, tReg, src2, src1);
buzbee82488f52012-03-02 08:20:26 -0800415 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700416 newLIR3(cUnit, sltOp, tReg, src1, src2);
buzbee5de34942012-03-01 14:51:57 -0800417 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700418 branch = newLIR1(cUnit, brOp, tReg);
419 oatFreeTemp(cUnit, tReg);
420 }
421 branch->target = target;
422 return branch;
buzbeee3acd072012-02-25 17:03:10 -0800423}
424
buzbee82488f52012-03-02 08:20:26 -0800425LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg,
Bill Buzbeea114add2012-05-03 15:00:40 -0700426 int checkValue, LIR* target)
buzbeee3acd072012-02-25 17:03:10 -0800427{
Bill Buzbeea114add2012-05-03 15:00:40 -0700428 LIR* branch;
429 if (checkValue != 0) {
430 // TUNING: handle s16 & kCondLt/Mi case using slti
431 int tReg = oatAllocTemp(cUnit);
432 loadConstant(cUnit, tReg, checkValue);
433 branch = opCmpBranch(cUnit, cond, reg, tReg, target);
434 oatFreeTemp(cUnit, tReg);
buzbee82488f52012-03-02 08:20:26 -0800435 return branch;
Bill Buzbeea114add2012-05-03 15:00:40 -0700436 }
437 MipsOpCode opc;
438 switch (cond) {
439 case kCondEq: opc = kMipsBeqz; break;
440 case kCondGe: opc = kMipsBgez; break;
441 case kCondGt: opc = kMipsBgtz; break;
442 case kCondLe: opc = kMipsBlez; break;
443 //case KCondMi:
444 case kCondLt: opc = kMipsBltz; break;
445 case kCondNe: opc = kMipsBnez; break;
446 default:
447 // Tuning: use slti when applicable
448 int tReg = oatAllocTemp(cUnit);
449 loadConstant(cUnit, tReg, checkValue);
450 branch = opCmpBranch(cUnit, cond, reg, tReg, target);
451 oatFreeTemp(cUnit, tReg);
452 return branch;
453 }
454 branch = newLIR1(cUnit, opc, reg);
455 branch->target = target;
456 return branch;
buzbeee3acd072012-02-25 17:03:10 -0800457}
458
buzbee82488f52012-03-02 08:20:26 -0800459LIR* opRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
buzbeee3acd072012-02-25 17:03:10 -0800460{
buzbeee3acd072012-02-25 17:03:10 -0800461#ifdef __mips_hard_float
Bill Buzbeea114add2012-05-03 15:00:40 -0700462 if (FPREG(rDest) || FPREG(rSrc))
463 return fpRegCopy(cUnit, rDest, rSrc);
buzbee5de34942012-03-01 14:51:57 -0800464#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700465 LIR* res = rawLIR(cUnit, cUnit->currentDalvikOffset, kMipsMove,
466 rDest, rSrc);
467 if (!(cUnit->disableOpt & (1 << kSafeOptimizations)) && rDest == rSrc) {
468 res->flags.isNop = true;
469 }
470 return res;
buzbee5de34942012-03-01 14:51:57 -0800471}
472
buzbee82488f52012-03-02 08:20:26 -0800473LIR* opRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
buzbee5de34942012-03-01 14:51:57 -0800474{
Bill Buzbeea114add2012-05-03 15:00:40 -0700475 LIR *res = opRegCopyNoInsert(cUnit, rDest, rSrc);
476 oatAppendLIR(cUnit, (LIR*)res);
477 return res;
buzbee5de34942012-03-01 14:51:57 -0800478}
479
buzbee82488f52012-03-02 08:20:26 -0800480void opRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
Bill Buzbeea114add2012-05-03 15:00:40 -0700481 int srcLo, int srcHi)
buzbee5de34942012-03-01 14:51:57 -0800482{
483#ifdef __mips_hard_float
Bill Buzbeea114add2012-05-03 15:00:40 -0700484 bool destFP = FPREG(destLo) && FPREG(destHi);
485 bool srcFP = FPREG(srcLo) && FPREG(srcHi);
486 assert(FPREG(srcLo) == FPREG(srcHi));
487 assert(FPREG(destLo) == FPREG(destHi));
488 if (destFP) {
489 if (srcFP) {
490 opRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
buzbee5de34942012-03-01 14:51:57 -0800491 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700492 /* note the operands are swapped for the mtc1 instr */
493 newLIR2(cUnit, kMipsMtc1, srcLo, destLo);
494 newLIR2(cUnit, kMipsMtc1, srcHi, destHi);
buzbee5de34942012-03-01 14:51:57 -0800495 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700496 } else {
497 if (srcFP) {
498 newLIR2(cUnit, kMipsMfc1, destLo, srcLo);
499 newLIR2(cUnit, kMipsMfc1, destHi, srcHi);
500 } else {
501 // Handle overlap
502 if (srcHi == destLo) {
503 opRegCopy(cUnit, destHi, srcHi);
504 opRegCopy(cUnit, destLo, srcLo);
505 } else {
506 opRegCopy(cUnit, destLo, srcLo);
507 opRegCopy(cUnit, destHi, srcHi);
508 }
509 }
510 }
buzbeee3acd072012-02-25 17:03:10 -0800511#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700512 // Handle overlap
513 if (srcHi == destLo) {
514 opRegCopy(cUnit, destHi, srcHi);
515 opRegCopy(cUnit, destLo, srcLo);
516 } else {
517 opRegCopy(cUnit, destLo, srcLo);
518 opRegCopy(cUnit, destHi, srcHi);
519 }
buzbeee3acd072012-02-25 17:03:10 -0800520#endif
buzbeee3acd072012-02-25 17:03:10 -0800521}
522
jeffhao4b771a02012-07-25 15:07:21 -0700523void genFusedLongCmpBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir)
524{
525 UNIMPLEMENTED(FATAL) << "Need codegen for fused long cmp branch";
526}
527
buzbeee3acd072012-02-25 17:03:10 -0800528} // namespace art