blob: adde4829eff47b050c23948647a36dd889ba199e [file] [log] [blame]
buzbeeefc63692012-11-14 16:31:52 -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/* This file contains codegen for the X86 ISA */
18
buzbee1bc37c62012-11-20 13:35:41 -080019#include "x86_lir.h"
20#include "../codegen_util.h"
21#include "../ralloc_util.h"
22
buzbeeefc63692012-11-14 16:31:52 -080023namespace art {
24
25/*
26 * Perform register memory operation.
27 */
28LIR* genRegMemCheck(CompilationUnit* cUnit, ConditionCode cCode,
29 int reg1, int base, int offset, ThrowKind kind)
30{
31 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
32 cUnit->currentDalvikOffset, reg1, base, offset);
33 opRegMem(cUnit, kOpCmp, reg1, base, offset);
34 LIR* branch = opCondBranch(cUnit, cCode, tgt);
35 // Remember branch target - will process later
buzbeecbd6d442012-11-17 14:11:25 -080036 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, reinterpret_cast<uintptr_t>(tgt));
buzbeeefc63692012-11-14 16:31:52 -080037 return branch;
38}
39
40/*
41 * Compare two 64-bit values
42 * x = y return 0
43 * x < y return -1
44 * x > y return 1
45 *
46 * slt t0, x.hi, y.hi; # (x.hi < y.hi) ? 1:0
47 * sgt t1, x.hi, y.hi; # (y.hi > x.hi) ? 1:0
48 * subu res, t0, t1 # res = -1:1:0 for [ < > = ]
49 * bnez res, finish
50 * sltu t0, x.lo, y.lo
51 * sgtu r1, x.lo, y.lo
52 * subu res, t0, t1
53 * finish:
54 *
55 */
56void genCmpLong(CompilationUnit* cUnit, RegLocation rlDest,
57 RegLocation rlSrc1, RegLocation rlSrc2)
58{
59 oatFlushAllRegs(cUnit);
60 oatLockCallTemps(cUnit); // Prepare for explicit register usage
61 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
62 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
63 // Compute (r1:r0) = (r1:r0) - (r3:r2)
64 opRegReg(cUnit, kOpSub, r0, r2); // r0 = r0 - r2
65 opRegReg(cUnit, kOpSbc, r1, r3); // r1 = r1 - r3 - CF
66 newLIR2(cUnit, kX86Set8R, r2, kX86CondL); // r2 = (r1:r0) < (r3:r2) ? 1 : 0
67 newLIR2(cUnit, kX86Movzx8RR, r2, r2);
68 opReg(cUnit, kOpNeg, r2); // r2 = -r2
69 opRegReg(cUnit, kOpOr, r0, r1); // r0 = high | low - sets ZF
70 newLIR2(cUnit, kX86Set8R, r0, kX86CondNz); // r0 = (r1:r0) != (r3:r2) ? 1 : 0
71 newLIR2(cUnit, kX86Movzx8RR, r0, r0);
72 opRegReg(cUnit, kOpOr, r0, r2); // r0 = r0 | r2
73 RegLocation rlResult = locCReturn();
74 storeValue(cUnit, rlDest, rlResult);
75}
76
77X86ConditionCode oatX86ConditionEncoding(ConditionCode cond) {
78 switch (cond) {
79 case kCondEq: return kX86CondEq;
80 case kCondNe: return kX86CondNe;
81 case kCondCs: return kX86CondC;
82 case kCondCc: return kX86CondNc;
83 case kCondMi: return kX86CondS;
84 case kCondPl: return kX86CondNs;
85 case kCondVs: return kX86CondO;
86 case kCondVc: return kX86CondNo;
87 case kCondHi: return kX86CondA;
88 case kCondLs: return kX86CondBe;
89 case kCondGe: return kX86CondGe;
90 case kCondLt: return kX86CondL;
91 case kCondGt: return kX86CondG;
92 case kCondLe: return kX86CondLe;
93 case kCondAl:
94 case kCondNv: LOG(FATAL) << "Should not reach here";
95 }
96 return kX86CondO;
97}
98
99LIR* opCmpBranch(CompilationUnit* cUnit, ConditionCode cond, int src1,
100 int src2, LIR* target)
101{
102 newLIR2(cUnit, kX86Cmp32RR, src1, src2);
103 X86ConditionCode cc = oatX86ConditionEncoding(cond);
104 LIR* branch = newLIR2(cUnit, kX86Jcc8, 0 /* lir operand for Jcc offset */ ,
105 cc);
106 branch->target = target;
107 return branch;
108}
109
110LIR* opCmpImmBranch(CompilationUnit* cUnit, ConditionCode cond, int reg,
111 int checkValue, LIR* target)
112{
113 if ((checkValue == 0) && (cond == kCondEq || cond == kCondNe)) {
114 // TODO: when checkValue == 0 and reg is rCX, use the jcxz/nz opcode
115 newLIR2(cUnit, kX86Test32RR, reg, reg);
116 } else {
117 newLIR2(cUnit, IS_SIMM8(checkValue) ? kX86Cmp32RI8 : kX86Cmp32RI, reg, checkValue);
118 }
119 X86ConditionCode cc = oatX86ConditionEncoding(cond);
120 LIR* branch = newLIR2(cUnit, kX86Jcc8, 0 /* lir operand for Jcc offset */ , cc);
121 branch->target = target;
122 return branch;
123}
124
125LIR* opRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
126{
127 if (X86_FPREG(rDest) || X86_FPREG(rSrc))
128 return fpRegCopy(cUnit, rDest, rSrc);
129 LIR* res = rawLIR(cUnit, cUnit->currentDalvikOffset, kX86Mov32RR,
130 rDest, rSrc);
131 if (rDest == rSrc) {
132 res->flags.isNop = true;
133 }
134 return res;
135}
136
137LIR* opRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
138{
139 LIR *res = opRegCopyNoInsert(cUnit, rDest, rSrc);
140 oatAppendLIR(cUnit, res);
141 return res;
142}
143
144void opRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
145 int srcLo, int srcHi)
146{
147 bool destFP = X86_FPREG(destLo) && X86_FPREG(destHi);
148 bool srcFP = X86_FPREG(srcLo) && X86_FPREG(srcHi);
149 assert(X86_FPREG(srcLo) == X86_FPREG(srcHi));
150 assert(X86_FPREG(destLo) == X86_FPREG(destHi));
151 if (destFP) {
152 if (srcFP) {
153 opRegCopy(cUnit, s2d(destLo, destHi), s2d(srcLo, srcHi));
154 } else {
155 // TODO: Prevent this from happening in the code. The result is often
156 // unused or could have been loaded more easily from memory.
157 newLIR2(cUnit, kX86MovdxrRR, destLo, srcLo);
158 newLIR2(cUnit, kX86MovdxrRR, destHi, srcHi);
159 newLIR2(cUnit, kX86PsllqRI, destHi, 32);
160 newLIR2(cUnit, kX86OrpsRR, destLo, destHi);
161 }
162 } else {
163 if (srcFP) {
164 newLIR2(cUnit, kX86MovdrxRR, destLo, srcLo);
165 newLIR2(cUnit, kX86PsrlqRI, srcLo, 32);
166 newLIR2(cUnit, kX86MovdrxRR, destHi, srcLo);
167 } else {
168 // Handle overlap
169 if (srcHi == destLo) {
170 opRegCopy(cUnit, destHi, srcHi);
171 opRegCopy(cUnit, destLo, srcLo);
172 } else {
173 opRegCopy(cUnit, destLo, srcLo);
174 opRegCopy(cUnit, destHi, srcHi);
175 }
176 }
177 }
178}
179
180void genFusedLongCmpBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir) {
181 LIR* labelList = cUnit->blockLabelList;
182 LIR* taken = &labelList[bb->taken->id];
183 RegLocation rlSrc1 = oatGetSrcWide(cUnit, mir, 0);
184 RegLocation rlSrc2 = oatGetSrcWide(cUnit, mir, 2);
185 oatFlushAllRegs(cUnit);
186 oatLockCallTemps(cUnit); // Prepare for explicit register usage
187 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
188 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
189 ConditionCode ccode = static_cast<ConditionCode>(mir->dalvikInsn.arg[0]);
190 // Swap operands and condition code to prevent use of zero flag.
191 if (ccode == kCondLe || ccode == kCondGt) {
192 // Compute (r3:r2) = (r3:r2) - (r1:r0)
193 opRegReg(cUnit, kOpSub, r2, r0); // r2 = r2 - r0
194 opRegReg(cUnit, kOpSbc, r3, r1); // r3 = r3 - r1 - CF
195 } else {
196 // Compute (r1:r0) = (r1:r0) - (r3:r2)
197 opRegReg(cUnit, kOpSub, r0, r2); // r0 = r0 - r2
198 opRegReg(cUnit, kOpSbc, r1, r3); // r1 = r1 - r3 - CF
199 }
200 switch (ccode) {
201 case kCondEq:
202 case kCondNe:
203 opRegReg(cUnit, kOpOr, r0, r1); // r0 = r0 | r1
204 break;
205 case kCondLe:
206 ccode = kCondGe;
207 break;
208 case kCondGt:
209 ccode = kCondLt;
210 break;
211 case kCondLt:
212 case kCondGe:
213 break;
214 default:
buzbeecbd6d442012-11-17 14:11:25 -0800215 LOG(FATAL) << "Unexpected ccode: " << ccode;
buzbeeefc63692012-11-14 16:31:52 -0800216 }
217 opCondBranch(cUnit, ccode, taken);
218}
219RegLocation genDivRemLit(CompilationUnit* cUnit, RegLocation rlDest, int regLo, int lit, bool isDiv)
220{
221 LOG(FATAL) << "Unexpected use of genDivRemLit for x86";
222 return rlDest;
223}
224
225RegLocation genDivRem(CompilationUnit* cUnit, RegLocation rlDest, int regLo, int regHi, bool isDiv)
226{
227 LOG(FATAL) << "Unexpected use of genDivRem for x86";
228 return rlDest;
229}
230
231bool genInlinedMinMaxInt(CompilationUnit *cUnit, CallInfo* info, bool isMin)
232{
233 DCHECK_EQ(cUnit->instructionSet, kX86);
234 RegLocation rlSrc1 = info->args[0];
235 RegLocation rlSrc2 = info->args[1];
236 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
237 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
238 RegLocation rlDest = inlineTarget(cUnit, info);
239 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
240 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
241 DCHECK_EQ(cUnit->instructionSet, kX86);
242 LIR* branch = newLIR2(cUnit, kX86Jcc8, 0, isMin ? kX86CondG : kX86CondL);
243 opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc1.lowReg);
244 LIR* branch2 = newLIR1(cUnit, kX86Jmp8, 0);
245 branch->target = newLIR0(cUnit, kPseudoTargetLabel);
246 opRegReg(cUnit, kOpMov, rlResult.lowReg, rlSrc2.lowReg);
247 branch2->target = newLIR0(cUnit, kPseudoTargetLabel);
248 storeValue(cUnit, rlDest, rlResult);
249 return true;
250}
251
252void opLea(CompilationUnit* cUnit, int rBase, int reg1, int reg2, int scale, int offset)
253{
254 newLIR5(cUnit, kX86Lea32RA, rBase, reg1, reg2, scale, offset);
255}
256
257void opTlsCmp(CompilationUnit* cUnit, int offset, int val)
258{
259 newLIR2(cUnit, kX86Cmp16TI8, offset, val);
260}
261
262bool genInlinedCas32(CompilationUnit* cUnit, CallInfo* info, bool need_write_barrier) {
263 DCHECK_NE(cUnit->instructionSet, kThumb2);
264 return false;
265}
266
267LIR* opPcRelLoad(CompilationUnit* cUnit, int reg, LIR* target) {
268 LOG(FATAL) << "Unexpected use of opPcRelLoad for x86";
269 return NULL;
270}
271
272LIR* opVldm(CompilationUnit* cUnit, int rBase, int count)
273{
274 LOG(FATAL) << "Unexpected use of opVldm for x86";
275 return NULL;
276}
277
278LIR* opVstm(CompilationUnit* cUnit, int rBase, int count)
279{
280 LOG(FATAL) << "Unexpected use of opVstm for x86";
281 return NULL;
282}
283
284void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc,
285 RegLocation rlResult, int lit,
286 int firstBit, int secondBit)
287{
288 int tReg = oatAllocTemp(cUnit);
289 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, secondBit - firstBit);
290 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, tReg);
291 oatFreeTemp(cUnit, tReg);
292 if (firstBit != 0) {
293 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
294 }
295}
296
297void genDivZeroCheck(CompilationUnit* cUnit, int regLo, int regHi)
298{
299 int tReg = oatAllocTemp(cUnit);
300 opRegRegReg(cUnit, kOpOr, tReg, regLo, regHi);
301 genImmedCheck(cUnit, kCondEq, tReg, 0, kThrowDivZero);
302 oatFreeTemp(cUnit, tReg);
303}
304
305// Test suspend flag, return target of taken suspend branch
306LIR* opTestSuspend(CompilationUnit* cUnit, LIR* target)
307{
308 opTlsCmp(cUnit, Thread::ThreadFlagsOffset().Int32Value(), 0);
309 return opCondBranch(cUnit, (target == NULL) ? kCondNe : kCondEq, target);
310}
311
312// Decrement register and branch on condition
313LIR* opDecAndBranch(CompilationUnit* cUnit, ConditionCode cCode, int reg, LIR* target)
314{
315 opRegImm(cUnit, kOpSub, reg, 1);
316 return opCmpImmBranch(cUnit, cCode, reg, 0, target);
317}
318
319bool smallLiteralDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode,
320 RegLocation rlSrc, RegLocation rlDest, int lit)
321{
322 LOG(FATAL) << "Unexpected use of smallLiteralDive in x86";
323 return false;
324}
325
326LIR* opIT(CompilationUnit* cUnit, ArmConditionCode cond, const char* guide)
327{
328 LOG(FATAL) << "Unexpected use of opIT in x86";
329 return NULL;
330}
331bool genAddLong(CompilationUnit* cUnit, RegLocation rlDest,
332 RegLocation rlSrc1, RegLocation rlSrc2)
333{
334 oatFlushAllRegs(cUnit);
335 oatLockCallTemps(cUnit); // Prepare for explicit register usage
336 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
337 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
338 // Compute (r1:r0) = (r1:r0) + (r2:r3)
339 opRegReg(cUnit, kOpAdd, r0, r2); // r0 = r0 + r2
340 opRegReg(cUnit, kOpAdc, r1, r3); // r1 = r1 + r3 + CF
341 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
342 INVALID_SREG, INVALID_SREG};
343 storeValueWide(cUnit, rlDest, rlResult);
344 return false;
345}
346
347bool genSubLong(CompilationUnit* cUnit, RegLocation rlDest,
348 RegLocation rlSrc1, RegLocation rlSrc2)
349{
350 oatFlushAllRegs(cUnit);
351 oatLockCallTemps(cUnit); // Prepare for explicit register usage
352 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
353 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
354 // Compute (r1:r0) = (r1:r0) + (r2:r3)
355 opRegReg(cUnit, kOpSub, r0, r2); // r0 = r0 - r2
356 opRegReg(cUnit, kOpSbc, r1, r3); // r1 = r1 - r3 - CF
357 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
358 INVALID_SREG, INVALID_SREG};
359 storeValueWide(cUnit, rlDest, rlResult);
360 return false;
361}
362
363bool genAndLong(CompilationUnit* cUnit, RegLocation rlDest,
364 RegLocation rlSrc1, RegLocation rlSrc2)
365{
366 oatFlushAllRegs(cUnit);
367 oatLockCallTemps(cUnit); // Prepare for explicit register usage
368 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
369 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
370 // Compute (r1:r0) = (r1:r0) + (r2:r3)
371 opRegReg(cUnit, kOpAnd, r0, r2); // r0 = r0 - r2
372 opRegReg(cUnit, kOpAnd, r1, r3); // r1 = r1 - r3 - CF
373 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
374 INVALID_SREG, INVALID_SREG};
375 storeValueWide(cUnit, rlDest, rlResult);
376 return false;
377}
378
379bool genOrLong(CompilationUnit* cUnit, RegLocation rlDest,
380 RegLocation rlSrc1, RegLocation rlSrc2)
381{
382 oatFlushAllRegs(cUnit);
383 oatLockCallTemps(cUnit); // Prepare for explicit register usage
384 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
385 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
386 // Compute (r1:r0) = (r1:r0) + (r2:r3)
387 opRegReg(cUnit, kOpOr, r0, r2); // r0 = r0 - r2
388 opRegReg(cUnit, kOpOr, r1, r3); // r1 = r1 - r3 - CF
389 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
390 INVALID_SREG, INVALID_SREG};
391 storeValueWide(cUnit, rlDest, rlResult);
392 return false;
393}
394
395bool genXorLong(CompilationUnit* cUnit, RegLocation rlDest,
396 RegLocation rlSrc1, RegLocation rlSrc2)
397{
398 oatFlushAllRegs(cUnit);
399 oatLockCallTemps(cUnit); // Prepare for explicit register usage
400 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
401 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
402 // Compute (r1:r0) = (r1:r0) + (r2:r3)
403 opRegReg(cUnit, kOpXor, r0, r2); // r0 = r0 - r2
404 opRegReg(cUnit, kOpXor, r1, r3); // r1 = r1 - r3 - CF
405 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
406 INVALID_SREG, INVALID_SREG};
407 storeValueWide(cUnit, rlDest, rlResult);
408 return false;
409}
410
411bool genNegLong(CompilationUnit* cUnit, RegLocation rlDest,
412 RegLocation rlSrc)
413{
414 oatFlushAllRegs(cUnit);
415 oatLockCallTemps(cUnit); // Prepare for explicit register usage
416 loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
417 // Compute (r1:r0) = -(r1:r0)
418 opRegReg(cUnit, kOpNeg, r0, r0); // r0 = -r0
419 opRegImm(cUnit, kOpAdc, r1, 0); // r1 = r1 + CF
420 opRegReg(cUnit, kOpNeg, r1, r1); // r1 = -r1
421 RegLocation rlResult = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, r0, r1,
422 INVALID_SREG, INVALID_SREG};
423 storeValueWide(cUnit, rlDest, rlResult);
424 return false;
425}
426
427void opRegThreadMem(CompilationUnit* cUnit, OpKind op, int rDest, int threadOffset) {
428 X86OpCode opcode = kX86Bkpt;
429 switch (op) {
430 case kOpCmp: opcode = kX86Cmp32RT; break;
431 default:
432 LOG(FATAL) << "Bad opcode: " << op;
433 break;
434 }
435 newLIR2(cUnit, opcode, rDest, threadOffset);
436}
437
438} // namespace art