blob: f2dbc11b505b8d1edb8b1a7684ab06e523cbdf14 [file] [log] [blame]
buzbeee88dfbf2012-03-05 11:19:57 -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/*
buzbeea7678db2012-03-05 15:35:46 -080018 * This file contains codegen for the X86 ISA and is intended to be
buzbeee88dfbf2012-03-05 11:19:57 -080019 * 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
buzbeee88dfbf2012-03-05 11:19:57 -080033/*
Ian Rogersb5d09b22012-03-06 22:14:17 -080034 * Perform register memory operation.
35 */
36LIR* genRegMemCheck(CompilationUnit* cUnit, ConditionCode cCode,
37 int reg1, int base, int offset, MIR* mir, ThrowKind kind)
38{
39 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
40 mir ? mir->offset : 0, reg1, base, offset);
41 opRegMem(cUnit, kOpCmp, reg1, base, offset);
42 LIR* branch = opCondBranch(cUnit, cCode, tgt);
43 // Remember branch target - will process later
44 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
45 return branch;
46}
47
48/*
Ian Rogers55bd45f2012-04-04 17:31:20 -070049 * The sparse table in the literal pool is an array of <key,displacement>
50 * pairs.
buzbeee88dfbf2012-03-05 11:19:57 -080051 */
Ian Rogers55bd45f2012-04-04 17:31:20 -070052BasicBlock *findBlock(CompilationUnit* cUnit, unsigned int codeOffset,
53 bool split, bool create, BasicBlock** immedPredBlockP);
54void genSparseSwitch(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc, LIR* labelList) {
55 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
56 if (cUnit->printMe) {
57 dumpSparseSwitchTable(table);
58 }
59 int entries = table[1];
60 int* keys = (int*)&table[2];
61 int* targets = &keys[entries];
62 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
63 for (int i = 0; i < entries; i++) {
64 int key = keys[i];
65 BasicBlock* case_block = findBlock(cUnit, mir->offset + targets[i],
66 false, false, NULL);
67 opCmpImmBranch(cUnit, kCondEq, rlSrc.lowReg, key, &labelList[case_block->id]);
68 }
buzbeee88dfbf2012-03-05 11:19:57 -080069}
70
71/*
72 * Code pattern will look something like:
73 *
Ian Rogers55bd45f2012-04-04 17:31:20 -070074 * mov rVal, ..
75 * call 0
76 * pop rStartOfMethod
77 * sub rStartOfMethod, ..
78 * mov rKeyReg, rVal
79 * sub rKeyReg, lowKey
80 * cmp rKeyReg, size-1 ; bound check
81 * ja done
82 * mov rDisp, [rStartOfMethod + rKeyReg * 4 + tableOffset]
83 * add rStartOfMethod, rDisp
84 * jmp rStartOfMethod
buzbeee88dfbf2012-03-05 11:19:57 -080085 * done:
86 */
Ian Rogers7caad772012-03-30 01:07:54 -070087void genPackedSwitch(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc) {
88 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
89 if (cUnit->printMe) {
90 dumpPackedSwitchTable(table);
91 }
92 // Add the table to the list - we'll process it later
93 SwitchTable *tabRec = (SwitchTable *)oatNew(cUnit, sizeof(SwitchTable),
94 true, kAllocData);
95 tabRec->table = table;
96 tabRec->vaddr = mir->offset;
97 int size = table[1];
98 tabRec->targets = (LIR* *)oatNew(cUnit, size * sizeof(LIR*), true,
99 kAllocLIR);
100 oatInsertGrowableList(cUnit, &cUnit->switchTables, (intptr_t)tabRec);
buzbeee88dfbf2012-03-05 11:19:57 -0800101
Ian Rogers7caad772012-03-30 01:07:54 -0700102 // Get the switch value
103 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
104 int startOfMethodReg = oatAllocTemp(cUnit);
105 // Materialize a pointer to the switch table
106 //newLIR0(cUnit, kX86Bkpt);
107 newLIR1(cUnit, kX86StartOfMethod, startOfMethodReg);
108 int lowKey = s4FromSwitchData(&table[2]);
109 int keyReg;
110 // Remove the bias, if necessary
111 if (lowKey == 0) {
112 keyReg = rlSrc.lowReg;
113 } else {
114 keyReg = oatAllocTemp(cUnit);
115 opRegRegImm(cUnit, kOpSub, keyReg, rlSrc.lowReg, lowKey);
116 }
117 // Bounds check - if < 0 or >= size continue following switch
118 opRegImm(cUnit, kOpCmp, keyReg, size-1);
119 LIR* branchOver = opCondBranch(cUnit, kCondHi, NULL);
buzbeee88dfbf2012-03-05 11:19:57 -0800120
Ian Rogers7caad772012-03-30 01:07:54 -0700121 // Load the displacement from the switch table
122 int dispReg = oatAllocTemp(cUnit);
123 newLIR5(cUnit, kX86PcRelLoadRA, dispReg, startOfMethodReg, keyReg, 2, (intptr_t)tabRec);
124 // Add displacement to start of method
125 opRegReg(cUnit, kOpAdd, startOfMethodReg, dispReg);
126 // ..and go!
127 LIR* switchBranch = newLIR1(cUnit, kX86JmpR, startOfMethodReg);
128 tabRec->anchor = switchBranch;
buzbeee88dfbf2012-03-05 11:19:57 -0800129
Ian Rogers7caad772012-03-30 01:07:54 -0700130 /* branchOver target here */
131 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
132 branchOver->target = (LIR*)target;
buzbeee88dfbf2012-03-05 11:19:57 -0800133}
134
Ian Rogers7caad772012-03-30 01:07:54 -0700135void callRuntimeHelperRegReg(CompilationUnit* cUnit, int helperOffset, int arg0, int arg1);
buzbeee88dfbf2012-03-05 11:19:57 -0800136/*
137 * Array data table format:
138 * ushort ident = 0x0300 magic value
139 * ushort width width of each element in the table
140 * uint size number of elements in the table
141 * ubyte data[size*width] table of data values (may contain a single-byte
142 * padding at the end)
143 *
144 * Total size is 4+(width * size + 1)/2 16-bit code units.
145 */
146void genFillArrayData(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
147{
Ian Rogers7caad772012-03-30 01:07:54 -0700148 const u2* table = cUnit->insns + mir->offset + mir->dalvikInsn.vB;
149 // Add the table to the list - we'll process it later
150 FillArrayData *tabRec = (FillArrayData *)oatNew(cUnit, sizeof(FillArrayData), true, kAllocData);
151 tabRec->table = table;
152 tabRec->vaddr = mir->offset;
153 u2 width = tabRec->table[1];
154 u4 size = tabRec->table[2] | (((u4)tabRec->table[3]) << 16);
155 tabRec->size = (size * width) + 8;
buzbeee88dfbf2012-03-05 11:19:57 -0800156
Ian Rogers7caad772012-03-30 01:07:54 -0700157 oatInsertGrowableList(cUnit, &cUnit->fillArrayData, (intptr_t)tabRec);
buzbeee88dfbf2012-03-05 11:19:57 -0800158
Ian Rogers7caad772012-03-30 01:07:54 -0700159 // Making a call - use explicit registers
160 oatFlushAllRegs(cUnit); /* Everything to home location */
161 loadValueDirectFixed(cUnit, rlSrc, rARG0);
162 // Materialize a pointer to the fill data image
163 newLIR1(cUnit, kX86StartOfMethod, rARG2);
164 newLIR2(cUnit, kX86PcRelAdr, rARG1, (intptr_t)tabRec);
165 newLIR2(cUnit, kX86Add32RR, rARG1, rARG2);
166 callRuntimeHelperRegReg(cUnit, ENTRYPOINT_OFFSET(pHandleFillArrayDataFromCode), rARG0, rARG1);
buzbeee88dfbf2012-03-05 11:19:57 -0800167}
168
169void genNegFloat(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
170{
buzbeea7678db2012-03-05 15:35:46 -0800171 UNIMPLEMENTED(WARNING) << "genNegFloat";
Ian Rogers7caad772012-03-30 01:07:54 -0700172 newLIR0(cUnit, kX86Bkpt);
buzbeea7678db2012-03-05 15:35:46 -0800173#if 0
buzbeee88dfbf2012-03-05 11:19:57 -0800174 RegLocation rlResult;
175 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
176 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
177 opRegRegImm(cUnit, kOpAdd, rlResult.lowReg,
178 rlSrc.lowReg, 0x80000000);
179 storeValue(cUnit, rlDest, rlResult);
180#endif
181}
182
183void genNegDouble(CompilationUnit *cUnit, RegLocation rlDest, RegLocation rlSrc)
184{
185 UNIMPLEMENTED(WARNING) << "genNegDouble";
Ian Rogers7caad772012-03-30 01:07:54 -0700186 newLIR0(cUnit, kX86Bkpt);
buzbeee88dfbf2012-03-05 11:19:57 -0800187#if 0
188 RegLocation rlResult;
189 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
190 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
191 opRegRegImm(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg,
192 0x80000000);
193 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
194 storeValueWide(cUnit, rlDest, rlResult);
195#endif
196}
197
Ian Rogers7caad772012-03-30 01:07:54 -0700198LIR* genNullCheck(CompilationUnit* cUnit, int sReg, int mReg, MIR* mir);
199void callRuntimeHelperReg(CompilationUnit* cUnit, int helperOffset, int arg0);
200
buzbeee88dfbf2012-03-05 11:19:57 -0800201/*
202 * TODO: implement fast path to short-circuit thin-lock case
203 */
204void genMonitorEnter(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
205{
buzbeee88dfbf2012-03-05 11:19:57 -0800206 oatFlushAllRegs(cUnit);
207 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get obj
208 oatLockCallTemps(cUnit); // Prepare for explicit register usage
209 genNullCheck(cUnit, rlSrc.sRegLow, rARG0, mir);
210 // Go expensive route - artLockObjectFromCode(self, obj);
Ian Rogers7caad772012-03-30 01:07:54 -0700211 callRuntimeHelperReg(cUnit, ENTRYPOINT_OFFSET(pLockObjectFromCode), rARG0);
buzbeee88dfbf2012-03-05 11:19:57 -0800212}
213
214/*
215 * TODO: implement fast path to short-circuit thin-lock case
216 */
217void genMonitorExit(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
218{
buzbeee88dfbf2012-03-05 11:19:57 -0800219 oatFlushAllRegs(cUnit);
220 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get obj
221 oatLockCallTemps(cUnit); // Prepare for explicit register usage
222 genNullCheck(cUnit, rlSrc.sRegLow, rARG0, mir);
223 // Go expensive route - UnlockObjectFromCode(obj);
Ian Rogers7caad772012-03-30 01:07:54 -0700224 callRuntimeHelperReg(cUnit, ENTRYPOINT_OFFSET(pUnlockObjectFromCode), rARG0);
buzbeee88dfbf2012-03-05 11:19:57 -0800225}
226
227/*
228 * Compare two 64-bit values
229 * x = y return 0
230 * x < y return -1
231 * x > y return 1
232 *
233 * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
234 * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
235 * subu res, t0, t1 # res = -1:1:0 for [ < > = ]
236 * bnez res, finish
237 * sltu t0, x.lo, y.lo
238 * sgtu r1, x.lo, y.lo
239 * subu res, t0, t1
240 * finish:
241 *
242 */
243void genCmpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
244 RegLocation rlSrc1, RegLocation rlSrc2)
245{
Ian Rogers7caad772012-03-30 01:07:54 -0700246 oatFlushAllRegs(cUnit);
247 oatLockCallTemps(cUnit); // Prepare for explicit register usage
248 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
249 loadValueDirectWideFixed(cUnit, rlSrc1, r2, r3);
250 // Compute (r1:r0) = (r1:r0) - (r2:r3)
251 opRegReg(cUnit, kOpSub, r0, r2); // r0 = r0 - r2
252 opRegReg(cUnit, kOpSbc, r1, r3); // r1 = r1 - r3 - CF
253 opRegReg(cUnit, kOpOr, r0, r1); // r0 = high | low - sets ZF
254 newLIR2(cUnit, kX86Set8R, r0, kX86CondNz); // r0 = (r1:r0) != (r2:r3) ? 1 : 0
255 newLIR2(cUnit, kX86Movzx8RR, r0, r0);
256 opRegImm(cUnit, kOpAsr, r1, 31); // r1 = high >> 31
257 opRegReg(cUnit, kOpOr, r0, r1); // r0 holds result
258 RegLocation rlResult = LOC_C_RETURN;
buzbeee88dfbf2012-03-05 11:19:57 -0800259 storeValue(cUnit, rlDest, rlResult);
buzbeee88dfbf2012-03-05 11:19:57 -0800260}
261
Ian Rogersb5d09b22012-03-06 22:14:17 -0800262X86ConditionCode oatX86ConditionEncoding(ConditionCode cond) {
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700263 switch (cond) {
Ian Rogersb5d09b22012-03-06 22:14:17 -0800264 case kCondEq: return kX86CondEq;
265 case kCondNe: return kX86CondNe;
266 case kCondCs: return kX86CondC;
267 case kCondCc: return kX86CondNc;
268 case kCondMi: return kX86CondS;
269 case kCondPl: return kX86CondNs;
270 case kCondVs: return kX86CondO;
271 case kCondVc: return kX86CondNo;
272 case kCondHi: return kX86CondA;
273 case kCondLs: return kX86CondBe;
274 case kCondGe: return kX86CondGe;
275 case kCondLt: return kX86CondL;
276 case kCondGt: return kX86CondG;
277 case kCondLe: return kX86CondLe;
278 case kCondAl:
279 case kCondNv: LOG(FATAL) << "Should not reach here";
280 }
281 return kX86CondO;
282}
283
284LIR* opCmpBranch(CompilationUnit* cUnit, ConditionCode cond, int src1, int src2, LIR* target)
buzbeee88dfbf2012-03-05 11:19:57 -0800285{
Ian Rogersb5d09b22012-03-06 22:14:17 -0800286 newLIR2(cUnit, kX86Cmp32RR, src1, src2);
287 X86ConditionCode cc = oatX86ConditionEncoding(cond);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700288 LIR* branch = newLIR2(cUnit, kX86Jcc8, 0 /* lir operand for Jcc offset */ , cc);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800289 branch->target = target;
290 return branch;
buzbeee88dfbf2012-03-05 11:19:57 -0800291}
292
293LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg,
294 int checkValue, LIR* target)
295{
Ian Rogers7caad772012-03-30 01:07:54 -0700296 if (false && (checkValue == 0) && (cond == kCondEq || cond == kCondNe)) {
297 // TODO: when checkValue == 0 and reg is rCX, use the jcxz/nz opcode
298 // newLIR2(cUnit, kX86Test32RR, reg, reg);
299 } else {
300 newLIR2(cUnit, kX86Cmp32RI, reg, checkValue);
301 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800302 X86ConditionCode cc = oatX86ConditionEncoding(cond);
Ian Rogersb41b33b2012-03-20 14:22:54 -0700303 LIR* branch = newLIR2(cUnit, kX86Jcc8, 0 /* lir operand for Jcc offset */ , cc);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800304 branch->target = target;
305 return branch;
buzbeee88dfbf2012-03-05 11:19:57 -0800306}
307
308LIR* opRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
309{
buzbeee88dfbf2012-03-05 11:19:57 -0800310 if (FPREG(rDest) || FPREG(rSrc))
311 return fpRegCopy(cUnit, rDest, rSrc);
Ian Rogersb5d09b22012-03-06 22:14:17 -0800312 LIR* res = rawLIR(cUnit, cUnit->currentDalvikOffset, kX86Mov32RR,
buzbeee88dfbf2012-03-05 11:19:57 -0800313 rDest, rSrc);
314 if (rDest == rSrc) {
315 res->flags.isNop = true;
316 }
317 return res;
buzbeee88dfbf2012-03-05 11:19:57 -0800318}
319
320LIR* opRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
321{
322 LIR *res = opRegCopyNoInsert(cUnit, rDest, rSrc);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700323 oatAppendLIR(cUnit, res);
buzbeee88dfbf2012-03-05 11:19:57 -0800324 return res;
325}
326
327void opRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700328 int srcLo, int srcHi) {
329 bool destFP = FPREG(destLo) && FPREG(destHi);
330 bool srcFP = FPREG(srcLo) && FPREG(srcHi);
331 assert(FPREG(srcLo) == FPREG(srcHi));
332 assert(FPREG(destLo) == FPREG(destHi));
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700333 if (destFP) {
334 if (srcFP) {
335 opRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
buzbeee88dfbf2012-03-05 11:19:57 -0800336 } else {
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700337 UNIMPLEMENTED(WARNING);
Ian Rogers7caad772012-03-30 01:07:54 -0700338 newLIR0(cUnit, kX86Bkpt);
buzbeee88dfbf2012-03-05 11:19:57 -0800339 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700340 } else {
341 if (srcFP) {
342 UNIMPLEMENTED(WARNING);
Ian Rogers7caad772012-03-30 01:07:54 -0700343 newLIR0(cUnit, kX86Bkpt);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700344 } else {
345 // Handle overlap
346 if (srcHi == destLo) {
buzbeee88dfbf2012-03-05 11:19:57 -0800347 opRegCopy(cUnit, destHi, srcHi);
348 opRegCopy(cUnit, destLo, srcLo);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700349 } else {
buzbeee88dfbf2012-03-05 11:19:57 -0800350 opRegCopy(cUnit, destLo, srcLo);
351 opRegCopy(cUnit, destHi, srcHi);
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700352 }
buzbeee88dfbf2012-03-05 11:19:57 -0800353 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -0700354 }
buzbeee88dfbf2012-03-05 11:19:57 -0800355}
356
357} // namespace art