blob: 22c8b84e5becbeb4903b98b7a9bc41941858ca65 [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
buzbeeb046e162012-10-30 15:48:42 -070017/* This file contains codegen for the Mips ISA */
buzbeee3acd072012-02-25 17:03:10 -080018
Ian Rogers57b86d42012-03-27 16:05:41 -070019#include "oat/runtime/oat_support_entrypoints.h"
20
buzbeee3acd072012-02-25 17:03:10 -080021namespace art {
22
buzbee16da88c2012-03-20 10:38:17 -070023void genSpecialCase(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
24 SpecialCaseHandler specialCase)
25{
26 // TODO
27}
28
buzbeee3acd072012-02-25 17:03:10 -080029/*
buzbeec5159d52012-03-03 11:48:39 -080030 * The lack of pc-relative loads on Mips presents somewhat of a challenge
31 * for our PIC switch table strategy. To materialize the current location
32 * we'll do a dummy JAL and reference our tables using r_RA as the
33 * base register. Note that r_RA will be used both as the base to
34 * locate the switch table data and as the reference base for the switch
35 * target offsets stored in the table. We'll use a special pseudo-instruction
36 * to represent the jal and trigger the construction of the
37 * switch table offsets (which will happen after final assembly and all
38 * labels are fixed).
buzbeee3acd072012-02-25 17:03:10 -080039 *
40 * The test loop will look something like:
41 *
buzbeec5159d52012-03-03 11:48:39 -080042 * ori rEnd, r_ZERO, #tableSize ; size in bytes
43 * jal BaseLabel ; stores "return address" (BaseLabel) in r_RA
44 * nop ; opportunistically fill
45 * BaseLabel:
46 * addiu rBase, r_RA, <table> - <BaseLabel> ; table relative to BaseLabel
47 addu rEnd, rEnd, rBase ; end of table
48 * lw rVal, [rSP, vRegOff] ; Test Value
49 * loop:
50 * beq rBase, rEnd, done
51 * lw rKey, 0(rBase)
52 * addu rBase, 8
53 * bne rVal, rKey, loop
54 * lw rDisp, -4(rBase)
55 * addu r_RA, rDisp
56 * jr r_RA
57 * done:
58 *
buzbeee3acd072012-02-25 17:03:10 -080059 */
buzbee408ad162012-06-06 16:45:18 -070060void genSparseSwitch(CompilationUnit* cUnit, uint32_t tableOffset,
buzbeea1da8a52012-07-09 14:00:21 -070061 RegLocation rlSrc)
buzbeee3acd072012-02-25 17:03:10 -080062{
buzbee408ad162012-06-06 16:45:18 -070063 const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -070064 if (cUnit->printMe) {
65 dumpSparseSwitchTable(table);
66 }
67 // Add the table to the list - we'll process it later
68 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
69 true, kAllocData);
70 tabRec->table = table;
buzbee408ad162012-06-06 16:45:18 -070071 tabRec->vaddr = cUnit->currentDalvikOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -070072 int elements = table[1];
73 tabRec->targets = (LIR* *)oatNew(cUnit, elements * sizeof(LIR*), true,
74 kAllocLIR);
75 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
buzbeee3acd072012-02-25 17:03:10 -080076
Bill Buzbeea114add2012-05-03 15:00:40 -070077 // The table is composed of 8-byte key/disp pairs
78 int byteSize = elements * 8;
buzbeec5159d52012-03-03 11:48:39 -080079
Bill Buzbeea114add2012-05-03 15:00:40 -070080 int sizeHi = byteSize >> 16;
81 int sizeLo = byteSize & 0xffff;
buzbeec5159d52012-03-03 11:48:39 -080082
Bill Buzbeea114add2012-05-03 15:00:40 -070083 int rEnd = oatAllocTemp(cUnit);
84 if (sizeHi) {
85 newLIR2(cUnit, kMipsLui, rEnd, sizeHi);
86 }
87 // Must prevent code motion for the curr pc pair
88 genBarrier(cUnit); // Scheduling barrier
89 newLIR0(cUnit, kMipsCurrPC); // Really a jal to .+8
90 // Now, fill the branch delay slot
91 if (sizeHi) {
92 newLIR3(cUnit, kMipsOri, rEnd, rEnd, sizeLo);
93 } else {
94 newLIR3(cUnit, kMipsOri, rEnd, r_ZERO, sizeLo);
95 }
96 genBarrier(cUnit); // Scheduling barrier
buzbeec5159d52012-03-03 11:48:39 -080097
Bill Buzbeea114add2012-05-03 15:00:40 -070098 // Construct BaseLabel and set up table base register
99 LIR* baseLabel = newLIR0(cUnit, kPseudoTargetLabel);
100 // Remember base label so offsets can be computed later
101 tabRec->anchor = baseLabel;
102 int rBase = oatAllocTemp(cUnit);
103 newLIR4(cUnit, kMipsDelta, rBase, 0, (intptr_t)baseLabel, (intptr_t)tabRec);
104 opRegRegReg(cUnit, kOpAdd, rEnd, rEnd, rBase);
buzbeec5159d52012-03-03 11:48:39 -0800105
Bill Buzbeea114add2012-05-03 15:00:40 -0700106 // Grab switch test value
107 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
buzbeec5159d52012-03-03 11:48:39 -0800108
Bill Buzbeea114add2012-05-03 15:00:40 -0700109 // Test loop
110 int rKey = oatAllocTemp(cUnit);
111 LIR* loopLabel = newLIR0(cUnit, kPseudoTargetLabel);
112 LIR* exitBranch = opCmpBranch(cUnit , kCondEq, rBase, rEnd, NULL);
113 loadWordDisp(cUnit, rBase, 0, rKey);
114 opRegImm(cUnit, kOpAdd, rBase, 8);
115 opCmpBranch(cUnit, kCondNe, rlSrc.lowReg, rKey, loopLabel);
116 int rDisp = oatAllocTemp(cUnit);
117 loadWordDisp(cUnit, rBase, -4, rDisp);
118 opRegRegReg(cUnit, kOpAdd, r_RA, r_RA, rDisp);
119 opReg(cUnit, kOpBx, r_RA);
buzbeec5159d52012-03-03 11:48:39 -0800120
Bill Buzbeea114add2012-05-03 15:00:40 -0700121 // Loop exit
122 LIR* exitLabel = newLIR0(cUnit, kPseudoTargetLabel);
123 exitBranch->target = exitLabel;
buzbeee3acd072012-02-25 17:03:10 -0800124}
125
buzbeec5159d52012-03-03 11:48:39 -0800126/*
127 * Code pattern will look something like:
128 *
129 * lw rVal
130 * jal BaseLabel ; stores "return address" (BaseLabel) in r_RA
131 * nop ; opportunistically fill
132 * [subiu rVal, bias] ; Remove bias if lowVal != 0
133 * bound check -> done
134 * lw rDisp, [r_RA, rVal]
135 * addu r_RA, rDisp
136 * jr r_RA
137 * done:
138 */
buzbee408ad162012-06-06 16:45:18 -0700139void genPackedSwitch(CompilationUnit* cUnit, uint32_t tableOffset,
140 RegLocation rlSrc)
buzbeee3acd072012-02-25 17:03:10 -0800141{
buzbee408ad162012-06-06 16:45:18 -0700142 const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700143 if (cUnit->printMe) {
144 dumpPackedSwitchTable(table);
145 }
146 // Add the table to the list - we'll process it later
147 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
148 true, kAllocData);
149 tabRec->table = table;
buzbee408ad162012-06-06 16:45:18 -0700150 tabRec->vaddr = cUnit->currentDalvikOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700151 int size = table[1];
152 tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true,
153 kAllocLIR);
154 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
buzbeee3acd072012-02-25 17:03:10 -0800155
Bill Buzbeea114add2012-05-03 15:00:40 -0700156 // Get the switch value
157 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
buzbeec5159d52012-03-03 11:48:39 -0800158
Bill Buzbeea114add2012-05-03 15:00:40 -0700159 // Prepare the bias. If too big, handle 1st stage here
160 int lowKey = s4FromSwitchData(&table[2]);
161 bool largeBias = false;
162 int rKey;
163 if (lowKey == 0) {
164 rKey = rlSrc.lowReg;
165 } else if ((lowKey & 0xffff) != lowKey) {
166 rKey = oatAllocTemp(cUnit);
167 loadConstant(cUnit, rKey, lowKey);
168 largeBias = true;
169 } else {
170 rKey = oatAllocTemp(cUnit);
171 }
172
173 // Must prevent code motion for the curr pc pair
174 genBarrier(cUnit);
175 newLIR0(cUnit, kMipsCurrPC); // Really a jal to .+8
176 // Now, fill the branch delay slot with bias strip
177 if (lowKey == 0) {
178 newLIR0(cUnit, kMipsNop);
179 } else {
180 if (largeBias) {
181 opRegRegReg(cUnit, kOpSub, rKey, rlSrc.lowReg, rKey);
buzbeee3acd072012-02-25 17:03:10 -0800182 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700183 opRegRegImm(cUnit, kOpSub, rKey, rlSrc.lowReg, lowKey);
buzbeee3acd072012-02-25 17:03:10 -0800184 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700185 }
186 genBarrier(cUnit); // Scheduling barrier
buzbeec5159d52012-03-03 11:48:39 -0800187
Bill Buzbeea114add2012-05-03 15:00:40 -0700188 // Construct BaseLabel and set up table base register
189 LIR* baseLabel = newLIR0(cUnit, kPseudoTargetLabel);
190 // Remember base label so offsets can be computed later
191 tabRec->anchor = baseLabel;
buzbeec5159d52012-03-03 11:48:39 -0800192
Bill Buzbeea114add2012-05-03 15:00:40 -0700193 // Bounds check - if < 0 or >= size continue following switch
194 LIR* branchOver = opCmpImmBranch(cUnit, kCondHi, rKey, size-1, NULL);
buzbeec5159d52012-03-03 11:48:39 -0800195
Bill Buzbeea114add2012-05-03 15:00:40 -0700196 // Materialize the table base pointer
197 int rBase = oatAllocTemp(cUnit);
198 newLIR4(cUnit, kMipsDelta, rBase, 0, (intptr_t)baseLabel, (intptr_t)tabRec);
buzbeec5159d52012-03-03 11:48:39 -0800199
Bill Buzbeea114add2012-05-03 15:00:40 -0700200 // Load the displacement from the switch table
201 int rDisp = oatAllocTemp(cUnit);
202 loadBaseIndexed(cUnit, rBase, rKey, rDisp, 2, kWord);
buzbeee3acd072012-02-25 17:03:10 -0800203
Bill Buzbeea114add2012-05-03 15:00:40 -0700204 // Add to r_AP and go
205 opRegRegReg(cUnit, kOpAdd, r_RA, r_RA, rDisp);
206 opReg(cUnit, kOpBx, r_RA);
buzbeee3acd072012-02-25 17:03:10 -0800207
Bill Buzbeea114add2012-05-03 15:00:40 -0700208 /* branchOver target here */
209 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
210 branchOver->target = (LIR*)target;
buzbeee3acd072012-02-25 17:03:10 -0800211}
212
213/*
214 * Array data table format:
215 * ushort ident = 0x0300 magic value
216 * ushort width width of each element in the table
217 * uint size number of elements in the table
218 * ubyte data[size*width] table of data values (may contain a single-byte
219 * padding at the end)
220 *
221 * Total size is 4+(width * size + 1)/2 16-bit code units.
222 */
buzbee408ad162012-06-06 16:45:18 -0700223void genFillArrayData(CompilationUnit* cUnit, uint32_t tableOffset,
224 RegLocation rlSrc)
buzbeee3acd072012-02-25 17:03:10 -0800225{
buzbee408ad162012-06-06 16:45:18 -0700226 const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700227 // Add the table to the list - we'll process it later
228 FillArrayData *tabRec = (FillArrayData *)
229 oatNew(cUnit, sizeof(FillArrayData), true, kAllocData);
230 tabRec->table = table;
buzbee408ad162012-06-06 16:45:18 -0700231 tabRec->vaddr = cUnit->currentDalvikOffset;
Bill Buzbeea114add2012-05-03 15:00:40 -0700232 u2 width = tabRec->table[1];
233 u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
234 tabRec->size = (size * width) + 8;
buzbeee3acd072012-02-25 17:03:10 -0800235
Bill Buzbeea114add2012-05-03 15:00:40 -0700236 oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec);
buzbeee3acd072012-02-25 17:03:10 -0800237
Bill Buzbeea114add2012-05-03 15:00:40 -0700238 // Making a call - use explicit registers
239 oatFlushAllRegs(cUnit); /* Everything to home location */
240 oatLockCallTemps(cUnit);
241 loadValueDirectFixed(cUnit, rlSrc, rARG0);
buzbeec5159d52012-03-03 11:48:39 -0800242
Bill Buzbeea114add2012-05-03 15:00:40 -0700243 // Must prevent code motion for the curr pc pair
244 genBarrier(cUnit);
245 newLIR0(cUnit, kMipsCurrPC); // Really a jal to .+8
246 // Now, fill the branch delay slot with the helper load
247 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pHandleFillArrayDataFromCode));
248 genBarrier(cUnit); // Scheduling barrier
buzbeec5159d52012-03-03 11:48:39 -0800249
Bill Buzbeea114add2012-05-03 15:00:40 -0700250 // Construct BaseLabel and set up table base register
251 LIR* baseLabel = newLIR0(cUnit, kPseudoTargetLabel);
buzbeec5159d52012-03-03 11:48:39 -0800252
Bill Buzbeea114add2012-05-03 15:00:40 -0700253 // Materialize a pointer to the fill data image
254 newLIR4(cUnit, kMipsDelta, rARG1, 0, (intptr_t)baseLabel, (intptr_t)tabRec);
buzbeec5159d52012-03-03 11:48:39 -0800255
Bill Buzbeea114add2012-05-03 15:00:40 -0700256 // And go...
257 oatClobberCalleeSave(cUnit);
buzbee8320f382012-09-11 16:29:42 -0700258 LIR* callInst = opReg(cUnit, kOpBlx, rTgt); // ( array*, fill_data* )
259 markSafepointPC(cUnit, callInst);
buzbeee3acd072012-02-25 17:03:10 -0800260}
261
buzbee71ac9942012-03-01 17:23:10 -0800262void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
263{
Bill Buzbeea114add2012-05-03 15:00:40 -0700264 RegLocation rlResult;
265 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
266 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
267 opRegRegImm(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, 0x80000000);
268 storeValue(cUnit, rlDest, rlResult);
buzbee71ac9942012-03-01 17:23:10 -0800269}
270
271void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
272{
Bill Buzbeea114add2012-05-03 15:00:40 -0700273 RegLocation rlResult;
274 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
275 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
276 opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg, 0x80000000);
277 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
278 storeValueWide(cUnit, rlDest, rlResult);
buzbee71ac9942012-03-01 17:23:10 -0800279}
280
buzbee5de34942012-03-01 14:51:57 -0800281/*
282 * TODO: implement fast path to short-circuit thin-lock case
283 */
buzbee408ad162012-06-06 16:45:18 -0700284void genMonitorEnter(CompilationUnit* cUnit, int optFlags, RegLocation rlSrc)
buzbeee3acd072012-02-25 17:03:10 -0800285{
Bill Buzbeea114add2012-05-03 15:00:40 -0700286 oatFlushAllRegs(cUnit);
287 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get obj
288 oatLockCallTemps(cUnit); // Prepare for explicit register usage
buzbee408ad162012-06-06 16:45:18 -0700289 genNullCheck(cUnit, rlSrc.sRegLow, rARG0, optFlags);
Bill Buzbeea114add2012-05-03 15:00:40 -0700290 // Go expensive route - artLockObjectFromCode(self, obj);
291 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pLockObjectFromCode));
292 oatClobberCalleeSave(cUnit);
buzbee8320f382012-09-11 16:29:42 -0700293 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
294 markSafepointPC(cUnit, callInst);
buzbeee3acd072012-02-25 17:03:10 -0800295}
296
297/*
buzbee5de34942012-03-01 14:51:57 -0800298 * TODO: implement fast path to short-circuit thin-lock case
buzbeee3acd072012-02-25 17:03:10 -0800299 */
buzbee408ad162012-06-06 16:45:18 -0700300void genMonitorExit(CompilationUnit* cUnit, int optFlags, RegLocation rlSrc)
buzbeee3acd072012-02-25 17:03:10 -0800301{
Bill Buzbeea114add2012-05-03 15:00:40 -0700302 oatFlushAllRegs(cUnit);
303 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get obj
304 oatLockCallTemps(cUnit); // Prepare for explicit register usage
buzbee408ad162012-06-06 16:45:18 -0700305 genNullCheck(cUnit, rlSrc.sRegLow, rARG0, optFlags);
Bill Buzbeea114add2012-05-03 15:00:40 -0700306 // Go expensive route - UnlockObjectFromCode(obj);
307 int rTgt = loadHelper(cUnit, ENTRYPOINT_OFFSET(pUnlockObjectFromCode));
308 oatClobberCalleeSave(cUnit);
buzbee8320f382012-09-11 16:29:42 -0700309 LIR* callInst = opReg(cUnit, kOpBlx, rTgt);
310 markSafepointPC(cUnit, callInst);
buzbee5de34942012-03-01 14:51:57 -0800311}
312
313/*
314 * Compare two 64-bit values
315 * x = y return 0
316 * x < y return -1
317 * x > y return 1
318 *
319 * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
320 * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
321 * subu res, t0, t1 # res = -1:1:0 for [ < > = ]
322 * bnez res, finish
323 * sltu t0, x.lo, y.lo
324 * sgtu r1, x.lo, y.lo
325 * subu res, t0, t1
326 * finish:
327 *
328 */
buzbee408ad162012-06-06 16:45:18 -0700329void genCmpLong(CompilationUnit* cUnit, RegLocation rlDest,
Bill Buzbeea114add2012-05-03 15:00:40 -0700330 RegLocation rlSrc1, RegLocation rlSrc2)
buzbee5de34942012-03-01 14:51:57 -0800331{
Bill Buzbeea114add2012-05-03 15:00:40 -0700332 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
333 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
334 int t0 = oatAllocTemp(cUnit);
335 int t1 = oatAllocTemp(cUnit);
336 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
337 newLIR3(cUnit, kMipsSlt, t0, rlSrc1.highReg, rlSrc2.highReg);
338 newLIR3(cUnit, kMipsSlt, t1, rlSrc2.highReg, rlSrc1.highReg);
339 newLIR3(cUnit, kMipsSubu, rlResult.lowReg, t1, t0);
340 LIR* branch = opCmpImmBranch(cUnit, kCondNe, rlResult.lowReg, 0, NULL);
341 newLIR3(cUnit, kMipsSltu, t0, rlSrc1.lowReg, rlSrc2.lowReg);
342 newLIR3(cUnit, kMipsSltu, t1, rlSrc2.lowReg, rlSrc1.lowReg);
343 newLIR3(cUnit, kMipsSubu, rlResult.lowReg, t1, t0);
344 oatFreeTemp(cUnit, t0);
345 oatFreeTemp(cUnit, t1);
346 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
347 branch->target = (LIR*)target;
348 storeValue(cUnit, rlDest, rlResult);
buzbeee3acd072012-02-25 17:03:10 -0800349}
350
buzbee82488f52012-03-02 08:20:26 -0800351LIR* opCmpBranch(CompilationUnit* cUnit, ConditionCode cond, int src1,
Bill Buzbeea114add2012-05-03 15:00:40 -0700352 int src2, LIR* target)
buzbeee3acd072012-02-25 17:03:10 -0800353{
Bill Buzbeea114add2012-05-03 15:00:40 -0700354 LIR* branch;
355 MipsOpCode sltOp;
356 MipsOpCode brOp;
357 bool cmpZero = false;
358 bool swapped = false;
359 switch (cond) {
360 case kCondEq:
361 brOp = kMipsBeq;
362 cmpZero = true;
363 break;
364 case kCondNe:
365 brOp = kMipsBne;
366 cmpZero = true;
367 break;
368 case kCondCc:
369 sltOp = kMipsSltu;
370 brOp = kMipsBnez;
371 break;
372 case kCondCs:
373 sltOp = kMipsSltu;
374 brOp = kMipsBeqz;
375 break;
376 case kCondGe:
377 sltOp = kMipsSlt;
378 brOp = kMipsBeqz;
379 break;
380 case kCondGt:
381 sltOp = kMipsSlt;
382 brOp = kMipsBnez;
383 swapped = true;
384 break;
385 case kCondLe:
386 sltOp = kMipsSlt;
387 brOp = kMipsBeqz;
388 swapped = true;
389 break;
390 case kCondLt:
391 sltOp = kMipsSlt;
392 brOp = kMipsBnez;
393 break;
394 case kCondHi: // Gtu
395 sltOp = kMipsSltu;
396 brOp = kMipsBnez;
397 swapped = true;
398 break;
399 default:
400 LOG(FATAL) << "No support for ConditionCode: " << (int) cond;
401 return NULL;
402 }
403 if (cmpZero) {
404 branch = newLIR2(cUnit, brOp, src1, src2);
405 } else {
406 int tReg = oatAllocTemp(cUnit);
407 if (swapped) {
408 newLIR3(cUnit, sltOp, tReg, src2, src1);
buzbee82488f52012-03-02 08:20:26 -0800409 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700410 newLIR3(cUnit, sltOp, tReg, src1, src2);
buzbee5de34942012-03-01 14:51:57 -0800411 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700412 branch = newLIR1(cUnit, brOp, tReg);
413 oatFreeTemp(cUnit, tReg);
414 }
415 branch->target = target;
416 return branch;
buzbeee3acd072012-02-25 17:03:10 -0800417}
418
buzbee82488f52012-03-02 08:20:26 -0800419LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg,
Bill Buzbeea114add2012-05-03 15:00:40 -0700420 int checkValue, LIR* target)
buzbeee3acd072012-02-25 17:03:10 -0800421{
Bill Buzbeea114add2012-05-03 15:00:40 -0700422 LIR* branch;
423 if (checkValue != 0) {
424 // TUNING: handle s16 & kCondLt/Mi case using slti
425 int tReg = oatAllocTemp(cUnit);
426 loadConstant(cUnit, tReg, checkValue);
427 branch = opCmpBranch(cUnit, cond, reg, tReg, target);
428 oatFreeTemp(cUnit, tReg);
buzbee82488f52012-03-02 08:20:26 -0800429 return branch;
Bill Buzbeea114add2012-05-03 15:00:40 -0700430 }
431 MipsOpCode opc;
432 switch (cond) {
433 case kCondEq: opc = kMipsBeqz; break;
434 case kCondGe: opc = kMipsBgez; break;
435 case kCondGt: opc = kMipsBgtz; break;
436 case kCondLe: opc = kMipsBlez; break;
437 //case KCondMi:
438 case kCondLt: opc = kMipsBltz; break;
439 case kCondNe: opc = kMipsBnez; break;
440 default:
441 // Tuning: use slti when applicable
442 int tReg = oatAllocTemp(cUnit);
443 loadConstant(cUnit, tReg, checkValue);
444 branch = opCmpBranch(cUnit, cond, reg, tReg, target);
445 oatFreeTemp(cUnit, tReg);
446 return branch;
447 }
448 branch = newLIR1(cUnit, opc, reg);
449 branch->target = target;
450 return branch;
buzbeee3acd072012-02-25 17:03:10 -0800451}
452
buzbee82488f52012-03-02 08:20:26 -0800453LIR* opRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
buzbeee3acd072012-02-25 17:03:10 -0800454{
buzbeee3acd072012-02-25 17:03:10 -0800455#ifdef __mips_hard_float
Bill Buzbeea114add2012-05-03 15:00:40 -0700456 if (FPREG(rDest) || FPREG(rSrc))
457 return fpRegCopy(cUnit, rDest, rSrc);
buzbee5de34942012-03-01 14:51:57 -0800458#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700459 LIR* res = rawLIR(cUnit, cUnit->currentDalvikOffset, kMipsMove,
460 rDest, rSrc);
461 if (!(cUnit->disableOpt & (1 << kSafeOptimizations)) && rDest == rSrc) {
462 res->flags.isNop = true;
463 }
464 return res;
buzbee5de34942012-03-01 14:51:57 -0800465}
466
buzbee82488f52012-03-02 08:20:26 -0800467LIR* opRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
buzbee5de34942012-03-01 14:51:57 -0800468{
Bill Buzbeea114add2012-05-03 15:00:40 -0700469 LIR *res = opRegCopyNoInsert(cUnit, rDest, rSrc);
470 oatAppendLIR(cUnit, (LIR*)res);
471 return res;
buzbee5de34942012-03-01 14:51:57 -0800472}
473
buzbee82488f52012-03-02 08:20:26 -0800474void opRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
Bill Buzbeea114add2012-05-03 15:00:40 -0700475 int srcLo, int srcHi)
buzbee5de34942012-03-01 14:51:57 -0800476{
477#ifdef __mips_hard_float
Bill Buzbeea114add2012-05-03 15:00:40 -0700478 bool destFP = FPREG(destLo) && FPREG(destHi);
479 bool srcFP = FPREG(srcLo) && FPREG(srcHi);
480 assert(FPREG(srcLo) == FPREG(srcHi));
481 assert(FPREG(destLo) == FPREG(destHi));
482 if (destFP) {
483 if (srcFP) {
484 opRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
buzbee5de34942012-03-01 14:51:57 -0800485 } else {
Bill Buzbeea114add2012-05-03 15:00:40 -0700486 /* note the operands are swapped for the mtc1 instr */
487 newLIR2(cUnit, kMipsMtc1, srcLo, destLo);
488 newLIR2(cUnit, kMipsMtc1, srcHi, destHi);
buzbee5de34942012-03-01 14:51:57 -0800489 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700490 } else {
491 if (srcFP) {
492 newLIR2(cUnit, kMipsMfc1, destLo, srcLo);
493 newLIR2(cUnit, kMipsMfc1, destHi, srcHi);
494 } else {
495 // Handle overlap
496 if (srcHi == destLo) {
497 opRegCopy(cUnit, destHi, srcHi);
498 opRegCopy(cUnit, destLo, srcLo);
499 } else {
500 opRegCopy(cUnit, destLo, srcLo);
501 opRegCopy(cUnit, destHi, srcHi);
502 }
503 }
504 }
buzbeee3acd072012-02-25 17:03:10 -0800505#else
Bill Buzbeea114add2012-05-03 15:00:40 -0700506 // Handle overlap
507 if (srcHi == destLo) {
508 opRegCopy(cUnit, destHi, srcHi);
509 opRegCopy(cUnit, destLo, srcLo);
510 } else {
511 opRegCopy(cUnit, destLo, srcLo);
512 opRegCopy(cUnit, destHi, srcHi);
513 }
buzbeee3acd072012-02-25 17:03:10 -0800514#endif
buzbeee3acd072012-02-25 17:03:10 -0800515}
516
jeffhao4b771a02012-07-25 15:07:21 -0700517void genFusedLongCmpBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir)
518{
519 UNIMPLEMENTED(FATAL) << "Need codegen for fused long cmp branch";
520}
521
buzbeeb046e162012-10-30 15:48:42 -0700522LIR* genRegMemCheck(CompilationUnit* cUnit, ConditionCode cCode,
523 int reg1, int base, int offset, ThrowKind kind)
524{
525 LOG(FATAL) << "Unexpected use of genRegMemCheck for Arm";
526 return NULL;
527}
528
529RegLocation genDivRem(CompilationUnit* cUnit, RegLocation rlDest, int reg1, int reg2, bool isDiv)
530{
531 newLIR4(cUnit, kMipsDiv, r_HI, r_LO, reg1, reg2);
532 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
533 if (isDiv) {
534 newLIR2(cUnit, kMipsMflo, rlResult.lowReg, r_LO);
535 } else {
536 newLIR2(cUnit, kMipsMfhi, rlResult.lowReg, r_HI);
537 }
538 return rlResult;
539}
540
541RegLocation genDivRemLit(CompilationUnit* cUnit, RegLocation rlDest, int reg1, int lit, bool isDiv)
542{
543 int tReg = oatAllocTemp(cUnit);
544 newLIR3(cUnit, kMipsAddiu, tReg, r_ZERO, lit);
545 newLIR4(cUnit, kMipsDiv, r_HI, r_LO, reg1, tReg);
546 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
547 if (isDiv) {
548 newLIR2(cUnit, kMipsMflo, rlResult.lowReg, r_LO);
549 } else {
550 newLIR2(cUnit, kMipsMfhi, rlResult.lowReg, r_HI);
551 }
552 oatFreeTemp(cUnit, tReg);
553 return rlResult;
554}
555
556/*
557 * Mark garbage collection card. Skip if the value we're storing is null.
558 */
559void markGCCard(CompilationUnit* cUnit, int valReg, int tgtAddrReg)
560{
561 int regCardBase = oatAllocTemp(cUnit);
562 int regCardNo = oatAllocTemp(cUnit);
563 LIR* branchOver = opCmpImmBranch(cUnit, kCondEq, valReg, 0, NULL);
564 loadWordDisp(cUnit, rSELF, Thread::CardTableOffset().Int32Value(), regCardBase);
565 opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, CardTable::kCardShift);
566 storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
567 kUnsignedByte);
568 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
569 branchOver->target = (LIR*)target;
570 oatFreeTemp(cUnit, regCardBase);
571 oatFreeTemp(cUnit, regCardNo);
572}
573
574bool genInlinedMinMaxInt(CompilationUnit *cUnit, CallInfo* info, bool isMin)
575{
576 // TODO: need Mips implementation
577 return false;
578}
579
580void opLea(CompilationUnit* cUnit, int rBase, int reg1, int reg2, int scale, int offset)
581{
582 LOG(FATAL) << "Unexpected use of opLea for Arm";
583}
584
585void opTlsCmp(CompilationUnit* cUnit, int offset, int val)
586{
587 LOG(FATAL) << "Unexpected use of opTlsCmp for Arm";
588}
589
590bool genInlinedCas32(CompilationUnit* cUnit, CallInfo* info, bool need_write_barrier) {
591 DCHECK_NE(cUnit->instructionSet, kThumb2);
592 return false;
593}
594
595bool genInlinedSqrt(CompilationUnit* cUnit, CallInfo* info) {
596 DCHECK_NE(cUnit->instructionSet, kThumb2);
597 return false;
598}
599
600LIR* opPcRelLoad(CompilationUnit* cUnit, int reg, LIR* target) {
601 LOG(FATAL) << "Unexpected use of opPcRelLoad for Mips";
602 return NULL;
603}
604
605LIR* opVldm(CompilationUnit* cUnit, int rBase, int count)
606{
607 LOG(FATAL) << "Unexpected use of opVldm for Mips";
608 return NULL;
609}
610
611LIR* opVstm(CompilationUnit* cUnit, int rBase, int count)
612{
613 LOG(FATAL) << "Unexpected use of opVstm for Mips";
614 return NULL;
615}
616
617void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc,
618 RegLocation rlResult, int lit,
619 int firstBit, int secondBit)
620{
621 int tReg = oatAllocTemp(cUnit);
622 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, secondBit - firstBit);
623 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, tReg);
624 oatFreeTemp(cUnit, tReg);
625 if (firstBit != 0) {
626 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
627 }
628}
629
630void genDivZeroCheck(CompilationUnit* cUnit, int regLo, int regHi)
631{
632 int tReg = oatAllocTemp(cUnit);
633 opRegRegReg(cUnit, kOpOr, tReg, regLo, regHi);
634 genImmedCheck(cUnit, kCondEq, tReg, 0, kThrowDivZero);
635 oatFreeTemp(cUnit, tReg);
636}
637
638// Test suspend flag, return target of taken suspend branch
639LIR* opTestSuspend(CompilationUnit* cUnit, LIR* target)
640{
641 opRegImm(cUnit, kOpSub, rSUSPEND, 1);
642 return opCmpImmBranch(cUnit, (target == NULL) ? kCondEq : kCondNe, rSUSPEND, 0, target);
643}
644
645// Decrement register and branch on condition
646LIR* opDecAndBranch(CompilationUnit* cUnit, ConditionCode cCode, int reg, LIR* target)
647{
648 opRegImm(cUnit, kOpSub, reg, 1);
649 return opCmpImmBranch(cUnit, cCode, reg, 0, target);
650}
651
652bool smallLiteralDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode,
653 RegLocation rlSrc, RegLocation rlDest, int lit)
654{
655 LOG(FATAL) << "Unexpected use of smallLiteralDive in Mips";
656 return false;
657}
658
659LIR* opIT(CompilationUnit* cUnit, ArmConditionCode cond, const char* guide)
660{
661 LOG(FATAL) << "Unexpected use of opIT in Mips";
662 return NULL;
663}
664
buzbeee3acd072012-02-25 17:03:10 -0800665} // namespace art